]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/udev/udev-watch.c
tree-wide: drop empty lines in comments
[thirdparty/systemd.git] / src / udev / udev-watch.c
1 /* SPDX-License-Identifier: GPL-2.0+ */
2 /*
3 * Copyright © 2009 Canonical Ltd.
4 * Copyright © 2009 Scott James Remnant <scott@netsplit.com>
5 */
6
7 #include <errno.h>
8 #include <stddef.h>
9 #include <stdio.h>
10 #include <sys/inotify.h>
11 #include <unistd.h>
12
13 #include "dirent-util.h"
14 #include "stdio-util.h"
15 #include "udev.h"
16
17 static int inotify_fd = -1;
18
19 /* inotify descriptor, will be shared with rules directory;
20 * set to cloexec since we need our children to be able to add
21 * watches for us
22 */
23 int udev_watch_init(struct udev *udev) {
24 inotify_fd = inotify_init1(IN_CLOEXEC);
25 if (inotify_fd < 0)
26 log_error_errno(errno, "inotify_init failed: %m");
27 return inotify_fd;
28 }
29
30 /* move any old watches directory out of the way, and then restore
31 * the watches
32 */
33 void udev_watch_restore(struct udev *udev) {
34 if (inotify_fd < 0)
35 return;
36
37 if (rename("/run/udev/watch", "/run/udev/watch.old") == 0) {
38 DIR *dir;
39 struct dirent *ent;
40
41 dir = opendir("/run/udev/watch.old");
42 if (dir == NULL) {
43 log_error_errno(errno, "unable to open old watches dir /run/udev/watch.old; old watches will not be restored: %m");
44 return;
45 }
46
47 FOREACH_DIRENT_ALL(ent, dir, break) {
48 char device[UTIL_PATH_SIZE];
49 ssize_t len;
50 struct udev_device *dev;
51
52 if (ent->d_name[0] == '.')
53 continue;
54
55 len = readlinkat(dirfd(dir), ent->d_name, device, sizeof(device));
56 if (len <= 0 || len == (ssize_t)sizeof(device))
57 goto unlink;
58 device[len] = '\0';
59
60 dev = udev_device_new_from_device_id(udev, device);
61 if (dev == NULL)
62 goto unlink;
63
64 log_debug("restoring old watch on '%s'", udev_device_get_devnode(dev));
65 udev_watch_begin(udev, dev);
66 udev_device_unref(dev);
67 unlink:
68 (void) unlinkat(dirfd(dir), ent->d_name, 0);
69 }
70
71 closedir(dir);
72 rmdir("/run/udev/watch.old");
73
74 } else if (errno != ENOENT)
75 log_error_errno(errno, "unable to move watches dir /run/udev/watch; old watches will not be restored: %m");
76 }
77
78 void udev_watch_begin(struct udev *udev, struct udev_device *dev) {
79 char filename[sizeof("/run/udev/watch/") + DECIMAL_STR_MAX(int)];
80 int wd;
81 int r;
82
83 if (inotify_fd < 0)
84 return;
85
86 log_debug("adding watch on '%s'", udev_device_get_devnode(dev));
87 wd = inotify_add_watch(inotify_fd, udev_device_get_devnode(dev), IN_CLOSE_WRITE);
88 if (wd < 0) {
89 log_error_errno(errno, "inotify_add_watch(%d, %s, %o) failed: %m",
90 inotify_fd, udev_device_get_devnode(dev), IN_CLOSE_WRITE);
91 return;
92 }
93
94 xsprintf(filename, "/run/udev/watch/%d", wd);
95 mkdir_parents(filename, 0755);
96 unlink(filename);
97 r = symlink(udev_device_get_id_filename(dev), filename);
98 if (r < 0)
99 log_error_errno(errno, "Failed to create symlink %s: %m", filename);
100
101 udev_device_set_watch_handle(dev, wd);
102 }
103
104 void udev_watch_end(struct udev *udev, struct udev_device *dev) {
105 int wd;
106 char filename[sizeof("/run/udev/watch/") + DECIMAL_STR_MAX(int)];
107
108 if (inotify_fd < 0)
109 return;
110
111 wd = udev_device_get_watch_handle(dev);
112 if (wd < 0)
113 return;
114
115 log_debug("removing watch on '%s'", udev_device_get_devnode(dev));
116 inotify_rm_watch(inotify_fd, wd);
117
118 xsprintf(filename, "/run/udev/watch/%d", wd);
119 unlink(filename);
120
121 udev_device_set_watch_handle(dev, -1);
122 }
123
124 struct udev_device *udev_watch_lookup(struct udev *udev, int wd) {
125 char filename[sizeof("/run/udev/watch/") + DECIMAL_STR_MAX(int)];
126 char device[UTIL_NAME_SIZE];
127 ssize_t len;
128
129 if (inotify_fd < 0 || wd < 0)
130 return NULL;
131
132 xsprintf(filename, "/run/udev/watch/%d", wd);
133 len = readlink(filename, device, sizeof(device));
134 if (len <= 0 || (size_t)len == sizeof(device))
135 return NULL;
136 device[len] = '\0';
137
138 return udev_device_new_from_device_id(udev, device);
139 }