]>
Commit | Line | Data |
---|---|---|
88a6477e KS |
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 | ***/ | |
33a5cc29 | 19 | |
33a5cc29 KS |
20 | #include <stdio.h> |
21 | #include <stdlib.h> | |
22 | #include <stddef.h> | |
4cf23685 | 23 | #include <stdarg.h> |
33a5cc29 KS |
24 | #include <unistd.h> |
25 | #include <errno.h> | |
26 | #include <string.h> | |
7d563a17 | 27 | #include <ctype.h> |
4f1795cc | 28 | #include <time.h> |
33a5cc29 KS |
29 | |
30 | #include "libudev.h" | |
31 | #include "libudev-private.h" | |
4db17f29 | 32 | #include "missing.h" |
33a5cc29 | 33 | |
ce1d6d7f KS |
34 | /** |
35 | * SECTION:libudev | |
36 | * @short_description: libudev context | |
37 | * | |
38 | * The context contains the default values read from the udev config file, | |
39 | * and is passed to all library operations. | |
40 | */ | |
41 | ||
1e511322 KS |
42 | /** |
43 | * udev: | |
44 | * | |
ce1d6d7f | 45 | * Opaque object representing the library context. |
1e511322 | 46 | */ |
ba6929f6 | 47 | struct udev { |
912541b0 KS |
48 | int refcount; |
49 | void (*log_fn)(struct udev *udev, | |
50 | int priority, const char *file, int line, const char *fn, | |
51 | const char *format, va_list args); | |
52 | void *userdata; | |
912541b0 KS |
53 | struct udev_list properties_list; |
54 | int log_priority; | |
ba6929f6 KS |
55 | }; |
56 | ||
33a5cc29 | 57 | void udev_log(struct udev *udev, |
912541b0 KS |
58 | int priority, const char *file, int line, const char *fn, |
59 | const char *format, ...) | |
33a5cc29 | 60 | { |
912541b0 | 61 | va_list args; |
33a5cc29 | 62 | |
912541b0 KS |
63 | va_start(args, format); |
64 | udev->log_fn(udev, priority, file, line, fn, format, args); | |
65 | va_end(args); | |
33a5cc29 KS |
66 | } |
67 | ||
9091e686 | 68 | _printf_(6,0) |
33a5cc29 | 69 | static void log_stderr(struct udev *udev, |
912541b0 KS |
70 | int priority, const char *file, int line, const char *fn, |
71 | const char *format, va_list args) | |
33a5cc29 | 72 | { |
912541b0 KS |
73 | fprintf(stderr, "libudev: %s: ", fn); |
74 | vfprintf(stderr, format, args); | |
33a5cc29 | 75 | } |
33a5cc29 | 76 | |
1e511322 KS |
77 | /** |
78 | * udev_get_userdata: | |
79 | * @udev: udev library context | |
80 | * | |
81 | * Retrieve stored data pointer from library context. This might be useful | |
dbba7e40 | 82 | * to access from callbacks like a custom logging function. |
1e511322 KS |
83 | * |
84 | * Returns: stored userdata | |
85 | **/ | |
54cf0b7f | 86 | _public_ void *udev_get_userdata(struct udev *udev) |
c8e32461 | 87 | { |
912541b0 KS |
88 | if (udev == NULL) |
89 | return NULL; | |
90 | return udev->userdata; | |
c8e32461 KS |
91 | } |
92 | ||
1e511322 KS |
93 | /** |
94 | * udev_set_userdata: | |
95 | * @udev: udev library context | |
96 | * @userdata: data pointer | |
97 | * | |
98 | * Store custom @userdata in the library context. | |
99 | **/ | |
54cf0b7f | 100 | _public_ void udev_set_userdata(struct udev *udev, void *userdata) |
c8e32461 | 101 | { |
912541b0 KS |
102 | if (udev == NULL) |
103 | return; | |
104 | udev->userdata = userdata; | |
c8e32461 KS |
105 | } |
106 | ||
33a5cc29 KS |
107 | /** |
108 | * udev_new: | |
109 | * | |
1e511322 KS |
110 | * Create udev library context. This reads the udev configuration |
111 | * file, and fills in the default values. | |
33a5cc29 KS |
112 | * |
113 | * The initial refcount is 1, and needs to be decremented to | |
be7de409 | 114 | * release the resources of the udev library context. |
33a5cc29 KS |
115 | * |
116 | * Returns: a new udev library context | |
117 | **/ | |
54cf0b7f | 118 | _public_ struct udev *udev_new(void) |
33a5cc29 | 119 | { |
912541b0 KS |
120 | struct udev *udev; |
121 | const char *env; | |
fe756ed9 | 122 | _cleanup_free_ FILE *f = NULL; |
912541b0 | 123 | |
955d98c9 | 124 | udev = new0(struct udev, 1); |
912541b0 KS |
125 | if (udev == NULL) |
126 | return NULL; | |
127 | udev->refcount = 1; | |
128 | udev->log_fn = log_stderr; | |
2004d23a | 129 | udev->log_priority = LOG_INFO; |
912541b0 KS |
130 | udev_list_init(udev, &udev->properties_list, true); |
131 | ||
ff944daa | 132 | f = fopen("/etc/udev/udev.conf", "re"); |
912541b0 KS |
133 | if (f != NULL) { |
134 | char line[UTIL_LINE_SIZE]; | |
fe756ed9 | 135 | unsigned line_nr = 0; |
912541b0 KS |
136 | |
137 | while (fgets(line, sizeof(line), f)) { | |
138 | size_t len; | |
139 | char *key; | |
140 | char *val; | |
141 | ||
142 | line_nr++; | |
143 | ||
144 | /* find key */ | |
145 | key = line; | |
146 | while (isspace(key[0])) | |
147 | key++; | |
148 | ||
149 | /* comment or empty line */ | |
150 | if (key[0] == '#' || key[0] == '\0') | |
151 | continue; | |
152 | ||
153 | /* split key/value */ | |
154 | val = strchr(key, '='); | |
155 | if (val == NULL) { | |
fe756ed9 | 156 | udev_err(udev, "/etc/udev/udev.conf:%u: missing assignment, skipping line.\n", line_nr); |
912541b0 KS |
157 | continue; |
158 | } | |
159 | val[0] = '\0'; | |
160 | val++; | |
161 | ||
162 | /* find value */ | |
163 | while (isspace(val[0])) | |
164 | val++; | |
165 | ||
166 | /* terminate key */ | |
167 | len = strlen(key); | |
168 | if (len == 0) | |
169 | continue; | |
170 | while (isspace(key[len-1])) | |
171 | len--; | |
172 | key[len] = '\0'; | |
173 | ||
174 | /* terminate value */ | |
175 | len = strlen(val); | |
176 | if (len == 0) | |
177 | continue; | |
178 | while (isspace(val[len-1])) | |
179 | len--; | |
180 | val[len] = '\0'; | |
181 | ||
182 | if (len == 0) | |
183 | continue; | |
184 | ||
185 | /* unquote */ | |
186 | if (val[0] == '"' || val[0] == '\'') { | |
187 | if (val[len-1] != val[0]) { | |
fe756ed9 | 188 | udev_err(udev, "/etc/udev/udev.conf:%u: inconsistent quoting, skipping line.\n", line_nr); |
912541b0 KS |
189 | continue; |
190 | } | |
191 | val[len-1] = '\0'; | |
192 | val++; | |
193 | } | |
194 | ||
090be865 | 195 | if (streq(key, "udev_log")) { |
ee7122c0 ZJS |
196 | int prio; |
197 | ||
198 | prio = util_log_priority(val); | |
199 | if (prio < 0) | |
200 | udev_err(udev, "/etc/udev/udev.conf:%u: invalid logging level '%s', ignoring.\n", line_nr, val); | |
201 | else | |
202 | udev_set_log_priority(udev, prio); | |
912541b0 KS |
203 | continue; |
204 | } | |
912541b0 | 205 | } |
912541b0 KS |
206 | } |
207 | ||
91418155 | 208 | /* environment overrides config */ |
4db17f29 | 209 | env = secure_getenv("UDEV_LOG"); |
ee7122c0 ZJS |
210 | if (env != NULL) { |
211 | int prio; | |
212 | ||
213 | prio = util_log_priority(env); | |
214 | if (prio < 0) | |
215 | udev_err(udev, "$UDEV_LOG specifies invalid logging level '%s', ignoring.\n", env); | |
216 | else | |
217 | udev_set_log_priority(udev, prio); | |
218 | } | |
912541b0 | 219 | |
912541b0 | 220 | return udev; |
33a5cc29 KS |
221 | } |
222 | ||
223 | /** | |
224 | * udev_ref: | |
225 | * @udev: udev library context | |
226 | * | |
227 | * Take a reference of the udev library context. | |
228 | * | |
229 | * Returns: the passed udev library context | |
230 | **/ | |
54cf0b7f | 231 | _public_ struct udev *udev_ref(struct udev *udev) |
33a5cc29 | 232 | { |
912541b0 KS |
233 | if (udev == NULL) |
234 | return NULL; | |
235 | udev->refcount++; | |
236 | return udev; | |
33a5cc29 KS |
237 | } |
238 | ||
239 | /** | |
240 | * udev_unref: | |
241 | * @udev: udev library context | |
242 | * | |
243 | * Drop a reference of the udev library context. If the refcount | |
be7de409 | 244 | * reaches zero, the resources of the context will be released. |
33a5cc29 | 245 | * |
c1959569 | 246 | * Returns: the passed udev library context if it has still an active reference, or #NULL otherwise. |
33a5cc29 | 247 | **/ |
20bbd54f | 248 | _public_ struct udev *udev_unref(struct udev *udev) |
33a5cc29 | 249 | { |
912541b0 | 250 | if (udev == NULL) |
20bbd54f | 251 | return NULL; |
912541b0 KS |
252 | udev->refcount--; |
253 | if (udev->refcount > 0) | |
20bbd54f | 254 | return udev; |
912541b0 | 255 | udev_list_cleanup(&udev->properties_list); |
912541b0 | 256 | free(udev); |
20bbd54f | 257 | return NULL; |
33a5cc29 KS |
258 | } |
259 | ||
260 | /** | |
261 | * udev_set_log_fn: | |
262 | * @udev: udev library context | |
263 | * @log_fn: function to be called for logging messages | |
264 | * | |
be7de409 | 265 | * The built-in logging writes to stderr. It can be |
33a5cc29 | 266 | * overridden by a custom function, to plug log messages |
be7de409 | 267 | * into the users' logging functionality. |
33a5cc29 KS |
268 | * |
269 | **/ | |
54cf0b7f | 270 | _public_ void udev_set_log_fn(struct udev *udev, |
912541b0 KS |
271 | void (*log_fn)(struct udev *udev, |
272 | int priority, const char *file, int line, const char *fn, | |
273 | const char *format, va_list args)) | |
33a5cc29 | 274 | { |
912541b0 | 275 | udev->log_fn = log_fn; |
c8f8394a | 276 | udev_dbg(udev, "custom logging function %p registered\n", log_fn); |
7d563a17 KS |
277 | } |
278 | ||
1e511322 KS |
279 | /** |
280 | * udev_get_log_priority: | |
281 | * @udev: udev library context | |
282 | * | |
dbba7e40 | 283 | * The initial logging priority is read from the udev config file |
1e511322 KS |
284 | * at startup. |
285 | * | |
dbba7e40 | 286 | * Returns: the current logging priority |
1e511322 | 287 | **/ |
54cf0b7f | 288 | _public_ int udev_get_log_priority(struct udev *udev) |
7d563a17 | 289 | { |
912541b0 | 290 | return udev->log_priority; |
7d563a17 KS |
291 | } |
292 | ||
1e511322 KS |
293 | /** |
294 | * udev_set_log_priority: | |
295 | * @udev: udev library context | |
dbba7e40 | 296 | * @priority: the new logging priority |
1e511322 | 297 | * |
dbba7e40 KS |
298 | * Set the current logging priority. The value controls which messages |
299 | * are logged. | |
1e511322 | 300 | **/ |
54cf0b7f | 301 | _public_ void udev_set_log_priority(struct udev *udev, int priority) |
7d563a17 | 302 | { |
912541b0 | 303 | char num[32]; |
f183b6ed | 304 | |
912541b0 KS |
305 | udev->log_priority = priority; |
306 | snprintf(num, sizeof(num), "%u", udev->log_priority); | |
307 | udev_add_property(udev, "UDEV_LOG", num); | |
7d563a17 KS |
308 | } |
309 | ||
f183b6ed KS |
310 | struct udev_list_entry *udev_add_property(struct udev *udev, const char *key, const char *value) |
311 | { | |
912541b0 KS |
312 | if (value == NULL) { |
313 | struct udev_list_entry *list_entry; | |
314 | ||
315 | list_entry = udev_get_properties_list_entry(udev); | |
316 | list_entry = udev_list_entry_get_by_name(list_entry, key); | |
317 | if (list_entry != NULL) | |
318 | udev_list_entry_delete(list_entry); | |
319 | return NULL; | |
320 | } | |
321 | return udev_list_entry_add(&udev->properties_list, key, value); | |
f183b6ed KS |
322 | } |
323 | ||
324 | struct udev_list_entry *udev_get_properties_list_entry(struct udev *udev) | |
325 | { | |
912541b0 | 326 | return udev_list_get_entry(&udev->properties_list); |
f183b6ed | 327 | } |