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/>.
28 * Index abstract data type (used only by depmod)
31 struct index_node
*index_create()
33 struct index_node
*node
;
35 node
= NOFAIL(calloc(sizeof(struct index_node
), 1));
36 node
->prefix
= NOFAIL(strdup(""));
37 node
->first
= INDEX_CHILDMAX
;
42 void index_destroy(struct index_node
*node
)
46 for (c
= node
->first
; c
<= node
->last
; c
++) {
47 struct index_node
*child
= node
->children
[c
];
56 static void index__checkstring(const char *str
)
61 for (i
= 0; str
[i
]; i
++) {
64 if (ch
>= INDEX_CHILDMAX
)
65 fatal("Module index: bad character '%c'=0x%x - only 7-bit ASCII is supported:"
66 "\n%s\n", (char) ch
, (int) ch
, str
);
73 fatal("Module index: internal error - missing space (key/value separator)"
77 int index_insert(struct index_node
*node
, const char *str
)
79 int i
= 0; /* index within str */
83 index__checkstring(str
);
86 int j
; /* index within node->prefix */
88 /* Ensure node->prefix is a prefix of &str[i].
89 If it is not already, then we must split node. */
90 for (j
= 0; node
->prefix
[j
]; j
++) {
94 char *prefix
= node
->prefix
;
97 /* New child is copy of node with prefix[j+1..N] */
98 n
= NOFAIL(calloc(sizeof(struct index_node
), 1));
99 memcpy(n
, node
, sizeof(struct index_node
));
100 n
->prefix
= NOFAIL(strdup(&prefix
[j
+1]));
102 /* Parent has prefix[0..j], child at prefix[j] */
103 memset(node
, 0, sizeof(struct index_node
));
105 node
->prefix
= prefix
;
108 node
->children
[ch
] = n
;
113 /* j is now length of node->prefix */
118 if (node
->isendpoint
)
121 node
->isendpoint
= 1;
125 if (!node
->children
[ch
]) {
126 struct index_node
*child
;
128 if (ch
< node
->first
)
132 node
->children
[ch
] = NOFAIL(calloc(sizeof(struct index_node
), 1));
134 child
= node
->children
[ch
];
135 child
->prefix
= NOFAIL(strdup(&str
[i
+1]));
136 child
->isendpoint
= 1;
137 child
->first
= INDEX_CHILDMAX
;
142 /* Descend into child node and continue */
143 node
= node
->children
[ch
];
148 static int index__haschildren(const struct index_node
*node
)
150 return node
->first
< INDEX_CHILDMAX
;
153 /* Recursive post-order traversal
155 Pre-order would make for better read-side buffering / readahead / caching.
156 (post-order means you go backwards in the file as you descend the tree).
157 However, index reading is already fast enough.
158 Pre-order is simpler for writing, and depmod is already slow.
160 static uint32_t index_write__node(const struct index_node
*node
, FILE *out
)
162 uint32_t *child_offs
= NULL
;
169 /* Write children and save their offsets */
170 if (index__haschildren(node
)) {
171 const struct index_node
*child
;
174 child_count
= node
->last
- node
->first
+ 1;
175 child_offs
= NOFAIL(malloc(child_count
* sizeof(uint32_t)));
177 for (i
= 0; i
< child_count
; i
++) {
178 child
= node
->children
[node
->first
+ i
];
179 child_offs
[i
] = htonl(index_write__node(child
, out
));
183 /* Now write this node */
186 if (node
->prefix
[0]) {
187 fputs(node
->prefix
, out
);
189 offset
|= INDEX_NODE_PREFIX
;
193 fputc(node
->first
, out
);
194 fputc(node
->last
, out
);
195 fwrite(child_offs
, sizeof(uint32_t), child_count
, out
);
197 offset
|= INDEX_NODE_CHILDS
;
200 if (node
->isendpoint
)
201 offset
|= INDEX_NODE_ENDPOINT
;
206 void index_write(const struct index_node
*node
, FILE *out
)
208 long initial_offset
, final_offset
;
211 u
= htonl(INDEX_MAGIC
);
212 fwrite(&u
, sizeof(u
), 1, out
);
214 /* First word is reserved for the offset of the root node */
215 initial_offset
= ftell(out
);
217 fwrite(&u
, sizeof(uint32_t), 1, out
);
220 u
= htonl(index_write__node(node
, out
));
222 /* Update first word */
223 final_offset
= ftell(out
);
224 fseek(out
, initial_offset
, SEEK_SET
);
225 fwrite(&u
, sizeof(uint32_t), 1, out
);
226 fseek(out
, final_offset
, SEEK_SET
);
231 static void read_error()
233 fatal("Module index: unexpected error: %s\n"
234 "Try re-running depmod\n", errno
? strerror(errno
) : "EOF");
237 static int read_char(FILE *in
)
242 ch
= getc_unlocked(in
);
248 static uint32_t read_long(FILE *in
)
253 if (fread(&l
, sizeof(uint32_t), 1, in
) <= 0)
259 * Buffer abstract data type
261 * Used internally to store the current path during tree traversal.
262 * They help build wildcard key strings to pass to fnmatch(),
263 * as well as building values of matching keys.
272 static void buf__realloc(struct buffer
*buf
, unsigned size
)
274 if (size
> buf
->size
) {
275 buf
->bytes
= NOFAIL(realloc(buf
->bytes
, size
));
280 static struct buffer
*buf_create()
284 buf
= NOFAIL(calloc(sizeof(struct buffer
), 1));
285 buf__realloc(buf
, 256);
289 static void buf_destroy(struct buffer
*buf
)
295 /* Destroy buffer and return a copy as a C string */
296 static char *buf_detach(struct buffer
*buf
)
300 bytes
= NOFAIL(realloc(buf
->bytes
, buf
->used
+ 1));
301 bytes
[buf
->used
] = '\0';
307 /* Return a C string owned by the buffer
308 (invalidated if the buffer is changed).
310 static const char *buf_str(struct buffer
*buf
)
312 buf__realloc(buf
, buf
->used
+ 1);
313 buf
->bytes
[buf
->used
] = '\0';
317 static int buf_fwrite(struct buffer
*buf
, FILE *out
)
319 return fwrite(buf
->bytes
, 1, buf
->used
, out
);
322 static struct index_value
*add_value(struct buffer
*buf
,
323 struct index_value
*values
)
325 struct index_value
*n
= malloc(sizeof(struct index_value
) + buf
->used
+ 1);
327 memcpy(n
->value
, buf
->bytes
, buf
->used
);
328 n
->value
[buf
->used
] = '\0';
334 static void buf_popchars(struct buffer
*buf
, unsigned n
)
339 static void buf_pushchar(struct buffer
*buf
, char ch
)
341 buf__realloc(buf
, buf
->used
+ 1);
342 buf
->bytes
[buf
->used
] = ch
;
346 static unsigned buf_pushchars(struct buffer
*buf
, const char *str
)
351 while ((ch
= str
[i
])) {
352 buf_pushchar(buf
, ch
);
358 /* like buf_pushchars(), but the string comes from a file */
359 static unsigned buf_freadchars(struct buffer
*buf
, FILE *in
)
364 while ((ch
= read_char(in
))) {
365 buf_pushchar(buf
, ch
);
372 static void buf_popchar(struct buffer
*buf
)
378 * Index file searching (used only by modprobe)
381 struct index_node_f
{
383 char *prefix
; /* path compression */
384 char isendpoint
; /* does this node represent a string? */
385 unsigned char first
; /* range of child nodes */
387 uint32_t children
[0];
390 static void index_fatal(const char *why
)
392 fatal("Module index corrupt: %s\n"
393 "Try re-running depmod\n", why
);
396 static struct index_node_f
*index_read(FILE *in
, uint32_t offset
)
398 struct index_node_f
*node
;
400 int i
, child_count
= 0;
402 if ((offset
& INDEX_NODE_MASK
) == 0)
405 fseek(in
, offset
& INDEX_NODE_MASK
, SEEK_SET
);
407 if (offset
& INDEX_NODE_PREFIX
) {
408 struct buffer
*buf
= buf_create();
409 buf_freadchars(buf
, in
);
410 prefix
= buf_detach(buf
);
412 prefix
= NOFAIL(strdup(""));
414 if (offset
& INDEX_NODE_CHILDS
) {
415 char first
= read_char(in
);
416 char last
= read_char(in
);
417 child_count
= last
- first
+ 1;
419 node
= NOFAIL(malloc(sizeof(struct index_node_f
) +
420 sizeof(uint32_t) * child_count
));
425 for (i
= 0; i
< child_count
; i
++)
426 node
->children
[i
] = read_long(in
);
428 node
= NOFAIL(malloc(sizeof(struct index_node_f
)));
429 node
->first
= INDEX_CHILDMAX
;
433 node
->prefix
= prefix
;
434 node
->isendpoint
= !!(offset
& INDEX_NODE_ENDPOINT
);
439 static void index_close(struct index_node_f
*node
)
445 static struct index_node_f
*index_readchild(const struct index_node_f
*parent
,
448 if (parent
->first
<= ch
&& ch
<= parent
->last
)
449 return index_read(parent
->file
,
450 parent
->children
[ch
- parent
->first
]);
455 static struct index_node_f
*index_readroot(FILE *in
)
459 fseek(in
, 0, SEEK_SET
);
461 if (read_long(in
) != INDEX_MAGIC
)
462 index_fatal("Bad magic number");
464 offset
= read_long(in
);
465 return index_read(in
, offset
);
469 * Dump all strings as lines in a plain text file.
472 static void index_dump_node(struct index_node_f
*node
,
479 pushed
= buf_pushchars(buf
, node
->prefix
);
481 if (node
->isendpoint
) {
483 buf_fwrite(buf
, out
);
487 for (ch
= node
->first
; ch
<= node
->last
; ch
++) {
488 struct index_node_f
*child
= index_readchild(node
, ch
);
493 buf_pushchar(buf
, ch
);
494 index_dump_node(child
, buf
, out
, prefix
);
498 buf_popchars(buf
, pushed
);
502 void index_dump(FILE *in
, FILE *out
, const char *prefix
)
504 struct index_node_f
*root
;
508 root
= index_readroot(in
);
509 index_dump_node(root
, buf
, out
, prefix
);
514 * Search the index for a key
516 * Returns the value of the first match
518 * The calling convention for the inner functions
519 * is for the callee to free the node argument (using index_close).
522 /* Level 1: interface function */
523 char *index_search(FILE *in
, const char *key
);
525 /* Level 2: descend the tree */
526 static char *index_search__node(struct index_node_f
*node
, const char *key
, int i
);
528 /* Level 3: return the first value in the subtree.
529 The first character of the value is node->prefix[j] */
530 static char *index_search__firstvalue(struct index_node_f
*node
, int j
);
532 char *index_search(FILE *in
, const char *key
)
534 struct index_node_f
*root
;
537 root
= index_readroot(in
);
538 value
= index_search__node(root
, key
, 0);
543 static char *index_search__node(struct index_node_f
*node
, const char *key
, int i
)
545 struct index_node_f
*child
;
550 for (j
= 0; node
->prefix
[j
]; j
++) {
551 ch
= node
->prefix
[j
];
553 if (ch
== ' ' && key
[i
+j
] == '\0')
554 return index_search__firstvalue(node
, j
+1);
556 if (ch
!= key
[i
+j
]) {
563 if (key
[i
] == '\0') {
564 child
= index_readchild(node
, ' ');
567 return index_search__firstvalue(child
, 0);
572 child
= index_readchild(node
, key
[i
]);
581 static char *index_search__firstvalue(struct index_node_f
*node
, int j
)
583 struct index_node_f
*child
;
587 buf_pushchars(buf
, &node
->prefix
[j
]);
589 while (!node
->isendpoint
) {
590 if (node
->first
== INDEX_CHILDMAX
)
591 index_fatal("Index node is neither parent nor endpoint");
593 buf_pushchar(buf
, node
->first
);
594 child
= index_readchild(node
, node
->first
);
598 index_fatal("Index node has non-existent first child");
600 buf_pushchars(buf
, node
->prefix
);
604 return buf_detach(buf
);
608 * Search the index for a key. The index may contain wildcards.
610 * Returns a list of all the values of matching keys.
613 /* Level 1: interface function */
614 struct index_value
*index_searchwild(FILE *in
, const char *key
);
616 /* Level 2: descend the tree (until we hit a wildcard) */
617 static void index_searchwild__node(struct index_node_f
*node
,
619 const char *key
, int i
,
620 struct index_value
**out
);
622 /* Level 3: traverse a sub-keyspace which starts with a wildcard,
623 generating all subkeys.
625 static void index_searchwild__all(struct index_node_f
*node
, int j
,
628 struct index_value
**out
);
630 /* Level 4: check for a subkey match */
631 static void index_searchwild__match(struct index_node_f
*node
, int j
,
634 struct index_value
**out
);
636 /* Level 5: add all values for a matching subkey */
637 static void index_searchwild__allvalues(struct index_node_f
*node
, int j
,
638 struct buffer
*value_buf
,
639 struct index_value
**out
);
642 struct index_value
*index_searchwild(FILE *in
, const char *key
)
644 struct index_node_f
*root
= index_readroot(in
);
645 struct buffer
*buf
= buf_create();
646 struct index_value
*out
= NULL
;
648 index_searchwild__node(root
, buf
, key
, 0, &out
);
653 static void index_searchwild__node(struct index_node_f
*node
,
655 const char *key
, int i
,
656 struct index_value
**out
)
658 struct index_node_f
*child
;
663 for (j
= 0; node
->prefix
[j
]; j
++) {
664 ch
= node
->prefix
[j
];
666 if (ch
== '*' || ch
== '?' || ch
== '[') {
667 index_searchwild__all(node
, j
, buf
,
672 if (ch
== ' ' && key
[i
+j
] == '\0') {
673 /* Note: buf matches &key[i+j] - both are empty */
674 index_searchwild__match(node
, j
+1, buf
,
679 if (ch
!= key
[i
+j
]) {
686 child
= index_readchild(node
, '*');
688 buf_pushchar(buf
, '*');
689 index_searchwild__all(child
, 0, buf
, &key
[i
], out
);
693 child
= index_readchild(node
, '?');
695 buf_pushchar(buf
, '*');
696 index_searchwild__all(child
, 0, buf
, &key
[i
], out
);
700 child
= index_readchild(node
, '[');
702 buf_pushchar(buf
, '[');
703 index_searchwild__all(child
, 0, buf
, &key
[i
], out
);
707 if (key
[i
] == '\0') {
708 child
= index_readchild(node
, ' ');
710 /* Note: buf matches &key[i] - both are empty */
712 index_searchwild__match(child
, 0,
717 child
= index_readchild(node
, key
[i
]);
724 static void index_searchwild__all(struct index_node_f
*node
, int j
,
727 struct index_value
**out
)
732 while (node
->prefix
[j
]) {
733 ch
= node
->prefix
[j
];
736 index_searchwild__match(node
, j
+1, buf
, subkey
, out
);
739 buf_pushchar(buf
, ch
);
744 for (ch
= node
->first
; ch
<= node
->last
; ch
++) {
745 struct index_node_f
*child
= index_readchild(node
, ch
);
751 index_searchwild__match(child
, 0, buf
, subkey
, out
);
753 buf_pushchar(buf
, ch
);
754 index_searchwild__all(child
, 0, buf
, subkey
, out
);
762 buf_popchars(buf
, pushed
);
765 static void index_searchwild__match(struct index_node_f
*node
, int j
,
768 struct index_value
**out
)
770 struct buffer
*value_buf
;
773 pattern
= buf_str(buf
);
774 if (fnmatch(pattern
, subkey
, 0) == 0) {
775 value_buf
= buf_create();
776 index_searchwild__allvalues(node
, j
, value_buf
, out
);
777 buf_destroy(value_buf
);
782 static void index_searchwild__allvalues(struct index_node_f
*node
, int j
,
783 struct buffer
*value_buf
,
784 struct index_value
**out
)
789 pushed
= buf_pushchars(value_buf
, &node
->prefix
[j
]);
791 if (node
->isendpoint
)
792 *out
= add_value(value_buf
, *out
);
794 for (ch
= node
->first
; ch
<= node
->last
; ch
++) {
795 struct index_node_f
*child
= index_readchild(node
, ch
);
800 buf_pushchar(value_buf
, ch
);
801 index_searchwild__allvalues(child
, 0, value_buf
, out
);
802 buf_popchar(value_buf
);
806 buf_popchars(value_buf
, pushed
);