]> git.ipfire.org Git - thirdparty/systemd.git/blame - udevinfo.c
add $driver subtitution
[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>
492e76c9
KS
29#include <sys/stat.h>
30#include <sys/types.h>
be9b51f6 31
869fc2f1 32#include "udev.h"
be9b51f6
KS
33
34
6c18b1fb 35#ifdef USE_LOG
6b493a20 36void log_message (int priority, const char *format, ...)
51a8bb2f 37{
d026a35d
GKH
38 va_list args;
39
6b493a20
KS
40 if (priority > udev_log_priority)
41 return;
42
d026a35d 43 va_start(args, format);
6b493a20 44 vsyslog(priority, format, args);
d026a35d 45 va_end(args);
51a8bb2f 46}
d026a35d 47#endif
51a8bb2f 48
95776dc6 49static void print_all_attributes(const char *devpath, const char *key)
be9b51f6 50{
1aa1e248
KS
51 char path[PATH_SIZE];
52 DIR *dir;
53 struct dirent *dent;
54
55 strlcpy(path, sysfs_path, sizeof(path));
56 strlcat(path, devpath, sizeof(path));
57
58 dir = opendir(path);
59 if (dir != NULL) {
60 for (dent = readdir(dir); dent != NULL; dent = readdir(dir)) {
492e76c9
KS
61 struct stat statbuf;
62 char filename[PATH_SIZE];
1aa1e248
KS
63 char *attr_value;
64 char value[NAME_SIZE];
65 size_t len;
66
492e76c9
KS
67 if (dent->d_name[0] == '.')
68 continue;
69
70 strlcpy(filename, path, sizeof(filename));
71 strlcat(filename, "/", sizeof(filename));
72 strlcat(filename, dent->d_name, sizeof(filename));
73 if (lstat(filename, &statbuf) != 0)
74 continue;
75 if (S_ISLNK(statbuf.st_mode))
76 continue;
77
1aa1e248
KS
78 attr_value = sysfs_attr_get_value(devpath, dent->d_name);
79 if (attr_value == NULL)
80 continue;
81 len = strlcpy(value, attr_value, sizeof(value));
82 dbg("attr '%s'='%s'(%zi)", dent->d_name, value, len);
83
84 /* remove trailing newlines */
85 while (len && value[len-1] == '\n')
86 value[--len] = '\0';
87
88 /* skip nonprintable attributes */
89 while (len && isprint(value[len-1]))
90 len--;
91 if (len) {
92 dbg("attribute value of '%s' non-printable, skip", dent->d_name);
93 continue;
94 }
6276fdd2 95
2f2c4fa4 96 replace_chars(value, ALLOWED_CHARS_INPUT);
95776dc6 97 printf(" %s{%s}==\"%s\"\n", key, dent->d_name, value);
6276fdd2 98 }
be9b51f6
KS
99 }
100 printf("\n");
be9b51f6
KS
101}
102
1aa1e248 103static int print_device_chain(const char *devpath)
87171e46 104{
1aa1e248 105 struct sysfs_device *dev;
e48fc108 106
bc2a89fa
KS
107 dev = sysfs_device_get(devpath);
108 if (dev == NULL)
109 return -1;
110
1aa1e248 111 printf("\n"
6cf19e52
KS
112 "Udevinfo starts with the device specified by the devpath and then\n"
113 "walks up the chain of parent devices. It prints for every device\n"
114 "found, all possible attributes in the udev rules key format.\n"
115 "A rule to match, can be composed by the attributes of the device\n"
116 "and the attributes from one single parent device.\n"
dba8c18b 117 "\n");
f61d732a 118
1aa1e248 119 printf(" looking at device '%s':\n", dev->devpath);
95776dc6 120 printf(" KERNEL==\"%s\"\n", dev->kernel);
1aa1e248 121 printf(" SUBSYSTEM==\"%s\"\n", dev->subsystem);
22f5934a 122 printf(" DRIVER==\"%s\"\n", dev->driver);
95776dc6 123 print_all_attributes(dev->devpath, "ATTR");
034f35d7 124
1aa1e248
KS
125 /* walk up the chain of devices */
126 while (1) {
127 dev = sysfs_device_get_parent(dev);
128 if (dev == NULL)
034f35d7 129 break;
6cf19e52 130 printf(" looking at parent device '%s':\n", dev->devpath);
95776dc6 131 printf(" KERNELS==\"%s\"\n", dev->kernel);
64e0ce85 132 printf(" SUBSYSTEMS==\"%s\"\n", dev->subsystem);
95776dc6 133 printf(" DRIVERS==\"%s\"\n", dev->driver);
1aa1e248 134
95776dc6 135 print_all_attributes(dev->devpath, "ATTRS");
be9b51f6
KS
136 }
137
1aa1e248
KS
138 return 0;
139}
140
141static void print_record(struct udevice *udev)
142{
143 struct name_entry *name_loop;
144
145 printf("P: %s\n", udev->dev->devpath);
146 printf("N: %s\n", udev->name);
147 list_for_each_entry(name_loop, &udev->symlink_list, node)
148 printf("S: %s\n", name_loop->name);
019d6669
KS
149 if (udev->link_priority != 0)
150 printf("L: %i\n", udev->link_priority);
151 if (udev->partitions != 0)
152 printf("A:%u\n", udev->partitions);
153 if (udev->ignore_remove)
154 printf("R:%u\n", udev->ignore_remove);
1aa1e248
KS
155 list_for_each_entry(name_loop, &udev->env_list, node)
156 printf("E: %s\n", name_loop->name);
be9b51f6 157}
87171e46 158
3045132a 159static void export_db(void) {
db481105
KS
160 LIST_HEAD(name_list);
161 struct name_entry *name_loop;
db481105
KS
162
163 udev_db_get_all_entries(&name_list);
fb179207 164 list_for_each_entry(name_loop, &name_list, node) {
1aa1e248 165 struct udevice *udev_db;
db481105 166
31de3a2b 167 udev_db = udev_device_init(NULL);
1aa1e248
KS
168 if (udev_db == NULL)
169 continue;
170 if (udev_db_get_device(udev_db, name_loop->name) == 0)
3045132a
KS
171 print_record(udev_db);
172 printf("\n");
1aa1e248 173 udev_device_cleanup(udev_db);
db481105 174 }
fb179207 175 name_list_cleanup(&name_list);
9fe1a96d
KS
176}
177
31de3a2b
KS
178static int lookup_device_by_name(struct udevice *udev, const char *name)
179{
180 LIST_HEAD(name_list);
be8594ab 181 int count;
31de3a2b
KS
182 struct name_entry *device;
183 int rc = -1;
184
be8594ab
KS
185 count = udev_db_get_devices_by_name(name, &name_list);
186 if (count <= 0)
31de3a2b
KS
187 goto out;
188
be8594ab
KS
189 info("found %i devices for '%s'", count, name);
190
191 /* select the device that seems to match */
31de3a2b
KS
192 list_for_each_entry(device, &name_list, node) {
193 char filename[PATH_SIZE];
194 struct stat statbuf;
195
196 udev_device_init(udev);
197 if (udev_db_get_device(udev, device->name) != 0)
198 continue;
199 info("found db entry '%s'", device->name);
200
be8594ab 201 /* make sure, we don't get a link of a differnt device */
31de3a2b
KS
202 strlcpy(filename, udev_root, sizeof(filename));
203 strlcat(filename, "/", sizeof(filename));
204 strlcat(filename, name, sizeof(filename));
205 if (stat(filename, &statbuf) != 0)
206 continue;
be8594ab
KS
207 if (major(udev->devt) > 0 && udev->devt != statbuf.st_rdev) {
208 info("skip '%s', dev_t doesn't match", udev->name);
209 continue;
31de3a2b 210 }
be8594ab
KS
211 rc = 0;
212 break;
31de3a2b
KS
213 }
214out:
215 name_list_cleanup(&name_list);
216 return rc;
217}
218
e48fc108 219int main(int argc, char *argv[], char *envp[])
87171e46 220{
87171e46 221 int option;
1aa1e248 222 struct udevice *udev;
87171e46 223 int root = 0;
24ca5c33 224
e97717ba 225 static const struct option options[] = {
11f1bb5a
KS
226 { "name", 1, NULL, 'n' },
227 { "path", 1, NULL, 'p' },
228 { "query", 1, NULL, 'q' },
229 { "attribute-walk", 0, NULL, 'a' },
230 { "export-db", 0, NULL, 'e' },
231 { "root", 0, NULL, 'r' },
88caa9da 232 { "version", 0, NULL, 1 }, /* -V outputs braindead format */
11f1bb5a
KS
233 { "help", 0, NULL, 'h' },
234 {}
235 };
236
24ca5c33
KS
237 enum action_type {
238 ACTION_NONE,
239 ACTION_QUERY,
240 ACTION_ATTRIBUTE_WALK,
241 ACTION_ROOT,
242 } action = ACTION_NONE;
243
b8476286
KS
244 enum query_type {
245 QUERY_NONE,
246 QUERY_NAME,
247 QUERY_PATH,
248 QUERY_SYMLINK,
249 QUERY_ENV,
250 QUERY_ALL,
251 } query = QUERY_NONE;
24ca5c33 252
63f61c5c
KS
253 char path[PATH_SIZE] = "";
254 char name[PATH_SIZE] = "";
e48fc108 255 struct name_entry *name_loop;
1aa1e248 256 int rc = 0;
e48fc108
KS
257
258 logging_init("udevinfo");
1aa1e248
KS
259 udev_config_init();
260 sysfs_init();
261
31de3a2b 262 udev = udev_device_init(NULL);
1aa1e248
KS
263 if (udev == NULL) {
264 rc = 1;
265 goto exit;
266 }
87171e46 267
87171e46 268 while (1) {
3045132a 269 option = getopt_long(argc, argv, "aen:p:q:rVh", options, NULL);
87171e46
KS
270 if (option == -1)
271 break;
272
273 dbg("option '%c'", option);
274 switch (option) {
275 case 'n':
2362eea6
KS
276 /* remove /dev if given */
277 if (strncmp(optarg, udev_root, strlen(udev_root)) == 0)
278 strlcpy(name, &optarg[strlen(udev_root)+1], sizeof(name));
279 else
280 strlcpy(name, optarg, sizeof(name));
92b229c7 281 dbg("name: %s", name);
87171e46 282 break;
87171e46 283 case 'p':
2362eea6 284 /* remove /sys if given */
1aa1e248
KS
285 if (strncmp(optarg, sysfs_path, strlen(sysfs_path)) == 0)
286 strlcpy(path, &optarg[strlen(sysfs_path)], sizeof(path));
287 else
288 strlcpy(path, optarg, sizeof(path));
92b229c7 289 dbg("path: %s", path);
87171e46 290 break;
87171e46 291 case 'q':
24ca5c33 292 action = ACTION_QUERY;
87171e46 293 if (strcmp(optarg, "name") == 0) {
b8476286 294 query = QUERY_NAME;
87171e46
KS
295 break;
296 }
87171e46 297 if (strcmp(optarg, "symlink") == 0) {
b8476286 298 query = QUERY_SYMLINK;
87171e46
KS
299 break;
300 }
87171e46 301 if (strcmp(optarg, "path") == 0) {
b8476286
KS
302 query = QUERY_PATH;
303 break;
304 }
b8476286
KS
305 if (strcmp(optarg, "env") == 0) {
306 query = QUERY_ENV;
87171e46
KS
307 break;
308 }
8ea84a8a 309 if (strcmp(optarg, "all") == 0) {
b8476286 310 query = QUERY_ALL;
8ea84a8a
KS
311 break;
312 }
61b1b706 313 fprintf(stderr, "unknown query type\n");
1aa1e248 314 rc = 2;
e48fc108 315 goto exit;
87171e46 316 case 'r':
24ca5c33
KS
317 if (action == ACTION_NONE)
318 action = ACTION_ROOT;
87171e46
KS
319 root = 1;
320 break;
87171e46 321 case 'a':
24ca5c33 322 action = ACTION_ATTRIBUTE_WALK;
87171e46 323 break;
24ca5c33 324 case 'e':
3045132a 325 export_db();
e48fc108 326 goto exit;
88caa9da
KS
327 case 1:
328 printf("%s\n", UDEV_VERSION);
329 goto exit;
87171e46 330 case 'V':
869fc2f1 331 printf("udevinfo, version %s\n", UDEV_VERSION);
e48fc108 332 goto exit;
87171e46 333 case 'h':
11f1bb5a
KS
334 printf("Usage: udevinfo OPTIONS\n"
335 " --query=<type> query database for the specified value:\n"
336 " name name of device node\n"
337 " symlink pointing to node\n"
338 " path sysfs device path\n"
339 " env the device related imported environment\n"
340 " all all values\n"
e3396a2d 341 "\n"
11f1bb5a
KS
342 " --path=<devpath> sysfs device path used for query or chain\n"
343 " --name=<name> node or symlink name used for query\n"
e3396a2d 344 "\n"
11f1bb5a
KS
345 " --root prepend to query result or print udev_root\n"
346 " --attribute-walk print all SYSFS_attributes along the device chain\n"
347 " --export-db export the content of the udev database\n"
11f1bb5a 348 " --help print this text\n"
e3396a2d
KS
349 "\n");
350 goto exit;
87171e46 351 default:
24ca5c33 352 goto exit;
87171e46
KS
353 }
354 }
355
24ca5c33
KS
356 /* run action */
357 switch (action) {
358 case ACTION_QUERY:
2362eea6 359 /* needs devpath or node/symlink name for query */
87171e46 360 if (path[0] != '\0') {
2362eea6
KS
361 if (udev_db_get_device(udev, path) != 0) {
362 fprintf(stderr, "no record for '%s' in database\n", path);
1aa1e248 363 rc = 3;
87171e46
KS
364 goto exit;
365 }
24ca5c33 366 } else if (name[0] != '\0') {
31de3a2b 367 if (lookup_device_by_name(udev, name) != 0) {
2362eea6
KS
368 fprintf(stderr, "node name not found\n");
369 rc = 4;
87171e46
KS
370 goto exit;
371 }
24ca5c33 372 } else {
11f1bb5a 373 fprintf(stderr, "query needs --path or node --name specified\n");
1aa1e248 374 rc = 4;
24ca5c33 375 goto exit;
87171e46
KS
376 }
377
87171e46 378 switch(query) {
b8476286 379 case QUERY_NAME:
e48fc108 380 if (root)
1aa1e248 381 printf("%s/%s\n", udev_root, udev->name);
e48fc108 382 else
1aa1e248 383 printf("%s\n", udev->name);
24ca5c33 384 break;
b8476286 385 case QUERY_SYMLINK:
1aa1e248 386 if (list_empty(&udev->symlink_list))
a1ea706a 387 goto exit;
e48fc108 388 if (root)
1aa1e248 389 list_for_each_entry(name_loop, &udev->symlink_list, node)
e48fc108
KS
390 printf("%s/%s ", udev_root, name_loop->name);
391 else
1aa1e248 392 list_for_each_entry(name_loop, &udev->symlink_list, node)
e48fc108
KS
393 printf("%s ", name_loop->name);
394 printf("\n");
24ca5c33 395 break;
b8476286 396 case QUERY_PATH:
1aa1e248 397 printf("%s\n", udev->dev->devpath);
e48fc108 398 goto exit;
b8476286 399 case QUERY_ENV:
1aa1e248 400 list_for_each_entry(name_loop, &udev->env_list, node)
b8476286 401 printf("%s\n", name_loop->name);
24ca5c33 402 break;
b8476286 403 case QUERY_ALL:
1aa1e248 404 print_record(udev);
24ca5c33 405 break;
87171e46 406 default:
e3396a2d 407 fprintf(stderr, "unknown query type\n");
24ca5c33 408 break;
87171e46 409 }
24ca5c33
KS
410 break;
411 case ACTION_ATTRIBUTE_WALK:
1aa0c52b 412 if (path[0] != '\0') {
bc2a89fa 413 if (print_device_chain(path) != 0) {
fd807192 414 fprintf(stderr, "no valid sysfs device found\n");
bc2a89fa
KS
415 rc = 4;
416 goto exit;
417 }
1aa0c52b 418 } else if (name[0] != '\0') {
31de3a2b 419 if (lookup_device_by_name(udev, name) != 0) {
1aa0c52b
KS
420 fprintf(stderr, "node name not found\n");
421 rc = 4;
422 goto exit;
423 }
31de3a2b 424 if (print_device_chain(udev->dev->devpath) != 0) {
fd807192 425 fprintf(stderr, "no valid sysfs device found\n");
bc2a89fa
KS
426 rc = 4;
427 goto exit;
428 }
1aa0c52b 429 } else {
11f1bb5a 430 fprintf(stderr, "attribute walk needs --path or node --name specified\n");
1aa0c52b
KS
431 rc = 5;
432 goto exit;
433 }
24ca5c33
KS
434 break;
435 case ACTION_ROOT:
87171e46 436 printf("%s\n", udev_root);
24ca5c33
KS
437 break;
438 default:
e3396a2d 439 fprintf(stderr, "missing option\n");
1aa1e248 440 rc = 1;
24ca5c33 441 break;
87171e46
KS
442 }
443
e48fc108 444exit:
1aa1e248
KS
445 udev_device_cleanup(udev);
446 sysfs_cleanup();
7257cb18 447 logging_close();
1aa1e248 448 return rc;
87171e46 449}