chiark / gitweb /
udev_event_run() -> udev_event_execute_rules()
[elogind.git] / udev / udev-event.c
1 /*
2  * Copyright (C) 2004-2008 Kay Sievers <kay.sievers@vrfy.org>
3  *
4  * This program is free software: you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation, either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
16  */
17
18 #include <stdlib.h>
19 #include <stdio.h>
20 #include <stddef.h>
21 #include <unistd.h>
22 #include <fcntl.h>
23 #include <errno.h>
24 #include <ctype.h>
25 #include <string.h>
26 #include <sys/ioctl.h>
27 #include <sys/socket.h>
28 #include <net/if.h>
29 #include <linux/sockios.h>
30
31 #include "udev.h"
32
33 struct udev_event *udev_event_new(struct udev_device *dev)
34 {
35         struct udev_event *event;
36
37         event = malloc(sizeof(struct udev_event));
38         if (event == NULL)
39                 return NULL;
40         memset(event, 0x00, sizeof(struct udev_event));
41
42         event->dev = dev;
43         event->udev = udev_device_get_udev(dev);
44         udev_list_init(&event->run_list);
45         event->mode = 0660;
46         util_strlcpy(event->owner, "0", sizeof(event->owner));
47         util_strlcpy(event->group, "0", sizeof(event->group));
48
49         dbg(event->udev, "allocated event %p\n", event);
50         return event;
51 }
52
53 void udev_event_unref(struct udev_event *event)
54 {
55         udev_list_cleanup(event->udev, &event->run_list);
56         dbg(event->udev, "free event %p\n", event);
57         free(event);
58 }
59
60 static void kernel_log(struct ifreq ifr)
61 {
62         int klog;
63         FILE *f;
64
65         klog = open("/dev/kmsg", O_WRONLY);
66         if (klog < 0)
67                 return;
68
69         f = fdopen(klog, "w");
70         if (f == NULL) {
71                 close(klog);
72                 return;
73         }
74
75         fprintf(f, "<6>udev: renamed network interface %s to %s\n",
76                 ifr.ifr_name, ifr.ifr_newname);
77         fclose(f);
78 }
79
80 static int rename_netif(struct udev_event *event)
81 {
82         struct udev_device *dev = event->dev;
83         int sk;
84         struct ifreq ifr;
85         int err;
86
87         info(event->udev, "changing net interface name from '%s' to '%s'\n",
88              udev_device_get_sysname(dev), event->name);
89         if (event->test)
90                 return 0;
91
92         sk = socket(PF_INET, SOCK_DGRAM, 0);
93         if (sk < 0) {
94                 err(event->udev, "error opening socket: %m\n");
95                 return -1;
96         }
97
98         memset(&ifr, 0x00, sizeof(struct ifreq));
99         util_strlcpy(ifr.ifr_name, udev_device_get_sysname(dev), IFNAMSIZ);
100         util_strlcpy(ifr.ifr_newname, event->name, IFNAMSIZ);
101         err = ioctl(sk, SIOCSIFNAME, &ifr);
102         if (err == 0)
103                 kernel_log(ifr);
104         else {
105                 int loop;
106
107                 /* see if the destination interface name already exists */
108                 if (errno != EEXIST) {
109                         err(event->udev, "error changing netif name %s to %s: %m\n",
110                             ifr.ifr_name, ifr.ifr_newname);
111                         goto exit;
112                 }
113
114                 /* free our own name, another process may wait for us */
115                 util_strlcpy(ifr.ifr_newname, udev_device_get_sysname(dev), IFNAMSIZ);
116                 util_strlcat(ifr.ifr_newname, "_rename", IFNAMSIZ);
117                 err = ioctl(sk, SIOCSIFNAME, &ifr);
118                 if (err != 0) {
119                         err(event->udev, "error changing netif name %s to %s: %m\n",
120                             ifr.ifr_name, ifr.ifr_newname);
121                         goto exit;
122                 }
123
124                 /* wait 30 seconds for our target to become available */
125                 util_strlcpy(ifr.ifr_name, ifr.ifr_newname, IFNAMSIZ);
126                 util_strlcpy(ifr.ifr_newname, udev_device_get_devnode(dev), IFNAMSIZ);
127                 loop = 30 * 20;
128                 while (loop--) {
129                         err = ioctl(sk, SIOCSIFNAME, &ifr);
130                         if (err == 0) {
131                                 kernel_log(ifr);
132                                 break;
133                         }
134
135                         if (errno != EEXIST) {
136                                 err(event->udev, "error changing net interface name %s to %s: %m\n",
137                                     ifr.ifr_name, ifr.ifr_newname);
138                                 break;
139                         }
140                         dbg(event->udev, "wait for netif '%s' to become free, loop=%i\n",
141                             udev_device_get_devnode(dev), (30 * 20) - loop);
142                         usleep(1000 * 1000 / 20);
143                 }
144         }
145 exit:
146         close(sk);
147         return err;
148 }
149
150 int udev_event_execute_rules(struct udev_event *event, struct udev_rules *rules)
151 {
152         struct udev_device *dev = event->dev;
153         int err = 0;
154
155         if (udev_device_get_devpath_old(dev) != NULL) {
156                 if (udev_device_rename_db(dev, udev_device_get_devpath(dev)) == 0)
157                         info(event->udev, "moved database from '%s' to '%s'\n",
158                              udev_device_get_devpath_old(dev), udev_device_get_devpath(dev));
159         }
160
161         /* add device node */
162         if (major(udev_device_get_devnum(dev)) != 0 &&
163             (strcmp(udev_device_get_action(dev), "add") == 0 || strcmp(udev_device_get_action(dev), "change") == 0)) {
164                 char filename[UTIL_PATH_SIZE];
165                 struct udev_device *dev_old;
166
167                 dbg(event->udev, "device node add '%s'\n", udev_device_get_devpath(dev));
168
169                 udev_rules_get_name(rules, event);
170                 if (event->ignore_device) {
171                         info(event->udev, "device event will be ignored\n");
172                         goto exit;
173                 }
174
175                 if (event->name[0] == '\0') {
176                         info(event->udev, "device node creation supressed\n");
177                         goto exit;
178                 }
179
180                 /* set device node name */
181                 util_strlcpy(filename, udev_get_dev_path(event->udev), sizeof(filename));
182                 util_strlcat(filename, "/", sizeof(filename));
183                 util_strlcat(filename, event->name, sizeof(filename));
184                 udev_device_set_devnode(dev, filename);
185
186                 /* read current database entry; cleanup, if it is known device */
187                 dev_old = udev_device_new_from_syspath(event->udev, udev_device_get_syspath(dev));
188                 if (dev_old != NULL) {
189                         info(event->udev, "device '%s' already in database, updating\n",
190                              udev_device_get_devpath(dev));
191                         udev_node_update_old_links(dev, dev_old, event->test);
192                         udev_device_unref(dev_old);
193                 }
194
195                 udev_device_update_db(dev);
196
197                 err = udev_node_add(dev, event->mode, event->owner, event->group, event->test);
198                 if (err != 0)
199                         goto exit;
200
201                 goto exit;
202         }
203
204         /* add netif */
205         if (strcmp(udev_device_get_subsystem(dev), "net") == 0 && strcmp(udev_device_get_action(dev), "add") == 0) {
206                 dbg(event->udev, "netif add '%s'\n", udev_device_get_devpath(dev));
207
208                 udev_rules_get_name(rules, event);
209                 if (event->ignore_device) {
210                         info(event->udev, "device event will be ignored\n");
211                         goto exit;
212                 }
213                 if (event->name[0] == '\0') {
214                         info(event->udev, "device renaming supressed\n");
215                         goto exit;
216                 }
217
218                 /* look if we want to change the name of the netif */
219                 if (strcmp(event->name, udev_device_get_sysname(dev)) != 0) {
220                         char syspath[UTIL_PATH_SIZE];
221                         char *pos;
222
223                         err = rename_netif(event);
224                         if (err != 0)
225                                 goto exit;
226                         info(event->udev, "renamed netif to '%s'\n", event->name);
227
228                         /* remember old name */
229                         udev_device_add_property(dev, "INTERFACE_OLD", udev_device_get_sysname(dev));
230
231                         /* now change the devpath, because the kernel device name has changed */
232                         util_strlcpy(syspath, udev_device_get_syspath(dev), sizeof(syspath));
233                         pos = strrchr(syspath, '/');
234                         if (pos != NULL) {
235                                 pos[1] = '\0';
236                                 util_strlcat(syspath, event->name, sizeof(syspath));
237                                 udev_device_set_syspath(event->dev, syspath);
238                                 udev_device_add_property(dev, "INTERFACE", udev_device_get_sysname(dev));
239                                 info(event->udev, "changed devpath to '%s'\n", udev_device_get_devpath(dev));
240                         }
241                 }
242                 goto exit;
243         }
244
245         /* remove device node */
246         if (major(udev_device_get_devnum(dev)) != 0 && strcmp(udev_device_get_action(dev), "remove") == 0) {
247                 /* import database entry and delete it */
248                 udev_device_read_db(dev);
249                 if (!event->test)
250                         udev_device_delete_db(dev);
251
252                 if (udev_device_get_devnode(dev) == NULL) {
253                         char devnode[UTIL_PATH_SIZE];
254
255                         info(event->udev, "'%s' not found in database, using kernel name '%s'\n",
256                              udev_device_get_syspath(dev), udev_device_get_sysname(dev));
257                         util_strlcpy(devnode, udev_get_dev_path(event->udev), sizeof(devnode));
258                         util_strlcat(devnode, "/", sizeof(devnode));
259                         util_strlcat(devnode, udev_device_get_sysname(dev), sizeof(devnode));
260                         udev_device_set_devnode(dev, devnode);
261                 }
262
263                 udev_rules_get_run(rules, event);
264                 if (event->ignore_device) {
265                         info(event->udev, "device event will be ignored\n");
266                         goto exit;
267                 }
268
269                 if (udev_device_get_ignore_remove(dev)) {
270                         info(event->udev, "ignore_remove for '%s'\n", udev_device_get_devnode(dev));
271                         goto exit;
272                 }
273
274                 err = udev_node_remove(dev, event->test);
275                 goto exit;
276         }
277
278         /* default devices */
279         udev_rules_get_run(rules, event);
280         if (event->ignore_device)
281                 info(event->udev, "device event will be ignored\n");
282 exit:
283         return err;
284 }