chiark / gitweb /
[PATCH] remove the device node only if the major/minor number matches
[elogind.git] / udev_db.c
1 /*
2  * udev_db.c
3  *
4  * Userspace devfs
5  *
6  * Copyright (C) 2003 Greg Kroah-Hartman <greg@kroah.com>
7  * Copyright (C) 2004 Kay Sievers <kay.sievers@vrfy.org>
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
25 #include <stdlib.h>
26 #include <stdio.h>
27 #include <string.h>
28 #include <stddef.h>
29 #include <fcntl.h>
30 #include <string.h>
31 #include <errno.h>
32 #include <dirent.h>
33
34 #include "libsysfs/sysfs/libsysfs.h"
35 #include "udev.h"
36 #include "udev_utils.h"
37 #include "logging.h"
38 #include "udev_db.h"
39
40 #define PATH_TO_NAME_CHAR               '@'
41
42 static int get_db_filename(struct udevice *udev, char *filename, int len)
43 {
44         char devpath[SYSFS_PATH_MAX];
45         char *pos;
46
47         /* replace '/' to transform path into a filename */
48         strfieldcpy(devpath, udev->devpath);
49         pos = strchr(&devpath[1], '/');
50         while (pos) {
51                 pos[0] = PATH_TO_NAME_CHAR;
52                 pos = strchr(&pos[1], '/');
53         }
54         snprintf(filename, len, "%s%s", udev_db_path, devpath);
55         filename[len-1] = '\0';
56
57         return 0;
58 }
59
60 int udev_db_add_device(struct udevice *udev)
61 {
62         char filename[SYSFS_PATH_MAX];
63         FILE *f;
64
65         if (udev->test_run)
66                 return 0;
67
68         get_db_filename(udev, filename, SYSFS_PATH_MAX);
69
70         create_path(filename);
71
72         f = fopen(filename, "w");
73         if (f == NULL) {
74                 dbg("unable to create db file '%s'", filename);
75                 return -1;
76         }
77         dbg("storing data for device '%s' in '%s'", udev->devpath, filename);
78
79         fprintf(f, "P:%s\n", udev->devpath);
80         fprintf(f, "N:%s\n", udev->name);
81         fprintf(f, "S:%s\n", udev->symlink);
82         fprintf(f, "M:%u:%u\n", udev->major, udev->minor);
83         fprintf(f, "A:%u\n", udev->partitions);
84         fprintf(f, "R:%u\n", udev->ignore_remove);
85
86         fclose(f);
87
88         return 0;
89 }
90
91 static int parse_db_file(struct udevice *udev, const char *filename)
92 {
93         char line[NAME_SIZE];
94         char temp[NAME_SIZE];
95         char *bufline;
96         char *buf;
97         size_t bufsize;
98         size_t cur;
99         size_t count;
100
101         if (file_map(filename, &buf, &bufsize) != 0) {
102                 dbg("unable to read db file '%s'", filename);
103                 return -1;
104         }
105
106         cur = 0;
107         while (cur < bufsize) {
108                 count = buf_get_line(buf, bufsize, cur);
109                 bufline = &buf[cur];
110                 cur += count+1;
111
112                 switch(bufline[0]) {
113                 case 'P':
114                         if (count > DEVPATH_SIZE)
115                                 count = DEVPATH_SIZE-1;
116                         strncpy(udev->devpath, &bufline[2], count-2);
117                         udev->devpath[count-2] = '\0';
118                         break;
119                 case 'N':
120                         if (count > NAME_SIZE)
121                                 count = NAME_SIZE-1;
122                         strncpy(udev->name, &bufline[2], count-2);
123                         udev->name[count-2] = '\0';
124                         break;
125                 case 'M':
126                         if (count > NAME_SIZE)
127                                 count = NAME_SIZE-1;
128                         strncpy(temp, &bufline[2], count-2);
129                         temp[count-2] = '\0';
130                         sscanf(temp, "%u:%u", &udev->major, &udev->minor);
131                         break;
132                 case 'S':
133                         if (count > NAME_SIZE)
134                                 count = NAME_SIZE-1;
135                         strncpy(udev->symlink, &bufline[2], count-2);
136                         udev->symlink[count-2] = '\0';
137                         break;
138                 case 'A':
139                         if (count > NAME_SIZE)
140                                 count = NAME_SIZE-1;
141                         strncpy(line, &bufline[2], count-2);
142                         line[count-2] = '\0';
143                         udev->partitions = atoi(line);
144                         break;
145                 case 'R':
146                         if (count > NAME_SIZE)
147                                 count = NAME_SIZE-1;
148                         strncpy(line, &bufline[2], count-2);
149                         line[count-2] = '\0';
150                         udev->ignore_remove = atoi(line);
151                         break;
152                 }
153         }
154
155         if (udev->name[0] == '\0')
156                 return -1;
157
158         return 0;
159 }
160
161 int udev_db_get_device(struct udevice *udev)
162 {
163         char filename[SYSFS_PATH_MAX];
164
165         get_db_filename(udev, filename, SYSFS_PATH_MAX);
166
167         return parse_db_file(udev, filename);
168 }
169
170 int udev_db_delete_device(struct udevice *udev)
171 {
172         char filename[SYSFS_PATH_MAX];
173
174         get_db_filename(udev, filename, SYSFS_PATH_MAX);
175         unlink(filename);
176
177         return 0;
178 }
179
180 int udev_db_get_device_byname(struct udevice *udev, const char *name)
181 {
182         struct dirent *ent;
183         DIR *dir;
184         char filename[NAME_SIZE];
185         struct udevice db_udev;
186
187         dir = opendir(udev_db_path);
188         if (dir == NULL) {
189                 dbg("unable to udev db '%s'", udev_db_path);
190                 return -1;
191         }
192
193         while (1) {
194                 ent = readdir(dir);
195                 if (ent == NULL || ent->d_name[0] == '\0')
196                         break;
197
198                 if (ent->d_name[0] == '.')
199                         continue;
200
201                 snprintf(filename, NAME_SIZE, "%s/%s", udev_db_path, ent->d_name);
202                 filename[NAME_SIZE-1] = '\0';
203
204                 memset(&db_udev, 0x00, sizeof(struct udevice));
205                 if (parse_db_file(&db_udev, filename) == 0) {
206                         char *pos;
207                         unsigned int len;
208
209                         if (strncmp(name, db_udev.name, NAME_SIZE) == 0) {
210                                 goto found;
211                         }
212
213                         foreach_strpart(db_udev.symlink, " ", pos, len) {
214                                 if (strncmp(name, pos, len) != 0)
215                                         continue;
216
217                                 if (len == strlen(name))
218                                         goto found;
219                         }
220
221                 }
222         }
223
224         closedir(dir);
225
226         return -1;
227
228 found:
229         closedir(dir);
230
231         strfieldcpy(udev->devpath, db_udev.devpath);
232         strfieldcpy(udev->name, db_udev.name);
233         strfieldcpy(udev->symlink, db_udev.symlink);
234         udev->partitions = db_udev.partitions;
235
236         return 0;
237 }