prepareRootfs +createDevices
// prepareRootfs sets up the devices, mount points, and filesystems for use // inside a new mount namespace. It doesn't set anything as ro. You must call // finalizeRootfs after this function to finish setting up the rootfs. func prepareRootfs(pipe io.ReadWriter, iConfig *initConfig) (err error) { config := iConfig.Config if err := prepareRoot(config); err != nil { return newSystemErrorWithCause(err, "preparing rootfs") } hasCgroupns := config.Namespaces.Contains(configs.NEWCGROUP) setupDev := needsSetupDev(config) for _, m := range config.Mounts { for _, precmd := range m.PremountCmds { if err := mountCmd(precmd); err != nil { return newSystemErrorWithCause(err, "running premount command") } } if err := mountToRootfs(m, config.Rootfs, config.MountLabel, hasCgroupns); err != nil { return newSystemErrorWithCausef(err, "mounting %q to rootfs %q at %q", m.Source, config.Rootfs, m.Destination) } for _, postcmd := range m.PostmountCmds { if err := mountCmd(postcmd); err != nil { return newSystemErrorWithCause(err, "running postmount command") } } } if setupDev { if err := createDevices(config); err != nil { return newSystemErrorWithCause(err, "creating device nodes") } if err := setupPtmx(config); err != nil { return newSystemErrorWithCause(err, "setting up ptmx") } if err := setupDevSymlinks(config.Rootfs); err != nil { return newSystemErrorWithCause(err, "setting up /dev symlinks") } }
// Create the device nodes in the container. func createDevices(config *configs.Config) error { useBindMount := system.RunningInUserNS() || config.Namespaces.Contains(configs.NEWUSER) oldMask := unix.Umask(0000) for _, node := range config.Devices { // containers running in a user namespace are not allowed to mknod // devices so we can just bind mount it from the host. if err := createDeviceNode(config.Rootfs, node, useBindMount); err != nil { unix.Umask(oldMask) return err } } unix.Umask(oldMask) return nil }
// Creates the device node in the rootfs of the container. func createDeviceNode(rootfs string, node *configs.Device, bind bool) error { dest := filepath.Join(rootfs, node.Path) if err := os.MkdirAll(filepath.Dir(dest), 0755); err != nil { return err } if bind { return bindMountDeviceNode(dest, node) } if err := mknodDevice(dest, node); err != nil { if os.IsExist(err) { return nil } else if os.IsPermission(err) { return bindMountDeviceNode(dest, node) } return err } return nil } func mknodDevice(dest string, node *configs.Device) error { fileMode := node.FileMode switch node.Type { case 'c', 'u': fileMode |= unix.S_IFCHR case 'b': fileMode |= unix.S_IFBLK case 'p': fileMode |= unix.S_IFIFO default: return fmt.Errorf("%c is not a valid device type for device %s", node.Type, node.Path) } if err := unix.Mknod(dest, uint32(fileMode), node.Mkdev()); err != nil { return err } return unix.Chown(dest, int(node.Uid), int(node.Gid)) }
- switch { - case mode&unix.S_IFBLK == unix.S_IFBLK: + switch mode & unix.S_IFMT { + case unix.S_IFBLK: devType = configs.BlockDevice - case mode&unix.S_IFCHR == unix.S_IFCHR: + case unix.S_IFCHR: devType = configs.CharDevice - case mode&unix.S_IFIFO == unix.S_IFIFO: + case unix.S_IFIFO: devType = configs.FifoDevice default: return nil, ErrNotADevice
// include/uapi/linux/stat.h #define S_ISLNK(m) (((m) & S_IFMT) == S_IFLNK) #define S_ISREG(m) (((m) & S_IFMT) == S_IFREG) #define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR) #define S_ISCHR(m) (((m) & S_IFMT) == S_IFCHR) #define S_ISBLK(m) (((m) & S_IFMT) == S_IFBLK) #define S_ISFIFO(m) (((m) & S_IFMT) == S_IFIFO) #define S_ISSOCK(m) (((m) & S_IFMT) == S_IFSOCK)
'm running a GUI app inside Docker on Raspberry Pi. I need to use keyboard in that app. So far I got to the point, where I run the container as privileged and I mount /run/udev to it which enables detection of the keyboard even when it's disconnected and reconnected again. docker run -d --privileged -v /run/udev:/run/udev:ro <image> Because it's privileged, if I exec into the container, I can see the keyboard devices: ls /dev/input by-id by-path event0 event1 event2 event3 event4 event5 mice mouse0 mouse1 However, if I first start the container with no keyboard connected and then connect the keyboard, these devices won't show up in the container and I can't use the keyboard: ls /dev/input event0 mice mouse0