]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/libudev/libudev-list.c
journal: set secure deletion flags for FSS file
[thirdparty/systemd.git] / src / libudev / libudev-list.c
CommitLineData
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
ce1d6d7f
KS
22/**
23 * SECTION:libudev-list
24 * @short_description: list operation
25 *
26 * Libudev list operations.
27 */
28
1e511322
KS
29/**
30 * udev_list_entry:
31 *
ce1d6d7f
KS
32 * Opaque object representing one entry in a list. An entry contains
33 * contains a name, and optionally a value.
1e511322 34 */
0de33a61 35struct udev_list_entry {
912541b0
KS
36 struct udev_list_node node;
37 struct udev_list *list;
38 char *name;
39 char *value;
40 int num;
e345e267
KS
41};
42
8958da13 43/* the list's head points to itself if empty */
869c9031 44void udev_list_node_init(struct udev_list_node *list)
e345e267 45{
912541b0
KS
46 list->next = list;
47 list->prev = list;
e345e267
KS
48}
49
869c9031 50int udev_list_node_is_empty(struct udev_list_node *list)
e345e267 51{
912541b0 52 return list->next == list;
e345e267
KS
53}
54
3feeb77c 55static void udev_list_node_insert_between(struct udev_list_node *new,
912541b0
KS
56 struct udev_list_node *prev,
57 struct udev_list_node *next)
e345e267 58{
912541b0
KS
59 next->prev = new;
60 new->next = next;
61 new->prev = prev;
62 prev->next = new;
e345e267
KS
63}
64
9dcf7ec8
KS
65void udev_list_node_append(struct udev_list_node *new, struct udev_list_node *list)
66{
912541b0 67 udev_list_node_insert_between(new, list->prev, list);
9dcf7ec8
KS
68}
69
70void udev_list_node_remove(struct udev_list_node *entry)
e345e267 71{
912541b0
KS
72 struct udev_list_node *prev = entry->prev;
73 struct udev_list_node *next = entry->next;
e345e267 74
912541b0
KS
75 next->prev = prev;
76 prev->next = next;
0de33a61 77
912541b0
KS
78 entry->prev = NULL;
79 entry->next = NULL;
e345e267
KS
80}
81
0de33a61 82/* return list entry which embeds this node */
b27ee00b 83static inline struct udev_list_entry *list_node_to_entry(struct udev_list_node *node)
0de33a61 84{
b27ee00b 85 return container_of(node, struct udev_list_entry, node);
0de33a61
KS
86}
87
869c9031 88void udev_list_init(struct udev *udev, struct udev_list *list, bool unique)
0de33a61 89{
912541b0
KS
90 memset(list, 0x00, sizeof(struct udev_list));
91 list->udev = udev;
92 list->unique = unique;
93 udev_list_node_init(&list->node);
0de33a61
KS
94}
95
869c9031
KS
96/* insert entry into a list as the last element */
97void udev_list_entry_append(struct udev_list_entry *new, struct udev_list *list)
1e78dcbe 98{
912541b0
KS
99 /* inserting before the list head make the node the last node in the list */
100 udev_list_node_insert_between(&new->node, list->node.prev, &list->node);
101 new->list = list;
1e78dcbe
KS
102}
103
0de33a61 104/* insert entry into a list, before a given existing entry */
1e78dcbe 105void udev_list_entry_insert_before(struct udev_list_entry *new, struct udev_list_entry *entry)
0de33a61 106{
912541b0
KS
107 udev_list_node_insert_between(&new->node, entry->node.prev, &entry->node);
108 new->list = entry->list;
0de33a61 109}
e345e267 110
869c9031
KS
111/* binary search in sorted array */
112static int list_search(struct udev_list *list, const char *name)
0de33a61 113{
912541b0
KS
114 unsigned int first, last;
115
116 first = 0;
117 last = list->entries_cur;
118 while (first < last) {
119 unsigned int i;
120 int cmp;
121
122 i = (first + last)/2;
123 cmp = strcmp(name, list->entries[i]->name);
124 if (cmp < 0)
125 last = i;
126 else if (cmp > 0)
127 first = i+1;
128 else
129 return i;
130 }
131
132 /* not found, return negative insertion-index+1 */
133 return -(first+1);
869c9031
KS
134}
135
136struct udev_list_entry *udev_list_entry_add(struct udev_list *list, const char *name, const char *value)
137{
912541b0
KS
138 struct udev_list_entry *entry;
139 int i = 0;
140
141 if (list->unique) {
142 /* lookup existing name or insertion-index */
143 i = list_search(list, name);
144 if (i >= 0) {
145 entry = list->entries[i];
146
912541b0
KS
147 free(entry->value);
148 if (value == NULL) {
149 entry->value = NULL;
912541b0
KS
150 return entry;
151 }
152 entry->value = strdup(value);
153 if (entry->value == NULL)
154 return NULL;
912541b0
KS
155 return entry;
156 }
157 }
158
159 /* add new name */
160 entry = calloc(1, sizeof(struct udev_list_entry));
161 if (entry == NULL)
162 return NULL;
163 entry->name = strdup(name);
164 if (entry->name == NULL) {
165 free(entry);
166 return NULL;
167 }
168 if (value != NULL) {
169 entry->value = strdup(value);
170 if (entry->value == NULL) {
171 free(entry->name);
172 free(entry);
173 return NULL;
174 }
175 }
176
177 if (list->unique) {
178 /* allocate or enlarge sorted array if needed */
179 if (list->entries_cur >= list->entries_max) {
180 unsigned int add;
181
182 add = list->entries_max;
183 if (add < 1)
184 add = 64;
185 list->entries = realloc(list->entries, (list->entries_max + add) * sizeof(struct udev_list_entry *));
186 if (list->entries == NULL) {
187 free(entry->name);
188 free(entry->value);
64825d3c 189 free(entry);
912541b0
KS
190 return NULL;
191 }
192 list->entries_max += add;
193 }
194
195 /* the negative i returned the insertion index */
196 i = (-i)-1;
197
198 /* insert into sorted list */
199 if ((unsigned int)i < list->entries_cur)
200 udev_list_entry_insert_before(entry, list->entries[i]);
201 else
202 udev_list_entry_append(entry, list);
203
204 /* insert into sorted array */
205 memmove(&list->entries[i+1], &list->entries[i],
206 (list->entries_cur - i) * sizeof(struct udev_list_entry *));
207 list->entries[i] = entry;
208 list->entries_cur++;
209 } else {
210 udev_list_entry_append(entry, list);
211 }
212
912541b0 213 return entry;
e345e267
KS
214}
215
1e78dcbe 216void udev_list_entry_delete(struct udev_list_entry *entry)
e345e267 217{
912541b0
KS
218 if (entry->list->entries != NULL) {
219 int i;
220 struct udev_list *list = entry->list;
221
222 /* remove entry from sorted array */
223 i = list_search(list, entry->name);
224 if (i >= 0) {
225 memmove(&list->entries[i], &list->entries[i+1],
226 ((list->entries_cur-1) - i) * sizeof(struct udev_list_entry *));
227 list->entries_cur--;
228 }
229 }
230
231 udev_list_node_remove(&entry->node);
232 free(entry->name);
233 free(entry->value);
234 free(entry);
e345e267
KS
235}
236
869c9031 237void udev_list_cleanup(struct udev_list *list)
e345e267 238{
912541b0
KS
239 struct udev_list_entry *entry_loop;
240 struct udev_list_entry *entry_tmp;
241
242 free(list->entries);
243 list->entries = NULL;
244 list->entries_cur = 0;
245 list->entries_max = 0;
246 udev_list_entry_foreach_safe(entry_loop, entry_tmp, udev_list_get_entry(list))
247 udev_list_entry_delete(entry_loop);
be7f7f57
KS
248}
249
869c9031 250struct udev_list_entry *udev_list_get_entry(struct udev_list *list)
e345e267 251{
912541b0
KS
252 if (udev_list_node_is_empty(&list->node))
253 return NULL;
254 return list_node_to_entry(list->node.next);
e345e267
KS
255}
256
1e511322
KS
257/**
258 * udev_list_entry_get_next:
259 * @list_entry: current entry
260 *
21dbe43a
KS
261 * Get the next entry from the list.
262 *
263 * Returns: udev_list_entry, #NULL if no more entries are available.
1e511322 264 */
54cf0b7f 265_public_ struct udev_list_entry *udev_list_entry_get_next(struct udev_list_entry *list_entry)
e345e267 266{
912541b0
KS
267 struct udev_list_node *next;
268
269 if (list_entry == NULL)
270 return NULL;
271 next = list_entry->node.next;
272 /* empty list or no more entries */
273 if (next == &list_entry->list->node)
274 return NULL;
275 return list_node_to_entry(next);
e345e267
KS
276}
277
1e511322
KS
278/**
279 * udev_list_entry_get_by_name:
280 * @list_entry: current entry
281 * @name: name string to match
282 *
21dbe43a
KS
283 * Lookup an entry in the list with a certain name.
284 *
285 * Returns: udev_list_entry, #NULL if no matching entry is found.
1e511322 286 */
54cf0b7f 287_public_ struct udev_list_entry *udev_list_entry_get_by_name(struct udev_list_entry *list_entry, const char *name)
bc8184ed 288{
912541b0 289 int i;
bc8184ed 290
912541b0
KS
291 if (list_entry == NULL)
292 return NULL;
869c9031 293
912541b0
KS
294 if (!list_entry->list->unique)
295 return NULL;
869c9031 296
912541b0
KS
297 i = list_search(list_entry->list, name);
298 if (i < 0)
299 return NULL;
300 return list_entry->list->entries[i];
bc8184ed
KS
301}
302
1e511322
KS
303/**
304 * udev_list_entry_get_name:
305 * @list_entry: current entry
306 *
21dbe43a
KS
307 * Get the name of a list entry.
308 *
1e511322
KS
309 * Returns: the name string of this entry.
310 */
54cf0b7f 311_public_ const char *udev_list_entry_get_name(struct udev_list_entry *list_entry)
e345e267 312{
912541b0
KS
313 if (list_entry == NULL)
314 return NULL;
315 return list_entry->name;
e345e267
KS
316}
317
1e511322
KS
318/**
319 * udev_list_entry_get_value:
320 * @list_entry: current entry
321 *
21dbe43a
KS
322 * Get the value of list entry.
323 *
1e511322
KS
324 * Returns: the value string of this entry.
325 */
54cf0b7f 326_public_ const char *udev_list_entry_get_value(struct udev_list_entry *list_entry)
e345e267 327{
912541b0
KS
328 if (list_entry == NULL)
329 return NULL;
330 return list_entry->value;
e345e267 331}
df1dcc09 332
8958da13 333int udev_list_entry_get_num(struct udev_list_entry *list_entry)
df1dcc09 334{
912541b0
KS
335 if (list_entry == NULL)
336 return -EINVAL;
337 return list_entry->num;
df1dcc09
KS
338}
339
8958da13 340void udev_list_entry_set_num(struct udev_list_entry *list_entry, int num)
df1dcc09 341{
912541b0
KS
342 if (list_entry == NULL)
343 return;
344 list_entry->num = num;
df1dcc09 345}