]> git.ipfire.org Git - thirdparty/systemd.git/blame - libudev/libudev.c
libudev: add gtk-doc
[thirdparty/systemd.git] / libudev / libudev.c
CommitLineData
33a5cc29
KS
1/*
2 * libudev - interface to udev device information
3 *
4 * Copyright (C) 2008 Kay Sievers <kay.sievers@vrfy.org>
5 *
4061ab9f
KS
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.
33a5cc29
KS
10 */
11
33a5cc29
KS
12#include <stdio.h>
13#include <stdlib.h>
14#include <stddef.h>
4cf23685 15#include <stdarg.h>
33a5cc29
KS
16#include <unistd.h>
17#include <errno.h>
18#include <string.h>
7d563a17 19#include <ctype.h>
33a5cc29
KS
20
21#include "libudev.h"
22#include "libudev-private.h"
33a5cc29 23
ba6929f6
KS
24struct udev {
25 int refcount;
26 void (*log_fn)(struct udev *udev,
27 int priority, const char *file, int line, const char *fn,
28 const char *format, va_list args);
c8e32461 29 void *userdata;
7d563a17
KS
30 char *sys_path;
31 char *dev_path;
32 char *rules_path;
f183b6ed 33 struct udev_list_node properties_list;
7d563a17 34 int log_priority;
6bd1c78a 35 int run;
ba6929f6
KS
36};
37
33a5cc29
KS
38void udev_log(struct udev *udev,
39 int priority, const char *file, int line, const char *fn,
40 const char *format, ...)
41{
42 va_list args;
43
44 va_start(args, format);
45 udev->log_fn(udev, priority, file, line, fn, format, args);
46 va_end(args);
47}
48
49static void log_stderr(struct udev *udev,
50 int priority, const char *file, int line, const char *fn,
51 const char *format, va_list args)
52{
7d563a17
KS
53 fprintf(stderr, "libudev: %s: ", fn);
54 vfprintf(stderr, format, args);
33a5cc29 55}
33a5cc29 56
c8e32461
KS
57void *udev_get_userdata(struct udev *udev)
58{
59 if (udev == NULL)
60 return NULL;
61 return udev->userdata;
62}
63
64void udev_set_userdata(struct udev *udev, void *userdata)
65{
66 if (udev == NULL)
67 return;
68 udev->userdata = userdata;
69}
70
33a5cc29
KS
71/**
72 * udev_new:
73 *
74 * Create udev library context.
75 *
76 * The initial refcount is 1, and needs to be decremented to
be7de409 77 * release the resources of the udev library context.
33a5cc29
KS
78 *
79 * Returns: a new udev library context
80 **/
81struct udev *udev_new(void)
82{
83 struct udev *udev;
7d563a17
KS
84 const char *env;
85 char *config_file;
86 FILE *f;
33a5cc29 87
b29a5e4a 88 udev = calloc(1, sizeof(struct udev));
33a5cc29
KS
89 if (udev == NULL)
90 return NULL;
33a5cc29
KS
91 udev->refcount = 1;
92 udev->log_fn = log_stderr;
7d563a17 93 udev->log_priority = LOG_ERR;
f183b6ed 94 udev_list_init(&udev->properties_list);
7d563a17
KS
95 udev->run = 1;
96 udev->dev_path = strdup(UDEV_PREFIX "/dev");
97 udev->sys_path = strdup("/sys");
98 config_file = strdup(SYSCONFDIR "/udev/udev.conf");
a035bf27
KS
99 if (udev->dev_path == NULL ||
100 udev->sys_path == NULL ||
101 config_file == NULL)
7d563a17
KS
102 goto err;
103
104 /* settings by environment and config file */
105 env = getenv("SYSFS_PATH");
106 if (env != NULL) {
107 free(udev->sys_path);
108 udev->sys_path = strdup(env);
7a01f11a 109 util_remove_trailing_chars(udev->sys_path, '/');
f183b6ed 110 udev_add_property(udev, "SYSFS_PATH", udev->sys_path);
7d563a17
KS
111 }
112
113 env = getenv("UDEV_RUN");
7a01f11a 114 if (env != NULL && strcmp(env, "0") == 0)
7d563a17
KS
115 udev->run = 0;
116
117 env = getenv("UDEV_CONFIG_FILE");
118 if (env != NULL) {
119 free(config_file);
120 config_file = strdup(env);
7a01f11a 121 util_remove_trailing_chars(config_file, '/');
7d563a17
KS
122 }
123 if (config_file == NULL)
124 goto err;
125 f = fopen(config_file, "r");
126 if (f != NULL) {
3eb46ec6 127 char line[UTIL_LINE_SIZE];
7d563a17
KS
128 int line_nr = 0;
129
130 while (fgets(line, sizeof(line), f)) {
131 size_t len;
132 char *key;
133 char *val;
134
135 line_nr++;
136
137 /* find key */
138 key = line;
139 while (isspace(key[0]))
140 key++;
141
142 /* comment or empty line */
143 if (key[0] == '#' || key[0] == '\0')
144 continue;
145
146 /* split key/value */
147 val = strchr(key, '=');
148 if (val == NULL) {
149 err(udev, "missing <key>=<value> in '%s'[%i], skip line\n", config_file, line_nr);
150 continue;
151 }
152 val[0] = '\0';
153 val++;
154
155 /* find value */
156 while (isspace(val[0]))
157 val++;
158
159 /* terminate key */
160 len = strlen(key);
161 if (len == 0)
162 continue;
163 while (isspace(key[len-1]))
164 len--;
165 key[len] = '\0';
166
167 /* terminate value */
168 len = strlen(val);
169 if (len == 0)
170 continue;
171 while (isspace(val[len-1]))
172 len--;
173 val[len] = '\0';
174
175 if (len == 0)
176 continue;
177
178 /* unquote */
179 if (val[0] == '"' || val[0] == '\'') {
180 if (val[len-1] != val[0]) {
181 err(udev, "inconsistent quoting in '%s'[%i], skip line\n", config_file, line_nr);
182 continue;
183 }
184 val[len-1] = '\0';
185 val++;
186 }
187
bd75fddb 188 if (strcmp(key, "udev_log") == 0) {
3fb629fd 189 udev_set_log_priority(udev, util_log_priority(val));
7d563a17
KS
190 continue;
191 }
bd75fddb 192 if (strcmp(key, "udev_root") == 0) {
7d563a17
KS
193 free(udev->dev_path);
194 udev->dev_path = strdup(val);
7a01f11a 195 util_remove_trailing_chars(udev->dev_path, '/');
7d563a17
KS
196 continue;
197 }
bd75fddb 198 if (strcmp(key, "udev_rules") == 0) {
7d563a17
KS
199 free(udev->rules_path);
200 udev->rules_path = strdup(val);
7a01f11a 201 util_remove_trailing_chars(udev->rules_path, '/');
7d563a17
KS
202 continue;
203 }
204 }
205 fclose(f);
206 }
7d563a17
KS
207
208 env = getenv("UDEV_ROOT");
209 if (env != NULL) {
210 free(udev->dev_path);
211 udev->dev_path = strdup(env);
7a01f11a 212 util_remove_trailing_chars(udev->dev_path, '/');
f183b6ed 213 udev_add_property(udev, "UDEV_ROOT", udev->dev_path);
7d563a17
KS
214 }
215
216 env = getenv("UDEV_LOG");
217 if (env != NULL)
f183b6ed 218 udev_set_log_priority(udev, util_log_priority(env));
7d563a17
KS
219
220 if (udev->dev_path == NULL || udev->sys_path == NULL)
221 goto err;
86b57788
KS
222 dbg(udev, "context %p created\n", udev);
223 dbg(udev, "log_priority=%d\n", udev->log_priority);
224 dbg(udev, "config_file='%s'\n", config_file);
225 dbg(udev, "dev_path='%s'\n", udev->dev_path);
226 dbg(udev, "sys_path='%s'\n", udev->sys_path);
7d563a17 227 if (udev->rules_path != NULL)
86b57788 228 dbg(udev, "rules_path='%s'\n", udev->rules_path);
a035bf27 229 free(config_file);
33a5cc29 230 return udev;
7d563a17 231err:
a035bf27 232 free(config_file);
7d563a17
KS
233 err(udev, "context creation failed\n");
234 udev_unref(udev);
235 return NULL;
33a5cc29
KS
236}
237
238/**
239 * udev_ref:
240 * @udev: udev library context
241 *
242 * Take a reference of the udev library context.
243 *
244 * Returns: the passed udev library context
245 **/
246struct udev *udev_ref(struct udev *udev)
247{
ba6929f6
KS
248 if (udev == NULL)
249 return NULL;
33a5cc29
KS
250 udev->refcount++;
251 return udev;
252}
253
254/**
255 * udev_unref:
256 * @udev: udev library context
257 *
258 * Drop a reference of the udev library context. If the refcount
be7de409 259 * reaches zero, the resources of the context will be released.
33a5cc29
KS
260 *
261 **/
262void udev_unref(struct udev *udev)
263{
ba6929f6
KS
264 if (udev == NULL)
265 return;
33a5cc29
KS
266 udev->refcount--;
267 if (udev->refcount > 0)
268 return;
eb8837e1 269 udev_list_cleanup_entries(udev, &udev->properties_list);
7d563a17
KS
270 free(udev->dev_path);
271 free(udev->sys_path);
a035bf27 272 free(udev->rules_path);
86b57788 273 dbg(udev, "context %p released\n", udev);
33a5cc29
KS
274 free(udev);
275}
276
277/**
278 * udev_set_log_fn:
279 * @udev: udev library context
280 * @log_fn: function to be called for logging messages
281 *
be7de409 282 * The built-in logging writes to stderr. It can be
33a5cc29 283 * overridden by a custom function, to plug log messages
be7de409 284 * into the users' logging functionality.
33a5cc29
KS
285 *
286 **/
287void udev_set_log_fn(struct udev *udev,
288 void (*log_fn)(struct udev *udev,
289 int priority, const char *file, int line, const char *fn,
290 const char *format, va_list args))
291{
292 udev->log_fn = log_fn;
7d563a17
KS
293 info(udev, "custom logging function %p registered\n", udev);
294}
295
296int udev_get_log_priority(struct udev *udev)
297{
298 return udev->log_priority;
299}
300
301void udev_set_log_priority(struct udev *udev, int priority)
302{
f183b6ed
KS
303 char num[32];
304
7d563a17 305 udev->log_priority = priority;
f183b6ed
KS
306 snprintf(num, sizeof(num), "%u", udev->log_priority);
307 udev_add_property(udev, "UDEV_LOG", num);
7d563a17
KS
308}
309
310const char *udev_get_rules_path(struct udev *udev)
311{
312 return udev->rules_path;
313}
314
315int udev_get_run(struct udev *udev)
316{
317 return udev->run;
33a5cc29
KS
318}
319
320/**
321 * udev_get_sys_path:
322 * @udev: udev library context
323 *
324 * Retrieve the sysfs mount point. The default is "/sys". For
325 * testing purposes, it can be overridden with the environment
326 * variable SYSFS_PATH.
327 *
328 * Returns: the sys mount point
329 **/
330const char *udev_get_sys_path(struct udev *udev)
331{
ba6929f6
KS
332 if (udev == NULL)
333 return NULL;
7d563a17 334 return udev->sys_path;
33a5cc29
KS
335}
336
337/**
338 * udev_get_dev_path:
339 * @udev: udev library context
340 *
341 * Retrieve the device directory path. The default value is "/dev",
342 * the actual value may be overridden in the udev configuration
343 * file.
344 *
345 * Returns: the device directory path
346 **/
347const char *udev_get_dev_path(struct udev *udev)
348{
ba6929f6
KS
349 if (udev == NULL)
350 return NULL;
7d563a17 351 return udev->dev_path;
33a5cc29 352}
f183b6ed
KS
353
354struct udev_list_entry *udev_add_property(struct udev *udev, const char *key, const char *value)
355{
356 if (value == NULL) {
357 struct udev_list_entry *list_entry;
358
359 list_entry = udev_get_properties_list_entry(udev);
360 list_entry = udev_list_entry_get_by_name(list_entry, key);
361 if (list_entry != NULL)
1e78dcbe 362 udev_list_entry_delete(list_entry);
f183b6ed
KS
363 return NULL;
364 }
365 return udev_list_entry_add(udev, &udev->properties_list, key, value, 1, 0);
366}
367
368struct udev_list_entry *udev_get_properties_list_entry(struct udev *udev)
369{
370 return udev_list_get_entry(&udev->properties_list);
371}