]>
git.ipfire.org Git - thirdparty/systemd.git/blob - src/udev/udev-watch.c
2 * Copyright (C) 2004-2012 Kay Sievers <kay.sievers@vrfy.org>
3 * Copyright (C) 2009 Canonical Ltd.
4 * Copyright (C) 2009 Scott James Remnant <scott@netsplit.com>
6 * This program is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
20 #include <sys/types.h>
29 #include <sys/inotify.h>
33 static int inotify_fd
= -1;
35 /* inotify descriptor, will be shared with rules directory;
36 * set to cloexec since we need our children to be able to add
39 int udev_watch_init(struct udev
*udev
)
41 inotify_fd
= inotify_init1(IN_CLOEXEC
);
43 log_error("inotify_init failed: %m\n");
47 /* move any old watches directory out of the way, and then restore
50 void udev_watch_restore(struct udev
*udev
)
52 char filename
[UTIL_PATH_SIZE
], oldname
[UTIL_PATH_SIZE
];
57 util_strscpyl(oldname
, sizeof(oldname
), udev_get_run_path(udev
), "/watch.old", NULL
);
58 util_strscpyl(filename
, sizeof(filename
), udev_get_run_path(udev
), "/watch", NULL
);
59 if (rename(filename
, oldname
) == 0) {
63 dir
= opendir(oldname
);
65 log_error("unable to open old watches dir '%s', old watches will not be restored: %m", oldname
);
69 for (ent
= readdir(dir
); ent
!= NULL
; ent
= readdir(dir
)) {
70 char device
[UTIL_PATH_SIZE
];
74 struct udev_device
*dev
;
76 if (ent
->d_name
[0] == '.')
80 l
= util_strpcpy(&s
, sizeof(device
), udev_get_sys_path(udev
));
81 len
= readlinkat(dirfd(dir
), ent
->d_name
, s
, l
);
82 if (len
<= 0 || len
== (ssize_t
)l
)
86 dev
= udev_device_new_from_id_filename(udev
, s
);
90 log_debug("restoring old watch on '%s'\n", udev_device_get_devnode(dev
));
91 udev_watch_begin(udev
, dev
);
92 udev_device_unref(dev
);
94 unlinkat(dirfd(dir
), ent
->d_name
, 0);
100 } else if (errno
!= ENOENT
) {
101 log_error("unable to move watches dir '%s', old watches will not be restored: %m", filename
);
105 void udev_watch_begin(struct udev
*udev
, struct udev_device
*dev
)
107 char filename
[UTIL_PATH_SIZE
];
113 log_debug("adding watch on '%s'\n", udev_device_get_devnode(dev
));
114 wd
= inotify_add_watch(inotify_fd
, udev_device_get_devnode(dev
), IN_CLOSE_WRITE
);
116 log_error("inotify_add_watch(%d, %s, %o) failed: %m\n",
117 inotify_fd
, udev_device_get_devnode(dev
), IN_CLOSE_WRITE
);
121 snprintf(filename
, sizeof(filename
), "%s/watch/%d", udev_get_run_path(udev
), wd
);
122 util_create_path(udev
, filename
);
124 symlink(udev_device_get_id_filename(dev
), filename
);
126 udev_device_set_watch_handle(dev
, wd
);
129 void udev_watch_end(struct udev
*udev
, struct udev_device
*dev
)
132 char filename
[UTIL_PATH_SIZE
];
137 wd
= udev_device_get_watch_handle(dev
);
141 log_debug("removing watch on '%s'\n", udev_device_get_devnode(dev
));
142 inotify_rm_watch(inotify_fd
, wd
);
144 snprintf(filename
, sizeof(filename
), "%s/watch/%d", udev_get_run_path(udev
), wd
);
147 udev_device_set_watch_handle(dev
, -1);
150 struct udev_device
*udev_watch_lookup(struct udev
*udev
, int wd
)
152 char filename
[UTIL_PATH_SIZE
];
153 char majmin
[UTIL_PATH_SIZE
];
158 if (inotify_fd
< 0 || wd
< 0)
161 snprintf(filename
, sizeof(filename
), "%s/watch/%d", udev_get_run_path(udev
), wd
);
163 l
= util_strpcpy(&s
, sizeof(majmin
), udev_get_sys_path(udev
));
164 len
= readlink(filename
, s
, l
);
165 if (len
<= 0 || (size_t)len
== l
)
169 return udev_device_new_from_id_filename(udev
, s
);