Rewrite makedb to avoid using db library

This commit is contained in:
Ulrich Drepper 2011-06-02 14:43:16 -04:00
parent c71ca1f89c
commit 9ee76b5ae8
3 changed files with 606 additions and 101 deletions

View File

@ -1,3 +1,8 @@
2011-06-02 Ulrich Drepper <drepper@gmail.com>
* nss/makedb.c: Rewritten to not use database library.
* nss/Makefile: Update to build new makedb program.
2011-06-14 Andreas Jaeger <aj@suse.de>
* sysdeps/unix/sysv/linux/check_native.c: Include <string.h> for

View File

@ -37,8 +37,10 @@ routines = nsswitch getnssent getnssent_r digits_dots \
databases = proto service hosts network grp pwd rpc ethers \
spwd netgrp key alias sgrp
others := getent
install-bin := getent
others := getent makedb
install-bin := getent makedb
makedb-modules = xmalloc hash-string
extra-objs += $(makedb-modules:=.o)
tests = test-netdb tst-nss-test1
xtests = bug-erange
@ -60,7 +62,7 @@ extra-libs-others = $(extra-libs)
# The sources are found in the appropriate subdir.
subdir-dirs = $(services:%=nss_%)
vpath %.c $(subdir-dirs)
vpath %.c $(subdir-dirs) ../locale/programs ../intl
libnss_files-routines := $(addprefix files-,$(databases)) \
@ -80,6 +82,10 @@ ifeq (yes,$(build-static-nss))
$(objpfx)getent: $(objpfx)libnss_files.a
endif
ifeq (yes,$(have-selinux))
LDLIBS-makedb := -lselinux
endif
# Depend on libc.so so a DT_NEEDED is generated in the shared objects.
# This ensures they will load libc.so for needed symbols if loaded by
# a statically-linked program that hasn't already loaded it.
@ -88,6 +94,8 @@ $(services:%=$(objpfx)libnss_%.so): $(libnss-libc) \
$(common-objpfx)libc_nonshared.a
$(objpfx)makedb: $(makedb-modules:%=$(objpfx)%.o)
distribute += nss_test1.c
CFLAGS-nss_test1.c = -DNOT_IN_libc=1

View File

