]> git.ipfire.org Git - thirdparty/systemd.git/blob - udevinfo.c
[PATCH] clarify udevinfo device walk
[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_version.h"
34 #include "logging.h"
35 #include "udevdb.h"
36
37
38 # define SYSFS_VALUE_MAX 200
39
40 char **main_argv;
41 int main_argc;
42
43 #ifdef LOG
44 unsigned char logname[42];
45 void log_message (int level, const char *format, ...)
46 {
47 va_list args;
48
49 va_start(args, format);
50 vsyslog(level, format, args);
51 va_end(args);
52 }
53 #endif
54
55 static int print_all_attributes(const char *path)
56 {
57 struct dlist *attributes;
58 struct sysfs_attribute *attr;
59 struct sysfs_directory *sysfs_dir;
60 char value[SYSFS_VALUE_MAX];
61 int len;
62 int retval = 0;
63
64 sysfs_dir = sysfs_open_directory(path);
65 if (sysfs_dir == NULL)
66 return -1;
67
68 attributes = sysfs_get_dir_attributes(sysfs_dir);
69 if (attributes == NULL) {
70 retval = -1;
71 goto exit;
72 }
73
74 dlist_for_each_data(attributes, attr, struct sysfs_attribute) {
75 if (attr->value != NULL) {
76 strfieldcpy(value, attr->value);
77 len = strlen(value);
78 if (len == 0)
79 continue;
80
81 /* remove trailing newline */
82 if (value[len-1] == '\n') {
83 value[len-1] = '\0';
84 len--;
85 }
86
87 /* skip nonprintable values */
88 while (len) {
89 if (isprint(value[len-1]) == 0)
90 break;
91 len--;
92 }
93 if (len == 0)
94 printf(" SYSFS{%s}=\"%s\"\n", attr->name, value);
95 }
96 }
97 printf("\n");
98
99 exit:
100 sysfs_close_directory(sysfs_dir);
101
102 return retval;
103 }
104
105 /* callback for database dump */
106 static int print_record(char *path, struct udevice *dev)
107 {
108 printf("P: %s\n", path);
109 printf("N: %s\n", dev->name);
110 printf("M: %#o\n", dev->mode);
111 printf("S: %s\n", dev->symlink);
112 printf("O: %s\n", dev->owner);
113 printf("G: %s\n", dev->group);
114 printf("\n");
115 return 0;
116 }
117
118 enum query_type {
119 NONE,
120 NAME,
121 PATH,
122 SYMLINK,
123 MODE,
124 OWNER,
125 GROUP,
126 ALL
127 };
128
129 static int print_device_chain(const char *path)
130 {
131 struct sysfs_class_device *class_dev;
132 struct sysfs_class_device *class_dev_parent;
133 struct sysfs_attribute *attr;
134 struct sysfs_device *sysfs_dev;
135 struct sysfs_device *sysfs_dev_parent;
136 int retval = 0;
137
138 /* get the class dev */
139 class_dev = sysfs_open_class_device_path(path);
140 if (class_dev == NULL) {
141 printf("couldn't get the class device\n");
142 return -1;
143 }
144
145 /* read the 'dev' file for major/minor*/
146 attr = sysfs_get_classdev_attr(class_dev, "dev");
147 if (attr == NULL) {
148 printf("couldn't get the \"dev\" file\n");
149 retval = -1;
150 goto exit;
151 }
152
153 printf("\nudevinfo starts with the device the node belongs to and then walks up the\n"
154 "device chain to print for every device found all possibly useful attributes\n"
155 "in the udev key format.\n"
156 "Only attributes within one device section may be used in a rule to match the\n"
157 "device for which the node will be created.\n"
158 "\n");
159 printf("device '%s' has major:minor %s", class_dev->path, attr->value);
160 sysfs_close_attribute(attr);
161
162 /* open sysfs class device directory and print all attributes */
163 printf(" looking at class device '%s':\n", class_dev->path);
164 if (print_all_attributes(class_dev->path) != 0) {
165 printf("couldn't open class device directory\n");
166 retval = -1;
167 goto exit;
168 }
169
170 /* get the device link (if parent exists look here) */
171 class_dev_parent = sysfs_get_classdev_parent(class_dev);
172 if (class_dev_parent != NULL) {
173 //sysfs_close_class_device(class_dev);
174 class_dev = class_dev_parent;
175 }
176 sysfs_dev = sysfs_get_classdev_device(class_dev);
177 if (sysfs_dev != NULL)
178 printf("follow the class device's \"device\"\n");
179
180 /* look the device chain upwards */
181 while (sysfs_dev != NULL) {
182 printf(" looking at the device chain at '%s':\n", sysfs_dev->path);
183 printf(" BUS=\"%s\"\n", sysfs_dev->bus);
184 printf(" ID=\"%s\"\n", sysfs_dev->bus_id);
185
186 /* open sysfs device directory and print all attributes */
187 print_all_attributes(sysfs_dev->path);
188
189 sysfs_dev_parent = sysfs_get_device_parent(sysfs_dev);
190 if (sysfs_dev_parent == NULL)
191 break;
192
193 //sysfs_close_device(sysfs_dev);
194 sysfs_dev = sysfs_dev_parent;
195 }
196 sysfs_close_device(sysfs_dev);
197
198 exit:
199 //sysfs_close_class_device(class_dev);
200 return retval;
201 }
202
203 static int process_options(void)
204 {
205 static const char short_options[] = "adn:p:q:rVh";
206 int option;
207 int retval = 1;
208 struct udevice dev;
209 int root = 0;
210 int attributes = 0;
211 enum query_type query = NONE;
212 char result[NAME_SIZE] = "";
213 char path[NAME_SIZE] = "";
214 char name[NAME_SIZE] = "";
215 char temp[NAME_SIZE];
216 char *pos;
217
218 /* get command line options */
219 while (1) {
220 option = getopt(main_argc, main_argv, short_options);
221 if (option == -1)
222 break;
223
224 dbg("option '%c'", option);
225 switch (option) {
226 case 'n':
227 dbg("udev name: %s\n", optarg);
228 strfieldcpy(name, optarg);
229 break;
230
231 case 'p':
232 dbg("udev path: %s\n", optarg);
233 strfieldcpy(path, optarg);
234 break;
235
236 case 'q':
237 dbg("udev query: %s\n", optarg);
238
239 if (strcmp(optarg, "name") == 0) {
240 query = NAME;
241 break;
242 }
243
244 if (strcmp(optarg, "symlink") == 0) {
245 query = SYMLINK;
246 break;
247 }
248
249 if (strcmp(optarg, "mode") == 0) {
250 query = MODE;
251 break;
252 }
253
254 if (strcmp(optarg, "owner") == 0) {
255 query = OWNER;
256 break;
257 }
258
259 if (strcmp(optarg, "group") == 0) {
260 query = GROUP;
261 break;
262 }
263
264 if (strcmp(optarg, "path") == 0) {
265 query = PATH;
266 break;
267 }
268
269 if (strcmp(optarg, "all") == 0) {
270 query = ALL;
271 break;
272 }
273
274 printf("unknown query type\n");
275 exit(1);
276
277 case 'r':
278 root = 1;
279 break;
280
281 case 'a':
282 attributes = 1;
283 break;
284
285 case 'd':
286 retval = udevdb_open_ro();
287 if (retval != 0) {
288 printf("unable to open udev database\n");
289 exit(2);
290 }
291 udevdb_call_foreach(print_record);
292 udevdb_exit();
293 exit(0);
294
295 case 'V':
296 printf("udevinfo, version %s\n", UDEV_VERSION);
297 exit(0);
298
299 case 'h':
300 retval = 0;
301 case '?':
302 default:
303 goto help;
304 }
305 }
306
307 /* process options */
308 if (query != NONE) {
309 retval = udevdb_open_ro();
310 if (retval != 0) {
311 printf("unable to open udev database\n");
312 return -EACCES;
313 }
314
315 if (path[0] != '\0') {
316 /* remove sysfs_path if given */
317 if (strncmp(path, sysfs_path, strlen(sysfs_path)) == 0) {
318 pos = path + strlen(sysfs_path);
319 } else {
320 if (path[0] != '/') {
321 /* prepend '/' if missing */
322 strfieldcat(temp, "/");
323 strfieldcat(temp, path);
324 pos = temp;
325 } else {
326 pos = path;
327 }
328 }
329 retval = udevdb_get_dev(pos, &dev);
330 if (retval != 0) {
331 printf("device not found in database\n");
332 goto exit;
333 }
334 goto print;
335 }
336
337 if (name[0] != '\0') {
338 /* remove udev_root if given */
339 if (strncmp(name, udev_root, strlen(udev_root)) == 0) {
340 pos = name + strlen(udev_root);
341 } else
342 pos = name;
343 retval = udevdb_get_dev_byname(pos, path, &dev);
344 if (retval != 0) {
345 printf("device not found in database\n");
346 goto exit;
347 }
348 goto print;
349 }
350
351 printf("query needs device path(-p) or node name(-n) specified\n");
352 goto exit;
353
354 print:
355 switch(query) {
356 case NAME:
357 if (root)
358 strfieldcpy(result, udev_root);
359 strfieldcat(result, dev.name);
360 break;
361
362 case SYMLINK:
363 strfieldcpy(result, dev.symlink);
364 break;
365
366 case MODE:
367 sprintf(result, "%#o", dev.mode);
368 break;
369
370 case GROUP:
371 strfieldcpy(result, dev.group);
372 break;
373
374 case OWNER:
375 strfieldcpy(result, dev.owner);
376 break;
377
378 case PATH:
379 strfieldcpy(result, path);
380 break;
381
382 case ALL:
383 print_record(path, &dev);
384 goto exit;
385
386 default:
387 goto exit;
388 }
389 printf("%s\n", result);
390
391 exit:
392 udevdb_exit();
393 return retval;
394 }
395
396 if (attributes) {
397 if (path[0] == '\0') {
398 printf("attribute walk on device chain needs path(-p) specified\n");
399 return -EINVAL;
400 } else {
401 if (strncmp(path, sysfs_path, strlen(sysfs_path)) != 0) {
402 /* prepend sysfs mountpoint if not given */
403 strfieldcpy(temp, path);
404 strfieldcpy(path, sysfs_path);
405 strfieldcat(path, temp);
406 }
407 print_device_chain(path);
408 return 0;
409 }
410 }
411
412 if (root) {
413 printf("%s\n", udev_root);
414 return 0;
415 }
416
417 help:
418 printf("Usage: [-anpqrdVh]\n"
419 " -q TYPE query database for the specified value:\n"
420 " 'name' name of device node\n"
421 " 'symlink' pointing to node\n"
422 " 'mode' permissions of node\n"
423 " 'owner' of node\n"
424 " 'group' of node\n"
425 " 'path' sysfs device path\n"
426 " 'all' all values\n"
427 "\n"
428 " -p PATH sysfs device path used for query or chain\n"
429 " -n NAME node/symlink name used for query\n"
430 "\n"
431 " -r print udev root\n"
432 " -a print all SYSFS_attributes along the device chain\n"
433 " -d dump whole database\n"
434 " -V print udev version\n"
435 " -h print this help text\n"
436 "\n");
437 return retval;
438 }
439
440 int main(int argc, char *argv[], char *envp[])
441 {
442 int retval;
443
444 main_argv = argv;
445 main_argc = argc;
446
447 init_logging("udevinfo");
448
449 /* initialize our configuration */
450 udev_init_config();
451
452 retval = process_options();
453 if (retval != 0)
454 exit(1);
455 exit(0);
456 }