-int udev_node_mknod(struct udev_device *dev, const char *file, mode_t mode, uid_t uid, gid_t gid)
-{
- struct udev *udev = udev_device_get_udev(dev);
- dev_t devnum = udev_device_get_devnum(dev);
- struct stat stats;
- int err = 0;
-
-
- if (strcmp(udev_device_get_subsystem(dev), "block") == 0)
- mode |= S_IFBLK;
- else
- mode |= S_IFCHR;
-
- if (file == NULL)
- file = udev_device_get_devnode(dev);
-
- if (lstat(file, &stats) == 0) {
- if (((stats.st_mode & S_IFMT) == (mode & S_IFMT)) && (stats.st_rdev == devnum)) {
- info(udev, "preserve file '%s', because it has correct dev_t\n", file);
- if ((stats.st_mode & 0777) != (mode & 0777) || stats.st_uid != uid || stats.st_gid != gid) {
- /* preserve 'sticky' bit, if already set */
- mode |= stats.st_mode & 01000;
- info(udev, "set permissions %s, %#o, uid=%u, gid=%u\n", file, mode, uid, gid);
- chmod(file, mode);
- chown(file, uid, gid);
- } else {
- info(udev, "preserve permissions %s, %#o, uid=%u, gid=%u\n", file, mode, uid, gid);
- }
- /*
- * Set initial selinux file context only on add events.
- * We set the proper context on bootup (triger) or for newly
- * added devices, but we don't change it later, in case
- * something else has set a custom context in the meantime.
- */
- if (strcmp(udev_device_get_action(dev), "add") == 0)
- udev_selinux_lsetfilecon(udev, file, mode);
- /* always update timestamp when we re-use the node, like on media change events */
- utimensat(AT_FDCWD, file, NULL, 0);
- } else {
- char file_tmp[UTIL_PATH_SIZE + sizeof(TMP_FILE_EXT)];
-
- info(udev, "atomically replace existing file '%s'\n", file);
- util_strscpyl(file_tmp, sizeof(file_tmp), file, TMP_FILE_EXT, NULL);
- unlink(file_tmp);
- udev_selinux_setfscreatecon(udev, file_tmp, mode);
- err = mknod(file_tmp, mode, devnum);
- udev_selinux_resetfscreatecon(udev);
- if (err != 0) {
- err(udev, "mknod '%s' %u:%u %#o failed: %m\n",
- file_tmp, major(devnum), minor(devnum), mode);
- goto exit;
- }
- err = rename(file_tmp, file);
- if (err != 0) {
- err(udev, "rename '%s' '%s' failed: %m\n", file_tmp, file);
- unlink(file_tmp);
- goto exit;
- }
- info(udev, "set permissions '%s' %#o uid=%u gid=%u\n", file, mode, uid, gid);
- chmod(file, mode);
- chown(file, uid, gid);
- }
- } else {
- info(udev, "mknod '%s' %u:%u %#o\n", file, major(devnum), minor(devnum), mode);
- do {
- err = util_create_path_selinux(udev, file);
- if (err != 0 && err != -ENOENT)
- break;
- udev_selinux_setfscreatecon(udev, file, mode);
- err = mknod(file, mode, devnum);
- if (err != 0)
- err = -errno;
- udev_selinux_resetfscreatecon(udev);
- } while (err == -ENOENT);
- if (err != 0 && err != -EEXIST)
- err(udev, "mknod '%s' %u:%u %#o' failed: %m\n", file, major(devnum), minor(devnum), mode);
- info(udev, "set permissions '%s' %#o uid=%u gid=%u\n", file, mode, uid, gid);
- chmod(file, mode);
- chown(file, uid, gid);
- }
-exit:
- return err;
-}
-