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

 

posted on 2020-11-18 15:21  tycoon3  阅读(168)  评论(0编辑  收藏  举报

导航