]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/libudev/libudev-list.c
Merge pull request #12753 from jrouleau/fix/hibernate-resume-timeout
[thirdparty/systemd.git] / src / libudev / libudev-list.c
CommitLineData
53e1b683 1/* SPDX-License-Identifier: LGPL-2.1+ */
e345e267 2
b5efdb8a 3#include "alloc-util.h"
c0113082 4#include "hashmap.h"
5ea78a39 5#include "libudev-list-internal.h"
c0113082
YW
6#include "list.h"
7#include "sort-util.h"
e345e267 8
ce1d6d7f
KS
9/**
10 * SECTION:libudev-list
11 * @short_description: list operation
12 *
13 * Libudev list operations.
14 */
15
1e511322
KS
16/**
17 * udev_list_entry:
18 *
ce1d6d7f
KS
19 * Opaque object representing one entry in a list. An entry contains
20 * contains a name, and optionally a value.
1e511322 21 */
0de33a61 22struct udev_list_entry {
912541b0
KS
23 struct udev_list *list;
24 char *name;
25 char *value;
c0113082
YW
26
27 LIST_FIELDS(struct udev_list_entry, entries);
e345e267
KS
28};
29
dcf557f7 30struct udev_list {
c0113082
YW
31 Hashmap *unique_entries;
32 LIST_HEAD(struct udev_list_entry, entries);
33 bool unique:1;
34 bool uptodate:1;
dcf557f7
YW
35};
36
c0113082
YW
37static struct udev_list_entry *udev_list_entry_free(struct udev_list_entry *entry) {
38 if (!entry)
39 return NULL;
e345e267 40
c0113082
YW
41 if (entry->list) {
42 if (entry->list->unique)
43 hashmap_remove(entry->list->unique_entries, entry->name);
44 else
45 LIST_REMOVE(entries, entry->list->entries, entry);
46 }
e345e267 47
c0113082
YW
48 free(entry->name);
49 free(entry->value);
0de33a61 50
c0113082 51 return mfree(entry);
e345e267
KS
52}
53
c0113082 54DEFINE_TRIVIAL_CLEANUP_FUNC(struct udev_list_entry *, udev_list_entry_free);
0de33a61 55
dcf557f7
YW
56struct udev_list *udev_list_new(bool unique) {
57 struct udev_list *list;
58
59 list = new(struct udev_list, 1);
60 if (!list)
61 return NULL;
62
63 *list = (struct udev_list) {
64 .unique = unique,
65 };
66
dcf557f7 67 return list;
0de33a61
KS
68}
69
c0113082
YW
70struct udev_list_entry *udev_list_entry_add(struct udev_list *list, const char *_name, const char *_value) {
71 _cleanup_(udev_list_entry_freep) struct udev_list_entry *entry = NULL;
72 _cleanup_free_ char *name = NULL, *value = NULL;
73 int r;
912541b0 74
c0113082 75 assert(list);
869c9031 76
c0113082
YW
77 name = strdup(_name);
78 if (!name)
79 return NULL;
912541b0 80
c0113082
YW
81 if (_value) {
82 value = strdup(_value);
83 if (!value)
84 return NULL;
912541b0
KS
85 }
86
c0113082 87 entry = new(struct udev_list_entry, 1);
62d74c78 88 if (!entry)
912541b0 89 return NULL;
6b430fdb 90
c0113082
YW
91 *entry = (struct udev_list_entry) {
92 .list = list,
93 .name = TAKE_PTR(name),
94 .value = TAKE_PTR(value),
95 };
912541b0
KS
96
97 if (list->unique) {
c0113082
YW
98 r = hashmap_ensure_allocated(&list->unique_entries, &string_hash_ops);
99 if (r < 0)
100 return NULL;
912541b0 101
c0113082 102 udev_list_entry_free(hashmap_get(list->unique_entries, entry->name));
912541b0 103
c0113082
YW
104 r = hashmap_put(list->unique_entries, entry->name, entry);
105 if (r < 0)
106 return NULL;
912541b0 107
c0113082 108 list->uptodate = false;
62d74c78 109 } else
c0113082 110 LIST_APPEND(entries, list->entries, entry);
912541b0 111
c0113082 112 return TAKE_PTR(entry);
e345e267
KS
113}
114
5ea78a39 115void udev_list_cleanup(struct udev_list *list) {
c0113082 116 struct udev_list_entry *i, *n;
912541b0 117
c0113082
YW
118 if (!list)
119 return;
120
121 if (list->unique) {
122 hashmap_clear_with_destructor(list->unique_entries, udev_list_entry_free);
123 list->uptodate = false;
124 } else
125 LIST_FOREACH_SAFE(entries, i, n, list->entries)
126 udev_list_entry_free(i);
be7f7f57 127}
dcf557f7
YW
128
129struct udev_list *udev_list_free(struct udev_list *list) {
130 if (!list)
131 return NULL;
132
133 udev_list_cleanup(list);
c0113082 134 hashmap_free(list->unique_entries);
dcf557f7
YW
135
136 return mfree(list);
137}
be7f7f57 138
c0113082
YW
139static int udev_list_entry_compare_func(struct udev_list_entry * const *a, struct udev_list_entry * const *b) {
140 return strcmp((*a)->name, (*b)->name);
141}
142
5ea78a39 143struct udev_list_entry *udev_list_get_entry(struct udev_list *list) {
c0113082 144 if (!list)
912541b0 145 return NULL;
c0113082
YW
146
147 if (list->unique && !list->uptodate) {
148 size_t n;
149
150 LIST_HEAD_INIT(list->entries);
151
152 n = hashmap_size(list->unique_entries);
153 if (n == 0)
154 ;
155 else if (n == 1)
156 LIST_PREPEND(entries, list->entries, hashmap_first(list->unique_entries));
157 else {
158 _cleanup_free_ struct udev_list_entry **buf = NULL;
159 struct udev_list_entry *entry, **p;
160 Iterator i;
161 size_t j;
162
163 buf = new(struct udev_list_entry *, n);
164 if (!buf)
165 return NULL;
166
167 p = buf;
168 HASHMAP_FOREACH(entry, list->unique_entries, i)
169 *p++ = entry;
170
171 typesafe_qsort(buf, n, udev_list_entry_compare_func);
172
173 for (j = n; j > 0; j--)
174 LIST_PREPEND(entries, list->entries, buf[j-1]);
175 }
176
177 list->uptodate = true;
178 }
179
180 return list->entries;
e345e267
KS
181}
182
1e511322
KS
183/**
184 * udev_list_entry_get_next:
185 * @list_entry: current entry
186 *
21dbe43a
KS
187 * Get the next entry from the list.
188 *
189 * Returns: udev_list_entry, #NULL if no more entries are available.
1e511322 190 */
5ea78a39 191_public_ struct udev_list_entry *udev_list_entry_get_next(struct udev_list_entry *list_entry) {
f921b457 192 if (!list_entry)
912541b0 193 return NULL;
c0113082 194 if (list_entry->list->unique && !list_entry->list->uptodate)
912541b0 195 return NULL;
c0113082 196 return list_entry->entries_next;
e345e267
KS
197}
198
1e511322
KS
199/**
200 * udev_list_entry_get_by_name:
201 * @list_entry: current entry
202 * @name: name string to match
203 *
21dbe43a
KS
204 * Lookup an entry in the list with a certain name.
205 *
206 * Returns: udev_list_entry, #NULL if no matching entry is found.
1e511322 207 */
5ea78a39 208_public_ struct udev_list_entry *udev_list_entry_get_by_name(struct udev_list_entry *list_entry, const char *name) {
f921b457 209 if (!list_entry)
912541b0 210 return NULL;
c0113082 211 if (!list_entry->list->unique || !list_entry->list->uptodate)
912541b0 212 return NULL;
c0113082 213 return hashmap_get(list_entry->list->unique_entries, name);
bc8184ed
KS
214}
215
1e511322
KS
216/**
217 * udev_list_entry_get_name:
218 * @list_entry: current entry
219 *
21dbe43a
KS
220 * Get the name of a list entry.
221 *
1e511322
KS
222 * Returns: the name string of this entry.
223 */
5ea78a39 224_public_ const char *udev_list_entry_get_name(struct udev_list_entry *list_entry) {
f921b457 225 if (!list_entry)
912541b0
KS
226 return NULL;
227 return list_entry->name;
e345e267
KS
228}
229
1e511322
KS
230/**
231 * udev_list_entry_get_value:
232 * @list_entry: current entry
233 *
21dbe43a
KS
234 * Get the value of list entry.
235 *
1e511322
KS
236 * Returns: the value string of this entry.
237 */
5ea78a39 238_public_ const char *udev_list_entry_get_value(struct udev_list_entry *list_entry) {
f921b457 239 if (!list_entry)
912541b0
KS
240 return NULL;
241 return list_entry->value;
e345e267 242}