|
|
@ -34,17 +34,19 @@ func main() { |
|
|
|
} |
|
|
|
} |
|
|
|
conf.Argv = args |
|
|
|
conf.Args = strings.Join(conf.Argv, " ") |
|
|
|
|
|
|
|
force := false |
|
|
|
forUser := false |
|
|
|
forSystem := false |
|
|
|
flag.StringVar(&conf.Title, "title", "", "a human-friendly name for the service") |
|
|
|
flag.StringVar(&conf.Desc, "desc", "", "a human-friendly description of the service (ex: Foo App)") |
|
|
|
flag.StringVar(&conf.Name, "name", "", "a computer-friendly name for the service (ex: foo-app)") |
|
|
|
flag.StringVar(&conf.URL, "url", "", "the documentation on home page of the service") |
|
|
|
//flag.StringVar(&conf.Workdir, "workdir", "", "the directory in which the service should be started")
|
|
|
|
flag.StringVar(&conf.ReverseDNS, "rdns", "", "a plist-friendly Reverse DNS name for launchctl (ex: com.example.foo-app)") |
|
|
|
flag.BoolVar(&forSystem, "system", false, "attempt to install system service as an unprivileged/unelevated user") |
|
|
|
flag.BoolVar(&forUser, "user", false, "install user space / user mode service even when admin/root/sudo/elevated") |
|
|
|
flag.BoolVar(&force, "force", false, "if the interpreter or executable doesn't exist, or things don't make sense, try anyway") |
|
|
|
flag.StringVar(&conf.User, "username", "", "run the service as this user") |
|
|
|
flag.StringVar(&conf.Group, "groupname", "", "run the service as this group") |
|
|
|
flag.BoolVar(&conf.PrivilegedPorts, "cap-net-bind", false, "this service should have access to privileged ports") |
|
|
@ -54,6 +56,7 @@ func main() { |
|
|
|
if forUser && forSystem { |
|
|
|
fmt.Println("Pfff! You can't --user AND --system! What are you trying to pull?") |
|
|
|
os.Exit(1) |
|
|
|
return |
|
|
|
} |
|
|
|
if forUser { |
|
|
|
conf.System = false |
|
|
@ -66,15 +69,20 @@ func main() { |
|
|
|
n := len(args) |
|
|
|
if 0 == n { |
|
|
|
fmt.Println("Usage: serviceman install ./foo-app -- --foo-arg") |
|
|
|
os.Exit(1) |
|
|
|
os.Exit(2) |
|
|
|
return |
|
|
|
} |
|
|
|
|
|
|
|
execpath, err := installer.WhereIs(args[0]) |
|
|
|
if nil != err { |
|
|
|
fmt.Fprintf(os.Stderr, "Error: '%s' could not be found.", args[0]) |
|
|
|
os.Exit(1) |
|
|
|
fmt.Fprintf(os.Stderr, "Error: '%s' could not be found.\n", args[0]) |
|
|
|
if !force { |
|
|
|
os.Exit(3) |
|
|
|
return |
|
|
|
} |
|
|
|
} else { |
|
|
|
args[0] = execpath |
|
|
|
} |
|
|
|
args[0] = execpath |
|
|
|
conf.Exec = args[0] |
|
|
|
args = args[1:] |
|
|
|
|
|
|
@ -93,7 +101,54 @@ func main() { |
|
|
|
conf.Title = conf.Name |
|
|
|
} |
|
|
|
if "" == conf.ReverseDNS { |
|
|
|
conf.ReverseDNS = "com.example." + conf.Name |
|
|
|
// technically should be something more like "com.example." + conf.Name,
|
|
|
|
// but whatever
|
|
|
|
conf.ReverseDNS = conf.Name |
|
|
|
} |
|
|
|
|
|
|
|
if !conf.System { |
|
|
|
home, err := os.UserHomeDir() |
|
|
|
if nil != err { |
|
|
|
fmt.Fprintf(os.Stderr, "Unrecoverable Error: %s", err) |
|
|
|
os.Exit(4) |
|
|
|
return |
|
|
|
} |
|
|
|
conf.Local = filepath.Join(home, ".local") |
|
|
|
conf.LogDir = filepath.Join(home, ".local", "share", conf.Name, "var", "log") |
|
|
|
} else { |
|
|
|
conf.LogDir = "/var/log/" + conf.Name |
|
|
|
} |
|
|
|
|
|
|
|
// Check to see if Exec exists
|
|
|
|
// /whatever => must exist exactly
|
|
|
|
// ./whatever => must exist in current or WorkDir(TODO)
|
|
|
|
// whatever => may also exist in {{ .Local }}/opt/{{ .Name }}/{{ .Exec }}
|
|
|
|
_, err = os.Stat(conf.Exec) |
|
|
|
if nil != err { |
|
|
|
bad := true |
|
|
|
if !strings.Contains(filepath.ToSlash(conf.Exec), "/") { |
|
|
|
optpath := filepath.Join(conf.Local, "/opt", conf.Name, conf.Exec) |
|
|
|
_, err := os.Stat(optpath) |
|
|
|
if nil == err { |
|
|
|
bad = false |
|
|
|
fmt.Fprintf(os.Stderr, "Using '%s' for '%s'\n", optpath, conf.Exec) |
|
|
|
conf.Exec = optpath |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
if bad { |
|
|
|
// TODO look for it in WorkDir?
|
|
|
|
fmt.Fprintf(os.Stderr, "Error: '%s' could not be found.\n", conf.Exec) |
|
|
|
if !force { |
|
|
|
os.Exit(5) |
|
|
|
return |
|
|
|
} |
|
|
|
execpath, err := filepath.Abs(conf.Exec) |
|
|
|
if nil == err { |
|
|
|
conf.Exec = execpath |
|
|
|
} |
|
|
|
fmt.Fprintf(os.Stderr, "Using '%s' anyway.\n", conf.Exec) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
fmt.Printf("\n%#v\n\n", conf) |
|
|
|