diff --git a/src/cmd/initContainer.go b/src/cmd/initContainer.go index 3c31d2a..03bb066 100644 --- a/src/cmd/initContainer.go +++ b/src/cmd/initContainer.go @@ -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 +} diff --git a/src/go.mod b/src/go.mod index 2b1ac30..823b8d9 100644 --- a/src/go.mod +++ b/src/go.mod @@ -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 diff --git a/src/go.sum b/src/go.sum index 4d6a003..5a03a68 100644 --- a/src/go.sum +++ b/src/go.sum @@ -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= diff --git a/test/system/helpers.bash b/test/system/helpers.bash index 497b35c..d7e5162 100644 --- a/test/system/helpers.bash +++ b/test/system/helpers.bash @@ -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