blob: c0785245a6293d7a5daddb771d36c65cbd11bb32 [file] [log] [blame]
Lucas De Marchie8847fd2011-11-30 15:23:28 -02001/* index.c: module index file shared functions for modprobe and depmod
2 Copyright (C) 2008 Alan Jenkins <alan-jenkins@tuffmail.co.uk>.
3
4 These programs are free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with these programs. If not, see <http://www.gnu.org/licenses/>.
16*/
17
18#include <arpa/inet.h> /* htonl */
19#include <stdlib.h>
20#include <stdio.h>
21#include <string.h>
22#include <errno.h>
23#include <fnmatch.h>
24
25#include "libkmod-private.h"
26#include "libkmod-index.h"
27#include "macro.h"
28
Lucas De Marchie8847fd2011-11-30 15:23:28 -020029void index_values_free(struct index_value *values)
30{
31 while (values) {
32 struct index_value *value = values;
33
34 values = value->next;
35 free(value);
36 }
37}
38
Lucas De Marchie8847fd2011-11-30 15:23:28 -020039static int add_value(struct index_value **values,
40 const char *value, unsigned int priority)
41{
42 struct index_value *v;
43 int duplicate = 0;
44 int len;
45
46 /* report the presence of duplicate values */
47 for (v = *values; v; v = v->next) {
48 if (streq(v->value, value))
49 duplicate = 1;
50 }
51
52 /* find position to insert value */
53 while (*values && (*values)->priority < priority)
54 values = &(*values)->next;
55
56 len = strlen(value);
57 v = NOFAIL(calloc(sizeof(struct index_value) + len + 1, 1));
58 v->next = *values;
59 v->priority = priority;
60 memcpy(v->value, value, len + 1);
61 *values = v;
62
63 return duplicate;
64}
65
Lucas De Marchi93688882011-12-02 10:05:31 -020066static void read_error(void)
Lucas De Marchie8847fd2011-11-30 15:23:28 -020067{
68 fatal("Module index: unexpected error: %s\n"
69 "Try re-running depmod\n", errno ? strerror(errno) : "EOF");
70}
71
72static int read_char(FILE *in)
73{
74 int ch;
75
76 errno = 0;
77 ch = getc_unlocked(in);
78 if (ch == EOF)
79 read_error();
80 return ch;
81}
82
83static uint32_t read_long(FILE *in)
84{
85 uint32_t l;
86
87 errno = 0;
88 if (fread(&l, sizeof(uint32_t), 1, in) <= 0)
89 read_error();
90 return ntohl(l);
91}
92
93/*
94 * Buffer abstract data type
95 *
96 * Used internally to store the current path during tree traversal.
97 * They help build wildcard key strings to pass to fnmatch(),
98 * as well as building values of matching keys.
99 */
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200100struct buffer {
101 char *bytes;
102 unsigned size;
103 unsigned used;
104};
105
106static void buf__realloc(struct buffer *buf, unsigned size)
107{
108 if (size > buf->size) {
109 buf->bytes = NOFAIL(realloc(buf->bytes, size));
110 buf->size = size;
111 }
112}
113
Lucas De Marchi93688882011-12-02 10:05:31 -0200114static struct buffer *buf_create(void)
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200115{
116 struct buffer *buf;
Lucas De Marchia7be73b2011-11-30 15:59:36 -0200117
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200118 buf = NOFAIL(calloc(sizeof(struct buffer), 1));
119 buf__realloc(buf, 256);
120 return buf;
121}
122
123static void buf_destroy(struct buffer *buf)
124{
125 free(buf->bytes);
126 free(buf);
127}
128
129/* Destroy buffer and return a copy as a C string */
130static char *buf_detach(struct buffer *buf)
131{
132 char *bytes;
133
134 bytes = NOFAIL(realloc(buf->bytes, buf->used + 1));
135 bytes[buf->used] = '\0';
136
137 free(buf);
138 return bytes;
139}
140
141/* Return a C string owned by the buffer
142 (invalidated if the buffer is changed).
143 */
144static const char *buf_str(struct buffer *buf)
145{
146 buf__realloc(buf, buf->used + 1);
147 buf->bytes[buf->used] = '\0';
148 return buf->bytes;
149}
150
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200151static void buf_pushchar(struct buffer *buf, char ch)
152{
153 buf__realloc(buf, buf->used + 1);
154 buf->bytes[buf->used] = ch;
155 buf->used++;
156}
157
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200158static unsigned buf_freadchars(struct buffer *buf, FILE *in)
159{
160 unsigned i = 0;
161 int ch;
162
163 while ((ch = read_char(in))) {
164 buf_pushchar(buf, ch);
165 i++;
166 }
167
168 return i;
169}
170
171static void buf_popchar(struct buffer *buf)
172{
173 buf->used--;
174}
175
176static void buf_popchars(struct buffer *buf, unsigned n)
177{
178 buf->used -= n;
179}
180
181static void buf_clear(struct buffer *buf)
182{
183 buf->used = 0;
184}
185
186/*
Lucas De Marchieb8bb322011-12-02 10:23:02 -0200187 * Index file searching
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200188 */
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200189struct index_node_f {
190 FILE *file;
191 char *prefix; /* path compression */
192 struct index_value *values;
193 unsigned char first; /* range of child nodes */
194 unsigned char last;
195 uint32_t children[0];
196};
197
198static struct index_node_f *index_read(FILE *in, uint32_t offset)
199{
200 struct index_node_f *node;
201 char *prefix;
202 int i, child_count = 0;
203
204 if ((offset & INDEX_NODE_MASK) == 0)
205 return NULL;
206
207 fseek(in, offset & INDEX_NODE_MASK, SEEK_SET);
Lucas De Marchia7be73b2011-11-30 15:59:36 -0200208
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200209 if (offset & INDEX_NODE_PREFIX) {
210 struct buffer *buf = buf_create();
211 buf_freadchars(buf, in);
212 prefix = buf_detach(buf);
213 } else
214 prefix = NOFAIL(strdup(""));
Lucas De Marchia7be73b2011-11-30 15:59:36 -0200215
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200216 if (offset & INDEX_NODE_CHILDS) {
217 char first = read_char(in);
218 char last = read_char(in);
219 child_count = last - first + 1;
Lucas De Marchia7be73b2011-11-30 15:59:36 -0200220
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200221 node = NOFAIL(malloc(sizeof(struct index_node_f) +
222 sizeof(uint32_t) * child_count));
Lucas De Marchia7be73b2011-11-30 15:59:36 -0200223
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200224 node->first = first;
225 node->last = last;
226
227 for (i = 0; i < child_count; i++)
228 node->children[i] = read_long(in);
229 } else {
230 node = NOFAIL(malloc(sizeof(struct index_node_f)));
231 node->first = INDEX_CHILDMAX;
232 node->last = 0;
233 }
Lucas De Marchia7be73b2011-11-30 15:59:36 -0200234
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200235 node->values = NULL;
236 if (offset & INDEX_NODE_VALUES) {
237 int value_count;
238 struct buffer *buf = buf_create();
239 const char *value;
240 unsigned int priority;
241
242 value_count = read_long(in);
243
244 while (value_count--) {
245 priority = read_long(in);
246 buf_freadchars(buf, in);
247 value = buf_str(buf);
248 add_value(&node->values, value, priority);
249 buf_clear(buf);
250 }
251 buf_destroy(buf);
252 }
253
254 node->prefix = prefix;
255 node->file = in;
256 return node;
257}
258
259static void index_close(struct index_node_f *node)
260{
261 free(node->prefix);
262 index_values_free(node->values);
263 free(node);
264}
265
266struct index_file {
267 FILE *file;
268 uint32_t root_offset;
269};
270
271/* Failures are silent; modprobe will fall back to text files */
272struct index_file *index_file_open(const char *filename)
273{
274 FILE *file;
275 uint32_t magic, version;
276 struct index_file *new;
277
278 file = fopen(filename, "r");
279 if (!file)
280 return NULL;
281 errno = EINVAL;
282
283 magic = read_long(file);
284 if (magic != INDEX_MAGIC)
285 return NULL;
286
287 version = read_long(file);
288 if (version >> 16 != INDEX_VERSION_MAJOR)
289 return NULL;
290
291 new = NOFAIL(malloc(sizeof(struct index_file)));
292 new->file = file;
293 new->root_offset = read_long(new->file);
294
295 errno = 0;
296 return new;
297}
298
Lucas De Marchi0fbdfef2011-12-02 09:56:22 -0200299void index_file_close(struct index_file *idx)
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200300{
Lucas De Marchi0fbdfef2011-12-02 09:56:22 -0200301 fclose(idx->file);
302 free(idx);
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200303}
304
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200305static struct index_node_f *index_readroot(struct index_file *in)
306{
307 return index_read(in->file, in->root_offset);
308}
309
310static struct index_node_f *index_readchild(const struct index_node_f *parent,
311 int ch)
312{
Lucas De Marchie71970a2011-12-02 10:27:15 -0200313 if (parent->first <= ch && ch <= parent->last) {
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200314 return index_read(parent->file,
315 parent->children[ch - parent->first]);
Lucas De Marchie71970a2011-12-02 10:27:15 -0200316 }
317
318 return NULL;
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200319}
320
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200321static char *index_search__node(struct index_node_f *node, const char *key, int i)
322{
323 char *value;
324 struct index_node_f *child;
325 int ch;
326 int j;
327
328 while(node) {
329 for (j = 0; node->prefix[j]; j++) {
330 ch = node->prefix[j];
Lucas De Marchia7be73b2011-11-30 15:59:36 -0200331
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200332 if (ch != key[i+j]) {
333 index_close(node);
334 return NULL;
335 }
336 }
Lucas De Marchie71970a2011-12-02 10:27:15 -0200337
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200338 i += j;
Lucas De Marchia7be73b2011-11-30 15:59:36 -0200339
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200340 if (key[i] == '\0') {
341 if (node->values) {
342 value = strdup(node->values[0].value);
343 index_close(node);
344 return value;
345 } else {
346 return NULL;
347 }
348 }
Lucas De Marchia7be73b2011-11-30 15:59:36 -0200349
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200350 child = index_readchild(node, key[i]);
351 index_close(node);
352 node = child;
353 i++;
354 }
Lucas De Marchia7be73b2011-11-30 15:59:36 -0200355
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200356 return NULL;
357}
358
359/*
Lucas De Marchi1d152ac2011-12-02 10:15:00 -0200360 * Search the index for a key
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200361 *
Lucas De Marchi1d152ac2011-12-02 10:15:00 -0200362 * Returns the value of the first match
363 *
364 * The recursive functions free their node argument (using index_close).
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200365 */
Lucas De Marchi1d152ac2011-12-02 10:15:00 -0200366char *index_search(struct index_file *in, const char *key)
367{
368 struct index_node_f *root;
369 char *value;
370
371 root = index_readroot(in);
372 value = index_search__node(root, key, 0);
373
374 return value;
375}
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200376
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200377
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200378
379/* Level 4: add all the values from a matching node */
380static void index_searchwild__allvalues(struct index_node_f *node,
Lucas De Marchi1d152ac2011-12-02 10:15:00 -0200381 struct index_value **out)
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200382{
Lucas De Marchi1d152ac2011-12-02 10:15:00 -0200383 struct index_value *v;
Lucas De Marchia7be73b2011-11-30 15:59:36 -0200384
Lucas De Marchi1d152ac2011-12-02 10:15:00 -0200385 for (v = node->values; v != NULL; v = v->next)
386 add_value(out, v->value, v->priority);
387
388 index_close(node);
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200389}
390
Lucas De Marchi1d152ac2011-12-02 10:15:00 -0200391/*
392 * Level 3: traverse a sub-keyspace which starts with a wildcard,
393 * looking for matches.
394 */
395static void index_searchwild__all(struct index_node_f *node, int j,
396 struct buffer *buf,
397 const char *subkey,
398 struct index_value **out)
399{
400 int pushed = 0;
401 int ch;
402
403 while (node->prefix[j]) {
404 ch = node->prefix[j];
405
406 buf_pushchar(buf, ch);
407 pushed++;
408 j++;
409 }
410
411 for (ch = node->first; ch <= node->last; ch++) {
412 struct index_node_f *child = index_readchild(node, ch);
413
414 if (!child)
415 continue;
416
417 buf_pushchar(buf, ch);
418 index_searchwild__all(child, 0, buf, subkey, out);
419 buf_popchar(buf);
420 }
421
422 if (node->values) {
423 if (fnmatch(buf_str(buf), subkey, 0) == 0)
424 index_searchwild__allvalues(node, out);
425 } else {
426 index_close(node);
427 }
428
429 buf_popchars(buf, pushed);
430}
431
432/* Level 2: descend the tree (until we hit a wildcard) */
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200433static void index_searchwild__node(struct index_node_f *node,
434 struct buffer *buf,
435 const char *key, int i,
436 struct index_value **out)
437{
438 struct index_node_f *child;
439 int j;
440 int ch;
441
442 while(node) {
443 for (j = 0; node->prefix[j]; j++) {
444 ch = node->prefix[j];
Lucas De Marchia7be73b2011-11-30 15:59:36 -0200445
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200446 if (ch == '*' || ch == '?' || ch == '[') {
447 index_searchwild__all(node, j, buf,
448 &key[i+j], out);
449 return;
450 }
Lucas De Marchia7be73b2011-11-30 15:59:36 -0200451
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200452 if (ch != key[i+j]) {
453 index_close(node);
454 return;
455 }
456 }
Lucas De Marchie71970a2011-12-02 10:27:15 -0200457
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200458 i += j;
Lucas De Marchia7be73b2011-11-30 15:59:36 -0200459
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200460 child = index_readchild(node, '*');
461 if (child) {
462 buf_pushchar(buf, '*');
463 index_searchwild__all(child, 0, buf, &key[i], out);
464 buf_popchar(buf);
465 }
Lucas De Marchia7be73b2011-11-30 15:59:36 -0200466
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200467 child = index_readchild(node, '?');
468 if (child) {
469 buf_pushchar(buf, '?');
470 index_searchwild__all(child, 0, buf, &key[i], out);
471 buf_popchar(buf);
472 }
Lucas De Marchia7be73b2011-11-30 15:59:36 -0200473
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200474 child = index_readchild(node, '[');
475 if (child) {
476 buf_pushchar(buf, '[');
477 index_searchwild__all(child, 0, buf, &key[i], out);
478 buf_popchar(buf);
479 }
Lucas De Marchia7be73b2011-11-30 15:59:36 -0200480
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200481 if (key[i] == '\0') {
482 index_searchwild__allvalues(node, out);
483
484 return;
485 }
Lucas De Marchia7be73b2011-11-30 15:59:36 -0200486
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200487 child = index_readchild(node, key[i]);
488 index_close(node);
489 node = child;
490 i++;
491 }
492}
493
Lucas De Marchi1d152ac2011-12-02 10:15:00 -0200494/*
495 * Search the index for a key. The index may contain wildcards.
496 *
497 * Returns a list of all the values of matching keys.
498 */
499struct index_value *index_searchwild(struct index_file *in, const char *key)
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200500{
Lucas De Marchi1d152ac2011-12-02 10:15:00 -0200501 struct index_node_f *root = index_readroot(in);
502 struct buffer *buf = buf_create();
503 struct index_value *out = NULL;
Lucas De Marchia7be73b2011-11-30 15:59:36 -0200504
Lucas De Marchi1d152ac2011-12-02 10:15:00 -0200505 index_searchwild__node(root, buf, key, 0, &out);
506 buf_destroy(buf);
507 return out;
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200508}
Lucas De Marchib471a6b2011-12-01 23:14:20 -0200509
510#include <sys/mman.h>
511#include <sys/stat.h>
512#include <unistd.h>
513
514/**************************************************************************/
515/*
516 * Alternative implementation, using mmap to map all the file to memory when
517 * starting
518 */
519struct index_mm {
520 struct kmod_ctx *ctx;
521 void *mm;
522 uint32_t root_offset;
523 size_t size;
524};
525
526struct index_mm *index_mm_open(struct kmod_ctx *ctx, const char *filename)
527{
528 int fd;
529 struct stat st;
530 struct index_mm *idx;
531 struct {
532 uint32_t magic;
533 uint32_t version;
534 uint32_t root_offset;
535 } hdr;
536 void *p;
537
538 DBG(ctx, "file=%s\n", filename);
539
540 if ((fd = open(filename, O_RDONLY)) < 0) {
541 ERR(ctx, "%m\n");
542 return NULL;
543 }
544
545 fstat(fd, &st);
546
547 idx = malloc(sizeof(*idx));
548 if (idx == NULL) {
549 ERR(ctx, "%m\n");
550 goto fail;
551 }
552
553 if ((idx->mm = mmap(0, st.st_size, PROT_READ,
554 MAP_PRIVATE | MAP_POPULATE,
555 fd, 0)) == MAP_FAILED) {
556 ERR(ctx, "%m\n");
557 goto fail;
558 }
559
560 p = idx->mm;
561 hdr.magic = read_long_mm(&p);
562 hdr.version = read_long_mm(&p);
563 hdr.root_offset = read_long_mm(&p);
564
565 if (hdr.magic != INDEX_MAGIC) {
566 ERR(ctx, "magic check fail: %x instead of %x\n", hdr.magic,
567 INDEX_MAGIC);
568 goto fail;
569 }
570
571 if (hdr.version >> 16 != INDEX_VERSION_MAJOR) {
572 ERR(ctx, "major version check fail: %u instead of %u\n",
573 hdr.version, INDEX_MAGIC);
574 goto fail;
575 }
576
577 idx->root_offset = hdr.root_offset;
578 idx->size = st.st_size;
579 idx->ctx = ctx;
580 close(fd);
581
582 return idx;
583
584fail:
585 close(fd);
586 if (idx->mm)
587 munmap(idx->mm, st.st_size);
588 free(idx);
589 return NULL;
590}
591
592void index_mm_close(struct index_mm *idx)
593{
594 munmap(idx->mm, idx->size);
595 free(idx);
596}