chiark / gitweb /
libudev: add selinux
[elogind.git] / udev / udev_db.c
1 /*
2  * Copyright (C) 2003 Greg Kroah-Hartman <greg@kroah.com>
3  * Copyright (C) 2004-2005 Kay Sievers <kay.sievers@vrfy.org>
4  *
5  *      This program is free software; you can redistribute it and/or modify it
6  *      under the terms of the GNU General Public License as published by the
7  *      Free Software Foundation version 2 of the License.
8  * 
9  *      This program is distributed in the hope that it will be useful, but
10  *      WITHOUT ANY WARRANTY; without even the implied warranty of
11  *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  *      General Public License for more details.
13  * 
14  *      You should have received a copy of the GNU General Public License along
15  *      with this program; if not, write to the Free Software Foundation, Inc.,
16  *      51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
17  *
18  */
19
20
21 #include <stdlib.h>
22 #include <stdio.h>
23 #include <string.h>
24 #include <stddef.h>
25 #include <unistd.h>
26 #include <fcntl.h>
27 #include <string.h>
28 #include <errno.h>
29 #include <dirent.h>
30 #include <sys/stat.h>
31 #include <sys/types.h>
32
33 #include "udev.h"
34
35 static size_t devpath_to_db_path(struct udev *udev, const char *devpath, char *filename, size_t len)
36 {
37         size_t start;
38
39         /* translate to location of db file */
40         strlcpy(filename, udev_get_dev_path(udev), len);
41         start = strlcat(filename, "/.udev/db/", len);
42         strlcat(filename, devpath, len);
43         return path_encode(&filename[start], len - start);
44 }
45
46 /* reverse mapping from the device file name to the devpath */
47 static int name_index(struct udev *udev, const char *devpath, const char *name, int add)
48 {
49         char device[PATH_SIZE];
50         char filename[PATH_SIZE * 2];
51         size_t start;
52         int fd;
53
54         /* directory with device name */
55         strlcpy(filename, udev_get_dev_path(udev), sizeof(filename));
56         start = strlcat(filename, "/.udev/names/", sizeof(filename));
57         strlcat(filename, name, sizeof(filename));
58         path_encode(&filename[start], sizeof(filename) - start);
59         /* entry with the devpath */
60         strlcpy(device, devpath, sizeof(device));
61         path_encode(device, sizeof(device));
62         strlcat(filename, "/", sizeof(filename));
63         strlcat(filename, device, sizeof(filename));
64
65         if (add) {
66                 info(udev, "creating index: '%s'\n", filename);
67                 create_path(udev, filename);
68                 fd = open(filename, O_WRONLY|O_TRUNC|O_CREAT, 0644);
69                 if (fd > 0)
70                         close(fd);
71         } else {
72                 info(udev, "removing index: '%s'\n", filename);
73                 unlink(filename);
74                 delete_path(udev, filename);
75         }
76         return 0;
77 }
78
79 int udev_db_get_devices_by_name(struct udev *udev, const char *name, struct list_head *name_list)
80 {
81         char dirname[PATH_MAX];
82         size_t start;
83         DIR *dir;
84         int rc = 0;
85
86         strlcpy(dirname, udev_get_dev_path(udev), sizeof(dirname));
87         start = strlcat(dirname, "/.udev/names/", sizeof(dirname));
88         strlcat(dirname, name, sizeof(dirname));
89         path_encode(&dirname[start], sizeof(dirname) - start);
90
91         dir = opendir(dirname);
92         if (dir == NULL) {
93                 info(udev, "no index directory '%s': %s\n", dirname, strerror(errno));
94                 rc = -1;
95                 goto out;
96         }
97
98         info(udev, "found index directory '%s'\n", dirname);
99         while (1) {
100                 struct dirent *ent;
101                 char device[PATH_SIZE];
102
103                 ent = readdir(dir);
104                 if (ent == NULL || ent->d_name[0] == '\0')
105                         break;
106                 if (ent->d_name[0] == '.')
107                         continue;
108
109                 strlcpy(device, ent->d_name, sizeof(device));
110                 path_decode(device);
111                 name_list_add(udev, name_list, device, 0);
112                 rc++;
113         }
114         closedir(dir);
115 out:
116         return rc;
117 }
118
119 int udev_db_rename(struct udev *udev, const char *devpath_old, const char *devpath)
120 {
121         char filename[PATH_SIZE];
122         char filename_old[PATH_SIZE];
123
124         devpath_to_db_path(udev, devpath_old, filename_old, sizeof(filename_old));
125         devpath_to_db_path(udev, devpath, filename, sizeof(filename));
126         return rename(filename_old, filename);
127 }
128
129 int udev_db_add_device(struct udevice *udevice)
130 {
131         char filename[PATH_SIZE];
132
133         if (udevice->test_run)
134                 return 0;
135
136         devpath_to_db_path(udevice->udev, udevice->dev->devpath, filename, sizeof(filename));
137         create_path(udevice->udev, filename);
138         unlink(filename);
139
140         /*
141          * don't waste tmpfs memory pages, if we don't have any data to store
142          * create fake db-file; store the node-name in a symlink target
143          */
144         if (list_empty(&udevice->symlink_list) && list_empty(&udevice->env_list) &&
145             !udevice->partitions && !udevice->ignore_remove) {
146                 int ret;
147                 dbg(udevice->udev, "nothing interesting to store, create symlink\n");
148                 udev_selinux_setfscreatecon(udevice->udev, filename, S_IFLNK);
149                 ret = symlink(udevice->name, filename);
150                 udev_selinux_resetfscreatecon(udevice->udev);
151                 if (ret != 0) {
152                         err(udevice->udev, "unable to create db link '%s': %s\n", filename, strerror(errno));
153                         return -1;
154                 }
155         } else {
156                 FILE *f;
157                 struct name_entry *name_loop;
158
159                 f = fopen(filename, "w");
160                 if (f == NULL) {
161                         err(udevice->udev, "unable to create db file '%s': %s\n", filename, strerror(errno));
162                         return -1;
163                 }
164                 dbg(udevice->udev, "storing data for device '%s' in '%s'\n", udevice->dev->devpath, filename);
165
166                 fprintf(f, "N:%s\n", udevice->name);
167                 list_for_each_entry(name_loop, &udevice->symlink_list, node) {
168                         fprintf(f, "S:%s\n", name_loop->name);
169                         /* add symlink-name to index */
170                         name_index(udevice->udev, udevice->dev->devpath, name_loop->name, 1);
171                 }
172                 fprintf(f, "M:%u:%u\n", major(udevice->devt), minor(udevice->devt));
173                 if (udevice->link_priority != 0)
174                         fprintf(f, "L:%u\n", udevice->link_priority);
175                 if (udevice->event_timeout >= 0)
176                         fprintf(f, "T:%u\n", udevice->event_timeout);
177                 if (udevice->partitions != 0)
178                         fprintf(f, "A:%u\n", udevice->partitions);
179                 if (udevice->ignore_remove)
180                         fprintf(f, "R:%u\n", udevice->ignore_remove);
181                 list_for_each_entry(name_loop, &udevice->env_list, node)
182                         fprintf(f, "E:%s\n", name_loop->name);
183                 fclose(f);
184         }
185
186         /* add name to index */
187         name_index(udevice->udev, udevice->dev->devpath, udevice->name, 1);
188
189         return 0;
190 }
191
192 int udev_db_get_device(struct udevice *udevice, const char *devpath)
193 {
194         struct stat stats;
195         char filename[PATH_SIZE];
196         char line[PATH_SIZE];
197         unsigned int maj, min;
198         char *bufline;
199         char *buf;
200         size_t bufsize;
201         size_t cur;
202         size_t count;
203
204         sysfs_device_set_values(udevice->udev, udevice->dev, devpath, NULL, NULL);
205         devpath_to_db_path(udevice->udev, devpath, filename, sizeof(filename));
206
207         if (lstat(filename, &stats) != 0) {
208                 info(udevice->udev, "no db file to read %s: %s\n", filename, strerror(errno));
209                 return -1;
210         }
211         if ((stats.st_mode & S_IFMT) == S_IFLNK) {
212                 char target[NAME_SIZE];
213                 int target_len;
214
215                 info(udevice->udev, "found a symlink as db file\n");
216                 target_len = readlink(filename, target, sizeof(target));
217                 if (target_len > 0)
218                         target[target_len] = '\0';
219                 else {
220                         info(udevice->udev, "error reading db link %s: %s\n", filename, strerror(errno));
221                         return -1;
222                 }
223                 dbg(udevice->udev, "db link points to '%s'\n", target);
224                 strlcpy(udevice->name, target, sizeof(udevice->name));
225                 return 0;
226         }
227
228         if (file_map(filename, &buf, &bufsize) != 0) {
229                 info(udevice->udev, "error reading db file %s: %s\n", filename, strerror(errno));
230                 return -1;
231         }
232
233         cur = 0;
234         while (cur < bufsize) {
235                 count = buf_get_line(buf, bufsize, cur);
236                 bufline = &buf[cur];
237                 cur += count+1;
238
239                 if (count > sizeof(line))
240                         count = sizeof(line);
241                 memcpy(line, &bufline[2], count-2);
242                 line[count-2] = '\0';
243
244                 switch(bufline[0]) {
245                 case 'N':
246                         strlcpy(udevice->name, line, sizeof(udevice->name));
247                         break;
248                 case 'M':
249                         sscanf(line, "%u:%u", &maj, &min);
250                         udevice->devt = makedev(maj, min);
251                         break;
252                 case 'S':
253                         name_list_add(udevice->udev, &udevice->symlink_list, line, 0);
254                         break;
255                 case 'L':
256                         udevice->link_priority = atoi(line);
257                         break;
258                 case 'T':
259                         udevice->event_timeout = atoi(line);
260                         break;
261                 case 'A':
262                         udevice->partitions = atoi(line);
263                         break;
264                 case 'R':
265                         udevice->ignore_remove = atoi(line);
266                         break;
267                 case 'E':
268                         name_list_add(udevice->udev, &udevice->env_list, line, 0);
269                         break;
270                 }
271         }
272         file_unmap(buf, bufsize);
273
274         if (udevice->name[0] == '\0')
275                 return -1;
276
277         return 0;
278 }
279
280 int udev_db_delete_device(struct udevice *udevice)
281 {
282         char filename[PATH_SIZE];
283         struct name_entry *name_loop;
284
285         if (udevice->test_run)
286                 return 0;
287
288         devpath_to_db_path(udevice->udev, udevice->dev->devpath, filename, sizeof(filename));
289         unlink(filename);
290
291         name_index(udevice->udev, udevice->dev->devpath, udevice->name, 0);
292         list_for_each_entry(name_loop, &udevice->symlink_list, node)
293                 name_index(udevice->udev, udevice->dev->devpath, name_loop->name, 0);
294
295         return 0;
296 }
297
298 int udev_db_get_all_entries(struct udev *udev, struct list_head *name_list)
299 {
300         char dbpath[PATH_MAX];
301         DIR *dir;
302
303         strlcpy(dbpath, udev_get_dev_path(udev), sizeof(dbpath));
304         strlcat(dbpath, "/.udev/db", sizeof(dbpath));
305         dir = opendir(dbpath);
306         if (dir == NULL) {
307                 info(udev, "no udev_db available '%s': %s\n", dbpath, strerror(errno));
308                 return -1;
309         }
310
311         while (1) {
312                 struct dirent *ent;
313                 char device[PATH_SIZE];
314
315                 ent = readdir(dir);
316                 if (ent == NULL || ent->d_name[0] == '\0')
317                         break;
318                 if (ent->d_name[0] == '.')
319                         continue;
320
321                 strlcpy(device, ent->d_name, sizeof(device));
322                 path_decode(device);
323                 name_list_add(udev, name_list, device, 1);
324                 dbg(udev, "added '%s'\n", device);
325         }
326
327         closedir(dir);
328         return 0;
329 }