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