blob: fddcf51009252a2c5f067ea0799f3995cf872b18 [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,
Gustavo Sverzut Barbieri1433ba92011-12-08 14:50:29 -020046 const char *value, unsigned len, unsigned int priority)
Lucas De Marchie8847fd2011-11-30 15:23:28 -020047{
48 struct index_value *v;
49 int duplicate = 0;
Lucas De Marchie8847fd2011-11-30 15:23:28 -020050
51 /* report the presence of duplicate values */
52 for (v = *values; v; v = v->next) {
53 if (streq(v->value, value))
54 duplicate = 1;
55 }
56
57 /* find position to insert value */
58 while (*values && (*values)->priority < priority)
59 values = &(*values)->next;
60
Gustavo Sverzut Barbieri1433ba92011-12-08 14:50:29 -020061 v = malloc(sizeof(struct index_value) + len + 1);
62 if (!v)
63 return -1;
Lucas De Marchie8847fd2011-11-30 15:23:28 -020064 v->next = *values;
65 v->priority = priority;
Gustavo Sverzut Barbieri1433ba92011-12-08 14:50:29 -020066 v->len = len;
67 memcpy(v->value, value, len);
68 v->value[len] = '\0';
Lucas De Marchie8847fd2011-11-30 15:23:28 -020069 *values = v;
70
71 return duplicate;
72}
73
Lucas De Marchi93688882011-12-02 10:05:31 -020074static void read_error(void)
Lucas De Marchie8847fd2011-11-30 15:23:28 -020075{
76 fatal("Module index: unexpected error: %s\n"
77 "Try re-running depmod\n", errno ? strerror(errno) : "EOF");
78}
79
80static int read_char(FILE *in)
81{
82 int ch;
83
84 errno = 0;
85 ch = getc_unlocked(in);
86 if (ch == EOF)
87 read_error();
88 return ch;
89}
90
91static uint32_t read_long(FILE *in)
92{
93 uint32_t l;
94
95 errno = 0;
96 if (fread(&l, sizeof(uint32_t), 1, in) <= 0)
97 read_error();
98 return ntohl(l);
99}
100
101/*
102 * Buffer abstract data type
103 *
104 * Used internally to store the current path during tree traversal.
105 * They help build wildcard key strings to pass to fnmatch(),
106 * as well as building values of matching keys.
107 */
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200108struct buffer {
109 char *bytes;
110 unsigned size;
111 unsigned used;
112};
113
Gustavo Sverzut Barbieri405f6142011-12-08 14:36:30 -0200114#define BUF_STEP (2048)
115static bool buf_grow(struct buffer *buf, size_t newsize)
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200116{
Gustavo Sverzut Barbieri405f6142011-12-08 14:36:30 -0200117 void *tmp;
118 size_t sz;
119
120 if (newsize % BUF_STEP == 0)
121 sz = newsize;
122 else
123 sz = ((newsize / BUF_STEP) + 1) * BUF_STEP;
124
Gustavo Sverzut Barbieri435ad782011-12-08 16:35:08 -0200125 if (buf->size == sz)
126 return true;
127
Gustavo Sverzut Barbieri405f6142011-12-08 14:36:30 -0200128 tmp = realloc(buf->bytes, sz);
129 if (sz > 0 && tmp == NULL)
130 return false;
131 buf->bytes = tmp;
132 buf->size = sz;
133 return true;
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200134}
135
Gustavo Sverzut Barbieri405f6142011-12-08 14:36:30 -0200136static void buf_init(struct buffer *buf)
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200137{
Gustavo Sverzut Barbieri405f6142011-12-08 14:36:30 -0200138 buf->bytes = NULL;
139 buf->size = 0;
140 buf->used = 0;
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200141}
142
Gustavo Sverzut Barbieri405f6142011-12-08 14:36:30 -0200143static void buf_release(struct buffer *buf)
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200144{
145 free(buf->bytes);
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200146}
147
148/* Destroy buffer and return a copy as a C string */
Gustavo Sverzut Barbieri405f6142011-12-08 14:36:30 -0200149static char *buf_steal(struct buffer *buf)
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200150{
151 char *bytes;
152
Gustavo Sverzut Barbieri405f6142011-12-08 14:36:30 -0200153 bytes = realloc(buf->bytes, buf->used + 1);
154 if (!bytes) {
155 free(buf->bytes);
156 return NULL;
157 }
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200158 bytes[buf->used] = '\0';
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200159 return bytes;
160}
161
162/* Return a C string owned by the buffer
163 (invalidated if the buffer is changed).
164 */
165static const char *buf_str(struct buffer *buf)
166{
Gustavo Sverzut Barbieri405f6142011-12-08 14:36:30 -0200167 if (!buf_grow(buf, buf->used + 1))
168 return NULL;
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200169 buf->bytes[buf->used] = '\0';
170 return buf->bytes;
171}
172
Gustavo Sverzut Barbieri405f6142011-12-08 14:36:30 -0200173static bool buf_pushchar(struct buffer *buf, char ch)
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200174{
Gustavo Sverzut Barbieri405f6142011-12-08 14:36:30 -0200175 if (!buf_grow(buf, buf->used + 1))
176 return false;
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200177 buf->bytes[buf->used] = ch;
178 buf->used++;
Gustavo Sverzut Barbieri405f6142011-12-08 14:36:30 -0200179 return true;
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200180}
181
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200182static unsigned buf_freadchars(struct buffer *buf, FILE *in)
183{
184 unsigned i = 0;
185 int ch;
186
187 while ((ch = read_char(in))) {
Gustavo Sverzut Barbieri405f6142011-12-08 14:36:30 -0200188 if (!buf_pushchar(buf, ch))
189 break;
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200190 i++;
191 }
192
193 return i;
194}
195
196static void buf_popchar(struct buffer *buf)
197{
Gustavo Sverzut Barbieri405f6142011-12-08 14:36:30 -0200198 assert(buf->used > 0);
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200199 buf->used--;
200}
201
202static void buf_popchars(struct buffer *buf, unsigned n)
203{
Gustavo Sverzut Barbieri405f6142011-12-08 14:36:30 -0200204 assert(buf->used >= n);
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200205 buf->used -= n;
206}
207
208static void buf_clear(struct buffer *buf)
209{
210 buf->used = 0;
211}
212
213/*
Lucas De Marchieb8bb322011-12-02 10:23:02 -0200214 * Index file searching
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200215 */
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200216struct index_node_f {
217 FILE *file;
218 char *prefix; /* path compression */
219 struct index_value *values;
220 unsigned char first; /* range of child nodes */
221 unsigned char last;
222 uint32_t children[0];
223};
224
225static struct index_node_f *index_read(FILE *in, uint32_t offset)
226{
227 struct index_node_f *node;
228 char *prefix;
229 int i, child_count = 0;
230
231 if ((offset & INDEX_NODE_MASK) == 0)
232 return NULL;
233
234 fseek(in, offset & INDEX_NODE_MASK, SEEK_SET);
Lucas De Marchia7be73b2011-11-30 15:59:36 -0200235
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200236 if (offset & INDEX_NODE_PREFIX) {
Gustavo Sverzut Barbieri405f6142011-12-08 14:36:30 -0200237 struct buffer buf;
238 buf_init(&buf);
239 buf_freadchars(&buf, in);
240 prefix = buf_steal(&buf);
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200241 } else
242 prefix = NOFAIL(strdup(""));
Lucas De Marchia7be73b2011-11-30 15:59:36 -0200243
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200244 if (offset & INDEX_NODE_CHILDS) {
245 char first = read_char(in);
246 char last = read_char(in);
247 child_count = last - first + 1;
Lucas De Marchia7be73b2011-11-30 15:59:36 -0200248
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200249 node = NOFAIL(malloc(sizeof(struct index_node_f) +
250 sizeof(uint32_t) * child_count));
Lucas De Marchia7be73b2011-11-30 15:59:36 -0200251
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200252 node->first = first;
253 node->last = last;
254
255 for (i = 0; i < child_count; i++)
256 node->children[i] = read_long(in);
257 } else {
258 node = NOFAIL(malloc(sizeof(struct index_node_f)));
259 node->first = INDEX_CHILDMAX;
260 node->last = 0;
261 }
Lucas De Marchia7be73b2011-11-30 15:59:36 -0200262
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200263 node->values = NULL;
264 if (offset & INDEX_NODE_VALUES) {
265 int value_count;
Gustavo Sverzut Barbieri405f6142011-12-08 14:36:30 -0200266 struct buffer buf;
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200267 const char *value;
268 unsigned int priority;
269
270 value_count = read_long(in);
271
Gustavo Sverzut Barbieri405f6142011-12-08 14:36:30 -0200272 buf_init(&buf);
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200273 while (value_count--) {
274 priority = read_long(in);
Gustavo Sverzut Barbieri405f6142011-12-08 14:36:30 -0200275 buf_freadchars(&buf, in);
276 value = buf_str(&buf);
Gustavo Sverzut Barbieri1433ba92011-12-08 14:50:29 -0200277 add_value(&node->values, value, buf.used, priority);
Gustavo Sverzut Barbieri405f6142011-12-08 14:36:30 -0200278 buf_clear(&buf);
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200279 }
Gustavo Sverzut Barbieri405f6142011-12-08 14:36:30 -0200280 buf_release(&buf);
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200281 }
282
283 node->prefix = prefix;
284 node->file = in;
285 return node;
286}
287
288static void index_close(struct index_node_f *node)
289{
290 free(node->prefix);
291 index_values_free(node->values);
292 free(node);
293}
294
295struct index_file {
296 FILE *file;
297 uint32_t root_offset;
298};
299
300/* Failures are silent; modprobe will fall back to text files */
301struct index_file *index_file_open(const char *filename)
302{
303 FILE *file;
304 uint32_t magic, version;
305 struct index_file *new;
306
307 file = fopen(filename, "r");
308 if (!file)
309 return NULL;
310 errno = EINVAL;
311
312 magic = read_long(file);
313 if (magic != INDEX_MAGIC)
314 return NULL;
315
316 version = read_long(file);
317 if (version >> 16 != INDEX_VERSION_MAJOR)
318 return NULL;
319
320 new = NOFAIL(malloc(sizeof(struct index_file)));
321 new->file = file;
322 new->root_offset = read_long(new->file);
323
324 errno = 0;
325 return new;
326}
327
Lucas De Marchi0fbdfef2011-12-02 09:56:22 -0200328void index_file_close(struct index_file *idx)
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200329{
Lucas De Marchi0fbdfef2011-12-02 09:56:22 -0200330 fclose(idx->file);
331 free(idx);
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200332}
333
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200334static struct index_node_f *index_readroot(struct index_file *in)
335{
336 return index_read(in->file, in->root_offset);
337}
338
339static struct index_node_f *index_readchild(const struct index_node_f *parent,
340 int ch)
341{
Lucas De Marchie71970a2011-12-02 10:27:15 -0200342 if (parent->first <= ch && ch <= parent->last) {
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200343 return index_read(parent->file,
344 parent->children[ch - parent->first]);
Lucas De Marchie71970a2011-12-02 10:27:15 -0200345 }
346
347 return NULL;
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200348}
349
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200350static char *index_search__node(struct index_node_f *node, const char *key, int i)
351{
352 char *value;
353 struct index_node_f *child;
354 int ch;
355 int j;
356
357 while(node) {
358 for (j = 0; node->prefix[j]; j++) {
359 ch = node->prefix[j];
Lucas De Marchia7be73b2011-11-30 15:59:36 -0200360
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200361 if (ch != key[i+j]) {
362 index_close(node);
363 return NULL;
364 }
365 }
Lucas De Marchie71970a2011-12-02 10:27:15 -0200366
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200367 i += j;
Lucas De Marchia7be73b2011-11-30 15:59:36 -0200368
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200369 if (key[i] == '\0') {
370 if (node->values) {
371 value = strdup(node->values[0].value);
372 index_close(node);
373 return value;
374 } else {
375 return NULL;
376 }
377 }
Lucas De Marchia7be73b2011-11-30 15:59:36 -0200378
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200379 child = index_readchild(node, key[i]);
380 index_close(node);
381 node = child;
382 i++;
383 }
Lucas De Marchia7be73b2011-11-30 15:59:36 -0200384
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200385 return NULL;
386}
387
388/*
Lucas De Marchi1d152ac2011-12-02 10:15:00 -0200389 * Search the index for a key
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200390 *
Lucas De Marchi1d152ac2011-12-02 10:15:00 -0200391 * Returns the value of the first match
392 *
393 * The recursive functions free their node argument (using index_close).
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200394 */
Lucas De Marchi1d152ac2011-12-02 10:15:00 -0200395char *index_search(struct index_file *in, const char *key)
396{
397 struct index_node_f *root;
398 char *value;
399
400 root = index_readroot(in);
401 value = index_search__node(root, key, 0);
402
403 return value;
404}
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200405
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200406
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200407
408/* Level 4: add all the values from a matching node */
409static void index_searchwild__allvalues(struct index_node_f *node,
Lucas De Marchi1d152ac2011-12-02 10:15:00 -0200410 struct index_value **out)
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200411{
Lucas De Marchi1d152ac2011-12-02 10:15:00 -0200412 struct index_value *v;
Lucas De Marchia7be73b2011-11-30 15:59:36 -0200413
Lucas De Marchi1d152ac2011-12-02 10:15:00 -0200414 for (v = node->values; v != NULL; v = v->next)
Gustavo Sverzut Barbieri1433ba92011-12-08 14:50:29 -0200415 add_value(out, v->value, v->len, v->priority);
Lucas De Marchi1d152ac2011-12-02 10:15:00 -0200416
417 index_close(node);
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200418}
419
Lucas De Marchi1d152ac2011-12-02 10:15:00 -0200420/*
421 * Level 3: traverse a sub-keyspace which starts with a wildcard,
422 * looking for matches.
423 */
424static void index_searchwild__all(struct index_node_f *node, int j,
425 struct buffer *buf,
426 const char *subkey,
427 struct index_value **out)
428{
429 int pushed = 0;
430 int ch;
431
432 while (node->prefix[j]) {
433 ch = node->prefix[j];
434
435 buf_pushchar(buf, ch);
436 pushed++;
437 j++;
438 }
439
440 for (ch = node->first; ch <= node->last; ch++) {
441 struct index_node_f *child = index_readchild(node, ch);
442
443 if (!child)
444 continue;
445
446 buf_pushchar(buf, ch);
447 index_searchwild__all(child, 0, buf, subkey, out);
448 buf_popchar(buf);
449 }
450
451 if (node->values) {
452 if (fnmatch(buf_str(buf), subkey, 0) == 0)
453 index_searchwild__allvalues(node, out);
454 } else {
455 index_close(node);
456 }
457
458 buf_popchars(buf, pushed);
459}
460
461/* Level 2: descend the tree (until we hit a wildcard) */
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200462static void index_searchwild__node(struct index_node_f *node,
463 struct buffer *buf,
464 const char *key, int i,
465 struct index_value **out)
466{
467 struct index_node_f *child;
468 int j;
469 int ch;
470
471 while(node) {
472 for (j = 0; node->prefix[j]; j++) {
473 ch = node->prefix[j];
Lucas De Marchia7be73b2011-11-30 15:59:36 -0200474
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200475 if (ch == '*' || ch == '?' || ch == '[') {
476 index_searchwild__all(node, j, buf,
477 &key[i+j], out);
478 return;
479 }
Lucas De Marchia7be73b2011-11-30 15:59:36 -0200480
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200481 if (ch != key[i+j]) {
482 index_close(node);
483 return;
484 }
485 }
Lucas De Marchie71970a2011-12-02 10:27:15 -0200486
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200487 i += j;
Lucas De Marchia7be73b2011-11-30 15:59:36 -0200488
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200489 child = index_readchild(node, '*');
490 if (child) {
491 buf_pushchar(buf, '*');
492 index_searchwild__all(child, 0, buf, &key[i], out);
493 buf_popchar(buf);
494 }
Lucas De Marchia7be73b2011-11-30 15:59:36 -0200495
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200496 child = index_readchild(node, '?');
497 if (child) {
498 buf_pushchar(buf, '?');
499 index_searchwild__all(child, 0, buf, &key[i], out);
500 buf_popchar(buf);
501 }
Lucas De Marchia7be73b2011-11-30 15:59:36 -0200502
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200503 child = index_readchild(node, '[');
504 if (child) {
505 buf_pushchar(buf, '[');
506 index_searchwild__all(child, 0, buf, &key[i], out);
507 buf_popchar(buf);
508 }
Lucas De Marchia7be73b2011-11-30 15:59:36 -0200509
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200510 if (key[i] == '\0') {
511 index_searchwild__allvalues(node, out);
512
513 return;
514 }
Lucas De Marchia7be73b2011-11-30 15:59:36 -0200515
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200516 child = index_readchild(node, key[i]);
517 index_close(node);
518 node = child;
519 i++;
520 }
521}
522
Lucas De Marchi1d152ac2011-12-02 10:15:00 -0200523/*
524 * Search the index for a key. The index may contain wildcards.
525 *
526 * Returns a list of all the values of matching keys.
527 */
528struct index_value *index_searchwild(struct index_file *in, const char *key)
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200529{
Lucas De Marchi1d152ac2011-12-02 10:15:00 -0200530 struct index_node_f *root = index_readroot(in);
Gustavo Sverzut Barbieri405f6142011-12-08 14:36:30 -0200531 struct buffer buf;
Lucas De Marchi1d152ac2011-12-02 10:15:00 -0200532 struct index_value *out = NULL;
Lucas De Marchia7be73b2011-11-30 15:59:36 -0200533
Gustavo Sverzut Barbieri405f6142011-12-08 14:36:30 -0200534 buf_init(&buf);
535 index_searchwild__node(root, &buf, key, 0, &out);
536 buf_release(&buf);
Lucas De Marchi1d152ac2011-12-02 10:15:00 -0200537 return out;
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200538}
Lucas De Marchib471a6b2011-12-01 23:14:20 -0200539
540#include <sys/mman.h>
541#include <sys/stat.h>
542#include <unistd.h>
543
544/**************************************************************************/
545/*
546 * Alternative implementation, using mmap to map all the file to memory when
547 * starting
548 */
549struct index_mm {
550 struct kmod_ctx *ctx;
551 void *mm;
552 uint32_t root_offset;
553 size_t size;
554};
555
Lucas De Marchi836be9a2011-12-02 17:27:52 -0200556struct index_mm_node {
557 struct index_mm *idx;
558 char *prefix;
559 struct index_value *values;
560 unsigned char first;
561 unsigned char last;
562 uint32_t children[];
563};
564
565static inline uint32_t read_long_mm(void **p)
566{
567 uint32_t v = **((uint32_t **)p);
568
569 *p = *((uint8_t **)p) + sizeof(uint32_t);
570
571 return ntohl(v);
572}
573
574static inline uint8_t read_char_mm(void **p)
575{
576 uint8_t *v = *((uint8_t **)p);
577 *p = v + 1;
578 return *v;
579}
580
581static inline char *read_alloc_chars_mm(void **p)
582{
583 char *s = *((char **)p);
584 size_t len = strlen(s) + 1;
585 *p = ((char *)p) + len;
586
587 return memdup(s, len);
588}
589
Gustavo Sverzut Barbieri1433ba92011-12-08 14:50:29 -0200590static inline char *read_chars_mm(void **p, unsigned *rlen)
Lucas De Marchi836be9a2011-12-02 17:27:52 -0200591{
592 char *s = *((char **)p);
Gustavo Sverzut Barbieri1433ba92011-12-08 14:50:29 -0200593 size_t len = *rlen = strlen(s);
594 *p = ((char *)p) + len + 1;
Lucas De Marchi836be9a2011-12-02 17:27:52 -0200595
596 return s;
597}
598
599static struct index_mm_node *index_mm_read_node(struct index_mm *idx,
600 uint32_t offset) {
601 void *p = idx->mm;
602 struct index_mm_node *node;
603 char *prefix;
604 int i, child_count = 0;
605
606
607 if ((offset & INDEX_NODE_MASK) == 0)
608 return NULL;
609
610 p = (char *)p + (offset & INDEX_NODE_MASK);
611
612 if (offset & INDEX_NODE_PREFIX)
613 prefix = read_alloc_chars_mm(&p);
614 else
615 prefix = strdup("");
616
617 if (offset & INDEX_NODE_CHILDS) {
618 char first = read_char_mm(&p);
619 char last = read_char_mm(&p);
620 child_count = last - first + 1;
621
622 node = malloc(sizeof(*node) + sizeof(uint32_t) * child_count);
623
624 node->first = first;
625 node->last = last;
626
627 for (i = 0; i < child_count; i++)
628 node->children[i] = read_long_mm(&p);
629 } else {
630 node = malloc(sizeof(*node));
631 node->first = INDEX_CHILDMAX;
632 node->last = 0;
633 }
634
635 node->values = NULL;
636
637 if (offset & INDEX_NODE_VALUES) {
638 uint32_t j;
639
640 for (j = read_long_mm(&p); j > 0; j--) {
641 unsigned int priority;
642 const char *value;
Gustavo Sverzut Barbieri1433ba92011-12-08 14:50:29 -0200643 unsigned len;
Lucas De Marchi836be9a2011-12-02 17:27:52 -0200644
645 priority = read_long_mm(&p);
Gustavo Sverzut Barbieri1433ba92011-12-08 14:50:29 -0200646 value = read_chars_mm(&p, &len);
647 add_value(&node->values, value, len, priority);
Lucas De Marchi836be9a2011-12-02 17:27:52 -0200648 }
649 }
650
651 node->prefix = prefix;
652 node->idx = idx;
653
654 return node;
655}
656
657static void index_mm_free_node(struct index_mm_node *node)
658{
659 free(node->prefix);
660 index_values_free(node->values);
661 free(node);
662}
663
Lucas De Marchib471a6b2011-12-01 23:14:20 -0200664struct index_mm *index_mm_open(struct kmod_ctx *ctx, const char *filename)
665{
666 int fd;
667 struct stat st;
668 struct index_mm *idx;
669 struct {
670 uint32_t magic;
671 uint32_t version;
672 uint32_t root_offset;
673 } hdr;
674 void *p;
675
676 DBG(ctx, "file=%s\n", filename);
677
678 if ((fd = open(filename, O_RDONLY)) < 0) {
679 ERR(ctx, "%m\n");
680 return NULL;
681 }
682
683 fstat(fd, &st);
684
685 idx = malloc(sizeof(*idx));
686 if (idx == NULL) {
687 ERR(ctx, "%m\n");
688 goto fail;
689 }
690
691 if ((idx->mm = mmap(0, st.st_size, PROT_READ,
692 MAP_PRIVATE | MAP_POPULATE,
693 fd, 0)) == MAP_FAILED) {
694 ERR(ctx, "%m\n");
695 goto fail;
696 }
697
698 p = idx->mm;
699 hdr.magic = read_long_mm(&p);
700 hdr.version = read_long_mm(&p);
701 hdr.root_offset = read_long_mm(&p);
702
703 if (hdr.magic != INDEX_MAGIC) {
704 ERR(ctx, "magic check fail: %x instead of %x\n", hdr.magic,
705 INDEX_MAGIC);
706 goto fail;
707 }
708
709 if (hdr.version >> 16 != INDEX_VERSION_MAJOR) {
710 ERR(ctx, "major version check fail: %u instead of %u\n",
711 hdr.version, INDEX_MAGIC);
712 goto fail;
713 }
714
715 idx->root_offset = hdr.root_offset;
716 idx->size = st.st_size;
717 idx->ctx = ctx;
718 close(fd);
719
720 return idx;
721
722fail:
723 close(fd);
724 if (idx->mm)
725 munmap(idx->mm, st.st_size);
726 free(idx);
727 return NULL;
728}
729
730void index_mm_close(struct index_mm *idx)
731{
732 munmap(idx->mm, idx->size);
733 free(idx);
734}
Lucas De Marchi77bf9362011-12-02 17:41:30 -0200735
736static struct index_mm_node *index_mm_readroot(struct index_mm *idx)
737{
738 return index_mm_read_node(idx, idx->root_offset);
739}
Lucas De Marchi91298dc2011-12-02 17:41:46 -0200740
741static struct index_mm_node *index_mm_readchild(const struct index_mm_node *parent,
742 int ch)
743{
744 if (parent->first <= ch && ch <= parent->last) {
745 return index_mm_read_node(parent->idx,
746 parent->children[ch - parent->first]);
747 }
748
749 return NULL;
750}
Lucas De Marchie33bb872011-12-02 17:45:01 -0200751
752static char *index_mm_search_node(struct index_mm_node *node, const char *key,
753 int i)
754{
755 char *value;
756 struct index_mm_node *child;
757 int ch;
758 int j;
759
760 while(node) {
761 for (j = 0; node->prefix[j]; j++) {
762 ch = node->prefix[j];
763
764 if (ch != key[i+j]) {
765 index_mm_free_node(node);
766 return NULL;
767 }
768 }
769
770 i += j;
771
772 if (key[i] == '\0') {
773 if (node->values) {
774 value = strdup(node->values[0].value);
775 index_mm_free_node(node);
776 return value;
777 } else {
778 return NULL;
779 }
780 }
781
782 child = index_mm_readchild(node, key[i]);
783 index_mm_free_node(node);
784 node = child;
785 i++;
786 }
787
788 return NULL;
789}
Lucas De Marchib797b792011-12-02 17:49:03 -0200790
791/*
792 * Search the index for a key
793 *
794 * Returns the value of the first match
795 *
796 * The recursive functions free their node argument (using index_close).
797 */
798char *index_mm_search(struct index_mm *idx, const char *key)
799{
800 struct index_mm_node *root;
801 char *value;
802
803 root = index_mm_readroot(idx);
804 value = index_mm_search_node(root, key, 0);
805
806 return value;
807}
Lucas De Marchibf89f702011-12-02 18:23:36 -0200808
809/* Level 4: add all the values from a matching node */
810static void index_mm_searchwild_allvalues(struct index_mm_node *node,
811 struct index_value **out)
812{
813 struct index_value *v;
814
815 for (v = node->values; v != NULL; v = v->next)
Gustavo Sverzut Barbieri1433ba92011-12-08 14:50:29 -0200816 add_value(out, v->value, v->len, v->priority);
Lucas De Marchibf89f702011-12-02 18:23:36 -0200817
818 index_mm_free_node(node);
819}
820
821/*
822 * Level 3: traverse a sub-keyspace which starts with a wildcard,
823 * looking for matches.
824 */
825static void index_mm_searchwild_all(struct index_mm_node *node, int j,
826 struct buffer *buf,
827 const char *subkey,
828 struct index_value **out)
829{
830 int pushed = 0;
831 int ch;
832
833 while (node->prefix[j]) {
834 ch = node->prefix[j];
835
836 buf_pushchar(buf, ch);
837 pushed++;
838 j++;
839 }
840
841 for (ch = node->first; ch <= node->last; ch++) {
842 struct index_mm_node *child = index_mm_readchild(node, ch);
843
844 if (!child)
845 continue;
846
847 buf_pushchar(buf, ch);
848 index_mm_searchwild_all(child, 0, buf, subkey, out);
849 buf_popchar(buf);
850 }
851
852 if (node->values) {
853 if (fnmatch(buf_str(buf), subkey, 0) == 0)
854 index_mm_searchwild_allvalues(node, out);
855 } else {
856 index_mm_free_node(node);
857 }
858
859 buf_popchars(buf, pushed);
860}
861
862/* Level 2: descend the tree (until we hit a wildcard) */
863static void index_mm_searchwild_node(struct index_mm_node *node,
864 struct buffer *buf,
865 const char *key, int i,
866 struct index_value **out)
867{
868 struct index_mm_node *child;
869 int j;
870 int ch;
871
872 while(node) {
873 for (j = 0; node->prefix[j]; j++) {
874 ch = node->prefix[j];
875
876 if (ch == '*' || ch == '?' || ch == '[') {
877 index_mm_searchwild_all(node, j, buf,
878 &key[i+j], out);
879 return;
880 }
881
882 if (ch != key[i+j]) {
883 index_mm_free_node(node);
884 return;
885 }
886 }
887
888 i += j;
889
890 child = index_mm_readchild(node, '*');
891 if (child) {
892 buf_pushchar(buf, '*');
893 index_mm_searchwild_all(child, 0, buf, &key[i], out);
894 buf_popchar(buf);
895 }
896
897 child = index_mm_readchild(node, '?');
898 if (child) {
899 buf_pushchar(buf, '?');
900 index_mm_searchwild_all(child, 0, buf, &key[i], out);
901 buf_popchar(buf);
902 }
903
904 child = index_mm_readchild(node, '[');
905 if (child) {
906 buf_pushchar(buf, '[');
907 index_mm_searchwild_all(child, 0, buf, &key[i], out);
908 buf_popchar(buf);
909 }
910
911 if (key[i] == '\0') {
912 index_mm_searchwild_allvalues(node, out);
913
914 return;
915 }
916
917 child = index_mm_readchild(node, key[i]);
918 index_mm_free_node(node);
919 node = child;
920 i++;
921 }
922}
923
924/*
925 * Search the index for a key. The index may contain wildcards.
926 *
927 * Returns a list of all the values of matching keys.
928 */
929struct index_value *index_mm_searchwild(struct index_mm *idx, const char *key)
930{
931 struct index_mm_node *root = index_mm_readroot(idx);
Gustavo Sverzut Barbieri405f6142011-12-08 14:36:30 -0200932 struct buffer buf;
Lucas De Marchibf89f702011-12-02 18:23:36 -0200933 struct index_value *out = NULL;
934
Gustavo Sverzut Barbieri405f6142011-12-08 14:36:30 -0200935 buf_init(&buf);
936 index_mm_searchwild_node(root, &buf, key, 0, &out);
937 buf_release(&buf);
Lucas De Marchibf89f702011-12-02 18:23:36 -0200938 return out;
939}