]>
Commit | Line | Data |
---|---|---|
ea733a2f | 1 | /* |
0ec5b5e1 | 2 | * Copyright (C) 2003-2010 Kay Sievers <kay.sievers@vrfy.org> |
ea733a2f | 3 | * |
55e9959b KS |
4 | * This program is free software: you can redistribute it and/or modify |
5 | * it under the terms of the GNU General Public License as published by | |
6 | * the Free Software Foundation, either version 2 of the License, or | |
7 | * (at your option) any later version. | |
ea733a2f | 8 | * |
55e9959b KS |
9 | * This program is distributed in the hope that it will be useful, |
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
12 | * GNU General Public License for more details. | |
13 | * | |
14 | * You should have received a copy of the GNU General Public License | |
15 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | |
ea733a2f GKH |
16 | */ |
17 | ||
18 | #include <stdlib.h> | |
19 | #include <string.h> | |
20 | #include <stdio.h> | |
1aa1e248 | 21 | #include <stddef.h> |
6c29f2b9 | 22 | #include <stdbool.h> |
ea733a2f GKH |
23 | #include <fcntl.h> |
24 | #include <unistd.h> | |
25 | #include <errno.h> | |
67f69ae1 | 26 | #include <grp.h> |
24f0605c | 27 | #include <dirent.h> |
56073914 | 28 | #include <sys/time.h> |
32ff5bca | 29 | #include <sys/stat.h> |
10950dfe | 30 | #include <sys/types.h> |
ea733a2f GKH |
31 | |
32 | #include "udev.h" | |
9825617b | 33 | |
e54f0b4a | 34 | #define TMP_FILE_EXT ".udev-tmp" |
ea733a2f | 35 | |
c7cdd8b2 | 36 | int udev_node_mknod(struct udev_device *dev, const char *file, mode_t mode, uid_t uid, gid_t gid) |
aa8734ff KS |
37 | { |
38 | struct udev *udev = udev_device_get_udev(dev); | |
c7cdd8b2 | 39 | dev_t devnum = udev_device_get_devnum(dev); |
49747bdc | 40 | struct stat stats; |
0cd9f451 | 41 | int err = 0; |
49747bdc | 42 | |
aa8734ff KS |
43 | |
44 | if (strcmp(udev_device_get_subsystem(dev), "block") == 0) | |
57663b36 | 45 | mode |= S_IFBLK; |
1aa1e248 | 46 | else |
57663b36 | 47 | mode |= S_IFCHR; |
57663b36 | 48 | |
cb14f454 | 49 | if (file == NULL) |
aa8734ff KS |
50 | file = udev_device_get_devnode(dev); |
51 | ||
e54f0b4a | 52 | if (lstat(file, &stats) == 0) { |
aa8734ff KS |
53 | if (((stats.st_mode & S_IFMT) == (mode & S_IFMT)) && (stats.st_rdev == devnum)) { |
54 | info(udev, "preserve file '%s', because it has correct dev_t\n", file); | |
578cc8a8 KS |
55 | if (stats.st_mode != mode || stats.st_uid != uid || stats.st_gid != gid) { |
56 | info(udev, "set permissions %s, %#o, uid=%u, gid=%u\n", file, mode, uid, gid); | |
57 | chmod(file, mode); | |
58 | chown(file, uid, gid); | |
578cc8a8 KS |
59 | } else { |
60 | info(udev, "preserve permissions %s, %#o, uid=%u, gid=%u\n", file, mode, uid, gid); | |
61 | } | |
326c5fc3 KS |
62 | /* |
63 | * Set initial selinux file context only on add events. | |
64 | * We set the proper context on bootup (triger) or for newly | |
65 | * added devices, but we don't change it later, in case | |
66 | * something else has set a custom context in the meantime. | |
67 | */ | |
68 | if (strcmp(udev_device_get_action(dev), "add") == 0) | |
69 | udev_selinux_lsetfilecon(udev, file, mode); | |
578cc8a8 | 70 | /* always update timestamp when we re-use the node, like on media change events */ |
455f792e | 71 | utimensat(AT_FDCWD, file, NULL, 0); |
0cd9f451 | 72 | } else { |
540f4669 KS |
73 | char file_tmp[UTIL_PATH_SIZE + sizeof(TMP_FILE_EXT)]; |
74 | ||
aa8734ff | 75 | info(udev, "atomically replace existing file '%s'\n", file); |
065db052 | 76 | util_strscpyl(file_tmp, sizeof(file_tmp), file, TMP_FILE_EXT, NULL); |
0cd9f451 | 77 | unlink(file_tmp); |
aa8734ff KS |
78 | udev_selinux_setfscreatecon(udev, file_tmp, mode); |
79 | err = mknod(file_tmp, mode, devnum); | |
80 | udev_selinux_resetfscreatecon(udev); | |
0cd9f451 | 81 | if (err != 0) { |
761dfddc KS |
82 | err(udev, "mknod '%s' %u:%u %#o failed: %m\n", |
83 | file_tmp, major(devnum), minor(devnum), mode); | |
0cd9f451 KS |
84 | goto exit; |
85 | } | |
86 | err = rename(file_tmp, file); | |
87 | if (err != 0) { | |
761dfddc | 88 | err(udev, "rename '%s' '%s' failed: %m\n", file_tmp, file); |
0cd9f451 | 89 | unlink(file_tmp); |
578cc8a8 | 90 | goto exit; |
0cd9f451 | 91 | } |
761dfddc | 92 | info(udev, "set permissions '%s' %#o uid=%u gid=%u\n", file, mode, uid, gid); |
578cc8a8 KS |
93 | chmod(file, mode); |
94 | chown(file, uid, gid); | |
e54f0b4a | 95 | } |
678484af | 96 | } else { |
761dfddc | 97 | info(udev, "mknod '%s' %u:%u %#o\n", file, major(devnum), minor(devnum), mode); |
b6a26375 | 98 | do { |
51f43b53 | 99 | err = util_create_path_selinux(udev, file); |
6834a442 KS |
100 | if (err != 0 && err != -ENOENT) |
101 | break; | |
b6a26375 KS |
102 | udev_selinux_setfscreatecon(udev, file, mode); |
103 | err = mknod(file, mode, devnum); | |
104 | if (err != 0) | |
6834a442 | 105 | err = -errno; |
b6a26375 | 106 | udev_selinux_resetfscreatecon(udev); |
6834a442 | 107 | } while (err == -ENOENT); |
578cc8a8 | 108 | if (err != 0) |
761dfddc KS |
109 | err(udev, "mknod '%s' %u:%u %#o' failed: %m\n", file, major(devnum), minor(devnum), mode); |
110 | info(udev, "set permissions '%s' %#o uid=%u gid=%u\n", file, mode, uid, gid); | |
578cc8a8 KS |
111 | chmod(file, mode); |
112 | chown(file, uid, gid); | |
50e5de03 | 113 | } |
bbbe503e | 114 | exit: |
0cd9f451 | 115 | return err; |
50e5de03 KS |
116 | } |
117 | ||
aa8734ff | 118 | static int node_symlink(struct udev *udev, const char *node, const char *slink) |
fa33d857 | 119 | { |
e54f0b4a | 120 | struct stat stats; |
1822e9b0 | 121 | char target[UTIL_PATH_SIZE]; |
065db052 KS |
122 | char *s; |
123 | size_t l; | |
17fcfb59 | 124 | char slink_tmp[UTIL_PATH_SIZE + sizeof(TMP_FILE_EXT)]; |
27d4bf18 KS |
125 | int i = 0; |
126 | int tail = 0; | |
aa8734ff | 127 | int err = 0; |
fa33d857 | 128 | |
27d4bf18 | 129 | /* use relative link */ |
1822e9b0 | 130 | target[0] = '\0'; |
27d4bf18 KS |
131 | while (node[i] && (node[i] == slink[i])) { |
132 | if (node[i] == '/') | |
133 | tail = i+1; | |
134 | i++; | |
135 | } | |
065db052 KS |
136 | s = target; |
137 | l = sizeof(target); | |
27d4bf18 KS |
138 | while (slink[i] != '\0') { |
139 | if (slink[i] == '/') | |
065db052 | 140 | l = util_strpcpy(&s, l, "../"); |
27d4bf18 KS |
141 | i++; |
142 | } | |
065db052 KS |
143 | l = util_strscpy(s, l, &node[tail]); |
144 | if (l == 0) { | |
145 | err = -EINVAL; | |
146 | goto exit; | |
147 | } | |
27d4bf18 | 148 | |
e54f0b4a KS |
149 | /* preserve link with correct target, do not replace node of other device */ |
150 | if (lstat(slink, &stats) == 0) { | |
151 | if (S_ISBLK(stats.st_mode) || S_ISCHR(stats.st_mode)) { | |
152 | struct stat stats2; | |
153 | ||
aa8734ff | 154 | info(udev, "found existing node instead of symlink '%s'\n", slink); |
e54f0b4a KS |
155 | if (lstat(node, &stats2) == 0) { |
156 | if ((stats.st_mode & S_IFMT) == (stats2.st_mode & S_IFMT) && | |
6c29f2b9 | 157 | stats.st_rdev == stats2.st_rdev && stats.st_ino != stats2.st_ino) { |
aa8734ff KS |
158 | info(udev, "replace device node '%s' with symlink to our node '%s'\n", |
159 | slink, node); | |
e54f0b4a | 160 | } else { |
aa8734ff KS |
161 | err(udev, "device node '%s' already exists, " |
162 | "link to '%s' will not overwrite it\n", | |
163 | slink, node); | |
e54f0b4a KS |
164 | goto exit; |
165 | } | |
166 | } | |
167 | } else if (S_ISLNK(stats.st_mode)) { | |
17fcfb59 | 168 | char buf[UTIL_PATH_SIZE]; |
065db052 | 169 | int len; |
e54f0b4a | 170 | |
5755d586 | 171 | dbg(udev, "found existing symlink '%s'\n", slink); |
60067cc7 KS |
172 | len = readlink(slink, buf, sizeof(buf)); |
173 | if (len > 0 && len < (int)sizeof(buf)) { | |
e54f0b4a KS |
174 | buf[len] = '\0'; |
175 | if (strcmp(target, buf) == 0) { | |
aa8734ff KS |
176 | info(udev, "preserve already existing symlink '%s' to '%s'\n", |
177 | slink, target); | |
178 | udev_selinux_lsetfilecon(udev, slink, S_IFLNK); | |
455f792e | 179 | utimensat(AT_FDCWD, slink, NULL, AT_SYMLINK_NOFOLLOW); |
e54f0b4a KS |
180 | goto exit; |
181 | } | |
182 | } | |
fa33d857 | 183 | } |
678484af | 184 | } else { |
aa8734ff | 185 | info(udev, "creating symlink '%s' to '%s'\n", slink, target); |
b6a26375 | 186 | do { |
51f43b53 | 187 | err = util_create_path_selinux(udev, slink); |
6834a442 KS |
188 | if (err != 0 && err != -ENOENT) |
189 | break; | |
b6a26375 KS |
190 | udev_selinux_setfscreatecon(udev, slink, S_IFLNK); |
191 | err = symlink(target, slink); | |
192 | if (err != 0) | |
6834a442 | 193 | err = -errno; |
b6a26375 | 194 | udev_selinux_resetfscreatecon(udev); |
6834a442 | 195 | } while (err == -ENOENT); |
aa8734ff | 196 | if (err == 0) |
678484af | 197 | goto exit; |
fa33d857 KS |
198 | } |
199 | ||
aa8734ff | 200 | info(udev, "atomically replace '%s'\n", slink); |
065db052 | 201 | util_strscpyl(slink_tmp, sizeof(slink_tmp), slink, TMP_FILE_EXT, NULL); |
14c79942 | 202 | unlink(slink_tmp); |
b6a26375 | 203 | do { |
51f43b53 | 204 | err = util_create_path_selinux(udev, slink_tmp); |
6834a442 KS |
205 | if (err != 0 && err != -ENOENT) |
206 | break; | |
207 | udev_selinux_setfscreatecon(udev, slink_tmp, S_IFLNK); | |
b6a26375 KS |
208 | err = symlink(target, slink_tmp); |
209 | if (err != 0) | |
6834a442 | 210 | err = -errno; |
b6a26375 | 211 | udev_selinux_resetfscreatecon(udev); |
6834a442 | 212 | } while (err == -ENOENT); |
aa8734ff | 213 | if (err != 0) { |
761dfddc | 214 | err(udev, "symlink '%s' '%s' failed: %m\n", target, slink_tmp); |
e54f0b4a KS |
215 | goto exit; |
216 | } | |
aa8734ff KS |
217 | err = rename(slink_tmp, slink); |
218 | if (err != 0) { | |
761dfddc | 219 | err(udev, "rename '%s' '%s' failed: %m\n", slink_tmp, slink); |
e54f0b4a | 220 | unlink(slink_tmp); |
e54f0b4a | 221 | } |
fa33d857 | 222 | exit: |
aa8734ff | 223 | return err; |
fa33d857 KS |
224 | } |
225 | ||
6c29f2b9 KS |
226 | /* find device node of device with highest priority */ |
227 | static const char *link_find_prioritized(struct udev_device *dev, bool add, const char *stackdir, char *buf, size_t bufsize) | |
24f0605c | 228 | { |
6c29f2b9 | 229 | struct udev *udev = udev_device_get_udev(dev); |
aa8734ff | 230 | DIR *dir; |
6c29f2b9 KS |
231 | int priority = 0; |
232 | const char *target = NULL; | |
233 | ||
234 | if (add) { | |
235 | priority = udev_device_get_devlink_priority(dev); | |
236 | util_strscpy(buf, bufsize, udev_device_get_devnode(dev)); | |
237 | target = buf; | |
aa8734ff | 238 | } |
7db6580f | 239 | |
6c29f2b9 KS |
240 | dir = opendir(stackdir); |
241 | if (dir == NULL) | |
242 | return target; | |
243 | for (;;) { | |
244 | struct udev_device *dev_db; | |
2ffc9cc1 | 245 | struct dirent *dent; |
aa8734ff | 246 | |
2ffc9cc1 KS |
247 | dent = readdir(dir); |
248 | if (dent == NULL || dent->d_name[0] == '\0') | |
aa8734ff | 249 | break; |
2ffc9cc1 | 250 | if (dent->d_name[0] == '.') |
aa8734ff | 251 | continue; |
cad40a5f KS |
252 | |
253 | info(udev, "found '%s' claiming '%s'\n", dent->d_name, stackdir); | |
6c29f2b9 KS |
254 | |
255 | /* did we find ourself? */ | |
cad40a5f | 256 | if (strcmp(dent->d_name, udev_device_get_id_filename(dev)) == 0) |
6c29f2b9 KS |
257 | continue; |
258 | ||
cad40a5f | 259 | dev_db = udev_device_new_from_id_filename(udev, dent->d_name); |
6c29f2b9 KS |
260 | if (dev_db != NULL) { |
261 | const char *devnode; | |
262 | ||
263 | devnode = udev_device_get_devnode(dev_db); | |
264 | if (devnode != NULL) { | |
265 | dbg(udev, "compare priority of '%s'(%i) > '%s'(%i)\n", target, priority, | |
266 | udev_device_get_devnode(dev_db), udev_device_get_devlink_priority(dev_db)); | |
267 | if (target == NULL || udev_device_get_devlink_priority(dev_db) > priority) { | |
268 | info(udev, "'%s' claims priority %i for '%s'\n", | |
af24bb17 | 269 | udev_device_get_syspath(dev_db), udev_device_get_devlink_priority(dev_db), stackdir); |
6c29f2b9 KS |
270 | priority = udev_device_get_devlink_priority(dev_db); |
271 | util_strscpy(buf, bufsize, devnode); | |
272 | target = buf; | |
273 | } | |
274 | } | |
275 | udev_device_unref(dev_db); | |
276 | } | |
aa8734ff | 277 | } |
495d408b | 278 | closedir(dir); |
6c29f2b9 | 279 | return target; |
aa8734ff KS |
280 | } |
281 | ||
6c29f2b9 KS |
282 | /* manage "stack of names" with possibly specified device priorities */ |
283 | static void link_update(struct udev_device *dev, const char *slink, bool add) | |
aa8734ff KS |
284 | { |
285 | struct udev *udev = udev_device_get_udev(dev); | |
6c29f2b9 KS |
286 | char name_enc[UTIL_PATH_SIZE]; |
287 | char filename[UTIL_PATH_SIZE * 2]; | |
288 | char dirname[UTIL_PATH_SIZE]; | |
289 | const char *target; | |
290 | char buf[UTIL_PATH_SIZE]; | |
24f0605c | 291 | |
5755d586 | 292 | dbg(udev, "update symlink '%s' of '%s'\n", slink, udev_device_get_syspath(dev)); |
24f0605c | 293 | |
6c29f2b9 | 294 | util_path_encode(&slink[strlen(udev_get_dev_path(udev))+1], name_enc, sizeof(name_enc)); |
4ec9c3e7 | 295 | util_strscpyl(dirname, sizeof(dirname), udev_get_run_path(udev), "/links/", name_enc, NULL); |
4281da1f | 296 | util_strscpyl(filename, sizeof(filename), dirname, "/", udev_device_get_id_filename(dev), NULL); |
6c29f2b9 KS |
297 | |
298 | if (!add) { | |
299 | dbg(udev, "removing index: '%s'\n", filename); | |
8e5a620b KS |
300 | if (unlink(filename) == 0) |
301 | rmdir(dirname); | |
6c29f2b9 | 302 | } |
24f0605c | 303 | |
6c29f2b9 KS |
304 | target = link_find_prioritized(dev, add, dirname, buf, sizeof(buf)); |
305 | if (target == NULL) { | |
aa8734ff | 306 | info(udev, "no reference left, remove '%s'\n", slink); |
8e5a620b KS |
307 | if (unlink(slink) == 0) |
308 | util_delete_path(udev, slink); | |
6c29f2b9 | 309 | } else { |
6c29f2b9 KS |
310 | info(udev, "creating link '%s' to '%s'\n", slink, target); |
311 | node_symlink(udev, target, slink); | |
24f0605c | 312 | } |
24f0605c | 313 | |
6c29f2b9 | 314 | if (add) { |
6834a442 KS |
315 | int err; |
316 | ||
6c29f2b9 | 317 | dbg(udev, "creating index: '%s'\n", filename); |
b6a26375 | 318 | do { |
af24bb17 KS |
319 | int fd; |
320 | ||
6834a442 KS |
321 | err = util_create_path(udev, filename); |
322 | if (err != 0 && err != -ENOENT) | |
323 | break; | |
24d10766 | 324 | fd = open(filename, O_WRONLY|O_CREAT|O_CLOEXEC|O_TRUNC|O_NOFOLLOW, 0444); |
af24bb17 KS |
325 | if (fd >= 0) |
326 | close(fd); | |
327 | else | |
6834a442 KS |
328 | err = -errno; |
329 | } while (err == -ENOENT); | |
24f0605c | 330 | } |
24f0605c KS |
331 | } |
332 | ||
ec2dd02e | 333 | void udev_node_update_old_links(struct udev_device *dev, struct udev_device *dev_old) |
24f0605c | 334 | { |
aa8734ff KS |
335 | struct udev *udev = udev_device_get_udev(dev); |
336 | struct udev_list_entry *list_entry; | |
aa8734ff KS |
337 | |
338 | /* update possible left-over symlinks */ | |
339 | udev_list_entry_foreach(list_entry, udev_device_get_devlinks_list_entry(dev_old)) { | |
6e0cb78c | 340 | const char *name = udev_list_entry_get_name(list_entry); |
aa8734ff | 341 | struct udev_list_entry *list_entry_current; |
5755d586 | 342 | int found; |
aa8734ff | 343 | |
f408fd91 | 344 | /* check if old link name still belongs to this device */ |
5755d586 | 345 | found = 0; |
aa8734ff | 346 | udev_list_entry_foreach(list_entry_current, udev_device_get_devlinks_list_entry(dev)) { |
6e0cb78c KS |
347 | const char *name_current = udev_list_entry_get_name(list_entry_current); |
348 | ||
f408fd91 | 349 | if (strcmp(name, name_current) == 0) { |
5755d586 KS |
350 | found = 1; |
351 | break; | |
352 | } | |
aa8734ff | 353 | } |
5755d586 KS |
354 | if (found) |
355 | continue; | |
f408fd91 | 356 | |
8257730d KS |
357 | info(udev, "update old name, '%s' no longer belonging to '%s'\n", |
358 | name, udev_device_get_devpath(dev)); | |
6c29f2b9 | 359 | link_update(dev, name, 0); |
24f0605c KS |
360 | } |
361 | } | |
362 | ||
ec2dd02e | 363 | int udev_node_add(struct udev_device *dev, mode_t mode, uid_t uid, gid_t gid) |
97853b4f | 364 | { |
aa8734ff | 365 | struct udev *udev = udev_device_get_udev(dev); |
2713e6ab | 366 | char filename[UTIL_PATH_SIZE]; |
aa8734ff KS |
367 | struct udev_list_entry *list_entry; |
368 | int err = 0; | |
a4d5ca64 | 369 | |
aa8734ff KS |
370 | info(udev, "creating device node '%s', devnum=%d:%d, mode=%#o, uid=%d, gid=%d\n", |
371 | udev_device_get_devnode(dev), | |
372 | major(udev_device_get_devnum(dev)), minor(udev_device_get_devnum(dev)), | |
373 | mode, uid, gid); | |
ad27f5b3 | 374 | |
c7cdd8b2 | 375 | if (udev_node_mknod(dev, NULL, mode, uid, gid) != 0) { |
ec2dd02e KS |
376 | err = -1; |
377 | goto exit; | |
378 | } | |
ad27f5b3 | 379 | |
2713e6ab KS |
380 | /* always add /dev/{block,char}/$major:$minor */ |
381 | snprintf(filename, sizeof(filename), "%s/%s/%u:%u", | |
382 | udev_get_dev_path(udev), | |
383 | strcmp(udev_device_get_subsystem(dev), "block") == 0 ? "block" : "char", | |
384 | major(udev_device_get_devnum(dev)), minor(udev_device_get_devnum(dev))); | |
385 | node_symlink(udev, udev_device_get_devnode(dev), filename); | |
386 | ||
aa8734ff KS |
387 | /* create/update symlinks, add symlinks to name index */ |
388 | udev_list_entry_foreach(list_entry, udev_device_get_devlinks_list_entry(dev)) { | |
fbb31cd6 | 389 | if (udev_list_entry_get_flags(list_entry)) |
6c29f2b9 | 390 | /* simple unmanaged link name */ |
6c29f2b9 | 391 | node_symlink(udev, udev_device_get_devnode(dev), udev_list_entry_get_name(list_entry)); |
676d294c | 392 | else |
6c29f2b9 | 393 | link_update(dev, udev_list_entry_get_name(list_entry), 1); |
aa8734ff | 394 | } |
a4d5ca64 | 395 | exit: |
aa8734ff | 396 | return err; |
ea733a2f GKH |
397 | } |
398 | ||
37ed4f56 | 399 | int udev_node_remove(struct udev_device *dev) |
ff9a488d | 400 | { |
aa8734ff KS |
401 | struct udev *udev = udev_device_get_udev(dev); |
402 | struct udev_list_entry *list_entry; | |
403 | const char *devnode; | |
ff9a488d | 404 | struct stat stats; |
a89d342d | 405 | struct udev_device *dev_check; |
2713e6ab | 406 | char filename[UTIL_PATH_SIZE]; |
aa8734ff | 407 | int err = 0; |
ff9a488d | 408 | |
889dd106 | 409 | /* remove/update symlinks, remove symlinks from name index */ |
6c29f2b9 KS |
410 | udev_list_entry_foreach(list_entry, udev_device_get_devlinks_list_entry(dev)) |
411 | link_update(dev, udev_list_entry_get_name(list_entry), 0); | |
aa8734ff KS |
412 | |
413 | devnode = udev_device_get_devnode(dev); | |
414 | if (devnode == NULL) | |
a89d342d KS |
415 | goto out; |
416 | ||
aa8734ff KS |
417 | if (stat(devnode, &stats) != 0) { |
418 | info(udev, "device node '%s' not found\n", devnode); | |
a89d342d | 419 | goto out; |
a4d5ca64 | 420 | } |
a89d342d | 421 | |
aa8734ff KS |
422 | if (stats.st_rdev != udev_device_get_devnum(dev)) { |
423 | info(udev, "device node '%s' points to a different device, skip removal\n", devnode); | |
a89d342d KS |
424 | err = -1; |
425 | goto out; | |
a4d5ca64 KS |
426 | } |
427 | ||
a89d342d KS |
428 | dev_check = udev_device_new_from_syspath(udev, udev_device_get_syspath(dev)); |
429 | if (dev_check != NULL) { | |
430 | /* do not remove device node if the same sys-device is re-created in the meantime */ | |
431 | info(udev, "keeping device node of existing device'%s'\n", devnode); | |
0ec5b5e1 | 432 | udev_device_unref(dev_check); |
a89d342d KS |
433 | goto out; |
434 | } | |
435 | ||
a89d342d KS |
436 | info(udev, "removing device node '%s'\n", devnode); |
437 | err = util_unlink_secure(udev, devnode); | |
8e5a620b KS |
438 | if (err == 0) |
439 | util_delete_path(udev, devnode); | |
2713e6ab KS |
440 | |
441 | /* remove /dev/{block,char}/$major:$minor */ | |
442 | snprintf(filename, sizeof(filename), "%s/%s/%u:%u", | |
443 | udev_get_dev_path(udev), | |
444 | strcmp(udev_device_get_subsystem(dev), "block") == 0 ? "block" : "char", | |
445 | major(udev_device_get_devnum(dev)), minor(udev_device_get_devnum(dev))); | |
446 | unlink(filename); | |
a89d342d | 447 | out: |
aa8734ff | 448 | return err; |
ea733a2f | 449 | } |