sacadm.c revision 7c478bd95313f5f23a4c958a745db2134aa03244
/*
* 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 (c) 1999 by Sun Microsystems, Inc.
* All rights reserved.
*/
/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
/* All Rights Reserved */
#pragma ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.15*/
# include <stdio.h>
# include <fcntl.h>
# include <errno.h>
# include <sys/types.h>
# include <sys/stat.h>
# include <signal.h>
# include <unistd.h>
# include <sac.h>
# include "misc.h"
# include "structs.h"
# include "adm.h"
# include "extern.h"
/*
* functions
*/
char *pflags();
char *getfield();
void add_pm();
void cleandirs();
void rem_pm();
void start_pm();
void kill_pm();
void enable_pm();
void disable_pm();
void list_pms();
void read_db();
void sendcmd();
void checkresp();
void single_print();
void catch();
void usage();
# define START 0x1 /* -s seen */
# define KILL 0x2 /* -k seen */
# define ENABLE 0x4 /* -e seen */
# define DISABLE 0x8 /* -d seen */
# define PLIST 0x10 /* -l seen */
# define LIST 0x20 /* -L seen */
# define DBREAD 0x40 /* -x seen */
# define CONFIG 0x80 /* -G seen */
# define PCONFIG 0x100 /* -g seen */
# define ADD 0x200 /* -a or other required options seen */
# define REMOVE 0x400 /* -r seen */
/*
* common error messages
*/
# define NOTPRIV "User not privileged for operation"
# define SACERR "Can not contact SAC"
# define BADINP "Embedded newlines not allowed"
int Saferrno; /* internal `errno' for exit */
/*
* main - scan args for sacadm and call appropriate handling code
*/
main(argc, argv)
int argc;
char *argv[];
{
int c; /* option letter */
uid_t uid; /* invoker's real uid */
int ret; /* return code from check_version */
int flag = 0; /* flag to record requested operations */
int errflg = 0; /* error indicator */
int version = -1; /* argument to -v */
int count = 0; /* argument to -n */
int badcnt = 0; /* count of bad args to -f */
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 */
FILE *fp; /* scratch file pointer */
char *pmtag = NULL; /* argument to -p */
char *type = NULL; /* argument to -t */
char *script = NULL; /* argument to -z */
char *command = NULL; /* argument to -c */
char *comment = " "; /* argument to -y */
char badargs[BADFARGSIZE]; /* 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, "ac:def:GgkLln:p:rst:v:xy:z:")) != -1) {
switch (c) {
case 'a':
flag |= ADD;
sawaflag = 1;
break;
case 'c':
flag |= ADD;
if (strchr(optarg, '\n')) {
Saferrno = E_BADARGS;
error(BADINP);
}
command = optarg;
if (*command != '/') {
Saferrno = E_BADARGS;
error("command must be a full pathname");
}
break;
case 'd':
flag |= DISABLE;
break;
case 'e':
flag |= ENABLE;
break;
case 'f':
flag |= ADD;
while (*optarg) {
switch (*optarg++) {
case 'd':
flags |= D_FLAG;
break;
case 'x':
flags |= X_FLAG;
break;
default:
if (badcnt < (BADFARGSIZE -1))
badargs[badcnt++] = *(optarg - 1);
break;
}
}
/* null terminate just in case anything is there */
badargs[badcnt] = '\0';
break;
case 'G':
flag |= CONFIG;
break;
case 'g':
flag |= PCONFIG;
break;
case 'k':
flag |= KILL;
break;
case 'L':
flag |= LIST;
break;
case 'l':
flag |= PLIST;
break;
case 'n':
flag |= ADD;
count = atoi(optarg);
if (count < 0) {
Saferrno = E_BADARGS;
error("restart count can not be negative");
}
break;
case 'p':
pmtag = optarg;
if (strchr(optarg, '\n')) {
Saferrno = E_BADARGS;
error(BADINP);
}
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':
flag |= START;
break;
case 't':
type = optarg;
if (strchr(optarg, '\n')) {
Saferrno = E_BADARGS;
error(BADINP);
}
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 'x':
flag |= DBREAD;
break;
case 'y':
flag |= ADD;
if (strchr(optarg, '\n')) {
Saferrno = E_BADARGS;
error(BADINP);
}
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 */
Saferrno = E_BADARGS;
(void) sprintf(buf,
"Invalid request, %s are not valid arguments for \"-f\"",
badargs);
error(buf);
}
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);
}
uid = getuid();
switch (flag) {
case ADD:
if (uid) {
Saferrno = E_NOPRIV;
error(NOTPRIV);
}
if (!sawaflag || !pmtag || !type || !command || (version < 0))
usage(argv[0]);
add_pm(pmtag, type, command, version, flags, count, script, comment);
break;
case REMOVE:
if (uid) {
Saferrno = E_NOPRIV;
error(NOTPRIV);
}
if (!pmtag || type || script)
usage(argv[0]);
rem_pm(pmtag);
break;
case START:
if (uid) {
Saferrno = E_NOPRIV;
error(NOTPRIV);
}
if (!pmtag || type || script)
usage(argv[0]);
start_pm(pmtag);
break;
case KILL:
if (uid) {
Saferrno = E_NOPRIV;
error(NOTPRIV);
}
if (!pmtag || type || script)
usage(argv[0]);
kill_pm(pmtag);
break;
case ENABLE:
if (uid) {
Saferrno = E_NOPRIV;
error(NOTPRIV);
}
if (!pmtag || type || script)
usage(argv[0]);
enable_pm(pmtag);
break;
case DISABLE:
if (uid) {
Saferrno = E_NOPRIV;
error(NOTPRIV);
}
if (!pmtag || type || script)
usage(argv[0]);
disable_pm(pmtag);
break;
case LIST:
conflag = 1;
/* fall through */
case PLIST:
if ((pmtag && type) || script)
usage(argv[0]);
list_pms(pmtag, type, conflag);
break;
case DBREAD:
if (uid) {
Saferrno = E_NOPRIV;
error(NOTPRIV);
}
if (type || script)
usage(argv[0]);
read_db(pmtag);
break;
case CONFIG:
if (script && uid) {
Saferrno = E_NOPRIV;
error(NOTPRIV);
}
if (type || pmtag)
usage(argv[0]);
(void) do_config(script, "_sysconfig");
break;
case PCONFIG:
if (script && uid) {
Saferrno = E_NOPRIV;
error(NOTPRIV);
}
if (!pmtag || type)
usage(argv[0]);
fp = fopen(SACTAB, "r");
if (fp == NULL) {
Saferrno = E_SYSERR;
error("Could not open _sactab");
}
if (!find_pm(fp, pmtag)) {
Saferrno = E_NOEXIST;
(void) sprintf(buf, "Invalid request, %s does not exist", pmtag);
error(buf);
}
(void) fclose(fp);
(void) sprintf(buf, "%s/_config", pmtag);
(void) do_config(script, buf);
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 -c cmd -v ver [ -f dx ] [ -n count ]\n", cmdname);
(void) fprintf(stderr, "\t\t[ -y comment ] [ -z script]\n");
(void) fprintf(stderr, "\t%s -r -p pmtag\n", cmdname);
(void) fprintf(stderr, "\t%s -s -p pmtag\n", cmdname);
(void) fprintf(stderr, "\t%s -k -p pmtag\n", cmdname);
(void) fprintf(stderr, "\t%s -e -p pmtag\n", cmdname);
(void) fprintf(stderr, "\t%s -d -p pmtag\n", cmdname);
(void) fprintf(stderr, "\t%s -l [ -p pmtag | -t type ]\n", cmdname);
(void) fprintf(stderr, "\t%s -L [ -p pmtag | -t type ]\n", cmdname);
(void) fprintf(stderr, "\t%s -g -p pmtag [ -z script ]\n", cmdname);
(void) fprintf(stderr, "\t%s -G [ -z script ]\n", cmdname);
(void) fprintf(stderr, "\t%s -x [ -p pmtag ]\n", cmdname);
Saferrno = E_BADARGS;
quit();
}
/*
* add_pm - add a port monitor entry
*
* args: tag - port monitor's tag
* type - port monitor's type
* command - command string to invoke port monitor
* version - version number of port monitor's pmtab
* flags - port monitor flags
* count - restart count
* script - port monitor's configuration script
* comment - comment describing port monitor
*/
void
add_pm(tag, type, command, version, flags, count, script, comment)
char *tag;
char *type;
char *command;
int version;
long flags;
int count;
char *script;
char *comment;
{
FILE *fp; /* file pointer for _sactab */
int fd; /* scratch file descriptor */
struct stat statbuf; /* file status info */
char buf[SIZE]; /* scratch buffer */
char fname[SIZE]; /* scratch buffer for building names */
register int i; /* scratch variable */
fp = fopen(SACTAB, "r");
if (fp == NULL) {
Saferrno = E_SYSERR;
error("Could not open _sactab");
}
if (find_pm(fp, tag)) {
Saferrno = E_DUP;
(void) sprintf(buf, "Invalid request, %s already exists", tag);
error(buf);
}
(void) fclose(fp);
/*
* create the directories for it if needed and put in initial files
* (/etc/saf and /var/saf)
*/
for (i = 0; i < 2; i++) {
/* i == 0 do /etc/saf i == 1 do /var/saf */
(void) sprintf(fname, "%s/%s", (i == 0 ) ? HOME : ALTHOME, tag);
if (access(fname, 0) == 0) {
/* something is there, find out what it is */
if (stat(fname, &statbuf) < 0) {
Saferrno = E_SYSERR;
(void) sprintf(buf, "could not stat <%s>", fname);
error(buf);
}
if ((statbuf.st_mode & S_IFMT) != S_IFDIR) {
Saferrno = E_SYSERR;
(void) sprintf(buf, "<%s> exists and is not a directory", fname);
error(buf);
}
/* note: this removes the directory too */
(void) sprintf(buf, "rm -rf %s", fname);
if (system(buf) < 0) {
Saferrno = E_SYSERR;
(void) sprintf(buf, "could not remove files under <%s>", fname);
error(buf);
}
}
/*
* create the directory
*/
if (mkdir(fname, 0755) < 0) {
Saferrno = E_SYSERR;
(void) sprintf(buf, "could not create directory <%s>", fname);
cleandirs(tag);
error(buf);
}
}
/*
* put in the config script, if specified
*/
if (script) {
(void) sprintf(fname, "%s/_config", tag);
if (do_config(script, fname)) {
cleandirs(tag);
/* do_config put out any messages */
quit();
}
}
/*
* create the communications pipe, but first make sure that the
* permissions we specify are what we get
*/
(void) umask(0);
(void) sprintf(fname, "%s/%s/_pmpipe", HOME, tag);
if (mknod(fname, S_IFIFO | 0600, 0) < 0) {
Saferrno = E_SYSERR;
cleandirs(tag);
error("could not create communications pipe");
}
/*
* create the _pid file
*/
(void) sprintf(fname, "%s/%s/_pid", HOME, tag);
if ((fd = creat(fname, 0644)) < 0) {
Saferrno = E_SYSERR;
cleandirs(tag);
error("could not create _pid file");
}
(void) close(fd);
/*
* create the _pmtab file
*/
(void) sprintf(fname, "%s/%s/_pmtab", HOME, tag);
if ((fd = creat(fname, 0644)) < 0) {
Saferrno = E_SYSERR;
cleandirs(tag);
error("could not create _pmtab file");
}
(void) sprintf(buf, "%s%d\n", VSTR, version);
if (write(fd, buf, (unsigned) strlen(buf)) != strlen(buf)) {
(void) close(fd);
(void) unlink(fname);
Saferrno = E_SYSERR;
cleandirs(tag);
error("error initializing _pmtab");
}
(void) close(fd);
/*
* isolate the command name, but remember it since strtok() trashes it
*/
(void) strcpy(buf, command);
(void) strtok(command, " \t");
/*
* check out the command - let addition succeed if it doesn't exist (assume
* it will be added later); fail anything else
*/
if (access(command, 0) == 0) {
if (stat(command, &statbuf) < 0) {
Saferrno = E_SYSERR;
(void) fprintf(stderr, "Could not stat <%s>\n", command);
cleandirs(tag);
quit();
}
if (!(statbuf.st_mode & 0111)) {
Saferrno = E_BADARGS;
(void) fprintf(stderr, "%s not executable\n", command);
cleandirs(tag);
quit();
}
if ((statbuf.st_mode & S_IFMT) != S_IFREG) {
Saferrno = E_BADARGS;
(void) fprintf(stderr, "%s not a regular file\n", command);
cleandirs(tag);
quit();
}
}
else {
(void) fprintf(stderr, "warning - %s does not exist\n", command);
}
/*
* add the line
*/
fp = fopen(SACTAB, "a");
if (fp == NULL) {
Saferrno = E_SYSERR;
cleandirs(tag);
error("Could not open _sactab");
}
(void) fprintf(fp, "%s:%s:%s:%d:%s\t#%s\n", tag, type,
(flags ? pflags(flags, FALSE) : ""), count, buf,
(comment ? comment : ""));
(void) fclose(fp);
/*
* tell the SAC to read _sactab if its there (i.e. single user)
*/
if (sac_home())
read_db(NULL);
return;
}
/*
* cleandirs - remove anything that might have been created (i.e. failed
* addition. Saferrno is set elsewhere; this is strictly an attempt
* to clean up what mess we've left, so don't check to see if the
* cleanup worked.
*
* args: tag - tag of port monitor whose trees should be removed
*/
void
cleandirs(tag)
char *tag;
{
char buf[SIZE]; /* scratch buffer */
/* note: this removes the directory too, first zap /etc/saf/<tag> */
(void) sprintf(buf, "rm -rf %s/%s", HOME, tag);
(void) system(buf);
/* now remove /var/saf/<tag> */
(void) sprintf(buf, "%s/%s", ALTHOME, tag);
(void) rmdir(buf);
}
/*
* rem_pm - remove a port monitor
*
* args: tag - tag of port monitor to be removed
*/
void
rem_pm(tag)
char *tag;
{
FILE *fp; /* file pointer for _sactab */
FILE *tfp; /* file pointer for temp file */
int line; /* line number entry is on */
char *tname; /* temp file name */
char buf[SIZE]; /* scratch buffer */
fp = fopen(SACTAB, "r");
if (fp == NULL) {
Saferrno = E_SYSERR;
error("Could not open _sactab");
}
if ((line = find_pm(fp, tag)) == 0) {
Saferrno = E_NOEXIST;
(void) sprintf(buf, "Invalid request, %s does not exist", tag);
error(buf);
}
tname = make_tempname("_sactab");
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("_sactab", tname);
/*
* tell the SAC to read _sactab if its there (i.e. single user)
*/
if (sac_home())
read_db(NULL);
return;
}
/*
* start_pm - start a particular port monitor
*
* args: tag - tag of port monitor to be started
*/
void
start_pm(tag)
char *tag;
{
struct admcmd cmd; /* command structure */
register struct admcmd *ap = &cmd; /* and a pointer to it */
ap->ac_mtype = AC_START;
(void) strcpy(ap->ac_tag, tag);
ap->ac_pid = getpid();
sendcmd(ap, NULL, tag);
return;
}
/*
* kill_pm - stop a particular port monitor
*
* args: tag - tag of port monitor to be stopped
*/
void
kill_pm(tag)
char *tag;
{
struct admcmd cmd; /* command structure */
register struct admcmd *ap = &cmd; /* and a pointer to it */
ap->ac_mtype = AC_KILL;
(void) strcpy(ap->ac_tag, tag);
ap->ac_pid = getpid();
sendcmd(ap, NULL, tag);
return;
}
/*
* enable_pm - enable a particular port monitor
*
* args: tag - tag of port monitor to be enabled
*/
void
enable_pm(tag)
char *tag;
{
struct admcmd cmd; /* command structure */
register struct admcmd *ap = &cmd; /* and a pointer to it */
ap->ac_mtype = AC_ENABLE;
(void) strcpy(ap->ac_tag, tag);
ap->ac_pid = getpid();
sendcmd(ap, NULL, tag);
return;
}
/*
* disable_pm - disable a particular port monitor
*
* args: tag - tag of port monitor to be disabled
*/
void
disable_pm(tag)
char *tag;
{
struct admcmd cmd; /* command structure */
register struct admcmd *ap = &cmd; /* and a pointer to it */
ap->ac_mtype = AC_DISABLE;
(void) strcpy(ap->ac_tag, tag);
ap->ac_pid = getpid();
sendcmd(ap, NULL, tag);
return;
}
/*
* read_db - tell SAC or a port monitor to read its administrative file.
*
* args: tag - tag of port monitor that should read its administrative
* file. If NULL, it means SAC should.
*/
void
read_db(tag)
char *tag;
{
struct admcmd cmd; /* command structure */
register struct admcmd *ap = &cmd; /* and a pointer to it */
ap->ac_mtype = (tag) ? AC_PMREAD : AC_SACREAD;
if (tag)
(void) strcpy(ap->ac_tag, tag);
ap->ac_pid = getpid();
sendcmd(ap, NULL, tag);
return;
}
/*
* list_pms - request information about port monitors from SAC and output
* requested info
*
* args: pmtag - tag of port monitor to be listed (may be null)
* pmtype - type of port monitors to be listed (may be null)
* oflag - true if output should be easily parseable
*/
void
list_pms(pmtag, pmtype, oflag)
char *pmtag;
char *pmtype;
int oflag;
{
struct admcmd acmd; /* command structure */
register struct admcmd *ap = &acmd; /* and a pointer to it */
int nprint = 0; /* count # of PMs printed */
char *p; /* scratch pointer */
char *tag; /* returned tag */
char *type; /* returned type */
char *flags; /* returned flags */
char *rsmax; /* returned restart count */
char *state; /* returned state */
char *cmd; /* returned command string */
char *comment; /* returned comment string */
/*
* if sac isn't there (single user), provide info direct from _sactab
* note: when this routine returns, the process exits, so there is no
* need to free up any memory
*/
p = NULL;
if (sac_home()) {
ap->ac_mtype = AC_STATUS;
ap->ac_tag[0] = '\0';
ap->ac_pid = getpid();
sendcmd(ap, &p, NULL);
}
else {
single_print(&p);
}
/*
* SAC sends back info in condensed form, we have to separate it out
* fields come in ':' separated, records are separated by newlines
*/
while (p && *p) {
tag = getfield(&p, ':'); /* PM tag */
type = getfield(&p, ':'); /* PM type */
flags = getfield(&p, ':'); /* flags */
rsmax = getfield(&p, ':'); /* restart count */
state = pstate((unchar) atoi(getfield(&p, ':'))); /* state in nice output format */
cmd = getfield(&p, ':'); /* command */
comment = getfield(&p, '\n'); /* comment */
/*
* print out if no selectors specified, else check to see if
* a selector matched
*/
if ((!pmtag && !pmtype) || (pmtag && !strcmp(pmtag, tag)) || (pmtype && !strcmp(pmtype, type))) {
if (oflag) {
(void) printf("%s:%s:%s:%s:%s:%s#%s\n", tag, type, pflags(atol(flags), FALSE),
rsmax, state, cmd, comment);
}
else {
if (nprint == 0) {
(void) printf("PMTAG PMTYPE FLGS RCNT STATUS COMMAND\n");
}
(void) printf("%-14s %-14s %-4s %-4s %-10s %s #%s\n", tag, type, pflags(atol(flags), TRUE),
rsmax, state, cmd, comment);
}
nprint++;
}
}
/*
* if we didn't find any valid ones, indicate an error (note: 1 and
* only 1 of the if statements should be true)
*/
if (nprint == 0) {
if (pmtype)
(void) fprintf(stderr, "Invalid request, %s does not exist\n", pmtype);
else if (pmtag)
(void) fprintf(stderr, "Invalid request, %s does not exist\n", pmtag);
else if (!pmtag && !pmtype)
(void) fprintf(stderr, "No port monitors defined\n");
Saferrno = E_NOEXIST;
}
return;
}
/*
* getfield - retrieve and return a field from the sac "status" string (input
* argument is modified to point to next field as a side-effect)
*
* args: p - address of remaining portion of string
* sepchar - field terminator character
*/
char *
getfield(p, sepchar)
char **p;
char sepchar;
{
char *savep; /* for saving argument */
savep = *p;
*p = strchr(*p, sepchar);
if (*p == NULL) {
Saferrno = E_SAFERR;
(void) fprintf(stderr, "Improper message from SAC\n");
return(NULL);
}
**p = '\0';
(*p)++;
return(savep);
}
/*
* single_print - print out _sactab if sac not at home (should only happen
* in single user mode
*
* args: p - address of pointer where formatted data should be
* placed (space allocated here)
*/
void
single_print(p)
char **p;
{
FILE *fp; /* file pointer for _sactab */
struct stat statbuf; /* file status info */
register char *tp1; /* scratch pointer */
register char *tp2; /* scratch pointer */
struct sactab stab; /* place to hold parsed info */
register struct sactab *sp = &stab; /* and a pointer to it */
char buf[SIZE]; /* scratch buffer */
fp = fopen(SACTAB, "r");
if (fp == NULL) {
Saferrno = E_SYSERR;
error("Could not open _sactab");
}
if (fstat(fileno(fp), &statbuf) < 0) {
Saferrno = E_SYSERR;
error("could not stat _sactab");
}
/*
* allocate space to build return string, twice file size should be more
* than enough (and make sure it's zero'ed out)
*/
tp1 = calloc(2 * statbuf.st_size, sizeof(char));
if (tp1 == NULL) {
Saferrno = E_SYSERR;
error("could not allocate storage");
}
/*
* read the file and build the string
*/
while (fgets(buf, SIZE, fp)) {
tp2 = trim(buf);
if (*tp2 == '\0')
continue;
parse(tp2, &stab);
(void) sprintf(buf, "%s:%s:%d:%d:%d:%s:%s\n", sp->sc_tag, sp->sc_type,
sp->sc_flags, sp->sc_rsmax, SSTATE, sp->sc_cmd, sp->sc_comment);
(void) strcat(tp1, buf);
free(sp->sc_cmd);
free(sp->sc_comment);
}
if (!feof(fp)) {
Saferrno = E_SYSERR;
error("error reading _sactab");
}
(void) fclose(fp);
/*
* point at the just-built string
*/
*p = tp1;
return;
}
/*
* openpipe - open up command pipe to SAC
*/
openpipe()
{
int fd; /* file descriptor associated with command pipe */
fd = open(CMDPIPE, O_RDWR);
if (fd < 0) {
Saferrno = E_SYSERR;
error(SACERR);
}
/*
* lock pipe to insure serial access, lock will disappear if process dies
*/
if (lockf(fd, F_LOCK, 0) < 0) {
Saferrno = E_SYSERR;
error("unable to lock command pipe");
}
return(fd);
}
/*
* sendcmd - send a command to the SAC
*
* args: ap - pointer to command to send
* info - pointer to return information from the SAC
* tag - tag of port monitor to which the command applies (may
* be NULL)
*/
void
sendcmd(ap, info, tag)
struct admcmd *ap;
char **info;
char *tag;
{
int fd; /* file descriptor of command pipe */
fd = openpipe();
if (write(fd, ap, sizeof(struct admcmd)) < 0) {
Saferrno = E_SYSERR;
error(SACERR);
}
checkresp(fd, info, tag);
/*
* unlock the command pipe - not really necessary since we're about to close
*/
(void) lockf(fd, F_ULOCK, 0);
(void) close(fd);
return;
}
/*
* checkresp - check the SAC's response to our command
*
* args: fd - file descriptor of command pipe
* info - pointer to return and info send along by SAC
* tag - tag of port monitor that the command had been
* for, only used for error reporting
*/
void
checkresp(fd, info, tag)
int fd;
char **info;
char *tag;
{
struct admack ack; /* acknowledgment struct */
register struct admack *ak = &ack; /* and a pointer to it */
pid_t pid; /* my pid */
struct sigaction sigact; /* signal handler setup */
/*
* make sure this ack is meant for me, put an alarm around the read
* so we don't hang out forever.
*/
pid = getpid();
sigact.sa_flags = 0;
sigact.sa_handler = catch;
(void) sigemptyset(&sigact.sa_mask);
(void) sigaddset(&sigact.sa_mask, SIGALRM);
(void) sigaction(SIGALRM, &sigact, NULL);
(void) alarm(10);
do {
if (read(fd, ak, sizeof(ack)) != sizeof(ack)) {
Saferrno = E_SACNOTRUN;
error(SACERR);
}
} while (pid != ak->ak_pid);
(void) alarm(0);
/*
* check out what happened
*/
switch (ak->ak_resp) {
case AK_ACK:
/* everything was A-OK */
if (info && ak->ak_size) {
/* there is return info and a place to put it */
if ((*info = malloc((unsigned) (ak->ak_size + 1))) == NULL) {
Saferrno = E_SYSERR;
error("could not allocate storage");
}
if (read(fd, *info, (unsigned) ak->ak_size) != ak->ak_size) {
Saferrno = E_SYSERR;
error(SACERR);
}
/* make sure "string" is null-terminated */
(*info)[ak->ak_size] = '\0';
}
return;
/* something went wrong - see what */
case AK_PMRUN:
Saferrno = E_PMRUN;
(void) fprintf(stderr, "Port monitor, %s, is already running\n", tag);
break;
case AK_PMNOTRUN:
Saferrno = E_PMNOTRUN;
(void) fprintf(stderr, "Port monitor, %s, is not running\n", tag);
break;
case AK_NOPM:
Saferrno = E_NOEXIST;
(void) fprintf(stderr, "Invalid request, %s does not exist\n", tag);
break;
case AK_UNKNOWN:
Saferrno = E_SAFERR;
(void) fprintf(stderr, "Internal error - sent invalid command\n");
break;
case AK_NOCONTACT:
Saferrno = E_SAFERR;
(void) fprintf(stderr, "Could not contact %s\n", tag);
break;
case AK_PMLOCK:
Saferrno = E_SAFERR;
(void) fprintf(stderr, "Could not start %s - _pid file locked\n", tag);
break;
case AK_RECOVER:
Saferrno = E_RECOVER;
(void) fprintf(stderr, "Port monitor, %s, is in recovery\n", tag);
break;
case AK_REQFAIL:
Saferrno = E_SAFERR;
(void) fprintf(stderr, "This request could not be completed - see sac log file for details\n");
break;
default:
Saferrno = E_SAFERR;
(void) fprintf(stderr, "unknown response\n");
break;
}
}
/*
* catch - catcher for SIGALRM, don't need to do anything
*/
void
catch()
{
}
/*
* pflags - put port monitor 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 & D_FLAG) {
buf[i++] = 'd';
flags &= ~D_FLAG;
}
if (flags & X_FLAG) {
buf[i++] = 'x';
flags &= ~X_FLAG;
}
if (flags) {
(void) fprintf(stderr, "Bad information from SAC\n");
exit(1);
}
buf[i] = '\0';
return(buf);
}
/*
* sac_home - returns true is sac has a lock on its logfile, false
* otherwise (useful to avoid errors for administrative actions in
* single user mode)
*/
sac_home()
{
int fd; /* fd to sac logfile */
fd = open(LOGFILE, O_RDONLY);
if (fd < 0) {
fprintf(stderr, "warning - could not ascertain sac status\n");
return(FALSE);
}
if (lockf(fd, F_TEST, 0) < 0) {
/* everything is ok */
(void) close(fd);
return(TRUE);
}
else {
/* no one home */
(void) close(fd);
return(FALSE);
}
}