1331722Seadler/*
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");
87297961Saraujo		if (debug == NULL) {
88297961Saraujo			DEBUG1("rmtd: error to open %s\n", *argv);
891553Srgrimes			exit(1);
90297961Saraujo		}
911553Srgrimes		(void)setbuf(debug, (char *)0);
921553Srgrimes	}
931553Srgrimestop:
941553Srgrimes	errno = 0;
951553Srgrimes	rval = 0;
9680381Ssheldonh	if (read(STDIN_FILENO, &c, 1) != 1)
971553Srgrimes		exit(0);
981553Srgrimes	switch (c) {
991553Srgrimes
1001553Srgrimes	case 'O':
1011553Srgrimes		if (tape >= 0)
1021553Srgrimes			(void) close(tape);
1031553Srgrimes		getstring(device);
1041553Srgrimes		getstring(mode);
1051553Srgrimes		DEBUG2("rmtd: O %s %s\n", device, mode);
1067707Sjoerg		/*
1077707Sjoerg		 * XXX the rmt protocol does not provide a means to
1087707Sjoerg		 * specify the permission bits; allow rw for everyone,
1097707Sjoerg		 * as modified by the users umask
1107707Sjoerg		 */
1117707Sjoerg		tape = open(device, atoi(mode), 0666);
1121553Srgrimes		if (tape < 0)
1131553Srgrimes			goto ioerror;
1141553Srgrimes		goto respond;
1151553Srgrimes
1161553Srgrimes	case 'C':
1171553Srgrimes		DEBUG("rmtd: C\n");
1181553Srgrimes		getstring(device);		/* discard */
1191553Srgrimes		if (close(tape) < 0)
1201553Srgrimes			goto ioerror;
1211553Srgrimes		tape = -1;
1221553Srgrimes		goto respond;
1231553Srgrimes
1241553Srgrimes	case 'L':
1251553Srgrimes		getstring(count);
1261553Srgrimes		getstring(pos);
1271553Srgrimes		DEBUG2("rmtd: L %s %s\n", count, pos);
12883096Sache		rval = lseek(tape, (off_t)strtoll(count, NULL, 10), atoi(pos));
1291553Srgrimes		if (rval < 0)
1301553Srgrimes			goto ioerror;
1311553Srgrimes		goto respond;
1321553Srgrimes
1331553Srgrimes	case 'W':
1341553Srgrimes		getstring(count);
1351553Srgrimes		n = atoi(count);
1361553Srgrimes		DEBUG1("rmtd: W %s\n", count);
1371553Srgrimes		record = checkbuf(record, n);
1381553Srgrimes		for (i = 0; i < n; i += cc) {
13980381Ssheldonh			cc = read(STDIN_FILENO, &record[i], n - i);
1401553Srgrimes			if (cc <= 0) {
1411553Srgrimes				DEBUG("rmtd: premature eof\n");
1421553Srgrimes				exit(2);
1431553Srgrimes			}
1441553Srgrimes		}
1451553Srgrimes		rval = write(tape, record, n);
1461553Srgrimes		if (rval < 0)
1471553Srgrimes			goto ioerror;
1481553Srgrimes		goto respond;
1491553Srgrimes
1501553Srgrimes	case 'R':
1511553Srgrimes		getstring(count);
1521553Srgrimes		DEBUG1("rmtd: R %s\n", count);
1531553Srgrimes		n = atoi(count);
1541553Srgrimes		record = checkbuf(record, n);
1551553Srgrimes		rval = read(tape, record, n);
1561553Srgrimes		if (rval < 0)
1571553Srgrimes			goto ioerror;
1581553Srgrimes		(void)sprintf(resp, "A%d\n", rval);
15980381Ssheldonh		(void)write(STDOUT_FILENO, resp, strlen(resp));
16080381Ssheldonh		(void)write(STDOUT_FILENO, record, rval);
1611553Srgrimes		goto top;
1621553Srgrimes
1631553Srgrimes	case 'I':
1641553Srgrimes		getstring(op);
1651553Srgrimes		getstring(count);
1661553Srgrimes		DEBUG2("rmtd: I %s %s\n", op, count);
1671553Srgrimes		{ struct mtop mtop;
1681553Srgrimes		  mtop.mt_op = atoi(op);
1691553Srgrimes		  mtop.mt_count = atoi(count);
1701553Srgrimes		  if (ioctl(tape, MTIOCTOP, (char *)&mtop) < 0)
1711553Srgrimes			goto ioerror;
1721553Srgrimes		  rval = mtop.mt_count;
1731553Srgrimes		}
1741553Srgrimes		goto respond;
1751553Srgrimes
1761553Srgrimes	case 'S':		/* status */
1771553Srgrimes		DEBUG("rmtd: S\n");
1781553Srgrimes		{ struct mtget mtget;
1791553Srgrimes		  if (ioctl(tape, MTIOCGET, (char *)&mtget) < 0)
1801553Srgrimes			goto ioerror;
1811553Srgrimes		  rval = sizeof (mtget);
18257155Smjacob		  if (rval > 24)	/* original mtget structure size */
18357155Smjacob			rval = 24;
1841553Srgrimes		  (void)sprintf(resp, "A%d\n", rval);
18580381Ssheldonh		  (void)write(STDOUT_FILENO, resp, strlen(resp));
18680381Ssheldonh		  (void)write(STDOUT_FILENO, (char *)&mtget, rval);
1871553Srgrimes		  goto top;
1881553Srgrimes		}
1891553Srgrimes
19039264Sgibbs        case 'V':               /* version */
19139264Sgibbs                getstring(op);
19239264Sgibbs                DEBUG1("rmtd: V %s\n", op);
19339264Sgibbs                rval = 2;
19439264Sgibbs                goto respond;
19539264Sgibbs
1961553Srgrimes	default:
1971553Srgrimes		DEBUG1("rmtd: garbage command %c\n", c);
1981553Srgrimes		exit(3);
1991553Srgrimes	}
2001553Srgrimesrespond:
2011553Srgrimes	DEBUG1("rmtd: A %d\n", rval);
2021553Srgrimes	(void)sprintf(resp, "A%d\n", rval);
20380381Ssheldonh	(void)write(STDOUT_FILENO, resp, strlen(resp));
2041553Srgrimes	goto top;
2051553Srgrimesioerror:
2061553Srgrimes	error(errno);
2071553Srgrimes	goto top;
2081553Srgrimes}
2091553Srgrimes
2101553Srgrimesvoid
211201387Sedgetstring(char *bp)
2121553Srgrimes{
2131553Srgrimes	int i;
2141553Srgrimes	char *cp = bp;
2151553Srgrimes
2161553Srgrimes	for (i = 0; i < SSIZE; i++) {
21780381Ssheldonh		if (read(STDIN_FILENO, cp+i, 1) != 1)
2181553Srgrimes			exit(0);
2191553Srgrimes		if (cp[i] == '\n')
2201553Srgrimes			break;
2211553Srgrimes	}
2221553Srgrimes	cp[i] = '\0';
2231553Srgrimes}
2241553Srgrimes
225227259Sedstatic char *
226201387Sedcheckbuf(char *rec, int size)
2271553Srgrimes{
2281553Srgrimes
2291553Srgrimes	if (size <= maxrecsize)
23099822Salfred		return (rec);
231297961Saraujo	if (rec != NULL)
23299822Salfred		free(rec);
23399822Salfred	rec = malloc(size);
234297961Saraujo	if (rec == NULL) {
2351553Srgrimes		DEBUG("rmtd: cannot allocate buffer space\n");
2361553Srgrimes		exit(4);
2371553Srgrimes	}
2381553Srgrimes	maxrecsize = size;
2391553Srgrimes	while (size > 1024 &&
2401553Srgrimes	       setsockopt(0, SOL_SOCKET, SO_RCVBUF, &size, sizeof (size)) < 0)
2411553Srgrimes		size -= 1024;
24299822Salfred	return (rec);
2431553Srgrimes}
2441553Srgrimes
245227259Sedstatic void
246201387Sederror(int num)
2471553Srgrimes{
2481553Srgrimes
2491553Srgrimes	DEBUG2("rmtd: E %d (%s)\n", num, strerror(num));
25022464Simp	(void)snprintf(resp, sizeof(resp), "E%d\n%s\n", num, strerror(num));
25180381Ssheldonh	(void)write(STDOUT_FILENO, resp, strlen(resp));
2521553Srgrimes}
253