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 * 4. Neither the name of the University nor the names of its contributors
141553Srgrimes *    may be used to endorse or promote products derived from this software
151553Srgrimes *    without specific prior written permission.
161553Srgrimes *
171553Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
181553Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
191553Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
201553Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
211553Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
221553Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
231553Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
241553Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
251553Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
261553Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
271553Srgrimes * SUCH DAMAGE.
281553Srgrimes */
291553Srgrimes
30114601Sobrien#if 0
311553Srgrimes#ifndef lint
3230374Scharnierstatic const char copyright[] =
331553Srgrimes"@(#) Copyright (c) 1983, 1993\n\
341553Srgrimes	The Regents of the University of California.  All rights reserved.\n";
351553Srgrimes#endif /* not lint */
361553Srgrimes
371553Srgrimes#ifndef lint
381553Srgrimesstatic char sccsid[] = "@(#)rmt.c	8.1 (Berkeley) 6/6/93";
39114601Sobrien#endif /* not lint */
4030374Scharnier#endif
41114601Sobrien#include <sys/cdefs.h>
42114601Sobrien__FBSDID("$FreeBSD$");
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 <stdio.h>
531553Srgrimes#include <stdlib.h>
541553Srgrimes#include <string.h>
551553Srgrimes#include <unistd.h>
561553Srgrimes
57227259Sedstatic int	tape = -1;
581553Srgrimes
59227259Sedstatic char	*record;
60227259Sedstatic int	maxrecsize = -1;
611553Srgrimes
621553Srgrimes#define	SSIZE	64
63227259Sedstatic char	device[SSIZE];
64227259Sedstatic char	count[SSIZE], mode[SSIZE], pos[SSIZE], op[SSIZE];
651553Srgrimes
66227259Sedstatic char	resp[BUFSIZ];
671553Srgrimes
68227259Sedstatic FILE	*debug;
691553Srgrimes#define	DEBUG(f)	if (debug) fprintf(debug, f)
701553Srgrimes#define	DEBUG1(f,a)	if (debug) fprintf(debug, f, a)
711553Srgrimes#define	DEBUG2(f,a1,a2)	if (debug) fprintf(debug, f, a1, a2)
721553Srgrimes
73227259Sedstatic char	*checkbuf(char *, int);
74227259Sedstatic void	 error(int);
75227259Sedstatic void	 getstring(char *);
761553Srgrimes
771553Srgrimesint
7899822Salfredmain(int argc, char **argv)
791553Srgrimes{
801553Srgrimes	int rval;
811553Srgrimes	char c;
821553Srgrimes	int n, i, cc;
831553Srgrimes
841553Srgrimes	argc--, argv++;
851553Srgrimes	if (argc > 0) {
861553Srgrimes		debug = fopen(*argv, "w");
871553Srgrimes		if (debug == 0)
881553Srgrimes			exit(1);
891553Srgrimes		(void)setbuf(debug, (char *)0);
901553Srgrimes	}
911553Srgrimestop:
921553Srgrimes	errno = 0;
931553Srgrimes	rval = 0;
9480381Ssheldonh	if (read(STDIN_FILENO, &c, 1) != 1)
951553Srgrimes		exit(0);
961553Srgrimes	switch (c) {
971553Srgrimes
981553Srgrimes	case 'O':
991553Srgrimes		if (tape >= 0)
1001553Srgrimes			(void) close(tape);
1011553Srgrimes		getstring(device);
1021553Srgrimes		getstring(mode);
1031553Srgrimes		DEBUG2("rmtd: O %s %s\n", device, mode);
1047707Sjoerg		/*
1057707Sjoerg		 * XXX the rmt protocol does not provide a means to
1067707Sjoerg		 * specify the permission bits; allow rw for everyone,
1077707Sjoerg		 * as modified by the users umask
1087707Sjoerg		 */
1097707Sjoerg		tape = open(device, atoi(mode), 0666);
1101553Srgrimes		if (tape < 0)
1111553Srgrimes			goto ioerror;
1121553Srgrimes		goto respond;
1131553Srgrimes
1141553Srgrimes	case 'C':
1151553Srgrimes		DEBUG("rmtd: C\n");
1161553Srgrimes		getstring(device);		/* discard */
1171553Srgrimes		if (close(tape) < 0)
1181553Srgrimes			goto ioerror;
1191553Srgrimes		tape = -1;
1201553Srgrimes		goto respond;
1211553Srgrimes
1221553Srgrimes	case 'L':
1231553Srgrimes		getstring(count);
1241553Srgrimes		getstring(pos);
1251553Srgrimes		DEBUG2("rmtd: L %s %s\n", count, pos);
12683096Sache		rval = lseek(tape, (off_t)strtoll(count, NULL, 10), atoi(pos));
1271553Srgrimes		if (rval < 0)
1281553Srgrimes			goto ioerror;
1291553Srgrimes		goto respond;
1301553Srgrimes
1311553Srgrimes	case 'W':
1321553Srgrimes		getstring(count);
1331553Srgrimes		n = atoi(count);
1341553Srgrimes		DEBUG1("rmtd: W %s\n", count);
1351553Srgrimes		record = checkbuf(record, n);
1361553Srgrimes		for (i = 0; i < n; i += cc) {
13780381Ssheldonh			cc = read(STDIN_FILENO, &record[i], n - i);
1381553Srgrimes			if (cc <= 0) {
1391553Srgrimes				DEBUG("rmtd: premature eof\n");
1401553Srgrimes				exit(2);
1411553Srgrimes			}
1421553Srgrimes		}
1431553Srgrimes		rval = write(tape, record, n);
1441553Srgrimes		if (rval < 0)
1451553Srgrimes			goto ioerror;
1461553Srgrimes		goto respond;
1471553Srgrimes
1481553Srgrimes	case 'R':
1491553Srgrimes		getstring(count);
1501553Srgrimes		DEBUG1("rmtd: R %s\n", count);
1511553Srgrimes		n = atoi(count);
1521553Srgrimes		record = checkbuf(record, n);
1531553Srgrimes		rval = read(tape, record, n);
1541553Srgrimes		if (rval < 0)
1551553Srgrimes			goto ioerror;
1561553Srgrimes		(void)sprintf(resp, "A%d\n", rval);
15780381Ssheldonh		(void)write(STDOUT_FILENO, resp, strlen(resp));
15880381Ssheldonh		(void)write(STDOUT_FILENO, record, rval);
1591553Srgrimes		goto top;
1601553Srgrimes
1611553Srgrimes	case 'I':
1621553Srgrimes		getstring(op);
1631553Srgrimes		getstring(count);
1641553Srgrimes		DEBUG2("rmtd: I %s %s\n", op, count);
1651553Srgrimes		{ struct mtop mtop;
1661553Srgrimes		  mtop.mt_op = atoi(op);
1671553Srgrimes		  mtop.mt_count = atoi(count);
1681553Srgrimes		  if (ioctl(tape, MTIOCTOP, (char *)&mtop) < 0)
1691553Srgrimes			goto ioerror;
1701553Srgrimes		  rval = mtop.mt_count;
1711553Srgrimes		}
1721553Srgrimes		goto respond;
1731553Srgrimes
1741553Srgrimes	case 'S':		/* status */
1751553Srgrimes		DEBUG("rmtd: S\n");
1761553Srgrimes		{ struct mtget mtget;
1771553Srgrimes		  if (ioctl(tape, MTIOCGET, (char *)&mtget) < 0)
1781553Srgrimes			goto ioerror;
1791553Srgrimes		  rval = sizeof (mtget);
18057155Smjacob		  if (rval > 24)	/* original mtget structure size */
18157155Smjacob			rval = 24;
1821553Srgrimes		  (void)sprintf(resp, "A%d\n", rval);
18380381Ssheldonh		  (void)write(STDOUT_FILENO, resp, strlen(resp));
18480381Ssheldonh		  (void)write(STDOUT_FILENO, (char *)&mtget, rval);
1851553Srgrimes		  goto top;
1861553Srgrimes		}
1871553Srgrimes
18839264Sgibbs        case 'V':               /* version */
18939264Sgibbs                getstring(op);
19039264Sgibbs                DEBUG1("rmtd: V %s\n", op);
19139264Sgibbs                rval = 2;
19239264Sgibbs                goto respond;
19339264Sgibbs
1941553Srgrimes	default:
1951553Srgrimes		DEBUG1("rmtd: garbage command %c\n", c);
1961553Srgrimes		exit(3);
1971553Srgrimes	}
1981553Srgrimesrespond:
1991553Srgrimes	DEBUG1("rmtd: A %d\n", rval);
2001553Srgrimes	(void)sprintf(resp, "A%d\n", rval);
20180381Ssheldonh	(void)write(STDOUT_FILENO, resp, strlen(resp));
2021553Srgrimes	goto top;
2031553Srgrimesioerror:
2041553Srgrimes	error(errno);
2051553Srgrimes	goto top;
2061553Srgrimes}
2071553Srgrimes
2081553Srgrimesvoid
209201387Sedgetstring(char *bp)
2101553Srgrimes{
2111553Srgrimes	int i;
2121553Srgrimes	char *cp = bp;
2131553Srgrimes
2141553Srgrimes	for (i = 0; i < SSIZE; i++) {
21580381Ssheldonh		if (read(STDIN_FILENO, cp+i, 1) != 1)
2161553Srgrimes			exit(0);
2171553Srgrimes		if (cp[i] == '\n')
2181553Srgrimes			break;
2191553Srgrimes	}
2201553Srgrimes	cp[i] = '\0';
2211553Srgrimes}
2221553Srgrimes
223227259Sedstatic char *
224201387Sedcheckbuf(char *rec, int size)
2251553Srgrimes{
2261553Srgrimes
2271553Srgrimes	if (size <= maxrecsize)
22899822Salfred		return (rec);
22999822Salfred	if (rec != 0)
23099822Salfred		free(rec);
23199822Salfred	rec = malloc(size);
23299822Salfred	if (rec == 0) {
2331553Srgrimes		DEBUG("rmtd: cannot allocate buffer space\n");
2341553Srgrimes		exit(4);
2351553Srgrimes	}
2361553Srgrimes	maxrecsize = size;
2371553Srgrimes	while (size > 1024 &&
2381553Srgrimes	       setsockopt(0, SOL_SOCKET, SO_RCVBUF, &size, sizeof (size)) < 0)
2391553Srgrimes		size -= 1024;
24099822Salfred	return (rec);
2411553Srgrimes}
2421553Srgrimes
243227259Sedstatic void
244201387Sederror(int num)
2451553Srgrimes{
2461553Srgrimes
2471553Srgrimes	DEBUG2("rmtd: E %d (%s)\n", num, strerror(num));
24822464Simp	(void)snprintf(resp, sizeof(resp), "E%d\n%s\n", num, strerror(num));
24980381Ssheldonh	(void)write(STDOUT_FILENO, resp, strlen(resp));
2501553Srgrimes}
251