chiark / gitweb /
remove unused includes
[elogind.git] / src / libudev / libudev-device-private.c
1 /***
2   This file is part of systemd.
3
4   Copyright 2008-2012 Kay Sievers <kay@vrfy.org>
5
6   systemd is free software; you can redistribute it and/or modify it
7   under the terms of the GNU Lesser General Public License as published by
8   the Free Software Foundation; either version 2.1 of the License, or
9   (at your option) any later version.
10
11   systemd 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   Lesser General Public License for more details.
15
16   You should have received a copy of the GNU Lesser General Public License
17   along with systemd; If not, see <http://www.gnu.org/licenses/>.
18 ***/
19
20 #include <stdio.h>
21 #include <string.h>
22 #include <stddef.h>
23 #include <stdbool.h>
24 #include <unistd.h>
25 #include <fcntl.h>
26 #include <sys/stat.h>
27
28 #include "libudev.h"
29 #include "libudev-private.h"
30
31 static void udev_device_tag(struct udev_device *dev, const char *tag, bool add)
32 {
33         const char *id;
34         char filename[UTIL_PATH_SIZE];
35
36         id = udev_device_get_id_filename(dev);
37         if (id == NULL)
38                 return;
39         strscpyl(filename, sizeof(filename), "/run/udev/tags/", tag, "/", id, NULL);
40
41         if (add) {
42                 int fd;
43
44                 mkdir_parents(filename, 0755);
45                 fd = open(filename, O_WRONLY|O_CREAT|O_CLOEXEC|O_TRUNC|O_NOFOLLOW, 0444);
46                 if (fd >= 0)
47                         close(fd);
48         } else {
49                 unlink(filename);
50         }
51 }
52
53 int udev_device_tag_index(struct udev_device *dev, struct udev_device *dev_old, bool add)
54 {
55         struct udev_list_entry *list_entry;
56         bool found;
57
58         if (add && dev_old != NULL) {
59                 /* delete possible left-over tags */
60                 udev_list_entry_foreach(list_entry, udev_device_get_tags_list_entry(dev_old)) {
61                         const char *tag_old = udev_list_entry_get_name(list_entry);
62                         struct udev_list_entry *list_entry_current;
63
64                         found = false;
65                         udev_list_entry_foreach(list_entry_current, udev_device_get_tags_list_entry(dev)) {
66                                 const char *tag = udev_list_entry_get_name(list_entry_current);
67
68                                 if (streq(tag, tag_old)) {
69                                         found = true;
70                                         break;
71                                 }
72                         }
73                         if (!found)
74                                 udev_device_tag(dev_old, tag_old, false);
75                 }
76         }
77
78         udev_list_entry_foreach(list_entry, udev_device_get_tags_list_entry(dev))
79                 udev_device_tag(dev, udev_list_entry_get_name(list_entry), add);
80
81         return 0;
82 }
83
84 static bool device_has_info(struct udev_device *udev_device)
85 {
86         struct udev_list_entry *list_entry;
87
88         if (udev_device_get_devlinks_list_entry(udev_device) != NULL)
89                 return true;
90         if (udev_device_get_devlink_priority(udev_device) != 0)
91                 return true;
92         udev_list_entry_foreach(list_entry, udev_device_get_properties_list_entry(udev_device))
93                 if (udev_list_entry_get_num(list_entry))
94                         return true;
95         if (udev_device_get_tags_list_entry(udev_device) != NULL)
96                 return true;
97         if (udev_device_get_watch_handle(udev_device) >= 0)
98                 return true;
99         return false;
100 }
101
102 int udev_device_update_db(struct udev_device *udev_device)
103 {
104         bool has_info;
105         const char *id;
106         char filename[UTIL_PATH_SIZE];
107         char filename_tmp[UTIL_PATH_SIZE];
108         FILE *f;
109         int r;
110
111         id = udev_device_get_id_filename(udev_device);
112         if (id == NULL)
113                 return -1;
114
115         has_info = device_has_info(udev_device);
116         strscpyl(filename, sizeof(filename), "/run/udev/data/", id, NULL);
117
118         /* do not store anything for otherwise empty devices */
119         if (!has_info &&
120             major(udev_device_get_devnum(udev_device)) == 0 &&
121             udev_device_get_ifindex(udev_device) == 0) {
122                 unlink(filename);
123                 return 0;
124         }
125
126         /* write a database file */
127         strscpyl(filename_tmp, sizeof(filename_tmp), filename, ".tmp", NULL);
128         mkdir_parents(filename_tmp, 0755);
129         f = fopen(filename_tmp, "we");
130         if (f == NULL)
131                 return log_debug_errno(errno, "unable to create temporary db file '%s': %m", filename_tmp);
132
133         /*
134          * set 'sticky' bit to indicate that we should not clean the
135          * database when we transition from initramfs to the real root
136          */
137         if (udev_device_get_db_persist(udev_device))
138                 fchmod(fileno(f), 01644);
139
140         if (has_info) {
141                 struct udev_list_entry *list_entry;
142
143                 if (major(udev_device_get_devnum(udev_device)) > 0) {
144                         udev_list_entry_foreach(list_entry, udev_device_get_devlinks_list_entry(udev_device))
145                                 fprintf(f, "S:%s\n", udev_list_entry_get_name(list_entry) + strlen("/dev/"));
146                         if (udev_device_get_devlink_priority(udev_device) != 0)
147                                 fprintf(f, "L:%i\n", udev_device_get_devlink_priority(udev_device));
148                         if (udev_device_get_watch_handle(udev_device) >= 0)
149                                 fprintf(f, "W:%i\n", udev_device_get_watch_handle(udev_device));
150                 }
151
152                 if (udev_device_get_usec_initialized(udev_device) > 0)
153                         fprintf(f, "I:"USEC_FMT"\n", udev_device_get_usec_initialized(udev_device));
154
155                 udev_list_entry_foreach(list_entry, udev_device_get_properties_list_entry(udev_device)) {
156                         if (!udev_list_entry_get_num(list_entry))
157                                 continue;
158                         fprintf(f, "E:%s=%s\n",
159                                 udev_list_entry_get_name(list_entry),
160                                 udev_list_entry_get_value(list_entry));
161                 }
162
163                 udev_list_entry_foreach(list_entry, udev_device_get_tags_list_entry(udev_device))
164                         fprintf(f, "G:%s\n", udev_list_entry_get_name(list_entry));
165         }
166
167         fclose(f);
168         r = rename(filename_tmp, filename);
169         if (r < 0)
170                 return -1;
171         log_debug("created %s file '%s' for '%s'", has_info ? "db" : "empty",
172              filename, udev_device_get_devpath(udev_device));
173         return 0;
174 }
175
176 int udev_device_delete_db(struct udev_device *udev_device)
177 {
178         const char *id;
179         char filename[UTIL_PATH_SIZE];
180
181         id = udev_device_get_id_filename(udev_device);
182         if (id == NULL)
183                 return -1;
184         strscpyl(filename, sizeof(filename), "/run/udev/data/", id, NULL);
185         unlink(filename);
186         return 0;
187 }