github.com/jerryclinesmith/packer@v0.3.7/builder/amazon/chroot/communicator.go (about) 1 package chroot 2 3 import ( 4 "github.com/mitchellh/packer/packer" 5 "io" 6 "log" 7 "os" 8 "os/exec" 9 "path/filepath" 10 "syscall" 11 ) 12 13 // Communicator is a special communicator that works by executing 14 // commands locally but within a chroot. 15 type Communicator struct { 16 Chroot string 17 } 18 19 func (c *Communicator) Start(cmd *packer.RemoteCmd) error { 20 chrootCmdPath, err := exec.LookPath("chroot") 21 if err != nil { 22 return err 23 } 24 25 localCmd := exec.Command(chrootCmdPath, c.Chroot, "/bin/sh", "-c", cmd.Command) 26 localCmd.Stdin = cmd.Stdin 27 localCmd.Stdout = cmd.Stdout 28 localCmd.Stderr = cmd.Stderr 29 log.Printf("Executing: %s %#v", localCmd.Path, localCmd.Args) 30 if err := localCmd.Start(); err != nil { 31 return err 32 } 33 34 go func() { 35 exitStatus := 0 36 if err := localCmd.Wait(); err != nil { 37 if exitErr, ok := err.(*exec.ExitError); ok { 38 exitStatus = 1 39 40 // There is no process-independent way to get the REAL 41 // exit status so we just try to go deeper. 42 if status, ok := exitErr.Sys().(syscall.WaitStatus); ok { 43 exitStatus = status.ExitStatus() 44 } 45 } 46 } 47 48 log.Printf( 49 "Chroot executation ended with '%d': '%s'", 50 exitStatus, cmd.Command) 51 cmd.SetExited(exitStatus) 52 }() 53 54 return nil 55 } 56 57 func (c *Communicator) Upload(dst string, r io.Reader) error { 58 dst = filepath.Join(c.Chroot, dst) 59 log.Printf("Uploading to chroot dir: %s", dst) 60 f, err := os.Create(dst) 61 if err != nil { 62 return err 63 } 64 defer f.Close() 65 66 if _, err := io.Copy(f, r); err != nil { 67 return err 68 } 69 70 return nil 71 } 72 73 func (c *Communicator) UploadDir(dst string, src string, exclude []string) error { 74 walkFn := func(fullPath string, info os.FileInfo, err error) error { 75 if err != nil { 76 return err 77 } 78 79 path, err := filepath.Rel(src, fullPath) 80 if err != nil { 81 return err 82 } 83 84 for _, e := range exclude { 85 if e == path { 86 log.Printf("Skipping excluded file: %s", path) 87 return nil 88 } 89 } 90 91 dstPath := filepath.Join(dst, path) 92 f, err := os.Open(fullPath) 93 if err != nil { 94 return err 95 } 96 defer f.Close() 97 98 return c.Upload(dstPath, f) 99 } 100 101 log.Printf("Uploading directory '%s' to '%s'", src, dst) 102 return filepath.Walk(src, walkFn) 103 } 104 105 func (c *Communicator) Download(src string, w io.Writer) error { 106 src = filepath.Join(c.Chroot, src) 107 log.Printf("Downloading from chroot dir: %s", src) 108 f, err := os.Open(src) 109 if err != nil { 110 return err 111 } 112 defer f.Close() 113 114 if _, err := io.Copy(w, f); err != nil { 115 return err 116 } 117 118 return nil 119 }