Allow IPv6 address entry in tools>ping - Loosens valid character check
[tomato/davidwu.git] / release / src / router / udev / udevinfo.c
blobd0b1c447f4d65f2692b026996333dbf58f8f0328
1 /*
2 * Copyright (C) 2004-2006 Kay Sievers <kay.sievers@vrfy.org>
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License as published by the
6 * Free Software Foundation version 2 of the License.
7 *
8 * This program is distributed in the hope that it will be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 * General Public License for more details.
13 * You should have received a copy of the GNU General Public License along
14 * with this program; if not, write to the Free Software Foundation, Inc.,
15 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19 #include <stdlib.h>
20 #include <string.h>
21 #include <stdio.h>
22 #include <stddef.h>
23 #include <ctype.h>
24 #include <stdarg.h>
25 #include <unistd.h>
26 #include <dirent.h>
27 #include <errno.h>
28 #include <getopt.h>
29 #include <sys/stat.h>
30 #include <sys/types.h>
32 #include "udev.h"
35 #ifdef USE_LOG
36 void log_message (int priority, const char *format, ...)
38 va_list args;
40 if (priority > udev_log_priority)
41 return;
43 va_start(args, format);
44 vsyslog(priority, format, args);
45 va_end(args);
47 #endif
49 static void print_all_attributes(const char *devpath, const char *key)
51 char path[PATH_SIZE];
52 DIR *dir;
53 struct dirent *dent;
55 strlcpy(path, sysfs_path, sizeof(path));
56 strlcat(path, devpath, sizeof(path));
58 dir = opendir(path);
59 if (dir != NULL) {
60 for (dent = readdir(dir); dent != NULL; dent = readdir(dir)) {
61 struct stat statbuf;
62 char filename[PATH_SIZE];
63 char *attr_value;
64 char value[NAME_SIZE];
65 size_t len;
67 if (dent->d_name[0] == '.')
68 continue;
70 strlcpy(filename, path, sizeof(filename));
71 strlcat(filename, "/", sizeof(filename));
72 strlcat(filename, dent->d_name, sizeof(filename));
73 if (lstat(filename, &statbuf) != 0)
74 continue;
75 if (S_ISLNK(statbuf.st_mode))
76 continue;
78 attr_value = sysfs_attr_get_value(devpath, dent->d_name);
79 if (attr_value == NULL)
80 continue;
81 len = strlcpy(value, attr_value, sizeof(value));
82 dbg("attr '%s'='%s'(%zi)", dent->d_name, value, len);
84 /* remove trailing newlines */
85 while (len && value[len-1] == '\n')
86 value[--len] = '\0';
88 /* skip nonprintable attributes */
89 while (len && isprint(value[len-1]))
90 len--;
91 if (len) {
92 dbg("attribute value of '%s' non-printable, skip", dent->d_name);
93 continue;
96 replace_chars(value, ALLOWED_CHARS_INPUT);
97 printf(" %s{%s}==\"%s\"\n", key, dent->d_name, value);
100 printf("\n");
103 static int print_device_chain(const char *devpath)
105 struct sysfs_device *dev;
107 dev = sysfs_device_get(devpath);
108 if (dev == NULL)
109 return -1;
111 printf("\n"
112 "Udevinfo starts with the device specified by the devpath and then\n"
113 "walks up the chain of parent devices. It prints for every device\n"
114 "found, all possible attributes in the udev rules key format.\n"
115 "A rule to match, can be composed by the attributes of the device\n"
116 "and the attributes from one single parent device.\n"
117 "\n");
119 printf(" looking at device '%s':\n", dev->devpath);
120 printf(" KERNEL==\"%s\"\n", dev->kernel);
121 printf(" SUBSYSTEM==\"%s\"\n", dev->subsystem);
122 printf(" DRIVER==\"%s\"\n", dev->driver);
123 print_all_attributes(dev->devpath, "ATTR");
125 /* walk up the chain of devices */
126 while (1) {
127 dev = sysfs_device_get_parent(dev);
128 if (dev == NULL)
129 break;
130 printf(" looking at parent device '%s':\n", dev->devpath);
131 printf(" KERNELS==\"%s\"\n", dev->kernel);
132 printf(" SUBSYSTEMS==\"%s\"\n", dev->subsystem);
133 printf(" DRIVERS==\"%s\"\n", dev->driver);
135 print_all_attributes(dev->devpath, "ATTRS");
138 return 0;
141 static void print_record(struct udevice *udev)
143 struct name_entry *name_loop;
145 printf("P: %s\n", udev->dev->devpath);
146 printf("N: %s\n", udev->name);
147 list_for_each_entry(name_loop, &udev->symlink_list, node)
148 printf("S: %s\n", name_loop->name);
149 if (udev->link_priority != 0)
150 printf("L: %i\n", udev->link_priority);
151 if (udev->partitions != 0)
152 printf("A:%u\n", udev->partitions);
153 if (udev->ignore_remove)
154 printf("R:%u\n", udev->ignore_remove);
155 list_for_each_entry(name_loop, &udev->env_list, node)
156 printf("E: %s\n", name_loop->name);
159 static void export_db(void) {
160 LIST_HEAD(name_list);
161 struct name_entry *name_loop;
163 udev_db_get_all_entries(&name_list);
164 list_for_each_entry(name_loop, &name_list, node) {
165 struct udevice *udev_db;
167 udev_db = udev_device_init(NULL);
168 if (udev_db == NULL)
169 continue;
170 if (udev_db_get_device(udev_db, name_loop->name) == 0)
171 print_record(udev_db);
172 printf("\n");
173 udev_device_cleanup(udev_db);
175 name_list_cleanup(&name_list);
178 static int lookup_device_by_name(struct udevice *udev, const char *name)
180 LIST_HEAD(name_list);
181 int count;
182 struct name_entry *device;
183 int rc = -1;
185 count = udev_db_get_devices_by_name(name, &name_list);
186 if (count <= 0)
187 goto out;
189 info("found %i devices for '%s'", count, name);
191 /* select the device that seems to match */
192 list_for_each_entry(device, &name_list, node) {
193 char filename[PATH_SIZE];
194 struct stat statbuf;
196 udev_device_init(udev);
197 if (udev_db_get_device(udev, device->name) != 0)
198 continue;
199 info("found db entry '%s'", device->name);
201 /* make sure, we don't get a link of a differnt device */
202 strlcpy(filename, udev_root, sizeof(filename));
203 strlcat(filename, "/", sizeof(filename));
204 strlcat(filename, name, sizeof(filename));
205 if (stat(filename, &statbuf) != 0)
206 continue;
207 if (major(udev->devt) > 0 && udev->devt != statbuf.st_rdev) {
208 info("skip '%s', dev_t doesn't match", udev->name);
209 continue;
211 rc = 0;
212 break;
214 out:
215 name_list_cleanup(&name_list);
216 return rc;
219 int main(int argc, char *argv[], char *envp[])
221 int option;
222 struct udevice *udev;
223 int root = 0;
225 static const struct option options[] = {
226 { "name", 1, NULL, 'n' },
227 { "path", 1, NULL, 'p' },
228 { "query", 1, NULL, 'q' },
229 { "attribute-walk", 0, NULL, 'a' },
230 { "export-db", 0, NULL, 'e' },
231 { "root", 0, NULL, 'r' },
232 { "version", 0, NULL, 1 }, /* -V outputs braindead format */
233 { "help", 0, NULL, 'h' },
237 enum action_type {
238 ACTION_NONE,
239 ACTION_QUERY,
240 ACTION_ATTRIBUTE_WALK,
241 ACTION_ROOT,
242 } action = ACTION_NONE;
244 enum query_type {
245 QUERY_NONE,
246 QUERY_NAME,
247 QUERY_PATH,
248 QUERY_SYMLINK,
249 QUERY_ENV,
250 QUERY_ALL,
251 } query = QUERY_NONE;
253 char path[PATH_SIZE] = "";
254 char name[PATH_SIZE] = "";
255 struct name_entry *name_loop;
256 int rc = 0;
258 logging_init("udevinfo");
259 udev_config_init();
260 sysfs_init();
262 udev = udev_device_init(NULL);
263 if (udev == NULL) {
264 rc = 1;
265 goto exit;
268 while (1) {
269 option = getopt_long(argc, argv, "aen:p:q:rVh", options, NULL);
270 if (option == -1)
271 break;
273 dbg("option '%c'", option);
274 switch (option) {
275 case 'n':
276 /* remove /dev if given */
277 if (strncmp(optarg, udev_root, strlen(udev_root)) == 0)
278 strlcpy(name, &optarg[strlen(udev_root)+1], sizeof(name));
279 else
280 strlcpy(name, optarg, sizeof(name));
281 dbg("name: %s", name);
282 break;
283 case 'p':
284 /* remove /sys if given */
285 if (strncmp(optarg, sysfs_path, strlen(sysfs_path)) == 0)
286 strlcpy(path, &optarg[strlen(sysfs_path)], sizeof(path));
287 else
288 strlcpy(path, optarg, sizeof(path));
289 dbg("path: %s", path);
290 break;
291 case 'q':
292 action = ACTION_QUERY;
293 if (strcmp(optarg, "name") == 0) {
294 query = QUERY_NAME;
295 break;
297 if (strcmp(optarg, "symlink") == 0) {
298 query = QUERY_SYMLINK;
299 break;
301 if (strcmp(optarg, "path") == 0) {
302 query = QUERY_PATH;
303 break;
305 if (strcmp(optarg, "env") == 0) {
306 query = QUERY_ENV;
307 break;
309 if (strcmp(optarg, "all") == 0) {
310 query = QUERY_ALL;
311 break;
313 fprintf(stderr, "unknown query type\n");
314 rc = 2;
315 goto exit;
316 case 'r':
317 if (action == ACTION_NONE)
318 action = ACTION_ROOT;
319 root = 1;
320 break;
321 case 'a':
322 action = ACTION_ATTRIBUTE_WALK;
323 break;
324 case 'e':
325 export_db();
326 goto exit;
327 case 1:
328 printf("%s\n", UDEV_VERSION);
329 goto exit;
330 case 'V':
331 printf("udevinfo, version %s\n", UDEV_VERSION);
332 goto exit;
333 case 'h':
334 printf("Usage: udevinfo OPTIONS\n"
335 " --query=<type> query database for the specified value:\n"
336 " name name of device node\n"
337 " symlink pointing to node\n"
338 " path sysfs device path\n"
339 " env the device related imported environment\n"
340 " all all values\n"
341 "\n"
342 " --path=<devpath> sysfs device path used for query or chain\n"
343 " --name=<name> node or symlink name used for query\n"
344 "\n"
345 " --root prepend to query result or print udev_root\n"
346 " --attribute-walk print all SYSFS_attributes along the device chain\n"
347 " --export-db export the content of the udev database\n"
348 " --help print this text\n"
349 "\n");
350 goto exit;
351 default:
352 goto exit;
356 /* run action */
357 switch (action) {
358 case ACTION_QUERY:
359 /* needs devpath or node/symlink name for query */
360 if (path[0] != '\0') {
361 if (udev_db_get_device(udev, path) != 0) {
362 fprintf(stderr, "no record for '%s' in database\n", path);
363 rc = 3;
364 goto exit;
366 } else if (name[0] != '\0') {
367 if (lookup_device_by_name(udev, name) != 0) {
368 fprintf(stderr, "node name not found\n");
369 rc = 4;
370 goto exit;
372 } else {
373 fprintf(stderr, "query needs --path or node --name specified\n");
374 rc = 4;
375 goto exit;
378 switch(query) {
379 case QUERY_NAME:
380 if (root)
381 printf("%s/%s\n", udev_root, udev->name);
382 else
383 printf("%s\n", udev->name);
384 break;
385 case QUERY_SYMLINK:
386 if (list_empty(&udev->symlink_list))
387 goto exit;
388 if (root)
389 list_for_each_entry(name_loop, &udev->symlink_list, node)
390 printf("%s/%s ", udev_root, name_loop->name);
391 else
392 list_for_each_entry(name_loop, &udev->symlink_list, node)
393 printf("%s ", name_loop->name);
394 printf("\n");
395 break;
396 case QUERY_PATH:
397 printf("%s\n", udev->dev->devpath);
398 goto exit;
399 case QUERY_ENV:
400 list_for_each_entry(name_loop, &udev->env_list, node)
401 printf("%s\n", name_loop->name);
402 break;
403 case QUERY_ALL:
404 print_record(udev);
405 break;
406 default:
407 fprintf(stderr, "unknown query type\n");
408 break;
410 break;
411 case ACTION_ATTRIBUTE_WALK:
412 if (path[0] != '\0') {
413 if (print_device_chain(path) != 0) {
414 fprintf(stderr, "no valid sysfs device found\n");
415 rc = 4;
416 goto exit;
418 } else if (name[0] != '\0') {
419 if (lookup_device_by_name(udev, name) != 0) {
420 fprintf(stderr, "node name not found\n");
421 rc = 4;
422 goto exit;
424 if (print_device_chain(udev->dev->devpath) != 0) {
425 fprintf(stderr, "no valid sysfs device found\n");
426 rc = 4;
427 goto exit;
429 } else {
430 fprintf(stderr, "attribute walk needs --path or node --name specified\n");
431 rc = 5;
432 goto exit;
434 break;
435 case ACTION_ROOT:
436 printf("%s\n", udev_root);
437 break;
438 default:
439 fprintf(stderr, "missing option\n");
440 rc = 1;
441 break;
444 exit:
445 udev_device_cleanup(udev);
446 sysfs_cleanup();
447 logging_close();
448 return rc;