]>
Commit | Line | Data |
---|---|---|
0d5be398 | 1 | /* |
1298001e | 2 | * Copyright (C) 2008-2009 Kay Sievers <kay@vrfy.org> |
0d5be398 | 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. | |
0d5be398 | 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/>. | |
0d5be398 KS |
16 | */ |
17 | ||
07630cea LP |
18 | #include <errno.h> |
19 | #include <fcntl.h> | |
20 | #include <getopt.h> | |
0d5be398 | 21 | #include <stddef.h> |
0d5be398 | 22 | #include <stdio.h> |
07630cea | 23 | #include <string.h> |
0d5be398 | 24 | #include <unistd.h> |
0d5be398 | 25 | |
07630cea | 26 | #include "string-util.h" |
44433ebd | 27 | #include "udev-util.h" |
07630cea | 28 | #include "udev.h" |
d6170d27 | 29 | #include "udevadm-util.h" |
c5383e79 | 30 | #include "util.h" |
0d5be398 | 31 | |
c48622cc KS |
32 | static int verbose; |
33 | static int dry_run; | |
c48622cc | 34 | |
9ec6e95b | 35 | static void exec_list(struct udev_enumerate *udev_enumerate, const char *action) { |
912541b0 KS |
36 | struct udev_list_entry *entry; |
37 | ||
38 | udev_list_entry_foreach(entry, udev_enumerate_get_list_entry(udev_enumerate)) { | |
39 | char filename[UTIL_PATH_SIZE]; | |
40 | int fd; | |
41 | ||
42 | if (verbose) | |
43 | printf("%s\n", udev_list_entry_get_name(entry)); | |
44 | if (dry_run) | |
45 | continue; | |
d5a89d7d | 46 | strscpyl(filename, sizeof(filename), udev_list_entry_get_name(entry), "/uevent", NULL); |
c8a202b7 | 47 | fd = open(filename, O_WRONLY|O_CLOEXEC); |
baa30fbc | 48 | if (fd < 0) |
912541b0 | 49 | continue; |
912541b0 | 50 | if (write(fd, action, strlen(action)) < 0) |
56f64d95 | 51 | log_debug_errno(errno, "error writing '%s' to '%s': %m", action, filename); |
912541b0 KS |
52 | close(fd); |
53 | } | |
0d5be398 KS |
54 | } |
55 | ||
9ec6e95b | 56 | static const char *keyval(const char *str, const char **val, char *buf, size_t size) { |
912541b0 KS |
57 | char *pos; |
58 | ||
d5a89d7d | 59 | strscpy(buf, size,str); |
912541b0 KS |
60 | pos = strchr(buf, '='); |
61 | if (pos != NULL) { | |
62 | pos[0] = 0; | |
63 | pos++; | |
64 | } | |
65 | *val = pos; | |
66 | return buf; | |
80381823 KS |
67 | } |
68 | ||
7643ac9a | 69 | static void help(void) { |
5ac0162c LP |
70 | printf("%s trigger OPTIONS\n\n" |
71 | "Request events from the kernel.\n\n" | |
72 | " -h --help Show this help\n" | |
73 | " --version Show package version\n" | |
74 | " -v --verbose Print the list of devices while running\n" | |
75 | " -n --dry-run Do not actually trigger the events\n" | |
76 | " -t --type= Type of events to trigger\n" | |
77 | " devices sysfs devices (default)\n" | |
78 | " subsystems sysfs subsystems and drivers\n" | |
79 | " -c --action=ACTION Event action value, default is \"change\"\n" | |
80 | " -s --subsystem-match=SUBSYSTEM Trigger devices from a matching subsystem\n" | |
81 | " -S --subsystem-nomatch=SUBSYSTEM Exclude devices from a matching subsystem\n" | |
82 | " -a --attr-match=FILE[=VALUE] Trigger devices with a matching attribute\n" | |
83 | " -A --attr-nomatch=FILE[=VALUE] Exclude devices with a matching attribute\n" | |
84 | " -p --property-match=KEY=VALUE Trigger devices with a matching property\n" | |
85 | " -g --tag-match=KEY=VALUE Trigger devices with a matching property\n" | |
86 | " -y --sysname-match=NAME Trigger devices with this /sys path\n" | |
87 | " --name-match=NAME Trigger devices with this /dev name\n" | |
88 | " -b --parent-match=NAME Trigger devices with that parent device\n" | |
89 | , program_invocation_short_name); | |
7643ac9a ZJS |
90 | } |
91 | ||
9ec6e95b | 92 | static int adm_trigger(struct udev *udev, int argc, char *argv[]) { |
80877656 ZJS |
93 | enum { |
94 | ARG_NAME = 0x100, | |
95 | }; | |
96 | ||
912541b0 | 97 | static const struct option options[] = { |
80877656 ZJS |
98 | { "verbose", no_argument, NULL, 'v' }, |
99 | { "dry-run", no_argument, NULL, 'n' }, | |
100 | { "type", required_argument, NULL, 't' }, | |
101 | { "action", required_argument, NULL, 'c' }, | |
102 | { "subsystem-match", required_argument, NULL, 's' }, | |
103 | { "subsystem-nomatch", required_argument, NULL, 'S' }, | |
104 | { "attr-match", required_argument, NULL, 'a' }, | |
105 | { "attr-nomatch", required_argument, NULL, 'A' }, | |
106 | { "property-match", required_argument, NULL, 'p' }, | |
107 | { "tag-match", required_argument, NULL, 'g' }, | |
108 | { "sysname-match", required_argument, NULL, 'y' }, | |
109 | { "name-match", required_argument, NULL, ARG_NAME }, | |
110 | { "parent-match", required_argument, NULL, 'b' }, | |
111 | { "help", no_argument, NULL, 'h' }, | |
912541b0 KS |
112 | {} |
113 | }; | |
114 | enum { | |
115 | TYPE_DEVICES, | |
116 | TYPE_SUBSYSTEMS, | |
117 | } device_type = TYPE_DEVICES; | |
118 | const char *action = "change"; | |
44433ebd | 119 | _cleanup_udev_enumerate_unref_ struct udev_enumerate *udev_enumerate = NULL; |
56b13bcc | 120 | int c, r; |
912541b0 | 121 | |
912541b0 | 122 | udev_enumerate = udev_enumerate_new(udev); |
44433ebd ZJS |
123 | if (udev_enumerate == NULL) |
124 | return 1; | |
912541b0 | 125 | |
7643ac9a | 126 | while ((c = getopt_long(argc, argv, "vno:t:c:s:S:a:A:p:g:y:b:h", options, NULL)) >= 0) { |
912541b0 KS |
127 | const char *key; |
128 | const char *val; | |
129 | char buf[UTIL_PATH_SIZE]; | |
130 | ||
7643ac9a | 131 | switch (c) { |
912541b0 KS |
132 | case 'v': |
133 | verbose = 1; | |
134 | break; | |
135 | case 'n': | |
136 | dry_run = 1; | |
137 | break; | |
138 | case 't': | |
44433ebd | 139 | if (streq(optarg, "devices")) |
912541b0 | 140 | device_type = TYPE_DEVICES; |
44433ebd | 141 | else if (streq(optarg, "subsystems")) |
912541b0 | 142 | device_type = TYPE_SUBSYSTEMS; |
44433ebd | 143 | else { |
9f6445e3 | 144 | log_error("unknown type --type=%s", optarg); |
44433ebd | 145 | return 2; |
912541b0 KS |
146 | } |
147 | break; | |
148 | case 'c': | |
5991ce44 | 149 | if (!STR_IN_SET(optarg, "add", "remove", "change")) { |
9f6445e3 | 150 | log_error("unknown action '%s'", optarg); |
44433ebd ZJS |
151 | return 2; |
152 | } else | |
c5383e79 | 153 | action = optarg; |
44433ebd | 154 | |
912541b0 KS |
155 | break; |
156 | case 's': | |
56b13bcc TG |
157 | r = udev_enumerate_add_match_subsystem(udev_enumerate, optarg); |
158 | if (r < 0) { | |
159 | log_error_errno(r, "could not add subsystem match '%s': %m", optarg); | |
160 | return 2; | |
161 | } | |
912541b0 KS |
162 | break; |
163 | case 'S': | |
56b13bcc TG |
164 | r = udev_enumerate_add_nomatch_subsystem(udev_enumerate, optarg); |
165 | if (r < 0) { | |
166 | log_error_errno(r, "could not add negative subsystem match '%s': %m", optarg); | |
167 | return 2; | |
168 | } | |
912541b0 KS |
169 | break; |
170 | case 'a': | |
171 | key = keyval(optarg, &val, buf, sizeof(buf)); | |
56b13bcc TG |
172 | r = udev_enumerate_add_match_sysattr(udev_enumerate, key, val); |
173 | if (r < 0) { | |
174 | log_error_errno(r, "could not add sysattr match '%s=%s': %m", key, val); | |
175 | return 2; | |
176 | } | |
912541b0 KS |
177 | break; |
178 | case 'A': | |
179 | key = keyval(optarg, &val, buf, sizeof(buf)); | |
56b13bcc TG |
180 | r = udev_enumerate_add_nomatch_sysattr(udev_enumerate, key, val); |
181 | if (r < 0) { | |
182 | log_error_errno(r, "could not add negative sysattr match '%s=%s': %m", key, val); | |
183 | return 2; | |
184 | } | |
912541b0 KS |
185 | break; |
186 | case 'p': | |
187 | key = keyval(optarg, &val, buf, sizeof(buf)); | |
56b13bcc TG |
188 | r = udev_enumerate_add_match_property(udev_enumerate, key, val); |
189 | if (r < 0) { | |
190 | log_error_errno(r, "could not add property match '%s=%s': %m", key, val); | |
191 | return 2; | |
192 | } | |
912541b0 KS |
193 | break; |
194 | case 'g': | |
56b13bcc TG |
195 | r = udev_enumerate_add_match_tag(udev_enumerate, optarg); |
196 | if (r < 0) { | |
197 | log_error_errno(r, "could not add tag match '%s': %m", optarg); | |
198 | return 2; | |
199 | } | |
912541b0 KS |
200 | break; |
201 | case 'y': | |
56b13bcc TG |
202 | r = udev_enumerate_add_match_sysname(udev_enumerate, optarg); |
203 | if (r < 0) { | |
204 | log_error_errno(r, "could not add sysname match '%s': %m", optarg); | |
205 | return 2; | |
206 | } | |
912541b0 KS |
207 | break; |
208 | case 'b': { | |
d6170d27 ZJS |
209 | _cleanup_udev_device_unref_ struct udev_device *dev; |
210 | ||
211 | dev = find_device(udev, optarg, "/sys"); | |
912541b0 | 212 | if (dev == NULL) { |
9f6445e3 | 213 | log_error("unable to open the device '%s'", optarg); |
44433ebd | 214 | return 2; |
912541b0 | 215 | } |
d6170d27 | 216 | |
56b13bcc TG |
217 | r = udev_enumerate_add_match_parent(udev_enumerate, dev); |
218 | if (r < 0) { | |
219 | log_error_errno(r, "could not add parent match '%s': %m", optarg); | |
220 | return 2; | |
221 | } | |
912541b0 KS |
222 | break; |
223 | } | |
d6170d27 | 224 | |
80877656 ZJS |
225 | case ARG_NAME: { |
226 | _cleanup_udev_device_unref_ struct udev_device *dev; | |
227 | ||
228 | dev = find_device(udev, optarg, "/dev/"); | |
229 | if (dev == NULL) { | |
230 | log_error("unable to open the device '%s'", optarg); | |
231 | return 2; | |
232 | } | |
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 | } | |
80877656 ZJS |
239 | break; |
240 | } | |
241 | ||
912541b0 | 242 | case 'h': |
7643ac9a | 243 | help(); |
44433ebd | 244 | return 0; |
7643ac9a | 245 | case '?': |
44433ebd | 246 | return 1; |
7643ac9a ZJS |
247 | default: |
248 | assert_not_reached("Unknown option"); | |
912541b0 KS |
249 | } |
250 | } | |
251 | ||
80877656 ZJS |
252 | for (; optind < argc; optind++) { |
253 | _cleanup_udev_device_unref_ struct udev_device *dev; | |
254 | ||
255 | dev = find_device(udev, argv[optind], NULL); | |
256 | if (dev == NULL) { | |
257 | log_error("unable to open the device '%s'", argv[optind]); | |
258 | return 2; | |
259 | } | |
260 | ||
56b13bcc TG |
261 | r = udev_enumerate_add_match_parent(udev_enumerate, dev); |
262 | if (r < 0) { | |
263 | log_error_errno(r, "could not add tag match '%s': %m", optarg); | |
264 | return 2; | |
265 | } | |
7643ac9a ZJS |
266 | } |
267 | ||
912541b0 KS |
268 | switch (device_type) { |
269 | case TYPE_SUBSYSTEMS: | |
270 | udev_enumerate_scan_subsystems(udev_enumerate); | |
271 | exec_list(udev_enumerate, action); | |
44433ebd | 272 | return 0; |
912541b0 KS |
273 | case TYPE_DEVICES: |
274 | udev_enumerate_scan_devices(udev_enumerate); | |
275 | exec_list(udev_enumerate, action); | |
44433ebd | 276 | return 0; |
912541b0 | 277 | default: |
4dd1de72 | 278 | assert_not_reached("device_type"); |
912541b0 | 279 | } |
0d5be398 | 280 | } |
1985c76e KS |
281 | |
282 | const struct udevadm_cmd udevadm_trigger = { | |
912541b0 KS |
283 | .name = "trigger", |
284 | .cmd = adm_trigger, | |
5ac0162c | 285 | .help = "Request events from the kernel", |
1985c76e | 286 | }; |