Created
March 3, 2019 01:05
-
-
Save mdevaev/d4bcdc467b4cfb973a84be64c7ba3597 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!mkcmd | |
# $Mkcmd(*): ${mkcmd-mkcmd} %f | |
# | |
from '<sys/types.h>' | |
from '<sys/time.h>' | |
from '<sys/socket.h>' | |
from '<sys/ioctl.h>' | |
from '<netinet/in.h>' | |
from '<fcntl.h>' | |
from '<signal.h>' | |
from '<stdio.h>' | |
from '<netdb.h>' | |
from '<pwd.h>' | |
from '<errno.h>' | |
from '<ctype.h>' | |
from '<pwd.h>' | |
from '<unistd.h>' | |
from '"cons.h"' | |
from '"machine.h"' | |
require "std_help.m" "std_version.m" "std_noargs.m" | |
getenv "CONSOLE" | |
basename "console" "" | |
usage "Usage" | |
# buffers | |
string[32] variable "acMe" { | |
before "FindUser(acMe);" | |
help "holds the login name of the client user" | |
} | |
char* variable "pcCmd" { | |
static | |
help "internal command string decoded from options" | |
after 'if ((char *)0 == %n) {%n = "attach";}' | |
} | |
boolean variable "fLocal" { | |
static init "0" | |
} | |
boolean variable "fReplay" { | |
static init "0" | |
} | |
char* variable "pcTo" { | |
param "machine" | |
init '"*"' | |
help "connect to the slaved console of this machine" | |
} | |
string[256] variable "acMyName" { | |
help "what we call ourselves" | |
} | |
string[1024] variable "acPorts" { | |
local | |
after '(void)sprintf(%n, "@%%s", pcInMaster);' | |
} | |
string variable "acLocalhost" { | |
init '"localhost"' | |
help "the loopback device" | |
} | |
init "RunTime();" | |
# options | |
function 'e' { | |
named "ParseEsc" | |
param "attn" | |
update '%n(%N);' | |
help "negotiate a different attention character sequence" | |
} | |
char* 'M' { | |
named "pcInMaster" | |
param "master" | |
init 'HOST' | |
help "master console server host for this cluster" | |
} | |
boolean 'r' { | |
named "fRaw" | |
user 'if ((char *)0 == pcCmd) {pcCmd = "spy";}' | |
help "connection to host should be raw" | |
} | |
boolean 'v' { | |
named "fVerbose" | |
help "be more verbose" | |
} | |
exclude "asfduqY" | |
action 'aA' { | |
once | |
update 'pcCmd = "attach";' | |
user 'fReplay = isupper(%w);' | |
help "attach to the named machine (with replay)" | |
} | |
action 'fF' { | |
once | |
update 'pcCmd = "force";' | |
user 'fReplay = isupper(%w);' | |
help "force connection to the named machine (with replay)" | |
} | |
action 'sS' { | |
once | |
update 'pcCmd = "spy";' | |
user 'fReplay = isupper(%w);' | |
help "spy connection to the named machine (with replay)" | |
} | |
left "pcTo" { | |
} | |
action 'Y' { | |
exclude "reM" | |
update "%rMn = acLocalhost;" | |
from '<stdio.h>' | |
list { | |
param "" | |
update "if (argc - %K<getopt_switches>1v > 0) {fprintf(stderr, \"%%s: too many arguments (%%s%%s)\\n\", %b, argv[%K<getopt_switches>1v], argc - %K<getopt_switches>1v > 1 ? \"...\" : \"\");exit(1);}" | |
abort 'exit(Gather(CtlSignal, acPorts, pcInMaster, "*", "pid", acMe));' | |
} | |
help "send a restart signal to the local console server" | |
} | |
%c | |
/* replace a very long ?: expession with something we can read (ksb) | |
*/ | |
static char * | |
ActMap(cKey) | |
char cKey; | |
{ | |
switch (cKey) { | |
default: | |
break; | |
case 'D': | |
case 'd': | |
return "version"; | |
case 'x': | |
case 'X': | |
return "xamine"; | |
case 'P': | |
case 'p': | |
return "pid"; | |
case 'U': | |
case 'u': | |
return "users"; | |
case 'W': | |
case 'w': | |
return "groups"; | |
} | |
fprintf(stderr, "%s: unknown key `%c'\n", progname, cKey); | |
exit(1); | |
} | |
%% | |
action 'dDpP' { | |
update 'pcCmd = ActMap(%w);' | |
user 'fLocal = isupper(%w);' | |
help "poll the (primary) console server for version information" | |
exclude "re" | |
exit { | |
update "" | |
named "Gather" | |
aborts "exit(%n(fLocal ? Ctl : CtlMaster, acPorts, %rMn, pcTo, pcCmd, acMe));" | |
} | |
} | |
augment action "pP" { | |
help "poll the (primary) console server its process id" | |
} | |
action 'uUwWxX' { | |
update 'pcCmd = ActMap(%w);' | |
user 'fLocal = isupper(%w);' | |
help "poll the (primary) console groups for console access lists" | |
exclude "re" | |
exit { | |
update "" | |
named "Gather" | |
aborts "exit(%n(fLocal ? CmdGroup : CmdMaster, acPorts, %rMn, pcTo, pcCmd, acMe));" | |
} | |
} | |
augment action 'wW' { | |
help "poll the (primary) console groups for connected clients lists" | |
} | |
augment action 'xX' { | |
help "poll the (primary) console groups for console baud rates" | |
} | |
action 'qQ' { | |
track | |
exclude "re" | |
update 'pcCmd = "quit";' | |
user 'fLocal = isupper(%w);' | |
help "send a quit request to the (primary) console server" | |
string[32] variable "acPass" { | |
local | |
help "hold the console server password for quit" | |
} | |
after 'if (%U) {(void)strcpy(acPass, getpass("Enter password:"));}' | |
exit { | |
update "" | |
named "Gather" | |
aborts "exit(%n(fLocal ? Ctl : CtlMaster, acPorts, %rMn, acPass, pcCmd, acMe));" | |
} | |
} | |
augment action 'V' { | |
user "Version();" | |
} | |
exit { | |
update "" | |
named "Gather" | |
aborts "if (0 == %n(Indir, acPorts, %rMn, pcTo, pcCmd, acMe)) {exit(0);}(void)sprintf(acPorts, \"@%%s\", pcTo);exit(%n(Indir, acPorts, %rMn, pcTo, pcCmd, acMe));" | |
} | |
%c | |
/* | |
* Copyright (c) 1990 The Ohio State University. | |
* All rights reserved. | |
* | |
* Redistribution and use in source and binary forms are permitted | |
* provided that: (1) source distributions retain this entire copyright | |
* notice and comment, and (2) distributions including binaries display | |
* the following acknowledgement: ``This product includes software | |
* developed by The Ohio State University and its contributors'' | |
* in the documentation or other materials provided with the distribution | |
* and in all advertising materials mentioning features or use of this | |
* software. Neither the name of the University nor the names of its | |
* contributors may be used to endorse or promote products derived | |
* from this software without specific prior written permission. | |
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR | |
* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED | |
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. | |
*/ | |
%% | |
%i | |
#if USE_STRINGS | |
#include <strings.h> | |
#else | |
#include <string.h> | |
#endif | |
#if USE_TERMIOS | |
#include <termios.h> | |
#include <unistd.h> | |
#else | |
#if USE_TERMIO | |
#include <termio.h> | |
#else /* use ioctl stuff */ | |
#include <sgtty.h> | |
#include <sys/ioctl.h> | |
#endif | |
#endif | |
#if HAVE_MALLOC_H | |
#include <malloc.h> | |
#else | |
#if NEED_MALLOC_EXTERN | |
extern char *calloc(), *realloc(); | |
#endif | |
#endif | |
#if HAVE_STDLIB_H | |
#include <stdlib.h> | |
#else | |
extern char *getenv(), *getpass(); | |
#endif | |
extern int errno; | |
#if !HAVE_STRERROR | |
extern char *sys_errlist[]; | |
#define strerror(Me) (sys_errlist[Me]) | |
#endif | |
#if HAVE_SELECT_H | |
#include <sys/select.h> | |
#endif | |
static char rcsid[] = | |
"$Id: console.m,v 8.3 2000/08/02 18:34:03 ksb Exp $"; | |
int chAttn = -1, chEsc = -1; | |
%% | |
%c | |
/* panic -- we have no more momory | |
*/ | |
static void | |
OutOfMem() | |
{ | |
static char acNoMem[] = ": out of memory\n"; | |
write(2, progname, strlen(progname)); | |
write(2, acNoMem, sizeof(acNoMem)-1); | |
exit(1); | |
} | |
/* | |
* remove from "host1" those domains common to "host1" and "host2" | |
*/ | |
static char * | |
whittle(host1, host2) | |
char *host1, *host2; | |
{ | |
char *p1, *p2; | |
p1 = strchr(host1, '.'); | |
p2 = strchr(host2, '.'); | |
while (p1 != (char*)0 && p2 != (char*)0) { | |
if (strcmp(p1+1, p2+1) == 0) { | |
*p1 = '\000'; | |
break; | |
} | |
p1 = strchr(p1+1, '.'); | |
p2 = strchr(p2+1, '.'); | |
} | |
return host1; | |
} | |
static char | |
acMesg[8192+2], /* the buffer for startup negotiation */ | |
acThisHost[256]; /* what the remote host would call us */ | |
static struct sockaddr_in | |
local_port; /* the looback address, if local use it */ | |
/* output a control (or plain) character as a UNIX user would expect it (ksb) | |
*/ | |
static void | |
putCtlc(c, fp) | |
int c; | |
FILE *fp; | |
{ | |
if (0 != (0200 & c)) { | |
(void)putc('M', fp); | |
(void)putc('-', fp); | |
c &= ~0200; | |
} | |
if (isprint(c)) { | |
(void)putc(c, fp); | |
return; | |
} | |
(void)putc('^', fp); | |
if (c == 0177) { | |
(void)putc('?', fp); | |
return; | |
} | |
(void)putc(c+0100, fp); | |
} | |
#if defined(SERVICE) | |
static struct servent *pSE; | |
static char acService[] = SERVICE; | |
#endif | |
/* expain who we are and which revision we are (ksb) | |
*/ | |
static void | |
Version() | |
{ | |
register unsigned char *puc; | |
printf("%s: initial master server `%s\'\n", progname, pcInMaster); | |
printf("%s: default escape sequence `", progname); | |
putCtlc(DEFATTN, stdout); | |
putCtlc(DEFESC, stdout); | |
printf("\'\n"); | |
puc = (unsigned char *)&local_port.sin_addr; | |
printf("%s: loopback address for %s is %d.%d.%d.%d\n", progname, acMyName, puc[0], puc[1], puc[2], puc[3]); | |
#if defined(SERVICE) | |
if ((struct servent *)0 == (pSE = getservbyname(acService, "tcp"))) { | |
fprintf(stderr, "%s: getservbyname: %s: %s\n", progname, acService, strerror(errno)); | |
return; | |
} | |
printf("%s: service name `%s\'", progname, pSE->s_name); | |
if (0 != strcmp(pSE->s_name, acService)) { | |
printf(" (which we call `%s\')", acService); | |
} | |
printf(" on port %d\n", ntohs((u_short)pSE->s_port)); | |
#else | |
#if defined(PORT) | |
printf("%s: on port %d\n", progname, PORT); | |
#else | |
printf("%s: no service or port compiled in\n", progname); | |
exit(1); | |
#endif | |
#endif | |
} | |
/* convert text to control chars, we take `cat -v' style (ksb) | |
* ^X (or ^x) contro-x | |
* M-x x plus 8th bit | |
* c a plain character | |
*/ | |
static int | |
ParseChar(ppcSrc, pcOut) | |
char **ppcSrc, *pcOut; | |
{ | |
register int cvt, n; | |
register char *pcScan = *ppcSrc; | |
if ('M' == pcScan[0] && '-' == pcScan[1] && '\000' != pcScan[2]) { | |
cvt = 0x80; | |
pcScan += 2; | |
} else { | |
cvt = 0; | |
} | |
if ('\000' == *pcScan) { | |
return 1; | |
} | |
if ('^' == (n = *pcScan++)) { | |
if ('\000' == (n = *pcScan++)) { | |
return 1; | |
} | |
if (islower(n)) { | |
n = toupper(n); | |
} | |
if ('@' <= n && n <= '_') { | |
cvt |= n - '@'; | |
} else if ('?' == *pcScan) { | |
cvt |= '\177'; | |
} else { | |
return 1; | |
} | |
} else { | |
cvt |= n; | |
} | |
if ((char *)0 != pcOut) { | |
*pcOut = cvt; | |
} | |
*ppcSrc = pcScan; | |
return 0; | |
} | |
/* find the two characters that makeup the users escape sequence (ksb) | |
*/ | |
static void | |
ParseEsc(pcText) | |
char *pcText; | |
{ | |
auto char *pcTemp; | |
auto char c1, c2; | |
pcTemp = pcText; | |
if (ParseChar(&pcTemp, &c1) || ParseChar(&pcTemp, &c2)) { | |
fprintf(stderr, "%s: poorly formed escape sequence `%s\'\n", progname, pcText); | |
exit(3); | |
} | |
if ('\000' != *pcTemp) { | |
fprintf(stderr, "%s: too many characters in new escape sequence at ...`%s\'\n", progname, pcTemp); | |
exit(3); | |
} | |
chAttn = c1; | |
chEsc = c2; | |
} | |
/* set the port for socket connection (ksb) | |
* return the fd for the new connection; if we can use the loopback, do | |
* as a side effect we set ThisHost to a short name for this host | |
*/ | |
int | |
GetPort(pcToHost, pPort, sPort) | |
char *pcToHost; | |
struct sockaddr_in *pPort; | |
short sPort; | |
{ | |
register int s; | |
register struct hostent *hp; | |
#if USE_STRINGS | |
(void)bzero((char *)pPort, sizeof(*pPort)); | |
#else | |
memset((void *)pPort, '\000', sizeof(*pPort)); | |
#endif | |
if (0 == strcmp(pcToHost, strcpy(acThisHost, acMyName))) { | |
(void)strcpy(pcToHost, acLocalhost); | |
#if USE_STRINGS | |
(void)bcopy((char *)&local_port.sin_addr, (char *)&pPort->sin_addr, sizeof(local_port.sin_addr)); | |
#else | |
memcpy((char *)&pPort->sin_addr, (char *)&local_port.sin_addr, sizeof(local_port.sin_addr)); | |
#endif | |
} else if ((struct hostent *)0 != (hp = gethostbyname(pcToHost))) { | |
#if USE_STRINGS | |
(void)bcopy((char *)hp->h_addr, (char *)&pPort->sin_addr, hp->h_length); | |
#else | |
memcpy((char *)&pPort->sin_addr, (char *)hp->h_addr, hp->h_length); | |
#endif | |
} else { | |
extern int h_errno; | |
fprintf(stderr, "%s: gethostbyname: %s: %s\n", progname, pcToHost, hstrerror(h_errno)); | |
return -1; | |
} | |
pPort->sin_port = sPort; | |
pPort->sin_family = AF_INET; | |
/* make hostname short, if we are calling ourself, chop at first dot | |
*/ | |
if (0 == strcmp(pcToHost, acLocalhost)) { | |
register char *pcChop; | |
if ((char *)0 != (pcChop = strchr(acThisHost, '.'))) { | |
*pcChop = '\000'; | |
} | |
} else { | |
(void)whittle(acThisHost, pcToHost); | |
} | |
/* set up the socket to talk to the server for all consoles | |
* (it will tell us who to talk to to get a real connection) | |
*/ | |
if ((s = socket(AF_INET, SOCK_STREAM, 0)) < 0) { | |
fprintf(stderr, "%s: socket: %s\n", progname, strerror(errno)); | |
return -1; | |
} | |
if (connect(s, (struct sockaddr *)pPort, sizeof(*pPort)) < 0) { | |
fprintf(stderr, "%s: connect: %d@%s: %s\n", progname, ntohs(pPort->sin_port), pcToHost, strerror(errno)); | |
close(s); | |
return -1; | |
} | |
return s; | |
} | |
/* the next two routines assure that the users tty is in the | |
* correct mode for us to do our thing | |
*/ | |
static int screwy = 0; | |
#if USE_TERMIOS | |
static struct termios o_tios; | |
#else | |
#if USE_TERMIO | |
static struct termio o_tio; | |
#else | |
static struct sgttyb o_sty; | |
static struct tchars o_tchars; | |
static struct ltchars o_ltchars; | |
#endif | |
#endif | |
/* | |
* show characters that are already tty processed, | |
* and read characters before cononical processing | |
* we really use cbreak at PUCC because we need even parity... | |
*/ | |
static void | |
c2raw() | |
{ | |
#if USE_TERMIOS | |
auto struct termios n_tios; | |
#else | |
#if USE_TERMIO | |
auto struct termio n_tio; | |
#else | |
auto struct sgttyb n_sty; | |
auto struct tchars n_tchars; | |
auto struct ltchars n_ltchars; | |
#endif | |
#endif | |
if (!isatty(0) || 0 != screwy) | |
return; | |
#if USE_TERMIOS | |
if (0 != ioctl(0, TCGETS, & o_tios)) { | |
fprintf(stderr, "%s: iotcl: getsw: %s\n", progname, strerror(errno)); | |
exit(10); | |
} | |
n_tios = o_tios; | |
n_tios.c_iflag &= ~(INLCR|IGNCR|ICRNL|IUCLC|IXON); | |
n_tios.c_oflag &= ~OPOST; | |
n_tios.c_lflag &= ~(ICANON|ISIG|ECHO); | |
n_tios.c_cc[VMIN] = 1; | |
n_tios.c_cc[VTIME] = 0; | |
if (0 != ioctl(0, TCSETS, & n_tios)) { | |
fprintf(stderr, "%s: getarrt: %s\n", progname, strerror(errno)); | |
exit(10); | |
} | |
#else | |
#if USE_TERMIO | |
if (0 != ioctl(0, TCGETA, & o_tio)) { | |
fprintf(stderr, "%s: iotcl: geta: %s\n", progname, strerror(errno)); | |
exit(10); | |
} | |
n_tio = o_tio; | |
n_tio.c_iflag &= ~(INLCR|IGNCR|ICRNL|IUCLC|IXON); | |
n_tio.c_oflag &= ~OPOST; | |
n_tio.c_lflag &= ~(ICANON|ISIG|ECHO|ECHOE|ECHOK|ECHONL); | |
n_tio.c_cc[VMIN] = 1; | |
n_tio.c_cc[VTIME] = 0; | |
if (0 != ioctl(0, TCSETAF, & n_tio)) { | |
fprintf(stderr, "%s: iotcl: seta: %s\n", progname, strerror(errno)); | |
exit(10); | |
} | |
#else | |
if (0 != ioctl(0, TIOCGETP, (char *)&o_sty)) { | |
fprintf(stderr, "%s: iotcl: getp: %s\n", progname, strerror(errno)); | |
exit(10); | |
} | |
n_sty = o_sty; | |
n_sty.sg_flags |= CBREAK; | |
n_sty.sg_flags &= ~(CRMOD|ECHO); | |
n_sty.sg_kill = -1; | |
n_sty.sg_erase = -1; | |
if (0 != ioctl(0, TIOCSETP, (char *)&n_sty)) { | |
fprintf(stderr, "%s: iotcl: setp: %s\n", progname, strerror(errno)); | |
exit(10); | |
} | |
/* stty undef all tty chars | |
*/ | |
if (-1 == ioctl(0, TIOCGETC, (char *)&n_tchars)) { | |
fprintf(stderr, "%s: ioctl: getc: %s\n", progname, strerror(errno)); | |
return; | |
} | |
o_tchars = n_tchars; | |
n_tchars.t_intrc = -1; | |
n_tchars.t_quitc = -1; | |
if (-1 == ioctl(0, TIOCSETC, (char *)&n_tchars)) { | |
fprintf(stderr, "%s: ioctl: setc: %s\n", progname, strerror(errno)); | |
return; | |
} | |
if (-1 == ioctl(0, TIOCGLTC, (char *)&n_ltchars)) { | |
fprintf(stderr, "%s: ioctl: gltc: %s\n", progname, strerror(errno)); | |
return; | |
} | |
o_ltchars = n_ltchars; | |
n_ltchars.t_suspc = -1; | |
n_ltchars.t_dsuspc = -1; | |
n_ltchars.t_flushc = -1; | |
n_ltchars.t_lnextc = -1; | |
if (-1 == ioctl(0, TIOCSLTC, (char *)&n_ltchars)) { | |
fprintf(stderr, "%s: ioctl: sltc: %s\n", progname, strerror(errno)); | |
return; | |
} | |
#endif | |
#endif | |
screwy = 1; | |
} | |
/* | |
* put the tty back as it was, however that was | |
*/ | |
static void | |
c2cooked() | |
{ | |
if (!screwy) | |
return; | |
#if USE_TERMIOS | |
(void)ioctl(0, TCSETS, (char *)&o_tios); | |
#else | |
#if USE_TERMIO | |
(void)ioctl(0, TCSETA, (char *)&o_tio); | |
#else | |
(void)ioctl(0, TIOCSETP, (char *)&o_sty); | |
(void)ioctl(0, TIOCSETC, (char *)&o_tchars); | |
(void)ioctl(0, TIOCSLTC, (char *)&o_ltchars); | |
#endif | |
#endif | |
screwy = 0; | |
} | |
/* send out some data along the connection (ksb) | |
*/ | |
static void | |
SendOut(fd, pcBuf, iLen) | |
int fd, iLen; | |
char *pcBuf; | |
{ | |
register int nr; | |
while (0 != iLen) { | |
if (-1 == (nr = write(fd, pcBuf, iLen))) { | |
c2cooked(); | |
fprintf(stderr, "%s: lost connection\n", progname); | |
exit(3); | |
} | |
iLen -= nr; | |
pcBuf += nr; | |
} | |
} | |
/* read a reply from the console server (ksb) | |
* if pcWnat == (char *)0 we strip \r\n from the end and return strlen | |
*/ | |
static int | |
ReadReply(fd, pcBuf, iLen, pcWant) | |
int fd, iLen; | |
char *pcBuf, *pcWant; | |
{ | |
register int nr, j, iKeep; | |
iKeep = iLen; | |
for (j = 0; j < iLen; /* j+=nr */) { | |
switch (nr = read(fd, &pcBuf[j], iLen-1)) { | |
case 0: | |
if (iKeep != iLen) { | |
break; | |
} | |
/* fall through */ | |
case -1: | |
c2cooked(); | |
fprintf(stderr, "%s: lost connection\n", progname); | |
exit(3); | |
default: | |
j += nr; | |
iLen -= nr; | |
if ('\n' == pcBuf[j-1]) { | |
pcBuf[j] = '\000'; | |
break; | |
} | |
if (0 == iLen) { | |
c2cooked(); | |
fprintf(stderr, "%s: reply too long\n", progname); | |
exit(3); | |
} | |
continue; | |
} | |
break; | |
} | |
/* in this case the called wants a line of text | |
* remove the cr/lf sequence and any trtailing spaces | |
* (s/[ \t\r\n]*$//) | |
*/ | |
if ((char *)0 == pcWant) { | |
while (0 != j && isspace(pcBuf[j-1])) { | |
pcBuf[--j] = '\000'; | |
} | |
return j; | |
} | |
return strcmp(pcBuf, pcWant); | |
} | |
#if DO_POWER | |
/* we are on a control port, shift to power controller (ksb) | |
* and send commands to it, then hang up to get back on the console | |
*/ | |
static int | |
PowerCtl(s, pcKey, pcController, pcMaster) | |
int s; | |
char *pcKey, *pcController, *pcMaster; | |
{ | |
register int nc; | |
register char **ppc; | |
auto fd_set rmask, rinit; | |
static char *apcHelp[] = { | |
" help", | |
" . quit power mode", | |
" 0 power down the unit", | |
" 1 power up the unit", | |
" # describe power status of unit", | |
" ? output this help message", | |
" w which key and controller line infomation", | |
" (other commands might be accepted by some units)", | |
(char *)0 | |
}; | |
(void)sprintf(acMesg, "%c%c;", DEFATTN, DEFESC); | |
SendOut(s, acMesg, 3); | |
if (0 != ReadReply(s, acMesg, sizeof(acMesg), "[login:\r\n") && 0 != strcmp(acMesg, "\r\n[login:\r\n")) { | |
CSTROUT(1," login "); | |
SendOut(1, acMesg, strlen(acMesg)); | |
return 1; | |
} | |
(void)sprintf(acMesg, "%s\n", pcKey); | |
SendOut(s, acMesg, strlen(acMesg)); | |
if (0 != ReadReply(s, acMesg, sizeof(acMesg), "host:\r\n")) { | |
CSTROUT(1, " "); | |
SendOut(1, pcKey, strlen(pcKey)); | |
CSTROUT(1, " "); | |
SendOut(1, acMesg, strlen(acMesg)); | |
return 2; | |
} | |
/* which host we want, and a passwd if asked for one | |
*/ | |
(void)sprintf(acMesg, "%s\n", pcController); | |
SendOut(s, acMesg, strlen(acMesg)); | |
(void)ReadReply(s, acMesg, sizeof(acMesg), (char *)0); | |
if (0 == strcmp(acMesg, "passwd:")) { | |
auto char pass[32]; | |
c2cooked(); | |
(void)strcpy(pass, getpass(" need password:")); | |
c2raw(); | |
(void)sprintf(acMesg, "%s\n", pass); | |
SendOut(s, acMesg, strlen(acMesg)); | |
(void)ReadReply(s, acMesg, sizeof(acMesg), (char *)0); | |
} | |
/* how did we do, did we get a read-only or read-write? | |
*/ | |
if (0 != strcmp(acMesg, "attached]")) { | |
register char *pcClose; | |
if ((char *)0 != (pcClose = strchr(acMesg, ']'))) | |
*pcClose = '\000'; | |
CSTROUT(1, " aborted "); | |
write(1, acMesg, strlen(acMesg)); | |
return 3; | |
} | |
FD_ZERO(& rinit); | |
FD_SET(s, &rinit); | |
FD_SET(0, &rinit); | |
/* reset read mask and select on it | |
* ZZZ set a timeout on power line attach of 10 minutes? -- ksb | |
*/ | |
while (rmask = rinit, -1 != select(sizeof(rmask)*8, &rmask, (fd_set *)0, (fd_set *)0, (struct timeval *)0)) { | |
/* anything from socket? */ | |
if (FD_ISSET(s, &rmask)) { | |
if ((nc = read(s, acMesg, sizeof(acMesg))) == 0) { | |
break; | |
} | |
#if STRIP8 | |
/* clear parity? */ | |
for (i = 0; i < nc; ++i) | |
acMesg[i] &= 127; | |
#endif | |
SendOut(1, acMesg, nc); | |
} | |
/* anything from stdin? */ | |
if (!FD_ISSET(0, &rmask)) { | |
continue; | |
} | |
if ((nc = read(0, acMesg, 1)) == 0) { | |
break; | |
} | |
if ('q' == acMesg[0] || 'Q' == acMesg[0] || '.' == acMesg[0]) { | |
break; | |
} | |
/* must be a controller command, send any of: | |
* \n status of all lines? [not on the POW-R-Switch] | |
* key # power status | |
* key 1 power on | |
* key 0 power off | |
* key _ [where _ is something else] unknown pass through | |
*/ | |
switch (acMesg[0]) { | |
case '?': /* meta help */ | |
for (ppc = apcHelp; (char *)0 != *ppc; ++ppc) { | |
(void)write(1, *ppc, strlen(*ppc)); | |
(void)write(1, "\r\n", 2); | |
} | |
/* sprintf(acMesg, "?\n"); and break? XXX */ | |
continue; | |
case 'w': /* which line */ | |
sprintf(acMesg, " %s line %s on %s", pcKey, pcController, pcMaster); | |
(void)write(1, acMesg, strlen(acMesg)); | |
continue; | |
case '\r': /* power might want newlines passed */ | |
case '\n': | |
sprintf(acMesg, "\n"); | |
break; | |
case '#': | |
sprintf(acMesg, "%s#\n", pcKey); | |
break; | |
case '0': | |
case '-': | |
case 'd': | |
sprintf(acMesg, "%s0\n", pcKey); | |
break; | |
case '1': | |
case '+': | |
case 'u': | |
sprintf(acMesg, "%s1\n", pcKey); | |
break; | |
default: /* try anything else as a command */ | |
sprintf(acMesg, "%s%c\n", pcKey, acMesg[0]); | |
break; | |
} | |
/* The power controller might not say anything if the | |
* key is wrong, show the User that we sent something -- ksb | |
*/ | |
CSTROUT(1, " "); | |
SendOut(s, acMesg, strlen(acMesg)); | |
} | |
close(s); | |
CSTROUT(1, " done"); | |
return 0; | |
} | |
#endif | |
/* call a machine master for group master ports and machine master ports | |
* take a list like "1782@localhost:mentor.cc.purdue.edu:@pop.stat.purdue.edu" | |
*/ | |
static int | |
Gather(pfi, pcPorts, pcMaster, pcTo, pcCmd, pcWho) | |
int (*pfi)(); | |
char *pcPorts, *pcMaster, *pcTo, *pcCmd, *pcWho; | |
{ | |
register int s; | |
register short j; | |
register char *pcNext, *pcServer; | |
auto char acExcg[256]; | |
auto struct sockaddr_in client_port; | |
auto int iRet = 0; | |
for (/* param */; '\000' != *pcPorts; pcPorts = pcNext) { | |
if ((char *)0 == (pcNext = strchr(pcPorts, ':'))) | |
pcNext = ""; | |
else | |
*pcNext++ = '\000'; | |
if ((char *)0 != (pcServer = strchr(pcPorts, '@'))) { | |
*pcServer++ = '\000'; | |
if ('\000' != *pcServer) { | |
(void)strcpy(acExcg, pcServer); | |
} | |
} else if (isdigit(pcPorts[0])) { | |
(void)strcpy(acExcg, pcMaster); | |
} else { | |
(void)strcpy(acExcg, pcPorts); | |
pcPorts = ""; | |
} | |
if ('\000' == *pcPorts) { | |
#if defined(SERVICE) | |
/* in net order -- ksb */ | |
j = pSE->s_port; | |
#else | |
#if defined(PORT) | |
j = htons(PORT); | |
#else | |
fprintf(stderr, "%s: no port or service compiled in?\n", progname); | |
exit(8); | |
#endif | |
#endif | |
} else if (!isdigit(pcPorts[0])) { | |
/* XXX we should look up the service here */ | |
fprintf(stderr, "%s: %s: %s\n", progname, pcMaster, pcPorts); | |
iRet += 32; | |
continue; | |
} else { | |
j = htons((short)atoi(pcPorts)); | |
} | |
if (-1 == (s = GetPort(acExcg, & client_port, j))) { | |
iRet += 8; | |
} else { | |
if (0 != ReadReply(s, acMesg, sizeof(acMesg), "ok\r\n")) { | |
fprintf(stderr, "%s: %s: %s", progname, acExcg, acMesg); | |
iRet += 16; | |
} else { | |
iRet += (*pfi)(s, acExcg, pcTo, pcCmd, pcWho); | |
} | |
(void)close(s); | |
} | |
if ((char *)0 != pcServer) { | |
*pcServer = '@'; | |
} | |
} | |
return iRet; | |
} | |
static int SawUrg = 0; | |
#if DO_POWER | |
static char acPowCtl[128]; | |
/* We take a moment to call the power controller and ask (ksb) | |
* them about the console line we were chatting with. We'll be right | |
* back after this little diversion. | |
* For your enjoyment: note we can power a power controller as well. | |
*/ | |
int | |
Power(pcControl, pcLine, pcCurrent) | |
char *pcControl, *pcLine, *pcCurrent; | |
{ | |
register char *pcAt; | |
static int Indir(); | |
if ((char *)0 != (pcAt = strchr(pcControl, '@'))) { | |
*pcAt++ = '\000'; | |
} else { | |
pcAt = pcCurrent; | |
} | |
return Gather(Indir, pcAt, pcAt, pcControl, acPowCtl, pcLine); | |
} | |
#endif /* power controller */ | |
/* when the conserver program gets the suspend sequence it will send us | |
* an out of band command to suspend ourself. We just tell the reader | |
* routine we saw one | |
*/ | |
SIGRET_T | |
oob(sig) | |
int sig; | |
{ | |
++SawUrg; | |
} | |
/* interact with a group server (ksb) | |
*/ | |
static int | |
CallUp(s, pcMaster, pcMach, pcHow, pcUser) | |
int s; | |
char *pcMaster, *pcMach, *pcHow, *pcUser; | |
{ | |
register int nc; | |
register int fIn; | |
auto fd_set rmask, rinit; | |
extern int atoi(); | |
#if DO_POWER | |
auto char acCtlr[4096-128]; | |
#endif | |
if (fVerbose) { | |
printf("%s: %s to %s (%son %s)\n", progname, pcHow, pcMach, fRaw ? "raw " : "", pcMaster); | |
} | |
#if defined(F_SETOWN) | |
if (-1 == fcntl(s, F_SETOWN, getpid())) { | |
fprintf(stderr, "%s: fcntl: %d: %s\n", progname, s, strerror(errno)); | |
} | |
#else | |
#if defined(SIOCSPGRP) | |
{ | |
auto int iTemp; | |
/* on the HP-UX systems it is different | |
*/ | |
iTemp = -getpid(); | |
if (-1 == ioctl(s, SIOCSPGRP, & iTemp)) { | |
fprintf(stderr, "%s: ioctl: %d: %s\n", progname, s, strerror(errno)); | |
} | |
} | |
#endif | |
#endif | |
#if defined(SIGURG) | |
(void)signal(SIGURG, oob); | |
#endif | |
#if DO_POWER | |
if (acPowCtl == pcHow) { | |
return PowerCtl(s, acPowCtl, pcMach, pcMaster); | |
} | |
#endif | |
/* change escape sequence (if set on the command line) | |
* and replay the log for the user, if asked | |
*/ | |
if (chAttn == -1 || chEsc == -1) { | |
chAttn = DEFATTN; | |
chEsc = DEFESC; | |
} else { | |
/* tell the conserver to change escape sequences, assmue OK | |
* (we'll find out soon enough) | |
*/ | |
(void)sprintf(acMesg, "%c%ce%c%c", DEFATTN, DEFESC, chAttn, chEsc); | |
SendOut(s, acMesg, 5); | |
if (0 == ReadReply(s, acMesg, sizeof(acMesg), (char *)0)) { | |
fprintf(stderr, "protocol botch on redef of escape sequence\n"); | |
exit(8); | |
} | |
} | |
if (fVerbose) { | |
printf("Enter `"); | |
putCtlc(chAttn, stdout); | |
putCtlc(chEsc, stdout); | |
printf("?\' for help.\n"); | |
} | |
/* if we are going for a particular console | |
* send sign-on stuff, then wait for some indication of what mode | |
* we got from the server (if we are the only people on we get write | |
* access by default, which is fine for most people). | |
*/ | |
if (!fRaw) { | |
/* begin connect with who we are | |
*/ | |
(void)sprintf(acMesg, "%c%c;", chAttn, chEsc); | |
SendOut(s, acMesg, 3); | |
if (0 != ReadReply(s, acMesg, sizeof(acMesg), "[login:\r\n") && 0 != strcmp(acMesg, "\r\n[login:\r\n")) { | |
fprintf(stderr, "%s: call: %s\n", progname, acMesg); | |
exit(2); | |
} | |
(void)sprintf(acMesg, "%s@%s\n", pcUser, acThisHost); | |
SendOut(s, acMesg, strlen(acMesg)); | |
if (0 != ReadReply(s, acMesg, sizeof(acMesg), "host:\r\n")) { | |
fprintf(stderr, "%s: %s\n", progname, acMesg); | |
exit(2); | |
} | |
/* which host we want, and a passwd if asked for one | |
*/ | |
(void)sprintf(acMesg, "%s\n", pcMach); | |
SendOut(s, acMesg, strlen(acMesg)); | |
(void)ReadReply(s, acMesg, sizeof(acMesg), (char *)0); | |
if (0 == strcmp(acMesg, "passwd:")) { | |
auto char pass[32]; | |
(void)strcpy(pass, getpass("Enter password:")); | |
(void)sprintf(acMesg, "%s\n", pass); | |
SendOut(s, acMesg, strlen(acMesg)); | |
(void)ReadReply(s, acMesg, sizeof(acMesg), (char *)0); | |
} | |
/* how did we do, did we get a read-only or read-write? | |
*/ | |
if (0 == strcmp(acMesg, "attached]")) { | |
/* OK -- we are good as gold */ | |
fIn = 'a'; | |
} else if (0 == strcmp(acMesg, "spy]") || 0 == strcmp(acMesg, "ok]")) { | |
/* Humph, someone else is on | |
* or we have an old version of the server (4.X) | |
*/ | |
fIn = 's'; | |
} else if (0 == strcmp(acMesg, "host is read-only]")) { | |
fIn = 'r'; | |
} else if (0 == strcmp(acMesg, "line to host is down]")) { | |
/* ouch, the machine is down on the server */ | |
fIn = '-'; | |
fprintf(stderr, "%s: %s is down\n", progname, pcMach); | |
if (fVerbose) { | |
printf("[use `"); | |
putCtlc(chAttn, stdout); | |
putCtlc(chEsc, stdout); | |
printf("o\' to open console line]\n"); | |
} | |
} else if (0 == strcmp(acMesg, "no -- on ctl]")) { | |
fIn = '-'; | |
fprintf(stderr, "%s: %s is a control port\n", progname, pcMach); | |
if (fVerbose) { | |
printf("[use `"); | |
putCtlc(chAttn, stdout); | |
putCtlc(chEsc, stdout); | |
printf(";\' to open a console line]\n"); | |
} | |
} else { | |
fprintf(stderr, "%s: %s: %s\n", progname, pcMach, acMesg); | |
c2cooked(); | |
exit(5); | |
} | |
} | |
/* if the host is not down, finish the connection, and force | |
* the correct attachment for the user | |
*/ | |
if ('-' != fIn) { | |
if (fIn == 'r') { | |
if ('s' != *pcHow) { | |
fprintf(stderr, "%s: %s is read-only\n", progname, pcMach); | |
} | |
} else if (fIn != ('f' == *pcHow ? 'a' : *pcHow)) { | |
(void)sprintf(acMesg, "%c%c%c", chAttn, chEsc, *pcHow); | |
SendOut(s, acMesg, 3); | |
} | |
if (fReplay) { | |
(void)sprintf(acMesg, "%c%cr", chAttn, chEsc); | |
SendOut(s, acMesg, 3); | |
} else if (fVerbose) { | |
(void)sprintf(acMesg, "%c%c\022", chAttn, chEsc); | |
SendOut(s, acMesg, 3); | |
} | |
} | |
(void)fflush(stdout); | |
(void)fflush(stderr); | |
c2raw(); | |
/* read from stdin and the socket (non-blocking!). | |
* rmask indicates which descriptors to read from, | |
* the others are not used, nor is the result from | |
* select, read, or write. | |
*/ | |
FD_ZERO(& rinit); | |
FD_SET(s, &rinit); | |
FD_SET(0, &rinit); | |
for (;;) { | |
/* reset read mask and select on it | |
*/ | |
rmask = rinit; | |
while (-1 == select(sizeof(rmask)*8, &rmask, (fd_set *)0, (fd_set *)0, (struct timeval *)0)) { | |
static char acCmd[64]; | |
rmask = rinit; | |
/* if we were suspened, try again */ | |
if (EINTR != errno || !SawUrg) { | |
continue; | |
} | |
SawUrg = 0; | |
#if defined(SIGURG) | |
(void)signal(SIGURG, oob); | |
#endif | |
/* get the pending urgent message | |
*/ | |
while (recv(s, acCmd, 1, MSG_OOB) < 0) { | |
switch (errno) { | |
case EWOULDBLOCK: | |
/* clear any pending input to make room */ | |
(void)read(s, acCmd, sizeof(acCmd)); | |
CSTROUT(1, "."); | |
continue; | |
case EINVAL: | |
default: | |
fprintf(stderr, "%s: recv: %d: %s\r\n", progname, s, strerror(errno)); | |
sleep(1); | |
continue; | |
} | |
} | |
switch (acCmd[0]) { | |
case OB_SUSP: | |
#if defined(SIGSTOP) | |
CSTROUT(1, "stop]"); | |
c2cooked(); | |
(void)kill(getpid(), SIGSTOP); | |
c2raw(); | |
CSTROUT(1, "[press any character to continue"); | |
#else | |
CSTROUT(1, "stop not supported -- press any character to continue"); | |
#endif | |
break; | |
case OB_DROP: | |
CSTROUT(1, "dropped by server]\r\n"); | |
c2cooked(); | |
exit(1); | |
/*NOTREACHED*/ | |
case OB_POWER: | |
#if DO_POWER | |
CSTROUT(1, "power"); | |
/* get address to call and prefix */ | |
SendOut(s, "k", 1); | |
if (0 == ReadReply(s, acPowCtl, sizeof(acPowCtl), (char *)0)) { | |
CSTROUT(1, "no key"); | |
SendOut(s, "b", 1); | |
break; | |
} | |
SendOut(s, "s", 1); | |
if (0 == ReadReply(s, acCtlr, sizeof(acCtlr), (char *)0)) { | |
CSTROUT(1, "no controller"); | |
SendOut(s, "b", 1); | |
break; | |
} | |
Power(acCtlr, pcMach, pcMaster); | |
#else | |
CSTROUT(1, "no client support"); | |
#endif | |
SendOut(s, "b", 1); | |
break; | |
default: | |
fprintf(stderr, "%s: unknown out of band command `%c\'\r\n", progname, acCmd[0]); | |
(void)fflush(stderr); | |
break; | |
} | |
} | |
/* anything from socket? */ | |
if (FD_ISSET(s, &rmask)) { | |
if ((nc = read(s, acMesg, sizeof(acMesg))) == 0) { | |
break; | |
} | |
#if STRIP8 | |
/* clear parity? */ | |
for (i = 0; i < nc; ++i) | |
acMesg[i] &= 127; | |
#endif | |
SendOut(1, acMesg, nc); | |
} | |
/* anything from stdin? */ | |
if (FD_ISSET(0, &rmask)) { | |
if ((nc = read(0, acMesg, sizeof(acMesg))) == 0) | |
break; | |
SendOut(s, acMesg, nc); | |
} | |
} | |
c2cooked(); | |
if (fVerbose) | |
printf("Console %s closed.\n", pcMach); | |
return 0; | |
} | |
/* the group leader tells is the server to connect to (ksb) | |
* we use CallUp to start a session with each target, or forward it | |
*/ | |
static int | |
Indir(s, pcMaster, pcMach, pcCmd, pcWho) | |
int s; | |
char *pcMaster, *pcMach, *pcCmd, *pcWho; | |
{ | |
auto char acPorts[4097]; | |
/* send request for master list | |
*/ | |
(void)sprintf(acPorts, "call:%s\r\n", pcMach); | |
SendOut(s, acPorts, strlen(acPorts)); | |
/* get the ports number */ | |
if (0 >= ReadReply(s, acPorts, sizeof(acPorts), (char *)0)) { | |
fprintf(stderr, "%s: %s: call forward broken\n", progname, pcMaster); | |
exit(1); | |
} | |
if ('@' == acPorts[0]) { | |
static int iLimit = 0; | |
if (iLimit++ > 10) { | |
fprintf(stderr, "%s: forwarding level too deep!\n", progname); | |
return 1; | |
} | |
return Gather(Indir, acPorts, pcMaster, pcMach, pcCmd, pcWho); | |
} | |
/* send the command to each master | |
*/ | |
return Gather(CallUp, acPorts, pcMaster, pcMach, pcCmd, pcWho); | |
} | |
#define BUF_G1 (MAXGRP*80) | |
#define BUF_MIN 80 | |
#define BUF_CHUNK (2*132) | |
/* Cmd is implemented seperately from above because of the need buffer (ksb) | |
* the ports' output. It's about the same as what's above otherwise. | |
* We trick lint because we have to be call compatible (prototype'd) | |
* the same as all the other Gather functions. | |
*/ | |
/*ARGSUSED*/ | |
static int | |
Cmd(s, pcMaster, pcMach, pcCmd, pcWho) | |
int s; | |
char *pcMaster, *pcMach, *pcCmd, *pcWho; | |
{ | |
static int iMax = 0; | |
static char *pcBuf = (char *)0; | |
register int nr, iRem, i, fBrace; | |
/* setup the big buffer for the server output | |
*/ | |
if ((char *)0 == pcBuf) { | |
iMax = BUF_G1; | |
if ((char *)0 == (pcBuf = calloc(BUF_G1, sizeof(char)))) { | |
OutOfMem(); | |
} | |
} | |
/* send sign-on stuff, then wait for a reply, like "ok\r\n" | |
* before allowing a write | |
*/ | |
(void)sprintf(acMesg, "%c%c%c%c%c.", DEFATTN, DEFESC, *pcCmd, DEFATTN, DEFESC); | |
SendOut(s, acMesg, 6); | |
/* read the server's reply, | |
* We buffer until we close the connection because it | |
* wouldn't be fair to ask the server to keep up with | |
* itself :-) {if we are inside a console connection}. | |
*/ | |
iRem = iMax; | |
i = 0; | |
while (0 < (nr = read(s, pcBuf+i, iRem))) { | |
i += nr; | |
iRem -= nr; | |
if (iRem >= BUF_MIN) { | |
continue; | |
} | |
iMax += BUF_CHUNK; | |
if ((char *)0 == (pcBuf = realloc(pcBuf, iMax))) { | |
OutOfMem(); | |
} | |
iRem += BUF_CHUNK; | |
} | |
/* edit out the command lines [...] | |
*/ | |
iRem = fBrace = 0; | |
for (nr = 0; nr < i; ++nr) { | |
if (0 != fBrace) { | |
if (']' == pcBuf[nr]) { | |
fBrace = 0; | |
} | |
continue; | |
} | |
switch (pcBuf[nr]) { | |
case '\r': | |
if (0 == iRem) | |
continue; | |
break; | |
case '\n': | |
if (0 == iRem) | |
continue; | |
(void)putchar('\n'); | |
iRem = 0; | |
continue; | |
case '[': | |
fBrace = 1; | |
continue; | |
} | |
(void)putchar(pcBuf[nr]); | |
iRem = 1; | |
} | |
(void)fflush(stdout); | |
return 0; | |
} | |
/* the masters tell us the group masters with a "groups" command (ksb) | |
*/ | |
static int | |
CmdGroup(s, pcMaster, pcMach, pcCmd, pcWho) | |
int s; | |
char *pcMaster, *pcMach, *pcCmd, *pcWho; | |
{ | |
auto char acPorts[4097]; | |
register int iNull; | |
/* send request for master list | |
*/ | |
(void)sprintf(acPorts, "groups\r\n", pcCmd); | |
SendOut(s, acPorts, strlen(acPorts)); | |
/* get the port numbers for the groups on this master | |
*/ | |
if (0 > (iNull = ReadReply(s, acPorts, sizeof(acPorts), (char *)0))) { | |
fprintf(stderr, "%s: %s: group forward broken\n", progname, pcMaster); | |
exit(1); | |
} | |
/* an empty list means this console server node _just_ forwards | |
*/ | |
if (0 == iNull) { | |
if (fVerbose) { | |
printf("%s:<none>\r\n", pcMaster); | |
} | |
return 0; | |
} | |
if (fVerbose) { | |
printf("%s:\r\n", pcMaster); | |
} | |
/* to the command to each master | |
*/ | |
return Gather(Cmd, acPorts, pcMaster, pcMach, pcCmd, pcWho); | |
} | |
/* the master tells us the machine masters with a "master" command (ksb) | |
* we ask each of those for the group members | |
*/ | |
static int | |
CmdMaster(s, pcMaster, pcMach, pcCmd, pcWho) | |
int s; | |
char *pcMaster, *pcMach, *pcCmd, *pcWho; | |
{ | |
auto char acPorts[4097]; | |
register int iNull; | |
/* send request for master list | |
*/ | |
CSTROUT(s, "master\r\n"); | |
/* get the ports number */ | |
if (0 > (iNull = ReadReply(s, acPorts, sizeof(acPorts), (char *)0))) { | |
fprintf(stderr, "%s: %s: master forward broken\n", progname, pcMaster); | |
exit(1); | |
} | |
if (0 == iNull) { | |
if (fVerbose) { | |
printf("%s: master list empyt\r\n", pcMaster); | |
} | |
return 0; | |
} | |
if (fVerbose) { | |
printf("%s: %s\r\n", pcMaster, acPorts); | |
} | |
/* to the command to each master | |
*/ | |
return Gather(CmdGroup, acPorts, pcMaster, pcMach, pcCmd, pcWho); | |
} | |
/* The masters tell us the group masters with a "groups" command. (ksb) | |
* We trick lint because we have to be call compatible (prototype'd) | |
* the same as all the other Gather functions. | |
*/ | |
/*ARGSUSED*/ | |
static int | |
Ctl(s, pcMaster, pcMach, pcCmd, pcWho) | |
int s; | |
char *pcMaster, *pcMach, *pcCmd, *pcWho; | |
{ | |
auto char acPorts[4097]; | |
/* send request for master list | |
*/ | |
(void)sprintf(acPorts, "%s:%s\r\n", pcCmd, pcMach); | |
SendOut(s, acPorts, strlen(acPorts)); | |
/* get the ports number */ | |
if (0 >= ReadReply(s, acPorts, sizeof(acPorts), (char *)0)) { | |
fprintf(stderr, "%s: group leader died?\n", progname); | |
return 1; | |
} | |
if (fVerbose) { | |
printf("%s:\r\n", pcMaster); | |
} | |
printf("%s: %s\r\n", pcMaster, acPorts); | |
/* to the command to each master | |
*/ | |
return 0; | |
} | |
/* the master tells us the machine masters with a "master" command (ksb) | |
* we tell each of those the command we want them to do | |
*/ | |
static int | |
CtlMaster(s, pcMaster, pcMach, pcCmd, pcWho) | |
int s; | |
char *pcMaster, *pcMach, *pcCmd, *pcWho; | |
{ | |
auto char acPorts[4097]; | |
/* send request for master list | |
*/ | |
CSTROUT(s, "master\r\n"); | |
/* get the ports number */ | |
if (0 >= ReadReply(s, acPorts, sizeof(acPorts), (char *)0)) { | |
fprintf(stderr, "%s: %s: master forward broken\n", progname, pcMaster); | |
exit(1); | |
} | |
/* to the command to each master | |
*/ | |
return Gather(Ctl, acPorts, pcMaster, pcMach, pcCmd, pcWho); | |
} | |
%% | |
from '<pwd.h>' | |
%c | |
/* get the user's password entry name, believe $USER or $LOGNAME (ksb) | |
* if they have the correct uid | |
*/ | |
char * | |
FindUser(pcOut) | |
char *pcOut; | |
{ | |
register char *pcEnv; | |
register struct passwd *pwdMe; | |
if (((char *)0 != (pcEnv = getenv("USER")) || (char *)0 != (pcEnv = getenv("LOGNAME"))) && | |
(struct passwd *)0 != (pwdMe = getpwnam(pcEnv)) && | |
getuid() == pwdMe->pw_uid) { | |
/* use the login $USER is set to, if it is our (real) uid */; | |
} else if ((struct passwd *)0 == (pwdMe = getpwuid(getuid()))) { | |
fprintf(stderr, "%s: getpwuid: %d: %s\n", progname, getuid(), strerror(errno)); | |
exit(1); | |
} | |
return strcpy(pcOut, pwdMe->pw_name); | |
} | |
/* Lookup runtime information, like the loopback interface address (ksb) | |
* to use (should be 127.0.0.1, but let's look) and the service if | |
* we don't know the port. | |
*/ | |
static void | |
RunTime() | |
{ | |
register struct hostent *hp; | |
if ((struct hostent *)0 != (hp = gethostbyname(acLocalhost))) { | |
#if USE_STRINGS | |
(void)bcopy((char *)hp->h_addr, (char *)&local_port.sin_addr, hp->h_length); | |
#else | |
memcpy((char *)&local_port.sin_addr, (char *)hp->h_addr, hp->h_length); | |
#endif | |
} else { | |
acLocalhost[0] = '\000'; | |
} | |
if (-1 == gethostname(acMyName, sizeof(acMyName))) { | |
fprintf(stderr, "%s: gethostname: %s\n", progname, strerror(errno)); | |
exit(1); | |
} | |
#if defined(SERVICE) | |
if ((struct servent *)0 == (pSE = getservbyname(acService, "tcp"))) { | |
fprintf(stderr, "%s: getservbyname: %s: %s\n", progname, acService, strerror(errno)); | |
exit(1); | |
} | |
#endif | |
} | |
/* like the above, but we signal the console server with a USR2 (ksb) | |
*/ | |
/*ARGSUSED*/ | |
static int | |
CtlSignal(s, pcMaster, pcMach, pcCmd, pcWho) | |
int s; | |
char *pcMaster, *pcMach, *pcCmd, *pcWho; | |
{ | |
register int iPid; | |
auto char acPorts[4097]; | |
/* send request for master list | |
*/ | |
(void)sprintf(acPorts, "%s:%s\r\n", pcCmd, pcMach); | |
SendOut(s, acPorts, strlen(acPorts)); | |
/* get the ports number */ | |
if (0 >= ReadReply(s, acPorts, sizeof(acPorts), (char *)0)) { | |
fprintf(stderr, "%s: group leader died?\n", progname); | |
return 1; | |
} | |
iPid = atoi(acPorts); | |
if (fVerbose) { | |
printf("%s: kill -USR2 %d\r\n", pcMaster, iPid); | |
} | |
return -1 == kill(iPid, SIGUSR2); | |
} | |
%% |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment