diff --git a/builder/osc/chroot/lockfile.go b/builder/osc/chroot/lockfile.go new file mode 100644 index 000000000..1ba13e04b --- /dev/null +++ b/builder/osc/chroot/lockfile.go @@ -0,0 +1,16 @@ +// +build windows + +package chroot + +import ( + "errors" + "os" +) + +func lockFile(*os.File) error { + return errors.New("not supported on Windows") +} + +func unlockFile(f *os.File) error { + return nil +} diff --git a/builder/osc/chroot/lockfile_unix.go b/builder/osc/chroot/lockfile_unix.go new file mode 100644 index 000000000..0d0f8c8f7 --- /dev/null +++ b/builder/osc/chroot/lockfile_unix.go @@ -0,0 +1,27 @@ +// +build !windows + +package chroot + +import ( + "os" + + "golang.org/x/sys/unix" +) + +// See: http://linux.die.net/include/sys/file.h +const LOCK_EX = 2 +const LOCK_NB = 4 +const LOCK_UN = 8 + +func lockFile(f *os.File) error { + err := unix.Flock(int(f.Fd()), LOCK_EX) + if err != nil { + return err + } + + return nil +} + +func unlockFile(f *os.File) error { + return unix.Flock(int(f.Fd()), LOCK_UN) +} diff --git a/builder/osc/chroot/step_flock.go b/builder/osc/chroot/step_flock.go new file mode 100644 index 000000000..2c81193da --- /dev/null +++ b/builder/osc/chroot/step_flock.go @@ -0,0 +1,74 @@ +package chroot + +import ( + "context" + "fmt" + "log" + "os" + "path/filepath" + + "github.com/hashicorp/packer/helper/multistep" + "github.com/hashicorp/packer/packer" +) + +// StepFlock provisions the vm within a chroot. +// +// Produces: +// flock_cleanup Cleanup - To perform early cleanup +type StepFlock struct { + fh *os.File +} + +func (s *StepFlock) Run(_ context.Context, state multistep.StateBag) multistep.StepAction { + ui := state.Get("ui").(packer.Ui) + + lockfile := "/var/lock/packer-chroot/lock" + if err := os.MkdirAll(filepath.Dir(lockfile), 0755); err != nil { + err := fmt.Errorf("Error creating lock: %s", err) + state.Put("error", err) + ui.Error(err.Error()) + return multistep.ActionHalt + } + + log.Printf("Obtaining lock: %s", lockfile) + f, err := os.Create(lockfile) + if err != nil { + err := fmt.Errorf("Error creating lock: %s", err) + state.Put("error", err) + ui.Error(err.Error()) + return multistep.ActionHalt + } + + // LOCK! + if err := lockFile(f); err != nil { + err := fmt.Errorf("Error obtaining lock: %s", err) + state.Put("error", err) + ui.Error(err.Error()) + return multistep.ActionHalt + } + + // Set the file handle, we can't close it because we need to hold + // the lock. + s.fh = f + + state.Put("flock_cleanup", s) + return multistep.ActionContinue +} + +func (s *StepFlock) Cleanup(state multistep.StateBag) { + s.CleanupFunc(state) +} + +func (s *StepFlock) CleanupFunc(state multistep.StateBag) error { + if s.fh == nil { + return nil + } + + log.Printf("Unlocking: %s", s.fh.Name()) + if err := unlockFile(s.fh); err != nil { + return err + } + + s.fh = nil + return nil +}