diff --git a/internal/helper/helper.go b/internal/helper/helper.go index df63f293..a50450ea 100644 --- a/internal/helper/helper.go +++ b/internal/helper/helper.go @@ -20,8 +20,12 @@ import ( ) // define some functions that can be mocked by test cases -var osRename = os.Rename -var osRemove = os.Remove +var ( + osRename = os.Rename + osRemove = os.Remove + osWriteFile = os.WriteFile + osutilFileExists = osutil.FileExists +) func BoolPtr(b bool) *bool { return &b @@ -492,3 +496,42 @@ func RestoreResolvConf(chroot string) error { } return nil } + +const backupExt = ".REAL" + +// BackupReplace backup the target file and replace it with the given content +// Returns the restore function. +func BackupReplace(target string, content string) (func(error) error, error) { + backup := target + backupExt + if osutilFileExists(backup) { + // already backed up so do nothing + return nil, nil + } + + if err := osRename(target, backup); err != nil { + return nil, fmt.Errorf("Error moving file \"%s\" to \"%s\": %s", target, backup, err.Error()) + } + + if err := osWriteFile(target, []byte(content), 0755); err != nil { + return nil, fmt.Errorf("Error writing to %s : %s", target, err.Error()) + } + + return genRestoreFile(target), nil +} + +// genRestoreFile returns the function to be called to restore the backuped file +func genRestoreFile(target string) func(err error) error { + return func(err error) error { + src := target + backupExt + if !osutilFileExists(src) { + return err + } + + if tmpErr := osRename(src, target); tmpErr != nil { + tmpErr = fmt.Errorf("Error moving file \"%s\" to \"%s\": %s", src, target, tmpErr.Error()) + return fmt.Errorf("%s\n%s", err, tmpErr) + } + + return err + } +} diff --git a/internal/statemachine/classic_states.go b/internal/statemachine/classic_states.go index 46687734..ea988b20 100644 --- a/internal/statemachine/classic_states.go +++ b/internal/statemachine/classic_states.go @@ -410,6 +410,28 @@ func (stateMachine *StateMachine) installPackages() error { err = unsetDenyingPolicyRcD(err) }() + restoreStartStopDaemon, err := backupReplaceStartStopDaemon(classicStateMachine.tempDirs.chroot) + if err != nil { + return err + } + + defer func() { + err = restoreStartStopDaemon(err) + }() + + initctlPath := filepath.Join(classicStateMachine.tempDirs.chroot, "sbin", "initctl") + + if osutil.FileExists(initctlPath) { + restoreInitctl, err := backupReplaceInitctl(classicStateMachine.tempDirs.chroot) + if err != nil { + return err + } + + defer func() { + err = restoreInitctl(err) + }() + } + installPackagesCmds := generateAptCmds(stateMachine.tempDirs.chroot, classicStateMachine.Packages) err = helper.RunCmds(installPackagesCmds, classicStateMachine.commonFlags.Debug) diff --git a/internal/statemachine/helper.go b/internal/statemachine/helper.go index 113d25e2..4d0d0f31 100644 --- a/internal/statemachine/helper.go +++ b/internal/statemachine/helper.go @@ -705,6 +705,31 @@ func dpkgDivert(baseDir string, target string) (*exec.Cmd, *exec.Cmd) { return execCommand("chroot", divert...), execCommand("chroot", undivert...) } +// backupReplaceStartStopDaemon backup start-stop-daemon and replace it with a fake one +// Returns a restore function to put the original one in place +func backupReplaceStartStopDaemon(baseDir string) (func(error) error, error) { + const startStopDaemonContent = `#!/bin/sh +echo +echo "Warning: Fake start-stop-daemon called, doing nothing" +` + + startStopDaemon := filepath.Join(baseDir, "sbin", "start-stop-daemon") + return helper.BackupReplace(startStopDaemon, startStopDaemonContent) +} + +// backupReplaceInitctl backup initctl and replace it with a fake one +// Returns a restore function to put the original one in place +func backupReplaceInitctl(baseDir string) (func(error) error, error) { + const initctlContent = `#!/bin/sh +if [ "$1" = version ]; then exec /sbin/initctl.REAL "$@"; fi +echo +echo "Warning: Fake initctl called, doing nothing" +` + + initctl := filepath.Join(baseDir, "sbin", "initctl") + return helper.BackupReplace(initctl, initctlContent) +} + // createPPAInfo generates the name for a PPA sources.list file // in the convention of add-apt-repository, and the contents // that define the sources.list in the DEB822 format