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