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