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:
-rw-r--r--app.go5
-rw-r--r--daemon.go124
-rw-r--r--main.go48
3 files changed, 126 insertions, 51 deletions
diff --git a/app.go b/app.go
index 04f71949..4ab6a3e7 100644
--- a/app.go
+++ b/app.go
@@ -124,3 +124,8 @@ func (a *theApp) Run() {
wg.Wait()
}
+
+func runApp(config appConfig) {
+ a := theApp{appConfig: config}
+ a.Run()
+}
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()
}
diff --git a/main.go b/main.go
index 14179ae4..623d2538 100644
--- a/main.go
+++ b/main.go
@@ -16,6 +16,8 @@ var VERSION = "dev"
var REVISION = "HEAD"
func main() {
+ daemonMain()
+
var listenHTTP = flag.String("listen-http", ":80", "The address to listen for HTTP requests")
var listenHTTPS = flag.String("listen-https", "", "The address to listen for HTTPS requests")
var listenProxy = flag.String("listen-proxy", "", "The address to listen for proxy requests")
@@ -36,58 +38,40 @@ func main() {
log.Fatalln(err)
}
- var app theApp
- app.Domain = strings.ToLower(*pagesDomain)
- app.RedirectHTTP = *redirectHTTP
- app.HTTP2 = *useHTTP2
+ var config appConfig
+ config.Domain = strings.ToLower(*pagesDomain)
+ config.RedirectHTTP = *redirectHTTP
+ config.HTTP2 = *useHTTP2
if *pagesRootCert != "" {
- app.RootCertificate = readFile(*pagesRootCert)
+ config.RootCertificate = readFile(*pagesRootCert)
}
if *pagesRootKey != "" {
- app.RootKey = readFile(*pagesRootKey)
- }
-
-<<<<<<< 9042f5171c4bddc3da330b0e236e5faa78e657c3
-=======
- //daemonize()
-
- fmt.Println("Starting...")
-
- // We don't need root privileges any more
- // if err := syscall.Setgid(33); err != nil {
- // log.Fatalln("setgid:", err)
- // }
- if err := syscall.Setuid(33); err != nil {
- log.Fatalln("setuid:", err)
+ config.RootKey = readFile(*pagesRootKey)
}
- err := syscall.Chroot(*pagesRoot)
- if err != nil {
- log.Fatalln("chroot:", err)
- }
- *pagesRoot = "/"
-
- // Listen for HTTP
->>>>>>> Daemonize
if *listenHTTP != "" {
var l net.Listener
- l, app.ListenHTTP = createSocket(*listenHTTP)
+ l, config.ListenHTTP = createSocket(*listenHTTP)
defer l.Close()
}
if *listenHTTPS != "" {
var l net.Listener
- l, app.ListenHTTPS = createSocket(*listenHTTPS)
+ l, config.ListenHTTPS = createSocket(*listenHTTPS)
defer l.Close()
}
if *listenProxy != "" {
var l net.Listener
- l, app.ListenHTTPS = createSocket(*listenProxy)
+ l, config.ListenHTTPS = createSocket(*listenProxy)
defer l.Close()
}
- app.Run()
+ if *pagesUser != "" {
+ daemonize(config, *pagesUser)
+ } else {
+ runApp(config)
+ }
}