chiark / gitweb /
087 release
[elogind.git] / udev_db.c
1 /*
2  * udev_db.c
3  *
4  * Copyright (C) 2003 Greg Kroah-Hartman <greg@kroah.com>
5  * Copyright (C) 2004-2005 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
23 #include <stdlib.h>
24 #include <stdio.h>
25 #include <string.h>
26 #include <stddef.h>
27 #include <unistd.h>
28 #include <fcntl.h>
29 #include <string.h>
30 #include <errno.h>
31 #include <dirent.h>
32
33 #include "udev.h"
34
35
36 static int devpath_to_db_path(const char *devpath, char *filename, size_t len)
37 {
38         size_t start, end, i;
39
40         /* add location of db files */
41         strlcpy(filename, udev_root, len);
42         start = strlcat(filename, "/"DB_DIR, len);
43         end = strlcat(filename, devpath, len);
44         if (end > len)
45                 end = len;
46
47         /* replace '/' to transform path into a filename */
48         for (i = start+1; i < end; i++)
49                 if (filename[i] == '/')
50                         filename[i] = PATH_TO_NAME_CHAR;
51
52         return 0;
53 }
54
55 static int db_file_to_devpath(const char *filename, char *devpath, size_t len)
56 {
57         size_t end, i;
58
59         strlcpy(devpath, "/", len);
60         end = strlcat(devpath, filename, len);
61
62         /* replace PATH_TO_NAME_CHAR to transform name into devpath */
63         for (i = 1; i < end; i++)
64                 if (devpath[i] == PATH_TO_NAME_CHAR)
65                         devpath[i] = '/';
66
67         return 0;
68 }
69
70 int udev_db_add_device(struct udevice *udev)
71 {
72         char filename[PATH_SIZE];
73         struct name_entry *name_loop;
74         FILE *f;
75
76         if (udev->test_run)
77                 return 0;
78
79         /* don't write anything if udev created only the node with the
80          * kernel name without any interesting data to remember
81          */
82         if (strcmp(udev->name, udev->dev->kernel_name) == 0 &&
83             list_empty(&udev->symlink_list) && list_empty(&udev->env_list) &&
84             !udev->partitions && !udev->ignore_remove) {
85                 dbg("nothing interesting to store in udevdb, skip");
86                 goto exit;
87         }
88
89         devpath_to_db_path(udev->dev->devpath, filename, sizeof(filename));
90         create_path(filename);
91         f = fopen(filename, "w");
92         if (f == NULL) {
93                 err("unable to create db file '%s': %s", filename, strerror(errno));
94                 return -1;
95         }
96         dbg("storing data for device '%s' in '%s'", udev->dev->devpath, filename);
97
98         fprintf(f, "N:%s\n", udev->name);
99         list_for_each_entry(name_loop, &udev->symlink_list, node)
100                 fprintf(f, "S:%s\n", name_loop->name);
101         fprintf(f, "M:%u:%u\n", major(udev->devt), minor(udev->devt));
102         if (udev->partitions)
103                 fprintf(f, "A:%u\n", udev->partitions);
104         if (udev->ignore_remove)
105                 fprintf(f, "R:%u\n", udev->ignore_remove);
106         list_for_each_entry(name_loop, &udev->env_list, node)
107                 fprintf(f, "E:%s\n", name_loop->name);
108         fclose(f);
109
110 exit:
111         return 0;
112 }
113
114 int udev_db_get_device(struct udevice *udev, const char *devpath)
115 {
116         char filename[PATH_SIZE];
117         char line[PATH_SIZE];
118         unsigned int major, minor;
119         char *bufline;
120         char *buf;
121         size_t bufsize;
122         size_t cur;
123         size_t count;
124
125         devpath_to_db_path(devpath, filename, sizeof(filename));
126         if (file_map(filename, &buf, &bufsize) != 0) {
127                 info("no db file to read %s: %s", filename, strerror(errno));
128                 return -1;
129         }
130
131         strlcpy(udev->dev->devpath, devpath, sizeof(udev->dev->devpath));
132         cur = 0;
133         while (cur < bufsize) {
134                 count = buf_get_line(buf, bufsize, cur);
135                 bufline = &buf[cur];
136                 cur += count+1;
137
138                 switch(bufline[0]) {
139                 case 'N':
140                         if (count > sizeof(udev->name))
141                                 count = sizeof(udev->name);
142                         memcpy(udev->name, &bufline[2], count-2);
143                         udev->name[count-2] = '\0';
144                         break;
145                 case 'M':
146                         if (count > sizeof(line))
147                                 count = sizeof(line);
148                         memcpy(line, &bufline[2], count-2);
149                         line[count-2] = '\0';
150                         sscanf(line, "%u:%u", &major, &minor);
151                         udev->devt = makedev(major, minor);
152                         break;
153                 case 'S':
154                         if (count > sizeof(line))
155                                 count =  sizeof(line);
156                         memcpy(line, &bufline[2], count-2);
157                         line[count-2] = '\0';
158                         name_list_add(&udev->symlink_list, line, 0);
159                         break;
160                 case 'A':
161                         if (count > sizeof(line))
162                                 count =  sizeof(line);
163                         memcpy(line, &bufline[2], count-2);
164                         line[count-2] = '\0';
165                         udev->partitions = atoi(line);
166                         break;
167                 case 'R':
168                         if (count > sizeof(line))
169                                 count =  sizeof(line);
170                         memcpy(line, &bufline[2], count-2);
171                         line[count-2] = '\0';
172                         udev->ignore_remove = atoi(line);
173                         break;
174                 case 'E':
175                         if (count > sizeof(line))
176                                 count =  sizeof(line);
177                         memcpy(line, &bufline[2], count-2);
178                         line[count-2] = '\0';
179                         name_list_add(&udev->env_list, line, 0);
180                         break;
181                 }
182         }
183         file_unmap(buf, bufsize);
184
185         if (udev->name[0] == '\0')
186                 return -1;
187
188         return 0;
189 }
190
191 int udev_db_delete_device(struct udevice *udev)
192 {
193         char filename[PATH_SIZE];
194
195         devpath_to_db_path(udev->dev->devpath, filename, sizeof(filename));
196         unlink(filename);
197
198         return 0;
199 }
200
201 int udev_db_lookup_name(const char *name, char *devpath, size_t len)
202 {
203         char dbpath[PATH_MAX];
204         DIR *dir;
205         int found = 0;
206
207         strlcpy(dbpath, udev_root, sizeof(dbpath));
208         strlcat(dbpath, "/"DB_DIR, sizeof(dbpath));
209         dir = opendir(dbpath);
210         if (dir == NULL) {
211                 info("no udev_db available '%s': %s", dbpath, strerror(errno));
212                 return -1;
213         }
214
215         while (!found) {
216                 struct dirent *ent;
217                 char filename[PATH_SIZE];
218                 char nodename[PATH_SIZE];
219                 char *bufline;
220                 char *buf;
221                 size_t bufsize;
222                 size_t cur;
223                 size_t count;
224
225                 ent = readdir(dir);
226                 if (ent == NULL || ent->d_name[0] == '\0')
227                         break;
228                 if (ent->d_name[0] == '.')
229                         continue;
230
231                 snprintf(filename, sizeof(filename), "%s/%s", dbpath, ent->d_name);
232                 filename[sizeof(filename)-1] = '\0';
233                 dbg("looking at '%s'", filename);
234
235                 if (file_map(filename, &buf, &bufsize) != 0) {
236                         err("unable to read db file '%s': %s", filename, strerror(errno));
237                         continue;
238                 }
239
240                 cur = 0;
241                 while (cur < bufsize && !found) {
242                         count = buf_get_line(buf, bufsize, cur);
243                         bufline = &buf[cur];
244                         cur += count+1;
245
246                         switch(bufline[0]) {
247                         case 'N':
248                         case 'S':
249                                 if (count > sizeof(nodename))
250                                         count = sizeof(nodename);
251                                 memcpy(nodename, &bufline[2], count-2);
252                                 nodename[count-2] = '\0';
253                                 dbg("compare '%s' '%s'", nodename, name);
254                                 if (strcmp(nodename, name) == 0) {
255                                         db_file_to_devpath(ent->d_name, devpath, len);
256                                         found = 1;
257                                 }
258                                 break;
259                         default:
260                                 continue;
261                         }
262                 }
263                 file_unmap(buf, bufsize);
264         }
265
266         closedir(dir);
267         if (found)
268                 return 0;
269         else
270                 return -1;
271 }
272
273 int udev_db_get_all_entries(struct list_head *name_list)
274 {
275         char dbpath[PATH_MAX];
276         DIR *dir;
277
278         strlcpy(dbpath, udev_root, sizeof(dbpath));
279         strlcat(dbpath, "/"DB_DIR, sizeof(dbpath));
280         dir = opendir(dbpath);
281         if (dir == NULL) {
282                 info("no udev_db available '%s': %s", dbpath, strerror(errno));
283                 return -1;
284         }
285
286         while (1) {
287                 struct dirent *ent;
288                 char filename[PATH_SIZE] = "/";
289                 size_t end, i;
290
291                 ent = readdir(dir);
292                 if (ent == NULL || ent->d_name[0] == '\0')
293                         break;
294                 if (ent->d_name[0] == '.')
295                         continue;
296
297                 end = strlcat(filename, ent->d_name, sizeof(filename));
298                 for (i = 1; i < end; i++)
299                         if (filename[i] == PATH_TO_NAME_CHAR)
300                                 filename[i] = '/';
301                 name_list_add(name_list, filename, 1);
302                 dbg("added '%s'", filename);
303         }
304
305         closedir(dir);
306         return 0;
307 }