gopkg.in/hugelgupf/u-root.v4@v4.0.0-20180831060141-1d761fb73d50/xcmds/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. 8 // This could have been a simple program but mksquashfs does not 9 // preserve path information. 10 // Yeah. 11 // 12 // Synopsis: 13 // pox [-d] -[output|o file] 14 // 15 // Description: 16 // pox makes portable executables in squashfs format compatible with 17 // tcz format. We don't build in the execution code, rather, we set it 18 // up so we can use the command itself. 19 // 20 // Options: 21 // debug|d: verbose 22 // output|o file: output file name (default /tmp/pox.tcz) 23 // test|t: run a test by loopback mounting the squashfs and using the first arg as a command to run in a chroot 24 // 25 // Example: 26 // pox -d -t /bin/bash /bin/cat /bin/ls /etc/hosts 27 // Will build and squashfs, mount it, and drop you into it running bash. 28 // You can use ls and cat on /etc/hosts. 29 // Simpler example: 30 // pox -d -t /bin/ls /etc/hosts 31 // will run ls and exit. 32 package main 33 34 import ( 35 "fmt" 36 "io" 37 "io/ioutil" 38 "log" 39 "os" 40 "os/exec" 41 "syscall" 42 43 flag "github.com/spf13/pflag" 44 "github.com/u-root/u-root/pkg/cpio" 45 "github.com/u-root/u-root/pkg/ldd" 46 "github.com/u-root/u-root/pkg/loop" 47 ) 48 49 const usage = "pox [-d] [-f file] command..." 50 51 var ( 52 debug = flag.BoolP("debug", "d", false, "enable debug prints") 53 test = flag.BoolP("test", "t", false, "run a test with the first argument") 54 create = flag.BoolP("create", "c", true, "create it") 55 v = func(string, ...interface{}) {} 56 ofile = flag.StringP("output", "o", "/tmp/pox.tcz", "Output file") 57 ) 58 59 func pox() error { 60 flag.Parse() 61 if *debug { 62 v = log.Printf 63 } 64 names := flag.Args() 65 if len(names) == 0 { 66 return fmt.Errorf(usage) 67 } 68 69 if *create { 70 l, err := ldd.Ldd(names) 71 if err != nil { 72 return err 73 } 74 75 for _, dep := range l { 76 v("%s", dep.FullName) 77 names = append(names, dep.FullName) 78 } 79 // Now we need to make a template file hierarchy and put 80 // the stuff we want in there. 81 dir, err := ioutil.TempDir("", "pox") 82 if err != nil { 83 return err 84 } 85 if !*debug { 86 defer os.RemoveAll(dir) 87 } 88 archiver := cpio.InMemArchive() 89 for _, f := range names { 90 v("Process %v", f) 91 rec, err := cpio.GetRecord(f) 92 if err != nil { 93 return err 94 } 95 if err := archiver.WriteRecord(rec); err != nil { 96 return err 97 } 98 } 99 v("%v", archiver) 100 rr := archiver.Reader() 101 for { 102 r, err := rr.ReadRecord() 103 v("%v %v", r, err) 104 if err == io.EOF { 105 break 106 } 107 if err != nil { 108 return err 109 } 110 if err := cpio.CreateFileInRoot(r, dir); err != nil { 111 return err 112 } 113 114 } 115 c := exec.Command("mksquashfs", dir, *ofile, "-noappend") 116 o, err := c.CombinedOutput() 117 v("%v", string(o)) 118 if err != nil { 119 return fmt.Errorf("%v: %v: %v", c.Args, string(o), err) 120 } 121 } 122 123 if !*test { 124 return nil 125 } 126 dir, err := ioutil.TempDir("", "pox") 127 if err != nil { 128 return err 129 } 130 if !*debug { 131 defer os.RemoveAll(dir) 132 } 133 m, err := loop.New(*ofile, dir, "squashfs", 0, "") 134 if err != nil { 135 return err 136 } 137 if err := m.Mount(); err != nil { 138 return err 139 } 140 c := exec.Command(names[0]) 141 c.Stdin, c.Stdout, c.Stderr = os.Stdin, os.Stdout, os.Stderr 142 c.SysProcAttr = &syscall.SysProcAttr{ 143 Chroot: dir, 144 } 145 146 err = c.Run() 147 if err != nil { 148 log.Printf("Running test: %v", err) 149 } 150 if err := m.Unmount(0); err != nil { 151 v("Unmounting and freeing %v: %v", m, err) 152 } 153 154 v("Done, your pox is in %v", *ofile) 155 return err 156 } 157 158 func main() { 159 if err := pox(); err != nil { 160 log.Fatal(err) 161 } 162 }