Files
Arquivotheca.SunOS-4.1.4/etc/rmt.c
seta75D ff309bfe1c Init
2021-10-11 18:37:13 -03:00

264 lines
5.6 KiB
C

#ifndef lint
static char *sccsid = "@(#)rmt.c 1.1 94/10/31 SMI"; /* from CalTech */
#endif not lint
/*
* Multi-process streaming 4.3bsd /etc/rmt server.
* Has three locks (for stdin, stdout, and the tape)
* that are passed by signals and received by sigpause().
*/
#include <stdio.h>
#include <signal.h>
#include <setjmp.h>
#include <sys/types.h>
#include <sys/ioctl.h>
#include <sys/mtio.h>
struct mtop mtop;
struct mtget mtget;
extern long atol();
extern int errno;
jmp_buf sjbuf;
#define RECV SIGIO
#define TAPE SIGURG
#define SEND SIGALRM
#define ERROR SIGTERM
#define OPEN SIGUSR1
#define CLOSE SIGUSR2
#define CMDMASK (sigmask(RECV) | sigmask(OPEN) | sigmask(CLOSE) | sigmask(ERROR))
#define MASKALL (CMDMASK | sigmask(TAPE) | sigmask(SEND))
#define MAXCHILD 1
int children, childpid[MAXCHILD];
int tape = -1;
int maxrecsize;
char *record;
#define SSIZE 64
char device[SSIZE], pos[SSIZE], op[SSIZE], mode[SSIZE], count[SSIZE];
FILE *debug;
#define DEBUG(f) if (debug) fprintf(debug, f)
#define DEBUG1(f,a) if (debug) fprintf(debug, f, a)
#define DEBUG2(f,a1,a2) if (debug) fprintf(debug, f, a1, a2)
char key;
catch(sig)
int sig;
{
switch (sig) {
default: return;
case OPEN: key = 'O'; break;
case CLOSE: key = 'C'; break;
case ERROR: key = 'E'; break;
}
longjmp(sjbuf, 1);
}
main(argc, argv)
int argc;
char *argv[];
{
int parent = getpid(), next = parent;
register int n, i, cc, rval, saverr;
if (argc > 1) {
if ((debug=fopen(argv[1], "w")) == NULL)
exit(1);
setbuf(debug, NULL);
}
signal(RECV, catch);
signal(SEND, catch);
signal(TAPE, catch);
signal(OPEN, catch);
signal(CLOSE, catch);
signal(ERROR, catch);
sigblock(MASKALL);
kill(parent, TAPE);
kill(parent, SEND);
while (read(0, &key, 1) == 1) {
switch (key) {
case 'L': /* lseek */
getstring(count);
getstring(pos);
DEBUG2("rmtd: L %s %s\n", count, pos);
kill(next, RECV);
sigpause(MASKALL &~ sigmask(TAPE));
rval = lseek(tape, atol(count), atoi(pos));
saverr = errno;
kill(next, TAPE);
sigpause(MASKALL &~ sigmask(SEND));
respond(rval, saverr);
break;
case 'I': /* ioctl */
getstring(op);
getstring(count);
DEBUG2("rmtd: I %s %s\n", op, count);
mtop.mt_op = atoi(op);
mtop.mt_count = atoi(count);
kill(next, RECV);
sigpause(MASKALL &~ sigmask(TAPE));
rval = ioctl(tape, MTIOCTOP, (char *)&mtop);
saverr = errno;
kill(next, TAPE);
sigpause(MASKALL &~ sigmask(SEND));
respond(rval < 0 ? rval : mtop.mt_count, saverr);
break;
case 'S': /* status */
DEBUG("rmtd: S\n");
kill(next, RECV);
sigpause(MASKALL &~ sigmask(TAPE));
rval = ioctl(tape, MTIOCGET, (char *)&mtget);
saverr = errno;
kill(next, TAPE);
sigpause(MASKALL &~ sigmask(SEND));
if (rval < 0)
respond(rval, saverr);
else {
respond(sizeof(mtget), saverr);
write(1, (char *)&mtget, sizeof(mtget));
}
break;
case 'W':
getstring(count);
n = atoi(count);
checkbuf(n);
DEBUG1("rmtd: W %s\n", count);
for (i = 0; i < n; i += cc) {
cc = read(0, &record[i], n - i);
if (cc <= 0) {
DEBUG("rmtd: premature eof\n");
exit(2);
}
}
kill(next, RECV);
sigpause(MASKALL &~ sigmask(TAPE));
rval = write(tape, record, n);
saverr = errno;
kill(next, TAPE);
sigpause(MASKALL &~ sigmask(SEND));
respond(rval, saverr);
break;
case 'R':
getstring(count);
n = atoi(count);
checkbuf(n);
DEBUG1("rmtd: R %s\n", count);
kill(next, RECV);
sigpause(MASKALL &~ sigmask(TAPE));
rval = read(tape, record, n);
saverr = errno;
kill(next, TAPE);
sigpause(MASKALL &~ sigmask(SEND));
respond(rval, saverr);
write(1, record, rval);
break;
default:
DEBUG1("rmtd: garbage command %c\n", key);
/*FALLTHROUGH*/
case 'C':
case 'O':
/* rendezvous back into a single process */
if (setjmp(sjbuf) == 0 || getpid() != parent) {
sigpause(MASKALL &~ sigmask(TAPE));
sigpause(MASKALL &~ sigmask(SEND));
kill(parent, key == 'O' ? OPEN :
key == 'C' ? CLOSE : ERROR);
sigpause(0);
}
while (children > 0) {
kill(childpid[--children], SIGKILL);
while (wait(NULL) != childpid[children])
;
}
next = parent;
if (key == 'C') {
getstring(device);
DEBUG1("rmtd: C %s\n", device);
rval = close(tape);
respond(rval, errno);
kill(parent, TAPE);
kill(parent, SEND);
continue;
}
if (key != 'O') /* garbage command */
exit(3);
close(tape);
getstring(device);
getstring(mode);
DEBUG2("rmtd: O %s %s\n", device, mode);
tape = open(device, atoi(mode));
respond(tape, errno);
if (tape >= 0) /* fork off */
while (children < MAXCHILD &&
(childpid[children] = fork()) > 0)
next = childpid[children++];
if (next == parent) {
kill(parent, RECV);
kill(parent, TAPE);
kill(parent, SEND);
}
sigpause(MASKALL &~ CMDMASK);
continue;
}
kill(next, SEND);
sigpause(MASKALL &~ CMDMASK);
}
kill(next, RECV);
exit(0);
/* NOTREACHED */
}
respond(rval, errno)
register int rval, errno;
{
extern char *sys_errlist[];
char resp[SSIZE];
if (rval < 0) {
sprintf(resp, "E%d\n%s\n", errno, sys_errlist[errno]);
DEBUG2("rmtd: E %d (%s)\n", errno, sys_errlist[errno]);
} else {
sprintf(resp, "A%d\n", rval);
DEBUG1("rmtd: A %d\n", rval);
}
write(1, resp, strlen(resp));
}
getstring(cp)
register char *cp;
{
do {
if (read(0, cp, 1) != 1)
exit(0);
} while (*cp++ != '\n');
*--cp = '\0';
}
checkbuf(size)
unsigned size;
{
extern char *malloc();
if (size <= maxrecsize)
return;
if (record != 0)
free(record);
if ((record=malloc(size)) == NULL) {
DEBUG("rmtd: cannot allocate buffer space\n");
exit(4);
}
maxrecsize = size;
}