]> git.ipfire.org Git - thirdparty/systemd.git/blame - udevinfo.c
[PATCH] replace fgets() with mmap() and introduce udev_lib.[hc]
[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);
111 printf("M: %#o\n", dev->mode);
112 printf("S: %s\n", dev->symlink);
113 printf("O: %s\n", dev->owner);
114 printf("G: %s\n", dev->group);
115 printf("\n");
116 return 0;
117}
118
119enum query_type {
120 NONE,
121 NAME,
122 PATH,
123 SYMLINK,
124 MODE,
125 OWNER,
8ea84a8a
KS
126 GROUP,
127 ALL
87171e46
KS
128};
129
130static int print_device_chain(const char *path)
be9b51f6 131{
be9b51f6
KS
132 struct sysfs_class_device *class_dev;
133 struct sysfs_class_device *class_dev_parent;
134 struct sysfs_attribute *attr;
034f35d7
KS
135 struct sysfs_device *sysfs_dev;
136 struct sysfs_device *sysfs_dev_parent;
be9b51f6
KS
137 int retval = 0;
138
be9b51f6
KS
139 /* get the class dev */
140 class_dev = sysfs_open_class_device_path(path);
141 if (class_dev == NULL) {
142 printf("couldn't get the class device\n");
143 return -1;
144 }
145
146 /* read the 'dev' file for major/minor*/
147 attr = sysfs_get_classdev_attr(class_dev, "dev");
148 if (attr == NULL) {
149 printf("couldn't get the \"dev\" file\n");
150 retval = -1;
151 goto exit;
152 }
dba8c18b
KS
153
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
KS
159 "\n");
160 printf("device '%s' has major:minor %s", class_dev->path, attr->value);
be9b51f6
KS
161 sysfs_close_attribute(attr);
162
163 /* open sysfs class device directory and print all attributes */
034f35d7 164 printf(" looking at class device '%s':\n", class_dev->path);
be9b51f6
KS
165 if (print_all_attributes(class_dev->path) != 0) {
166 printf("couldn't open class device directory\n");
167 retval = -1;
168 goto exit;
169 }
170
034f35d7 171 /* get the device link (if parent exists look here) */
be9b51f6
KS
172 class_dev_parent = sysfs_get_classdev_parent(class_dev);
173 if (class_dev_parent != NULL) {
174 //sysfs_close_class_device(class_dev);
175 class_dev = class_dev_parent;
176 }
034f35d7
KS
177 sysfs_dev = sysfs_get_classdev_device(class_dev);
178 if (sysfs_dev != NULL)
179 printf("follow the class device's \"device\"\n");
180
181 /* look the device chain upwards */
182 while (sysfs_dev != NULL) {
183 printf(" looking at the device chain at '%s':\n", sysfs_dev->path);
184 printf(" BUS=\"%s\"\n", sysfs_dev->bus);
185 printf(" ID=\"%s\"\n", sysfs_dev->bus_id);
be9b51f6
KS
186
187 /* open sysfs device directory and print all attributes */
034f35d7
KS
188 print_all_attributes(sysfs_dev->path);
189
190 sysfs_dev_parent = sysfs_get_device_parent(sysfs_dev);
191 if (sysfs_dev_parent == NULL)
192 break;
193
194 //sysfs_close_device(sysfs_dev);
195 sysfs_dev = sysfs_dev_parent;
be9b51f6 196 }
034f35d7 197 sysfs_close_device(sysfs_dev);
be9b51f6
KS
198
199exit:
200 //sysfs_close_class_device(class_dev);
201 return retval;
202}
87171e46
KS
203
204static int process_options(void)
205{
206 static const char short_options[] = "adn:p:q:rVh";
207 int option;
208 int retval = 1;
209 struct udevice dev;
210 int root = 0;
211 int attributes = 0;
212 enum query_type query = NONE;
213 char result[NAME_SIZE] = "";
214 char path[NAME_SIZE] = "";
215 char name[NAME_SIZE] = "";
216 char temp[NAME_SIZE];
217 char *pos;
218
219 /* get command line options */
220 while (1) {
221 option = getopt(main_argc, main_argv, short_options);
222 if (option == -1)
223 break;
224
225 dbg("option '%c'", option);
226 switch (option) {
227 case 'n':
228 dbg("udev name: %s\n", optarg);
229 strfieldcpy(name, optarg);
230 break;
231
232 case 'p':
233 dbg("udev path: %s\n", optarg);
234 strfieldcpy(path, optarg);
235 break;
236
237 case 'q':
238 dbg("udev query: %s\n", optarg);
239
240 if (strcmp(optarg, "name") == 0) {
241 query = NAME;
242 break;
243 }
244
245 if (strcmp(optarg, "symlink") == 0) {
246 query = SYMLINK;
247 break;
248 }
249
250 if (strcmp(optarg, "mode") == 0) {
251 query = MODE;
252 break;
253 }
254
255 if (strcmp(optarg, "owner") == 0) {
256 query = OWNER;
257 break;
258 }
259
260 if (strcmp(optarg, "group") == 0) {
261 query = GROUP;
262 break;
263 }
264
265 if (strcmp(optarg, "path") == 0) {
266 query = PATH;
267 break;
268 }
269
8ea84a8a
KS
270 if (strcmp(optarg, "all") == 0) {
271 query = ALL;
272 break;
273 }
274
87171e46
KS
275 printf("unknown query type\n");
276 exit(1);
277
278 case 'r':
279 root = 1;
280 break;
281
282 case 'a':
283 attributes = 1;
284 break;
285
286 case 'd':
287 retval = udevdb_open_ro();
288 if (retval != 0) {
289 printf("unable to open udev database\n");
290 exit(2);
291 }
292 udevdb_call_foreach(print_record);
293 udevdb_exit();
294 exit(0);
295
296 case 'V':
869fc2f1 297 printf("udevinfo, version %s\n", UDEV_VERSION);
87171e46
KS
298 exit(0);
299
300 case 'h':
301 retval = 0;
302 case '?':
303 default:
304 goto help;
305 }
306 }
307
308 /* process options */
309 if (query != NONE) {
310 retval = udevdb_open_ro();
311 if (retval != 0) {
312 printf("unable to open udev database\n");
313 return -EACCES;
314 }
315
316 if (path[0] != '\0') {
317 /* remove sysfs_path if given */
318 if (strncmp(path, sysfs_path, strlen(sysfs_path)) == 0) {
319 pos = path + strlen(sysfs_path);
320 } else {
321 if (path[0] != '/') {
322 /* prepend '/' if missing */
c472e3c8
KS
323 strfieldcat(temp, "/");
324 strfieldcat(temp, path);
87171e46
KS
325 pos = temp;
326 } else {
327 pos = path;
328 }
329 }
330 retval = udevdb_get_dev(pos, &dev);
331 if (retval != 0) {
332 printf("device not found in database\n");
333 goto exit;
334 }
335 goto print;
336 }
337
338 if (name[0] != '\0') {
339 /* remove udev_root if given */
340 if (strncmp(name, udev_root, strlen(udev_root)) == 0) {
341 pos = name + strlen(udev_root);
342 } else
343 pos = name;
344 retval = udevdb_get_dev_byname(pos, path, &dev);
345 if (retval != 0) {
346 printf("device not found in database\n");
347 goto exit;
348 }
349 goto print;
350 }
351
352 printf("query needs device path(-p) or node name(-n) specified\n");
353 goto exit;
354
355print:
356 switch(query) {
357 case NAME:
358 if (root)
359 strfieldcpy(result, udev_root);
c472e3c8 360 strfieldcat(result, dev.name);
87171e46
KS
361 break;
362
363 case SYMLINK:
364 strfieldcpy(result, dev.symlink);
365 break;
366
367 case MODE:
368 sprintf(result, "%#o", dev.mode);
369 break;
370
371 case GROUP:
372 strfieldcpy(result, dev.group);
373 break;
374
375 case OWNER:
376 strfieldcpy(result, dev.owner);
377 break;
378
379 case PATH:
380 strfieldcpy(result, path);
381 break;
382
8ea84a8a
KS
383 case ALL:
384 print_record(path, &dev);
385 goto exit;
386
87171e46
KS
387 default:
388 goto exit;
389 }
390 printf("%s\n", result);
391
392exit:
393 udevdb_exit();
394 return retval;
395 }
396
397 if (attributes) {
398 if (path[0] == '\0') {
399 printf("attribute walk on device chain needs path(-p) specified\n");
400 return -EINVAL;
401 } else {
402 if (strncmp(path, sysfs_path, strlen(sysfs_path)) != 0) {
403 /* prepend sysfs mountpoint if not given */
404 strfieldcpy(temp, path);
405 strfieldcpy(path, sysfs_path);
c472e3c8 406 strfieldcat(path, temp);
87171e46
KS
407 }
408 print_device_chain(path);
409 return 0;
410 }
411 }
412
413 if (root) {
414 printf("%s\n", udev_root);
415 return 0;
416 }
417
418help:
419 printf("Usage: [-anpqrdVh]\n"
420 " -q TYPE query database for the specified value:\n"
421 " 'name' name of device node\n"
422 " 'symlink' pointing to node\n"
423 " 'mode' permissions of node\n"
424 " 'owner' of node\n"
425 " 'group' of node\n"
426 " 'path' sysfs device path\n"
8ea84a8a
KS
427 " 'all' all values\n"
428 "\n"
87171e46 429 " -p PATH sysfs device path used for query or chain\n"
8ea84a8a 430 " -n NAME node/symlink name used for query\n"
87171e46
KS
431 "\n"
432 " -r print udev root\n"
2a25816f 433 " -a print all SYSFS_attributes along the device chain\n"
87171e46
KS
434 " -d dump whole database\n"
435 " -V print udev version\n"
436 " -h print this help text\n"
437 "\n");
438 return retval;
439}
440
441int main(int argc, char *argv[], char *envp[])
442{
443 int retval;
444
445 main_argv = argv;
446 main_argc = argc;
87171e46 447
95a6f4c8
GKH
448 init_logging("udevinfo");
449
87171e46
KS
450 /* initialize our configuration */
451 udev_init_config();
452
453 retval = process_options();
454 if (retval != 0)
455 exit(1);
456 exit(0);
457}