From 0cc9b20c15460213e488bf5e70963b941482f628 Mon Sep 17 00:00:00 2001 From: William Harrington Date: Tue, 14 Jan 2025 16:06:02 -0600 Subject: Add source. --- utils/Makefile.in | 31 ++++ utils/README | 9 ++ utils/down.8 | 44 ++++++ utils/down.c | 129 ++++++++++++++++ utils/say.1 | 35 +++++ utils/say.c | 34 +++++ utils/vmon.8 | 65 ++++++++ utils/vmon.c | 442 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 8 files changed, 789 insertions(+) create mode 100644 utils/Makefile.in create mode 100644 utils/README create mode 100644 utils/down.8 create mode 100644 utils/down.c create mode 100644 utils/say.1 create mode 100644 utils/say.c create mode 100644 utils/vmon.8 create mode 100644 utils/vmon.c (limited to 'utils') diff --git a/utils/Makefile.in b/utils/Makefile.in new file mode 100644 index 0000000..8ff750c --- /dev/null +++ b/utils/Makefile.in @@ -0,0 +1,31 @@ +# +# Template to build speak utilities. +# $Id: Makefile.in 1.2 Mon, 24 Mar 1997 12:25:37 -0500 dyfet $ +# Copyright (c) 1997 by Tycho Softworks. +# + +UPROGS = say +SPROGS = down vmon +PROGS = $(SPROGS) $(UPROGS) + +all: $(PROGS) + +install: $(PROGS) + install -s -g bin $(UPROGS) $(BINDIR) + install -s -g bin $(SPROGS) $(SBINDIR) + ln -sf $(SBINDIR)/vmon $(SBINDIR)/vstat + ../sdk/bin/instman $(MANDIR) 1 say + ../sdk/bin/instman $(MANDIR) 8 down vmon + +clean: + rm $(PROGS) + +say: say.c + $(CC) $(CFLAGS) $(OPTIMIZE) -I../sdk -L../sdk/lib -o $@ say.c $(LIBS) + +down: down.c + $(CC) $(CFLAGS) $(OPTIMIZE) -I../sdk -L../sdk/lib -o $@ down.c $(LIBS) + +vmon: vmon.c + $(CC) $(CFLAGS) $(OPTIMIZE) -I../sdk -L../sdk/lib -o $@ vmon.c $(LIBS) + diff --git a/utils/README b/utils/README new file mode 100644 index 0000000..66d3435 --- /dev/null +++ b/utils/README @@ -0,0 +1,9 @@ +This section includes portable 'speak' service based utilities. These +utilities are being ported from the original WorldVU SPO speak services. So +far, only "say", "down", and "vmon" have been ported. Additional +utilities to be added will include a new non-WorldVU related user session +announcement daemon, perhaps as part of vmon. The original user session +monitoring utility was closely tied into the WorldVU user cluster +monitoring system. + + diff --git a/utils/down.8 b/utils/down.8 new file mode 100644 index 0000000..fe0b81d --- /dev/null +++ b/utils/down.8 @@ -0,0 +1,44 @@ +.TH "down" "8" "January 1997" "Speak 0.2" "Text-to-Speech" +.PP +.SH NAME +.PP +\fBdown\fP - warn and then shutdown system. +.PP +.SH SYNOPSIS +.PP +\fBdown\fP [\fIseconds\fP] +.PP +.SH DESCRIPTION +.PP +The Text-to-speech package introduces a standard TCP/IP port service for +attaching text-to-speech resources to your network. These resources can +be used to monitor system status, provide verbal alarms, etc. This network +service may be accessed by telnetting to a machine running a "speak" server, +or by using the various application utilities, such as \fBdown\fP. +.PP + +The \fBdown\fP program will provide a warning with a countdown that may +be aborted. When the countdown reaches 0, your system will begin a normal +shutdown and reboot. The warning and countdown is shown on screen and +spoken over the text-to-speech interface. The \fBdown\fP program uses the +[\fIdown\fP] information in \fBspeak.conf\fP for default values. Only an +alternate countdown (in seconds) may be specified via a command line +argument. + +.PP +The [\fIdown\fP] section specifies a default timer to use, the hostname +where the speech server is running, and the program to execute to bring +the system down. If you are using \fBdown\fP on a machine that does not +have it's own text-to-speech server, then you will need to create a local +\fB/etc/speak.conf\fP file on that machine with at minimum a [\fIdown\fP] +section with an entry for the text-to-speech host server to use. + +.PP +.SH SEE ALSO +.PP +.BR speak.conf (7) +.PP +.SH AUTHOR +.PP +David Sugar (dyfet@tycho.com) +.PP diff --git a/utils/down.c b/utils/down.c new file mode 100644 index 0000000..66d9d19 --- /dev/null +++ b/utils/down.c @@ -0,0 +1,129 @@ +/* + * A verbal system shutdown utility. + * $Id: down.c 1.2 Mon, 24 Mar 1997 12:25:37 -0500 dyfet $ + * Copyright (c) 1997 by Tycho Softworks. + * For conditions of distribution and reuse see product license. + * + * Abstract: + * A verbal system shutdown utility. You may need to adjust the name + * of the shutdown program used. This gives some warning and then + * initiates the shutdown processing, unless cancelled in time. + */ + +#include +#include +#include +#include +#include +#include + +static char host[128] = "localhost"; +static char halt[60] = "/sbin/halt"; +static char abort_msg[] = "System shutdown overriden. Resuming normal operation.\n"; +static char down_msg[] = "%s system shutdown sequence initiated. You have %d seconds to override.\n"; +static int timer = 10; +static STREAM fp = NULL; + +/* + * If the user aborts the shutdown, then we send the cancellation message + * and gracefully exit the scene. + */ + +static void abort_sig() +{ + if(fp) + { + puttcp(abort_msg, fp); + closetcp(fp); + } + fputs("\n", stdout); + exit(-1); +} + +void main(int argc, char **argv) +{ + char *p; + char *reboot = halt; + int port = getservice("speak"); + CONFIG *cfg = sys_config("speak"); + char hostname[128]; + + if(argc < 1 || argc > 2) + fatal(EX_USAGE, "use: down [timer]\n"); + + if(!port) + fatal(EX_UNAVAILABLE, "down: speak: service unlisted in /etc/services\n"); + + if(!cfg) + fatal(EX_CONFIG, "down: speak.conf: config missing\n"); + + seek_config(cfg, "down"); + while(read_config(cfg)) + { + if(NULL != (p = get_config(cfg, "timer"))) + { + timer = atoi(p); + continue; + } + + if(NULL != (p = get_config(cfg, "halt"))) + { + strcpy(halt, p); + continue; + } + + if(NULL != (p = get_config(cfg, "host"))) + { + strcpy(host, p); + continue; + } + + if(NULL != (p = get_config(cfg, "server"))) + { + strcpy(host, p); + continue; + } + } + close_config(cfg); + if(argc > 1) + timer = atoi(argv[1]); + + fp = opentcp(host, port); + if(!fp) + fatal(EX_UNAVAILABLE, "down: %s: speak service unreachable\n", host); + + printf("System shutdown initiated...use to override; "); + fflush(stdout); + signal(SIGINT, abort_sig); + gettcp(hostname, 127, fp); + gethostname(hostname, 80); + fprintf(fp, down_msg, hostname, timer); + fflush(fp); + sleep(strlen(down_msg) / 9 + 1); + + /* count down timer until 0 */ + + while(timer) + { + printf("%d ", timer); + fflush(stdout); + fprintf(fp, "%d\n", timer); + fflush(fp); + sleep(1); + --timer; + } + + /* too late now!! */ + + signal(SIGINT, SIG_IGN); + printf("\n"); + closetcp(fp); + + /* detach return to user and execute reboot program */ + + pdetach(D_KEEPALL); + argv[0] = reboot; + argv[1] = NULL; + execvp(reboot, argv); +} + diff --git a/utils/say.1 b/utils/say.1 new file mode 100644 index 0000000..1807b76 --- /dev/null +++ b/utils/say.1 @@ -0,0 +1,35 @@ +.TH "say" "1" "January 1997" "Speak 0.2" "Text-to-Speech" +.PP +.SH NAME +.PP +\fBsay\fP - send output string to text-to-speech service. +.PP +.SH SYNOPSIS +.PP +\fBspeak\fP \fIhostname\fP "\fImessage\fP" +.PP +.SH DESCRIPTION +.PP +The Text-to-speech package introduces a standard TCP/IP port service for +attaching text-to-speech resources to your network. These resources can +be used to monitor system status, provide verbal alarms, etc. This network +service may be accessed by telnetting to a machine running a "speak" server, +or by using the various application utilities, such as \fBsay\fP. +.PP + +The \fBsay\fP program will send a specified string of text to a specified +network speech server. The intent is to use say to produce verbal output +much like the way "echo" may be used to create screen output. \fBsay\fP +will form a momentary connection with the speech server (such as +\fBspo256\fP), send the message, and then disconnect. The TCP +service port used for the connection is specified in \fI/etc/services\fP. + +.PP +.SH SEE ALSO +.PP +.BR speak (1) +.PP +.SH AUTHOR +.PP +David Sugar (dyfet@tycho.com) +.PP diff --git a/utils/say.c b/utils/say.c new file mode 100644 index 0000000..b774eaf --- /dev/null +++ b/utils/say.c @@ -0,0 +1,34 @@ +/* + * Send text to speech server. May be used in script files. + * $Id: say.c 1.2 Mon, 24 Mar 1997 12:25:37 -0500 dyfet $ + * Copyright (c) 1997 by Tycho Softworks. + * For conditions on distribution and reuse see product license. + */ + +#include +#include +#include + +void main(int argc, char **argv) +{ + STREAM fp; + int port = getservice("speak"); + char buf[128]; + + if(argc != 3) + fatal(EX_USAGE, "use: say host \"message\"\n"); + + if(!port) + fatal(EX_UNAVAILABLE, "say: speak: service not in /etc/services\n"); + + fp = opentcp(argv[1], port); + if(!fp) + fatal(EX_UNAVAILABLE, "say: %s: speak service unavailable\n", argv[1]); + + gettcp(buf, 127, fp); + puttcp(argv[2], fp); + puttcp("\n", fp); + closetcp(fp); +} + + diff --git a/utils/vmon.8 b/utils/vmon.8 new file mode 100644 index 0000000..84a1308 --- /dev/null +++ b/utils/vmon.8 @@ -0,0 +1,65 @@ +.TH "vmon" "8" "January 1997" "Speak 0.2" "Text-to-Speech" +.PP +.SH NAME +.PP +\fBvmon\fP - monitor system status (town crier). +.PP +.SH SYNOPSIS +.PP +\fBvmon\fP \fIfilesystems\fP +.br +\fBvstat\fP \fIfilesystems\fP +.PP +.SH DESCRIPTION +.PP +The Text-to-speech package introduces a standard TCP/IP port service for +attaching text-to-speech resources to your network. These resources can +be used to monitor system status, provide verbal alarms, etc. This network +service may be accessed by telnetting to a machine running a "speak" server, +or by using the various application utilities, such as \fBvmon\fP. +.PP + +The \fBvmon\fP program will monitor the specified list of file systems. +If any of these file systems exceed a maximum "quota" (such as over 90% +capacity in blocks or i-node use), then the monitor will send verbal +alerts every 5 minutes. This quota, and other parameters for vmon, may +be found in the [\fIvmon\fP] section of \fBspeak.conf\fP. +.PP + +The \fBvmon\fP program will also announce current system status once +every hour. This system status includes the total used capacity of +all file systems being monitored, how long the system has been up, and +how many users are currently logged in (excluding root). This hourly +announcement can be used to determine a given system is still alive. +.PP + +The \fBvmon\fP program will now also monitor specified user mailboxes +for new mail and announce when new mail arrives. The users to be +monitored are specified in the [\fIvmon\fP] section of \fBspeak.conf\fP. +Simply list mailbox= entries for each mailbox you wish to monitor. See +the example speak.conf included with the distribution. +.PP + +The \fBvmon\fP program can also be ran as \fBvstat\fP. When used as +\fBvstat\fP, the program performs an immediate system check, announces, +and then terminates. You can either use \fBvstat\fP from a crontab or +start \fBvmon\fP from \fBspeak.init\fP. You may also start \fBvmon\fP +from a \fBrc.local\fP file. Please check the \fBspeak.init\fP file +to add any file systems you wish to monitor. By default, the root +filesystem is enabled in \fBspeak.init\fP. +.PP + +A mute option may also be specified in the [\fIvmon\fP] section of +\fBspeak.conf\fP. This option mutes voice output during certain times of +the day. This is normally specified by 24 hour clock in hours, hence 18-7 +means to mute output anytime after 18' hours (6pm) and anytime before 7' +hours (7am). +.PP +.SH SEE ALSO +.PP +.BR speak.conf (7) +.PP +.SH AUTHOR +.PP +David Sugar (dyfet@tycho.com) +.PP diff --git a/utils/vmon.c b/utils/vmon.c new file mode 100644 index 0000000..e1015b4 --- /dev/null +++ b/utils/vmon.c @@ -0,0 +1,442 @@ +/* Verbal monitor system status. + * $Id: vmon.c 1.2 Mon, 24 Mar 1997 12:25:37 -0500 dyfet $ + * Copyright (c) 1997 by Tycho Softworks. + * For conditions on distribution and reuse see product license. + * + * Abstract: + * Monitor system status in background. This service is normally + * started with the speech server. It may also be ran as 'vstat' + * to perform immediate notification. + */ + +#include +#include +#include +#include +#include +#include + +/* For systems that use statfs! */ + +#ifdef __linux__ +#include +#define __statfs__ +#endif + +typedef struct _MAILBOX +{ + struct _MAILBOX *next; + time_t update; + ulong size; + char name[0]; +} MAILBOX; + +static int freq = 3600; +static int timer = 3600; +static int interval = 300; +static int iter; +static int orig_timer; +static int alert = 90; /* warn on 90% full */ +static char alertmsg[] = "emergency alert emergency alert \r\n"; +static char **fs; +static char host[128] = "localhost"; +static int mute[2] = {24, 0}; + +static char *vmailbox(MAILBOX *mbox) +{ + struct stat ino; + static char buf[80]; + + if(stat(mbox->name, &ino)) + return NULL; + + if(!ino.st_size) + { + mbox->size = 0; + return NULL; + } + + if(ino.st_size == mbox->size) + return NULL; + + if(mbox->size == -1) + { + mbox->size = ino.st_size; + return NULL; + } + + mbox->size = ino.st_size; + sprintf(buf, "User %s has new mail\n", mbox->name); + return buf; +} + +static void vmbox(MAILBOX *box, int port) +{ + STREAM fp = NULL; + char *p; + time_t now; + struct tm *dt; + char buf[128]; + + time(&now); + dt = localtime(&now); + if(dt->tm_hour > mute[0] || dt->tm_hour < mute[1]) + return; + + while(box) + { + p = vmailbox(box); + if(!p) + { + box = box->next; + continue; + } + if(!fp) + { + fp = opentcp(host, port); + if(!fp) + return; + + gettcp(buf, sizeof(buf) - 1, fp); + } + puttcp(p, fp); + box = box->next; + } + if(fp) + closetcp(fp); +} + +static int vstat(int port) +{ + int i = 0; + char *f; + long btotal = 0; + long bfree = 0; + bool failed = FALSE; + STREAM fp = NULL; +#ifdef __statfs__ + struct statfs fnode; +#endif + int blocks, inodes; + char buf[128]; + int newtimer = orig_timer; + time_t now; + static prior = -1; + struct tm *dt; + int apm, hour; + char *apmstr[] = {" A M ", " P M "}; + int fd; + struct utmp *utmp, uptime; + int users = 0; + int utcnt = 0; + +#ifdef __statfs__ + while(fs[i]) + { + if(!statfs(fs[i], &fnode)) + { + btotal += fnode.f_blocks; + bfree += fnode.f_bfree; + blocks = 100 - (int)(fnode.f_ffree / (fnode.f_files / 100l)); + inodes = 100 - (int)(fnode.f_bfree / (fnode.f_blocks / 100l)); + if((blocks < alert) && (inodes < alert)) + { + ++i; + continue; + } + } + else + { + inodes = 0; + blocks = 0; + failed = TRUE; + } + if(!fp) + { + fp = opentcp(host, port); + if(!fp) + { + newtimer = 300; + break; + } + gettcp(buf, 128, fp); + puttcp(alertmsg, fp); + } + + if(blocks > alert) + fprintf(fp, "File system %s is %d percent full.\r\n", fs[i], blocks); + + if(inodes > alert) + fprintf(fp, "File system %s i-node table is %d percent full.\r\n", fs[i], inodes); + + if(failed) + fprintf(fp, "File system %s is dismounted or failed\r\n", fs[i]); + + fflush(fp); + newtimer = 60; + ++i; + } +#endif + + if(fp) + closetcp(fp); + + time(&now); + if(prior == (now / freq)) + return newtimer; + + if(prior == -1) + prior = now / freq - 1; + else + prior = now / freq; + + dt = localtime(&now); + hour = dt->tm_hour % 12; + if(dt->tm_hour > mute[0] || dt->tm_hour < mute[1]) + return newtimer; + + if(!hour) + hour = 12; + + if(dt->tm_hour > 11) + apm = 1; + else + apm = 0; + + fp = opentcp(host, port); + if(!fp) + return newtimer; + + gettcp(buf, 128, fp); + fprintf(fp, "It is %d:%d %s \r\n", hour, dt->tm_min, apmstr[apm]); + fflush(fp); + + fd = open("/proc/uptime", O_RDONLY); + hour = -1; + if(fd > -1) + { + read(fd, buf, 128); + close(fd); + hour = atol(buf) / 3600; + } + +#if defined(BOOT_TIME) || defined(RUN_LVL) + if(hour == -1) + { + utmp = NULL; + memset(&uptime, 0, sizeof(uptime)); +#ifdef BOOT_TIME + setutent(); + uptime.ut_type = BOOT_TIME; + utmp = getutid(&uptime); +#endif +#ifdef RUN_LVL + if(!utmp) + { + setutent(); + uptime.ut_type = RUN_LVL; + utmp = getutid(&uptime); + } +#endif + if(utmp) + hour = (now - utmp->ut_time) / 3600l; + + endutent(); + } +#endif + + if(hour > -1) + { + if(hour == 1) + fprintf(fp, "The system has been up 1 hour\r\n"); + else if(hour < 48) + fprintf(fp, "The system has been up %d hours\r\n", hour); + else + fprintf(fp, "The system has been up %d days\r\n", hour / 24); + fflush(fp); + } + + setutent(); + while(NULL != (utmp = getutent())) + { + ++utcnt; + +#ifdef USER_PROCESS + if(utmp->ut_type != USER_PROCESS) + continue; +#endif + + utmp->ut_user[sizeof(utmp->ut_user)] = 0; + if(!strcmp(utmp->ut_user, "root")) + continue; + + if(!utmp->ut_user[0]) + continue; + + if(!utmp->ut_line[0]) + continue; + +#ifdef USER_PROCESS + if(kill(utmp->ut_pid, 0)) + continue; +#endif + + ++users; + } + endutent(); + + if(utcnt) + { + if(!users) + fprintf(fp, "There are no users online\r\n"); + else if(users == 1) + fprintf(fp, "There is 1 user online\r\n"); + else + fprintf(fp, "There are %d users online\r\n", users); + fflush(fp); + } + + if(btotal) + { + fprintf(fp, "The main system drives are at %d percent of capacity\r\n", + 100 - (int)(bfree / (btotal / 100))); + fflush(fp); + } + + closetcp(fp); + return newtimer; +} + +void main(int argc, char **argv) +{ + int port = getservice("speak"); + char *maildir = getenv("MAILDIR"); + MAILBOX *mbox = NULL, *newbox; + char *prog = basename(*argv); + CONFIG *cfg = sys_config("speak"); + time_t now; + char *p; + + if(argc < 2) + fatal(EX_USAGE, "use %s filesystems...\n", prog); + + if(!maildir) + maildir = "/var/spool/mail"; + + fs = ++argv; + + if(!port) + fatal(EX_UNAVAILABLE, "%s: speak: service unavailable\n", prog); + + if(!cfg) + fatal(EX_UNAVAILABLE, "%s: speak.conf: missing\n", prog); + + seek_config(cfg, "vmon"); + while(read_config(cfg)) + { + if(NULL != (p = get_config(cfg, "mailbox"))) + { + p = strtok(p, __SPACES); + while(p) + { + newbox = (MAILBOX *)malloc(sizeof(MAILBOX) + strlen(p) + 1); + newbox->next = mbox; + time(&newbox->update); + newbox->size = -1l; + strcpy(newbox->name, p); + mbox = newbox; + p = strtok(NULL, __SPACES); + } + continue; + } + + if(NULL != (p = get_config(cfg, "interval"))) + { + interval = atoi(p) * 60; + continue; + } + + if(NULL != (p = get_config(cfg, "frequency"))) + { + timer = 3600 / atoi(p); + continue; + } + + if(NULL != (p = get_config(cfg, "server"))) + { + strcpy(host, p); + continue; + } + + if(NULL != (p = get_config(cfg, "host"))) + { + strcpy(host, p); + continue; + } + + if(NULL != (p = get_config(cfg, "alert"))) + { + alert = atoi(p); + continue; + } + + if(NULL != (p = get_config(cfg, "timer"))) + { + timer = atoi(p) * 60; + continue; + } + + if(NULL != (p = get_config(cfg, "mute"))) + { + mute[0] = atoi(p); + p = strchr(p, '-'); + if(p) + mute[1] = atoi(strtrim(++p, __SPACES)); + continue; + } + + if(NULL != (p = get_config(cfg, "maildir"))) + { + maildir = strdup(p); + continue; + } + + } + close_config(cfg); + + if(stricmp(prog, "vmon")) + { + vstat(port); + exit(0); + } + + pdetach(D_KEEPNONE); + + chdir(maildir); + freq = timer; + orig_timer = timer; + time(&now); + for(;;) + { + timer = vstat(port); + iter = interval; + for(;;) + { + vmbox(mbox, port); + sleep(iter); + time(&now); + iter = timer - (now % timer) - 1; + + if(iter > interval) + iter = interval; + + if(iter < 2) + { + sleep(iter + 2); + break; + } + } + } +} + + -- cgit v1.2.3-54-g00ecf