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