1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21
22 /*
23 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
25 */
26
27 /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
28 /* All Rights Reserved */
29
30 /*
31 * Portions of this source code were derived from Berkeley
32 * under license from the Regents of the University of
33 * California.
34 */
35
36 #pragma ident "%Z%%M% %I% %E% SMI"
37
38 #undef NULL
39 #include <stdio.h>
40 #include <sys/types.h>
41 #include <sys/file.h>
42 #include <sys/param.h>
43 #include <sys/stat.h>
44 #include <ctype.h>
45 #include <limits.h>
46 #include <string.h>
47 #include <unistd.h>
48 #include <stdlib.h>
49 #include <sys/systeminfo.h>
50 #include <dlfcn.h>
51
52 #include "ypdefs.h"
53 #include "ypsym.h"
54 USE_YP_MASTER_NAME
55 USE_YP_LAST_MODIFIED
56 USE_YP_INPUT_FILE
57 USE_YP_OUTPUT_NAME
58 USE_YP_DOMAIN_NAME
59 USE_YP_SECURE
60 USE_YP_INTERDOMAIN
61 USE_DBM
62
63 #ifdef SYSVCONFIG
64 extern void sysvconfig();
65 #endif
66 extern int yp_getalias();
67
68 #define MAXLINE 4096 /* max length of input line */
69 #define DEFAULT_SEP " "
70 static char *get_date();
71 static char *any();
72 static void addpair();
73 static void unmake();
74 static void usage();
75
76 int inode_dev_valid = 0;
77 ino64_t inode;
78 dev_t dev;
79
80 /*
81 * Interpose close(2) to enable us to keep one of the output
82 * files open until process exit.
83 */
84 #pragma weak _close = close
85 int
close(int filedes)86 close(int filedes) {
87
88 struct stat64 sb;
89 static int (*fptr)() = 0;
90
91 if (fptr == 0) {
92 fptr = (int (*)())dlsym(RTLD_NEXT, "close");
93 if (fptr == 0) {
94 fprintf(stderr, "makedbm: dlopen(close): %s\n",
95 dlerror());
96 errno = ELIBACC;
97 return (-1);
98 }
99 }
100
101 if (inode_dev_valid != 0 && fstat64(filedes, &sb) == 0) {
102 if (sb.st_ino == inode && sb.st_dev == dev) {
103 /* Keep open; pretend successful */
104 return (0);
105 }
106 }
107
108 return ((*fptr)(filedes));
109 }
110
111 int
main(argc,argv)112 main(argc, argv)
113 int argc;
114 char **argv;
115 {
116 FILE *infp, *outfp;
117 datum key, content, tmp;
118 char buf[MAXLINE];
119 char pagbuf[MAXPATHLEN];
120 char tmppagbuf[MAXPATHLEN];
121 char dirbuf[MAXPATHLEN];
122 char tmpdirbuf[MAXPATHLEN];
123 char *p, ic;
124 char *infile, *outfile;
125 char outalias[MAXPATHLEN];
126 char outaliasmap[MAXNAMLEN];
127 char outaliasdomain[MAXNAMLEN];
128 char *last_slash, *next_to_last_slash;
129 char *infilename, *outfilename, *mastername, *domainname,
130 *interdomain_bind, *security, *lower_case_keys;
131 char *key_sep = DEFAULT_SEP;
132 char local_host[MAX_MASTER_NAME];
133 int cnt, i;
134 DBM *fdb;
135 struct stat64 statbuf;
136 int num_del_to_match = 0;
137 /* flag to indicate if matching char can be escaped */
138 int count_esp = 0;
139
140 /* Ignore existing umask, always force 077 (owner rw only) */
141 umask(077);
142
143 infile = outfile = NULL; /* where to get files */
144 /* name to imbed in database */
145 infilename = outfilename = mastername = domainname = interdomain_bind =
146 security = lower_case_keys = NULL;
147 argv++;
148 argc--;
149 while (argc > 0) {
150 if (argv[0][0] == '-' && argv[0][1]) {
151 switch (argv[0][1]) {
152 case 'i':
153 infilename = argv[1];
154 argv++;
155 argc--;
156 break;
157 case 'o':
158 outfilename = argv[1];
159 argv++;
160 argc--;
161 break;
162 case 'm':
163 mastername = argv[1];
164 argv++;
165 argc--;
166 break;
167 case 'b':
168 interdomain_bind = argv[0];
169 break;
170 case 'd':
171 domainname = argv[1];
172 argv++;
173 argc--;
174 break;
175 case 'l':
176 lower_case_keys = argv[0];
177 break;
178 case 's':
179 security = argv[0];
180 break;
181 case 'S' :
182 strcpy(key_sep, argv[1]);
183 argv++;
184 argc--;
185 if (strlen(key_sep) != 1) {
186 fprintf(stderr,
187 "bad separator\n");
188 usage();
189 }
190 break;
191 case 'D' :
192 num_del_to_match = atoi(argv[1]);
193 argv++;
194 argc--;
195 break;
196 case 'E' :
197 count_esp = 1;
198 break;
199 case 'u':
200 unmake(argv[1]);
201 argv++;
202 argc--;
203 exit(0);
204 default:
205 usage();
206 }
207 } else if (infile == NULL)
208 infile = argv[0];
209 else if (outfile == NULL)
210 outfile = argv[0];
211 else
212 usage();
213 argv++;
214 argc--;
215 }
216 if (infile == NULL || outfile == NULL)
217 usage();
218
219 /*
220 * do alias mapping if necessary
221 */
222 last_slash = strrchr(outfile, '/');
223 if (last_slash) {
224 *last_slash = '\0';
225 next_to_last_slash = strrchr(outfile, '/');
226 if (next_to_last_slash) *next_to_last_slash = '\0';
227 } else next_to_last_slash = NULL;
228
229 #ifdef DEBUG
230 if (last_slash) printf("last_slash=%s\n", last_slash+1);
231 if (next_to_last_slash) printf("next_to_last_slash=%s\n",
232 next_to_last_slash+1);
233 #endif /* DEBUG */
234
235 /* reads in alias file for system v filename translation */
236 #ifdef SYSVCONFIG
237 sysvconfig();
238 #endif
239
240 if (last_slash && next_to_last_slash) {
241 if (yp_getalias(last_slash+1, outaliasmap, MAXALIASLEN) < 0) {
242 if ((int)strlen(last_slash+1) <= MAXALIASLEN)
243 strcpy(outaliasmap, last_slash+1);
244 else
245 fprintf(stderr,
246 "makedbm: warning: no alias for %s\n",
247 last_slash+1);
248 }
249 #ifdef DEBUG
250 printf("%s\n", last_slash+1);
251 printf("%s\n", outaliasmap);
252 #endif /* DEBUG */
253 if (yp_getalias(next_to_last_slash+1, outaliasdomain,
254 NAME_MAX) < 0) {
255 if ((int)strlen(last_slash+1) <= NAME_MAX)
256 strcpy(outaliasdomain, next_to_last_slash+1);
257 else
258 fprintf(stderr,
259 "makedbm: warning: no alias for %s\n",
260 next_to_last_slash+1);
261 }
262 #ifdef DEBUG
263 printf("%s\n", next_to_last_slash+1);
264 printf("%s\n", outaliasdomain);
265 #endif /* DEBUG */
266 sprintf(outalias, "%s/%s/%s", outfile, outaliasdomain,
267 outaliasmap);
268 #ifdef DEBUG
269 printf("outlias=%s\n", outalias);
270 #endif /* DEBUG */
271
272 } else if (last_slash) {
273 if (yp_getalias(last_slash+1, outaliasmap, MAXALIASLEN) < 0) {
274 if ((int)strlen(last_slash+1) <= MAXALIASLEN)
275 strcpy(outaliasmap, last_slash+1);
276 else
277 fprintf(stderr,
278 "makedbm: warning: no alias for %s\n",
279 last_slash+1);
280 }
281 if (yp_getalias(outfile, outaliasdomain, NAME_MAX) < 0) {
282 if ((int)strlen(outfile) <= NAME_MAX)
283 strcpy(outaliasdomain, outfile);
284 else
285 fprintf(stderr,
286 "makedbm: warning: no alias for %s\n",
287 last_slash+1);
288 }
289 sprintf(outalias, "%s/%s", outaliasdomain, outaliasmap);
290 } else {
291 if (yp_getalias(outfile, outalias, MAXALIASLEN) < 0) {
292 if ((int)strlen(last_slash+1) <= MAXALIASLEN)
293 strcpy(outalias, outfile);
294 else
295 fprintf(stderr,
296 "makedbm: warning: no alias for %s\n",
297 outfile);
298 }
299 }
300 #ifdef DEBUG
301 fprintf(stderr, "outalias=%s\n", outalias);
302 fprintf(stderr, "outfile=%s\n", outfile);
303 #endif /* DEBUG */
304
305 strcpy(tmppagbuf, outalias);
306 strcat(tmppagbuf, ".tmp");
307 strcpy(tmpdirbuf, tmppagbuf);
308 strcat(tmpdirbuf, dbm_dir);
309 strcat(tmppagbuf, dbm_pag);
310
311 /* Loop until we can lock the tmpdirbuf file */
312 for (;;) {
313
314 if (strcmp(infile, "-") != 0)
315 infp = fopen(infile, "r");
316 else if (fstat64(fileno(stdin), &statbuf) == -1) {
317 fprintf(stderr, "makedbm: can't open stdin\n");
318 exit(1);
319 } else
320 infp = stdin;
321
322 if (infp == NULL) {
323 fprintf(stderr, "makedbm: can't open %s\n", infile);
324 exit(1);
325 }
326
327 if ((outfp = fopen(tmpdirbuf, "w")) == (FILE *)NULL) {
328 fprintf(stderr, "makedbm: can't create %s\n",
329 tmpdirbuf);
330 exit(1);
331 }
332
333 if (lockf(fileno(outfp), F_TLOCK, 0) == 0) {
334 /* Got exclusive access; save inode and dev */
335 if (fstat64(fileno(outfp), &statbuf) != 0) {
336 fprintf(stderr, "makedbm: can't fstat ");
337 perror(tmpdirbuf);
338 exit(1);
339 }
340 inode = statbuf.st_ino;
341 dev = statbuf.st_dev;
342 inode_dev_valid = 1;
343 break;
344 }
345
346 if (errno != EAGAIN) {
347 fprintf(stderr, "makedbm: can't lock ");
348 perror(tmpdirbuf);
349 exit(1);
350 }
351
352 /*
353 * Someone else is holding the lock.
354 * Close both output and input file
355 * (the latter to ensure consistency
356 * if the input file is updated while
357 * we're suspended), wait a little,
358 * and try again.
359 */
360 if (infp != stdin)
361 (void) fclose(infp);
362 (void) fclose(outfp);
363 sleep(1);
364 }
365
366 if (fopen(tmppagbuf, "w") == (FILE *)NULL) {
367 fprintf(stderr, "makedbm: can't create %s\n", tmppagbuf);
368 exit(1);
369 }
370 strcpy(dirbuf, outalias);
371 strcat(dirbuf, ".tmp");
372 if ((fdb = dbm_open(dirbuf, O_RDWR | O_CREAT, 0644)) == NULL) {
373 fprintf(stderr, "makedbm: can't open %s\n", dirbuf);
374 exit(1);
375 }
376 strcpy(dirbuf, outalias);
377 strcpy(pagbuf, outalias);
378 strcat(dirbuf, dbm_dir);
379 strcat(pagbuf, dbm_pag);
380 while (fgets(buf, sizeof (buf), infp) != NULL) {
381 p = buf;
382 cnt = strlen(buf) - 1; /* erase trailing newline */
383 while (p[cnt-1] == '\\') {
384 p += cnt-1;
385 if (fgets(p, sizeof (buf)-(p-buf), infp) == NULL)
386 goto breakout;
387 cnt = strlen(p) - 1;
388 }
389 if (strcmp(key_sep, DEFAULT_SEP) == 0) {
390 p = any(buf, " \t\n", num_del_to_match, count_esp);
391 } else {
392 p = any(buf, key_sep, num_del_to_match, count_esp);
393 }
394 key.dptr = buf;
395 key.dsize = p - buf;
396 for (;;) {
397 if (p == NULL || *p == NULL) {
398 fprintf(stderr,
399 "makedbm: source files is garbage!\n");
400 exit(1);
401 }
402 if (*p != ' ' && *p != '\t' && *p != key_sep[0])
403 break;
404 p++;
405 }
406 content.dptr = p;
407 content.dsize = strlen(p) - 1; /* erase trailing newline */
408 if (lower_case_keys) {
409 for (i = (strncmp(key.dptr, "YP_MULTI_", 9) ? 0 : 9);
410 i < key.dsize; i++) {
411
412 ic = *(key.dptr+i);
413 if (isascii(ic) && isupper(ic))
414 *(key.dptr+i) = tolower(ic);
415 }
416 }
417 tmp = dbm_fetch(fdb, key);
418 if (tmp.dptr == NULL) {
419 if (dbm_store(fdb, key, content, 1) != 0) {
420 printf("problem storing %.*s %.*s\n",
421 key.dsize, key.dptr,
422 content.dsize, content.dptr);
423 exit(1);
424 }
425 }
426 #ifdef DEBUG
427 else {
428 printf("duplicate: %.*s %.*s\n",
429 key.dsize, key.dptr,
430 content.dsize, content.dptr);
431 }
432 #endif
433 }
434 breakout:
435 addpair(fdb, yp_last_modified, get_date(infile));
436 if (infilename)
437 addpair(fdb, yp_input_file, infilename);
438 if (outfilename)
439 addpair(fdb, yp_output_file, outfilename);
440 if (domainname)
441 addpair(fdb, yp_domain_name, domainname);
442 if (security)
443 addpair(fdb, yp_secure, "");
444 if (interdomain_bind)
445 addpair(fdb, yp_interdomain, "");
446 if (!mastername) {
447 sysinfo(SI_HOSTNAME, local_host, sizeof (local_host) - 1);
448 mastername = local_host;
449 }
450 addpair(fdb, yp_master_name, mastername);
451 (void) dbm_close(fdb);
452 #ifdef DEBUG
453 fprintf(stderr, ".tmp ndbm map closed. ndbm successful !\n");
454 #endif
455 if (rename(tmppagbuf, pagbuf) < 0) {
456 perror("makedbm: rename");
457 unlink(tmppagbuf); /* Remove the tmp files */
458 unlink(tmpdirbuf);
459 exit(1);
460 }
461 if (rename(tmpdirbuf, dirbuf) < 0) {
462 perror("makedbm: rename");
463 unlink(tmppagbuf); /* Remove the tmp files */
464 unlink(tmpdirbuf);
465 exit(1);
466 }
467 /*
468 * sprintf(buf, "mv %s %s", tmppagbuf, pagbuf);
469 * if (system(buf) < 0)
470 * perror("makedbm: rename");
471 * sprintf(buf, "mv %s %s", tmpdirbuf, dirbuf);
472 * if (system(buf) < 0)
473 * perror("makedbm: rename");
474 */
475 exit(0);
476 }
477
478
479 /*
480 * scans cp, looking for a match with any character
481 * in match. Returns pointer to place in cp that matched
482 * (or NULL if no match)
483 *
484 * It will find the num_del_to_match+1
485 * matching character in the line.
486 *
487 * The backslash escapes a delimiter if count_esp==1
488 * We don't count it as a character match if
489 * an escape character precedes a matching character.
490 *
491 */
492 static char *
any(cp,match,num_del_to_match,count_esp)493 any(cp, match, num_del_to_match, count_esp)
494 register char *cp;
495 char *match;
496 int num_del_to_match;
497 int count_esp;
498 {
499 register char *mp, c, prev_char;
500 int num_del_matched;
501
502 num_del_matched = 0;
503 prev_char = ' ';
504 while (c = *cp) {
505 for (mp = match; *mp; mp++) {
506 if (*mp == c) {
507 if (!count_esp) {
508 num_del_matched++;
509 } else if (prev_char != '\\') {
510 num_del_matched++;
511 }
512 if (num_del_matched > num_del_to_match)
513 return (cp);
514 }
515 }
516 prev_char = c;
517 cp++;
518 }
519 return ((char *)0);
520 }
521
522 static char *
get_date(name)523 get_date(name)
524 char *name;
525 {
526 struct stat filestat;
527 static char ans[MAX_ASCII_ORDER_NUMBER_LENGTH];
528 /* ASCII numeric string */
529
530 if (strcmp(name, "-") == 0)
531 sprintf(ans, "%010ld", (long)time(0));
532 else {
533 if (stat(name, &filestat) < 0) {
534 fprintf(stderr, "makedbm: can't stat %s\n", name);
535 exit(1);
536 }
537 sprintf(ans, "%010ld", (long)filestat.st_mtime);
538 }
539 return (ans);
540 }
541
542 void
usage()543 usage()
544 {
545 fprintf(stderr,
546 "usage: makedbm -u file\n makedbm [-b] [-l] [-s] [-i YP_INPUT_FILE] "
547 "[-o YP_OUTPUT_FILE] [-d YP_DOMAIN_NAME] [-m YP_MASTER_NAME] "
548 "[-S DELIMITER] [-D NUM_DELIMITER_TO_SKIP] [-E] "
549 "infile outfile\n");
550 exit(1);
551 }
552
553 void
addpair(fdb,str1,str2)554 addpair(fdb, str1, str2)
555 DBM *fdb;
556 char *str1, *str2;
557 {
558 datum key;
559 datum content;
560
561 key.dptr = str1;
562 key.dsize = strlen(str1);
563 content.dptr = str2;
564 content.dsize = strlen(str2);
565 if (dbm_store(fdb, key, content, 1) != 0) {
566 printf("makedbm: problem storing %.*s %.*s\n",
567 key.dsize, key.dptr, content.dsize, content.dptr);
568 exit(1);
569 }
570 }
571
572 void
unmake(file)573 unmake(file)
574 char *file;
575 {
576 datum key, content;
577 DBM *fdb;
578
579 if (file == NULL)
580 usage();
581
582 if ((fdb = dbm_open(file, O_RDONLY, 0644)) == NULL) {
583 fprintf(stderr, "makedbm: couldn't open %s dbm file\n", file);
584 exit(1);
585 }
586
587 for (key = dbm_firstkey(fdb); key.dptr != NULL;
588 key = dbm_nextkey(fdb)) {
589 content = dbm_fetch(fdb, key);
590 printf("%.*s %.*s\n", key.dsize, key.dptr,
591 content.dsize, content.dptr);
592 }
593
594 dbm_close(fdb);
595 }
596