1/*
2 * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * "Portions Copyright (c) 1999 Apple Computer, Inc.  All Rights
7 * Reserved.  This file contains Original Code and/or Modifications of
8 * Original Code as defined in and that are subject to the Apple Public
9 * Source License Version 1.0 (the 'License').  You may not use this file
10 * except in compliance with the License.  Please obtain a copy of the
11 * License at http://www.apple.com/publicsource and read it before using
12 * this file.
13 *
14 * The Original Code and all software distributed under the License are
15 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
16 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
17 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT.  Please see the
19 * License for the specific language governing rights and limitations
20 * under the License."
21 *
22 * @APPLE_LICENSE_HEADER_END@
23 */
24/*	$OpenBSD: makedbm.c,v 1.9 1997/08/18 03:11:34 millert Exp $ */
25
26/*
27 * Copyright (c) 1994-97 Mats O Jansson <moj@stacken.kth.se>
28 * All rights reserved.
29 *
30 * Redistribution and use in source and binary forms, with or without
31 * modification, are permitted provided that the following conditions
32 * are met:
33 * 1. Redistributions of source code must retain the above copyright
34 *    notice, this list of conditions and the following disclaimer.
35 * 2. Redistributions in binary form must reproduce the above copyright
36 *    notice, this list of conditions and the following disclaimer in the
37 *    documentation and/or other materials provided with the distribution.
38 * 3. All advertising materials mentioning features or use of this software
39 *    must display the following acknowledgement:
40 *	This product includes software developed by Mats O Jansson
41 * 4. The name of the author may not be used to endorse or promote products
42 *    derived from this software without specific prior written permission.
43 *
44 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
45 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
46 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
47 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
48 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
49 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
50 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
51 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
52 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
53 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
54 * SUCH DAMAGE.
55 */
56
57#include <sys/cdefs.h>
58#ifndef LINT
59__unused static char rcsid[] = "$OpenBSD: makedbm.c,v 1.9 1997/08/18 03:11:34 millert Exp $";
60#endif
61
62#include <stdio.h>
63#include <stdlib.h>
64#include <time.h>
65#include <fcntl.h>
66#include <ctype.h>
67#include <sys/stat.h>
68#include <sys/param.h>
69#include <unistd.h>
70#include <string.h>
71#include <sys/errno.h>
72#include "ypdb.h"
73#include "ypdef.h"
74#include "db.h"
75
76extern char *__progname;		/* from crt0.o */
77extern int db_hash_list_database(char *);
78
79/*
80 * Read one line
81 */
82
83static int read_line(fp, buf, size)
84	FILE	*fp;
85	char	*buf;
86	int	size;
87{
88	int	done;
89
90	done = 0;
91
92	do {
93		while (fgets(buf, size, fp)) {
94			int len = strlen(buf);
95			done += len;
96			if (len > 1 && buf[len-2] == '\\' &&
97					buf[len-1] == '\n') {
98				int ch;
99				buf += len - 2;
100				size -= len - 2;
101				*buf = '\n'; buf[1] = '\0';
102
103				/* Skip leading white space on next line */
104				while ((ch = getc(fp)) != EOF &&
105					isascii(ch) && isspace(ch))
106						;
107				(void) ungetc(ch, fp);
108			} else {
109				return done;
110			}
111		}
112	} while (size > 0 && !feof(fp));
113
114	return done;
115}
116
117void
118add_record(db, str1, str2, check)
119	DBM	*db;
120	char	*str1, *str2;
121	int     check;
122{
123        datum   key,val;
124        int     status;
125
126	key.dptr = str1;
127	key.dsize = strlen(str1);
128
129	if (check) {
130	        val = ypdb_fetch(db,key);
131
132		if (val.dptr != NULL)
133			return;		/* already there */
134
135	}
136
137        val.dptr  = str2;
138	val.dsize = strlen(str2);
139	status = ypdb_store(db, key, val, YPDB_INSERT);
140
141	if (status != 0) {
142		printf("%s: problem storing %s %s\n",__progname,str1,str2);
143		exit(1);
144	}
145}
146
147static char *
148file_date(filename)
149	char	*filename;
150{
151	struct	stat finfo;
152	static	char datestr[11];
153	int	status;
154
155	if (strcmp(filename,"-") == 0) {
156		sprintf(datestr, "%010ld", time(0));
157	} else {
158		status = stat(filename, &finfo);
159		if (status < 0) {
160			fprintf(stderr, "%s: can't stat %s\n", __progname, filename);
161			exit(1);
162		}
163		sprintf(datestr, "%010ld", finfo.st_mtime);
164	}
165
166	return datestr;
167}
168
169void
170list_database(database,Uflag)
171	char	*database;
172	int	Uflag;
173{
174	DBM	*db;
175	datum	key,val;
176
177	db = ypdb_open(database, O_RDONLY, 0444);
178
179	if (db == NULL) {
180
181		if (Uflag != 0) {
182
183			if (db_hash_list_database(database)) return;
184
185		}
186
187
188		fprintf(stderr, "%s: can't open database %s\n", __progname, database);
189		exit(1);
190	}
191
192	key = ypdb_firstkey(db);
193
194	while (key.dptr != NULL) {
195	        val = ypdb_fetch(db,key);
196		printf("%*.*s %*.*s\n",
197		       key.dsize, key.dsize, key.dptr,
198		       val.dsize, val.dsize, val.dptr);
199		key = ypdb_nextkey(db);
200	}
201
202	ypdb_close(db);
203
204}
205
206void
207
208create_database(infile,database,
209		yp_input_file,yp_output_file,
210		yp_master_name,yp_domain_name,
211		bflag, lflag, sflag)
212	char	*infile, *database;
213	char	*yp_input_file, *yp_output_file;
214	char	*yp_master_name, *yp_domain_name;
215	int	bflag, lflag, sflag;
216{
217	FILE	*data_file;
218	char	data_line[4096]; /* XXX: DB bsize = 4096 in ypdb.c */
219	char	myname[MAXHOSTNAMELEN];
220	int	line_no = 0;
221	int	len;
222	char	*p,*k,*v;
223	char	*slash;
224	DBM	*new_db;
225	static	char mapname[] = "ypdbXXXXXXXXXX";
226	char	db_mapname[MAXPATHLEN],db_outfile[MAXPATHLEN],
227		db_tempname[MAXPATHLEN];
228	char	empty_str[] = "";
229
230	if (strcmp(infile,"-") == 0) {
231		data_file = stdin;
232	} else {
233		data_file = fopen(infile, "r");
234		if (errno != 0) {
235			(void)fprintf(stderr,"%s: ",__progname);
236			perror(infile);
237			exit(1);
238		}
239	}
240
241	if (strlen(database) + strlen(YPDB_SUFFIX) > MAXPATHLEN) {
242		fprintf(stderr,"%s: %s: file name too long\n",
243			__progname, database);
244		exit(1);
245	}
246	snprintf(db_outfile, sizeof(db_outfile), "%s%s", database, YPDB_SUFFIX);
247
248	slash = strrchr(database, '/');
249	if (slash != NULL)
250		slash[1] = 0; 			/* truncate to dir */
251	else
252		*database = 0;			/* elminate */
253
254	/* note: database is now directory where map goes ! */
255
256	if (strlen(database) + strlen(mapname)
257			+ strlen(YPDB_SUFFIX) > MAXPATHLEN) {
258		fprintf(stderr,"%s: %s: directory name too long\n",
259			__progname, database);
260		exit(1);
261	}
262
263	snprintf(db_tempname, sizeof(db_tempname), "%s%s", database,
264		mapname);
265	mktemp(db_tempname);
266	snprintf(db_mapname, sizeof(db_mapname), "%s%s", db_tempname,
267		YPDB_SUFFIX);
268
269	new_db = ypdb_open(db_tempname, O_RDWR|O_CREAT, 0444);
270
271	while (read_line(data_file,data_line,sizeof(data_line))) {
272
273		line_no++;
274		len =  strlen(data_line);
275
276		/* Check if we have the whole line */
277
278		if (data_line[len-1] != '\n') {
279			fprintf(stderr, "line %d in \"%s\" is too long",
280				line_no, infile);
281		} else {
282			data_line[len-1] = '\0';
283		}
284
285		p = (char *) &data_line;
286
287		k  = p;				     /* save start of key */
288		while (!isspace(*p)) {		    /* find first "space" */
289			if (lflag && isupper(*p))   /* if force lower case */
290				*p = tolower(*p);   /* fix it */
291			p++;
292		};
293		while (isspace(*p)) {		/* replace space with <NUL> */
294			*p = '\0';
295			p++;
296		};
297
298		v = p;				/* save start of value */
299		while(*p != '\0') { p++; };	/* find end of string */
300
301		add_record(new_db, k, v, TRUE);	/* save record */
302
303	}
304
305	if (strcmp(infile,"-") != 0) {
306		(void) fclose(data_file);
307	}
308
309	add_record(new_db, YP_LAST_KEY, file_date(infile), FALSE);
310
311	if (yp_input_file) {
312		add_record(new_db, YP_INPUT_KEY, yp_input_file, FALSE);
313	}
314
315	if (yp_output_file) {
316		add_record(new_db, YP_OUTPUT_KEY, yp_output_file, FALSE);
317	}
318
319	if (yp_master_name) {
320		add_record(new_db, YP_MASTER_KEY, yp_master_name, FALSE);
321	} else {
322		gethostname(myname, sizeof(myname) - 1);
323		add_record(new_db, YP_MASTER_KEY, myname, FALSE);
324	}
325
326	if (yp_domain_name) {
327		add_record(new_db, YP_DOMAIN_KEY, yp_domain_name, FALSE);
328	}
329
330	if (bflag) {
331		add_record(new_db, YP_INTERDOMAIN_KEY, empty_str, FALSE);
332	}
333
334	if (sflag) {
335		add_record(new_db, YP_SECURE_KEY, empty_str, FALSE);
336	}
337
338	ypdb_close(new_db);
339	if (rename(db_mapname,db_outfile) < 0) {
340		perror("rename");
341		fprintf(stderr,"rename %s -> %s failed!\n", db_mapname,
342			db_outfile);
343		exit(1);
344	}
345
346}
347
348int
349main (argc,argv)
350	int	argc;
351	char	*argv[];
352{
353	int	aflag, uflag, bflag, lflag, sflag, Uflag;
354	char	*yp_input_file, *yp_output_file;
355	char	*yp_master_name,*yp_domain_name;
356	char	*infile,*outfile;
357	int	usage = 0;
358	int	ch;
359
360	extern int optind;
361
362	yp_input_file = yp_output_file = NULL;
363	yp_master_name = yp_domain_name = NULL;
364	aflag = uflag = bflag = lflag = sflag = Uflag = 0;
365	infile = outfile = NULL;
366
367	while ((ch = getopt(argc, argv, "Ublsui:o:m:d:")) != -1)
368		switch (ch) {
369			case 'U':
370				uflag++;
371				Uflag++;
372				break;
373			case 'b':
374		  		bflag++;
375				aflag++;
376				break;
377			case 'l':
378				lflag++;
379				aflag++;
380				break;
381			case 's':
382				sflag++;
383				aflag++;
384				break;
385			case 'i':
386				yp_input_file = argv[optind];
387				aflag++;
388				break;
389			case 'o':
390				yp_output_file = argv[optind];
391				aflag++;
392				break;
393			case 'm':
394				yp_master_name = argv[optind];
395				aflag++;
396				break;
397			case 'd':
398				yp_domain_name = argv[optind];
399				aflag++;
400				break;
401			case 'u':
402				uflag++;
403				break;
404			default:
405				usage++;
406				break;
407		}
408
409	if ((uflag != 0) && (aflag != 0)) {
410		usage++;
411	} else {
412
413		if (uflag != 0) {
414			if (argc == (optind + 1)) {
415				infile = argv[optind];
416			} else {
417				usage++;
418			}
419		} else {
420			if (argc == (optind + 2)) {
421				infile = argv[optind];
422				outfile = argv[optind+1];
423			} else {
424				usage++;
425			}
426		}
427	}
428
429	if (usage) {
430		fprintf(stderr,"%s%s%s",
431			"usage:\tmakedbm [-u|-U] file\n\tmakedbm [-bls]",
432			" [-i YP_INPUT_FILE] [-o YP_OUTPUT_FILE]\n\t\t",
433			"[-d YP_DOMAIN_NAME] [-m YP_MASTER_NAME] infile outfile\n");
434		exit(1);
435	}
436
437	if (uflag != 0) {
438		list_database(infile,Uflag);
439	} else {
440		create_database(infile,outfile,
441				yp_input_file,yp_output_file,
442				yp_master_name,yp_domain_name,
443				bflag, lflag, sflag);
444	}
445
446	return(0);
447
448}
449