package rootfs import ( "os" "path/filepath" "syscall" ) const ( defaultInitializer = "linux-init" ) func init() { initializers[defaultInitializer] = initFS } func createDirectory(name string, uid, gid int) initializerFunc { return func(root string) error { dname := filepath.Join(root, name) st, err := os.Stat(dname) if err != nil && !os.IsNotExist(err) { return err } else if err == nil { if st.IsDir() { stat := st.Sys().(*syscall.Stat_t) if int(stat.Gid) == gid && int(stat.Uid) == uid { return nil } } else { if err := os.Remove(dname); err != nil { return err } if err := os.Mkdir(dname, 0755); err != nil { return err } } } else { if err := os.Mkdir(dname, 0755); err != nil { return err } } return os.Chown(dname, uid, gid) } } func touchFile(name string, uid, gid int) initializerFunc { return func(root string) error { fname := filepath.Join(root, name) st, err := os.Stat(fname) if err != nil && !os.IsNotExist(err) { return err } else if err == nil { stat := st.Sys().(*syscall.Stat_t) if int(stat.Gid) == gid && int(stat.Uid) == uid { return nil } return os.Chown(fname, uid, gid) } f, err := os.OpenFile(fname, os.O_CREATE, 0644) if err != nil { return err } defer f.Close() return f.Chown(uid, gid) } } func symlink(oldname, newname string) initializerFunc { return func(root string) error { linkName := filepath.Join(root, newname) if _, err := os.Stat(linkName); err != nil && !os.IsNotExist(err) { return err } else if err == nil { return nil } return os.Symlink(oldname, linkName) } } func initFS(root string) error { st, err := os.Stat(root) if err != nil { return err } stat := st.Sys().(*syscall.Stat_t) uid := int(stat.Uid) gid := int(stat.Gid) initFuncs := []initializerFunc{ createDirectory("/dev", uid, gid), createDirectory("/dev/pts", uid, gid), createDirectory("/dev/shm", uid, gid), touchFile("/dev/console", uid, gid), createDirectory("/proc", uid, gid), createDirectory("/sys", uid, gid), createDirectory("/etc", uid, gid), touchFile("/etc/resolv.conf", uid, gid), touchFile("/etc/hosts", uid, gid), touchFile("/etc/hostname", uid, gid), symlink("/proc/mounts", "/etc/mtab"), } for _, fn := range initFuncs { if err := fn(root); err != nil { return err } } return nil }