return attr;
}
-/* extract possible format length and move str behind it*/
-static int get_format_len(struct udev *udev, char **str)
-{
- int num;
- char *tail;
-
- if (isdigit(*str[0])) {
- num = (int) strtoul(*str, &tail, 10);
- if (num > 0) {
- *str = tail;
- dbg(udev, "format length=%i\n", num);
- return num;
- } else {
- err(udev, "format parsing error '%s'\n", *str);
- }
- }
- return -1;
-}
-
void udev_event_apply_format(struct udev_event *event, char *string, size_t maxsize)
{
struct udev_device *dev = event->dev;
char temp[UTIL_PATH_SIZE];
char temp2[UTIL_PATH_SIZE];
char *head, *tail, *cpos, *attr, *rest;
- int len;
int i;
int count;
enum subst_type {
head = string;
while (1) {
- len = -1;
while (head[0] != '\0') {
if (head[0] == '$') {
/* substitute named variable */
}
head[0] = '\0';
tail = head+1;
- len = get_format_len(event->udev, &tail);
for (subst = map; subst->name; subst++) {
if (tail[0] == subst->fmt) {
type = subst->type;
if (event->tmp_node != NULL) {
util_strlcat(string, event->tmp_node, maxsize);
- dbg(event->udev, "return existing temporary node\n");
+ dbg(event->udev, "tempnode: return earlier created one\n");
break;
}
devnum = udev_device_get_devnum(dev);
- if (major(udev_device_get_devnum(dev) == 0))
+ if (major(devnum) == 0)
break;
+ /* lookup kernel provided node */
+ if (udev_device_get_knodename(dev) != NULL) {
+ util_strlcpy(filename, udev_get_dev_path(event->udev), sizeof(filename));
+ util_strlcat(filename, "/", sizeof(filename));
+ util_strlcat(filename, udev_device_get_knodename(dev), sizeof(filename));
+ if (stat(filename, &statbuf) == 0 && statbuf.st_rdev == devnum) {
+ util_strlcat(string, filename, maxsize);
+ dbg(event->udev, "tempnode: return kernel node\n");
+ break;
+ }
+ }
+ /* lookup /dev/{char,block}/<maj>:<min> */
if (strcmp(udev_device_get_subsystem(dev), "block") == 0)
devtype = "block";
else
minor(udev_device_get_devnum(dev)));
if (stat(filename, &statbuf) == 0 && statbuf.st_rdev == devnum) {
util_strlcat(string, filename, maxsize);
- dbg(event->udev, "return existing temporary node\n");
+ dbg(event->udev, "tempnode: return maj:min node\n");
break;
}
- dbg(event->udev, "create temporary node\n");
+ /* create temporary node */
+ dbg(event->udev, "tempnode: create temp node\n");
asprintf(&event->tmp_node, "%s/.tmp-%s-%u:%u",
udev_get_dev_path(event->udev), devtype,
major(udev_device_get_devnum(dev)),
err(event->udev, "unknown substitution type=%i\n", type);
break;
}
- /* possibly truncate to format-char specified length */
- if (len >= 0 && len < (int)strlen(head)) {
- head[len] = '\0';
- dbg(event->udev, "truncate to %i chars, subtitution string becomes '%s'\n", len, head);
- }
util_strlcat(string, temp, maxsize);
}
}
(strcmp(udev_device_get_action(dev), "add") == 0 || strcmp(udev_device_get_action(dev), "change") == 0)) {
char filename[UTIL_PATH_SIZE];
struct udev_device *dev_old;
+ int delete_kdevnode = 0;
dbg(event->udev, "device node add '%s'\n", udev_device_get_devpath(dev));
+ /* read old database entry */
+ dev_old = udev_device_new_from_syspath(event->udev, udev_device_get_syspath(dev));
+ if (dev_old != NULL) {
+ udev_device_read_db(dev_old);
+ udev_device_set_info_loaded(dev_old);
+
+ /* disable watch during event processing */
+ udev_watch_end(event->udev, dev_old);
+ }
+
udev_rules_apply_to_event(rules, event);
if (event->tmp_node != NULL) {
- dbg(event->udev, "removing temporary device node\n");
+ dbg(event->udev, "cleanup temporary device node\n");
util_unlink_secure(event->udev, event->tmp_node);
free(event->tmp_node);
event->tmp_node = NULL;
if (event->ignore_device) {
info(event->udev, "device event will be ignored\n");
- goto exit;
+ delete_kdevnode = 1;
+ goto exit_add;
}
if (event->name != NULL && event->name[0] == '\0') {
info(event->udev, "device node creation supressed\n");
- goto exit;
+ delete_kdevnode = 1;
+ goto exit_add;
+ }
+
+ /* if rule given name disagrees with kernel node name, delete kernel node */
+ if (event->name != NULL && udev_device_get_knodename(dev) != NULL) {
+ if (strcmp(event->name, udev_device_get_knodename(dev)) != 0)
+ delete_kdevnode = 1;
}
+ /* no rule, use kernel provided name */
if (event->name == NULL) {
- info(event->udev, "no node name set, will use kernel name '%s'\n",
- udev_device_get_sysname(event->dev));
- event->name = strdup(udev_device_get_sysname(event->dev));
- if (event->name == NULL)
- goto exit;
+ if (udev_device_get_knodename(dev) != NULL) {
+ event->name = strdup(udev_device_get_knodename(dev));
+ info(event->udev, "no node name set, will use kernel supplied name '%s'\n", event->name);
+ } else {
+ event->name = strdup(udev_device_get_sysname(event->dev));
+ info(event->udev, "no node name set, will use device name '%s'\n", event->name);
+ }
+ }
+
+ /* something went wrong */
+ if (event->name == NULL) {
+ err(event->udev, "no node name for '%s'\n", udev_device_get_sysname(event->dev));
+ goto exit_add;
}
/* set device node name */
util_strlcat(filename, event->name, sizeof(filename));
udev_device_set_devnode(dev, filename);
- /* read old database entry */
- dev_old = udev_device_new_from_syspath(event->udev, udev_device_get_syspath(dev));
- if (dev_old != NULL) {
- udev_device_read_db(dev_old);
- udev_device_set_info_loaded(dev_old);
- }
-
/* write current database entry */
udev_device_update_db(dev);
/* remove/update possible left-over symlinks from old database entry */
- if (dev_old != NULL) {
+ if (dev_old != NULL)
udev_node_update_old_links(dev, dev_old);
- udev_device_unref(dev_old);
- }
/* create new node and symlinks */
err = udev_node_add(dev, event->mode, event->uid, event->gid);
-
- /* watch for changes */
- if (event->inotify_watch && inotify_fd != -1) {
- info(event->udev, "device will be watched for changes\n");
- udev_watch_begin(event->udev, event->dev);
- } else {
- udev_watch_clear(event->udev, event->dev);
+exit_add:
+ if (delete_kdevnode && udev_device_get_knodename(dev) != NULL) {
+ struct stat stats;
+
+ util_strlcpy(filename, udev_get_dev_path(event->udev), sizeof(filename));
+ util_strlcat(filename, "/", sizeof(filename));
+ util_strlcat(filename, udev_device_get_knodename(dev), sizeof(filename));
+ if (stat(filename, &stats) == 0 && stats.st_rdev == udev_device_get_devnum(dev)) {
+ unlink(filename);
+ util_delete_path(event->udev, filename);
+ info(event->udev, "removed kernel created node '%s'\n", filename);
+ }
}
+ udev_device_unref(dev_old);
goto exit;
}
udev_device_set_info_loaded(dev);
udev_device_delete_db(dev);
+ /* remove watch */
+ udev_watch_end(event->udev, dev);
+
if (udev_device_get_devnode(dev) == NULL) {
char devnode[UTIL_PATH_SIZE];