]> git.ipfire.org Git - thirdparty/systemd.git/blame - udevinfo.c
[PATCH] klibc supports LOG_PID now, so remove our own implementation
[thirdparty/systemd.git] / udevinfo.c
CommitLineData
be9b51f6
KS
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>
034f35d7 25#include <ctype.h>
87171e46
KS
26#include <stdarg.h>
27#include <unistd.h>
28#include <errno.h>
be9b51f6 29
c80da508
GKH
30#include "libsysfs/sysfs/libsysfs.h"
31#include "libsysfs/dlist.h"
869fc2f1 32#include "udev.h"
9af5bb2f 33#include "udev_utils.h"
869fc2f1 34#include "udev_version.h"
02fa9ae5 35#include "udev_db.h"
869fc2f1 36#include "logging.h"
be9b51f6
KS
37
38
af4b05d4 39#define SYSFS_VALUE_SIZE 256
be9b51f6 40
d026a35d 41#ifdef LOG
d026a35d 42void log_message (int level, const char *format, ...)
51a8bb2f 43{
d026a35d
GKH
44 va_list args;
45
46 va_start(args, format);
47 vsyslog(level, format, args);
48 va_end(args);
51a8bb2f 49}
d026a35d 50#endif
51a8bb2f 51
87171e46 52static int print_all_attributes(const char *path)
be9b51f6
KS
53{
54 struct dlist *attributes;
55 struct sysfs_attribute *attr;
56 struct sysfs_directory *sysfs_dir;
af4b05d4 57 char value[SYSFS_VALUE_SIZE];
be9b51f6
KS
58 int len;
59 int retval = 0;
60
61 sysfs_dir = sysfs_open_directory(path);
62 if (sysfs_dir == NULL)
63 return -1;
64
65 attributes = sysfs_get_dir_attributes(sysfs_dir);
66 if (attributes == NULL) {
67 retval = -1;
68 goto exit;
69 }
70
71 dlist_for_each_data(attributes, attr, struct sysfs_attribute) {
72 if (attr->value != NULL) {
c472e3c8 73 strfieldcpy(value, attr->value);
be9b51f6 74 len = strlen(value);
034f35d7
KS
75 if (len == 0)
76 continue;
77
78 /* remove trailing newline */
79 if (value[len-1] == '\n') {
be9b51f6 80 value[len-1] = '\0';
034f35d7
KS
81 len--;
82 }
83
84 /* skip nonprintable values */
85 while (len) {
86 if (isprint(value[len-1]) == 0)
87 break;
88 len--;
89 }
90 if (len == 0)
16378373 91 printf(" SYSFS{%s}=\"%s\"\n", attr->name, value);
be9b51f6
KS
92 }
93 }
94 printf("\n");
95
96exit:
97 sysfs_close_directory(sysfs_dir);
98
99 return retval;
100}
101
2b41e68a 102static int print_record(struct udevice *udev)
87171e46 103{
2b41e68a
KS
104 printf("P: %s\n", udev->devpath);
105 printf("N: %s\n", udev->name);
106 printf("S: %s\n", udev->symlink);
87171e46
KS
107 printf("\n");
108 return 0;
109}
110
111enum query_type {
112 NONE,
113 NAME,
114 PATH,
115 SYMLINK,
8ea84a8a 116 ALL
87171e46
KS
117};
118
119static int print_device_chain(const char *path)
be9b51f6 120{
be9b51f6
KS
121 struct sysfs_class_device *class_dev;
122 struct sysfs_class_device *class_dev_parent;
123 struct sysfs_attribute *attr;
034f35d7
KS
124 struct sysfs_device *sysfs_dev;
125 struct sysfs_device *sysfs_dev_parent;
be9b51f6
KS
126 int retval = 0;
127
be9b51f6
KS
128 /* get the class dev */
129 class_dev = sysfs_open_class_device_path(path);
130 if (class_dev == NULL) {
131 printf("couldn't get the class device\n");
132 return -1;
133 }
134
dba8c18b 135 printf("\nudevinfo starts with the device the node belongs to and then walks up the\n"
ebc39fef 136 "device chain, to print for every device found, all possibly useful attributes\n"
dba8c18b 137 "in the udev key format.\n"
ebc39fef
KS
138 "Only attributes within one device section may be used together in one rule,\n"
139 "to match the device for which the node will be created.\n"
dba8c18b 140 "\n");
f61d732a 141
fc2aa296
KS
142 /* look for the 'dev' file */
143 attr = sysfs_get_classdev_attr(class_dev, "dev");
c02ae2fe 144 if (attr != NULL)
f61d732a 145 printf("device '%s' has major:minor %s", class_dev->path, attr->value);
be9b51f6
KS
146
147 /* open sysfs class device directory and print all attributes */
034f35d7 148 printf(" looking at class device '%s':\n", class_dev->path);
be9b51f6
KS
149 if (print_all_attributes(class_dev->path) != 0) {
150 printf("couldn't open class device directory\n");
151 retval = -1;
152 goto exit;
153 }
154
034f35d7 155 /* get the device link (if parent exists look here) */
be9b51f6 156 class_dev_parent = sysfs_get_classdev_parent(class_dev);
a291a14b
DS
157 if (class_dev_parent != NULL)
158 sysfs_dev = sysfs_get_classdev_device(class_dev_parent);
159 else
160 sysfs_dev = sysfs_get_classdev_device(class_dev);
161
034f35d7
KS
162 if (sysfs_dev != NULL)
163 printf("follow the class device's \"device\"\n");
164
165 /* look the device chain upwards */
166 while (sysfs_dev != NULL) {
167 printf(" looking at the device chain at '%s':\n", sysfs_dev->path);
168 printf(" BUS=\"%s\"\n", sysfs_dev->bus);
169 printf(" ID=\"%s\"\n", sysfs_dev->bus_id);
be9b51f6
KS
170
171 /* open sysfs device directory and print all attributes */
034f35d7
KS
172 print_all_attributes(sysfs_dev->path);
173
174 sysfs_dev_parent = sysfs_get_device_parent(sysfs_dev);
175 if (sysfs_dev_parent == NULL)
176 break;
177
034f35d7 178 sysfs_dev = sysfs_dev_parent;
be9b51f6
KS
179 }
180
181exit:
a291a14b 182 sysfs_close_class_device(class_dev);
be9b51f6
KS
183 return retval;
184}
87171e46 185
3bdef393
KS
186/* print all class/main block devices with major/minor, physical device, driver and bus */
187static int print_sysfs_devices(void)
f156b6d2
KS
188{
189 struct dlist *subsyslist;
190 char *class;
191
192 subsyslist = sysfs_open_subsystem_list("class");
193 if (!subsyslist)
3bdef393 194 return -1;
f156b6d2
KS
195
196 dlist_for_each_data(subsyslist, class, char) {
197 struct sysfs_class *cls;
198 struct dlist *class_devices;
199 struct sysfs_class_device *class_dev;
200 struct sysfs_device *phys_dev;
e4ad54a3 201 unsigned int major, minor;
f156b6d2
KS
202
203 cls = sysfs_open_class(class);
204 if (!cls)
205 continue;
206
207 class_devices = sysfs_get_class_devices(cls);
208 if (!class_devices)
209 continue;
210
211 dlist_for_each_data(class_devices, class_dev, struct sysfs_class_device) {
212 struct sysfs_attribute *attr;
213
214 printf("\n");
215 printf("DEVPATH '%s'\n", class_dev->path);
216 printf("SUBSYSTEM '%s'\n", class_dev->classname);
f156b6d2
KS
217
218 attr = sysfs_get_classdev_attr(class_dev, "dev");
219 if (attr) {
e4ad54a3
KS
220 sscanf(attr->value, "%u:%u", &major, &minor);
221 printf("MAJOR %u\n", minor);
222 printf("MINOR %u\n", major);
f156b6d2
KS
223 }
224
225 phys_dev = sysfs_get_classdev_device(class_dev);
226 if (phys_dev) {
227 printf("PHYSDEVPATH '%s'\n", phys_dev->path);
228 if (phys_dev->bus[0] != '\0')
3bdef393 229 printf("PHYSDEVBUS '%s'\n", phys_dev->bus);
e4ad54a3
KS
230
231 if (phys_dev->driver_name[0] != '\0')
232 printf("PHYSDEVDRIVER '%s'\n", phys_dev->driver_name);
f156b6d2
KS
233 }
234 }
f156b6d2
KS
235 sysfs_close_class(cls);
236 }
f156b6d2 237 sysfs_close_list(subsyslist);
3bdef393
KS
238
239 return 0;
f156b6d2
KS
240}
241
af4b05d4 242static int process_options(int argc, char *argv[])
87171e46 243{
9af17555 244 static const char short_options[] = "an:p:q:rsVh";
87171e46
KS
245 int option;
246 int retval = 1;
2b41e68a 247 struct udevice udev;
87171e46
KS
248 int root = 0;
249 int attributes = 0;
250 enum query_type query = NONE;
31fd3403 251 char result[1024] = "";
87171e46
KS
252 char path[NAME_SIZE] = "";
253 char name[NAME_SIZE] = "";
254 char temp[NAME_SIZE];
255 char *pos;
256
257 /* get command line options */
258 while (1) {
af4b05d4 259 option = getopt(argc, argv, short_options);
87171e46
KS
260 if (option == -1)
261 break;
262
263 dbg("option '%c'", option);
264 switch (option) {
265 case 'n':
266 dbg("udev name: %s\n", optarg);
267 strfieldcpy(name, optarg);
268 break;
269
270 case 'p':
271 dbg("udev path: %s\n", optarg);
272 strfieldcpy(path, optarg);
273 break;
274
275 case 'q':
276 dbg("udev query: %s\n", optarg);
277
278 if (strcmp(optarg, "name") == 0) {
279 query = NAME;
280 break;
281 }
282
283 if (strcmp(optarg, "symlink") == 0) {
284 query = SYMLINK;
285 break;
286 }
287
87171e46
KS
288 if (strcmp(optarg, "path") == 0) {
289 query = PATH;
290 break;
291 }
292
8ea84a8a
KS
293 if (strcmp(optarg, "all") == 0) {
294 query = ALL;
295 break;
296 }
297
87171e46
KS
298 printf("unknown query type\n");
299 exit(1);
300
301 case 'r':
302 root = 1;
303 break;
304
f156b6d2
KS
305 case 's':
306 print_sysfs_devices();
307 exit(0);
308
87171e46
KS
309 case 'a':
310 attributes = 1;
311 break;
312
87171e46 313 case 'V':
869fc2f1 314 printf("udevinfo, version %s\n", UDEV_VERSION);
87171e46
KS
315 exit(0);
316
317 case 'h':
318 retval = 0;
319 case '?':
320 default:
321 goto help;
322 }
323 }
324
325 /* process options */
326 if (query != NONE) {
87171e46
KS
327 if (path[0] != '\0') {
328 /* remove sysfs_path if given */
329 if (strncmp(path, sysfs_path, strlen(sysfs_path)) == 0) {
330 pos = path + strlen(sysfs_path);
331 } else {
332 if (path[0] != '/') {
333 /* prepend '/' if missing */
c472e3c8
KS
334 strfieldcat(temp, "/");
335 strfieldcat(temp, path);
87171e46
KS
336 pos = temp;
337 } else {
338 pos = path;
339 }
340 }
2b41e68a
KS
341 memset(&udev, 0x00, sizeof(struct udevice));
342 strfieldcpy(udev.devpath, pos);
02fa9ae5 343 retval = udev_db_get_device(&udev);
87171e46
KS
344 if (retval != 0) {
345 printf("device not found in database\n");
346 goto exit;
347 }
348 goto print;
349 }
350
351 if (name[0] != '\0') {
352 /* remove udev_root if given */
2b41e68a
KS
353 int len = strlen(udev_root);
354
355 if (strncmp(name, udev_root, len) == 0) {
356 pos = &name[len+1];
87171e46
KS
357 } else
358 pos = name;
2b41e68a
KS
359
360 memset(&udev, 0x00, sizeof(struct udevice));
361 strfieldcpy(udev.name, pos);
02fa9ae5 362 retval = udev_db_get_device_byname(&udev, pos);
87171e46
KS
363 if (retval != 0) {
364 printf("device not found in database\n");
365 goto exit;
366 }
2b41e68a 367
87171e46
KS
368 goto print;
369 }
370
371 printf("query needs device path(-p) or node name(-n) specified\n");
372 goto exit;
373
374print:
375 switch(query) {
376 case NAME:
2b41e68a
KS
377 if (root) {
378 snprintf(result, NAME_SIZE-1, "%s/%s", udev_root, udev.name);
379 result[NAME_SIZE-1] = '\0';
380 } else {
381 strfieldcpy(result, udev.name);
382 }
87171e46
KS
383 break;
384
385 case SYMLINK:
31fd3403
KS
386 if (root) {
387 int slen;
388 char *spos;
389 char slink[NAME_SIZE];
390
391 pos = result;
392 foreach_strpart(udev.symlink, " \n\r", spos, slen) {
393 strncpy(slink, spos, slen);
394 slink[slen] = '\0';
395 pos += sprintf(pos, "%s/%s ", udev_root, slink);
396 }
397 } else {
398 strfieldcpy(result, udev.symlink);
399 }
87171e46
KS
400 break;
401
402 case PATH:
18ebc430 403 strfieldcpy(result, udev.devpath);
87171e46
KS
404 break;
405
8ea84a8a 406 case ALL:
2b41e68a 407 print_record(&udev);
8ea84a8a
KS
408 goto exit;
409
87171e46
KS
410 default:
411 goto exit;
412 }
413 printf("%s\n", result);
414
415exit:
87171e46
KS
416 return retval;
417 }
418
419 if (attributes) {
420 if (path[0] == '\0') {
421 printf("attribute walk on device chain needs path(-p) specified\n");
422 return -EINVAL;
423 } else {
424 if (strncmp(path, sysfs_path, strlen(sysfs_path)) != 0) {
425 /* prepend sysfs mountpoint if not given */
426 strfieldcpy(temp, path);
427 strfieldcpy(path, sysfs_path);
c472e3c8 428 strfieldcat(path, temp);
87171e46
KS
429 }
430 print_device_chain(path);
431 return 0;
432 }
433 }
434
435 if (root) {
436 printf("%s\n", udev_root);
437 return 0;
438 }
439
440help:
9af17555 441 printf("Usage: udevinfo [-anpqrVh]\n"
87171e46
KS
442 " -q TYPE query database for the specified value:\n"
443 " 'name' name of device node\n"
444 " 'symlink' pointing to node\n"
87171e46 445 " 'path' sysfs device path\n"
8ea84a8a
KS
446 " 'all' all values\n"
447 "\n"
87171e46 448 " -p PATH sysfs device path used for query or chain\n"
8ea84a8a 449 " -n NAME node/symlink name used for query\n"
87171e46
KS
450 "\n"
451 " -r print udev root\n"
2a25816f 452 " -a print all SYSFS_attributes along the device chain\n"
f156b6d2 453 " -s print all sysfs devices with major/minor, physical device and bus\n"
87171e46
KS
454 " -V print udev version\n"
455 " -h print this help text\n"
456 "\n");
457 return retval;
458}
459
460int main(int argc, char *argv[], char *envp[])
461{
7257cb18 462 int rc = 0;
87171e46 463
7257cb18 464 logging_init("udevinfo");
95a6f4c8 465
87171e46
KS
466 /* initialize our configuration */
467 udev_init_config();
468
af4b05d4 469 rc = process_options(argc, argv);
7257cb18
KS
470
471 logging_close();
472 exit(rc);
87171e46 473}