From mboxrd@z Thu Jan 1 00:00:00 1970 From: Kay Sievers Date: Sun, 07 Dec 2003 06:02:59 +0000 Subject: Re: [udev] experimental (very simple) SYMLINK creation MIME-Version: 1 Content-Type: multipart/mixed; boundary="Kj7319i9nmIyA2yE" Message-Id: List-Id: References: In-Reply-To: To: linux-hotplug@vger.kernel.org --Kj7319i9nmIyA2yE Content-Type: text/plain; charset=us-ascii Content-Disposition: inline On Fri, Dec 05, 2003 at 04:45:28PM +0100, Kay Sievers wrote: > On Fri, Dec 05, 2003 at 05:24:33AM +0100, Kay Sievers wrote: > > here is a experimental symlink creation patch - for discussion, > > in which direction we should go. > > It is possible now to define SYMLINK= after the NAME= in udev.rules. > > The link is relative to the node, but the path is not optimized now > > if the node and the link are in the same nested directory. > > Only one link is supported, cause i need to sleep now :) > > > > 06-simple-symlink-creation.diff > > simple symlink creation > > reorganized udev-remove to have access to the symlink field > > subdir creation/removal are functions now > > udev-test.pl tests for link creation/removal Here is a new version with relative link target path optimization an better tests in udev-test.pl: LABEL, BUS="scsi", vendor="IBM-ESXS", NAME="1/2/a/b/node", SYMLINK="1/2/c/d/symlink" Dec 7 06:48:34 pim udev[13789]: create_node: symlink 'udev-root/1/2/c/d/symlink' to node '1/2/a/b/node' requested Dec 7 06:48:34 pim udev[13789]: create_path: created 'udev-root/1/2/c' Dec 7 06:48:34 pim udev[13789]: create_path: created 'udev-root/1/2/c/d' Dec 7 06:48:34 pim udev[13789]: create_node: symlink(../../a/b/node, udev-root/1/2/c/d/symlink) thanks, Kay --Kj7319i9nmIyA2yE Content-Type: text/plain; charset=us-ascii Content-Disposition: inline; filename="06-simple-symlink-creation.diff" diff -Nru a/namedev.c b/namedev.c --- a/namedev.c Sun Dec 7 06:58:47 2003 +++ b/namedev.c Sun Dec 7 06:58:47 2003 @@ -121,6 +121,7 @@ copy_string(dev, new_dev, place); copy_string(dev, new_dev, kernel_name); copy_string(dev, new_dev, exec_program); + copy_string(dev, new_dev, symlink); return 0; } @@ -366,6 +367,7 @@ if (strcmp_pattern(dev->id, udev->callout_value) != 0) continue; strfieldcpy(udev->name, dev->name); + strfieldcpy(udev->symlink, dev->symlink); dbg("callout returned matching value '%s', '%s' becomes '%s'", dev->id, class_dev->name, udev->name); return 0; @@ -416,6 +418,7 @@ continue; strfieldcpy(udev->name, dev->name); + strfieldcpy(udev->symlink, dev->symlink); dbg("found matching attribute '%s', '%s' becomes '%s' ", dev->sysfs_file, class_dev->name, udev->name); @@ -461,6 +464,7 @@ if (!found) continue; strfieldcpy(udev->name, dev->name); + strfieldcpy(udev->symlink, dev->symlink); dbg("found matching id '%s', '%s' becomes '%s'", dev->id, class_dev->name, udev->name); return 0; @@ -506,6 +510,7 @@ continue; strfieldcpy(udev->name, dev->name); + strfieldcpy(udev->symlink, dev->symlink); dbg("found matching place '%s', '%s' becomes '%s'", dev->place, class_dev->name, udev->name); return 0; @@ -528,6 +533,7 @@ continue; strfieldcpy(udev->name, dev->name); + strfieldcpy(udev->symlink, dev->symlink); dbg("found name, '%s' becomes '%s'", dev->kernel_name, udev->name); return 0; @@ -618,8 +624,9 @@ goto done; found: - /* substitute placeholder in NAME */ + /* substitute placeholder */ apply_format(udev, udev->name); + apply_format(udev, udev->symlink); done: perm = find_perm(udev->name); diff -Nru a/namedev.h b/namedev.h --- a/namedev.h Sun Dec 7 06:58:47 2003 +++ b/namedev.h Sun Dec 7 06:58:47 2003 @@ -63,6 +63,7 @@ char kernel_name[NAME_SIZE]; char exec_program[FILE_SIZE]; char name[NAME_SIZE]; + char symlink[NAME_SIZE]; }; struct perm_device { diff -Nru a/namedev_parse.c b/namedev_parse.c --- a/namedev_parse.c Sun Dec 7 06:58:47 2003 +++ b/namedev_parse.c Sun Dec 7 06:58:47 2003 @@ -213,10 +213,16 @@ break; strfieldcpy(dev.name, temp3); + /* SYMLINK="name" */ + temp2 = strsep(&temp, ","); + retval = get_value("SYMLINK", &temp, &temp3); + if (retval == 0) + strfieldcpy(dev.symlink, temp3); + dbg_parse("LABEL name='%s', bus='%s', " - "sysfs_file='%s', sysfs_value='%s'", + "sysfs_file='%s', sysfs_value='%s', symlink='%s'", dev.name, dev.bus, dev.sysfs_file, - dev.sysfs_value); + dev.sysfs_value, dev.symlink); } if (strcasecmp(temp2, TYPE_NUMBER) == 0) { @@ -243,8 +249,14 @@ break; strfieldcpy(dev.name, temp3); - dbg_parse("NUMBER name='%s', bus='%s', id='%s'", - dev.name, dev.bus, dev.id); + /* SYMLINK="name" */ + temp2 = strsep(&temp, ","); + retval = get_value("SYMLINK", &temp, &temp3); + if (retval == 0) + strfieldcpy(dev.symlink, temp3); + + dbg_parse("NUMBER name='%s', bus='%s', id='%s', symlink='%s'", + dev.name, dev.bus, dev.id, dev.symlink); } if (strcasecmp(temp2, TYPE_TOPOLOGY) == 0) { @@ -271,8 +283,15 @@ break; strfieldcpy(dev.name, temp3); - dbg_parse("TOPOLOGY name='%s', bus='%s', place='%s'", - dev.name, dev.bus, dev.place); + /* SYMLINK="name" */ + temp2 = strsep(&temp, ","); + retval = get_value("SYMLINK", &temp, &temp3); + if (retval == 0) + strfieldcpy(dev.symlink, temp3); + + dbg_parse("TOPOLOGY name='%s', bus='%s', " + "place='%s', symlink='%s'", + dev.name, dev.bus, dev.place, dev.symlink); } if (strcasecmp(temp2, TYPE_REPLACE) == 0) { @@ -291,9 +310,17 @@ if (retval) break; strfieldcpy(dev.name, temp3); - dbg_parse("REPLACE name='%s', kernel_name='%s'", - dev.name, dev.kernel_name); + + /* SYMLINK="name" */ + temp2 = strsep(&temp, ","); + retval = get_value("SYMLINK", &temp, &temp3); + if (retval == 0) + strfieldcpy(dev.symlink, temp3); + + dbg_parse("REPLACE name='%s', kernel_name='%s', symlink='%s'", + dev.name, dev.kernel_name, dev.symlink); } + if (strcasecmp(temp2, TYPE_CALLOUT) == 0) { /* number type */ dev.type = CALLOUT; @@ -324,8 +351,17 @@ if (retval) break; strfieldcpy(dev.name, temp3); - dbg_parse("CALLOUT name='%s', program='%s'", - dev.name, dev.exec_program); + + /* SYMLINK="name" */ + temp2 = strsep(&temp, ","); + retval = get_value("SYMLINK", &temp, &temp3); + if (retval == 0) + strfieldcpy(dev.symlink, temp3); + + dbg_parse("CALLOUT name='%s', bus='%s', program='%s', " + "id='%s', symlink='%s'", + dev.name, dev.bus, dev.exec_program, + dev.id, dev.symlink); } retval = add_config_dev(&dev); @@ -414,7 +450,7 @@ dev.mode); retval = add_perm_dev(&dev); if (retval) { - dbg("add_config_dev returned with error %d", retval); + dbg("add_perm_dev returned with error %d", retval); goto exit; } } diff -Nru a/test/udev-test.pl b/test/udev-test.pl --- a/test/udev-test.pl Sun Dec 7 06:58:47 2003 +++ b/test/udev-test.pl Sun Dec 7 06:58:47 2003 @@ -39,7 +39,7 @@ expected => "boot_disk" , conf => < "symlink creation (same directory)", + subsys => "tty", + devpath => "class/tty/ttyUSB0", + expected => "visor0" , + conf => < "symlink creation (relative link back)", + subsys => "block", + devpath => "block/sda/sda2", + expected => "1/2/a/b/symlink" , + conf => < "symlink creation (relative link forward)", + subsys => "block", + devpath => "block/sda/sda2", + expected => "1/2/symlink" , + conf => < "symlink creation (relative link back and forward)", + subsys => "block", + devpath => "block/sda/sda2", + expected => "1/2/c/d/symlink" , + conf => <{subsys}, $config->{devpath}, \$config->{conf}); - if (-e "$PWD/$udev_root$config->{expected}") { + if ((-e "$PWD/$udev_root$config->{expected}") || + (-l "$PWD/$udev_root$config->{expected}")) { print "remove: error\n\n"; system("tree $udev_root"); $error++; diff -Nru a/udev-add.c b/udev-add.c --- a/udev-add.c Sun Dec 7 06:58:47 2003 +++ b/udev-add.c Sun Dec 7 06:58:47 2003 @@ -72,6 +72,34 @@ return retval; } +static int create_path(char *file) +{ + char p[NAME_SIZE]; + char *pos; + int retval; + struct stat stats; + + strncpy(p, file, sizeof(p)); + pos = strchr(p+1, '/'); + while (1) { + pos = strchr(pos+1, '/'); + if (pos == NULL) + break; + *pos = 0x00; + if (stat(p, &stats)) { + retval = mkdir(p, 0755); + if (retval) { + dbg("mkdir(%s) failed with error '%s'", + p, strerror(errno)); + return retval; + } + dbg("created '%s'", p); + } + *pos = '/'; + } + return 0; +} + /* * we possibly want to add some symlinks here * only numeric owner/group id's are supported @@ -79,10 +107,14 @@ static int create_node(struct udevice *dev) { char filename[255]; + char linktarget[255]; int retval = 0; uid_t uid = 0; gid_t gid = 0; dev_t res; + int i; + int tail; + strncpy(filename, udev_root, sizeof(filename)); strncat(filename, dev->name, sizeof(filename)); @@ -109,31 +141,9 @@ return -EINVAL; } - /* create subdirectories if requested */ - if (strchr(dev->name, '/')) { - char path[255]; - char *pos; - struct stat stats; - - strncpy(path, filename, sizeof(path)); - pos = strchr(path+1, '/'); - while (1) { - pos = strchr(pos+1, '/'); - if (pos == NULL) - break; - *pos = 0x00; - if (stat(path, &stats)) { - retval = mkdir(path, 0755); - if (retval) { - dbg("mkdir(%s) failed with error '%s'", - path, strerror(errno)); - return retval; - } - dbg("created '%s'", path); - } - *pos = '/'; - } - } + /* create parent directories if needed */ + if (strrchr(dev->name, '/')) + create_path(filename); dbg("mknod(%s, %#o, %u, %u)", filename, dev->mode, dev->major, dev->minor); retval = mknod(filename, dev->mode, res); @@ -179,8 +189,43 @@ dbg("chown(%s, %u, %u)", filename, uid, gid); retval = chown(filename, uid, gid); if (retval) - dbg("chown(%s, %u, %u) failed with error '%s'", filename, - uid, gid, strerror(errno)); + dbg("chown(%s, %u, %u) failed with error '%s'", + filename, uid, gid, strerror(errno)); + } + + + /* create symlink if requested */ + if (*dev->symlink) { + strncpy(filename, udev_root, sizeof(filename)); + strncat(filename, dev->symlink, sizeof(filename)); + dbg("symlink '%s' to node '%s' requested", filename, dev->name); + if (strrchr(dev->symlink, '/')) + create_path(filename); + + /* optimize relative link */ + linktarget[0] = '\0'; + i = 0; + tail = 0; + while ((dev->name[i] == dev->symlink[i]) && dev->name[i]) { + if (dev->name[i] == '/') + tail = i+1; + i++; + } + while (dev->symlink[i]) { + if (dev->symlink[i] == '/') + strcat(linktarget, "../"); + i++; + } + + if (*linktarget == '\0') + strcpy(linktarget, "./"); + strcat(linktarget, &dev->name[tail]); + + dbg("symlink(%s, %s)", linktarget, filename); + retval = symlink(linktarget, filename); + if (retval) + dbg("symlink(%s, %s) failed with error '%s'", + linktarget, filename, strerror(errno)); } return retval; diff -Nru a/udev-remove.c b/udev-remove.c --- a/udev-remove.c Sun Dec 7 06:58:47 2003 +++ b/udev-remove.c Sun Dec 7 06:58:47 2003 @@ -34,47 +34,43 @@ #include "udevdb.h" #include "libsysfs/libsysfs.h" - -/* - * Look up the sysfs path in the database to see if we have named this device - * something different from the kernel name. If we have, us it. If not, use - * the default kernel name for lack of anything else to know to do. - */ -static char *get_name(char *path, int major, int minor) +static int delete_path(char *path) { - static char name[100]; - struct udevice *dev; - char *temp; + char *pos; + int retval; - dev = udevdb_get_dev(path); - if (dev != NULL) { - strcpy(name, dev->name); - goto exit; + pos = strrchr(path, '/'); + while (1) { + *pos = '\0'; + pos = strrchr(path, '/'); + + /* don't remove the last one */ + if ((pos == path) || (pos == NULL)) + break; + + /* remove if empty */ + retval = rmdir(path); + if (retval) { + if (errno == ENOTEMPTY) + return 0; + dbg("rmdir(%s) failed with error '%s'", + path, strerror(errno)); + break; + } + dbg("removed '%s'", path); } - - dbg("'%s' not found in database, falling back on default name", path); - temp = strrchr(path, '/'); - if (temp == NULL) - return NULL; - strncpy(name, &temp[1], sizeof(name)); - -exit: - dbg("name is '%s'", name); - return &name[0]; + return 0; } -/* - * We also want to clean up any symlinks that were created in create_node() - */ -static int delete_node(char *name) +static int delete_node(struct udevice *dev) { char filename[255]; int retval; strncpy(filename, udev_root, sizeof(filename)); - strncat(filename, name, sizeof(filename)); + strncat(filename, dev->name, sizeof(filename)); - dbg("unlinking '%s'", filename); + dbg("unlinking node '%s'", filename); retval = unlink(filename); if (retval) { dbg("unlink(%s) failed with error '%s'", @@ -83,49 +79,48 @@ } /* remove subdirectories */ - if (strchr(name, '/')) { - char *pos; + if (strchr(dev->name, '/')) + delete_path(filename); - pos = strrchr(filename, '/'); - while (1) { - *pos = 0x00; - pos = strrchr(filename, '/'); - - /* don't remove the last one */ - if ((pos == filename) || (pos == NULL)) - break; - - /* remove if empty */ - retval = rmdir(filename); - if (retval) { - if (errno == ENOTEMPTY) - return 0; - dbg("rmdir(%s) failed with error '%s'", - filename, strerror(errno)); - break; - } - dbg("removed '%s'", filename); + if (*dev->symlink) { + strncpy(filename, udev_root, sizeof(filename)); + strncat(filename, dev->symlink, sizeof(filename)); + dbg("unlinking symlink '%s'", filename); + retval = unlink(filename); + if (retval) { + dbg("unlink(%s) failed with error '%s'", + filename, strerror(errno)); + return retval; + } + if (strchr(dev->symlink, '/')) { + delete_path(filename); } } + return retval; } -int udev_remove_device(char *device, char *subsystem) +/* + * Look up the sysfs path in the database to see if we have named this device + * something different from the kernel name. If we have, us it. If not, use + * the default kernel name for lack of anything else to know to do. + */ +int udev_remove_device(char *path, char *subsystem) { - char *name; - int retval = 0; + char name[100]; + struct udevice *dev; + char *temp; - name = get_name(device, 0, 0); - if (name == NULL) { - dbg ("get_name failed"); - retval = -ENODEV; - goto exit; + dev = udevdb_get_dev(path); + if (dev == NULL) { + dbg("'%s' not found in database, falling back on default name", path); + temp = strrchr(path, '/'); + if (temp == NULL) + return -ENODEV; + strncpy(name, &temp[1], sizeof(name)); } - udevdb_delete_dev(device); - - return delete_node(name); - -exit: - return retval; + dbg("name is '%s'", dev->name); + udevdb_delete_dev(path); + return delete_node(dev); } diff -Nru a/udev.h b/udev.h --- a/udev.h Sun Dec 7 06:58:47 2003 +++ b/udev.h Sun Dec 7 06:58:47 2003 @@ -64,6 +64,7 @@ int major; int minor; mode_t mode; + char symlink[NAME_SIZE]; /* fields that help us in building strings */ unsigned char bus_id[SYSFS_NAME_LEN]; --Kj7319i9nmIyA2yE-- ------------------------------------------------------- This SF.net email is sponsored by: IBM Linux Tutorials. Become an expert in LINUX or just sharpen your skills. Sign up for IBM's Free Linux Tutorials. Learn everything from the bash shell to sys admin. Click now! http://ads.osdn.com/?ad_id=1278&alloc_id=3371&op=click _______________________________________________ Linux-hotplug-devel mailing list http://linux-hotplug.sourceforge.net Linux-hotplug-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/linux-hotplug-devel