cmd/initContainer, test/system: Don't rely on D-Bus for /etc/timezone
This is one more step towards enabling toolbox(1) to be run as root. When invoked as 'sudo toolbox ...' there's no user or session D-Bus instance available for the root user, which prevents the use of D-Bus services like org.freedesktop.Flatpak.SessionHelper. The code is forgiving to runtime errors when reacting to file system events because it's not worth abruptly terminating the entry point because of what might be a passing error. However, it's a lot stricter when initially configuring the container because the failure mode isn't as surprising for the user and it's worth starting from a valid state. https://github.com/containers/toolbox/issues/267
This commit is contained in:
parent
4c9b80aee2
commit
b9a0bd5f0c
4 changed files with 75 additions and 29 deletions
|
@ -21,14 +21,13 @@ import (
|
|||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"os/exec"
|
||||
"os/user"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"syscall"
|
||||
|
||||
"github.com/containers/toolbox/pkg/shell"
|
||||
"github.com/containers/toolbox/pkg/utils"
|
||||
"github.com/fsnotify/fsnotify"
|
||||
"github.com/sirupsen/logrus"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
@ -177,6 +176,10 @@ func initContainer(cmd *cobra.Command, args []string) error {
|
|||
}
|
||||
}
|
||||
|
||||
if err := updateTimeZoneFromLocalTime(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if _, err := os.Readlink("/etc/resolv.conf"); err != nil {
|
||||
if err := redirectPath("/etc/resolv.conf",
|
||||
"/run/host/etc/resolv.conf",
|
||||
|
@ -197,18 +200,6 @@ func initContainer(cmd *cobra.Command, args []string) error {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
if utils.PathExists("/run/host/monitor") {
|
||||
logrus.Debug("Path /run/host/monitor exists")
|
||||
|
||||
if _, err := os.Readlink("/etc/timezone"); err != nil {
|
||||
if err := redirectPath("/etc/timezone",
|
||||
"/run/host/monitor/timezone",
|
||||
false); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if initContainerFlags.mediaLink {
|
||||
|
@ -267,6 +258,19 @@ func initContainer(cmd *cobra.Command, args []string) error {
|
|||
}
|
||||
}
|
||||
|
||||
logrus.Debug("Setting up watches for file system events")
|
||||
|
||||
watcherForHost, err := fsnotify.NewWatcher()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
defer watcherForHost.Close()
|
||||
|
||||
if err := watcherForHost.Add("/run/host/etc"); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
logrus.Debug("Finished initializing container")
|
||||
|
||||
toolboxRuntimeDirectory := runtimeDirectory + "/toolbox"
|
||||
|
@ -297,22 +301,15 @@ func initContainer(cmd *cobra.Command, args []string) error {
|
|||
return errors.New("failed to change ownership of initialization stamp")
|
||||
}
|
||||
|
||||
logrus.Debug("Going to sleep")
|
||||
logrus.Debug("Listening to file system events")
|
||||
|
||||
sleepBinary, err := exec.LookPath("sleep")
|
||||
if err != nil {
|
||||
if errors.Is(err, exec.ErrNotFound) {
|
||||
return errors.New("sleep(1) not found")
|
||||
for {
|
||||
select {
|
||||
case event := <-watcherForHost.Events:
|
||||
handleFileSystemEvent(event)
|
||||
case err := <-watcherForHost.Errors:
|
||||
logrus.Warnf("Received an error from the file system watcher: %v", err)
|
||||
}
|
||||
|
||||
return errors.New("failed to lookup sleep(1)")
|
||||
}
|
||||
|
||||
sleepArgs := []string{"sleep", "+Inf"}
|
||||
env := os.Environ()
|
||||
|
||||
if err := syscall.Exec(sleepBinary, sleepArgs, env); err != nil {
|
||||
return errors.New("failed to invoke sleep(1)")
|
||||
}
|
||||
|
||||
return nil
|
||||
|
@ -410,6 +407,17 @@ func configureUsers(targetUserUid int,
|
|||
return nil
|
||||
}
|
||||
|
||||
func handleFileSystemEvent(event fsnotify.Event) {
|
||||
eventOpString := event.Op.String()
|
||||
logrus.Debugf("Handling file system event: operation %s on %s", eventOpString, event.Name)
|
||||
|
||||
if event.Name == "/run/host/etc/localtime" {
|
||||
if err := updateTimeZoneFromLocalTime(); err != nil {
|
||||
logrus.Warnf("Failed to handle changes to the host's /etc/localtime: %v", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func mountBind(containerPath, source, flags string) error {
|
||||
fi, err := os.Stat(source)
|
||||
if err != nil {
|
||||
|
@ -555,3 +563,39 @@ func sanitizeRedirectionTarget(target string) string {
|
|||
|
||||
return target
|
||||
}
|
||||
|
||||
func updateTimeZoneFromLocalTime() error {
|
||||
localTimeEvaled, err := filepath.EvalSymlinks("/etc/localtime")
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to resolve /etc/localtime: %w", err)
|
||||
}
|
||||
|
||||
logrus.Debugf("Resolved /etc/localtime to %s", localTimeEvaled)
|
||||
|
||||
const zoneInfoRoot = "/run/host/usr/share/zoneinfo"
|
||||
|
||||
if !strings.HasPrefix(localTimeEvaled, zoneInfoRoot) {
|
||||
return errors.New("/etc/localtime points to unknown location")
|
||||
}
|
||||
|
||||
timeZone, err := filepath.Rel(zoneInfoRoot, localTimeEvaled)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to extract time zone: %w", err)
|
||||
}
|
||||
|
||||
const etcTimeZone = "/etc/timezone"
|
||||
|
||||
if err := os.Remove(etcTimeZone); err != nil {
|
||||
if !os.IsNotExist(err) {
|
||||
return fmt.Errorf("failed to remove old %s: %w", etcTimeZone, err)
|
||||
}
|
||||
}
|
||||
|
||||
timeZoneBytes := []byte(timeZone + "\n")
|
||||
err = ioutil.WriteFile(etcTimeZone, timeZoneBytes, 0664)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to create new %s: %w", etcTimeZone, err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -7,6 +7,7 @@ require (
|
|||
github.com/acobaugh/osrelease v0.0.0-20181218015638-a93a0a55a249
|
||||
github.com/briandowns/spinner v1.10.0
|
||||
github.com/docker/go-units v0.4.0
|
||||
github.com/fsnotify/fsnotify v1.4.7
|
||||
github.com/godbus/dbus/v5 v5.0.3
|
||||
github.com/sirupsen/logrus v1.4.2
|
||||
github.com/spf13/cobra v0.0.5
|
||||
|
|
|
@ -16,6 +16,7 @@ github.com/docker/go-units v0.4.0 h1:3uh0PgVws3nIA0Q+MwDC8yjEPf9zjRfZZWXZYDct3Tw
|
|||
github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
|
||||
github.com/fatih/color v1.7.0 h1:DkWD4oS2D8LGGgTQ6IvwJJXSL5Vp2ffcQg58nFV38Ys=
|
||||
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
|
||||
github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I=
|
||||
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
||||
github.com/godbus/dbus/v5 v5.0.3 h1:ZqHaoEF7TBzh4jzPmqVhE/5A1z9of6orkAe5uHoAeME=
|
||||
github.com/godbus/dbus/v5 v5.0.3/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
|
||||
|
|
|
@ -113,7 +113,7 @@ function run_toolbox() {
|
|||
|
||||
function is_toolbox_ready() {
|
||||
toolbox_container="$1"
|
||||
expected_string="Going to sleep"
|
||||
expected_string="Listening to file system events"
|
||||
num_of_tries=5
|
||||
timeout=2
|
||||
|
||||
|
|
Loading…
Reference in a new issue