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 2005 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 int 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 stat 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 strcpy(key_sep, argv[1]); 181 argv++; 182 argc--; 183 if (strlen(key_sep) != 1) { 184 fprintf(stderr, 185 "bad separator\n"); 186 usage(); 187 } 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 (fstat(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 (fstat(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 * 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 * 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 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 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 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