blob: 1698d7fc96749f0eaa55d388ea6ffe2fbe8e56db [file] [log] [blame]
Lucas De Marchi8f923be2011-12-03 04:28:49 -02001/*
2 * libkmod - interface to kernel module operations
3 *
Lucas De Marchia66a6a92012-01-09 00:40:50 -02004 * Copyright (C) 2011-2012 ProFUSION embedded systems
Lucas De Marchi8f923be2011-12-03 04:28:49 -02005 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
Lucas De Marchicb451f32011-12-12 18:24:35 -02008 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
Lucas De Marchi8f923be2011-12-03 04:28:49 -020010 *
11 * This library is distributed in the hope that it will be useful,
12 * but 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
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
19 */
Lucas De Marchie8847fd2011-11-30 15:23:28 -020020
21#include <arpa/inet.h> /* htonl */
22#include <stdlib.h>
23#include <stdio.h>
24#include <string.h>
25#include <errno.h>
26#include <fnmatch.h>
Gustavo Sverzut Barbieri405f6142011-12-08 14:36:30 -020027#include <assert.h>
Lucas De Marchie8847fd2011-11-30 15:23:28 -020028
29#include "libkmod-private.h"
30#include "libkmod-index.h"
31#include "macro.h"
32
Lucas De Marchi8f923be2011-12-03 04:28:49 -020033/* index.c: module index file shared functions for modprobe and depmod */
34
Gustavo Sverzut Barbieri148226e2011-12-10 11:53:51 -020035#define INDEX_CHILDMAX 128
36
37/* Disk format:
38
39 uint32_t magic = INDEX_MAGIC;
40 uint32_t version = INDEX_VERSION;
41 uint32_t root_offset;
42
43 (node_offset & INDEX_NODE_MASK) specifies the file offset of nodes:
44
45 char[] prefix; // nul terminated
46
47 char first;
48 char last;
49 uint32_t children[last - first + 1];
50
51 uint32_t value_count;
52 struct {
53 uint32_t priority;
54 char[] value; // nul terminated
55 } values[value_count];
56
57 (node_offset & INDEX_NODE_FLAGS) indicates which fields are present.
58 Empty prefixes are omitted, leaf nodes omit the three child-related fields.
59
60 This could be optimised further by adding a sparse child format
61 (indicated using a new flag).
62 */
63
64/* Format of node offsets within index file */
65enum node_offset {
66 INDEX_NODE_FLAGS = 0xF0000000, /* Flags in high nibble */
67 INDEX_NODE_PREFIX = 0x80000000,
68 INDEX_NODE_VALUES = 0x40000000,
69 INDEX_NODE_CHILDS = 0x20000000,
70
71 INDEX_NODE_MASK = 0x0FFFFFFF, /* Offset value */
72};
73
Lucas De Marchie8847fd2011-11-30 15:23:28 -020074void index_values_free(struct index_value *values)
75{
76 while (values) {
77 struct index_value *value = values;
78
79 values = value->next;
80 free(value);
81 }
82}
83
Lucas De Marchie8847fd2011-11-30 15:23:28 -020084static int add_value(struct index_value **values,
Gustavo Sverzut Barbieri1433ba92011-12-08 14:50:29 -020085 const char *value, unsigned len, unsigned int priority)
Lucas De Marchie8847fd2011-11-30 15:23:28 -020086{
87 struct index_value *v;
Lucas De Marchie8847fd2011-11-30 15:23:28 -020088
89 /* find position to insert value */
90 while (*values && (*values)->priority < priority)
91 values = &(*values)->next;
92
Gustavo Sverzut Barbieri1433ba92011-12-08 14:50:29 -020093 v = malloc(sizeof(struct index_value) + len + 1);
94 if (!v)
95 return -1;
Lucas De Marchie8847fd2011-11-30 15:23:28 -020096 v->next = *values;
97 v->priority = priority;
Gustavo Sverzut Barbieri1433ba92011-12-08 14:50:29 -020098 v->len = len;
99 memcpy(v->value, value, len);
100 v->value[len] = '\0';
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200101 *values = v;
102
Gustavo Sverzut Barbieri558b0202011-12-08 16:36:48 -0200103 return 0;
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200104}
105
Lucas De Marchi93688882011-12-02 10:05:31 -0200106static void read_error(void)
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200107{
108 fatal("Module index: unexpected error: %s\n"
109 "Try re-running depmod\n", errno ? strerror(errno) : "EOF");
110}
111
112static int read_char(FILE *in)
113{
114 int ch;
115
116 errno = 0;
117 ch = getc_unlocked(in);
118 if (ch == EOF)
119 read_error();
120 return ch;
121}
122
123static uint32_t read_long(FILE *in)
124{
125 uint32_t l;
126
127 errno = 0;
128 if (fread(&l, sizeof(uint32_t), 1, in) <= 0)
129 read_error();
130 return ntohl(l);
131}
132
133/*
134 * Buffer abstract data type
135 *
136 * Used internally to store the current path during tree traversal.
137 * They help build wildcard key strings to pass to fnmatch(),
138 * as well as building values of matching keys.
139 */
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200140struct buffer {
141 char *bytes;
142 unsigned size;
143 unsigned used;
144};
145
Gustavo Sverzut Barbieri405f6142011-12-08 14:36:30 -0200146#define BUF_STEP (2048)
147static bool buf_grow(struct buffer *buf, size_t newsize)
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200148{
Gustavo Sverzut Barbieri405f6142011-12-08 14:36:30 -0200149 void *tmp;
150 size_t sz;
151
152 if (newsize % BUF_STEP == 0)
153 sz = newsize;
154 else
155 sz = ((newsize / BUF_STEP) + 1) * BUF_STEP;
156
Gustavo Sverzut Barbieri435ad782011-12-08 16:35:08 -0200157 if (buf->size == sz)
158 return true;
159
Gustavo Sverzut Barbieri405f6142011-12-08 14:36:30 -0200160 tmp = realloc(buf->bytes, sz);
161 if (sz > 0 && tmp == NULL)
162 return false;
163 buf->bytes = tmp;
164 buf->size = sz;
165 return true;
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200166}
167
Gustavo Sverzut Barbieri405f6142011-12-08 14:36:30 -0200168static void buf_init(struct buffer *buf)
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200169{
Gustavo Sverzut Barbieri405f6142011-12-08 14:36:30 -0200170 buf->bytes = NULL;
171 buf->size = 0;
172 buf->used = 0;
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200173}
174
Gustavo Sverzut Barbieri405f6142011-12-08 14:36:30 -0200175static void buf_release(struct buffer *buf)
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200176{
177 free(buf->bytes);
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200178}
179
180/* Destroy buffer and return a copy as a C string */
Gustavo Sverzut Barbieri405f6142011-12-08 14:36:30 -0200181static char *buf_steal(struct buffer *buf)
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200182{
183 char *bytes;
184
Gustavo Sverzut Barbieri405f6142011-12-08 14:36:30 -0200185 bytes = realloc(buf->bytes, buf->used + 1);
186 if (!bytes) {
187 free(buf->bytes);
188 return NULL;
189 }
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200190 bytes[buf->used] = '\0';
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200191 return bytes;
192}
193
194/* Return a C string owned by the buffer
195 (invalidated if the buffer is changed).
196 */
197static const char *buf_str(struct buffer *buf)
198{
Gustavo Sverzut Barbieri405f6142011-12-08 14:36:30 -0200199 if (!buf_grow(buf, buf->used + 1))
200 return NULL;
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200201 buf->bytes[buf->used] = '\0';
202 return buf->bytes;
203}
204
Gustavo Sverzut Barbieri405f6142011-12-08 14:36:30 -0200205static bool buf_pushchar(struct buffer *buf, char ch)
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200206{
Gustavo Sverzut Barbieri405f6142011-12-08 14:36:30 -0200207 if (!buf_grow(buf, buf->used + 1))
208 return false;
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200209 buf->bytes[buf->used] = ch;
210 buf->used++;
Gustavo Sverzut Barbieri405f6142011-12-08 14:36:30 -0200211 return true;
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200212}
213
Lucas De Marchi758428a2012-01-16 15:56:17 -0200214static unsigned buf_pushchars(struct buffer *buf, const char *str)
215{
216 unsigned i = 0;
217 int ch;
218
219 while ((ch = str[i])) {
220 buf_pushchar(buf, ch);
221 i++;
222 }
223
224 return i;
225}
226
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200227static unsigned buf_freadchars(struct buffer *buf, FILE *in)
228{
229 unsigned i = 0;
230 int ch;
231
232 while ((ch = read_char(in))) {
Gustavo Sverzut Barbieri405f6142011-12-08 14:36:30 -0200233 if (!buf_pushchar(buf, ch))
234 break;
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200235 i++;
236 }
237
238 return i;
239}
240
241static void buf_popchar(struct buffer *buf)
242{
Gustavo Sverzut Barbieri405f6142011-12-08 14:36:30 -0200243 assert(buf->used > 0);
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200244 buf->used--;
245}
246
247static void buf_popchars(struct buffer *buf, unsigned n)
248{
Gustavo Sverzut Barbieri405f6142011-12-08 14:36:30 -0200249 assert(buf->used >= n);
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200250 buf->used -= n;
251}
252
253static void buf_clear(struct buffer *buf)
254{
255 buf->used = 0;
256}
257
258/*
Lucas De Marchieb8bb322011-12-02 10:23:02 -0200259 * Index file searching
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200260 */
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200261struct index_node_f {
262 FILE *file;
263 char *prefix; /* path compression */
264 struct index_value *values;
265 unsigned char first; /* range of child nodes */
266 unsigned char last;
267 uint32_t children[0];
268};
269
270static struct index_node_f *index_read(FILE *in, uint32_t offset)
271{
272 struct index_node_f *node;
273 char *prefix;
274 int i, child_count = 0;
275
276 if ((offset & INDEX_NODE_MASK) == 0)
277 return NULL;
278
279 fseek(in, offset & INDEX_NODE_MASK, SEEK_SET);
Lucas De Marchia7be73b2011-11-30 15:59:36 -0200280
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200281 if (offset & INDEX_NODE_PREFIX) {
Gustavo Sverzut Barbieri405f6142011-12-08 14:36:30 -0200282 struct buffer buf;
283 buf_init(&buf);
284 buf_freadchars(&buf, in);
285 prefix = buf_steal(&buf);
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200286 } else
287 prefix = NOFAIL(strdup(""));
Lucas De Marchia7be73b2011-11-30 15:59:36 -0200288
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200289 if (offset & INDEX_NODE_CHILDS) {
290 char first = read_char(in);
291 char last = read_char(in);
292 child_count = last - first + 1;
Lucas De Marchia7be73b2011-11-30 15:59:36 -0200293
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200294 node = NOFAIL(malloc(sizeof(struct index_node_f) +
295 sizeof(uint32_t) * child_count));
Lucas De Marchia7be73b2011-11-30 15:59:36 -0200296
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200297 node->first = first;
298 node->last = last;
299
300 for (i = 0; i < child_count; i++)
301 node->children[i] = read_long(in);
302 } else {
303 node = NOFAIL(malloc(sizeof(struct index_node_f)));
304 node->first = INDEX_CHILDMAX;
305 node->last = 0;
306 }
Lucas De Marchia7be73b2011-11-30 15:59:36 -0200307
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200308 node->values = NULL;
309 if (offset & INDEX_NODE_VALUES) {
310 int value_count;
Gustavo Sverzut Barbieri405f6142011-12-08 14:36:30 -0200311 struct buffer buf;
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200312 const char *value;
313 unsigned int priority;
314
315 value_count = read_long(in);
316
Gustavo Sverzut Barbieri405f6142011-12-08 14:36:30 -0200317 buf_init(&buf);
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200318 while (value_count--) {
319 priority = read_long(in);
Gustavo Sverzut Barbieri405f6142011-12-08 14:36:30 -0200320 buf_freadchars(&buf, in);
321 value = buf_str(&buf);
Gustavo Sverzut Barbieri1433ba92011-12-08 14:50:29 -0200322 add_value(&node->values, value, buf.used, priority);
Gustavo Sverzut Barbieri405f6142011-12-08 14:36:30 -0200323 buf_clear(&buf);
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200324 }
Gustavo Sverzut Barbieri405f6142011-12-08 14:36:30 -0200325 buf_release(&buf);
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200326 }
327
328 node->prefix = prefix;
329 node->file = in;
330 return node;
331}
332
333static void index_close(struct index_node_f *node)
334{
335 free(node->prefix);
336 index_values_free(node->values);
337 free(node);
338}
339
340struct index_file {
341 FILE *file;
342 uint32_t root_offset;
343};
344
345/* Failures are silent; modprobe will fall back to text files */
346struct index_file *index_file_open(const char *filename)
347{
348 FILE *file;
349 uint32_t magic, version;
350 struct index_file *new;
351
Cristian Rodríguez79e5ea92011-12-16 02:49:54 -0300352 file = fopen(filename, "re");
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200353 if (!file)
354 return NULL;
355 errno = EINVAL;
356
357 magic = read_long(file);
Cristian Rodríguez67d94ad2011-12-23 03:06:56 -0200358 if (magic != INDEX_MAGIC) {
359 fclose(file);
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200360 return NULL;
Cristian Rodríguez67d94ad2011-12-23 03:06:56 -0200361 }
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200362
363 version = read_long(file);
Cristian Rodríguez4088b272011-12-26 01:38:04 -0300364 if (version >> 16 != INDEX_VERSION_MAJOR) {
365 fclose(file);
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200366 return NULL;
Cristian Rodríguez4088b272011-12-26 01:38:04 -0300367 }
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200368
369 new = NOFAIL(malloc(sizeof(struct index_file)));
370 new->file = file;
371 new->root_offset = read_long(new->file);
372
373 errno = 0;
374 return new;
375}
376
Lucas De Marchi0fbdfef2011-12-02 09:56:22 -0200377void index_file_close(struct index_file *idx)
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200378{
Lucas De Marchi0fbdfef2011-12-02 09:56:22 -0200379 fclose(idx->file);
380 free(idx);
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200381}
382
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200383static struct index_node_f *index_readroot(struct index_file *in)
384{
385 return index_read(in->file, in->root_offset);
386}
387
388static struct index_node_f *index_readchild(const struct index_node_f *parent,
389 int ch)
390{
Lucas De Marchie71970a2011-12-02 10:27:15 -0200391 if (parent->first <= ch && ch <= parent->last) {
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200392 return index_read(parent->file,
393 parent->children[ch - parent->first]);
Lucas De Marchie71970a2011-12-02 10:27:15 -0200394 }
395
396 return NULL;
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200397}
398
Lucas De Marchi758428a2012-01-16 15:56:17 -0200399static void index_dump_node(struct index_node_f *node, struct buffer *buf,
400 int fd)
401{
402 struct index_value *v;
403 int ch, pushed;
404
405 pushed = buf_pushchars(buf, node->prefix);
406
407 for (v = node->values; v != NULL; v = v->next) {
408 write_str_safe(fd, buf->bytes, buf->used);
409 write_str_safe(fd, " ", 1);
410 write_str_safe(fd, v->value, strlen(v->value));
411 write_str_safe(fd, "\n", 1);
412 }
413
414 for (ch = node->first; ch <= node->last; ch++) {
415 struct index_node_f *child = index_readchild(node, ch);
416
417 if (!child)
418 continue;
419
420 buf_pushchar(buf, ch);
421 index_dump_node(child, buf, fd);
422 buf_popchar(buf);
423 }
424
425 buf_popchars(buf, pushed);
426 index_close(node);
427}
428
429void index_dump(struct index_file *in, int fd, const char *prefix)
430{
431 struct index_node_f *root;
432 struct buffer buf;
433
434 buf_init(&buf);
435 buf_pushchars(&buf, prefix);
436 root = index_readroot(in);
437 index_dump_node(root, &buf, fd);
438 buf_release(&buf);
439}
440
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200441static char *index_search__node(struct index_node_f *node, const char *key, int i)
442{
443 char *value;
444 struct index_node_f *child;
445 int ch;
446 int j;
447
448 while(node) {
449 for (j = 0; node->prefix[j]; j++) {
450 ch = node->prefix[j];
Lucas De Marchia7be73b2011-11-30 15:59:36 -0200451
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200452 if (ch != key[i+j]) {
453 index_close(node);
454 return NULL;
455 }
456 }
Lucas De Marchie71970a2011-12-02 10:27:15 -0200457
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200458 i += j;
Lucas De Marchia7be73b2011-11-30 15:59:36 -0200459
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200460 if (key[i] == '\0') {
Lucas De Marchi817f4e32012-02-27 19:54:33 -0300461 value = node->values != NULL
462 ? strdup(node->values[0].value)
463 : NULL;
464
465 index_close(node);
466 return value;
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200467 }
Lucas De Marchia7be73b2011-11-30 15:59:36 -0200468
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200469 child = index_readchild(node, key[i]);
470 index_close(node);
471 node = child;
472 i++;
473 }
Lucas De Marchia7be73b2011-11-30 15:59:36 -0200474
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200475 return NULL;
476}
477
478/*
Lucas De Marchi1d152ac2011-12-02 10:15:00 -0200479 * Search the index for a key
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200480 *
Lucas De Marchi1d152ac2011-12-02 10:15:00 -0200481 * Returns the value of the first match
482 *
483 * The recursive functions free their node argument (using index_close).
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200484 */
Lucas De Marchi1d152ac2011-12-02 10:15:00 -0200485char *index_search(struct index_file *in, const char *key)
486{
Lucas De Marchiee1d1882012-02-27 18:48:02 -0300487// FIXME: return value by reference instead of strdup
Lucas De Marchi1d152ac2011-12-02 10:15:00 -0200488 struct index_node_f *root;
489 char *value;
490
491 root = index_readroot(in);
492 value = index_search__node(root, key, 0);
493
494 return value;
495}
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200496
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200497
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200498
499/* Level 4: add all the values from a matching node */
500static void index_searchwild__allvalues(struct index_node_f *node,
Lucas De Marchi1d152ac2011-12-02 10:15:00 -0200501 struct index_value **out)
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200502{
Lucas De Marchi1d152ac2011-12-02 10:15:00 -0200503 struct index_value *v;
Lucas De Marchia7be73b2011-11-30 15:59:36 -0200504
Lucas De Marchi1d152ac2011-12-02 10:15:00 -0200505 for (v = node->values; v != NULL; v = v->next)
Gustavo Sverzut Barbieri1433ba92011-12-08 14:50:29 -0200506 add_value(out, v->value, v->len, v->priority);
Lucas De Marchi1d152ac2011-12-02 10:15:00 -0200507
508 index_close(node);
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200509}
510
Lucas De Marchi1d152ac2011-12-02 10:15:00 -0200511/*
512 * Level 3: traverse a sub-keyspace which starts with a wildcard,
513 * looking for matches.
514 */
515static void index_searchwild__all(struct index_node_f *node, int j,
516 struct buffer *buf,
517 const char *subkey,
518 struct index_value **out)
519{
520 int pushed = 0;
521 int ch;
522
523 while (node->prefix[j]) {
524 ch = node->prefix[j];
525
526 buf_pushchar(buf, ch);
527 pushed++;
528 j++;
529 }
530
531 for (ch = node->first; ch <= node->last; ch++) {
532 struct index_node_f *child = index_readchild(node, ch);
533
534 if (!child)
535 continue;
536
537 buf_pushchar(buf, ch);
538 index_searchwild__all(child, 0, buf, subkey, out);
539 buf_popchar(buf);
540 }
541
542 if (node->values) {
543 if (fnmatch(buf_str(buf), subkey, 0) == 0)
544 index_searchwild__allvalues(node, out);
Gustavo Sverzut Barbieri27fdf632011-12-10 13:28:18 -0200545 else
546 index_close(node);
Lucas De Marchi1d152ac2011-12-02 10:15:00 -0200547 } else {
548 index_close(node);
549 }
550
551 buf_popchars(buf, pushed);
552}
553
554/* Level 2: descend the tree (until we hit a wildcard) */
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200555static void index_searchwild__node(struct index_node_f *node,
556 struct buffer *buf,
557 const char *key, int i,
558 struct index_value **out)
559{
560 struct index_node_f *child;
561 int j;
562 int ch;
563
564 while(node) {
565 for (j = 0; node->prefix[j]; j++) {
566 ch = node->prefix[j];
Lucas De Marchia7be73b2011-11-30 15:59:36 -0200567
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200568 if (ch == '*' || ch == '?' || ch == '[') {
569 index_searchwild__all(node, j, buf,
570 &key[i+j], out);
571 return;
572 }
Lucas De Marchia7be73b2011-11-30 15:59:36 -0200573
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200574 if (ch != key[i+j]) {
575 index_close(node);
576 return;
577 }
578 }
Lucas De Marchie71970a2011-12-02 10:27:15 -0200579
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200580 i += j;
Lucas De Marchia7be73b2011-11-30 15:59:36 -0200581
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200582 child = index_readchild(node, '*');
583 if (child) {
584 buf_pushchar(buf, '*');
585 index_searchwild__all(child, 0, buf, &key[i], out);
586 buf_popchar(buf);
587 }
Lucas De Marchia7be73b2011-11-30 15:59:36 -0200588
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200589 child = index_readchild(node, '?');
590 if (child) {
591 buf_pushchar(buf, '?');
592 index_searchwild__all(child, 0, buf, &key[i], out);
593 buf_popchar(buf);
594 }
Lucas De Marchia7be73b2011-11-30 15:59:36 -0200595
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200596 child = index_readchild(node, '[');
597 if (child) {
598 buf_pushchar(buf, '[');
599 index_searchwild__all(child, 0, buf, &key[i], out);
600 buf_popchar(buf);
601 }
Lucas De Marchia7be73b2011-11-30 15:59:36 -0200602
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200603 if (key[i] == '\0') {
604 index_searchwild__allvalues(node, out);
605
606 return;
607 }
Lucas De Marchia7be73b2011-11-30 15:59:36 -0200608
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200609 child = index_readchild(node, key[i]);
610 index_close(node);
611 node = child;
612 i++;
613 }
614}
615
Lucas De Marchi1d152ac2011-12-02 10:15:00 -0200616/*
617 * Search the index for a key. The index may contain wildcards.
618 *
619 * Returns a list of all the values of matching keys.
620 */
621struct index_value *index_searchwild(struct index_file *in, const char *key)
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200622{
Lucas De Marchi1d152ac2011-12-02 10:15:00 -0200623 struct index_node_f *root = index_readroot(in);
Gustavo Sverzut Barbieri405f6142011-12-08 14:36:30 -0200624 struct buffer buf;
Lucas De Marchi1d152ac2011-12-02 10:15:00 -0200625 struct index_value *out = NULL;
Lucas De Marchia7be73b2011-11-30 15:59:36 -0200626
Gustavo Sverzut Barbieri405f6142011-12-08 14:36:30 -0200627 buf_init(&buf);
628 index_searchwild__node(root, &buf, key, 0, &out);
629 buf_release(&buf);
Lucas De Marchi1d152ac2011-12-02 10:15:00 -0200630 return out;
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200631}
Lucas De Marchib471a6b2011-12-01 23:14:20 -0200632
633#include <sys/mman.h>
634#include <sys/stat.h>
635#include <unistd.h>
636
Gustavo Sverzut Barbieri15c1c142011-12-10 11:44:31 -0200637static const char _idx_empty_str[] = "";
638
Lucas De Marchib471a6b2011-12-01 23:14:20 -0200639/**************************************************************************/
640/*
641 * Alternative implementation, using mmap to map all the file to memory when
642 * starting
643 */
644struct index_mm {
645 struct kmod_ctx *ctx;
646 void *mm;
647 uint32_t root_offset;
648 size_t size;
649};
650
Gustavo Sverzut Barbierid0915462011-12-10 13:04:43 -0200651struct index_mm_value {
652 unsigned int priority;
653 unsigned int len;
654 const char *value;
655};
656
657struct index_mm_value_array {
658 struct index_mm_value *values;
659 unsigned int len;
660};
661
Lucas De Marchi836be9a2011-12-02 17:27:52 -0200662struct index_mm_node {
663 struct index_mm *idx;
Gustavo Sverzut Barbieri15c1c142011-12-10 11:44:31 -0200664 const char *prefix; /* mmape'd value */
Gustavo Sverzut Barbierid0915462011-12-10 13:04:43 -0200665 struct index_mm_value_array values;
Lucas De Marchi836be9a2011-12-02 17:27:52 -0200666 unsigned char first;
667 unsigned char last;
668 uint32_t children[];
669};
670
671static inline uint32_t read_long_mm(void **p)
672{
Gustavo Sverzut Barbierifc2d8352011-12-10 11:36:35 -0200673 uint8_t *addr = *(uint8_t **)p;
674 uint32_t v;
Lucas De Marchi836be9a2011-12-02 17:27:52 -0200675
Gustavo Sverzut Barbierifc2d8352011-12-10 11:36:35 -0200676 /* addr may be unalined to uint32_t */
677 memcpy(&v, addr, sizeof(uint32_t));
Lucas De Marchi836be9a2011-12-02 17:27:52 -0200678
Gustavo Sverzut Barbierifc2d8352011-12-10 11:36:35 -0200679 *p = addr + sizeof(uint32_t);
Lucas De Marchi836be9a2011-12-02 17:27:52 -0200680 return ntohl(v);
681}
682
683static inline uint8_t read_char_mm(void **p)
684{
Gustavo Sverzut Barbierifc2d8352011-12-10 11:36:35 -0200685 uint8_t *addr = *(uint8_t **)p;
686 uint8_t v = *addr;
687 *p = addr + sizeof(uint8_t);
688 return v;
Lucas De Marchi836be9a2011-12-02 17:27:52 -0200689}
690
Gustavo Sverzut Barbieri1433ba92011-12-08 14:50:29 -0200691static inline char *read_chars_mm(void **p, unsigned *rlen)
Lucas De Marchi836be9a2011-12-02 17:27:52 -0200692{
Gustavo Sverzut Barbierifc2d8352011-12-10 11:36:35 -0200693 char *addr = *(char **)p;
694 size_t len = *rlen = strlen(addr);
695 *p = addr + len + 1;
696 return addr;
Lucas De Marchi836be9a2011-12-02 17:27:52 -0200697}
698
699static struct index_mm_node *index_mm_read_node(struct index_mm *idx,
700 uint32_t offset) {
701 void *p = idx->mm;
702 struct index_mm_node *node;
Gustavo Sverzut Barbieri15c1c142011-12-10 11:44:31 -0200703 const char *prefix;
Gustavo Sverzut Barbierid0915462011-12-10 13:04:43 -0200704 int i, child_count, value_count, children_padding;
705 uint32_t children[INDEX_CHILDMAX];
706 char first, last;
Lucas De Marchi836be9a2011-12-02 17:27:52 -0200707
708 if ((offset & INDEX_NODE_MASK) == 0)
709 return NULL;
710
711 p = (char *)p + (offset & INDEX_NODE_MASK);
712
Gustavo Sverzut Barbieri15c1c142011-12-10 11:44:31 -0200713 if (offset & INDEX_NODE_PREFIX) {
714 unsigned len;
715 prefix = read_chars_mm(&p, &len);
716 } else
717 prefix = _idx_empty_str;
Lucas De Marchi836be9a2011-12-02 17:27:52 -0200718
719 if (offset & INDEX_NODE_CHILDS) {
Gustavo Sverzut Barbierid0915462011-12-10 13:04:43 -0200720 first = read_char_mm(&p);
721 last = read_char_mm(&p);
Lucas De Marchi836be9a2011-12-02 17:27:52 -0200722 child_count = last - first + 1;
Lucas De Marchi836be9a2011-12-02 17:27:52 -0200723 for (i = 0; i < child_count; i++)
Gustavo Sverzut Barbierid0915462011-12-10 13:04:43 -0200724 children[i] = read_long_mm(&p);
Lucas De Marchi836be9a2011-12-02 17:27:52 -0200725 } else {
Gustavo Sverzut Barbierid0915462011-12-10 13:04:43 -0200726 first = INDEX_CHILDMAX;
727 last = 0;
728 child_count = 0;
Lucas De Marchi836be9a2011-12-02 17:27:52 -0200729 }
730
Gustavo Sverzut Barbieric6824b62011-12-21 18:23:58 -0200731 children_padding = (sizeof(struct index_mm_node) +
Gustavo Sverzut Barbierid0915462011-12-10 13:04:43 -0200732 (sizeof(uint32_t) * child_count)) % sizeof(void *);
Lucas De Marchi836be9a2011-12-02 17:27:52 -0200733
Gustavo Sverzut Barbierid0915462011-12-10 13:04:43 -0200734 if (offset & INDEX_NODE_VALUES)
735 value_count = read_long_mm(&p);
736 else
737 value_count = 0;
Lucas De Marchi836be9a2011-12-02 17:27:52 -0200738
Gustavo Sverzut Barbierid0915462011-12-10 13:04:43 -0200739 node = malloc(sizeof(struct index_mm_node)
740 + sizeof(uint32_t) * child_count + children_padding
741 + sizeof(struct index_mm_value) * value_count);
742 if (node == NULL)
743 return NULL;
Lucas De Marchi836be9a2011-12-02 17:27:52 -0200744
Lucas De Marchi836be9a2011-12-02 17:27:52 -0200745 node->idx = idx;
Gustavo Sverzut Barbierid0915462011-12-10 13:04:43 -0200746 node->prefix = prefix;
747 if (value_count == 0)
748 node->values.values = NULL;
749 else {
750 node->values.values = (struct index_mm_value *)
751 ((char *)node + sizeof(struct index_mm_node) +
752 sizeof(uint32_t) * child_count + children_padding);
753 }
754 node->values.len = value_count;
755 node->first = first;
756 node->last = last;
757 memcpy(node->children, children, sizeof(uint32_t) * child_count);
758
759 for (i = 0; i < value_count; i++) {
760 struct index_mm_value *v = node->values.values + i;
761 v->priority = read_long_mm(&p);
762 v->value = read_chars_mm(&p, &v->len);
763 }
Lucas De Marchi836be9a2011-12-02 17:27:52 -0200764
765 return node;
766}
767
768static void index_mm_free_node(struct index_mm_node *node)
769{
Lucas De Marchi836be9a2011-12-02 17:27:52 -0200770 free(node);
771}
772
Lucas De Marchi5109f2b2011-12-08 15:10:55 -0200773struct index_mm *index_mm_open(struct kmod_ctx *ctx, const char *filename,
Lucas De Marchi9fd58f32011-12-31 18:53:24 -0200774 bool populate, unsigned long long *stamp)
Lucas De Marchib471a6b2011-12-01 23:14:20 -0200775{
776 int fd;
Lucas De Marchi5109f2b2011-12-08 15:10:55 -0200777 int flags;
Lucas De Marchib471a6b2011-12-01 23:14:20 -0200778 struct stat st;
779 struct index_mm *idx;
780 struct {
781 uint32_t magic;
782 uint32_t version;
783 uint32_t root_offset;
784 } hdr;
785 void *p;
786
787 DBG(ctx, "file=%s\n", filename);
788
Lucas De Marchi7d51d8b2011-12-12 18:41:57 -0200789 idx = malloc(sizeof(*idx));
790 if (idx == NULL) {
Gustavo Sverzut Barbieridfa96f12012-01-07 19:37:37 -0200791 ERR(ctx, "malloc: %m\n");
Lucas De Marchib471a6b2011-12-01 23:14:20 -0200792 return NULL;
793 }
794
Cristian Rodríguez79e5ea92011-12-16 02:49:54 -0300795 if ((fd = open(filename, O_RDONLY|O_CLOEXEC)) < 0) {
Lucas De Marchi73298172012-02-13 21:58:36 -0200796 DBG(ctx, "open(%s, O_RDONLY|O_CLOEXEC): %m\n", filename);
Lucas De Marchi7d51d8b2011-12-12 18:41:57 -0200797 goto fail_open;
Lucas De Marchib471a6b2011-12-01 23:14:20 -0200798 }
799
Lucas De Marchi7d51d8b2011-12-12 18:41:57 -0200800 fstat(fd, &st);
Lucas De Marchi5109f2b2011-12-08 15:10:55 -0200801 flags = MAP_PRIVATE;
802 if (populate)
803 flags |= MAP_POPULATE;
804
805 if ((idx->mm = mmap(0, st.st_size, PROT_READ, flags, fd, 0))
806 == MAP_FAILED) {
Gustavo Sverzut Barbieridfa96f12012-01-07 19:37:37 -0200807 ERR(ctx, "mmap(0, %zd, PROT_READ, %d, %d, 0): %m\n",
808 (size_t)st.st_size, flags, fd);
Lucas De Marchib471a6b2011-12-01 23:14:20 -0200809 goto fail;
810 }
811
812 p = idx->mm;
813 hdr.magic = read_long_mm(&p);
814 hdr.version = read_long_mm(&p);
815 hdr.root_offset = read_long_mm(&p);
816
817 if (hdr.magic != INDEX_MAGIC) {
818 ERR(ctx, "magic check fail: %x instead of %x\n", hdr.magic,
819 INDEX_MAGIC);
820 goto fail;
821 }
822
823 if (hdr.version >> 16 != INDEX_VERSION_MAJOR) {
824 ERR(ctx, "major version check fail: %u instead of %u\n",
825 hdr.version, INDEX_MAGIC);
826 goto fail;
827 }
828
829 idx->root_offset = hdr.root_offset;
830 idx->size = st.st_size;
831 idx->ctx = ctx;
832 close(fd);
833
Lucas De Marchi6068aaa2012-01-17 12:10:42 -0200834 *stamp = stat_mstamp(&st);
Lucas De Marchi9fd58f32011-12-31 18:53:24 -0200835
Lucas De Marchib471a6b2011-12-01 23:14:20 -0200836 return idx;
837
838fail:
839 close(fd);
Gustavo Sverzut Barbieria5a92a62011-12-16 16:17:50 -0200840 if (idx->mm != MAP_FAILED)
Lucas De Marchib471a6b2011-12-01 23:14:20 -0200841 munmap(idx->mm, st.st_size);
Gustavo Sverzut Barbieria5a92a62011-12-16 16:17:50 -0200842fail_open:
Lucas De Marchib471a6b2011-12-01 23:14:20 -0200843 free(idx);
844 return NULL;
845}
846
847void index_mm_close(struct index_mm *idx)
848{
849 munmap(idx->mm, idx->size);
850 free(idx);
851}
Lucas De Marchi77bf9362011-12-02 17:41:30 -0200852
853static struct index_mm_node *index_mm_readroot(struct index_mm *idx)
854{
855 return index_mm_read_node(idx, idx->root_offset);
856}
Lucas De Marchi91298dc2011-12-02 17:41:46 -0200857
858static struct index_mm_node *index_mm_readchild(const struct index_mm_node *parent,
859 int ch)
860{
861 if (parent->first <= ch && ch <= parent->last) {
862 return index_mm_read_node(parent->idx,
863 parent->children[ch - parent->first]);
864 }
865
866 return NULL;
867}
Lucas De Marchie33bb872011-12-02 17:45:01 -0200868
Lucas De Marchi758428a2012-01-16 15:56:17 -0200869static void index_mm_dump_node(struct index_mm_node *node, struct buffer *buf,
870 int fd)
871{
872 struct index_mm_value *itr, *itr_end;
873 int ch, pushed;
874
875 pushed = buf_pushchars(buf, node->prefix);
876
877 itr = node->values.values;
878 itr_end = itr + node->values.len;
879 for (; itr < itr_end; itr++) {
880 write_str_safe(fd, buf->bytes, buf->used);
881 write_str_safe(fd, " ", 1);
882 write_str_safe(fd, itr->value, itr->len);
883 write_str_safe(fd, "\n", 1);
884 }
885
886 for (ch = node->first; ch <= node->last; ch++) {
887 struct index_mm_node *child = index_mm_readchild(node, ch);
888
889 if (child == NULL)
890 continue;
891
892 buf_pushchar(buf, ch);
893 index_mm_dump_node(child, buf, fd);
894 buf_popchar(buf);
895 }
896
897 buf_popchars(buf, pushed);
898 index_mm_free_node(node);
899}
900
901void index_mm_dump(struct index_mm *idx, int fd, const char *prefix)
902{
903 struct index_mm_node *root;
904 struct buffer buf;
905
906 buf_init(&buf);
907 buf_pushchars(&buf, prefix);
908 root = index_mm_readroot(idx);
909 index_mm_dump_node(root, &buf, fd);
910 buf_release(&buf);
911}
912
Lucas De Marchie33bb872011-12-02 17:45:01 -0200913static char *index_mm_search_node(struct index_mm_node *node, const char *key,
914 int i)
915{
916 char *value;
917 struct index_mm_node *child;
918 int ch;
919 int j;
920
921 while(node) {
922 for (j = 0; node->prefix[j]; j++) {
923 ch = node->prefix[j];
924
925 if (ch != key[i+j]) {
926 index_mm_free_node(node);
927 return NULL;
928 }
929 }
930
931 i += j;
932
933 if (key[i] == '\0') {
Lucas De Marchi817f4e32012-02-27 19:54:33 -0300934 value = node->values.len > 0
935 ? strdup(node->values.values[0].value)
936 : NULL;
937
938 index_mm_free_node(node);
939 return value;
Lucas De Marchie33bb872011-12-02 17:45:01 -0200940 }
941
942 child = index_mm_readchild(node, key[i]);
943 index_mm_free_node(node);
944 node = child;
945 i++;
946 }
947
948 return NULL;
949}
Lucas De Marchib797b792011-12-02 17:49:03 -0200950
951/*
952 * Search the index for a key
953 *
954 * Returns the value of the first match
955 *
956 * The recursive functions free their node argument (using index_close).
957 */
958char *index_mm_search(struct index_mm *idx, const char *key)
959{
Lucas De Marchiee1d1882012-02-27 18:48:02 -0300960// FIXME: return value by reference instead of strdup
Lucas De Marchib797b792011-12-02 17:49:03 -0200961 struct index_mm_node *root;
962 char *value;
963
964 root = index_mm_readroot(idx);
965 value = index_mm_search_node(root, key, 0);
966
967 return value;
968}
Lucas De Marchibf89f702011-12-02 18:23:36 -0200969
970/* Level 4: add all the values from a matching node */
971static void index_mm_searchwild_allvalues(struct index_mm_node *node,
972 struct index_value **out)
973{
Gustavo Sverzut Barbierid0915462011-12-10 13:04:43 -0200974 struct index_mm_value *itr, *itr_end;
Lucas De Marchibf89f702011-12-02 18:23:36 -0200975
Gustavo Sverzut Barbierid0915462011-12-10 13:04:43 -0200976 itr = node->values.values;
977 itr_end = itr + node->values.len;
978 for (; itr < itr_end; itr++)
979 add_value(out, itr->value, itr->len, itr->priority);
Lucas De Marchibf89f702011-12-02 18:23:36 -0200980
981 index_mm_free_node(node);
982}
983
984/*
985 * Level 3: traverse a sub-keyspace which starts with a wildcard,
986 * looking for matches.
987 */
988static void index_mm_searchwild_all(struct index_mm_node *node, int j,
989 struct buffer *buf,
990 const char *subkey,
991 struct index_value **out)
992{
993 int pushed = 0;
994 int ch;
995
996 while (node->prefix[j]) {
997 ch = node->prefix[j];
998
999 buf_pushchar(buf, ch);
1000 pushed++;
1001 j++;
1002 }
1003
1004 for (ch = node->first; ch <= node->last; ch++) {
1005 struct index_mm_node *child = index_mm_readchild(node, ch);
1006
1007 if (!child)
1008 continue;
1009
1010 buf_pushchar(buf, ch);
1011 index_mm_searchwild_all(child, 0, buf, subkey, out);
1012 buf_popchar(buf);
1013 }
1014
Gustavo Sverzut Barbierid0915462011-12-10 13:04:43 -02001015 if (node->values.len > 0) {
Lucas De Marchibf89f702011-12-02 18:23:36 -02001016 if (fnmatch(buf_str(buf), subkey, 0) == 0)
1017 index_mm_searchwild_allvalues(node, out);
Gustavo Sverzut Barbieri27fdf632011-12-10 13:28:18 -02001018 else
1019 index_mm_free_node(node);
Lucas De Marchibf89f702011-12-02 18:23:36 -02001020 } else {
1021 index_mm_free_node(node);
1022 }
1023
1024 buf_popchars(buf, pushed);
1025}
1026
1027/* Level 2: descend the tree (until we hit a wildcard) */
1028static void index_mm_searchwild_node(struct index_mm_node *node,
1029 struct buffer *buf,
1030 const char *key, int i,
1031 struct index_value **out)
1032{
1033 struct index_mm_node *child;
1034 int j;
1035 int ch;
1036
1037 while(node) {
1038 for (j = 0; node->prefix[j]; j++) {
1039 ch = node->prefix[j];
1040
1041 if (ch == '*' || ch == '?' || ch == '[') {
1042 index_mm_searchwild_all(node, j, buf,
1043 &key[i+j], out);
1044 return;
1045 }
1046
1047 if (ch != key[i+j]) {
1048 index_mm_free_node(node);
1049 return;
1050 }
1051 }
1052
1053 i += j;
1054
1055 child = index_mm_readchild(node, '*');
1056 if (child) {
1057 buf_pushchar(buf, '*');
1058 index_mm_searchwild_all(child, 0, buf, &key[i], out);
1059 buf_popchar(buf);
1060 }
1061
1062 child = index_mm_readchild(node, '?');
1063 if (child) {
1064 buf_pushchar(buf, '?');
1065 index_mm_searchwild_all(child, 0, buf, &key[i], out);
1066 buf_popchar(buf);
1067 }
1068
1069 child = index_mm_readchild(node, '[');
1070 if (child) {
1071 buf_pushchar(buf, '[');
1072 index_mm_searchwild_all(child, 0, buf, &key[i], out);
1073 buf_popchar(buf);
1074 }
1075
1076 if (key[i] == '\0') {
1077 index_mm_searchwild_allvalues(node, out);
1078
1079 return;
1080 }
1081
1082 child = index_mm_readchild(node, key[i]);
1083 index_mm_free_node(node);
1084 node = child;
1085 i++;
1086 }
1087}
1088
1089/*
1090 * Search the index for a key. The index may contain wildcards.
1091 *
1092 * Returns a list of all the values of matching keys.
1093 */
1094struct index_value *index_mm_searchwild(struct index_mm *idx, const char *key)
1095{
1096 struct index_mm_node *root = index_mm_readroot(idx);
Gustavo Sverzut Barbieri405f6142011-12-08 14:36:30 -02001097 struct buffer buf;
Lucas De Marchibf89f702011-12-02 18:23:36 -02001098 struct index_value *out = NULL;
1099
Gustavo Sverzut Barbieri405f6142011-12-08 14:36:30 -02001100 buf_init(&buf);
1101 index_mm_searchwild_node(root, &buf, key, 0, &out);
1102 buf_release(&buf);
Lucas De Marchibf89f702011-12-02 18:23:36 -02001103 return out;
1104}