chiark / gitweb /
fix SYMLINK{} option parsing
[elogind.git] / udev / udev-rules.c
index 96d7377472789f148b200d49d635d89f7a3ff776..ddb51de8e1dc6f243dbe4dc5530adb83265499d3 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2008-2009 Kay Sievers <kay.sievers@vrfy.org>
+ * Copyright (C) 2003-2009 Kay Sievers <kay.sievers@vrfy.org>
  * Copyright (C) 2008 Alan Jenkins <alan-jenkins@tuffmail.co.uk>
  *
  * This program is free software: you can redistribute it and/or modify
@@ -27,6 +27,7 @@
 #include <errno.h>
 #include <dirent.h>
 #include <fnmatch.h>
+#include <time.h>
 
 #include "udev.h"
 
@@ -189,7 +190,8 @@ struct token {
                        unsigned int value_off;
                        union {
                                unsigned int attr_off;
-                               int ignore_error;
+                               int devlink_unique;
+                               int fail_on_error;
                                unsigned int rule_goto;
                                mode_t  mode;
                                uid_t uid;
@@ -270,7 +272,7 @@ static const char *token_str(enum token_type type)
                [TK_M_PROGRAM] =                "M PROGRAM",
                [TK_M_IMPORT_FILE] =            "M IMPORT_FILE",
                [TK_M_IMPORT_PROG] =            "M IMPORT_PROG",
-               [TK_M_IMPORT_PARENT] =          "M MPORT_PARENT",
+               [TK_M_IMPORT_PARENT] =          "M IMPORT_PARENT",
                [TK_M_RESULT] =                 "M RESULT",
                [TK_M_MAX] =                    "M MAX",
 
@@ -748,7 +750,7 @@ static int import_program_into_properties(struct udev_device *dev, const char *p
        char *line;
 
        envp = udev_device_get_properties_envp(dev);
-       if (util_run_program(udev, program, envp, result, sizeof(result), &reslen) != 0)
+       if (util_run_program(udev, program, envp, result, sizeof(result), &reslen, NULL) != 0)
                return -1;
 
        line = result;
@@ -814,6 +816,8 @@ static int wait_for_file(struct udev_device *dev, const char *file, int timeout)
 
        dbg(udev, "will wait %i sec for '%s'\n", timeout, file);
        while (--loop) {
+               const struct timespec duration = { 0, 1000 * 1000 * 1000 / WAIT_LOOP_PER_SECOND };
+
                /* lookup file */
                if (stat(file, &stats) == 0) {
                        info(udev, "file '%s' appeared after %i loops\n", file, (timeout * WAIT_LOOP_PER_SECOND) - loop-1);
@@ -825,7 +829,7 @@ static int wait_for_file(struct udev_device *dev, const char *file, int timeout)
                        return -2;
                }
                info(udev, "wait for '%s' for %i mseconds\n", file, 1000 / WAIT_LOOP_PER_SECOND);
-               usleep(1000 * 1000 / WAIT_LOOP_PER_SECOND);
+               nanosleep(&duration, NULL);
        }
        info(udev, "waiting for '%s' failed\n", file);
        return -1;
@@ -875,7 +879,7 @@ static int get_key(struct udev *udev, char **line, char **key, enum operation_ty
        char *temp;
 
        linepos = *line;
-       if (linepos == NULL && linepos[0] == '\0')
+       if (linepos == NULL || linepos[0] == '\0')
                return -1;
 
        /* skip whitespace */
@@ -1008,7 +1012,6 @@ static int rule_add_key(struct rule_tmp *rule_tmp, enum token_type type,
        case TK_A_GROUP:
        case TK_A_MODE:
        case TK_A_NAME:
-       case TK_A_DEVLINK:
        case TK_A_GOTO:
                token->key.value_off = add_string(rule_tmp->rules, value);
                break;
@@ -1021,6 +1024,10 @@ static int rule_add_key(struct rule_tmp *rule_tmp, enum token_type type,
                token->key.value_off = add_string(rule_tmp->rules, value);
                token->key.attr_off = add_string(rule_tmp->rules, attr);
                break;
+       case TK_A_DEVLINK:
+               token->key.value_off = add_string(rule_tmp->rules, value);
+               token->key.devlink_unique = *(int *)data;
+               break;
        case TK_M_TEST:
                token->key.value_off = add_string(rule_tmp->rules, value);
                if (data != NULL)
@@ -1034,7 +1041,7 @@ static int rule_add_key(struct rule_tmp *rule_tmp, enum token_type type,
                break;
        case TK_A_RUN:
                token->key.value_off = add_string(rule_tmp->rules, value);
-               token->key.ignore_error = *(int *)data;
+               token->key.fail_on_error = *(int *)data;
                break;
        case TK_A_INOTIFY_WATCH:
        case TK_A_NUM_FAKE_PART:
@@ -1124,7 +1131,7 @@ static int sort_token(struct udev_rules *rules, struct rule_tmp *rule_tmp)
 
        for (i = 0; i < rule_tmp->token_cur; i++) {
                enum token_type next_val = TK_UNSET;
-               unsigned int next_idx;
+               unsigned int next_idx = 0;
                unsigned int j;
 
                /* find smallest value */
@@ -1379,7 +1386,7 @@ static int add_rule(struct udev_rules *rules, char *line,
                        int flag = 0;
 
                        attr = get_key_attribute(rules->udev, key + sizeof("RUN")-1);
-                       if (attr != NULL && strstr(attr, "ignore_error"))
+                       if (attr != NULL && strstr(attr, "fail_event_on_error"))
                                flag = 1;
                        rule_add_key(&rule_tmp, TK_A_RUN, op, value, &flag);
                        continue;
@@ -1406,6 +1413,9 @@ static int add_rule(struct udev_rules *rules, char *line,
                        } else {
                                if (value[0] == '\0')
                                        info(rules->udev, "name empty, node creation suppressed\n");
+                               else if (strcmp(value, "%k") == 0)
+                                       err(rules->udev, "NAME=\"%%k\" is superfluous and breaks "
+                                           "kernel supplied names, please remove it from %s:%u\n", filename, lineno);
                                rule_add_key(&rule_tmp, TK_A_NAME, op, value, NULL);
                                attr = get_key_attribute(rules->udev, key + sizeof("NAME")-1);
                                if (attr != NULL) {
@@ -1425,11 +1435,17 @@ static int add_rule(struct udev_rules *rules, char *line,
                        continue;
                }
 
-               if (strcmp(key, "SYMLINK") == 0) {
-                       if (op < OP_MATCH_MAX)
+               if (strncmp(key, "SYMLINK", sizeof("SYMLINK")-1) == 0) {
+                       if (op < OP_MATCH_MAX) {
                                rule_add_key(&rule_tmp, TK_M_DEVLINK, op, value, NULL);
-                       else
-                               rule_add_key(&rule_tmp, TK_A_DEVLINK, op, value, NULL);
+                       } else {
+                               int flag = 0;
+
+                               attr = get_key_attribute(rules->udev, key + sizeof("SYMLINK")-1);
+                               if (attr != NULL && strstr(attr, "unique") != NULL)
+                                       flag = 1;
+                               rule_add_key(&rule_tmp, TK_A_DEVLINK, op, value, &flag);
+                       }
                        rule_tmp.rule.rule.flags = 1;
                        continue;
                }
@@ -1508,7 +1524,7 @@ static int add_rule(struct udev_rules *rules, char *line,
                                int tout = atoi(&pos[strlen("event_timeout=")]);
 
                                rule_add_key(&rule_tmp, TK_A_EVENT_TIMEOUT, 0, NULL, &tout);
-                               dbg(rules->udev, "event timout=%i\n", tout);
+                               dbg(rules->udev, "event timeout=%i\n", tout);
                        }
                        pos = strstr(value, "string_escape=");
                        if (pos != NULL) {
@@ -1575,7 +1591,7 @@ static int parse_file(struct udev_rules *rules, const char *filename, unsigned s
 
        first_token = rules->token_cur;
 
-       while(fgets(line, sizeof(line), f) != NULL) {
+       while (fgets(line, sizeof(line), f) != NULL) {
                char *key;
                size_t len;
 
@@ -1597,6 +1613,8 @@ static int parse_file(struct udev_rules *rules, const char *filename, unsigned s
                while (line[len-2] == '\\') {
                        if (fgets(&line[len-2], (sizeof(line)-len)+2, f) == NULL)
                                break;
+                       if (strlen(&line[len-2]) < 2)
+                               break;
                        line_nr++;
                        len = strlen(line);
                }
@@ -1795,7 +1813,7 @@ struct udev_rules *udev_rules_new(struct udev *udev, int resolve_names)
                if (stat(filename, &statbuf) == 0 && statbuf.st_size > 0)
                        parse_file(rules, filename, filename_off);
                else
-                       info(udev, "can not read '%s'\n", filename);
+                       err(udev, "can not read '%s'\n", filename);
                udev_list_entry_delete(file_loop);
        }
 
@@ -2198,7 +2216,7 @@ int udev_rules_apply_to_event(struct udev_rules *rules, struct udev_event *event
                                     program,
                                     &rules->buf[rule->rule.filename_off],
                                     rule->rule.filename_line);
-                               if (util_run_program(event->udev, program, envp, result, sizeof(result), NULL) != 0) {
+                               if (util_run_program(event->udev, program, envp, result, sizeof(result), NULL, NULL) != 0) {
                                        if (cur->key.op != OP_NOMATCH)
                                                goto nomatch;
                                } else {
@@ -2437,26 +2455,22 @@ int udev_rules_apply_to_event(struct udev_rules *rules, struct udev_event *event
                                while (isspace(pos[0]))
                                        pos++;
                                next = strchr(pos, ' ');
-                               while (next) {
+                               while (next != NULL) {
                                        next[0] = '\0';
-                                       info(event->udev, "LINK '%s' %s:%u\n",
-                                            pos,
-                                            &rules->buf[rule->rule.filename_off],
-                                            rule->rule.filename_line);
+                                       info(event->udev, "LINK '%s' %s:%u\n", pos,
+                                            &rules->buf[rule->rule.filename_off], rule->rule.filename_line);
                                        util_strscpyl(filename, sizeof(filename), udev_get_dev_path(event->udev), "/", pos, NULL);
-                                       udev_device_add_devlink(event->dev, filename);
+                                       udev_device_add_devlink(event->dev, filename, cur->key.devlink_unique);
                                        while (isspace(next[1]))
                                                next++;
                                        pos = &next[1];
                                        next = strchr(pos, ' ');
                                }
                                if (pos[0] != '\0') {
-                                       info(event->udev, "LINK '%s' %s:%u\n",
-                                            pos,
-                                            &rules->buf[rule->rule.filename_off],
-                                            rule->rule.filename_line);
+                                       info(event->udev, "LINK '%s' %s:%u\n", pos,
+                                            &rules->buf[rule->rule.filename_off], rule->rule.filename_line);
                                        util_strscpyl(filename, sizeof(filename), udev_get_dev_path(event->udev), "/", pos, NULL);
-                                       udev_device_add_devlink(event->dev, filename);
+                                       udev_device_add_devlink(event->dev, filename, cur->key.devlink_unique);
                                }
                        }
                        break;
@@ -2503,7 +2517,7 @@ int udev_rules_apply_to_event(struct udev_rules *rules, struct udev_event *event
                                     rule->rule.filename_line);
                                list_entry = udev_list_entry_add(event->udev, &event->run_list,
                                                                 &rules->buf[cur->key.value_off], NULL, 1, 0);
-                               if (cur->key.ignore_error)
+                               if (cur->key.fail_on_error)
                                        udev_list_entry_set_flag(list_entry, 1);
                                break;
                        }