]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/libudev/libudev-list.c
Add SPDX license identifiers to source files under the LGPL
[thirdparty/systemd.git] / src / libudev / libudev-list.c
CommitLineData
53e1b683 1/* SPDX-License-Identifier: LGPL-2.1+ */
88a6477e
KS
2/***
3 This file is part of systemd.
4
5 Copyright 2008-2012 Kay Sievers <kay@vrfy.org>
6
7 systemd is free software; you can redistribute it and/or modify it
8 under the terms of the GNU Lesser General Public License as published by
9 the Free Software Foundation; either version 2.1 of the License, or
10 (at your option) any later version.
11
12 systemd is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Lesser General Public License for more details.
16
17 You should have received a copy of the GNU Lesser General Public License
18 along with systemd; If not, see <http://www.gnu.org/licenses/>.
19***/
e345e267 20
e345e267 21#include <errno.h>
b5efdb8a
LP
22#include <stddef.h>
23#include <stdlib.h>
e345e267
KS
24#include <string.h>
25
b5efdb8a 26#include "alloc-util.h"
e345e267
KS
27#include "libudev-private.h"
28
ce1d6d7f
KS
29/**
30 * SECTION:libudev-list
31 * @short_description: list operation
32 *
33 * Libudev list operations.
34 */
35
1e511322
KS
36/**
37 * udev_list_entry:
38 *
ce1d6d7f
KS
39 * Opaque object representing one entry in a list. An entry contains
40 * contains a name, and optionally a value.
1e511322 41 */
0de33a61 42struct udev_list_entry {
912541b0
KS
43 struct udev_list_node node;
44 struct udev_list *list;
45 char *name;
46 char *value;
47 int num;
e345e267
KS
48};
49
8958da13 50/* the list's head points to itself if empty */
869c9031 51void udev_list_node_init(struct udev_list_node *list)
e345e267 52{
912541b0
KS
53 list->next = list;
54 list->prev = list;
e345e267
KS
55}
56
869c9031 57int udev_list_node_is_empty(struct udev_list_node *list)
e345e267 58{
912541b0 59 return list->next == list;
e345e267
KS
60}
61
3feeb77c 62static void udev_list_node_insert_between(struct udev_list_node *new,
912541b0
KS
63 struct udev_list_node *prev,
64 struct udev_list_node *next)
e345e267 65{
912541b0
KS
66 next->prev = new;
67 new->next = next;
68 new->prev = prev;
69 prev->next = new;
e345e267
KS
70}
71
9dcf7ec8
KS
72void udev_list_node_append(struct udev_list_node *new, struct udev_list_node *list)
73{
912541b0 74 udev_list_node_insert_between(new, list->prev, list);
9dcf7ec8
KS
75}
76
77void udev_list_node_remove(struct udev_list_node *entry)
e345e267 78{
912541b0
KS
79 struct udev_list_node *prev = entry->prev;
80 struct udev_list_node *next = entry->next;
e345e267 81
912541b0
KS
82 next->prev = prev;
83 prev->next = next;
0de33a61 84
912541b0
KS
85 entry->prev = NULL;
86 entry->next = NULL;
e345e267
KS
87}
88
0de33a61 89/* return list entry which embeds this node */
b27ee00b 90static inline struct udev_list_entry *list_node_to_entry(struct udev_list_node *node)
0de33a61 91{
b27ee00b 92 return container_of(node, struct udev_list_entry, node);
0de33a61
KS
93}
94
869c9031 95void udev_list_init(struct udev *udev, struct udev_list *list, bool unique)
0de33a61 96{
29804cc1 97 memzero(list, sizeof(struct udev_list));
912541b0
KS
98 list->udev = udev;
99 list->unique = unique;
100 udev_list_node_init(&list->node);
0de33a61
KS
101}
102
869c9031 103/* insert entry into a list as the last element */
e3dc56a2 104static void udev_list_entry_append(struct udev_list_entry *new, struct udev_list *list)
1e78dcbe 105{
912541b0
KS
106 /* inserting before the list head make the node the last node in the list */
107 udev_list_node_insert_between(&new->node, list->node.prev, &list->node);
108 new->list = list;
1e78dcbe
KS
109}
110
0de33a61 111/* insert entry into a list, before a given existing entry */
e3dc56a2 112static void udev_list_entry_insert_before(struct udev_list_entry *new, struct udev_list_entry *entry)
0de33a61 113{
912541b0
KS
114 udev_list_node_insert_between(&new->node, entry->node.prev, &entry->node);
115 new->list = entry->list;
0de33a61 116}
e345e267 117
869c9031
KS
118/* binary search in sorted array */
119static int list_search(struct udev_list *list, const char *name)
0de33a61 120{
912541b0
KS
121 unsigned int first, last;
122
123 first = 0;
124 last = list->entries_cur;
125 while (first < last) {
126 unsigned int i;
127 int cmp;
128
129 i = (first + last)/2;
130 cmp = strcmp(name, list->entries[i]->name);
131 if (cmp < 0)
132 last = i;
133 else if (cmp > 0)
134 first = i+1;
135 else
136 return i;
137 }
138
139 /* not found, return negative insertion-index+1 */
140 return -(first+1);
869c9031
KS
141}
142
143struct udev_list_entry *udev_list_entry_add(struct udev_list *list, const char *name, const char *value)
144{
912541b0
KS
145 struct udev_list_entry *entry;
146 int i = 0;
147
148 if (list->unique) {
149 /* lookup existing name or insertion-index */
150 i = list_search(list, name);
151 if (i >= 0) {
152 entry = list->entries[i];
153
912541b0
KS
154 free(entry->value);
155 if (value == NULL) {
156 entry->value = NULL;
912541b0
KS
157 return entry;
158 }
159 entry->value = strdup(value);
160 if (entry->value == NULL)
161 return NULL;
912541b0
KS
162 return entry;
163 }
164 }
165
166 /* add new name */
955d98c9 167 entry = new0(struct udev_list_entry, 1);
912541b0
KS
168 if (entry == NULL)
169 return NULL;
6b430fdb 170
912541b0 171 entry->name = strdup(name);
6b430fdb
ZJS
172 if (entry->name == NULL)
173 return mfree(entry);
174
912541b0
KS
175 if (value != NULL) {
176 entry->value = strdup(value);
177 if (entry->value == NULL) {
178 free(entry->name);
6b430fdb 179 return mfree(entry);
912541b0
KS
180 }
181 }
182
183 if (list->unique) {
184 /* allocate or enlarge sorted array if needed */
185 if (list->entries_cur >= list->entries_max) {
cf2292f5 186 struct udev_list_entry **entries;
912541b0
KS
187 unsigned int add;
188
189 add = list->entries_max;
190 if (add < 1)
191 add = 64;
cf2292f5
MD
192 entries = realloc(list->entries, (list->entries_max + add) * sizeof(struct udev_list_entry *));
193 if (entries == NULL) {
912541b0
KS
194 free(entry->name);
195 free(entry->value);
6b430fdb 196 return mfree(entry);
912541b0 197 }
cf2292f5 198 list->entries = entries;
912541b0
KS
199 list->entries_max += add;
200 }
201
202 /* the negative i returned the insertion index */
203 i = (-i)-1;
204
205 /* insert into sorted list */
206 if ((unsigned int)i < list->entries_cur)
207 udev_list_entry_insert_before(entry, list->entries[i]);
208 else
209 udev_list_entry_append(entry, list);
210
211 /* insert into sorted array */
212 memmove(&list->entries[i+1], &list->entries[i],
213 (list->entries_cur - i) * sizeof(struct udev_list_entry *));
214 list->entries[i] = entry;
215 list->entries_cur++;
216 } else {
217 udev_list_entry_append(entry, list);
218 }
219
912541b0 220 return entry;
e345e267
KS
221}
222
1e78dcbe 223void udev_list_entry_delete(struct udev_list_entry *entry)
e345e267 224{
912541b0
KS
225 if (entry->list->entries != NULL) {
226 int i;
227 struct udev_list *list = entry->list;
228
229 /* remove entry from sorted array */
230 i = list_search(list, entry->name);
231 if (i >= 0) {
232 memmove(&list->entries[i], &list->entries[i+1],
233 ((list->entries_cur-1) - i) * sizeof(struct udev_list_entry *));
234 list->entries_cur--;
235 }
236 }
237
238 udev_list_node_remove(&entry->node);
239 free(entry->name);
240 free(entry->value);
241 free(entry);
e345e267
KS
242}
243
869c9031 244void udev_list_cleanup(struct udev_list *list)
e345e267 245{
912541b0
KS
246 struct udev_list_entry *entry_loop;
247 struct udev_list_entry *entry_tmp;
248
a1e58e8e 249 list->entries = mfree(list->entries);
912541b0
KS
250 list->entries_cur = 0;
251 list->entries_max = 0;
252 udev_list_entry_foreach_safe(entry_loop, entry_tmp, udev_list_get_entry(list))
253 udev_list_entry_delete(entry_loop);
be7f7f57
KS
254}
255
869c9031 256struct udev_list_entry *udev_list_get_entry(struct udev_list *list)
e345e267 257{
912541b0
KS
258 if (udev_list_node_is_empty(&list->node))
259 return NULL;
260 return list_node_to_entry(list->node.next);
e345e267
KS
261}
262
1e511322
KS
263/**
264 * udev_list_entry_get_next:
265 * @list_entry: current entry
266 *
21dbe43a
KS
267 * Get the next entry from the list.
268 *
269 * Returns: udev_list_entry, #NULL if no more entries are available.
1e511322 270 */
54cf0b7f 271_public_ struct udev_list_entry *udev_list_entry_get_next(struct udev_list_entry *list_entry)
e345e267 272{
912541b0
KS
273 struct udev_list_node *next;
274
275 if (list_entry == NULL)
276 return NULL;
277 next = list_entry->node.next;
278 /* empty list or no more entries */
279 if (next == &list_entry->list->node)
280 return NULL;
281 return list_node_to_entry(next);
e345e267
KS
282}
283
1e511322
KS
284/**
285 * udev_list_entry_get_by_name:
286 * @list_entry: current entry
287 * @name: name string to match
288 *
21dbe43a
KS
289 * Lookup an entry in the list with a certain name.
290 *
291 * Returns: udev_list_entry, #NULL if no matching entry is found.
1e511322 292 */
54cf0b7f 293_public_ struct udev_list_entry *udev_list_entry_get_by_name(struct udev_list_entry *list_entry, const char *name)
bc8184ed 294{
912541b0 295 int i;
bc8184ed 296
912541b0
KS
297 if (list_entry == NULL)
298 return NULL;
869c9031 299
912541b0
KS
300 if (!list_entry->list->unique)
301 return NULL;
869c9031 302
912541b0
KS
303 i = list_search(list_entry->list, name);
304 if (i < 0)
305 return NULL;
306 return list_entry->list->entries[i];
bc8184ed
KS
307}
308
1e511322
KS
309/**
310 * udev_list_entry_get_name:
311 * @list_entry: current entry
312 *
21dbe43a
KS
313 * Get the name of a list entry.
314 *
1e511322
KS
315 * Returns: the name string of this entry.
316 */
54cf0b7f 317_public_ const char *udev_list_entry_get_name(struct udev_list_entry *list_entry)
e345e267 318{
912541b0
KS
319 if (list_entry == NULL)
320 return NULL;
321 return list_entry->name;
e345e267
KS
322}
323
1e511322
KS
324/**
325 * udev_list_entry_get_value:
326 * @list_entry: current entry
327 *
21dbe43a
KS
328 * Get the value of list entry.
329 *
1e511322
KS
330 * Returns: the value string of this entry.
331 */
54cf0b7f 332_public_ const char *udev_list_entry_get_value(struct udev_list_entry *list_entry)
e345e267 333{
912541b0
KS
334 if (list_entry == NULL)
335 return NULL;
336 return list_entry->value;
e345e267 337}
df1dcc09 338
8958da13 339int udev_list_entry_get_num(struct udev_list_entry *list_entry)
df1dcc09 340{
912541b0
KS
341 if (list_entry == NULL)
342 return -EINVAL;
343 return list_entry->num;
df1dcc09
KS
344}
345
8958da13 346void udev_list_entry_set_num(struct udev_list_entry *list_entry, int num)
df1dcc09 347{
912541b0
KS
348 if (list_entry == NULL)
349 return;
350 list_entry->num = num;
df1dcc09 351}