aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBill Nottingham <notting@redhat.com>2006-03-17 16:57:08 +0000
committerBill Nottingham <notting@redhat.com>2006-03-17 16:57:08 +0000
commit4fc1aa45b7f26bf9eda11e80d6614fb96c9e7355 (patch)
tree3bd7b4c2f69422f3637f80d974fad08f2ce126f7
parente610427d049989b94a29443d0c26ae657d420475 (diff)
downloadinitscripts-4fc1aa45b7f26bf9eda11e80d6614fb96c9e7355.tar
initscripts-4fc1aa45b7f26bf9eda11e80d6614fb96c9e7355.tar.gz
initscripts-4fc1aa45b7f26bf9eda11e80d6614fb96c9e7355.tar.bz2
initscripts-4fc1aa45b7f26bf9eda11e80d6614fb96c9e7355.tar.xz
initscripts-4fc1aa45b7f26bf9eda11e80d6614fb96c9e7355.zip
add a udev helper to do device renames on module load. Essentially,
it's network-functions rename_device ported to C, with locking added.
-rw-r--r--initscripts.spec6
-rw-r--r--src/Makefile7
-rw-r--r--src/rename_device.143
-rw-r--r--src/rename_device.c325
-rw-r--r--udev/rules.d/60-net.rules1
5 files changed, 380 insertions, 2 deletions
diff --git a/initscripts.spec b/initscripts.spec
index 4a15f207..bab84c2e 100644
--- a/initscripts.spec
+++ b/initscripts.spec
@@ -1,6 +1,6 @@
Summary: The inittab file and the /etc/init.d scripts.
Name: initscripts
-Version: 8.31.1
+Version: 8.31.2
License: GPL
Group: System Environment/Base
Release: 1
@@ -189,6 +189,7 @@ rm -rf $RPM_BUILD_ROOT
/sbin/getkey
%attr(2755,root,root) /sbin/netreport
/sbin/initlog
+/sbin/rename_device
/sbin/service
/sbin/ppp-watch
%{_mandir}/man*/*
@@ -208,6 +209,9 @@ rm -rf $RPM_BUILD_ROOT
%ghost %attr(0664,root,utmp) /var/run/utmp
%changelog
+* Fri Mar 17 2006 Bill Nottingham <notting@redhat.com> 8.31.2-1
+- add udev helper to rename network devices on device creation
+
* Tue Mar 14 2006 Bill Nottingham <notting@redhat.com> 8.31.1-1
- fix context of /dev/pts (#185436)
- translation updates
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);
+}
diff --git a/udev/rules.d/60-net.rules b/udev/rules.d/60-net.rules
index ca0b3967..872c7eed 100644
--- a/udev/rules.d/60-net.rules
+++ b/udev/rules.d/60-net.rules
@@ -1 +1,2 @@
+ACTION="add", SUBSYSTEM=="net", IMPORT{program}="/sbin/rename_device"
SUBSYSTEM=="net", RUN+="/etc/sysconfig/network-scripts/net.hotplug"