2015-10-11 18:02:48 +02:00
|
|
|
package main
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
2015-10-11 18:51:56 +02:00
|
|
|
"os"
|
|
|
|
"os/exec"
|
2015-10-11 18:02:48 +02:00
|
|
|
"os/signal"
|
2015-10-11 18:51:56 +02:00
|
|
|
"syscall"
|
2016-06-05 14:26:16 +02:00
|
|
|
|
2017-05-07 22:15:01 +02:00
|
|
|
"github.com/rfjakob/gocryptfs/internal/exitcodes"
|
2017-07-23 19:18:58 +02:00
|
|
|
"github.com/rfjakob/gocryptfs/internal/syscallcompat"
|
2016-06-15 23:30:44 +02:00
|
|
|
"github.com/rfjakob/gocryptfs/internal/tlog"
|
2015-10-11 18:02:48 +02:00
|
|
|
)
|
|
|
|
|
2016-11-26 18:18:14 +01:00
|
|
|
// The child sends us USR1 if the mount was successful. Exit with error code
|
|
|
|
// 0 if we get it.
|
2015-11-14 21:25:10 +01:00
|
|
|
func exitOnUsr1() {
|
2015-10-11 18:02:48 +02:00
|
|
|
c := make(chan os.Signal, 1)
|
|
|
|
signal.Notify(c, syscall.SIGUSR1)
|
2016-11-26 18:18:14 +01:00
|
|
|
go func() {
|
|
|
|
<-c
|
|
|
|
os.Exit(0)
|
|
|
|
}()
|
2015-10-11 18:02:48 +02:00
|
|
|
}
|
|
|
|
|
2016-11-01 19:04:49 +01:00
|
|
|
// forkChild - execute ourselves once again, this time with the "-fg" flag, and
|
2015-11-14 21:25:10 +01:00
|
|
|
// wait for SIGUSR1 or child exit.
|
|
|
|
// This is a workaround for the missing true fork function in Go.
|
2016-09-20 19:49:44 +02:00
|
|
|
func forkChild() int {
|
2015-10-11 18:02:48 +02:00
|
|
|
name := os.Args[0]
|
2018-06-07 23:06:03 +02:00
|
|
|
// Use the full path to our executable if we can get if from /proc.
|
2018-06-08 00:47:48 +02:00
|
|
|
buf := make([]byte, syscallcompat.PATH_MAX)
|
2018-06-07 23:06:03 +02:00
|
|
|
n, err := syscall.Readlink("/proc/self/exe", buf)
|
|
|
|
if err == nil {
|
|
|
|
name = string(buf[:n])
|
|
|
|
tlog.Debug.Printf("forkChild: readlink worked: %q", name)
|
|
|
|
}
|
2016-11-01 18:59:34 +01:00
|
|
|
newArgs := []string{"-fg", fmt.Sprintf("-notifypid=%d", os.Getpid())}
|
2015-10-11 18:02:48 +02:00
|
|
|
newArgs = append(newArgs, os.Args[1:]...)
|
|
|
|
c := exec.Command(name, newArgs...)
|
|
|
|
c.Stdout = os.Stdout
|
|
|
|
c.Stderr = os.Stderr
|
|
|
|
c.Stdin = os.Stdin
|
2016-11-26 18:18:14 +01:00
|
|
|
exitOnUsr1()
|
2018-06-07 23:06:03 +02:00
|
|
|
err = c.Start()
|
2015-10-11 18:02:48 +02:00
|
|
|
if err != nil {
|
2018-06-07 22:50:30 +02:00
|
|
|
tlog.Fatal.Printf("forkChild: starting %s failed: %v", name, err)
|
2017-05-07 22:15:01 +02:00
|
|
|
return exitcodes.ForkChild
|
2015-10-11 18:02:48 +02:00
|
|
|
}
|
|
|
|
err = c.Wait()
|
|
|
|
if err != nil {
|
|
|
|
if exiterr, ok := err.(*exec.ExitError); ok {
|
|
|
|
if waitstat, ok := exiterr.Sys().(syscall.WaitStatus); ok {
|
2015-10-11 18:51:56 +02:00
|
|
|
os.Exit(waitstat.ExitStatus())
|
|
|
|
}
|
2015-10-11 18:02:48 +02:00
|
|
|
}
|
2018-06-07 22:50:30 +02:00
|
|
|
tlog.Fatal.Printf("forkChild: wait returned an unknown error: %v", err)
|
2017-05-07 22:15:01 +02:00
|
|
|
return exitcodes.ForkChild
|
2015-10-11 18:02:48 +02:00
|
|
|
}
|
|
|
|
// The child exited with 0 - let's do the same.
|
2016-09-20 19:49:44 +02:00
|
|
|
return 0
|
2015-10-11 18:02:48 +02:00
|
|
|
}
|
2017-07-23 19:18:58 +02:00
|
|
|
|
|
|
|
// redirectStdFds redirects stderr and stdout to syslog; stdin to /dev/null
|
|
|
|
func redirectStdFds() {
|
2017-07-23 23:55:59 +02:00
|
|
|
// Create a pipe pair "pw" -> "pr" and start logger reading from "pr".
|
|
|
|
// We do it ourselves instead of using StdinPipe() because we need access
|
|
|
|
// to the fd numbers.
|
2017-07-23 19:18:58 +02:00
|
|
|
pr, pw, err := os.Pipe()
|
|
|
|
if err != nil {
|
|
|
|
tlog.Warn.Printf("redirectStdFds: could not create pipe: %v\n", err)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
tag := fmt.Sprintf("gocryptfs-%d-logger", os.Getpid())
|
2018-04-11 20:31:02 +02:00
|
|
|
// SUSE has /bin/logger, everybody else has /usr/bin/logger.
|
|
|
|
for _, path := range []string{"/usr/bin/logger", "/bin/logger"} {
|
|
|
|
cmd := exec.Command(path, "-t", tag)
|
|
|
|
cmd.Stdin = pr
|
|
|
|
err = cmd.Start()
|
|
|
|
if err == nil {
|
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
2017-07-23 19:18:58 +02:00
|
|
|
if err != nil {
|
|
|
|
tlog.Warn.Printf("redirectStdFds: could not start logger: %v\n", err)
|
2017-07-23 23:55:59 +02:00
|
|
|
return
|
2017-07-23 19:18:58 +02:00
|
|
|
}
|
2017-07-23 23:55:59 +02:00
|
|
|
// The logger now reads on "pr". We can close it.
|
2017-07-23 19:18:58 +02:00
|
|
|
pr.Close()
|
2017-07-23 23:55:59 +02:00
|
|
|
// Redirect stout and stderr to "pw".
|
2017-07-23 19:18:58 +02:00
|
|
|
err = syscallcompat.Dup3(int(pw.Fd()), 1, 0)
|
|
|
|
if err != nil {
|
|
|
|
tlog.Warn.Printf("redirectStdFds: stdout dup error: %v\n", err)
|
|
|
|
}
|
|
|
|
syscallcompat.Dup3(int(pw.Fd()), 2, 0)
|
|
|
|
if err != nil {
|
|
|
|
tlog.Warn.Printf("redirectStdFds: stderr dup error: %v\n", err)
|
|
|
|
}
|
2017-07-23 23:55:59 +02:00
|
|
|
// Our stout and stderr point to "pw". We can close the extra copy.
|
2017-07-23 19:18:58 +02:00
|
|
|
pw.Close()
|
2017-07-23 23:55:59 +02:00
|
|
|
// Redirect stdin to /dev/null
|
2017-07-23 19:18:58 +02:00
|
|
|
nullFd, err := os.Open("/dev/null")
|
|
|
|
if err != nil {
|
|
|
|
tlog.Warn.Printf("redirectStdFds: could not open /dev/null: %v\n", err)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
err = syscallcompat.Dup3(int(nullFd.Fd()), 0, 0)
|
|
|
|
if err != nil {
|
|
|
|
tlog.Warn.Printf("redirectStdFds: stdin dup error: %v\n", err)
|
|
|
|
}
|
|
|
|
nullFd.Close()
|
|
|
|
}
|