X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?p=elogind.git;a=blobdiff_plain;f=udev_device.c;h=87f90c76769b714320381368ab9cf02649c2030e;hp=b356f163a5b6f43a259445486fb67d6a6dd5700a;hb=1aa0c52b4458be4cf6e55b2faf5c602761f5d3a3;hpb=ff9a488d8c559a2ee40e522cdc68b750670711e4 diff --git a/udev_device.c b/udev_device.c index b356f163a..87f90c767 100644 --- a/udev_device.c +++ b/udev_device.c @@ -26,7 +26,8 @@ #include #include #include -#include +#include +#include #include #include @@ -80,7 +81,7 @@ dev_t udev_device_get_devt(struct udevice *udev) return makedev(0, 0); } -static int rename_net_if(struct udevice *udev) +static int rename_netif(struct udevice *udev) { int sk; struct ifreq ifr; @@ -99,12 +100,45 @@ static int rename_net_if(struct udevice *udev) memset(&ifr, 0x00, sizeof(struct ifreq)); strlcpy(ifr.ifr_name, udev->dev->kernel_name, IFNAMSIZ); strlcpy(ifr.ifr_newname, udev->name, IFNAMSIZ); - retval = ioctl(sk, SIOCSIFNAME, &ifr); - if (retval != 0) - err("error changing net interface name: %s", strerror(errno)); - close(sk); + if (retval != 0) { + int loop; + + /* see if the destination interface name already exists */ + if (errno != EEXIST) { + err("error changing netif name %s to %s: %s", ifr.ifr_name, ifr.ifr_newname, strerror(errno)); + goto exit; + } + + /* free our own name, another process may wait for us */ + strlcpy(ifr.ifr_newname, udev->dev->kernel_name, IFNAMSIZ); + strlcat(ifr.ifr_newname, "_rename", IFNAMSIZ); + retval = ioctl(sk, SIOCSIFNAME, &ifr); + if (retval != 0) { + err("error changing netif name %s to %s: %s", ifr.ifr_name, ifr.ifr_newname, strerror(errno)); + goto exit; + } + + /* wait 30 seconds for our target to become available */ + strlcpy(ifr.ifr_name, ifr.ifr_newname, IFNAMSIZ); + strlcpy(ifr.ifr_newname, udev->name, IFNAMSIZ); + loop = 30 * 20; + while (loop--) { + retval = ioctl(sk, SIOCSIFNAME, &ifr); + if (retval != 0) { + if (errno != EEXIST) { + err("error changing net interface name %s to %s: %s", + ifr.ifr_name, ifr.ifr_newname, strerror(errno)); + break; + } + dbg("wait for netif '%s' to become free, loop=%i", udev->name, (30 * 20) - loop); + usleep(1000 * 1000 / 20); + } + } + } +exit: + close(sk); return retval; } @@ -113,7 +147,8 @@ int udev_device_event(struct udev_rules *rules, struct udevice *udev) int retval = 0; /* add device node */ - if (major(udev->devt) != 0 && strcmp(udev->action, "add") == 0) { + if (major(udev->devt) != 0 && + (strcmp(udev->action, "add") == 0 || strcmp(udev->action, "change") == 0)) { struct udevice *udev_old; dbg("device node add '%s'", udev->dev->devpath); @@ -131,17 +166,38 @@ int udev_device_event(struct udev_rules *rules, struct udevice *udev) /* read current database entry, we may want to cleanup symlinks */ udev_old = udev_device_init(); if (udev_old != NULL) { - if (udev_db_get_device(udev_old, udev->dev->devpath) == 0) { - info("device '%s' already known, remove possible symlinks", udev->dev->devpath); - udev_node_remove_symlinks(udev_old); - } - udev_device_cleanup(udev_old); + if (udev_db_get_device(udev_old, udev->dev->devpath) != 0) { + udev_device_cleanup(udev_old); + udev_old = NULL; + } else + info("device '%s' already in database, validate currently present symlinks", + udev->dev->devpath); } - /* create node and symlinks, store record in database */ + /* create node and symlinks */ retval = udev_node_add(udev, udev_old); - if (retval == 0) + if (retval == 0) { + /* store record in database */ udev_db_add_device(udev); + + /* remove possibly left-over symlinks */ + if (udev_old != NULL) { + struct name_entry *link_loop; + struct name_entry *link_old_loop; + struct name_entry *link_old_tmp_loop; + + /* remove still valid symlinks from old list */ + list_for_each_entry_safe(link_old_loop, link_old_tmp_loop, &udev_old->symlink_list, node) + list_for_each_entry(link_loop, &udev->symlink_list, node) + if (strcmp(link_old_loop->name, link_loop->name) == 0) { + dbg("symlink '%s' still valid, keep it", link_old_loop->name); + list_del(&link_old_loop->node); + free(link_old_loop); + } + udev_node_remove_symlinks(udev_old); + udev_device_cleanup(udev_old); + } + } goto exit; } @@ -158,7 +214,7 @@ int udev_device_event(struct udev_rules *rules, struct udevice *udev) if (strcmp(udev->name, udev->dev->kernel_name) != 0) { char *pos; - retval = rename_net_if(udev); + retval = rename_netif(udev); if (retval != 0) goto exit; info("renamed netif to '%s'", udev->name);