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