Files
Arquivotheca.Solaris-2.5/cmd/backup/operd/monitor/message.c
seta75D 7c4988eac0 Init
2021-10-11 19:38:01 -03:00

566 lines
12 KiB
C
Executable File

/*
* Copyright (c) 1990,1991,1992 by Sun Microsystems, Inc.
*/
#ident "@(#)message.c 1.0 91/01/28 SMI"
#ident "@(#)message.c 1.20 92/03/25"
#include <stdio.h>
#include <ctype.h>
#include <locale.h>
#include <errno.h>
#include <stdlib.h>
#include <unistd.h>
#include <setjmp.h>
#include <string.h>
#include <signal.h>
#include <sys/time.h>
#include <sys/timeb.h>
#include "defs.h"
struct msg_cache *msgcache[NPIDS][NSEQ]; /* message cache */
struct msg_cache timeorder; /* time ordered list */
struct msg_cache *top; /* first displayed message */
struct msg_cache *bottom; /* last displayed message */
int maxcache;
static struct msg_cache *msgfreelist; /* free-list */
static int msgcnt; /* number of allocated messages */
static int incache; /* number of active messages */
jmp_buf resetbuf;
int ready;
#ifdef __STDC__
static void reset(int);
static int cmp_msgid(msg_id *, msg_id *);
static void msg_add(msg_t *);
static struct msg_cache *getmsgbyid(msg_id *);
static int cmp_tag(tag_t, tag_t);
static void msg_rm(struct msg_cache *);
#else
static void reset();
static int cmp_msgid();
static void msg_add();
static struct msg_cache *getmsgbyid();
static int cmp_tag();
static void msg_rm();
#endif
/*ARGSUSED*/
static void
reset(sig)
int sig;
{
if (ready)
longjmp(resetbuf, 1);
status(1, gettext("Connection with server lost, aborting"));
Exit(-1);
}
/*
* Intialize message cache
*/
void
#ifdef __STDC__
msg_init(void)
#else
msg_init()
#endif
{
(void) signal(SIGPIPE, reset);
timeorder.mc_nextrcvd = &timeorder;
timeorder.mc_prevrcvd = &timeorder;
}
/*
* Generate a reply to a message
*/
msg_reply(tag)
tag_t tag; /* tag name */
{
char buf[MAXMSGLEN];
struct msg_cache *mc;
char *program;
int n;
mc = getmsgbytag(tag);
if (mc == NULL) {
bell();
status(1, "%s%s\n%s",
gettext("Message response rejected: "),
gettext("That message does not exist."),
gettext(
"You may only respond to messages marked (*) or (?)."));
return (-1);
}
if ((mc->mc_status & GOTACK) || (mc->mc_status & GOTNACK)) {
bell();
status(1, "%s%s\n%s",
gettext("Message response rejected: "),
gettext(
"A response to that message has already been received."),
gettext(
"You may only respond to messages marked (*) or (?)."));
return (-1);
}
scr_reverse(mc);
program = mc->mc_msg.msg_progname;
mainprompt = 0;
prompt("%s[%d]@%s> ",
program == NULL || *program == '\0' ? gettext("unnamed") : program,
mc->mc_msg.msg_ident.mid_pid, mc->mc_msg.msg_ident.mid_host);
buf[0] = '\0';
current_input = buf;
cgets(buf, sizeof (buf));
current_input = NULL;
scr_reverse(mc);
if (buf[0] == '\0') { /* abort response */
bell();
status(1, gettext("Message response aborted"));
} else {
n = oper_reply(mc->mc_msg.msg_arbiter,
&mc->mc_msg.msg_ident, buf);
if (n == 0) {
bell();
status(1, "%s%s\n%s",
gettext("Message response rejected: "),
gettext("Could not forward your response."),
gettext(
"You may only respond to messages marked (*) or (?)."));
}
mc->mc_status |= SENTREPLY;
}
return (n == 0 ? -1 : n);
}
/*
* Format a message for printing. Modifies
* nlines to reflect the number of lines
* of display required. Replaces the original
* message's length and data.
*/
void
msg_format(mc, linelen, indent)
struct msg_cache *mc;
int linelen; /* length of text line */
int indent; /* indentation for FIRST line */
{
msg_t *msgp = &mc->mc_msg;
struct tm *mtm;
char msgbuf[1024];
register char *cp, *dp;
register int i;
int thisline; /* length of current line */
int len; /* length of formatted message text */
int inspace = 0; /* currently in white space */
if (mc->mc_status & FORMAT)
return; /* already re-formatted */
mc->mc_nlines = 1;
mtm = localtime(&msgp->msg_time);
(void) strftime(msgbuf, sizeof (msgbuf), gettext(MSGDATEFMT), mtm);
cp = &msgbuf[strlen(msgbuf)];
(void) sprintf(cp, " %s@%s: ",
msgp->msg_progname[0] ? msgp->msg_progname : gettext("unnamed"),
msgp->msg_ident.mid_host);
cp = strrchr(msgbuf, ' ');
len = ++cp - msgbuf;
thisline = linelen - indent;
/*
* Fit the message text onto as many lines
* as needed by breaking on word boundaries.
* All contiguous white space is treated as
* a single blank.
*/
for (i = 0, dp = msgp->msg_data; i < msgp->msg_len; i++) {
register char *wp; /* pointer within a word */
int lpw; /* letters this word */
if (isspace((u_char)*dp)) {
++dp;
if (!inspace) {
inspace++;
if (++len > thisline) {
len = 0;
mc->mc_nlines++;
thisline = linelen - TABCOLS;
} else
*cp++ = ' ';
}
continue;
}
inspace = 0;
for (wp = dp, lpw = 0; *wp && !isspace((u_char)*wp); wp++)
lpw++;
if (len + lpw > thisline) {
for (; len < thisline; len++)
*cp++ = ' '; /* pad to eol */
len = 0;
mc->mc_nlines++;
thisline = linelen - TABCOLS;
}
(void) strncpy(cp, dp, lpw);
cp += lpw;
dp += lpw;
len += lpw;
}
*cp = '\0';
/*
* We may have to extend the data portion
* of the message to make room for the
* additional status info and padding
* we added to the original text.
*/
len = strlen(msgbuf)+1;
if (len > MAXMSGLEN) {
mc = (struct msg_cache *)realloc((char *)mc,
(unsigned)(sizeof (struct msg_cache)+(len - MAXMSGLEN)));
if (mc == NULL) {
bell();
status(0, "realloc: %s", strerror(errno));
Exit(-1);
}
}
(void) strcpy(mc->mc_msg.msg_data, msgbuf);
mc->mc_msg.msg_len = len;
mc->mc_status |= FORMAT;
}
/*
* Apply filters to a message. Return 1
* if message passes filter parameters,
* 0 otherwise.
*/
msg_filter(mc)
struct msg_cache *mc;
{
msg_t *msgp = &mc->mc_msg;
if (mc->mc_status & EXPIRED)
return (0);
if ((msgp->msg_type & MSG_DISPLAY) == 0)
return (0);
if (current_filter && (mreg_exec(msgp->msg_data) != 1))
return (0);
return (1);
}
/*
* Dispatch to appropriate message
* processing function
*/
void
msg_dispatch(msgp)
msg_t *msgp;
{
struct msg_cache *target;
if (HASTARGET(msgp->msg_type)) {
target = getmsgbyid(&msgp->msg_target);
if (target == NULL) {
#ifdef DEBUG
/* XGETTEXT: #ifdef DEBUG only */
status(1, gettext(
"Target for %x (%d from %d on %s) not found"),
msgp->msg_type,
msgp->msg_target.mid_seq,
msgp->msg_target.mid_pid,
msgp->msg_target.mid_host);
#endif
return;
}
if (msgp->msg_type & MSG_ACK) {
target->mc_status |= GOTACK;
} else if (msgp->msg_type & MSG_NACK) {
target->mc_status |= GOTNACK;
status(1, "%s%s",
gettext("Message response rejected: "),
gettext(
"A response to that message has already been received."));
} else if (msgp->msg_type & MSG_NOTOP) {
target->mc_status |= GOTNACK;
status(1, gettext(
"%sYou are not an operator on system '%s'."),
gettext("Message response rejected: "),
target->mc_msg.msg_ident.mid_host);
} else if (msgp->msg_type & MSG_CANCEL) {
msg_rm(target);
if (!suspend)
scr_topdown(0);
}
resetprompt();
scr_redraw(0);
} else
msg_add(msgp);
}
/*
* Add a message to the cache
*/
static void
msg_add(msgp)
msg_t *msgp;
{
struct msg_cache *mc, **bucket;
time_t h;
if (getmsgbyid(&msgp->msg_ident)) { /* duplicate */
#ifdef DEBUG
/* XGETTEXT: #ifdef DEBUG only */
status(1, gettext("Duplicate message %d@%s[%d] received"),
msgp->msg_ident.mid_seq,
msgp->msg_ident.mid_host,
msgp->msg_ident.mid_pid);
#endif
return;
}
/*
* There are three places we can obtain storage:
* - the free list of cancelled/expired messages
* - dynamic memory allocation
* - the oldest active message
* The oldest active message is only used if the
* number of cached messages is equal or greater
* than the specified maximum.
*/
if (msgfreelist) {
mc = msgfreelist;
msgfreelist = msgfreelist->mc_nextrcvd;
if (msgfreelist == &timeorder)
msgfreelist = NULL;
} else if (maxcache == 0 || msgcnt < maxcache) {
msgcnt++;
mc = (struct msg_cache *)
malloc((unsigned)sizeof (struct msg_cache));
if (mc == NULL) {
bell();
status(0, "malloc: %s", strerror(errno));
Exit(-1);
}
} else {
for (mc = timeorder.mc_nextrcvd;
mc != &timeorder; mc = mc->mc_nextrcvd)
if ((mc->mc_status & DISPLAY) == 0)
break;
if (mc == &timeorder) {
status(0, gettext(
"PANIC: cannot allocate space for incoming message!"));
Exit(-1);
}
/*
* remove from time-ordered list
*/
mc->mc_nextrcvd->mc_prevrcvd = mc->mc_prevrcvd;
mc->mc_prevrcvd->mc_nextrcvd = mc->mc_nextrcvd;
/*
* remove from hash bucket
*/
if (mc->mc_prevhash)
mc->mc_prevhash->mc_nexthash = mc->mc_nexthash;
if (mc->mc_nexthash)
mc->mc_nexthash->mc_prevhash = mc->mc_prevhash;
bucket = &HASHMSG(&msgp->msg_ident);
if (*bucket)
*bucket = NULL;
incache--;
}
incache++;
mc->mc_msg = *msgp;
(void) time(&mc->mc_rcvd);
mc->mc_nlines = 0;
mc->mc_status = 0;
mc->mc_tag = NOTAG;
if (mc->mc_msg.msg_type & MSG_NEEDREPLY)
mc->mc_status |= NEEDREPLY;
/*
* Add to cache at beginning of appropriate bucket
*/
bucket = &HASHMSG(&msgp->msg_ident);
if (*bucket == NULL) {
mc->mc_nexthash = NULL;
mc->mc_prevhash = NULL;
*bucket = mc;
} else {
mc->mc_nexthash = (*bucket)->mc_nexthash;
mc->mc_prevhash = *bucket;
(*bucket)->mc_nexthash = mc;
}
/*
* Add to time-ordered receipt list
*/
h = scr_hold(0);
mc->mc_nextrcvd = &timeorder;
mc->mc_prevrcvd = timeorder.mc_prevrcvd;
timeorder.mc_prevrcvd->mc_nextrcvd = mc;
timeorder.mc_prevrcvd = mc;
scr_release(h);
scr_add(mc);
}
/*
* Locate a message in the cache
*/
static struct msg_cache *
getmsgbyid(id)
msg_id *id;
{
register struct msg_cache *mc;
struct msg_cache **bucket = &HASHMSG(id);
if (*bucket == NULL)
return (NULL);
for (mc = *bucket; mc; mc = mc->mc_nexthash)
if (cmp_msgid(id, &mc->mc_msg.msg_ident) == 0)
break;
return (mc);
}
struct msg_cache *
getmsgbytag(tag)
tag_t tag;
{
register struct msg_cache *mc;
if (!top || !bottom)
return (NULL);
for (mc = top; mc != bottom->mc_nextrcvd; mc = mc->mc_nextrcvd)
if (cmp_tag(mc->mc_tag, tag) == 0)
break;
return (mc != bottom->mc_nextrcvd ? mc : NULL);
}
static int
cmp_msgid(id1, id2)
msg_id *id1, *id2;
{
if (id1->mid_pid != id2->mid_pid)
return (1);
if (id1->mid_seq != id2->mid_seq)
return (1);
if (strcmp(id1->mid_host, id2->mid_host))
return (1);
return (0);
}
static int
cmp_tag(tag1, tag2)
tag_t tag1, tag2;
{
if (tag1 == tag2)
return (0);
if (tag1 < tag2)
return (-1);
return (1);
}
/*
* Make a pass through all cached messages and throw away
* those that have expired. This occurs every 60 seconds.
*/
void
#ifdef __STDC__
expire_all(void)
#else
expire_all()
#endif
{
register struct msg_cache *mc, *next;
register msg_t *msgp;
#ifdef DEBUG
if (screen_hold || suspend)
/* XGETTEXT: #ifdef DEBUG only */
status(1,
gettext("%s: marking expired messages"), "expire_all");
else
/* XGETTEXT: #ifdef DEBUG only */
status(1,
gettext("%s: removing expired messages"), "expire_all");
#endif
#ifdef lint
next = &timeorder;
#endif
for (mc = timeorder.mc_nextrcvd; mc != &timeorder; mc = next) {
next = mc->mc_nextrcvd;
msgp = &mc->mc_msg;
if (msgp->msg_ttl &&
current_time >= (mc->mc_rcvd + msgp->msg_ttl))
msg_rm(mc);
}
if (!screen_hold && !suspend) {
scr_topdown(0);
resetprompt();
scr_redraw(0);
}
}
/*
* Delete a message from the cache
*/
static void
msg_rm(mc)
struct msg_cache *mc;
{
struct msg_cache **bucket;
time_t h;
mc->mc_status |= EXPIRED;
if ((screen_hold || suspend) && (mc->mc_status & DISPLAY))
return;
h = scr_hold(0);
scr_adjust(mc);
/*
* remove from time-ordered list
*/
mc->mc_nextrcvd->mc_prevrcvd = mc->mc_prevrcvd;
mc->mc_prevrcvd->mc_nextrcvd = mc->mc_nextrcvd;
/*
* remove from active cache
*/
if (mc->mc_prevhash)
mc->mc_prevhash->mc_nexthash = mc->mc_nexthash;
if (mc->mc_nexthash)
mc->mc_nexthash->mc_prevhash = mc->mc_prevhash;
bucket = &HASHMSG(&mc->mc_msg.msg_ident);
if (*bucket == mc)
*bucket = NULL;
/*
* add to free list
*/
mc->mc_nextrcvd = msgfreelist;
mc->mc_prevrcvd = NULL;
msgfreelist = mc;
incache--;
scr_release(h);
}
/*
* Remove all messages from the cache
*/
void
#ifdef __STDC__
msg_reset(void)
#else
msg_reset()
#endif
{
time_t h = scr_hold(0);
(void) memset((char *)msgcache, 0, sizeof (msgcache));
msgfreelist = timeorder.mc_nextrcvd;
if (msgfreelist == &timeorder)
msgfreelist = NULL;
timeorder.mc_nextrcvd = &timeorder;
timeorder.mc_prevrcvd = &timeorder;
msgs_above = msgs_below = 0;
top = bottom = NULL;
incache = 0;
scr_release(h);
}