modindex: simplify option handling
[mit.git] / index.c
blobd656c0f3681129cf62ecedb929ea5ded30594f46
1 /* index.c: module index file shared functions for modprobe and depmod
2 Copyright (C) 2008 Alan Jenkins <alan-jenkins@tuffmail.co.uk>.
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.
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.
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/>.
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>
25 #include "util.h"
26 #include "logging.h"
27 #include "index.h"
29 #include "testing.h"
32 * Index abstract data type (used only by depmod)
35 struct index_node *index_create()
37 struct index_node *node;
39 node = NOFAIL(calloc(sizeof(struct index_node), 1));
40 node->prefix = NOFAIL(strdup(""));
41 node->first = INDEX_CHILDMAX;
43 return node;
46 void index_values_free(struct index_value *values)
48 while (values) {
49 struct index_value *value = values;
51 values = value->next;
52 free(value);
56 void index_destroy(struct index_node *node)
58 int c;
60 for (c = node->first; c <= node->last; c++) {
61 struct index_node *child = node->children[c];
63 if (child)
64 index_destroy(child);
66 index_values_free(node->values);
67 free(node->prefix);
68 free(node);
71 static void index__checkstring(const char *str)
73 int i;
75 for (i = 0; str[i]; i++) {
76 int ch = str[i];
78 if (ch >= INDEX_CHILDMAX)
79 fatal("Module index: bad character '%c'=0x%x - only 7-bit ASCII is supported:"
80 "\n%s\n", (char) ch, (int) ch, str);
84 static int add_value(struct index_value **values,
85 const char *value, unsigned int priority)
87 struct index_value *v;
88 int duplicate = 0;
89 int len;
91 /* report the presence of duplicate values */
92 for (v = *values; v; v = v->next) {
93 if (streq(v->value, value))
94 duplicate = 1;
97 /* find position to insert value */
98 while (*values && (*values)->priority < priority)
99 values = &(*values)->next;
101 len = strlen(value);
102 v = NOFAIL(calloc(sizeof(struct index_value) + len + 1, 1));
103 v->next = *values;
104 v->priority = priority;
105 memcpy(v->value, value, len + 1);
106 *values = v;
108 return duplicate;
111 int index_insert(struct index_node *node, const char *key,
112 const char *value, unsigned int priority)
114 int i = 0; /* index within str */
115 int ch;
117 index__checkstring(key);
118 index__checkstring(value);
120 while(1) {
121 int j; /* index within node->prefix */
123 /* Ensure node->prefix is a prefix of &str[i].
124 If it is not already, then we must split node. */
125 for (j = 0; node->prefix[j]; j++) {
126 ch = node->prefix[j];
128 if (ch != key[i+j]) {
129 char *prefix = node->prefix;
130 struct index_node *n;
132 /* New child is copy of node with prefix[j+1..N] */
133 n = NOFAIL(calloc(sizeof(struct index_node), 1));
134 memcpy(n, node, sizeof(struct index_node));
135 n->prefix = NOFAIL(strdup(&prefix[j+1]));
137 /* Parent has prefix[0..j], child at prefix[j] */
138 memset(node, 0, sizeof(struct index_node));
139 prefix[j] = '\0';
140 node->prefix = prefix;
141 node->first = ch;
142 node->last = ch;
143 node->children[ch] = n;
145 break;
148 /* j is now length of node->prefix */
149 i += j;
151 ch = key[i];
152 if(ch == '\0')
153 return add_value(&node->values, value, priority);
155 if (!node->children[ch]) {
156 struct index_node *child;
158 if (ch < node->first)
159 node->first = ch;
160 if (ch > node->last)
161 node->last = ch;
162 node->children[ch] = NOFAIL(calloc(sizeof(struct index_node), 1));
164 child = node->children[ch];
165 child->prefix = NOFAIL(strdup(&key[i+1]));
166 child->first = INDEX_CHILDMAX;
167 add_value(&child->values, value, priority);
169 return 0;
172 /* Descend into child node and continue */
173 node = node->children[ch];
174 i++;
178 static int index__haschildren(const struct index_node *node)
180 return node->first < INDEX_CHILDMAX;
183 /* Recursive post-order traversal
185 Pre-order would make for better read-side buffering / readahead / caching.
186 (post-order means you go backwards in the file as you descend the tree).
187 However, index reading is already fast enough.
188 Pre-order is simpler for writing, and depmod is already slow.
190 static uint32_t index_write__node(const struct index_node *node, FILE *out)
192 uint32_t *child_offs = NULL;
193 int child_count = 0;
194 long offset;
196 if (!node)
197 return 0;
199 /* Write children and save their offsets */
200 if (index__haschildren(node)) {
201 const struct index_node *child;
202 int i;
204 child_count = node->last - node->first + 1;
205 child_offs = NOFAIL(malloc(child_count * sizeof(uint32_t)));
207 for (i = 0; i < child_count; i++) {
208 child = node->children[node->first + i];
209 child_offs[i] = htonl(index_write__node(child, out));
213 /* Now write this node */
214 offset = ftell(out);
216 if (node->prefix[0]) {
217 fputs(node->prefix, out);
218 fputc('\0', out);
219 offset |= INDEX_NODE_PREFIX;
222 if (child_count) {
223 fputc(node->first, out);
224 fputc(node->last, out);
225 fwrite(child_offs, sizeof(uint32_t), child_count, out);
226 free(child_offs);
227 offset |= INDEX_NODE_CHILDS;
230 if (node->values) {
231 const struct index_value *v;
232 unsigned int value_count;
233 uint32_t u;
235 value_count = 0;
236 for (v = node->values; v != NULL; v = v->next)
237 value_count++;
238 u = htonl(value_count);
239 fwrite(&u, sizeof(u), 1, out);
241 for (v = node->values; v != NULL; v = v->next) {
242 u = htonl(v->priority);
243 fwrite(&u, sizeof(u), 1, out);
244 fputs(v->value, out);
245 fputc('\0', out);
247 offset |= INDEX_NODE_VALUES;
250 return offset;
253 void index_write(const struct index_node *node, FILE *out)
255 long initial_offset, final_offset;
256 uint32_t u;
258 u = htonl(INDEX_MAGIC);
259 fwrite(&u, sizeof(u), 1, out);
260 u = htonl(INDEX_VERSION);
261 fwrite(&u, sizeof(u), 1, out);
263 /* Second word is reserved for the offset of the root node */
264 initial_offset = ftell(out);
265 u = 0;
266 fwrite(&u, sizeof(uint32_t), 1, out);
268 /* Dump trie */
269 u = htonl(index_write__node(node, out));
271 /* Update first word */
272 final_offset = ftell(out);
273 fseek(out, initial_offset, SEEK_SET);
274 fwrite(&u, sizeof(uint32_t), 1, out);
275 fseek(out, final_offset, SEEK_SET);
280 static void read_error()
282 fatal("Module index: unexpected error: %s\n"
283 "Try re-running depmod\n", errno ? strerror(errno) : "EOF");
286 static int read_char(FILE *in)
288 int ch;
290 errno = 0;
291 ch = getc_unlocked(in);
292 if (ch == EOF)
293 read_error();
294 return ch;
297 static uint32_t read_long(FILE *in)
299 uint32_t l;
301 errno = 0;
302 if (fread(&l, sizeof(uint32_t), 1, in) <= 0)
303 read_error();
304 return ntohl(l);
308 * Buffer abstract data type
310 * Used internally to store the current path during tree traversal.
311 * They help build wildcard key strings to pass to fnmatch(),
312 * as well as building values of matching keys.
315 struct buffer {
316 char *bytes;
317 unsigned size;
318 unsigned used;
321 static void buf__realloc(struct buffer *buf, unsigned size)
323 if (size > buf->size) {
324 buf->bytes = NOFAIL(realloc(buf->bytes, size));
325 buf->size = size;
329 static struct buffer *buf_create()
331 struct buffer *buf;
333 buf = NOFAIL(calloc(sizeof(struct buffer), 1));
334 buf__realloc(buf, 256);
335 return buf;
338 static void buf_destroy(struct buffer *buf)
340 free(buf->bytes);
341 free(buf);
344 /* Destroy buffer and return a copy as a C string */
345 static char *buf_detach(struct buffer *buf)
347 char *bytes;
349 bytes = NOFAIL(realloc(buf->bytes, buf->used + 1));
350 bytes[buf->used] = '\0';
352 free(buf);
353 return bytes;
356 /* Return a C string owned by the buffer
357 (invalidated if the buffer is changed).
359 static const char *buf_str(struct buffer *buf)
361 buf__realloc(buf, buf->used + 1);
362 buf->bytes[buf->used] = '\0';
363 return buf->bytes;
366 static int buf_fwrite(struct buffer *buf, FILE *out)
368 return fwrite(buf->bytes, 1, buf->used, out);
371 static void buf_pushchar(struct buffer *buf, char ch)
373 buf__realloc(buf, buf->used + 1);
374 buf->bytes[buf->used] = ch;
375 buf->used++;
378 static unsigned buf_pushchars(struct buffer *buf, const char *str)
380 unsigned i = 0;
381 int ch;
383 while ((ch = str[i])) {
384 buf_pushchar(buf, ch);
385 i++;
387 return i;
390 /* like buf_pushchars(), but the string comes from a file */
391 static unsigned buf_freadchars(struct buffer *buf, FILE *in)
393 unsigned i = 0;
394 int ch;
396 while ((ch = read_char(in))) {
397 buf_pushchar(buf, ch);
398 i++;
401 return i;
404 static void buf_popchar(struct buffer *buf)
406 buf->used--;
409 static void buf_popchars(struct buffer *buf, unsigned n)
411 buf->used -= n;
414 static void buf_clear(struct buffer *buf)
416 buf->used = 0;
420 * Index file searching (used only by modprobe)
423 struct index_node_f {
424 FILE *file;
425 char *prefix; /* path compression */
426 struct index_value *values;
427 unsigned char first; /* range of child nodes */
428 unsigned char last;
429 uint32_t children[0];
432 static struct index_node_f *index_read(FILE *in, uint32_t offset)
434 struct index_node_f *node;
435 char *prefix;
436 int i, child_count = 0;
438 if ((offset & INDEX_NODE_MASK) == 0)
439 return NULL;
441 fseek(in, offset & INDEX_NODE_MASK, SEEK_SET);
443 if (offset & INDEX_NODE_PREFIX) {
444 struct buffer *buf = buf_create();
445 buf_freadchars(buf, in);
446 prefix = buf_detach(buf);
447 } else
448 prefix = NOFAIL(strdup(""));
450 if (offset & INDEX_NODE_CHILDS) {
451 char first = read_char(in);
452 char last = read_char(in);
453 child_count = last - first + 1;
455 node = NOFAIL(malloc(sizeof(struct index_node_f) +
456 sizeof(uint32_t) * child_count));
458 node->first = first;
459 node->last = last;
461 for (i = 0; i < child_count; i++)
462 node->children[i] = read_long(in);
463 } else {
464 node = NOFAIL(malloc(sizeof(struct index_node_f)));
465 node->first = INDEX_CHILDMAX;
466 node->last = 0;
469 node->values = NULL;
470 if (offset & INDEX_NODE_VALUES) {
471 int value_count;
472 struct buffer *buf = buf_create();
473 const char *value;
474 unsigned int priority;
476 value_count = read_long(in);
478 while (value_count--) {
479 priority = read_long(in);
480 buf_freadchars(buf, in);
481 value = buf_str(buf);
482 add_value(&node->values, value, priority);
483 buf_clear(buf);
485 buf_destroy(buf);
488 node->prefix = prefix;
489 node->file = in;
490 return node;
493 static void index_close(struct index_node_f *node)
495 free(node->prefix);
496 index_values_free(node->values);
497 free(node);
500 struct index_file {
501 FILE *file;
502 uint32_t root_offset;
505 /* Failures are silent; modprobe will fall back to text files */
506 struct index_file *index_file_open(const char *filename)
508 FILE *file;
509 uint32_t magic, version;
510 struct index_file *new;
512 file = fopen(filename, "r");
513 if (!file)
514 return NULL;
515 errno = EINVAL;
517 magic = read_long(file);
518 if (magic != INDEX_MAGIC)
519 return NULL;
521 version = read_long(file);
522 if (version >> 16 != INDEX_VERSION_MAJOR)
523 return NULL;
525 new = NOFAIL(malloc(sizeof(struct index_file)));
526 new->file = file;
527 new->root_offset = read_long(new->file);
529 errno = 0;
530 return new;
533 void index_file_close(struct index_file *index)
535 fclose(index->file);
536 free(index);
540 static struct index_node_f *index_readroot(struct index_file *in)
542 return index_read(in->file, in->root_offset);
545 static struct index_node_f *index_readchild(const struct index_node_f *parent,
546 int ch)
548 if (parent->first <= ch && ch <= parent->last)
549 return index_read(parent->file,
550 parent->children[ch - parent->first]);
551 else
552 return NULL;
556 * Dump all strings as lines in a plain text file.
559 static void index_dump_node(struct index_node_f *node,
560 struct buffer *buf,
561 FILE *out,
562 const char *prefix)
564 struct index_value *v;
565 int ch, pushed;
567 pushed = buf_pushchars(buf, node->prefix);
569 for (v = node->values; v != NULL; v = v->next) {
570 fputs(prefix, out);
571 buf_fwrite(buf, out);
572 fputc(' ', out);
573 fputs(v->value, out);
574 fputc('\n', out);
577 for (ch = node->first; ch <= node->last; ch++) {
578 struct index_node_f *child = index_readchild(node, ch);
580 if (!child)
581 continue;
583 buf_pushchar(buf, ch);
584 index_dump_node(child, buf, out, prefix);
585 buf_popchar(buf);
588 buf_popchars(buf, pushed);
589 index_close(node);
592 void index_dump(struct index_file *in, FILE *out, const char *prefix)
594 struct index_node_f *root;
595 struct buffer *buf;
597 buf = buf_create();
598 root = index_readroot(in);
599 index_dump_node(root, buf, out, prefix);
600 buf_destroy(buf);
604 * Search the index for a key
606 * Returns the value of the first match
608 * The recursive functions free their node argument (using index_close).
611 char *index_search(struct index_file *in, const char *key);
612 static char *index_search__node(struct index_node_f *node, const char *key, int i);
614 char *index_search(struct index_file *in, const char *key)
616 struct index_node_f *root;
617 char *value;
619 root = index_readroot(in);
620 value = index_search__node(root, key, 0);
622 return value;
625 static char *index_search__node(struct index_node_f *node, const char *key, int i)
627 struct index_node_f *child;
628 int ch;
629 int j;
631 while(node) {
632 for (j = 0; node->prefix[j]; j++) {
633 ch = node->prefix[j];
635 if (ch != key[i+j]) {
636 index_close(node);
637 return NULL;
640 i += j;
642 if (key[i] == '\0') {
643 if (node->values)
644 return strdup(node->values[0].value);
645 else
646 return NULL;
649 child = index_readchild(node, key[i]);
650 index_close(node);
651 node = child;
652 i++;
655 return NULL;
659 * Search the index for a key. The index may contain wildcards.
661 * Returns a list of all the values of matching keys.
664 /* Level 1: interface function */
665 struct index_value *index_searchwild(struct index_file *in, const char *key);
667 /* Level 2: descend the tree (until we hit a wildcard) */
668 static void index_searchwild__node(struct index_node_f *node,
669 struct buffer *buf,
670 const char *key, int i,
671 struct index_value **out);
673 /* Level 3: traverse a sub-keyspace which starts with a wildcard,
674 looking for matches.
676 static void index_searchwild__all(struct index_node_f *node, int j,
677 struct buffer *buf,
678 const char *subkey,
679 struct index_value **out);
681 /* Level 4: add all the values from a matching node */
682 static void index_searchwild__allvalues(struct index_node_f *node,
683 struct index_value **out);
686 struct index_value *index_searchwild(struct index_file *in, const char *key)
688 struct index_node_f *root = index_readroot(in);
689 struct buffer *buf = buf_create();
690 struct index_value *out = NULL;
692 index_searchwild__node(root, buf, key, 0, &out);
693 buf_destroy(buf);
694 return out;
697 static void index_searchwild__node(struct index_node_f *node,
698 struct buffer *buf,
699 const char *key, int i,
700 struct index_value **out)
702 struct index_node_f *child;
703 int j;
704 int ch;
706 while(node) {
707 for (j = 0; node->prefix[j]; j++) {
708 ch = node->prefix[j];
710 if (ch == '*' || ch == '?' || ch == '[') {
711 index_searchwild__all(node, j, buf,
712 &key[i+j], out);
713 return;
716 if (ch != key[i+j]) {
717 index_close(node);
718 return;
721 i += j;
723 child = index_readchild(node, '*');
724 if (child) {
725 buf_pushchar(buf, '*');
726 index_searchwild__all(child, 0, buf, &key[i], out);
727 buf_popchar(buf);
730 child = index_readchild(node, '?');
731 if (child) {
732 buf_pushchar(buf, '?');
733 index_searchwild__all(child, 0, buf, &key[i], out);
734 buf_popchar(buf);
737 child = index_readchild(node, '[');
738 if (child) {
739 buf_pushchar(buf, '[');
740 index_searchwild__all(child, 0, buf, &key[i], out);
741 buf_popchar(buf);
744 if (key[i] == '\0') {
745 index_searchwild__allvalues(node, out);
747 return;
750 child = index_readchild(node, key[i]);
751 index_close(node);
752 node = child;
753 i++;
757 static void index_searchwild__all(struct index_node_f *node, int j,
758 struct buffer *buf,
759 const char *subkey,
760 struct index_value **out)
762 int pushed = 0;
763 int ch;
765 while (node->prefix[j]) {
766 ch = node->prefix[j];
768 buf_pushchar(buf, ch);
769 pushed++;
770 j++;
773 for (ch = node->first; ch <= node->last; ch++) {
774 struct index_node_f *child = index_readchild(node, ch);
776 if (!child)
777 continue;
779 buf_pushchar(buf, ch);
780 index_searchwild__all(child, 0, buf, subkey, out);
781 buf_popchar(buf);
784 if (node->values) {
785 if (fnmatch(buf_str(buf), subkey, 0) == 0)
786 index_searchwild__allvalues(node, out);
789 index_close(node);
790 buf_popchars(buf, pushed);
793 static void index_searchwild__allvalues(struct index_node_f *node,
794 struct index_value **out)
796 struct index_value *v;
798 for (v = node->values; v != NULL; v = v->next)
799 add_value(out, v->value, v->priority);