Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-pages.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKamil Trzcinski <ayufan@ayufan.eu>2016-02-12 16:01:54 +0300
committerKamil Trzcinski <ayufan@ayufan.eu>2016-02-12 16:01:54 +0300
commit34f19dff7a86564df6afe5fdf34a3ac94cc14b33 (patch)
tree16a8ab94132a9a46fc77f3e0eda075d699d4c073 /daemon.go
parent88e8fb2a91372ec8a64b82a976a0e51c8f925446 (diff)
Allow to daemonize the app
Diffstat (limited to 'daemon.go')
-rw-r--r--daemon.go124
1 files changed, 105 insertions, 19 deletions
diff --git a/daemon.go b/daemon.go
index 54592de8..5fc4b651 100644
--- a/daemon.go
+++ b/daemon.go
@@ -6,61 +6,147 @@ import (
"os/exec"
"os/user"
+ "encoding/json"
"fmt"
"github.com/kardianos/osext"
+ "os/signal"
"strconv"
"syscall"
)
-func daemonize() {
- if *pagesUser == "" {
+const daemonRunProgram = "daemon-run"
+
+func daemonMain() {
+ if os.Args[0] != daemonRunProgram {
return
}
+ fmt.Printf("Starting the daemon as unprivileged user...\n")
+
+ // read the configuration from the pipe "ExtraFiles"
+ var config appConfig
+ if err := json.NewDecoder(os.NewFile(3, "options")).Decode(&config); err != nil {
+ log.Fatalln(err)
+ }
+ runApp(config)
+ os.Exit(0)
+}
+
+func daemonReexec(cmdUser string, args ...string) (cmd *exec.Cmd, err error) {
path, err := osext.Executable()
if err != nil {
- log.Fatalln(err)
+ return
}
- u, err := user.Lookup(*pagesUser)
+ u, err := user.Lookup(cmdUser)
if err != nil {
- log.Fatalln(err)
+ return
}
uid, err := strconv.Atoi(u.Uid)
if err != nil {
- log.Fatalln(err)
+ return
}
gid, err := strconv.Atoi(u.Gid)
if err != nil {
- log.Fatalln(err)
+ return
}
- cmd := &exec.Cmd{
+ cmd = &exec.Cmd{
Path: path,
- Args: append(os.Args, "-pages-user", "", "-pages-root", "/"),
+ Args: args,
Stdin: os.Stdin,
Stdout: os.Stdout,
Stderr: os.Stderr,
SysProcAttr: &syscall.SysProcAttr{
- Chroot: *pagesRoot,
Credential: &syscall.Credential{
Uid: uint32(uid),
Gid: uint32(gid),
},
- //Setsid: true,
- Setpgid: true,
+ Setsid: true,
},
}
- //cmd.SysProcAttr = nil
+ return
+}
- fmt.Println("Deamonizing as", uid, "and", gid, "...")
- err = cmd.Run()
+func daemonUpdateFd(cmd *exec.Cmd, fd *uintptr) {
+ if *fd == 0 {
+ return
+ }
+
+ file := os.NewFile(*fd, "[socket]")
+ // we add 3 since, we have a 3 predefined FDs
+ *fd = uintptr(3 + len(cmd.ExtraFiles))
+ cmd.ExtraFiles = append(cmd.ExtraFiles, file)
+}
+
+func killProcess(cmd *exec.Cmd) {
+ if cmd.Process != nil {
+ cmd.Process.Kill()
+ }
+ cmd.Wait()
+ for _, file := range cmd.ExtraFiles {
+ file.Close()
+ }
+}
+
+func passSignals(cmd *exec.Cmd) {
+ s := make(chan os.Signal)
+ signal.Notify(s, syscall.SIGTERM)
+
+ go func() {
+ for {
+ <-s
+ if cmd.Process != nil {
+ cmd.Process.Kill()
+ }
+ }
+ }()
+}
+
+func daemonize(config appConfig, cmdUser string) {
+ var err error
+ defer func() {
+ if err != nil {
+ log.Fatalln(err)
+ }
+ }()
+ fmt.Printf("Running the daemon as unprivileged user: %v...\n", cmdUser)
+
+ cmd, err := daemonReexec(cmdUser, daemonRunProgram)
if err != nil {
- log.Fatalln(err)
- os.Exit(1)
- } else {
- os.Exit(0)
+ return
}
+ defer killProcess(cmd)
+
+ // Create a pipe to pass the configuration
+ configReader, configWriter, err := os.Pipe()
+ if err != nil {
+ return
+ }
+ defer configWriter.Close()
+ cmd.ExtraFiles = append(cmd.ExtraFiles, configReader)
+
+ // Create a new file and store the FD
+ daemonUpdateFd(cmd, &config.ListenHTTP)
+ daemonUpdateFd(cmd, &config.ListenHTTPS)
+ daemonUpdateFd(cmd, &config.listenProxy)
+
+ // Start the process
+ if err = cmd.Start(); err != nil {
+ return
+ }
+
+ // Write the configuration
+ if err = json.NewEncoder(configWriter).Encode(config); err != nil {
+ return
+ }
+ configWriter.Close()
+
+ // Pass through signals
+ passSignals(cmd)
+
+ // Wait for process to exit
+ err = cmd.Wait()
}