~ubuntu-branches/ubuntu/trusty/systemd/trusty

« back to all changes in this revision

Viewing changes to .pc/debian-changes/src/udev/udevadm-hwdb.c

  • Committer: Package Import Robot
  • Author(s): Michael Biebl, Michael Biebl, Michael Stapelberg, Daniel Schaal, Ondrej Balaz
  • Date: 2013-09-12 00:13:11 UTC
  • mfrom: (1.1.11) (9.1.2 experimental)
  • mto: This revision was merged to the branch mainline in revision 53.
  • Revision ID: package-import@ubuntu.com-20130912001311-dz35it34wr2lbday
Tags: 204-3
[ Michael Biebl ]
* Upload to unstable.
* Use /bin/bash in debug-shell.service as Debian doesn't have /sbin/sushell.
* Only import net.ifaces cmdline property for network devices.
* Generate strict dependencies between the binary packages using a
  shlibs.local file and add an explicit versioned dependency on
  libsystemd-login0 to systemd to ensure packages are upgraded in sync.
  Closes: #719444
* Drop obsolete Replaces: libudev0 from udev package.
* Use correct paths for various binaries, like /sbin/quotaon, which are
  installed in / and not /usr in Debian.  Closes: #721347
* Don't install kernel-install(8) man page since we don't install the
  corresponding binary either.  Closes: #722180
* Cherry-pick upstream fixes to make switching runlevels and starting
  reboot via ctrl-alt-del more robust.
* Cherry-pick upstream fix to properly apply ACLs to Journal files.

[ Michael Stapelberg ]
* Make systemctl enable|disable call update-rc.d for SysV init scripts.
  Closes: #709780
* Don't mount /tmp as tmpfs by default and make it possible to enable this
  feature via "systemctl enable tmp.mount".

[ Daniel Schaal ]
* Add bug-script to systemd and udev.  Closes: #711245

[ Ondrej Balaz ]
* Recognize discard option in /etc/crypttab.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/***
 
2
  This file is part of systemd.
 
3
 
 
4
  Copyright 2012 Kay Sievers <kay@vrfy.org>
 
5
 
 
6
  systemd is free software; you can redistribute it and/or modify it
 
7
  under the terms of the GNU Lesser General Public License as published by
 
8
  the Free Software Foundation; either version 2.1 of the License, or
 
9
  (at your option) any later version.
 
10
 
 
11
  systemd is distributed in the hope that it will be useful, but
 
12
  WITHOUT ANY WARRANTY; without even the implied warranty of
 
13
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 
14
  Lesser General Public License for more details.
 
15
 
 
16
  You should have received a copy of the GNU Lesser General Public License
 
17
  along with systemd; If not, see <http://www.gnu.org/licenses/>.
 
18
***/
 
19
 
 
20
#include <stdlib.h>
 
21
#include <unistd.h>
 
22
#include <getopt.h>
 
23
#include <string.h>
 
24
 
 
25
#include "util.h"
 
26
#include "strbuf.h"
 
27
#include "conf-files.h"
 
28
 
 
29
#include "udev.h"
 
30
#include "libudev-hwdb-def.h"
 
31
 
 
32
/*
 
33
 * Generic udev properties, key/value database based on modalias strings.
 
34
 * Uses a Patricia/radix trie to index all matches for efficient lookup.
 
35
 */
 
36
 
 
37
static const char * const conf_file_dirs[] = {
 
38
        "/etc/udev/hwdb.d",
 
39
        UDEVLIBEXECDIR "/hwdb.d",
 
40
        NULL
 
41
};
 
42
 
 
43
/* in-memory trie objects */
 
44
struct trie {
 
45
        struct trie_node *root;
 
46
        struct strbuf *strings;
 
47
 
 
48
        size_t nodes_count;
 
49
        size_t children_count;
 
50
        size_t values_count;
 
51
};
 
52
 
 
53
struct trie_node {
 
54
        /* prefix, common part for all children of this node */
 
55
        size_t prefix_off;
 
56
 
 
57
        /* sorted array of pointers to children nodes */
 
58
        struct trie_child_entry *children;
 
59
        uint8_t children_count;
 
60
 
 
61
        /* sorted array of key/value pairs */
 
62
        struct trie_value_entry *values;
 
63
        size_t values_count;
 
64
};
 
65
 
 
66
/* children array item with char (0-255) index */
 
67
struct trie_child_entry {
 
68
        uint8_t c;
 
69
        struct trie_node *child;
 
70
};
 