@ -1,5 +1,5 @@
/* Create simple DB database from textual input.
Copyright (C) 1996, 1997, 1998, 1999, 2000 Free Software Foundation, Inc.
Copyright (C) 1996-2000, 2011 Free Software Foundation, Inc.
This file is part of the GNU C Library.
Contributed by Ulrich Drepper <drepper@cygnus.com>, 1996.
@ -19,25 +19,115 @@
02111-1307 USA. */
#include <argp.h>
#include <assert.h>
#include <ctype.h>
#include <dlfcn.h>
#include <errno.h>
#include <error.h>
#include <fcntl.h>
#include <inttypes.h>
#include <libintl.h>
#include <locale.h>
#include <search.h>
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include "nss_db/dummy-db.h"
/* Get libc version number. */
#include "../version.h"
/* The hashing function we use. */
#include "../intl/hash-string.h"
/* SELinux support. */
#ifdef HAVE_SELINUX
# include <selinux/selinux.h>
#endif
#define PACKAGE _libc_intl_domainname
/* String table index type. */
typedef uint32_t stridx_t;
/* Database file header. */
struct nss_db_header
{
uint32_t magic;
#define NSS_DB_MAGIC 0xdd110601
uint32_t ndbs;
uint64_t valstroffset;
uint64_t valstrlen;
struct
{
char id;
enum nss_db_type { nss_db_type_hash = 0,
nss_db_type_iterate,
nss_db_type_int4 } type:8;
char pad[sizeof (uint32_t) - 2];
uint32_t hashsize;
uint64_t hashoffset;
uint64_t stroffset;
} dbs[0];
};
struct nss_db_entry
{
stridx_t keyidx;
stridx_t dataidx;
};
/* List of data bases. */
struct database
{
char dbid;
enum nss_db_type type;
struct database *next;
void *entries;
size_t nentries;
size_t keystrlen;
size_t nhashentries;
struct nss_db_entry *hashtable;
char *keystrtab;
} *databases;
static size_t ndatabases;
static size_t valstrlen;
static void *valstrtree;
static char *valstrtab;
/* Database entry. */
struct dbentry
{
size_t keylen;
stridx_t validx;
uint32_t hashval;
char str[0];
};
/* Stored string entry. */
struct valstrentry
{
stridx_t idx;
char str[0];
};
/* Database type specifiers. */
struct dbtype
{
char dbid;
enum nss_db_type type;
struct dbtype *next;
};
static struct dbtype *dbtypes;
/* True if any entry has been added. */
static bool any_dbentry;
/* If non-zero convert key to lower case. */
static int to_lowercase;
@ -63,11 +153,16 @@ static const struct argp_option options[] =
N_("Do not print messages while building database") },
{ "undo", 'u', NULL, 0,
N_("Print content of database file, one entry a line") },
{ NULL, 0, NULL, 0, N_("Select index type") },
{ "iterate", 'I', "KEY", 0,
N_("Index identified by KEY used to iterate over database") },
{ "binary", 'B', "KEY", 0,
N_("Index identified by KEY has binary key value") },
{ NULL, 0, NULL, 0, NULL }
};
/* Short description of program. */
static const char doc[] = N_("Create simple DB database from textual input.");
static const char doc[] = N_("Create simple database from textual input.");
/* Strings for arguments in help texts. */
static const char args_doc[] = N_("\
@ -87,9 +182,26 @@ static struct argp argp =
/* Prototypes for local functions. */
static int process_input (FILE *input, const char *inname, NSS_DB *output,
static int process_input (FILE *input, const char *inname,
int to_lowercase, int be_quiet);
static int print_database (NSS_DB *db);
static int print_database (int fd);
static void compute_tables (void);
static int write_output (int fd);
/* SELinux support. */
#ifdef HAVE_SELINUX
/* Set the SELinux file creation context for the given file. */
static void set_file_creation_context (const char *outname, mode_t mode);
static void reset_file_creation_context (void);
#else
# define set_file_creation_context(_outname,_mode)
# define reset_file_creation_context()
#endif
/* External functions. */
extern void *xmalloc (size_t n) __attribute_malloc__;
extern void *xcalloc (size_t n, size_t m) __attribute_malloc__;
int
@ -97,8 +209,6 @@ main (int argc, char *argv[])
{
const char *input_name;
FILE *input_file;
NSS_DB *db_file;
int status;
int remaining;
int mode = 0666;
@ -136,24 +246,17 @@ main (int argc, char *argv[])
output_name = argv[remaining];
}
/* First load the shared object to initialize version dependend
variables. */
if (load_db () != NSS_STATUS_SUCCESS)
error (EXIT_FAILURE, 0, gettext ("No usable database library found."));
/* Special handling if we are asked to print the database. */
if (do_undo)
{
dbopen (input_name, db_rdonly, 0666, &db_file);
if (db_file == NULL)
error (EXIT_FAILURE, 0, gettext ("cannot open database file `%s': %s"),
input_name,
(errno == EINVAL ? gettext ("incorrectly formatted file")
: strerror (errno)));
int fd = open (input_name, O_RDONLY);
if (fd == -1)
error (EXIT_FAILURE, errno, gettext ("cannot open database file `%s'"),
input_name);
status = print_database (db_file);
int status = print_database (fd);
db_file->close (db_file->db, 0);
close (fd);
return status;
}
@ -163,34 +266,83 @@ main (int argc, char *argv[])
input_file = stdin;
else
{
struct stat st;
struct stat64 st;
input_file = fopen (input_name, "r");
input_file = fopen64 (input_name, "r");
if (input_file == NULL)
error (EXIT_FAILURE, errno, gettext ("cannot open input file `%s'"),
input_name);
/* Get the access rights from the source file. The output file should
have the same. */
if (fstat (fileno (input_file), &st) >= 0)
if (fstat64 (fileno (input_file), &st) >= 0)
mode = st.st_mode & ACCESSPERMS;
}
/* Open output file. This must not be standard output so we don't
handle "-" and "/dev/stdout" special. */
dbopen (output_name, DB_CREATE | db_truncate, mode, &db_file);
if (db_file == NULL)
error (EXIT_FAILURE, errno, gettext ("cannot open output file `%s'"),
output_name);
/* Start the real work. */
status = process_input (input_file, input_name, db_file, to_lowercase,
be_quiet);
int status = process_input (input_file, input_name, to_lowercase, be_quiet);
/* Close files. */
if (input_file != stdin)
fclose (input_file);
db_file->close (db_file->db, 0);
/* No need to continue when we did not read the file successfully. */
if (status != EXIT_SUCCESS)
return status;
/* Bail out if nothing is to be done. */
if (!any_dbentry)
error (EXIT_SUCCESS, 0, gettext ("no entries to be processed"));
/* Compute hash and string tables. */
compute_tables ();
/* Open output file. This must not be standard output so we don't
handle "-" and "/dev/stdout" special. */
char *tmp_output_name;
if (asprintf (&tmp_output_name, "%s.XXXXXX", output_name) == -1)
error (EXIT_FAILURE, errno, gettext ("cannot create temporary file name"));
set_file_creation_context (output_name, mode);
int fd = mkstemp (tmp_output_name);
reset_file_creation_context ();
if (fd == -1)
error (EXIT_FAILURE, errno, gettext ("cannot create temporary file"));
// XXX SELinux context
status = write_output (fd);
if (status == EXIT_SUCCESS)
{
struct stat64 st;
if (fstat64 (fd, &st) == 0)
{
if ((st.st_mode & ACCESSPERMS) != mode)
/* We ignore problems with changing the mode. */
fchmod (fd, mode);
}
else
{
error (0, errno, gettext ("cannot stat newly created file"));
status = EXIT_FAILURE;
}
}
close (fd);
if (status == EXIT_SUCCESS)
{
if (rename (tmp_output_name, output_name) != 0)
{
error (0, errno, gettext ("cannot rename temporary file"));
status = EXIT_FAILURE;
goto do_unlink;
}
}
else
do_unlink:
unlink (tmp_output_name);
return status;
}
@ -200,6 +352,7 @@ main (int argc, char *argv[])
static error_t
parse_opt (int key, char *arg, struct argp_state *state)
{
struct dbtype *newtype;
switch (key)
{
case 'f':
@ -214,6 +367,17 @@ parse_opt (int key, char *arg, struct argp_state *state)
case 'u':
do_undo = 1;
break;
case 'I':
case 'B':
if (arg[0] == '\0' || arg[1] != '\0')
error (EXIT_FAILURE, 0, gettext ("\
argument for option to specify database type must be a single-byte character"));
newtype = xmalloc (sizeof (struct dbtype));
newtype->dbid = arg[0];
newtype->type = key == 'I' ? nss_db_type_iterate : nss_db_type_int4;
newtype->next = dbtypes;
dbtypes = newtype;
break;
default:
return ARGP_ERR_UNKNOWN;
}
@ -246,16 +410,44 @@ print_version (FILE *stream, struct argp_state *state)
Copyright (C) %s Free Software Foundation, Inc.\n\
This is free software; see the source for copying conditions. There is NO\n\
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\
"), "2000");
"), "2011");
fprintf (stream, gettext ("Written by %s.\n"), "Ulrich Drepper");
}
static int
process_input (input, inname, output, to_lowercase, be_quiet)
dbentry_compare (const void *p1, const void *p2)
{
const struct dbentry *d1 = (const struct dbentry *) p1;
const struct dbentry *d2 = (const struct dbentry *) p2;
if (d1->hashval != d2->hashval)
return d1->hashval < d2->hashval ? -1 : 1;
if (d1->keylen < d2->keylen)
return -1;
if (d1->keylen > d2->keylen)
return 1;
return memcmp (d1->str, d2->str, d1->keylen);
}
static int
valstr_compare (const void *p1, const void *p2)
{
const struct valstrentry *d1 = (const struct valstrentry *) p1;
const struct valstrentry *d2 = (const struct valstrentry *) p2;
return strcmp (d1->str, d2->str);
}
static int
process_input (input, inname, to_lowercase, be_quiet)
FILE *input;
const char *inname;
NSS_DB *output;
int to_lowercase;
int be_quiet;
{
@ -269,14 +461,11 @@ process_input (input, inname, output, to_lowercase, be_quiet)
status = EXIT_SUCCESS;
linenr = 0;
while (!feof (input))
{
DBT key;
DBT val;
char *cp;
int n;
struct database *last_database = NULL;
n = getline (&line, &linelen, input);
while (!feof_unlocked (input))
{
ssize_t n = getline (&line, &linelen, input);
if (n < 0)
/* This means end of file or some bug. */
break;
@ -290,15 +479,18 @@ process_input (input, inname, output, to_lowercase, be_quiet)
/* Remove trailing newline. */
line[--n] = '\0';
cp = line;
char *cp = line;
while (isspace (*cp))
++cp;
if (*cp == '#')
/* First non-space character in line '#': it's a comment. */
if (*cp == '#' || *cp == '\0')
/* First non-space character in line '#': it's a comment.
Also go to the next line if it is empty except for whitespaces. */
continue;
key.data = cp;
/* Skip over the character indicating the database so that it is not
affected by TO_LOWERCASE. */
char *key = cp++;
while (*cp != '\0' && !isspace (*cp))
{
if (to_lowercase)
@ -306,44 +498,131 @@ process_input (input, inname, output, to_lowercase, be_quiet)
++cp;
}
if (key.data == cp)
/* It's an empty line. */
if (*cp == '\0')
/* It's a line without a value field. */
continue;
key.size = cp - (char *) key.data;
key.flags = 0;
*cp++ = '\0';
size_t keylen = cp - key;
while (isspace (*cp))
++cp;
val.data = cp;
val.size = (&line[n] - cp) + 1;
val.flags = 0;
char *data = cp;
size_t datalen = (&line[n] - cp) + 1;
/* Store the value. */
status = output->put (output->db, NULL, &key, &val, db_nooverwrite);
if (status != 0)
/* Find the database. */
if (last_database == NULL || last_database->dbid != key[0])
{
if (status == db_keyexist)
last_database = databases;
while (last_database != NULL && last_database->dbid != key[0])
last_database = last_database->next;
if (last_database == NULL)
{
if (!be_quiet)
error_at_line (0, 0, inname, linenr,
gettext ("duplicate key"));
/* This is no real error. Just give a warning. */
status = 0;
continue;
last_database = xmalloc (sizeof (*last_database));
last_database->dbid = key[0];
last_database->type = nss_db_type_hash; /* Default. */
last_database->next = databases;
last_database->entries = NULL;
last_database->nentries = 0;
last_database->keystrlen = 0;
databases = last_database;
struct dbtype *typeit = dbtypes;
while (typeit != NULL)
if (typeit->dbid == last_database->dbid)
{
last_database->type = typeit->type;
break;
}
else
typeit = typeit->next;
}
else
error (0, status, gettext ("while writing database file"));
status = EXIT_FAILURE;
clearerr (input);
break;
}
/* Skip the database selector. */
++key;
--keylen;
/* Check the key value if it has to be numeric. */
unsigned long int keyvalue = 0;
if (last_database->type != nss_db_type_hash)
{
char *endp;
errno = 0;
keyvalue = strtoul (key, &endp, 0);
if ((keyvalue == ULONG_MAX && errno == ERANGE)
|| keyvalue > ~((stridx_t) 0))
error (EXIT_FAILURE, 0,
gettext ("index value in line %zu too large"), linenr);
if (*endp != '\0')
error (EXIT_FAILURE, 0,
gettext ("index value in line %zu is not a number"),
linenr);
}
/* Store the data. */
struct valstrentry *nentry = xmalloc (sizeof (struct valstrentry)
+ datalen);
nentry->idx = valstrlen;
memcpy (nentry->str, data, datalen);
struct valstrentry **fdata = tsearch (nentry, &valstrtree,
valstr_compare);
if (fdata == NULL)
error (EXIT_FAILURE, errno, gettext ("cannot create search tree"));
if (*fdata != nentry)
{
/* We can reuse a string. */
free (nentry);
nentry = *fdata;
}
else
valstrlen += datalen;
/* Store the key. */
struct dbentry *newp;
if (last_database->type == nss_db_type_hash)
{
newp = xmalloc (sizeof (struct dbentry) + keylen);
newp->keylen = keylen;
newp->validx = nentry->idx;
newp->hashval = __hash_string (key);
memcpy (newp->str, key, keylen);
}
else
{
newp = xmalloc (sizeof (struct dbentry) + sizeof (stridx_t));
newp->keylen = keylen = sizeof (stridx_t);
newp->validx = nentry->idx;
newp->hashval = keyvalue;
stridx_t value = keyvalue;
memcpy (newp->str, &value, sizeof (stridx_t));
}
struct dbentry **found = tsearch (newp, &last_database->entries,
dbentry_compare);
if (found == NULL)
error (EXIT_FAILURE, errno, gettext ("cannot create search tree"));
if (*found != newp)
{
free (newp);
if (!be_quiet)
error_at_line (0, 0, inname, linenr, gettext ("duplicate key"));
continue;
}
++last_database->nentries;
last_database->keystrlen += keylen;
any_dbentry = true;
}
if (ferror (input))
if (ferror_unlocked (input))
{
error (0, 0, gettext ("problems while reading `%s'"), inname);
status = EXIT_FAILURE;
@ -353,38 +632,251 @@ process_input (input, inname, output, to_lowercase, be_quiet)
}
static int
print_database (db)
NSS_DB *db;
static void
copy_valstr (const void *nodep, const VISIT which, const int depth)
{
DBT key;
DBT val;
NSS_DBC *cursor;
int status;
if (which != leaf && which != postorder)
return;
status = db->cursor (db->db, NULL, &cursor);
if (status != 0)
{
error (0, status, gettext ("while reading database"));
return EXIT_FAILURE;
const struct valstrentry *p = *(const struct valstrentry **) nodep;
strcpy (valstrtab + p->idx, p->str);
}
static void
compute_tables (void)
{
valstrtab = xmalloc (roundup (valstrlen, sizeof (stridx_t)));
while (valstrlen % sizeof (stridx_t) != 0)
valstrtab[valstrlen++] = '\0';
twalk (valstrtree, copy_valstr);
for (struct database *db = databases; db != NULL; db = db->next)
if (db->nentries != 0)
{
++ndatabases;
if (db->type == nss_db_type_iterate)
{
/* We need no hash table and no key value table in this case. */
db->nhashentries = 0;
db->hashtable = NULL;
db->keystrtab = NULL;
db->keystrlen = 0;
continue;
}
if (db->keystrlen > ~((stridx_t) 0))
error (EXIT_FAILURE, 0, gettext ("\
table size too large; recompile with larger stridx_t"));
/* We simply use an odd number large than twice the number of
elements to store in the hash table for the size. This gives
enough efficiency. */
db->nhashentries = db->nentries * 2 + 1;
db->hashtable = xmalloc (db->nhashentries
* sizeof (struct nss_db_entry));
memset (db->hashtable, '\xff',
db->nhashentries * sizeof (struct nss_db_entry));
db->keystrlen = roundup (db->keystrlen, sizeof (stridx_t));
db->keystrtab = xmalloc (db->keystrlen);
size_t max_chainlength = 0;
char *wp = db->keystrtab;
void add_key(const void *nodep, const VISIT which, const int depth)
{
if (which != leaf && which != postorder)
return;
const struct dbentry *dbe = *(const struct dbentry **) nodep;
ptrdiff_t stridx = wp - db->keystrtab;
wp = mempcpy (wp, dbe->str, dbe->keylen);
size_t hidx = dbe->hashval % db->nhashentries;
size_t hval2 = 1 + dbe->hashval % (db->nhashentries - 2);
size_t chainlength = 0;
while (db->hashtable[hidx].keyidx != ~((stridx_t) 0))
{
++chainlength;
if ((hidx += hval2) >= db->nhashentries)
hidx -= db->nhashentries;
}
db->hashtable[hidx].keyidx = stridx;
db->hashtable[hidx].dataidx = dbe->validx;
max_chainlength = MAX (max_chainlength, chainlength);
}
twalk (db->entries, add_key);
// XXX if hash length is too long resize table and start again
while ((wp - db->keystrtab) % sizeof (stridx_t) != 0)
*wp++ = '\0';
}
}
key.flags = 0;
val.flags = 0;
status = cursor->c_get (cursor->cursor, &key, &val, db_first);
while (status == 0)
static int
write_output (int fd)
{
struct nss_db_header *header;
uint64_t file_offset = (sizeof (struct nss_db_header)
+ (ndatabases * sizeof (header->dbs[0])));
header = alloca (file_offset);
header->magic = NSS_DB_MAGIC;
header->ndbs = ndatabases;
header->valstroffset = file_offset;
header->valstrlen = valstrlen;
size_t filled_dbs = 0;
struct iovec iov[2 + 2 * ndatabases];
iov[0].iov_base = header;
iov[0].iov_len = file_offset;
iov[1].iov_base = valstrtab;
iov[1].iov_len = valstrlen;
file_offset += valstrlen;
for (struct database *db = databases; db != NULL; db = db->next)
if (db->entries != NULL)
{
assert (file_offset % sizeof (stridx_t) == 0);
assert (filled_dbs < ndatabases);
header->dbs[filled_dbs].id = db->dbid;
header->dbs[filled_dbs].type = db->type;
memset (header->dbs[filled_dbs].pad, '\0',
sizeof (header->dbs[0].pad));
header->dbs[filled_dbs].hashsize = db->nhashentries;
iov[2 + filled_dbs * 2].iov_base = db->hashtable;
iov[2 + filled_dbs * 2].iov_len = (db->nhashentries
* sizeof (struct nss_db_entry));
header->dbs[filled_dbs].hashoffset = file_offset;
file_offset += iov[2 + filled_dbs * 2].iov_len;
iov[3 + filled_dbs * 2].iov_base = db->keystrtab;
iov[3 + filled_dbs * 2].iov_len = db->keystrlen;
header->dbs[filled_dbs].stroffset = file_offset;
file_offset += iov[3 + filled_dbs * 2].iov_len;
++filled_dbs;
}
assert (filled_dbs == ndatabases);
if (writev (fd, iov, 2 + 2 * ndatabases) != file_offset)
{
printf ("%.*s %s\n", (int) key.size, (char *) key.data,
(char *) val.data);
status = cursor->c_get (cursor->cursor, &key, &val, db_next);
}
if (status != db_notfound)
{
error (0, status, gettext ("while reading database"));
error (0, errno, gettext ("failed to write new database file"));
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}
static int
print_database (int fd)
{
struct stat64 st;
if (fstat64 (fd, &st) != 0)
error (EXIT_FAILURE, errno, gettext ("cannot stat database file"));
const struct nss_db_header *header = mmap (NULL, st.st_size, PROT_READ,
MAP_PRIVATE|MAP_POPULATE, fd, 0);
if (header == MAP_FAILED)
error (EXIT_FAILURE, errno, gettext ("cannot map database file"));
if (header->magic != NSS_DB_MAGIC)
error (EXIT_FAILURE, 0, gettext ("file not a database file"));
const char *valstrtab = (const char *) header + header->valstroffset;
for (unsigned int dbidx = 0; dbidx < header->ndbs; ++dbidx)
{
const char *keystrtab
= (const char *) header + header->dbs[dbidx].stroffset;
const struct nss_db_entry *hashtab
= (const struct nss_db_entry *) ((const char *) header
+ header->dbs[dbidx].hashoffset);
if (header->dbs[dbidx].type == nss_db_type_hash)
{
for (uint32_t hidx = 0; hidx < header->dbs[dbidx].hashsize; ++hidx)
if (hashtab[hidx].keyidx != ~((stridx_t) 0))
printf ("%c%s %s\n",
header->dbs[dbidx].id,
keystrtab + hashtab[hidx].keyidx,
valstrtab + hashtab[hidx].dataidx);
}
else if (header->dbs[dbidx].type == nss_db_type_iterate)
{
const char *endvalstrtab = valstrtab + header->valstrlen;
const char *cp = valstrtab;
unsigned int count = 0;
while (cp < endvalstrtab && *cp != '\0')
{
printf ("%c%u %s\n", header->dbs[dbidx].id, count++, cp);
cp = rawmemchr (cp, '\0') + 1;
}
}
else
{
assert (header->dbs[dbidx].type == nss_db_type_int4);
for (uint32_t hidx = 0; hidx < header->dbs[dbidx].hashsize; ++hidx)
if (hashtab[hidx].keyidx != ~((stridx_t) 0))
printf ("%c%" PRIu32 " %s\n",
header->dbs[dbidx].id,
*((uint32_t *) (keystrtab + hashtab[hidx].keyidx)),
valstrtab + hashtab[hidx].dataidx);
}
}
return EXIT_SUCCESS;
}
#ifdef HAVE_SELINUX
static void
set_file_creation_context (const char *outname, mode_t mode)
{
static int enabled;
static int enforcing;
security_context_t ctx;
/* Check if SELinux is enabled, and remember. */
if (enabled == 0)
enabled = is_selinux_enabled ();
if (enabled < 0)
return;
/* Check if SELinux is enforcing, and remember. */
if (enforcing == 0)
enforcing = security_getenforce () ? 1 : -1;
/* Determine the context which the file should have. */
ctx = NULL;
if (matchpathcon (outname, S_IFREG | mode, &ctx) == 0 && ctx != NULL)
{
if (setfscreatecon (ctx) != 0)
error (enforcing > 0 ? EXIT_FAILURE : 0, 0,
gettext ("cannot set file creation context for `%s'"),
outname);
freecon (ctx);
}
}
static void
reset_file_creation_context (void)
{
setfscreatecon (NULL);
}
#endif