blob: c3252fede06f5052ffb23fa8d38a3d1938938300 [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
123 tmp = realloc(buf->bytes, sz);
124 if (sz > 0 && tmp == NULL)
125 return false;
126 buf->bytes = tmp;
127 buf->size = sz;
128 return true;
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200129}
130
Gustavo Sverzut Barbieri405f6142011-12-08 14:36:30 -0200131static void buf_init(struct buffer *buf)
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200132{
Gustavo Sverzut Barbieri405f6142011-12-08 14:36:30 -0200133 buf->bytes = NULL;
134 buf->size = 0;
135 buf->used = 0;
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200136}
137
Gustavo Sverzut Barbieri405f6142011-12-08 14:36:30 -0200138static void buf_release(struct buffer *buf)
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200139{
140 free(buf->bytes);
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200141}
142
143/* Destroy buffer and return a copy as a C string */
Gustavo Sverzut Barbieri405f6142011-12-08 14:36:30 -0200144static char *buf_steal(struct buffer *buf)
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200145{
146 char *bytes;
147
Gustavo Sverzut Barbieri405f6142011-12-08 14:36:30 -0200148 bytes = realloc(buf->bytes, buf->used + 1);
149 if (!bytes) {
150 free(buf->bytes);
151 return NULL;
152 }
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200153 bytes[buf->used] = '\0';
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200154 return bytes;
155}
156
157/* Return a C string owned by the buffer
158 (invalidated if the buffer is changed).
159 */
160static const char *buf_str(struct buffer *buf)
161{
Gustavo Sverzut Barbieri405f6142011-12-08 14:36:30 -0200162 if (!buf_grow(buf, buf->used + 1))
163 return NULL;
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200164 buf->bytes[buf->used] = '\0';
165 return buf->bytes;
166}
167
Gustavo Sverzut Barbieri405f6142011-12-08 14:36:30 -0200168static bool buf_pushchar(struct buffer *buf, char ch)
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200169{
Gustavo Sverzut Barbieri405f6142011-12-08 14:36:30 -0200170 if (!buf_grow(buf, buf->used + 1))
171 return false;
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200172 buf->bytes[buf->used] = ch;
173 buf->used++;
Gustavo Sverzut Barbieri405f6142011-12-08 14:36:30 -0200174 return true;
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200175}
176
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200177static unsigned buf_freadchars(struct buffer *buf, FILE *in)
178{
179 unsigned i = 0;
180 int ch;
181
182 while ((ch = read_char(in))) {
Gustavo Sverzut Barbieri405f6142011-12-08 14:36:30 -0200183 if (!buf_pushchar(buf, ch))
184 break;
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200185 i++;
186 }
187
188 return i;
189}
190
191static void buf_popchar(struct buffer *buf)
192{
Gustavo Sverzut Barbieri405f6142011-12-08 14:36:30 -0200193 assert(buf->used > 0);
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200194 buf->used--;
195}
196
197static void buf_popchars(struct buffer *buf, unsigned n)
198{
Gustavo Sverzut Barbieri405f6142011-12-08 14:36:30 -0200199 assert(buf->used >= n);
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200200 buf->used -= n;
201}
202
203static void buf_clear(struct buffer *buf)
204{
205 buf->used = 0;
206}
207
208/*
Lucas De Marchieb8bb322011-12-02 10:23:02 -0200209 * Index file searching
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200210 */
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200211struct index_node_f {
212 FILE *file;
213 char *prefix; /* path compression */
214 struct index_value *values;
215 unsigned char first; /* range of child nodes */
216 unsigned char last;
217 uint32_t children[0];
218};
219
220static struct index_node_f *index_read(FILE *in, uint32_t offset)
221{
222 struct index_node_f *node;
223 char *prefix;
224 int i, child_count = 0;
225
226 if ((offset & INDEX_NODE_MASK) == 0)
227 return NULL;
228
229 fseek(in, offset & INDEX_NODE_MASK, SEEK_SET);
Lucas De Marchia7be73b2011-11-30 15:59:36 -0200230
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200231 if (offset & INDEX_NODE_PREFIX) {
Gustavo Sverzut Barbieri405f6142011-12-08 14:36:30 -0200232 struct buffer buf;
233 buf_init(&buf);
234 buf_freadchars(&buf, in);
235 prefix = buf_steal(&buf);
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200236 } else
237 prefix = NOFAIL(strdup(""));
Lucas De Marchia7be73b2011-11-30 15:59:36 -0200238
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200239 if (offset & INDEX_NODE_CHILDS) {
240 char first = read_char(in);
241 char last = read_char(in);
242 child_count = last - first + 1;
Lucas De Marchia7be73b2011-11-30 15:59:36 -0200243
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200244 node = NOFAIL(malloc(sizeof(struct index_node_f) +
245 sizeof(uint32_t) * child_count));
Lucas De Marchia7be73b2011-11-30 15:59:36 -0200246
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200247 node->first = first;
248 node->last = last;
249
250 for (i = 0; i < child_count; i++)
251 node->children[i] = read_long(in);
252 } else {
253 node = NOFAIL(malloc(sizeof(struct index_node_f)));
254 node->first = INDEX_CHILDMAX;
255 node->last = 0;
256 }
Lucas De Marchia7be73b2011-11-30 15:59:36 -0200257
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200258 node->values = NULL;
259 if (offset & INDEX_NODE_VALUES) {
260 int value_count;
Gustavo Sverzut Barbieri405f6142011-12-08 14:36:30 -0200261 struct buffer buf;
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200262 const char *value;
263 unsigned int priority;
264
265 value_count = read_long(in);
266
Gustavo Sverzut Barbieri405f6142011-12-08 14:36:30 -0200267 buf_init(&buf);
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200268 while (value_count--) {
269 priority = read_long(in);
Gustavo Sverzut Barbieri405f6142011-12-08 14:36:30 -0200270 buf_freadchars(&buf, in);
271 value = buf_str(&buf);
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200272 add_value(&node->values, value, priority);
Gustavo Sverzut Barbieri405f6142011-12-08 14:36:30 -0200273 buf_clear(&buf);
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200274 }
Gustavo Sverzut Barbieri405f6142011-12-08 14:36:30 -0200275 buf_release(&buf);
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200276 }
277
278 node->prefix = prefix;
279 node->file = in;
280 return node;
281}
282
283static void index_close(struct index_node_f *node)
284{
285 free(node->prefix);
286 index_values_free(node->values);
287 free(node);
288}
289
290struct index_file {
291 FILE *file;
292 uint32_t root_offset;
293};
294
295/* Failures are silent; modprobe will fall back to text files */
296struct index_file *index_file_open(const char *filename)
297{
298 FILE *file;
299 uint32_t magic, version;
300 struct index_file *new;
301
302 file = fopen(filename, "r");
303 if (!file)
304 return NULL;
305 errno = EINVAL;
306
307 magic = read_long(file);
308 if (magic != INDEX_MAGIC)
309 return NULL;
310
311 version = read_long(file);
312 if (version >> 16 != INDEX_VERSION_MAJOR)
313 return NULL;
314
315 new = NOFAIL(malloc(sizeof(struct index_file)));
316 new->file = file;
317 new->root_offset = read_long(new->file);
318
319 errno = 0;
320 return new;
321}
322
Lucas De Marchi0fbdfef2011-12-02 09:56:22 -0200323void index_file_close(struct index_file *idx)
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200324{
Lucas De Marchi0fbdfef2011-12-02 09:56:22 -0200325 fclose(idx->file);
326 free(idx);
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200327}
328
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200329static struct index_node_f *index_readroot(struct index_file *in)
330{
331 return index_read(in->file, in->root_offset);
332}
333
334static struct index_node_f *index_readchild(const struct index_node_f *parent,
335 int ch)
336{
Lucas De Marchie71970a2011-12-02 10:27:15 -0200337 if (parent->first <= ch && ch <= parent->last) {
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200338 return index_read(parent->file,
339 parent->children[ch - parent->first]);
Lucas De Marchie71970a2011-12-02 10:27:15 -0200340 }
341
342 return NULL;
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200343}
344
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200345static char *index_search__node(struct index_node_f *node, const char *key, int i)
346{
347 char *value;
348 struct index_node_f *child;
349 int ch;
350 int j;
351
352 while(node) {
353 for (j = 0; node->prefix[j]; j++) {
354 ch = node->prefix[j];
Lucas De Marchia7be73b2011-11-30 15:59:36 -0200355
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200356 if (ch != key[i+j]) {
357 index_close(node);
358 return NULL;
359 }
360 }
Lucas De Marchie71970a2011-12-02 10:27:15 -0200361
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200362 i += j;
Lucas De Marchia7be73b2011-11-30 15:59:36 -0200363
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200364 if (key[i] == '\0') {
365 if (node->values) {
366 value = strdup(node->values[0].value);
367 index_close(node);
368 return value;
369 } else {
370 return NULL;
371 }
372 }
Lucas De Marchia7be73b2011-11-30 15:59:36 -0200373
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200374 child = index_readchild(node, key[i]);
375 index_close(node);
376 node = child;
377 i++;
378 }
Lucas De Marchia7be73b2011-11-30 15:59:36 -0200379
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200380 return NULL;
381}
382
383/*
Lucas De Marchi1d152ac2011-12-02 10:15:00 -0200384 * Search the index for a key
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200385 *
Lucas De Marchi1d152ac2011-12-02 10:15:00 -0200386 * Returns the value of the first match
387 *
388 * The recursive functions free their node argument (using index_close).
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200389 */
Lucas De Marchi1d152ac2011-12-02 10:15:00 -0200390char *index_search(struct index_file *in, const char *key)
391{
392 struct index_node_f *root;
393 char *value;
394
395 root = index_readroot(in);
396 value = index_search__node(root, key, 0);
397
398 return value;
399}
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200400
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200401
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200402
403/* Level 4: add all the values from a matching node */
404static void index_searchwild__allvalues(struct index_node_f *node,
Lucas De Marchi1d152ac2011-12-02 10:15:00 -0200405 struct index_value **out)
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200406{
Lucas De Marchi1d152ac2011-12-02 10:15:00 -0200407 struct index_value *v;
Lucas De Marchia7be73b2011-11-30 15:59:36 -0200408
Lucas De Marchi1d152ac2011-12-02 10:15:00 -0200409 for (v = node->values; v != NULL; v = v->next)
410 add_value(out, v->value, v->priority);
411
412 index_close(node);
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200413}
414
Lucas De Marchi1d152ac2011-12-02 10:15:00 -0200415/*
416 * Level 3: traverse a sub-keyspace which starts with a wildcard,
417 * looking for matches.
418 */
419static void index_searchwild__all(struct index_node_f *node, int j,
420 struct buffer *buf,
421 const char *subkey,
422 struct index_value **out)
423{
424 int pushed = 0;
425 int ch;
426
427 while (node->prefix[j]) {
428 ch = node->prefix[j];
429
430 buf_pushchar(buf, ch);
431 pushed++;
432 j++;
433 }
434
435 for (ch = node->first; ch <= node->last; ch++) {
436 struct index_node_f *child = index_readchild(node, ch);
437
438 if (!child)
439 continue;
440
441 buf_pushchar(buf, ch);
442 index_searchwild__all(child, 0, buf, subkey, out);
443 buf_popchar(buf);
444 }
445
446 if (node->values) {
447 if (fnmatch(buf_str(buf), subkey, 0) == 0)
448 index_searchwild__allvalues(node, out);
449 } else {
450 index_close(node);
451 }
452
453 buf_popchars(buf, pushed);
454}
455
456/* Level 2: descend the tree (until we hit a wildcard) */
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200457static void index_searchwild__node(struct index_node_f *node,
458 struct buffer *buf,
459 const char *key, int i,
460 struct index_value **out)
461{
462 struct index_node_f *child;
463 int j;
464 int ch;
465
466 while(node) {
467 for (j = 0; node->prefix[j]; j++) {
468 ch = node->prefix[j];
Lucas De Marchia7be73b2011-11-30 15:59:36 -0200469
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200470 if (ch == '*' || ch == '?' || ch == '[') {
471 index_searchwild__all(node, j, buf,
472 &key[i+j], out);
473 return;
474 }
Lucas De Marchia7be73b2011-11-30 15:59:36 -0200475
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200476 if (ch != key[i+j]) {
477 index_close(node);
478 return;
479 }
480 }
Lucas De Marchie71970a2011-12-02 10:27:15 -0200481
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200482 i += j;
Lucas De Marchia7be73b2011-11-30 15:59:36 -0200483
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200484 child = index_readchild(node, '*');
485 if (child) {
486 buf_pushchar(buf, '*');
487 index_searchwild__all(child, 0, buf, &key[i], out);
488 buf_popchar(buf);
489 }
Lucas De Marchia7be73b2011-11-30 15:59:36 -0200490
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200491 child = index_readchild(node, '?');
492 if (child) {
493 buf_pushchar(buf, '?');
494 index_searchwild__all(child, 0, buf, &key[i], out);
495 buf_popchar(buf);
496 }
Lucas De Marchia7be73b2011-11-30 15:59:36 -0200497
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200498 child = index_readchild(node, '[');
499 if (child) {
500 buf_pushchar(buf, '[');
501 index_searchwild__all(child, 0, buf, &key[i], out);
502 buf_popchar(buf);
503 }
Lucas De Marchia7be73b2011-11-30 15:59:36 -0200504
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200505 if (key[i] == '\0') {
506 index_searchwild__allvalues(node, out);
507
508 return;
509 }
Lucas De Marchia7be73b2011-11-30 15:59:36 -0200510
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200511 child = index_readchild(node, key[i]);
512 index_close(node);
513 node = child;
514 i++;
515 }
516}
517
Lucas De Marchi1d152ac2011-12-02 10:15:00 -0200518/*
519 * Search the index for a key. The index may contain wildcards.
520 *
521 * Returns a list of all the values of matching keys.
522 */
523struct index_value *index_searchwild(struct index_file *in, const char *key)
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200524{
Lucas De Marchi1d152ac2011-12-02 10:15:00 -0200525 struct index_node_f *root = index_readroot(in);
Gustavo Sverzut Barbieri405f6142011-12-08 14:36:30 -0200526 struct buffer buf;
Lucas De Marchi1d152ac2011-12-02 10:15:00 -0200527 struct index_value *out = NULL;
Lucas De Marchia7be73b2011-11-30 15:59:36 -0200528
Gustavo Sverzut Barbieri405f6142011-12-08 14:36:30 -0200529 buf_init(&buf);
530 index_searchwild__node(root, &buf, key, 0, &out);
531 buf_release(&buf);
Lucas De Marchi1d152ac2011-12-02 10:15:00 -0200532 return out;
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200533}
Lucas De Marchib471a6b2011-12-01 23:14:20 -0200534
535#include <sys/mman.h>
536#include <sys/stat.h>
537#include <unistd.h>
538
539/**************************************************************************/
540/*
541 * Alternative implementation, using mmap to map all the file to memory when
542 * starting
543 */
544struct index_mm {
545 struct kmod_ctx *ctx;
546 void *mm;
547 uint32_t root_offset;
548 size_t size;
549};
550
Lucas De Marchi836be9a2011-12-02 17:27:52 -0200551struct index_mm_node {
552 struct index_mm *idx;
553 char *prefix;
554 struct index_value *values;
555 unsigned char first;
556 unsigned char last;
557 uint32_t children[];
558};
559
560static inline uint32_t read_long_mm(void **p)
561{
562 uint32_t v = **((uint32_t **)p);
563
564 *p = *((uint8_t **)p) + sizeof(uint32_t);
565
566 return ntohl(v);
567}
568
569static inline uint8_t read_char_mm(void **p)
570{
571 uint8_t *v = *((uint8_t **)p);
572 *p = v + 1;
573 return *v;
574}
575
576static inline char *read_alloc_chars_mm(void **p)
577{
578 char *s = *((char **)p);
579 size_t len = strlen(s) + 1;
580 *p = ((char *)p) + len;
581
582 return memdup(s, len);
583}
584
585static inline char *read_chars_mm(void **p)
586{
587 char *s = *((char **)p);
588 size_t len = strlen(s) + 1;
589 *p = ((char *)p) + len;
590
591 return s;
592}
593
594static struct index_mm_node *index_mm_read_node(struct index_mm *idx,
595 uint32_t offset) {
596 void *p = idx->mm;
597 struct index_mm_node *node;
598 char *prefix;
599 int i, child_count = 0;
600
601
602 if ((offset & INDEX_NODE_MASK) == 0)
603 return NULL;
604
605 p = (char *)p + (offset & INDEX_NODE_MASK);
606
607 if (offset & INDEX_NODE_PREFIX)
608 prefix = read_alloc_chars_mm(&p);
609 else
610 prefix = strdup("");
611
612 if (offset & INDEX_NODE_CHILDS) {
613 char first = read_char_mm(&p);
614 char last = read_char_mm(&p);
615 child_count = last - first + 1;
616
617 node = malloc(sizeof(*node) + sizeof(uint32_t) * child_count);
618
619 node->first = first;
620 node->last = last;
621
622 for (i = 0; i < child_count; i++)
623 node->children[i] = read_long_mm(&p);
624 } else {
625 node = malloc(sizeof(*node));
626 node->first = INDEX_CHILDMAX;
627 node->last = 0;
628 }
629
630 node->values = NULL;
631
632 if (offset & INDEX_NODE_VALUES) {
633 uint32_t j;
634
635 for (j = read_long_mm(&p); j > 0; j--) {
636 unsigned int priority;
637 const char *value;
638
639 priority = read_long_mm(&p);
640 value = read_chars_mm(&p);
641 add_value(&node->values, value, priority);
642 }
643 }
644
645 node->prefix = prefix;
646 node->idx = idx;
647
648 return node;
649}
650
651static void index_mm_free_node(struct index_mm_node *node)
652{
653 free(node->prefix);
654 index_values_free(node->values);
655 free(node);
656}
657
Lucas De Marchib471a6b2011-12-01 23:14:20 -0200658struct index_mm *index_mm_open(struct kmod_ctx *ctx, const char *filename)
659{
660 int fd;
661 struct stat st;
662 struct index_mm *idx;
663 struct {
664 uint32_t magic;
665 uint32_t version;
666 uint32_t root_offset;
667 } hdr;
668 void *p;
669
670 DBG(ctx, "file=%s\n", filename);
671
672 if ((fd = open(filename, O_RDONLY)) < 0) {
673 ERR(ctx, "%m\n");
674 return NULL;
675 }
676
677 fstat(fd, &st);
678
679 idx = malloc(sizeof(*idx));
680 if (idx == NULL) {
681 ERR(ctx, "%m\n");
682 goto fail;
683 }
684
685 if ((idx->mm = mmap(0, st.st_size, PROT_READ,
686 MAP_PRIVATE | MAP_POPULATE,
687 fd, 0)) == MAP_FAILED) {
688 ERR(ctx, "%m\n");
689 goto fail;
690 }
691
692 p = idx->mm;
693 hdr.magic = read_long_mm(&p);
694 hdr.version = read_long_mm(&p);
695 hdr.root_offset = read_long_mm(&p);
696
697 if (hdr.magic != INDEX_MAGIC) {
698 ERR(ctx, "magic check fail: %x instead of %x\n", hdr.magic,
699 INDEX_MAGIC);
700 goto fail;
701 }
702
703 if (hdr.version >> 16 != INDEX_VERSION_MAJOR) {
704 ERR(ctx, "major version check fail: %u instead of %u\n",
705 hdr.version, INDEX_MAGIC);
706 goto fail;
707 }
708
709 idx->root_offset = hdr.root_offset;
710 idx->size = st.st_size;
711 idx->ctx = ctx;
712 close(fd);
713
714 return idx;
715
716fail:
717 close(fd);
718 if (idx->mm)
719 munmap(idx->mm, st.st_size);
720 free(idx);
721 return NULL;
722}
723
724void index_mm_close(struct index_mm *idx)
725{
726 munmap(idx->mm, idx->size);
727 free(idx);
728}
Lucas De Marchi77bf9362011-12-02 17:41:30 -0200729
730static struct index_mm_node *index_mm_readroot(struct index_mm *idx)
731{
732 return index_mm_read_node(idx, idx->root_offset);
733}
Lucas De Marchi91298dc2011-12-02 17:41:46 -0200734
735static struct index_mm_node *index_mm_readchild(const struct index_mm_node *parent,
736 int ch)
737{
738 if (parent->first <= ch && ch <= parent->last) {
739 return index_mm_read_node(parent->idx,
740 parent->children[ch - parent->first]);
741 }
742
743 return NULL;
744}
Lucas De Marchie33bb872011-12-02 17:45:01 -0200745
746static char *index_mm_search_node(struct index_mm_node *node, const char *key,
747 int i)
748{
749 char *value;
750 struct index_mm_node *child;
751 int ch;
752 int j;
753
754 while(node) {
755 for (j = 0; node->prefix[j]; j++) {
756 ch = node->prefix[j];
757
758 if (ch != key[i+j]) {
759 index_mm_free_node(node);
760 return NULL;
761 }
762 }
763
764 i += j;
765
766 if (key[i] == '\0') {
767 if (node->values) {
768 value = strdup(node->values[0].value);
769 index_mm_free_node(node);
770 return value;
771 } else {
772 return NULL;
773 }
774 }
775
776 child = index_mm_readchild(node, key[i]);
777 index_mm_free_node(node);
778 node = child;
779 i++;
780 }
781
782 return NULL;
783}
Lucas De Marchib797b792011-12-02 17:49:03 -0200784
785/*
786 * Search the index for a key
787 *
788 * Returns the value of the first match
789 *
790 * The recursive functions free their node argument (using index_close).
791 */
792char *index_mm_search(struct index_mm *idx, const char *key)
793{
794 struct index_mm_node *root;
795 char *value;
796
797 root = index_mm_readroot(idx);
798 value = index_mm_search_node(root, key, 0);
799
800 return value;
801}
Lucas De Marchibf89f702011-12-02 18:23:36 -0200802
803/* Level 4: add all the values from a matching node */
804static void index_mm_searchwild_allvalues(struct index_mm_node *node,
805 struct index_value **out)
806{
807 struct index_value *v;
808
809 for (v = node->values; v != NULL; v = v->next)
810 add_value(out, v->value, v->priority);
811
812 index_mm_free_node(node);
813}
814
815/*
816 * Level 3: traverse a sub-keyspace which starts with a wildcard,
817 * looking for matches.
818 */
819static void index_mm_searchwild_all(struct index_mm_node *node, int j,
820 struct buffer *buf,
821 const char *subkey,
822 struct index_value **out)
823{
824 int pushed = 0;
825 int ch;
826
827 while (node->prefix[j]) {
828 ch = node->prefix[j];
829
830 buf_pushchar(buf, ch);
831 pushed++;
832 j++;
833 }
834
835 for (ch = node->first; ch <= node->last; ch++) {
836 struct index_mm_node *child = index_mm_readchild(node, ch);
837
838 if (!child)
839 continue;
840
841 buf_pushchar(buf, ch);
842 index_mm_searchwild_all(child, 0, buf, subkey, out);
843 buf_popchar(buf);
844 }
845
846 if (node->values) {
847 if (fnmatch(buf_str(buf), subkey, 0) == 0)
848 index_mm_searchwild_allvalues(node, out);
849 } else {
850 index_mm_free_node(node);
851 }
852
853 buf_popchars(buf, pushed);
854}
855
856/* Level 2: descend the tree (until we hit a wildcard) */
857static void index_mm_searchwild_node(struct index_mm_node *node,
858 struct buffer *buf,
859 const char *key, int i,
860 struct index_value **out)
861{
862 struct index_mm_node *child;
863 int j;
864 int ch;
865
866 while(node) {
867 for (j = 0; node->prefix[j]; j++) {
868 ch = node->prefix[j];
869
870 if (ch == '*' || ch == '?' || ch == '[') {
871 index_mm_searchwild_all(node, j, buf,
872 &key[i+j], out);
873 return;
874 }
875
876 if (ch != key[i+j]) {
877 index_mm_free_node(node);
878 return;
879 }
880 }
881
882 i += j;
883
884 child = index_mm_readchild(node, '*');
885 if (child) {
886 buf_pushchar(buf, '*');
887 index_mm_searchwild_all(child, 0, buf, &key[i], out);
888 buf_popchar(buf);
889 }
890
891 child = index_mm_readchild(node, '?');
892 if (child) {
893 buf_pushchar(buf, '?');
894 index_mm_searchwild_all(child, 0, buf, &key[i], out);
895 buf_popchar(buf);
896 }
897
898 child = index_mm_readchild(node, '[');
899 if (child) {
900 buf_pushchar(buf, '[');
901 index_mm_searchwild_all(child, 0, buf, &key[i], out);
902 buf_popchar(buf);
903 }
904
905 if (key[i] == '\0') {
906 index_mm_searchwild_allvalues(node, out);
907
908 return;
909 }
910
911 child = index_mm_readchild(node, key[i]);
912 index_mm_free_node(node);
913 node = child;
914 i++;
915 }
916}
917
918/*
919 * Search the index for a key. The index may contain wildcards.
920 *
921 * Returns a list of all the values of matching keys.
922 */
923struct index_value *index_mm_searchwild(struct index_mm *idx, const char *key)
924{
925 struct index_mm_node *root = index_mm_readroot(idx);
Gustavo Sverzut Barbieri405f6142011-12-08 14:36:30 -0200926 struct buffer buf;
Lucas De Marchibf89f702011-12-02 18:23:36 -0200927 struct index_value *out = NULL;
928
Gustavo Sverzut Barbieri405f6142011-12-08 14:36:30 -0200929 buf_init(&buf);
930 index_mm_searchwild_node(root, &buf, key, 0, &out);
931 buf_release(&buf);
Lucas De Marchibf89f702011-12-02 18:23:36 -0200932 return out;
933}