blob: a0cb510a11f7922a58d3ee20221db2010206d755 [file] [log] [blame]
Lucas De Marchi8f923be2011-12-03 04:28:49 -02001/*
2 * libkmod - interface to kernel module operations
3 *
4 * Copyright (C) 2008 Alan Jenkins <alan.christopher.jenkins@googlemail.com>
5 * Copyright (C) 2011 ProFUSION embedded systems
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation version 2.1.
10 *
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
Lucas De Marchie8847fd2011-11-30 15:23:28 -020035void index_values_free(struct index_value *values)
36{
37 while (values) {
38 struct index_value *value = values;
39
40 values = value->next;
41 free(value);
42 }
43}
44
Lucas De Marchie8847fd2011-11-30 15:23:28 -020045static int add_value(struct index_value **values,
46 const char *value, unsigned int priority)
47{
48 struct index_value *v;
49 int duplicate = 0;
50 int len;
51
52 /* report the presence of duplicate values */
53 for (v = *values; v; v = v->next) {
54 if (streq(v->value, value))
55 duplicate = 1;
56 }
57
58 /* find position to insert value */
59 while (*values && (*values)->priority < priority)
60 values = &(*values)->next;
61
62 len = strlen(value);
63 v = NOFAIL(calloc(sizeof(struct index_value) + len + 1, 1));
64 v->next = *values;
65 v->priority = priority;
66 memcpy(v->value, value, len + 1);
67 *values = v;
68
69 return duplicate;
70}
71
Lucas De Marchi93688882011-12-02 10:05:31 -020072static void read_error(void)
Lucas De Marchie8847fd2011-11-30 15:23:28 -020073{
74 fatal("Module index: unexpected error: %s\n"
75 "Try re-running depmod\n", errno ? strerror(errno) : "EOF");
76}
77
78static int read_char(FILE *in)
79{
80 int ch;
81
82 errno = 0;
83 ch = getc_unlocked(in);
84 if (ch == EOF)
85 read_error();
86 return ch;
87}
88
89static uint32_t read_long(FILE *in)
90{
91 uint32_t l;
92
93 errno = 0;
94 if (fread(&l, sizeof(uint32_t), 1, in) <= 0)
95 read_error();
96 return ntohl(l);
97}
98
99/*
100 * Buffer abstract data type
101 *
102 * Used internally to store the current path during tree traversal.
103 * They help build wildcard key strings to pass to fnmatch(),
104 * as well as building values of matching keys.
105 */
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200106struct buffer {
107 char *bytes;
108 unsigned size;
109 unsigned used;
110};
111
Gustavo Sverzut Barbieri405f6142011-12-08 14:36:30 -0200112#define BUF_STEP (2048)
113static bool buf_grow(struct buffer *buf, size_t newsize)
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200114{
Gustavo Sverzut Barbieri405f6142011-12-08 14:36:30 -0200115 void *tmp;
116 size_t sz;
117
118 if (newsize % BUF_STEP == 0)
119 sz = newsize;
120 else
121 sz = ((newsize / BUF_STEP) + 1) * BUF_STEP;
122
Gustavo Sverzut Barbieri435ad782011-12-08 16:35:08 -0200123 if (buf->size == sz)
124 return true;
125
Gustavo Sverzut Barbieri405f6142011-12-08 14:36:30 -0200126 tmp = realloc(buf->bytes, sz);
127 if (sz > 0 && tmp == NULL)
128 return false;
129 buf->bytes = tmp;
130 buf->size = sz;
131 return true;
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200132}
133
Gustavo Sverzut Barbieri405f6142011-12-08 14:36:30 -0200134static void buf_init(struct buffer *buf)
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200135{
Gustavo Sverzut Barbieri405f6142011-12-08 14:36:30 -0200136 buf->bytes = NULL;
137 buf->size = 0;
138 buf->used = 0;
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200139}
140
Gustavo Sverzut Barbieri405f6142011-12-08 14:36:30 -0200141static void buf_release(struct buffer *buf)
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200142{
143 free(buf->bytes);
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200144}
145
146/* Destroy buffer and return a copy as a C string */
Gustavo Sverzut Barbieri405f6142011-12-08 14:36:30 -0200147static char *buf_steal(struct buffer *buf)
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200148{
149 char *bytes;
150
Gustavo Sverzut Barbieri405f6142011-12-08 14:36:30 -0200151 bytes = realloc(buf->bytes, buf->used + 1);
152 if (!bytes) {
153 free(buf->bytes);
154 return NULL;
155 }
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200156 bytes[buf->used] = '\0';
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200157 return bytes;
158}
159
160/* Return a C string owned by the buffer
161 (invalidated if the buffer is changed).
162 */
163static const char *buf_str(struct buffer *buf)
164{
Gustavo Sverzut Barbieri405f6142011-12-08 14:36:30 -0200165 if (!buf_grow(buf, buf->used + 1))
166 return NULL;
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200167 buf->bytes[buf->used] = '\0';
168 return buf->bytes;
169}
170
Gustavo Sverzut Barbieri405f6142011-12-08 14:36:30 -0200171static bool buf_pushchar(struct buffer *buf, char ch)
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200172{
Gustavo Sverzut Barbieri405f6142011-12-08 14:36:30 -0200173 if (!buf_grow(buf, buf->used + 1))
174 return false;
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200175 buf->bytes[buf->used] = ch;
176 buf->used++;
Gustavo Sverzut Barbieri405f6142011-12-08 14:36:30 -0200177 return true;
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200178}
179
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200180static unsigned buf_freadchars(struct buffer *buf, FILE *in)
181{
182 unsigned i = 0;
183 int ch;
184
185 while ((ch = read_char(in))) {
Gustavo Sverzut Barbieri405f6142011-12-08 14:36:30 -0200186 if (!buf_pushchar(buf, ch))
187 break;
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200188 i++;
189 }
190
191 return i;
192}
193
194static void buf_popchar(struct buffer *buf)
195{
Gustavo Sverzut Barbieri405f6142011-12-08 14:36:30 -0200196 assert(buf->used > 0);
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200197 buf->used--;
198}
199
200static void buf_popchars(struct buffer *buf, unsigned n)
201{
Gustavo Sverzut Barbieri405f6142011-12-08 14:36:30 -0200202 assert(buf->used >= n);
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200203 buf->used -= n;
204}
205
206static void buf_clear(struct buffer *buf)
207{
208 buf->used = 0;
209}
210
211/*
Lucas De Marchieb8bb322011-12-02 10:23:02 -0200212 * Index file searching
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200213 */
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200214struct index_node_f {
215 FILE *file;
216 char *prefix; /* path compression */
217 struct index_value *values;
218 unsigned char first; /* range of child nodes */
219 unsigned char last;
220 uint32_t children[0];
221};
222
223static struct index_node_f *index_read(FILE *in, uint32_t offset)
224{
225 struct index_node_f *node;
226 char *prefix;
227 int i, child_count = 0;
228
229 if ((offset & INDEX_NODE_MASK) == 0)
230 return NULL;
231
232 fseek(in, offset & INDEX_NODE_MASK, SEEK_SET);
Lucas De Marchia7be73b2011-11-30 15:59:36 -0200233
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200234 if (offset & INDEX_NODE_PREFIX) {
Gustavo Sverzut Barbieri405f6142011-12-08 14:36:30 -0200235 struct buffer buf;
236 buf_init(&buf);
237 buf_freadchars(&buf, in);
238 prefix = buf_steal(&buf);
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200239 } else
240 prefix = NOFAIL(strdup(""));
Lucas De Marchia7be73b2011-11-30 15:59:36 -0200241
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200242 if (offset & INDEX_NODE_CHILDS) {
243 char first = read_char(in);
244 char last = read_char(in);
245 child_count = last - first + 1;
Lucas De Marchia7be73b2011-11-30 15:59:36 -0200246
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200247 node = NOFAIL(malloc(sizeof(struct index_node_f) +
248 sizeof(uint32_t) * child_count));
Lucas De Marchia7be73b2011-11-30 15:59:36 -0200249
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200250 node->first = first;
251 node->last = last;
252
253 for (i = 0; i < child_count; i++)
254 node->children[i] = read_long(in);
255 } else {
256 node = NOFAIL(malloc(sizeof(struct index_node_f)));
257 node->first = INDEX_CHILDMAX;
258 node->last = 0;
259 }
Lucas De Marchia7be73b2011-11-30 15:59:36 -0200260
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200261 node->values = NULL;
262 if (offset & INDEX_NODE_VALUES) {
263 int value_count;
Gustavo Sverzut Barbieri405f6142011-12-08 14:36:30 -0200264 struct buffer buf;
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200265 const char *value;
266 unsigned int priority;
267
268 value_count = read_long(in);
269
Gustavo Sverzut Barbieri405f6142011-12-08 14:36:30 -0200270 buf_init(&buf);
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200271 while (value_count--) {
272 priority = read_long(in);
Gustavo Sverzut Barbieri405f6142011-12-08 14:36:30 -0200273 buf_freadchars(&buf, in);
274 value = buf_str(&buf);
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200275 add_value(&node->values, value, priority);
Gustavo Sverzut Barbieri405f6142011-12-08 14:36:30 -0200276 buf_clear(&buf);
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200277 }
Gustavo Sverzut Barbieri405f6142011-12-08 14:36:30 -0200278 buf_release(&buf);
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200279 }
280
281 node->prefix = prefix;
282 node->file = in;
283 return node;
284}
285
286static void index_close(struct index_node_f *node)
287{
288 free(node->prefix);
289 index_values_free(node->values);
290 free(node);
291}
292
293struct index_file {
294 FILE *file;
295 uint32_t root_offset;
296};
297
298/* Failures are silent; modprobe will fall back to text files */
299struct index_file *index_file_open(const char *filename)
300{
301 FILE *file;
302 uint32_t magic, version;
303 struct index_file *new;
304
305 file = fopen(filename, "r");
306 if (!file)
307 return NULL;
308 errno = EINVAL;
309
310 magic = read_long(file);
311 if (magic != INDEX_MAGIC)
312 return NULL;
313
314 version = read_long(file);
315 if (version >> 16 != INDEX_VERSION_MAJOR)
316 return NULL;
317
318 new = NOFAIL(malloc(sizeof(struct index_file)));
319 new->file = file;
320 new->root_offset = read_long(new->file);
321
322 errno = 0;
323 return new;
324}
325
Lucas De Marchi0fbdfef2011-12-02 09:56:22 -0200326void index_file_close(struct index_file *idx)
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200327{
Lucas De Marchi0fbdfef2011-12-02 09:56:22 -0200328 fclose(idx->file);
329 free(idx);
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200330}
331
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200332static struct index_node_f *index_readroot(struct index_file *in)
333{
334 return index_read(in->file, in->root_offset);
335}
336
337static struct index_node_f *index_readchild(const struct index_node_f *parent,
338 int ch)
339{
Lucas De Marchie71970a2011-12-02 10:27:15 -0200340 if (parent->first <= ch && ch <= parent->last) {
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200341 return index_read(parent->file,
342 parent->children[ch - parent->first]);
Lucas De Marchie71970a2011-12-02 10:27:15 -0200343 }
344
345 return NULL;
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200346}
347
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200348static char *index_search__node(struct index_node_f *node, const char *key, int i)
349{
350 char *value;
351 struct index_node_f *child;
352 int ch;
353 int j;
354
355 while(node) {
356 for (j = 0; node->prefix[j]; j++) {
357 ch = node->prefix[j];
Lucas De Marchia7be73b2011-11-30 15:59:36 -0200358
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200359 if (ch != key[i+j]) {
360 index_close(node);
361 return NULL;
362 }
363 }
Lucas De Marchie71970a2011-12-02 10:27:15 -0200364
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200365 i += j;
Lucas De Marchia7be73b2011-11-30 15:59:36 -0200366
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200367 if (key[i] == '\0') {
368 if (node->values) {
369 value = strdup(node->values[0].value);
370 index_close(node);
371 return value;
372 } else {
373 return NULL;
374 }
375 }
Lucas De Marchia7be73b2011-11-30 15:59:36 -0200376
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200377 child = index_readchild(node, key[i]);
378 index_close(node);
379 node = child;
380 i++;
381 }
Lucas De Marchia7be73b2011-11-30 15:59:36 -0200382
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200383 return NULL;
384}
385
386/*
Lucas De Marchi1d152ac2011-12-02 10:15:00 -0200387 * Search the index for a key
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200388 *
Lucas De Marchi1d152ac2011-12-02 10:15:00 -0200389 * Returns the value of the first match
390 *
391 * The recursive functions free their node argument (using index_close).
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200392 */
Lucas De Marchi1d152ac2011-12-02 10:15:00 -0200393char *index_search(struct index_file *in, const char *key)
394{
395 struct index_node_f *root;
396 char *value;
397
398 root = index_readroot(in);
399 value = index_search__node(root, key, 0);
400
401 return value;
402}
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200403
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200404
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200405
406/* Level 4: add all the values from a matching node */
407static void index_searchwild__allvalues(struct index_node_f *node,
Lucas De Marchi1d152ac2011-12-02 10:15:00 -0200408 struct index_value **out)
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200409{
Lucas De Marchi1d152ac2011-12-02 10:15:00 -0200410 struct index_value *v;
Lucas De Marchia7be73b2011-11-30 15:59:36 -0200411
Lucas De Marchi1d152ac2011-12-02 10:15:00 -0200412 for (v = node->values; v != NULL; v = v->next)
413 add_value(out, v->value, v->priority);
414
415 index_close(node);
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200416}
417
Lucas De Marchi1d152ac2011-12-02 10:15:00 -0200418/*
419 * Level 3: traverse a sub-keyspace which starts with a wildcard,
420 * looking for matches.
421 */
422static void index_searchwild__all(struct index_node_f *node, int j,
423 struct buffer *buf,
424 const char *subkey,
425 struct index_value **out)
426{
427 int pushed = 0;
428 int ch;
429
430 while (node->prefix[j]) {
431 ch = node->prefix[j];
432
433 buf_pushchar(buf, ch);
434 pushed++;
435 j++;
436 }
437
438 for (ch = node->first; ch <= node->last; ch++) {
439 struct index_node_f *child = index_readchild(node, ch);
440
441 if (!child)
442 continue;
443
444 buf_pushchar(buf, ch);
445 index_searchwild__all(child, 0, buf, subkey, out);
446 buf_popchar(buf);
447 }
448
449 if (node->values) {
450 if (fnmatch(buf_str(buf), subkey, 0) == 0)
451 index_searchwild__allvalues(node, out);
452 } else {
453 index_close(node);
454 }
455
456 buf_popchars(buf, pushed);
457}
458
459/* Level 2: descend the tree (until we hit a wildcard) */
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200460static void index_searchwild__node(struct index_node_f *node,
461 struct buffer *buf,
462 const char *key, int i,
463 struct index_value **out)
464{
465 struct index_node_f *child;
466 int j;
467 int ch;
468
469 while(node) {
470 for (j = 0; node->prefix[j]; j++) {
471 ch = node->prefix[j];
Lucas De Marchia7be73b2011-11-30 15:59:36 -0200472
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200473 if (ch == '*' || ch == '?' || ch == '[') {
474 index_searchwild__all(node, j, buf,
475 &key[i+j], out);
476 return;
477 }
Lucas De Marchia7be73b2011-11-30 15:59:36 -0200478
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200479 if (ch != key[i+j]) {
480 index_close(node);
481 return;
482 }
483 }
Lucas De Marchie71970a2011-12-02 10:27:15 -0200484
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200485 i += j;
Lucas De Marchia7be73b2011-11-30 15:59:36 -0200486
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200487 child = index_readchild(node, '*');
488 if (child) {
489 buf_pushchar(buf, '*');
490 index_searchwild__all(child, 0, buf, &key[i], out);
491 buf_popchar(buf);
492 }
Lucas De Marchia7be73b2011-11-30 15:59:36 -0200493
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200494 child = index_readchild(node, '?');
495 if (child) {
496 buf_pushchar(buf, '?');
497 index_searchwild__all(child, 0, buf, &key[i], out);
498 buf_popchar(buf);
499 }
Lucas De Marchia7be73b2011-11-30 15:59:36 -0200500
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200501 child = index_readchild(node, '[');
502 if (child) {
503 buf_pushchar(buf, '[');
504 index_searchwild__all(child, 0, buf, &key[i], out);
505 buf_popchar(buf);
506 }
Lucas De Marchia7be73b2011-11-30 15:59:36 -0200507
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200508 if (key[i] == '\0') {
509 index_searchwild__allvalues(node, out);
510
511 return;
512 }
Lucas De Marchia7be73b2011-11-30 15:59:36 -0200513
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200514 child = index_readchild(node, key[i]);
515 index_close(node);
516 node = child;
517 i++;
518 }
519}
520
Lucas De Marchi1d152ac2011-12-02 10:15:00 -0200521/*
522 * Search the index for a key. The index may contain wildcards.
523 *
524 * Returns a list of all the values of matching keys.
525 */
526struct index_value *index_searchwild(struct index_file *in, const char *key)
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200527{
Lucas De Marchi1d152ac2011-12-02 10:15:00 -0200528 struct index_node_f *root = index_readroot(in);
Gustavo Sverzut Barbieri405f6142011-12-08 14:36:30 -0200529 struct buffer buf;
Lucas De Marchi1d152ac2011-12-02 10:15:00 -0200530 struct index_value *out = NULL;
Lucas De Marchia7be73b2011-11-30 15:59:36 -0200531
Gustavo Sverzut Barbieri405f6142011-12-08 14:36:30 -0200532 buf_init(&buf);
533 index_searchwild__node(root, &buf, key, 0, &out);
534 buf_release(&buf);
Lucas De Marchi1d152ac2011-12-02 10:15:00 -0200535 return out;
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200536}
Lucas De Marchib471a6b2011-12-01 23:14:20 -0200537
538#include <sys/mman.h>
539#include <sys/stat.h>
540#include <unistd.h>
541
542/**************************************************************************/
543/*
544 * Alternative implementation, using mmap to map all the file to memory when
545 * starting
546 */
547struct index_mm {
548 struct kmod_ctx *ctx;
549 void *mm;
550 uint32_t root_offset;
551 size_t size;
552};
553
Lucas De Marchi836be9a2011-12-02 17:27:52 -0200554struct index_mm_node {
555 struct index_mm *idx;
556 char *prefix;
557 struct index_value *values;
558 unsigned char first;
559 unsigned char last;
560 uint32_t children[];
561};
562
563static inline uint32_t read_long_mm(void **p)
564{
565 uint32_t v = **((uint32_t **)p);
566
567 *p = *((uint8_t **)p) + sizeof(uint32_t);
568
569 return ntohl(v);
570}
571
572static inline uint8_t read_char_mm(void **p)
573{
574 uint8_t *v = *((uint8_t **)p);
575 *p = v + 1;
576 return *v;
577}
578
579static inline char *read_alloc_chars_mm(void **p)
580{
581 char *s = *((char **)p);
582 size_t len = strlen(s) + 1;
583 *p = ((char *)p) + len;
584
585 return memdup(s, len);
586}
587
588static inline char *read_chars_mm(void **p)
589{
590 char *s = *((char **)p);
591 size_t len = strlen(s) + 1;
592 *p = ((char *)p) + len;
593
594 return s;
595}
596
597static struct index_mm_node *index_mm_read_node(struct index_mm *idx,
598 uint32_t offset) {
599 void *p = idx->mm;
600 struct index_mm_node *node;
601 char *prefix;
602 int i, child_count = 0;
603
604
605 if ((offset & INDEX_NODE_MASK) == 0)
606 return NULL;
607
608 p = (char *)p + (offset & INDEX_NODE_MASK);
609
610 if (offset & INDEX_NODE_PREFIX)
611 prefix = read_alloc_chars_mm(&p);
612 else
613 prefix = strdup("");
614
615 if (offset & INDEX_NODE_CHILDS) {
616 char first = read_char_mm(&p);
617 char last = read_char_mm(&p);
618 child_count = last - first + 1;
619
620 node = malloc(sizeof(*node) + sizeof(uint32_t) * child_count);
621
622 node->first = first;
623 node->last = last;
624
625 for (i = 0; i < child_count; i++)
626 node->children[i] = read_long_mm(&p);
627 } else {
628 node = malloc(sizeof(*node));
629 node->first = INDEX_CHILDMAX;
630 node->last = 0;
631 }
632
633 node->values = NULL;
634
635 if (offset & INDEX_NODE_VALUES) {
636 uint32_t j;
637
638 for (j = read_long_mm(&p); j > 0; j--) {
639 unsigned int priority;
640 const char *value;
641
642 priority = read_long_mm(&p);
643 value = read_chars_mm(&p);
644 add_value(&node->values, value, priority);
645 }
646 }
647
648 node->prefix = prefix;
649 node->idx = idx;
650
651 return node;
652}
653
654static void index_mm_free_node(struct index_mm_node *node)
655{
656 free(node->prefix);
657 index_values_free(node->values);
658 free(node);
659}
660
Lucas De Marchib471a6b2011-12-01 23:14:20 -0200661struct index_mm *index_mm_open(struct kmod_ctx *ctx, const char *filename)
662{
663 int fd;
664 struct stat st;
665 struct index_mm *idx;
666 struct {
667 uint32_t magic;
668 uint32_t version;
669 uint32_t root_offset;
670 } hdr;
671 void *p;
672
673 DBG(ctx, "file=%s\n", filename);
674
675 if ((fd = open(filename, O_RDONLY)) < 0) {
676 ERR(ctx, "%m\n");
677 return NULL;
678 }
679
680 fstat(fd, &st);
681
682 idx = malloc(sizeof(*idx));
683 if (idx == NULL) {
684 ERR(ctx, "%m\n");
685 goto fail;
686 }
687
688 if ((idx->mm = mmap(0, st.st_size, PROT_READ,
689 MAP_PRIVATE | MAP_POPULATE,
690 fd, 0)) == MAP_FAILED) {
691 ERR(ctx, "%m\n");
692 goto fail;
693 }
694
695 p = idx->mm;
696 hdr.magic = read_long_mm(&p);
697 hdr.version = read_long_mm(&p);
698 hdr.root_offset = read_long_mm(&p);
699
700 if (hdr.magic != INDEX_MAGIC) {
701 ERR(ctx, "magic check fail: %x instead of %x\n", hdr.magic,
702 INDEX_MAGIC);
703 goto fail;
704 }
705
706 if (hdr.version >> 16 != INDEX_VERSION_MAJOR) {
707 ERR(ctx, "major version check fail: %u instead of %u\n",
708 hdr.version, INDEX_MAGIC);
709 goto fail;
710 }
711
712 idx->root_offset = hdr.root_offset;
713 idx->size = st.st_size;
714 idx->ctx = ctx;
715 close(fd);
716
717 return idx;
718
719fail:
720 close(fd);
721 if (idx->mm)
722 munmap(idx->mm, st.st_size);
723 free(idx);
724 return NULL;
725}
726
727void index_mm_close(struct index_mm *idx)
728{
729 munmap(idx->mm, idx->size);
730 free(idx);
731}
Lucas De Marchi77bf9362011-12-02 17:41:30 -0200732
733static struct index_mm_node *index_mm_readroot(struct index_mm *idx)
734{
735 return index_mm_read_node(idx, idx->root_offset);
736}
Lucas De Marchi91298dc2011-12-02 17:41:46 -0200737
738static struct index_mm_node *index_mm_readchild(const struct index_mm_node *parent,
739 int ch)
740{
741 if (parent->first <= ch && ch <= parent->last) {
742 return index_mm_read_node(parent->idx,
743 parent->children[ch - parent->first]);
744 }
745
746 return NULL;
747}
Lucas De Marchie33bb872011-12-02 17:45:01 -0200748
749static char *index_mm_search_node(struct index_mm_node *node, const char *key,
750 int i)
751{
752 char *value;
753 struct index_mm_node *child;
754 int ch;
755 int j;
756
757 while(node) {
758 for (j = 0; node->prefix[j]; j++) {
759 ch = node->prefix[j];
760
761 if (ch != key[i+j]) {
762 index_mm_free_node(node);
763 return NULL;
764 }
765 }
766
767 i += j;
768
769 if (key[i] == '\0') {
770 if (node->values) {
771 value = strdup(node->values[0].value);
772 index_mm_free_node(node);
773 return value;
774 } else {
775 return NULL;
776 }
777 }
778
779 child = index_mm_readchild(node, key[i]);
780 index_mm_free_node(node);
781 node = child;
782 i++;
783 }
784
785 return NULL;
786}
Lucas De Marchib797b792011-12-02 17:49:03 -0200787
788/*
789 * Search the index for a key
790 *
791 * Returns the value of the first match
792 *
793 * The recursive functions free their node argument (using index_close).
794 */
795char *index_mm_search(struct index_mm *idx, const char *key)
796{
797 struct index_mm_node *root;
798 char *value;
799
800 root = index_mm_readroot(idx);
801 value = index_mm_search_node(root, key, 0);
802
803 return value;
804}
Lucas De Marchibf89f702011-12-02 18:23:36 -0200805
806/* Level 4: add all the values from a matching node */
807static void index_mm_searchwild_allvalues(struct index_mm_node *node,
808 struct index_value **out)
809{
810 struct index_value *v;
811
812 for (v = node->values; v != NULL; v = v->next)
813 add_value(out, v->value, v->priority);
814
815 index_mm_free_node(node);
816}
817
818/*
819 * Level 3: traverse a sub-keyspace which starts with a wildcard,
820 * looking for matches.
821 */
822static void index_mm_searchwild_all(struct index_mm_node *node, int j,
823 struct buffer *buf,
824 const char *subkey,
825 struct index_value **out)
826{
827 int pushed = 0;
828 int ch;
829
830 while (node->prefix[j]) {
831 ch = node->prefix[j];
832
833 buf_pushchar(buf, ch);
834 pushed++;
835 j++;
836 }
837
838 for (ch = node->first; ch <= node->last; ch++) {
839 struct index_mm_node *child = index_mm_readchild(node, ch);
840
841 if (!child)
842 continue;
843
844 buf_pushchar(buf, ch);
845 index_mm_searchwild_all(child, 0, buf, subkey, out);
846 buf_popchar(buf);
847 }
848
849 if (node->values) {
850 if (fnmatch(buf_str(buf), subkey, 0) == 0)
851 index_mm_searchwild_allvalues(node, out);
852 } else {
853 index_mm_free_node(node);
854 }
855
856 buf_popchars(buf, pushed);
857}
858
859/* Level 2: descend the tree (until we hit a wildcard) */
860static void index_mm_searchwild_node(struct index_mm_node *node,
861 struct buffer *buf,
862 const char *key, int i,
863 struct index_value **out)
864{
865 struct index_mm_node *child;
866 int j;
867 int ch;
868
869 while(node) {
870 for (j = 0; node->prefix[j]; j++) {
871 ch = node->prefix[j];
872
873 if (ch == '*' || ch == '?' || ch == '[') {
874 index_mm_searchwild_all(node, j, buf,
875 &key[i+j], out);
876 return;
877 }
878
879 if (ch != key[i+j]) {
880 index_mm_free_node(node);
881 return;
882 }
883 }
884
885 i += j;
886
887 child = index_mm_readchild(node, '*');
888 if (child) {
889 buf_pushchar(buf, '*');
890 index_mm_searchwild_all(child, 0, buf, &key[i], out);
891 buf_popchar(buf);
892 }
893
894 child = index_mm_readchild(node, '?');
895 if (child) {
896 buf_pushchar(buf, '?');
897 index_mm_searchwild_all(child, 0, buf, &key[i], out);
898 buf_popchar(buf);
899 }
900
901 child = index_mm_readchild(node, '[');
902 if (child) {
903 buf_pushchar(buf, '[');
904 index_mm_searchwild_all(child, 0, buf, &key[i], out);
905 buf_popchar(buf);
906 }
907
908 if (key[i] == '\0') {
909 index_mm_searchwild_allvalues(node, out);
910
911 return;
912 }
913
914 child = index_mm_readchild(node, key[i]);
915 index_mm_free_node(node);
916 node = child;
917 i++;
918 }
919}
920
921/*
922 * Search the index for a key. The index may contain wildcards.
923 *
924 * Returns a list of all the values of matching keys.
925 */
926struct index_value *index_mm_searchwild(struct index_mm *idx, const char *key)
927{
928 struct index_mm_node *root = index_mm_readroot(idx);
Gustavo Sverzut Barbieri405f6142011-12-08 14:36:30 -0200929 struct buffer buf;
Lucas De Marchibf89f702011-12-02 18:23:36 -0200930 struct index_value *out = NULL;
931
Gustavo Sverzut Barbieri405f6142011-12-08 14:36:30 -0200932 buf_init(&buf);
933 index_mm_searchwild_node(root, &buf, key, 0, &out);
934 buf_release(&buf);
Lucas De Marchibf89f702011-12-02 18:23:36 -0200935 return out;
936}