|
Packit |
6c4009 |
/* Create simple DB database from textual input.
|
|
Packit |
6c4009 |
Copyright (C) 1996-2018 Free Software Foundation, Inc.
|
|
Packit |
6c4009 |
This file is part of the GNU C Library.
|
|
Packit |
6c4009 |
Contributed by Ulrich Drepper <drepper@cygnus.com>, 1996.
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
The GNU C Library is free software; you can redistribute it and/or
|
|
Packit |
6c4009 |
modify it under the terms of the GNU Lesser General Public
|
|
Packit |
6c4009 |
License as published by the Free Software Foundation; either
|
|
Packit |
6c4009 |
version 2.1 of the License, or (at your option) any later version.
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
The GNU C Library is distributed in the hope that it will be useful,
|
|
Packit |
6c4009 |
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
Packit |
6c4009 |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
Packit |
6c4009 |
Lesser General Public License for more details.
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
You should have received a copy of the GNU Lesser General Public
|
|
Packit |
6c4009 |
License along with the GNU C Library; if not, see
|
|
Packit |
6c4009 |
<http://www.gnu.org/licenses/>. */
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
#include <argp.h>
|
|
Packit |
6c4009 |
#include <assert.h>
|
|
Packit |
6c4009 |
#include <ctype.h>
|
|
Packit |
6c4009 |
#include <errno.h>
|
|
Packit |
6c4009 |
#include <error.h>
|
|
Packit |
6c4009 |
#include <fcntl.h>
|
|
Packit |
6c4009 |
#include <inttypes.h>
|
|
Packit |
6c4009 |
#include <libintl.h>
|
|
Packit |
6c4009 |
#include <locale.h>
|
|
Packit |
6c4009 |
#include <search.h>
|
|
Packit |
6c4009 |
#include <stdbool.h>
|
|
Packit |
6c4009 |
#include <stdio.h>
|
|
Packit |
6c4009 |
#include <stdlib.h>
|
|
Packit |
6c4009 |
#include <string.h>
|
|
Packit |
6c4009 |
#include <unistd.h>
|
|
Packit |
6c4009 |
#include <stdint.h>
|
|
Packit |
6c4009 |
#include <sys/mman.h>
|
|
Packit |
6c4009 |
#include <sys/param.h>
|
|
Packit |
6c4009 |
#include <sys/stat.h>
|
|
Packit |
6c4009 |
#include <sys/uio.h>
|
|
Packit |
6c4009 |
#include "nss_db/nss_db.h"
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
/* Get libc version number. */
|
|
Packit |
6c4009 |
#include "../version.h"
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
/* The hashing function we use. */
|
|
Packit |
6c4009 |
#include "../intl/hash-string.h"
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
/* SELinux support. */
|
|
Packit |
6c4009 |
#ifdef HAVE_SELINUX
|
|
Packit |
6c4009 |
# include <selinux/selinux.h>
|
|
Packit |
6c4009 |
#endif
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
#ifndef MAP_POPULATE
|
|
Packit |
6c4009 |
# define MAP_POPULATE 0
|
|
Packit |
6c4009 |
#endif
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
#define PACKAGE _libc_intl_domainname
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
/* List of data bases. */
|
|
Packit |
6c4009 |
struct database
|
|
Packit |
6c4009 |
{
|
|
Packit |
6c4009 |
char dbid;
|
|
Packit |
6c4009 |
bool extra_string;
|
|
Packit |
6c4009 |
struct database *next;
|
|
Packit |
6c4009 |
void *entries;
|
|
Packit |
6c4009 |
size_t nentries;
|
|
Packit |
6c4009 |
size_t nhashentries;
|
|
Packit |
6c4009 |
stridx_t *hashtable;
|
|
Packit |
6c4009 |
size_t keystrlen;
|
|
Packit |
6c4009 |
stridx_t *keyidxtab;
|
|
Packit |
6c4009 |
char *keystrtab;
|
|
Packit |
6c4009 |
} *databases;
|
|
Packit |
6c4009 |
static size_t ndatabases;
|
|
Packit |
6c4009 |
static size_t nhashentries_total;
|
|
Packit |
6c4009 |
static size_t valstrlen;
|
|
Packit |
6c4009 |
static void *valstrtree;
|
|
Packit |
6c4009 |
static char *valstrtab;
|
|
Packit |
6c4009 |
static size_t extrastrlen;
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
/* Database entry. */
|
|
Packit |
6c4009 |
struct dbentry
|
|
Packit |
6c4009 |
{
|
|
Packit |
6c4009 |
stridx_t validx;
|
|
Packit |
6c4009 |
uint32_t hashval;
|
|
Packit |
6c4009 |
char str[0];
|
|
Packit |
6c4009 |
};
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
/* Stored string entry. */
|
|
Packit |
6c4009 |
struct valstrentry
|
|
Packit |
6c4009 |
{
|
|
Packit |
6c4009 |
stridx_t idx;
|
|
Packit |
6c4009 |
bool extra_string;
|
|
Packit |
6c4009 |
char str[0];
|
|
Packit |
6c4009 |
};
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
/* True if any entry has been added. */
|
|
Packit |
6c4009 |
static bool any_dbentry;
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
/* If non-zero convert key to lower case. */
|
|
Packit |
6c4009 |
static int to_lowercase;
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
/* If non-zero print content of input file, one entry per line. */
|
|
Packit |
6c4009 |
static int do_undo;
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
/* If non-zero do not print informational messages. */
|
|
Packit |
6c4009 |
static int be_quiet;
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
/* Name of output file. */
|
|
Packit |
6c4009 |
static const char *output_name;
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
/* Name and version of program. */
|
|
Packit |
6c4009 |
static void print_version (FILE *stream, struct argp_state *state);
|
|
Packit |
6c4009 |
void (*argp_program_version_hook) (FILE *, struct argp_state *) = print_version;
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
/* Definitions of arguments for argp functions. */
|
|
Packit |
6c4009 |
static const struct argp_option options[] =
|
|
Packit |
6c4009 |
{
|
|
Packit |
6c4009 |
{ "fold-case", 'f', NULL, 0, N_("Convert key to lower case") },
|
|
Packit |
6c4009 |
{ "output", 'o', N_("NAME"), 0, N_("Write output to file NAME") },
|
|
Packit |
6c4009 |
{ "quiet", 'q', NULL, 0,
|
|
Packit |
6c4009 |
N_("Do not print messages while building database") },
|
|
Packit |
6c4009 |
{ "undo", 'u', NULL, 0,
|
|
Packit |
6c4009 |
N_("Print content of database file, one entry a line") },
|
|
Packit |
6c4009 |
{ "generated", 'g', N_("CHAR"), 0,
|
|
Packit |
6c4009 |
N_("Generated line not part of iteration") },
|
|
Packit |
6c4009 |
{ NULL, 0, NULL, 0, NULL }
|
|
Packit |
6c4009 |
};
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
/* Short description of program. */
|
|
Packit |
6c4009 |
static const char doc[] = N_("Create simple database from textual input.");
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
/* Strings for arguments in help texts. */
|
|
Packit |
6c4009 |
static const char args_doc[] = N_("\
|
|
Packit |
6c4009 |
INPUT-FILE OUTPUT-FILE\n-o OUTPUT-FILE INPUT-FILE\n-u INPUT-FILE");
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
/* Prototype for option handler. */
|
|
Packit |
6c4009 |
static error_t parse_opt (int key, char *arg, struct argp_state *state);
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
/* Function to print some extra text in the help message. */
|
|
Packit |
6c4009 |
static char *more_help (int key, const char *text, void *input);
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
/* Data structure to communicate with argp functions. */
|
|
Packit |
6c4009 |
static struct argp argp =
|
|
Packit |
6c4009 |
{
|
|
Packit |
6c4009 |
options, parse_opt, args_doc, doc, NULL, more_help
|
|
Packit |
6c4009 |
};
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
/* List of databases which are not part of the iteration table. */
|
|
Packit |
6c4009 |
static struct db_option
|
|
Packit |
6c4009 |
{
|
|
Packit |
6c4009 |
char dbid;
|
|
Packit |
6c4009 |
struct db_option *next;
|
|
Packit |
6c4009 |
} *db_options;
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
/* Prototypes for local functions. */
|
|
Packit |
6c4009 |
static int process_input (FILE *input, const char *inname,
|
|
Packit |
6c4009 |
int to_lowercase, int be_quiet);
|
|
Packit |
6c4009 |
static int print_database (int fd);
|
|
Packit |
6c4009 |
static void compute_tables (void);
|
|
Packit |
6c4009 |
static int write_output (int fd);
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
/* SELinux support. */
|
|
Packit |
6c4009 |
#ifdef HAVE_SELINUX
|
|
Packit |
6c4009 |
/* Set the SELinux file creation context for the given file. */
|
|
Packit |
6c4009 |
static void set_file_creation_context (const char *outname, mode_t mode);
|
|
Packit |
6c4009 |
static void reset_file_creation_context (void);
|
|
Packit |
6c4009 |
#else
|
|
Packit |
6c4009 |
# define set_file_creation_context(_outname,_mode)
|
|
Packit |
6c4009 |
# define reset_file_creation_context()
|
|
Packit |
6c4009 |
#endif
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
/* External functions. */
|
|
Packit |
6c4009 |
#include <programs/xmalloc.h>
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
int
|
|
Packit |
6c4009 |
main (int argc, char *argv[])
|
|
Packit |
6c4009 |
{
|
|
Packit |
6c4009 |
const char *input_name;
|
|
Packit |
6c4009 |
FILE *input_file;
|
|
Packit |
6c4009 |
int remaining;
|
|
Packit |
6c4009 |
int mode = 0644;
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
/* Set locale via LC_ALL. */
|
|
Packit |
6c4009 |
setlocale (LC_ALL, "");
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
/* Set the text message domain. */
|
|
Packit |
6c4009 |
textdomain (_libc_intl_domainname);
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
/* Initialize local variables. */
|
|
Packit |
6c4009 |
input_name = NULL;
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
/* Parse and process arguments. */
|
|
Packit |
6c4009 |
argp_parse (&argp, argc, argv, 0, &remaining, NULL);
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
/* Determine file names. */
|
|
Packit |
6c4009 |
if (do_undo || output_name != NULL)
|
|
Packit |
6c4009 |
{
|
|
Packit |
6c4009 |
if (remaining + 1 != argc)
|
|
Packit |
6c4009 |
{
|
|
Packit |
6c4009 |
wrong_arguments:
|
|
Packit |
6c4009 |
error (0, 0, gettext ("wrong number of arguments"));
|
|
Packit |
6c4009 |
argp_help (&argp, stdout, ARGP_HELP_SEE,
|
|
Packit |
6c4009 |
program_invocation_short_name);
|
|
Packit |
6c4009 |
exit (1);
|
|
Packit |
6c4009 |
}
|
|
Packit |
6c4009 |
input_name = argv[remaining];
|
|
Packit |
6c4009 |
}
|
|
Packit |
6c4009 |
else
|
|
Packit |
6c4009 |
{
|
|
Packit |
6c4009 |
if (remaining + 2 != argc)
|
|
Packit |
6c4009 |
goto wrong_arguments;
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
input_name = argv[remaining++];
|
|
Packit |
6c4009 |
output_name = argv[remaining];
|
|
Packit |
6c4009 |
}
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
/* Special handling if we are asked to print the database. */
|
|
Packit |
6c4009 |
if (do_undo)
|
|
Packit |
6c4009 |
{
|
|
Packit |
6c4009 |
int fd = open (input_name, O_RDONLY);
|
|
Packit |
6c4009 |
if (fd == -1)
|
|
Packit |
6c4009 |
error (EXIT_FAILURE, errno, gettext ("cannot open database file `%s'"),
|
|
Packit |
6c4009 |
input_name);
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
int status = print_database (fd);
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
close (fd);
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
return status;
|
|
Packit |
6c4009 |
}
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
/* Open input file. */
|
|
Packit |
6c4009 |
if (strcmp (input_name, "-") == 0 || strcmp (input_name, "/dev/stdin") == 0)
|
|
Packit |
6c4009 |
input_file = stdin;
|
|
Packit |
6c4009 |
else
|
|
Packit |
6c4009 |
{
|
|
Packit |
6c4009 |
struct stat64 st;
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
input_file = fopen64 (input_name, "r");
|
|
Packit |
6c4009 |
if (input_file == NULL)
|
|
Packit |
6c4009 |
error (EXIT_FAILURE, errno, gettext ("cannot open input file `%s'"),
|
|
Packit |
6c4009 |
input_name);
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
/* Get the access rights from the source file. The output file should
|
|
Packit |
6c4009 |
have the same. */
|
|
Packit |
6c4009 |
if (fstat64 (fileno (input_file), &st) >= 0)
|
|
Packit |
6c4009 |
mode = st.st_mode & ACCESSPERMS;
|
|
Packit |
6c4009 |
}
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
/* Start the real work. */
|
|
Packit |
6c4009 |
int status = process_input (input_file, input_name, to_lowercase, be_quiet);
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
/* Close files. */
|
|
Packit |
6c4009 |
if (input_file != stdin)
|
|
Packit |
6c4009 |
fclose (input_file);
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
/* No need to continue when we did not read the file successfully. */
|
|
Packit |
6c4009 |
if (status != EXIT_SUCCESS)
|
|
Packit |
6c4009 |
return status;
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
/* Bail out if nothing is to be done. */
|
|
Packit |
6c4009 |
if (!any_dbentry)
|
|
Packit |
6c4009 |
{
|
|
Packit |
6c4009 |
if (be_quiet)
|
|
Packit |
6c4009 |
return EXIT_SUCCESS;
|
|
Packit |
6c4009 |
else
|
|
Packit |
6c4009 |
error (EXIT_SUCCESS, 0, gettext ("no entries to be processed"));
|
|
Packit |
6c4009 |
}
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
/* Compute hash and string tables. */
|
|
Packit |
6c4009 |
compute_tables ();
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
/* Open output file. This must not be standard output so we don't
|
|
Packit |
6c4009 |
handle "-" and "/dev/stdout" special. */
|
|
Packit |
6c4009 |
char *tmp_output_name;
|
|
Packit |
6c4009 |
if (asprintf (&tmp_output_name, "%s.XXXXXX", output_name) == -1)
|
|
Packit |
6c4009 |
error (EXIT_FAILURE, errno, gettext ("cannot create temporary file name"));
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
set_file_creation_context (output_name, mode);
|
|
Packit |
6c4009 |
int fd = mkstemp (tmp_output_name);
|
|
Packit |
6c4009 |
reset_file_creation_context ();
|
|
Packit |
6c4009 |
if (fd == -1)
|
|
Packit |
6c4009 |
error (EXIT_FAILURE, errno, gettext ("cannot create temporary file"));
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
status = write_output (fd);
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
if (status == EXIT_SUCCESS)
|
|
Packit |
6c4009 |
{
|
|
Packit |
6c4009 |
struct stat64 st;
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
if (fstat64 (fd, &st) == 0)
|
|
Packit |
6c4009 |
{
|
|
Packit |
6c4009 |
if ((st.st_mode & ACCESSPERMS) != mode)
|
|
Packit |
6c4009 |
/* We ignore problems with changing the mode. */
|
|
Packit |
6c4009 |
fchmod (fd, mode);
|
|
Packit |
6c4009 |
}
|
|
Packit |
6c4009 |
else
|
|
Packit |
6c4009 |
{
|
|
Packit |
6c4009 |
error (0, errno, gettext ("cannot stat newly created file"));
|
|
Packit |
6c4009 |
status = EXIT_FAILURE;
|
|
Packit |
6c4009 |
}
|
|
Packit |
6c4009 |
}
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
close (fd);
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
if (status == EXIT_SUCCESS)
|
|
Packit |
6c4009 |
{
|
|
Packit |
6c4009 |
if (rename (tmp_output_name, output_name) != 0)
|
|
Packit |
6c4009 |
{
|
|
Packit |
6c4009 |
error (0, errno, gettext ("cannot rename temporary file"));
|
|
Packit |
6c4009 |
status = EXIT_FAILURE;
|
|
Packit |
6c4009 |
goto do_unlink;
|
|
Packit |
6c4009 |
}
|
|
Packit |
6c4009 |
}
|
|
Packit |
6c4009 |
else
|
|
Packit |
6c4009 |
do_unlink:
|
|
Packit |
6c4009 |
unlink (tmp_output_name);
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
return status;
|
|
Packit |
6c4009 |
}
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
/* Handle program arguments. */
|
|
Packit |
6c4009 |
static error_t
|
|
Packit |
6c4009 |
parse_opt (int key, char *arg, struct argp_state *state)
|
|
Packit |
6c4009 |
{
|
|
Packit |
6c4009 |
struct db_option *newp;
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
switch (key)
|
|
Packit |
6c4009 |
{
|
|
Packit |
6c4009 |
case 'f':
|
|
Packit |
6c4009 |
to_lowercase = 1;
|
|
Packit |
6c4009 |
break;
|
|
Packit |
6c4009 |
case 'o':
|
|
Packit |
6c4009 |
output_name = arg;
|
|
Packit |
6c4009 |
break;
|
|
Packit |
6c4009 |
case 'q':
|
|
Packit |
6c4009 |
be_quiet = 1;
|
|
Packit |
6c4009 |
break;
|
|
Packit |
6c4009 |
case 'u':
|
|
Packit |
6c4009 |
do_undo = 1;
|
|
Packit |
6c4009 |
break;
|
|
Packit |
6c4009 |
case 'g':
|
|
Packit |
6c4009 |
newp = xmalloc (sizeof (*newp));
|
|
Packit |
6c4009 |
newp->dbid = arg[0];
|
|
Packit |
6c4009 |
newp->next = db_options;
|
|
Packit |
6c4009 |
db_options = newp;
|
|
Packit |
6c4009 |
break;
|
|
Packit |
6c4009 |
default:
|
|
Packit |
6c4009 |
return ARGP_ERR_UNKNOWN;
|
|
Packit |
6c4009 |
}
|
|
Packit |
6c4009 |
return 0;
|
|
Packit |
6c4009 |
}
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
static char *
|
|
Packit |
6c4009 |
more_help (int key, const char *text, void *input)
|
|
Packit |
6c4009 |
{
|
|
Packit |
6c4009 |
char *tp = NULL;
|
|
Packit |
6c4009 |
switch (key)
|
|
Packit |
6c4009 |
{
|
|
Packit |
6c4009 |
case ARGP_KEY_HELP_EXTRA:
|
|
Packit |
6c4009 |
/* We print some extra information. */
|
|
Packit |
6c4009 |
if (asprintf (&tp, gettext ("\
|
|
Packit |
6c4009 |
For bug reporting instructions, please see:\n\
|
|
Packit |
6c4009 |
%s.\n"), REPORT_BUGS_TO) < 0)
|
|
Packit |
6c4009 |
return NULL;
|
|
Packit |
6c4009 |
return tp;
|
|
Packit |
6c4009 |
default:
|
|
Packit |
6c4009 |
break;
|
|
Packit |
6c4009 |
}
|
|
Packit |
6c4009 |
return (char *) text;
|
|
Packit |
6c4009 |
}
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
/* Print the version information. */
|
|
Packit |
6c4009 |
static void
|
|
Packit |
6c4009 |
print_version (FILE *stream, struct argp_state *state)
|
|
Packit |
6c4009 |
{
|
|
Packit |
6c4009 |
fprintf (stream, "makedb %s%s\n", PKGVERSION, VERSION);
|
|
Packit |
6c4009 |
fprintf (stream, gettext ("\
|
|
Packit |
6c4009 |
Copyright (C) %s Free Software Foundation, Inc.\n\
|
|
Packit |
6c4009 |
This is free software; see the source for copying conditions. There is NO\n\
|
|
Packit |
6c4009 |
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\
|
|
Packit |
6c4009 |
"), "2018");
|
|
Packit |
6c4009 |
fprintf (stream, gettext ("Written by %s.\n"), "Ulrich Drepper");
|
|
Packit |
6c4009 |
}
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
static int
|
|
Packit |
6c4009 |
dbentry_compare (const void *p1, const void *p2)
|
|
Packit |
6c4009 |
{
|
|
Packit |
6c4009 |
const struct dbentry *d1 = (const struct dbentry *) p1;
|
|
Packit |
6c4009 |
const struct dbentry *d2 = (const struct dbentry *) p2;
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
if (d1->hashval != d2->hashval)
|
|
Packit |
6c4009 |
return d1->hashval < d2->hashval ? -1 : 1;
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
return strcmp (d1->str, d2->str);
|
|
Packit |
6c4009 |
}
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
static int
|
|
Packit |
6c4009 |
valstr_compare (const void *p1, const void *p2)
|
|
Packit |
6c4009 |
{
|
|
Packit |
6c4009 |
const struct valstrentry *d1 = (const struct valstrentry *) p1;
|
|
Packit |
6c4009 |
const struct valstrentry *d2 = (const struct valstrentry *) p2;
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
return strcmp (d1->str, d2->str);
|
|
Packit |
6c4009 |
}
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
static int
|
|
Packit |
6c4009 |
process_input (FILE *input, const char *inname, int to_lowercase, int be_quiet)
|
|
Packit |
6c4009 |
{
|
|
Packit |
6c4009 |
char *line;
|
|
Packit |
6c4009 |
size_t linelen;
|
|
Packit |
6c4009 |
int status;
|
|
Packit |
6c4009 |
size_t linenr;
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
line = NULL;
|
|
Packit |
6c4009 |
linelen = 0;
|
|
Packit |
6c4009 |
status = EXIT_SUCCESS;
|
|
Packit |
6c4009 |
linenr = 0;
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
struct database *last_database = NULL;
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
while (!feof_unlocked (input))
|
|
Packit |
6c4009 |
{
|
|
Packit |
6c4009 |
ssize_t n = getline (&line, &linelen, input);
|
|
Packit |
6c4009 |
if (n < 0)
|
|
Packit |
6c4009 |
/* This means end of file or some bug. */
|
|
Packit |
6c4009 |
break;
|
|
Packit |
6c4009 |
if (n == 0)
|
|
Packit |
6c4009 |
/* Short read. Probably interrupted system call. */
|
|
Packit |
6c4009 |
continue;
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
++linenr;
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
if (line[n - 1] == '\n')
|
|
Packit |
6c4009 |
/* Remove trailing newline. */
|
|
Packit |
6c4009 |
line[--n] = '\0';
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
char *cp = line;
|
|
Packit |
6c4009 |
while (isspace (*cp))
|
|
Packit |
6c4009 |
++cp;
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
if (*cp == '#' || *cp == '\0')
|
|
Packit |
6c4009 |
/* First non-space character in line '#': it's a comment.
|
|
Packit |
6c4009 |
Also go to the next line if it is empty except for whitespaces. */
|
|
Packit |
6c4009 |
continue;
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
/* Skip over the character indicating the database so that it is not
|
|
Packit |
6c4009 |
affected by TO_LOWERCASE. */
|
|
Packit |
6c4009 |
char *key = cp++;
|
|
Packit |
6c4009 |
while (*cp != '\0' && !isspace (*cp))
|
|
Packit |
6c4009 |
{
|
|
Packit |
6c4009 |
if (to_lowercase)
|
|
Packit |
6c4009 |
*cp = tolower (*cp);
|
|
Packit |
6c4009 |
++cp;
|
|
Packit |
6c4009 |
}
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
if (*cp == '\0')
|
|
Packit |
6c4009 |
/* It's a line without a value field. */
|
|
Packit |
6c4009 |
continue;
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
*cp++ = '\0';
|
|
Packit |
6c4009 |
size_t keylen = cp - key;
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
while (isspace (*cp))
|
|
Packit |
6c4009 |
++cp;
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
char *data = cp;
|
|
Packit |
6c4009 |
size_t datalen = (&line[n] - cp) + 1;
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
/* Find the database. */
|
|
Packit |
6c4009 |
if (last_database == NULL || last_database->dbid != key[0])
|
|
Packit |
6c4009 |
{
|
|
Packit |
6c4009 |
last_database = databases;
|
|
Packit |
6c4009 |
while (last_database != NULL && last_database->dbid != key[0])
|
|
Packit |
6c4009 |
last_database = last_database->next;
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
if (last_database == NULL)
|
|
Packit |
6c4009 |
{
|
|
Packit |
6c4009 |
last_database = xmalloc (sizeof (*last_database));
|
|
Packit |
6c4009 |
last_database->dbid = key[0];
|
|
Packit |
6c4009 |
last_database->extra_string = false;
|
|
Packit |
6c4009 |
last_database->next = databases;
|
|
Packit |
6c4009 |
last_database->entries = NULL;
|
|
Packit |
6c4009 |
last_database->nentries = 0;
|
|
Packit |
6c4009 |
last_database->keystrlen = 0;
|
|
Packit |
6c4009 |
databases = last_database;
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
struct db_option *runp = db_options;
|
|
Packit |
6c4009 |
while (runp != NULL)
|
|
Packit |
6c4009 |
if (runp->dbid == key[0])
|
|
Packit |
6c4009 |
{
|
|
Packit |
6c4009 |
last_database->extra_string = true;
|
|
Packit |
6c4009 |
break;
|
|
Packit |
6c4009 |
}
|
|
Packit |
6c4009 |
else
|
|
Packit |
6c4009 |
runp = runp->next;
|
|
Packit |
6c4009 |
}
|
|
Packit |
6c4009 |
}
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
/* Skip the database selector. */
|
|
Packit |
6c4009 |
++key;
|
|
Packit |
6c4009 |
--keylen;
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
/* Store the data. */
|
|
Packit |
6c4009 |
struct valstrentry *nentry = xmalloc (sizeof (struct valstrentry)
|
|
Packit |
6c4009 |
+ datalen);
|
|
Packit |
6c4009 |
if (last_database->extra_string)
|
|
Packit |
6c4009 |
nentry->idx = extrastrlen;
|
|
Packit |
6c4009 |
else
|
|
Packit |
6c4009 |
nentry->idx = valstrlen;
|
|
Packit |
6c4009 |
nentry->extra_string = last_database->extra_string;
|
|
Packit |
6c4009 |
memcpy (nentry->str, data, datalen);
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
struct valstrentry **fdata = tsearch (nentry, &valstrtree,
|
|
Packit |
6c4009 |
valstr_compare);
|
|
Packit |
6c4009 |
if (fdata == NULL)
|
|
Packit |
6c4009 |
error (EXIT_FAILURE, errno, gettext ("cannot create search tree"));
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
if (*fdata != nentry)
|
|
Packit |
6c4009 |
{
|
|
Packit |
6c4009 |
/* We can reuse a string. */
|
|
Packit |
6c4009 |
free (nentry);
|
|
Packit |
6c4009 |
nentry = *fdata;
|
|
Packit |
6c4009 |
}
|
|
Packit |
6c4009 |
else
|
|
Packit |
6c4009 |
if (last_database->extra_string)
|
|
Packit |
6c4009 |
extrastrlen += datalen;
|
|
Packit |
6c4009 |
else
|
|
Packit |
6c4009 |
valstrlen += datalen;
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
/* Store the key. */
|
|
Packit |
6c4009 |
struct dbentry *newp = xmalloc (sizeof (struct dbentry) + keylen);
|
|
Packit |
6c4009 |
newp->validx = nentry->idx;
|
|
Packit |
6c4009 |
newp->hashval = __hash_string (key);
|
|
Packit |
6c4009 |
memcpy (newp->str, key, keylen);
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
struct dbentry **found = tsearch (newp, &last_database->entries,
|
|
Packit |
6c4009 |
dbentry_compare);
|
|
Packit |
6c4009 |
if (found == NULL)
|
|
Packit |
6c4009 |
error (EXIT_FAILURE, errno, gettext ("cannot create search tree"));
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
if (*found != newp)
|
|
Packit |
6c4009 |
{
|
|
Packit |
6c4009 |
free (newp);
|
|
Packit |
6c4009 |
if (!be_quiet)
|
|
Packit |
6c4009 |
error_at_line (0, 0, inname, linenr, gettext ("duplicate key"));
|
|
Packit |
6c4009 |
continue;
|
|
Packit |
6c4009 |
}
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
++last_database->nentries;
|
|
Packit |
6c4009 |
last_database->keystrlen += keylen;
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
any_dbentry = true;
|
|
Packit |
6c4009 |
}
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
if (ferror_unlocked (input))
|
|
Packit |
6c4009 |
{
|
|
Packit |
6c4009 |
error (0, 0, gettext ("problems while reading `%s'"), inname);
|
|
Packit |
6c4009 |
status = EXIT_FAILURE;
|
|
Packit |
6c4009 |
}
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
return status;
|
|
Packit |
6c4009 |
}
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
static void
|
|
Packit |
6c4009 |
copy_valstr (const void *nodep, const VISIT which, const int depth)
|
|
Packit |
6c4009 |
{
|
|
Packit |
6c4009 |
if (which != leaf && which != postorder)
|
|
Packit |
6c4009 |
return;
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
const struct valstrentry *p = *(const struct valstrentry **) nodep;
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
strcpy (valstrtab + (p->extra_string ? valstrlen : 0) + p->idx, p->str);
|
|
Packit |
6c4009 |
}
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
/* Determine if the candidate is prime by using a modified trial division
|
|
Packit |
6c4009 |
algorithm. The candidate must be both odd and greater than 4. */
|
|
Packit |
6c4009 |
static int
|
|
Packit |
6c4009 |
is_prime (size_t candidate)
|
|
Packit |
6c4009 |
{
|
|
Packit |
6c4009 |
size_t divn = 3;
|
|
Packit |
6c4009 |
size_t sq = divn * divn;
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
assert (candidate > 4 && candidate % 2 != 0);
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
while (sq < candidate && candidate % divn != 0)
|
|
Packit |
6c4009 |
{
|
|
Packit |
6c4009 |
++divn;
|
|
Packit |
6c4009 |
sq += 4 * divn;
|
|
Packit |
6c4009 |
++divn;
|
|
Packit |
6c4009 |
}
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
return candidate % divn != 0;
|
|
Packit |
6c4009 |
}
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
static size_t
|
|
Packit |
6c4009 |
next_prime (size_t seed)
|
|
Packit |
6c4009 |
{
|
|
Packit |
6c4009 |
/* Make sure that we're always greater than 4. */
|
|
Packit |
6c4009 |
seed = (seed + 4) | 1;
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
while (!is_prime (seed))
|
|
Packit |
6c4009 |
seed += 2;
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
return seed;
|
|
Packit |
6c4009 |
}
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
static void
|
|
Packit |
6c4009 |
compute_tables (void)
|
|
Packit |
6c4009 |
{
|
|
Packit |
6c4009 |
valstrtab = xmalloc (roundup (valstrlen + extrastrlen, sizeof (stridx_t)));
|
|
Packit |
6c4009 |
while ((valstrlen + extrastrlen) % sizeof (stridx_t) != 0)
|
|
Packit |
6c4009 |
valstrtab[valstrlen++] = '\0';
|
|
Packit |
6c4009 |
twalk (valstrtree, copy_valstr);
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
static struct database *db;
|
|
Packit |
6c4009 |
for (db = databases; db != NULL; db = db->next)
|
|
Packit |
6c4009 |
if (db->nentries != 0)
|
|
Packit |
6c4009 |
{
|
|
Packit |
6c4009 |
++ndatabases;
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
/* We simply use an odd number large than twice the number of
|
|
Packit |
6c4009 |
elements to store in the hash table for the size. This gives
|
|
Packit |
6c4009 |
enough efficiency. */
|
|
Packit |
6c4009 |
#define TEST_RANGE 30
|
|
Packit |
6c4009 |
size_t nhashentries_min = next_prime (db->nentries < TEST_RANGE
|
|
Packit |
6c4009 |
? db->nentries
|
|
Packit |
6c4009 |
: db->nentries * 2 - TEST_RANGE);
|
|
Packit |
6c4009 |
size_t nhashentries_max = MAX (nhashentries_min, db->nentries * 4);
|
|
Packit |
6c4009 |
size_t nhashentries_best = nhashentries_min;
|
|
Packit |
6c4009 |
size_t chainlength_best = db->nentries;
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
db->hashtable = xmalloc (2 * nhashentries_max * sizeof (stridx_t)
|
|
Packit |
6c4009 |
+ db->keystrlen);
|
|
Packit |
6c4009 |
db->keyidxtab = db->hashtable + nhashentries_max;
|
|
Packit |
6c4009 |
db->keystrtab = (char *) (db->keyidxtab + nhashentries_max);
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
static size_t max_chainlength;
|
|
Packit |
6c4009 |
static char *wp;
|
|
Packit |
6c4009 |
static size_t nhashentries;
|
|
Packit |
6c4009 |
static bool copy_string;
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
void add_key(const void *nodep, const VISIT which, const int depth)
|
|
Packit |
6c4009 |
{
|
|
Packit |
6c4009 |
if (which != leaf && which != postorder)
|
|
Packit |
6c4009 |
return;
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
const struct dbentry *dbe = *(const struct dbentry **) nodep;
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
ptrdiff_t stridx;
|
|
Packit |
6c4009 |
if (copy_string)
|
|
Packit |
6c4009 |
{
|
|
Packit |
6c4009 |
stridx = wp - db->keystrtab;
|
|
Packit |
6c4009 |
wp = stpcpy (wp, dbe->str) + 1;
|
|
Packit |
6c4009 |
}
|
|
Packit |
6c4009 |
else
|
|
Packit |
6c4009 |
stridx = 0;
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
size_t hidx = dbe->hashval % nhashentries;
|
|
Packit |
6c4009 |
size_t hval2 = 1 + dbe->hashval % (nhashentries - 2);
|
|
Packit |
6c4009 |
size_t chainlength = 0;
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
while (db->hashtable[hidx] != ~((stridx_t) 0))
|
|
Packit |
6c4009 |
{
|
|
Packit |
6c4009 |
++chainlength;
|
|
Packit |
6c4009 |
if ((hidx += hval2) >= nhashentries)
|
|
Packit |
6c4009 |
hidx -= nhashentries;
|
|
Packit |
6c4009 |
}
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
db->hashtable[hidx] = ((db->extra_string ? valstrlen : 0)
|
|
Packit |
6c4009 |
+ dbe->validx);
|
|
Packit |
6c4009 |
db->keyidxtab[hidx] = stridx;
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
max_chainlength = MAX (max_chainlength, chainlength);
|
|
Packit |
6c4009 |
}
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
copy_string = false;
|
|
Packit |
6c4009 |
nhashentries = nhashentries_min;
|
|
Packit |
6c4009 |
for (size_t cnt = 0; cnt < TEST_RANGE; ++cnt)
|
|
Packit |
6c4009 |
{
|
|
Packit |
6c4009 |
memset (db->hashtable, '\xff', nhashentries * sizeof (stridx_t));
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
max_chainlength = 0;
|
|
Packit |
6c4009 |
wp = db->keystrtab;
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
twalk (db->entries, add_key);
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
if (max_chainlength == 0)
|
|
Packit |
6c4009 |
{
|
|
Packit |
6c4009 |
/* No need to look further, this is as good as it gets. */
|
|
Packit |
6c4009 |
nhashentries_best = nhashentries;
|
|
Packit |
6c4009 |
break;
|
|
Packit |
6c4009 |
}
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
if (max_chainlength < chainlength_best)
|
|
Packit |
6c4009 |
{
|
|
Packit |
6c4009 |
chainlength_best = max_chainlength;
|
|
Packit |
6c4009 |
nhashentries_best = nhashentries;
|
|
Packit |
6c4009 |
}
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
nhashentries = next_prime (nhashentries + 1);
|
|
Packit |
6c4009 |
if (nhashentries > nhashentries_max)
|
|
Packit |
6c4009 |
break;
|
|
Packit |
6c4009 |
}
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
/* Recompute the best table again, this time fill in the strings. */
|
|
Packit |
6c4009 |
nhashentries = nhashentries_best;
|
|
Packit |
6c4009 |
memset (db->hashtable, '\xff',
|
|
Packit |
6c4009 |
2 * nhashentries_max * sizeof (stridx_t));
|
|
Packit |
6c4009 |
copy_string = true;
|
|
Packit |
6c4009 |
wp = db->keystrtab;
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
twalk (db->entries, add_key);
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
db->nhashentries = nhashentries_best;
|
|
Packit |
6c4009 |
nhashentries_total += nhashentries_best;
|
|
Packit |
6c4009 |
}
|
|
Packit |
6c4009 |
}
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
static int
|
|
Packit |
6c4009 |
write_output (int fd)
|
|
Packit |
6c4009 |
{
|
|
Packit |
6c4009 |
struct nss_db_header *header;
|
|
Packit |
6c4009 |
uint64_t file_offset = (sizeof (struct nss_db_header)
|
|
Packit |
6c4009 |
+ (ndatabases * sizeof (header->dbs[0])));
|
|
Packit |
6c4009 |
header = alloca (file_offset);
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
header->magic = NSS_DB_MAGIC;
|
|
Packit |
6c4009 |
header->ndbs = ndatabases;
|
|
Packit |
6c4009 |
header->valstroffset = file_offset;
|
|
Packit |
6c4009 |
header->valstrlen = valstrlen;
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
size_t filled_dbs = 0;
|
|
Packit |
6c4009 |
struct iovec iov[2 + ndatabases * 3];
|
|
Packit |
6c4009 |
iov[0].iov_base = header;
|
|
Packit |
6c4009 |
iov[0].iov_len = file_offset;
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
iov[1].iov_base = valstrtab;
|
|
Packit |
6c4009 |
iov[1].iov_len = valstrlen + extrastrlen;
|
|
Packit |
6c4009 |
file_offset += iov[1].iov_len;
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
size_t keydataoffset = file_offset + nhashentries_total * sizeof (stridx_t);
|
|
Packit |
6c4009 |
for (struct database *db = databases; db != NULL; db = db->next)
|
|
Packit |
6c4009 |
if (db->entries != NULL)
|
|
Packit |
6c4009 |
{
|
|
Packit |
6c4009 |
assert (file_offset % sizeof (stridx_t) == 0);
|
|
Packit |
6c4009 |
assert (filled_dbs < ndatabases);
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
header->dbs[filled_dbs].id = db->dbid;
|
|
Packit |
6c4009 |
memset (header->dbs[filled_dbs].pad, '\0',
|
|
Packit |
6c4009 |
sizeof (header->dbs[0].pad));
|
|
Packit |
6c4009 |
header->dbs[filled_dbs].hashsize = db->nhashentries;
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
iov[2 + filled_dbs].iov_base = db->hashtable;
|
|
Packit |
6c4009 |
iov[2 + filled_dbs].iov_len = db->nhashentries * sizeof (stridx_t);
|
|
Packit |
6c4009 |
header->dbs[filled_dbs].hashoffset = file_offset;
|
|
Packit |
6c4009 |
file_offset += iov[2 + filled_dbs].iov_len;
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
iov[2 + ndatabases + filled_dbs * 2].iov_base = db->keyidxtab;
|
|
Packit |
6c4009 |
iov[2 + ndatabases + filled_dbs * 2].iov_len
|
|
Packit |
6c4009 |
= db->nhashentries * sizeof (stridx_t);
|
|
Packit |
6c4009 |
header->dbs[filled_dbs].keyidxoffset = keydataoffset;
|
|
Packit |
6c4009 |
keydataoffset += iov[2 + ndatabases + filled_dbs * 2].iov_len;
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
iov[3 + ndatabases + filled_dbs * 2].iov_base = db->keystrtab;
|
|
Packit |
6c4009 |
iov[3 + ndatabases + filled_dbs * 2].iov_len = db->keystrlen;
|
|
Packit |
6c4009 |
header->dbs[filled_dbs].keystroffset = keydataoffset;
|
|
Packit |
6c4009 |
keydataoffset += iov[3 + ndatabases + filled_dbs * 2].iov_len;
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
++filled_dbs;
|
|
Packit |
6c4009 |
}
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
assert (filled_dbs == ndatabases);
|
|
Packit |
6c4009 |
assert (file_offset == (iov[0].iov_len + iov[1].iov_len
|
|
Packit |
6c4009 |
+ nhashentries_total * sizeof (stridx_t)));
|
|
Packit |
6c4009 |
header->allocate = file_offset;
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
if (writev (fd, iov, 2 + ndatabases * 3) != keydataoffset)
|
|
Packit |
6c4009 |
{
|
|
Packit |
6c4009 |
error (0, errno, gettext ("failed to write new database file"));
|
|
Packit |
6c4009 |
return EXIT_FAILURE;
|
|
Packit |
6c4009 |
}
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
return EXIT_SUCCESS;
|
|
Packit |
6c4009 |
}
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
static int
|
|
Packit |
6c4009 |
print_database (int fd)
|
|
Packit |
6c4009 |
{
|
|
Packit |
6c4009 |
struct stat64 st;
|
|
Packit |
6c4009 |
if (fstat64 (fd, &st) != 0)
|
|
Packit |
6c4009 |
error (EXIT_FAILURE, errno, gettext ("cannot stat database file"));
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
const struct nss_db_header *header = mmap (NULL, st.st_size, PROT_READ,
|
|
Packit |
6c4009 |
MAP_PRIVATE|MAP_POPULATE, fd, 0);
|
|
Packit |
6c4009 |
if (header == MAP_FAILED)
|
|
Packit |
6c4009 |
error (EXIT_FAILURE, errno, gettext ("cannot map database file"));
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
if (header->magic != NSS_DB_MAGIC)
|
|
Packit |
6c4009 |
error (EXIT_FAILURE, 0, gettext ("file not a database file"));
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
const char *valstrtab = (const char *) header + header->valstroffset;
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
for (unsigned int dbidx = 0; dbidx < header->ndbs; ++dbidx)
|
|
Packit |
6c4009 |
{
|
|
Packit |
6c4009 |
const stridx_t *stridxtab
|
|
Packit |
6c4009 |
= ((const stridx_t *) ((const char *) header
|
|
Packit |
6c4009 |
+ header->dbs[dbidx].keyidxoffset));
|
|
Packit |
6c4009 |
const char *keystrtab
|
|
Packit |
6c4009 |
= (const char *) header + header->dbs[dbidx].keystroffset;
|
|
Packit |
6c4009 |
const stridx_t *hashtab
|
|
Packit |
6c4009 |
= (const stridx_t *) ((const char *) header
|
|
Packit |
6c4009 |
+ header->dbs[dbidx].hashoffset);
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
for (uint32_t hidx = 0; hidx < header->dbs[dbidx].hashsize; ++hidx)
|
|
Packit |
6c4009 |
if (hashtab[hidx] != ~((stridx_t) 0))
|
|
Packit |
6c4009 |
printf ("%c%s %s\n",
|
|
Packit |
6c4009 |
header->dbs[dbidx].id,
|
|
Packit |
6c4009 |
keystrtab + stridxtab[hidx],
|
|
Packit |
6c4009 |
valstrtab + hashtab[hidx]);
|
|
Packit |
6c4009 |
}
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
return EXIT_SUCCESS;
|
|
Packit |
6c4009 |
}
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
#ifdef HAVE_SELINUX
|
|
Packit |
6c4009 |
static void
|
|
Packit |
6c4009 |
set_file_creation_context (const char *outname, mode_t mode)
|
|
Packit |
6c4009 |
{
|
|
Packit |
6c4009 |
static int enabled;
|
|
Packit |
6c4009 |
static int enforcing;
|
|
Packit |
6c4009 |
security_context_t ctx;
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
/* Check if SELinux is enabled, and remember. */
|
|
Packit |
6c4009 |
if (enabled == 0)
|
|
Packit |
6c4009 |
enabled = is_selinux_enabled () ? 1 : -1;
|
|
Packit |
6c4009 |
if (enabled < 0)
|
|
Packit |
6c4009 |
return;
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
/* Check if SELinux is enforcing, and remember. */
|
|
Packit |
6c4009 |
if (enforcing == 0)
|
|
Packit |
6c4009 |
enforcing = security_getenforce () ? 1 : -1;
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
/* Determine the context which the file should have. */
|
|
Packit |
6c4009 |
ctx = NULL;
|
|
Packit |
6c4009 |
if (matchpathcon (outname, S_IFREG | mode, &ctx) == 0 && ctx != NULL)
|
|
Packit |
6c4009 |
{
|
|
Packit |
6c4009 |
if (setfscreatecon (ctx) != 0)
|
|
Packit |
6c4009 |
error (enforcing > 0 ? EXIT_FAILURE : 0, 0,
|
|
Packit |
6c4009 |
gettext ("cannot set file creation context for `%s'"),
|
|
Packit |
6c4009 |
outname);
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
freecon (ctx);
|
|
Packit |
6c4009 |
}
|
|
Packit |
6c4009 |
}
|
|
Packit |
6c4009 |
|
|
Packit |
6c4009 |
static void
|
|
Packit |
6c4009 |
reset_file_creation_context (void)
|
|
Packit |
6c4009 |
{
|
|
Packit |
6c4009 |
setfscreatecon (NULL);
|
|
Packit |
6c4009 |
}
|
|
Packit |
6c4009 |
#endif
|