blob: 1c64743d0fc6c9a1fcc7d39b3665dbe7dd26a15b [file] [log] [blame]
Lucas De Marchi8f923be2011-12-03 04:28:49 -02001/*
2 * libkmod - interface to kernel module operations
3 *
Lucas De Marchie6b0e492013-01-16 11:27:21 -02004 * Copyright (C) 2011-2013 ProFUSION embedded systems
Lucas De Marchi8f923be2011-12-03 04:28:49 -02005 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
Lucas De Marchicb451f32011-12-12 18:24:35 -02008 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
Lucas De Marchi8f923be2011-12-03 04:28:49 -020010 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
19 */
Lucas De Marchie8847fd2011-11-30 15:23:28 -020020
21#include <arpa/inet.h> /* htonl */
22#include <stdlib.h>
23#include <stdio.h>
24#include <string.h>
25#include <errno.h>
26#include <fnmatch.h>
Gustavo Sverzut Barbieri405f6142011-12-08 14:36:30 -020027#include <assert.h>
Lucas De Marchibfcd31d2012-03-02 21:28:11 -030028#include <inttypes.h>
Lucas De Marchie8847fd2011-11-30 15:23:28 -020029
Lucas De Marchi576dd432014-10-02 22:03:19 -030030#include <shared/macro.h>
31
Lucas De Marchi83b855a2013-07-04 16:13:11 -030032#include "libkmod-internal.h"
Lucas De Marchie8847fd2011-11-30 15:23:28 -020033#include "libkmod-index.h"
Lucas De Marchie8847fd2011-11-30 15:23:28 -020034
Lucas De Marchi8f923be2011-12-03 04:28:49 -020035/* index.c: module index file shared functions for modprobe and depmod */
36
Gustavo Sverzut Barbieri148226e2011-12-10 11:53:51 -020037#define INDEX_CHILDMAX 128
38
39/* Disk format:
40
41 uint32_t magic = INDEX_MAGIC;
42 uint32_t version = INDEX_VERSION;
43 uint32_t root_offset;
44
45 (node_offset & INDEX_NODE_MASK) specifies the file offset of nodes:
46
47 char[] prefix; // nul terminated
48
49 char first;
50 char last;
51 uint32_t children[last - first + 1];
52
53 uint32_t value_count;
54 struct {
55 uint32_t priority;
56 char[] value; // nul terminated
57 } values[value_count];
58
59 (node_offset & INDEX_NODE_FLAGS) indicates which fields are present.
60 Empty prefixes are omitted, leaf nodes omit the three child-related fields.
61
62 This could be optimised further by adding a sparse child format
63 (indicated using a new flag).
64 */
65
66/* Format of node offsets within index file */
67enum node_offset {
68 INDEX_NODE_FLAGS = 0xF0000000, /* Flags in high nibble */
69 INDEX_NODE_PREFIX = 0x80000000,
70 INDEX_NODE_VALUES = 0x40000000,
71 INDEX_NODE_CHILDS = 0x20000000,
72
73 INDEX_NODE_MASK = 0x0FFFFFFF, /* Offset value */
74};
75
Lucas De Marchie8847fd2011-11-30 15:23:28 -020076void index_values_free(struct index_value *values)
77{
78 while (values) {
79 struct index_value *value = values;
80
81 values = value->next;
82 free(value);
83 }
84}
85
Lucas De Marchie8847fd2011-11-30 15:23:28 -020086static int add_value(struct index_value **values,
Gustavo Sverzut Barbieri1433ba92011-12-08 14:50:29 -020087 const char *value, unsigned len, unsigned int priority)
Lucas De Marchie8847fd2011-11-30 15:23:28 -020088{
89 struct index_value *v;
Lucas De Marchie8847fd2011-11-30 15:23:28 -020090
91 /* find position to insert value */
92 while (*values && (*values)->priority < priority)
93 values = &(*values)->next;
94
Gustavo Sverzut Barbieri1433ba92011-12-08 14:50:29 -020095 v = malloc(sizeof(struct index_value) + len + 1);
96 if (!v)
97 return -1;
Lucas De Marchie8847fd2011-11-30 15:23:28 -020098 v->next = *values;
99 v->priority = priority;
Gustavo Sverzut Barbieri1433ba92011-12-08 14:50:29 -0200100 v->len = len;
101 memcpy(v->value, value, len);
102 v->value[len] = '\0';
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200103 *values = v;
104
Gustavo Sverzut Barbieri558b0202011-12-08 16:36:48 -0200105 return 0;
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200106}
107
Lucas De Marchi93688882011-12-02 10:05:31 -0200108static void read_error(void)
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200109{
110 fatal("Module index: unexpected error: %s\n"
111 "Try re-running depmod\n", errno ? strerror(errno) : "EOF");
112}
113
114static int read_char(FILE *in)
115{
116 int ch;
117
118 errno = 0;
119 ch = getc_unlocked(in);
120 if (ch == EOF)
121 read_error();
122 return ch;
123}
124
125static uint32_t read_long(FILE *in)
126{
127 uint32_t l;
128
129 errno = 0;
Leandro Pereirab6d985c2014-04-28 20:47:49 -0300130 if (fread(&l, sizeof(uint32_t), 1, in) != sizeof(uint32_t))
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200131 read_error();
132 return ntohl(l);
133}
134
135/*
136 * Buffer abstract data type
137 *
138 * Used internally to store the current path during tree traversal.
139 * They help build wildcard key strings to pass to fnmatch(),
140 * as well as building values of matching keys.
141 */
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200142struct buffer {
143 char *bytes;
144 unsigned size;
145 unsigned used;
146};
147
Gustavo Sverzut Barbieri405f6142011-12-08 14:36:30 -0200148#define BUF_STEP (2048)
149static bool buf_grow(struct buffer *buf, size_t newsize)
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200150{
Gustavo Sverzut Barbieri405f6142011-12-08 14:36:30 -0200151 void *tmp;
152 size_t sz;
153
154 if (newsize % BUF_STEP == 0)
155 sz = newsize;
156 else
157 sz = ((newsize / BUF_STEP) + 1) * BUF_STEP;
158
Gustavo Sverzut Barbieri435ad782011-12-08 16:35:08 -0200159 if (buf->size == sz)
160 return true;
161
Gustavo Sverzut Barbieri405f6142011-12-08 14:36:30 -0200162 tmp = realloc(buf->bytes, sz);
163 if (sz > 0 && tmp == NULL)
164 return false;
165 buf->bytes = tmp;
166 buf->size = sz;
167 return true;
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200168}
169
Gustavo Sverzut Barbieri405f6142011-12-08 14:36:30 -0200170static void buf_init(struct buffer *buf)
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200171{
Gustavo Sverzut Barbieri405f6142011-12-08 14:36:30 -0200172 buf->bytes = NULL;
173 buf->size = 0;
174 buf->used = 0;
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200175}
176
Gustavo Sverzut Barbieri405f6142011-12-08 14:36:30 -0200177static void buf_release(struct buffer *buf)
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200178{
179 free(buf->bytes);
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200180}
181
182/* Destroy buffer and return a copy as a C string */
Gustavo Sverzut Barbieri405f6142011-12-08 14:36:30 -0200183static char *buf_steal(struct buffer *buf)
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200184{
185 char *bytes;
186
Gustavo Sverzut Barbieri405f6142011-12-08 14:36:30 -0200187 bytes = realloc(buf->bytes, buf->used + 1);
188 if (!bytes) {
189 free(buf->bytes);
190 return NULL;
191 }
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200192 bytes[buf->used] = '\0';
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200193 return bytes;
194}
195
196/* Return a C string owned by the buffer
197 (invalidated if the buffer is changed).
198 */
199static const char *buf_str(struct buffer *buf)
200{
Gustavo Sverzut Barbieri405f6142011-12-08 14:36:30 -0200201 if (!buf_grow(buf, buf->used + 1))
202 return NULL;
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200203 buf->bytes[buf->used] = '\0';
204 return buf->bytes;
205}
206
Gustavo Sverzut Barbieri405f6142011-12-08 14:36:30 -0200207static bool buf_pushchar(struct buffer *buf, char ch)
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200208{
Gustavo Sverzut Barbieri405f6142011-12-08 14:36:30 -0200209 if (!buf_grow(buf, buf->used + 1))
210 return false;
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200211 buf->bytes[buf->used] = ch;
212 buf->used++;
Gustavo Sverzut Barbieri405f6142011-12-08 14:36:30 -0200213 return true;
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200214}
215
Lucas De Marchi758428a2012-01-16 15:56:17 -0200216static unsigned buf_pushchars(struct buffer *buf, const char *str)
217{
218 unsigned i = 0;
219 int ch;
220
221 while ((ch = str[i])) {
222 buf_pushchar(buf, ch);
223 i++;
224 }
225
226 return i;
227}
228
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200229static unsigned buf_freadchars(struct buffer *buf, FILE *in)
230{
231 unsigned i = 0;
232 int ch;
233
234 while ((ch = read_char(in))) {
Gustavo Sverzut Barbieri405f6142011-12-08 14:36:30 -0200235 if (!buf_pushchar(buf, ch))
236 break;
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200237 i++;
238 }
239
240 return i;
241}
242
243static void buf_popchar(struct buffer *buf)
244{
Gustavo Sverzut Barbieri405f6142011-12-08 14:36:30 -0200245 assert(buf->used > 0);
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200246 buf->used--;
247}
248
249static void buf_popchars(struct buffer *buf, unsigned n)
250{
Gustavo Sverzut Barbieri405f6142011-12-08 14:36:30 -0200251 assert(buf->used >= n);
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200252 buf->used -= n;
253}
254
255static void buf_clear(struct buffer *buf)
256{
257 buf->used = 0;
258}
259
260/*
Lucas De Marchieb8bb322011-12-02 10:23:02 -0200261 * Index file searching
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200262 */
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200263struct index_node_f {
264 FILE *file;
265 char *prefix; /* path compression */
266 struct index_value *values;
267 unsigned char first; /* range of child nodes */
268 unsigned char last;
269 uint32_t children[0];
270};
271
272static struct index_node_f *index_read(FILE *in, uint32_t offset)
273{
274 struct index_node_f *node;
275 char *prefix;
276 int i, child_count = 0;
277
278 if ((offset & INDEX_NODE_MASK) == 0)
279 return NULL;
280
281 fseek(in, offset & INDEX_NODE_MASK, SEEK_SET);
Lucas De Marchia7be73b2011-11-30 15:59:36 -0200282
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200283 if (offset & INDEX_NODE_PREFIX) {
Gustavo Sverzut Barbieri405f6142011-12-08 14:36:30 -0200284 struct buffer buf;
285 buf_init(&buf);
286 buf_freadchars(&buf, in);
287 prefix = buf_steal(&buf);
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200288 } else
289 prefix = NOFAIL(strdup(""));
Lucas De Marchia7be73b2011-11-30 15:59:36 -0200290
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200291 if (offset & INDEX_NODE_CHILDS) {
292 char first = read_char(in);
293 char last = read_char(in);
294 child_count = last - first + 1;
Lucas De Marchia7be73b2011-11-30 15:59:36 -0200295
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200296 node = NOFAIL(malloc(sizeof(struct index_node_f) +
297 sizeof(uint32_t) * child_count));
Lucas De Marchia7be73b2011-11-30 15:59:36 -0200298
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200299 node->first = first;
300 node->last = last;
301
302 for (i = 0; i < child_count; i++)
303 node->children[i] = read_long(in);
304 } else {
305 node = NOFAIL(malloc(sizeof(struct index_node_f)));
306 node->first = INDEX_CHILDMAX;
307 node->last = 0;
308 }
Lucas De Marchia7be73b2011-11-30 15:59:36 -0200309
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200310 node->values = NULL;
311 if (offset & INDEX_NODE_VALUES) {
312 int value_count;
Gustavo Sverzut Barbieri405f6142011-12-08 14:36:30 -0200313 struct buffer buf;
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200314 const char *value;
315 unsigned int priority;
316
317 value_count = read_long(in);
318
Gustavo Sverzut Barbieri405f6142011-12-08 14:36:30 -0200319 buf_init(&buf);
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200320 while (value_count--) {
321 priority = read_long(in);
Gustavo Sverzut Barbieri405f6142011-12-08 14:36:30 -0200322 buf_freadchars(&buf, in);
323 value = buf_str(&buf);
Gustavo Sverzut Barbieri1433ba92011-12-08 14:50:29 -0200324 add_value(&node->values, value, buf.used, priority);
Gustavo Sverzut Barbieri405f6142011-12-08 14:36:30 -0200325 buf_clear(&buf);
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200326 }
Gustavo Sverzut Barbieri405f6142011-12-08 14:36:30 -0200327 buf_release(&buf);
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200328 }
329
330 node->prefix = prefix;
331 node->file = in;
332 return node;
333}
334
335static void index_close(struct index_node_f *node)
336{
337 free(node->prefix);
338 index_values_free(node->values);
339 free(node);
340}
341
342struct index_file {
343 FILE *file;
344 uint32_t root_offset;
345};
346
347/* Failures are silent; modprobe will fall back to text files */
348struct index_file *index_file_open(const char *filename)
349{
350 FILE *file;
351 uint32_t magic, version;
352 struct index_file *new;
353
Cristian Rodríguez79e5ea92011-12-16 02:49:54 -0300354 file = fopen(filename, "re");
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200355 if (!file)
356 return NULL;
357 errno = EINVAL;
358
359 magic = read_long(file);
Cristian Rodríguez67d94ad2011-12-23 03:06:56 -0200360 if (magic != INDEX_MAGIC) {
361 fclose(file);
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200362 return NULL;
Cristian Rodríguez67d94ad2011-12-23 03:06:56 -0200363 }
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200364
365 version = read_long(file);
Cristian Rodríguez4088b272011-12-26 01:38:04 -0300366 if (version >> 16 != INDEX_VERSION_MAJOR) {
367 fclose(file);
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200368 return NULL;
Cristian Rodríguez4088b272011-12-26 01:38:04 -0300369 }
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200370
371 new = NOFAIL(malloc(sizeof(struct index_file)));
372 new->file = file;
373 new->root_offset = read_long(new->file);
374
375 errno = 0;
376 return new;
377}
378
Lucas De Marchi0fbdfef2011-12-02 09:56:22 -0200379void index_file_close(struct index_file *idx)
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200380{
Lucas De Marchi0fbdfef2011-12-02 09:56:22 -0200381 fclose(idx->file);
382 free(idx);
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200383}
384
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200385static struct index_node_f *index_readroot(struct index_file *in)
386{
387 return index_read(in->file, in->root_offset);
388}
389
390static struct index_node_f *index_readchild(const struct index_node_f *parent,
391 int ch)
392{
Lucas De Marchie71970a2011-12-02 10:27:15 -0200393 if (parent->first <= ch && ch <= parent->last) {
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200394 return index_read(parent->file,
395 parent->children[ch - parent->first]);
Lucas De Marchie71970a2011-12-02 10:27:15 -0200396 }
397
398 return NULL;
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200399}
400
Lucas De Marchi758428a2012-01-16 15:56:17 -0200401static void index_dump_node(struct index_node_f *node, struct buffer *buf,
402 int fd)
403{
404 struct index_value *v;
405 int ch, pushed;
406
407 pushed = buf_pushchars(buf, node->prefix);
408
409 for (v = node->values; v != NULL; v = v->next) {
410 write_str_safe(fd, buf->bytes, buf->used);
411 write_str_safe(fd, " ", 1);
412 write_str_safe(fd, v->value, strlen(v->value));
413 write_str_safe(fd, "\n", 1);
414 }
415
416 for (ch = node->first; ch <= node->last; ch++) {
417 struct index_node_f *child = index_readchild(node, ch);
418
419 if (!child)
420 continue;
421
422 buf_pushchar(buf, ch);
423 index_dump_node(child, buf, fd);
424 buf_popchar(buf);
425 }
426
427 buf_popchars(buf, pushed);
428 index_close(node);
429}
430
431void index_dump(struct index_file *in, int fd, const char *prefix)
432{
433 struct index_node_f *root;
434 struct buffer buf;
435
Lucas De Marchi681bf892013-04-23 21:21:00 -0300436 root = index_readroot(in);
437 if (root == NULL)
438 return;
439
Lucas De Marchi758428a2012-01-16 15:56:17 -0200440 buf_init(&buf);
441 buf_pushchars(&buf, prefix);
Lucas De Marchi758428a2012-01-16 15:56:17 -0200442 index_dump_node(root, &buf, fd);
443 buf_release(&buf);
444}
445
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200446static char *index_search__node(struct index_node_f *node, const char *key, int i)
447{
448 char *value;
449 struct index_node_f *child;
450 int ch;
451 int j;
452
453 while(node) {
454 for (j = 0; node->prefix[j]; j++) {
455 ch = node->prefix[j];
Lucas De Marchia7be73b2011-11-30 15:59:36 -0200456
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200457 if (ch != key[i+j]) {
458 index_close(node);
459 return NULL;
460 }
461 }
Lucas De Marchie71970a2011-12-02 10:27:15 -0200462
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200463 i += j;
Lucas De Marchia7be73b2011-11-30 15:59:36 -0200464
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200465 if (key[i] == '\0') {
Lucas De Marchi817f4e32012-02-27 19:54:33 -0300466 value = node->values != NULL
467 ? strdup(node->values[0].value)
468 : NULL;
469
470 index_close(node);
471 return value;
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200472 }
Lucas De Marchia7be73b2011-11-30 15:59:36 -0200473
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200474 child = index_readchild(node, key[i]);
475 index_close(node);
476 node = child;
477 i++;
478 }
Lucas De Marchia7be73b2011-11-30 15:59:36 -0200479
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200480 return NULL;
481}
482
483/*
Lucas De Marchi1d152ac2011-12-02 10:15:00 -0200484 * Search the index for a key
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200485 *
Lucas De Marchi1d152ac2011-12-02 10:15:00 -0200486 * Returns the value of the first match
487 *
488 * The recursive functions free their node argument (using index_close).
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200489 */
Lucas De Marchi1d152ac2011-12-02 10:15:00 -0200490char *index_search(struct index_file *in, const char *key)
491{
Lucas De Marchiee1d1882012-02-27 18:48:02 -0300492// FIXME: return value by reference instead of strdup
Lucas De Marchi1d152ac2011-12-02 10:15:00 -0200493 struct index_node_f *root;
494 char *value;
495
496 root = index_readroot(in);
497 value = index_search__node(root, key, 0);
498
499 return value;
500}
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200501
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200502
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200503
504/* Level 4: add all the values from a matching node */
505static void index_searchwild__allvalues(struct index_node_f *node,
Lucas De Marchi1d152ac2011-12-02 10:15:00 -0200506 struct index_value **out)
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200507{
Lucas De Marchi1d152ac2011-12-02 10:15:00 -0200508 struct index_value *v;
Lucas De Marchia7be73b2011-11-30 15:59:36 -0200509
Lucas De Marchi1d152ac2011-12-02 10:15:00 -0200510 for (v = node->values; v != NULL; v = v->next)
Gustavo Sverzut Barbieri1433ba92011-12-08 14:50:29 -0200511 add_value(out, v->value, v->len, v->priority);
Lucas De Marchi1d152ac2011-12-02 10:15:00 -0200512
513 index_close(node);
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200514}
515
Lucas De Marchi1d152ac2011-12-02 10:15:00 -0200516/*
517 * Level 3: traverse a sub-keyspace which starts with a wildcard,
518 * looking for matches.
519 */
520static void index_searchwild__all(struct index_node_f *node, int j,
521 struct buffer *buf,
522 const char *subkey,
523 struct index_value **out)
524{
525 int pushed = 0;
526 int ch;
527
528 while (node->prefix[j]) {
529 ch = node->prefix[j];
530
531 buf_pushchar(buf, ch);
532 pushed++;
533 j++;
534 }
535
536 for (ch = node->first; ch <= node->last; ch++) {
537 struct index_node_f *child = index_readchild(node, ch);
538
539 if (!child)
540 continue;
541
542 buf_pushchar(buf, ch);
543 index_searchwild__all(child, 0, buf, subkey, out);
544 buf_popchar(buf);
545 }
546
547 if (node->values) {
548 if (fnmatch(buf_str(buf), subkey, 0) == 0)
549 index_searchwild__allvalues(node, out);
Gustavo Sverzut Barbieri27fdf632011-12-10 13:28:18 -0200550 else
551 index_close(node);
Lucas De Marchi1d152ac2011-12-02 10:15:00 -0200552 } else {
553 index_close(node);
554 }
555
556 buf_popchars(buf, pushed);
557}
558
559/* Level 2: descend the tree (until we hit a wildcard) */
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200560static void index_searchwild__node(struct index_node_f *node,
561 struct buffer *buf,
562 const char *key, int i,
563 struct index_value **out)
564{
565 struct index_node_f *child;
566 int j;
567 int ch;
568
569 while(node) {
570 for (j = 0; node->prefix[j]; j++) {
571 ch = node->prefix[j];
Lucas De Marchia7be73b2011-11-30 15:59:36 -0200572
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200573 if (ch == '*' || ch == '?' || ch == '[') {
574 index_searchwild__all(node, j, buf,
575 &key[i+j], out);
576 return;
577 }
Lucas De Marchia7be73b2011-11-30 15:59:36 -0200578
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200579 if (ch != key[i+j]) {
580 index_close(node);
581 return;
582 }
583 }
Lucas De Marchie71970a2011-12-02 10:27:15 -0200584
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200585 i += j;
Lucas De Marchia7be73b2011-11-30 15:59:36 -0200586
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200587 child = index_readchild(node, '*');
588 if (child) {
589 buf_pushchar(buf, '*');
590 index_searchwild__all(child, 0, buf, &key[i], out);
591 buf_popchar(buf);
592 }
Lucas De Marchia7be73b2011-11-30 15:59:36 -0200593
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200594 child = index_readchild(node, '?');
595 if (child) {
596 buf_pushchar(buf, '?');
597 index_searchwild__all(child, 0, buf, &key[i], out);
598 buf_popchar(buf);
599 }
Lucas De Marchia7be73b2011-11-30 15:59:36 -0200600
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200601 child = index_readchild(node, '[');
602 if (child) {
603 buf_pushchar(buf, '[');
604 index_searchwild__all(child, 0, buf, &key[i], out);
605 buf_popchar(buf);
606 }
Lucas De Marchia7be73b2011-11-30 15:59:36 -0200607
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200608 if (key[i] == '\0') {
609 index_searchwild__allvalues(node, out);
610
611 return;
612 }
Lucas De Marchia7be73b2011-11-30 15:59:36 -0200613
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200614 child = index_readchild(node, key[i]);
615 index_close(node);
616 node = child;
617 i++;
618 }
619}
620
Lucas De Marchi1d152ac2011-12-02 10:15:00 -0200621/*
622 * Search the index for a key. The index may contain wildcards.
623 *
624 * Returns a list of all the values of matching keys.
625 */
626struct index_value *index_searchwild(struct index_file *in, const char *key)
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200627{
Lucas De Marchi1d152ac2011-12-02 10:15:00 -0200628 struct index_node_f *root = index_readroot(in);
Gustavo Sverzut Barbieri405f6142011-12-08 14:36:30 -0200629 struct buffer buf;
Lucas De Marchi1d152ac2011-12-02 10:15:00 -0200630 struct index_value *out = NULL;
Lucas De Marchia7be73b2011-11-30 15:59:36 -0200631
Gustavo Sverzut Barbieri405f6142011-12-08 14:36:30 -0200632 buf_init(&buf);
633 index_searchwild__node(root, &buf, key, 0, &out);
634 buf_release(&buf);
Lucas De Marchi1d152ac2011-12-02 10:15:00 -0200635 return out;
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200636}
Lucas De Marchib471a6b2011-12-01 23:14:20 -0200637
638#include <sys/mman.h>
639#include <sys/stat.h>
640#include <unistd.h>
641
Gustavo Sverzut Barbieri15c1c142011-12-10 11:44:31 -0200642static const char _idx_empty_str[] = "";
643
Lucas De Marchib471a6b2011-12-01 23:14:20 -0200644/**************************************************************************/
645/*
646 * Alternative implementation, using mmap to map all the file to memory when
647 * starting
648 */
649struct index_mm {
650 struct kmod_ctx *ctx;
651 void *mm;
652 uint32_t root_offset;
653 size_t size;
654};
655
Gustavo Sverzut Barbierid0915462011-12-10 13:04:43 -0200656struct index_mm_value {
657 unsigned int priority;
658 unsigned int len;
659 const char *value;
660};
661
662struct index_mm_value_array {
663 struct index_mm_value *values;
664 unsigned int len;
665};
666
Lucas De Marchi836be9a2011-12-02 17:27:52 -0200667struct index_mm_node {
668 struct index_mm *idx;
Gustavo Sverzut Barbieri15c1c142011-12-10 11:44:31 -0200669 const char *prefix; /* mmape'd value */
Gustavo Sverzut Barbierid0915462011-12-10 13:04:43 -0200670 struct index_mm_value_array values;
Lucas De Marchi836be9a2011-12-02 17:27:52 -0200671 unsigned char first;
672 unsigned char last;
673 uint32_t children[];
674};
675
676static inline uint32_t read_long_mm(void **p)
677{
Gustavo Sverzut Barbierifc2d8352011-12-10 11:36:35 -0200678 uint8_t *addr = *(uint8_t **)p;
679 uint32_t v;
Lucas De Marchi836be9a2011-12-02 17:27:52 -0200680
Gustavo Sverzut Barbierifc2d8352011-12-10 11:36:35 -0200681 /* addr may be unalined to uint32_t */
Lucas De Marchi5bbec8c2012-05-23 19:32:58 -0300682 v = get_unaligned((uint32_t *) addr);
Lucas De Marchi836be9a2011-12-02 17:27:52 -0200683
Gustavo Sverzut Barbierifc2d8352011-12-10 11:36:35 -0200684 *p = addr + sizeof(uint32_t);
Lucas De Marchi836be9a2011-12-02 17:27:52 -0200685 return ntohl(v);
686}
687
688static inline uint8_t read_char_mm(void **p)
689{
Gustavo Sverzut Barbierifc2d8352011-12-10 11:36:35 -0200690 uint8_t *addr = *(uint8_t **)p;
691 uint8_t v = *addr;
692 *p = addr + sizeof(uint8_t);
693 return v;
Lucas De Marchi836be9a2011-12-02 17:27:52 -0200694}
695
Gustavo Sverzut Barbieri1433ba92011-12-08 14:50:29 -0200696static inline char *read_chars_mm(void **p, unsigned *rlen)
Lucas De Marchi836be9a2011-12-02 17:27:52 -0200697{
Gustavo Sverzut Barbierifc2d8352011-12-10 11:36:35 -0200698 char *addr = *(char **)p;
699 size_t len = *rlen = strlen(addr);
700 *p = addr + len + 1;
701 return addr;
Lucas De Marchi836be9a2011-12-02 17:27:52 -0200702}
703
704static struct index_mm_node *index_mm_read_node(struct index_mm *idx,
705 uint32_t offset) {
706 void *p = idx->mm;
707 struct index_mm_node *node;
Gustavo Sverzut Barbieri15c1c142011-12-10 11:44:31 -0200708 const char *prefix;
Gustavo Sverzut Barbierid0915462011-12-10 13:04:43 -0200709 int i, child_count, value_count, children_padding;
710 uint32_t children[INDEX_CHILDMAX];
711 char first, last;
Lucas De Marchi836be9a2011-12-02 17:27:52 -0200712
713 if ((offset & INDEX_NODE_MASK) == 0)
714 return NULL;
715
716 p = (char *)p + (offset & INDEX_NODE_MASK);
717
Gustavo Sverzut Barbieri15c1c142011-12-10 11:44:31 -0200718 if (offset & INDEX_NODE_PREFIX) {
719 unsigned len;
720 prefix = read_chars_mm(&p, &len);
721 } else
722 prefix = _idx_empty_str;
Lucas De Marchi836be9a2011-12-02 17:27:52 -0200723
724 if (offset & INDEX_NODE_CHILDS) {
Gustavo Sverzut Barbierid0915462011-12-10 13:04:43 -0200725 first = read_char_mm(&p);
726 last = read_char_mm(&p);
Lucas De Marchi836be9a2011-12-02 17:27:52 -0200727 child_count = last - first + 1;
Lucas De Marchi836be9a2011-12-02 17:27:52 -0200728 for (i = 0; i < child_count; i++)
Gustavo Sverzut Barbierid0915462011-12-10 13:04:43 -0200729 children[i] = read_long_mm(&p);
Lucas De Marchi836be9a2011-12-02 17:27:52 -0200730 } else {
Gustavo Sverzut Barbierid0915462011-12-10 13:04:43 -0200731 first = INDEX_CHILDMAX;
732 last = 0;
733 child_count = 0;
Lucas De Marchi836be9a2011-12-02 17:27:52 -0200734 }
735
Gustavo Sverzut Barbieric6824b62011-12-21 18:23:58 -0200736 children_padding = (sizeof(struct index_mm_node) +
Gustavo Sverzut Barbierid0915462011-12-10 13:04:43 -0200737 (sizeof(uint32_t) * child_count)) % sizeof(void *);
Lucas De Marchi836be9a2011-12-02 17:27:52 -0200738
Gustavo Sverzut Barbierid0915462011-12-10 13:04:43 -0200739 if (offset & INDEX_NODE_VALUES)
740 value_count = read_long_mm(&p);
741 else
742 value_count = 0;
Lucas De Marchi836be9a2011-12-02 17:27:52 -0200743
Gustavo Sverzut Barbierid0915462011-12-10 13:04:43 -0200744 node = malloc(sizeof(struct index_mm_node)
745 + sizeof(uint32_t) * child_count + children_padding
746 + sizeof(struct index_mm_value) * value_count);
747 if (node == NULL)
748 return NULL;
Lucas De Marchi836be9a2011-12-02 17:27:52 -0200749
Lucas De Marchi836be9a2011-12-02 17:27:52 -0200750 node->idx = idx;
Gustavo Sverzut Barbierid0915462011-12-10 13:04:43 -0200751 node->prefix = prefix;
752 if (value_count == 0)
753 node->values.values = NULL;
754 else {
755 node->values.values = (struct index_mm_value *)
756 ((char *)node + sizeof(struct index_mm_node) +
757 sizeof(uint32_t) * child_count + children_padding);
758 }
759 node->values.len = value_count;
760 node->first = first;
761 node->last = last;
762 memcpy(node->children, children, sizeof(uint32_t) * child_count);
763
764 for (i = 0; i < value_count; i++) {
765 struct index_mm_value *v = node->values.values + i;
766 v->priority = read_long_mm(&p);
767 v->value = read_chars_mm(&p, &v->len);
768 }
Lucas De Marchi836be9a2011-12-02 17:27:52 -0200769
770 return node;
771}
772
773static void index_mm_free_node(struct index_mm_node *node)
774{
Lucas De Marchi836be9a2011-12-02 17:27:52 -0200775 free(node);
776}
777
Lucas De Marchi5109f2b2011-12-08 15:10:55 -0200778struct index_mm *index_mm_open(struct kmod_ctx *ctx, const char *filename,
Lucas De Marchi2e2e2522012-03-02 20:33:26 -0300779 unsigned long long *stamp)
Lucas De Marchib471a6b2011-12-01 23:14:20 -0200780{
781 int fd;
782 struct stat st;
783 struct index_mm *idx;
784 struct {
785 uint32_t magic;
786 uint32_t version;
787 uint32_t root_offset;
788 } hdr;
789 void *p;
790
791 DBG(ctx, "file=%s\n", filename);
792
Lucas De Marchi7d51d8b2011-12-12 18:41:57 -0200793 idx = malloc(sizeof(*idx));
794 if (idx == NULL) {
Gustavo Sverzut Barbieridfa96f12012-01-07 19:37:37 -0200795 ERR(ctx, "malloc: %m\n");
Lucas De Marchib471a6b2011-12-01 23:14:20 -0200796 return NULL;
797 }
798
Cristian Rodríguez79e5ea92011-12-16 02:49:54 -0300799 if ((fd = open(filename, O_RDONLY|O_CLOEXEC)) < 0) {
Lucas De Marchi73298172012-02-13 21:58:36 -0200800 DBG(ctx, "open(%s, O_RDONLY|O_CLOEXEC): %m\n", filename);
Lucas De Marchi7d51d8b2011-12-12 18:41:57 -0200801 goto fail_open;
Lucas De Marchib471a6b2011-12-01 23:14:20 -0200802 }
803
Leandro Pereirad36c8862014-04-28 20:44:14 -0300804 if (fstat(fd, &st) < 0)
805 goto fail_nommap;
Lucas De Marchi5b05c322012-06-06 09:36:29 -0300806 if ((size_t) st.st_size < sizeof(hdr))
807 goto fail_nommap;
Lucas De Marchi5109f2b2011-12-08 15:10:55 -0200808
Kees Cookc3e8d262013-02-18 12:02:34 -0800809 if ((idx->mm = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0))
Lucas De Marchi5109f2b2011-12-08 15:10:55 -0200810 == MAP_FAILED) {
Kees Cookc3e8d262013-02-18 12:02:34 -0800811 ERR(ctx, "mmap(NULL, %"PRIu64", PROT_READ, %d, MAP_PRIVATE, 0): %m\n",
Lucas De Marchi2e2e2522012-03-02 20:33:26 -0300812 st.st_size, fd);
Lucas De Marchi5b05c322012-06-06 09:36:29 -0300813 goto fail_nommap;
Lucas De Marchib471a6b2011-12-01 23:14:20 -0200814 }
815
816 p = idx->mm;
817 hdr.magic = read_long_mm(&p);
818 hdr.version = read_long_mm(&p);
819 hdr.root_offset = read_long_mm(&p);
820
821 if (hdr.magic != INDEX_MAGIC) {
822 ERR(ctx, "magic check fail: %x instead of %x\n", hdr.magic,
823 INDEX_MAGIC);
824 goto fail;
825 }
826
827 if (hdr.version >> 16 != INDEX_VERSION_MAJOR) {
828 ERR(ctx, "major version check fail: %u instead of %u\n",
Holger Obermaier1a4aa7e2014-09-04 14:38:16 +0200829 hdr.version >> 16, INDEX_VERSION_MAJOR);
Lucas De Marchib471a6b2011-12-01 23:14:20 -0200830 goto fail;
831 }
832
833 idx->root_offset = hdr.root_offset;
834 idx->size = st.st_size;
835 idx->ctx = ctx;
836 close(fd);
837
Lucas De Marchi6068aaa2012-01-17 12:10:42 -0200838 *stamp = stat_mstamp(&st);
Lucas De Marchi9fd58f32011-12-31 18:53:24 -0200839
Lucas De Marchib471a6b2011-12-01 23:14:20 -0200840 return idx;
841
842fail:
Lucas De Marchi5b05c322012-06-06 09:36:29 -0300843 munmap(idx->mm, st.st_size);
844fail_nommap:
Lucas De Marchib471a6b2011-12-01 23:14:20 -0200845 close(fd);
Gustavo Sverzut Barbieria5a92a62011-12-16 16:17:50 -0200846fail_open:
Lucas De Marchib471a6b2011-12-01 23:14:20 -0200847 free(idx);
848 return NULL;
849}
850
851void index_mm_close(struct index_mm *idx)
852{
853 munmap(idx->mm, idx->size);
854 free(idx);
855}
Lucas De Marchi77bf9362011-12-02 17:41:30 -0200856
857static struct index_mm_node *index_mm_readroot(struct index_mm *idx)
858{
859 return index_mm_read_node(idx, idx->root_offset);
860}
Lucas De Marchi91298dc2011-12-02 17:41:46 -0200861
862static struct index_mm_node *index_mm_readchild(const struct index_mm_node *parent,
863 int ch)
864{
865 if (parent->first <= ch && ch <= parent->last) {
866 return index_mm_read_node(parent->idx,
867 parent->children[ch - parent->first]);
868 }
869
870 return NULL;
871}
Lucas De Marchie33bb872011-12-02 17:45:01 -0200872
Lucas De Marchi758428a2012-01-16 15:56:17 -0200873static void index_mm_dump_node(struct index_mm_node *node, struct buffer *buf,
874 int fd)
875{
876 struct index_mm_value *itr, *itr_end;
877 int ch, pushed;
878
879 pushed = buf_pushchars(buf, node->prefix);
880
881 itr = node->values.values;
882 itr_end = itr + node->values.len;
883 for (; itr < itr_end; itr++) {
884 write_str_safe(fd, buf->bytes, buf->used);
885 write_str_safe(fd, " ", 1);
886 write_str_safe(fd, itr->value, itr->len);
887 write_str_safe(fd, "\n", 1);
888 }
889
890 for (ch = node->first; ch <= node->last; ch++) {
891 struct index_mm_node *child = index_mm_readchild(node, ch);
892
893 if (child == NULL)
894 continue;
895
896 buf_pushchar(buf, ch);
897 index_mm_dump_node(child, buf, fd);
898 buf_popchar(buf);
899 }
900
901 buf_popchars(buf, pushed);
902 index_mm_free_node(node);
903}
904
905void index_mm_dump(struct index_mm *idx, int fd, const char *prefix)
906{
907 struct index_mm_node *root;
908 struct buffer buf;
909
Lucas De Marchi681bf892013-04-23 21:21:00 -0300910 root = index_mm_readroot(idx);
911 if (root == NULL)
912 return;
913
Lucas De Marchi758428a2012-01-16 15:56:17 -0200914 buf_init(&buf);
915 buf_pushchars(&buf, prefix);
Lucas De Marchi758428a2012-01-16 15:56:17 -0200916 index_mm_dump_node(root, &buf, fd);
917 buf_release(&buf);
918}
919
Lucas De Marchie33bb872011-12-02 17:45:01 -0200920static char *index_mm_search_node(struct index_mm_node *node, const char *key,
921 int i)
922{
923 char *value;
924 struct index_mm_node *child;
925 int ch;
926 int j;
927
928 while(node) {
929 for (j = 0; node->prefix[j]; j++) {
930 ch = node->prefix[j];
931
932 if (ch != key[i+j]) {
933 index_mm_free_node(node);
934 return NULL;
935 }
936 }
937
938 i += j;
939
940 if (key[i] == '\0') {
Lucas De Marchi817f4e32012-02-27 19:54:33 -0300941 value = node->values.len > 0
942 ? strdup(node->values.values[0].value)
943 : NULL;
944
945 index_mm_free_node(node);
946 return value;
Lucas De Marchie33bb872011-12-02 17:45:01 -0200947 }
948
949 child = index_mm_readchild(node, key[i]);
950 index_mm_free_node(node);
951 node = child;
952 i++;
953 }
954
955 return NULL;
956}
Lucas De Marchib797b792011-12-02 17:49:03 -0200957
958/*
959 * Search the index for a key
960 *
961 * Returns the value of the first match
962 *
963 * The recursive functions free their node argument (using index_close).
964 */
965char *index_mm_search(struct index_mm *idx, const char *key)
966{
Lucas De Marchiee1d1882012-02-27 18:48:02 -0300967// FIXME: return value by reference instead of strdup
Lucas De Marchib797b792011-12-02 17:49:03 -0200968 struct index_mm_node *root;
969 char *value;
970
971 root = index_mm_readroot(idx);
972 value = index_mm_search_node(root, key, 0);
973
974 return value;
975}
Lucas De Marchibf89f702011-12-02 18:23:36 -0200976
977/* Level 4: add all the values from a matching node */
978static void index_mm_searchwild_allvalues(struct index_mm_node *node,
979 struct index_value **out)
980{
Gustavo Sverzut Barbierid0915462011-12-10 13:04:43 -0200981 struct index_mm_value *itr, *itr_end;
Lucas De Marchibf89f702011-12-02 18:23:36 -0200982
Gustavo Sverzut Barbierid0915462011-12-10 13:04:43 -0200983 itr = node->values.values;
984 itr_end = itr + node->values.len;
985 for (; itr < itr_end; itr++)
986 add_value(out, itr->value, itr->len, itr->priority);
Lucas De Marchibf89f702011-12-02 18:23:36 -0200987
988 index_mm_free_node(node);
989}
990
991/*
992 * Level 3: traverse a sub-keyspace which starts with a wildcard,
993 * looking for matches.
994 */
995static void index_mm_searchwild_all(struct index_mm_node *node, int j,
996 struct buffer *buf,
997 const char *subkey,
998 struct index_value **out)
999{
1000 int pushed = 0;
1001 int ch;
1002
1003 while (node->prefix[j]) {
1004 ch = node->prefix[j];
1005
1006 buf_pushchar(buf, ch);
1007 pushed++;
1008 j++;
1009 }
1010
1011 for (ch = node->first; ch <= node->last; ch++) {
1012 struct index_mm_node *child = index_mm_readchild(node, ch);
1013
1014 if (!child)
1015 continue;
1016
1017 buf_pushchar(buf, ch);
1018 index_mm_searchwild_all(child, 0, buf, subkey, out);
1019 buf_popchar(buf);
1020 }
1021
Gustavo Sverzut Barbierid0915462011-12-10 13:04:43 -02001022 if (node->values.len > 0) {
Lucas De Marchibf89f702011-12-02 18:23:36 -02001023 if (fnmatch(buf_str(buf), subkey, 0) == 0)
1024 index_mm_searchwild_allvalues(node, out);
Gustavo Sverzut Barbieri27fdf632011-12-10 13:28:18 -02001025 else
1026 index_mm_free_node(node);
Lucas De Marchibf89f702011-12-02 18:23:36 -02001027 } else {
1028 index_mm_free_node(node);
1029 }
1030
1031 buf_popchars(buf, pushed);
1032}
1033
1034/* Level 2: descend the tree (until we hit a wildcard) */
1035static void index_mm_searchwild_node(struct index_mm_node *node,
1036 struct buffer *buf,
1037 const char *key, int i,
1038 struct index_value **out)
1039{
1040 struct index_mm_node *child;
1041 int j;
1042 int ch;
1043
1044 while(node) {
1045 for (j = 0; node->prefix[j]; j++) {
1046 ch = node->prefix[j];
1047
1048 if (ch == '*' || ch == '?' || ch == '[') {
1049 index_mm_searchwild_all(node, j, buf,
1050 &key[i+j], out);
1051 return;
1052 }
1053
1054 if (ch != key[i+j]) {
1055 index_mm_free_node(node);
1056 return;
1057 }
1058 }
1059
1060 i += j;
1061
1062 child = index_mm_readchild(node, '*');
1063 if (child) {
1064 buf_pushchar(buf, '*');
1065 index_mm_searchwild_all(child, 0, buf, &key[i], out);
1066 buf_popchar(buf);
1067 }
1068
1069 child = index_mm_readchild(node, '?');
1070 if (child) {
1071 buf_pushchar(buf, '?');
1072 index_mm_searchwild_all(child, 0, buf, &key[i], out);
1073 buf_popchar(buf);
1074 }
1075
1076 child = index_mm_readchild(node, '[');
1077 if (child) {
1078 buf_pushchar(buf, '[');
1079 index_mm_searchwild_all(child, 0, buf, &key[i], out);
1080 buf_popchar(buf);
1081 }
1082
1083 if (key[i] == '\0') {
1084 index_mm_searchwild_allvalues(node, out);
1085
1086 return;
1087 }
1088
1089 child = index_mm_readchild(node, key[i]);
1090 index_mm_free_node(node);
1091 node = child;
1092 i++;
1093 }
1094}
1095
1096/*
1097 * Search the index for a key. The index may contain wildcards.
1098 *
1099 * Returns a list of all the values of matching keys.
1100 */
1101struct index_value *index_mm_searchwild(struct index_mm *idx, const char *key)
1102{
1103 struct index_mm_node *root = index_mm_readroot(idx);
Gustavo Sverzut Barbieri405f6142011-12-08 14:36:30 -02001104 struct buffer buf;
Lucas De Marchibf89f702011-12-02 18:23:36 -02001105 struct index_value *out = NULL;
1106
Gustavo Sverzut Barbieri405f6142011-12-08 14:36:30 -02001107 buf_init(&buf);
1108 index_mm_searchwild_node(root, &buf, key, 0, &out);
1109 buf_release(&buf);
Lucas De Marchibf89f702011-12-02 18:23:36 -02001110 return out;
1111}