71
 
 
72
/* value array item with key/value pairs */
 
73
struct trie_value_entry {
 
74
        size_t key_off;
 
75
        size_t value_off;
 
76
};
 
77
 
 
78
static int trie_children_cmp(const void *v1, const void *v2) {
 
79
        const struct trie_child_entry *n1 = v1;
 
80
        const struct trie_child_entry *n2 = v2;
 
81
 
 
82
        return n1->c - n2->c;
 
83
}
 
84
 
 
85
static int node_add_child(struct trie *trie, struct trie_node *node, struct trie_node *node_child, uint8_t c) {
 
86
        struct trie_child_entry *child;
 
87
 
 
88
        /* extend array, add new entry, sort for bisection */
 
89
        child = realloc(node->children, (node->children_count + 1) * sizeof(struct trie_child_entry));
 
90
        if (!child)
 
91
                return -ENOMEM;
 
92
 
 
93
        node->children = child;
 
94
        trie->children_count++;
 
95
        node->children[node->children_count].c = c;
 
96
        node->children[node->children_count].child = node_child;
 
97
        node->children_count++;
 
98
        qsort(node->children, node->children_count, sizeof(struct trie_child_entry), trie_children_cmp);
 
99
        trie->nodes_count++;
 
100
 
 
101
        return 0;
 
102
}
 
103
 
 
104
static struct trie_node *node_lookup(const struct trie_node *node, uint8_t c) {
 
105
        struct trie_child_entry *child;
 
106
        struct trie_child_entry search;
 
107
 
 
108
        search.c = c;
 
109
        child = bsearch(&search, node->children, node->children_count, sizeof(struct trie_child_entry), trie_children_cmp);
 
110
        if (child)
 
111
                return child->child;
 
112
        return NULL;
 
113
}
 
114
 
 
115
static void trie_node_cleanup(struct trie_node *node) {
 
116
        size_t i;
 
117
 
 
118
        for (i = 0; i < node->children_count; i++)
 
119
                trie_node_cleanup(node->children[i].child);
 
120
        free(node->children);
 
121
        free(node->values);
 
122
        free(node);
 
123
}
 
124
 
 
125
static int trie_values_cmp(const void *v1, const void *v2, void *arg) {
 
126
        const struct trie_value_entry *val1 = v1;
 
127
        const struct trie_value_entry *val2 = v2;
 
128
        struct trie *trie = arg;
 
129
 
 
130
        return strcmp(trie->strings->buf + val1->key_off,
 
131
                      trie->strings->buf + val2->key_off);
 
132
}
 
133
 
 
134
static int trie_node_add_value(struct trie *trie, struct trie_node *node,
 
135
                          const char *key, const char *value) {
 
136
        ssize_t k, v;
 
137
        struct trie_value_entry *val;
 
138
 
 
139
        k = strbuf_add_string(trie->strings, key, strlen(key));
 
140
        if (k < 0)
 
141
                return k;
 
142
        v = strbuf_add_string(trie->strings, value, strlen(value));
 
143
        if (v < 0)
 
144
                return v;
 
145
 
 
146
        if (node->values_count) {
 
147
                struct trie_value_entry search = {
 
148
                        .key_off = k,
 
149
                        .value_off = v,
 
150
                };
 
151
 
 
152
                val = xbsearch_r(&search, node->values, node->values_count, sizeof(struct trie_value_entry), trie_values_cmp, trie);
 
153
                if (val) {
 
154
                        /* replace existing earlier key with new value */
 
155
                        val->value_off = v;
 
156
                        return 0;
 
157
                }
 
158
        }
 
159
 
 
160
        /* extend array, add new entry, sort for bisection */
 
161
        val = realloc(node->values, (node->values_count + 1) * sizeof(struct trie_value_entry));
 
162
        if (!val)
 
163
                return -ENOMEM;
 
164
        trie->values_count++;
 
165
        node->values = val;
 
166
        node->values[node->values_count].key_off = k;
 
167
        node->values[node->values_count].value_off = v;
 
168
        node->values_count++;
 
169
        qsort_r(node->values, node->values_count, sizeof(struct trie_value_entry), trie_values_cmp, trie);
 
170
        return 0;
 
171
}
 
