2023-05-31 13:52:33 -06:00
|
|
|
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)
|
2023-05-31 22:59:03 -06:00
|
|
|
restartService := restartCommand.String("s", "router", "Service to restart")
|
2023-05-31 13:52:33 -06:00
|
|
|
|
|
|
|
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
|
|
|
|
}
|