- if (lstat(file, &stats) != 0)
- goto create;
-
- /* preserve node with already correct numbers, to prevent changing the inode number */
- if ((stats.st_mode & S_IFMT) == (mode & S_IFMT) && (stats.st_rdev == devt)) {
- info("preserve file '%s', because it has correct dev_t", file);
- selinux_setfilecon(file, udev->dev->kernel, stats.st_mode);
- goto perms;
- }
-
- if (unlink(file) != 0)
- err("unlink(%s) failed: %s", file, strerror(errno));
- else
- dbg("already present file '%s' unlinked", file);
-
-create:
- selinux_setfscreatecon(file, udev->dev->kernel, mode);
- retval = mknod(file, mode, devt);
- selinux_resetfscreatecon();
- if (retval != 0) {
- err("mknod(%s, %#o, %u, %u) failed: %s",
- file, mode, major(devt), minor(devt), strerror(errno));
- goto exit;
+ if (lstat(file, &stats) == 0) {
+ if (((stats.st_mode & S_IFMT) == (mode & S_IFMT)) && (stats.st_rdev == devt)) {
+ info("preserve file '%s', because it has correct dev_t\n", file);
+ preserve = 1;
+ selinux_setfilecon(file, udev->dev->kernel, mode);
+ } else {
+ info("atomically replace existing file '%s'\n", file);
+ strlcpy(file_tmp, file, sizeof(file_tmp));
+ strlcat(file_tmp, TMP_FILE_EXT, sizeof(file_tmp));
+ unlink(file_tmp);
+ selinux_setfscreatecon(file_tmp, udev->dev->kernel, mode);
+ err = mknod(file_tmp, mode, devt);
+ selinux_resetfscreatecon();
+ if (err != 0) {
+ err("mknod(%s, %#o, %u, %u) failed: %s\n",
+ file_tmp, mode, major(devt), minor(devt), strerror(errno));
+ goto exit;
+ }
+ err = rename(file_tmp, file);
+ if (err != 0) {
+ err("rename(%s, %s) failed: %s\n",
+ file_tmp, file, strerror(errno));
+ unlink(file_tmp);
+ }
+ }
+ } else {
+ info("mknod(%s, %#o, (%u,%u))\n", file, mode, major(devt), minor(devt));
+ selinux_setfscreatecon(file, udev->dev->kernel, mode);
+ err = mknod(file, mode, devt);
+ selinux_resetfscreatecon();
+ if (err != 0) {
+ err("mknod(%s, %#o, (%u,%u) failed: %s\n",
+ file, mode, major(devt), minor(devt), strerror(errno));
+ goto exit;
+ }