594 lines
12 KiB
C
594 lines
12 KiB
C
/* Copyright (c) 1990, 1991 UNIX System Laboratories, Inc. */
|
|
/* Copyright (c) 1984, 1986, 1987, 1988, 1989, 1990 AT&T */
|
|
/* All Rights Reserved */
|
|
|
|
/* THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF */
|
|
/* UNIX System Laboratories, Inc. */
|
|
/* The copyright notice above does not evidence any */
|
|
/* actual or intended publication of such source code. */
|
|
|
|
# ident "@(#)saf:misc.c 1.10.4.1"
|
|
|
|
# include <stdio.h>
|
|
# include <unistd.h>
|
|
# include <fcntl.h>
|
|
# include <sys/types.h>
|
|
# include <signal.h>
|
|
# include <sys/stat.h>
|
|
# include <poll.h>
|
|
# include "misc.h"
|
|
# include "msgs.h"
|
|
# include "extern.h"
|
|
# include <sac.h>
|
|
# include "adm.h"
|
|
# include "structs.h"
|
|
|
|
|
|
/*
|
|
* findpm - find a port monitor entry
|
|
*
|
|
* args: tag - tag of desired port monitor
|
|
*/
|
|
|
|
|
|
struct sactab *
|
|
findpm(tag)
|
|
register char *tag;
|
|
{
|
|
register struct sactab *sp; /* working pointer */
|
|
|
|
for (sp = Sactab; sp; sp = sp->sc_next) {
|
|
if (!strcmp(tag, sp->sc_tag))
|
|
return(sp);
|
|
}
|
|
return(NULL);
|
|
}
|
|
|
|
|
|
/*
|
|
* Procedure: sigpoll
|
|
*
|
|
* Restrictions:
|
|
write(2): None
|
|
|
|
* Notes - handle messages coming in on the command pipe (SIGPOLL signal
|
|
* handler)
|
|
*/
|
|
|
|
|
|
void
|
|
sigpoll()
|
|
{
|
|
struct pollfd fds; /* array of fds to poll */
|
|
struct admcmd cmd; /* incoming command */
|
|
register struct admcmd *ap = &cmd; /* and a pointer to it */
|
|
struct admack ack; /* acknowledgment */
|
|
register struct admack *ak = &ack; /* and a pointer to it */
|
|
register struct sactab *sp; /* working pointer */
|
|
struct sacmsg sacmsg; /* message to port monitor */
|
|
char **data; /* "dumped" sactab */
|
|
char *p; /* scratch pointer */
|
|
register int i; /* loop control variable */
|
|
int ret; /* return value */
|
|
sigset_t cset; /* for signal handling */
|
|
sigset_t tset; /* for signal handling */
|
|
|
|
# ifdef DEBUG
|
|
debug("in sigpoll");
|
|
# endif
|
|
fds.fd = Cfd;
|
|
fds.events = POLLIN;
|
|
fds.revents = 0;
|
|
if (poll(&fds, 1, 0) < 0)
|
|
error(E_POLL, EXIT);
|
|
switch (fds.revents) {
|
|
case POLLIN:
|
|
if (read(Cfd, ap, sizeof(struct admcmd)) < 0) {
|
|
error(E_READ, EXIT);
|
|
}
|
|
switch (ap->ac_mtype) {
|
|
|
|
/*
|
|
* request to start a port monitor
|
|
*/
|
|
|
|
case AC_START:
|
|
# ifdef DEBUG
|
|
(void) sprintf(Scratch, "Got AC_START for <%s>", ap->ac_tag);
|
|
log(Scratch);
|
|
# endif
|
|
if ((sp = findpm(ap->ac_tag)) == NULL) {
|
|
ak->ak_pid = ap->ac_pid;
|
|
ak->ak_resp = AK_NOPM;
|
|
ak->ak_size = 0;
|
|
sendack(ak);
|
|
break;
|
|
}
|
|
switch (sp->sc_sstate) {
|
|
case UNKNOWN:
|
|
ak->ak_pid = ap->ac_pid;
|
|
ak->ak_resp = AK_RECOVER;
|
|
ak->ak_size = 0;
|
|
sendack(ak);
|
|
break;
|
|
case FAILED:
|
|
case NOTRUNNING:
|
|
sp->sc_rscnt = 0; /* fresh start in life */
|
|
if (ret = startpm(sp)) {
|
|
ak->ak_pid = ap->ac_pid;
|
|
if (ret == -1)
|
|
ak->ak_resp = AK_PMLOCK;
|
|
else
|
|
ak->ak_resp = AK_REQFAIL;
|
|
ak->ak_size = 0;
|
|
sendack(ak);
|
|
break;
|
|
}
|
|
ak->ak_pid = ap->ac_pid;
|
|
ak->ak_resp = AK_ACK;
|
|
ak->ak_size = 0;
|
|
sendack(ak);
|
|
break;
|
|
case ENABLED:
|
|
case DISABLED:
|
|
case STARTING:
|
|
case STOPPING:
|
|
ak->ak_pid = ap->ac_pid;
|
|
ak->ak_resp = AK_PMRUN;
|
|
ak->ak_size = 0;
|
|
sendack(ak);
|
|
break;
|
|
}
|
|
break;
|
|
|
|
/*
|
|
* request to kill a port monitor
|
|
*/
|
|
|
|
case AC_KILL:
|
|
# ifdef DEBUG
|
|
(void) sprintf(Scratch, "Got AC_KILL for <%s>", ap->ac_tag);
|
|
log(Scratch);
|
|
# endif
|
|
if ((sp = findpm(ap->ac_tag)) == NULL) {
|
|
ak->ak_pid = ap->ac_pid;
|
|
ak->ak_resp = AK_NOPM;
|
|
ak->ak_size = 0;
|
|
sendack(ak);
|
|
break;
|
|
}
|
|
switch (sp->sc_sstate) {
|
|
case UNKNOWN:
|
|
ak->ak_pid = ap->ac_pid;
|
|
ak->ak_resp = AK_RECOVER;
|
|
ak->ak_size = 0;
|
|
sendack(ak);
|
|
break;
|
|
case NOTRUNNING:
|
|
case FAILED:
|
|
case STOPPING:
|
|
ak->ak_pid = ap->ac_pid;
|
|
ak->ak_resp = AK_PMNOTRUN;
|
|
ak->ak_size = 0;
|
|
sendack(ak);
|
|
break;
|
|
case STARTING:
|
|
case ENABLED:
|
|
case DISABLED:
|
|
(void) sigprocmask(SIG_SETMASK, NULL, &cset);
|
|
tset = cset;
|
|
(void) sigaddset(&tset, SIGALRM);
|
|
(void) sigaddset(&tset, SIGCLD);
|
|
(void) sigprocmask(SIG_SETMASK, &tset, NULL);
|
|
if (sendsig(sp, SIGTERM)) {
|
|
(void) sprintf(Scratch, "could not send SIGTERM to <%s>", sp->sc_tag);
|
|
log(Scratch);
|
|
ak->ak_pid = ap->ac_pid;
|
|
ak->ak_resp = AK_NOCONTACT;
|
|
ak->ak_size = 0;
|
|
sendack(ak);
|
|
(void) sigprocmask(SIG_SETMASK, &cset, NULL);
|
|
break;
|
|
}
|
|
/* signal sent ok */
|
|
sp->sc_lstate = NOTRUNNING;
|
|
sp->sc_sstate = NOTRUNNING;
|
|
sp->sc_pstate = STOPPING;
|
|
ak->ak_pid = ap->ac_pid;
|
|
ak->ak_resp = AK_ACK;
|
|
ak->ak_size = 0;
|
|
sendack(ak);
|
|
(void) sprintf(Scratch, "terminating <%s>", sp->sc_tag);
|
|
log(Scratch);
|
|
(void) sigprocmask(SIG_SETMASK, &cset, NULL);
|
|
break;
|
|
}
|
|
break;
|
|
|
|
/*
|
|
* request to enable a port monitor
|
|
*/
|
|
|
|
case AC_ENABLE:
|
|
# ifdef DEBUG
|
|
(void) sprintf(Scratch, "Got AC_ENABLE for <%s>", ap->ac_tag);
|
|
log(Scratch);
|
|
# endif
|
|
if ((sp = findpm(ap->ac_tag)) == NULL) {
|
|
ak->ak_pid = ap->ac_pid;
|
|
ak->ak_resp = AK_NOPM;
|
|
ak->ak_size = 0;
|
|
sendack(ak);
|
|
break;
|
|
}
|
|
switch (sp->sc_sstate) {
|
|
case UNKNOWN:
|
|
ak->ak_pid = ap->ac_pid;
|
|
ak->ak_resp = AK_RECOVER;
|
|
ak->ak_size = 0;
|
|
sendack(ak);
|
|
break;
|
|
case NOTRUNNING:
|
|
case FAILED:
|
|
case STOPPING:
|
|
ak->ak_pid = ap->ac_pid;
|
|
ak->ak_resp = AK_PMNOTRUN;
|
|
ak->ak_size = 0;
|
|
sendack(ak);
|
|
break;
|
|
case STARTING:
|
|
case DISABLED:
|
|
sacmsg.sc_type = SC_ENABLE;
|
|
sacmsg.sc_size = 0;
|
|
sp->sc_sstate = ENABLED;
|
|
sp->sc_lstate = ENABLED;
|
|
sendpmmsg(sp, &sacmsg);
|
|
ak->ak_pid = ap->ac_pid;
|
|
ak->ak_resp = AK_ACK;
|
|
ak->ak_size = 0;
|
|
sendack(ak);
|
|
break;
|
|
case ENABLED:
|
|
ak->ak_pid = ap->ac_pid;
|
|
ak->ak_resp = AK_ACK;
|
|
ak->ak_size = 0;
|
|
sendack(ak);
|
|
break;
|
|
}
|
|
break;
|
|
|
|
/*
|
|
* request to disable a port monitor
|
|
*/
|
|
|
|
case AC_DISABLE:
|
|
# ifdef DEBUG
|
|
(void) sprintf(Scratch, "Got AC_DISABLE for <%s>", ap->ac_tag);
|
|
log(Scratch);
|
|
# endif
|
|
if ((sp = findpm(ap->ac_tag)) == NULL) {
|
|
ak->ak_pid = ap->ac_pid;
|
|
ak->ak_resp = AK_NOPM;
|
|
ak->ak_size = 0;
|
|
sendack(ak);
|
|
break;
|
|
}
|
|
switch (sp->sc_sstate) {
|
|
case UNKNOWN:
|
|
ak->ak_pid = ap->ac_pid;
|
|
ak->ak_resp = AK_RECOVER;
|
|
ak->ak_size = 0;
|
|
sendack(ak);
|
|
break;
|
|
case NOTRUNNING:
|
|
case FAILED:
|
|
case STOPPING:
|
|
ak->ak_pid = ap->ac_pid;
|
|
ak->ak_resp = AK_PMNOTRUN;
|
|
ak->ak_size = 0;
|
|
sendack(ak);
|
|
break;
|
|
case STARTING:
|
|
case ENABLED:
|
|
sacmsg.sc_type = SC_DISABLE;
|
|
sacmsg.sc_size = 0;
|
|
sp->sc_sstate = DISABLED;
|
|
sp->sc_lstate = DISABLED;
|
|
sendpmmsg(sp, &sacmsg);
|
|
ak->ak_pid = ap->ac_pid;
|
|
ak->ak_resp = AK_ACK;
|
|
ak->ak_size = 0;
|
|
sendack(ak);
|
|
break;
|
|
case DISABLED:
|
|
ak->ak_pid = ap->ac_pid;
|
|
ak->ak_resp = AK_ACK;
|
|
ak->ak_size = 0;
|
|
sendack(ak);
|
|
break;
|
|
}
|
|
break;
|
|
|
|
/*
|
|
* request for port monitor status information
|
|
*/
|
|
|
|
case AC_STATUS:
|
|
# ifdef DEBUG
|
|
log("Got AC_STATUS");
|
|
# endif
|
|
/* get all the info in one convenient place */
|
|
data = dump_table();
|
|
if ((data == NULL) && (Nentries > 0)) {
|
|
/* something bad happened in dump_table */
|
|
ak->ak_pid = ap->ac_pid;
|
|
ak->ak_resp = AK_REQFAIL;
|
|
ak->ak_size = 0;
|
|
sendack(ak);
|
|
break;
|
|
}
|
|
/* count how big it is */
|
|
ak->ak_size = 0;
|
|
for (i = 0; i < Nentries; ++i)
|
|
ak->ak_size += strlen(data[i]);
|
|
# ifdef DEBUG
|
|
(void) sprintf(Scratch, "ak_size is %d", ak->ak_size);
|
|
debug(Scratch);
|
|
# endif
|
|
/* get a contiguous chunk */
|
|
if ((p = malloc((unsigned) (ak->ak_size + 1))) == NULL) {
|
|
error(E_MALLOC, CONT);
|
|
for (i = 0; i < Nentries; ++i)
|
|
free(data[i]);
|
|
free((char *) data);
|
|
ak->ak_pid = ap->ac_pid;
|
|
ak->ak_resp = AK_REQFAIL;
|
|
ak->ak_size = 0;
|
|
sendack(ak);
|
|
break;
|
|
}
|
|
/* condense the data into the contiguous chunk */
|
|
*p = '\0';
|
|
for (i = 0; i < Nentries; ++i) {
|
|
(void) strcat(p, data[i]);
|
|
free(data[i]);
|
|
}
|
|
# ifdef DEBUG
|
|
debug(p);
|
|
# endif
|
|
if (data)
|
|
free((char *) data);
|
|
/* ak->ak_size was set above */
|
|
ak->ak_pid = ap->ac_pid;
|
|
ak->ak_resp = AK_ACK;
|
|
sendack(ak);
|
|
if (ak->ak_size)
|
|
if (write(Cfd, p, (unsigned) ak->ak_size) != ak->ak_size)
|
|
log("could not send info");
|
|
free(p);
|
|
break;
|
|
|
|
/*
|
|
* request for sac to read sactab
|
|
*/
|
|
|
|
case AC_SACREAD:
|
|
# ifdef DEBUG
|
|
log("Got AC_SACREAD");
|
|
# endif
|
|
ak->ak_pid = ap->ac_pid;
|
|
ak->ak_resp = AK_ACK;
|
|
ak->ak_size = 0;
|
|
read_table(TRUE);
|
|
sendack(ak);
|
|
break;
|
|
|
|
/*
|
|
* request for port monitor to read _pmtab
|
|
*/
|
|
|
|
case AC_PMREAD:
|
|
# ifdef DEBUG
|
|
(void) sprintf(Scratch, "Got AC_PMREAD for <%s>", ap->ac_tag);
|
|
log(Scratch);
|
|
# endif
|
|
if ((sp = findpm(ap->ac_tag)) == NULL) {
|
|
ak->ak_pid = ap->ac_pid;
|
|
ak->ak_resp = AK_NOPM;
|
|
ak->ak_size = 0;
|
|
sendack(ak);
|
|
break;
|
|
}
|
|
switch (sp->sc_sstate) {
|
|
case UNKNOWN:
|
|
ak->ak_pid = ap->ac_pid;
|
|
ak->ak_resp = AK_RECOVER;
|
|
ak->ak_size = 0;
|
|
sendack(ak);
|
|
break;
|
|
case NOTRUNNING:
|
|
case FAILED:
|
|
case STOPPING:
|
|
ak->ak_pid = ap->ac_pid;
|
|
ak->ak_resp = AK_PMNOTRUN;
|
|
ak->ak_size = 0;
|
|
sendack(ak);
|
|
break;
|
|
case STARTING:
|
|
case ENABLED:
|
|
case DISABLED:
|
|
sacmsg.sc_type = SC_READDB;
|
|
sacmsg.sc_size = 0;
|
|
sendpmmsg(sp, &sacmsg);
|
|
ak->ak_pid = ap->ac_pid;
|
|
ak->ak_resp = AK_ACK;
|
|
ak->ak_size = 0;
|
|
sendack(ak);
|
|
break;
|
|
}
|
|
break;
|
|
/*
|
|
* garbled message
|
|
*/
|
|
|
|
default:
|
|
(void) sprintf(Scratch, "Got unknown message for <%s>", ap->ac_tag);
|
|
log(Scratch);
|
|
ak->ak_pid = ap->ac_pid;
|
|
ak->ak_resp = AK_UNKNOWN;
|
|
ak->ak_size = 0;
|
|
sendack(ak);
|
|
break;
|
|
}
|
|
break;
|
|
default:
|
|
error(E_POLL, EXIT);
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
* Procedure: sendack
|
|
*
|
|
* Restrictions:
|
|
write(2): None
|
|
*
|
|
* Notes - send a response to the administrative command
|
|
*
|
|
* args: ap - pointer to acknowlegment message
|
|
*/
|
|
|
|
void
|
|
sendack(ap)
|
|
struct admack *ap;
|
|
{
|
|
# ifdef DEBUG
|
|
debug("in sendack");
|
|
# endif
|
|
if (write(Cfd, ap, sizeof(struct admack)) != sizeof(struct admack))
|
|
log("Could not send ack");
|
|
}
|
|
|
|
|
|
/*
|
|
* Procedure: sendpmmsg
|
|
*
|
|
* Restrictions:
|
|
write(2): None
|
|
*/
|
|
/*
|
|
* Notes - send a message to a PM. Note: sc_size is always 0 in
|
|
* this version so just send the header.
|
|
*
|
|
* args: sp - pointer to sac's port monitor information for
|
|
* designated port monitor
|
|
* sm - pointer to message to send
|
|
*/
|
|
|
|
void
|
|
sendpmmsg(sp, sm)
|
|
register struct sactab *sp;
|
|
register struct sacmsg *sm;
|
|
{
|
|
char buf[SIZE]; /* scratch buffer */
|
|
|
|
# ifdef DEBUG
|
|
debug("in sendpmmsg");
|
|
# endif
|
|
if (write(sp->sc_fd, sm, sizeof(struct sacmsg)) != sizeof(struct sacmsg)) {
|
|
(void) sprintf(buf, "message to <%s> failed", sp->sc_tag);
|
|
log(buf);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Procedure: sendsig
|
|
*
|
|
* Restrictions:
|
|
kill(2): none
|
|
* Notes:
|
|
* sendsig - send a signal to the port monitor
|
|
*
|
|
* args: sp - pointer to sac's port monitor infomation for
|
|
* designated port monitor
|
|
* signo - signal number to send
|
|
*/
|
|
|
|
|
|
sendsig(sp, signo)
|
|
register struct sactab *sp;
|
|
int signo;
|
|
{
|
|
pid_t pid; /* pid of designated port monitor */
|
|
pid_t checklock();
|
|
|
|
# ifdef DEBUG
|
|
(void) sprintf(Scratch, "in sendsig - sending signo %d to %s", signo, sp->sc_tag);
|
|
debug(Scratch);
|
|
# endif
|
|
if (pid = checklock(sp)) {
|
|
if (kill(pid, signo) < 0) {
|
|
# ifdef DEBUG
|
|
debug("in sendsig - kill failed");
|
|
# endif
|
|
return(-1);
|
|
}
|
|
else
|
|
return(0);
|
|
}
|
|
else {
|
|
# ifdef DEBUG
|
|
debug("in sendsig - checklock failed");
|
|
# endif
|
|
return(-1);
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
* Procedure: checklock
|
|
*
|
|
* Restrictions:
|
|
sprintf: None
|
|
open(2): None
|
|
lockf: None
|
|
*
|
|
* Notes - check to see if a _pid file is locked
|
|
* if so, return pid in file, else 0
|
|
*
|
|
* args: sp - pointer to sac's port monitor infomation for
|
|
* designated port monitor
|
|
*/
|
|
|
|
pid_t
|
|
checklock(sp)
|
|
register struct sactab *sp;
|
|
{
|
|
int fd; /* scratch file descriptor */
|
|
char buf[SIZE]; /* scratch buffer */
|
|
int ret; /* return value */
|
|
|
|
# ifdef DEBUG
|
|
debug("in checklock");
|
|
# endif
|
|
(void) sprintf(Scratch, "%s/%s/_pid", HOME, sp->sc_tag);
|
|
fd = open(Scratch, O_RDONLY);
|
|
if (fd < 0) {
|
|
(void) sprintf(Scratch, "can not open _pid file for <%s>", sp->sc_tag);
|
|
log(Scratch);
|
|
return((pid_t)0);
|
|
}
|
|
if (lockf(fd, F_TEST, 0) < 0) {
|
|
if ((ret = read(fd, buf, SIZE - 1)) < 0) {
|
|
(void) close(fd);
|
|
return((pid_t)0);
|
|
}
|
|
(void) close(fd);
|
|
/* in case pid wasn't null-terminated */
|
|
buf[ret] = '\0';
|
|
return((pid_t)atol(buf));
|
|
}
|
|
(void) close(fd);
|
|
return((pid_t)0);
|
|
}
|