]> git.ipfire.org Git - thirdparty/systemd.git/blame - udevinfo.c
add ID_BUS to *_id programs
[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 *
be9b51f6
KS
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>
034f35d7 24#include <ctype.h>
87171e46
KS
25#include <stdarg.h>
26#include <unistd.h>
27#include <errno.h>
be9b51f6 28
c80da508 29#include "libsysfs/sysfs/libsysfs.h"
63f61c5c 30#include "udev_libc_wrapper.h"
869fc2f1 31#include "udev.h"
9af5bb2f 32#include "udev_utils.h"
869fc2f1 33#include "udev_version.h"
02fa9ae5 34#include "udev_db.h"
869fc2f1 35#include "logging.h"
be9b51f6
KS
36
37
6c18b1fb 38#ifdef USE_LOG
6b493a20 39void log_message (int priority, const char *format, ...)
51a8bb2f 40{
d026a35d
GKH
41 va_list args;
42
6b493a20
KS
43 if (priority > udev_log_priority)
44 return;
45
d026a35d 46 va_start(args, format);
6b493a20 47 vsyslog(priority, format, args);
d026a35d 48 va_end(args);
51a8bb2f 49}
d026a35d 50#endif
51a8bb2f 51
f385ff65 52static void print_all_attributes(struct dlist *attr_list)
be9b51f6 53{
be9b51f6 54 struct sysfs_attribute *attr;
63f61c5c 55 char value[VALUE_SIZE];
6276fdd2 56 size_t len;
be9b51f6 57
f385ff65 58 dlist_for_each_data(attr_list, attr, struct sysfs_attribute) {
6276fdd2
KS
59 if (attr->value == NULL)
60 continue;
61 len = strlcpy(value, attr->value, sizeof(value));
62 if (len >= sizeof(value)) {
63 dbg("attribute value of '%s' too long, skip", attr->name);
64 continue;
be9b51f6 65 }
6276fdd2
KS
66
67 /* remove trailing newlines */
68 while (len && value[len-1] == '\n')
69 value[--len] = '\0';
70 /* skip nonprintable attributes */
71 while (len && isprint(value[len-1]))
72 len--;
73 if (len) {
74 dbg("attribute value of '%s' non-printable, skip", attr->name);
75 continue;
76 }
77 replace_untrusted_chars(value);
78 printf(" SYSFS{%s}==\"%s\"\n", attr->name, value);
be9b51f6
KS
79 }
80 printf("\n");
be9b51f6
KS
81}
82
2b41e68a 83static int print_record(struct udevice *udev)
87171e46 84{
e48fc108
KS
85 struct name_entry *name_loop;
86
2b41e68a
KS
87 printf("P: %s\n", udev->devpath);
88 printf("N: %s\n", udev->name);
e48fc108
KS
89 list_for_each_entry(name_loop, &udev->symlink_list, node)
90 printf("S: %s\n", name_loop->name);
91
87171e46
KS
92 return 0;
93}
94
87171e46 95static int print_device_chain(const char *path)
be9b51f6 96{
be9b51f6
KS
97 struct sysfs_class_device *class_dev;
98 struct sysfs_class_device *class_dev_parent;
99 struct sysfs_attribute *attr;
034f35d7 100 struct sysfs_device *sysfs_dev;
f385ff65 101 struct dlist *attr_list;
be9b51f6
KS
102 int retval = 0;
103
be9b51f6
KS
104 /* get the class dev */
105 class_dev = sysfs_open_class_device_path(path);
106 if (class_dev == NULL) {
61b1b706 107 fprintf(stderr, "couldn't get the class device\n");
be9b51f6
KS
108 return -1;
109 }
110
dba8c18b 111 printf("\nudevinfo starts with the device the node belongs to and then walks up the\n"
ebc39fef 112 "device chain, to print for every device found, all possibly useful attributes\n"
dba8c18b 113 "in the udev key format.\n"
ebc39fef
KS
114 "Only attributes within one device section may be used together in one rule,\n"
115 "to match the device for which the node will be created.\n"
dba8c18b 116 "\n");
f61d732a 117
fc2aa296
KS
118 /* look for the 'dev' file */
119 attr = sysfs_get_classdev_attr(class_dev, "dev");
c02ae2fe 120 if (attr != NULL)
f61d732a 121 printf("device '%s' has major:minor %s", class_dev->path, attr->value);
be9b51f6
KS
122
123 /* open sysfs class device directory and print all attributes */
034f35d7 124 printf(" looking at class device '%s':\n", class_dev->path);
61b1b706 125 printf(" SUBSYSTEM==\"%s\"\n", class_dev->classname);
f385ff65
KS
126
127 attr_list = sysfs_get_classdev_attributes(class_dev);
128 if (attr_list == NULL) {
61b1b706 129 fprintf(stderr, "couldn't open class device directory\n");
be9b51f6
KS
130 retval = -1;
131 goto exit;
132 }
f385ff65 133 print_all_attributes(attr_list);
be9b51f6 134
034f35d7 135 /* get the device link (if parent exists look here) */
be9b51f6 136 class_dev_parent = sysfs_get_classdev_parent(class_dev);
6276fdd2 137 if (class_dev_parent != NULL)
a291a14b
DS
138 sysfs_dev = sysfs_get_classdev_device(class_dev_parent);
139 else
140 sysfs_dev = sysfs_get_classdev_device(class_dev);
141
034f35d7 142 if (sysfs_dev != NULL)
6276fdd2 143 printf("follow the \"device\"-link to the physical device:\n");
034f35d7
KS
144
145 /* look the device chain upwards */
146 while (sysfs_dev != NULL) {
147 printf(" looking at the device chain at '%s':\n", sysfs_dev->path);
61b1b706
KS
148 printf(" BUS==\"%s\"\n", sysfs_dev->bus);
149 printf(" ID==\"%s\"\n", sysfs_dev->bus_id);
150 printf(" DRIVER==\"%s\"\n", sysfs_dev->driver_name);
be9b51f6 151
e2bd03ff
GKH
152 attr_list = sysfs_get_device_attributes(sysfs_dev);
153 if (attr_list != NULL)
154 print_all_attributes(attr_list);
155 else
156 printf("\n");
034f35d7 157
6276fdd2
KS
158 sysfs_dev = sysfs_get_device_parent(sysfs_dev);
159 if (sysfs_dev == NULL)
034f35d7 160 break;
be9b51f6
KS
161 }
162
163exit:
a291a14b 164 sysfs_close_class_device(class_dev);
be9b51f6
KS
165 return retval;
166}
87171e46 167
599e17a3 168static int print_dump(const char *devpath, const char *name) {
3810823b 169 printf("%s=%s/%s\n", devpath, udev_root, name);
9fe1a96d
KS
170 return 0;
171}
172
e48fc108 173int main(int argc, char *argv[], char *envp[])
87171e46 174{
9fe1a96d 175 static const char short_options[] = "adn:p:q:rVh";
87171e46 176 int option;
2b41e68a 177 struct udevice udev;
87171e46
KS
178 int root = 0;
179 int attributes = 0;
b8476286
KS
180 enum query_type {
181 QUERY_NONE,
182 QUERY_NAME,
183 QUERY_PATH,
184 QUERY_SYMLINK,
185 QUERY_ENV,
186 QUERY_ALL,
187 } query = QUERY_NONE;
63f61c5c
KS
188 char path[PATH_SIZE] = "";
189 char name[PATH_SIZE] = "";
190 char temp[PATH_SIZE];
e48fc108 191 struct name_entry *name_loop;
87171e46 192 char *pos;
e48fc108
KS
193 int retval = 0;
194
195 logging_init("udevinfo");
196
197 udev_init_config();
fb39f056 198 udev_init_device(&udev, NULL, NULL, NULL);
87171e46
KS
199
200 /* get command line options */
201 while (1) {
af4b05d4 202 option = getopt(argc, argv, short_options);
87171e46
KS
203 if (option == -1)
204 break;
205
206 dbg("option '%c'", option);
207 switch (option) {
208 case 'n':
209 dbg("udev name: %s\n", optarg);
63f61c5c 210 strlcpy(name, optarg, sizeof(name));
87171e46
KS
211 break;
212
213 case 'p':
214 dbg("udev path: %s\n", optarg);
63f61c5c 215 strlcpy(path, optarg, sizeof(path));
87171e46
KS
216 break;
217
218 case 'q':
219 dbg("udev query: %s\n", optarg);
220
221 if (strcmp(optarg, "name") == 0) {
b8476286 222 query = QUERY_NAME;
87171e46
KS
223 break;
224 }
225
226 if (strcmp(optarg, "symlink") == 0) {
b8476286 227 query = QUERY_SYMLINK;
87171e46
KS
228 break;
229 }
230
87171e46 231 if (strcmp(optarg, "path") == 0) {
b8476286
KS
232 query = QUERY_PATH;
233 break;
234 }
235
236 if (strcmp(optarg, "env") == 0) {
237 query = QUERY_ENV;
87171e46
KS
238 break;
239 }
240
8ea84a8a 241 if (strcmp(optarg, "all") == 0) {
b8476286 242 query = QUERY_ALL;
8ea84a8a
KS
243 break;
244 }
245
61b1b706 246 fprintf(stderr, "unknown query type\n");
e48fc108
KS
247 retval = 1;
248 goto exit;
87171e46
KS
249
250 case 'r':
251 root = 1;
252 break;
253
254 case 'a':
255 attributes = 1;
256 break;
257
9fe1a96d 258 case 'd':
599e17a3 259 udev_db_dump_names(print_dump);
e48fc108 260 goto exit;
9fe1a96d 261
87171e46 262 case 'V':
869fc2f1 263 printf("udevinfo, version %s\n", UDEV_VERSION);
e48fc108 264 goto exit;
87171e46
KS
265
266 case 'h':
e48fc108 267 retval = 2;
87171e46
KS
268 case '?':
269 default:
270 goto help;
271 }
272 }
273
274 /* process options */
b8476286 275 if (query != QUERY_NONE) {
87171e46
KS
276 if (path[0] != '\0') {
277 /* remove sysfs_path if given */
278 if (strncmp(path, sysfs_path, strlen(sysfs_path)) == 0) {
279 pos = path + strlen(sysfs_path);
280 } else {
281 if (path[0] != '/') {
282 /* prepend '/' if missing */
e48fc108 283 strcpy(temp, "/");
63f61c5c 284 strlcpy(temp, path, sizeof(temp));
87171e46
KS
285 pos = temp;
286 } else {
287 pos = path;
288 }
289 }
e48fc108 290 retval = udev_db_get_device(&udev, pos);
87171e46 291 if (retval != 0) {
61b1b706 292 fprintf(stderr, "device not found in database\n");
87171e46
KS
293 goto exit;
294 }
295 goto print;
296 }
297
298 if (name[0] != '\0') {
63f61c5c 299 char devpath[PATH_SIZE];
e48fc108 300 int len;
2b41e68a 301
e48fc108
KS
302 /* remove udev_root if given */
303 len = strlen(udev_root);
2b41e68a
KS
304 if (strncmp(name, udev_root, len) == 0) {
305 pos = &name[len+1];
87171e46
KS
306 } else
307 pos = name;
2b41e68a 308
63f61c5c 309 retval = udev_db_search_name(devpath, sizeof(devpath), pos);
87171e46 310 if (retval != 0) {
61b1b706 311 fprintf(stderr, "device not found in database\n");
87171e46
KS
312 goto exit;
313 }
e48fc108 314 udev_db_get_device(&udev, devpath);
87171e46
KS
315 goto print;
316 }
317
61b1b706 318 fprintf(stderr, "query needs device path(-p) or node name(-n) specified\n");
e48fc108 319 retval = 3;
87171e46
KS
320 goto exit;
321
322print:
323 switch(query) {
b8476286 324 case QUERY_NAME:
e48fc108
KS
325 if (root)
326 printf("%s/%s\n", udev_root, udev.name);
327 else
328 printf("%s\n", udev.name);
329 goto exit;
b8476286 330 case QUERY_SYMLINK:
e48fc108
KS
331 if (list_empty(&udev.symlink_list))
332 break;
333 if (root)
334 list_for_each_entry(name_loop, &udev.symlink_list, node)
335 printf("%s/%s ", udev_root, name_loop->name);
336 else
337 list_for_each_entry(name_loop, &udev.symlink_list, node)
338 printf("%s ", name_loop->name);
339 printf("\n");
340 goto exit;
b8476286 341 case QUERY_PATH:
e48fc108
KS
342 printf("%s\n", udev.devpath);
343 goto exit;
b8476286
KS
344 case QUERY_ENV:
345 list_for_each_entry(name_loop, &udev.env_list, node)
346 printf("%s\n", name_loop->name);
347 goto exit;
348 case QUERY_ALL:
2b41e68a 349 print_record(&udev);
8ea84a8a 350 goto exit;
87171e46 351 default:
e48fc108 352 goto help;
87171e46 353 }
87171e46
KS
354 }
355
356 if (attributes) {
357 if (path[0] == '\0') {
61b1b706 358 fprintf(stderr, "attribute walk on device chain needs path(-p) specified\n");
e48fc108
KS
359 retval = 4;
360 goto exit;
87171e46
KS
361 } else {
362 if (strncmp(path, sysfs_path, strlen(sysfs_path)) != 0) {
363 /* prepend sysfs mountpoint if not given */
63f61c5c
KS
364 snprintf(temp, sizeof(temp), "%s%s", sysfs_path, path);
365 temp[sizeof(temp)-1] = '\0';
366 strlcpy(path, temp, sizeof(temp));
87171e46
KS
367 }
368 print_device_chain(path);
e48fc108 369 goto exit;
87171e46
KS
370 }
371 }
372
373 if (root) {
374 printf("%s\n", udev_root);
e48fc108 375 goto exit;
87171e46
KS
376 }
377
378help:
61b1b706 379 fprintf(stderr, "Usage: udevinfo [-anpqrVh]\n"
87171e46
KS
380 " -q TYPE query database for the specified value:\n"
381 " 'name' name of device node\n"
382 " 'symlink' pointing to node\n"
87171e46 383 " 'path' sysfs device path\n"
b8476286 384 " 'env' the device related imported environment\n"
8ea84a8a
KS
385 " 'all' all values\n"
386 "\n"
87171e46 387 " -p PATH sysfs device path used for query or chain\n"
8ea84a8a 388 " -n NAME node/symlink name used for query\n"
87171e46
KS
389 "\n"
390 " -r print udev root\n"
2a25816f 391 " -a print all SYSFS_attributes along the device chain\n"
9fe1a96d
KS
392 " -d print the relationship of devpath and the node name for all\n"
393 " devices available in the database\n"
87171e46
KS
394 " -V print udev version\n"
395 " -h print this help text\n"
396 "\n");
7257cb18 397
e48fc108
KS
398exit:
399 udev_cleanup_device(&udev);
7257cb18 400 logging_close();
e48fc108 401 return retval;
87171e46 402}