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  }