rmt.c revision 7707
11553Srgrimes/*
21553Srgrimes * Copyright (c) 1983, 1993
31553Srgrimes *	The Regents of the University of California.  All rights reserved.
41553Srgrimes *
51553Srgrimes * Redistribution and use in source and binary forms, with or without
61553Srgrimes * modification, are permitted provided that the following conditions
71553Srgrimes * are met:
81553Srgrimes * 1. Redistributions of source code must retain the above copyright
91553Srgrimes *    notice, this list of conditions and the following disclaimer.
101553Srgrimes * 2. Redistributions in binary form must reproduce the above copyright
111553Srgrimes *    notice, this list of conditions and the following disclaimer in the
121553Srgrimes *    documentation and/or other materials provided with the distribution.
131553Srgrimes * 3. All advertising materials mentioning features or use of this software
141553Srgrimes *    must display the following acknowledgement:
151553Srgrimes *	This product includes software developed by the University of
161553Srgrimes *	California, Berkeley and its contributors.
171553Srgrimes * 4. Neither the name of the University nor the names of its contributors
181553Srgrimes *    may be used to endorse or promote products derived from this software
191553Srgrimes *    without specific prior written permission.
201553Srgrimes *
211553Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
221553Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
231553Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
241553Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
251553Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
261553Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
271553Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
281553Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
291553Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
301553Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
311553Srgrimes * SUCH DAMAGE.
321553Srgrimes */
331553Srgrimes
341553Srgrimes#ifndef lint
351553Srgrimesstatic char copyright[] =
361553Srgrimes"@(#) Copyright (c) 1983, 1993\n\
371553Srgrimes	The Regents of the University of California.  All rights reserved.\n";
381553Srgrimes#endif /* not lint */
391553Srgrimes
401553Srgrimes#ifndef lint
411553Srgrimesstatic char sccsid[] = "@(#)rmt.c	8.1 (Berkeley) 6/6/93";
421553Srgrimes#endif /* not lint */
431553Srgrimes
441553Srgrimes/*
451553Srgrimes * rmt
461553Srgrimes */
471553Srgrimes#include <sys/types.h>
481553Srgrimes#include <sys/socket.h>
491553Srgrimes#include <sys/mtio.h>
501553Srgrimes#include <errno.h>
511553Srgrimes#include <fcntl.h>
521553Srgrimes#include <sgtty.h>
531553Srgrimes#include <stdio.h>
541553Srgrimes#include <stdlib.h>
551553Srgrimes#include <string.h>
561553Srgrimes#include <unistd.h>
571553Srgrimes
581553Srgrimesint	tape = -1;
591553Srgrimes
601553Srgrimeschar	*record;
611553Srgrimesint	maxrecsize = -1;
621553Srgrimes
631553Srgrimes#define	SSIZE	64
641553Srgrimeschar	device[SSIZE];
651553Srgrimeschar	count[SSIZE], mode[SSIZE], pos[SSIZE], op[SSIZE];
661553Srgrimes
671553Srgrimeschar	resp[BUFSIZ];
681553Srgrimes
691553SrgrimesFILE	*debug;
701553Srgrimes#define	DEBUG(f)	if (debug) fprintf(debug, f)
711553Srgrimes#define	DEBUG1(f,a)	if (debug) fprintf(debug, f, a)
721553Srgrimes#define	DEBUG2(f,a1,a2)	if (debug) fprintf(debug, f, a1, a2)
731553Srgrimes
741553Srgrimeschar	*checkbuf __P((char *, int));
751553Srgrimesvoid	 error __P((int));
761553Srgrimesvoid	 getstring __P((char *));
771553Srgrimes
781553Srgrimesint
791553Srgrimesmain(argc, argv)
801553Srgrimes	int argc;
811553Srgrimes	char **argv;
821553Srgrimes{
831553Srgrimes	int rval;
841553Srgrimes	char c;
851553Srgrimes	int n, i, cc;
861553Srgrimes
871553Srgrimes	argc--, argv++;
881553Srgrimes	if (argc > 0) {
891553Srgrimes		debug = fopen(*argv, "w");
901553Srgrimes		if (debug == 0)
911553Srgrimes			exit(1);
921553Srgrimes		(void)setbuf(debug, (char *)0);
931553Srgrimes	}
941553Srgrimestop:
951553Srgrimes	errno = 0;
961553Srgrimes	rval = 0;
971553Srgrimes	if (read(0, &c, 1) != 1)
981553Srgrimes		exit(0);
991553Srgrimes	switch (c) {
1001553Srgrimes
1011553Srgrimes	case 'O':
1021553Srgrimes		if (tape >= 0)
1031553Srgrimes			(void) close(tape);
1041553Srgrimes		getstring(device);
1051553Srgrimes		getstring(mode);
1061553Srgrimes		DEBUG2("rmtd: O %s %s\n", device, mode);
1077707Sjoerg		/*
1087707Sjoerg		 * XXX the rmt protocol does not provide a means to
1097707Sjoerg		 * specify the permission bits; allow rw for everyone,
1107707Sjoerg		 * as modified by the users umask
1117707Sjoerg		 */
1127707Sjoerg		tape = open(device, atoi(mode), 0666);
1131553Srgrimes		if (tape < 0)
1141553Srgrimes			goto ioerror;
1151553Srgrimes		goto respond;
1161553Srgrimes
1171553Srgrimes	case 'C':
1181553Srgrimes		DEBUG("rmtd: C\n");
1191553Srgrimes		getstring(device);		/* discard */
1201553Srgrimes		if (close(tape) < 0)
1211553Srgrimes			goto ioerror;
1221553Srgrimes		tape = -1;
1231553Srgrimes		goto respond;
1241553Srgrimes
1251553Srgrimes	case 'L':
1261553Srgrimes		getstring(count);
1271553Srgrimes		getstring(pos);
1281553Srgrimes		DEBUG2("rmtd: L %s %s\n", count, pos);
1291553Srgrimes		rval = lseek(tape, (off_t)atol(count), atoi(pos));
1301553Srgrimes		if (rval < 0)
1311553Srgrimes			goto ioerror;
1321553Srgrimes		goto respond;
1331553Srgrimes
1341553Srgrimes	case 'W':
1351553Srgrimes		getstring(count);
1361553Srgrimes		n = atoi(count);
1371553Srgrimes		DEBUG1("rmtd: W %s\n", count);
1381553Srgrimes		record = checkbuf(record, n);
1391553Srgrimes		for (i = 0; i < n; i += cc) {
1401553Srgrimes			cc = read(0, &record[i], n - i);
1411553Srgrimes			if (cc <= 0) {
1421553Srgrimes				DEBUG("rmtd: premature eof\n");
1431553Srgrimes				exit(2);
1441553Srgrimes			}
1451553Srgrimes		}
1461553Srgrimes		rval = write(tape, record, n);
1471553Srgrimes		if (rval < 0)
1481553Srgrimes			goto ioerror;
1491553Srgrimes		goto respond;
1501553Srgrimes
1511553Srgrimes	case 'R':
1521553Srgrimes		getstring(count);
1531553Srgrimes		DEBUG1("rmtd: R %s\n", count);
1541553Srgrimes		n = atoi(count);
1551553Srgrimes		record = checkbuf(record, n);
1561553Srgrimes		rval = read(tape, record, n);
1571553Srgrimes		if (rval < 0)
1581553Srgrimes			goto ioerror;
1591553Srgrimes		(void)sprintf(resp, "A%d\n", rval);
1601553Srgrimes		(void)write(1, resp, strlen(resp));
1611553Srgrimes		(void)write(1, record, rval);
1621553Srgrimes		goto top;
1631553Srgrimes
1641553Srgrimes	case 'I':
1651553Srgrimes		getstring(op);
1661553Srgrimes		getstring(count);
1671553Srgrimes		DEBUG2("rmtd: I %s %s\n", op, count);
1681553Srgrimes		{ struct mtop mtop;
1691553Srgrimes		  mtop.mt_op = atoi(op);
1701553Srgrimes		  mtop.mt_count = atoi(count);
1711553Srgrimes		  if (ioctl(tape, MTIOCTOP, (char *)&mtop) < 0)
1721553Srgrimes			goto ioerror;
1731553Srgrimes		  rval = mtop.mt_count;
1741553Srgrimes		}
1751553Srgrimes		goto respond;
1761553Srgrimes
1771553Srgrimes	case 'S':		/* status */
1781553Srgrimes		DEBUG("rmtd: S\n");
1791553Srgrimes		{ struct mtget mtget;
1801553Srgrimes		  if (ioctl(tape, MTIOCGET, (char *)&mtget) < 0)
1811553Srgrimes			goto ioerror;
1821553Srgrimes		  rval = sizeof (mtget);
1831553Srgrimes		  (void)sprintf(resp, "A%d\n", rval);
1841553Srgrimes		  (void)write(1, resp, strlen(resp));
1851553Srgrimes		  (void)write(1, (char *)&mtget, sizeof (mtget));
1861553Srgrimes		  goto top;
1871553Srgrimes		}
1881553Srgrimes
1891553Srgrimes	default:
1901553Srgrimes		DEBUG1("rmtd: garbage command %c\n", c);
1911553Srgrimes		exit(3);
1921553Srgrimes	}
1931553Srgrimesrespond:
1941553Srgrimes	DEBUG1("rmtd: A %d\n", rval);
1951553Srgrimes	(void)sprintf(resp, "A%d\n", rval);
1961553Srgrimes	(void)write(1, resp, strlen(resp));
1971553Srgrimes	goto top;
1981553Srgrimesioerror:
1991553Srgrimes	error(errno);
2001553Srgrimes	goto top;
2011553Srgrimes}
2021553Srgrimes
2031553Srgrimesvoid
2041553Srgrimesgetstring(bp)
2051553Srgrimes	char *bp;
2061553Srgrimes{
2071553Srgrimes	int i;
2081553Srgrimes	char *cp = bp;
2091553Srgrimes
2101553Srgrimes	for (i = 0; i < SSIZE; i++) {
2111553Srgrimes		if (read(0, cp+i, 1) != 1)
2121553Srgrimes			exit(0);
2131553Srgrimes		if (cp[i] == '\n')
2141553Srgrimes			break;
2151553Srgrimes	}
2161553Srgrimes	cp[i] = '\0';
2171553Srgrimes}
2181553Srgrimes
2191553Srgrimeschar *
2201553Srgrimescheckbuf(record, size)
2211553Srgrimes	char *record;
2221553Srgrimes	int size;
2231553Srgrimes{
2241553Srgrimes
2251553Srgrimes	if (size <= maxrecsize)
2261553Srgrimes		return (record);
2271553Srgrimes	if (record != 0)
2281553Srgrimes		free(record);
2291553Srgrimes	record = malloc(size);
2301553Srgrimes	if (record == 0) {
2311553Srgrimes		DEBUG("rmtd: cannot allocate buffer space\n");
2321553Srgrimes		exit(4);
2331553Srgrimes	}
2341553Srgrimes	maxrecsize = size;
2351553Srgrimes	while (size > 1024 &&
2361553Srgrimes	       setsockopt(0, SOL_SOCKET, SO_RCVBUF, &size, sizeof (size)) < 0)
2371553Srgrimes		size -= 1024;
2381553Srgrimes	return (record);
2391553Srgrimes}
2401553Srgrimes
2411553Srgrimesvoid
2421553Srgrimeserror(num)
2431553Srgrimes	int num;
2441553Srgrimes{
2451553Srgrimes
2461553Srgrimes	DEBUG2("rmtd: E %d (%s)\n", num, strerror(num));
2471553Srgrimes	(void)sprintf(resp, "E%d\n%s\n", num, strerror(num));
2481553Srgrimes	(void)write(1, resp, strlen(resp));
2491553Srgrimes}
250