chiark / gitweb /
[PATCH] handle whole hotplug event with udevd/udev
[elogind.git] / udev_lib.c
index 50598a4a318592d315fc942d6fead6b89ced4b41..86a526f7e816ecca46aedf4dc622a355d92b7b74 100644 (file)
 
 #include <stdlib.h>
 #include <stdio.h>
+#include <stddef.h>
 #include <unistd.h>
 #include <fcntl.h>
+#include <errno.h>
+#include <dirent.h>
 #include <sys/stat.h>
 #include <sys/mman.h>
+#include <sys/utsname.h>
 
-#include "libsysfs/sysfs/libsysfs.h"
 #include "udev.h"
+#include "logging.h"
 #include "udev_lib.h"
+#include "list.h"
 
 
-char *get_action(void)
+void udev_set_values(struct udevice *udev, const char* devpath,
+                    const char *subsystem, const char* action)
 {
-       char *action;
-
-       action = getenv("ACTION");
-       if (action != NULL && strlen(action) > ACTION_SIZE)
-               action[ACTION_SIZE-1] = '\0';
-
-       return action;
+       memset(udev, 0x00, sizeof(struct udevice));
+
+       if (devpath)
+               strfieldcpy(udev->devpath, devpath);
+       if (subsystem)
+               strfieldcpy(udev->subsystem, subsystem);
+       if (action)
+               strfieldcpy(udev->action, action);
+
+       if (strcmp(udev->subsystem, "block") == 0)
+               udev->type = 'b';
+       else if (strcmp(udev->subsystem, "net") == 0)
+               udev->type = 'n';
+       else if (strncmp(udev->devpath, "/block/", 7) == 0)
+               udev->type = 'b';
+       else if (strncmp(udev->devpath, "/class/net/", 11) == 0)
+               udev->type = 'n';
+       else if (strncmp(udev->devpath, "/class/", 7) == 0)
+               udev->type = 'c';
 }
 
-char *get_devpath(void)
+int kernel_release_satisfactory(int version, int patchlevel, int sublevel)
 {
-       char *devpath;
-
-       devpath = getenv("DEVPATH");
-       if (devpath != NULL && strlen(devpath) > DEVPATH_SIZE)
-               devpath[DEVPATH_SIZE-1] = '\0';
+       static int kversion = 0;
+       static int kpatchlevel;
+       static int ksublevel;
+
+       if (kversion == 0) {
+               struct utsname uts;
+               if (uname(&uts) != 0)
+                       return -1;
+
+               if (sscanf (uts.release, "%u.%u.%u", &kversion, &kpatchlevel, &ksublevel) != 3) {
+                       kversion = 0;
+                       return -1;
+               }
+       }
 
-       return devpath;
+       if (kversion >= version && kpatchlevel >= patchlevel && ksublevel >= sublevel)
+               return 1;
+       else
+               return 0;
 }
 
-char *get_seqnum(void)
+int create_path(const char *path)
 {
-       char *seqnum;
+       char p[NAME_SIZE];
+       char *pos;
+       struct stat stats;
 
-       seqnum = getenv("SEQNUM");
+       strcpy (p, path);
+       pos = strrchr(p, '/');
+       if (pos == p || pos == NULL)
+               return 0;
 
-       return seqnum;
-}
+       while (pos[-1] == '/')
+               pos--;
 
-char *get_subsystem(char *subsystem)
-{
-       if (subsystem != NULL && strlen(subsystem) > SUBSYSTEM_SIZE)
-               subsystem[SUBSYSTEM_SIZE-1] = '\0';
+       pos[0] = '\0';
+
+       dbg("stat '%s'\n", p);
+       if (stat (p, &stats) == 0 && (stats.st_mode & S_IFMT) == S_IFDIR)
+               return 0;
 
-       return subsystem;
+       if (create_path (p) != 0)
+               return -1;
+
+       dbg("mkdir '%s'\n", p);
+       return mkdir(p, 0755);
 }
 
 int file_map(const char *filename, char **buf, size_t *bufsize)
@@ -81,11 +121,13 @@ int file_map(const char *filename, char **buf, size_t *bufsize)
        }
 
        if (fstat(fd, &stats) < 0) {
+               close(fd);
                return -1;
        }
 
        *buf = mmap(NULL, stats.st_size, PROT_READ, MAP_SHARED, fd, 0);
        if (*buf == MAP_FAILED) {
+               close(fd);
                return -1;
        }
        *bufsize = stats.st_size;
@@ -109,3 +151,94 @@ size_t buf_get_line(char *buf, size_t buflen, size_t cur)
        return count - cur;
 }
 
+void no_trailing_slash(char *path)
+{
+       int len;
+
+       len = strlen(path);
+       if (len > 0 && path[len-1] == '/')
+               path[len-1] = '\0';
+}
+
+struct files {
+       struct list_head list;
+       char name[NAME_SIZE];
+};
+
+/* sort files in lexical order */
+static int file_list_insert(char *filename, struct list_head *file_list)
+{
+       struct files *loop_file;
+       struct files *new_file;
+
+       list_for_each_entry(loop_file, file_list, list) {
+               if (strcmp(loop_file->name, filename) > 0) {
+                       break;
+               }
+       }
+
+       new_file = malloc(sizeof(struct files));
+       if (new_file == NULL) {
+               dbg("error malloc");
+               return -ENOMEM;
+       }
+
+       strfieldcpy(new_file->name, filename);
+       list_add_tail(&new_file->list, &loop_file->list);
+       return 0;
+}
+
+/* calls function for every file found in specified directory */
+int call_foreach_file(file_fnct_t fnct, const char *dirname,
+                     const char *suffix, void *data)
+{
+       struct dirent *ent;
+       DIR *dir;
+       char *ext;
+       struct files *loop_file;
+       struct files *tmp_file;
+       LIST_HEAD(file_list);
+
+       dbg("open directory '%s'", dirname);
+       dir = opendir(dirname);
+       if (dir == NULL) {
+               dbg("unable to open '%s'", dirname);
+               return -1;
+       }
+
+       while (1) {
+               ent = readdir(dir);
+               if (ent == NULL || ent->d_name[0] == '\0')
+                       break;
+
+               if ((ent->d_name[0] == '.') || (ent->d_name[0] == COMMENT_CHARACTER))
+                       continue;
+
+               /* look for file with specified suffix */
+               ext = strrchr(ent->d_name, '.');
+               if (ext == NULL)
+                       continue;
+
+               if (strcmp(ext, suffix) != 0)
+                       continue;
+
+               dbg("put file '%s/%s' in list", dirname, ent->d_name);
+               file_list_insert(ent->d_name, &file_list);
+       }
+
+       /* call function for every file in the list */
+       list_for_each_entry_safe(loop_file, tmp_file, &file_list, list) {
+               char filename[NAME_SIZE];
+
+               snprintf(filename, NAME_SIZE, "%s/%s", dirname, loop_file->name);
+               filename[NAME_SIZE-1] = '\0';
+
+               fnct(filename, data);
+
+               list_del(&loop_file->list);
+               free(loop_file);
+       }
+
+       closedir(dir);
+       return 0;
+}