- /* look if symlink already exists */
- len = readlink(slink, buf, sizeof(buf));
- if (len > 0) {
- buf[len] = '\0';
- if (strcmp(target, buf) == 0) {
- info("preserve already existing symlink '%s' to '%s'", slink, target);
- selinux_setfilecon(slink, NULL, S_IFLNK);
- 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("found existing node instead of symlink '%s'", slink);
+ if (lstat(node, &stats2) == 0) {
+ if ((stats.st_mode & S_IFMT) == (stats2.st_mode & S_IFMT) &&
+ stats.st_rdev == stats2.st_rdev) {
+ info("replace device node '%s' with symlink to our node '%s'", slink, node);
+ } else {
+ err("device node '%s' already exists, link to '%s' will not overwrite it", slink, node);
+ goto exit;
+ }
+ }
+ } else if (S_ISLNK(stats.st_mode)) {
+ char buf[PATH_SIZE];
+
+ info("found existing symlink '%s'", slink);
+ len = readlink(slink, buf, sizeof(buf));
+ if (len > 0) {
+ buf[len] = '\0';
+ if (strcmp(target, buf) == 0) {
+ info("preserve already existing symlink '%s' to '%s'", slink, target);
+ selinux_setfilecon(slink, NULL, S_IFLNK);
+ goto exit;
+ }
+ }