]> git.ipfire.org Git - thirdparty/systemd.git/blob - udevinfo.c
[PATCH] replace fgets() with mmap() and introduce udev_lib.[hc]
[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("\n");
116 return 0;
117 }
118
119 enum query_type {
120 NONE,
121 NAME,
122 PATH,
123 SYMLINK,
124 MODE,
125 OWNER,
126 GROUP,
127 ALL
128 };
129
130 static int print_device_chain(const char *path)
131 {
132 struct sysfs_class_device *class_dev;
133 struct sysfs_class_device *class_dev_parent;
134 struct sysfs_attribute *attr;
135 struct sysfs_device *sysfs_dev;
136 struct sysfs_device *sysfs_dev_parent;
137 int retval = 0;
138
139 /* get the class dev */
140 class_dev = sysfs_open_class_device_path(path);
141 if (class_dev == NULL) {
142 printf("couldn't get the class device\n");
143 return -1;
144 }
145
146 /* read the 'dev' file for major/minor*/
147 attr = sysfs_get_classdev_attr(class_dev, "dev");
148 if (attr == NULL) {
149 printf("couldn't get the \"dev\" file\n");
150 retval = -1;
151 goto exit;
152 }
153
154 printf("\nudevinfo starts with the device the node belongs to and then walks up the\n"
155 "device chain, to print for every device found, all possibly useful attributes\n"
156 "in the udev key format.\n"
157 "Only attributes within one device section may be used together in one rule,\n"
158 "to match the device for which the node will be created.\n"
159 "\n");
160 printf("device '%s' has major:minor %s", class_dev->path, attr->value);
161 sysfs_close_attribute(attr);
162
163 /* open sysfs class device directory and print all attributes */
164 printf(" looking at class device '%s':\n", class_dev->path);
165 if (print_all_attributes(class_dev->path) != 0) {
166 printf("couldn't open class device directory\n");
167 retval = -1;
168 goto exit;
169 }
170
171 /* get the device link (if parent exists look here) */
172 class_dev_parent = sysfs_get_classdev_parent(class_dev);
173 if (class_dev_parent != NULL) {
174 //sysfs_close_class_device(class_dev);
175 class_dev = class_dev_parent;
176 }
177 sysfs_dev = sysfs_get_classdev_device(class_dev);
178 if (sysfs_dev != NULL)
179 printf("follow the class device's \"device\"\n");
180
181 /* look the device chain upwards */
182 while (sysfs_dev != NULL) {
183 printf(" looking at the device chain at '%s':\n", sysfs_dev->path);
184 printf(" BUS=\"%s\"\n", sysfs_dev->bus);
185 printf(" ID=\"%s\"\n", sysfs_dev->bus_id);
186
187 /* open sysfs device directory and print all attributes */
188 print_all_attributes(sysfs_dev->path);
189
190 sysfs_dev_parent = sysfs_get_device_parent(sysfs_dev);
191 if (sysfs_dev_parent == NULL)
192 break;
193
194 //sysfs_close_device(sysfs_dev);
195 sysfs_dev = sysfs_dev_parent;
196 }
197 sysfs_close_device(sysfs_dev);
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 }