chiark / gitweb /
skip device mapper devices for persistent links
[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 the node belongs to and then walks up the\n"
95                "device chain, to print for every device found, all possibly useful attributes\n"
96                "in the udev key format.\n"
97                "Only attributes within one device section may be used together in one rule,\n"
98                "to match the device for which the node will be created.\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         print_all_attributes(dev->devpath);
109
110         /* walk up the chain of devices */
111         while (1) {
112                 dev = sysfs_device_get_parent(dev);
113                 if (dev == NULL)
114                         break;
115                 printf("  looking at device '%s':\n", dev->devpath);
116                 printf("    ID==\"%s\"\n", dev->kernel_name);
117                 printf("    BUS==\"%s\"\n", dev->subsystem);
118                 printf("    DRIVER==\"%s\"\n", dev->driver);
119
120                 print_all_attributes(dev->devpath);
121         }
122
123         return 0;
124 }
125
126 static void print_record(struct udevice *udev)
127 {
128         struct name_entry *name_loop;
129
130         printf("P: %s\n", udev->dev->devpath);
131         printf("N: %s\n", udev->name);
132         list_for_each_entry(name_loop, &udev->symlink_list, node)
133                 printf("S: %s\n", name_loop->name);
134         list_for_each_entry(name_loop, &udev->env_list, node)
135                 printf("E: %s\n", name_loop->name);
136 }
137
138 static void export_name_devpath(struct udevice *udev) {
139         printf("%s=%s/%s\n", udev->dev->devpath, udev_root, udev->name);
140 }
141
142 static void export_record(struct udevice *udev) {
143         print_record(udev);
144         printf("\n");
145 }
146
147 static void export_db(void fnct(struct udevice *udev)) {
148         LIST_HEAD(name_list);
149         struct name_entry *name_loop;
150
151         udev_db_get_all_entries(&name_list);
152         list_for_each_entry(name_loop, &name_list, node) {
153                 struct udevice *udev_db;
154
155                 udev_db = udev_device_init();
156                 if (udev_db == NULL)
157                         continue;
158                 if (udev_db_get_device(udev_db, name_loop->name) == 0)
159                         fnct(udev_db);
160                 udev_device_cleanup(udev_db);
161         }
162         name_list_cleanup(&name_list);
163 }
164
165 static void print_help(void)
166 {
167         fprintf(stderr, "Usage: udevinfo [-anpqrVh]\n"
168                "  -q TYPE  query database for the specified value:\n"
169                "             'name'    name of device node\n"
170                "             'symlink' pointing to node\n"
171                "             'path'    sysfs device path\n"
172                "             'env'     the device related imported environment\n"
173                "             'all'     all values\n"
174                "\n"
175                "  -p PATH  sysfs device path used for query or chain\n"
176                "  -n NAME  node/symlink name used for query\n"
177                "\n"
178                "  -r       prepend to query result or print udev_root\n"
179                "  -a       print all SYSFS_attributes along the device chain\n"
180                "  -e       export the content of the udev database\n"
181                "  -V       print udev version\n"
182                "  -h       print this help text\n"
183                "\n");
184 }
185
186 int main(int argc, char *argv[], char *envp[])
187 {
188         static const char short_options[] = "aden:p:q:rVh";
189         int option;
190         struct udevice *udev;
191         int root = 0;
192
193         enum action_type {
194                 ACTION_NONE,
195                 ACTION_QUERY,
196                 ACTION_ATTRIBUTE_WALK,
197                 ACTION_ROOT,
198         } action = ACTION_NONE;
199
200         enum query_type {
201                 QUERY_NONE,
202                 QUERY_NAME,
203                 QUERY_PATH,
204                 QUERY_SYMLINK,
205                 QUERY_ENV,
206                 QUERY_ALL,
207         } query = QUERY_NONE;
208
209         char path[PATH_SIZE] = "";
210         char name[PATH_SIZE] = "";
211         char temp[PATH_SIZE];
212         struct name_entry *name_loop;
213         char *pos;
214         int rc = 0;
215
216         logging_init("udevinfo");
217
218         udev_config_init();
219         sysfs_init();
220
221         udev = udev_device_init();
222         if (udev == NULL) {
223                 rc = 1;
224                 goto exit;
225         }
226
227         /* get command line options */
228         while (1) {
229                 option = getopt(argc, argv, short_options);
230                 if (option == -1)
231                         break;
232
233                 dbg("option '%c'", option);
234                 switch (option) {
235                 case 'n':
236                         dbg("udev name: %s\n", optarg);
237                         strlcpy(name, optarg, sizeof(name));
238                         break;
239                 case 'p':
240                         dbg("udev path: %s\n", optarg);
241                         /* remove sysfs mountpoint if not given */
242                         if (strncmp(optarg, sysfs_path, strlen(sysfs_path)) == 0)
243                                 strlcpy(path, &optarg[strlen(sysfs_path)], sizeof(path));
244                         else
245                                 strlcpy(path, optarg, sizeof(path));
246                         break;
247                 case 'q':
248                         dbg("udev query: %s\n", optarg);
249                         action = ACTION_QUERY;
250                         if (strcmp(optarg, "name") == 0) {
251                                 query = QUERY_NAME;
252                                 break;
253                         }
254                         if (strcmp(optarg, "symlink") == 0) {
255                                 query = QUERY_SYMLINK;
256                                 break;
257                         }
258                         if (strcmp(optarg, "path") == 0) {
259                                 query = QUERY_PATH;
260                                 break;
261                         }
262                         if (strcmp(optarg, "env") == 0) {
263                                 query = QUERY_ENV;
264                                 break;
265                         }
266                         if (strcmp(optarg, "all") == 0) {
267                                 query = QUERY_ALL;
268                                 break;
269                         }
270                         fprintf(stderr, "unknown query type\n");
271                         rc = 2;
272                         goto exit;
273                 case 'r':
274                         if (action == ACTION_NONE)
275                                 action = ACTION_ROOT;
276                         root = 1;
277                         break;
278                 case 'a':
279                         action = ACTION_ATTRIBUTE_WALK;
280                         break;
281                 case 'd':
282                         export_db(export_name_devpath);
283                         goto exit;
284                 case 'e':
285                         export_db(export_record);
286                         goto exit;
287                 case 'V':
288                         printf("udevinfo, version %s\n", UDEV_VERSION);
289                         goto exit;
290                 case 'h':
291                 case '?':
292                 default:
293                         print_help();
294                         goto exit;
295                 }
296         }
297
298         /* run action */
299         switch (action) {
300         case ACTION_QUERY:
301                 /* need devpath or node/symlink name for query */
302                 if (path[0] != '\0') {
303                         /* remove sysfs_path if given */
304                         if (strncmp(path, sysfs_path, strlen(sysfs_path)) == 0) {
305                                 pos = path + strlen(sysfs_path);
306                         } else {
307                                 if (path[0] != '/') {
308                                         /* prepend '/' if missing */
309                                         strcpy(temp, "/");
310                                         strlcpy(temp, path, sizeof(temp));
311                                         pos = temp;
312                                 } else {
313                                         pos = path;
314                                 }
315                         }
316                         if (udev_db_get_device(udev, pos) != 0) {
317                                 fprintf(stderr, "no record for '%s' in database\n", pos);
318                                 rc = 3;
319                                 goto exit;
320                         }
321                 } else if (name[0] != '\0') {
322                         char devpath[PATH_SIZE];
323                         int len;
324
325                         /* remove udev_root if given */
326                         len = strlen(udev_root);
327                         if (strncmp(name, udev_root, len) == 0) {
328                                 pos = &name[len+1];
329                         } else
330                                 pos = name;
331
332                         if (udev_db_lookup_name(pos, devpath, sizeof(devpath)) != 0) {
333                                 fprintf(stderr, "no record for '%s' in database\n", pos);
334                                 rc = 3;
335                                 goto exit;
336                         }
337                         udev_db_get_device(udev, devpath);
338                 } else {
339                         fprintf(stderr, "query needs device path(-p) or node name(-n) specified\n");
340                         rc = 4;
341                         goto exit;
342                 }
343
344                 switch(query) {
345                 case QUERY_NAME:
346                         if (root)
347                                 printf("%s/%s\n", udev_root, udev->name);
348                         else
349                                 printf("%s\n", udev->name);
350                         break;
351                 case QUERY_SYMLINK:
352                         if (list_empty(&udev->symlink_list))
353                                 goto exit;
354                         if (root)
355                                 list_for_each_entry(name_loop, &udev->symlink_list, node)
356                                         printf("%s/%s ", udev_root, name_loop->name);
357                         else
358                                 list_for_each_entry(name_loop, &udev->symlink_list, node)
359                                         printf("%s ", name_loop->name);
360                         printf("\n");
361                         break;
362                 case QUERY_PATH:
363                         printf("%s\n", udev->dev->devpath);
364                         goto exit;
365                 case QUERY_ENV:
366                         list_for_each_entry(name_loop, &udev->env_list, node)
367                                 printf("%s\n", name_loop->name);
368                         break;
369                 case QUERY_ALL:
370                         print_record(udev);
371                         break;
372                 default:
373                         print_help();
374                         break;
375                 }
376                 break;
377         case ACTION_ATTRIBUTE_WALK:
378                 if (path[0] == '\0') {
379                         fprintf(stderr, "attribute walk on device chain needs path(-p) specified\n");
380                         rc = 4;
381                         goto exit;
382                 } else
383                         print_device_chain(path);
384                 break;
385         case ACTION_ROOT:
386                 printf("%s\n", udev_root);
387                 break;
388         default:
389                 print_help();
390                 rc = 1;
391                 break;
392         }
393
394 exit:
395         udev_device_cleanup(udev);
396         sysfs_cleanup();
397         logging_close();
398         return rc;
399 }