/*
#ident "@(#)smail/util:RELEASE-3_2_0_121:mkdbm.c,v 1.45 2005/11/15 01:17:23 woods Exp"
*/
/*
* Copyright (C) 1987, 1988 Ronald S. Karr and Landon Curt Noll
* Copyright (C) 1992 Ronald S. Karr
*
* See the file COPYING, distributed with smail, for restriction
* and warranty information.
*/
/*
* mkdbm.c:
* Take a list of lines with a key followed by a colon character
* or white space followed by data and build a dbm database from
* them. If the flag -f is given, downcase the keys.
*
* Usage: mkdbm [-o database] [-fvndy] [input_file ...]
*/
#include "defs.h"
#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
#include <errno.h>
#include <ctype.h>
#include <limits.h>
#ifdef STDC_HEADERS
# include <stdlib.h>
# include <stddef.h>
#else
# ifdef HAVE_STDLIB_H
# include <stdlib.h>
# endif
#endif
#ifdef HAVE_STRING_H
# if !defined(STDC_HEADERS) && defined(HAVE_MEMORY_H)
# include <memory.h>
# endif
# include <string.h>
#endif
#ifdef HAVE_STRINGS_H
# include <strings.h>
#endif
#ifdef __STDC__
# include <stdarg.h>
#else
# include <varargs.h>
#endif
#if defined(HAVE_UNISTD_H)
# include <unistd.h>
#endif
#ifdef TIME_WITH_SYS_TIME
# include <sys/time.h>
# include <time.h>
#else
# ifdef HAVE_SYS_TIME_H
# include <sys/time.h>
# else
# include <time.h>
# endif
#endif
#if defined(UNIX_SYS5) || defined(POSIX_OS) || defined(USE_FCNTL)
# include <fcntl.h>
#else
# if defined(UNIX_BSD)
# include <sys/file.h>
# endif
#endif
#if !defined(HAVE_GETHOSTNAME) && defined(HAVE_UNAME)
#include <sys/utsname.h>
#endif
#include "config.h"
#include "smail.h"
#include "alloc.h"
#include "list.h"
#include "main.h"
#include "parse.h"
#include "addr.h"
#include "smailstring.h"
#include "dys.h"
#include "smailsock.h"
#include "route.h"
#include "bindlib.h"
#include "transports/smtplib.h" /* rfc821_is_*() decls. */
#include "spool.h"
#include "exitcodes.h"
#include "log.h"
#include "dbm_compat.h"
#include "extern.h"
#include "smailport.h"
/* variables provided by this file */
char *program; /* argv[0] from main */
int debug = 0;
FILE *errfile;
int only_testing = TRUE;
/* variables local to this file */
static char *out_name = NULL;
static char *temp_dir = NULL;
#ifndef DBM_SUFFIX
static char *temp_pag = NULL;
#endif
static int downcase = FALSE;
static int ypstamps = FALSE;
static int verbose = FALSE;
static int no_at_record = FALSE;
static int no_nul_byte = FALSE;
static int reccnt = 0;
static int maxlen = 0;
/* functions local to this file */
static void done __P((int));
static char **read_args __P((char **));
static char *build_temp_name __P((char *));
static void create_database __P((char *));
static void add_to_database __P((FILE *));
static void add_ending_record __P((void));
static char *getline __P((FILE *));
static void rename_database __P((char *, char *));
static void add_yp_stamps __P((void));
/*ARGSUSED*/
int
main(argc, argv)
int argc GCC_UNUSED_HACK;
char **argv;
{
char **files;
char *temp_name;
program = *argv++;
errfile = stderr;
files = read_args(argv);
if (out_name == NULL) {
if (files[0] && ! EQ(files[0], "-")) {
out_name = files[0];
} else {
out_name = "dbm";
}
}
if (!(temp_name = build_temp_name(out_name))) {
(void) fprintf(stderr, "%s: %s: %s\n", program, out_name, strerror(errno));
done(EX_CANTCREAT);
}
create_database(temp_name);
if (*files) {
while (*files) {
FILE *f;
if (EQ(*files, "-")) {
add_to_database(stdin);
files++;
continue;
}
f = fopen(*files, "r");
if (f == NULL) {
(void) fprintf(stderr, "%s: cannot open ", program);
(void) perror(*files);
done(EX_NOINPUT);
}
add_to_database(f);
files++;
}
} else {
add_to_database(stdin);
}
if (ypstamps) {
add_yp_stamps();
}
if (! no_at_record) {
add_ending_record();
}
rename_database(temp_name, out_name);
if (verbose) {
(void) printf("Added %d records, longest record was %d bytes\n",
reccnt, maxlen);
}
(void) dbmclose();
exit(EX_OK);
/* NOTREACHED */
}
static void
add_yp_stamps()
{
datum key_lastmod, val_lastmod;
datum key_master, val_master;
time_t now;
char nows[32];
#ifdef HAVE_GETHOSTNAME
char host[256];
if(gethostname(host, sizeof(host)) < 0) {
done(EX_DATAERR);
}
#else
#ifdef HAVE_UNAME
struct utsname utsnm;
char *host;
(void) uname(&utsnm);
host = utsnm.nodename;
#else
#ifdef SITENAME_FILE
char host[4096];
FILE *f;
char *p;
f = fopen(SITENAME_FILE, "r");
if (f == NULL) {
fprintf(stderr, "%s: cannot open ", program);
perror(SITENAME_FILE);
done(EX_OSFILE);
}
host[0] = '\0';
fgets(host, sizeof(host), f);
if (host[0] == '\0') {
fprintf(stderr, "%s: no hostname found in %s\n",
program, SITENAME_FILE);
exit(EX_OSFILE);
}
p = strchr(host, '\n');
if (p)
*p = '\0';
fclose(f);
#else
fprintf(stderr, "%s: No known method for computing hostname\n",
program);
done(EX_USAGE);
#endif /* SITENAME_FILE */
#endif /* HAVE_UNAME */
#endif /* HAVE_GETHOSTNAME */
(void) time(&now);
sprintf(nows, "%10.10ld", (long) now);
key_lastmod.dptr = "YP_LAST_MODIFIED";
key_lastmod.dsize = strlen(key_lastmod.dptr);
val_lastmod.dptr = nows;
val_lastmod.dsize = strlen(val_lastmod.dptr);
key_master.dptr = "YP_MASTER_NAME";
key_master.dsize = strlen(key_master.dptr);
val_master.dptr = host;
val_master.dsize = strlen(val_master.dptr);
if (store(key_lastmod, val_lastmod) < 0) {
(void) fprintf(stderr, "%s: store failed for %s\n",
program, (char *) key_lastmod.dptr);
done(EX_DATAERR);
}
if (store(key_master, val_master) < 0) {
(void) fprintf(stderr, "%s: store failed for %s\n",
program, (char *) key_master.dptr);
done(EX_DATAERR);
}
}
/*
* for errors or signals, remove the temp files
*/
static void
done(ex)
int ex;
{
(void) dbmclose();
(void) unlink(temp_dir);
#ifndef DBM_SUFFIX
(void) unlink(temp_pag);
#endif
exit(ex);
}
/*
* read through the arglist and turn argv into list of input files
*/
static char **
read_args(args)
char **args;
{
char **filev = args;
char **filep = args;
while (*args) {
if ((*args)[0] == '-' && (*args)[1] != '\0') {
static char *end_arg = "";
char *s = &(*args)[1];
while (*s) {
switch (*s++) {
case 'y':
ypstamps = TRUE;
break;
case 'f':
downcase = TRUE;
break;
case 'v':
verbose = TRUE;
break;
case 'n':
no_nul_byte = TRUE;
break;
case 'd':
no_at_record = TRUE;
break;
case 'o':
if (*s != '\0') {
out_name = s;
s = end_arg;
} else {
out_name = *++args;
}
break;
default:
(void) fprintf(stderr,
"Usage: %s [-yfvnd] [-o database] [file ...]\n",
program);
exit(EX_USAGE);
}
}
} else {
*filep++ = *args;
}
args++;
}
*filep = NULL;
return filev;
}
/*
* build a temp filename in the same directory as the given file
*/
static char *
build_temp_name(name)
char *name;
{
char *fn;
size_t dirlen;
char *slash = strrchr(name, '/');
if (slash) {
dirlen = slash - name;
fn = xmalloc(dirlen + sizeof("/dbmXXXXXX"));
(void) strncpy(fn, name, dirlen);
(void) strcpy(fn + dirlen, "/dbmXXXXXX");
} else {
fn = xmalloc(sizeof("dbmXXXXXX"));
strcpy(fn, "dbmXXXXXX");
}
return mktemp(fn);
}
/*
* create a DBM database with the given basename
*/
static void
create_database(dbm_name)
char *dbm_name;
{
#ifdef DBM_SUFFIX /* indicates db(3) emulation of ndbm */
temp_dir = xmalloc(strlen(dbm_name) + sizeof(DBM_SUFFIX));
(void) sprintf(temp_dir, "%s%s", dbm_name, DBM_SUFFIX);
#endif
#if defined(HAVE_DBM) && !defined(HAVE_NDBM)
mkdbfiles(dbm_name); /* ancient dbm won't create its own files */
#endif
/* open the new DBM database */
if (dbminit(dbm_name) < 0) {
(void) fprintf(stderr, "%s: dbminit failed ", program);
(void) perror(dbm_name);
done(EX_TEMPFAIL);
}
}
#if defined(HAVE_DBM) && !defined(HAVE_NDBM)
static void
mkdbfiles(dbm_name)
char *dbm_name;
{
int temp_len = strlen(dbm_name);
temp_dir = xmalloc(temp_len + sizeof(".dir"));
temp_pag = xmalloc(temp_len + sizeof(".pag"));
(void) sprintf(temp_dir, "%s.dir", dbm_name);
(void) sprintf(temp_pag, "%s.pag", dbm_name);
fd = creat(temp_dir, 0644);
if (fd < 0) {
(void) fprintf(stderr, "%s: cannot create ", program);
(void) perror(temp_dir);
exit(EX_TEMPFAIL);
}
(void) close(fd);
fd = creat(temp_pag, 0644);
if (fd < 0) {
(void) fprintf(stderr, "%s: cannot create ", program);
(void) perror(temp_pag);
(void) unlink(temp_dir);
exit(EX_TEMPFAIL);
}
(void) close(fd);
}
#endif
/*
* add all entries in the file to the DBM database
*/
static void
add_to_database(f)
FILE *f;
{
register char *s;
while ((s = getline(f))) {
register char *data;
datum key, content;
for (data = s; *data && *data != ':' && !isspace((int) *data); data++) {
;
}
if (*data) {
*data++ = '\0';
key.dptr = s;
key.dsize = data - s - 1;
content.dptr = data;
content.dsize = strlen(data);
if (! no_nul_byte) {
key.dsize++;
content.dsize++;
}
if (downcase) {
register char *sp;
for (sp = s; *sp; sp++) {
*sp = tolower((int) *sp);
}
}
if (store(key, content) < 0) {
(void) fprintf(stderr, "%s: store failed for %s\n",
program, s);
done(EX_DATAERR);
}
reccnt++;
if ((size_t) (content.dsize + key.dsize) > (size_t) maxlen) {
maxlen = content.dsize + key.dsize;
}
} else {
(void) fprintf(stderr, "%s: no value for key %s, ignored\n",
program, s);
}
}
}
/*
* add the ending `@' record, to make sendmail happy.
*/
static void
add_ending_record()
{
datum key, content;
content.dptr = key.dptr = "@";
content.dsize = key.dsize = (no_nul_byte? 1: 2);
if (store(key, content) < 0) {
(void) fprintf(stderr, "%s: store failed for end record\n", program);
}
}
/*
* read and return one line from the given file.
*
* return NULL on end of input.
*/
static char *
getline(f)
register FILE *f;
{
static struct str str;
static int inited = FALSE;
register int c;
if (! inited) {
STR_INIT(&str);
inited = TRUE;
} else {
str.i = 0;
}
while ((c = getc(f)) != EOF && c != '\n') {
STR_NEXT(&str, c);
}
if (c == EOF && str.i == 0) {
return NULL;
}
STR_NEXT(&str, '\0');
return str.p;
}
/*
* rename the database from the old name to a new one.
*
* Allow some time after unlinking the old name so that smail will not
* open the .dir file of the old database and the .pag file of the new
* one accidentally.
*/
static void
rename_database(from, to)
char *from;
char *to;
{
unsigned int fromlen = (unsigned int) strlen(from);
unsigned int tolen = (unsigned int) strlen(to);
#ifdef DBM_SUFFIX
char *from_dir = xmalloc(fromlen + sizeof(DBM_SUFFIX));
char *to_dir = xmalloc(tolen + sizeof(DBM_SUFFIX));
(void) sprintf(from_dir, "%s%s", from, DBM_SUFFIX);
(void) sprintf(to_dir, "%s%s", to, DBM_SUFFIX);
#else /* !DBM_SUFFIX */
char *from_dir = xmalloc(fromlen + sizeof(".dir"));
char *to_dir = xmalloc(tolen + sizeof(".dir"));
char *to_pag = xmalloc(tolen + sizeof(".pag"));
char *from_pag = xmalloc(fromlen + sizeof(".pag"));
(void) sprintf(from_dir, "%s.dir", from);
(void) sprintf(from_pag, "%s.pag", from);
(void) sprintf(to_dir, "%s.dir", to);
(void) sprintf(to_pag, "%s.pag", to);
(void) unlink(to_pag);
#endif /* DBM_SUFFIX */
(void) unlink(to_dir);
(void) sleep(2); /* sleep at least 1 second */
if (link(from_dir, to_dir) < 0) {
(void) fprintf(stderr, "%s: cannot link %s to ", program, from_dir);
(void) perror(to_dir);
done(EX_CANTCREAT);
}
#ifndef DBM_SUFFIX
if (link(from_pag, to_pag) < 0) {
(void) fprintf(stderr, "%s: cannot link %s to ", program, from_pag);
(void) perror(to_pag);
done(EX_CANTCREAT);
}
(void) unlink(from_pag);
#endif
(void) unlink(from_dir);
}
/*
* standalone versions of some referenced routines
*/
/*ARGSUSED*/
char *
qualify_domain(s)
char *s GCC_UNUSED_HACK;
{
return NULL;
}
void
freeze_message()
{
return;
}
char *
bind_compute_domain ()
{
return NULL;
}
int
rfc821_is_dot_string(s)
char *s GCC_UNUSED_HACK;
{
return 0;
}
int
rfc821_is_quoted_string(s)
char *s GCC_UNUSED_HACK;
{
return 0;
}
char *
bind_lookup_txt_rr(s, ep)
char *s GCC_UNUSED_HACK;
struct error **ep GCC_UNUSED_HACK;
{
return NULL;
}
/*
* standalone versions of some referenced variables
*/
enum er_proc error_processing = MAIL_BACK;
int force_zero_exitvalue = FALSE;
pid_t daemon_pid = 0xDEAD;
char *message_id = NULL; /* unique ID for this message */
enum op_mode operation_mode = MODE_DEFAULT; /* mode of operation */
char *spool_dir; /* directory used to spool message */
char *spool_fn = NULL; /* basename of open spool file */
int islocal = TRUE;
char *sender = "nsc!tron";
char *sender_name = "MasterControlProgram";
char *smtp_local_net = NULL;
char *local_sender;
uid_t real_uid = 0;
gid_t prog_egid = 0;
/*
* Local Variables:
* c-file-style: "smail"
* End:
*/
syntax highlighted by Code2HTML, v. 0.9.1