]> git.ipfire.org Git - thirdparty/systemd.git/blame - udevinfo.c
remove extra space from udevinfo symlink output
[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));
1f7a36f2
MM
82 if(len >= sizeof(value))
83 len = sizeof(value) - 1;
1aa1e248
KS
84 dbg("attr '%s'='%s'(%zi)", dent->d_name, value, len);
85
86 /* remove trailing newlines */
87 while (len && value[len-1] == '\n')
88 value[--len] = '\0';
89
90 /* skip nonprintable attributes */
91 while (len && isprint(value[len-1]))
92 len--;
93 if (len) {
94 dbg("attribute value of '%s' non-printable, skip", dent->d_name);
95 continue;
96 }
6276fdd2 97
2f2c4fa4 98 replace_chars(value, ALLOWED_CHARS_INPUT);
95776dc6 99 printf(" %s{%s}==\"%s\"\n", key, dent->d_name, value);
6276fdd2 100 }
be9b51f6
KS
101 }
102 printf("\n");
be9b51f6
KS
103}
104
1aa1e248 105static int print_device_chain(const char *devpath)
87171e46 106{
1aa1e248 107 struct sysfs_device *dev;
e48fc108 108
bc2a89fa
KS
109 dev = sysfs_device_get(devpath);
110 if (dev == NULL)
111 return -1;
112
1aa1e248 113 printf("\n"
6cf19e52
KS
114 "Udevinfo starts with the device specified by the devpath and then\n"
115 "walks up the chain of parent devices. It prints for every device\n"
116 "found, all possible attributes in the udev rules key format.\n"
117 "A rule to match, can be composed by the attributes of the device\n"
118 "and the attributes from one single parent device.\n"
dba8c18b 119 "\n");
f61d732a 120
1aa1e248 121 printf(" looking at device '%s':\n", dev->devpath);
95776dc6 122 printf(" KERNEL==\"%s\"\n", dev->kernel);
1aa1e248 123 printf(" SUBSYSTEM==\"%s\"\n", dev->subsystem);
22f5934a 124 printf(" DRIVER==\"%s\"\n", dev->driver);
95776dc6 125 print_all_attributes(dev->devpath, "ATTR");
034f35d7 126
1aa1e248
KS
127 /* walk up the chain of devices */
128 while (1) {
129 dev = sysfs_device_get_parent(dev);
130 if (dev == NULL)
034f35d7 131 break;
6cf19e52 132 printf(" looking at parent device '%s':\n", dev->devpath);
95776dc6 133 printf(" KERNELS==\"%s\"\n", dev->kernel);
64e0ce85 134 printf(" SUBSYSTEMS==\"%s\"\n", dev->subsystem);
95776dc6 135 printf(" DRIVERS==\"%s\"\n", dev->driver);
1aa1e248 136
95776dc6 137 print_all_attributes(dev->devpath, "ATTRS");
be9b51f6
KS
138 }
139
1aa1e248
KS
140 return 0;
141}
142
143static void print_record(struct udevice *udev)
144{
145 struct name_entry *name_loop;
146
147 printf("P: %s\n", udev->dev->devpath);
148 printf("N: %s\n", udev->name);
149 list_for_each_entry(name_loop, &udev->symlink_list, node)
150 printf("S: %s\n", name_loop->name);
019d6669
KS
151 if (udev->link_priority != 0)
152 printf("L: %i\n", udev->link_priority);
153 if (udev->partitions != 0)
154 printf("A:%u\n", udev->partitions);
155 if (udev->ignore_remove)
156 printf("R:%u\n", udev->ignore_remove);
1aa1e248
KS
157 list_for_each_entry(name_loop, &udev->env_list, node)
158 printf("E: %s\n", name_loop->name);
be9b51f6 159}
87171e46 160
3045132a 161static void export_db(void) {
db481105
KS
162 LIST_HEAD(name_list);
163 struct name_entry *name_loop;
db481105
KS
164
165 udev_db_get_all_entries(&name_list);
fb179207 166 list_for_each_entry(name_loop, &name_list, node) {
1aa1e248 167 struct udevice *udev_db;
db481105 168
31de3a2b 169 udev_db = udev_device_init(NULL);
1aa1e248
KS
170 if (udev_db == NULL)
171 continue;
172 if (udev_db_get_device(udev_db, name_loop->name) == 0)
3045132a
KS
173 print_record(udev_db);
174 printf("\n");
1aa1e248 175 udev_device_cleanup(udev_db);
db481105 176 }
fb179207 177 name_list_cleanup(&name_list);
9fe1a96d
KS
178}
179
31de3a2b
KS
180static int lookup_device_by_name(struct udevice *udev, const char *name)
181{
182 LIST_HEAD(name_list);
be8594ab 183 int count;
31de3a2b
KS
184 struct name_entry *device;
185 int rc = -1;
186
be8594ab
KS
187 count = udev_db_get_devices_by_name(name, &name_list);
188 if (count <= 0)
31de3a2b
KS
189 goto out;
190
be8594ab
KS
191 info("found %i devices for '%s'", count, name);
192
193 /* select the device that seems to match */
31de3a2b
KS
194 list_for_each_entry(device, &name_list, node) {
195 char filename[PATH_SIZE];
196 struct stat statbuf;
197
198 udev_device_init(udev);
199 if (udev_db_get_device(udev, device->name) != 0)
200 continue;
201 info("found db entry '%s'", device->name);
202
be8594ab 203 /* make sure, we don't get a link of a differnt device */
31de3a2b
KS
204 strlcpy(filename, udev_root, sizeof(filename));
205 strlcat(filename, "/", sizeof(filename));
206 strlcat(filename, name, sizeof(filename));
207 if (stat(filename, &statbuf) != 0)
208 continue;
be8594ab
KS
209 if (major(udev->devt) > 0 && udev->devt != statbuf.st_rdev) {
210 info("skip '%s', dev_t doesn't match", udev->name);
211 continue;
31de3a2b 212 }
be8594ab
KS
213 rc = 0;
214 break;
31de3a2b
KS
215 }
216out:
217 name_list_cleanup(&name_list);
218 return rc;
219}
220
e48fc108 221int main(int argc, char *argv[], char *envp[])
87171e46 222{
87171e46 223 int option;
1aa1e248 224 struct udevice *udev;
87171e46 225 int root = 0;
24ca5c33 226
e97717ba 227 static const struct option options[] = {
11f1bb5a
KS
228 { "name", 1, NULL, 'n' },
229 { "path", 1, NULL, 'p' },
230 { "query", 1, NULL, 'q' },
231 { "attribute-walk", 0, NULL, 'a' },
232 { "export-db", 0, NULL, 'e' },
233 { "root", 0, NULL, 'r' },
88caa9da 234 { "version", 0, NULL, 1 }, /* -V outputs braindead format */
11f1bb5a
KS
235 { "help", 0, NULL, 'h' },
236 {}
237 };
238
24ca5c33
KS
239 enum action_type {
240 ACTION_NONE,
241 ACTION_QUERY,
242 ACTION_ATTRIBUTE_WALK,
243 ACTION_ROOT,
244 } action = ACTION_NONE;
245
b8476286
KS
246 enum query_type {
247 QUERY_NONE,
248 QUERY_NAME,
249 QUERY_PATH,
250 QUERY_SYMLINK,
251 QUERY_ENV,
252 QUERY_ALL,
253 } query = QUERY_NONE;
24ca5c33 254
63f61c5c
KS
255 char path[PATH_SIZE] = "";
256 char name[PATH_SIZE] = "";
e48fc108 257 struct name_entry *name_loop;
1aa1e248 258 int rc = 0;
e48fc108
KS
259
260 logging_init("udevinfo");
1aa1e248
KS
261 udev_config_init();
262 sysfs_init();
263
31de3a2b 264 udev = udev_device_init(NULL);
1aa1e248
KS
265 if (udev == NULL) {
266 rc = 1;
267 goto exit;
268 }
87171e46 269
87171e46 270 while (1) {
3045132a 271 option = getopt_long(argc, argv, "aen:p:q:rVh", options, NULL);
87171e46
KS
272 if (option == -1)
273 break;
274
275 dbg("option '%c'", option);
276 switch (option) {
277 case 'n':
2362eea6
KS
278 /* remove /dev if given */
279 if (strncmp(optarg, udev_root, strlen(udev_root)) == 0)
280 strlcpy(name, &optarg[strlen(udev_root)+1], sizeof(name));
281 else
282 strlcpy(name, optarg, sizeof(name));
92b229c7 283 dbg("name: %s", name);
87171e46 284 break;
87171e46 285 case 'p':
2362eea6 286 /* remove /sys if given */
1aa1e248
KS
287 if (strncmp(optarg, sysfs_path, strlen(sysfs_path)) == 0)
288 strlcpy(path, &optarg[strlen(sysfs_path)], sizeof(path));
289 else
290 strlcpy(path, optarg, sizeof(path));
92b229c7 291 dbg("path: %s", path);
87171e46 292 break;
87171e46 293 case 'q':
24ca5c33 294 action = ACTION_QUERY;
87171e46 295 if (strcmp(optarg, "name") == 0) {
b8476286 296 query = QUERY_NAME;
87171e46
KS
297 break;
298 }
87171e46 299 if (strcmp(optarg, "symlink") == 0) {
b8476286 300 query = QUERY_SYMLINK;
87171e46
KS
301 break;
302 }
87171e46 303 if (strcmp(optarg, "path") == 0) {
b8476286
KS
304 query = QUERY_PATH;
305 break;
306 }
b8476286
KS
307 if (strcmp(optarg, "env") == 0) {
308 query = QUERY_ENV;
87171e46
KS
309 break;
310 }
8ea84a8a 311 if (strcmp(optarg, "all") == 0) {
b8476286 312 query = QUERY_ALL;
8ea84a8a
KS
313 break;
314 }
61b1b706 315 fprintf(stderr, "unknown query type\n");
1aa1e248 316 rc = 2;
e48fc108 317 goto exit;
87171e46 318 case 'r':
24ca5c33
KS
319 if (action == ACTION_NONE)
320 action = ACTION_ROOT;
87171e46
KS
321 root = 1;
322 break;
87171e46 323 case 'a':
24ca5c33 324 action = ACTION_ATTRIBUTE_WALK;
87171e46 325 break;
24ca5c33 326 case 'e':
3045132a 327 export_db();
e48fc108 328 goto exit;
88caa9da
KS
329 case 1:
330 printf("%s\n", UDEV_VERSION);
331 goto exit;
87171e46 332 case 'V':
869fc2f1 333 printf("udevinfo, version %s\n", UDEV_VERSION);
e48fc108 334 goto exit;
87171e46 335 case 'h':
11f1bb5a
KS
336 printf("Usage: udevinfo OPTIONS\n"
337 " --query=<type> query database for the specified value:\n"
338 " name name of device node\n"
339 " symlink pointing to node\n"
340 " path sysfs device path\n"
341 " env the device related imported environment\n"
342 " all all values\n"
e3396a2d 343 "\n"
11f1bb5a
KS
344 " --path=<devpath> sysfs device path used for query or chain\n"
345 " --name=<name> node or symlink name used for query\n"
e3396a2d 346 "\n"
11f1bb5a
KS
347 " --root prepend to query result or print udev_root\n"
348 " --attribute-walk print all SYSFS_attributes along the device chain\n"
349 " --export-db export the content of the udev database\n"
11f1bb5a 350 " --help print this text\n"
e3396a2d
KS
351 "\n");
352 goto exit;
87171e46 353 default:
24ca5c33 354 goto exit;
87171e46
KS
355 }
356 }
357
24ca5c33
KS
358 /* run action */
359 switch (action) {
360 case ACTION_QUERY:
2362eea6 361 /* needs devpath or node/symlink name for query */
87171e46 362 if (path[0] != '\0') {
2362eea6
KS
363 if (udev_db_get_device(udev, path) != 0) {
364 fprintf(stderr, "no record for '%s' in database\n", path);
1aa1e248 365 rc = 3;
87171e46
KS
366 goto exit;
367 }
24ca5c33 368 } else if (name[0] != '\0') {
31de3a2b 369 if (lookup_device_by_name(udev, name) != 0) {
2362eea6
KS
370 fprintf(stderr, "node name not found\n");
371 rc = 4;
87171e46
KS
372 goto exit;
373 }
24ca5c33 374 } else {
11f1bb5a 375 fprintf(stderr, "query needs --path or node --name specified\n");
1aa1e248 376 rc = 4;
24ca5c33 377 goto exit;
87171e46
KS
378 }
379
87171e46 380 switch(query) {
b8476286 381 case QUERY_NAME:
e48fc108 382 if (root)
1aa1e248 383 printf("%s/%s\n", udev_root, udev->name);
e48fc108 384 else
1aa1e248 385 printf("%s\n", udev->name);
24ca5c33 386 break;
b8476286 387 case QUERY_SYMLINK:
1aa1e248 388 if (list_empty(&udev->symlink_list))
a1ea706a 389 goto exit;
e48fc108 390 if (root)
1aa1e248 391 list_for_each_entry(name_loop, &udev->symlink_list, node)
c9523566
HH
392 if (name_loop->node.next != &udev->symlink_list)
393 printf("%s/%s ", udev_root, name_loop->name);
394 else
395 printf("%s/%s", udev_root, name_loop->name);
e48fc108 396 else
1aa1e248 397 list_for_each_entry(name_loop, &udev->symlink_list, node)
c9523566
HH
398 if (name_loop->node.next != &udev->symlink_list)
399 printf("%s ", name_loop->name);
400 else
401 printf("%s", name_loop->name);
e48fc108 402 printf("\n");
24ca5c33 403 break;
b8476286 404 case QUERY_PATH:
1aa1e248 405 printf("%s\n", udev->dev->devpath);
e48fc108 406 goto exit;
b8476286 407 case QUERY_ENV:
1aa1e248 408 list_for_each_entry(name_loop, &udev->env_list, node)
b8476286 409 printf("%s\n", name_loop->name);
24ca5c33 410 break;
b8476286 411 case QUERY_ALL:
1aa1e248 412 print_record(udev);
24ca5c33 413 break;
87171e46 414 default:
e3396a2d 415 fprintf(stderr, "unknown query type\n");
24ca5c33 416 break;
87171e46 417 }
24ca5c33
KS
418 break;
419 case ACTION_ATTRIBUTE_WALK:
1aa0c52b 420 if (path[0] != '\0') {
bc2a89fa 421 if (print_device_chain(path) != 0) {
fd807192 422 fprintf(stderr, "no valid sysfs device found\n");
bc2a89fa
KS
423 rc = 4;
424 goto exit;
425 }
1aa0c52b 426 } else if (name[0] != '\0') {
31de3a2b 427 if (lookup_device_by_name(udev, name) != 0) {
1aa0c52b
KS
428 fprintf(stderr, "node name not found\n");
429 rc = 4;
430 goto exit;
431 }
31de3a2b 432 if (print_device_chain(udev->dev->devpath) != 0) {
fd807192 433 fprintf(stderr, "no valid sysfs device found\n");
bc2a89fa
KS
434 rc = 4;
435 goto exit;
436 }
1aa0c52b 437 } else {
11f1bb5a 438 fprintf(stderr, "attribute walk needs --path or node --name specified\n");
1aa0c52b
KS
439 rc = 5;
440 goto exit;
441 }
24ca5c33
KS
442 break;
443 case ACTION_ROOT:
87171e46 444 printf("%s\n", udev_root);
24ca5c33
KS
445 break;
446 default:
e3396a2d 447 fprintf(stderr, "missing option\n");
1aa1e248 448 rc = 1;
24ca5c33 449 break;
87171e46
KS
450 }
451
e48fc108 452exit:
1aa1e248
KS
453 udev_device_cleanup(udev);
454 sysfs_cleanup();
7257cb18 455 logging_close();
1aa1e248 456 return rc;
87171e46 457}