summaryrefslogtreecommitdiff
path: root/internal/jailmgr
diff options
context:
space:
mode:
authorClaude <noreply@anthropic.com>2026-08-05 23:14:29 -0500
committerClaude <noreply@anthropic.com>2026-08-05 23:14:29 -0500
commit9f7c9f2f31acd7bc544dd988af1c8c2fe63ec504 (patch)
tree6d7ab2a965c3e138a56c625197658ef2b324b045 /internal/jailmgr
Initial commit of skiff scaffolding
Diffstat (limited to 'internal/jailmgr')
-rw-r--r--internal/jailmgr/jailmgr.go71
1 files changed, 71 insertions, 0 deletions
diff --git a/internal/jailmgr/jailmgr.go b/internal/jailmgr/jailmgr.go
new file mode 100644
index 0000000..54cf614
--- /dev/null
+++ b/internal/jailmgr/jailmgr.go
@@ -0,0 +1,71 @@
+// Package jailmgr talks to jail(8) directly via jail.conf.d and the base
+// system's `service jail` rc.d script - no bastille/iocage in the loop.
+package jailmgr
+
+import (
+ "context"
+ "fmt"
+ "io"
+ "os"
+ "path/filepath"
+
+ "skiff/internal/layout"
+ "skiff/internal/sh"
+ "skiff/internal/tmpl"
+)
+
+// WriteConf renders jail.conf.d/<app>.conf and the jail's own rc.d service
+// script + rc.conf enable line. Called once, from `skiff new-app`.
+func WriteConf(cfg layout.Config, app, ip string) error {
+ conf, err := tmpl.JailConf(tmpl.JailConfData{
+ Name: app,
+ JailRoot: cfg.JailRoot(app),
+ IP: ip,
+ })
+ if err != nil {
+ return err
+ }
+ if err := os.WriteFile(cfg.JailConfPath(app), []byte(conf), 0644); err != nil {
+ return fmt.Errorf("write jail.conf: %w", err)
+ }
+
+ rc, err := tmpl.RCScript(tmpl.RCData{Name: app})
+ if err != nil {
+ return err
+ }
+ rcPath := filepath.Join(cfg.JailRoot(app), "usr", "local", "etc", "rc.d", app)
+ if err := os.MkdirAll(filepath.Dir(rcPath), 0755); err != nil {
+ return err
+ }
+ if err := os.WriteFile(rcPath, []byte(rc), 0755); err != nil {
+ return fmt.Errorf("write rc.d script: %w", err)
+ }
+
+ rcConfLine := fmt.Sprintf("\n%s_enable=\"YES\"\n", app)
+ f, err := os.OpenFile(filepath.Join(cfg.JailRoot(app), "etc", "rc.conf"), os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
+ if err != nil {
+ return fmt.Errorf("open jail rc.conf: %w", err)
+ }
+ defer f.Close()
+ if _, err := f.WriteString(rcConfLine); err != nil {
+ return fmt.Errorf("enable service in jail rc.conf: %w", err)
+ }
+ return nil
+}
+
+func Start(ctx context.Context, out io.Writer, app string) error {
+ return sh.Run(ctx, out, "", "service", "jail", "start", app)
+}
+
+func Stop(ctx context.Context, out io.Writer, app string) error {
+ return sh.Run(ctx, out, "", "service", "jail", "stop", app)
+}
+
+// Restart restarts an already-running jail, or starts it if this is its
+// first deploy and it isn't up yet.
+func Restart(ctx context.Context, out io.Writer, app string) error {
+ if err := sh.Run(ctx, out, "", "service", "jail", "restart", app); err != nil {
+ return sh.Run(ctx, out, "", "service", "jail", "start", app)
+ }
+ return nil
+}