172
 
 
173
static int trie_insert(struct trie *trie, struct trie_node *node, const char *search,
 
174
                       const char *key, const char *value) {
 
175
        size_t i = 0;
 
176
        int err = 0;
 
177
 
 
178
        for (;;) {
 
179
                size_t p;
 
180
                uint8_t c;
 
181
                struct trie_node *child;
 
182
 
 
183
                for (p = 0; (c = trie->strings->buf[node->prefix_off + p]); p++) {
 
184
                        _cleanup_free_ char *s = NULL;
 
185
                        ssize_t off;
 
186
                        _cleanup_free_ struct trie_node *new_child = NULL;
 
187
 
 
188
                        if (c == search[i + p])
 
189
                                continue;
 
190
 
 
191
                        /* split node */
 
192
                        new_child = calloc(sizeof(struct trie_node), 1);
 
193
                        if (!new_child)
 
194
                                return -ENOMEM;
 
195
 
 
196
                        /* move values from parent to child */
 
197
                        new_child->prefix_off = node->prefix_off + p+1;
 
198
                        new_child->children = node->children;
 
199
                        new_child->children_count = node->children_count;
 
200
                        new_child->values = node->values;
 
201
                        new_child->values_count = node->values_count;
 
202
 
 
203
                        /* update parent; use strdup() because the source gets realloc()d */
 
204
                        s = strndup(trie->strings->buf + node->prefix_off, p);
 
205
                        if (!s)
 
206
                                return -ENOMEM;
 
207
 
 
208
                        off = strbuf_add_string(trie->strings, s, p);
 
209
                        if (off < 0)
 
210
                                return off;
 
211
 
 
212
                        node->prefix_off = off;
 
213
                        node->children = NULL;
 
214
                        node->children_count = 0;
 
215
                        node->values = NULL;
 
216
                        node->values_count = 0;
 
217
                        err = node_add_child(trie, node, new_child, c);
 
218
                        if (err)
 
219
                                return err;
 
220
 
 
221
                        new_child = NULL; /* avoid cleanup */
 
222
                        break;
 
223
                }
 
224
                i += p;
 
225
 
 
226
                c = search[i];
 
227
                if (c == '\0')
 
228
                        return trie_node_add_value(trie, node, key, value);
 
229
 
 
230
                child = node_lookup(node, c);
 
231
                if (!child) {
 
232
                        ssize_t off;
 
233
 
 
234
                        /* new child */
 
235
                        child = calloc(sizeof(struct trie_node), 1);
 
236
                        if (!child)
 
237
                                return -ENOMEM;
 
238
 
 
239
                        off = strbuf_add_string(trie->strings, search + i+1, strlen(search + i+1));
 
240
                        if (off < 0) {
 
241
                                free(child);
 
242
                                return off;
 
243
                        }
 
244
 
 
245
                        child->prefix_off = off;
 
246
                        err = node_add_child(trie, node, child, c);
 
247
                        if (err) {
 
248
                                free(child);
 
249
                                return err;
 
250
                        }
 
251
 
 
252
                        return trie_node_add_value(trie, child, key, value);
 
253
                }
 
254
 
 
255
                node = child;
 
256
                i++;
 
257
        }
 
258
}
 
259
 
 
260
struct trie_f {
 
261
        FILE *f;
 
262
        struct trie *trie;
 
263
        uint64_t strings_off;
 
264
 
 
265
        uint64_t nodes_count;
 
266
        uint64_t children_count;
 
267
        uint64_t values_count;
 
268
};
 
269
 
 
270
/* calculate the storage space for the nodes, children arrays, value arrays */
 
271
static void trie_store_nodes_size(struct trie_f *trie, struct trie_node *node) {
 
272
        uint64_t i;
 
273
 
 
274
        for (i = 0; i < node->children_count; i++)
 
275
                trie_store_nodes_size(trie, node->children[i].child);
 
276
 
 
277
        trie->strings_off += sizeof(struct trie_node_f);
 
278
        for (i = 0; i < node->children_count; i++)
 
279
                trie->strings_off += sizeof(struct trie_child_entry_f);
 
280
        for (i = 0; i < node->values_count; i++)
 
281
                trie->strings_off += sizeof(struct trie_value_entry_f);
 
282
}
 
