/*
* 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 2005 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 <stdio.h>
#include <stdlib.h>
#include <strings.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include "extern.h"
#include "misc.h"
#include <sac.h>
#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
*/
int
main(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
*/
int
tell_sac(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 <PMSPECIFIC>\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
*/
int
find_svc(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);
/* NOTREACHED */
return (0);
} else
return (0);
}
/*
* 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");
/* NOTREACHED */
return (0);
} else
return (thead ? thead : NULL);
}