...

Source file src/github.com/opencontainers/runc/libcontainer/cgroups/systemd/user.go

Documentation: github.com/opencontainers/runc/libcontainer/cgroups/systemd

     1  package systemd
     2  
     3  import (
     4  	"bufio"
     5  	"bytes"
     6  	"errors"
     7  	"fmt"
     8  	"os"
     9  	"os/exec"
    10  	"path/filepath"
    11  	"strconv"
    12  	"strings"
    13  
    14  	systemdDbus "github.com/coreos/go-systemd/v22/dbus"
    15  	dbus "github.com/godbus/dbus/v5"
    16  
    17  	"github.com/opencontainers/runc/libcontainer/userns"
    18  )
    19  
    20  // newUserSystemdDbus creates a connection for systemd user-instance.
    21  func newUserSystemdDbus() (*systemdDbus.Conn, error) {
    22  	addr, err := DetectUserDbusSessionBusAddress()
    23  	if err != nil {
    24  		return nil, err
    25  	}
    26  	uid, err := DetectUID()
    27  	if err != nil {
    28  		return nil, err
    29  	}
    30  
    31  	return systemdDbus.NewConnection(func() (*dbus.Conn, error) {
    32  		conn, err := dbus.Dial(addr)
    33  		if err != nil {
    34  			return nil, fmt.Errorf("error while dialing %q: %w", addr, err)
    35  		}
    36  		methods := []dbus.Auth{dbus.AuthExternal(strconv.Itoa(uid))}
    37  		err = conn.Auth(methods)
    38  		if err != nil {
    39  			conn.Close()
    40  			return nil, fmt.Errorf("error while authenticating connection (address=%q, UID=%d): %w", addr, uid, err)
    41  		}
    42  		if err = conn.Hello(); err != nil {
    43  			conn.Close()
    44  			return nil, fmt.Errorf("error while sending Hello message (address=%q, UID=%d): %w", addr, uid, err)
    45  		}
    46  		return conn, nil
    47  	})
    48  }
    49  
    50  // DetectUID detects UID from the OwnerUID field of `busctl --user status`
    51  // if running in userNS. The value corresponds to sd_bus_creds_get_owner_uid(3) .
    52  //
    53  // Otherwise returns os.Getuid() .
    54  func DetectUID() (int, error) {
    55  	if !userns.RunningInUserNS() {
    56  		return os.Getuid(), nil
    57  	}
    58  	b, err := exec.Command("busctl", "--user", "--no-pager", "status").CombinedOutput()
    59  	if err != nil {
    60  		return -1, fmt.Errorf("could not execute `busctl --user --no-pager status` (output: %q): %w", string(b), err)
    61  	}
    62  	scanner := bufio.NewScanner(bytes.NewReader(b))
    63  	for scanner.Scan() {
    64  		s := strings.TrimSpace(scanner.Text())
    65  		if strings.HasPrefix(s, "OwnerUID=") {
    66  			uidStr := strings.TrimPrefix(s, "OwnerUID=")
    67  			i, err := strconv.Atoi(uidStr)
    68  			if err != nil {
    69  				return -1, fmt.Errorf("could not detect the OwnerUID: %w", err)
    70  			}
    71  			return i, nil
    72  		}
    73  	}
    74  	if err := scanner.Err(); err != nil {
    75  		return -1, err
    76  	}
    77  	return -1, errors.New("could not detect the OwnerUID")
    78  }
    79  
    80  // DetectUserDbusSessionBusAddress returns $DBUS_SESSION_BUS_ADDRESS if set.
    81  // Otherwise returns "unix:path=$XDG_RUNTIME_DIR/bus" if $XDG_RUNTIME_DIR/bus exists.
    82  // Otherwise parses the value from `systemctl --user show-environment` .
    83  func DetectUserDbusSessionBusAddress() (string, error) {
    84  	if env := os.Getenv("DBUS_SESSION_BUS_ADDRESS"); env != "" {
    85  		return env, nil
    86  	}
    87  	if xdr := os.Getenv("XDG_RUNTIME_DIR"); xdr != "" {
    88  		busPath := filepath.Join(xdr, "bus")
    89  		if _, err := os.Stat(busPath); err == nil {
    90  			busAddress := "unix:path=" + busPath
    91  			return busAddress, nil
    92  		}
    93  	}
    94  	b, err := exec.Command("systemctl", "--user", "--no-pager", "show-environment").CombinedOutput()
    95  	if err != nil {
    96  		return "", fmt.Errorf("could not execute `systemctl --user --no-pager show-environment` (output=%q): %w", string(b), err)
    97  	}
    98  	scanner := bufio.NewScanner(bytes.NewReader(b))
    99  	for scanner.Scan() {
   100  		s := strings.TrimSpace(scanner.Text())
   101  		if strings.HasPrefix(s, "DBUS_SESSION_BUS_ADDRESS=") {
   102  			return strings.TrimPrefix(s, "DBUS_SESSION_BUS_ADDRESS="), nil
   103  		}
   104  	}
   105  	return "", errors.New("could not detect DBUS_SESSION_BUS_ADDRESS from `systemctl --user --no-pager show-environment`. Make sure you have installed the dbus-user-session or dbus-daemon package and then run: `systemctl --user start dbus`")
   106  }
   107  

View as plain text