]> git.ipfire.org Git - thirdparty/systemd.git/blame - udevinfo.c
remove old error message
[thirdparty/systemd.git] / udevinfo.c
CommitLineData
be9b51f6 1/*
27b77df4 2 * Copyright (C) 2004-2006 Kay Sievers <kay.sievers@vrfy.org>
be9b51f6 3 *
be9b51f6
KS
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.
12 *
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.,
27b77df4 15 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
be9b51f6
KS
16 *
17 */
18
19#include <stdlib.h>
20#include <string.h>
21#include <stdio.h>
1aa1e248 22#include <stddef.h>
034f35d7 23#include <ctype.h>
87171e46
KS
24#include <stdarg.h>
25#include <unistd.h>
1aa1e248 26#include <dirent.h>
87171e46 27#include <errno.h>
11f1bb5a 28#include <getopt.h>
492e76c9
KS
29#include <sys/stat.h>
30#include <sys/types.h>
be9b51f6 31
869fc2f1 32#include "udev.h"
be9b51f6
KS
33
34
6c18b1fb 35#ifdef USE_LOG
6b493a20 36void log_message (int priority, const char *format, ...)
51a8bb2f 37{
d026a35d
GKH
38 va_list args;
39
6b493a20
KS
40 if (priority > udev_log_priority)
41 return;
42
d026a35d 43 va_start(args, format);
6b493a20 44 vsyslog(priority, format, args);
d026a35d 45 va_end(args);
51a8bb2f 46}
d026a35d 47#endif
51a8bb2f 48
95776dc6 49static void print_all_attributes(const char *devpath, const char *key)
be9b51f6 50{
1aa1e248
KS
51 char path[PATH_SIZE];
52 DIR *dir;
53 struct dirent *dent;
54
55 strlcpy(path, sysfs_path, sizeof(path));
56 strlcat(path, devpath, sizeof(path));
57
58 dir = opendir(path);
59 if (dir != NULL) {
60 for (dent = readdir(dir); dent != NULL; dent = readdir(dir)) {
492e76c9
KS
61 struct stat statbuf;
62 char filename[PATH_SIZE];
1aa1e248
KS
63 char *attr_value;
64 char value[NAME_SIZE];
65 size_t len;
66
492e76c9
KS
67 if (dent->d_name[0] == '.')
68 continue;
69
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;
77
1aa1e248
KS
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);
83
84 /* remove trailing newlines */
85 while (len && value[len-1] == '\n')
86 value[--len] = '\0';
87
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;
94 }
6276fdd2 95
1aa1e248 96 replace_untrusted_chars(value);
95776dc6 97 printf(" %s{%s}==\"%s\"\n", key, dent->d_name, value);
6276fdd2 98 }
be9b51f6
KS
99 }
100 printf("\n");
be9b51f6
KS
101}
102
1aa1e248 103static int print_device_chain(const char *devpath)
87171e46 104{
1aa1e248 105 struct sysfs_device *dev;
e48fc108 106
bc2a89fa
KS
107 dev = sysfs_device_get(devpath);
108 if (dev == NULL)
109 return -1;
110
1aa1e248 111 printf("\n"
6cf19e52
KS
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"
dba8c18b 117 "\n");
f61d732a 118
1aa1e248 119 printf(" looking at device '%s':\n", dev->devpath);
95776dc6 120 printf(" KERNEL==\"%s\"\n", dev->kernel);
1aa1e248 121 printf(" SUBSYSTEM==\"%s\"\n", dev->subsystem);
22f5934a 122 printf(" DRIVER==\"%s\"\n", dev->driver);
95776dc6 123 print_all_attributes(dev->devpath, "ATTR");
034f35d7 124
1aa1e248
KS
125 /* walk up the chain of devices */
126 while (1) {
127 dev = sysfs_device_get_parent(dev);
128 if (dev == NULL)
034f35d7 129 break;
6cf19e52 130 printf(" looking at parent device '%s':\n", dev->devpath);
95776dc6 131 printf(" KERNELS==\"%s\"\n", dev->kernel);
64e0ce85 132 printf(" SUBSYSTEMS==\"%s\"\n", dev->subsystem);
95776dc6 133 printf(" DRIVERS==\"%s\"\n", dev->driver);
1aa1e248 134
95776dc6 135 print_all_attributes(dev->devpath, "ATTRS");
be9b51f6
KS
136 }
137
1aa1e248
KS
138 return 0;
139}
140
141static void print_record(struct udevice *udev)
142{
143 struct name_entry *name_loop;
144
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 list_for_each_entry(name_loop, &udev->env_list, node)
150 printf("E: %s\n", name_loop->name);
be9b51f6 151}
87171e46 152
ae8cc07b 153static void export_name_devpath(struct udevice *udev) {
1aa1e248 154 printf("%s=%s/%s\n", udev->dev->devpath, udev_root, udev->name);
24ca5c33
KS
155}
156
ae8cc07b 157static void export_record(struct udevice *udev) {
24ca5c33
KS
158 print_record(udev);
159 printf("\n");
160}
161
ae8cc07b 162static void export_db(void fnct(struct udevice *udev)) {
db481105
KS
163 LIST_HEAD(name_list);
164 struct name_entry *name_loop;
db481105
KS
165
166 udev_db_get_all_entries(&name_list);
fb179207 167 list_for_each_entry(name_loop, &name_list, node) {
1aa1e248 168 struct udevice *udev_db;
db481105 169
1aa1e248
KS
170 udev_db = udev_device_init();
171 if (udev_db == NULL)
172 continue;
173 if (udev_db_get_device(udev_db, name_loop->name) == 0)
174 fnct(udev_db);
175 udev_device_cleanup(udev_db);
db481105 176 }
fb179207 177 name_list_cleanup(&name_list);
9fe1a96d
KS
178}
179
e48fc108 180int main(int argc, char *argv[], char *envp[])
87171e46 181{
87171e46 182 int option;
1aa1e248 183 struct udevice *udev;
87171e46 184 int root = 0;
24ca5c33 185
e97717ba 186 static const struct option options[] = {
11f1bb5a
KS
187 { "name", 1, NULL, 'n' },
188 { "path", 1, NULL, 'p' },
189 { "query", 1, NULL, 'q' },
190 { "attribute-walk", 0, NULL, 'a' },
191 { "export-db", 0, NULL, 'e' },
192 { "root", 0, NULL, 'r' },
88caa9da 193 { "version", 0, NULL, 1 }, /* -V outputs braindead format */
11f1bb5a
KS
194 { "help", 0, NULL, 'h' },
195 {}
196 };
197
24ca5c33
KS
198 enum action_type {
199 ACTION_NONE,
200 ACTION_QUERY,
201 ACTION_ATTRIBUTE_WALK,
202 ACTION_ROOT,
203 } action = ACTION_NONE;
204
b8476286
KS
205 enum query_type {
206 QUERY_NONE,
207 QUERY_NAME,
208 QUERY_PATH,
209 QUERY_SYMLINK,
210 QUERY_ENV,
211 QUERY_ALL,
212 } query = QUERY_NONE;
24ca5c33 213
63f61c5c
KS
214 char path[PATH_SIZE] = "";
215 char name[PATH_SIZE] = "";
e48fc108 216 struct name_entry *name_loop;
1aa1e248 217 int rc = 0;
e48fc108
KS
218
219 logging_init("udevinfo");
1aa1e248
KS
220 udev_config_init();
221 sysfs_init();
222
223 udev = udev_device_init();
224 if (udev == NULL) {
225 rc = 1;
226 goto exit;
227 }
87171e46
KS
228
229 /* get command line options */
230 while (1) {
11f1bb5a 231 option = getopt_long(argc, argv, "aden:p:q:rVh", options, NULL);
87171e46
KS
232 if (option == -1)
233 break;
234
235 dbg("option '%c'", option);
236 switch (option) {
237 case 'n':
2362eea6
KS
238 /* remove /dev if given */
239 if (strncmp(optarg, udev_root, strlen(udev_root)) == 0)
240 strlcpy(name, &optarg[strlen(udev_root)+1], sizeof(name));
241 else
242 strlcpy(name, optarg, sizeof(name));
243 dbg("name: %s\n", name);
87171e46 244 break;
87171e46 245 case 'p':
2362eea6 246 /* remove /sys if given */
1aa1e248
KS
247 if (strncmp(optarg, sysfs_path, strlen(sysfs_path)) == 0)
248 strlcpy(path, &optarg[strlen(sysfs_path)], sizeof(path));
249 else
250 strlcpy(path, optarg, sizeof(path));
2362eea6 251 dbg("path: %s\n", path);
87171e46 252 break;
87171e46
KS
253 case 'q':
254 dbg("udev query: %s\n", optarg);
24ca5c33 255 action = ACTION_QUERY;
87171e46 256 if (strcmp(optarg, "name") == 0) {
b8476286 257 query = QUERY_NAME;
87171e46
KS
258 break;
259 }
87171e46 260 if (strcmp(optarg, "symlink") == 0) {
b8476286 261 query = QUERY_SYMLINK;
87171e46
KS
262 break;
263 }
87171e46 264 if (strcmp(optarg, "path") == 0) {
b8476286
KS
265 query = QUERY_PATH;
266 break;
267 }
b8476286
KS
268 if (strcmp(optarg, "env") == 0) {
269 query = QUERY_ENV;
87171e46
KS
270 break;
271 }
8ea84a8a 272 if (strcmp(optarg, "all") == 0) {
b8476286 273 query = QUERY_ALL;
8ea84a8a
KS
274 break;
275 }
61b1b706 276 fprintf(stderr, "unknown query type\n");
1aa1e248 277 rc = 2;
e48fc108 278 goto exit;
87171e46 279 case 'r':
24ca5c33
KS
280 if (action == ACTION_NONE)
281 action = ACTION_ROOT;
87171e46
KS
282 root = 1;
283 break;
87171e46 284 case 'a':
24ca5c33 285 action = ACTION_ATTRIBUTE_WALK;
87171e46 286 break;
9fe1a96d 287 case 'd':
ae8cc07b 288 export_db(export_name_devpath);
24ca5c33
KS
289 goto exit;
290 case 'e':
ae8cc07b 291 export_db(export_record);
e48fc108 292 goto exit;
88caa9da
KS
293 case 1:
294 printf("%s\n", UDEV_VERSION);
295 goto exit;
87171e46 296 case 'V':
869fc2f1 297 printf("udevinfo, version %s\n", UDEV_VERSION);
e48fc108 298 goto exit;
87171e46 299 case 'h':
11f1bb5a
KS
300 printf("Usage: udevinfo OPTIONS\n"
301 " --query=<type> query database for the specified value:\n"
302 " name name of device node\n"
303 " symlink pointing to node\n"
304 " path sysfs device path\n"
305 " env the device related imported environment\n"
306 " all all values\n"
e3396a2d 307 "\n"
11f1bb5a
KS
308 " --path=<devpath> sysfs device path used for query or chain\n"
309 " --name=<name> node or symlink name used for query\n"
e3396a2d 310 "\n"
11f1bb5a
KS
311 " --root prepend to query result or print udev_root\n"
312 " --attribute-walk print all SYSFS_attributes along the device chain\n"
313 " --export-db export the content of the udev database\n"
11f1bb5a 314 " --help print this text\n"
e3396a2d
KS
315 "\n");
316 goto exit;
87171e46 317 default:
24ca5c33 318 goto exit;
87171e46
KS
319 }
320 }
321
24ca5c33
KS
322 /* run action */
323 switch (action) {
324 case ACTION_QUERY:
2362eea6 325 /* needs devpath or node/symlink name for query */
87171e46 326 if (path[0] != '\0') {
2362eea6
KS
327 if (udev_db_get_device(udev, path) != 0) {
328 fprintf(stderr, "no record for '%s' in database\n", path);
1aa1e248 329 rc = 3;
87171e46
KS
330 goto exit;
331 }
24ca5c33 332 } else if (name[0] != '\0') {
63f61c5c 333 char devpath[PATH_SIZE];
2b41e68a 334
2362eea6
KS
335 if (udev_db_lookup_name(name, devpath, sizeof(devpath)) != 0) {
336 fprintf(stderr, "node name not found\n");
337 rc = 4;
87171e46
KS
338 goto exit;
339 }
1aa1e248 340 udev_db_get_device(udev, devpath);
24ca5c33 341 } else {
11f1bb5a 342 fprintf(stderr, "query needs --path or node --name specified\n");
1aa1e248 343 rc = 4;
24ca5c33 344 goto exit;
87171e46
KS
345 }
346
87171e46 347 switch(query) {
b8476286 348 case QUERY_NAME:
e48fc108 349 if (root)
1aa1e248 350 printf("%s/%s\n", udev_root, udev->name);
e48fc108 351 else
1aa1e248 352 printf("%s\n", udev->name);
24ca5c33 353 break;
b8476286 354 case QUERY_SYMLINK:
1aa1e248 355 if (list_empty(&udev->symlink_list))
a1ea706a 356 goto exit;
e48fc108 357 if (root)
1aa1e248 358 list_for_each_entry(name_loop, &udev->symlink_list, node)
e48fc108
KS
359 printf("%s/%s ", udev_root, name_loop->name);
360 else
1aa1e248 361 list_for_each_entry(name_loop, &udev->symlink_list, node)
e48fc108
KS
362 printf("%s ", name_loop->name);
363 printf("\n");
24ca5c33 364 break;
b8476286 365 case QUERY_PATH:
1aa1e248 366 printf("%s\n", udev->dev->devpath);
e48fc108 367 goto exit;
b8476286 368 case QUERY_ENV:
1aa1e248 369 list_for_each_entry(name_loop, &udev->env_list, node)
b8476286 370 printf("%s\n", name_loop->name);
24ca5c33 371 break;
b8476286 372 case QUERY_ALL:
1aa1e248 373 print_record(udev);
24ca5c33 374 break;
87171e46 375 default:
e3396a2d 376 fprintf(stderr, "unknown query type\n");
24ca5c33 377 break;
87171e46 378 }
24ca5c33
KS
379 break;
380 case ACTION_ATTRIBUTE_WALK:
1aa0c52b 381 if (path[0] != '\0') {
bc2a89fa
KS
382 if (print_device_chain(path) != 0) {
383 fprintf(stderr, "device not found\n");
384 rc = 4;
385 goto exit;
386 }
1aa0c52b
KS
387 } else if (name[0] != '\0') {
388 char devpath[PATH_SIZE];
389
390 if (udev_db_lookup_name(name, devpath, sizeof(devpath)) != 0) {
391 fprintf(stderr, "node name not found\n");
392 rc = 4;
393 goto exit;
394 }
bc2a89fa
KS
395 if (print_device_chain(devpath) != 0) {
396 fprintf(stderr, "device not found\n");
397 rc = 4;
398 goto exit;
399 }
1aa0c52b 400 } else {
11f1bb5a 401 fprintf(stderr, "attribute walk needs --path or node --name specified\n");
1aa0c52b
KS
402 rc = 5;
403 goto exit;
404 }
24ca5c33
KS
405 break;
406 case ACTION_ROOT:
87171e46 407 printf("%s\n", udev_root);
24ca5c33
KS
408 break;
409 default:
e3396a2d 410 fprintf(stderr, "missing option\n");
1aa1e248 411 rc = 1;
24ca5c33 412 break;
87171e46
KS
413 }
414
e48fc108 415exit:
1aa1e248
KS
416 udev_device_cleanup(udev);
417 sysfs_cleanup();
7257cb18 418 logging_close();
1aa1e248 419 return rc;
87171e46 420}