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