]> git.ipfire.org Git - thirdparty/systemd.git/blob - udevinfo.c
[PATCH] klibc: remove SCCS directories from the temporary klibc install
[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 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation version 2 of the License.
9 *
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 675 Mass Ave, Cambridge, MA 02139, USA.
18 *
19 */
20
21 #include <stdlib.h>
22 #include <string.h>
23 #include <stdio.h>
24 #include <ctype.h>
25 #include <stdarg.h>
26 #include <unistd.h>
27 #include <errno.h>
28
29 #include "libsysfs/sysfs/libsysfs.h"
30 #include "udev_libc_wrapper.h"
31 #include "udev.h"
32 #include "udev_utils.h"
33 #include "udev_version.h"
34 #include "udev_db.h"
35 #include "logging.h"
36
37
38 #ifdef USE_LOG
39 void log_message (int level, const char *format, ...)
40 {
41 va_list args;
42
43 va_start(args, format);
44 vsyslog(level, format, args);
45 va_end(args);
46 }
47 #endif
48
49 static void print_all_attributes(struct dlist *attr_list)
50 {
51 struct sysfs_attribute *attr;
52 char value[VALUE_SIZE];
53 int len;
54
55 dlist_for_each_data(attr_list, attr, struct sysfs_attribute) {
56 if (attr->value != NULL) {
57 strlcpy(value, attr->value, sizeof(value));
58 len = strlen(value);
59 if (len == 0)
60 continue;
61
62 /* remove trailing newline */
63 if (value[len-1] == '\n') {
64 value[len-1] = '\0';
65 len--;
66 }
67
68 /* skip nonprintable values */
69 while (len) {
70 if (isprint(value[len-1]) == 0)
71 break;
72 len--;
73 }
74 if (len == 0)
75 printf(" SYSFS{%s}=\"%s\"\n", attr->name, value);
76 }
77 }
78 printf("\n");
79 }
80
81 static int print_record(struct udevice *udev)
82 {
83 struct name_entry *name_loop;
84
85 printf("P: %s\n", udev->devpath);
86 printf("N: %s\n", udev->name);
87 list_for_each_entry(name_loop, &udev->symlink_list, node)
88 printf("S: %s\n", name_loop->name);
89
90 return 0;
91 }
92
93 enum query_type {
94 NONE,
95 NAME,
96 PATH,
97 SYMLINK,
98 ALL,
99 };
100
101 static int print_device_chain(const char *path)
102 {
103 struct sysfs_class_device *class_dev;
104 struct sysfs_class_device *class_dev_parent;
105 struct sysfs_attribute *attr;
106 struct sysfs_device *sysfs_dev;
107 struct sysfs_device *sysfs_dev_parent;
108 struct dlist *attr_list;
109 int retval = 0;
110
111 /* get the class dev */
112 class_dev = sysfs_open_class_device_path(path);
113 if (class_dev == NULL) {
114 printf("couldn't get the class device\n");
115 return -1;
116 }
117
118 printf("\nudevinfo starts with the device the node belongs to and then walks up the\n"
119 "device chain, to print for every device found, all possibly useful attributes\n"
120 "in the udev key format.\n"
121 "Only attributes within one device section may be used together in one rule,\n"
122 "to match the device for which the node will be created.\n"
123 "\n");
124
125 /* look for the 'dev' file */
126 attr = sysfs_get_classdev_attr(class_dev, "dev");
127 if (attr != NULL)
128 printf("device '%s' has major:minor %s", class_dev->path, attr->value);
129
130 /* open sysfs class device directory and print all attributes */
131 printf(" looking at class device '%s':\n", class_dev->path);
132 printf(" SUBSYSTEM=\"%s\"\n", class_dev->classname);
133
134 attr_list = sysfs_get_classdev_attributes(class_dev);
135 if (attr_list == NULL) {
136 printf("couldn't open class device directory\n");
137 retval = -1;
138 goto exit;
139 }
140 print_all_attributes(attr_list);
141
142 /* get the device link (if parent exists look here) */
143 class_dev_parent = sysfs_get_classdev_parent(class_dev);
144 if (class_dev_parent != NULL)
145 sysfs_dev = sysfs_get_classdev_device(class_dev_parent);
146 else
147 sysfs_dev = sysfs_get_classdev_device(class_dev);
148
149 if (sysfs_dev != NULL)
150 printf("follow the class device's \"device\"\n");
151
152 /* look the device chain upwards */
153 while (sysfs_dev != NULL) {
154 attr_list = sysfs_get_device_attributes(sysfs_dev);
155 if (attr_list == NULL) {
156 printf("couldn't open device directory\n");
157 retval = -1;
158 goto exit;
159 }
160
161 printf(" looking at the device chain at '%s':\n", sysfs_dev->path);
162 printf(" BUS=\"%s\"\n", sysfs_dev->bus);
163 printf(" ID=\"%s\"\n", sysfs_dev->bus_id);
164 printf(" DRIVER=\"%s\"\n", sysfs_dev->driver_name);
165
166 /* open sysfs device directory and print all attributes */
167 print_all_attributes(attr_list);
168
169 sysfs_dev_parent = sysfs_get_device_parent(sysfs_dev);
170 if (sysfs_dev_parent == NULL)
171 break;
172
173 sysfs_dev = sysfs_dev_parent;
174 }
175
176 exit:
177 sysfs_close_class_device(class_dev);
178 return retval;
179 }
180
181 static int print_dump(const char *devpath, const char *name) {
182 printf("%s=%s/%s\n", devpath, udev_root, name);
183 return 0;
184 }
185
186 int main(int argc, char *argv[], char *envp[])
187 {
188 static const char short_options[] = "adn:p:q:rVh";
189 int option;
190 struct udevice udev;
191 int root = 0;
192 int attributes = 0;
193 enum query_type query = NONE;
194 char path[PATH_SIZE] = "";
195 char name[PATH_SIZE] = "";
196 char temp[PATH_SIZE];
197 struct name_entry *name_loop;
198 char *pos;
199 int retval = 0;
200
201 logging_init("udevinfo");
202
203 udev_init_config();
204 udev_init_device(&udev, NULL, NULL);
205
206 /* get command line options */
207 while (1) {
208 option = getopt(argc, argv, short_options);
209 if (option == -1)
210 break;
211
212 dbg("option '%c'", option);
213 switch (option) {
214 case 'n':
215 dbg("udev name: %s\n", optarg);
216 strlcpy(name, optarg, sizeof(name));
217 break;
218
219 case 'p':
220 dbg("udev path: %s\n", optarg);
221 strlcpy(path, optarg, sizeof(path));
222 break;
223
224 case 'q':
225 dbg("udev query: %s\n", optarg);
226
227 if (strcmp(optarg, "name") == 0) {
228 query = NAME;
229 break;
230 }
231
232 if (strcmp(optarg, "symlink") == 0) {
233 query = SYMLINK;
234 break;
235 }
236
237 if (strcmp(optarg, "path") == 0) {
238 query = PATH;
239 break;
240 }
241
242 if (strcmp(optarg, "all") == 0) {
243 query = ALL;
244 break;
245 }
246
247 printf("unknown query type\n");
248 retval = 1;
249 goto exit;
250
251 case 'r':
252 root = 1;
253 break;
254
255 case 'a':
256 attributes = 1;
257 break;
258
259 case 'd':
260 udev_db_dump_names(print_dump);
261 goto exit;
262
263 case 'V':
264 printf("udevinfo, version %s\n", UDEV_VERSION);
265 goto exit;
266
267 case 'h':
268 retval = 2;
269 case '?':
270 default:
271 goto help;
272 }
273 }
274
275 /* process options */
276 if (query != NONE) {
277 if (path[0] != '\0') {
278 /* remove sysfs_path if given */
279 if (strncmp(path, sysfs_path, strlen(sysfs_path)) == 0) {
280 pos = path + strlen(sysfs_path);
281 } else {
282 if (path[0] != '/') {
283 /* prepend '/' if missing */
284 strcpy(temp, "/");
285 strlcpy(temp, path, sizeof(temp));
286 pos = temp;
287 } else {
288 pos = path;
289 }
290 }
291 retval = udev_db_get_device(&udev, pos);
292 if (retval != 0) {
293 printf("device not found in database\n");
294 goto exit;
295 }
296 goto print;
297 }
298
299 if (name[0] != '\0') {
300 char devpath[PATH_SIZE];
301 int len;
302
303 /* remove udev_root if given */
304 len = strlen(udev_root);
305 if (strncmp(name, udev_root, len) == 0) {
306 pos = &name[len+1];
307 } else
308 pos = name;
309
310 retval = udev_db_search_name(devpath, sizeof(devpath), pos);
311 if (retval != 0) {
312 printf("device not found in database\n");
313 goto exit;
314 }
315 udev_db_get_device(&udev, devpath);
316 goto print;
317 }
318
319 printf("query needs device path(-p) or node name(-n) specified\n");
320 retval = 3;
321 goto exit;
322
323 print:
324 switch(query) {
325 case NAME:
326 if (root)
327 printf("%s/%s\n", udev_root, udev.name);
328 else
329 printf("%s\n", udev.name);
330 goto exit;
331 case SYMLINK:
332 if (list_empty(&udev.symlink_list))
333 break;
334 if (root)
335 list_for_each_entry(name_loop, &udev.symlink_list, node)
336 printf("%s/%s ", udev_root, name_loop->name);
337 else
338 list_for_each_entry(name_loop, &udev.symlink_list, node)
339 printf("%s ", name_loop->name);
340 printf("\n");
341 goto exit;
342 case PATH:
343 printf("%s\n", udev.devpath);
344 goto exit;
345 case ALL:
346 print_record(&udev);
347 goto exit;
348 default:
349 goto help;
350 }
351 }
352
353 if (attributes) {
354 if (path[0] == '\0') {
355 printf("attribute walk on device chain needs path(-p) specified\n");
356 retval = 4;
357 goto exit;
358 } else {
359 if (strncmp(path, sysfs_path, strlen(sysfs_path)) != 0) {
360 /* prepend sysfs mountpoint if not given */
361 snprintf(temp, sizeof(temp), "%s%s", sysfs_path, path);
362 temp[sizeof(temp)-1] = '\0';
363 strlcpy(path, temp, sizeof(temp));
364 }
365 print_device_chain(path);
366 goto exit;
367 }
368 }
369
370 if (root) {
371 printf("%s\n", udev_root);
372 goto exit;
373 }
374
375 help:
376 printf("Usage: udevinfo [-anpqrVh]\n"
377 " -q TYPE query database for the specified value:\n"
378 " 'name' name of device node\n"
379 " 'symlink' pointing to node\n"
380 " 'path' sysfs device path\n"
381 " 'all' all values\n"
382 "\n"
383 " -p PATH sysfs device path used for query or chain\n"
384 " -n NAME node/symlink name used for query\n"
385 "\n"
386 " -r print udev root\n"
387 " -a print all SYSFS_attributes along the device chain\n"
388 " -d print the relationship of devpath and the node name for all\n"
389 " devices available in the database\n"
390 " -V print udev version\n"
391 " -h print this help text\n"
392 "\n");
393
394 exit:
395 udev_cleanup_device(&udev);
396 logging_close();
397 return retval;
398 }