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(pmtag, type, svctag, oflag) 938 char *pmtag; 939 char *type; 940 char *svctag; 941 { 942 FILE *fp; /* scratch file pointer */ 943 register struct taglist *tp; /* pointer to PM list */ 944 int nprint = 0; /* count # of svcs printed */ 945 struct pmtab pmtab; /* place to hold parsed info */ 946 register struct pmtab *pp = &pmtab; /* and a pointer to it */ 947 register char *p; /* working pointer */ 948 char buf[SIZE]; /* scratch buffer */ 949 char fname[SIZE]; /* scratch buffer for building names */ 950 951 fp = fopen(SACTAB, "r"); 952 if (fp == NULL) { 953 Saferrno = E_SYSERR; 954 error("Could not open _sactab"); 955 } 956 if (pmtag && !find_pm(fp, pmtag)) { 957 (void) sprintf(buf, "Invalid request, %s does not exist", pmtag); 958 Saferrno = E_NOEXIST; 959 error(buf); 960 } 961 rewind(fp); 962 if (type) { 963 tp = find_type(fp, type); 964 if (tp == NULL) { 965 (void) sprintf(buf, "Invalid request, %s does not exist", type); 966 Saferrno = E_NOEXIST; 967 error(buf); 968 } 969 } 970 else 971 tp = find_type(fp, NULL); 972 (void) fclose(fp); 973 974 while (tp) { 975 if (pmtag && strcmp(tp->t_tag, pmtag)) { 976 /* not interested in this port monitor */ 977 tp = tp->t_next; 978 continue; 979 } 980 (void) sprintf(fname, "%s/%s/_pmtab", HOME, tp->t_tag); 981 fp = fopen(fname, "r"); 982 if (fp == NULL) { 983 (void) sprintf(buf, "Could not open %s", fname); 984 Saferrno = E_SYSERR; 985 error(buf); 986 } 987 while (fgets(buf, SIZE, fp)) { 988 p = trim(buf); 989 if (*p == '\0') 990 continue; 991 parseline(p, pp, tp->t_tag); 992 if (!svctag || !strcmp(pp->p_tag, svctag)) { 993 if (oflag) { 994 (void) printf("%s:%s:%s:%s:%s:%s:%s:%s:%s#%s\n", 995 tp->t_tag, tp->t_type, pp->p_tag, 996 pflags(pp->p_flags, FALSE), 997 pp->p_id, pp->p_res1, pp->p_res2, 998 pp->p_res3,pp->p_pmspec, Comment); 999 } 1000 else { 1001 if (nprint == 0) { 1002 (void) printf("PMTAG PMTYPE SVCTAG FLGS ID <PMSPECIFIC>\n"); 1003 } 1004 (void) printf("%-14s %-14s %-14s %-4s %-8s %s #%s\n", tp->t_tag, tp->t_type, pp->p_tag, 1005 pflags(pp->p_flags, TRUE), pp->p_id, pspec(pp->p_pmspec), Comment); 1006 } 1007 nprint++; 1008 } 1009 } 1010 if (!feof(fp)) { 1011 (void) sprintf(buf, "error reading %s", fname); 1012 Saferrno = E_SYSERR; 1013 error(buf); 1014 } 1015 else { 1016 (void) fclose(fp); 1017 tp = tp->t_next; 1018 } 1019 } 1020 /* if we didn't find any valid ones, indicate an error */ 1021 if (nprint == 0) { 1022 if (svctag) 1023 (void) fprintf(stderr, "Service <%s> does not exist\n", svctag); 1024 else 1025 (void) fprintf(stderr, "No services defined\n"); 1026 Saferrno = E_NOEXIST; 1027 } 1028 return; 1029 } 1030 1031 1032 /* 1033 * find_svc - find an entry in _pmtab for a particular service tag 1034 * 1035 * args: fp - file pointer for _pmtab 1036 * tag - port monitor tag (for error reporting) 1037 * svctag - tag of service we're looking for 1038 */ 1039 1040 int 1041 find_svc(FILE *fp, char *tag, char *svctag) 1042 { 1043 register char *p; /* working pointer */ 1044 int line = 0; /* line number we found entry on */ 1045 struct pmtab pmtab; /* place to hold parsed info */ 1046 static char buf[SIZE]; /* scratch buffer */ 1047 1048 while (fgets(buf, SIZE, fp)) { 1049 line++; 1050 p = trim(buf); 1051 if (*p == '\0') 1052 continue; 1053 parseline(p, &pmtab, tag); 1054 if (!(strcmp(pmtab.p_tag, svctag))) 1055 return(line); 1056 } 1057 if (!feof(fp)) { 1058 (void) sprintf(buf, "error reading %s/%s/_pmtab", HOME, tag); 1059 Saferrno = E_SYSERR; 1060 error(buf); 1061 /* NOTREACHED */ 1062 return (0); 1063 } else 1064 return (0); 1065 } 1066 1067 1068 /* 1069 * parseline - parse a line from _pmtab. This routine will return if the 1070 * parse wa successful, otherwise it will output an error and 1071 * exit. 1072 * 1073 * args: p - pointer to the data read from the file (note - this is 1074 * a static data region, so we can point into it) 1075 * pp - pointer to a structure in which the separated fields 1076 * are placed 1077 * tag - port monitor tag (for error reporting) 1078 * 1079 * A line in the file has the following format: 1080 * 1081 * tag:flags:identity:reserved:reserved:reserved:PM_spec_info # comment 1082 */ 1083 1084 1085 void 1086 parseline(p, pp, tag) 1087 register char *p; 1088 register struct pmtab *pp; 1089 char *tag; 1090 { 1091 char buf[SIZE]; /* scratch buffer */ 1092 1093 /* 1094 * get the service tag 1095 */ 1096 1097 p = nexttok(p, DELIM, FALSE); 1098 if (p == NULL) { 1099 (void) sprintf(buf, "%s/%s/_pmtab is corrupt", HOME, tag); 1100 Saferrno = E_SAFERR; 1101 error(buf); 1102 } 1103 if (strlen(p) > PMTAGSIZE) { 1104 p[PMTAGSIZE] = '\0'; 1105 (void) fprintf(stderr, "tag too long, truncated to <%s>", p); 1106 } 1107 pp->p_tag = p; 1108 1109 /* 1110 * get the flags 1111 */ 1112 1113 p = nexttok(NULL, DELIM, FALSE); 1114 if (p == NULL) { 1115 (void) sprintf(buf, "%s/%s/_pmtab is corrupt", HOME, tag); 1116 Saferrno = E_SAFERR; 1117 error(buf); 1118 } 1119 pp->p_flags = 0; 1120 while (*p) { 1121 switch (*p++) { 1122 case 'u': 1123 pp->p_flags |= U_FLAG; 1124 break; 1125 case 'x': 1126 pp->p_flags |= X_FLAG; 1127 break; 1128 default: 1129 (void) sprintf(buf, "Unrecognized flag <%c>", *(p - 1)); 1130 Saferrno = E_SAFERR; 1131 error(buf); 1132 break; 1133 } 1134 } 1135 1136 /* 1137 * get the identity 1138 */ 1139 1140 p = nexttok(NULL, DELIM, FALSE); 1141 if (p == NULL) { 1142 (void) sprintf(buf, "%s/%s/_pmtab is corrupt", HOME, tag); 1143 Saferrno = E_SAFERR; 1144 error(buf); 1145 } 1146 pp->p_id = p; 1147 1148 /* 1149 * get the first reserved field 1150 */ 1151 1152 p = nexttok(NULL, DELIM, FALSE); 1153 if (p == NULL) { 1154 (void) sprintf(buf, "%s/%s/_pmtab is corrupt", HOME, tag); 1155 Saferrno = E_SAFERR; 1156 error(buf); 1157 } 1158 pp->p_res1 = p; 1159 1160 /* 1161 * get the second reserved field 1162 */ 1163 1164 p = nexttok(NULL, DELIM, FALSE); 1165 if (p == NULL) { 1166 (void) sprintf(buf, "%s/%s/_pmtab is corrupt", HOME, tag); 1167 Saferrno = E_SAFERR; 1168 error(buf); 1169 } 1170 pp->p_res2 = p; 1171 1172 /* 1173 * get the third reserved field 1174 */ 1175 1176 p = nexttok(NULL, DELIM, FALSE); 1177 if (p == NULL) { 1178 (void) sprintf(buf, "%s/%s/_pmtab is corrupt", HOME, tag); 1179 Saferrno = E_SAFERR; 1180 error(buf); 1181 } 1182 pp->p_res3 = p; 1183 1184 /* 1185 * the rest is the port monitor specific info 1186 */ 1187 1188 p = nexttok(NULL, DELIM, TRUE); 1189 if (p == NULL) { 1190 (void) sprintf(buf, "%s/%s/_pmtab is corrupt", HOME, tag); 1191 Saferrno = E_SAFERR; 1192 error(buf); 1193 } 1194 pp->p_pmspec = p; 1195 return; 1196 } 1197 1198 1199 /* 1200 * pspec - format port monitor specific information 1201 * 1202 * args: spec - port monitor specific info, separated by 1203 * field separater character (may be escaped by \) 1204 */ 1205 1206 char * 1207 pspec(spec) 1208 char *spec; 1209 { 1210 static char buf[SIZE]; /* returned string */ 1211 register char *from; /* working pointer */ 1212 register char *to; /* working pointer */ 1213 int newflag; /* flag indicating new field */ 1214 1215 to = buf; 1216 from = spec; 1217 newflag = 1; 1218 while (*from) { 1219 switch (*from) { 1220 case ':': 1221 if (newflag) { 1222 *to++ = '-'; 1223 } 1224 *to++ = ' '; 1225 from++; 1226 newflag = 1; 1227 break; 1228 case '\\': 1229 if (*(from + 1) == ':') { 1230 *to++ = ':'; 1231 /* skip over \: */ 1232 from += 2; 1233 } 1234 else 1235 *to++ = *from++; 1236 newflag = 0; 1237 break; 1238 default: 1239 newflag = 0; 1240 *to++ = *from++; 1241 } 1242 } 1243 *to = '\0'; 1244 return(buf); 1245 } 1246 1247 1248 /* 1249 * pflags - put service flags into intelligible form for output 1250 * 1251 * args: flags - binary representation of flags 1252 * dflag - true if a "-" should be returned if no flags 1253 */ 1254 1255 char * 1256 pflags(flags, dflag) 1257 long flags; 1258 int dflag; 1259 { 1260 register int i; /* scratch counter */ 1261 static char buf[SIZE]; /* formatted flags */ 1262 1263 if (flags == 0) { 1264 if (dflag) 1265 return("-"); 1266 else 1267 return(""); 1268 } 1269 i = 0; 1270 if (flags & U_FLAG) { 1271 buf[i++] = 'u'; 1272 flags &= ~U_FLAG; 1273 } 1274 if (flags & X_FLAG) { 1275 buf[i++] = 'x'; 1276 flags &= ~X_FLAG; 1277 } 1278 if (flags) { 1279 Saferrno = E_SAFERR; 1280 error("Internal error in pflags"); 1281 } 1282 buf[i] = '\0'; 1283 return(buf); 1284 } 1285 1286 1287 /* 1288 * find_type - find entries in _sactab for a particular port monitor type 1289 * 1290 * args: fp - file pointer for _sactab 1291 * type - type of port monitor we're looking for (if type is 1292 * null, it means find all PMs) 1293 */ 1294 1295 struct taglist * 1296 find_type(fp, type) 1297 FILE *fp; 1298 char *type; 1299 { 1300 register char *p; /* working pointer */ 1301 struct sactab stab; /* place to hold parsed info */ 1302 register struct sactab *sp = &stab; /* and a pointer to it */ 1303 char buf[SIZE]; /* scratch buffer */ 1304 struct taglist *thead; /* linked list of tags */ 1305 register struct taglist *temp; /* scratch pointer */ 1306 1307 thead = NULL; 1308 while (fgets(buf, SIZE, fp)) { 1309 p = trim(buf); 1310 if (*p == '\0') 1311 continue; 1312 parse(p, sp); 1313 if ((type == NULL) || !(strcmp(sp->sc_type, type))) { 1314 temp = (struct taglist *) malloc(sizeof(struct taglist)); 1315 if (temp == NULL) { 1316 Saferrno = E_SYSERR; 1317 error("malloc failed"); 1318 } 1319 temp->t_next = thead; 1320 (void) strcpy(temp->t_tag, sp->sc_tag); 1321 (void) strcpy(temp->t_type, sp->sc_type); 1322 thead = temp; 1323 } 1324 } 1325 if (!feof(fp)) { 1326 Saferrno = E_SYSERR; 1327 error("error reading _sactab"); 1328 /* NOTREACHED */ 1329 return (0); 1330 } else 1331 return (thead ? thead : NULL); 1332 } 1333