diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/Makefile | 7 | ||||
-rw-r--r-- | src/rename_device.1 | 43 | ||||
-rw-r--r-- | src/rename_device.c | 325 |
3 files changed, 374 insertions, 1 deletions
diff --git a/src/Makefile b/src/Makefile index c691870b..dacc44bd 100644 --- a/src/Makefile +++ b/src/Makefile @@ -1,7 +1,7 @@ CFLAGS+=$(RPM_OPT_FLAGS) -Wall -D_GNU_SOURCE PROGS=usernetctl doexec netreport testd usleep ipcalc initlog \ - getkey ppp-watch consoletype genhostid + getkey ppp-watch consoletype genhostid rename_device PPPWATCH_OBJS=ppp-watch.o shvar.o INITLOG_OBJS=initlog.o process.o USLEEP_OBJS=usleep.o @@ -25,6 +25,7 @@ install: install -m 755 getkey $(ROOT)/sbin/getkey install -m 755 ppp-watch $(ROOT)/sbin/ppp-watch install -m 755 consoletype $(ROOT)/sbin/consoletype + install -m 755 rename_device $(ROOT)/sbin/rename_device install -m 644 initlog.1 $(ROOT)$(mandir)/man1 install -m 644 genhostid.1 $(ROOT)$(mandir)/man1 install -m 644 doexec.1 $(ROOT)$(mandir)/man1 @@ -35,6 +36,7 @@ install: install -m 644 ppp-watch.8 $(ROOT)$(mandir)/man8 install -m 644 ipcalc.1 $(ROOT)$(mandir)/man1 install -m 644 consoletype.1 $(ROOT)$(mandir)/man1 + install -m 644 rename_device.1 $(ROOT)$(mandir)/man1 install -m 644 initlog.conf $(ROOT)/etc # this daemon and initscript are useful for testing the up/down/status stuff @@ -70,5 +72,8 @@ shvar.o: shvar.c ppp-watch.o: ppp-watch.c $(CC) $(CFLAGS) `pkg-config glib-2.0 --cflags` -c ppp-watch.c -o ppp-watch.o +rename_device: rename_device.c + $(CC) $(CFLAGS) `pkg-config glib-2.0 --cflags` -o $@ $< -Wl,-Bstatic `pkg-config glib-2.0 --libs` -Wl,-Bdynamic + kmodule: kmodule.o $(CC) $(LDFLAGS) -o $@ $< -Wl,-Bstatic -lpopt -Wl,-Bdynamic -lkudzu -lpci diff --git a/src/rename_device.1 b/src/rename_device.1 new file mode 100644 index 00000000..faaaf5e0 --- /dev/null +++ b/src/rename_device.1 @@ -0,0 +1,43 @@ +.\" A man page for rename_device(1). -*- nroff -*- +.\" +.\" 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. +.\" +.\" Author: Bill Nottingham <notting@redhat.com> +.TH rename_device 1 "Mar 2006" + +.SH NAME +rename_device \- rename ethernet devices + +.SH SYNOPSIS +\fBrename_device\fR + +.SH DESCRIPTION +.B rename_device +renames ethernet devices, based on configuration in +\fI/etc/sysconfig/network-scripts\fR. It is meant to be run as a udev +helper; do not run it directly. + +.SH FILES + +\fI/etc/sysconfig/network-scripts\fR +.br +\fI/etc/udev/rules.d/60-net.rules\fR +.br + +.SH BUGS +Probably, but let's hope not. If you find any, please file them in the +bug database at http://bugzilla.redhat.com/ against the "initscripts" +component. diff --git a/src/rename_device.c b/src/rename_device.c new file mode 100644 index 00000000..9db4d41f --- /dev/null +++ b/src/rename_device.c @@ -0,0 +1,325 @@ + +/* + * 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 <dirent.h> +#include <errno.h> +#include <fcntl.h> +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include <sys/ioctl.h> +#include <sys/types.h> + +#include <linux/sockios.h> + +#include <net/if.h> + +#include <glib.h> + +#define LOCKFILE "/dev/.rename_device.lock" + +void sighandler(int dummy) { + unlink(LOCKFILE); + _exit(1); +} + +struct netdev { + char *hwaddr; + char *dev; + struct netdev *next; +}; + +struct netdev *configs = NULL; +struct netdev *devs = NULL; + +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 (asprintf(&path,"/sys/class/net/%s/address",entry->d_name) == -1) + continue; + g_file_get_contents(path, &contents, NULL, NULL); + 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-5,".bak",4)) + return 0; + return 1; +} + +struct netdev *get_configs() { + int ncfgs = 0; + struct netdev *ret, *tmpdev; + struct dirent **cfgs; + int x; + + ret = NULL; + + if ((ncfgs = scandir("/etc/sysconfig/network-scripts",&cfgs, + isCfg, alphasort)) == -1) { + return ret; + } + for (x = 0; x < ncfgs; x++ ) { + char *path; + char *devname, *hwaddr; + gchar *contents, **lines; + int i; + + devname = hwaddr = contents = NULL; + lines = NULL; + if (asprintf(&path,"/etc/sysconfig/network-scripts/%s", + cfgs[x]->d_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; + } + if (g_str_has_prefix(lines[i],"HWADDR=")) { + hwaddr = lines[i] + 7; + } + } + 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) { + struct netdev *config; + + if (!hwaddr) return NULL; + + for (config = configs; config; config = config->next) + if (!strcasecmp(config->hwaddr, hwaddr)) + return config->dev; + return NULL; +} + +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; +} + +int do_rename(char *src, char *target) { + int sock; + struct ifreq ifr; + int ret; + + sock = socket(PF_INET, SOCK_DGRAM, 0); + if (sock == -1) + return 1; + + memset(&ifr,'\0', sizeof(struct ifreq)); + g_strlcpy(ifr.ifr_name, src, IFNAMSIZ); + g_strlcpy(ifr.ifr_newname, target, IFNAMSIZ); + ret = ioctl(sock, SIOCSIFNAME, &ifr); + return ret; +} + + +void rename_device(char *src, char *target, struct netdev *current) { + int rc; + + if (!current) { + current = calloc(1, sizeof(struct netdev)); + current->dev = src; + } + + rc = do_rename(src, target); + if (rc && errno != ENODEV) { + char *hw; + char *nconfig; + char *curdev; + char *dev = NULL; + struct netdev *i, *tmpdev; + + hw = get_hwaddr(target); + if (!hw) + return; + + nconfig = get_config_by_hwaddr(hw); + curdev = get_device_by_hwaddr(hw); + + if (nconfig) { + dev = nconfig; + for (i = current; i; i = i->next) { + if (!strcmp(i->dev,dev)) + dev = NULL; + } + } + if (!dev) + asprintf(&dev,"dev%d",rand()); + if (!dev) + return; + tmpdev = calloc(1,sizeof(struct netdev)); + tmpdev->dev = curdev; + if (current) + tmpdev->next = current; + current = tmpdev; + rename_device(curdev, dev, current); + do_rename(src,target); + } +} + +void take_lock() { + int count = 0; + int lockfd; + + while (1) { + lockfd = open(LOCKFILE, O_RDWR|O_CREAT|O_EXCL); + 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; + + 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); + if (!target || !strcmp(src,target)) + goto out_unlock; + + rename_device(src, target, NULL); + printf("INTERFACE=%s\n",target); +out_unlock: + unlink(LOCKFILE); + exit(0); +} |