]> git.ipfire.org Git - thirdparty/systemd.git/blame - udevinfo.c
cdrom_id: add rules file to call cdrom_id
[thirdparty/systemd.git] / udevinfo.c
CommitLineData
be9b51f6 1/*
27b77df4 2 * Copyright (C) 2004-2006 Kay Sievers <kay.sievers@vrfy.org>
be9b51f6 3 *
be9b51f6
KS
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License as published by the
6 * Free Software Foundation version 2 of the License.
7 *
8 * This program is distributed in the hope that it will be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 * General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License along
14 * with this program; if not, write to the Free Software Foundation, Inc.,
27b77df4 15 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
be9b51f6
KS
16 *
17 */
18
19#include <stdlib.h>
20#include <string.h>
21#include <stdio.h>
1aa1e248 22#include <stddef.h>
034f35d7 23#include <ctype.h>
87171e46
KS
24#include <stdarg.h>
25#include <unistd.h>
1aa1e248 26#include <dirent.h>
87171e46 27#include <errno.h>
11f1bb5a 28#include <getopt.h>
be9b51f6 29
869fc2f1 30#include "udev.h"
be9b51f6
KS
31
32
6c18b1fb 33#ifdef USE_LOG
6b493a20 34void log_message (int priority, const char *format, ...)
51a8bb2f 35{
d026a35d
GKH
36 va_list args;
37
6b493a20
KS
38 if (priority > udev_log_priority)
39 return;
40
d026a35d 41 va_start(args, format);
6b493a20 42 vsyslog(priority, format, args);
d026a35d 43 va_end(args);
51a8bb2f 44}
d026a35d 45#endif
51a8bb2f 46
95776dc6 47static void print_all_attributes(const char *devpath, const char *key)
be9b51f6 48{
1aa1e248
KS
49 char path[PATH_SIZE];
50 DIR *dir;
51 struct dirent *dent;
52
53 strlcpy(path, sysfs_path, sizeof(path));
54 strlcat(path, devpath, sizeof(path));
55
56 dir = opendir(path);
57 if (dir != NULL) {
58 for (dent = readdir(dir); dent != NULL; dent = readdir(dir)) {
59 char *attr_value;
60 char value[NAME_SIZE];
61 size_t len;
62
63 attr_value = sysfs_attr_get_value(devpath, dent->d_name);
64 if (attr_value == NULL)
65 continue;
66 len = strlcpy(value, attr_value, sizeof(value));
67 dbg("attr '%s'='%s'(%zi)", dent->d_name, value, len);
68
69 /* remove trailing newlines */
70 while (len && value[len-1] == '\n')
71 value[--len] = '\0';
72
73 /* skip nonprintable attributes */
74 while (len && isprint(value[len-1]))
75 len--;
76 if (len) {
77 dbg("attribute value of '%s' non-printable, skip", dent->d_name);
78 continue;
79 }
6276fdd2 80
1aa1e248 81 replace_untrusted_chars(value);
95776dc6 82 printf(" %s{%s}==\"%s\"\n", key, dent->d_name, value);
6276fdd2 83 }
be9b51f6
KS
84 }
85 printf("\n");
be9b51f6
KS
86}
87
1aa1e248 88static int print_device_chain(const char *devpath)
87171e46 89{
1aa1e248 90 struct sysfs_device *dev;
e48fc108 91
1aa1e248 92 printf("\n"
6cf19e52
KS
93 "Udevinfo starts with the device specified by the devpath and then\n"
94 "walks up the chain of parent devices. It prints for every device\n"
95 "found, all possible attributes in the udev rules key format.\n"
96 "A rule to match, can be composed by the attributes of the device\n"
97 "and the attributes from one single parent device.\n"
dba8c18b 98 "\n");
f61d732a 99
1aa1e248
KS
100 dev = sysfs_device_get(devpath);
101 if (dev == NULL)
102 return -1;
f385ff65 103
1aa1e248 104 printf(" looking at device '%s':\n", dev->devpath);
95776dc6 105 printf(" KERNEL==\"%s\"\n", dev->kernel);
1aa1e248 106 printf(" SUBSYSTEM==\"%s\"\n", dev->subsystem);
22f5934a 107 printf(" DRIVER==\"%s\"\n", dev->driver);
95776dc6 108 print_all_attributes(dev->devpath, "ATTR");
034f35d7 109
1aa1e248
KS
110 /* walk up the chain of devices */
111 while (1) {
112 dev = sysfs_device_get_parent(dev);
113 if (dev == NULL)
034f35d7 114 break;
6cf19e52 115 printf(" looking at parent device '%s':\n", dev->devpath);
95776dc6 116 printf(" KERNELS==\"%s\"\n", dev->kernel);
64e0ce85 117 printf(" SUBSYSTEMS==\"%s\"\n", dev->subsystem);
95776dc6 118 printf(" DRIVERS==\"%s\"\n", dev->driver);
1aa1e248 119
95776dc6 120 print_all_attributes(dev->devpath, "ATTRS");
be9b51f6
KS
121 }
122
1aa1e248
KS
123 return 0;
124}
125
126static void print_record(struct udevice *udev)
127{
128 struct name_entry *name_loop;
129
130 printf("P: %s\n", udev->dev->devpath);
131 printf("N: %s\n", udev->name);
132 list_for_each_entry(name_loop, &udev->symlink_list, node)
133 printf("S: %s\n", name_loop->name);
134 list_for_each_entry(name_loop, &udev->env_list, node)
135 printf("E: %s\n", name_loop->name);
be9b51f6 136}
87171e46 137
ae8cc07b 138static void export_name_devpath(struct udevice *udev) {
1aa1e248 139 printf("%s=%s/%s\n", udev->dev->devpath, udev_root, udev->name);
24ca5c33
KS
140}
141
ae8cc07b 142static void export_record(struct udevice *udev) {
24ca5c33
KS
143 print_record(udev);
144 printf("\n");
145}
146
ae8cc07b 147static void export_db(void fnct(struct udevice *udev)) {
db481105
KS
148 LIST_HEAD(name_list);
149 struct name_entry *name_loop;
db481105
KS
150
151 udev_db_get_all_entries(&name_list);
fb179207 152 list_for_each_entry(name_loop, &name_list, node) {
1aa1e248 153 struct udevice *udev_db;
db481105 154
1aa1e248
KS
155 udev_db = udev_device_init();
156 if (udev_db == NULL)
157 continue;
158 if (udev_db_get_device(udev_db, name_loop->name) == 0)
159 fnct(udev_db);
160 udev_device_cleanup(udev_db);
db481105 161 }
fb179207 162 name_list_cleanup(&name_list);
9fe1a96d
KS
163}
164
e48fc108 165int main(int argc, char *argv[], char *envp[])
87171e46 166{
87171e46 167 int option;
1aa1e248 168 struct udevice *udev;
87171e46 169 int root = 0;
24ca5c33 170
e97717ba 171 static const struct option options[] = {
11f1bb5a
KS
172 { "name", 1, NULL, 'n' },
173 { "path", 1, NULL, 'p' },
174 { "query", 1, NULL, 'q' },
175 { "attribute-walk", 0, NULL, 'a' },
176 { "export-db", 0, NULL, 'e' },
177 { "root", 0, NULL, 'r' },
178 { "version", 0, NULL, 'V' },
179 { "help", 0, NULL, 'h' },
180 {}
181 };
182
24ca5c33
KS
183 enum action_type {
184 ACTION_NONE,
185 ACTION_QUERY,
186 ACTION_ATTRIBUTE_WALK,
187 ACTION_ROOT,
188 } action = ACTION_NONE;
189
b8476286
KS
190 enum query_type {
191 QUERY_NONE,
192 QUERY_NAME,
193 QUERY_PATH,
194 QUERY_SYMLINK,
195 QUERY_ENV,
196 QUERY_ALL,
197 } query = QUERY_NONE;
24ca5c33 198
63f61c5c
KS
199 char path[PATH_SIZE] = "";
200 char name[PATH_SIZE] = "";
e48fc108 201 struct name_entry *name_loop;
1aa1e248 202 int rc = 0;
e48fc108
KS
203
204 logging_init("udevinfo");
1aa1e248
KS
205 udev_config_init();
206 sysfs_init();
207
208 udev = udev_device_init();
209 if (udev == NULL) {
210 rc = 1;
211 goto exit;
212 }
87171e46
KS
213
214 /* get command line options */
215 while (1) {
11f1bb5a 216 option = getopt_long(argc, argv, "aden:p:q:rVh", options, NULL);
87171e46
KS
217 if (option == -1)
218 break;
219
220 dbg("option '%c'", option);
221 switch (option) {
222 case 'n':
2362eea6
KS
223 /* remove /dev if given */
224 if (strncmp(optarg, udev_root, strlen(udev_root)) == 0)
225 strlcpy(name, &optarg[strlen(udev_root)+1], sizeof(name));
226 else
227 strlcpy(name, optarg, sizeof(name));
228 dbg("name: %s\n", name);
87171e46 229 break;
87171e46 230 case 'p':
2362eea6 231 /* remove /sys if given */
1aa1e248
KS
232 if (strncmp(optarg, sysfs_path, strlen(sysfs_path)) == 0)
233 strlcpy(path, &optarg[strlen(sysfs_path)], sizeof(path));
234 else
235 strlcpy(path, optarg, sizeof(path));
2362eea6 236 dbg("path: %s\n", path);
87171e46 237 break;
87171e46
KS
238 case 'q':
239 dbg("udev query: %s\n", optarg);
24ca5c33 240 action = ACTION_QUERY;
87171e46 241 if (strcmp(optarg, "name") == 0) {
b8476286 242 query = QUERY_NAME;
87171e46
KS
243 break;
244 }
87171e46 245 if (strcmp(optarg, "symlink") == 0) {
b8476286 246 query = QUERY_SYMLINK;
87171e46
KS
247 break;
248 }
87171e46 249 if (strcmp(optarg, "path") == 0) {
b8476286
KS
250 query = QUERY_PATH;
251 break;
252 }
b8476286
KS
253 if (strcmp(optarg, "env") == 0) {
254 query = QUERY_ENV;
87171e46
KS
255 break;
256 }
8ea84a8a 257 if (strcmp(optarg, "all") == 0) {
b8476286 258 query = QUERY_ALL;
8ea84a8a
KS
259 break;
260 }
61b1b706 261 fprintf(stderr, "unknown query type\n");
1aa1e248 262 rc = 2;
e48fc108 263 goto exit;
87171e46 264 case 'r':
24ca5c33
KS
265 if (action == ACTION_NONE)
266 action = ACTION_ROOT;
87171e46
KS
267 root = 1;
268 break;
87171e46 269 case 'a':
24ca5c33 270 action = ACTION_ATTRIBUTE_WALK;
87171e46 271 break;
9fe1a96d 272 case 'd':
ae8cc07b 273 export_db(export_name_devpath);
24ca5c33
KS
274 goto exit;
275 case 'e':
ae8cc07b 276 export_db(export_record);
e48fc108 277 goto exit;
87171e46 278 case 'V':
869fc2f1 279 printf("udevinfo, version %s\n", UDEV_VERSION);
e48fc108 280 goto exit;
87171e46 281 case 'h':
11f1bb5a
KS
282 printf("Usage: udevinfo OPTIONS\n"
283 " --query=<type> query database for the specified value:\n"
284 " name name of device node\n"
285 " symlink pointing to node\n"
286 " path sysfs device path\n"
287 " env the device related imported environment\n"
288 " all all values\n"
e3396a2d 289 "\n"
11f1bb5a
KS
290 " --path=<devpath> sysfs device path used for query or chain\n"
291 " --name=<name> node or symlink name used for query\n"
e3396a2d 292 "\n"
11f1bb5a
KS
293 " --root prepend to query result or print udev_root\n"
294 " --attribute-walk print all SYSFS_attributes along the device chain\n"
295 " --export-db export the content of the udev database\n"
296 " --verision print udev version\n"
297 " --help print this text\n"
e3396a2d
KS
298 "\n");
299 goto exit;
87171e46 300 default:
24ca5c33 301 goto exit;
87171e46
KS
302 }
303 }
304
24ca5c33
KS
305 /* run action */
306 switch (action) {
307 case ACTION_QUERY:
2362eea6 308 /* needs devpath or node/symlink name for query */
87171e46 309 if (path[0] != '\0') {
2362eea6
KS
310 if (udev_db_get_device(udev, path) != 0) {
311 fprintf(stderr, "no record for '%s' in database\n", path);
1aa1e248 312 rc = 3;
87171e46
KS
313 goto exit;
314 }
24ca5c33 315 } else if (name[0] != '\0') {
63f61c5c 316 char devpath[PATH_SIZE];
2b41e68a 317
2362eea6
KS
318 if (udev_db_lookup_name(name, devpath, sizeof(devpath)) != 0) {
319 fprintf(stderr, "node name not found\n");
320 rc = 4;
87171e46
KS
321 goto exit;
322 }
1aa1e248 323 udev_db_get_device(udev, devpath);
24ca5c33 324 } else {
11f1bb5a 325 fprintf(stderr, "query needs --path or node --name specified\n");
1aa1e248 326 rc = 4;
24ca5c33 327 goto exit;
87171e46
KS
328 }
329
87171e46 330 switch(query) {
b8476286 331 case QUERY_NAME:
e48fc108 332 if (root)
1aa1e248 333 printf("%s/%s\n", udev_root, udev->name);
e48fc108 334 else
1aa1e248 335 printf("%s\n", udev->name);
24ca5c33 336 break;
b8476286 337 case QUERY_SYMLINK:
1aa1e248 338 if (list_empty(&udev->symlink_list))
a1ea706a 339 goto exit;
e48fc108 340 if (root)
1aa1e248 341 list_for_each_entry(name_loop, &udev->symlink_list, node)
e48fc108
KS
342 printf("%s/%s ", udev_root, name_loop->name);
343 else
1aa1e248 344 list_for_each_entry(name_loop, &udev->symlink_list, node)
e48fc108
KS
345 printf("%s ", name_loop->name);
346 printf("\n");
24ca5c33 347 break;
b8476286 348 case QUERY_PATH:
1aa1e248 349 printf("%s\n", udev->dev->devpath);
e48fc108 350 goto exit;
b8476286 351 case QUERY_ENV:
1aa1e248 352 list_for_each_entry(name_loop, &udev->env_list, node)
b8476286 353 printf("%s\n", name_loop->name);
24ca5c33 354 break;
b8476286 355 case QUERY_ALL:
1aa1e248 356 print_record(udev);
24ca5c33 357 break;
87171e46 358 default:
e3396a2d 359 fprintf(stderr, "unknown query type\n");
24ca5c33 360 break;
87171e46 361 }
24ca5c33
KS
362 break;
363 case ACTION_ATTRIBUTE_WALK:
1aa0c52b 364 if (path[0] != '\0') {
87171e46 365 print_device_chain(path);
1aa0c52b
KS
366 } else if (name[0] != '\0') {
367 char devpath[PATH_SIZE];
368
369 if (udev_db_lookup_name(name, devpath, sizeof(devpath)) != 0) {
370 fprintf(stderr, "node name not found\n");
371 rc = 4;
372 goto exit;
373 }
374 print_device_chain(devpath);
375 } else {
11f1bb5a 376 fprintf(stderr, "attribute walk needs --path or node --name specified\n");
1aa0c52b
KS
377 rc = 5;
378 goto exit;
379 }
24ca5c33
KS
380 break;
381 case ACTION_ROOT:
87171e46 382 printf("%s\n", udev_root);
24ca5c33
KS
383 break;
384 default:
e3396a2d 385 fprintf(stderr, "missing option\n");
1aa1e248 386 rc = 1;
24ca5c33 387 break;
87171e46
KS
388 }
389
e48fc108 390exit:
1aa1e248
KS
391 udev_device_cleanup(udev);
392 sysfs_cleanup();
7257cb18 393 logging_close();
1aa1e248 394 return rc;
87171e46 395}