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