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 }