github.com/hugelgupf/u-root@v0.0.0-20191023214958-4807c632154c/cmds/exp/pox/pox.go (about) 1 // Copyright 2012-2018 the u-root Authors. All rights reserved 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 // pox builds a portable executable as a squashfs image. 6 // It is intended to create files compatible with tinycore 7 // tcz files. One of more of the files can be programs 8 // but that is not required. 9 // This could have been a simple program but mksquashfs does not 10 // preserve path information. 11 // Yeah. 12 // 13 // Synopsis: 14 // pox [-[-debug]|d] -[-run|r file] [-[-create]|c] [-[-file]|f tcz-file] file [...file] 15 // 16 // Description: 17 // pox makes portable executables in squashfs format compatible with 18 // tcz format. We don't build in the execution code, rather, we set it 19 // up so we can use the command itself. You can create, create and run a command, 20 // mount a pox, or mount a pox and run a command in it. 21 // 22 // Options: 23 // debug|d: verbose 24 // file|f file: file name (default /tmp/pox.tcz) 25 // run|r: run a file by loopback mounting the squashfs and using the first arg as a command to run in a chroot 26 // create|c: create the file. 27 // both -c and -r can be used on the same command. 28 // 29 // Example: 30 // pox -d -r /bin/bash /bin/cat /bin/ls /etc/hosts 31 // Will build a squashfs, mount it, and drop you into it running bash. 32 // You can use ls and cat on /etc/hosts. 33 // Simpler example: 34 // pox -d -r /bin/ls /etc/hosts 35 // will run ls and exit. 36 package main 37 38 import ( 39 "fmt" 40 "io" 41 "io/ioutil" 42 "log" 43 "os" 44 "os/exec" 45 "path/filepath" 46 "syscall" 47 48 flag "github.com/spf13/pflag" 49 "github.com/u-root/u-root/pkg/ldd" 50 "github.com/u-root/u-root/pkg/loop" 51 ) 52 53 const usage = "pox [-[-debug]|d] -[-run|r file] [-[-create]|c] [-[-file]|f tcz-file] file [...file]" 54 55 var ( 56 debug = flag.BoolP("debug", "d", false, "enable debug prints") 57 run = flag.BoolP("run", "r", false, "run a test with the first argument") 58 create = flag.BoolP("create", "c", true, "create it") 59 file = flag.StringP("output", "f", "/tmp/pox.tcz", "Output file") 60 v = func(string, ...interface{}) {} 61 ) 62 63 func pox() error { 64 flag.Parse() 65 if *debug { 66 v = log.Printf 67 } 68 names := flag.Args() 69 if len(names) == 0 { 70 return fmt.Errorf(usage) 71 } 72 73 if *create { 74 l, err := ldd.Ldd(names) 75 if err != nil { 76 return fmt.Errorf("Running ldd on %v: %v", names, err) 77 } 78 79 for _, dep := range l { 80 v("%s", dep.FullName) 81 names = append(names, dep.FullName) 82 } 83 // Now we need to make a template file hierarchy and put 84 // the stuff we want in there. 85 dir, err := ioutil.TempDir("", "pox") 86 if err != nil { 87 return err 88 } 89 if !*debug { 90 defer os.RemoveAll(dir) 91 } 92 // We don't use defer() here to close files as 93 // that can cause open failures with a large enough number. 94 for _, f := range names { 95 v("Process %v", f) 96 fi, err := os.Stat(f) 97 if err != nil { 98 return err 99 } 100 in, err := os.Open(f) 101 if err != nil { 102 return err 103 } 104 dfile := filepath.Join(dir, f) 105 d := filepath.Dir(dfile) 106 if err := os.MkdirAll(d, 0755); err != nil { 107 in.Close() 108 return err 109 } 110 out, err := os.OpenFile(dfile, os.O_WRONLY|os.O_CREATE, fi.Mode().Perm()) 111 if err != nil { 112 in.Close() 113 return err 114 } 115 _, err = io.Copy(out, in) 116 in.Close() 117 out.Close() 118 if err != nil { 119 return err 120 } 121 122 } 123 c := exec.Command("mksquashfs", dir, *file, "-noappend") 124 o, err := c.CombinedOutput() 125 v("%v", string(o)) 126 if err != nil { 127 return fmt.Errorf("%v: %v: %v", c.Args, string(o), err) 128 } 129 } 130 131 if !*run { 132 return nil 133 } 134 dir, err := ioutil.TempDir("", "pox") 135 if err != nil { 136 return err 137 } 138 if !*debug { 139 defer os.RemoveAll(dir) 140 } 141 m, err := loop.New(*file, "squashfs", "") 142 if err != nil { 143 return err 144 } 145 if err := m.Mount(dir, 0); err != nil { 146 return err 147 } 148 c := exec.Command(names[0]) 149 c.Stdin, c.Stdout, c.Stderr = os.Stdin, os.Stdout, os.Stderr 150 c.SysProcAttr = &syscall.SysProcAttr{ 151 Chroot: dir, 152 } 153 154 err = c.Run() 155 if err != nil { 156 log.Printf("Running test: %v", err) 157 } 158 if err := m.Unmount(0); err != nil { 159 v("Unmounting and freeing %v: %v", m, err) 160 } 161 162 v("Done, your pox is in %v", *file) 163 return err 164 } 165 166 func main() { 167 if err := pox(); err != nil { 168 log.Fatal(err) 169 } 170 }