chiark / gitweb /
a423247d6b1074b1c1530cc12990fdb5462fbcd6
[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-2005 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(const char *devpath, char *filename, int len)
43 {
44         char temp[SYSFS_PATH_MAX];
45         char *pos;
46
47         /* replace '/' to transform path into a filename */
48         strfieldcpy(temp, devpath);
49         pos = strchr(&temp[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, temp);
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->devpath, 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", major(udev->devt), minor(udev->devt));
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         unsigned int major, minor;
96         char *bufline;
97         char *buf;
98         size_t bufsize;
99         size_t cur;
100         size_t count;
101
102         if (file_map(filename, &buf, &bufsize) != 0) {
103                 dbg("unable to read db file '%s'", filename);
104                 return -1;
105         }
106
107         cur = 0;
108         while (cur < bufsize) {
109                 count = buf_get_line(buf, bufsize, cur);
110                 bufline = &buf[cur];
111                 cur += count+1;
112
113                 switch(bufline[0]) {
114                 case 'P':
115                         if (count > DEVPATH_SIZE)
116                                 count = DEVPATH_SIZE-1;
117                         strncpy(udev->devpath, &bufline[2], count-2);
118                         udev->devpath[count-2] = '\0';
119                         break;
120                 case 'N':
121                         if (count > NAME_SIZE)
122                                 count = NAME_SIZE-1;
123                         strncpy(udev->name, &bufline[2], count-2);
124                         udev->name[count-2] = '\0';
125                         break;
126                 case 'M':
127                         if (count > NAME_SIZE)
128                                 count = NAME_SIZE-1;
129                         strncpy(temp, &bufline[2], count-2);
130                         temp[count-2] = '\0';
131                         sscanf(temp, "%u:%u", &major, &minor);
132                         udev->devt = makedev(major, minor);
133                         break;
134                 case 'S':
135                         if (count > NAME_SIZE)
136                                 count = NAME_SIZE-1;
137                         strncpy(udev->symlink, &bufline[2], count-2);
138                         udev->symlink[count-2] = '\0';
139                         break;
140                 case 'A':
141                         if (count > NAME_SIZE)
142                                 count = NAME_SIZE-1;
143                         strncpy(line, &bufline[2], count-2);
144                         line[count-2] = '\0';
145                         udev->partitions = atoi(line);
146                         break;
147                 case 'R':
148                         if (count > NAME_SIZE)
149                                 count = NAME_SIZE-1;
150                         strncpy(line, &bufline[2], count-2);
151                         line[count-2] = '\0';
152                         udev->ignore_remove = atoi(line);
153                         break;
154                 }
155         }
156         file_unmap(buf, bufsize);
157
158         if (udev->name[0] == '\0')
159                 return -1;
160
161         return 0;
162 }
163
164 int udev_db_delete_device(struct udevice *udev)
165 {
166         char filename[SYSFS_PATH_MAX];
167
168         get_db_filename(udev->devpath, filename, SYSFS_PATH_MAX);
169         unlink(filename);
170
171         return 0;
172 }
173
174 int udev_db_get_device_by_devpath(struct udevice *udev, const char *devpath)
175 {
176         char filename[SYSFS_PATH_MAX];
177
178         get_db_filename(devpath, filename, SYSFS_PATH_MAX);
179
180         return parse_db_file(udev, filename);
181 }
182
183 int udev_db_get_device_by_name(struct udevice *udev, const char *name)
184 {
185         struct dirent *ent;
186         DIR *dir;
187         char filename[NAME_SIZE];
188         struct udevice db_udev;
189
190         dir = opendir(udev_db_path);
191         if (dir == NULL) {
192                 dbg("unable to udev db '%s'", udev_db_path);
193                 return -1;
194         }
195
196         while (1) {
197                 ent = readdir(dir);
198                 if (ent == NULL || ent->d_name[0] == '\0')
199                         break;
200
201                 if (ent->d_name[0] == '.')
202                         continue;
203
204                 snprintf(filename, NAME_SIZE, "%s/%s", udev_db_path, ent->d_name);
205                 filename[NAME_SIZE-1] = '\0';
206
207                 memset(&db_udev, 0x00, sizeof(struct udevice));
208                 if (parse_db_file(&db_udev, filename) == 0) {
209                         char *pos;
210                         unsigned int len;
211
212                         if (strncmp(name, db_udev.name, NAME_SIZE) == 0) {
213                                 goto found;
214                         }
215
216                         foreach_strpart(db_udev.symlink, " ", pos, len) {
217                                 if (strncmp(name, pos, len) != 0)
218                                         continue;
219
220                                 if (len == strlen(name))
221                                         goto found;
222                         }
223
224                 }
225         }
226
227         closedir(dir);
228
229         return -1;
230
231 found:
232         closedir(dir);
233
234         strfieldcpy(udev->devpath, db_udev.devpath);
235         strfieldcpy(udev->name, db_udev.name);
236         strfieldcpy(udev->symlink, db_udev.symlink);
237         udev->partitions = db_udev.partitions;
238         udev->ignore_remove = db_udev.ignore_remove;
239         udev->devt = db_udev.devt;
240
241         return 0;
242 }
243
244 int udev_db_call_foreach(int (*handler_function)(struct udevice *udev))
245 {
246         struct dirent *ent;
247         DIR *dir;
248         char filename[NAME_SIZE];
249         struct udevice db_udev;
250
251         dir = opendir(udev_db_path);
252         if (dir == NULL) {
253                 dbg("unable to udev db '%s'", udev_db_path);
254                 return -1;
255         }
256
257         while (1) {
258                 ent = readdir(dir);
259                 if (ent == NULL || ent->d_name[0] == '\0')
260                         break;
261
262                 if (ent->d_name[0] == '.')
263                         continue;
264
265                 snprintf(filename, NAME_SIZE, "%s/%s", udev_db_path, ent->d_name);
266                 filename[NAME_SIZE-1] = '\0';
267
268                 memset(&db_udev, 0x00, sizeof(struct udevice));
269                 if (parse_db_file(&db_udev, filename) == 0) {
270                         if (handler_function(&db_udev) != 0)
271                                 break;
272                 }
273         }
274
275         closedir(dir);
276         return 0;
277 }