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