283
 
 
284
static int64_t trie_store_nodes(struct trie_f *trie, struct trie_node *node) {
 
285
        uint64_t i;
 
286
        struct trie_node_f n = {
 
287
                .prefix_off = htole64(trie->strings_off + node->prefix_off),
 
288
                .children_count = node->children_count,
 
289
                .values_count = htole64(node->values_count),
 
290
        };
 
291
        struct trie_child_entry_f *children = NULL;
 
292
        int64_t node_off;
 
293
 
 
294
        if (node->children_count) {
 
295
                children = new0(struct trie_child_entry_f, node->children_count);
 
296
                if (!children)
 
297
                        return -ENOMEM;
 
298
        }
 
299
 
 
300
        /* post-order recursion */
 
301
        for (i = 0; i < node->children_count; i++) {
 
302
                int64_t child_off;
 
303
 
 
304
                child_off = trie_store_nodes(trie, node->children[i].child);
 
305
                if (child_off < 0)
 
306
                        return child_off;
 
307
                children[i].c = node->children[i].c;
 
308
                children[i].child_off = htole64(child_off);
 
309
        }
 
310
 
 
311
        /* write node */
 
312
        node_off = ftello(trie->f);
 
313
        fwrite(&n, sizeof(struct trie_node_f), 1, trie->f);
 
314
        trie->nodes_count++;
 
315
 
 
316
        /* append children array */
 
317
        if (node->children_count) {
 
318
                fwrite(children, sizeof(struct trie_child_entry_f), node->children_count, trie->f);
 
319
                trie->children_count += node->children_count;
 
320
                free(children);
 
321
        }
 
322
 
 
323
        /* append values array */
 
324
        for (i = 0; i < node->values_count; i++) {
 
325
                struct trie_value_entry_f v = {
 
326
                        .key_off = htole64(trie->strings_off + node->values[i].key_off),
 
327
                        .value_off = htole64(trie->strings_off + node->values[i].value_off),
 
328
                };
 
329
 
 
330
                fwrite(&v, sizeof(struct trie_value_entry_f), 1, trie->f);
 
331
                trie->values_count++;
 
332
        }
 
333
 
 
334
        return node_off;
 
335
}
 
336
 
 
337
static int trie_store(struct trie *trie, const char *filename) {
 
338
        struct trie_f t = {
 
339
                .trie = trie,
 
340
        };
 
341
        char *filename_tmp;
 
342
        int64_t pos;
 
343
        int64_t root_off;
 
344
        int64_t size;
 
345
        struct trie_header_f h = {
 
346
                .signature = HWDB_SIG,
 
347
                .tool_version = htole64(atoi(VERSION)),
 
348
                .header_size = htole64(sizeof(struct trie_header_f)),
 
349
                .node_size = htole64(sizeof(struct trie_node_f)),
 
350
                .child_entry_size = htole64(sizeof(struct trie_child_entry_f)),
 
351
                .value_entry_size = htole64(sizeof(struct trie_value_entry_f)),
 
352
        };
 
353
        int err;
 
354
 
 
355
        /* calculate size of header, nodes, children entries, value entries */
 
356
        t.strings_off = sizeof(struct trie_header_f);
 
357
        trie_store_nodes_size(&t, trie->root);
 
358
 
 
359
        err = fopen_temporary(filename , &t.f, &filename_tmp);
 
360
        if (err < 0)
 
361
                return err;
 
362
        fchmod(fileno(t.f), 0444);
 
363
 
 
364
        /* write nodes */
 
365
        fseeko(t.f, sizeof(struct trie_header_f), SEEK_SET);
 
366
        root_off = trie_store_nodes(&t, trie->root);
 
367
        h.nodes_root_off = htole64(root_off);
 
368
        pos = ftello(t.f);
 
369
        h.nodes_len = htole64(pos - sizeof(struct trie_header_f));
 
370
 
 
371
        /* write string buffer */
 
372
        fwrite(trie->strings->buf, trie->strings->len, 1, t.f);
 
373
        h.strings_len = htole64(trie->strings->len);
 
374
 
 
375
        /* write header */
 
376
        size = ftello(t.f);
 
377
        h.file_size = htole64(size);
 
378
        fseeko(t.f, 0, SEEK_SET);
 
379
        fwrite(&h, sizeof(struct trie_header_f), 1, t.f);
 
380
        err = ferror(t.f);
 
381
        if (err)
 
382
                err = -errno;
 
383
        fclose(t.f);
 
384
        if (err < 0 || rename(filename_tmp, filename) < 0) {
 
385
                unlink(filename_tmp);
 
386
                goto out;
 
387
        }
 
388
 
 
389
        log_debug("=== trie on-disk ===\n");
 
390
        log_debug("size:             %8llu bytes\n", (unsigned long long)size);
 
391
        log_debug("header:           %8zu bytes\n", sizeof(struct trie_header_f));
 
392
        log_debug("nodes:            %8llu bytes (%8llu)\n",
 
393
                  (unsigned long long)t.nodes_count * sizeof(struct trie_node_f), (unsigned long long)t.nodes_count);
 
394
        log_debug("child pointers:   %8llu bytes (%8llu)\n",
 
395
                  (unsigned long long)t.children_count * sizeof(struct trie_child_entry_f), (unsigned long long)t.children_count);
 
396
        log_debug("value pointers:   %8llu bytes (%8llu)\n",
 
397
                  (unsigned long long)t.values_count * sizeof(struct trie_value_entry_f), (unsigned long long)t.values_count);
 
398
        log_debug("string store:     %8llu bytes\n", (unsigned long long)trie->strings->len);
 
399
        log_debug("strings start:    %8llu\n", (unsigned long long) t.strings_off);
 
400
out:
 
401
        free(filename_tmp);
 
402
        return err;
 
403
}
 
