chiark / gitweb /
[PATCH] big libsysfs diet (pre 2.0 version)
[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
157         if (udev->name[0] == '\0')
158                 return -1;
159
160         return 0;
161 }
162
163 int udev_db_delete_device(struct udevice *udev)
164 {
165         char filename[SYSFS_PATH_MAX];
166
167         get_db_filename(udev->devpath, filename, SYSFS_PATH_MAX);
168         unlink(filename);
169
170         return 0;
171 }
172
173 int udev_db_get_device_by_devpath(struct udevice *udev, const char *devpath)
174 {
175         char filename[SYSFS_PATH_MAX];
176
177         get_db_filename(devpath, filename, SYSFS_PATH_MAX);
178
179         return parse_db_file(udev, filename);
180 }
181
182 int udev_db_get_device_byname(struct udevice *udev, const char *name)
183 {
184         struct dirent *ent;
185         DIR *dir;
186         char filename[NAME_SIZE];
187         struct udevice db_udev;
188
189         dir = opendir(udev_db_path);
190         if (dir == NULL) {
191                 dbg("unable to udev db '%s'", udev_db_path);
192                 return -1;
193         }
194
195         while (1) {
196                 ent = readdir(dir);
197                 if (ent == NULL || ent->d_name[0] == '\0')
198                         break;
199
200                 if (ent->d_name[0] == '.')
201                         continue;
202
203                 snprintf(filename, NAME_SIZE, "%s/%s", udev_db_path, ent->d_name);
204                 filename[NAME_SIZE-1] = '\0';
205
206                 memset(&db_udev, 0x00, sizeof(struct udevice));
207                 if (parse_db_file(&db_udev, filename) == 0) {
208                         char *pos;
209                         unsigned int len;
210
211                         if (strncmp(name, db_udev.name, NAME_SIZE) == 0) {
212                                 goto found;
213                         }
214
215                         foreach_strpart(db_udev.symlink, " ", pos, len) {
216                                 if (strncmp(name, pos, len) != 0)
217                                         continue;
218
219                                 if (len == strlen(name))
220                                         goto found;
221                         }
222
223                 }
224         }
225
226         closedir(dir);
227
228         return -1;
229
230 found:
231         closedir(dir);
232
233         strfieldcpy(udev->devpath, db_udev.devpath);
234         strfieldcpy(udev->name, db_udev.name);
235         strfieldcpy(udev->symlink, db_udev.symlink);
236         udev->partitions = db_udev.partitions;
237         udev->ignore_remove = db_udev.ignore_remove;
238         udev->devt = db_udev.devt;
239
240         return 0;
241 }