github.com/cloudfoundry-attic/garden-linux@v0.333.2-candidate/containerizer/initc/main.go (about) 1 package main 2 3 import ( 4 "flag" 5 "fmt" 6 "net" 7 "os" 8 "runtime" 9 "strconv" 10 "syscall" 11 "time" 12 13 "github.com/cloudfoundry-incubator/cf-lager" 14 "github.com/cloudfoundry-incubator/garden-linux/containerizer" 15 "github.com/cloudfoundry-incubator/garden-linux/containerizer/system" 16 "github.com/cloudfoundry-incubator/garden-linux/network" 17 "github.com/cloudfoundry-incubator/garden-linux/process" 18 sys "github.com/cloudfoundry-incubator/garden-linux/system" 19 "github.com/docker/docker/pkg/reexec" 20 21 // for rexec.Register("initd") 22 _ "github.com/cloudfoundry-incubator/garden-linux/container_daemon/initd" 23 ) 24 25 func init() { 26 runtime.LockOSThread() 27 } 28 29 // initc initializes a newly created container and then execs to become 30 // the init process 31 func main() { 32 if reexec.Init() { 33 return 34 } 35 36 defer func() { 37 if r := recover(); r != nil { 38 fmt.Fprintf(os.Stderr, "initc: panicked: %s\n", r) 39 os.Exit(4) 40 } 41 }() 42 43 rootFsPath := flag.String("root", "", "Path for the root file system directory") 44 configFilePath := flag.String("config", "./etc/config", "Path for the configuration file") 45 title := flag.String("title", "", "") 46 cf_lager.AddFlags(flag.CommandLine) 47 flag.Parse() 48 49 if *rootFsPath == "" { 50 missing("--root") 51 } 52 53 syncReader := os.NewFile(uintptr(3), "/dev/a") 54 defer syncReader.Close() 55 syncWriter := os.NewFile(uintptr(4), "/dev/d") 56 defer syncWriter.Close() 57 58 sync := &containerizer.PipeSynchronizer{ 59 Reader: syncReader, 60 Writer: syncWriter, 61 } 62 63 if err := sync.Wait(2 * time.Minute); err != nil { 64 fail(fmt.Sprintf("initc: wait for host: %s", err), 8) 65 } 66 67 env, err := process.EnvFromFile(*configFilePath) 68 if err != nil { 69 fmt.Fprintf(os.Stderr, "initc: failed to get env from config file: %s\n", err) 70 os.Exit(3) 71 } 72 73 dropCapabilities := env["root_uid"] != "0" 74 procMountFlags := syscall.MS_NOSUID | syscall.MS_NODEV | syscall.MS_NOEXEC 75 sysMountFlags := syscall.MS_NOSUID | syscall.MS_NODEV | syscall.MS_NOEXEC | syscall.MS_RDONLY 76 77 if dropCapabilities { 78 procMountFlags = procMountFlags | syscall.MS_RDONLY 79 } 80 81 initializer := &system.Initializer{ 82 Steps: []system.StepRunner{ 83 &containerizer.FuncStep{system.Mount{ 84 Type: system.Tmpfs, 85 Flags: syscall.MS_NODEV, 86 TargetPath: "/dev/shm", 87 }.Mount}, 88 &containerizer.FuncStep{system.Mount{ 89 Type: system.Proc, 90 Flags: procMountFlags, 91 TargetPath: "/proc", 92 }.Mount}, 93 &containerizer.FuncStep{system.Mount{ 94 Type: system.Sys, 95 Flags: sysMountFlags, 96 TargetPath: "/sys", 97 }.Mount}, 98 &containerizer.FuncStep{system.Mount{ 99 Type: system.Devpts, 100 TargetPath: "/dev/pts", 101 Data: "newinstance,ptmxmode=0666", 102 }.Mount}, 103 &containerizer.FuncStep{system.Unmount{ 104 Dir: "/tmp/garden-host", 105 }.Unmount}, 106 &containerizer.FuncStep{func() error { 107 return setupNetwork(env) 108 }}, 109 &containerizer.CapabilitiesStep{ 110 Drop: dropCapabilities, 111 Capabilities: &sys.ProcessCapabilities{Pid: os.Getpid()}, 112 }, 113 }, 114 } 115 116 containerizer := containerizer.Containerizer{ 117 RootfsPath: *rootFsPath, 118 ContainerInitializer: initializer, 119 Waiter: sync, 120 Signaller: sync, 121 } 122 123 if err := containerizer.Init(); err != nil { 124 fail(fmt.Sprintf("failed to init containerizer: %s", err), 2) 125 } 126 127 syscall.RawSyscall(syscall.SYS_FCNTL, uintptr(4), syscall.F_SETFD, 0) 128 syscall.RawSyscall(syscall.SYS_FCNTL, uintptr(5), syscall.F_SETFD, 0) 129 130 if err := syscall.Exec("/proc/self/exe", []string{"initd", fmt.Sprintf("-dropCapabilities=%t", dropCapabilities), fmt.Sprintf("-title=\"%s\"", *title)}, os.Environ()); err != nil { 131 fail(fmt.Sprintf("failed to reexec: %s", err), 3) 132 } 133 } 134 135 func fail(err string, code int) { 136 fmt.Fprintf(os.Stderr, "initc: %s\n", err) 137 os.Exit(code) 138 } 139 140 func missing(flagName string) { 141 fmt.Fprintf(os.Stderr, "initc: %s is required\n", flagName) 142 flag.Usage() 143 os.Exit(1) 144 } 145 146 func setupNetwork(env process.Env) error { 147 _, ipNet, err := net.ParseCIDR(env["network_cidr"]) 148 if err != nil { 149 return fmt.Errorf("initc: failed to parse network CIDR: %s", err) 150 } 151 152 mtu, err := strconv.ParseInt(env["container_iface_mtu"], 0, 64) 153 if err != nil { 154 return fmt.Errorf("initc: failed to parse container interface MTU: %s", err) 155 } 156 157 logger, _ := cf_lager.New("hook") 158 configurer := network.NewConfigurer(logger.Session("initc: hook.CHILD_AFTER_PIVOT")) 159 err = configurer.ConfigureContainer(&network.ContainerConfig{ 160 Hostname: env["id"], 161 ContainerIntf: env["network_container_iface"], 162 ContainerIP: net.ParseIP(env["network_container_ip"]), 163 GatewayIP: net.ParseIP(env["network_host_ip"]), 164 Subnet: ipNet, 165 Mtu: int(mtu), 166 }) 167 if err != nil { 168 return fmt.Errorf("initc: failed to configure container network: %s", err) 169 } 170 171 return nil 172 }