]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/libudev/libudev.c
build-sys: __secure_getenv lost dunder in libc 2.17
[thirdparty/systemd.git] / src / libudev / libudev.c
1 /*
2 * libudev - interface to udev device information
3 *
4 * Copyright (C) 2008-2010 Kay Sievers <kay.sievers@vrfy.org>
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 */
11
12 #include <stdio.h>
13 #include <stdlib.h>
14 #include <stddef.h>
15 #include <stdarg.h>
16 #include <unistd.h>
17 #include <errno.h>
18 #include <string.h>
19 #include <ctype.h>
20 #include <time.h>
21
22 #include "libudev.h"
23 #include "libudev-private.h"
24 #include "missing.h"
25
26 /**
27 * SECTION:libudev
28 * @short_description: libudev context
29 *
30 * The context contains the default values read from the udev config file,
31 * and is passed to all library operations.
32 */
33
34 /**
35 * udev:
36 *
37 * Opaque object representing the library context.
38 */
39 struct udev {
40 int refcount;
41 void (*log_fn)(struct udev *udev,
42 int priority, const char *file, int line, const char *fn,
43 const char *format, va_list args);
44 void *userdata;
45 struct udev_list properties_list;
46 int log_priority;
47 };
48
49 void udev_log(struct udev *udev,
50 int priority, const char *file, int line, const char *fn,
51 const char *format, ...)
52 {
53 va_list args;
54
55 va_start(args, format);
56 udev->log_fn(udev, priority, file, line, fn, format, args);
57 va_end(args);
58 }
59
60 static void log_stderr(struct udev *udev,
61 int priority, const char *file, int line, const char *fn,
62 const char *format, va_list args)
63 {
64 fprintf(stderr, "libudev: %s: ", fn);
65 vfprintf(stderr, format, args);
66 }
67
68 /**
69 * udev_get_userdata:
70 * @udev: udev library context
71 *
72 * Retrieve stored data pointer from library context. This might be useful
73 * to access from callbacks like a custom logging function.
74 *
75 * Returns: stored userdata
76 **/
77 _public_ void *udev_get_userdata(struct udev *udev)
78 {
79 if (udev == NULL)
80 return NULL;
81 return udev->userdata;
82 }
83
84 /**
85 * udev_set_userdata:
86 * @udev: udev library context
87 * @userdata: data pointer
88 *
89 * Store custom @userdata in the library context.
90 **/
91 _public_ void udev_set_userdata(struct udev *udev, void *userdata)
92 {
93 if (udev == NULL)
94 return;
95 udev->userdata = userdata;
96 }
97
98 /**
99 * udev_new:
100 *
101 * Create udev library context. This reads the udev configuration
102 * file, and fills in the default values.
103 *
104 * The initial refcount is 1, and needs to be decremented to
105 * release the resources of the udev library context.
106 *
107 * Returns: a new udev library context
108 **/
109 _public_ struct udev *udev_new(void)
110 {
111 struct udev *udev;
112 const char *env;
113 FILE *f;
114
115 udev = calloc(1, sizeof(struct udev));
116 if (udev == NULL)
117 return NULL;
118 udev->refcount = 1;
119 udev->log_fn = log_stderr;
120 udev->log_priority = LOG_ERR;
121 udev_list_init(udev, &udev->properties_list, true);
122
123 f = fopen(SYSCONFDIR "/udev/udev.conf", "re");
124 if (f != NULL) {
125 char line[UTIL_LINE_SIZE];
126 int line_nr = 0;
127
128 while (fgets(line, sizeof(line), f)) {
129 size_t len;
130 char *key;
131 char *val;
132
133 line_nr++;
134
135 /* find key */
136 key = line;
137 while (isspace(key[0]))
138 key++;
139
140 /* comment or empty line */
141 if (key[0] == '#' || key[0] == '\0')
142 continue;
143
144 /* split key/value */
145 val = strchr(key, '=');
146 if (val == NULL) {
147 udev_err(udev, "missing <key>=<value> in " SYSCONFDIR "/udev/udev.conf[%i]; skip line\n", line_nr);
148 continue;
149 }
150 val[0] = '\0';
151 val++;
152
153 /* find value */
154 while (isspace(val[0]))
155 val++;
156
157 /* terminate key */
158 len = strlen(key);
159 if (len == 0)
160 continue;
161 while (isspace(key[len-1]))
162 len--;
163 key[len] = '\0';
164
165 /* terminate value */
166 len = strlen(val);
167 if (len == 0)
168 continue;
169 while (isspace(val[len-1]))
170 len--;
171 val[len] = '\0';
172
173 if (len == 0)
174 continue;
175
176 /* unquote */
177 if (val[0] == '"' || val[0] == '\'') {
178 if (val[len-1] != val[0]) {
179 udev_err(udev, "inconsistent quoting in " SYSCONFDIR "/udev/udev.conf[%i]; skip line\n", line_nr);
180 continue;
181 }
182 val[len-1] = '\0';
183 val++;
184 }
185
186 if (strcmp(key, "udev_log") == 0) {
187 udev_set_log_priority(udev, util_log_priority(val));
188 continue;
189 }
190 }
191 fclose(f);
192 }
193
194 /* environment overrides config */
195 env = secure_getenv("UDEV_LOG");
196 if (env != NULL)
197 udev_set_log_priority(udev, util_log_priority(env));
198
199 return udev;
200 }
201
202 /**
203 * udev_ref:
204 * @udev: udev library context
205 *
206 * Take a reference of the udev library context.
207 *
208 * Returns: the passed udev library context
209 **/
210 _public_ struct udev *udev_ref(struct udev *udev)
211 {
212 if (udev == NULL)
213 return NULL;
214 udev->refcount++;
215 return udev;
216 }
217
218 /**
219 * udev_unref:
220 * @udev: udev library context
221 *
222 * Drop a reference of the udev library context. If the refcount
223 * reaches zero, the resources of the context will be released.
224 *
225 * Returns: the passed udev library context if it has still an active reference, or #NULL otherwise.
226 **/
227 _public_ struct udev *udev_unref(struct udev *udev)
228 {
229 if (udev == NULL)
230 return NULL;
231 udev->refcount--;
232 if (udev->refcount > 0)
233 return udev;
234 udev_list_cleanup(&udev->properties_list);
235 free(udev);
236 return NULL;
237 }
238
239 /**
240 * udev_set_log_fn:
241 * @udev: udev library context
242 * @log_fn: function to be called for logging messages
243 *
244 * The built-in logging writes to stderr. It can be
245 * overridden by a custom function, to plug log messages
246 * into the users' logging functionality.
247 *
248 **/
249 _public_ void udev_set_log_fn(struct udev *udev,
250 void (*log_fn)(struct udev *udev,
251 int priority, const char *file, int line, const char *fn,
252 const char *format, va_list args))
253 {
254 udev->log_fn = log_fn;
255 udev_dbg(udev, "custom logging function %p registered\n", log_fn);
256 }
257
258 /**
259 * udev_get_log_priority:
260 * @udev: udev library context
261 *
262 * The initial logging priority is read from the udev config file
263 * at startup.
264 *
265 * Returns: the current logging priority
266 **/
267 _public_ int udev_get_log_priority(struct udev *udev)
268 {
269 return udev->log_priority;
270 }
271
272 /**
273 * udev_set_log_priority:
274 * @udev: udev library context
275 * @priority: the new logging priority
276 *
277 * Set the current logging priority. The value controls which messages
278 * are logged.
279 **/
280 _public_ void udev_set_log_priority(struct udev *udev, int priority)
281 {
282 char num[32];
283
284 udev->log_priority = priority;
285 snprintf(num, sizeof(num), "%u", udev->log_priority);
286 udev_add_property(udev, "UDEV_LOG", num);
287 }
288
289 struct udev_list_entry *udev_add_property(struct udev *udev, const char *key, const char *value)
290 {
291 if (value == NULL) {
292 struct udev_list_entry *list_entry;
293
294 list_entry = udev_get_properties_list_entry(udev);
295 list_entry = udev_list_entry_get_by_name(list_entry, key);
296 if (list_entry != NULL)
297 udev_list_entry_delete(list_entry);
298 return NULL;
299 }
300 return udev_list_entry_add(&udev->properties_list, key, value);
301 }
302
303 struct udev_list_entry *udev_get_properties_list_entry(struct udev *udev)
304 {
305 return udev_list_get_entry(&udev->properties_list);
306 }