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  }