]>
Commit | Line | Data |
---|---|---|
e345e267 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. | |
e345e267 KS |
10 | */ |
11 | ||
12 | #include <stdio.h> | |
13 | #include <stdlib.h> | |
14 | #include <stddef.h> | |
15 | #include <unistd.h> | |
16 | #include <errno.h> | |
17 | #include <string.h> | |
18 | ||
19 | #include "libudev.h" | |
20 | #include "libudev-private.h" | |
21 | ||
0de33a61 | 22 | struct udev_list_entry { |
8cd2e972 | 23 | struct udev_list_node node; |
1e78dcbe | 24 | struct udev *udev; |
8cd2e972 | 25 | struct udev_list_node *list; |
e345e267 KS |
26 | char *name; |
27 | char *value; | |
df1dcc09 | 28 | int flag; |
e345e267 KS |
29 | }; |
30 | ||
0de33a61 | 31 | /* list head point to itself if empty */ |
8cd2e972 | 32 | void udev_list_init(struct udev_list_node *list) |
e345e267 KS |
33 | { |
34 | list->next = list; | |
35 | list->prev = list; | |
36 | } | |
37 | ||
9dcf7ec8 | 38 | int udev_list_is_empty(struct udev_list_node *list) |
e345e267 KS |
39 | { |
40 | return list->next == list; | |
41 | } | |
42 | ||
3feeb77c | 43 | static void udev_list_node_insert_between(struct udev_list_node *new, |
9dcf7ec8 KS |
44 | struct udev_list_node *prev, |
45 | struct udev_list_node *next) | |
e345e267 | 46 | { |
e345e267 KS |
47 | next->prev = new; |
48 | new->next = next; | |
e345e267 KS |
49 | new->prev = prev; |
50 | prev->next = new; | |
51 | } | |
52 | ||
9dcf7ec8 KS |
53 | void udev_list_node_append(struct udev_list_node *new, struct udev_list_node *list) |
54 | { | |
55 | udev_list_node_insert_between(new, list->prev, list); | |
56 | } | |
57 | ||
58 | void udev_list_node_remove(struct udev_list_node *entry) | |
e345e267 | 59 | { |
8cd2e972 KS |
60 | struct udev_list_node *prev = entry->prev; |
61 | struct udev_list_node *next = entry->next; | |
e345e267 KS |
62 | |
63 | next->prev = prev; | |
64 | prev->next = next; | |
0de33a61 KS |
65 | |
66 | entry->prev = NULL; | |
67 | entry->next = NULL; | |
e345e267 KS |
68 | } |
69 | ||
0de33a61 | 70 | /* return list entry which embeds this node */ |
8cd2e972 | 71 | static struct udev_list_entry *list_node_to_entry(struct udev_list_node *node) |
0de33a61 KS |
72 | { |
73 | char *list; | |
e345e267 | 74 | |
0de33a61 KS |
75 | list = (char *)node; |
76 | list -= offsetof(struct udev_list_entry, node); | |
77 | return (struct udev_list_entry *)list; | |
78 | } | |
79 | ||
80 | /* insert entry into a list as the last element */ | |
1e78dcbe | 81 | void udev_list_entry_append(struct udev_list_entry *new, struct udev_list_node *list) |
0de33a61 KS |
82 | { |
83 | /* inserting before the list head make the node the last node in the list */ | |
3feeb77c | 84 | udev_list_node_insert_between(&new->node, list->prev, list); |
0de33a61 KS |
85 | new->list = list; |
86 | } | |
87 | ||
1e78dcbe KS |
88 | /* remove entry from a list */ |
89 | void udev_list_entry_remove(struct udev_list_entry *entry) | |
90 | { | |
91 | udev_list_node_remove(&entry->node); | |
92 | entry->list = NULL; | |
93 | } | |
94 | ||
0de33a61 | 95 | /* insert entry into a list, before a given existing entry */ |
1e78dcbe | 96 | void udev_list_entry_insert_before(struct udev_list_entry *new, struct udev_list_entry *entry) |
0de33a61 | 97 | { |
3feeb77c | 98 | udev_list_node_insert_between(&new->node, entry->node.prev, &entry->node); |
0de33a61 KS |
99 | new->list = entry->list; |
100 | } | |
e345e267 | 101 | |
8cd2e972 KS |
102 | struct udev_list_entry *udev_list_entry_add(struct udev *udev, struct udev_list_node *list, |
103 | const char *name, const char *value, | |
104 | int unique, int sort) | |
0de33a61 KS |
105 | { |
106 | struct udev_list_entry *entry_loop = NULL; | |
107 | struct udev_list_entry *entry_new; | |
108 | ||
109 | if (unique) | |
8cd2e972 | 110 | udev_list_entry_foreach(entry_loop, udev_list_get_entry(list)) { |
0de33a61 | 111 | if (strcmp(entry_loop->name, name) == 0) { |
86b57788 | 112 | dbg(udev, "'%s' is already in the list\n", name); |
2c09b3b4 KS |
113 | free(entry_loop->value); |
114 | if (value == NULL) { | |
115 | entry_loop->value = NULL; | |
86b57788 | 116 | dbg(udev, "'%s' value unset\n", name); |
2c09b3b4 | 117 | return entry_loop; |
0de33a61 | 118 | } |
2c09b3b4 KS |
119 | entry_loop->value = strdup(value); |
120 | if (entry_loop->value == NULL) | |
121 | return NULL; | |
86b57788 | 122 | dbg(udev, "'%s' value replaced with '%s'\n", name, value); |
0de33a61 KS |
123 | return entry_loop; |
124 | } | |
e345e267 | 125 | } |
e345e267 | 126 | |
0de33a61 | 127 | if (sort) |
8cd2e972 | 128 | udev_list_entry_foreach(entry_loop, udev_list_get_entry(list)) { |
0de33a61 | 129 | if (strcmp(entry_loop->name, name) > 0) |
e345e267 KS |
130 | break; |
131 | } | |
e345e267 | 132 | |
0de33a61 KS |
133 | entry_new = malloc(sizeof(struct udev_list_entry)); |
134 | if (entry_new == NULL) | |
e345e267 | 135 | return NULL; |
0de33a61 KS |
136 | memset(entry_new, 0x00, sizeof(struct udev_list_entry)); |
137 | entry_new->udev = udev; | |
138 | entry_new->name = strdup(name); | |
139 | if (entry_new->name == NULL) { | |
140 | free(entry_new); | |
e345e267 KS |
141 | return NULL; |
142 | } | |
143 | if (value != NULL) { | |
0de33a61 KS |
144 | entry_new->value = strdup(value); |
145 | if (entry_new->value == NULL) { | |
146 | free(entry_new->name); | |
147 | free(entry_new); | |
e345e267 KS |
148 | return NULL; |
149 | } | |
150 | } | |
0de33a61 | 151 | if (entry_loop != NULL) |
1e78dcbe | 152 | udev_list_entry_insert_before(entry_new, entry_loop); |
0de33a61 | 153 | else |
1e78dcbe | 154 | udev_list_entry_append(entry_new, list); |
be7f7f57 | 155 | dbg(udev, "'%s=%s' added\n", entry_new->name, entry_new->value); |
0de33a61 | 156 | return entry_new; |
e345e267 KS |
157 | } |
158 | ||
1e78dcbe | 159 | void udev_list_entry_delete(struct udev_list_entry *entry) |
e345e267 | 160 | { |
3feeb77c | 161 | udev_list_node_remove(&entry->node); |
2c09b3b4 KS |
162 | free(entry->name); |
163 | free(entry->value); | |
164 | free(entry); | |
e345e267 KS |
165 | } |
166 | ||
eb8837e1 | 167 | void udev_list_cleanup_entries(struct udev *udev, struct udev_list_node *list) |
e345e267 | 168 | { |
0de33a61 KS |
169 | struct udev_list_entry *entry_loop; |
170 | struct udev_list_entry *entry_tmp; | |
171 | ||
daa849db | 172 | udev_list_entry_foreach_safe(entry_loop, entry_tmp, udev_list_get_entry(list)) |
1e78dcbe | 173 | udev_list_entry_delete(entry_loop); |
be7f7f57 KS |
174 | } |
175 | ||
8cd2e972 | 176 | struct udev_list_entry *udev_list_get_entry(struct udev_list_node *list) |
e345e267 | 177 | { |
3feeb77c | 178 | if (udev_list_is_empty(list)) |
e345e267 | 179 | return NULL; |
0de33a61 | 180 | return list_node_to_entry(list->next); |
e345e267 KS |
181 | } |
182 | ||
0de33a61 | 183 | struct udev_list_entry *udev_list_entry_get_next(struct udev_list_entry *list_entry) |
e345e267 | 184 | { |
8cd2e972 | 185 | struct udev_list_node *next; |
e345e267 | 186 | |
0de33a61 KS |
187 | if (list_entry == NULL) |
188 | return NULL; | |
e345e267 | 189 | next = list_entry->node.next; |
0de33a61 | 190 | /* empty list or no more entries */ |
e345e267 KS |
191 | if (next == list_entry->list) |
192 | return NULL; | |
0de33a61 | 193 | return list_node_to_entry(next); |
e345e267 KS |
194 | } |
195 | ||
bc8184ed KS |
196 | struct udev_list_entry *udev_list_entry_get_by_name(struct udev_list_entry *list_entry, const char *name) |
197 | { | |
198 | struct udev_list_entry *entry; | |
199 | ||
517814e7 KS |
200 | udev_list_entry_foreach(entry, list_entry) { |
201 | if (strcmp(udev_list_entry_get_name(entry), name) == 0) { | |
202 | dbg(entry->udev, "found '%s=%s'\n", entry->name, entry->value); | |
bc8184ed | 203 | return entry; |
517814e7 KS |
204 | } |
205 | } | |
bc8184ed KS |
206 | return NULL; |
207 | } | |
208 | ||
0de33a61 | 209 | const char *udev_list_entry_get_name(struct udev_list_entry *list_entry) |
e345e267 KS |
210 | { |
211 | if (list_entry == NULL) | |
212 | return NULL; | |
213 | return list_entry->name; | |
214 | } | |
215 | ||
0de33a61 | 216 | const char *udev_list_entry_get_value(struct udev_list_entry *list_entry) |
e345e267 KS |
217 | { |
218 | if (list_entry == NULL) | |
219 | return NULL; | |
220 | return list_entry->value; | |
221 | } | |
df1dcc09 | 222 | |
37ed4f56 | 223 | int udev_list_entry_get_flag(struct udev_list_entry *list_entry) |
df1dcc09 KS |
224 | { |
225 | if (list_entry == NULL) | |
226 | return -EINVAL; | |
227 | return list_entry->flag; | |
228 | } | |
229 | ||
37ed4f56 | 230 | void udev_list_entry_set_flag(struct udev_list_entry *list_entry, int flag) |
df1dcc09 KS |
231 | { |
232 | if (list_entry == NULL) | |
233 | return; | |
234 | list_entry->flag = flag; | |
235 | } |