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