/* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (the "License"). You may not use this file except in compliance * with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 1998 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ /* All Rights Reserved */ #pragma ident "%Z%%M% %I% %E% SMI" # include # include # include # include # include "extern.h" # include "misc.h" # include # include "structs.h" # define ADD 0x1 /* -a or other required options seen */ # define REMOVE 0x2 /* -r seen */ # define ENABLE 0x4 /* -e seen */ # define DISABLE 0x8 /* -d seen */ # define PLIST 0x10 /* -l seen */ # define LIST 0x20 /* -L seen */ # define CONFIG 0x40 /* -g seen */ # define U_FLAG 0x1 /* -fu seen */ # define X_FLAG 0x2 /* -fx seen */ /* * functions */ char *pflags(); char *pspec(); struct taglist *find_type(); void usage(); void parseline(); void add_svc(); void rem_svc(); void ed_svc(); void list_svcs(); void doconf(); /* * format of a _pmtab entry - used to hold parsed info */ struct pmtab { char *p_tag; /* service tag */ long p_flags; /* flags */ char *p_id; /* logname to start service as */ char *p_res1; /* reserved field */ char *p_res2; /* reserved field */ char *p_res3; /* reserved field */ char *p_pmspec; /* port monitor specific info */ }; /* * format of a tag list, which is a list of port monitor tags of * a designated type */ struct taglist { struct taglist *t_next; /* next in list */ char t_tag[PMTAGSIZE + 1]; /* PM tag */ char t_type[PMTYPESIZE + 1]; /* PM type */ }; /* * common error messages */ # define NOTPRIV "User not privileged for operation" # define BADINP "Embedded newlines not allowed" int Saferrno; /* internal `errno' for exit */ /* * main - scan args for pmadm and call appropriate handling code */ main(argc, argv) int argc; char *argv[]; { int c; /* option letter */ int ret; /* return code from check_version */ uid_t uid; /* invoker's real uid */ int flag = 0; /* flag to record requested operations */ int errflg = 0; /* error indicator */ int badcnt = 0; /* count of bad args to -f */ int version = -1; /* argument to -v */ int sawaflag = 0; /* true if actually saw -a */ int conflag = 0; /* true if output should be in condensed form */ long flags = 0; /* arguments to -f */ char *pmtag = NULL; /* argument to -p */ char *type = NULL; /* argument to -t */ char *script = NULL; /* argument to -z */ char *comment = " "; /* argument to -y */ char *id = NULL; /* argument to -i */ char *svctag = NULL; /* argument to -s */ char *pmspec = NULL; /* argument to -m */ char badargs[SIZE]; /* place to hold bad args to -f */ char buf[SIZE]; /* scratch buffer */ register char *p; /* scratch pointer */ if (argc == 1) usage(argv[0]); while ((c = getopt(argc, argv, "adef:gi:Llm:p:rs:t:v:y:z:")) != -1) { switch (c) { case 'a': flag |= ADD; sawaflag = 1; break; case 'd': flag |= DISABLE; break; case 'e': flag |= ENABLE; break; case 'f': flag |= ADD; while (*optarg) { switch (*optarg++) { case 'u': flags |= U_FLAG; break; case 'x': flags |= X_FLAG; break; default: badargs[badcnt++] = *(optarg - 1); break; } } /* null terminate just in case anything is there */ badargs[badcnt] = '\0'; break; case 'g': flag |= CONFIG; break; case 'i': if (strchr(optarg, '\n')) { Saferrno = E_BADARGS; error(BADINP); } flag |= ADD; id = optarg; break; case 'L': flag |= LIST; break; case 'l': flag |= PLIST; break; case 'm': if (strchr(optarg, '\n')) { Saferrno = E_BADARGS; error(BADINP); } if (*optarg == '\0') { /* this will generate a usage message below */ errflg++; break; } flag |= ADD; pmspec = optarg; break; case 'p': if (strchr(optarg, '\n')) { Saferrno = E_BADARGS; error(BADINP); } pmtag = optarg; if (strlen(pmtag) > PMTAGSIZE) { pmtag[PMTAGSIZE] = '\0'; (void) fprintf(stderr, "tag too long, truncated to <%s>\n", pmtag); } for (p = pmtag; *p; p++) { if (!isalnum(*p)) { Saferrno = E_BADARGS; error("port monitor tag must be alphanumeric"); } } break; case 'r': flag |= REMOVE; break; case 's': if (strchr(optarg, '\n')) { Saferrno = E_BADARGS; error(BADINP); } svctag = optarg; if (strlen(svctag) > SVCTAGSIZE) { svctag[SVCTAGSIZE] = '\0'; (void) fprintf(stderr, "svctag too long, truncated to <%s>\n", svctag); } for (p = svctag; *p; p++) { if (!isalnum(*p)) { Saferrno = E_BADARGS; error("service tag must be alphanumeric"); } } break; case 't': if (strchr(optarg, '\n')) { Saferrno = E_BADARGS; error(BADINP); } type = optarg; if (strlen(type) > PMTYPESIZE) { type[PMTYPESIZE] = '\0'; (void) fprintf(stderr, "type too long, truncated to <%s>\n", type); } for (p = type; *p; p++) { if (!isalnum(*p)) { Saferrno = E_BADARGS; error("port monitor type must be alphanumeric"); } } break; case 'v': flag |= ADD; version = atoi(optarg); if (version < 0) { Saferrno = E_BADARGS; error("version number can not be negative"); } break; case 'y': if (strchr(optarg, '\n')) { Saferrno = E_BADARGS; error(BADINP); } flag |= ADD; comment = optarg; break; case 'z': if (strchr(optarg, '\n')) { Saferrno = E_BADARGS; error(BADINP); } script = optarg; break; case '?': errflg++; } } if (errflg || (optind < argc)) usage(argv[0]); if (badcnt) { /* bad flags were given to -f */ (void) sprintf(buf, "Invalid request, %s are not valid arguments for \"-f\"", badargs); Saferrno = E_BADARGS; error(buf); } uid = getuid(); /* * don't do anything if _sactab isn't the version we understand */ if ((ret = check_version(VERSION, SACTAB)) == 1) { Saferrno = E_SAFERR; error("_sactab version number is incorrect"); } else if (ret == 2) { (void) sprintf(buf, "could not open %s", SACTAB); Saferrno = E_SYSERR; error(buf); } else if (ret == 3) { (void) sprintf(buf, "%s file is corrupt", SACTAB); Saferrno = E_SAFERR; error(buf); } switch (flag) { case ADD: if (uid) { Saferrno = E_NOPRIV; error(NOTPRIV); } if (!sawaflag || (pmtag && type) || (!pmtag && !type) || !svctag || !id || !pmspec || (version < 0)) usage(argv[0]); add_svc(pmtag, type, svctag, id, pmspec, flags, version, comment, script); break; case REMOVE: if (uid) { Saferrno = E_NOPRIV; error(NOTPRIV); } if (!pmtag || !svctag || type || script) usage(argv[0]); rem_svc(pmtag, svctag); break; case ENABLE: if (uid) { Saferrno = E_NOPRIV; error(NOTPRIV); } if (!pmtag || !svctag || type || script) usage(argv[0]); ed_svc(pmtag, svctag, ENABLE); break; case DISABLE: if (uid) { Saferrno = E_NOPRIV; error(NOTPRIV); } if (!pmtag || !svctag || type || script) usage(argv[0]); ed_svc(pmtag, svctag, DISABLE); break; case LIST: conflag = 1; /* fall through */ case PLIST: if ((pmtag && type) || script) usage(argv[0]); list_svcs(pmtag, type, svctag, conflag); break; case CONFIG: if (script && uid) { Saferrno = E_NOPRIV; error(NOTPRIV); } if ((pmtag && type) || (!pmtag && !type) || !svctag || (type && !script)) usage(argv[0]); doconf(script, pmtag, type, svctag); break; default: /* we only get here if more than one flag bit was set */ usage(argv[0]); /* NOTREACHED */ } quit(); /* NOTREACHED */ } /* * usage - print out a usage message * * args: cmdname - the name command was invoked with */ void usage(cmdname) char *cmdname; { (void) fprintf(stderr, "Usage:\t%s -a [ -p pmtag | -t type ] -s svctag -i id -m \"pmspecific\"\n", cmdname); (void) fprintf(stderr, "\t\t-v version [ -f xu ] [ -y comment ] [ -z script]\n"); (void) fprintf(stderr, "\t%s -r -p pmtag -s svctag\n", cmdname); (void) fprintf(stderr, "\t%s -e -p pmtag -s svctag\n", cmdname); (void) fprintf(stderr, "\t%s -d -p pmtag -s svctag\n", cmdname); (void) fprintf(stderr, "\t%s -l [ -p pmtag | -t type ] [ -s svctag ]\n", cmdname); (void) fprintf(stderr, "\t%s -L [ -p pmtag | -t type ] [ -s svctag ]\n", cmdname); (void) fprintf(stderr, "\t%s -g -p pmtag -s svctag [ -z script ]\n", cmdname); (void) fprintf(stderr, "\t%s -g -s svctag -t type -z script\n", cmdname); Saferrno = E_BADARGS; quit(); } /* * add_svc - add a service entry * * args: tag - port monitor's tag (may be null) * type - port monitor's type (may be null) * svctag - service's tag * id - identity under which service should run * pmspec - uninterpreted port monitor-specific info * flags - service flags * version - version number of port monitor's pmtab * comment - comment describing service * script - service's configuration script */ void add_svc(tag, type, svctag, id, pmspec, flags, version, comment, script) char *tag; char *type; char *svctag; char *id; char *pmspec; long flags; int version; char *comment; char *script; { FILE *fp; /* scratch file pointer */ struct taglist tl; /* 'list' for degenerate case (1 PM) */ register struct taglist *tp = NULL; /* working pointer */ int ret; /* return code from check_version */ char buf[SIZE]; /* scratch buffer */ char fname[SIZE]; /* scratch buffer for building names */ int added; /* count number added */ fp = fopen(SACTAB, "r"); if (fp == NULL) { Saferrno = E_SYSERR; error("Could not open _sactab"); } if (tag && !find_pm(fp, tag)) { (void) sprintf(buf, "Invalid request, %s does not exist", tag); Saferrno = E_NOEXIST; error(buf); } if (type && !(tp = find_type(fp, type))) { (void) sprintf(buf, "Invalid request, %s does not exist", type); Saferrno = E_NOEXIST; error(buf); } (void) fclose(fp); if (tag) { /* * treat the case of 1 PM as a degenerate case of a list of PMs from a * type specification. Build the 'list' here. */ tp = &tl; tp->t_next = NULL; (void) strcpy(tp->t_tag, tag); } added = 0; while (tp) { (void) sprintf(fname, "%s/%s/_pmtab", HOME, tp->t_tag); if ((ret = check_version(version, fname)) == 1) { (void) sprintf(buf, "%s version number is incorrect", fname); Saferrno = E_SAFERR; error(buf); } else if (ret == 2) { (void) sprintf(buf, "could not open %s", fname); Saferrno = E_SYSERR; error(buf); } else if (ret == 3) { (void) sprintf(buf, "%s file is corrupt", fname); Saferrno = E_SAFERR; error(buf); } fp = fopen(fname, "r"); if (fp == NULL) { (void) sprintf(buf, "Could not open %s", fname); Saferrno = E_SYSERR; error(buf); } if (find_svc(fp, tp->t_tag, svctag)) { if (tag) { /* special case of tag only */ (void) sprintf(buf, "Invalid request, %s already exists under %s", svctag, tag); Saferrno = E_DUP; error(buf); } else { (void) fprintf(stderr, "warning - %s already exists under %s - ignoring\n", svctag, tp->t_tag); tp = tp->t_next; (void) fclose(fp); continue; } } (void) fclose(fp); /* * put in the config script, if specified */ if (script) { (void) sprintf(fname, "%s/%s", tp->t_tag, svctag); if (do_config(script, fname)) { /* do_config put out any messages */ tp = tp->t_next; continue; } } /* * add the line */ (void) sprintf(fname, "%s/%s/_pmtab", HOME, tp->t_tag); fp = fopen(fname, "a"); if (fp == NULL) { (void) sprintf(buf, "Could not open %s", fname); Saferrno = E_SYSERR; error(buf); } (void) fprintf(fp, "%s:%s:%s:reserved:reserved:reserved:%s#%s\n", svctag, (flags ? pflags(flags, FALSE) : ""), id, pmspec, (comment ? comment : "")); (void) fclose(fp); added++; /* * tell the SAC to to tell PM to read _pmtab */ (void) tell_sac(tp->t_tag); tp = tp->t_next; } if (added == 0) { Saferrno = E_SAFERR; error("No services added"); } return; } /* * rem_svc - remove a service * * args: pmtag - tag of port monitor responsible for the service * svctag - tag of the service to be removed */ void rem_svc(pmtag, svctag) char *pmtag; char *svctag; { FILE *fp; /* scratch file pointer */ FILE *tfp; /* file pointer for temp file */ int line; /* line number entry is on */ char *tname; /* temp file name */ char buf[SIZE]; /* scratch buffer */ char fname[SIZE]; /* path to correct _pmtab */ fp = fopen(SACTAB, "r"); if (fp == NULL) { Saferrno = E_SYSERR; error("Could not open _sactab"); } if (!find_pm(fp, pmtag)) { (void) sprintf(buf, "Invalid request, %s does not exist", pmtag); Saferrno = E_NOEXIST; error(buf); } (void) fclose(fp); (void) sprintf(fname, "%s/_pmtab", pmtag); (void) sprintf(buf, "%s/%s", HOME, fname); fp = fopen(buf, "r"); if (fp == NULL) { (void) sprintf(buf, "Could not open %s/%s", HOME, fname); Saferrno = E_SYSERR; error(buf); } if ((line = find_svc(fp, pmtag, svctag)) == 0) { (void) sprintf(buf, "Invalid request, %s does not exist under %s", svctag, pmtag); Saferrno = E_NOEXIST; error(buf); } tname = make_tempname(fname); tfp = open_temp(tname); if (line != 1) { if (copy_file(fp, tfp, 1, line - 1)) { (void) unlink(tname); Saferrno = E_SYSERR; error("error accessing temp file"); } } if (copy_file(fp, tfp, line + 1, -1)) { (void) unlink(tname); Saferrno = E_SYSERR; error("error accessing temp file"); } (void) fclose(fp); if (fclose(tfp) == EOF) { (void) unlink(tname); Saferrno = E_SYSERR; error("error closing tempfile"); } /* note - replace only returns if successful */ replace(fname, tname); /* * tell the SAC to to tell PM to read _pmtab */ if (tell_sac(pmtag)) { /* * if we got rid of the service, try to remove the config script too. * Don't check return status since it may not have existed anyhow. */ (void) sprintf(buf, "%s/%s/%s", HOME, pmtag, svctag); (void) unlink(buf); return; } } /* * ed_svc - enable or disable a particular service * * args: pmtag - tag of port monitor responsible for the service * svctag - tag of service to be enabled or disabled * flag - operation to perform (ENABLE or DISABLE) */ void ed_svc(pmtag, svctag, flag) char *pmtag; char *svctag; int flag; { FILE *fp; /* scratch file pointer */ FILE *tfp; /* file pointer for temp file */ int line; /* line number entry is on */ register char *from; /* working pointer */ register char *to; /* working pointer */ char *tname; /* temp file name */ char *p; /* scratch pointer */ char buf[SIZE]; /* scratch buffer */ char tbuf[SIZE]; /* scratch buffer */ char fname[SIZE]; /* path to correct _pmtab */ fp = fopen(SACTAB, "r"); if (fp == NULL) { Saferrno = E_SYSERR; error("Could not open _sactab"); } if (!find_pm(fp, pmtag)) { (void) sprintf(buf, "Invalid request, %s does not exist", pmtag); Saferrno = E_NOEXIST; error(buf); } (void) fclose(fp); (void) sprintf(fname, "%s/_pmtab", pmtag); (void) sprintf(buf, "%s/%s", HOME, fname); fp = fopen(buf, "r"); if (fp == NULL) { (void) sprintf(buf, "Could not open %s/%s", HOME, fname); Saferrno = E_SYSERR; error(buf); } if ((line = find_svc(fp, pmtag, svctag)) == 0) { (void) sprintf(buf, "Invalid request, %s does not exist under %s", svctag, pmtag); Saferrno = E_NOEXIST; error(buf); } tname = make_tempname(fname); tfp = open_temp(tname); if (line != 1) { if (copy_file(fp, tfp, 1, line - 1)) { (void) unlink(tname); Saferrno = E_SYSERR; error("error accessing temp file"); } } /* * Note: find_svc above has already read and parsed this entry, thus * we know it to be well-formed, so just change the flags as appropriate */ if (fgets(buf, SIZE, fp) == NULL) { (void) unlink(tname); Saferrno = E_SYSERR; error("error accessing temp file"); } from = buf; to = tbuf; /* * copy initial portion of entry */ p = strchr(from, DELIMC); for ( ; from <= p; ) *to++ = *from++; /* * isolate and fix the flags */ p = strchr(from, DELIMC); for ( ; from < p; ) { if (*from == 'x') { from++; continue; } *to++ = *from++; } /* * above we removed x flag, if this was a disable operation, stick it in * and also copy the field delimiter */ if (flag == DISABLE) *to++ = 'x'; *to++ = *from++; /* * copy the rest of the line */ for ( ; from < &buf[SIZE - 1] ;) *to++ = *from++; /*** *to = '\0'; BUG: Don't uncomment it ****/ (void) fprintf(tfp, "%s", tbuf); if (copy_file(fp, tfp, line + 1, -1)) { (void) unlink(tname); Saferrno = E_SYSERR; error("error accessing temp file"); } (void) fclose(fp); if (fclose(tfp) == EOF) { (void) unlink(tname); Saferrno = E_SYSERR; error("error closing tempfile"); } /* note - replace only returns if successful */ replace(fname, tname); /* * tell the SAC to to tell PM to read _pmtab */ (void) tell_sac(pmtag); } /* * doconf - take a config script and have it put where it belongs or * output an existing one * * args: script - name of file containing script (if NULL, means * output existing one instead) * tag - tag of port monitor that is responsible for the * designated service (may be null) * type - type of port monitor that is responsible for the * designated service (may be null) * svctag - tag of service whose config script we're operating on */ void doconf(script, tag, type, svctag) char *script; char *tag; char *type; char *svctag; { FILE *fp; /* scratch file pointer */ int added; /* count of config scripts added */ struct taglist tl; /* 'list' for degenerate case (1 PM) */ register struct taglist *tp = NULL; /* working pointer */ char buf[SIZE]; /* scratch buffer */ char fname[SIZE]; /* scratch buffer for names */ fp = fopen(SACTAB, "r"); if (fp == NULL) { Saferrno = E_SYSERR; error("Could not open _sactab"); } if (tag && !find_pm(fp, tag)) { (void) sprintf(buf, "Invalid request, %s does not exist", tag); Saferrno = E_NOEXIST; error(buf); } if (type && !(tp = find_type(fp, type))) { (void) sprintf(buf, "Invalid request, %s does not exist", type); Saferrno = E_NOEXIST; error(buf); } (void) fclose(fp); if (tag) { /* * treat the case of 1 PM as a degenerate case of a list of PMs from a * type specification. Build the 'list' here. */ tp = &tl; tp->t_next = NULL; (void) strcpy(tp->t_tag, tag); } added = 0; while (tp) { (void) sprintf(fname, "%s/%s/_pmtab", HOME, tp->t_tag); fp = fopen(fname, "r"); if (fp == NULL) { (void) sprintf(buf, "Could not open %s", fname); Saferrno = E_SYSERR; error(buf); } if (!find_svc(fp, tp->t_tag, svctag)) { if (tag) { /* special case of tag only */ (void) sprintf(buf, "Invalid request, %s does not exist under %s", svctag, tag); Saferrno = E_NOEXIST; error(buf); } else { (void) fprintf(stderr, "warning - %s does not exist under %s - ignoring\n", svctag, tp->t_tag); Saferrno = E_NOEXIST; tp = tp->t_next; (void) fclose(fp); continue; } } (void) fclose(fp); (void) sprintf(fname, "%s/%s", tp->t_tag, svctag); /* * do_config does all the real work (keep track if any errors occurred) */ if (do_config(script, fname) == 0) added++; tp = tp->t_next; } if (added == 0) { Saferrno = E_SAFERR; error("No configuration scripts installed"); } return; } /* * tell_sac - use sacadm to tell the sac to tell a port monitor to read * its _pmtab. Return TRUE on success, FALSE on failure. * * args: tag - tag of port monitor to be notified */ tell_sac(tag) char *tag; { pid_t pid; /* returned pid from fork */ int status; /* return status from sacadm child */ if ((pid = fork()) < 0) { (void) fprintf(stderr, "warning - fork failed - could not notify <%s> about modified table\n", tag); (void) fprintf(stderr, "try executing the command \"sacadm -x -p %s\"\n", tag); Saferrno = E_SYSERR; return(FALSE); } else if (pid) { /* parent */ (void) wait(&status); if (status) { if (((status >> 8) & 0xff) == E_PMNOTRUN) { (void) fprintf(stderr, "warning - port monitor, %s is not running\n", tag); return (FALSE); } if (((status >> 8) & 0xff) == E_SACNOTRUN) { Saferrno = E_SACNOTRUN; } else { Saferrno = E_SYSERR; } (void) fprintf(stderr, "warning - could not notify <%s> about modified" " table\n", tag); (void) fprintf(stderr, "try executing the command" " \"sacadm -x -p %s\"\n", tag); return(FALSE); } else { return(TRUE); } } else { /* set IFS for security */ (void) putenv("IFS=\" \""); /* muffle sacadm warning messages */ (void) fclose(stderr); (void) fopen("/dev/null", "w"); (void) execl("/usr/sbin/sacadm", "sacadm", "-x", "-p", tag, 0); /* * if we got here, it didn't work, exit status will clue in parent to * put out the warning */ exit(1); } /* NOTREACHED */ } /* * list_svcs - list information about services * * args: pmtag - tag of port monitor responsible for the service * (may be null) * type - type of port monitor responsible for the service * (may be null) * svctag - tag of service to be listed (may be null) * oflag - true if output should be easily parseable */ void list_svcs(pmtag, type, svctag, oflag) char *pmtag; char *type; char *svctag; { FILE *fp; /* scratch file pointer */ register struct taglist *tp; /* pointer to PM list */ int nprint = 0; /* count # of svcs printed */ struct pmtab pmtab; /* place to hold parsed info */ register struct pmtab *pp = &pmtab; /* and a pointer to it */ register char *p; /* working pointer */ char buf[SIZE]; /* scratch buffer */ char fname[SIZE]; /* scratch buffer for building names */ fp = fopen(SACTAB, "r"); if (fp == NULL) { Saferrno = E_SYSERR; error("Could not open _sactab"); } if (pmtag && !find_pm(fp, pmtag)) { (void) sprintf(buf, "Invalid request, %s does not exist", pmtag); Saferrno = E_NOEXIST; error(buf); } rewind(fp); if (type) { tp = find_type(fp, type); if (tp == NULL) { (void) sprintf(buf, "Invalid request, %s does not exist", type); Saferrno = E_NOEXIST; error(buf); } } else tp = find_type(fp, NULL); (void) fclose(fp); while (tp) { if (pmtag && strcmp(tp->t_tag, pmtag)) { /* not interested in this port monitor */ tp = tp->t_next; continue; } (void) sprintf(fname, "%s/%s/_pmtab", HOME, tp->t_tag); fp = fopen(fname, "r"); if (fp == NULL) { (void) sprintf(buf, "Could not open %s", fname); Saferrno = E_SYSERR; error(buf); } while (fgets(buf, SIZE, fp)) { p = trim(buf); if (*p == '\0') continue; parseline(p, pp, tp->t_tag); if (!svctag || !strcmp(pp->p_tag, svctag)) { if (oflag) { (void) printf("%s:%s:%s:%s:%s:%s:%s:%s:%s#%s\n", tp->t_tag, tp->t_type, pp->p_tag, pflags(pp->p_flags, FALSE), pp->p_id, pp->p_res1, pp->p_res2, pp->p_res3,pp->p_pmspec, Comment); } else { if (nprint == 0) { (void) printf("PMTAG PMTYPE SVCTAG FLGS ID \n"); } (void) printf("%-14s %-14s %-14s %-4s %-8s %s #%s\n", tp->t_tag, tp->t_type, pp->p_tag, pflags(pp->p_flags, TRUE), pp->p_id, pspec(pp->p_pmspec), Comment); } nprint++; } } if (!feof(fp)) { (void) sprintf(buf, "error reading %s", fname); Saferrno = E_SYSERR; error(buf); } else { (void) fclose(fp); tp = tp->t_next; } } /* if we didn't find any valid ones, indicate an error */ if (nprint == 0) { if (svctag) (void) fprintf(stderr, "Service <%s> does not exist\n", svctag); else (void) fprintf(stderr, "No services defined\n"); Saferrno = E_NOEXIST; } return; } /* * find_svc - find an entry in _pmtab for a particular service tag * * args: fp - file pointer for _pmtab * tag - port monitor tag (for error reporting) * svctag - tag of service we're looking for */ find_svc(fp, tag, svctag) FILE *fp; char *tag; char *svctag; { register char *p; /* working pointer */ int line = 0; /* line number we found entry on */ struct pmtab pmtab; /* place to hold parsed info */ static char buf[SIZE]; /* scratch buffer */ while (fgets(buf, SIZE, fp)) { line++; p = trim(buf); if (*p == '\0') continue; parseline(p, &pmtab, tag); if (!(strcmp(pmtab.p_tag, svctag))) return(line); } if (!feof(fp)) { (void) sprintf(buf, "error reading %s/%s/_pmtab", HOME, tag); Saferrno = E_SYSERR; error(buf); } else return(0); /* NOTREACHED */ } /* * parseline - parse a line from _pmtab. This routine will return if the * parse wa successful, otherwise it will output an error and * exit. * * args: p - pointer to the data read from the file (note - this is * a static data region, so we can point into it) * pp - pointer to a structure in which the separated fields * are placed * tag - port monitor tag (for error reporting) * * A line in the file has the following format: * * tag:flags:identity:reserved:reserved:reserved:PM_spec_info # comment */ void parseline(p, pp, tag) register char *p; register struct pmtab *pp; char *tag; { char buf[SIZE]; /* scratch buffer */ /* * get the service tag */ p = nexttok(p, DELIM, FALSE); if (p == NULL) { (void) sprintf(buf, "%s/%s/_pmtab is corrupt", HOME, tag); Saferrno = E_SAFERR; error(buf); } if (strlen(p) > PMTAGSIZE) { p[PMTAGSIZE] = '\0'; (void) fprintf(stderr, "tag too long, truncated to <%s>", p); } pp->p_tag = p; /* * get the flags */ p = nexttok(NULL, DELIM, FALSE); if (p == NULL) { (void) sprintf(buf, "%s/%s/_pmtab is corrupt", HOME, tag); Saferrno = E_SAFERR; error(buf); } pp->p_flags = 0; while (*p) { switch (*p++) { case 'u': pp->p_flags |= U_FLAG; break; case 'x': pp->p_flags |= X_FLAG; break; default: (void) sprintf(buf, "Unrecognized flag <%c>", *(p - 1)); Saferrno = E_SAFERR; error(buf); break; } } /* * get the identity */ p = nexttok(NULL, DELIM, FALSE); if (p == NULL) { (void) sprintf(buf, "%s/%s/_pmtab is corrupt", HOME, tag); Saferrno = E_SAFERR; error(buf); } pp->p_id = p; /* * get the first reserved field */ p = nexttok(NULL, DELIM, FALSE); if (p == NULL) { (void) sprintf(buf, "%s/%s/_pmtab is corrupt", HOME, tag); Saferrno = E_SAFERR; error(buf); } pp->p_res1 = p; /* * get the second reserved field */ p = nexttok(NULL, DELIM, FALSE); if (p == NULL) { (void) sprintf(buf, "%s/%s/_pmtab is corrupt", HOME, tag); Saferrno = E_SAFERR; error(buf); } pp->p_res2 = p; /* * get the third reserved field */ p = nexttok(NULL, DELIM, FALSE); if (p == NULL) { (void) sprintf(buf, "%s/%s/_pmtab is corrupt", HOME, tag); Saferrno = E_SAFERR; error(buf); } pp->p_res3 = p; /* * the rest is the port monitor specific info */ p = nexttok(NULL, DELIM, TRUE); if (p == NULL) { (void) sprintf(buf, "%s/%s/_pmtab is corrupt", HOME, tag); Saferrno = E_SAFERR; error(buf); } pp->p_pmspec = p; return; } /* * pspec - format port monitor specific information * * args: spec - port monitor specific info, separated by * field separater character (may be escaped by \) */ char * pspec(spec) char *spec; { static char buf[SIZE]; /* returned string */ register char *from; /* working pointer */ register char *to; /* working pointer */ int newflag; /* flag indicating new field */ to = buf; from = spec; newflag = 1; while (*from) { switch (*from) { case ':': if (newflag) { *to++ = '-'; } *to++ = ' '; from++; newflag = 1; break; case '\\': if (*(from + 1) == ':') { *to++ = ':'; /* skip over \: */ from += 2; } else *to++ = *from++; newflag = 0; break; default: newflag = 0; *to++ = *from++; } } *to = '\0'; return(buf); } /* * pflags - put service flags into intelligible form for output * * args: flags - binary representation of flags * dflag - true if a "-" should be returned if no flags */ char * pflags(flags, dflag) long flags; int dflag; { register int i; /* scratch counter */ static char buf[SIZE]; /* formatted flags */ if (flags == 0) { if (dflag) return("-"); else return(""); } i = 0; if (flags & U_FLAG) { buf[i++] = 'u'; flags &= ~U_FLAG; } if (flags & X_FLAG) { buf[i++] = 'x'; flags &= ~X_FLAG; } if (flags) { Saferrno = E_SAFERR; error("Internal error in pflags"); } buf[i] = '\0'; return(buf); } /* * find_type - find entries in _sactab for a particular port monitor type * * args: fp - file pointer for _sactab * type - type of port monitor we're looking for (if type is * null, it means find all PMs) */ struct taglist * find_type(fp, type) FILE *fp; char *type; { register char *p; /* working pointer */ struct sactab stab; /* place to hold parsed info */ register struct sactab *sp = &stab; /* and a pointer to it */ char buf[SIZE]; /* scratch buffer */ struct taglist *thead; /* linked list of tags */ register struct taglist *temp; /* scratch pointer */ thead = NULL; while (fgets(buf, SIZE, fp)) { p = trim(buf); if (*p == '\0') continue; parse(p, sp); if ((type == NULL) || !(strcmp(sp->sc_type, type))) { temp = (struct taglist *) malloc(sizeof(struct taglist)); if (temp == NULL) { Saferrno = E_SYSERR; error("malloc failed"); } temp->t_next = thead; (void) strcpy(temp->t_tag, sp->sc_tag); (void) strcpy(temp->t_type, sp->sc_type); thead = temp; } } if (!feof(fp)) { Saferrno = E_SYSERR; error("error reading _sactab"); } else return(thead ? thead : NULL); /* NOTREACHED */ }