blob: 580b0599499fb9ebe018817b4ed6ea19f13b24e7 [file] [log] [blame]
Lucas De Marchi8f923be2011-12-03 04:28:49 -02001/*
2 * libkmod - interface to kernel module operations
3 *
Lucas De Marchi8f923be2011-12-03 04:28:49 -02004 * Copyright (C) 2011 ProFUSION embedded systems
5 *
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 Marchie8847fd2011-11-30 15:23:28 -0200214static unsigned buf_freadchars(struct buffer *buf, FILE *in)
215{
216 unsigned i = 0;
217 int ch;
218
219 while ((ch = read_char(in))) {
Gustavo Sverzut Barbieri405f6142011-12-08 14:36:30 -0200220 if (!buf_pushchar(buf, ch))
221 break;
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200222 i++;
223 }
224
225 return i;
226}
227
228static void buf_popchar(struct buffer *buf)
229{
Gustavo Sverzut Barbieri405f6142011-12-08 14:36:30 -0200230 assert(buf->used > 0);
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200231 buf->used--;
232}
233
234static void buf_popchars(struct buffer *buf, unsigned n)
235{
Gustavo Sverzut Barbieri405f6142011-12-08 14:36:30 -0200236 assert(buf->used >= n);
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200237 buf->used -= n;
238}
239
240static void buf_clear(struct buffer *buf)
241{
242 buf->used = 0;
243}
244
245/*
Lucas De Marchieb8bb322011-12-02 10:23:02 -0200246 * Index file searching
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200247 */
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200248struct index_node_f {
249 FILE *file;
250 char *prefix; /* path compression */
251 struct index_value *values;
252 unsigned char first; /* range of child nodes */
253 unsigned char last;
254 uint32_t children[0];
255};
256
257static struct index_node_f *index_read(FILE *in, uint32_t offset)
258{
259 struct index_node_f *node;
260 char *prefix;
261 int i, child_count = 0;
262
263 if ((offset & INDEX_NODE_MASK) == 0)
264 return NULL;
265
266 fseek(in, offset & INDEX_NODE_MASK, SEEK_SET);
Lucas De Marchia7be73b2011-11-30 15:59:36 -0200267
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200268 if (offset & INDEX_NODE_PREFIX) {
Gustavo Sverzut Barbieri405f6142011-12-08 14:36:30 -0200269 struct buffer buf;
270 buf_init(&buf);
271 buf_freadchars(&buf, in);
272 prefix = buf_steal(&buf);
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200273 } else
274 prefix = NOFAIL(strdup(""));
Lucas De Marchia7be73b2011-11-30 15:59:36 -0200275
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200276 if (offset & INDEX_NODE_CHILDS) {
277 char first = read_char(in);
278 char last = read_char(in);
279 child_count = last - first + 1;
Lucas De Marchia7be73b2011-11-30 15:59:36 -0200280
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200281 node = NOFAIL(malloc(sizeof(struct index_node_f) +
282 sizeof(uint32_t) * child_count));
Lucas De Marchia7be73b2011-11-30 15:59:36 -0200283
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200284 node->first = first;
285 node->last = last;
286
287 for (i = 0; i < child_count; i++)
288 node->children[i] = read_long(in);
289 } else {
290 node = NOFAIL(malloc(sizeof(struct index_node_f)));
291 node->first = INDEX_CHILDMAX;
292 node->last = 0;
293 }
Lucas De Marchia7be73b2011-11-30 15:59:36 -0200294
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200295 node->values = NULL;
296 if (offset & INDEX_NODE_VALUES) {
297 int value_count;
Gustavo Sverzut Barbieri405f6142011-12-08 14:36:30 -0200298 struct buffer buf;
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200299 const char *value;
300 unsigned int priority;
301
302 value_count = read_long(in);
303
Gustavo Sverzut Barbieri405f6142011-12-08 14:36:30 -0200304 buf_init(&buf);
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200305 while (value_count--) {
306 priority = read_long(in);
Gustavo Sverzut Barbieri405f6142011-12-08 14:36:30 -0200307 buf_freadchars(&buf, in);
308 value = buf_str(&buf);
Gustavo Sverzut Barbieri1433ba92011-12-08 14:50:29 -0200309 add_value(&node->values, value, buf.used, priority);
Gustavo Sverzut Barbieri405f6142011-12-08 14:36:30 -0200310 buf_clear(&buf);
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200311 }
Gustavo Sverzut Barbieri405f6142011-12-08 14:36:30 -0200312 buf_release(&buf);
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200313 }
314
315 node->prefix = prefix;
316 node->file = in;
317 return node;
318}
319
320static void index_close(struct index_node_f *node)
321{
322 free(node->prefix);
323 index_values_free(node->values);
324 free(node);
325}
326
327struct index_file {
328 FILE *file;
329 uint32_t root_offset;
330};
331
332/* Failures are silent; modprobe will fall back to text files */
333struct index_file *index_file_open(const char *filename)
334{
335 FILE *file;
336 uint32_t magic, version;
337 struct index_file *new;
338
Cristian Rodríguez79e5ea92011-12-16 02:49:54 -0300339 file = fopen(filename, "re");
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200340 if (!file)
341 return NULL;
342 errno = EINVAL;
343
344 magic = read_long(file);
Cristian Rodríguez67d94ad2011-12-23 03:06:56 -0200345 if (magic != INDEX_MAGIC) {
346 fclose(file);
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200347 return NULL;
Cristian Rodríguez67d94ad2011-12-23 03:06:56 -0200348 }
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200349
350 version = read_long(file);
Cristian Rodríguez4088b272011-12-26 01:38:04 -0300351 if (version >> 16 != INDEX_VERSION_MAJOR) {
352 fclose(file);
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200353 return NULL;
Cristian Rodríguez4088b272011-12-26 01:38:04 -0300354 }
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200355
356 new = NOFAIL(malloc(sizeof(struct index_file)));
357 new->file = file;
358 new->root_offset = read_long(new->file);
359
360 errno = 0;
361 return new;
362}
363
Lucas De Marchi0fbdfef2011-12-02 09:56:22 -0200364void index_file_close(struct index_file *idx)
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200365{
Lucas De Marchi0fbdfef2011-12-02 09:56:22 -0200366 fclose(idx->file);
367 free(idx);
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200368}
369
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200370static struct index_node_f *index_readroot(struct index_file *in)
371{
372 return index_read(in->file, in->root_offset);
373}
374
375static struct index_node_f *index_readchild(const struct index_node_f *parent,
376 int ch)
377{
Lucas De Marchie71970a2011-12-02 10:27:15 -0200378 if (parent->first <= ch && ch <= parent->last) {
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200379 return index_read(parent->file,
380 parent->children[ch - parent->first]);
Lucas De Marchie71970a2011-12-02 10:27:15 -0200381 }
382
383 return NULL;
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200384}
385
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200386static char *index_search__node(struct index_node_f *node, const char *key, int i)
387{
388 char *value;
389 struct index_node_f *child;
390 int ch;
391 int j;
392
393 while(node) {
394 for (j = 0; node->prefix[j]; j++) {
395 ch = node->prefix[j];
Lucas De Marchia7be73b2011-11-30 15:59:36 -0200396
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200397 if (ch != key[i+j]) {
398 index_close(node);
399 return NULL;
400 }
401 }
Lucas De Marchie71970a2011-12-02 10:27:15 -0200402
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200403 i += j;
Lucas De Marchia7be73b2011-11-30 15:59:36 -0200404
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200405 if (key[i] == '\0') {
406 if (node->values) {
407 value = strdup(node->values[0].value);
408 index_close(node);
409 return value;
410 } else {
411 return NULL;
412 }
413 }
Lucas De Marchia7be73b2011-11-30 15:59:36 -0200414
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200415 child = index_readchild(node, key[i]);
416 index_close(node);
417 node = child;
418 i++;
419 }
Lucas De Marchia7be73b2011-11-30 15:59:36 -0200420
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200421 return NULL;
422}
423
424/*
Lucas De Marchi1d152ac2011-12-02 10:15:00 -0200425 * Search the index for a key
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200426 *
Lucas De Marchi1d152ac2011-12-02 10:15:00 -0200427 * Returns the value of the first match
428 *
429 * The recursive functions free their node argument (using index_close).
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200430 */
Lucas De Marchi1d152ac2011-12-02 10:15:00 -0200431char *index_search(struct index_file *in, const char *key)
432{
433 struct index_node_f *root;
434 char *value;
435
436 root = index_readroot(in);
437 value = index_search__node(root, key, 0);
438
439 return value;
440}
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200441
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200442
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200443
444/* Level 4: add all the values from a matching node */
445static void index_searchwild__allvalues(struct index_node_f *node,
Lucas De Marchi1d152ac2011-12-02 10:15:00 -0200446 struct index_value **out)
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200447{
Lucas De Marchi1d152ac2011-12-02 10:15:00 -0200448 struct index_value *v;
Lucas De Marchia7be73b2011-11-30 15:59:36 -0200449
Lucas De Marchi1d152ac2011-12-02 10:15:00 -0200450 for (v = node->values; v != NULL; v = v->next)
Gustavo Sverzut Barbieri1433ba92011-12-08 14:50:29 -0200451 add_value(out, v->value, v->len, v->priority);
Lucas De Marchi1d152ac2011-12-02 10:15:00 -0200452
453 index_close(node);
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200454}
455
Lucas De Marchi1d152ac2011-12-02 10:15:00 -0200456/*
457 * Level 3: traverse a sub-keyspace which starts with a wildcard,
458 * looking for matches.
459 */
460static void index_searchwild__all(struct index_node_f *node, int j,
461 struct buffer *buf,
462 const char *subkey,
463 struct index_value **out)
464{
465 int pushed = 0;
466 int ch;
467
468 while (node->prefix[j]) {
469 ch = node->prefix[j];
470
471 buf_pushchar(buf, ch);
472 pushed++;
473 j++;
474 }
475
476 for (ch = node->first; ch <= node->last; ch++) {
477 struct index_node_f *child = index_readchild(node, ch);
478
479 if (!child)
480 continue;
481
482 buf_pushchar(buf, ch);
483 index_searchwild__all(child, 0, buf, subkey, out);
484 buf_popchar(buf);
485 }
486
487 if (node->values) {
488 if (fnmatch(buf_str(buf), subkey, 0) == 0)
489 index_searchwild__allvalues(node, out);
Gustavo Sverzut Barbieri27fdf632011-12-10 13:28:18 -0200490 else
491 index_close(node);
Lucas De Marchi1d152ac2011-12-02 10:15:00 -0200492 } else {
493 index_close(node);
494 }
495
496 buf_popchars(buf, pushed);
497}
498
499/* Level 2: descend the tree (until we hit a wildcard) */
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200500static void index_searchwild__node(struct index_node_f *node,
501 struct buffer *buf,
502 const char *key, int i,
503 struct index_value **out)
504{
505 struct index_node_f *child;
506 int j;
507 int ch;
508
509 while(node) {
510 for (j = 0; node->prefix[j]; j++) {
511 ch = node->prefix[j];
Lucas De Marchia7be73b2011-11-30 15:59:36 -0200512
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200513 if (ch == '*' || ch == '?' || ch == '[') {
514 index_searchwild__all(node, j, buf,
515 &key[i+j], out);
516 return;
517 }
Lucas De Marchia7be73b2011-11-30 15:59:36 -0200518
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200519 if (ch != key[i+j]) {
520 index_close(node);
521 return;
522 }
523 }
Lucas De Marchie71970a2011-12-02 10:27:15 -0200524
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200525 i += j;
Lucas De Marchia7be73b2011-11-30 15:59:36 -0200526
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200527 child = index_readchild(node, '*');
528 if (child) {
529 buf_pushchar(buf, '*');
530 index_searchwild__all(child, 0, buf, &key[i], out);
531 buf_popchar(buf);
532 }
Lucas De Marchia7be73b2011-11-30 15:59:36 -0200533
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200534 child = index_readchild(node, '?');
535 if (child) {
536 buf_pushchar(buf, '?');
537 index_searchwild__all(child, 0, buf, &key[i], out);
538 buf_popchar(buf);
539 }
Lucas De Marchia7be73b2011-11-30 15:59:36 -0200540
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200541 child = index_readchild(node, '[');
542 if (child) {
543 buf_pushchar(buf, '[');
544 index_searchwild__all(child, 0, buf, &key[i], out);
545 buf_popchar(buf);
546 }
Lucas De Marchia7be73b2011-11-30 15:59:36 -0200547
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200548 if (key[i] == '\0') {
549 index_searchwild__allvalues(node, out);
550
551 return;
552 }
Lucas De Marchia7be73b2011-11-30 15:59:36 -0200553
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200554 child = index_readchild(node, key[i]);
555 index_close(node);
556 node = child;
557 i++;
558 }
559}
560
Lucas De Marchi1d152ac2011-12-02 10:15:00 -0200561/*
562 * Search the index for a key. The index may contain wildcards.
563 *
564 * Returns a list of all the values of matching keys.
565 */
566struct index_value *index_searchwild(struct index_file *in, const char *key)
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200567{
Lucas De Marchi1d152ac2011-12-02 10:15:00 -0200568 struct index_node_f *root = index_readroot(in);
Gustavo Sverzut Barbieri405f6142011-12-08 14:36:30 -0200569 struct buffer buf;
Lucas De Marchi1d152ac2011-12-02 10:15:00 -0200570 struct index_value *out = NULL;
Lucas De Marchia7be73b2011-11-30 15:59:36 -0200571
Gustavo Sverzut Barbieri405f6142011-12-08 14:36:30 -0200572 buf_init(&buf);
573 index_searchwild__node(root, &buf, key, 0, &out);
574 buf_release(&buf);
Lucas De Marchi1d152ac2011-12-02 10:15:00 -0200575 return out;
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200576}
Lucas De Marchib471a6b2011-12-01 23:14:20 -0200577
578#include <sys/mman.h>
579#include <sys/stat.h>
580#include <unistd.h>
581
Gustavo Sverzut Barbieri15c1c142011-12-10 11:44:31 -0200582static const char _idx_empty_str[] = "";
583
Lucas De Marchib471a6b2011-12-01 23:14:20 -0200584/**************************************************************************/
585/*
586 * Alternative implementation, using mmap to map all the file to memory when
587 * starting
588 */
589struct index_mm {
590 struct kmod_ctx *ctx;
591 void *mm;
592 uint32_t root_offset;
593 size_t size;
594};
595
Gustavo Sverzut Barbierid0915462011-12-10 13:04:43 -0200596struct index_mm_value {
597 unsigned int priority;
598 unsigned int len;
599 const char *value;
600};
601
602struct index_mm_value_array {
603 struct index_mm_value *values;
604 unsigned int len;
605};
606
Lucas De Marchi836be9a2011-12-02 17:27:52 -0200607struct index_mm_node {
608 struct index_mm *idx;
Gustavo Sverzut Barbieri15c1c142011-12-10 11:44:31 -0200609 const char *prefix; /* mmape'd value */
Gustavo Sverzut Barbierid0915462011-12-10 13:04:43 -0200610 struct index_mm_value_array values;
Lucas De Marchi836be9a2011-12-02 17:27:52 -0200611 unsigned char first;
612 unsigned char last;
613 uint32_t children[];
614};
615
616static inline uint32_t read_long_mm(void **p)
617{
Gustavo Sverzut Barbierifc2d8352011-12-10 11:36:35 -0200618 uint8_t *addr = *(uint8_t **)p;
619 uint32_t v;
Lucas De Marchi836be9a2011-12-02 17:27:52 -0200620
Gustavo Sverzut Barbierifc2d8352011-12-10 11:36:35 -0200621 /* addr may be unalined to uint32_t */
622 memcpy(&v, addr, sizeof(uint32_t));
Lucas De Marchi836be9a2011-12-02 17:27:52 -0200623
Gustavo Sverzut Barbierifc2d8352011-12-10 11:36:35 -0200624 *p = addr + sizeof(uint32_t);
Lucas De Marchi836be9a2011-12-02 17:27:52 -0200625 return ntohl(v);
626}
627
628static inline uint8_t read_char_mm(void **p)
629{
Gustavo Sverzut Barbierifc2d8352011-12-10 11:36:35 -0200630 uint8_t *addr = *(uint8_t **)p;
631 uint8_t v = *addr;
632 *p = addr + sizeof(uint8_t);
633 return v;
Lucas De Marchi836be9a2011-12-02 17:27:52 -0200634}
635
Gustavo Sverzut Barbieri1433ba92011-12-08 14:50:29 -0200636static inline char *read_chars_mm(void **p, unsigned *rlen)
Lucas De Marchi836be9a2011-12-02 17:27:52 -0200637{
Gustavo Sverzut Barbierifc2d8352011-12-10 11:36:35 -0200638 char *addr = *(char **)p;
639 size_t len = *rlen = strlen(addr);
640 *p = addr + len + 1;
641 return addr;
Lucas De Marchi836be9a2011-12-02 17:27:52 -0200642}
643
644static struct index_mm_node *index_mm_read_node(struct index_mm *idx,
645 uint32_t offset) {
646 void *p = idx->mm;
647 struct index_mm_node *node;
Gustavo Sverzut Barbieri15c1c142011-12-10 11:44:31 -0200648 const char *prefix;
Gustavo Sverzut Barbierid0915462011-12-10 13:04:43 -0200649 int i, child_count, value_count, children_padding;
650 uint32_t children[INDEX_CHILDMAX];
651 char first, last;
Lucas De Marchi836be9a2011-12-02 17:27:52 -0200652
653 if ((offset & INDEX_NODE_MASK) == 0)
654 return NULL;
655
656 p = (char *)p + (offset & INDEX_NODE_MASK);
657
Gustavo Sverzut Barbieri15c1c142011-12-10 11:44:31 -0200658 if (offset & INDEX_NODE_PREFIX) {
659 unsigned len;
660 prefix = read_chars_mm(&p, &len);
661 } else
662 prefix = _idx_empty_str;
Lucas De Marchi836be9a2011-12-02 17:27:52 -0200663
664 if (offset & INDEX_NODE_CHILDS) {
Gustavo Sverzut Barbierid0915462011-12-10 13:04:43 -0200665 first = read_char_mm(&p);
666 last = read_char_mm(&p);
Lucas De Marchi836be9a2011-12-02 17:27:52 -0200667 child_count = last - first + 1;
Lucas De Marchi836be9a2011-12-02 17:27:52 -0200668 for (i = 0; i < child_count; i++)
Gustavo Sverzut Barbierid0915462011-12-10 13:04:43 -0200669 children[i] = read_long_mm(&p);
Lucas De Marchi836be9a2011-12-02 17:27:52 -0200670 } else {
Gustavo Sverzut Barbierid0915462011-12-10 13:04:43 -0200671 first = INDEX_CHILDMAX;
672 last = 0;
673 child_count = 0;
Lucas De Marchi836be9a2011-12-02 17:27:52 -0200674 }
675
Gustavo Sverzut Barbieric6824b62011-12-21 18:23:58 -0200676 children_padding = (sizeof(struct index_mm_node) +
Gustavo Sverzut Barbierid0915462011-12-10 13:04:43 -0200677 (sizeof(uint32_t) * child_count)) % sizeof(void *);
Lucas De Marchi836be9a2011-12-02 17:27:52 -0200678
Gustavo Sverzut Barbierid0915462011-12-10 13:04:43 -0200679 if (offset & INDEX_NODE_VALUES)
680 value_count = read_long_mm(&p);
681 else
682 value_count = 0;
Lucas De Marchi836be9a2011-12-02 17:27:52 -0200683
Gustavo Sverzut Barbierid0915462011-12-10 13:04:43 -0200684 node = malloc(sizeof(struct index_mm_node)
685 + sizeof(uint32_t) * child_count + children_padding
686 + sizeof(struct index_mm_value) * value_count);
687 if (node == NULL)
688 return NULL;
Lucas De Marchi836be9a2011-12-02 17:27:52 -0200689
Lucas De Marchi836be9a2011-12-02 17:27:52 -0200690 node->idx = idx;
Gustavo Sverzut Barbierid0915462011-12-10 13:04:43 -0200691 node->prefix = prefix;
692 if (value_count == 0)
693 node->values.values = NULL;
694 else {
695 node->values.values = (struct index_mm_value *)
696 ((char *)node + sizeof(struct index_mm_node) +
697 sizeof(uint32_t) * child_count + children_padding);
698 }
699 node->values.len = value_count;
700 node->first = first;
701 node->last = last;
702 memcpy(node->children, children, sizeof(uint32_t) * child_count);
703
704 for (i = 0; i < value_count; i++) {
705 struct index_mm_value *v = node->values.values + i;
706 v->priority = read_long_mm(&p);
707 v->value = read_chars_mm(&p, &v->len);
708 }
Lucas De Marchi836be9a2011-12-02 17:27:52 -0200709
710 return node;
711}
712
713static void index_mm_free_node(struct index_mm_node *node)
714{
Lucas De Marchi836be9a2011-12-02 17:27:52 -0200715 free(node);
716}
717
Lucas De Marchi5109f2b2011-12-08 15:10:55 -0200718struct index_mm *index_mm_open(struct kmod_ctx *ctx, const char *filename,
719 bool populate)
Lucas De Marchib471a6b2011-12-01 23:14:20 -0200720{
721 int fd;
Lucas De Marchi5109f2b2011-12-08 15:10:55 -0200722 int flags;
Lucas De Marchib471a6b2011-12-01 23:14:20 -0200723 struct stat st;
724 struct index_mm *idx;
725 struct {
726 uint32_t magic;
727 uint32_t version;
728 uint32_t root_offset;
729 } hdr;
730 void *p;
731
732 DBG(ctx, "file=%s\n", filename);
733
Lucas De Marchi7d51d8b2011-12-12 18:41:57 -0200734 idx = malloc(sizeof(*idx));
735 if (idx == NULL) {
Lucas De Marchib471a6b2011-12-01 23:14:20 -0200736 ERR(ctx, "%m\n");
737 return NULL;
738 }
739
Cristian Rodríguez79e5ea92011-12-16 02:49:54 -0300740 if ((fd = open(filename, O_RDONLY|O_CLOEXEC)) < 0) {
Lucas De Marchib471a6b2011-12-01 23:14:20 -0200741 ERR(ctx, "%m\n");
Lucas De Marchi7d51d8b2011-12-12 18:41:57 -0200742 goto fail_open;
Lucas De Marchib471a6b2011-12-01 23:14:20 -0200743 }
744
Lucas De Marchi7d51d8b2011-12-12 18:41:57 -0200745 fstat(fd, &st);
Lucas De Marchi5109f2b2011-12-08 15:10:55 -0200746 flags = MAP_PRIVATE;
747 if (populate)
748 flags |= MAP_POPULATE;
749
750 if ((idx->mm = mmap(0, st.st_size, PROT_READ, flags, fd, 0))
751 == MAP_FAILED) {
Lucas De Marchib471a6b2011-12-01 23:14:20 -0200752 ERR(ctx, "%m\n");
753 goto fail;
754 }
755
756 p = idx->mm;
757 hdr.magic = read_long_mm(&p);
758 hdr.version = read_long_mm(&p);
759 hdr.root_offset = read_long_mm(&p);
760
761 if (hdr.magic != INDEX_MAGIC) {
762 ERR(ctx, "magic check fail: %x instead of %x\n", hdr.magic,
763 INDEX_MAGIC);
764 goto fail;
765 }
766
767 if (hdr.version >> 16 != INDEX_VERSION_MAJOR) {
768 ERR(ctx, "major version check fail: %u instead of %u\n",
769 hdr.version, INDEX_MAGIC);
770 goto fail;
771 }
772
773 idx->root_offset = hdr.root_offset;
774 idx->size = st.st_size;
775 idx->ctx = ctx;
776 close(fd);
777
778 return idx;
779
780fail:
781 close(fd);
Gustavo Sverzut Barbieria5a92a62011-12-16 16:17:50 -0200782 if (idx->mm != MAP_FAILED)
Lucas De Marchib471a6b2011-12-01 23:14:20 -0200783 munmap(idx->mm, st.st_size);
Gustavo Sverzut Barbieria5a92a62011-12-16 16:17:50 -0200784fail_open:
Lucas De Marchib471a6b2011-12-01 23:14:20 -0200785 free(idx);
786 return NULL;
787}
788
789void index_mm_close(struct index_mm *idx)
790{
791 munmap(idx->mm, idx->size);
792 free(idx);
793}
Lucas De Marchi77bf9362011-12-02 17:41:30 -0200794
795static struct index_mm_node *index_mm_readroot(struct index_mm *idx)
796{
797 return index_mm_read_node(idx, idx->root_offset);
798}
Lucas De Marchi91298dc2011-12-02 17:41:46 -0200799
800static struct index_mm_node *index_mm_readchild(const struct index_mm_node *parent,
801 int ch)
802{
803 if (parent->first <= ch && ch <= parent->last) {
804 return index_mm_read_node(parent->idx,
805 parent->children[ch - parent->first]);
806 }
807
808 return NULL;
809}
Lucas De Marchie33bb872011-12-02 17:45:01 -0200810
811static char *index_mm_search_node(struct index_mm_node *node, const char *key,
812 int i)
813{
814 char *value;
815 struct index_mm_node *child;
816 int ch;
817 int j;
818
819 while(node) {
820 for (j = 0; node->prefix[j]; j++) {
821 ch = node->prefix[j];
822
823 if (ch != key[i+j]) {
824 index_mm_free_node(node);
825 return NULL;
826 }
827 }
828
829 i += j;
830
831 if (key[i] == '\0') {
Gustavo Sverzut Barbierid0915462011-12-10 13:04:43 -0200832 if (node->values.len > 0) {
833 value = strdup(node->values.values[0].value);
Lucas De Marchie33bb872011-12-02 17:45:01 -0200834 index_mm_free_node(node);
835 return value;
836 } else {
837 return NULL;
838 }
839 }
840
841 child = index_mm_readchild(node, key[i]);
842 index_mm_free_node(node);
843 node = child;
844 i++;
845 }
846
847 return NULL;
848}
Lucas De Marchib797b792011-12-02 17:49:03 -0200849
850/*
851 * Search the index for a key
852 *
853 * Returns the value of the first match
854 *
855 * The recursive functions free their node argument (using index_close).
856 */
857char *index_mm_search(struct index_mm *idx, const char *key)
858{
859 struct index_mm_node *root;
860 char *value;
861
862 root = index_mm_readroot(idx);
863 value = index_mm_search_node(root, key, 0);
864
865 return value;
866}
Lucas De Marchibf89f702011-12-02 18:23:36 -0200867
868/* Level 4: add all the values from a matching node */
869static void index_mm_searchwild_allvalues(struct index_mm_node *node,
870 struct index_value **out)
871{
Gustavo Sverzut Barbierid0915462011-12-10 13:04:43 -0200872 struct index_mm_value *itr, *itr_end;
Lucas De Marchibf89f702011-12-02 18:23:36 -0200873
Gustavo Sverzut Barbierid0915462011-12-10 13:04:43 -0200874 itr = node->values.values;
875 itr_end = itr + node->values.len;
876 for (; itr < itr_end; itr++)
877 add_value(out, itr->value, itr->len, itr->priority);
Lucas De Marchibf89f702011-12-02 18:23:36 -0200878
879 index_mm_free_node(node);
880}
881
882/*
883 * Level 3: traverse a sub-keyspace which starts with a wildcard,
884 * looking for matches.
885 */
886static void index_mm_searchwild_all(struct index_mm_node *node, int j,
887 struct buffer *buf,
888 const char *subkey,
889 struct index_value **out)
890{
891 int pushed = 0;
892 int ch;
893
894 while (node->prefix[j]) {
895 ch = node->prefix[j];
896
897 buf_pushchar(buf, ch);
898 pushed++;
899 j++;
900 }
901
902 for (ch = node->first; ch <= node->last; ch++) {
903 struct index_mm_node *child = index_mm_readchild(node, ch);
904
905 if (!child)
906 continue;
907
908 buf_pushchar(buf, ch);
909 index_mm_searchwild_all(child, 0, buf, subkey, out);
910 buf_popchar(buf);
911 }
912
Gustavo Sverzut Barbierid0915462011-12-10 13:04:43 -0200913 if (node->values.len > 0) {
Lucas De Marchibf89f702011-12-02 18:23:36 -0200914 if (fnmatch(buf_str(buf), subkey, 0) == 0)
915 index_mm_searchwild_allvalues(node, out);
Gustavo Sverzut Barbieri27fdf632011-12-10 13:28:18 -0200916 else
917 index_mm_free_node(node);
Lucas De Marchibf89f702011-12-02 18:23:36 -0200918 } else {
919 index_mm_free_node(node);
920 }
921
922 buf_popchars(buf, pushed);
923}
924
925/* Level 2: descend the tree (until we hit a wildcard) */
926static void index_mm_searchwild_node(struct index_mm_node *node,
927 struct buffer *buf,
928 const char *key, int i,
929 struct index_value **out)
930{
931 struct index_mm_node *child;
932 int j;
933 int ch;
934
935 while(node) {
936 for (j = 0; node->prefix[j]; j++) {
937 ch = node->prefix[j];
938
939 if (ch == '*' || ch == '?' || ch == '[') {
940 index_mm_searchwild_all(node, j, buf,
941 &key[i+j], out);
942 return;
943 }
944
945 if (ch != key[i+j]) {
946 index_mm_free_node(node);
947 return;
948 }
949 }
950
951 i += j;
952
953 child = index_mm_readchild(node, '*');
954 if (child) {
955 buf_pushchar(buf, '*');
956 index_mm_searchwild_all(child, 0, buf, &key[i], out);
957 buf_popchar(buf);
958 }
959
960 child = index_mm_readchild(node, '?');
961 if (child) {
962 buf_pushchar(buf, '?');
963 index_mm_searchwild_all(child, 0, buf, &key[i], out);
964 buf_popchar(buf);
965 }
966
967 child = index_mm_readchild(node, '[');
968 if (child) {
969 buf_pushchar(buf, '[');
970 index_mm_searchwild_all(child, 0, buf, &key[i], out);
971 buf_popchar(buf);
972 }
973
974 if (key[i] == '\0') {
975 index_mm_searchwild_allvalues(node, out);
976
977 return;
978 }
979
980 child = index_mm_readchild(node, key[i]);
981 index_mm_free_node(node);
982 node = child;
983 i++;
984 }
985}
986
987/*
988 * Search the index for a key. The index may contain wildcards.
989 *
990 * Returns a list of all the values of matching keys.
991 */
992struct index_value *index_mm_searchwild(struct index_mm *idx, const char *key)
993{
994 struct index_mm_node *root = index_mm_readroot(idx);
Gustavo Sverzut Barbieri405f6142011-12-08 14:36:30 -0200995 struct buffer buf;
Lucas De Marchibf89f702011-12-02 18:23:36 -0200996 struct index_value *out = NULL;
997
Gustavo Sverzut Barbieri405f6142011-12-08 14:36:30 -0200998 buf_init(&buf);
999 index_mm_searchwild_node(root, &buf, key, 0, &out);
1000 buf_release(&buf);
Lucas De Marchibf89f702011-12-02 18:23:36 -02001001 return out;
1002}