/*-
* Copyright (c) 1992, 1993
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
/*
* Mkcapdb creates a capability hash database for quick retrieval of capability
* records. The database contains 2 types of entries: records and references
* marked by the first byte in the data. A record entry contains the actual
* capability record whereas a reference contains the name (key) under which
* the correct record is stored.
*/
int
main(int argc, char *argv[])
{
int c, byteorder;
char *p;
capname = NULL;
byteorder = 0;
while ((c = getopt(argc, argv, "bf:lv")) != -1) {
switch(c) {
case 'b':
case 'l':
if (byteorder != 0)
usage();
byteorder = c == 'b' ? 4321 : 1234;
break;
case 'f':
capname = optarg;
break;
case 'v':
verbose = 1;
break;
case '?':
default:
usage();
}
}
argc -= optind;
argv += optind;
if (*argv == NULL)
usage();
/* Set byte order */
openinfo.lorder = byteorder;
/*
* Set nelem to twice the value returned by count_record().
*/
openinfo.nelem = count_records(argv) << 1;
/*
* The database file is the first argument if no name is specified.
* Make arrangements to unlink it if exit badly.
*/
(void)snprintf(outfile, sizeof(outfile), "%s.db.tmp",
capname ? capname : *argv);
if ((capname = strdup(outfile)) == NULL)
err(1, "strdup");
p = strrchr(outfile, '.');
assert(p != NULL);
*p = '\0';
(void)unlink(outfile);
if ((capdbp = dbopen(capname, O_CREAT | O_TRUNC | O_RDWR,
DEFFILEMODE, DB_HASH, &openinfo)) == NULL)
err(1, "%s", outfile);
static void
dounlink(void)
{
if (capname != NULL)
unlink(capname);
}
/*
* Any changes to these definitions should be made also in the getcap(3)
* library routines.
*/
#define RECOK (char)0
#define TCERR (char)1
#define SHADOW (char)2
/*
* Db_build() builds the name and capability databases according to the
* details above.
*/
static void
db_build(const char **ifiles)
{
DBT key, data;
recno_t reccnt;
size_t len, bplen;
int st;
char *bp, *p, *t, *n;
/*
* Allocate enough memory to store record, terminating
* NULL and one extra byte.
*/
len = strlen(bp);
if (bplen <= len + 2) {
if ((n = realloc(data.data,
bplen + MAX(256, len + 2))) == NULL)
err(1, "realloc");
data.data = n;
bplen += MAX(256, len + 2);
}
/* Find the end of the name field. */
if ((p = strchr(bp, ':')) == NULL) {
warnx("no name field: %.*s", (int)(MIN(len, 20)), bp);
continue;
}
/* First byte of stored record indicates status. */
switch(st) {
case 1:
((char *)(data.data))[0] = RECOK;
break;
case 2:
((char *)(data.data))[0] = TCERR;
warnx("Record not tc expanded: %.*s", (int)(p - bp),bp);
break;
}
/* Create the stored record. */
(void)memmove(&((u_char *)(data.data))[1], bp, len + 1);
data.size = len + 2;
/* Store the record under the name field. */
key.data = bp;
key.size = p - bp;
/*
* Count number of records in input files. This does not need
* to be really accurate (the result is used only as a hint).
* It seems to match number of records should a cgetnext() be used, though.
*/
static int
count_records(char **list)
{
FILE *fp;
char *line;
size_t len;
int nelem, slash;
if (nelem == 0) {
/* no records found; pass default size hint */
nelem = 1;
} else if (!powerof2(nelem)) {
/* set nelem to nearest bigger power-of-two number */
int bt = 1;
while(bt < nelem) bt <<= 1;
nelem = bt;
}