152 lines
3.4 KiB
Go
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
|
||
|
}
|