chiark / gitweb /
allow setting of MODE="0000"
[elogind.git] / udev_rules.c
index e464404b5947e14a9eb4a97a6edbb0266c0cc2ab..8a793ffded484552bcdf1bca23bb10f4f044379d 100644 (file)
@@ -35,6 +35,7 @@
 
 #include "udev.h"
 #include "udev_rules.h"
+#include "udev_selinux.h"
 
 extern char **environ;
 
@@ -455,24 +456,35 @@ static int import_parent_into_env(struct udevice *udev, const char *filter)
        return rc;
 }
 
-static int pass_env_to_socket(const char *sockname, const char *devpath, const char *action)
+static int pass_env_to_socket(const char *sockpath, const char *devpath, const char *action)
 {
        int sock;
        struct sockaddr_un saddr;
-       socklen_t addrlen;
+       socklen_t saddrlen;
+       struct stat stats;
        char buf[2048];
        size_t bufpos = 0;
        int i;
        ssize_t count;
        int retval = 0;
 
-       dbg("pass environment to socket '%s'", sockname);
+       dbg("pass environment to socket '%s'", sockpath);
        sock = socket(AF_LOCAL, SOCK_DGRAM, 0);
        memset(&saddr, 0x00, sizeof(struct sockaddr_un));
        saddr.sun_family = AF_LOCAL;
-       /* abstract namespace only */
-       strcpy(&saddr.sun_path[1], sockname);
-       addrlen = offsetof(struct sockaddr_un, sun_path) + strlen(saddr.sun_path+1) + 1;
+       if (sockpath[0] == '@') {
+               /* abstract namespace socket requested */
+               strlcpy(&saddr.sun_path[1], &sockpath[1], sizeof(saddr.sun_path)-1);
+               saddrlen = offsetof(struct sockaddr_un, sun_path) + 1 + strlen(&saddr.sun_path[1]);
+       } else if (stat(sockpath, &stats) == 0 && S_ISSOCK(stats.st_mode)) {
+               /* existing socket file */
+               strlcpy(saddr.sun_path, sockpath, sizeof(saddr.sun_path));
+               saddrlen = offsetof(struct sockaddr_un, sun_path) + strlen(saddr.sun_path);
+       } else {
+               /* no socket file, assume abstract namespace socket */
+               strlcpy(&saddr.sun_path[1], sockpath, sizeof(saddr.sun_path)-1);
+               saddrlen = offsetof(struct sockaddr_un, sun_path) + 1 + strlen(&saddr.sun_path[1]);
+       }
 
        bufpos = snprintf(buf, sizeof(buf)-1, "%s@%s", action, devpath);
        bufpos++;
@@ -483,10 +495,10 @@ static int pass_env_to_socket(const char *sockname, const char *devpath, const c
        if (bufpos > sizeof(buf))
                bufpos = sizeof(buf);
 
-       count = sendto(sock, &buf, bufpos, 0, (struct sockaddr *)&saddr, addrlen);
+       count = sendto(sock, &buf, bufpos, 0, (struct sockaddr *)&saddr, saddrlen);
        if (count < 0)
                retval = -1;
-       info("passed %zi bytes to socket '%s', ", count, sockname);
+       info("passed %zi bytes to socket '%s', ", count, sockpath);
 
        close(sock);
        return retval;
@@ -586,6 +598,44 @@ out:
        return found;
 }
 
+static int attr_subst_subdir(char *attr, size_t len)
+{
+       char *pos;
+       int found = 0;
+
+       pos = strstr(attr, "/*/");
+       if (pos != NULL) {
+               char str[PATH_SIZE];
+               DIR *dir;
+
+               pos[1] = '\0';
+               strlcpy(str, &pos[2], sizeof(str));
+               dir = opendir(attr);
+               if (dir != NULL) {
+                       struct dirent *dent;
+
+                       for (dent = readdir(dir); dent != NULL; dent = readdir(dir)) {
+                               struct stat stats;
+
+                               if (dent->d_name[0] == '.')
+                                       continue;
+                               strlcat(attr, dent->d_name, len);
+                               strlcat(attr, str, len);
+                               if (stat(attr, &stats) == 0) {
+                                       found = 1;
+                                       break;
+                               }
+                               pos[1] = '\0';
+                       }
+                       closedir(dir);
+               }
+               if (!found)
+                       strlcat(attr, str, len);
+       }
+
+       return found;
+}
+
 void udev_rules_apply_format(struct udevice *udev, char *string, size_t maxsize)
 {
        char temp[PATH_SIZE];
@@ -1023,6 +1073,8 @@ static int match_rule(struct udevice *udev, struct udev_rule *rule)
                        strlcpy(filename, tmp, sizeof(filename));
                }
 
+               attr_subst_subdir(filename, sizeof(filename));
+
                match = (stat(filename, &statbuf) == 0);
                info("'%s' %s", filename, match ? "exists" : "does not exist");
                if (match && rule->test_mode_mask > 0) {
@@ -1244,7 +1296,6 @@ try_parent:
                if (pair->key.operation == KEY_OP_ASSIGN) {
                        const char *key_name = key_pair_name(rule, pair);
                        char devpath[PATH_SIZE];
-                       char *pos;
                        char *attrib;
                        char attr[PATH_SIZE] = "";
                        char value[NAME_SIZE];
@@ -1266,27 +1317,7 @@ try_parent:
                                strlcat(attr, key_name, sizeof(attr));
                        }
 
-                       pos = strstr(attr, "/*/");
-                       if (pos != NULL) {
-                               char str[PATH_SIZE];
-                               DIR *dir;
-
-                               pos[1] = '\0';
-                               strlcpy(str, &pos[2], sizeof(str));
-                               dir = opendir(attr);
-                               if (dir != NULL) {
-                                       struct dirent *dent;
-
-                                       for (dent = readdir(dir); dent != NULL; dent = readdir(dir)) {
-                                               if (dent->d_name[0] == '.')
-                                                       continue;
-                                               strlcat(attr, dent->d_name, sizeof(attr));
-                                               break;
-                                       }
-                                       closedir(dir);
-                               }
-                               strlcat(attr, str, sizeof(attr));
-                       }
+                       attr_subst_subdir(attr, sizeof(attr));
 
                        strlcpy(value, key_val(rule, &pair->key), sizeof(value));
                        udev_rules_apply_format(udev, value, sizeof(value));
@@ -1354,11 +1385,11 @@ int udev_rules_get_name(struct udev_rules *rules, struct udevice *udev)
                        }
 
                        /* apply permissions */
-                       if (!udev->mode_final && rule->mode != 0000) {
-                               if (rule->mode_operation == KEY_OP_ASSIGN_FINAL)
+                       if (!udev->mode_final && rule->mode.operation != KEY_OP_UNSET) {
+                               if (rule->mode.operation == KEY_OP_ASSIGN_FINAL)
                                        udev->mode_final = 1;
-                               udev->mode = rule->mode;
-                               dbg("applied mode=%#o to '%s'", rule->mode, udev->dev->kernel);
+                               udev->mode = strtol(key_val(rule, &rule->mode), NULL, 8);
+                               dbg("applied mode=%#o to '%s'", udev->mode, udev->dev->kernel);
                        }
                        if (!udev->owner_final && rule->owner.operation != KEY_OP_UNSET) {
                                if (rule->owner.operation == KEY_OP_ASSIGN_FINAL)
@@ -1503,7 +1534,7 @@ int udev_rules_get_run(struct udev_rules *rules, struct udevice *udev)
                    rule->symlink.operation == KEY_OP_ASSIGN ||
                    rule->symlink.operation == KEY_OP_ASSIGN_FINAL ||
                    rule->symlink.operation == KEY_OP_ADD ||
-                   rule->mode_operation != KEY_OP_UNSET ||
+                   rule->mode.operation != KEY_OP_UNSET ||
                    rule->owner.operation != KEY_OP_UNSET || rule->group.operation != KEY_OP_UNSET) {
                        dbg("skip rule that names a device");
                        continue;