nworker int
logfile string
bkguser string
+ bkgwait bool
verbose bool
}{
iface: "localhost",
njobs: 50,
logfile: "",
bkguser: "",
+ bkgwait: false,
verbose: false,
}
cfg.logfile = val
case "bkguser":
cfg.bkguser = val
+ case "bkgwait":
+ cfg.bkgwait = strToBool(val)
case "verbose":
cfg.verbose = strToBool(val)
default:
flag.IntVar(&cfg.njobs, "lj", cfg.njobs, "set worker job queue size to `num`")
flag.StringVar(&cfg.logfile, "L", cfg.logfile, "write log to `file`; empty for stderr")
flag.StringVar(&cfg.bkguser, "b", cfg.bkguser, "restart the process in the background as `user`")
+ flag.BoolVar(&cfg.bkgwait, "w", cfg.bkgwait, "wait for background process")
flag.BoolVar(&cfg.verbose, "v", cfg.verbose, "produce verbose output")
flag.Parse()
if help {
tracer.Print("njobs: ", cfg.njobs)
tracer.Print("logfile: ", cfg.logfile)
tracer.Print("bkguser: ", cfg.bkguser)
+ tracer.Print("bkgwait: ", cfg.bkgwait)
tracer.Print("verbose: ", cfg.verbose)
tracer.Print("gogopherd version ", version)
}
)
var shutting_down bool = false
+var isdaemon bool = false
func createIndex(dirname string, selector string) (string, error) {
fi, err := ioutil.ReadDir(dirname)
return
}
req = strings.TrimSpace(req)
- logger.Print("[", conn.RemoteAddr(),"] '", req, "'")
+ logger.Print("[", conn.RemoteAddr(), "] '", req, "'")
// canonicalize and validate referenced path
rpath, err := validatePath(cfg.docroot, filepath.Join(cfg.docroot, filepath.FromSlash(req)))
if check(err, "validatePath "+rpath) != nil {
return
}
if checkFatal(err, "Accept") == nil {
- logger.Print("[", conn.RemoteAddr(),"] connect")
+ logger.Print("[", conn.RemoteAddr(), "] connect")
jobs <- conn
}
<-throttle
}
}
-func daemonize(asuser string, stdfiles []*os.File, xfiles []*os.File, env []string) (int, error) {
+func daemonize(asuser string, stdfiles []*os.File, xfiles []*os.File, env []string) (*exec.Cmd, error) {
userCurrent, err := user.Current()
if err != nil {
- return -1, err
+ return nil, err
}
userRequired, err := user.Lookup(asuser)
if err != nil {
- return -1, err
+ return nil, err
}
executable, err := filepath.Abs(os.Args[0])
if err != nil {
- return -1, err
+ return nil, err
}
cmd := exec.Command(executable)
cmd.Args = append([]string{executable}, os.Args[1:]...)
Credential: &syscall.Credential{Uid: uint32(uid), Gid: uint32(gid)},
}
}
+ if cfg.bkgwait {
+ cmd.SysProcAttr.Pdeathsig = syscall.SIGTERM
+ }
if len(stdfiles) > 0 {
cmd.Stdin = stdfiles[0]
}
cmd.ExtraFiles = xfiles
err = cmd.Start()
if err != nil {
- return -1, err
+ return nil, err
}
- return cmd.Process.Pid, nil
+ return cmd, nil
}
func main() {
+ const isdaemon_mark = "_ISDAEMON_"
+ isdaemon = os.Getenv(isdaemon_mark) == "1"
initialize()
if cfg.bkguser == "" {
checkFatal(err, "Listen")
go serveTCP(listener)
} else {
- const isdaemon = "_ISDAEMON_"
- if os.Getenv(isdaemon) != "1" {
+ if !isdaemon {
// parent
service := cfg.iface + ":" + cfg.port
address, err := net.ResolveTCPAddr("tcp", service)
fstd := []*os.File{
nil,
nil,
- os.Stderr, // inherit our logging fd
+ os.Stderr, // inherit our logging fd
}
env := []string{
"PATH=\"/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin\"",
- fmt.Sprintf("%s=1", isdaemon),
+ fmt.Sprintf("%s=1", isdaemon_mark),
}
- cpid, err := daemonize(cfg.bkguser, fstd, fxtra, env)
+ cmd, err := daemonize(cfg.bkguser, fstd, fxtra, env)
checkFatal(err, "daemonize")
- tracer.Print("background process spawned, child pid=", cpid, ", bye.")
+ cpid := cmd.Process.Pid
+ tracer.Print("background process spawned, child pid=", cpid)
+ if cfg.bkgwait {
+ err = cmd.Wait()
+ logger.Print("child process termintated (", err, ")")
+ }
+ tracer.Print("parent: bye.")
os.Exit(0)
} else {
// child
--- /dev/null
+#!/bin/sh
+
+### BEGIN INIT INFO
+# Provides: gopherd
+# Required-Start: $network
+# Required-Stop: $network
+# Default-Start: 2 3 4 5
+# Default-Stop:
+# Short-Description: Start gopher server
+### END INIT INFO
+
+PATH=/sbin:/bin:/usr/sbin:/usr/bin
+
+. /lib/lsb/init-functions
+
+PREFIX=/usr/local
+
+DAEMON="$PREFIX/bin/gogopherd"
+CFGFILE="$PREFIX/etc/gogopherd.cfg"
+PIDFILE=/var/run/gogopherd.pid
+GOGOPTS="$GOGOPTS -c $CFGFILE"
+
+test -x $DAEMON || exit 5
+test -f $CFGFILE || exit 5
+
+LOCKFILE=/run/lock/gogopherd
+
+case $1 in
+ start)
+ log_daemon_msg "Starting gopher server" "gogopherd"
+ (
+ flock -w 180 9
+ start-stop-daemon --start --quiet --oknodo --pidfile $PIDFILE --make-pidfile --background --exec $DAEMON -- $GOGOPTS
+ ) 9>$LOCKFILE
+ log_end_msg $?
+ ;;
+ stop)
+ log_daemon_msg "Stopping gopher server" "gogopherd"
+ start-stop-daemon --stop --quiet --oknodo --pidfile $PIDFILE --remove-pidfile --retry=TERM/30/KILL/5 --exec $DAEMON
+ log_end_msg $?
+ rm -f $PIDFILE
+ ;;
+ restart|force-reload)
+ $0 stop && sleep 2 && $0 start
+ ;;
+ try-restart)
+ if $0 status >/dev/null; then
+ $0 restart
+ else
+ exit 0
+ fi
+ ;;
+ reload)
+ exit 3
+ ;;
+ status)
+ status_of_proc $DAEMON "gogopherd"
+ ;;
+ *)
+ echo "Usage: $0 {start|stop|restart|try-restart|force-reload|status}"
+ exit 2
+ ;;
+esac