OpenSolaris_b135/cmd/ypcmd/makedbm.c

Compare this file to the similar file:
Show the results in this format:

/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License (the "License").
 * You may not use this file except in compliance with the License.
 *
 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
 * or http://www.opensolaris.org/os/licensing.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
 * If applicable, add the following below this CDDL HEADER, with the
 * fields enclosed by brackets "[]" replaced with your own identifying
 * information: Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 */

/*
 * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
 * Use is subject to license terms.
 */

/*	Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
/*	  All Rights Reserved   */

/*
 * Portions of this source code were derived from Berkeley
 * under license from the Regents of the University of
 * California.
 */

#pragma ident	"%Z%%M%	%I%	%E% SMI"

#undef NULL
#include <stdio.h>
#include <sys/types.h>
#include <sys/file.h>
#include <sys/param.h>
#include <sys/stat.h>
#include <ctype.h>
#include <limits.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/systeminfo.h>
#include <dlfcn.h>

#include "ypdefs.h"
#include "ypsym.h"
USE_YP_MASTER_NAME
USE_YP_LAST_MODIFIED
USE_YP_INPUT_FILE
USE_YP_OUTPUT_NAME
USE_YP_DOMAIN_NAME
USE_YP_SECURE
USE_YP_INTERDOMAIN
USE_DBM

#ifdef SYSVCONFIG
extern void sysvconfig();
#endif
extern int yp_getalias();

#define	MAXLINE 4096		/* max length of input line */
#define	DEFAULT_SEP	" "
static char *get_date();
static char *any();
static void addpair();
static void unmake();
static void usage();

int   inode_dev_valid = 0;
ino64_t inode;
dev_t dev;

/*
 * Interpose close(2) to enable us to keep one of the output
 * files open until process exit.
 */
#pragma weak _close = close
int
close(int filedes) {

	struct stat64	sb;
	static int	(*fptr)() = 0;

	if (fptr == 0) {
		fptr = (int (*)())dlsym(RTLD_NEXT, "close");
		if (fptr == 0) {
			fprintf(stderr, "makedbm: dlopen(close): %s\n",
				dlerror());
			errno = ELIBACC;
			return (-1);
		}
	}

	if (inode_dev_valid != 0 && fstat64(filedes, &sb) == 0) {
		if (sb.st_ino == inode && sb.st_dev == dev) {
			/* Keep open; pretend successful */
			return (0);
		}
	}

	return ((*fptr)(filedes));
}

