github.com/u-root/u-root@v7.0.1-0.20200915234505-ad7babab0a8e+incompatible/tools/testramfs/testramfs.go (about) 1 // Copyright 2012-2017 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 // testramfs tests things, badly 6 package main 7 8 import ( 9 "io" 10 "io/ioutil" 11 "log" 12 "os" 13 "syscall" 14 15 flag "github.com/spf13/pflag" 16 "golang.org/x/sys/unix" 17 18 "github.com/u-root/u-root/pkg/cpio" 19 "github.com/u-root/u-root/pkg/pty" 20 ) 21 22 const ( 23 unshareFlags = syscall.CLONE_NEWNS 24 cloneFlags = syscall.CLONE_NEWIPC | 25 syscall.CLONE_NEWNET | 26 // making newpid work will be more tricky, 27 // since none of my CLs to fix go runtime for 28 // it ever got in. 29 //syscall.CLONE_NEWPID | 30 syscall.CLONE_NEWUTS | 31 0 32 ) 33 34 var ( 35 noremove = flag.BoolP("noremove", "n", false, "remove tempdir when done") 36 interactive = flag.BoolP("interactive", "i", false, "interactive mode") 37 ) 38 39 func main() { 40 flag.Parse() 41 42 if flag.NArg() != 1 { 43 log.Fatalf("usage: %s <cpio-path>", os.Args[0]) 44 } 45 46 c := flag.Args()[0] 47 48 f, err := os.Open(c) 49 if err != nil { 50 log.Fatal(err) 51 } 52 53 // So, what's the plan here? 54 // 55 // - new mount namespace 56 // - root mount is a tmpfs mount filled with the archive. 57 // 58 // - new PID namespace 59 // - archive/init actually runs as PID 1. 60 61 // Note this is basically a chroot and umask is inherited. 62 // The umask has to be zero else some creation will end 63 // up with incorrect permissions, a particular problem 64 // in device creation. 65 u := unix.Umask(0) 66 defer unix.Umask(u) 67 68 tempDir, err := ioutil.TempDir("", "u-root") 69 if err != nil { 70 log.Fatal(err) 71 } 72 // Don't do a RemoveAll. This should be empty and 73 // an error can tell us we got something wrong. 74 if !*noremove { 75 defer func(n string) { 76 log.Printf("Removing %v", n) 77 if err := os.Remove(n); err != nil { 78 log.Fatal(err) 79 } 80 }(tempDir) 81 } 82 if err := syscall.Mount("", tempDir, "tmpfs", 0, ""); err != nil { 83 log.Fatal(err) 84 } 85 if !*noremove { 86 defer func(n string) { 87 log.Printf("Unmounting %v", n) 88 if err := syscall.Unmount(n, syscall.MNT_DETACH); err != nil { 89 log.Fatal(err) 90 } 91 }(tempDir) 92 } 93 94 archiver, err := cpio.Format("newc") 95 if err != nil { 96 log.Fatal(err) 97 } 98 99 r := archiver.Reader(f) 100 for { 101 rec, err := r.ReadRecord() 102 if err == io.EOF { 103 break 104 } 105 if err != nil { 106 log.Fatal(err) 107 } 108 cpio.CreateFileInRoot(rec, tempDir, false) 109 } 110 111 cmd, err := pty.New() 112 if err != nil { 113 log.Fatal(err) 114 } 115 cmd.Command("/init") 116 cmd.C.SysProcAttr.Chroot = tempDir 117 cmd.C.SysProcAttr.Cloneflags = cloneFlags 118 cmd.C.SysProcAttr.Unshareflags = cloneFlags 119 if *interactive { 120 if err := cmd.Run(); err != nil { 121 log.Fatal(err) 122 } 123 return 124 } 125 if err := cmd.Start(); err != nil { 126 log.Fatal(err) 127 } 128 go io.Copy(cmd.TTY, cmd.Ptm) 129 130 // At this point you could use an array of commands/output templates to 131 // drive the test, and end with the exit command shown nere. 132 for _, c := range []string{"date\n", "exit\n", "exit\n", "exit\n"} { 133 if _, err := cmd.Ptm.Write([]byte(c)); err != nil { 134 log.Printf("Writing %s: %v", c, err) 135 } 136 } 137 if err := cmd.Wait(); err != nil { 138 log.Fatal(err) 139 } 140 141 }