]> git.ipfire.org Git - thirdparty/systemd.git/blob - udevinfo.c
[PATCH] crap, I messed up the 'sed' instances pretty badly, this fixes the config...
[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("T: %c\n", dev->type);
112 printf("M: %#o\n", dev->mode);
113 printf("S: %s\n", dev->symlink);
114 printf("O: %s\n", dev->owner);
115 printf("G: %s\n", dev->group);
116 printf("F: %s\n", dev->config_file);
117 printf("L: %i\n", dev->config_line);
118 printf("U: %li\n", dev->config_uptime);
119 printf("\n");
120 return 0;
121 }
122
123 enum query_type {
124 NONE,
125 NAME,
126 PATH,
127 SYMLINK,
128 MODE,
129 OWNER,
130 GROUP,
131 ALL
132 };
133
134 static int print_device_chain(const char *path)
135 {
136 struct sysfs_class_device *class_dev;
137 struct sysfs_class_device *class_dev_parent;
138 struct sysfs_attribute *attr;
139 struct sysfs_device *sysfs_dev;
140 struct sysfs_device *sysfs_dev_parent;
141 int retval = 0;
142 char type;
143
144 type = get_device_type(path, "");
145 dbg("device type is %c", type);
146
147 /* get the class dev */
148 class_dev = sysfs_open_class_device_path(path);
149 if (class_dev == NULL) {
150 printf("couldn't get the class device\n");
151 return -1;
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
161 if (type == 'b' || type =='c') {
162 /* read the 'dev' file for major/minor*/
163 attr = sysfs_get_classdev_attr(class_dev, "dev");
164 if (attr == NULL) {
165 printf("couldn't get the \"dev\" file\n");
166 retval = -1;
167 goto exit;
168 }
169 printf("device '%s' has major:minor %s", class_dev->path, attr->value);
170 }
171
172 /* open sysfs class device directory and print all attributes */
173 printf(" looking at class device '%s':\n", class_dev->path);
174 if (print_all_attributes(class_dev->path) != 0) {
175 printf("couldn't open class device directory\n");
176 retval = -1;
177 goto exit;
178 }
179
180 /* get the device link (if parent exists look here) */
181 class_dev_parent = sysfs_get_classdev_parent(class_dev);
182 if (class_dev_parent != NULL)
183 sysfs_dev = sysfs_get_classdev_device(class_dev_parent);
184 else
185 sysfs_dev = sysfs_get_classdev_device(class_dev);
186
187 if (sysfs_dev != NULL)
188 printf("follow the class device's \"device\"\n");
189
190 /* look the device chain upwards */
191 while (sysfs_dev != NULL) {
192 printf(" looking at the device chain at '%s':\n", sysfs_dev->path);
193 printf(" BUS=\"%s\"\n", sysfs_dev->bus);
194 printf(" ID=\"%s\"\n", sysfs_dev->bus_id);
195
196 /* open sysfs device directory and print all attributes */
197 print_all_attributes(sysfs_dev->path);
198
199 sysfs_dev_parent = sysfs_get_device_parent(sysfs_dev);
200 if (sysfs_dev_parent == NULL)
201 break;
202
203 sysfs_dev = sysfs_dev_parent;
204 }
205
206 exit:
207 sysfs_close_class_device(class_dev);
208 return retval;
209 }
210
211 static int process_options(void)
212 {
213 static const char short_options[] = "adn:p:q:rVh";
214 int option;
215 int retval = 1;
216 struct udevice dev;
217 int root = 0;
218 int attributes = 0;
219 enum query_type query = NONE;
220 char result[NAME_SIZE] = "";
221 char path[NAME_SIZE] = "";
222 char name[NAME_SIZE] = "";
223 char temp[NAME_SIZE];
224 char *pos;
225
226 /* get command line options */
227 while (1) {
228 option = getopt(main_argc, main_argv, short_options);
229 if (option == -1)
230 break;
231
232 dbg("option '%c'", option);
233 switch (option) {
234 case 'n':
235 dbg("udev name: %s\n", optarg);
236 strfieldcpy(name, optarg);
237 break;
238
239 case 'p':
240 dbg("udev path: %s\n", optarg);
241 strfieldcpy(path, optarg);
242 break;
243
244 case 'q':
245 dbg("udev query: %s\n", optarg);
246
247 if (strcmp(optarg, "name") == 0) {
248 query = NAME;
249 break;
250 }
251
252 if (strcmp(optarg, "symlink") == 0) {
253 query = SYMLINK;
254 break;
255 }
256
257 if (strcmp(optarg, "mode") == 0) {
258 query = MODE;
259 break;
260 }
261
262 if (strcmp(optarg, "owner") == 0) {
263 query = OWNER;
264 break;
265 }
266
267 if (strcmp(optarg, "group") == 0) {
268 query = GROUP;
269 break;
270 }
271
272 if (strcmp(optarg, "path") == 0) {
273 query = PATH;
274 break;
275 }
276
277 if (strcmp(optarg, "all") == 0) {
278 query = ALL;
279 break;
280 }
281
282 printf("unknown query type\n");
283 exit(1);
284
285 case 'r':
286 root = 1;
287 break;
288
289 case 'a':
290 attributes = 1;
291 break;
292
293 case 'd':
294 retval = udevdb_open_ro();
295 if (retval != 0) {
296 printf("unable to open udev database\n");
297 exit(2);
298 }
299 udevdb_call_foreach(print_record);
300 udevdb_exit();
301 exit(0);
302
303 case 'V':
304 printf("udevinfo, version %s\n", UDEV_VERSION);
305 exit(0);
306
307 case 'h':
308 retval = 0;
309 case '?':
310 default:
311 goto help;
312 }
313 }
314
315 /* process options */
316 if (query != NONE) {
317 retval = udevdb_open_ro();
318 if (retval != 0) {
319 printf("unable to open udev database\n");
320 return -EACCES;
321 }
322
323 if (path[0] != '\0') {
324 /* remove sysfs_path if given */
325 if (strncmp(path, sysfs_path, strlen(sysfs_path)) == 0) {
326 pos = path + strlen(sysfs_path);
327 } else {
328 if (path[0] != '/') {
329 /* prepend '/' if missing */
330 strfieldcat(temp, "/");
331 strfieldcat(temp, path);
332 pos = temp;
333 } else {
334 pos = path;
335 }
336 }
337 retval = udevdb_get_dev(pos, &dev);
338 if (retval != 0) {
339 printf("device not found in database\n");
340 goto exit;
341 }
342 goto print;
343 }
344
345 if (name[0] != '\0') {
346 /* remove udev_root if given */
347 if (strncmp(name, udev_root, strlen(udev_root)) == 0) {
348 pos = name + strlen(udev_root);
349 } else
350 pos = name;
351 retval = udevdb_get_dev_byname(pos, path, &dev);
352 if (retval != 0) {
353 printf("device not found in database\n");
354 goto exit;
355 }
356 goto print;
357 }
358
359 printf("query needs device path(-p) or node name(-n) specified\n");
360 goto exit;
361
362 print:
363 switch(query) {
364 case NAME:
365 if (root)
366 strfieldcpy(result, udev_root);
367 strfieldcat(result, dev.name);
368 break;
369
370 case SYMLINK:
371 strfieldcpy(result, dev.symlink);
372 break;
373
374 case MODE:
375 sprintf(result, "%#o", dev.mode);
376 break;
377
378 case GROUP:
379 strfieldcpy(result, dev.group);
380 break;
381
382 case OWNER:
383 strfieldcpy(result, dev.owner);
384 break;
385
386 case PATH:
387 strfieldcpy(result, path);
388 break;
389
390 case ALL:
391 print_record(path, &dev);
392 goto exit;
393
394 default:
395 goto exit;
396 }
397 printf("%s\n", result);
398
399 exit:
400 udevdb_exit();
401 return retval;
402 }
403
404 if (attributes) {
405 if (path[0] == '\0') {
406 printf("attribute walk on device chain needs path(-p) specified\n");
407 return -EINVAL;
408 } else {
409 if (strncmp(path, sysfs_path, strlen(sysfs_path)) != 0) {
410 /* prepend sysfs mountpoint if not given */
411 strfieldcpy(temp, path);
412 strfieldcpy(path, sysfs_path);
413 strfieldcat(path, temp);
414 }
415 print_device_chain(path);
416 return 0;
417 }
418 }
419
420 if (root) {
421 printf("%s\n", udev_root);
422 return 0;
423 }
424
425 help:
426 printf("Usage: [-anpqrdVh]\n"
427 " -q TYPE query database for the specified value:\n"
428 " 'name' name of device node\n"
429 " 'symlink' pointing to node\n"
430 " 'mode' permissions of node\n"
431 " 'owner' of node\n"
432 " 'group' of node\n"
433 " 'path' sysfs device path\n"
434 " 'all' all values\n"
435 "\n"
436 " -p PATH sysfs device path used for query or chain\n"
437 " -n NAME node/symlink name used for query\n"
438 "\n"
439 " -r print udev root\n"
440 " -a print all SYSFS_attributes along the device chain\n"
441 " -d dump whole database\n"
442 " -V print udev version\n"
443 " -h print this help text\n"
444 "\n");
445 return retval;
446 }
447
448 int main(int argc, char *argv[], char *envp[])
449 {
450 int retval;
451
452 main_argv = argv;
453 main_argc = argc;
454
455 init_logging("udevinfo");
456
457 /* initialize our configuration */
458 udev_init_config();
459
460 retval = process_options();
461 if (retval != 0)
462 exit(1);
463 exit(0);
464 }