int
main(argc, argv)
	int argc;
	char **argv;
{
	FILE *infp, *outfp;
	datum key, content, tmp;
	char buf[MAXLINE];
	char pagbuf[MAXPATHLEN];
	char tmppagbuf[MAXPATHLEN];
	char dirbuf[MAXPATHLEN];
	char tmpdirbuf[MAXPATHLEN];
	char *p, ic;
	char *infile, *outfile;
	char outalias[MAXPATHLEN];
	char outaliasmap[MAXNAMLEN];
	char outaliasdomain[MAXNAMLEN];
	char *last_slash, *next_to_last_slash;
	char *infilename, *outfilename, *mastername, *domainname,
	    *interdomain_bind, *security, *lower_case_keys;
	char *key_sep = DEFAULT_SEP;
	char local_host[MAX_MASTER_NAME];
	int cnt, i;
	DBM *fdb;
	struct stat64 statbuf;
	int num_del_to_match = 0;
	/* flag to indicate if matching char can be escaped */
	int count_esp = 0;

	/* Ignore existing umask, always force 077 (owner rw only) */
	umask(077);

	infile = outfile = NULL; /* where to get files */
	/* name to imbed in database */
	infilename = outfilename = mastername = domainname = interdomain_bind =
	    security = lower_case_keys = NULL;
	argv++;
	argc--;
	while (argc > 0) {
		if (argv[0][0] == '-' && argv[0][1]) {
			switch (argv[0][1]) {
				case 'i':
					infilename = argv[1];
					argv++;
					argc--;
					break;
				case 'o':
					outfilename = argv[1];
					argv++;
					argc--;
					break;
				case 'm':
					mastername = argv[1];
					argv++;
					argc--;
					break;
				case 'b':
					interdomain_bind = argv[0];
					break;
				case 'd':
					domainname = argv[1];
					argv++;
					argc--;
					break;
				case 'l':
					lower_case_keys = argv[0];
					break;
				case 's':
					security = argv[0];
					break;
				case 'S' :
					strcpy(key_sep, argv[1]);
					argv++;
					argc--;
					if (strlen(key_sep) != 1) {
						fprintf(stderr,
							"bad separator\n");
						usage();
					}
					break;
				case 'D' :
					num_del_to_match = atoi(argv[1]);
					argv++;
					argc--;
					break;
				case 'E' :
					count_esp = 1;
					break;
				case 'u':
					unmake(argv[1]);
					argv++;
					argc--;
					exit(0);
				default:
					usage();
			}
		} else if (infile == NULL)
			infile = argv[0];
		else if (outfile == NULL)
			outfile = argv[0];
		else
			usage();
		argv++;
		argc--;
	}
	if (infile == NULL || outfile == NULL)
		usage();

	/*
	 *  do alias mapping if necessary
	 */
	last_slash = strrchr(outfile, '/');
	if (last_slash) {
		*last_slash = '\0';
		next_to_last_slash = strrchr(outfile, '/');
		if (next_to_last_slash) *next_to_last_slash = '\0';
	} else next_to_last_slash = NULL;

#ifdef DEBUG
	if (last_slash) printf("last_slash=%s\n", last_slash+1);
	if (next_to_last_slash) printf("next_to_last_slash=%s\n",
		next_to_last_slash+1);
#endif /* DEBUG */

	/* reads in alias file for system v filename translation */
#ifdef SYSVCONFIG
	sysvconfig();
#endif

	if (last_slash && next_to_last_slash) {
		if (yp_getalias(last_slash+1, outaliasmap, MAXALIASLEN) < 0) {
			if ((int)strlen(last_slash+1) <= MAXALIASLEN)
				strcpy(outaliasmap, last_slash+1);
			else
				fprintf(stderr,
				    "makedbm: warning: no alias for %s\n",
				    last_slash+1);
		}
#ifdef DEBUG
		printf("%s\n", last_slash+1);
		printf("%s\n", outaliasmap);
#endif /* DEBUG */
		if (yp_getalias(next_to_last_slash+1, outaliasdomain,
		    NAME_MAX) < 0) {
			if ((int)strlen(last_slash+1) <= NAME_MAX)
				strcpy(outaliasdomain, next_to_last_slash+1);
			else
				fprintf(stderr,
				    "makedbm: warning: no alias for %s\n",
				    next_to_last_slash+1);
		}
#ifdef DEBUG
		printf("%s\n", next_to_last_slash+1);
		printf("%s\n", outaliasdomain);
#endif /* DEBUG */
		sprintf(outalias, "%s/%s/%s", outfile, outaliasdomain,
			outaliasmap);
#ifdef DEBUG
		printf("outlias=%s\n", outalias);
#endif /* DEBUG */

	} else if (last_slash) {
		if (yp_getalias(last_slash+1, outaliasmap, MAXALIASLEN) < 0) {
			if ((int)strlen(last_slash+1) <= MAXALIASLEN)
				strcpy(outaliasmap, last_slash+1);
			else
				fprintf(stderr,
				    "makedbm: warning: no alias for %s\n",
				    last_slash+1);
		}
		if (yp_getalias(outfile, outaliasdomain, NAME_MAX) < 0) {
			if ((int)strlen(outfile) <= NAME_MAX)
				strcpy(outaliasdomain, outfile);
			else
				fprintf(stderr,
				    "makedbm: warning: no alias for %s\n",
				    last_slash+1);
		}
		sprintf(outalias, "%s/%s", outaliasdomain, outaliasmap);
	} else {
		if (yp_getalias(outfile, outalias, MAXALIASLEN) < 0) {
			if ((int)strlen(last_slash+1) <= MAXALIASLEN)
				strcpy(outalias, outfile);
			else
				fprintf(stderr,
				    "makedbm: warning: no alias for %s\n",
				    outfile);
			}
	}
#ifdef DEBUG
	fprintf(stderr, "outalias=%s\n", outalias);
	fprintf(stderr, "outfile=%s\n", outfile);
#endif /* DEBUG */

	strcpy(tmppagbuf, outalias);
	strcat(tmppagbuf, ".tmp");
	strcpy(tmpdirbuf, tmppagbuf);
	strcat(tmpdirbuf, dbm_dir);
	strcat(tmppagbuf, dbm_pag);

	/* Loop until we can lock the tmpdirbuf file */
	for (;;) {

		if (strcmp(infile, "-") != 0)
			infp = fopen(infile, "r");
		else if (fstat64(fileno(stdin), &statbuf) == -1) {
			fprintf(stderr, "makedbm: can't open stdin\n");
			exit(1);
		} else
			infp = stdin;

		if (infp == NULL) {
			fprintf(stderr, "makedbm: can't open %s\n", infile);
			exit(1);
		}

		if ((outfp = fopen(tmpdirbuf, "w")) == (FILE *)NULL) {
			fprintf(stderr, "makedbm: can't create %s\n",
				tmpdirbuf);
			exit(1);
		}

		if (lockf(fileno(outfp), F_TLOCK, 0) == 0) {
			/* Got exclusive access; save inode and dev */
			if (fstat64(fileno(outfp), &statbuf) != 0) {
				fprintf(stderr, "makedbm: can't fstat ");
				perror(tmpdirbuf);
				exit(1);
			}
			inode		= statbuf.st_ino;
			dev		= statbuf.st_dev;
			inode_dev_valid	= 1;
			break;
		}

		if (errno != EAGAIN) {
			fprintf(stderr, "makedbm: can't lock ");
			perror(tmpdirbuf);
			exit(1);
		}

		/*
		 * Someone else is holding the lock.
		 * Close both output and input file
		 * (the latter to ensure consistency
		 * if the input file is updated while
		 * we're suspended), wait a little,
		 * and try again.
		 */
		if (infp != stdin)
			(void) fclose(infp);
		(void) fclose(outfp);
		sleep(1);
	}

	if (fopen(tmppagbuf, "w") == (FILE *)NULL) {
		fprintf(stderr, "makedbm: can't create %s\n", tmppagbuf);
		exit(1);
	}
	strcpy(dirbuf, outalias);
	strcat(dirbuf, ".tmp");
	if ((fdb = dbm_open(dirbuf, O_RDWR | O_CREAT, 0644)) == NULL) {
		fprintf(stderr, "makedbm: can't open %s\n", dirbuf);
		exit(1);
	}
	strcpy(dirbuf, outalias);
	strcpy(pagbuf, outalias);
	strcat(dirbuf, dbm_dir);
	strcat(pagbuf, dbm_pag);
	while (fgets(buf, sizeof (buf), infp) != NULL) {
		p = buf;
		cnt = strlen(buf) - 1; /* erase trailing newline */
		while (p[cnt-1] == '\\') {
			p += cnt-1;
			if (fgets(p, sizeof (buf)-(p-buf), infp) == NULL)
				goto breakout;
			cnt = strlen(p) - 1;
		}
		if (strcmp(key_sep, DEFAULT_SEP) == 0) {
			p = any(buf, " \t\n", num_del_to_match, count_esp);
		} else {
			p = any(buf, key_sep, num_del_to_match, count_esp);
		}
		key.dptr = buf;
		key.dsize = p - buf;
		for (;;) {
			if (p == NULL || *p == NULL) {
				fprintf(stderr,
	"makedbm: source files is garbage!\n");
				exit(1);
			}
			if (*p != ' ' && *p != '\t' && *p != key_sep[0])
				break;
			p++;
		}
		content.dptr = p;
		content.dsize = strlen(p) - 1; /* erase trailing newline */
		if (lower_case_keys) {
			for (i = (strncmp(key.dptr, "YP_MULTI_", 9) ? 0 : 9);
					i < key.dsize; i++) {

				ic = *(key.dptr+i);
				if (isascii(ic) && isupper(ic))
					*(key.dptr+i) = tolower(ic);
			}
		}
		tmp = dbm_fetch(fdb, key);
		if (tmp.dptr == NULL) {
			if (dbm_store(fdb, key, content, 1) != 0) {
				printf("problem storing %.*s %.*s\n",
				    key.dsize, key.dptr,
				    content.dsize, content.dptr);
				exit(1);
			}
		}
#ifdef DEBUG
		else {
			printf("duplicate: %.*s %.*s\n",
			    key.dsize, key.dptr,
			    content.dsize, content.dptr);
		}
#endif
	}
	breakout:
	addpair(fdb, yp_last_modified, get_date(infile));
	if (infilename)
		addpair(fdb, yp_input_file, infilename);
	if (outfilename)
		addpair(fdb, yp_output_file, outfilename);
	if (domainname)
		addpair(fdb, yp_domain_name, domainname);
	if (security)
		addpair(fdb, yp_secure, "");
	if (interdomain_bind)
	    addpair(fdb, yp_interdomain, "");
	if (!mastername) {
		sysinfo(SI_HOSTNAME, local_host, sizeof (local_host) - 1);
		mastername = local_host;
	}
	addpair(fdb, yp_master_name, mastername);
	(void) dbm_close(fdb);
#ifdef DEBUG
	fprintf(stderr, ".tmp ndbm map closed. ndbm successful !\n");
#endif
	if (rename(tmppagbuf, pagbuf) < 0) {
		perror("makedbm: rename");
		unlink(tmppagbuf);		/* Remove the tmp files */
		unlink(tmpdirbuf);
		exit(1);
	}
	if (rename(tmpdirbuf, dirbuf) < 0) {
		perror("makedbm: rename");
		unlink(tmppagbuf); /* Remove the tmp files */
		unlink(tmpdirbuf);
		exit(1);
	}
/*
 *	sprintf(buf, "mv %s %s", tmppagbuf, pagbuf);
 *	if (system(buf) < 0)
 *		perror("makedbm: rename");
 *	sprintf(buf, "mv %s %s", tmpdirbuf, dirbuf);
 *	if (system(buf) < 0)
 *		perror("makedbm: rename");
 */
	exit(0);
}


