chiark / gitweb /
export INTERFACE_OLD if we renamed a netif
[elogind.git] / udev_device.c
1 /*
2  * udev_device.c - main udev data object
3  *
4  * Copyright (C) 2004-2006 Kay Sievers <kay.sievers@vrfy.org>
5  *
6  *      This program is free software; you can redistribute it and/or modify it
7  *      under the terms of the GNU General Public License as published by the
8  *      Free Software Foundation version 2 of the License.
9  * 
10  *      This program is distributed in the hope that it will be useful, but
11  *      WITHOUT ANY WARRANTY; without even the implied warranty of
12  *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  *      General Public License for more details.
14  * 
15  *      You should have received a copy of the GNU General Public License along
16  *      with this program; if not, write to the Free Software Foundation, Inc.,
17  *      675 Mass Ave, Cambridge, MA 02139, USA.
18  *
19  */
20
21
22 #include <stdlib.h>
23 #include <stdio.h>
24 #include <stddef.h>
25 #include <unistd.h>
26 #include <fcntl.h>
27 #include <errno.h>
28 #include <ctype.h>
29 #include <stropts.h>
30 #include <net/if.h>
31 #include <linux/sockios.h>
32
33 #include "udev.h"
34 #include "udev_rules.h"
35
36
37 struct udevice *udev_device_init(void)
38 {
39         struct udevice *udev;
40
41         udev = malloc(sizeof(struct udevice));
42         if (udev == NULL)
43                 return NULL;
44         memset(udev, 0x00, sizeof(struct udevice));
45
46         INIT_LIST_HEAD(&udev->symlink_list);
47         INIT_LIST_HEAD(&udev->run_list);
48         INIT_LIST_HEAD(&udev->env_list);
49
50         /* set sysfs device to local storage, can be overridden if needed */
51         udev->dev = &udev->dev_local;
52
53         /* default node permissions */
54         udev->mode = 0660;
55         strcpy(udev->owner, "root");
56         strcpy(udev->group, "root");
57
58         return udev;
59 }
60
61 void udev_device_cleanup(struct udevice *udev)
62 {
63         name_list_cleanup(&udev->symlink_list);
64         name_list_cleanup(&udev->run_list);
65         name_list_cleanup(&udev->env_list);
66         free(udev);
67 }
68
69 dev_t udev_device_get_devt(struct udevice *udev)
70 {
71         const char *attr;
72         unsigned int major, minor;
73
74         /* read it from sysfs  */
75         attr = sysfs_attr_get_value(udev->dev->devpath, "dev");
76         if (attr != NULL) {
77                 if (sscanf(attr, "%u:%u", &major, &minor) == 2)
78                         return makedev(major, minor);
79         }
80         return makedev(0, 0);
81 }
82
83 static int rename_net_if(struct udevice *udev)
84 {
85         int sk;
86         struct ifreq ifr;
87         int retval;
88
89         info("changing net interface name from '%s' to '%s'", udev->dev->kernel_name, udev->name);
90         if (udev->test_run)
91                 return 0;
92
93         sk = socket(PF_INET, SOCK_DGRAM, 0);
94         if (sk < 0) {
95                 err("error opening socket: %s", strerror(errno));
96                 return -1;
97         }
98
99         memset(&ifr, 0x00, sizeof(struct ifreq));
100         strlcpy(ifr.ifr_name, udev->dev->kernel_name, IFNAMSIZ);
101         strlcpy(ifr.ifr_newname, udev->name, IFNAMSIZ);
102
103         retval = ioctl(sk, SIOCSIFNAME, &ifr);
104         if (retval != 0)
105                 err("error changing net interface name: %s", strerror(errno));
106         close(sk);
107
108         return retval;
109 }
110
111 int udev_device_event(struct udev_rules *rules, struct udevice *udev)
112 {
113         int retval = 0;
114
115         /* add device node */
116         if (major(udev->devt) != 0 && strcmp(udev->action, "add") == 0) {
117                 dbg("device node add '%s'", udev->dev->devpath);
118                 udev_rules_get_name(rules, udev);
119                 if (udev->ignore_device) {
120                         info("device event will be ignored");
121                         goto exit;
122                 }
123                 if (udev->name[0] == '\0') {
124                         info("device node creation supressed");
125                         goto exit;
126                 }
127                 /* create node, store in db */
128                 retval = udev_node_add(udev);
129                 if (retval == 0)
130                         udev_db_add_device(udev);
131                 goto exit;
132         }
133
134         /* add netif */
135         if (strcmp(udev->dev->subsystem, "net") == 0 && strcmp(udev->action, "add") == 0) {
136                 dbg("netif add '%s'", udev->dev->devpath);
137                 udev_rules_get_name(rules, udev);
138                 if (udev->ignore_device) {
139                         info("device event will be ignored");
140                         goto exit;
141                 }
142
143                 /* look if we want to change the name of the netif */
144                 if (strcmp(udev->name, udev->dev->kernel_name) != 0) {
145                         char *pos;
146
147                         retval = rename_net_if(udev);
148                         if (retval != 0)
149                                 goto exit;
150                         info("renamed netif to '%s'", udev->name);
151
152                         /* export old name */
153                         setenv("INTERFACE_OLD", udev->dev->kernel_name, 1);
154
155                         /* now fake the devpath, because the kernel name changed silently */
156                         pos = strrchr(udev->dev->devpath, '/');
157                         if (pos != NULL) {
158                                 pos[1] = '\0';
159                                 strlcat(udev->dev->devpath, udev->name, sizeof(udev->dev->devpath));
160                                 strlcpy(udev->dev->kernel_name, udev->name, sizeof(udev->dev->kernel_name));
161                                 setenv("DEVPATH", udev->dev->devpath, 1);
162                                 setenv("INTERFACE", udev->name, 1);
163                         }
164                 }
165                 goto exit;
166         }
167
168         /* remove device node */
169         if (major(udev->devt) != 0 && strcmp(udev->action, "remove") == 0) {
170                 struct name_entry *name_loop;
171
172                 /* import and delete database entry */
173                 if (udev_db_get_device(udev, udev->dev->devpath) == 0) {
174                         udev_db_delete_device(udev);
175                         if (udev->ignore_remove) {
176                                 dbg("remove event for '%s' requested to be ignored by rule", udev->name);
177                                 return 0;
178                         }
179                         /* restore stored persistent data */
180                         list_for_each_entry(name_loop, &udev->env_list, node)
181                                 putenv(name_loop->name);
182                 } else {
183                         dbg("'%s' not found in database, using kernel name '%s'", udev->dev->devpath, udev->dev->kernel_name);
184                         strlcpy(udev->name, udev->dev->kernel_name, sizeof(udev->name));
185                 }
186
187                 udev_rules_get_run(rules, udev);
188                 if (udev->ignore_device) {
189                         info("device event will be ignored");
190                         goto exit;
191                 }
192
193                 retval = udev_node_remove(udev);
194                 goto exit;
195         }
196
197         /* default devices */
198         udev_rules_get_run(rules, udev);
199         if (udev->ignore_device)
200                 info("device event will be ignored");
201
202 exit:
203         return retval;
204 }