hnakra/cmd/hnctl/main.go
2023-05-31 15:52:33 -04:00

152 lines
3.4 KiB
Go

package main
import "os"
import "fmt"
import "time"
import "flag"
import "os/exec"
import "hnakra/cli"
import "path/filepath"
import "hnakra/cmd/hnctl/spawn"
func main () {
flag.Usage = func () {
out := flag.CommandLine.Output()
fmt.Fprintf(out, "Usage of %s:\n", os.Args[0])
fmt.Fprintf(out, " start\n")
fmt.Fprintf(out, " Start a service\n")
fmt.Fprintf(out, " stop\n")
fmt.Fprintf(out, " Stop a service\n")
fmt.Fprintf(out, " restart\n")
fmt.Fprintf(out, " Start and then stop a service\n")
os.Exit(1)
}
// define commands
startCommand := flag.NewFlagSet("start", flag.ExitOnError)
startService := startCommand.String("s", "router", "Service to start")
stopCommand := flag.NewFlagSet("stop", flag.ExitOnError)
stopService := stopCommand.String("s", "router", "Service to stop")
restartCommand := flag.NewFlagSet("restart", flag.ExitOnError)
restartService := stopCommand.String("s", "router", "Service to restart")
flag.Parse()
// execute correct command
if len(os.Args) < 2 {
flag.Usage()
os.Exit(1)
}
subCommandArgs := os.Args[2:]
switch os.Args[1] {
case "start":
startCommand.Parse(subCommandArgs)
execStart(*startService)
case "stop":
stopCommand.Parse(subCommandArgs)
execStop(*stopService)
case "restart":
restartCommand.Parse(subCommandArgs)
execStop(*restartService)
execStart(*restartService)
}
}
func execStart (service string) {
fullName := cli.ServiceUser(service)
cli.NeedRoot()
pid, err := spawn.PidOf(fullName)
if err == nil && spawn.Running(pid) {
cli.Sayf("service is already running")
return
}
uid, gid, err := spawn.LookupUID(fullName)
if err != nil {
cli.Sayf("cannot start service: %v", err)
os.Exit(1)
}
path, err := exec.LookPath(fullName)
if err != nil {
cli.Sayf("cannot start service: %v", err)
os.Exit(1)
}
logDir := filepath.Join("/var/log/", fullName)
env := append(os.Environ(), "HNAKRA_LOG_DIR=" + logDir)
err = ensureLogDir(logDir, int(uid), int(gid))
if err != nil {
cli.Sayf("cannot start service: %v", err)
os.Exit(1)
}
// prepare pidfile. the service will be responsible for actually writing
// to it
err = ensurePidFile(spawn.PidFile(fullName), int(uid), int(gid))
if err != nil {
cli.Sayf("cannot start service: %v", err)
os.Exit(1)
}
// spawn the service
pid, err = spawn.Spawn(path, uid, gid, env)
if err != nil {
cli.Sayf("cannot start service: %v", err)
os.Exit(1)
}
fmt.Println(pid)
}
func execStop (service string) {
fullName := cli.ServiceUser(service)
cli.NeedRoot()
pid, err := spawn.PidOf(fullName)
if err != nil || !spawn.Running(pid) {
cli.Sayf("service is not running")
return
}
process, err := os.FindProcess(pid)
if err != nil {
cli.Sayf("service is not running")
return
}
err = spawn.KillAndWait(process, 16 * time.Second)
if err != nil {
cli.Sayf("could not stop service: %v", err)
os.Exit(1)
}
}
func ensureLogDir (directory string, uid, gid int) error {
err := os.MkdirAll(directory, 0755)
if err != nil { return err }
err = os.Chmod(directory, 0770)
if err != nil { return err }
err = os.Chown(directory, uid, gid)
if err != nil { return err }
return nil
}
func ensurePidFile (file string, uid, gid int) error {
pidFile, err := os.Create(file)
if err != nil { return err }
err = pidFile.Close()
if err != nil { return err }
err = os.Chmod(file, 0660)
if err != nil { return err }
err = os.Chown(file, uid, gid)
if err != nil { return err }
return nil
}