/*
 * scans cp, looking for a match with any character
 * in match.  Returns pointer to place in cp that matched
 * (or NULL if no match)
 *
 * It will find the num_del_to_match+1
 * matching character in the line.
 *
 * The backslash escapes a delimiter if count_esp==1
 * We don't count it as a character match if
 * an escape character precedes a matching character.
 *
 */
static char *
any(cp, match, num_del_to_match, count_esp)
	register char *cp;
	char *match;
	int num_del_to_match;
	int count_esp;
{
	register char *mp, c, prev_char;
	int num_del_matched;

	num_del_matched = 0;
	prev_char = ' ';
	while (c = *cp) {
		for (mp = match; *mp; mp++) {
			if (*mp == c) {
				if (!count_esp) {
					num_del_matched++;
				} else if (prev_char != '\\') {
					num_del_matched++;
				}
				if (num_del_matched > num_del_to_match)
					return (cp);
			}
		}
		prev_char = c;
		cp++;
	}
	return ((char *)0);
}

static char *
get_date(name)
	char *name;
{
	struct stat filestat;
	static char ans[MAX_ASCII_ORDER_NUMBER_LENGTH];
	/* ASCII numeric string */

	if (strcmp(name, "-") == 0)
		sprintf(ans, "%010ld", (long)time(0));
	else {
		if (stat(name, &filestat) < 0) {
			fprintf(stderr, "makedbm: can't stat %s\n", name);
			exit(1);
		}
		sprintf(ans, "%010ld", (long)filestat.st_mtime);
	}
	return (ans);
}

