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 /* 23 * Copyright 1998 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ 28 /* All Rights Reserved */ 29 30 #pragma ident "%Z%%M% %I% %E% SMI" 31 32 # include <stdio.h> 33 # include <sys/types.h> 34 # include <sys/stat.h> 35 # include <unistd.h> 36 # include "extern.h" 37 # include "misc.h" 38 # include <sac.h> 39 # include "structs.h" 40 41 # define ADD 0x1 /* -a or other required options seen */ 42 # define REMOVE 0x2 /* -r seen */ 43 # define ENABLE 0x4 /* -e seen */ 44 # define DISABLE 0x8 /* -d seen */ 45 # define PLIST 0x10 /* -l seen */ 46 # define LIST 0x20 /* -L seen */ 47 # define CONFIG 0x40 /* -g seen */ 48 49 # define U_FLAG 0x1 /* -fu seen */ 50 # define X_FLAG 0x2 /* -fx seen */ 51 52 /* 53 * functions 54 */ 55 56 char *pflags(); 57 char *pspec(); 58 struct taglist *find_type(); 59 void usage(); 60 void parseline(); 61 void add_svc(); 62 void rem_svc(); 63 void ed_svc(); 64 void list_svcs(); 65 void doconf(); 66 67 /* 68 * format of a _pmtab entry - used to hold parsed info 69 */ 70 71 struct pmtab { 72 char *p_tag; /* service tag */ 73 long p_flags; /* flags */ 74 char *p_id; /* logname to start service as */ 75 char *p_res1; /* reserved field */ 76 char *p_res2; /* reserved field */ 77 char *p_res3; /* reserved field */ 78 char *p_pmspec; /* port monitor specific info */ 79 }; 80 81 /* 82 * format of a tag list, which is a list of port monitor tags of 83 * a designated type 84 */ 85 86 struct taglist { 87 struct taglist *t_next; /* next in list */ 88 char t_tag[PMTAGSIZE + 1]; /* PM tag */ 89 char t_type[PMTYPESIZE + 1]; /* PM type */ 90 }; 91 92 /* 93 * common error messages 94 */ 95 96 # define NOTPRIV "User not privileged for operation" 97 # define BADINP "Embedded newlines not allowed" 98 99 int Saferrno; /* internal `errno' for exit */ 100 101 102 /* 103 * main - scan args for pmadm and call appropriate handling code 104 */ 105 106 main(argc, argv) 107 int argc; 108 char *argv[]; 109 { 110 int c; /* option letter */ 111 int ret; /* return code from check_version */ 112 uid_t uid; /* invoker's real uid */ 113 int flag = 0; /* flag to record requested operations */ 114 int errflg = 0; /* error indicator */ 115 int badcnt = 0; /* count of bad args to -f */ 116 int version = -1; /* argument to -v */ 117 int sawaflag = 0; /* true if actually saw -a */ 118 int conflag = 0; /* true if output should be in condensed form */ 119 long flags = 0; /* arguments to -f */ 120 char *pmtag = NULL; /* argument to -p */ 121 char *type = NULL; /* argument to -t */ 122 char *script = NULL; /* argument to -z */ 123 char *comment = " "; /* argument to -y */ 124 char *id = NULL; /* argument to -i */ 125 char *svctag = NULL; /* argument to -s */ 126 char *pmspec = NULL; /* argument to -m */ 127 char badargs[SIZE]; /* place to hold bad args to -f */ 128 char buf[SIZE]; /* scratch buffer */ 129 register char *p; /* scratch pointer */ 130 131 if (argc == 1) 132 usage(argv[0]); 133 while ((c = getopt(argc, argv, "adef:gi:Llm:p:rs:t:v:y:z:")) != -1) { 134 switch (c) { 135 case 'a': 136 flag |= ADD; 137 sawaflag = 1; 138 break; 139 case 'd': 140 flag |= DISABLE; 141 break; 142 case 'e': 143 flag |= ENABLE; 144 break; 145 case 'f': 146 flag |= ADD; 147 while (*optarg) { 148 switch (*optarg++) { 149 case 'u': 150 flags |= U_FLAG; 151 break; 152 case 'x': 153 flags |= X_FLAG; 154 break; 155 default: 156 badargs[badcnt++] = *(optarg - 1); 157 break; 158 } 159 } 160 /* null terminate just in case anything is there */ 161 badargs[badcnt] = '\0'; 162 break; 163 case 'g': 164 flag |= CONFIG; 165 break; 166 case 'i': 167 if (strchr(optarg, '\n')) { 168 Saferrno = E_BADARGS; 169 error(BADINP); 170 } 171 flag |= ADD; 172 id = optarg; 173 break; 174 case 'L': 175 flag |= LIST; 176 break; 177 case 'l': 178 flag |= PLIST; 179 break; 180 case 'm': 181 if (strchr(optarg, '\n')) { 182 Saferrno = E_BADARGS; 183 error(BADINP); 184 } 185 if (*optarg == '\0') { 186 /* this will generate a usage message below */ 187 errflg++; 188 break; 189 } 190 flag |= ADD; 191 pmspec = optarg; 192 break; 193 case 'p': 194 if (strchr(optarg, '\n')) { 195 Saferrno = E_BADARGS; 196 error(BADINP); 197 } 198 pmtag = optarg; 199 if (strlen(pmtag) > PMTAGSIZE) { 200 pmtag[PMTAGSIZE] = '\0'; 201 (void) fprintf(stderr, "tag too long, truncated to <%s>\n", pmtag); 202 } 203 for (p = pmtag; *p; p++) { 204 if (!isalnum(*p)) { 205 Saferrno = E_BADARGS; 206 error("port monitor tag must be alphanumeric"); 207 } 208 } 209 break; 210 case 'r': 211 flag |= REMOVE; 212 break; 213 case 's': 214 if (strchr(optarg, '\n')) { 215 Saferrno = E_BADARGS; 216 error(BADINP); 217 } 218 svctag = optarg; 219 if (strlen(svctag) > SVCTAGSIZE) { 220 svctag[SVCTAGSIZE] = '\0'; 221 (void) fprintf(stderr, "svctag too long, truncated to <%s>\n", svctag); 222 } 223 for (p = svctag; *p; p++) { 224 if (!isalnum(*p)) { 225 Saferrno = E_BADARGS; 226 error("service tag must be alphanumeric"); 227 } 228 } 229 break; 230 case 't': 231 if (strchr(optarg, '\n')) { 232 Saferrno = E_BADARGS; 233 error(BADINP); 234 } 235 type = optarg; 236 if (strlen(type) > PMTYPESIZE) { 237 type[PMTYPESIZE] = '\0'; 238 (void) fprintf(stderr, "type too long, truncated to <%s>\n", type); 239 } 240 for (p = type; *p; p++) { 241 if (!isalnum(*p)) { 242 Saferrno = E_BADARGS; 243 error("port monitor type must be alphanumeric"); 244 } 245 } 246 break; 247 case 'v': 248 flag |= ADD; 249 version = atoi(optarg); 250 if (version < 0) { 251 Saferrno = E_BADARGS; 252 error("version number can not be negative"); 253 } 254 break; 255 case 'y': 256 if (strchr(optarg, '\n')) { 257 Saferrno = E_BADARGS; 258 error(BADINP); 259 } 260 flag |= ADD; 261 comment = optarg; 262 break; 263 case 'z': 264 if (strchr(optarg, '\n')) { 265 Saferrno = E_BADARGS; 266 error(BADINP); 267 } 268 script = optarg; 269 break; 270 case '?': 271 errflg++; 272 } 273 } 274 if (errflg || (optind < argc)) 275 usage(argv[0]); 276 277 if (badcnt) { 278 /* bad flags were given to -f */ 279 (void) sprintf(buf, "Invalid request, %s are not valid arguments for \"-f\"", badargs); 280 Saferrno = E_BADARGS; 281 error(buf); 282 } 283 284 uid = getuid(); 285 286 /* 287 * don't do anything if _sactab isn't the version we understand 288 */ 289 290 if ((ret = check_version(VERSION, SACTAB)) == 1) { 291 Saferrno = E_SAFERR; 292 error("_sactab version number is incorrect"); 293 } 294 else if (ret == 2) { 295 (void) sprintf(buf, "could not open %s", SACTAB); 296 Saferrno = E_SYSERR; 297 error(buf); 298 } 299 else if (ret == 3) { 300 (void) sprintf(buf, "%s file is corrupt", SACTAB); 301 Saferrno = E_SAFERR; 302 error(buf); 303 } 304 305 switch (flag) { 306 case ADD: 307 if (uid) { 308 Saferrno = E_NOPRIV; 309 error(NOTPRIV); 310 } 311 if (!sawaflag || (pmtag && type) || (!pmtag && !type) || !svctag || !id || !pmspec || (version < 0)) 312 usage(argv[0]); 313 add_svc(pmtag, type, svctag, id, pmspec, flags, version, comment, script); 314 break; 315 case REMOVE: 316 if (uid) { 317 Saferrno = E_NOPRIV; 318 error(NOTPRIV); 319 } 320 if (!pmtag || !svctag || type || script) 321 usage(argv[0]); 322 rem_svc(pmtag, svctag); 323 break; 324 case ENABLE: 325 if (uid) { 326 Saferrno = E_NOPRIV; 327 error(NOTPRIV); 328 } 329 if (!pmtag || !svctag || type || script) 330 usage(argv[0]); 331 ed_svc(pmtag, svctag, ENABLE); 332 break; 333 case DISABLE: 334 if (uid) { 335 Saferrno = E_NOPRIV; 336 error(NOTPRIV); 337 } 338 if (!pmtag || !svctag || type || script) 339 usage(argv[0]); 340 ed_svc(pmtag, svctag, DISABLE); 341 break; 342 case LIST: 343 conflag = 1; 344 /* fall through */ 345 case PLIST: 346 if ((pmtag && type) || script) 347 usage(argv[0]); 348 list_svcs(pmtag, type, svctag, conflag); 349 break; 350 case CONFIG: 351 if (script && uid) { 352 Saferrno = E_NOPRIV; 353 error(NOTPRIV); 354 } 355 if ((pmtag && type) || (!pmtag && !type) || !svctag || (type && !script)) 356 usage(argv[0]); 357 doconf(script, pmtag, type, svctag); 358 break; 359 default: 360 /* we only get here if more than one flag bit was set */ 361 usage(argv[0]); 362 /* NOTREACHED */ 363 } 364 quit(); 365 /* NOTREACHED */ 366 } 367 368 369 /* 370 * usage - print out a usage message 371 * 372 * args: cmdname - the name command was invoked with 373 */ 374 375 void 376 usage(cmdname) 377 char *cmdname; 378 { 379 (void) fprintf(stderr, "Usage:\t%s -a [ -p pmtag | -t type ] -s svctag -i id -m \"pmspecific\"\n", cmdname); 380 (void) fprintf(stderr, "\t\t-v version [ -f xu ] [ -y comment ] [ -z script]\n"); 381 (void) fprintf(stderr, "\t%s -r -p pmtag -s svctag\n", cmdname); 382 (void) fprintf(stderr, "\t%s -e -p pmtag -s svctag\n", cmdname); 383 (void) fprintf(stderr, "\t%s -d -p pmtag -s svctag\n", cmdname); 384 (void) fprintf(stderr, "\t%s -l [ -p pmtag | -t type ] [ -s svctag ]\n", cmdname); 385 (void) fprintf(stderr, "\t%s -L [ -p pmtag | -t type ] [ -s svctag ]\n", cmdname); 386 (void) fprintf(stderr, "\t%s -g -p pmtag -s svctag [ -z script ]\n", cmdname); 387 (void) fprintf(stderr, "\t%s -g -s svctag -t type -z script\n", cmdname); 388 Saferrno = E_BADARGS; 389 quit(); 390 } 391 392 393 /* 394 * add_svc - add a service entry 395 * 396 * args: tag - port monitor's tag (may be null) 397 * type - port monitor's type (may be null) 398 * svctag - service's tag 399 * id - identity under which service should run 400 * pmspec - uninterpreted port monitor-specific info 401 * flags - service flags 402 * version - version number of port monitor's pmtab 403 * comment - comment describing service 404 * script - service's configuration script 405 */ 406 407 void 408 add_svc(tag, type, svctag, id, pmspec, flags, version, comment, script) 409 char *tag; 410 char *type; 411 char *svctag; 412 char *id; 413 char *pmspec; 414 long flags; 415 int version; 416 char *comment; 417 char *script; 418 { 419 FILE *fp; /* scratch file pointer */ 420 struct taglist tl; /* 'list' for degenerate case (1 PM) */ 421 register struct taglist *tp = NULL; /* working pointer */ 422 int ret; /* return code from check_version */ 423 char buf[SIZE]; /* scratch buffer */ 424 char fname[SIZE]; /* scratch buffer for building names */ 425 int added; /* count number added */ 426 427 fp = fopen(SACTAB, "r"); 428 if (fp == NULL) { 429 Saferrno = E_SYSERR; 430 error("Could not open _sactab"); 431 } 432 if (tag && !find_pm(fp, tag)) { 433 (void) sprintf(buf, "Invalid request, %s does not exist", tag); 434 Saferrno = E_NOEXIST; 435 error(buf); 436 } 437 if (type && !(tp = find_type(fp, type))) { 438 (void) sprintf(buf, "Invalid request, %s does not exist", type); 439 Saferrno = E_NOEXIST; 440 error(buf); 441 } 442 (void) fclose(fp); 443 444 if (tag) { 445 446 /* 447 * treat the case of 1 PM as a degenerate case of a list of PMs from a 448 * type specification. Build the 'list' here. 449 */ 450 451 tp = &tl; 452 tp->t_next = NULL; 453 (void) strcpy(tp->t_tag, tag); 454 } 455 456 added = 0; 457 while (tp) { 458 (void) sprintf(fname, "%s/%s/_pmtab", HOME, tp->t_tag); 459 if ((ret = check_version(version, fname)) == 1) { 460 (void) sprintf(buf, "%s version number is incorrect", fname); 461 Saferrno = E_SAFERR; 462 error(buf); 463 } 464 else if (ret == 2) { 465 (void) sprintf(buf, "could not open %s", fname); 466 Saferrno = E_SYSERR; 467 error(buf); 468 } 469 else if (ret == 3) { 470 (void) sprintf(buf, "%s file is corrupt", fname); 471 Saferrno = E_SAFERR; 472 error(buf); 473 } 474 fp = fopen(fname, "r"); 475 if (fp == NULL) { 476 (void) sprintf(buf, "Could not open %s", fname); 477 Saferrno = E_SYSERR; 478 error(buf); 479 } 480 if (find_svc(fp, tp->t_tag, svctag)) { 481 if (tag) { 482 /* special case of tag only */ 483 (void) sprintf(buf, "Invalid request, %s already exists under %s", svctag, tag); 484 Saferrno = E_DUP; 485 error(buf); 486 } 487 else { 488 (void) fprintf(stderr, "warning - %s already exists under %s - ignoring\n", svctag, tp->t_tag); 489 tp = tp->t_next; 490 (void) fclose(fp); 491 continue; 492 } 493 } 494 (void) fclose(fp); 495 496 /* 497 * put in the config script, if specified 498 */ 499 500 if (script) { 501 (void) sprintf(fname, "%s/%s", tp->t_tag, svctag); 502 if (do_config(script, fname)) { 503 /* do_config put out any messages */ 504 tp = tp->t_next; 505 continue; 506 } 507 } 508 509 /* 510 * add the line 511 */ 512 513 (void) sprintf(fname, "%s/%s/_pmtab", HOME, tp->t_tag); 514 fp = fopen(fname, "a"); 515 if (fp == NULL) { 516 (void) sprintf(buf, "Could not open %s", fname); 517 Saferrno = E_SYSERR; 518 error(buf); 519 } 520 (void) fprintf(fp, "%s:%s:%s:reserved:reserved:reserved:%s#%s\n", 521 svctag, (flags ? pflags(flags, FALSE) : ""), id, pmspec, 522 (comment ? comment : "")); 523 (void) fclose(fp); 524 added++; 525 526 /* 527 * tell the SAC to to tell PM to read _pmtab 528 */ 529 530 (void) tell_sac(tp->t_tag); 531 tp = tp->t_next; 532 } 533 if (added == 0) { 534 Saferrno = E_SAFERR; 535 error("No services added"); 536 } 537 return; 538 } 539 540 541 /* 542 * rem_svc - remove a service 543 * 544 * args: pmtag - tag of port monitor responsible for the service 545 * svctag - tag of the service to be removed 546 */ 547 548 void 549 rem_svc(pmtag, svctag) 550 char *pmtag; 551 char *svctag; 552 { 553 FILE *fp; /* scratch file pointer */ 554 FILE *tfp; /* file pointer for temp file */ 555 int line; /* line number entry is on */ 556 char *tname; /* temp file name */ 557 char buf[SIZE]; /* scratch buffer */ 558 char fname[SIZE]; /* path to correct _pmtab */ 559 560 fp = fopen(SACTAB, "r"); 561 if (fp == NULL) { 562 Saferrno = E_SYSERR; 563 error("Could not open _sactab"); 564 } 565 if (!find_pm(fp, pmtag)) { 566 (void) sprintf(buf, "Invalid request, %s does not exist", pmtag); 567 Saferrno = E_NOEXIST; 568 error(buf); 569 } 570 (void) fclose(fp); 571 572 (void) sprintf(fname, "%s/_pmtab", pmtag); 573 (void) sprintf(buf, "%s/%s", HOME, fname); 574 fp = fopen(buf, "r"); 575 if (fp == NULL) { 576 (void) sprintf(buf, "Could not open %s/%s", HOME, fname); 577 Saferrno = E_SYSERR; 578 error(buf); 579 } 580 if ((line = find_svc(fp, pmtag, svctag)) == 0) { 581 (void) sprintf(buf, "Invalid request, %s does not exist under %s", svctag, pmtag); 582 Saferrno = E_NOEXIST; 583 error(buf); 584 } 585 tname = make_tempname(fname); 586 tfp = open_temp(tname); 587 if (line != 1) { 588 if (copy_file(fp, tfp, 1, line - 1)) { 589 (void) unlink(tname); 590 Saferrno = E_SYSERR; 591 error("error accessing temp file"); 592 } 593 } 594 if (copy_file(fp, tfp, line + 1, -1)) { 595 (void) unlink(tname); 596 Saferrno = E_SYSERR; 597 error("error accessing temp file"); 598 } 599 (void) fclose(fp); 600 if (fclose(tfp) == EOF) { 601 (void) unlink(tname); 602 Saferrno = E_SYSERR; 603 error("error closing tempfile"); 604 } 605 /* note - replace only returns if successful */ 606 replace(fname, tname); 607 608 /* 609 * tell the SAC to to tell PM to read _pmtab 610 */ 611 612 if (tell_sac(pmtag)) { 613 614 /* 615 * if we got rid of the service, try to remove the config script too. 616 * Don't check return status since it may not have existed anyhow. 617 */ 618 619 (void) sprintf(buf, "%s/%s/%s", HOME, pmtag, svctag); 620 (void) unlink(buf); 621 return; 622 } 623 } 624 625 626 627 /* 628 * ed_svc - enable or disable a particular service 629 * 630 * args: pmtag - tag of port monitor responsible for the service 631 * svctag - tag of service to be enabled or disabled 632 * flag - operation to perform (ENABLE or DISABLE) 633 */ 634 635 void 636 ed_svc(pmtag, svctag, flag) 637 char *pmtag; 638 char *svctag; 639 int flag; 640 { 641 FILE *fp; /* scratch file pointer */ 642 FILE *tfp; /* file pointer for temp file */ 643 int line; /* line number entry is on */ 644 register char *from; /* working pointer */ 645 register char *to; /* working pointer */ 646 char *tname; /* temp file name */ 647 char *p; /* scratch pointer */ 648 char buf[SIZE]; /* scratch buffer */ 649 char tbuf[SIZE]; /* scratch buffer */ 650 char fname[SIZE]; /* path to correct _pmtab */ 651 652 fp = fopen(SACTAB, "r"); 653 if (fp == NULL) { 654 Saferrno = E_SYSERR; 655 error("Could not open _sactab"); 656 } 657 if (!find_pm(fp, pmtag)) { 658 (void) sprintf(buf, "Invalid request, %s does not exist", pmtag); 659 Saferrno = E_NOEXIST; 660 error(buf); 661 } 662 (void) fclose(fp); 663 664 (void) sprintf(fname, "%s/_pmtab", pmtag); 665 (void) sprintf(buf, "%s/%s", HOME, fname); 666 fp = fopen(buf, "r"); 667 if (fp == NULL) { 668 (void) sprintf(buf, "Could not open %s/%s", HOME, fname); 669 Saferrno = E_SYSERR; 670 error(buf); 671 } 672 if ((line = find_svc(fp, pmtag, svctag)) == 0) { 673 (void) sprintf(buf, "Invalid request, %s does not exist under %s", svctag, pmtag); 674 Saferrno = E_NOEXIST; 675 error(buf); 676 } 677 tname = make_tempname(fname); 678 tfp = open_temp(tname); 679 if (line != 1) { 680 if (copy_file(fp, tfp, 1, line - 1)) { 681 (void) unlink(tname); 682 Saferrno = E_SYSERR; 683 error("error accessing temp file"); 684 } 685 } 686 687 /* 688 * Note: find_svc above has already read and parsed this entry, thus 689 * we know it to be well-formed, so just change the flags as appropriate 690 */ 691 692 if (fgets(buf, SIZE, fp) == NULL) { 693 (void) unlink(tname); 694 Saferrno = E_SYSERR; 695 error("error accessing temp file"); 696 } 697 from = buf; 698 to = tbuf; 699 700 /* 701 * copy initial portion of entry 702 */ 703 704 p = strchr(from, DELIMC); 705 for ( ; from <= p; ) 706 *to++ = *from++; 707 708 /* 709 * isolate and fix the flags 710 */ 711 712 p = strchr(from, DELIMC); 713 for ( ; from < p; ) { 714 if (*from == 'x') { 715 from++; 716 continue; 717 } 718 *to++ = *from++; 719 } 720 721 /* 722 * above we removed x flag, if this was a disable operation, stick it in 723 * and also copy the field delimiter 724 */ 725 726 if (flag == DISABLE) 727 *to++ = 'x'; 728 *to++ = *from++; 729 730 /* 731 * copy the rest of the line 732 */ 733 734 for ( ; from < &buf[SIZE - 1] ;) 735 *to++ = *from++; 736 /*** *to = '\0'; BUG: Don't uncomment it ****/ 737 738 (void) fprintf(tfp, "%s", tbuf); 739 740 if (copy_file(fp, tfp, line + 1, -1)) { 741 (void) unlink(tname); 742 Saferrno = E_SYSERR; 743 error("error accessing temp file"); 744 } 745 (void) fclose(fp); 746 if (fclose(tfp) == EOF) { 747 (void) unlink(tname); 748 Saferrno = E_SYSERR; 749 error("error closing tempfile"); 750 } 751 /* note - replace only returns if successful */ 752 replace(fname, tname); 753 754 755 /* 756 * tell the SAC to to tell PM to read _pmtab 757 */ 758 759 (void) tell_sac(pmtag); 760 } 761 762 763 /* 764 * doconf - take a config script and have it put where it belongs or 765 * output an existing one 766 * 767 * args: script - name of file containing script (if NULL, means 768 * output existing one instead) 769 * tag - tag of port monitor that is responsible for the 770 * designated service (may be null) 771 * type - type of port monitor that is responsible for the 772 * designated service (may be null) 773 * svctag - tag of service whose config script we're operating on 774 */ 775 776 void 777 doconf(script, tag, type, svctag) 778 char *script; 779 char *tag; 780 char *type; 781 char *svctag; 782 { 783 FILE *fp; /* scratch file pointer */ 784 int added; /* count of config scripts added */ 785 struct taglist tl; /* 'list' for degenerate case (1 PM) */ 786 register struct taglist *tp = NULL; /* working pointer */ 787 char buf[SIZE]; /* scratch buffer */ 788 char fname[SIZE]; /* scratch buffer for names */ 789 790 fp = fopen(SACTAB, "r"); 791 if (fp == NULL) { 792 Saferrno = E_SYSERR; 793 error("Could not open _sactab"); 794 } 795 if (tag && !find_pm(fp, tag)) { 796 (void) sprintf(buf, "Invalid request, %s does not exist", tag); 797 Saferrno = E_NOEXIST; 798 error(buf); 799 } 800 if (type && !(tp = find_type(fp, type))) { 801 (void) sprintf(buf, "Invalid request, %s does not exist", type); 802 Saferrno = E_NOEXIST; 803 error(buf); 804 } 805 (void) fclose(fp); 806 807 if (tag) { 808 809 /* 810 * treat the case of 1 PM as a degenerate case of a list of PMs from a 811 * type specification. Build the 'list' here. 812 */ 813 814 tp = &tl; 815 tp->t_next = NULL; 816 (void) strcpy(tp->t_tag, tag); 817 } 818 819 added = 0; 820 while (tp) { 821 (void) sprintf(fname, "%s/%s/_pmtab", HOME, tp->t_tag); 822 fp = fopen(fname, "r"); 823 if (fp == NULL) { 824 (void) sprintf(buf, "Could not open %s", fname); 825 Saferrno = E_SYSERR; 826 error(buf); 827 } 828 if (!find_svc(fp, tp->t_tag, svctag)) { 829 if (tag) { 830 /* special case of tag only */ 831 (void) sprintf(buf, "Invalid request, %s does not exist under %s", svctag, tag); 832 Saferrno = E_NOEXIST; 833 error(buf); 834 } 835 else { 836 (void) fprintf(stderr, "warning - %s does not exist under %s - ignoring\n", svctag, tp->t_tag); 837 Saferrno = E_NOEXIST; 838 tp = tp->t_next; 839 (void) fclose(fp); 840 continue; 841 } 842 } 843 (void) fclose(fp); 844 845 (void) sprintf(fname, "%s/%s", tp->t_tag, svctag); 846 847 /* 848 * do_config does all the real work (keep track if any errors occurred) 849 */ 850 851 if (do_config(script, fname) == 0) 852 added++; 853 tp = tp->t_next; 854 } 855 if (added == 0) { 856 Saferrno = E_SAFERR; 857 error("No configuration scripts installed"); 858 } 859 return; 860 } 861 862 863 /* 864 * tell_sac - use sacadm to tell the sac to tell a port monitor to read 865 * its _pmtab. Return TRUE on success, FALSE on failure. 866 * 867 * args: tag - tag of port monitor to be notified 868 */ 869 870 871 tell_sac(tag) 872 char *tag; 873 { 874 pid_t pid; /* returned pid from fork */ 875 int status; /* return status from sacadm child */ 876 877 if ((pid = fork()) < 0) { 878 (void) fprintf(stderr, "warning - fork failed - could not notify <%s> about modified table\n", tag); 879 (void) fprintf(stderr, "try executing the command \"sacadm -x -p %s\"\n", tag); 880 Saferrno = E_SYSERR; 881 return(FALSE); 882 } 883 else if (pid) { 884 /* parent */ 885 (void) wait(&status); 886 if (status) { 887 if (((status >> 8) & 0xff) == E_PMNOTRUN) { 888 (void) fprintf(stderr, "warning - port monitor, %s is not running\n", tag); 889 return (FALSE); 890 } 891 if (((status >> 8) & 0xff) == E_SACNOTRUN) { 892 Saferrno = E_SACNOTRUN; 893 } else { 894 Saferrno = E_SYSERR; 895 } 896 (void) fprintf(stderr, 897 "warning - could not notify <%s> about modified" 898 " table\n", tag); 899 (void) fprintf(stderr, "try executing the command" 900 " \"sacadm -x -p %s\"\n", tag); 901 return(FALSE); 902 } 903 else { 904 return(TRUE); 905 } 906 } 907 else { 908 /* set IFS for security */ 909 (void) putenv("IFS=\" \""); 910 /* muffle sacadm warning messages */ 911 (void) fclose(stderr); 912 (void) fopen("/dev/null", "w"); 913 (void) execl("/usr/sbin/sacadm", "sacadm", "-x", "-p", tag, 0); 914 915 /* 916 * if we got here, it didn't work, exit status will clue in parent to 917 * put out the warning 918 */ 919 920 exit(1); 921 } 922 /* NOTREACHED */ 923 } 924 925 926 /* 927 * list_svcs - list information about services 928 * 929 * args: pmtag - tag of port monitor responsible for the service 930 * (may be null) 931 * type - type of port monitor responsible for the service 932 * (may be null) 933 * svctag - tag of service to be listed (may be null) 934 * oflag - true if output should be easily parseable 935 */ 936 937 void 938 list_svcs(pmtag, type, svctag, oflag) 939 char *pmtag; 940 char *type; 941 char *svctag; 942 { 943 FILE *fp; /* scratch file pointer */ 944 register struct taglist *tp; /* pointer to PM list */ 945 int nprint = 0; /* count # of svcs printed */ 946 struct pmtab pmtab; /* place to hold parsed info */ 947 register struct pmtab *pp = &pmtab; /* and a pointer to it */ 948 register char *p; /* working pointer */ 949 char buf[SIZE]; /* scratch buffer */ 950 char fname[SIZE]; /* scratch buffer for building names */ 951 952 fp = fopen(SACTAB, "r"); 953 if (fp == NULL) { 954 Saferrno = E_SYSERR; 955 error("Could not open _sactab"); 956 } 957 if (pmtag && !find_pm(fp, pmtag)) { 958 (void) sprintf(buf, "Invalid request, %s does not exist", pmtag); 959 Saferrno = E_NOEXIST; 960 error(buf); 961 } 962 rewind(fp); 963 if (type) { 964 tp = find_type(fp, type); 965 if (tp == NULL) { 966 (void) sprintf(buf, "Invalid request, %s does not exist", type); 967 Saferrno = E_NOEXIST; 968 error(buf); 969 } 970 } 971 else 972 tp = find_type(fp, NULL); 973 (void) fclose(fp); 974 975 while (tp) { 976 if (pmtag && strcmp(tp->t_tag, pmtag)) { 977 /* not interested in this port monitor */ 978 tp = tp->t_next; 979 continue; 980 } 981 (void) sprintf(fname, "%s/%s/_pmtab", HOME, tp->t_tag); 982 fp = fopen(fname, "r"); 983 if (fp == NULL) { 984 (void) sprintf(buf, "Could not open %s", fname); 985 Saferrno = E_SYSERR; 986 error(buf); 987 } 988 while (fgets(buf, SIZE, fp)) { 989 p = trim(buf); 990 if (*p == '\0') 991 continue; 992 parseline(p, pp, tp->t_tag); 993 if (!svctag || !strcmp(pp->p_tag, svctag)) { 994 if (oflag) { 995 (void) printf("%s:%s:%s:%s:%s:%s:%s:%s:%s#%s\n", 996 tp->t_tag, tp->t_type, pp->p_tag, 997 pflags(pp->p_flags, FALSE), 998 pp->p_id, pp->p_res1, pp->p_res2, 999 pp->p_res3,pp->p_pmspec, Comment); 1000 } 1001 else { 1002 if (nprint == 0) { 1003 (void) printf("PMTAG PMTYPE SVCTAG FLGS ID <PMSPECIFIC>\n"); 1004 } 1005 (void) printf("%-14s %-14s %-14s %-4s %-8s %s #%s\n", tp->t_tag, tp->t_type, pp->p_tag, 1006 pflags(pp->p_flags, TRUE), pp->p_id, pspec(pp->p_pmspec), Comment); 1007 } 1008 nprint++; 1009 } 1010 } 1011 if (!feof(fp)) { 1012 (void) sprintf(buf, "error reading %s", fname); 1013 Saferrno = E_SYSERR; 1014 error(buf); 1015 } 1016 else { 1017 (void) fclose(fp); 1018 tp = tp->t_next; 1019 } 1020 } 1021 /* if we didn't find any valid ones, indicate an error */ 1022 if (nprint == 0) { 1023 if (svctag) 1024 (void) fprintf(stderr, "Service <%s> does not exist\n", svctag); 1025 else 1026 (void) fprintf(stderr, "No services defined\n"); 1027 Saferrno = E_NOEXIST; 1028 } 1029 return; 1030 } 1031 1032 1033 /* 1034 * find_svc - find an entry in _pmtab for a particular service tag 1035 * 1036 * args: fp - file pointer for _pmtab 1037 * tag - port monitor tag (for error reporting) 1038 * svctag - tag of service we're looking for 1039 */ 1040 1041 find_svc(fp, tag, svctag) 1042 FILE *fp; 1043 char *tag; 1044 char *svctag; 1045 { 1046 register char *p; /* working pointer */ 1047 int line = 0; /* line number we found entry on */ 1048 struct pmtab pmtab; /* place to hold parsed info */ 1049 static char buf[SIZE]; /* scratch buffer */ 1050 1051 while (fgets(buf, SIZE, fp)) { 1052 line++; 1053 p = trim(buf); 1054 if (*p == '\0') 1055 continue; 1056 parseline(p, &pmtab, tag); 1057 if (!(strcmp(pmtab.p_tag, svctag))) 1058 return(line); 1059 } 1060 if (!feof(fp)) { 1061 (void) sprintf(buf, "error reading %s/%s/_pmtab", HOME, tag); 1062 Saferrno = E_SYSERR; 1063 error(buf); 1064 } 1065 else 1066 return(0); 1067 /* NOTREACHED */ 1068 } 1069 1070 1071 /* 1072 * parseline - parse a line from _pmtab. This routine will return if the 1073 * parse wa successful, otherwise it will output an error and 1074 * exit. 1075 * 1076 * args: p - pointer to the data read from the file (note - this is 1077 * a static data region, so we can point into it) 1078 * pp - pointer to a structure in which the separated fields 1079 * are placed 1080 * tag - port monitor tag (for error reporting) 1081 * 1082 * A line in the file has the following format: 1083 * 1084 * tag:flags:identity:reserved:reserved:reserved:PM_spec_info # comment 1085 */ 1086 1087 1088 void 1089 parseline(p, pp, tag) 1090 register char *p; 1091 register struct pmtab *pp; 1092 char *tag; 1093 { 1094 char buf[SIZE]; /* scratch buffer */ 1095 1096 /* 1097 * get the service tag 1098 */ 1099 1100 p = nexttok(p, DELIM, FALSE); 1101 if (p == NULL) { 1102 (void) sprintf(buf, "%s/%s/_pmtab is corrupt", HOME, tag); 1103 Saferrno = E_SAFERR; 1104 error(buf); 1105 } 1106 if (strlen(p) > PMTAGSIZE) { 1107 p[PMTAGSIZE] = '\0'; 1108 (void) fprintf(stderr, "tag too long, truncated to <%s>", p); 1109 } 1110 pp->p_tag = p; 1111 1112 /* 1113 * get the flags 1114 */ 1115 1116 p = nexttok(NULL, DELIM, FALSE); 1117 if (p == NULL) { 1118 (void) sprintf(buf, "%s/%s/_pmtab is corrupt", HOME, tag); 1119 Saferrno = E_SAFERR; 1120 error(buf); 1121 } 1122 pp->p_flags = 0; 1123 while (*p) { 1124 switch (*p++) { 1125 case 'u': 1126 pp->p_flags |= U_FLAG; 1127 break; 1128 case 'x': 1129 pp->p_flags |= X_FLAG; 1130 break; 1131 default: 1132 (void) sprintf(buf, "Unrecognized flag <%c>", *(p - 1)); 1133 Saferrno = E_SAFERR; 1134 error(buf); 1135 break; 1136 } 1137 } 1138 1139 /* 1140 * get the identity 1141 */ 1142 1143 p = nexttok(NULL, DELIM, FALSE); 1144 if (p == NULL) { 1145 (void) sprintf(buf, "%s/%s/_pmtab is corrupt", HOME, tag); 1146 Saferrno = E_SAFERR; 1147 error(buf); 1148 } 1149 pp->p_id = p; 1150 1151 /* 1152 * get the first reserved field 1153 */ 1154 1155 p = nexttok(NULL, DELIM, FALSE); 1156 if (p == NULL) { 1157 (void) sprintf(buf, "%s/%s/_pmtab is corrupt", HOME, tag); 1158 Saferrno = E_SAFERR; 1159 error(buf); 1160 } 1161 pp->p_res1 = p; 1162 1163 /* 1164 * get the second reserved field 1165 */ 1166 1167 p = nexttok(NULL, DELIM, FALSE); 1168 if (p == NULL) { 1169 (void) sprintf(buf, "%s/%s/_pmtab is corrupt", HOME, tag); 1170 Saferrno = E_SAFERR; 1171 error(buf); 1172 } 1173 pp->p_res2 = p; 1174 1175 /* 1176 * get the third reserved field 1177 */ 1178 1179 p = nexttok(NULL, DELIM, FALSE); 1180 if (p == NULL) { 1181 (void) sprintf(buf, "%s/%s/_pmtab is corrupt", HOME, tag); 1182 Saferrno = E_SAFERR; 1183 error(buf); 1184 } 1185 pp->p_res3 = p; 1186 1187 /* 1188 * the rest is the port monitor specific info 1189 */ 1190 1191 p = nexttok(NULL, DELIM, TRUE); 1192 if (p == NULL) { 1193 (void) sprintf(buf, "%s/%s/_pmtab is corrupt", HOME, tag); 1194 Saferrno = E_SAFERR; 1195 error(buf); 1196 } 1197 pp->p_pmspec = p; 1198 return; 1199 } 1200 1201 1202 /* 1203 * pspec - format port monitor specific information 1204 * 1205 * args: spec - port monitor specific info, separated by 1206 * field separater character (may be escaped by \) 1207 */ 1208 1209 char * 1210 pspec(spec) 1211 char *spec; 1212 { 1213 static char buf[SIZE]; /* returned string */ 1214 register char *from; /* working pointer */ 1215 register char *to; /* working pointer */ 1216 int newflag; /* flag indicating new field */ 1217 1218 to = buf; 1219 from = spec; 1220 newflag = 1; 1221 while (*from) { 1222 switch (*from) { 1223 case ':': 1224 if (newflag) { 1225 *to++ = '-'; 1226 } 1227 *to++ = ' '; 1228 from++; 1229 newflag = 1; 1230 break; 1231 case '\\': 1232 if (*(from + 1) == ':') { 1233 *to++ = ':'; 1234 /* skip over \: */ 1235 from += 2; 1236 } 1237 else 1238 *to++ = *from++; 1239 newflag = 0; 1240 break; 1241 default: 1242 newflag = 0; 1243 *to++ = *from++; 1244 } 1245 } 1246 *to = '\0'; 1247 return(buf); 1248 } 1249 1250 1251 /* 1252 * pflags - put service flags into intelligible form for output 1253 * 1254 * args: flags - binary representation of flags 1255 * dflag - true if a "-" should be returned if no flags 1256 */ 1257 1258 char * 1259 pflags(flags, dflag) 1260 long flags; 1261 int dflag; 1262 { 1263 register int i; /* scratch counter */ 1264 static char buf[SIZE]; /* formatted flags */ 1265 1266 if (flags == 0) { 1267 if (dflag) 1268 return("-"); 1269 else 1270 return(""); 1271 } 1272 i = 0; 1273 if (flags & U_FLAG) { 1274 buf[i++] = 'u'; 1275 flags &= ~U_FLAG; 1276 } 1277 if (flags & X_FLAG) { 1278 buf[i++] = 'x'; 1279 flags &= ~X_FLAG; 1280 } 1281 if (flags) { 1282 Saferrno = E_SAFERR; 1283 error("Internal error in pflags"); 1284 } 1285 buf[i] = '\0'; 1286 return(buf); 1287 } 1288 1289 1290 /* 1291 * find_type - find entries in _sactab for a particular port monitor type 1292 * 1293 * args: fp - file pointer for _sactab 1294 * type - type of port monitor we're looking for (if type is 1295 * null, it means find all PMs) 1296 */ 1297 1298 struct taglist * 1299 find_type(fp, type) 1300 FILE *fp; 1301 char *type; 1302 { 1303 register char *p; /* working pointer */ 1304 struct sactab stab; /* place to hold parsed info */ 1305 register struct sactab *sp = &stab; /* and a pointer to it */ 1306 char buf[SIZE]; /* scratch buffer */ 1307 struct taglist *thead; /* linked list of tags */ 1308 register struct taglist *temp; /* scratch pointer */ 1309 1310 thead = NULL; 1311 while (fgets(buf, SIZE, fp)) { 1312 p = trim(buf); 1313 if (*p == '\0') 1314 continue; 1315 parse(p, sp); 1316 if ((type == NULL) || !(strcmp(sp->sc_type, type))) { 1317 temp = (struct taglist *) malloc(sizeof(struct taglist)); 1318 if (temp == NULL) { 1319 Saferrno = E_SYSERR; 1320 error("malloc failed"); 1321 } 1322 temp->t_next = thead; 1323 (void) strcpy(temp->t_tag, sp->sc_tag); 1324 (void) strcpy(temp->t_type, sp->sc_type); 1325 thead = temp; 1326 } 1327 } 1328 if (!feof(fp)) { 1329 Saferrno = E_SYSERR; 1330 error("error reading _sactab"); 1331 } 1332 else 1333 return(thead ? thead : NULL); 1334 /* NOTREACHED */ 1335 } 1336