404
 
 
405
static int import_file(struct trie *trie, const char *filename) {
 
406
        FILE *f;
 
407
        char line[LINE_MAX];
 
408
        char match[LINE_MAX];
 
409
        char cond[LINE_MAX];
 
410
 
 
411
        f = fopen(filename, "re");
 
412
        if (f == NULL)
 
413
                return -errno;
 
414
 
 
415
        match[0] = '\0';
 
416
        cond[0] = '\0';
 
417
        while (fgets(line, sizeof(line), f)) {
 
418
                size_t len;
 
419
 
 
420
                if (line[0] == '#')
 
421
                        continue;
 
422
 
 
423
                /* new line, new record */
 
424
                if (line[0] == '\n') {
 
425
                        match[0] = '\0';
 
426
                        cond[0] = '\0';
 
427
                        continue;
 
428
                }
 
429
 
 
430
                /* remove newline */
 
431
                len = strlen(line);
 
432
                if (len < 2)
 
433
                        continue;
 
434
                line[len-1] = '\0';
 
435
 
 
436
                /* start of new record */
 
437
                if (match[0] == '\0') {
 
438
                        strcpy(match, line);
 
439
                        cond[0] = '\0';
 
440
                        continue;
 
441
                }
 
442
 
 
443
                if (line[0] == '+') {
 
444
                        strcpy(cond, line);
 
445
                        continue;
 
446
                }
 
447
 
 
448
                /* TODO: support +; skip the entire record until we support it */
 
449
                if (cond[0] != '\0')
 
450
                        continue;
 
451
 
 
452
                /* value lines */
 
453
                if (line[0] == ' ') {
 
454
                        char *value;
 
455
 
 
456
                        value = strchr(line, '=');
 
457
                        if (!value)
 
458
                                continue;
 
459
                        value[0] = '\0';
 
460
                        value++;
 
461
                        trie_insert(trie, trie->root, match, line, value);
 
462
                }
 
463
        }
 
464
        fclose(f);
 
465
        return 0;
 
466
}
 
467
 
 
468
static void help(void) {
 
469
        printf("Usage: udevadm hwdb OPTIONS\n"
 
470
               "  --update            update the hardware database\n"
 
471
               "  --test=<modalias>   query database and print result\n"
 
472
               "  --root=<path>       alternative root path in the filesystem\n"
 
473
               "  --help\n\n");
 
474
}
 
