1/* 2 * Copyright (C) 2004-2006 Kay Sievers <kay.sievers@vrfy.org> 3 * 4 * This program is free software; you can redistribute it and/or modify it 5 * under the terms of the GNU General Public License as published by the 6 * Free Software Foundation version 2 of the License. 7 * 8 * This program is distributed in the hope that it will be useful, but 9 * WITHOUT ANY WARRANTY; without even the implied warranty of 10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 11 * General Public License for more details. 12 * 13 * You should have received a copy of the GNU General Public License along 14 * with this program; if not, write to the Free Software Foundation, Inc., 15 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 16 * 17 */ 18 19 20#include <stdlib.h> 21#include <stdio.h> 22#include <stddef.h> 23#include <unistd.h> 24#include <fcntl.h> 25#include <errno.h> 26#include <ctype.h> 27#include <sys/ioctl.h> 28#include <sys/socket.h> 29#include <net/if.h> 30#include <linux/sockios.h> 31 32#include "udev.h" 33#include "udev_rules.h" 34 35 36struct udevice *udev_device_init(struct udevice *udev) 37{ 38 if (udev == NULL) 39 udev = malloc(sizeof(struct udevice)); 40 if (udev == NULL) 41 return NULL; 42 memset(udev, 0x00, sizeof(struct udevice)); 43 44 INIT_LIST_HEAD(&udev->symlink_list); 45 INIT_LIST_HEAD(&udev->run_list); 46 INIT_LIST_HEAD(&udev->env_list); 47 48 /* set sysfs device to local storage, can be overridden if needed */ 49 udev->dev = &udev->dev_local; 50 51 /* default node permissions */ 52 udev->mode = 0660; 53 strcpy(udev->owner, "root"); 54 strcpy(udev->group, "root"); 55 56 return udev; 57} 58 59void udev_device_cleanup(struct udevice *udev) 60{ 61 name_list_cleanup(&udev->symlink_list); 62 name_list_cleanup(&udev->run_list); 63 name_list_cleanup(&udev->env_list); 64 free(udev); 65} 66 67dev_t udev_device_get_devt(struct udevice *udev) 68{ 69 const char *attr; 70 unsigned int maj, min; 71 72 /* read it from sysfs */ 73 attr = sysfs_attr_get_value(udev->dev->devpath, "dev"); 74 if (attr != NULL) { 75 if (sscanf(attr, "%u:%u", &maj, &min) == 2) 76 return makedev(maj, min); 77 } 78 return makedev(0, 0); 79} 80 81static int rename_netif(struct udevice *udev) 82{ 83 int sk; 84 struct ifreq ifr; 85 int retval; 86 87 info("changing net interface name from '%s' to '%s'", udev->dev->kernel, udev->name); 88 if (udev->test_run) 89 return 0; 90 91 sk = socket(PF_INET, SOCK_DGRAM, 0); 92 if (sk < 0) { 93 err("error opening socket: %s", strerror(errno)); 94 return -1; 95 } 96 97 memset(&ifr, 0x00, sizeof(struct ifreq)); 98 strlcpy(ifr.ifr_name, udev->dev->kernel, IFNAMSIZ); 99 strlcpy(ifr.ifr_newname, udev->name, IFNAMSIZ); 100 retval = ioctl(sk, SIOCSIFNAME, &ifr); 101 if (retval != 0) { 102 int loop; 103 104 /* see if the destination interface name already exists */ 105 if (errno != EEXIST) { 106 err("error changing netif name %s to %s: %s", ifr.ifr_name, ifr.ifr_newname, strerror(errno)); 107 goto exit; 108 } 109 110 /* free our own name, another process may wait for us */ 111 strlcpy(ifr.ifr_newname, udev->dev->kernel, IFNAMSIZ); 112 strlcat(ifr.ifr_newname, "_rename", IFNAMSIZ); 113 retval = ioctl(sk, SIOCSIFNAME, &ifr); 114 if (retval != 0) { 115 err("error changing netif name %s to %s: %s", ifr.ifr_name, ifr.ifr_newname, strerror(errno)); 116 goto exit; 117 } 118 119 /* wait 30 seconds for our target to become available */ 120 strlcpy(ifr.ifr_name, ifr.ifr_newname, IFNAMSIZ); 121 strlcpy(ifr.ifr_newname, udev->name, IFNAMSIZ); 122 loop = 30 * 20; 123 while (loop--) { 124 retval = ioctl(sk, SIOCSIFNAME, &ifr); 125 if (retval == 0) 126 break; 127 128 if (errno != EEXIST) { 129 err("error changing net interface name %s to %s: %s", 130 ifr.ifr_name, ifr.ifr_newname, strerror(errno)); 131 break; 132 } 133 dbg("wait for netif '%s' to become free, loop=%i", udev->name, (30 * 20) - loop); 134 usleep(1000 * 1000 / 20); 135 } 136 } 137 138exit: 139 close(sk); 140 return retval; 141} 142 143int udev_device_event(struct udev_rules *rules, struct udevice *udev) 144{ 145 int retval = 0; 146 147 /* add device node */ 148 if (major(udev->devt) != 0 && 149 (strcmp(udev->action, "add") == 0 || strcmp(udev->action, "change") == 0)) { 150 struct udevice *udev_old; 151 152 dbg("device node add '%s'", udev->dev->devpath); 153 154 udev_rules_get_name(rules, udev); 155 if (udev->ignore_device) { 156 info("device event will be ignored"); 157 goto exit; 158 } 159 if (udev->name[0] == '\0') { 160 info("device node creation supressed"); 161 goto exit; 162 } 163 164 /* read current database entry; cleanup, if it is known device */ 165 udev_old = udev_device_init(NULL); 166 if (udev_old != NULL) { 167 udev_old->test_run = udev->test_run; 168 if (udev_db_get_device(udev_old, udev->dev->devpath) == 0) { 169 info("device '%s' already in database, cleanup", udev->dev->devpath); 170 udev_db_delete_device(udev_old); 171 } else { 172 udev_device_cleanup(udev_old); 173 udev_old = NULL; 174 } 175 } 176 177 /* create node */ 178 retval = udev_node_add(udev); 179 if (retval != 0) 180 goto exit; 181 182 /* store in database */ 183 udev_db_add_device(udev); 184 185 /* create, replace, delete symlinks according to priority */ 186 udev_node_update_symlinks(udev, udev_old); 187 188 if (udev_old != NULL) 189 udev_device_cleanup(udev_old); 190 goto exit; 191 } 192 193 /* add netif */ 194 if (strcmp(udev->dev->subsystem, "net") == 0 && strcmp(udev->action, "add") == 0) { 195 dbg("netif add '%s'", udev->dev->devpath); 196 udev_rules_get_name(rules, udev); 197 if (udev->ignore_device) { 198 info("device event will be ignored"); 199 goto exit; 200 } 201 if (udev->name[0] == '\0') { 202 info("device renaming supressed"); 203 goto exit; 204 } 205 206 /* look if we want to change the name of the netif */ 207 if (strcmp(udev->name, udev->dev->kernel) != 0) { 208 char devpath[PATH_MAX]; 209 char *pos; 210 211 retval = rename_netif(udev); 212 if (retval != 0) 213 goto exit; 214 info("renamed netif to '%s'", udev->name); 215 216 /* export old name */ 217 setenv("INTERFACE_OLD", udev->dev->kernel, 1); 218 219 /* now change the devpath, because the kernel device name has changed */ 220 strlcpy(devpath, udev->dev->devpath, sizeof(devpath)); 221 pos = strrchr(devpath, '/'); 222 if (pos != NULL) { 223 pos[1] = '\0'; 224 strlcat(devpath, udev->name, sizeof(devpath)); 225 sysfs_device_set_values(udev->dev, devpath, NULL, NULL); 226 setenv("DEVPATH", udev->dev->devpath, 1); 227 setenv("INTERFACE", udev->name, 1); 228 info("changed devpath to '%s'", udev->dev->devpath); 229 } 230 } 231 goto exit; 232 } 233 234 /* remove device node */ 235 if (major(udev->devt) != 0 && strcmp(udev->action, "remove") == 0) { 236 struct name_entry *name_loop; 237 238 /* import database entry, and delete it */ 239 if (udev_db_get_device(udev, udev->dev->devpath) == 0) { 240 udev_db_delete_device(udev); 241 if (udev->ignore_remove) { 242 info("ignore_remove for '%s'", udev->name); 243 goto exit; 244 } 245 /* restore stored persistent data */ 246 list_for_each_entry(name_loop, &udev->env_list, node) 247 putenv(name_loop->name); 248 } else { 249 dbg("'%s' not found in database, using kernel name '%s'", 250 udev->dev->devpath, udev->dev->kernel); 251 strlcpy(udev->name, udev->dev->kernel, sizeof(udev->name)); 252 } 253 254 udev_rules_get_run(rules, udev); 255 if (udev->ignore_device) { 256 info("device event will be ignored"); 257 goto exit; 258 } 259 260 /* remove the node */ 261 retval = udev_node_remove(udev); 262 263 /* delete or restore symlinks according to priority */ 264 udev_node_update_symlinks(udev, NULL); 265 goto exit; 266 } 267 268 /* default devices */ 269 udev_rules_get_run(rules, udev); 270 if (udev->ignore_device) 271 info("device event will be ignored"); 272 273exit: 274 return retval; 275} 276