/* * rename_device.c: udev helper to rename ethernet devices. * * Copyright (C) 2006 Red Hat, Inc. All rights reserved. * * This copyrighted material is made available to anyone wishing to use, * modify, copy, or redistribute it subject to the terms and conditions of the * GNU General Public License v.2. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define LOCKFILE "/dev/.rename_device.lock" void sighandler(int dummy) { unlink(LOCKFILE); _exit(1); } struct netdev { char *hwaddr; char *dev; struct netdev *next; }; struct tmp { char *src; char *target; struct tmp *next; }; struct netdev *configs = NULL; struct netdev *devs = NULL; struct tmp *tmplist = NULL; #if defined(__s390__) || defined(__s390x__) static int is_cdev(const struct dirent *dent) { char *end = NULL; if (strncmp(dent->d_name,"cdev",4)) return 0; strtoul(dent->d_name+4,&end, 10); if (*end) return 0; return 1; } static inline char *getdev(char *path, char *ent) { char *a, *b, *ret; asprintf(&a,"%s/%s",path,ent); b = canonicalize_file_name(a); ret = strdup(basename(b)); free(b); free(a); return ret; } char *read_subchannels(char *device) { char *tmp, *path, *ret; int n, x; struct dirent **cdevs; if (asprintf(&path,"/sys/class/net/%s/device",device) == -1) return NULL; if ((n = scandir(path, &cdevs, is_cdev, alphasort)) <= 0) return NULL; ret = getdev(path,cdevs[0]->d_name); for (x = 1 ; x < n ; x++ ) { if (asprintf(&tmp, "%s,%s", ret, getdev(path, cdevs[x]->d_name)) == -1) return NULL; free(ret); ret = tmp; } free(path); return ret; } #endif struct netdev *get_devs() { DIR *dir; struct dirent *entry; struct netdev *ret = NULL, *tmpdev; dir = opendir("/sys/class/net"); if (!dir) return NULL; while ((entry = readdir(dir))) { char *path; gchar *contents; contents = NULL; if (!strcmp(entry->d_name,".") || !strcmp(entry->d_name,"..")) { continue; } if (asprintf(&path,"/sys/class/net/%s/type",entry->d_name) == -1) continue; g_file_get_contents(path, &contents, NULL, NULL); if (!contents) continue; if (atoi(contents) >= 256) { g_free(contents); continue; } g_free(contents); contents = NULL; #if defined(__s390__) || defined(__s390x__) contents = read_subchannels(entry->d_name); #else if (asprintf(&path,"/sys/class/net/%s/address",entry->d_name) == -1) continue; g_file_get_contents(path, &contents, NULL, NULL); #endif /* mainframe */ if (!contents) continue; contents = g_strstrip(contents); tmpdev = calloc(1, sizeof(struct netdev)); tmpdev->dev = g_strstrip(g_strdup(entry->d_name)); tmpdev->hwaddr = g_strstrip(g_strdup(contents)); if (ret) tmpdev->next = ret; ret = tmpdev; g_free(contents); } return ret; } int isCfg(const struct dirent *dent) { int len = strlen(dent->d_name); if (strncmp(dent->d_name,"ifcfg-",6)) return 0; if (strstr(dent->d_name,"rpmnew") || strstr(dent->d_name,"rpmsave") || strstr(dent->d_name,"rpmorig")) return 0; if (dent->d_name[len-1] == '~') return 0; if (!strncmp(dent->d_name+len-4,".bak",4)) return 0; return 1; } static inline char *dequote(char *start, char *end) { if (end==NULL) { end=start; while(*end) end++; } if (end > start) end--; if ((*start == '\'' || *start == '\"') && ( *start == *end ) ) { *end='\0'; if (startd_name) == -1) continue; g_file_get_contents(path, &contents, NULL, NULL); if (!contents) continue; lines = g_strsplit(contents,"\n", 0); for (i = 0; lines[i]; i++) { if (g_str_has_prefix(lines[i],"DEVICE=")) { devname = lines[i] + 7; /* ignore alias devices */ if (strchr(devname,':')) devname = NULL; } #if defined(__s390__) || defined(__s390x__) if (g_str_has_prefix(lines[i],"SUBCHANNELS=")) { hwaddr = dequote(lines[i] + 12, NULL); } #else if (g_str_has_prefix(lines[i],"HWADDR=")) { hwaddr = dequote(lines[i] + 7, NULL); } #endif } if (!devname || !hwaddr) { g_free(contents); g_strfreev(lines); continue; } tmpdev = calloc(1, sizeof(struct netdev)); tmpdev->dev = g_strstrip(g_strdup(devname)); tmpdev->hwaddr = g_strstrip(g_strdup(hwaddr)); if (ret) tmpdev->next = ret; ret = tmpdev; g_free(contents); g_strfreev(lines); } free(cfgs); return ret; } char *get_hwaddr(char *device) { struct netdev *dev; for (dev = devs; dev; dev = dev->next) if (!strcmp(dev->dev, device)) return dev->hwaddr; return NULL; } char *get_config_by_hwaddr(char *hwaddr, char *current) { struct netdev *config; char *first = NULL; if (!hwaddr) return NULL; for (config = configs; config; config = config->next) { if (strcasecmp(config->hwaddr, hwaddr) != 0) continue; if (!current || !strcasecmp(config->dev, current)) return config->dev; if (!first) first = config->dev; } return first; } char *get_device_by_hwaddr(char *hwaddr) { struct netdev *dev; if (!hwaddr) return NULL; for (dev = devs; dev; dev = dev->next) if (!strcasecmp(dev->hwaddr, hwaddr)) return dev->dev; return NULL; } void take_lock() { int count = 0; int lockfd; while (1) { lockfd = open(LOCKFILE, O_RDWR|O_CREAT|O_EXCL, 0644); if (lockfd != -1) { write(lockfd,"%d\n",getpid()); close(lockfd); break; } count++; /* If we've slept for 20 seconds, break the lock. */ if (count >= 200) { int fd; char buf[32]; int pid; fd = open(LOCKFILE, O_RDONLY); if (fd == -1) break; read(fd,buf,32); close(fd); pid = atoi(buf); if (pid && pid != 1) { kill(pid,SIGKILL); } } usleep(100000); continue; } return; } int main(int argc, char **argv) { char *src, *target, *hw; struct timeval tv; gettimeofday(&tv, NULL); srand(tv.tv_usec); take_lock(); signal(SIGSEGV,sighandler); signal(SIGKILL,sighandler); signal(SIGTERM,sighandler); signal(SIGSEGV,sighandler); signal(SIGALRM,sighandler); alarm(10); configs = get_configs(); devs = get_devs(); src = getenv("INTERFACE"); if (!src) goto out_unlock; hw = get_hwaddr(src); if (!hw) goto out_unlock; target = get_config_by_hwaddr(hw, src); if (!target) goto out_unlock; printf("%s", target); out_unlock: unlink(LOCKFILE); exit(0); }