/* #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 #include #include #include #include #include #ifdef STDC_HEADERS # include # include #else # ifdef HAVE_STDLIB_H # include # endif #endif #ifdef HAVE_STRING_H # if !defined(STDC_HEADERS) && defined(HAVE_MEMORY_H) # include # endif # include #endif #ifdef HAVE_STRINGS_H # include #endif #ifdef __STDC__ # include #else # include #endif #if defined(HAVE_UNISTD_H) # include #endif #ifdef TIME_WITH_SYS_TIME # include # include #else # ifdef HAVE_SYS_TIME_H # include # else # include # endif #endif #if defined(UNIX_SYS5) || defined(POSIX_OS) || defined(USE_FCNTL) # include #else # if defined(UNIX_BSD) # include # endif #endif #if !defined(HAVE_GETHOSTNAME) && defined(HAVE_UNAME) #include #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: */