/*
- * udev_lib - generic stuff used by udev
+ * udev_utils.c - generic stuff used by udev
*
- * Copyright (C) 2004 Kay Sievers <kay@vrfy.org>
+ * Copyright (C) 2004-2005 Kay Sievers <kay.sievers@vrfy.org>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
#include <ctype.h>
#include <dirent.h>
#include <syslog.h>
+#include <sys/socket.h>
+#include <sys/un.h>
#include <sys/wait.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include "udev_utils.h"
#include "list.h"
-
-int udev_init_device(struct udevice *udev, const char* devpath, const char *subsystem, const char *action)
+/* compare string with pattern (supports * ? [0-9] [!A-Z]) */
+int strcmp_pattern(const char *p, const char *s)
{
- char *pos;
-
- memset(udev, 0x00, sizeof(struct udevice));
- INIT_LIST_HEAD(&udev->symlink_list);
- INIT_LIST_HEAD(&udev->run_list);
-
- if (subsystem)
- strlcpy(udev->subsystem, subsystem, sizeof(udev->subsystem));
-
- if (action)
- strlcpy(udev->action, action, sizeof(udev->action));
-
- if (devpath) {
- strlcpy(udev->devpath, devpath, sizeof(udev->devpath));
- remove_trailing_char(udev->devpath, '/');
-
- if (strncmp(udev->devpath, "/block/", 7) == 0)
- udev->type = DEV_BLOCK;
- else if (strncmp(udev->devpath, "/class/net/", 11) == 0)
- udev->type = DEV_NET;
- else if (strncmp(udev->devpath, "/class/", 7) == 0)
- udev->type = DEV_CLASS;
- else if (strncmp(udev->devpath, "/devices/", 9) == 0)
- udev->type = DEV_DEVICE;
-
- /* get kernel name */
- pos = strrchr(udev->devpath, '/');
- if (pos) {
- strlcpy(udev->kernel_name, &pos[1], sizeof(udev->kernel_name));
- dbg("kernel_name='%s'", udev->kernel_name);
-
- /* Some block devices have '!' in their name, change that to '/' */
- pos = udev->kernel_name;
- while (pos[0] != '\0') {
- if (pos[0] == '!')
- pos[0] = '/';
- pos++;
+ if (s[0] == '\0') {
+ while (p[0] == '*')
+ p++;
+ return (p[0] != '\0');
+ }
+ switch (p[0]) {
+ case '[':
+ {
+ int not = 0;
+ p++;
+ if (p[0] == '!') {
+ not = 1;
+ p++;
+ }
+ while ((p[0] != '\0') && (p[0] != ']')) {
+ int match = 0;
+ if (p[1] == '-') {
+ if ((s[0] >= p[0]) && (s[0] <= p[2]))
+ match = 1;
+ p += 3;
+ } else {
+ match = (p[0] == s[0]);
+ p++;
+ }
+ if (match ^ not) {
+ while ((p[0] != '\0') && (p[0] != ']'))
+ p++;
+ if (p[0] == ']')
+ return strcmp_pattern(p+1, s+1);
+ }
}
-
- /* get kernel number */
- pos = &udev->kernel_name[strlen(udev->kernel_name)];
- while (isdigit(pos[-1]))
- pos--;
- strlcpy(udev->kernel_number, pos, sizeof(udev->kernel_number));
- dbg("kernel_number='%s'", udev->kernel_number);
}
+ break;
+ case '*':
+ if (strcmp_pattern(p, s+1))
+ return strcmp_pattern(p+1, s);
+ return 0;
+ case '\0':
+ if (s[0] == '\0') {
+ return 0;
+ }
+ break;
+ default:
+ if ((p[0] == s[0]) || (p[0] == '?'))
+ return strcmp_pattern(p+1, s+1);
+ break;
}
-
- if (udev->type == DEV_BLOCK || udev->type == DEV_CLASS) {
- udev->mode = 0660;
- strcpy(udev->owner, "root");
- strcpy(udev->group, "root");
- }
-
- return 0;
-}
-
-void udev_cleanup_device(struct udevice *udev)
-{
- struct name_entry *name_loop;
- struct name_entry *temp_loop;
-
- list_for_each_entry_safe(name_loop, temp_loop, &udev->symlink_list, node) {
- list_del(&name_loop->node);
- free(name_loop);
- }
- list_for_each_entry_safe(name_loop, temp_loop, &udev->run_list, node) {
- list_del(&name_loop->node);
- free(name_loop);
- }
+ return 1;
}
int string_is_true(const char *str)
dbg("'%s' is already in the list", name);
return 0;
}
- if (sort && strcmp(loop_name->name, name) > 0)
- break;
}
+ if (sort)
+ list_for_each_entry(loop_name, name_list, node) {
+ if (sort && strcmp(loop_name->name, name) > 0)
+ break;
+ }
+
new_name = malloc(sizeof(struct name_entry));
if (new_name == NULL) {
dbg("error malloc");
}
strlcpy(new_name->name, name, sizeof(new_name->name));
+ dbg("adding '%s'", new_name->name);
+ list_add_tail(&new_name->node, &loop_name->node);
+
+ return 0;
+}
+
+int name_list_key_add(struct list_head *name_list, const char *key, const char *value)
+{
+ struct name_entry *loop_name;
+ struct name_entry *new_name;
+
+ list_for_each_entry(loop_name, name_list, node) {
+ if (strncmp(loop_name->name, key, strlen(key)) == 0) {
+ dbg("key already present '%s', replace it", loop_name->name);
+ snprintf(loop_name->name, sizeof(loop_name->name), "%s=%s", key, value);
+ loop_name->name[sizeof(loop_name->name)-1] = '\0';
+ return 0;
+ }
+ }
+
+ new_name = malloc(sizeof(struct name_entry));
+ if (new_name == NULL) {
+ dbg("error malloc");
+ return -ENOMEM;
+ }
+
+ snprintf(new_name->name, sizeof(new_name->name), "%s=%s", key, value);
+ new_name->name[sizeof(new_name->name)-1] = '\0';
+ dbg("adding '%s'", new_name->name);
list_add_tail(&new_name->node, &loop_name->node);
return 0;
return 0;
}
+int pass_env_to_socket(const char *sockname, const char *devpath, const char *action)
+{
+ int sock;
+ struct sockaddr_un saddr;
+ socklen_t addrlen;
+ char buf[2048];
+ size_t bufpos = 0;
+ int i;
+ int retval;
+
+ dbg("pass environment to socket '%s'", sockname);
+ sock = socket(AF_LOCAL, SOCK_DGRAM, 0);
+ memset(&saddr, 0x00, sizeof(struct sockaddr_un));
+ saddr.sun_family = AF_LOCAL;
+ /* only abstract namespace is supported */
+ strcpy(&saddr.sun_path[1], sockname);
+ addrlen = offsetof(struct sockaddr_un, sun_path) + strlen(saddr.sun_path+1) + 1;
+
+ bufpos = snprintf(buf, sizeof(buf)-1, "%s@%s", action, devpath);
+ bufpos++;
+ for (i = 0; environ[i] != NULL && bufpos < sizeof(buf); i++) {
+ bufpos += strlcpy(&buf[bufpos], environ[i], sizeof(buf) - bufpos-1);
+ bufpos++;
+ }
+
+ retval = sendto(sock, &buf, bufpos, 0, (struct sockaddr *)&saddr, addrlen);
+ if (retval != -1)
+ retval = 0;
+
+ close(sock);
+ return retval;
+}
+
int execute_program(const char *command, const char *subsystem,
char *result, size_t ressize, size_t *reslen)
{
len += count;
if (len >= ressize-1) {
- err("ressize %d too short", ressize);
+ err("ressize %ld too short", (long)ressize);
retval = -1;
break;
}