xref: /onnv-gate/usr/src/cmd/sendmail/aux/makemap.c (revision 6562:53563fcf544b)
10Sstevel@tonic-gate /*
2*6562Sjbeck  * Copyright (c) 1998-2002, 2004, 2008 Sendmail, Inc. and its suppliers.
30Sstevel@tonic-gate  *	All rights reserved.
40Sstevel@tonic-gate  * Copyright (c) 1992 Eric P. Allman.  All rights reserved.
50Sstevel@tonic-gate  * Copyright (c) 1992, 1993
60Sstevel@tonic-gate  *	The Regents of the University of California.  All rights reserved.
70Sstevel@tonic-gate  *
80Sstevel@tonic-gate  * By using this file, you agree to the terms and conditions set
90Sstevel@tonic-gate  * forth in the LICENSE file which can be found at the top level of
100Sstevel@tonic-gate  * the sendmail distribution.
110Sstevel@tonic-gate  *
120Sstevel@tonic-gate  */
130Sstevel@tonic-gate 
140Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
150Sstevel@tonic-gate 
160Sstevel@tonic-gate #include <sm/gen.h>
170Sstevel@tonic-gate 
180Sstevel@tonic-gate SM_IDSTR(copyright,
190Sstevel@tonic-gate "@(#) Copyright (c) 1998-2002, 2004 Sendmail, Inc. and its suppliers.\n\
200Sstevel@tonic-gate 	All rights reserved.\n\
210Sstevel@tonic-gate      Copyright (c) 1992 Eric P. Allman.  All rights reserved.\n\
220Sstevel@tonic-gate      Copyright (c) 1992, 1993\n\
230Sstevel@tonic-gate 	The Regents of the University of California.  All rights reserved.\n")
240Sstevel@tonic-gate 
25*6562Sjbeck SM_IDSTR(id, "@(#)$Id: makemap.c,v 8.179 2008/04/14 02:06:16 ca Exp $")
260Sstevel@tonic-gate 
270Sstevel@tonic-gate 
280Sstevel@tonic-gate #include <sys/types.h>
290Sstevel@tonic-gate #ifndef ISC_UNIX
300Sstevel@tonic-gate # include <sys/file.h>
310Sstevel@tonic-gate #endif /* ! ISC_UNIX */
320Sstevel@tonic-gate #include <ctype.h>
330Sstevel@tonic-gate #include <stdlib.h>
340Sstevel@tonic-gate #include <unistd.h>
350Sstevel@tonic-gate #ifdef EX_OK
360Sstevel@tonic-gate # undef EX_OK		/* unistd.h may have another use for this */
370Sstevel@tonic-gate #endif /* EX_OK */
380Sstevel@tonic-gate #include <sysexits.h>
390Sstevel@tonic-gate #include <sendmail/sendmail.h>
400Sstevel@tonic-gate #include <sendmail/pathnames.h>
410Sstevel@tonic-gate #include <libsmdb/smdb.h>
420Sstevel@tonic-gate 
430Sstevel@tonic-gate uid_t	RealUid;
440Sstevel@tonic-gate gid_t	RealGid;
450Sstevel@tonic-gate char	*RealUserName;
460Sstevel@tonic-gate uid_t	RunAsUid;
475402Sjbeck gid_t	RunAsGid;
480Sstevel@tonic-gate char	*RunAsUserName;
490Sstevel@tonic-gate int	Verbose = 2;
500Sstevel@tonic-gate bool	DontInitGroups = false;
510Sstevel@tonic-gate uid_t	TrustedUid = 0;
520Sstevel@tonic-gate BITMAP256 DontBlameSendmail;
530Sstevel@tonic-gate 
540Sstevel@tonic-gate #define BUFSIZE		1024
550Sstevel@tonic-gate #define ISSEP(c) (sep == '\0' ? isascii(c) && isspace(c) : (c) == sep)
560Sstevel@tonic-gate 
570Sstevel@tonic-gate static void usage __P((char *));
580Sstevel@tonic-gate 
590Sstevel@tonic-gate static void
usage(progname)600Sstevel@tonic-gate usage(progname)
610Sstevel@tonic-gate 	char *progname;
620Sstevel@tonic-gate {
630Sstevel@tonic-gate 	sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
640Sstevel@tonic-gate 		      "Usage: %s [-C cffile] [-N] [-c cachesize] [-D commentchar]\n",
650Sstevel@tonic-gate 		      progname);
660Sstevel@tonic-gate 	sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
670Sstevel@tonic-gate 		      "       %*s [-d] [-e] [-f] [-l] [-o] [-r] [-s] [-t delimiter]\n",
680Sstevel@tonic-gate 		      (int) strlen(progname), "");
690Sstevel@tonic-gate 	sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
700Sstevel@tonic-gate 		      "       %*s [-u] [-v] type mapname\n",
710Sstevel@tonic-gate 		      (int) strlen(progname), "");
720Sstevel@tonic-gate 	exit(EX_USAGE);
730Sstevel@tonic-gate }
740Sstevel@tonic-gate 
750Sstevel@tonic-gate int
main(argc,argv)760Sstevel@tonic-gate main(argc, argv)
770Sstevel@tonic-gate 	int argc;
780Sstevel@tonic-gate 	char **argv;
790Sstevel@tonic-gate {
800Sstevel@tonic-gate 	char *progname;
810Sstevel@tonic-gate 	char *cfile;
820Sstevel@tonic-gate 	bool inclnull = false;
830Sstevel@tonic-gate 	bool notrunc = false;
840Sstevel@tonic-gate 	bool allowreplace = false;
850Sstevel@tonic-gate 	bool allowempty = false;
860Sstevel@tonic-gate 	bool verbose = false;
870Sstevel@tonic-gate 	bool foldcase = true;
880Sstevel@tonic-gate 	bool unmake = false;
890Sstevel@tonic-gate 	char sep = '\0';
900Sstevel@tonic-gate 	char comment = '#';
910Sstevel@tonic-gate 	int exitstat;
920Sstevel@tonic-gate 	int opt;
930Sstevel@tonic-gate 	char *typename = NULL;
940Sstevel@tonic-gate 	char *mapname = NULL;
950Sstevel@tonic-gate 	unsigned int lineno;
960Sstevel@tonic-gate 	int st;
970Sstevel@tonic-gate 	int mode;
980Sstevel@tonic-gate 	int smode;
990Sstevel@tonic-gate 	int putflags = 0;
1000Sstevel@tonic-gate 	long sff = SFF_ROOTOK|SFF_REGONLY;
1010Sstevel@tonic-gate 	struct passwd *pw;
1020Sstevel@tonic-gate 	SMDB_DATABASE *database;
1030Sstevel@tonic-gate 	SMDB_CURSOR *cursor;
1040Sstevel@tonic-gate 	SMDB_DBENT db_key, db_val;
1050Sstevel@tonic-gate 	SMDB_DBPARAMS params;
1060Sstevel@tonic-gate 	SMDB_USER_INFO user_info;
1070Sstevel@tonic-gate 	char ibuf[BUFSIZE];
1080Sstevel@tonic-gate #if HASFCHOWN
1090Sstevel@tonic-gate 	SM_FILE_T *cfp;
1100Sstevel@tonic-gate 	char buf[MAXLINE];
1110Sstevel@tonic-gate #endif /* HASFCHOWN */
1120Sstevel@tonic-gate 	static char rnamebuf[MAXNAME];	/* holds RealUserName */
1130Sstevel@tonic-gate 	extern char *optarg;
1140Sstevel@tonic-gate 	extern int optind;
1150Sstevel@tonic-gate 
1160Sstevel@tonic-gate 	memset(&params, '\0', sizeof params);
1170Sstevel@tonic-gate 	params.smdbp_cache_size = 1024 * 1024;
1180Sstevel@tonic-gate 
1190Sstevel@tonic-gate 	progname = strrchr(argv[0], '/');
1200Sstevel@tonic-gate 	if (progname != NULL)
1210Sstevel@tonic-gate 		progname++;
1220Sstevel@tonic-gate 	else
1230Sstevel@tonic-gate 		progname = argv[0];
1240Sstevel@tonic-gate 	cfile = getcfname(0, 0, SM_GET_SENDMAIL_CF, NULL);
1250Sstevel@tonic-gate 
1260Sstevel@tonic-gate 	clrbitmap(DontBlameSendmail);
1270Sstevel@tonic-gate 	RunAsUid = RealUid = getuid();
1280Sstevel@tonic-gate 	RunAsGid = RealGid = getgid();
1290Sstevel@tonic-gate 	pw = getpwuid(RealUid);
1300Sstevel@tonic-gate 	if (pw != NULL)
1310Sstevel@tonic-gate 		(void) sm_strlcpy(rnamebuf, pw->pw_name, sizeof rnamebuf);
1320Sstevel@tonic-gate 	else
1330Sstevel@tonic-gate 		(void) sm_snprintf(rnamebuf, sizeof rnamebuf,
1340Sstevel@tonic-gate 		    "Unknown UID %d", (int) RealUid);
1350Sstevel@tonic-gate 	RunAsUserName = RealUserName = rnamebuf;
1360Sstevel@tonic-gate 	user_info.smdbu_id = RunAsUid;
1370Sstevel@tonic-gate 	user_info.smdbu_group_id = RunAsGid;
1380Sstevel@tonic-gate 	(void) sm_strlcpy(user_info.smdbu_name, RunAsUserName,
1390Sstevel@tonic-gate 		       SMDB_MAX_USER_NAME_LEN);
1400Sstevel@tonic-gate 
1410Sstevel@tonic-gate #define OPTIONS		"C:D:Nc:deflorst:uv"
1420Sstevel@tonic-gate 	while ((opt = getopt(argc, argv, OPTIONS)) != -1)
1430Sstevel@tonic-gate 	{
1440Sstevel@tonic-gate 		switch (opt)
1450Sstevel@tonic-gate 		{
1460Sstevel@tonic-gate 		  case 'C':
1470Sstevel@tonic-gate 			cfile = optarg;
1480Sstevel@tonic-gate 			break;
1490Sstevel@tonic-gate 
1500Sstevel@tonic-gate 		  case 'N':
1510Sstevel@tonic-gate 			inclnull = true;
1520Sstevel@tonic-gate 			break;
1530Sstevel@tonic-gate 
1540Sstevel@tonic-gate 		  case 'c':
1550Sstevel@tonic-gate 			params.smdbp_cache_size = atol(optarg);
1560Sstevel@tonic-gate 			break;
1570Sstevel@tonic-gate 
1580Sstevel@tonic-gate 		  case 'd':
1590Sstevel@tonic-gate 			params.smdbp_allow_dup = true;
1600Sstevel@tonic-gate 			break;
1610Sstevel@tonic-gate 
1620Sstevel@tonic-gate 		  case 'e':
1630Sstevel@tonic-gate 			allowempty = true;
1640Sstevel@tonic-gate 			break;
1650Sstevel@tonic-gate 
1660Sstevel@tonic-gate 		  case 'f':
1670Sstevel@tonic-gate 			foldcase = false;
1680Sstevel@tonic-gate 			break;
1690Sstevel@tonic-gate 
1700Sstevel@tonic-gate 		  case 'D':
1710Sstevel@tonic-gate 			comment = *optarg;
1720Sstevel@tonic-gate 			break;
1730Sstevel@tonic-gate 
1740Sstevel@tonic-gate 		  case 'l':
1750Sstevel@tonic-gate 			smdb_print_available_types();
1760Sstevel@tonic-gate 			exit(EX_OK);
1770Sstevel@tonic-gate 			break;
1780Sstevel@tonic-gate 
1790Sstevel@tonic-gate 		  case 'o':
1800Sstevel@tonic-gate 			notrunc = true;
1810Sstevel@tonic-gate 			break;
1820Sstevel@tonic-gate 
1830Sstevel@tonic-gate 		  case 'r':
1840Sstevel@tonic-gate 			allowreplace = true;
1850Sstevel@tonic-gate 			break;
1860Sstevel@tonic-gate 
1870Sstevel@tonic-gate 		  case 's':
1880Sstevel@tonic-gate 			setbitn(DBS_MAPINUNSAFEDIRPATH, DontBlameSendmail);
1890Sstevel@tonic-gate 			setbitn(DBS_WRITEMAPTOHARDLINK, DontBlameSendmail);
1900Sstevel@tonic-gate 			setbitn(DBS_WRITEMAPTOSYMLINK, DontBlameSendmail);
1910Sstevel@tonic-gate 			setbitn(DBS_LINKEDMAPINWRITABLEDIR, DontBlameSendmail);
1920Sstevel@tonic-gate 			break;
1930Sstevel@tonic-gate 
1940Sstevel@tonic-gate 		  case 't':
1950Sstevel@tonic-gate 			if (optarg == NULL || *optarg == '\0')
1960Sstevel@tonic-gate 			{
1970Sstevel@tonic-gate 				sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
1980Sstevel@tonic-gate 					      "Invalid separator\n");
1990Sstevel@tonic-gate 				break;
2000Sstevel@tonic-gate 			}
2010Sstevel@tonic-gate 			sep = *optarg;
2020Sstevel@tonic-gate 			break;
2030Sstevel@tonic-gate 
2040Sstevel@tonic-gate 		  case 'u':
2050Sstevel@tonic-gate 			unmake = true;
2060Sstevel@tonic-gate 			break;
2070Sstevel@tonic-gate 
2080Sstevel@tonic-gate 		  case 'v':
2090Sstevel@tonic-gate 			verbose = true;
2100Sstevel@tonic-gate 			break;
2110Sstevel@tonic-gate 
2120Sstevel@tonic-gate 		  default:
2130Sstevel@tonic-gate 			usage(progname);
2140Sstevel@tonic-gate 			/* NOTREACHED */
2150Sstevel@tonic-gate 		}
2160Sstevel@tonic-gate 	}
2170Sstevel@tonic-gate 
2180Sstevel@tonic-gate 	if (!bitnset(DBS_WRITEMAPTOSYMLINK, DontBlameSendmail))
2190Sstevel@tonic-gate 		sff |= SFF_NOSLINK;
2200Sstevel@tonic-gate 	if (!bitnset(DBS_WRITEMAPTOHARDLINK, DontBlameSendmail))
2210Sstevel@tonic-gate 		sff |= SFF_NOHLINK;
2220Sstevel@tonic-gate 	if (!bitnset(DBS_LINKEDMAPINWRITABLEDIR, DontBlameSendmail))
2230Sstevel@tonic-gate 		sff |= SFF_NOWLINK;
2240Sstevel@tonic-gate 
2250Sstevel@tonic-gate 	argc -= optind;
2260Sstevel@tonic-gate 	argv += optind;
2270Sstevel@tonic-gate 	if (argc != 2)
2280Sstevel@tonic-gate 	{
2290Sstevel@tonic-gate 		usage(progname);
2300Sstevel@tonic-gate 		/* NOTREACHED */
2310Sstevel@tonic-gate 	}
2320Sstevel@tonic-gate 	else
2330Sstevel@tonic-gate 	{
2340Sstevel@tonic-gate 		typename = argv[0];
2350Sstevel@tonic-gate 		mapname = argv[1];
2360Sstevel@tonic-gate 	}
2370Sstevel@tonic-gate 
2380Sstevel@tonic-gate #if HASFCHOWN
2390Sstevel@tonic-gate 	/* Find TrustedUser value in sendmail.cf */
2400Sstevel@tonic-gate 	if ((cfp = sm_io_open(SmFtStdio, SM_TIME_DEFAULT, cfile, SM_IO_RDONLY,
2410Sstevel@tonic-gate 			      NULL)) == NULL)
2420Sstevel@tonic-gate 	{
2430Sstevel@tonic-gate 		sm_io_fprintf(smioerr, SM_TIME_DEFAULT, "makemap: %s: %s",
2440Sstevel@tonic-gate 			      cfile, sm_errstring(errno));
2450Sstevel@tonic-gate 		exit(EX_NOINPUT);
2460Sstevel@tonic-gate 	}
2470Sstevel@tonic-gate 	while (sm_io_fgets(cfp, SM_TIME_DEFAULT, buf, sizeof(buf)) != NULL)
2480Sstevel@tonic-gate 	{
2490Sstevel@tonic-gate 		register char *b;
2500Sstevel@tonic-gate 
2510Sstevel@tonic-gate 		if ((b = strchr(buf, '\n')) != NULL)
2520Sstevel@tonic-gate 			*b = '\0';
2530Sstevel@tonic-gate 
2540Sstevel@tonic-gate 		b = buf;
2550Sstevel@tonic-gate 		switch (*b++)
2560Sstevel@tonic-gate 		{
2570Sstevel@tonic-gate 		  case 'O':		/* option */
2580Sstevel@tonic-gate 			if (strncasecmp(b, " TrustedUser", 12) == 0 &&
2590Sstevel@tonic-gate 			    !(isascii(b[12]) && isalnum(b[12])))
2600Sstevel@tonic-gate 			{
2610Sstevel@tonic-gate 				b = strchr(b, '=');
2620Sstevel@tonic-gate 				if (b == NULL)
2630Sstevel@tonic-gate 					continue;
2640Sstevel@tonic-gate 				while (isascii(*++b) && isspace(*b))
2650Sstevel@tonic-gate 					continue;
2660Sstevel@tonic-gate 				if (isascii(*b) && isdigit(*b))
2670Sstevel@tonic-gate 					TrustedUid = atoi(b);
2680Sstevel@tonic-gate 				else
2690Sstevel@tonic-gate 				{
2700Sstevel@tonic-gate 					TrustedUid = 0;
2710Sstevel@tonic-gate 					pw = getpwnam(b);
2720Sstevel@tonic-gate 					if (pw == NULL)
2730Sstevel@tonic-gate 						(void) sm_io_fprintf(smioerr,
2740Sstevel@tonic-gate 								     SM_TIME_DEFAULT,
2750Sstevel@tonic-gate 								     "TrustedUser: unknown user %s\n", b);
2760Sstevel@tonic-gate 					else
2770Sstevel@tonic-gate 						TrustedUid = pw->pw_uid;
2780Sstevel@tonic-gate 				}
2790Sstevel@tonic-gate 
2800Sstevel@tonic-gate # ifdef UID_MAX
2810Sstevel@tonic-gate 				if (TrustedUid > UID_MAX)
2820Sstevel@tonic-gate 				{
2830Sstevel@tonic-gate 					(void) sm_io_fprintf(smioerr,
2840Sstevel@tonic-gate 							     SM_TIME_DEFAULT,
2850Sstevel@tonic-gate 							     "TrustedUser: uid value (%ld) > UID_MAX (%ld)",
2860Sstevel@tonic-gate 						(long) TrustedUid,
2870Sstevel@tonic-gate 						(long) UID_MAX);
2880Sstevel@tonic-gate 					TrustedUid = 0;
2890Sstevel@tonic-gate 				}
2900Sstevel@tonic-gate # endif /* UID_MAX */
2910Sstevel@tonic-gate 				break;
2920Sstevel@tonic-gate 			}
2930Sstevel@tonic-gate 
2940Sstevel@tonic-gate 
2950Sstevel@tonic-gate 		  default:
2960Sstevel@tonic-gate 			continue;
2970Sstevel@tonic-gate 		}
2980Sstevel@tonic-gate 	}
2990Sstevel@tonic-gate 	(void) sm_io_close(cfp, SM_TIME_DEFAULT);
3000Sstevel@tonic-gate #endif /* HASFCHOWN */
3010Sstevel@tonic-gate 
3020Sstevel@tonic-gate 	if (!params.smdbp_allow_dup && !allowreplace)
3030Sstevel@tonic-gate 		putflags = SMDBF_NO_OVERWRITE;
3040Sstevel@tonic-gate 
3050Sstevel@tonic-gate 	if (unmake)
3060Sstevel@tonic-gate 	{
3070Sstevel@tonic-gate 		mode = O_RDONLY;
3080Sstevel@tonic-gate 		smode = S_IRUSR;
3090Sstevel@tonic-gate 	}
3100Sstevel@tonic-gate 	else
3110Sstevel@tonic-gate 	{
3120Sstevel@tonic-gate 		mode = O_RDWR;
3130Sstevel@tonic-gate 		if (!notrunc)
3140Sstevel@tonic-gate 		{
3150Sstevel@tonic-gate 			mode |= O_CREAT|O_TRUNC;
3160Sstevel@tonic-gate 			sff |= SFF_CREAT;
3170Sstevel@tonic-gate 		}
3180Sstevel@tonic-gate 		smode = S_IWUSR;
3190Sstevel@tonic-gate 	}
3200Sstevel@tonic-gate 
3210Sstevel@tonic-gate 	params.smdbp_num_elements = 4096;
3220Sstevel@tonic-gate 
3230Sstevel@tonic-gate 	errno = smdb_open_database(&database, mapname, mode, smode, sff,
3240Sstevel@tonic-gate 				   typename, &user_info, &params);
3250Sstevel@tonic-gate 	if (errno != SMDBE_OK)
3260Sstevel@tonic-gate 	{
3270Sstevel@tonic-gate 		char *hint;
3280Sstevel@tonic-gate 
3290Sstevel@tonic-gate 		if (errno == SMDBE_UNSUPPORTED_DB_TYPE &&
3300Sstevel@tonic-gate 		    (hint = smdb_db_definition(typename)) != NULL)
3310Sstevel@tonic-gate 			(void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
3320Sstevel@tonic-gate 					     "%s: Need to recompile with -D%s for %s support\n",
3330Sstevel@tonic-gate 					     progname, hint, typename);
3340Sstevel@tonic-gate 		else
3350Sstevel@tonic-gate 			(void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
3360Sstevel@tonic-gate 					     "%s: error opening type %s map %s: %s\n",
3370Sstevel@tonic-gate 					     progname, typename, mapname,
3380Sstevel@tonic-gate 					     sm_errstring(errno));
3390Sstevel@tonic-gate 		exit(EX_CANTCREAT);
3400Sstevel@tonic-gate 	}
3410Sstevel@tonic-gate 
3420Sstevel@tonic-gate 	(void) database->smdb_sync(database, 0);
3430Sstevel@tonic-gate 
3440Sstevel@tonic-gate 	if (!unmake && geteuid() == 0 && TrustedUid != 0)
3450Sstevel@tonic-gate 	{
3460Sstevel@tonic-gate 		errno = database->smdb_set_owner(database, TrustedUid, -1);
3470Sstevel@tonic-gate 		if (errno != SMDBE_OK)
3480Sstevel@tonic-gate 		{
3490Sstevel@tonic-gate 			(void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
3500Sstevel@tonic-gate 					     "WARNING: ownership change on %s failed %s",
3510Sstevel@tonic-gate 					     mapname, sm_errstring(errno));
3520Sstevel@tonic-gate 		}
3530Sstevel@tonic-gate 	}
3540Sstevel@tonic-gate 
3550Sstevel@tonic-gate 	/*
3560Sstevel@tonic-gate 	**  Copy the data
3570Sstevel@tonic-gate 	*/
3580Sstevel@tonic-gate 
3590Sstevel@tonic-gate 	exitstat = EX_OK;
3600Sstevel@tonic-gate 	if (unmake)
3610Sstevel@tonic-gate 	{
3620Sstevel@tonic-gate 		errno = database->smdb_cursor(database, &cursor, 0);
3630Sstevel@tonic-gate 		if (errno != SMDBE_OK)
3640Sstevel@tonic-gate 		{
3650Sstevel@tonic-gate 
3660Sstevel@tonic-gate 			(void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
3670Sstevel@tonic-gate 					     "%s: cannot make cursor for type %s map %s\n",
3680Sstevel@tonic-gate 					     progname, typename, mapname);
3690Sstevel@tonic-gate 			exit(EX_SOFTWARE);
3700Sstevel@tonic-gate 		}
3710Sstevel@tonic-gate 
3720Sstevel@tonic-gate 		memset(&db_key, '\0', sizeof db_key);
3730Sstevel@tonic-gate 		memset(&db_val, '\0', sizeof db_val);
3740Sstevel@tonic-gate 
3750Sstevel@tonic-gate 		for (lineno = 0; ; lineno++)
3760Sstevel@tonic-gate 		{
3770Sstevel@tonic-gate 			errno = cursor->smdbc_get(cursor, &db_key, &db_val,
3780Sstevel@tonic-gate 						  SMDB_CURSOR_GET_NEXT);
3790Sstevel@tonic-gate 			if (errno != SMDBE_OK)
3800Sstevel@tonic-gate 				break;
3810Sstevel@tonic-gate 
3820Sstevel@tonic-gate 			(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
383*6562Sjbeck 					     "%.*s%c%.*s\n",
3840Sstevel@tonic-gate 					     (int) db_key.size,
3850Sstevel@tonic-gate 					     (char *) db_key.data,
386*6562Sjbeck 					     (sep != '\0') ? sep : '\t',
3870Sstevel@tonic-gate 					     (int) db_val.size,
3880Sstevel@tonic-gate 					     (char *)db_val.data);
3890Sstevel@tonic-gate 
3900Sstevel@tonic-gate 		}
3910Sstevel@tonic-gate 		(void) cursor->smdbc_close(cursor);
3920Sstevel@tonic-gate 	}
3930Sstevel@tonic-gate 	else
3940Sstevel@tonic-gate 	{
3950Sstevel@tonic-gate 		lineno = 0;
3960Sstevel@tonic-gate 		while (sm_io_fgets(smioin, SM_TIME_DEFAULT, ibuf, sizeof ibuf)
3970Sstevel@tonic-gate 		       != NULL)
3980Sstevel@tonic-gate 		{
3990Sstevel@tonic-gate 			register char *p;
4000Sstevel@tonic-gate 
4010Sstevel@tonic-gate 			lineno++;
4020Sstevel@tonic-gate 
4030Sstevel@tonic-gate 			/*
4040Sstevel@tonic-gate 			**  Parse the line.
4050Sstevel@tonic-gate 			*/
4060Sstevel@tonic-gate 
4070Sstevel@tonic-gate 			p = strchr(ibuf, '\n');
4080Sstevel@tonic-gate 			if (p != NULL)
4090Sstevel@tonic-gate 				*p = '\0';
4100Sstevel@tonic-gate 			else if (!sm_io_eof(smioin))
4110Sstevel@tonic-gate 			{
4120Sstevel@tonic-gate 				(void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
4130Sstevel@tonic-gate 						     "%s: %s: line %u: line too long (%ld bytes max)\n",
4140Sstevel@tonic-gate 						     progname, mapname, lineno,
4150Sstevel@tonic-gate 						     (long) sizeof ibuf);
4160Sstevel@tonic-gate 				exitstat = EX_DATAERR;
4170Sstevel@tonic-gate 				continue;
4180Sstevel@tonic-gate 			}
4190Sstevel@tonic-gate 
4200Sstevel@tonic-gate 			if (ibuf[0] == '\0' || ibuf[0] == comment)
4210Sstevel@tonic-gate 				continue;
4220Sstevel@tonic-gate 			if (sep == '\0' && isascii(ibuf[0]) && isspace(ibuf[0]))
4230Sstevel@tonic-gate 			{
4240Sstevel@tonic-gate 				(void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
4250Sstevel@tonic-gate 						     "%s: %s: line %u: syntax error (leading space)\n",
4260Sstevel@tonic-gate 						     progname, mapname, lineno);
4270Sstevel@tonic-gate 				exitstat = EX_DATAERR;
4280Sstevel@tonic-gate 				continue;
4290Sstevel@tonic-gate 			}
4300Sstevel@tonic-gate 
4310Sstevel@tonic-gate 			memset(&db_key, '\0', sizeof db_key);
4320Sstevel@tonic-gate 			memset(&db_val, '\0', sizeof db_val);
4330Sstevel@tonic-gate 			db_key.data = ibuf;
4340Sstevel@tonic-gate 
4350Sstevel@tonic-gate 			for (p = ibuf; *p != '\0' && !(ISSEP(*p)); p++)
4360Sstevel@tonic-gate 			{
4370Sstevel@tonic-gate 				if (foldcase && isascii(*p) && isupper(*p))
4380Sstevel@tonic-gate 					*p = tolower(*p);
4390Sstevel@tonic-gate 			}
4400Sstevel@tonic-gate 			db_key.size = p - ibuf;
4410Sstevel@tonic-gate 			if (inclnull)
4420Sstevel@tonic-gate 				db_key.size++;
4430Sstevel@tonic-gate 
4440Sstevel@tonic-gate 			if (*p != '\0')
4450Sstevel@tonic-gate 				*p++ = '\0';
4460Sstevel@tonic-gate 			while (*p != '\0' && ISSEP(*p))
4470Sstevel@tonic-gate 				p++;
4480Sstevel@tonic-gate 			if (!allowempty && *p == '\0')
4490Sstevel@tonic-gate 			{
4500Sstevel@tonic-gate 				(void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
4510Sstevel@tonic-gate 						     "%s: %s: line %u: no RHS for LHS %s\n",
4520Sstevel@tonic-gate 						     progname, mapname, lineno,
4530Sstevel@tonic-gate 						     (char *) db_key.data);
4540Sstevel@tonic-gate 				exitstat = EX_DATAERR;
4550Sstevel@tonic-gate 				continue;
4560Sstevel@tonic-gate 			}
4570Sstevel@tonic-gate 
4580Sstevel@tonic-gate 			db_val.data = p;
4590Sstevel@tonic-gate 			db_val.size = strlen(p);
4600Sstevel@tonic-gate 			if (inclnull)
4610Sstevel@tonic-gate 				db_val.size++;
4620Sstevel@tonic-gate 
4630Sstevel@tonic-gate 			/*
4640Sstevel@tonic-gate 			**  Do the database insert.
4650Sstevel@tonic-gate 			*/
4660Sstevel@tonic-gate 
4670Sstevel@tonic-gate 			if (verbose)
4680Sstevel@tonic-gate 			{
4690Sstevel@tonic-gate 				(void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
4700Sstevel@tonic-gate 						     "key=`%s', val=`%s'\n",
4710Sstevel@tonic-gate 						     (char *) db_key.data,
4720Sstevel@tonic-gate 						     (char *) db_val.data);
4730Sstevel@tonic-gate 			}
4740Sstevel@tonic-gate 
4750Sstevel@tonic-gate 			errno = database->smdb_put(database, &db_key, &db_val,
4760Sstevel@tonic-gate 						   putflags);
4770Sstevel@tonic-gate 			switch (errno)
4780Sstevel@tonic-gate 			{
4790Sstevel@tonic-gate 			  case SMDBE_KEY_EXIST:
4800Sstevel@tonic-gate 				st = 1;
4810Sstevel@tonic-gate 				break;
4820Sstevel@tonic-gate 
4830Sstevel@tonic-gate 			  case 0:
4840Sstevel@tonic-gate 				st = 0;
4850Sstevel@tonic-gate 				break;
4860Sstevel@tonic-gate 
4870Sstevel@tonic-gate 			  default:
4880Sstevel@tonic-gate 				st = -1;
4890Sstevel@tonic-gate 				break;
4900Sstevel@tonic-gate 			}
4910Sstevel@tonic-gate 
4920Sstevel@tonic-gate 			if (st < 0)
4930Sstevel@tonic-gate 			{
4940Sstevel@tonic-gate 				(void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
4950Sstevel@tonic-gate 						     "%s: %s: line %u: key %s: put error: %s\n",
4960Sstevel@tonic-gate 						     progname, mapname, lineno,
4970Sstevel@tonic-gate 						     (char *) db_key.data,
4980Sstevel@tonic-gate 						     sm_errstring(errno));
4990Sstevel@tonic-gate 				exitstat = EX_IOERR;
5000Sstevel@tonic-gate 			}
5010Sstevel@tonic-gate 			else if (st > 0)
5020Sstevel@tonic-gate 			{
5030Sstevel@tonic-gate 				(void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
5040Sstevel@tonic-gate 						     "%s: %s: line %u: key %s: duplicate key\n",
5050Sstevel@tonic-gate 						     progname, mapname,
5060Sstevel@tonic-gate 						     lineno,
5070Sstevel@tonic-gate 						     (char *) db_key.data);
5080Sstevel@tonic-gate 				exitstat = EX_DATAERR;
5090Sstevel@tonic-gate 			}
5100Sstevel@tonic-gate 		}
5110Sstevel@tonic-gate 	}
5120Sstevel@tonic-gate 
5130Sstevel@tonic-gate 	/*
5140Sstevel@tonic-gate 	**  Now close the database.
5150Sstevel@tonic-gate 	*/
5160Sstevel@tonic-gate 
5170Sstevel@tonic-gate 	errno = database->smdb_close(database);
5180Sstevel@tonic-gate 	if (errno != SMDBE_OK)
5190Sstevel@tonic-gate 	{
5200Sstevel@tonic-gate 		(void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
5210Sstevel@tonic-gate 				     "%s: close(%s): %s\n",
5220Sstevel@tonic-gate 				     progname, mapname, sm_errstring(errno));
5230Sstevel@tonic-gate 		exitstat = EX_IOERR;
5240Sstevel@tonic-gate 	}
5250Sstevel@tonic-gate 	smdb_free_database(database);
5260Sstevel@tonic-gate 
5270Sstevel@tonic-gate 	exit(exitstat);
5280Sstevel@tonic-gate 
5290Sstevel@tonic-gate 	/* NOTREACHED */
5300Sstevel@tonic-gate 	return exitstat;
5310Sstevel@tonic-gate }
532