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 */
30 #define streq(a,b) (strcmp((a),(b)) == 0)
33 * Index abstract data type (used only by depmod)
36 struct index_node
*index_create()
38 struct index_node
*node
;
40 node
= NOFAIL(calloc(sizeof(struct index_node
), 1));
41 node
->prefix
= NOFAIL(strdup(""));
42 node
->first
= INDEX_CHILDMAX
;
47 void index_values_free(struct index_value
*values
)
50 struct index_value
*value
= values
;
57 void index_destroy(struct index_node
*node
)
61 for (c
= node
->first
; c
<= node
->last
; c
++) {
62 struct index_node
*child
= node
->children
[c
];
67 index_values_free(node
->values
);
72 static void index__checkstring(const char *str
)
76 for (i
= 0; str
[i
]; i
++) {
79 if (ch
>= INDEX_CHILDMAX
)
80 fatal("Module index: bad character '%c'=0x%x - only 7-bit ASCII is supported:"
81 "\n%s\n", (char) ch
, (int) ch
, str
);
85 static int add_value(struct index_value
**values
,
86 const char *value
, unsigned int priority
)
88 struct index_value
*v
;
92 /* report the presence of duplicate values */
93 for (v
= *values
; v
; v
= v
->next
) {
94 if (streq(v
->value
, value
))
98 /* find position to insert value */
99 while (*values
&& (*values
)->priority
< priority
)
100 values
= &(*values
)->next
;
103 v
= NOFAIL(calloc(sizeof(struct index_value
) + len
+ 1, 1));
105 v
->priority
= priority
;
106 memcpy(v
->value
, value
, len
+ 1);
112 int index_insert(struct index_node
*node
, const char *key
,
113 const char *value
, unsigned int priority
)
115 int i
= 0; /* index within str */
118 index__checkstring(key
);
119 index__checkstring(value
);
122 int j
; /* index within node->prefix */
124 /* Ensure node->prefix is a prefix of &str[i].
125 If it is not already, then we must split node. */
126 for (j
= 0; node
->prefix
[j
]; j
++) {
127 ch
= node
->prefix
[j
];
129 if (ch
!= key
[i
+j
]) {
130 char *prefix
= node
->prefix
;
131 struct index_node
*n
;
133 /* New child is copy of node with prefix[j+1..N] */
134 n
= NOFAIL(calloc(sizeof(struct index_node
), 1));
135 memcpy(n
, node
, sizeof(struct index_node
));
136 n
->prefix
= NOFAIL(strdup(&prefix
[j
+1]));
138 /* Parent has prefix[0..j], child at prefix[j] */
139 memset(node
, 0, sizeof(struct index_node
));
141 node
->prefix
= prefix
;
144 node
->children
[ch
] = n
;
149 /* j is now length of node->prefix */
154 return add_value(&node
->values
, value
, priority
);
156 if (!node
->children
[ch
]) {
157 struct index_node
*child
;
159 if (ch
< node
->first
)
163 node
->children
[ch
] = NOFAIL(calloc(sizeof(struct index_node
), 1));
165 child
= node
->children
[ch
];
166 child
->prefix
= NOFAIL(strdup(&key
[i
+1]));
167 child
->first
= INDEX_CHILDMAX
;
168 add_value(&child
->values
, value
, priority
);
173 /* Descend into child node and continue */
174 node
= node
->children
[ch
];
179 static int index__haschildren(const struct index_node
*node
)
181 return node
->first
< INDEX_CHILDMAX
;
184 /* Recursive post-order traversal
186 Pre-order would make for better read-side buffering / readahead / caching.
187 (post-order means you go backwards in the file as you descend the tree).
188 However, index reading is already fast enough.
189 Pre-order is simpler for writing, and depmod is already slow.
191 static uint32_t index_write__node(const struct index_node
*node
, FILE *out
)
193 uint32_t *child_offs
= NULL
;
200 /* Write children and save their offsets */
201 if (index__haschildren(node
)) {
202 const struct index_node
*child
;
205 child_count
= node
->last
- node
->first
+ 1;
206 child_offs
= NOFAIL(malloc(child_count
* sizeof(uint32_t)));
208 for (i
= 0; i
< child_count
; i
++) {
209 child
= node
->children
[node
->first
+ i
];
210 child_offs
[i
] = htonl(index_write__node(child
, out
));
214 /* Now write this node */
217 if (node
->prefix
[0]) {
218 fputs(node
->prefix
, out
);
220 offset
|= INDEX_NODE_PREFIX
;
224 fputc(node
->first
, out
);
225 fputc(node
->last
, out
);
226 fwrite(child_offs
, sizeof(uint32_t), child_count
, out
);
228 offset
|= INDEX_NODE_CHILDS
;
232 const struct index_value
*v
;
233 unsigned int value_count
;
237 for (v
= node
->values
; v
!= NULL
; v
= v
->next
)
239 u
= htonl(value_count
);
240 fwrite(&u
, sizeof(u
), 1, out
);
242 for (v
= node
->values
; v
!= NULL
; v
= v
->next
) {
243 u
= htonl(v
->priority
);
244 fwrite(&u
, sizeof(u
), 1, out
);
245 fputs(v
->value
, out
);
248 offset
|= INDEX_NODE_VALUES
;
254 void index_write(const struct index_node
*node
, FILE *out
)
256 long initial_offset
, final_offset
;
259 u
= htonl(INDEX_MAGIC
);
260 fwrite(&u
, sizeof(u
), 1, out
);
261 u
= htonl(INDEX_VERSION
);
262 fwrite(&u
, sizeof(u
), 1, out
);
264 /* Second word is reserved for the offset of the root node */
265 initial_offset
= ftell(out
);
267 fwrite(&u
, sizeof(uint32_t), 1, out
);
270 u
= htonl(index_write__node(node
, out
));
272 /* Update first word */
273 final_offset
= ftell(out
);
274 fseek(out
, initial_offset
, SEEK_SET
);
275 fwrite(&u
, sizeof(uint32_t), 1, out
);
276 fseek(out
, final_offset
, SEEK_SET
);
281 static void read_error()
283 fatal("Module index: unexpected error: %s\n"
284 "Try re-running depmod\n", errno
? strerror(errno
) : "EOF");
287 static int read_char(FILE *in
)
292 ch
= getc_unlocked(in
);
298 static uint32_t read_long(FILE *in
)
303 if (fread(&l
, sizeof(uint32_t), 1, in
) <= 0)
309 * Buffer abstract data type
311 * Used internally to store the current path during tree traversal.
312 * They help build wildcard key strings to pass to fnmatch(),
313 * as well as building values of matching keys.
322 static void buf__realloc(struct buffer
*buf
, unsigned size
)
324 if (size
> buf
->size
) {
325 buf
->bytes
= NOFAIL(realloc(buf
->bytes
, size
));
330 static struct buffer
*buf_create()
334 buf
= NOFAIL(calloc(sizeof(struct buffer
), 1));
335 buf__realloc(buf
, 256);
339 static void buf_destroy(struct buffer
*buf
)
345 /* Destroy buffer and return a copy as a C string */
346 static char *buf_detach(struct buffer
*buf
)
350 bytes
= NOFAIL(realloc(buf
->bytes
, buf
->used
+ 1));
351 bytes
[buf
->used
] = '\0';
357 /* Return a C string owned by the buffer
358 (invalidated if the buffer is changed).
360 static const char *buf_str(struct buffer
*buf
)
362 buf__realloc(buf
, buf
->used
+ 1);
363 buf
->bytes
[buf
->used
] = '\0';
367 static int buf_fwrite(struct buffer
*buf
, FILE *out
)
369 return fwrite(buf
->bytes
, 1, buf
->used
, out
);
372 static void buf_pushchar(struct buffer
*buf
, char ch
)
374 buf__realloc(buf
, buf
->used
+ 1);
375 buf
->bytes
[buf
->used
] = ch
;
379 static unsigned buf_pushchars(struct buffer
*buf
, const char *str
)
384 while ((ch
= str
[i
])) {
385 buf_pushchar(buf
, ch
);
391 /* like buf_pushchars(), but the string comes from a file */
392 static unsigned buf_freadchars(struct buffer
*buf
, FILE *in
)
397 while ((ch
= read_char(in
))) {
398 buf_pushchar(buf
, ch
);
405 static void buf_popchar(struct buffer
*buf
)
410 static void buf_popchars(struct buffer
*buf
, unsigned n
)
415 static void buf_clear(struct buffer
*buf
)
421 * Index file searching (used only by modprobe)
424 struct index_node_f
{
426 char *prefix
; /* path compression */
427 struct index_value
*values
;
428 unsigned char first
; /* range of child nodes */
430 uint32_t children
[0];
433 static struct index_node_f
*index_read(FILE *in
, uint32_t offset
)
435 struct index_node_f
*node
;
437 int i
, child_count
= 0;
439 if ((offset
& INDEX_NODE_MASK
) == 0)
442 fseek(in
, offset
& INDEX_NODE_MASK
, SEEK_SET
);
444 if (offset
& INDEX_NODE_PREFIX
) {
445 struct buffer
*buf
= buf_create();
446 buf_freadchars(buf
, in
);
447 prefix
= buf_detach(buf
);
449 prefix
= NOFAIL(strdup(""));
451 if (offset
& INDEX_NODE_CHILDS
) {
452 char first
= read_char(in
);
453 char last
= read_char(in
);
454 child_count
= last
- first
+ 1;
456 node
= NOFAIL(malloc(sizeof(struct index_node_f
) +
457 sizeof(uint32_t) * child_count
));
462 for (i
= 0; i
< child_count
; i
++)
463 node
->children
[i
] = read_long(in
);
465 node
= NOFAIL(malloc(sizeof(struct index_node_f
)));
466 node
->first
= INDEX_CHILDMAX
;
471 if (offset
& INDEX_NODE_VALUES
) {
473 struct buffer
*buf
= buf_create();
475 unsigned int priority
;
477 value_count
= read_long(in
);
479 while (value_count
--) {
480 priority
= read_long(in
);
481 buf_freadchars(buf
, in
);
482 value
= buf_str(buf
);
483 add_value(&node
->values
, value
, priority
);
489 node
->prefix
= prefix
;
494 static void index_close(struct index_node_f
*node
)
497 index_values_free(node
->values
);
503 uint32_t root_offset
;
506 /* Failures are silent; modprobe will fall back to text files */
507 struct index_file
*index_file_open(const char *filename
)
510 uint32_t magic
, version
;
511 struct index_file
*new;
513 file
= fopen(filename
, "r");
518 magic
= read_long(file
);
519 if (magic
!= INDEX_MAGIC
)
522 version
= read_long(file
);
523 if (version
>> 16 != INDEX_VERSION_MAJOR
)
526 new = NOFAIL(malloc(sizeof(struct index_file
)));
528 new->root_offset
= read_long(new->file
);
534 void index_file_close(struct index_file
*index
)
541 static struct index_node_f
*index_readroot(struct index_file
*in
)
543 return index_read(in
->file
, in
->root_offset
);
546 static struct index_node_f
*index_readchild(const struct index_node_f
*parent
,
549 if (parent
->first
<= ch
&& ch
<= parent
->last
)
550 return index_read(parent
->file
,
551 parent
->children
[ch
- parent
->first
]);
557 * Dump all strings as lines in a plain text file.
560 static void index_dump_node(struct index_node_f
*node
,
565 struct index_value
*v
;
568 pushed
= buf_pushchars(buf
, node
->prefix
);
570 for (v
= node
->values
; v
!= NULL
; v
= v
->next
) {
572 buf_fwrite(buf
, out
);
574 fputs(v
->value
, out
);
578 for (ch
= node
->first
; ch
<= node
->last
; ch
++) {
579 struct index_node_f
*child
= index_readchild(node
, ch
);
584 buf_pushchar(buf
, ch
);
585 index_dump_node(child
, buf
, out
, prefix
);
589 buf_popchars(buf
, pushed
);
593 void index_dump(struct index_file
*in
, FILE *out
, const char *prefix
)
595 struct index_node_f
*root
;
599 root
= index_readroot(in
);
600 index_dump_node(root
, buf
, out
, prefix
);
605 * Search the index for a key
607 * Returns the value of the first match
609 * The recursive functions free their node argument (using index_close).
612 char *index_search(struct index_file
*in
, const char *key
);
613 static char *index_search__node(struct index_node_f
*node
, const char *key
, int i
);
615 char *index_search(struct index_file
*in
, const char *key
)
617 struct index_node_f
*root
;
620 root
= index_readroot(in
);
621 value
= index_search__node(root
, key
, 0);
626 static char *index_search__node(struct index_node_f
*node
, const char *key
, int i
)
628 struct index_node_f
*child
;
633 for (j
= 0; node
->prefix
[j
]; j
++) {
634 ch
= node
->prefix
[j
];
636 if (ch
!= key
[i
+j
]) {
643 if (key
[i
] == '\0') {
645 return strdup(node
->values
[0].value
);
650 child
= index_readchild(node
, key
[i
]);
660 * Search the index for a key. The index may contain wildcards.
662 * Returns a list of all the values of matching keys.
665 /* Level 1: interface function */
666 struct index_value
*index_searchwild(struct index_file
*in
, const char *key
);
668 /* Level 2: descend the tree (until we hit a wildcard) */
669 static void index_searchwild__node(struct index_node_f
*node
,
671 const char *key
, int i
,
672 struct index_value
**out
);
674 /* Level 3: traverse a sub-keyspace which starts with a wildcard,
677 static void index_searchwild__all(struct index_node_f
*node
, int j
,
680 struct index_value
**out
);
682 /* Level 4: add all the values from a matching node */
683 static void index_searchwild__allvalues(struct index_node_f
*node
,
684 struct index_value
**out
);
687 struct index_value
*index_searchwild(struct index_file
*in
, const char *key
)
689 struct index_node_f
*root
= index_readroot(in
);
690 struct buffer
*buf
= buf_create();
691 struct index_value
*out
= NULL
;
693 index_searchwild__node(root
, buf
, key
, 0, &out
);
698 static void index_searchwild__node(struct index_node_f
*node
,
700 const char *key
, int i
,
701 struct index_value
**out
)
703 struct index_node_f
*child
;
708 for (j
= 0; node
->prefix
[j
]; j
++) {
709 ch
= node
->prefix
[j
];
711 if (ch
== '*' || ch
== '?' || ch
== '[') {
712 index_searchwild__all(node
, j
, buf
,
717 if (ch
!= key
[i
+j
]) {
724 child
= index_readchild(node
, '*');
726 buf_pushchar(buf
, '*');
727 index_searchwild__all(child
, 0, buf
, &key
[i
], out
);
731 child
= index_readchild(node
, '?');
733 buf_pushchar(buf
, '?');
734 index_searchwild__all(child
, 0, buf
, &key
[i
], out
);
738 child
= index_readchild(node
, '[');
740 buf_pushchar(buf
, '[');
741 index_searchwild__all(child
, 0, buf
, &key
[i
], out
);
745 if (key
[i
] == '\0') {
746 index_searchwild__allvalues(node
, out
);
751 child
= index_readchild(node
, key
[i
]);
758 static void index_searchwild__all(struct index_node_f
*node
, int j
,
761 struct index_value
**out
)
766 while (node
->prefix
[j
]) {
767 ch
= node
->prefix
[j
];
769 buf_pushchar(buf
, ch
);
774 for (ch
= node
->first
; ch
<= node
->last
; ch
++) {
775 struct index_node_f
*child
= index_readchild(node
, ch
);
780 buf_pushchar(buf
, ch
);
781 index_searchwild__all(child
, 0, buf
, subkey
, out
);
786 if (fnmatch(buf_str(buf
), subkey
, 0) == 0)
787 index_searchwild__allvalues(node
, out
);
791 buf_popchars(buf
, pushed
);
794 static void index_searchwild__allvalues(struct index_node_f
*node
,
795 struct index_value
**out
)
797 struct index_value
*v
;
799 for (v
= node
->values
; v
!= NULL
; v
= v
->next
)
800 add_value(out
, v
->value
, v
->priority
);