chiark / gitweb /
307b907c8897be44a99122adbeca131c8e05e1b8
[elogind.git] / udev-remove.c
1 /*
2  * udev-remove.c
3  *
4  * Userspace devfs
5  *
6  * Copyright (C) 2003 Greg Kroah-Hartman <greg@kroah.com>
7  *
8  *
9  *      This program is free software; you can redistribute it and/or modify it
10  *      under the terms of the GNU General Public License as published by the
11  *      Free Software Foundation version 2 of the License.
12  * 
13  *      This program is distributed in the hope that it will be useful, but
14  *      WITHOUT ANY WARRANTY; without even the implied warranty of
15  *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  *      General Public License for more details.
17  * 
18  *      You should have received a copy of the GNU General Public License along
19  *      with this program; if not, write to the Free Software Foundation, Inc.,
20  *      675 Mass Ave, Cambridge, MA 02139, USA.
21  *
22  */
23
24 #include <stdlib.h>
25 #include <string.h>
26 #include <stdio.h>
27 #include <fcntl.h>
28 #include <unistd.h>
29 #include <errno.h>
30
31 #include "udev.h"
32 #include "udev_version.h"
33 #include "namedev.h"
34 #include "udevdb.h"
35 #include "libsysfs/libsysfs.h"
36
37 static int delete_path(char *path)
38 {
39         char *pos;
40         int retval;
41
42         pos = strrchr(path, '/');
43         while (1) {
44                 *pos = '\0';
45                 pos = strrchr(path, '/');
46
47                 /* don't remove the last one */
48                 if ((pos == path) || (pos == NULL))
49                         break;
50
51                 /* remove if empty */
52                 retval = rmdir(path);
53                 if (retval) {
54                         if (errno == ENOTEMPTY)
55                                 return 0;
56                         dbg("rmdir(%s) failed with error '%s'",
57                             path, strerror(errno));
58                         break;
59                 }
60                 dbg("removed '%s'", path);
61         }
62         return 0;
63 }
64
65 static int delete_node(struct udevice *dev)
66 {
67         char filename[255];
68         int retval;
69
70         strncpy(filename, udev_root, sizeof(filename));
71         strncat(filename, dev->name, sizeof(filename));
72
73         dbg("unlinking node '%s'", filename);
74         retval = unlink(filename);
75         if (retval) {
76                 dbg("unlink(%s) failed with error '%s'",
77                         filename, strerror(errno));
78                 return retval;
79         }
80
81         /* remove subdirectories */
82         if (strchr(dev->name, '/'))
83                 delete_path(filename);
84
85         if (*dev->symlink) {
86                 strncpy(filename, udev_root, sizeof(filename));
87                 strncat(filename, dev->symlink, sizeof(filename));
88                 dbg("unlinking symlink '%s'", filename);
89                 retval = unlink(filename);
90                 if (retval) {
91                         dbg("unlink(%s) failed with error '%s'",
92                                 filename, strerror(errno));
93                         return retval;
94                 }
95                 if (strchr(dev->symlink, '/')) {
96                         delete_path(filename);
97                 }
98         }
99
100         return retval;
101 }
102
103 #ifdef USE_DBUS
104 /** Send out a signal that a device node is deleted
105  *
106  *  @param  name                Name of the device node, e.g. /udev/sda1
107  *  @param  path                Sysfs path of device
108  */
109 static void sysbus_send_remove(const char* name, const char *path)
110 {
111         char filename[255];
112         DBusMessage* message;
113         DBusMessageIter iter;
114
115         if (sysbus_connection == NULL)
116                 return;
117
118         strncpy(filename, udev_root, sizeof(filename));
119         strncat(filename, name, sizeof(filename));
120
121         /* object, interface, member */
122         message = dbus_message_new_signal("/org/kernel/udev/NodeMonitor", 
123                                           "org.kernel.udev.NodeMonitor",
124                                           "NodeDeleted");
125         
126         dbus_message_iter_init(message, &iter);
127         dbus_message_iter_append_string(&iter, filename);
128         dbus_message_iter_append_string(&iter, path);
129         
130         if ( !dbus_connection_send(sysbus_connection, message, NULL) )
131                 dbg("error sending d-bus signal");
132         
133         dbus_message_unref(message);
134
135         dbus_connection_flush(sysbus_connection);
136 }
137 #endif /* USE_DBUS */
138
139 /*
140  * Look up the sysfs path in the database to see if we have named this device
141  * something different from the kernel name.  If we have, us it.  If not, use
142  * the default kernel name for lack of anything else to know to do.
143  */
144 int udev_remove_device(char *path, char *subsystem)
145 {
146         char name[100];
147         struct udevice *dev;
148         char *temp;
149
150         dev = udevdb_get_dev(path);
151         if (dev == NULL) {
152                 dbg("'%s' not found in database, falling back on default name", path);
153                 temp = strrchr(path, '/');
154                 if (temp == NULL)
155                         return -ENODEV;
156                 strncpy(name, &temp[1], sizeof(name));
157         }
158
159         dbg("name is '%s'", dev->name);
160         udevdb_delete_dev(path);
161
162 #ifdef USE_DBUS
163         sysbus_send_remove(name, device);
164 #endif /* USE_DBUS */
165   
166         return delete_node(dev);
167 }