]> git.ipfire.org Git - thirdparty/systemd.git/blob - udevinfo.c
[PATCH] klibc supports LOG_PID now, so remove our own implementation
[thirdparty/systemd.git] / udevinfo.c
1 /*
2 * udevinfo - fetches attributes for a device
3 *
4 * Copyright (C) 2004 Kay Sievers <kay.sievers@vrfy.org>
5 *
6 *
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by the
9 * Free Software Foundation version 2 of the License.
10 *
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License along
17 * with this program; if not, write to the Free Software Foundation, Inc.,
18 * 675 Mass Ave, Cambridge, MA 02139, USA.
19 *
20 */
21
22 #include <stdlib.h>
23 #include <string.h>
24 #include <stdio.h>
25 #include <ctype.h>
26 #include <stdarg.h>
27 #include <unistd.h>
28 #include <errno.h>
29
30 #include "libsysfs/sysfs/libsysfs.h"
31 #include "libsysfs/dlist.h"
32 #include "udev.h"
33 #include "udev_utils.h"
34 #include "udev_version.h"
35 #include "udev_db.h"
36 #include "logging.h"
37
38
39 #define SYSFS_VALUE_SIZE 256
40
41 #ifdef LOG
42 void log_message (int level, const char *format, ...)
43 {
44 va_list args;
45
46 va_start(args, format);
47 vsyslog(level, format, args);
48 va_end(args);
49 }
50 #endif
51
52 static int print_all_attributes(const char *path)
53 {
54 struct dlist *attributes;
55 struct sysfs_attribute *attr;
56 struct sysfs_directory *sysfs_dir;
57 char value[SYSFS_VALUE_SIZE];
58 int len;
59 int retval = 0;
60
61 sysfs_dir = sysfs_open_directory(path);
62 if (sysfs_dir == NULL)
63 return -1;
64
65 attributes = sysfs_get_dir_attributes(sysfs_dir);
66 if (attributes == NULL) {
67 retval = -1;
68 goto exit;
69 }
70
71 dlist_for_each_data(attributes, attr, struct sysfs_attribute) {
72 if (attr->value != NULL) {
73 strfieldcpy(value, attr->value);
74 len = strlen(value);
75 if (len == 0)
76 continue;
77
78 /* remove trailing newline */
79 if (value[len-1] == '\n') {
80 value[len-1] = '\0';
81 len--;
82 }
83
84 /* skip nonprintable values */
85 while (len) {
86 if (isprint(value[len-1]) == 0)
87 break;
88 len--;
89 }
90 if (len == 0)
91 printf(" SYSFS{%s}=\"%s\"\n", attr->name, value);
92 }
93 }
94 printf("\n");
95
96 exit:
97 sysfs_close_directory(sysfs_dir);
98
99 return retval;
100 }
101
102 static int print_record(struct udevice *udev)
103 {
104 printf("P: %s\n", udev->devpath);
105 printf("N: %s\n", udev->name);
106 printf("S: %s\n", udev->symlink);
107 printf("\n");
108 return 0;
109 }
110
111 enum query_type {
112 NONE,
113 NAME,
114 PATH,
115 SYMLINK,
116 ALL
117 };
118
119 static int print_device_chain(const char *path)
120 {
121 struct sysfs_class_device *class_dev;
122 struct sysfs_class_device *class_dev_parent;
123 struct sysfs_attribute *attr;
124 struct sysfs_device *sysfs_dev;
125 struct sysfs_device *sysfs_dev_parent;
126 int retval = 0;
127
128 /* get the class dev */
129 class_dev = sysfs_open_class_device_path(path);
130 if (class_dev == NULL) {
131 printf("couldn't get the class device\n");
132 return -1;
133 }
134
135 printf("\nudevinfo starts with the device the node belongs to and then walks up the\n"
136 "device chain, to print for every device found, all possibly useful attributes\n"
137 "in the udev key format.\n"
138 "Only attributes within one device section may be used together in one rule,\n"
139 "to match the device for which the node will be created.\n"
140 "\n");
141
142 /* look for the 'dev' file */
143 attr = sysfs_get_classdev_attr(class_dev, "dev");
144 if (attr != NULL)
145 printf("device '%s' has major:minor %s", class_dev->path, attr->value);
146
147 /* open sysfs class device directory and print all attributes */
148 printf(" looking at class device '%s':\n", class_dev->path);
149 if (print_all_attributes(class_dev->path) != 0) {
150 printf("couldn't open class device directory\n");
151 retval = -1;
152 goto exit;
153 }
154
155 /* get the device link (if parent exists look here) */
156 class_dev_parent = sysfs_get_classdev_parent(class_dev);
157 if (class_dev_parent != NULL)
158 sysfs_dev = sysfs_get_classdev_device(class_dev_parent);
159 else
160 sysfs_dev = sysfs_get_classdev_device(class_dev);
161
162 if (sysfs_dev != NULL)
163 printf("follow the class device's \"device\"\n");
164
165 /* look the device chain upwards */
166 while (sysfs_dev != NULL) {
167 printf(" looking at the device chain at '%s':\n", sysfs_dev->path);
168 printf(" BUS=\"%s\"\n", sysfs_dev->bus);
169 printf(" ID=\"%s\"\n", sysfs_dev->bus_id);
170
171 /* open sysfs device directory and print all attributes */
172 print_all_attributes(sysfs_dev->path);
173
174 sysfs_dev_parent = sysfs_get_device_parent(sysfs_dev);
175 if (sysfs_dev_parent == NULL)
176 break;
177
178 sysfs_dev = sysfs_dev_parent;
179 }
180
181 exit:
182 sysfs_close_class_device(class_dev);
183 return retval;
184 }
185
186 /* print all class/main block devices with major/minor, physical device, driver and bus */
187 static int print_sysfs_devices(void)
188 {
189 struct dlist *subsyslist;
190 char *class;
191
192 subsyslist = sysfs_open_subsystem_list("class");
193 if (!subsyslist)
194 return -1;
195
196 dlist_for_each_data(subsyslist, class, char) {
197 struct sysfs_class *cls;
198 struct dlist *class_devices;
199 struct sysfs_class_device *class_dev;
200 struct sysfs_device *phys_dev;
201 unsigned int major, minor;
202
203 cls = sysfs_open_class(class);
204 if (!cls)
205 continue;
206
207 class_devices = sysfs_get_class_devices(cls);
208 if (!class_devices)
209 continue;
210
211 dlist_for_each_data(class_devices, class_dev, struct sysfs_class_device) {
212 struct sysfs_attribute *attr;
213
214 printf("\n");
215 printf("DEVPATH '%s'\n", class_dev->path);
216 printf("SUBSYSTEM '%s'\n", class_dev->classname);
217
218 attr = sysfs_get_classdev_attr(class_dev, "dev");
219 if (attr) {
220 sscanf(attr->value, "%u:%u", &major, &minor);
221 printf("MAJOR %u\n", minor);
222 printf("MINOR %u\n", major);
223 }
224
225 phys_dev = sysfs_get_classdev_device(class_dev);
226 if (phys_dev) {
227 printf("PHYSDEVPATH '%s'\n", phys_dev->path);
228 if (phys_dev->bus[0] != '\0')
229 printf("PHYSDEVBUS '%s'\n", phys_dev->bus);
230
231 if (phys_dev->driver_name[0] != '\0')
232 printf("PHYSDEVDRIVER '%s'\n", phys_dev->driver_name);
233 }
234 }
235 sysfs_close_class(cls);
236 }
237 sysfs_close_list(subsyslist);
238
239 return 0;
240 }
241
242 static int process_options(int argc, char *argv[])
243 {
244 static const char short_options[] = "an:p:q:rsVh";
245 int option;
246 int retval = 1;
247 struct udevice udev;
248 int root = 0;
249 int attributes = 0;
250 enum query_type query = NONE;
251 char result[1024] = "";
252 char path[NAME_SIZE] = "";
253 char name[NAME_SIZE] = "";
254 char temp[NAME_SIZE];
255 char *pos;
256
257 /* get command line options */
258 while (1) {
259 option = getopt(argc, argv, short_options);
260 if (option == -1)
261 break;
262
263 dbg("option '%c'", option);
264 switch (option) {
265 case 'n':
266 dbg("udev name: %s\n", optarg);
267 strfieldcpy(name, optarg);
268 break;
269
270 case 'p':
271 dbg("udev path: %s\n", optarg);
272 strfieldcpy(path, optarg);
273 break;
274
275 case 'q':
276 dbg("udev query: %s\n", optarg);
277
278 if (strcmp(optarg, "name") == 0) {
279 query = NAME;
280 break;
281 }
282
283 if (strcmp(optarg, "symlink") == 0) {
284 query = SYMLINK;
285 break;
286 }
287
288 if (strcmp(optarg, "path") == 0) {
289 query = PATH;
290 break;
291 }
292
293 if (strcmp(optarg, "all") == 0) {
294 query = ALL;
295 break;
296 }
297
298 printf("unknown query type\n");
299 exit(1);
300
301 case 'r':
302 root = 1;
303 break;
304
305 case 's':
306 print_sysfs_devices();
307 exit(0);
308
309 case 'a':
310 attributes = 1;
311 break;
312
313 case 'V':
314 printf("udevinfo, version %s\n", UDEV_VERSION);
315 exit(0);
316
317 case 'h':
318 retval = 0;
319 case '?':
320 default:
321 goto help;
322 }
323 }
324
325 /* process options */
326 if (query != NONE) {
327 if (path[0] != '\0') {
328 /* remove sysfs_path if given */
329 if (strncmp(path, sysfs_path, strlen(sysfs_path)) == 0) {
330 pos = path + strlen(sysfs_path);
331 } else {
332 if (path[0] != '/') {
333 /* prepend '/' if missing */
334 strfieldcat(temp, "/");
335 strfieldcat(temp, path);
336 pos = temp;
337 } else {
338 pos = path;
339 }
340 }
341 memset(&udev, 0x00, sizeof(struct udevice));
342 strfieldcpy(udev.devpath, pos);
343 retval = udev_db_get_device(&udev);
344 if (retval != 0) {
345 printf("device not found in database\n");
346 goto exit;
347 }
348 goto print;
349 }
350
351 if (name[0] != '\0') {
352 /* remove udev_root if given */
353 int len = strlen(udev_root);
354
355 if (strncmp(name, udev_root, len) == 0) {
356 pos = &name[len+1];
357 } else
358 pos = name;
359
360 memset(&udev, 0x00, sizeof(struct udevice));
361 strfieldcpy(udev.name, pos);
362 retval = udev_db_get_device_byname(&udev, pos);
363 if (retval != 0) {
364 printf("device not found in database\n");
365 goto exit;
366 }
367
368 goto print;
369 }
370
371 printf("query needs device path(-p) or node name(-n) specified\n");
372 goto exit;
373
374 print:
375 switch(query) {
376 case NAME:
377 if (root) {
378 snprintf(result, NAME_SIZE-1, "%s/%s", udev_root, udev.name);
379 result[NAME_SIZE-1] = '\0';
380 } else {
381 strfieldcpy(result, udev.name);
382 }
383 break;
384
385 case SYMLINK:
386 if (root) {
387 int slen;
388 char *spos;
389 char slink[NAME_SIZE];
390
391 pos = result;
392 foreach_strpart(udev.symlink, " \n\r", spos, slen) {
393 strncpy(slink, spos, slen);
394 slink[slen] = '\0';
395 pos += sprintf(pos, "%s/%s ", udev_root, slink);
396 }
397 } else {
398 strfieldcpy(result, udev.symlink);
399 }
400 break;
401
402 case PATH:
403 strfieldcpy(result, udev.devpath);
404 break;
405
406 case ALL:
407 print_record(&udev);
408 goto exit;
409
410 default:
411 goto exit;
412 }
413 printf("%s\n", result);
414
415 exit:
416 return retval;
417 }
418
419 if (attributes) {
420 if (path[0] == '\0') {
421 printf("attribute walk on device chain needs path(-p) specified\n");
422 return -EINVAL;
423 } else {
424 if (strncmp(path, sysfs_path, strlen(sysfs_path)) != 0) {
425 /* prepend sysfs mountpoint if not given */
426 strfieldcpy(temp, path);
427 strfieldcpy(path, sysfs_path);
428 strfieldcat(path, temp);
429 }
430 print_device_chain(path);
431 return 0;
432 }
433 }
434
435 if (root) {
436 printf("%s\n", udev_root);
437 return 0;
438 }
439
440 help:
441 printf("Usage: udevinfo [-anpqrVh]\n"
442 " -q TYPE query database for the specified value:\n"
443 " 'name' name of device node\n"
444 " 'symlink' pointing to node\n"
445 " 'path' sysfs device path\n"
446 " 'all' all values\n"
447 "\n"
448 " -p PATH sysfs device path used for query or chain\n"
449 " -n NAME node/symlink name used for query\n"
450 "\n"
451 " -r print udev root\n"
452 " -a print all SYSFS_attributes along the device chain\n"
453 " -s print all sysfs devices with major/minor, physical device and bus\n"
454 " -V print udev version\n"
455 " -h print this help text\n"
456 "\n");
457 return retval;
458 }
459
460 int main(int argc, char *argv[], char *envp[])
461 {
462 int rc = 0;
463
464 logging_init("udevinfo");
465
466 /* initialize our configuration */
467 udev_init_config();
468
469 rc = process_options(argc, argv);
470
471 logging_close();
472 exit(rc);
473 }