chiark / gitweb /
[PATCH] switch major/minor to dev_t
[elogind.git] / udev_sysfs.c
index 624f53586f65c51dc63b481d99d79d5af57b47ac..f0666509eaca5b87614d4124eb5a5e0d014ff4c5 100644 (file)
 #include <errno.h>
 #include <sys/stat.h>
 
-#include "logging.h"
+#include "libsysfs/sysfs/libsysfs.h"
 #include "udev_version.h"
 #include "udev_sysfs.h"
-#include "libsysfs/sysfs/libsysfs.h"
+#include "udev_utils.h"
+#include "logging.h"
 
-/* list of subsystem specific files
- * NULL if there is no file to wait for
- */
-static struct subsystem_file {
-       char *subsystem;
-       char *file;
+/* list of subsystem specific files, NULL if there is no file to wait for */
+static const struct subsystem_file {
+       const char *subsystem;
+       const char *file;
 } subsystem_files[] = {
+       { .subsystem = "class",         .file = NULL },
        { .subsystem = "net",           .file = "ifindex" },
        { .subsystem = "scsi_host",     .file = "unique_id" },
        { .subsystem = "scsi_device",   .file = NULL },
@@ -52,12 +52,33 @@ static struct subsystem_file {
        { .subsystem = "ieee1394",      .file = NULL },
        { .subsystem = "ieee1394_host", .file = NULL },
        { .subsystem = "ieee1394_node", .file = NULL },
+       { .subsystem = "fc_transport",  .file = "port_id" },
+       { .subsystem = "fc_host",       .file = "port_id" },
+       { .subsystem = "spi_transport", .file = "width" },
+       { .subsystem = "spi_host",      .file = "width" },
        { NULL, NULL }
 };
 
+dev_t get_devt(struct sysfs_class_device *class_dev)
+{
+       struct sysfs_attribute *attr = NULL;
+       unsigned int major, minor;
+
+       attr = sysfs_get_classdev_attr(class_dev, "dev");
+       if (attr == NULL)
+               return 0;
+       dbg("dev='%s'", attr->value);
+
+       if (sscanf(attr->value, "%u:%u", &major, &minor) != 2)
+               return 0;
+       dbg("found major=%d, minor=%d", major, minor);
+
+       return makedev(major, minor);
+}
+
 int subsystem_expect_no_dev(const char *subsystem)
 {
-       struct subsystem_file *file;
+       const struct subsystem_file *file;
 
        for (file = subsystem_files; file->subsystem != NULL; file++)
                if (strcmp(subsystem, file->subsystem) == 0)
@@ -67,9 +88,9 @@ int subsystem_expect_no_dev(const char *subsystem)
 }
 
 /* get subsystem specific files, returns "dev" if no other found */
-static char *get_subsystem_specific_file(const char *subsystem)
+static const char *get_subsystem_specific_file(const char *subsystem)
 {
-       struct subsystem_file *file;
+       const struct subsystem_file *file;
 
        /* look if we want to look for another file instead of "dev" */
        for (file = subsystem_files; file->subsystem != NULL; file++)
@@ -93,10 +114,8 @@ static int wait_for_class_device_attributes(struct sysfs_class_device *class_dev
                return 0;
        }
 
-       strcpy(filename, class_dev->path);
-       strcat(filename, "/");
-       strcat(filename, file);
-       dbg("looking at class '%s' for specific file '%s' with full name %s", class_dev->classname, file, filename);
+       snprintf(filename, SYSFS_PATH_MAX-1, "%s/%s", class_dev->path, file);
+       dbg("looking at class '%s' for specific file '%s'", class_dev->classname, filename);
 
        loop = WAIT_MAX_SECONDS * WAIT_LOOP_PER_SECOND;
        while (--loop) {
@@ -126,9 +145,9 @@ static int class_device_expect_no_device_link(struct sysfs_class_device *class_d
 {
        /* list of devices without a "device" symlink to the physical device
         * if device is set to NULL, no devices in that subsystem has a link */
-       static struct class_device {
-               char *subsystem;
-               char *device;
+       static const struct class_device {
+               const char *subsystem;
+               const char *device;
        } class_device[] = {
                { .subsystem = "block",         .device = "double" },
                { .subsystem = "block",         .device = "nb" },
@@ -148,6 +167,7 @@ static int class_device_expect_no_device_link(struct sysfs_class_device *class_d
                { .subsystem = "block",         .device = "scd" },
                { .subsystem = "block",         .device = "ubd" },
                { .subsystem = "block",         .device = "dm-" },
+               { .subsystem = "block",         .device = "bcrypt" },
                { .subsystem = "input",         .device = "event" },
                { .subsystem = "input",         .device = "mice" },
                { .subsystem = "input",         .device = "mouse" },
@@ -167,11 +187,20 @@ static int class_device_expect_no_device_link(struct sysfs_class_device *class_d
                { .subsystem = "net",           .device = "dummy" },
                { .subsystem = "net",           .device = "irda" },
                { .subsystem = "net",           .device = "ppp" },
+               { .subsystem = "net",           .device = "tun" },
+               { .subsystem = "net",           .device = "pan" },
+               { .subsystem = "net",           .device = "bnep" },
+               { .subsystem = "net",           .device = "vmnet" },
+               { .subsystem = "net",           .device = "ippp" },
+               { .subsystem = "net",           .device = "nlv" },
+               { .subsystem = "net",           .device = "atml" },
                { .subsystem = "ppp",           .device = NULL },
                { .subsystem = "sound",         .device = NULL },
                { .subsystem = "printer",       .device = "lp" },
+               { .subsystem = "ppdev",         .device = NULL },
                { .subsystem = "nvidia",        .device = NULL },
                { .subsystem = "video4linux",   .device = "vbi" },
+               { .subsystem = "dvb",           .device = NULL },
                { .subsystem = "lirc",          .device = NULL },
                { .subsystem = "firmware",      .device = NULL },
                { .subsystem = "drm",           .device = NULL },
@@ -180,10 +209,33 @@ static int class_device_expect_no_device_link(struct sysfs_class_device *class_d
                { .subsystem = "ieee1394_host", .device = NULL },
                { .subsystem = "ieee1394_node", .device = NULL },
                { .subsystem = "raw",           .device = NULL },
+               { .subsystem = "zaptel",        .device = NULL },
+               { .subsystem = "tiglusb",       .device = NULL },
+               { .subsystem = "ppdev",         .device = NULL },
+               { .subsystem = "ticables",      .device = NULL },
+               { .subsystem = "snsc",          .device = NULL },
+               { .subsystem = "staliomem",     .device = NULL },
+               { .subsystem = "tape",          .device = NULL },
+               { .subsystem = "ip2",           .device = NULL },
+               { .subsystem = "tpqic02",       .device = NULL },
+               { .subsystem = "dsp56k",        .device = NULL },
+               { .subsystem = "zft",           .device = NULL },
+               { .subsystem = "adb",           .device = NULL },
+               { .subsystem = "cosa",          .device = NULL },
+               { .subsystem = "pg",            .device = NULL },
+               { .subsystem = "pt",            .device = NULL },
+               { .subsystem = "capi",          .device = NULL },
                { NULL, NULL }
        };
-       struct class_device *classdevice;
-       int len;
+       const struct class_device *classdevice;
+       unsigned int len;
+
+       /* the kernel may tell us what to wait for */
+       if (kernel_release_satisfactory(2,6,10) > 0)
+               if (getenv("PHYSDEVPATH") == NULL) {
+                       dbg("the kernel says, that there is no physical device for '%s'", class_dev->path);
+                       return 1;
+               }
 
        for (classdevice = class_device; classdevice->subsystem != NULL; classdevice++) {
                if (strcmp(class_dev->classname, classdevice->subsystem) == 0) {
@@ -210,15 +262,16 @@ static int class_device_expect_no_device_link(struct sysfs_class_device *class_d
        return 0;
 }
 
-/* skip waiting for the bus */
+/* skip waiting for the bus of the devices device */
 static int class_device_expect_no_bus(struct sysfs_class_device *class_dev)
 {
-       static char *devices_without_bus[] = {
+       static const char *devices_without_bus[] = {
                "scsi_host",
                "i2c-adapter",
+               "i2c-dev",
                NULL
        };
-       char **device;
+       const char **device;
 
        for (device = devices_without_bus; *device != NULL; device++) {
                int len = strlen(*device);
@@ -230,14 +283,14 @@ static int class_device_expect_no_bus(struct sysfs_class_device *class_dev)
        return 0;
 }
 
-/* wait for the bus and for a bus specific file to show up */
-int wait_for_bus_device(struct sysfs_device *devices_dev,
+/* wait for a devices device specific file to show up */
+int wait_for_devices_device(struct sysfs_device *devices_dev,
                        const char **error)
 {
-       static struct bus_file {
-               char *bus;
-               char *file;
-       } bus_files[] = {
+       static const struct device_file {
+               const char *bus;
+               const char *file;
+       } device_files[] = {
                { .bus = "scsi",        .file = "vendor" },
                { .bus = "usb",         .file = "idVendor" },
                { .bus = "usb",         .file = "iInterface" },
@@ -246,12 +299,45 @@ int wait_for_bus_device(struct sysfs_device *devices_dev,
                { .bus = "ide",         .file = "detach_state" },
                { .bus = "pci",         .file = "vendor" },
                { .bus = "platform",    .file = "detach_state" },
+               { .bus = "pcmcia",      .file = "detach_state" },
                { .bus = "i2c",         .file = "detach_state" },
-               { NULL }
+               { .bus = "ieee1394",    .file = "node_count" },
+               { .bus = "ieee1394",    .file = "nodeid" },
+               { .bus = "ieee1394",    .file = "address" },
+               { .bus = "bttv-sub",    .file = NULL },
+               { .bus = "pnp",         .file = "detach_state" },
+               { .bus = "eisa",        .file = "detach_state" },
+               { .bus = "pseudo",      .file = "detach_state" },
+               { .bus = "mmc",         .file = "detach_state" },
+               { .bus = "macio",       .file = "detach_state" },
+               { .bus = "of_platform", .file = "detach_state" },
+               { .bus = "vio",         .file = "detach_state" },
+               { .bus = "ecard",       .file = "detach_state" },
+               { .bus = "sa1111-rab",  .file = "detach_state" },
+               { .bus = "amba",        .file = "detach_state" },
+               { .bus = "locomo-bus",  .file = "detach_state" },
+               { .bus = "logicmodule", .file = "detach_state" },
+               { .bus = "parisc",      .file = "detach_state" },
+               { .bus = "ocp",         .file = "detach_state" },
+               { .bus = "dio",         .file = "detach_state" },
+               { .bus = "MCA",         .file = "detach_state" },
+               { .bus = "wl",          .file = "detach_state" },
+               { .bus = "ccwgroup",    .file = "detach_state" },
+               { .bus = "css",         .file = "detach_state" },
+               { .bus = "ccw",         .file = "detach_state" },
+               { .bus = "iucv",        .file = "detach_state" },
+               { NULL, NULL }
        };
-       struct bus_file *busfile;
+       const struct device_file *devicefile;
        int loop;
 
+       /* the kernel may tell us what to wait for */
+       if (kernel_release_satisfactory(2,6,10) > 0)
+               if (getenv("PHYSDEVBUS") == NULL) {
+                       dbg("the kernel says, that there is no bus for '%s'", devices_dev->path);
+                       return 0;
+               }
+
        /* wait for the bus device link to the devices device */
        loop = WAIT_MAX_SECONDS * WAIT_LOOP_PER_SECOND;
        while (--loop) {
@@ -268,22 +354,32 @@ int wait_for_bus_device(struct sysfs_device *devices_dev,
        }
        dbg("bus device link found for bus '%s'", devices_dev->bus);
 
-       /* wait for a bus specific file to show up */
+       /* wait for a bus device specific file to show up */
        loop = WAIT_MAX_SECONDS * WAIT_LOOP_PER_SECOND;
        while (--loop) {
-               int found = 0;
-
-               for (busfile = bus_files; busfile->bus != NULL; busfile++) {
-                       if (strcmp(devices_dev->bus, busfile->bus) == 0) {
-                               found = 1;
-                               dbg("looking at bus '%s' for specific file '%s'", devices_dev->bus, busfile->file);
-                               if (sysfs_get_device_attr(devices_dev, busfile->file) != NULL) {
-                                       dbg("bus '%s' specific file '%s' found", devices_dev->bus, busfile->file);
+               int found_bus_type = 0;
+
+               for (devicefile = device_files; devicefile->bus != NULL; devicefile++) {
+                       if (strcmp(devices_dev->bus, devicefile->bus) == 0) {
+                               char filename[SYSFS_PATH_MAX];
+                               struct stat stats;
+
+                               if (devicefile->file == NULL) {
+                                       dbg("bus '%s' has no file to wait for", devices_dev->bus);
+                                       return 0;
+                               }
+
+                               found_bus_type = 1;
+                               snprintf(filename, SYSFS_PATH_MAX-1, "%s/%s", devices_dev->path, devicefile->file);
+                               dbg("looking at bus '%s' device for specific file '%s'", devices_dev->bus, filename);
+
+                               if (stat(filename, &stats) == 0) {
+                                       dbg("bus '%s' device specific file '%s' found", devices_dev->bus, devicefile->file);
                                        return 0;
                                }
                        }
                }
-               if (found == 0) {
+               if (found_bus_type == 0) {
                        if (error)
                                *error = "unknown bus";
                        info("error: unknown bus, please report to "
@@ -293,16 +389,16 @@ int wait_for_bus_device(struct sysfs_device *devices_dev,
                usleep(1000 * 1000 / WAIT_LOOP_PER_SECOND);
        }
 
-       dbg("error: getting bus '%s' specific file '%s'", devices_dev->bus, busfile->file);
+       dbg("error: getting '%s' device specific file '%s'", devices_dev->bus, devicefile->file);
        if (error)
-               *error = "bus specific file unavailable";
+               *error = "bus device specific file unavailable";
        return -1;
 }
 
 
-struct sysfs_class_device *open_class_device_wait(const char *path)
+struct sysfs_class_device *wait_class_device_open(const char *path)
 {
-       struct sysfs_class_device *class_dev;
+       struct sysfs_class_device *class_dev = NULL;
        int loop;
 
        loop = WAIT_MAX_SECONDS * WAIT_LOOP_PER_SECOND;
@@ -314,7 +410,7 @@ struct sysfs_class_device *open_class_device_wait(const char *path)
                usleep(1000 * 1000 / WAIT_LOOP_PER_SECOND);
        }
 
-       return (class_dev);
+       return class_dev;
 }
 
 int wait_for_class_device(struct sysfs_class_device *class_dev,
@@ -330,7 +426,7 @@ int wait_for_class_device(struct sysfs_class_device *class_dev,
        /* skip devices without devices-link */
        if (class_device_expect_no_device_link(class_dev)) {
                dbg("no device symlink expected for '%s', ", class_dev->name);
-               return -ENODEV;
+               return 0;
        }
 
        /* the symlink may be on the parent device */
@@ -360,18 +456,18 @@ int wait_for_class_device(struct sysfs_class_device *class_dev,
        }
        dbg("device symlink found pointing to '%s'", devices_dev->path);
 
-       /* wait for the bus value */
+       /* wait for the devices device */
        if (class_device_expect_no_bus(class_dev)) {
                dbg("no bus device expected for '%s', ", class_dev->classname);
                return 0;
-       } else {
-               return wait_for_bus_device(devices_dev, error);
        }
+
+       return wait_for_devices_device(devices_dev, error);
 }
 
-struct sysfs_device *open_devices_device_wait(const char *path)
+struct sysfs_device *wait_devices_device_open(const char *path)
 {
-       struct sysfs_device *devices_dev;
+       struct sysfs_device *devices_dev = NULL;
        int loop;
 
        loop = WAIT_MAX_SECONDS * WAIT_LOOP_PER_SECOND;
@@ -383,5 +479,5 @@ struct sysfs_device *open_devices_device_wait(const char *path)
                usleep(1000 * 1000 / WAIT_LOOP_PER_SECOND);
        }
 
-       return(devices_dev);
+       return devices_dev;
 }