chiark / gitweb /
udevd: move some logging to "info" and "err"
[elogind.git] / udev_remove.c
1 /*
2  * udev-remove.c
3  *
4  * Copyright (C) 2003 Greg Kroah-Hartman <greg@kroah.com>
5  * Copyright (C) 2004 Kay Sievers <kay.sievers@vrfy.org>
6  *
7  *      This program is free software; you can redistribute it and/or modify it
8  *      under the terms of the GNU General Public License as published by the
9  *      Free Software Foundation version 2 of the License.
10  * 
11  *      This program is distributed in the hope that it will be useful, but
12  *      WITHOUT ANY WARRANTY; without even the implied warranty of
13  *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  *      General Public License for more details.
15  * 
16  *      You should have received a copy of the GNU General Public License along
17  *      with this program; if not, write to the Free Software Foundation, Inc.,
18  *      675 Mass Ave, Cambridge, MA 02139, USA.
19  *
20  */
21
22 #include <stdlib.h>
23 #include <string.h>
24 #include <stddef.h>
25 #include <stdio.h>
26 #include <fcntl.h>
27 #include <unistd.h>
28 #include <errno.h>
29 #include <sys/stat.h>
30
31 #include "udev_libc_wrapper.h"
32 #include "udev.h"
33 #include "udev_utils.h"
34 #include "udev_version.h"
35 #include "udev_db.h"
36 #include "logging.h"
37
38 static int delete_path(const char *path)
39 {
40         char *pos;
41         int retval;
42
43         pos = strrchr(path, '/');
44         while (1) {
45                 *pos = '\0';
46                 pos = strrchr(path, '/');
47
48                 /* don't remove the last one */
49                 if ((pos == path) || (pos == NULL))
50                         break;
51
52                 /* remove if empty */
53                 retval = rmdir(path);
54                 if (errno == ENOENT)
55                         retval = 0;
56                 if (retval) {
57                         if (errno == ENOTEMPTY)
58                                 return 0;
59                         dbg("rmdir(%s) failed with error '%s'",
60                             path, strerror(errno));
61                         break;
62                 }
63                 dbg("removed '%s'", path);
64         }
65         return 0;
66 }
67
68 static int delete_node(struct udevice *udev)
69 {
70         char filename[PATH_SIZE];
71         char partitionname[PATH_SIZE];
72         struct name_entry *name_loop;
73         struct stat stats;
74         int retval;
75         int i;
76         int num;
77
78         list_for_each_entry(name_loop, &udev->symlink_list, node) {
79                 snprintf(filename, sizeof(filename), "%s/%s", udev_root, name_loop->name);
80                 filename[sizeof(filename)-1] = '\0';
81
82                 if (stat(filename, &stats) != 0) {
83                         dbg("symlink '%s' not found", filename);
84                         continue;
85                 }
86                 if (udev->devt && stats.st_rdev != udev->devt) {
87                         info("symlink '%s' points to a different device, skip removal", filename);
88                         continue;;
89                 }
90
91                 info("removing symlink '%s'", filename);
92                 unlink(filename);
93
94                 if (strchr(filename, '/'))
95                         delete_path(filename);
96         }
97
98         snprintf(filename, sizeof(filename), "%s/%s", udev_root, udev->name);
99         filename[sizeof(filename)-1] = '\0';
100
101         if (stat(filename, &stats) != 0) {
102                 dbg("device node '%s' not found", filename);
103                 return -1;
104         }
105         if (udev->devt && stats.st_rdev != udev->devt) {
106                 info("device node '%s' points to a different device, skip removal", filename);
107                 return -1;
108         }
109
110         info("removing device node '%s'", filename);
111         retval = unlink_secure(filename);
112         if (retval)
113                 return retval;
114
115         num = udev->partitions;
116         if (num > 0) {
117                 info("removing all_partitions '%s[1-%i]'", filename, num);
118                 if (num > 255) {
119                         info("garbage from udev database, skip all_partitions removal");
120                         return -1;
121                 }
122                 for (i = 1; i <= num; i++) {
123                         snprintf(partitionname, sizeof(partitionname), "%s%d", filename, i);
124                         partitionname[sizeof(partitionname)-1] = '\0';
125                         unlink_secure(partitionname);
126                 }
127         }
128
129         if (strchr(udev->name, '/'))
130                 delete_path(filename);
131
132         return retval;
133 }
134
135 /*
136  * look up the sysfs path in the database to get the node name to remove
137  * If we can't find it, use kernel name for lack of anything else to know to do
138  */
139 int udev_remove_device(struct udevice *udev)
140 {
141         if (udev->type != DEV_BLOCK && udev->type != DEV_CLASS)
142                 return 0;
143
144         if (udev_db_get_device(udev, udev->devpath) == 0) {
145                 if (udev->ignore_remove) {
146                         dbg("remove event for '%s' requested to be ignored by rule", udev->name);
147                         return 0;
148                 }
149                 dbg("remove name='%s'", udev->name);
150                 udev_db_delete_device(udev);
151         } else {
152                 dbg("'%s' not found in database, using kernel name '%s'", udev->devpath, udev->kernel_name);
153                 strlcpy(udev->name, udev->kernel_name, sizeof(udev->name));
154         }
155         /* use full path to the environment */
156         snprintf(udev->devname, sizeof(udev->devname), "%s/%s", udev_root, udev->name);
157         udev->devname[sizeof(udev->devname)-1] = '\0';
158
159         return delete_node(udev);
160 }