]>
git.ipfire.org Git - thirdparty/systemd.git/blob - udevruler.c
2 * udevruler.c - simple udev-rule composer
4 * Reads the udev-db to get all currently known devices and
5 * scans the sysfs device chain for the choosen device to select attributes
6 * to compose a rule for the udev.rules file to uniquely name this device.
8 * Copyright (C) 2004 Kay Sievers <kay.sievers@vrfy.org>
10 * This program is free software; you can redistribute it and/or modify it
11 * under the terms of the GNU General Public License as published by the
12 * Free Software Foundation version 2 of the License.
14 * This program is distributed in the hope that it will be useful, but
15 * WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * General Public License for more details.
19 * You should have received a copy of the GNU General Public License along
20 * with this program; if not, write to the Free Software Foundation, Inc.,
21 * 675 Mass Ave, Cambridge, MA 02139, USA.
35 #include "udev_version.h"
38 #include "libsysfs/sysfs.h"
42 unsigned char logname
[LOGNAME_SIZE
];
43 void log_message(int level
, const char *format
, ...)
50 va_start(args
, format
);
51 vsyslog(level
, format
, args
);
56 static char *dev_blacklist
[] = {
75 struct list_head list
;
77 char devpath
[DEVPATH_SIZE
];
79 char config_file
[NAME_SIZE
];
84 static LIST_HEAD(device_list
);
85 static int device_count
;
87 /* callback for database dump */
88 static int add_record(char *path
, struct udevice
*udev
)
91 struct device
*loop_dev
;
94 while (dev_blacklist
[i
][0] != '\0') {
95 if (strncmp(udev
->name
, dev_blacklist
[i
], strlen(dev_blacklist
[i
])) == 0)
100 dev
= malloc(sizeof(struct device
));
102 printf("error malloc\n");
105 strfieldcpy(dev
->name
, udev
->name
);
106 strfieldcpy(dev
->devpath
, path
);
107 dev
->config_line
= udev
->config_line
;
108 strfieldcpy(dev
->config_file
, udev
->config_file
);
109 dev
->config_uptime
= udev
->config_uptime
;
112 /* sort in lexical order */
113 list_for_each_entry(loop_dev
, &device_list
, list
) {
114 if (strcmp(loop_dev
->name
, dev
->name
) > 0) {
119 list_add_tail(&dev
->list
, &loop_dev
->list
);
126 /* get all devices from udev database */
127 static int get_all_devices(void)
132 INIT_LIST_HEAD(&device_list
);
134 retval
= udevdb_open_ro();
136 printf("unable to open udev database\n");
140 udevdb_call_foreach(add_record
);
147 struct list_head list
;
152 static LIST_HEAD(attribute_list
);
153 static int attribute_count
;
155 static int add_attribute(const char *key
, int level
)
157 struct attribute
*attr
;
159 dbg("add attribute '%s'", key
);
160 attr
= malloc(sizeof(struct attribute
));
162 printf("error malloc\n");
166 strfieldcpy(attr
->key
, key
);
168 list_add_tail(&attr
->list
, &attribute_list
);
173 static int add_all_attributes(const char *path
, int level
)
175 struct dlist
*attributes
;
176 struct sysfs_attribute
*attr
;
177 struct sysfs_directory
*sysfs_dir
;
178 char value
[NAME_SIZE
];
183 dbg("look at '%s', level %i", path
, level
);
185 sysfs_dir
= sysfs_open_directory(path
);
186 if (sysfs_dir
== NULL
)
189 attributes
= sysfs_get_dir_attributes(sysfs_dir
);
190 if (attributes
== NULL
) {
195 dlist_for_each_data(attributes
, attr
, struct sysfs_attribute
)
196 if (attr
->value
!= NULL
) {
197 dbg("found attribute '%s'", attr
->name
);
198 strfieldcpy(value
, attr
->value
);
203 /* skip very long attributes */
207 /* remove trailing newline */
208 if (value
[len
-1] == '\n') {
213 /* skip nonprintable values */
215 if (!isprint(value
[len
-1]))
220 sprintf(key
, "SYSFS{%s}=\"%s\"", attr
->name
, value
);
221 add_attribute(key
, level
);
225 sysfs_close_directory(sysfs_dir
);
229 static int get_all_attributes(char *path
)
231 struct sysfs_class_device
*class_dev
;
232 struct sysfs_class_device
*class_dev_parent
;
233 struct sysfs_device
*sysfs_dev
;
234 struct sysfs_device
*sysfs_dev_parent
;
240 INIT_LIST_HEAD(&attribute_list
);
242 /* get the class dev */
243 class_dev
= sysfs_open_class_device_path(path
);
244 if (class_dev
== NULL
) {
245 dbg("couldn't get the class device");
249 /* open sysfs class device directory and get all attributes */
250 if (add_all_attributes(class_dev
->path
, level
) != 0) {
251 dbg("couldn't open class device directory");
257 /* get the device link (if parent exists look here) */
258 class_dev_parent
= sysfs_get_classdev_parent(class_dev
);
259 if (class_dev_parent
!= NULL
)
260 sysfs_dev
= sysfs_get_classdev_device(class_dev_parent
);
262 sysfs_dev
= sysfs_get_classdev_device(class_dev
);
264 /* look the device chain upwards */
265 while (sysfs_dev
!= NULL
) {
266 if (sysfs_dev
->bus
[0] != '\0') {
267 add_attribute("", level
);
268 sprintf(key
, "BUS=\"%s\"", sysfs_dev
->bus
);
269 add_attribute(key
, level
);
270 sprintf(key
, "ID=\"%s\"", sysfs_dev
->bus_id
);
271 add_attribute(key
, level
);
273 /* open sysfs device directory and print all attributes */
274 add_all_attributes(sysfs_dev
->path
, level
);
278 sysfs_dev_parent
= sysfs_get_device_parent(sysfs_dev
);
279 if (sysfs_dev_parent
== NULL
)
282 sysfs_dev
= sysfs_dev_parent
;
286 sysfs_close_class_device(class_dev
);
291 int main(int argc
, char *argv
[]) {
292 newtComponent lbox
, run
, lattr
;
293 newtComponent quit
, form
, answer
;
294 newtGrid grid
, grid2
;
296 char path
[NAME_SIZE
];
304 newtWinMessage("udevruler", "Ok",
305 "This program lets you select a device currently present "
306 "on the system and you may choose the attributes to uniquely "
307 "name the device with a udev rule.\n"
308 "No configuration will be changed, it just prints the rule "
309 "to place in a udev.rules configuration file. The \"%k\" in the "
310 "NAME key of the printed rule may be replaced by the name the "
311 "node should have.");
313 init_logging("udevruler");
317 lbox
= newtListbox(2, 1, 10, NEWT_FLAG_SCROLL
| NEWT_FLAG_RETURNEXIT
);
319 /* look for last discovered device */
321 list_for_each_entry(dev
, &device_list
, list
)
322 if (dev
->config_uptime
> time_last
)
323 time_last
= dev
->config_uptime
;
325 /* skip if more than 16 recent devices */
327 list_for_each_entry(dev
, &device_list
, list
) {
328 if (dev
->config_uptime
< time_last
- 10)
333 /* add devices up to 10 seconds older than the last one */
334 if (count_last
< 16) {
335 newtListboxAppendEntry(lbox
, "--- last dicovered ---", NULL
);
336 list_for_each_entry(dev
, &device_list
, list
) {
337 if (dev
->config_uptime
< time_last
- 10)
340 dbg("%s %i", dev
->name
, dev
->config_line
);
341 newtListboxAppendEntry(lbox
, dev
->name
, (void*) dev
);
344 newtListboxAppendEntry(lbox
, "", NULL
);
347 /* add devices not catched by a rule */
348 newtListboxAppendEntry(lbox
, "--- not configured by a rule ---", NULL
);
349 list_for_each_entry(dev
, &device_list
, list
) {
353 if (dev
->config_line
!= 0)
356 dbg("%s %i", dev
->name
, dev
->config_line
);
357 newtListboxAppendEntry(lbox
, dev
->name
, (void*) dev
);
360 newtListboxAppendEntry(lbox
, "", NULL
);
362 /* add remaining devices */
363 newtListboxAppendEntry(lbox
, "--- configured by a rule ---", NULL
);
364 list_for_each_entry(dev
, &device_list
, list
) {
368 dbg("%s %i", dev
->name
, dev
->config_line
);
369 newtListboxAppendEntry(lbox
, dev
->name
, (void*) dev
);
372 newtPushHelpLine(" <Tab>/<Alt-Tab> between elements | Use <Enter> to select a device");
373 snprintf(roottext
, sizeof(roottext
), "simple udev rule composer, version %s, (c) 2004 can't sleep team", UDEV_VERSION
);
374 roottext
[sizeof(roottext
)-1] = '\0';
375 newtDrawRootText(0, 0, roottext
);
377 form
= newtForm(NULL
, NULL
, 0);
378 grid
= newtCreateGrid(1, 2);
379 grid2
= newtButtonBar("Select device", &run
, "Quit", &quit
, NULL
);
380 newtGridSetField(grid
, 0, 0, NEWT_GRID_COMPONENT
, lbox
, 1, 0, 1, 0, NEWT_ANCHOR_TOP
, 0);
381 newtGridSetField(grid
, 0, 1, NEWT_GRID_SUBGRID
, grid2
, 0, 1, 0, 0, NEWT_ANCHOR_TOP
, 0);
382 newtFormAddComponents(form
, lbox
, run
, quit
, NULL
);
383 newtGridWrappedWindow(grid
,"Choose the device for which to compose a rule");
384 newtGridFree(grid
, 1);
387 struct attribute
*attr
;
388 newtComponent ok
, back
, form2
, answer2
, text
;
389 newtGrid grid3
, grid4
;
392 struct attribute
**selattr
;
395 answer
= newtRunForm(form
);
399 dev
= (struct device
*) newtListboxGetCurrent(lbox
);
403 if (dev
->config_line
> 0)
404 snprintf(text_rule
, sizeof(text_rule
),
405 "The device is handled by a rule in the file '%s', line %i.",
406 dev
->config_file
, dev
->config_line
);
408 strcpy(text_rule
, "The device was not handled by a rule.");
410 strfieldcpy(path
, sysfs_path
);
411 strfieldcat(path
, dev
->devpath
);
412 dbg("look at sysfs device '%s'", path
);
413 get_all_attributes(path
);
415 grid3
= newtCreateGrid(1, 3);
416 form2
= newtForm(NULL
, NULL
, 0);
417 grid4
= newtButtonBar("Ok", &ok
, "Back", &back
, NULL
);
419 lattr
= newtListbox(-1, -1, 10, NEWT_FLAG_MULTIPLE
| NEWT_FLAG_BORDER
| NEWT_FLAG_RETURNEXIT
);
420 list_for_each_entry(attr
, &attribute_list
, list
)
421 newtListboxAddEntry(lattr
, attr
->key
, (void *) attr
);
423 text
= newtTextbox(-1, -1, 50, 2, NEWT_FLAG_WRAP
);
424 newtTextboxSetText(text
, text_rule
);
426 newtGridSetField(grid3
, 0, 0, NEWT_GRID_COMPONENT
, lattr
, 0, 0, 0, 1, 0, 0);
427 newtGridSetField(grid3
, 0, 1, NEWT_GRID_COMPONENT
, text
, 0, 0, 0, 1, 0, 0);
428 newtGridSetField(grid3
, 0, 2, NEWT_GRID_SUBGRID
, grid4
, 0, 1, 0, 0, NEWT_ANCHOR_TOP
, 0);
430 newtFormAddComponents(form2
, text
, lattr
, ok
, back
, NULL
);
431 newtGridWrappedWindow(grid3
, "Select one ore more attributes within one section with the space bar");
432 newtGridFree(grid3
, 1);
439 answer2
= newtRunForm(form2
);
443 selattr
= (struct attribute
**) newtListboxGetSelection(lattr
, &numitems
);
450 for (i
= 0; i
< numitems
; i
++) {
451 if (selattr
[i
]->key
[0] == '\0')
454 if (onelevel
!= -1) {
455 if (onelevel
!= selattr
[i
]->level
) {
460 onelevel
= selattr
[i
]->level
;
463 dbg("'%s'\n", selattr
[i
]->key
);
464 strfieldcat(rule
, selattr
[i
]->key
);
465 strfieldcat(rule
, ", ");
468 newtWinMessage("error", "Ok", "Please select only attributes within one section");
472 if (strlen(rule
) > 200) {
473 newtWinMessage("error", "Ok", "The line is too long, please select fewer attributes.");
478 strfieldcat(rule
, "NAME=\"%k\"");
479 newtWinMessage("the rule to place in config file", "Ok", rule
);
487 newtFormDestroy(form
);