]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/udev/udevadm-trigger.c
udevadm: allow trigger command to be synchronous
[thirdparty/systemd.git] / src / udev / udevadm-trigger.c
CommitLineData
e7145211 1/* SPDX-License-Identifier: GPL-2.0+ */
0d5be398 2/*
1298001e 3 * Copyright (C) 2008-2009 Kay Sievers <kay@vrfy.org>
0d5be398 4 *
55e9959b
KS
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 2 of the License, or
8 * (at your option) any later version.
0d5be398 9 *
55e9959b
KS
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
0d5be398
KS
17 */
18
07630cea
LP
19#include <errno.h>
20#include <fcntl.h>
21#include <getopt.h>
0d5be398 22#include <stddef.h>
0d5be398 23#include <stdio.h>
07630cea 24#include <string.h>
0d5be398 25#include <unistd.h>
0d5be398 26
792cc203
MH
27#include "fd-util.h"
28#include "set.h"
07630cea 29#include "string-util.h"
44433ebd 30#include "udev-util.h"
07630cea 31#include "udev.h"
d6170d27 32#include "udevadm-util.h"
c5383e79 33#include "util.h"
0d5be398 34
c48622cc
KS
35static int verbose;
36static int dry_run;
c48622cc 37
792cc203 38static void exec_list(struct udev_enumerate *udev_enumerate, const char *action, Set *settle_set) {
912541b0
KS
39 struct udev_list_entry *entry;
40
41 udev_list_entry_foreach(entry, udev_enumerate_get_list_entry(udev_enumerate)) {
42 char filename[UTIL_PATH_SIZE];
792cc203 43 const char *syspath;
912541b0
KS
44 int fd;
45
792cc203 46 syspath = udev_list_entry_get_name(entry);
912541b0 47 if (verbose)
792cc203 48 printf("%s\n", syspath);
912541b0
KS
49 if (dry_run)
50 continue;
792cc203
MH
51
52 strscpyl(filename, sizeof(filename), syspath, "/uevent", NULL);
c8a202b7 53 fd = open(filename, O_WRONLY|O_CLOEXEC);
baa30fbc 54 if (fd < 0)
912541b0 55 continue;
792cc203
MH
56 if (settle_set != NULL)
57 set_put_strdup(settle_set, syspath);
912541b0 58 if (write(fd, action, strlen(action)) < 0)
56f64d95 59 log_debug_errno(errno, "error writing '%s' to '%s': %m", action, filename);
912541b0
KS
60 close(fd);
61 }
0d5be398
KS
62}
63
9ec6e95b 64static const char *keyval(const char *str, const char **val, char *buf, size_t size) {
912541b0
KS
65 char *pos;
66
d5a89d7d 67 strscpy(buf, size,str);
912541b0
KS
68 pos = strchr(buf, '=');
69 if (pos != NULL) {
70 pos[0] = 0;
71 pos++;
72 }
73 *val = pos;
74 return buf;
80381823
KS
75}
76
7643ac9a 77static void help(void) {
5639df9a 78 printf("%s trigger [OPTIONS] DEVPATH\n\n"
5ac0162c
LP
79 "Request events from the kernel.\n\n"
80 " -h --help Show this help\n"
5639df9a 81 " -V --version Show package version\n"
5ac0162c
LP
82 " -v --verbose Print the list of devices while running\n"
83 " -n --dry-run Do not actually trigger the events\n"
84 " -t --type= Type of events to trigger\n"
85 " devices sysfs devices (default)\n"
86 " subsystems sysfs subsystems and drivers\n"
87 " -c --action=ACTION Event action value, default is \"change\"\n"
88 " -s --subsystem-match=SUBSYSTEM Trigger devices from a matching subsystem\n"
89 " -S --subsystem-nomatch=SUBSYSTEM Exclude devices from a matching subsystem\n"
90 " -a --attr-match=FILE[=VALUE] Trigger devices with a matching attribute\n"
91 " -A --attr-nomatch=FILE[=VALUE] Exclude devices with a matching attribute\n"
92 " -p --property-match=KEY=VALUE Trigger devices with a matching property\n"
93 " -g --tag-match=KEY=VALUE Trigger devices with a matching property\n"
94 " -y --sysname-match=NAME Trigger devices with this /sys path\n"
95 " --name-match=NAME Trigger devices with this /dev name\n"
96 " -b --parent-match=NAME Trigger devices with that parent device\n"
792cc203 97 " -w --settle Wait for the triggered events to complete\n"
5ac0162c 98 , program_invocation_short_name);
7643ac9a
ZJS
99}
100
9ec6e95b 101static int adm_trigger(struct udev *udev, int argc, char *argv[]) {
80877656
ZJS
102 enum {
103 ARG_NAME = 0x100,
104 };
105
912541b0 106 static const struct option options[] = {
80877656
ZJS
107 { "verbose", no_argument, NULL, 'v' },
108 { "dry-run", no_argument, NULL, 'n' },
109 { "type", required_argument, NULL, 't' },
110 { "action", required_argument, NULL, 'c' },
111 { "subsystem-match", required_argument, NULL, 's' },
112 { "subsystem-nomatch", required_argument, NULL, 'S' },
113 { "attr-match", required_argument, NULL, 'a' },
114 { "attr-nomatch", required_argument, NULL, 'A' },
115 { "property-match", required_argument, NULL, 'p' },
116 { "tag-match", required_argument, NULL, 'g' },
117 { "sysname-match", required_argument, NULL, 'y' },
118 { "name-match", required_argument, NULL, ARG_NAME },
119 { "parent-match", required_argument, NULL, 'b' },
792cc203 120 { "settle", no_argument, NULL, 'w' },
5639df9a 121 { "version", no_argument, NULL, 'V' },
80877656 122 { "help", no_argument, NULL, 'h' },
912541b0
KS
123 {}
124 };
125 enum {
126 TYPE_DEVICES,
127 TYPE_SUBSYSTEMS,
128 } device_type = TYPE_DEVICES;
129 const char *action = "change";
44433ebd 130 _cleanup_udev_enumerate_unref_ struct udev_enumerate *udev_enumerate = NULL;
792cc203
MH
131 _cleanup_udev_monitor_unref_ struct udev_monitor *udev_monitor = NULL;
132 _cleanup_close_ int fd_ep = -1;
133 int fd_udev = -1;
134 struct epoll_event ep_udev;
135 bool settle = false;
136 _cleanup_set_free_free_ Set *settle_set = NULL;
56b13bcc 137 int c, r;
912541b0 138
912541b0 139 udev_enumerate = udev_enumerate_new(udev);
44433ebd
ZJS
140 if (udev_enumerate == NULL)
141 return 1;
912541b0 142
792cc203 143 while ((c = getopt_long(argc, argv, "vnt:c:s:S:a:A:p:g:y:b:wVh", options, NULL)) >= 0) {
912541b0
KS
144 const char *key;
145 const char *val;
146 char buf[UTIL_PATH_SIZE];
147
7643ac9a 148 switch (c) {
912541b0
KS
149 case 'v':
150 verbose = 1;
151 break;
152 case 'n':
153 dry_run = 1;
154 break;
155 case 't':
44433ebd 156 if (streq(optarg, "devices"))
912541b0 157 device_type = TYPE_DEVICES;
44433ebd 158 else if (streq(optarg, "subsystems"))
912541b0 159 device_type = TYPE_SUBSYSTEMS;
44433ebd 160 else {
9f6445e3 161 log_error("unknown type --type=%s", optarg);
44433ebd 162 return 2;
912541b0
KS
163 }
164 break;
165 case 'c':
5991ce44 166 if (!STR_IN_SET(optarg, "add", "remove", "change")) {
9f6445e3 167 log_error("unknown action '%s'", optarg);
44433ebd
ZJS
168 return 2;
169 } else
c5383e79 170 action = optarg;
44433ebd 171
912541b0
KS
172 break;
173 case 's':
56b13bcc
TG
174 r = udev_enumerate_add_match_subsystem(udev_enumerate, optarg);
175 if (r < 0) {
176 log_error_errno(r, "could not add subsystem match '%s': %m", optarg);
177 return 2;
178 }
912541b0
KS
179 break;
180 case 'S':
56b13bcc
TG
181 r = udev_enumerate_add_nomatch_subsystem(udev_enumerate, optarg);
182 if (r < 0) {
183 log_error_errno(r, "could not add negative subsystem match '%s': %m", optarg);
184 return 2;
185 }
912541b0
KS
186 break;
187 case 'a':
188 key = keyval(optarg, &val, buf, sizeof(buf));
56b13bcc
TG
189 r = udev_enumerate_add_match_sysattr(udev_enumerate, key, val);
190 if (r < 0) {
191 log_error_errno(r, "could not add sysattr match '%s=%s': %m", key, val);
192 return 2;
193 }
912541b0
KS
194 break;
195 case 'A':
196 key = keyval(optarg, &val, buf, sizeof(buf));
56b13bcc
TG
197 r = udev_enumerate_add_nomatch_sysattr(udev_enumerate, key, val);
198 if (r < 0) {
199 log_error_errno(r, "could not add negative sysattr match '%s=%s': %m", key, val);
200 return 2;
201 }
912541b0
KS
202 break;
203 case 'p':
204 key = keyval(optarg, &val, buf, sizeof(buf));
56b13bcc
TG
205 r = udev_enumerate_add_match_property(udev_enumerate, key, val);
206 if (r < 0) {
207 log_error_errno(r, "could not add property match '%s=%s': %m", key, val);
208 return 2;
209 }
912541b0
KS
210 break;
211 case 'g':
56b13bcc
TG
212 r = udev_enumerate_add_match_tag(udev_enumerate, optarg);
213 if (r < 0) {
214 log_error_errno(r, "could not add tag match '%s': %m", optarg);
215 return 2;
216 }
912541b0
KS
217 break;
218 case 'y':
56b13bcc
TG
219 r = udev_enumerate_add_match_sysname(udev_enumerate, optarg);
220 if (r < 0) {
221 log_error_errno(r, "could not add sysname match '%s': %m", optarg);
222 return 2;
223 }
912541b0
KS
224 break;
225 case 'b': {
d6170d27
ZJS
226 _cleanup_udev_device_unref_ struct udev_device *dev;
227
228 dev = find_device(udev, optarg, "/sys");
912541b0 229 if (dev == NULL) {
9f6445e3 230 log_error("unable to open the device '%s'", optarg);
44433ebd 231 return 2;
912541b0 232 }
d6170d27 233
56b13bcc
TG
234 r = udev_enumerate_add_match_parent(udev_enumerate, dev);
235 if (r < 0) {
236 log_error_errno(r, "could not add parent match '%s': %m", optarg);
237 return 2;
238 }
912541b0
KS
239 break;
240 }
792cc203
MH
241 case 'w':
242 settle = true;
243 break;
d6170d27 244
80877656
ZJS
245 case ARG_NAME: {
246 _cleanup_udev_device_unref_ struct udev_device *dev;
247
248 dev = find_device(udev, optarg, "/dev/");
249 if (dev == NULL) {
250 log_error("unable to open the device '%s'", optarg);
251 return 2;
252 }
253
56b13bcc
TG
254 r = udev_enumerate_add_match_parent(udev_enumerate, dev);
255 if (r < 0) {
256 log_error_errno(r, "could not add parent match '%s': %m", optarg);
257 return 2;
258 }
80877656
ZJS
259 break;
260 }
261
5639df9a
YW
262 case 'V':
263 print_version();
264 return 0;
912541b0 265 case 'h':
7643ac9a 266 help();
44433ebd 267 return 0;
7643ac9a 268 case '?':
44433ebd 269 return 1;
7643ac9a
ZJS
270 default:
271 assert_not_reached("Unknown option");
912541b0
KS
272 }
273 }
274
80877656
ZJS
275 for (; optind < argc; optind++) {
276 _cleanup_udev_device_unref_ struct udev_device *dev;
277
278 dev = find_device(udev, argv[optind], NULL);
279 if (dev == NULL) {
280 log_error("unable to open the device '%s'", argv[optind]);
281 return 2;
282 }
283
56b13bcc
TG
284 r = udev_enumerate_add_match_parent(udev_enumerate, dev);
285 if (r < 0) {
286 log_error_errno(r, "could not add tag match '%s': %m", optarg);
287 return 2;
288 }
7643ac9a
ZJS
289 }
290
792cc203
MH
291 if (settle) {
292 fd_ep = epoll_create1(EPOLL_CLOEXEC);
293 if (fd_ep < 0) {
294 log_error_errno(errno, "error creating epoll fd: %m");
295 return 1;
296 }
297
298 udev_monitor = udev_monitor_new_from_netlink(udev, "udev");
299 if (udev_monitor == NULL) {
300 log_error("error: unable to create netlink socket");
301 return 3;
302 }
303 fd_udev = udev_monitor_get_fd(udev_monitor);
304
305 if (udev_monitor_enable_receiving(udev_monitor) < 0) {
306 log_error("error: unable to subscribe to udev events");
307 return 4;
308 }
309
310 ep_udev = (struct epoll_event) { .events = EPOLLIN, .data.fd = fd_udev };
311 if (epoll_ctl(fd_ep, EPOLL_CTL_ADD, fd_udev, &ep_udev) < 0) {
312 log_error_errno(errno, "fail to add fd to epoll: %m");
313 return 5;
314 }
315
316 settle_set = set_new(&string_hash_ops);
317 if (settle_set == NULL) {
318 log_oom();
319 return 1;
320 }
321 }
322
912541b0
KS
323 switch (device_type) {
324 case TYPE_SUBSYSTEMS:
325 udev_enumerate_scan_subsystems(udev_enumerate);
792cc203 326 break;
912541b0
KS
327 case TYPE_DEVICES:
328 udev_enumerate_scan_devices(udev_enumerate);
792cc203 329 break;
912541b0 330 default:
4dd1de72 331 assert_not_reached("device_type");
912541b0 332 }
792cc203
MH
333 exec_list(udev_enumerate, action, settle_set);
334
335 while (!set_isempty(settle_set)) {
336 int fdcount;
337 struct epoll_event ev[4];
338 int i;
339
340 fdcount = epoll_wait(fd_ep, ev, ELEMENTSOF(ev), -1);
341 if (fdcount < 0) {
342 if (errno != EINTR)
343 log_error_errno(errno, "error receiving uevent message: %m");
344 continue;
345 }
346
347 for (i = 0; i < fdcount; i++) {
348 if (ev[i].data.fd == fd_udev && ev[i].events & EPOLLIN) {
349 _cleanup_udev_device_unref_ struct udev_device *device;
350 const char *syspath = NULL;
351
352 device = udev_monitor_receive_device(udev_monitor);
353 if (device == NULL)
354 continue;
355
356 syspath = udev_device_get_syspath(device);
357 if (verbose)
358 printf("settle %s\n", syspath);
359 if (!set_remove(settle_set, syspath))
360 log_debug("Got epoll event on syspath %s not present in syspath set", syspath);
361 }
362 }
363 }
364
365 return 0;
0d5be398 366}
1985c76e
KS
367
368const struct udevadm_cmd udevadm_trigger = {
912541b0
KS
369 .name = "trigger",
370 .cmd = adm_trigger,
5ac0162c 371 .help = "Request events from the kernel",
1985c76e 372};