]> git.ipfire.org Git - thirdparty/glibc.git/blame - nss/makedb.c
Reenable nss_db with a completely new implementation
[thirdparty/glibc.git] / nss / makedb.c
CommitLineData
793bd4d9 1/* Create simple DB database from textual input.
9ee76b5a 2 Copyright (C) 1996-2000, 2011 Free Software Foundation, Inc.
793bd4d9
UD
3 This file is part of the GNU C Library.
4 Contributed by Ulrich Drepper <drepper@cygnus.com>, 1996.
5
6 The GNU C Library is free software; you can redistribute it and/or
41bdb6e2
AJ
7 modify it under the terms of the GNU Lesser General Public
8 License as published by the Free Software Foundation; either
9 version 2.1 of the License, or (at your option) any later version.
793bd4d9
UD
10
11 The GNU C Library is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
41bdb6e2 14 Lesser General Public License for more details.
793bd4d9 15
41bdb6e2
AJ
16 You should have received a copy of the GNU Lesser General Public
17 License along with the GNU C Library; if not, write to the Free
18 Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
19 02111-1307 USA. */
793bd4d9
UD
20
21#include <argp.h>
9ee76b5a 22#include <assert.h>
793bd4d9 23#include <ctype.h>
793bd4d9
UD
24#include <errno.h>
25#include <error.h>
26#include <fcntl.h>
9ee76b5a 27#include <inttypes.h>
793bd4d9
UD
28#include <libintl.h>
29#include <locale.h>
9ee76b5a 30#include <search.h>
793bd4d9 31#include <stdio.h>
793bd4d9
UD
32#include <stdlib.h>
33#include <string.h>
9ee76b5a
UD
34#include <unistd.h>
35#include <sys/mman.h>
793bd4d9 36#include <sys/stat.h>
2666d441 37#include "nss_db/nss_db.h"
793bd4d9
UD
38
39/* Get libc version number. */
40#include "../version.h"
41
9ee76b5a
UD
42/* The hashing function we use. */
43#include "../intl/hash-string.h"
44
45/* SELinux support. */
46#ifdef HAVE_SELINUX
47# include <selinux/selinux.h>
48#endif
49
793bd4d9
UD
50#define PACKAGE _libc_intl_domainname
51
9ee76b5a
UD
52/* List of data bases. */
53struct database
54{
55 char dbid;
9ee76b5a
UD
56 struct database *next;
57 void *entries;
58 size_t nentries;
9ee76b5a 59 size_t nhashentries;
2666d441
UD
60 stridx_t *hashtable;
61 size_t keystrlen;
62 stridx_t *keyidxtab;
9ee76b5a
UD
63 char *keystrtab;
64} *databases;
65static size_t ndatabases;
2666d441 66static size_t nhashentries;
9ee76b5a
UD
67static size_t valstrlen;
68static void *valstrtree;
69static char *valstrtab;
70
71/* Database entry. */
72struct dbentry
73{
9ee76b5a
UD
74 stridx_t validx;
75 uint32_t hashval;
76 char str[0];
77};
78
79/* Stored string entry. */
80struct valstrentry
81{
82 stridx_t idx;
83 char str[0];
84};
85
86
9ee76b5a
UD
87/* True if any entry has been added. */
88static bool any_dbentry;
89
793bd4d9
UD
90/* If non-zero convert key to lower case. */
91static int to_lowercase;
92
93/* If non-zero print content of input file, one entry per line. */
94static int do_undo;
95
96/* If non-zero do not print informational messages. */
97static int be_quiet;
98
99/* Name of output file. */
100static const char *output_name;
101
793bd4d9
UD
102/* Name and version of program. */
103static void print_version (FILE *stream, struct argp_state *state);
104void (*argp_program_version_hook) (FILE *, struct argp_state *) = print_version;
105
106/* Definitions of arguments for argp functions. */
107static const struct argp_option options[] =
108{
109 { "fold-case", 'f', NULL, 0, N_("Convert key to lower case") },
110 { "output", 'o', N_("NAME"), 0, N_("Write output to file NAME") },
111 { "quiet", 'q', NULL, 0,
112 N_("Do not print messages while building database") },
113 { "undo", 'u', NULL, 0,
114 N_("Print content of database file, one entry a line") },
9ee76b5a 115 { NULL, 0, NULL, 0, N_("Select index type") },
793bd4d9
UD
116 { NULL, 0, NULL, 0, NULL }
117};
118
119/* Short description of program. */
9ee76b5a 120static const char doc[] = N_("Create simple database from textual input.");
793bd4d9
UD
121
122/* Strings for arguments in help texts. */
123static const char args_doc[] = N_("\
124INPUT-FILE OUTPUT-FILE\n-o OUTPUT-FILE INPUT-FILE\n-u INPUT-FILE");
125
126/* Prototype for option handler. */
cbc85992 127static error_t parse_opt (int key, char *arg, struct argp_state *state);
793bd4d9
UD
128
129/* Function to print some extra text in the help message. */
cbc85992 130static char *more_help (int key, const char *text, void *input);
793bd4d9
UD
131
132/* Data structure to communicate with argp functions. */
133static struct argp argp =
134{
135 options, parse_opt, args_doc, doc, NULL, more_help
136};
137
138
139/* Prototypes for local functions. */
9ee76b5a 140static int process_input (FILE *input, const char *inname,
cbc85992 141 int to_lowercase, int be_quiet);
9ee76b5a
UD
142static int print_database (int fd);
143static void compute_tables (void);
144static int write_output (int fd);
145
146/* SELinux support. */
147#ifdef HAVE_SELINUX
148/* Set the SELinux file creation context for the given file. */
149static void set_file_creation_context (const char *outname, mode_t mode);
150static void reset_file_creation_context (void);
151#else
152# define set_file_creation_context(_outname,_mode)
153# define reset_file_creation_context()
154#endif
155
156
157/* External functions. */
158extern void *xmalloc (size_t n) __attribute_malloc__;
159extern void *xcalloc (size_t n, size_t m) __attribute_malloc__;
793bd4d9
UD
160
161
162int
cbc85992 163main (int argc, char *argv[])
793bd4d9
UD
164{
165 const char *input_name;
166 FILE *input_file;
793bd4d9 167 int remaining;
2666d441 168 int mode = 0644;
793bd4d9
UD
169
170 /* Set locale via LC_ALL. */
171 setlocale (LC_ALL, "");
172
173 /* Set the text message domain. */
174 textdomain (_libc_intl_domainname);
175
176 /* Initialize local variables. */
177 input_name = NULL;
178
179 /* Parse and process arguments. */
180 argp_parse (&argp, argc, argv, 0, &remaining, NULL);
181
182 /* Determine file names. */
183 if (do_undo || output_name != NULL)
184 {
185 if (remaining + 1 != argc)
186 {
187 wrong_arguments:
188 error (0, 0, gettext ("wrong number of arguments"));
189 argp_help (&argp, stdout, ARGP_HELP_SEE,
190 program_invocation_short_name);
191 exit (1);
192 }
193 input_name = argv[remaining];
194 }
195 else
196 {
197 if (remaining + 2 != argc)
198 goto wrong_arguments;
199
200 input_name = argv[remaining++];
201 output_name = argv[remaining];
202 }
203
204 /* Special handling if we are asked to print the database. */
205 if (do_undo)
206 {
9ee76b5a
UD
207 int fd = open (input_name, O_RDONLY);
208 if (fd == -1)
209 error (EXIT_FAILURE, errno, gettext ("cannot open database file `%s'"),
210 input_name);
793bd4d9 211
9ee76b5a 212 int status = print_database (fd);
793bd4d9 213
9ee76b5a 214 close (fd);
793bd4d9
UD
215
216 return status;
217 }
218
219 /* Open input file. */
220 if (strcmp (input_name, "-") == 0 || strcmp (input_name, "/dev/stdin") == 0)
221 input_file = stdin;
222 else
223 {
9ee76b5a 224 struct stat64 st;
793bd4d9 225
9ee76b5a 226 input_file = fopen64 (input_name, "r");
793bd4d9
UD
227 if (input_file == NULL)
228 error (EXIT_FAILURE, errno, gettext ("cannot open input file `%s'"),
229 input_name);
230
231 /* Get the access rights from the source file. The output file should
232 have the same. */
9ee76b5a 233 if (fstat64 (fileno (input_file), &st) >= 0)
793bd4d9
UD
234 mode = st.st_mode & ACCESSPERMS;
235 }
236
793bd4d9 237 /* Start the real work. */
9ee76b5a 238 int status = process_input (input_file, input_name, to_lowercase, be_quiet);
793bd4d9
UD
239
240 /* Close files. */
241 if (input_file != stdin)
242 fclose (input_file);
9ee76b5a
UD
243
244 /* No need to continue when we did not read the file successfully. */
245 if (status != EXIT_SUCCESS)
246 return status;
247
248 /* Bail out if nothing is to be done. */
249 if (!any_dbentry)
2666d441
UD
250 {
251 if (be_quiet)
252 return EXIT_SUCCESS;
253 else
254 error (EXIT_SUCCESS, 0, gettext ("no entries to be processed"));
255 }
9ee76b5a
UD
256
257 /* Compute hash and string tables. */
258 compute_tables ();
259
260 /* Open output file. This must not be standard output so we don't
261 handle "-" and "/dev/stdout" special. */
262 char *tmp_output_name;
263 if (asprintf (&tmp_output_name, "%s.XXXXXX", output_name) == -1)
264 error (EXIT_FAILURE, errno, gettext ("cannot create temporary file name"));
265
266 set_file_creation_context (output_name, mode);
267 int fd = mkstemp (tmp_output_name);
268 reset_file_creation_context ();
269 if (fd == -1)
270 error (EXIT_FAILURE, errno, gettext ("cannot create temporary file"));
9ee76b5a
UD
271
272 status = write_output (fd);
273
274 if (status == EXIT_SUCCESS)
275 {
276 struct stat64 st;
277
278 if (fstat64 (fd, &st) == 0)
279 {
280 if ((st.st_mode & ACCESSPERMS) != mode)
281 /* We ignore problems with changing the mode. */
282 fchmod (fd, mode);
283 }
284 else
285 {
286 error (0, errno, gettext ("cannot stat newly created file"));
287 status = EXIT_FAILURE;
288 }
289 }
290
291 close (fd);
292
293 if (status == EXIT_SUCCESS)
294 {
295 if (rename (tmp_output_name, output_name) != 0)
296 {
297 error (0, errno, gettext ("cannot rename temporary file"));
298 status = EXIT_FAILURE;
299 goto do_unlink;
300 }
301 }
302 else
303 do_unlink:
304 unlink (tmp_output_name);
793bd4d9
UD
305
306 return status;
307}
308
309
310/* Handle program arguments. */
311static error_t
312parse_opt (int key, char *arg, struct argp_state *state)
313{
314 switch (key)
315 {
316 case 'f':
317 to_lowercase = 1;
318 break;
319 case 'o':
320 output_name = arg;
321 break;
322 case 'q':
323 be_quiet = 1;
324 break;
325 case 'u':
326 do_undo = 1;
327 break;
328 default:
329 return ARGP_ERR_UNKNOWN;
330 }
331 return 0;
332}
333
334
335static char *
336more_help (int key, const char *text, void *input)
337{
338 switch (key)
339 {
340 case ARGP_KEY_HELP_EXTRA:
341 /* We print some extra information. */
342 return strdup (gettext ("\
d40eb37a
UD
343For bug reporting instructions, please see:\n\
344<http://www.gnu.org/software/libc/bugs.html>.\n"));
793bd4d9
UD
345 default:
346 break;
347 }
348 return (char *) text;
349}
350
351/* Print the version information. */
352static void
353print_version (FILE *stream, struct argp_state *state)
354{
355 fprintf (stream, "makedb (GNU %s) %s\n", PACKAGE, VERSION);
356 fprintf (stream, gettext ("\
357Copyright (C) %s Free Software Foundation, Inc.\n\
358This is free software; see the source for copying conditions. There is NO\n\
359warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\
9ee76b5a 360"), "2011");
793bd4d9
UD
361 fprintf (stream, gettext ("Written by %s.\n"), "Ulrich Drepper");
362}
363
364
365static int
9ee76b5a
UD
366dbentry_compare (const void *p1, const void *p2)
367{
368 const struct dbentry *d1 = (const struct dbentry *) p1;
369 const struct dbentry *d2 = (const struct dbentry *) p2;
370
371 if (d1->hashval != d2->hashval)
372 return d1->hashval < d2->hashval ? -1 : 1;
373
2666d441 374 return strcmp (d1->str, d2->str);
9ee76b5a
UD
375}
376
377
378static int
379valstr_compare (const void *p1, const void *p2)
380{
381 const struct valstrentry *d1 = (const struct valstrentry *) p1;
382 const struct valstrentry *d2 = (const struct valstrentry *) p2;
383
384 return strcmp (d1->str, d2->str);
385}
386
387
388static int
389process_input (input, inname, to_lowercase, be_quiet)
793bd4d9
UD
390 FILE *input;
391 const char *inname;
793bd4d9
UD
392 int to_lowercase;
393 int be_quiet;
394{
395 char *line;
396 size_t linelen;
397 int status;
398 size_t linenr;
399
400 line = NULL;
401 linelen = 0;
402 status = EXIT_SUCCESS;
403 linenr = 0;
404
9ee76b5a 405 struct database *last_database = NULL;
793bd4d9 406
9ee76b5a
UD
407 while (!feof_unlocked (input))
408 {
409 ssize_t n = getline (&line, &linelen, input);
793bd4d9
UD
410 if (n < 0)
411 /* This means end of file or some bug. */
412 break;
413 if (n == 0)
414 /* Short read. Probably interrupted system call. */
415 continue;
416
417 ++linenr;
418
419 if (line[n - 1] == '\n')
420 /* Remove trailing newline. */
421 line[--n] = '\0';
422
9ee76b5a 423 char *cp = line;
793bd4d9
UD
424 while (isspace (*cp))
425 ++cp;
426
9ee76b5a
UD
427 if (*cp == '#' || *cp == '\0')
428 /* First non-space character in line '#': it's a comment.
429 Also go to the next line if it is empty except for whitespaces. */
793bd4d9
UD
430 continue;
431
9ee76b5a
UD
432 /* Skip over the character indicating the database so that it is not
433 affected by TO_LOWERCASE. */
434 char *key = cp++;
793bd4d9
UD
435 while (*cp != '\0' && !isspace (*cp))
436 {
437 if (to_lowercase)
438 *cp = tolower (*cp);
439 ++cp;
440 }
441
9ee76b5a
UD
442 if (*cp == '\0')
443 /* It's a line without a value field. */
793bd4d9
UD
444 continue;
445
9ee76b5a
UD
446 *cp++ = '\0';
447 size_t keylen = cp - key;
793bd4d9
UD
448
449 while (isspace (*cp))
450 ++cp;
451
9ee76b5a
UD
452 char *data = cp;
453 size_t datalen = (&line[n] - cp) + 1;
793bd4d9 454
9ee76b5a
UD
455 /* Find the database. */
456 if (last_database == NULL || last_database->dbid != key[0])
793bd4d9 457 {
9ee76b5a
UD
458 last_database = databases;
459 while (last_database != NULL && last_database->dbid != key[0])
460 last_database = last_database->next;
461
462 if (last_database == NULL)
793bd4d9 463 {
9ee76b5a
UD
464 last_database = xmalloc (sizeof (*last_database));
465 last_database->dbid = key[0];
9ee76b5a
UD
466 last_database->next = databases;
467 last_database->entries = NULL;
468 last_database->nentries = 0;
469 last_database->keystrlen = 0;
470 databases = last_database;
793bd4d9 471 }
9ee76b5a 472 }
793bd4d9 473
9ee76b5a
UD
474 /* Skip the database selector. */
475 ++key;
476 --keylen;
477
9ee76b5a
UD
478 /* Store the data. */
479 struct valstrentry *nentry = xmalloc (sizeof (struct valstrentry)
480 + datalen);
481 nentry->idx = valstrlen;
482 memcpy (nentry->str, data, datalen);
793bd4d9 483
9ee76b5a
UD
484 struct valstrentry **fdata = tsearch (nentry, &valstrtree,
485 valstr_compare);
486 if (fdata == NULL)
487 error (EXIT_FAILURE, errno, gettext ("cannot create search tree"));
488
489 if (*fdata != nentry)
490 {
491 /* We can reuse a string. */
492 free (nentry);
493 nentry = *fdata;
494 }
495 else
496 valstrlen += datalen;
497
498 /* Store the key. */
2666d441
UD
499 struct dbentry *newp = xmalloc (sizeof (struct dbentry) + keylen);
500 newp->validx = nentry->idx;
501 newp->hashval = __hash_string (key);
502 memcpy (newp->str, key, keylen);
9ee76b5a
UD
503
504 struct dbentry **found = tsearch (newp, &last_database->entries,
505 dbentry_compare);
506 if (found == NULL)
507 error (EXIT_FAILURE, errno, gettext ("cannot create search tree"));
508
509 if (*found != newp)
510 {
511 free (newp);
512 if (!be_quiet)
513 error_at_line (0, 0, inname, linenr, gettext ("duplicate key"));
514 continue;
515 }
516
517 ++last_database->nentries;
518 last_database->keystrlen += keylen;
519
520 any_dbentry = true;
793bd4d9
UD
521 }
522
9ee76b5a 523 if (ferror_unlocked (input))
793bd4d9
UD
524 {
525 error (0, 0, gettext ("problems while reading `%s'"), inname);
526 status = EXIT_FAILURE;
527 }
528
529 return status;
530}
531
532
9ee76b5a
UD
533static void
534copy_valstr (const void *nodep, const VISIT which, const int depth)
793bd4d9 535{
9ee76b5a
UD
536 if (which != leaf && which != postorder)
537 return;
538
539 const struct valstrentry *p = *(const struct valstrentry **) nodep;
540
541 strcpy (valstrtab + p->idx, p->str);
542}
543
544
545static void
546compute_tables (void)
547{
548 valstrtab = xmalloc (roundup (valstrlen, sizeof (stridx_t)));
549 while (valstrlen % sizeof (stridx_t) != 0)
550 valstrtab[valstrlen++] = '\0';
551 twalk (valstrtree, copy_valstr);
552
553 for (struct database *db = databases; db != NULL; db = db->next)
554 if (db->nentries != 0)
555 {
556 ++ndatabases;
557
9ee76b5a
UD
558 /* We simply use an odd number large than twice the number of
559 elements to store in the hash table for the size. This gives
560 enough efficiency. */
561 db->nhashentries = db->nentries * 2 + 1;
2666d441
UD
562 db->hashtable = xmalloc (db->nhashentries * sizeof (stridx_t));
563 memset (db->hashtable, '\xff', db->nhashentries * sizeof (stridx_t));
564 db->keyidxtab = xmalloc (db->nhashentries * sizeof (stridx_t));
565 memset (db->keyidxtab, '\xff', db->nhashentries * sizeof (stridx_t));
9ee76b5a
UD
566 db->keystrtab = xmalloc (db->keystrlen);
567
568 size_t max_chainlength = 0;
569 char *wp = db->keystrtab;
570
571 void add_key(const void *nodep, const VISIT which, const int depth)
572 {
573 if (which != leaf && which != postorder)
574 return;
575
576 const struct dbentry *dbe = *(const struct dbentry **) nodep;
577
578 ptrdiff_t stridx = wp - db->keystrtab;
2666d441 579 wp = stpcpy (wp, dbe->str) + 1;
9ee76b5a
UD
580
581 size_t hidx = dbe->hashval % db->nhashentries;
582 size_t hval2 = 1 + dbe->hashval % (db->nhashentries - 2);
583 size_t chainlength = 0;
584
2666d441 585 while (db->hashtable[hidx] != ~((stridx_t) 0))
9ee76b5a
UD
586 {
587 ++chainlength;
588 if ((hidx += hval2) >= db->nhashentries)
589 hidx -= db->nhashentries;
590 }
591
2666d441
UD
592 db->hashtable[hidx] = dbe->validx;
593 db->keyidxtab[hidx] = stridx;
9ee76b5a
UD
594
595 max_chainlength = MAX (max_chainlength, chainlength);
596 }
793bd4d9 597
9ee76b5a
UD
598 twalk (db->entries, add_key);
599
600 // XXX if hash length is too long resize table and start again
601
2666d441 602 nhashentries += db->nhashentries;
9ee76b5a
UD
603 }
604}
605
606
607static int
608write_output (int fd)
609{
610 struct nss_db_header *header;
611 uint64_t file_offset = (sizeof (struct nss_db_header)
612 + (ndatabases * sizeof (header->dbs[0])));
613 header = alloca (file_offset);
614
615 header->magic = NSS_DB_MAGIC;
616 header->ndbs = ndatabases;
617 header->valstroffset = file_offset;
618 header->valstrlen = valstrlen;
619
620 size_t filled_dbs = 0;
2666d441 621 struct iovec iov[2 + ndatabases * 3];
9ee76b5a
UD
622 iov[0].iov_base = header;
623 iov[0].iov_len = file_offset;
624
625 iov[1].iov_base = valstrtab;
626 iov[1].iov_len = valstrlen;
627 file_offset += valstrlen;
628
2666d441 629 size_t keydataoffset = file_offset + nhashentries * sizeof (stridx_t);
9ee76b5a
UD
630 for (struct database *db = databases; db != NULL; db = db->next)
631 if (db->entries != NULL)
632 {
633 assert (file_offset % sizeof (stridx_t) == 0);
634 assert (filled_dbs < ndatabases);
635
636 header->dbs[filled_dbs].id = db->dbid;
9ee76b5a
UD
637 memset (header->dbs[filled_dbs].pad, '\0',
638 sizeof (header->dbs[0].pad));
639 header->dbs[filled_dbs].hashsize = db->nhashentries;
640
2666d441
UD
641 iov[2 + filled_dbs].iov_base = db->hashtable;
642 iov[2 + filled_dbs].iov_len = db-> nhashentries * sizeof (stridx_t);
9ee76b5a 643 header->dbs[filled_dbs].hashoffset = file_offset;
2666d441 644 file_offset += iov[2 + filled_dbs].iov_len;
9ee76b5a 645
2666d441
UD
646 iov[2 + ndatabases + filled_dbs * 2].iov_base = db->keyidxtab;
647 iov[2 + ndatabases + filled_dbs * 2].iov_len
648 = db-> nhashentries * sizeof (stridx_t);
649 header->dbs[filled_dbs].keyidxoffset = keydataoffset;
650 keydataoffset += iov[2 + ndatabases + filled_dbs * 2].iov_len;
651
652 iov[3 + ndatabases + filled_dbs * 2].iov_base = db->keystrtab;
653 iov[3 + ndatabases + filled_dbs * 2].iov_len = db->keystrlen;
654 header->dbs[filled_dbs].keystroffset = keydataoffset;
655 keydataoffset += iov[3 + ndatabases + filled_dbs * 2].iov_len;
9ee76b5a
UD
656
657 ++filled_dbs;
658 }
659
660 assert (filled_dbs == ndatabases);
2666d441
UD
661 assert (file_offset == (iov[0].iov_len + iov[1].iov_len
662 + nhashentries * sizeof (stridx_t)));
663 header->allocate = file_offset;
9ee76b5a 664
2666d441 665 if (writev (fd, iov, 2 + ndatabases * 3) != keydataoffset)
793bd4d9 666 {
9ee76b5a 667 error (0, errno, gettext ("failed to write new database file"));
793bd4d9
UD
668 return EXIT_FAILURE;
669 }
670
9ee76b5a
UD
671 return EXIT_SUCCESS;
672}
673
674
675static int
676print_database (int fd)
677{
678 struct stat64 st;
679 if (fstat64 (fd, &st) != 0)
680 error (EXIT_FAILURE, errno, gettext ("cannot stat database file"));
681
682 const struct nss_db_header *header = mmap (NULL, st.st_size, PROT_READ,
683 MAP_PRIVATE|MAP_POPULATE, fd, 0);
684 if (header == MAP_FAILED)
685 error (EXIT_FAILURE, errno, gettext ("cannot map database file"));
686
687 if (header->magic != NSS_DB_MAGIC)
688 error (EXIT_FAILURE, 0, gettext ("file not a database file"));
689
690 const char *valstrtab = (const char *) header + header->valstroffset;
691
692 for (unsigned int dbidx = 0; dbidx < header->ndbs; ++dbidx)
793bd4d9 693 {
2666d441
UD
694 const stridx_t *stridxtab
695 = ((const stridx_t *) ((const char *) header
696 + header->dbs[dbidx].keyidxoffset));
9ee76b5a 697 const char *keystrtab
2666d441
UD
698 = (const char *) header + header->dbs[dbidx].keystroffset;
699 const stridx_t *hashtab
700 = (const stridx_t *) ((const char *) header
701 + header->dbs[dbidx].hashoffset);
702
703 for (uint32_t hidx = 0; hidx < header->dbs[dbidx].hashsize; ++hidx)
704 if (hashtab[hidx] != ~((stridx_t) 0))
705 printf ("%c%s %s\n",
706 header->dbs[dbidx].id,
707 keystrtab + stridxtab[hidx],
708 valstrtab + hashtab[hidx]);
793bd4d9
UD
709 }
710
9ee76b5a
UD
711 return EXIT_SUCCESS;
712}
713
714
715#ifdef HAVE_SELINUX
716static void
717set_file_creation_context (const char *outname, mode_t mode)
718{
719 static int enabled;
720 static int enforcing;
721 security_context_t ctx;
722
723 /* Check if SELinux is enabled, and remember. */
724 if (enabled == 0)
725 enabled = is_selinux_enabled ();
726 if (enabled < 0)
727 return;
728
729 /* Check if SELinux is enforcing, and remember. */
730 if (enforcing == 0)
731 enforcing = security_getenforce () ? 1 : -1;
732
733 /* Determine the context which the file should have. */
734 ctx = NULL;
735 if (matchpathcon (outname, S_IFREG | mode, &ctx) == 0 && ctx != NULL)
793bd4d9 736 {
9ee76b5a
UD
737 if (setfscreatecon (ctx) != 0)
738 error (enforcing > 0 ? EXIT_FAILURE : 0, 0,
739 gettext ("cannot set file creation context for `%s'"),
740 outname);
741
742 freecon (ctx);
793bd4d9 743 }
9ee76b5a 744}
793bd4d9 745
9ee76b5a
UD
746static void
747reset_file_creation_context (void)
748{
749 setfscreatecon (NULL);
793bd4d9 750}
9ee76b5a 751#endif