blob: 4f19f483f9395f56261dd0773e4f52f1e54208bc [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{
313 if (parent->first <= ch && ch <= parent->last)
314 return index_read(parent->file,
315 parent->children[ch - parent->first]);
316 else
317 return NULL;
318}
319
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200320static char *index_search__node(struct index_node_f *node, const char *key, int i)
321{
322 char *value;
323 struct index_node_f *child;
324 int ch;
325 int j;
326
327 while(node) {
328 for (j = 0; node->prefix[j]; j++) {
329 ch = node->prefix[j];
Lucas De Marchia7be73b2011-11-30 15:59:36 -0200330
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200331 if (ch != key[i+j]) {
332 index_close(node);
333 return NULL;
334 }
335 }
336 i += j;
Lucas De Marchia7be73b2011-11-30 15:59:36 -0200337
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200338 if (key[i] == '\0') {
339 if (node->values) {
340 value = strdup(node->values[0].value);
341 index_close(node);
342 return value;
343 } else {
344 return NULL;
345 }
346 }
Lucas De Marchia7be73b2011-11-30 15:59:36 -0200347
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200348 child = index_readchild(node, key[i]);
349 index_close(node);
350 node = child;
351 i++;
352 }
Lucas De Marchia7be73b2011-11-30 15:59:36 -0200353
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200354 return NULL;
355}
356
357/*
Lucas De Marchi1d152ac2011-12-02 10:15:00 -0200358 * Search the index for a key
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200359 *
Lucas De Marchi1d152ac2011-12-02 10:15:00 -0200360 * Returns the value of the first match
361 *
362 * The recursive functions free their node argument (using index_close).
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200363 */
Lucas De Marchi1d152ac2011-12-02 10:15:00 -0200364char *index_search(struct index_file *in, const char *key)
365{
366 struct index_node_f *root;
367 char *value;
368
369 root = index_readroot(in);
370 value = index_search__node(root, key, 0);
371
372 return value;
373}
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200374
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200375
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200376
377/* Level 4: add all the values from a matching node */
378static void index_searchwild__allvalues(struct index_node_f *node,
Lucas De Marchi1d152ac2011-12-02 10:15:00 -0200379 struct index_value **out)
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200380{
Lucas De Marchi1d152ac2011-12-02 10:15:00 -0200381 struct index_value *v;
Lucas De Marchia7be73b2011-11-30 15:59:36 -0200382
Lucas De Marchi1d152ac2011-12-02 10:15:00 -0200383 for (v = node->values; v != NULL; v = v->next)
384 add_value(out, v->value, v->priority);
385
386 index_close(node);
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200387}
388
Lucas De Marchi1d152ac2011-12-02 10:15:00 -0200389/*
390 * Level 3: traverse a sub-keyspace which starts with a wildcard,
391 * looking for matches.
392 */
393static void index_searchwild__all(struct index_node_f *node, int j,
394 struct buffer *buf,
395 const char *subkey,
396 struct index_value **out)
397{
398 int pushed = 0;
399 int ch;
400
401 while (node->prefix[j]) {
402 ch = node->prefix[j];
403
404 buf_pushchar(buf, ch);
405 pushed++;
406 j++;
407 }
408
409 for (ch = node->first; ch <= node->last; ch++) {
410 struct index_node_f *child = index_readchild(node, ch);
411
412 if (!child)
413 continue;
414
415 buf_pushchar(buf, ch);
416 index_searchwild__all(child, 0, buf, subkey, out);
417 buf_popchar(buf);
418 }
419
420 if (node->values) {
421 if (fnmatch(buf_str(buf), subkey, 0) == 0)
422 index_searchwild__allvalues(node, out);
423 } else {
424 index_close(node);
425 }
426
427 buf_popchars(buf, pushed);
428}
429
430/* Level 2: descend the tree (until we hit a wildcard) */
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200431static void index_searchwild__node(struct index_node_f *node,
432 struct buffer *buf,
433 const char *key, int i,
434 struct index_value **out)
435{
436 struct index_node_f *child;
437 int j;
438 int ch;
439
440 while(node) {
441 for (j = 0; node->prefix[j]; j++) {
442 ch = node->prefix[j];
Lucas De Marchia7be73b2011-11-30 15:59:36 -0200443
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200444 if (ch == '*' || ch == '?' || ch == '[') {
445 index_searchwild__all(node, j, buf,
446 &key[i+j], out);
447 return;
448 }
Lucas De Marchia7be73b2011-11-30 15:59:36 -0200449
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200450 if (ch != key[i+j]) {
451 index_close(node);
452 return;
453 }
454 }
455 i += j;
Lucas De Marchia7be73b2011-11-30 15:59:36 -0200456
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200457 child = index_readchild(node, '*');
458 if (child) {
459 buf_pushchar(buf, '*');
460 index_searchwild__all(child, 0, buf, &key[i], out);
461 buf_popchar(buf);
462 }
Lucas De Marchia7be73b2011-11-30 15:59:36 -0200463
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200464 child = index_readchild(node, '?');
465 if (child) {
466 buf_pushchar(buf, '?');
467 index_searchwild__all(child, 0, buf, &key[i], out);
468 buf_popchar(buf);
469 }
Lucas De Marchia7be73b2011-11-30 15:59:36 -0200470
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200471 child = index_readchild(node, '[');
472 if (child) {
473 buf_pushchar(buf, '[');
474 index_searchwild__all(child, 0, buf, &key[i], out);
475 buf_popchar(buf);
476 }
Lucas De Marchia7be73b2011-11-30 15:59:36 -0200477
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200478 if (key[i] == '\0') {
479 index_searchwild__allvalues(node, out);
480
481 return;
482 }
Lucas De Marchia7be73b2011-11-30 15:59:36 -0200483
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200484 child = index_readchild(node, key[i]);
485 index_close(node);
486 node = child;
487 i++;
488 }
489}
490
Lucas De Marchi1d152ac2011-12-02 10:15:00 -0200491/*
492 * Search the index for a key. The index may contain wildcards.
493 *
494 * Returns a list of all the values of matching keys.
495 */
496struct index_value *index_searchwild(struct index_file *in, const char *key)
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200497{
Lucas De Marchi1d152ac2011-12-02 10:15:00 -0200498 struct index_node_f *root = index_readroot(in);
499 struct buffer *buf = buf_create();
500 struct index_value *out = NULL;
Lucas De Marchia7be73b2011-11-30 15:59:36 -0200501
Lucas De Marchi1d152ac2011-12-02 10:15:00 -0200502 index_searchwild__node(root, buf, key, 0, &out);
503 buf_destroy(buf);
504 return out;
Lucas De Marchie8847fd2011-11-30 15:23:28 -0200505}