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 ino_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 86 close(int filedes) { 87 88 struct stat 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 && fstat(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 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 stat 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 (fstat(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 (fstat(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 * 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 * 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 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 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 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