chiark / gitweb /
udevinfo, udevtest: simplify '/sys' stripping from devpath argument
[elogind.git] / udevinfo.c
1 /*
2  * udevinfo.c - fetches stored device information or sysfs attributes
3  *
4  * Copyright (C) 2004-2005 Kay Sievers <kay.sievers@vrfy.org>
5  *
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>
24 #include <stddef.h>
25 #include <ctype.h>
26 #include <stdarg.h>
27 #include <unistd.h>
28 #include <dirent.h>
29 #include <errno.h>
30
31 #include "udev.h"
32
33
34 #ifdef USE_LOG
35 void log_message (int priority, const char *format, ...)
36 {
37         va_list args;
38
39         if (priority > udev_log_priority)
40                 return;
41
42         va_start(args, format);
43         vsyslog(priority, format, args);
44         va_end(args);
45 }
46 #endif
47
48 static void print_all_attributes(const char *devpath)
49 {
50         char path[PATH_SIZE];
51         DIR *dir;
52         struct dirent *dent;
53
54         strlcpy(path, sysfs_path, sizeof(path));
55         strlcat(path, devpath, sizeof(path));
56
57         dir = opendir(path);
58         if (dir != NULL) {
59                 for (dent = readdir(dir); dent != NULL; dent = readdir(dir)) {
60                         char *attr_value;
61                         char value[NAME_SIZE];
62                         size_t len;
63
64                         attr_value = sysfs_attr_get_value(devpath, dent->d_name);
65                         if (attr_value == NULL)
66                                 continue;
67                         len = strlcpy(value, attr_value, sizeof(value));
68                         dbg("attr '%s'='%s'(%zi)", dent->d_name, value, len);
69
70                         /* remove trailing newlines */
71                         while (len && value[len-1] == '\n')
72                                 value[--len] = '\0';
73
74                         /* skip nonprintable attributes */
75                         while (len && isprint(value[len-1]))
76                                 len--;
77                         if (len) {
78                                 dbg("attribute value of '%s' non-printable, skip", dent->d_name);
79                                 continue;
80                         }
81
82                         replace_untrusted_chars(value);
83                         printf("    SYSFS{%s}==\"%s\"\n", dent->d_name, value);
84                 }
85         }
86         printf("\n");
87 }
88
89 static int print_device_chain(const char *devpath)
90 {
91         struct sysfs_device *dev;
92
93         printf("\n"
94                "Udevinfo starts with the device specified by the devpath and then\n"
95                "walks up the chain of parent devices. It prints for every device\n"
96                "found, all possible attributes in the udev rules key format.\n"
97                "A rule to match, can be composed by the attributes of the device\n"
98                "and the attributes from one single parent device.\n"
99                "\n");
100
101         dev = sysfs_device_get(devpath);
102         if (dev == NULL)
103                 return -1;
104
105         printf("  looking at device '%s':\n", dev->devpath);
106         printf("    KERNEL==\"%s\"\n", dev->kernel_name);
107         printf("    SUBSYSTEM==\"%s\"\n", dev->subsystem);
108         printf("    DRIVER==\"%s\"\n", dev->driver);
109         print_all_attributes(dev->devpath);
110
111         /* walk up the chain of devices */
112         while (1) {
113                 dev = sysfs_device_get_parent(dev);
114                 if (dev == NULL)
115                         break;
116                 printf("  looking at parent device '%s':\n", dev->devpath);
117                 printf("    ID==\"%s\"\n", dev->kernel_name);
118                 printf("    BUS==\"%s\"\n", dev->subsystem);
119                 printf("    DRIVER==\"%s\"\n", dev->driver);
120
121                 print_all_attributes(dev->devpath);
122         }
123
124         return 0;
125 }
126
127 static void print_record(struct udevice *udev)
128 {
129         struct name_entry *name_loop;
130
131         printf("P: %s\n", udev->dev->devpath);
132         printf("N: %s\n", udev->name);
133         list_for_each_entry(name_loop, &udev->symlink_list, node)
134                 printf("S: %s\n", name_loop->name);
135         list_for_each_entry(name_loop, &udev->env_list, node)
136                 printf("E: %s\n", name_loop->name);
137 }
138
139 static void export_name_devpath(struct udevice *udev) {
140         printf("%s=%s/%s\n", udev->dev->devpath, udev_root, udev->name);
141 }
142
143 static void export_record(struct udevice *udev) {
144         print_record(udev);
145         printf("\n");
146 }
147
148 static void export_db(void fnct(struct udevice *udev)) {
149         LIST_HEAD(name_list);
150         struct name_entry *name_loop;
151
152         udev_db_get_all_entries(&name_list);
153         list_for_each_entry(name_loop, &name_list, node) {
154                 struct udevice *udev_db;
155
156                 udev_db = udev_device_init();
157                 if (udev_db == NULL)
158                         continue;
159                 if (udev_db_get_device(udev_db, name_loop->name) == 0)
160                         fnct(udev_db);
161                 udev_device_cleanup(udev_db);
162         }
163         name_list_cleanup(&name_list);
164 }
165
166 static void print_help(void)
167 {
168         fprintf(stderr, "Usage: udevinfo [-anpqrVh]\n"
169                "  -q TYPE  query database for the specified value:\n"
170                "             'name'    name of device node\n"
171                "             'symlink' pointing to node\n"
172                "             'path'    sysfs device path\n"
173                "             'env'     the device related imported environment\n"
174                "             'all'     all values\n"
175                "\n"
176                "  -p PATH  sysfs device path used for query or chain\n"
177                "  -n NAME  node/symlink name used for query\n"
178                "\n"
179                "  -r       prepend to query result or print udev_root\n"
180                "  -a       print all SYSFS_attributes along the device chain\n"
181                "  -e       export the content of the udev database\n"
182                "  -V       print udev version\n"
183                "  -h       print this help text\n"
184                "\n");
185 }
186
187 int main(int argc, char *argv[], char *envp[])
188 {
189         static const char short_options[] = "aden:p:q:rVh";
190         int option;
191         struct udevice *udev;
192         int root = 0;
193
194         enum action_type {
195                 ACTION_NONE,
196                 ACTION_QUERY,
197                 ACTION_ATTRIBUTE_WALK,
198                 ACTION_ROOT,
199         } action = ACTION_NONE;
200
201         enum query_type {
202                 QUERY_NONE,
203                 QUERY_NAME,
204                 QUERY_PATH,
205                 QUERY_SYMLINK,
206                 QUERY_ENV,
207                 QUERY_ALL,
208         } query = QUERY_NONE;
209
210         char path[PATH_SIZE] = "";
211         char name[PATH_SIZE] = "";
212         struct name_entry *name_loop;
213         int rc = 0;
214
215         logging_init("udevinfo");
216
217         udev_config_init();
218         sysfs_init();
219
220         udev = udev_device_init();
221         if (udev == NULL) {
222                 rc = 1;
223                 goto exit;
224         }
225
226         /* get command line options */
227         while (1) {
228                 option = getopt(argc, argv, short_options);
229                 if (option == -1)
230                         break;
231
232                 dbg("option '%c'", option);
233                 switch (option) {
234                 case 'n':
235                         /* remove /dev if given */
236                         if (strncmp(optarg, udev_root, strlen(udev_root)) == 0)
237                                 strlcpy(name, &optarg[strlen(udev_root)+1], sizeof(name));
238                         else
239                                 strlcpy(name, optarg, sizeof(name));
240                         dbg("name: %s\n", name);
241                         break;
242                 case 'p':
243                         /* remove /sys if given */
244                         if (strncmp(optarg, sysfs_path, strlen(sysfs_path)) == 0)
245                                 strlcpy(path, &optarg[strlen(sysfs_path)], sizeof(path));
246                         else
247                                 strlcpy(path, optarg, sizeof(path));
248                         dbg("path: %s\n", path);
249                         break;
250                 case 'q':
251                         dbg("udev query: %s\n", optarg);
252                         action = ACTION_QUERY;
253                         if (strcmp(optarg, "name") == 0) {
254                                 query = QUERY_NAME;
255                                 break;
256                         }
257                         if (strcmp(optarg, "symlink") == 0) {
258                                 query = QUERY_SYMLINK;
259                                 break;
260                         }
261                         if (strcmp(optarg, "path") == 0) {
262                                 query = QUERY_PATH;
263                                 break;
264                         }
265                         if (strcmp(optarg, "env") == 0) {
266                                 query = QUERY_ENV;
267                                 break;
268                         }
269                         if (strcmp(optarg, "all") == 0) {
270                                 query = QUERY_ALL;
271                                 break;
272                         }
273                         fprintf(stderr, "unknown query type\n");
274                         rc = 2;
275                         goto exit;
276                 case 'r':
277                         if (action == ACTION_NONE)
278                                 action = ACTION_ROOT;
279                         root = 1;
280                         break;
281                 case 'a':
282                         action = ACTION_ATTRIBUTE_WALK;
283                         break;
284                 case 'd':
285                         export_db(export_name_devpath);
286                         goto exit;
287                 case 'e':
288                         export_db(export_record);
289                         goto exit;
290                 case 'V':
291                         printf("udevinfo, version %s\n", UDEV_VERSION);
292                         goto exit;
293                 case 'h':
294                 case '?':
295                 default:
296                         print_help();
297                         goto exit;
298                 }
299         }
300
301         /* run action */
302         switch (action) {
303         case ACTION_QUERY:
304                 /* needs devpath or node/symlink name for query */
305                 if (path[0] != '\0') {
306                         if (udev_db_get_device(udev, path) != 0) {
307                                 fprintf(stderr, "no record for '%s' in database\n", path);
308                                 rc = 3;
309                                 goto exit;
310                         }
311                 } else if (name[0] != '\0') {
312                         char devpath[PATH_SIZE];
313
314                         if (udev_db_lookup_name(name, devpath, sizeof(devpath)) != 0) {
315                                 fprintf(stderr, "node name not found\n");
316                                 rc = 4;
317                                 goto exit;
318                         }
319                         udev_db_get_device(udev, devpath);
320                 } else {
321                         fprintf(stderr, "query needs device path(-p) or node name(-n) specified\n");
322                         rc = 4;
323                         goto exit;
324                 }
325
326                 switch(query) {
327                 case QUERY_NAME:
328                         if (root)
329                                 printf("%s/%s\n", udev_root, udev->name);
330                         else
331                                 printf("%s\n", udev->name);
332                         break;
333                 case QUERY_SYMLINK:
334                         if (list_empty(&udev->symlink_list))
335                                 goto exit;
336                         if (root)
337                                 list_for_each_entry(name_loop, &udev->symlink_list, node)
338                                         printf("%s/%s ", udev_root, name_loop->name);
339                         else
340                                 list_for_each_entry(name_loop, &udev->symlink_list, node)
341                                         printf("%s ", name_loop->name);
342                         printf("\n");
343                         break;
344                 case QUERY_PATH:
345                         printf("%s\n", udev->dev->devpath);
346                         goto exit;
347                 case QUERY_ENV:
348                         list_for_each_entry(name_loop, &udev->env_list, node)
349                                 printf("%s\n", name_loop->name);
350                         break;
351                 case QUERY_ALL:
352                         print_record(udev);
353                         break;
354                 default:
355                         print_help();
356                         break;
357                 }
358                 break;
359         case ACTION_ATTRIBUTE_WALK:
360                 if (path[0] != '\0') {
361                         print_device_chain(path);
362                 } else if (name[0] != '\0') {
363                         char devpath[PATH_SIZE];
364
365                         if (udev_db_lookup_name(name, devpath, sizeof(devpath)) != 0) {
366                                 fprintf(stderr, "node name not found\n");
367                                 rc = 4;
368                                 goto exit;
369                         }
370                         print_device_chain(devpath);
371                 } else {
372                         fprintf(stderr, "attribute walk needs device path(-p) or node name(-n) specified\n");
373                         rc = 5;
374                         goto exit;
375                 }
376                 break;
377         case ACTION_ROOT:
378                 printf("%s\n", udev_root);
379                 break;
380         default:
381                 print_help();
382                 rc = 1;
383                 break;
384         }
385
386 exit:
387         udev_device_cleanup(udev);
388         sysfs_cleanup();
389         logging_close();
390         return rc;
391 }