]> git.ipfire.org Git - thirdparty/systemd.git/blame - udev/lib/libudev-device.c
release 128
[thirdparty/systemd.git] / udev / lib / libudev-device.c
CommitLineData
eb1f0e66
KS
1/*
2 * libudev - interface to udev device information
3 *
4 * Copyright (C) 2008 Kay Sievers <kay.sievers@vrfy.org>
5 *
6 * This program is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20#include "config.h"
21
22#include <stdio.h>
23#include <stdlib.h>
24#include <stddef.h>
25#include <unistd.h>
26#include <errno.h>
27#include <string.h>
28#include <dirent.h>
29#include <sys/stat.h>
30
31#include "libudev.h"
32#include "libudev-private.h"
eb1f0e66 33
11d543c1
KS
34struct udev_device {
35 int refcount;
36 struct udev *udev;
11d543c1 37 char *syspath;
4ad3a37f
KS
38 const char *devpath;
39 const char *sysname;
11d543c1
KS
40 char *devname;
41 char *subsystem;
42 struct list_head link_list;
43 struct list_head env_list;
c4f5f942
KS
44 char *action;
45 char *driver;
46 char *devpath_old;
47 char *physdevpath;
48 int timeout;
49 dev_t devnum;
6bd1c78a
KS
50 unsigned long long int seqnum;
51 int num_fake_partitions;
e88a82b5 52 int devlink_priority;
6bd1c78a 53 int ignore_remove;
11d543c1
KS
54};
55
e88a82b5
KS
56static size_t devpath_to_db_path(struct udev *udev, const char *devpath, char *filename, size_t len)
57{
58 size_t start;
59
60 /* translate to location of db file */
3eb46ec6
KS
61 util_strlcpy(filename, udev_get_dev_path(udev), len);
62 start = util_strlcat(filename, "/.udev/db/", len);
63 util_strlcat(filename, devpath, len);
7a01f11a 64 return util_path_encode(&filename[start], len - start);
e88a82b5
KS
65}
66
67static int device_read_db(struct udev_device *udev_device)
68{
69 struct stat stats;
3eb46ec6
KS
70 char filename[UTIL_PATH_SIZE];
71 char line[UTIL_LINE_SIZE];
e88a82b5
KS
72 FILE *f;
73 int rc = 0;
74
75 devpath_to_db_path(udev_device->udev, udev_device->devpath, filename, sizeof(filename));
76
77 if (lstat(filename, &stats) != 0) {
78 info(udev_device->udev, "no db file to read %s: %s\n", filename, strerror(errno));
79 return -1;
80 }
81 if ((stats.st_mode & S_IFMT) == S_IFLNK) {
3eb46ec6 82 char target[UTIL_PATH_SIZE];
e88a82b5
KS
83 int target_len;
84
85 info(udev_device->udev, "found a symlink as db file\n");
86 target_len = readlink(filename, target, sizeof(target));
87 if (target_len > 0)
88 target[target_len] = '\0';
89 else {
90 info(udev_device->udev, "error reading db link %s: %s\n", filename, strerror(errno));
91 return -1;
92 }
93 dbg(udev_device->udev, "db link points to '%s'\n", target);
94 if (asprintf(&udev_device->devname, "%s/%s", udev_get_dev_path(udev_device->udev), target) < 0)
95 return -ENOMEM;
96 return 0;
97 }
98
99 f = fopen(filename, "r");
100 if (f == NULL) {
101 info(udev_device->udev, "error reading db file %s: %s\n", filename, strerror(errno));
102 return -1;
103 }
104 while (fgets(line, sizeof(line), f)) {
105 ssize_t len;
106 const char *val;
107 unsigned int maj, min;
108
109 len = strlen(line);
110 if (len < 4)
111 break;
112 line[len-1] = '\0';
113 val = &line[2];
114
115 switch(line[0]) {
116 case 'N':
117 asprintf(&udev_device->devname, "%s/%s", udev_get_dev_path(udev_device->udev), val);
118 break;
119 case 'M':
120 sscanf(val, "%u:%u", &maj, &min);
121 device_set_devnum(udev_device, makedev(maj, min));
122 break;
123 case 'S':
3eb46ec6
KS
124 util_strlcpy(filename, udev_get_dev_path(udev_device->udev), sizeof(filename));
125 util_strlcat(filename, "/", sizeof(filename));
126 util_strlcat(filename, val, sizeof(filename));
e88a82b5
KS
127 device_add_devlink(udev_device, filename);
128 break;
129 case 'L':
130 device_set_devlink_priority(udev_device, atoi(val));
131 break;
132 case 'T':
133 device_set_timeout(udev_device, atoi(val));
134 break;
135 case 'A':
136 device_set_num_fake_partitions(udev_device, atoi(val));
137 break;
138 case 'R':
139 device_set_ignore_remove(udev_device, atoi(val));
140 break;
141 case 'E':
142 device_add_property(udev_device, val);
143 break;
144 }
145 }
146 fclose(f);
147
148 return rc;
149}
150
ba6929f6 151struct udev_device *device_init(struct udev *udev)
eb1f0e66
KS
152{
153 struct udev_device *udev_device;
154
ba6929f6
KS
155 if (udev == NULL)
156 return NULL;
157
eb1f0e66
KS
158 udev_device = malloc(sizeof(struct udev_device));
159 if (udev_device == NULL)
160 return NULL;
161 memset(udev_device, 0x00, sizeof(struct udev_device));
162 udev_device->refcount = 1;
163 udev_device->udev = udev;
ba6929f6
KS
164 INIT_LIST_HEAD(&udev_device->link_list);
165 INIT_LIST_HEAD(&udev_device->env_list);
7d563a17 166 info(udev_device->udev, "udev_device: %p created\n", udev_device);
eb1f0e66
KS
167 return udev_device;
168}
169
170/**
171 * udev_device_new_from_devpath:
172 * @udev: udev library context
173 * @devpath: sys device path
174 *
175 * Create new udev device, and fill in information from the sysfs
176 * device and the udev database entry. The devpath must not contain
177 * the sysfs mount path, and must contain a leading '/'.
178 *
179 * The initial refcount is 1, and needs to be decremented to
180 * release the ressources of the udev device.
181 *
182 * Returns: a new udev device, or #NULL, if it does not exist
183 **/
184struct udev_device *udev_device_new_from_devpath(struct udev *udev, const char *devpath)
185{
3eb46ec6 186 char path[UTIL_PATH_SIZE];
eb1f0e66
KS
187 struct stat statbuf;
188 struct udev_device *udev_device;
eb1f0e66 189
ba6929f6
KS
190 if (udev == NULL)
191 return NULL;
192 if (devpath == NULL)
193 return NULL;
194
3eb46ec6
KS
195 util_strlcpy(path, udev_get_sys_path(udev), sizeof(path));
196 util_strlcat(path, devpath, sizeof(path));
4ad3a37f
KS
197 util_strlcat(path, "/uevent", sizeof(path));
198 if (stat(path, &statbuf) != 0) {
199 info(udev, "not a device :%s\n", path);
eb1f0e66 200 return NULL;
4ad3a37f 201 }
eb1f0e66
KS
202
203 udev_device = device_init(udev);
204 if (udev_device == NULL)
205 return NULL;
206
ba6929f6 207 /* resolve possible symlink to real path */
3eb46ec6 208 util_strlcpy(path, devpath, sizeof(path));
b21b95d7 209 util_resolve_sys_link(udev, path, sizeof(path));
e88a82b5 210 device_set_devpath(udev_device, path);
7d563a17 211 info(udev, "device %p has devpath '%s'\n", udev_device, udev_device_get_devpath(udev_device));
eb1f0e66 212
e88a82b5 213 if (device_read_db(udev_device) >= 0)
7d563a17 214 info(udev, "device %p filled with udev database data\n", udev_device);
ba6929f6 215
eb1f0e66
KS
216 return udev_device;
217}
218
4ad3a37f
KS
219struct udev_device *udev_device_new_from_parent(struct udev_device *udev_device)
220{
221 struct udev_device *udev_device_parent = NULL;
222 char path[UTIL_PATH_SIZE];
223 char *pos;
224
225 if (udev_device == NULL)
226 return NULL;
227
228 util_strlcpy(path, udev_device_get_devpath(udev_device), sizeof(path));
229 while (1) {
230 pos = strrchr(path, '/');
231 if (pos == NULL)
232 break;
233 pos[0] = '\0';
234 udev_device_parent = udev_device_new_from_devpath(udev_device->udev, path);
235 if (udev_device_parent != NULL)
236 break;
237 }
238 return udev_device_parent;
239}
240
eb1f0e66
KS
241/**
242 * udev_device_get_udev:
7d8787b3 243 * @udev_device: udev device
eb1f0e66
KS
244 *
245 * Retrieve the udev library context the device was created with.
246 *
247 * Returns: the udev library context
248 **/
249struct udev *udev_device_get_udev(struct udev_device *udev_device)
250{
ba6929f6
KS
251 if (udev_device == NULL)
252 return NULL;
eb1f0e66
KS
253 return udev_device->udev;
254}
255
256/**
257 * udev_device_ref:
258 * @udev_device: udev device
259 *
260 * Take a reference of a udev device.
261 *
262 * Returns: the passed udev device
263 **/
264struct udev_device *udev_device_ref(struct udev_device *udev_device)
265{
ba6929f6
KS
266 if (udev_device == NULL)
267 return NULL;
eb1f0e66
KS
268 udev_device->refcount++;
269 return udev_device;
270}
271
272/**
273 * udev_device_unref:
274 * @udev_device: udev device
275 *
276 * Drop a reference of a udev device. If the refcount reaches zero,
277 * the ressources of the device will be released.
278 *
279 **/
280void udev_device_unref(struct udev_device *udev_device)
281{
ba6929f6
KS
282 if (udev_device == NULL)
283 return;
eb1f0e66
KS
284 udev_device->refcount--;
285 if (udev_device->refcount > 0)
286 return;
11d543c1 287 free(udev_device->syspath);
ba6929f6
KS
288 free(udev_device->devname);
289 free(udev_device->subsystem);
7a01f11a
KS
290 util_name_list_cleanup(udev_device->udev, &udev_device->link_list);
291 util_name_list_cleanup(udev_device->udev, &udev_device->env_list);
1c7047ea
KS
292 free(udev_device->action);
293 free(udev_device->driver);
294 free(udev_device->devpath_old);
295 free(udev_device->physdevpath);
7d563a17 296 info(udev_device->udev, "udev_device: %p released\n", udev_device);
eb1f0e66
KS
297 free(udev_device);
298}
299
300/**
301 * udev_device_get_devpath:
302 * @udev_device: udev device
303 *
11d543c1
KS
304 * Retrieve the kernel devpath value of the udev device. The path
305 * does not contain the sys mount point, and starts with a '/'.
eb1f0e66 306 *
11d543c1 307 * Returns: the devpath of the udev device
eb1f0e66
KS
308 **/
309const char *udev_device_get_devpath(struct udev_device *udev_device)
310{
ba6929f6
KS
311 if (udev_device == NULL)
312 return NULL;
313 return udev_device->devpath;
eb1f0e66
KS
314}
315
11d543c1
KS
316/**
317 * udev_device_get_syspath:
318 * @udev_device: udev device
319 *
320 * Retrieve the sys path of the udev device. The path is an
321 * absolute path and starts with the sys mount point.
322 *
323 * Returns: the sys path of the udev device
324 **/
325const char *udev_device_get_syspath(struct udev_device *udev_device)
326{
327 if (udev_device == NULL)
328 return NULL;
329 return udev_device->syspath;
330}
331
4ad3a37f
KS
332const char *udev_device_get_sysname(struct udev_device *udev_device)
333{
334 if (udev_device == NULL)
335 return NULL;
336 return udev_device->sysname;
337}
338
eb1f0e66
KS
339/**
340 * udev_device_get_devname:
341 * @udev_device: udev device
342 *
343 * Retrieve the device node file name belonging to the udev device.
ba6929f6 344 * The path is an absolute path, and starts with the device directory.
eb1f0e66
KS
345 *
346 * Returns: the device node file name of the udev device, or #NULL if no device node exists
347 **/
348const char *udev_device_get_devname(struct udev_device *udev_device)
349{
ba6929f6 350 if (udev_device == NULL)
eb1f0e66 351 return NULL;
ba6929f6 352 return udev_device->devname;
eb1f0e66
KS
353}
354
355/**
356 * udev_device_get_subsystem:
357 * @udev_device: udev device
358 *
359 * Retrieve the subsystem string of the udev device. The string does not
360 * contain any "/".
361 *
362 * Returns: the subsystem name of the udev device, or #NULL if it can not be determined
363 **/
364const char *udev_device_get_subsystem(struct udev_device *udev_device)
365{
17fcfb59 366 char subsystem[UTIL_NAME_SIZE];
ba6929f6
KS
367
368 if (udev_device == NULL)
369 return NULL;
370 if (udev_device->subsystem != NULL)
371 return udev_device->subsystem;
372 if (util_get_sys_subsystem(udev_device->udev, udev_device->devpath, subsystem, sizeof(subsystem)) < 2)
eb1f0e66 373 return NULL;
ba6929f6
KS
374 udev_device->subsystem = strdup(subsystem);
375 return udev_device->subsystem;
eb1f0e66
KS
376}
377
378/**
379 * udev_device_get_devlinks:
380 * @udev_device: udev device
381 * @cb: function to be called for every device link found
382 * @data: data to be passed to the function
383 *
384 * Retrieve the device links pointing to the device file of the
385 * udev device. For every device link, the passed function will be
ba6929f6
KS
386 * called with the device link string.
387 * The path is an absolute path, and starts with the device directory.
388 * If the function returns 1, remaning device links will be ignored.
eb1f0e66
KS
389 *
390 * Returns: the number of device links passed to the caller, or a negative value on error
391 **/
392int udev_device_get_devlinks(struct udev_device *udev_device,
393 int (*cb)(struct udev_device *udev_device, const char *value, void *data),
394 void *data)
395{
3eb46ec6 396 struct util_name_entry *name_loop;
eb1f0e66
KS
397 int count = 0;
398
ba6929f6
KS
399 if (udev_device == NULL)
400 return -1;
401 list_for_each_entry(name_loop, &udev_device->link_list, node) {
eb1f0e66
KS
402 count++;
403 if (cb(udev_device, name_loop->name, data) != 0)
404 break;
405 }
406 return count;
407}
408
409/**
410 * udev_device_get_properties:
411 * @udev_device: udev device
412 * @cb: function to be called for every property found
413 * @data: data to be passed to the function
414 *
415 * Retrieve the property key/value pairs belonging to the
416 * udev device. For every key/value pair, the passed function will be
417 * called. If the function returns 1, remaning properties will be
418 * ignored.
419 *
420 * Returns: the number of properties passed to the caller, or a negative value on error
421 **/
422int udev_device_get_properties(struct udev_device *udev_device,
423 int (*cb)(struct udev_device *udev_device, const char *key, const char *value, void *data),
424 void *data)
425{
3eb46ec6 426 struct util_name_entry *name_loop;
eb1f0e66
KS
427 int count = 0;
428
ba6929f6
KS
429 if (udev_device == NULL)
430 return -1;
431 list_for_each_entry(name_loop, &udev_device->env_list, node) {
17fcfb59 432 char name[UTIL_NAME_SIZE];
eb1f0e66
KS
433 char *val;
434
3eb46ec6 435 strncpy(name, name_loop->name, sizeof(name));
eb1f0e66
KS
436 val = strchr(name, '=');
437 if (val == NULL)
438 continue;
439 val[0] = '\0';
440 val = &val[1];
ba6929f6 441 count++;
eb1f0e66
KS
442 if (cb(udev_device, name, val, data) != 0)
443 break;
444 }
445 return count;
446}
11d543c1 447
c4f5f942
KS
448const char *udev_device_get_driver(struct udev_device *udev_device)
449{
17fcfb59 450 char driver[UTIL_NAME_SIZE];
95d90c4f 451
c4f5f942
KS
452 if (udev_device == NULL)
453 return NULL;
95d90c4f
KS
454 if (udev_device->driver != NULL)
455 return udev_device->driver;
456 if (util_get_sys_driver(udev_device->udev, udev_device->devpath, driver, sizeof(driver)) < 2)
457 return NULL;
458 udev_device->driver = strdup(driver);
c4f5f942
KS
459 return udev_device->driver;
460}
461
462dev_t udev_device_get_devnum(struct udev_device *udev_device)
463{
464 if (udev_device == NULL)
465 return makedev(0, 0);
466 return udev_device->devnum;
467}
468
469const char *udev_device_get_action(struct udev_device *udev_device)
470{
471 if (udev_device == NULL)
472 return NULL;
473 return udev_device->action;
474}
475
37372bbc
KS
476unsigned long long int udev_device_get_seqnum(struct udev_device *udev_device)
477{
478 if (udev_device == NULL)
479 return 0;
480 return udev_device->seqnum;
481}
482
11d543c1
KS
483int device_set_devpath(struct udev_device *udev_device, const char *devpath)
484{
485 if (asprintf(&udev_device->syspath, "%s%s", udev_get_sys_path(udev_device->udev), devpath) < 0)
486 return -ENOMEM;
487 udev_device->devpath = &udev_device->syspath[strlen(udev_get_sys_path(udev_device->udev))];
4ad3a37f
KS
488 udev_device->sysname = strrchr(udev_device->syspath, '/');
489 if (udev_device->sysname != NULL)
490 udev_device->sysname = &udev_device->sysname[1];
11d543c1
KS
491 return 0;
492}
493
494int device_set_subsystem(struct udev_device *udev_device, const char *subsystem)
495{
496 udev_device->subsystem = strdup(subsystem);
497 if (udev_device->subsystem == NULL)
498 return -1;
499 return 0;
500}
501
502int device_set_devname(struct udev_device *udev_device, const char *devname)
503{
504 udev_device->devname = strdup(devname);
505 if (udev_device->devname == NULL)
506 return -ENOMEM;
507 return 0;
508}
509
510int device_add_devlink(struct udev_device *udev_device, const char *devlink)
511{
7a01f11a 512 if (util_name_list_add(udev_device->udev, &udev_device->link_list, devlink, 0) == NULL)
11d543c1
KS
513 return -ENOMEM;
514 return 0;
515}
516
517int device_add_property(struct udev_device *udev_device, const char *property)
518{
7a01f11a 519 if (util_name_list_add(udev_device->udev, &udev_device->env_list, property, 0) == NULL)
11d543c1
KS
520 return -ENOMEM;
521 return 0;
522}
c4f5f942
KS
523
524int device_set_action(struct udev_device *udev_device, const char *action)
525{
526 udev_device->action = strdup(action);
527 if (udev_device->action == NULL)
528 return -ENOMEM;
529 return 0;
530}
531
532int device_set_driver(struct udev_device *udev_device, const char *driver)
533{
534 udev_device->driver = strdup(driver);
535 if (udev_device->driver == NULL)
536 return -ENOMEM;
537 return 0;
538}
539
540const char *device_get_devpath_old(struct udev_device *udev_device)
541{
542 if (udev_device == NULL)
543 return NULL;
544 return udev_device->devpath_old;
545}
546
547int device_set_devpath_old(struct udev_device *udev_device, const char *devpath_old)
548{
549 udev_device->devpath_old = strdup(devpath_old);
550 if (udev_device->devpath_old == NULL)
551 return -ENOMEM;
552 return 0;
553}
554
555const char *device_get_physdevpath(struct udev_device *udev_device)
556{
557 if (udev_device == NULL)
558 return NULL;
559 return udev_device->physdevpath;
560}
561
562int device_set_physdevpath(struct udev_device *udev_device, const char *physdevpath)
563{
564 udev_device->physdevpath = strdup(physdevpath);
565 if (udev_device->physdevpath == NULL)
566 return -ENOMEM;
567 return 0;
568}
569
570int device_get_timeout(struct udev_device *udev_device)
571{
572 if (udev_device == NULL)
573 return -1;
574 return udev_device->timeout;
575}
576
577int device_set_timeout(struct udev_device *udev_device, int timeout)
578{
579 udev_device->timeout = timeout;
580 return 0;
581}
582
37372bbc
KS
583int device_set_seqnum(struct udev_device *udev_device, unsigned long long int seqnum)
584{
585 udev_device->seqnum = seqnum;
586 return 0;
587}
588
c4f5f942
KS
589int device_set_devnum(struct udev_device *udev_device, dev_t devnum)
590{
591 udev_device->devnum = devnum;
592 return 0;
593}
6bd1c78a
KS
594
595int device_get_num_fake_partitions(struct udev_device *udev_device)
596{
597 if (udev_device == NULL)
598 return -1;
599 return udev_device->num_fake_partitions;
600}
601
602int device_set_num_fake_partitions(struct udev_device *udev_device, int num)
603{
604 udev_device->num_fake_partitions = num;
e88a82b5 605 return 0;
6bd1c78a
KS
606}
607
e88a82b5 608int device_get_devlink_priority(struct udev_device *udev_device)
6bd1c78a
KS
609{
610 if (udev_device == NULL)
611 return -1;
e88a82b5 612 return udev_device->devlink_priority;
6bd1c78a
KS
613}
614
e88a82b5 615int device_set_devlink_priority(struct udev_device *udev_device, int prio)
6bd1c78a 616{
e88a82b5
KS
617 udev_device->devlink_priority = prio;
618 return 0;
6bd1c78a
KS
619}
620
621int device_get_ignore_remove(struct udev_device *udev_device)
622{
623 if (udev_device == NULL)
624 return -1;
625 return udev_device->ignore_remove;
626}
627
628int device_set_ignore_remove(struct udev_device *udev_device, int ignore)
629{
e88a82b5
KS
630 udev_device->ignore_remove = ignore;
631 return 0;
6bd1c78a 632}
e88a82b5 633