void
usage()
{
	fprintf(stderr,
"usage: makedbm -u file\n	makedbm [-b] [-l] [-s] [-i YP_INPUT_FILE] "
	    "[-o YP_OUTPUT_FILE] [-d YP_DOMAIN_NAME] [-m YP_MASTER_NAME] "
	    "[-S DELIMITER] [-D NUM_DELIMITER_TO_SKIP] [-E] "
	    "infile outfile\n");
	exit(1);
}

void
addpair(fdb, str1, str2)
DBM *fdb;
char *str1, *str2;
{
	datum key;
	datum content;

	key.dptr = str1;
	key.dsize = strlen(str1);
	content.dptr  = str2;
	content.dsize = strlen(str2);
	if (dbm_store(fdb, key, content, 1) != 0) {
		printf("makedbm: problem storing %.*s %.*s\n",
		    key.dsize, key.dptr, content.dsize, content.dptr);
		exit(1);
	}
}

void
unmake(file)
	char *file;
{
	datum key, content;
	DBM *fdb;

	if (file == NULL)
		usage();

	if ((fdb = dbm_open(file, O_RDONLY, 0644)) == NULL) {
		fprintf(stderr, "makedbm: couldn't open %s dbm file\n", file);
		exit(1);
	}

	for (key = dbm_firstkey(fdb); key.dptr != NULL;
		key = dbm_nextkey(fdb)) {
		content = dbm_fetch(fdb, key);
		printf("%.*s %.*s\n", key.dsize, key.dptr,
		    content.dsize, content.dptr);
	}

	dbm_close(fdb);
}