- struct stat stats;
- char target[UTIL_PATH_SIZE];
- char *s;
- size_t l;
- char slink_tmp[UTIL_PATH_SIZE + sizeof(TMP_FILE_EXT)];
- int i = 0;
- int tail = 0;
- int err = 0;
-
- /* use relative link */
- target[0] = '\0';
- while (node[i] && (node[i] == slink[i])) {
- if (node[i] == '/')
- tail = i+1;
- i++;
- }
- s = target;
- l = sizeof(target);
- while (slink[i] != '\0') {
- if (slink[i] == '/')
- l = util_strpcpy(&s, l, "../");
- i++;
- }
- l = util_strscpy(s, l, &node[tail]);
- if (l == 0) {
- err = -EINVAL;
- goto exit;
- }
-
- /* preserve link with correct target, do not replace node of other device */
- if (lstat(slink, &stats) == 0) {
- if (S_ISBLK(stats.st_mode) || S_ISCHR(stats.st_mode)) {
- struct stat stats2;
-
- info(udev, "found existing node instead of symlink '%s'\n", slink);
- if (lstat(node, &stats2) == 0) {
- if ((stats.st_mode & S_IFMT) == (stats2.st_mode & S_IFMT) &&
- stats.st_rdev == stats2.st_rdev && stats.st_ino != stats2.st_ino) {
- info(udev, "replace device node '%s' with symlink to our node '%s'\n",
- slink, node);
- } else {
- err(udev, "device node '%s' already exists, "
- "link to '%s' will not overwrite it\n",
- slink, node);
- goto exit;
- }
- }
- } else if (S_ISLNK(stats.st_mode)) {
- char buf[UTIL_PATH_SIZE];
- int len;
-
- dbg(udev, "found existing symlink '%s'\n", slink);
- len = readlink(slink, buf, sizeof(buf));
- if (len > 0 && len < (int)sizeof(buf)) {
- buf[len] = '\0';
- if (strcmp(target, buf) == 0) {
- info(udev, "preserve already existing symlink '%s' to '%s'\n",
- slink, target);
- udev_selinux_lsetfilecon(udev, slink, S_IFLNK);
- utimensat(AT_FDCWD, slink, NULL, AT_SYMLINK_NOFOLLOW);
- goto exit;
- }
- }
- }
- } else {
- info(udev, "creating symlink '%s' to '%s'\n", slink, target);
- do {
- err = util_create_path_selinux(udev, slink);
- if (err != 0 && err != -ENOENT)
- break;
- udev_selinux_setfscreatecon(udev, slink, S_IFLNK);
- err = symlink(target, slink);
- if (err != 0)
- err = -errno;
- udev_selinux_resetfscreatecon(udev);
- } while (err == -ENOENT);
- if (err == 0)
- goto exit;
- }
-
- info(udev, "atomically replace '%s'\n", slink);
- util_strscpyl(slink_tmp, sizeof(slink_tmp), slink, TMP_FILE_EXT, NULL);
- unlink(slink_tmp);
- do {
- err = util_create_path_selinux(udev, slink_tmp);
- if (err != 0 && err != -ENOENT)
- break;
- udev_selinux_setfscreatecon(udev, slink_tmp, S_IFLNK);
- err = symlink(target, slink_tmp);
- if (err != 0)
- err = -errno;
- udev_selinux_resetfscreatecon(udev);
- } while (err == -ENOENT);
- if (err != 0) {
- err(udev, "symlink '%s' '%s' failed: %m\n", target, slink_tmp);
- goto exit;
- }
- err = rename(slink_tmp, slink);
- if (err != 0) {
- err(udev, "rename '%s' '%s' failed: %m\n", slink_tmp, slink);
- unlink(slink_tmp);
- }
+ struct stat stats;
+ char target[UTIL_PATH_SIZE];
+ char *s;
+ size_t l;
+ char slink_tmp[UTIL_PATH_SIZE + sizeof(TMP_FILE_EXT)];
+ int i = 0;
+ int tail = 0;
+ int err = 0;
+
+ /* use relative link */
+ target[0] = '\0';
+ while (node[i] && (node[i] == slink[i])) {
+ if (node[i] == '/')
+ tail = i+1;
+ i++;
+ }
+ s = target;
+ l = sizeof(target);
+ while (slink[i] != '\0') {
+ if (slink[i] == '/')
+ l = util_strpcpy(&s, l, "../");
+ i++;
+ }
+ l = util_strscpy(s, l, &node[tail]);
+ if (l == 0) {
+ err = -EINVAL;
+ goto exit;
+ }
+
+ /* preserve link with correct target, do not replace node of other device */
+ if (lstat(slink, &stats) == 0) {
+ if (S_ISBLK(stats.st_mode) || S_ISCHR(stats.st_mode)) {
+ struct stat stats2;
+
+ info(udev, "found existing node instead of symlink '%s'\n", slink);
+ if (lstat(node, &stats2) == 0) {
+ if ((stats.st_mode & S_IFMT) == (stats2.st_mode & S_IFMT) &&
+ stats.st_rdev == stats2.st_rdev && stats.st_ino != stats2.st_ino) {
+ info(udev, "replace device node '%s' with symlink to our node '%s'\n",
+ slink, node);
+ } else {
+ err(udev, "device node '%s' already exists, "
+ "link to '%s' will not overwrite it\n",
+ slink, node);
+ goto exit;
+ }
+ }
+ } else if (S_ISLNK(stats.st_mode)) {
+ char buf[UTIL_PATH_SIZE];
+ int len;
+
+ dbg(udev, "found existing symlink '%s'\n", slink);
+ len = readlink(slink, buf, sizeof(buf));
+ if (len > 0 && len < (int)sizeof(buf)) {
+ buf[len] = '\0';
+ if (strcmp(target, buf) == 0) {
+ info(udev, "preserve already existing symlink '%s' to '%s'\n",
+ slink, target);
+ udev_selinux_lsetfilecon(udev, slink, S_IFLNK);
+ utimensat(AT_FDCWD, slink, NULL, AT_SYMLINK_NOFOLLOW);
+ goto exit;
+ }
+ }
+ }
+ } else {
+ info(udev, "creating symlink '%s' to '%s'\n", slink, target);
+ do {
+ err = util_create_path_selinux(udev, slink);
+ if (err != 0 && err != -ENOENT)
+ break;
+ udev_selinux_setfscreatecon(udev, slink, S_IFLNK);
+ err = symlink(target, slink);
+ if (err != 0)
+ err = -errno;
+ udev_selinux_resetfscreatecon(udev);
+ } while (err == -ENOENT);
+ if (err == 0)
+ goto exit;
+ }
+
+ info(udev, "atomically replace '%s'\n", slink);
+ util_strscpyl(slink_tmp, sizeof(slink_tmp), slink, TMP_FILE_EXT, NULL);
+ unlink(slink_tmp);
+ do {
+ err = util_create_path_selinux(udev, slink_tmp);
+ if (err != 0 && err != -ENOENT)
+ break;
+ udev_selinux_setfscreatecon(udev, slink_tmp, S_IFLNK);
+ err = symlink(target, slink_tmp);
+ if (err != 0)
+ err = -errno;
+ udev_selinux_resetfscreatecon(udev);
+ } while (err == -ENOENT);
+ if (err != 0) {
+ err(udev, "symlink '%s' '%s' failed: %m\n", target, slink_tmp);
+ goto exit;
+ }
+ err = rename(slink_tmp, slink);
+ if (err != 0) {
+ err(udev, "rename '%s' '%s' failed: %m\n", slink_tmp, slink);
+ unlink(slink_tmp);
+ }