summaryrefslogtreecommitdiff
path: root/pkg
diff options
context:
space:
mode:
Diffstat (limited to 'pkg')
-rw-r--r--pkg/adapter/containers.go4
-rw-r--r--pkg/adapter/containers_remote.go9
-rw-r--r--pkg/rootless/rootless_linux.go118
-rw-r--r--pkg/rootless/rootless_unsupported.go6
-rw-r--r--pkg/util/utils.go2
-rw-r--r--pkg/varlinkapi/attach.go1
-rw-r--r--pkg/varlinkapi/virtwriter/virtwriter.go24
7 files changed, 45 insertions, 119 deletions
diff --git a/pkg/adapter/containers.go b/pkg/adapter/containers.go
index 12fd98486..5c33467a7 100644
--- a/pkg/adapter/containers.go
+++ b/pkg/adapter/containers.go
@@ -612,7 +612,9 @@ func (r *LocalRuntime) Start(ctx context.Context, c *cliconfig.StartValues, sigP
if c.Attach {
inputStream := os.Stdin
if !c.Interactive {
- inputStream = nil
+ if !ctr.Stdin() {
+ inputStream = nil
+ }
}
// attach to the container and also start it not already running
diff --git a/pkg/adapter/containers_remote.go b/pkg/adapter/containers_remote.go
index f7cb28b0c..f4e83a975 100644
--- a/pkg/adapter/containers_remote.go
+++ b/pkg/adapter/containers_remote.go
@@ -1092,6 +1092,7 @@ func configureVarlinkAttachStdio(reader *bufio.Reader, writer *bufio.Writer, std
// These are the special writers that encode input from the client.
varlinkStdinWriter := virtwriter.NewVirtWriteCloser(writer, virtwriter.ToStdin)
varlinkResizeWriter := virtwriter.NewVirtWriteCloser(writer, virtwriter.TerminalResize)
+ varlinkHangupWriter := virtwriter.NewVirtWriteCloser(writer, virtwriter.HangUpFromClient)
go func() {
// Read from the wire and direct to stdout or stderr
@@ -1117,7 +1118,6 @@ func configureVarlinkAttachStdio(reader *bufio.Reader, writer *bufio.Writer, std
}
}
}()
-
if stdin != nil {
// Takes stdinput and sends it over the wire after being encoded
go func() {
@@ -1126,7 +1126,12 @@ func configureVarlinkAttachStdio(reader *bufio.Reader, writer *bufio.Writer, std
sendGenericError(ecChan)
errChan <- err
}
-
+ _, err := varlinkHangupWriter.Write([]byte("EOF"))
+ if err != nil {
+ logrus.Errorf("unable to notify server to hangup: %q", err)
+ }
+ err = varlinkStdinWriter.Close()
+ errChan <- err
}()
}
return errChan
diff --git a/pkg/rootless/rootless_linux.go b/pkg/rootless/rootless_linux.go
index 99307e8c4..94c42f7d0 100644
--- a/pkg/rootless/rootless_linux.go
+++ b/pkg/rootless/rootless_linux.go
@@ -11,20 +11,16 @@ import (
"os/exec"
gosignal "os/signal"
"os/user"
- "path/filepath"
"runtime"
"strconv"
- "strings"
"sync"
- "syscall"
"unsafe"
"github.com/containers/libpod/pkg/errorhandling"
"github.com/containers/storage/pkg/idtools"
- "github.com/docker/docker/pkg/signal"
- "github.com/godbus/dbus"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
+ "golang.org/x/sys/unix"
)
/*
@@ -130,7 +126,7 @@ func tryMappingTool(tool string, pid int, hostID int, mappings []idtools.IDMap)
func readUserNs(path string) (string, error) {
b := make([]byte, 256)
- _, err := syscall.Readlink(path, b)
+ _, err := unix.Readlink(path, b)
if err != nil {
return "", err
}
@@ -143,7 +139,7 @@ func readUserNsFd(fd uintptr) (string, error) {
func getParentUserNs(fd uintptr) (uintptr, error) {
const nsGetParent = 0xb702
- ret, _, errno := syscall.Syscall(syscall.SYS_IOCTL, fd, uintptr(nsGetParent), 0)
+ ret, _, errno := unix.Syscall(unix.SYS_IOCTL, fd, uintptr(nsGetParent), 0)
if errno != 0 {
return 0, errno
}
@@ -179,7 +175,7 @@ func getUserNSFirstChild(fd uintptr) (*os.File, error) {
for {
nextFd, err := getParentUserNs(fd)
if err != nil {
- if err == syscall.ENOTTY {
+ if err == unix.ENOTTY {
return os.NewFile(fd, "userns child"), nil
}
return nil, errors.Wrapf(err, "cannot get parent user namespace")
@@ -191,14 +187,14 @@ func getUserNSFirstChild(fd uintptr) (*os.File, error) {
}
if ns == currentNS {
- if err := syscall.Close(int(nextFd)); err != nil {
+ if err := unix.Close(int(nextFd)); err != nil {
return nil, err
}
// Drop O_CLOEXEC for the fd.
- _, _, errno := syscall.Syscall(syscall.SYS_FCNTL, fd, syscall.F_SETFD, 0)
+ _, _, errno := unix.Syscall(unix.SYS_FCNTL, fd, unix.F_SETFD, 0)
if errno != 0 {
- if err := syscall.Close(int(fd)); err != nil {
+ if err := unix.Close(int(fd)); err != nil {
logrus.Errorf("failed to close file descriptor %d", fd)
}
return nil, errno
@@ -206,99 +202,13 @@ func getUserNSFirstChild(fd uintptr) (*os.File, error) {
return os.NewFile(fd, "userns child"), nil
}
- if err := syscall.Close(int(fd)); err != nil {
+ if err := unix.Close(int(fd)); err != nil {
return nil, err
}
fd = nextFd
}
}
-// EnableLinger configures the system to not kill the user processes once the session
-// terminates
-func EnableLinger() (string, error) {
- uid := fmt.Sprintf("%d", GetRootlessUID())
-
- conn, err := dbus.SystemBus()
- if err == nil {
- defer func() {
- if err := conn.Close(); err != nil {
- logrus.Errorf("unable to close dbus connection: %q", err)
- }
- }()
- }
-
- lingerEnabled := false
-
- // If we have a D-BUS connection, attempt to read the LINGER property from it.
- if conn != nil {
- path := dbus.ObjectPath(fmt.Sprintf("/org/freedesktop/login1/user/_%s", uid))
- ret, err := conn.Object("org.freedesktop.login1", path).GetProperty("org.freedesktop.login1.User.Linger")
- if err == nil && ret.Value().(bool) {
- lingerEnabled = true
- }
- }
-
- xdgRuntimeDir := os.Getenv("XDG_RUNTIME_DIR")
- lingerFile := ""
- if xdgRuntimeDir != "" && !lingerEnabled {
- lingerFile = filepath.Join(xdgRuntimeDir, "libpod/linger")
- _, err := os.Stat(lingerFile)
- if err == nil {
- lingerEnabled = true
- }
- }
-
- if !lingerEnabled {
- // First attempt with D-BUS, if it fails, then attempt with "loginctl enable-linger"
- if conn != nil {
- o := conn.Object("org.freedesktop.login1", "/org/freedesktop/login1")
- ret := o.Call("org.freedesktop.login1.Manager.SetUserLinger", 0, uint32(GetRootlessUID()), true, true)
- if ret.Err == nil {
- lingerEnabled = true
- }
- }
- if !lingerEnabled {
- err := exec.Command("loginctl", "enable-linger", uid).Run()
- if err == nil {
- lingerEnabled = true
- } else {
- logrus.Debugf("cannot run `loginctl enable-linger` for the current user: %v", err)
- }
- }
- if lingerEnabled && lingerFile != "" {
- f, err := os.Create(lingerFile)
- if err == nil {
- if err := f.Close(); err != nil {
- logrus.Errorf("failed to close %s", f.Name())
- }
- } else {
- logrus.Debugf("could not create linger file: %v", err)
- }
- }
- }
-
- if !lingerEnabled {
- return "", nil
- }
-
- // If we have a D-BUS connection, attempt to read the RUNTIME PATH from it.
- if conn != nil {
- path := dbus.ObjectPath(fmt.Sprintf("/org/freedesktop/login1/user/_%s", uid))
- ret, err := conn.Object("org.freedesktop.login1", path).GetProperty("org.freedesktop.login1.User.RuntimePath")
- if err == nil {
- return strings.Trim(ret.String(), "\"\n"), nil
- }
- }
-
- // If XDG_RUNTIME_DIR is not set and the D-BUS call didn't work, try to get the runtime path with "loginctl"
- output, err := exec.Command("loginctl", "-pRuntimePath", "show-user", uid).Output()
- if err != nil {
- logrus.Debugf("could not get RuntimePath using loginctl: %v", err)
- return "", nil
- }
- return strings.Trim(strings.Replace(string(output), "RuntimePath=", "", -1), "\"\n"), nil
-}
-
// joinUserAndMountNS re-exec podman in a new userNS and join the user and mount
// namespace of the specified PID without looking up its parent. Useful to join directly
// the conmon process.
@@ -394,7 +304,7 @@ func becomeRootInUserNS(pausePid, fileToRead string, fileOutput *os.File) (bool,
runtime.LockOSThread()
defer runtime.UnlockOSThread()
- fds, err := syscall.Socketpair(syscall.AF_UNIX, syscall.SOCK_DGRAM, 0)
+ fds, err := unix.Socketpair(unix.AF_UNIX, unix.SOCK_DGRAM, 0)
if err != nil {
return false, -1, err
}
@@ -491,21 +401,21 @@ func becomeRootInUserNS(pausePid, fileToRead string, fileOutput *os.File) (bool,
signals := []os.Signal{}
for sig := 0; sig < numSig; sig++ {
- if sig == int(syscall.SIGTSTP) {
+ if sig == int(unix.SIGTSTP) {
continue
}
- signals = append(signals, syscall.Signal(sig))
+ signals = append(signals, unix.Signal(sig))
}
gosignal.Notify(c, signals...)
defer gosignal.Reset()
go func() {
for s := range c {
- if s == signal.SIGCHLD || s == signal.SIGPIPE {
+ if s == unix.SIGCHLD || s == unix.SIGPIPE {
continue
}
- if err := syscall.Kill(int(pidC), s.(syscall.Signal)); err != nil {
+ if err := unix.Kill(int(pidC), s.(unix.Signal)); err != nil {
logrus.Errorf("failed to kill %d", int(pidC))
}
}
@@ -560,7 +470,7 @@ func TryJoinFromFilePaths(pausePidPath string, needNewNamespace bool, paths []st
lastErr = nil
break
} else {
- fds, err := syscall.Socketpair(syscall.AF_UNIX, syscall.SOCK_DGRAM, 0)
+ fds, err := unix.Socketpair(unix.AF_UNIX, unix.SOCK_DGRAM, 0)
if err != nil {
lastErr = err
continue
diff --git a/pkg/rootless/rootless_unsupported.go b/pkg/rootless/rootless_unsupported.go
index ce488f364..1499b737f 100644
--- a/pkg/rootless/rootless_unsupported.go
+++ b/pkg/rootless/rootless_unsupported.go
@@ -37,12 +37,6 @@ func GetRootlessGID() int {
return -1
}
-// EnableLinger configures the system to not kill the user processes once the session
-// terminates
-func EnableLinger() (string, error) {
- return "", nil
-}
-
// TryJoinFromFilePaths attempts to join the namespaces of the pid files in paths.
// This is useful when there are already running containers and we
// don't have a pause process yet. We can use the paths to the conmon
diff --git a/pkg/util/utils.go b/pkg/util/utils.go
index 0190b106d..d9a84e4e5 100644
--- a/pkg/util/utils.go
+++ b/pkg/util/utils.go
@@ -318,7 +318,7 @@ func WriteStorageConfigFile(storageOpts *storage.StoreOptions, storageConf strin
if err := os.MkdirAll(filepath.Dir(storageConf), 0755); err != nil {
return err
}
- storageFile, err := os.OpenFile(storageConf, os.O_RDWR|os.O_CREATE|os.O_EXCL, 0666)
+ storageFile, err := os.OpenFile(storageConf, os.O_RDWR|os.O_TRUNC, 0600)
if err != nil {
return errors.Wrapf(err, "cannot open %s", storageConf)
}
diff --git a/pkg/varlinkapi/attach.go b/pkg/varlinkapi/attach.go
index f8557ae0c..37adbbf55 100644
--- a/pkg/varlinkapi/attach.go
+++ b/pkg/varlinkapi/attach.go
@@ -70,7 +70,6 @@ func (i *LibpodAPI) Attach(call iopodman.VarlinkCall, name string, detachKeys st
}
reader, writer, _, pw, streams := setupStreams(call)
-
go func() {
if err := virtwriter.Reader(reader, nil, nil, pw, resize, nil); err != nil {
errChan <- err
diff --git a/pkg/varlinkapi/virtwriter/virtwriter.go b/pkg/varlinkapi/virtwriter/virtwriter.go
index 27ecd1f52..dd171943f 100644
--- a/pkg/varlinkapi/virtwriter/virtwriter.go
+++ b/pkg/varlinkapi/virtwriter/virtwriter.go
@@ -5,6 +5,7 @@ import (
"encoding/binary"
"encoding/json"
"io"
+ "time"
"github.com/pkg/errors"
"k8s.io/client-go/tools/remotecommand"
@@ -26,8 +27,14 @@ const (
TerminalResize SocketDest = iota
// Quit and detach
Quit SocketDest = iota
+ // Quit from the client
+ HangUpFromClient SocketDest = iota
)
+// ClientHangup signifies that the client wants to drop its
+// connection from the server
+var ClientHangup = errors.New("client hangup")
+
// IntToSocketDest returns a socketdest based on integer input
func IntToSocketDest(i int) SocketDest {
switch i {
@@ -41,6 +48,8 @@ func IntToSocketDest(i int) SocketDest {
return TerminalResize
case Quit.Int():
return Quit
+ case HangUpFromClient.Int():
+ return HangUpFromClient
default:
return ToStderr
}
@@ -65,7 +74,7 @@ func NewVirtWriteCloser(w *bufio.Writer, dest SocketDest) VirtWriteCloser {
// Close is a required method for a writecloser
func (v VirtWriteCloser) Close() error {
- return nil
+ return v.writer.Flush()
}
// Write prepends a header to the input message. The header is
@@ -96,7 +105,6 @@ func Reader(r *bufio.Reader, output, errput, input io.Writer, resize chan remote
if r == nil {
return errors.Errorf("Reader must not be nil")
}
-
for {
n, err := io.ReadFull(r, headerBytes)
if err != nil {
@@ -107,7 +115,6 @@ func Reader(r *bufio.Reader, output, errput, input io.Writer, resize chan remote
}
messageSize = int64(binary.BigEndian.Uint32(headerBytes[4:8]))
-
switch IntToSocketDest(int(headerBytes[0])) {
case ToStdout:
if output != nil {
@@ -161,7 +168,16 @@ func Reader(r *bufio.Reader, output, errput, input io.Writer, resize chan remote
execEcChan <- int(ecInt)
}
return nil
-
+ case HangUpFromClient:
+ // This sleep allows the pipes to flush themselves before tearing everything down.
+ // It makes me sick to do it but after a full day I cannot put my finger on the race
+ // that occurs when closing things up. It would require a significant rewrite of code
+ // to make the pipes close down properly. Given that we are currently discussing a
+ // rewrite of all things remote, this hardly seems worth resolving.
+ //
+ // reproducer: echo hello | (podman-remote run -i alpine cat)
+ time.Sleep(1 * time.Second)
+ return ClientHangup
default:
// Something really went wrong
return errors.New("unknown multiplex destination")