475
 
 
476
static int adm_hwdb(struct udev *udev, int argc, char *argv[]) {
 
477
        static const struct option options[] = {
 
478
                { "update", no_argument, NULL, 'u' },
 
479
                { "root", required_argument, NULL, 'r' },
 
480
                { "test", required_argument, NULL, 't' },
 
481
                { "help", no_argument, NULL, 'h' },
 
482
                {}
 
483
        };
 
484
        const char *test = NULL;
 
485
        const char *root = "";
 
486
        bool update = false;
 
487
        struct trie *trie = NULL;
 
488
        int err;
 
489
        int rc = EXIT_SUCCESS;
 
490
 
 
491
        for (;;) {
 
492
                int option;
 
493
 
 
494
                option = getopt_long(argc, argv, "ut:r:h", options, NULL);
 
495
                if (option == -1)
 
496
                        break;
 
497
 
 
498
                switch (option) {
 
499
                case 'u':
 
500
                        update = true;
 
501
                        break;
 
502
                case 't':
 
503
                        test = optarg;
 
504
                        break;
 
505
                case 'r':
 
506
                        root = optarg;
 
507
                        break;
 
508
                case 'h':
 
509
                        help();
 
510
                        return EXIT_SUCCESS;
 
511
                }
 
512
        }
 
513
 
 
514
        if (!update && !test) {
 
515
                help();
 
516
                return EXIT_SUCCESS;
 
517
        }
 
518
 
 
519
        if (update) {
 
520
                char **files, **f;
 
521
                _cleanup_free_ char *hwdb_bin = NULL;
 
522
 
 
523
                trie = calloc(sizeof(struct trie), 1);
 
524
                if (!trie) {
 
525
                        rc = EXIT_FAILURE;
 
526
                        goto out;
 
527
                }
 
528
 
 
529
                /* string store */
 
530
                trie->strings = strbuf_new();
 
531
                if (!trie->strings) {
 
532
                        rc = EXIT_FAILURE;
 
533
                        goto out;
 
534
                }
 
535
 
 
536
                /* index */
 
537
                trie->root = calloc(sizeof(struct trie_node), 1);
 
538
                if (!trie->root) {
 
539
                        rc = EXIT_FAILURE;
 
540
                        goto out;
 
541
                }
 
542
                trie->nodes_count++;
 
543
 
 
544
                err = conf_files_list_strv(&files, ".hwdb", root, conf_file_dirs);
 
545
                if (err < 0) {
 
546
                        log_error("failed to enumerate hwdb files: %s\n", strerror(-err));
 
547
                        rc = EXIT_FAILURE;
 
548
                        goto out;
 
549
                }
 
550
                STRV_FOREACH(f, files) {
 
551
                        log_debug("reading file '%s'", *f);
 
552
                        import_file(trie, *f);
 
553
                }
 
554
                strv_free(files);
 
555
 
 
556
                strbuf_complete(trie->strings);
 
557
 
 
558
                log_debug("=== trie in-memory ===\n");
 
559
                log_debug("nodes:            %8zu bytes (%8zu)\n",
 
560
                          trie->nodes_count * sizeof(struct trie_node), trie->nodes_count);
 
561
                log_debug("children arrays:  %8zu bytes (%8zu)\n",
 
562
                          trie->children_count * sizeof(struct trie_child_entry), trie->children_count);
 
563
                log_debug("values arrays:    %8zu bytes (%8zu)\n",
 
564
                          trie->values_count * sizeof(struct trie_value_entry), trie->values_count);
 
565
                log_debug("strings:          %8zu bytes\n",
 
566
                          trie->strings->len);
 
567
                log_debug("strings incoming: %8zu bytes (%8zu)\n",
 
568
                          trie->strings->in_len, trie->strings->in_count);
 
569
                log_debug("strings dedup'ed: %8zu bytes (%8zu)\n",
 
570
                          trie->strings->dedup_len, trie->strings->dedup_count);
 
571
 
 
572
                if (asprintf(&hwdb_bin, "%s/etc/udev/hwdb.bin", root) < 0) {
 
573
                        rc = EXIT_FAILURE;
 
574
                        goto out;
 
575
                }
 
576
                mkdir_parents(hwdb_bin, 0755);
 
577
                err = trie_store(trie, hwdb_bin);
 
578
                if (err < 0) {
 
579
                        log_error("Failure writing database %s: %s", hwdb_bin, strerror(-err));
 
580
                        rc = EXIT_FAILURE;
 
581
                }
 
582
        }
 
583
 
 
584
        if (test) {
 
585
                struct udev_hwdb *hwdb = udev_hwdb_new(udev);
 
586
 
 
587
                if (hwdb) {
 
588
                        struct udev_list_entry *entry;
 
589
 
 
590
                        udev_list_entry_foreach(entry, udev_hwdb_get_properties_list_entry(hwdb, test, 0))
 
591
                                printf("%s=%s\n", udev_list_entry_get_name(entry), udev_list_entry_get_value(entry));
 
592
                        hwdb = udev_hwdb_unref(hwdb);
 
593
                }
 
594
        }
 
595
out:
 
596
        if (trie) {
 
597
                if (trie->root)
 
598
                        trie_node_cleanup(trie->root);
 
599
                strbuf_cleanup(trie->strings);
 
600
                free(trie);
 
601
        }
 
602
        return rc;
 
603
}
 
604
 
 
605
const struct udevadm_cmd udevadm_hwdb = {
 
606
        .name = "hwdb",
 
607
        .cmd = adm_hwdb,
 
608
        .help = "maintain the hardware database index",
 
609
};