rmt.c revision 80381
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
3530374Scharnierstatic const 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
4130374Scharnier#if 0
421553Srgrimesstatic char sccsid[] = "@(#)rmt.c	8.1 (Berkeley) 6/6/93";
4330374Scharnier#endif
4430374Scharnierstatic const char rcsid[] =
4550479Speter  "$FreeBSD: head/usr.sbin/rmt/rmt.c 80381 2001-07-26 11:02:39Z sheldonh $";
461553Srgrimes#endif /* not lint */
471553Srgrimes
481553Srgrimes/*
491553Srgrimes * rmt
501553Srgrimes */
511553Srgrimes#include <sys/types.h>
521553Srgrimes#include <sys/socket.h>
531553Srgrimes#include <sys/mtio.h>
541553Srgrimes#include <errno.h>
551553Srgrimes#include <fcntl.h>
561553Srgrimes#include <sgtty.h>
571553Srgrimes#include <stdio.h>
581553Srgrimes#include <stdlib.h>
591553Srgrimes#include <string.h>
601553Srgrimes#include <unistd.h>
611553Srgrimes
621553Srgrimesint	tape = -1;
631553Srgrimes
641553Srgrimeschar	*record;
651553Srgrimesint	maxrecsize = -1;
661553Srgrimes
671553Srgrimes#define	SSIZE	64
681553Srgrimeschar	device[SSIZE];
691553Srgrimeschar	count[SSIZE], mode[SSIZE], pos[SSIZE], op[SSIZE];
701553Srgrimes
711553Srgrimeschar	resp[BUFSIZ];
721553Srgrimes
731553SrgrimesFILE	*debug;
741553Srgrimes#define	DEBUG(f)	if (debug) fprintf(debug, f)
751553Srgrimes#define	DEBUG1(f,a)	if (debug) fprintf(debug, f, a)
761553Srgrimes#define	DEBUG2(f,a1,a2)	if (debug) fprintf(debug, f, a1, a2)
771553Srgrimes
781553Srgrimeschar	*checkbuf __P((char *, int));
791553Srgrimesvoid	 error __P((int));
801553Srgrimesvoid	 getstring __P((char *));
811553Srgrimes
821553Srgrimesint
831553Srgrimesmain(argc, argv)
841553Srgrimes	int argc;
851553Srgrimes	char **argv;
861553Srgrimes{
871553Srgrimes	int rval;
881553Srgrimes	char c;
891553Srgrimes	int n, i, cc;
901553Srgrimes
911553Srgrimes	argc--, argv++;
921553Srgrimes	if (argc > 0) {
931553Srgrimes		debug = fopen(*argv, "w");
941553Srgrimes		if (debug == 0)
951553Srgrimes			exit(1);
961553Srgrimes		(void)setbuf(debug, (char *)0);
971553Srgrimes	}
981553Srgrimestop:
991553Srgrimes	errno = 0;
1001553Srgrimes	rval = 0;
10180381Ssheldonh	if (read(STDIN_FILENO, &c, 1) != 1)
1021553Srgrimes		exit(0);
1031553Srgrimes	switch (c) {
1041553Srgrimes
1051553Srgrimes	case 'O':
1061553Srgrimes		if (tape >= 0)
1071553Srgrimes			(void) close(tape);
1081553Srgrimes		getstring(device);
1091553Srgrimes		getstring(mode);
1101553Srgrimes		DEBUG2("rmtd: O %s %s\n", device, mode);
1117707Sjoerg		/*
1127707Sjoerg		 * XXX the rmt protocol does not provide a means to
1137707Sjoerg		 * specify the permission bits; allow rw for everyone,
1147707Sjoerg		 * as modified by the users umask
1157707Sjoerg		 */
1167707Sjoerg		tape = open(device, atoi(mode), 0666);
1171553Srgrimes		if (tape < 0)
1181553Srgrimes			goto ioerror;
1191553Srgrimes		goto respond;
1201553Srgrimes
1211553Srgrimes	case 'C':
1221553Srgrimes		DEBUG("rmtd: C\n");
1231553Srgrimes		getstring(device);		/* discard */
1241553Srgrimes		if (close(tape) < 0)
1251553Srgrimes			goto ioerror;
1261553Srgrimes		tape = -1;
1271553Srgrimes		goto respond;
1281553Srgrimes
1291553Srgrimes	case 'L':
1301553Srgrimes		getstring(count);
1311553Srgrimes		getstring(pos);
1321553Srgrimes		DEBUG2("rmtd: L %s %s\n", count, pos);
1331553Srgrimes		rval = lseek(tape, (off_t)atol(count), atoi(pos));
1341553Srgrimes		if (rval < 0)
1351553Srgrimes			goto ioerror;
1361553Srgrimes		goto respond;
1371553Srgrimes
1381553Srgrimes	case 'W':
1391553Srgrimes		getstring(count);
1401553Srgrimes		n = atoi(count);
1411553Srgrimes		DEBUG1("rmtd: W %s\n", count);
1421553Srgrimes		record = checkbuf(record, n);
1431553Srgrimes		for (i = 0; i < n; i += cc) {
14480381Ssheldonh			cc = read(STDIN_FILENO, &record[i], n - i);
1451553Srgrimes			if (cc <= 0) {
1461553Srgrimes				DEBUG("rmtd: premature eof\n");
1471553Srgrimes				exit(2);
1481553Srgrimes			}
1491553Srgrimes		}
1501553Srgrimes		rval = write(tape, record, n);
1511553Srgrimes		if (rval < 0)
1521553Srgrimes			goto ioerror;
1531553Srgrimes		goto respond;
1541553Srgrimes
1551553Srgrimes	case 'R':
1561553Srgrimes		getstring(count);
1571553Srgrimes		DEBUG1("rmtd: R %s\n", count);
1581553Srgrimes		n = atoi(count);
1591553Srgrimes		record = checkbuf(record, n);
1601553Srgrimes		rval = read(tape, record, n);
1611553Srgrimes		if (rval < 0)
1621553Srgrimes			goto ioerror;
1631553Srgrimes		(void)sprintf(resp, "A%d\n", rval);
16480381Ssheldonh		(void)write(STDOUT_FILENO, resp, strlen(resp));
16580381Ssheldonh		(void)write(STDOUT_FILENO, record, rval);
1661553Srgrimes		goto top;
1671553Srgrimes
1681553Srgrimes	case 'I':
1691553Srgrimes		getstring(op);
1701553Srgrimes		getstring(count);
1711553Srgrimes		DEBUG2("rmtd: I %s %s\n", op, count);
1721553Srgrimes		{ struct mtop mtop;
1731553Srgrimes		  mtop.mt_op = atoi(op);
1741553Srgrimes		  mtop.mt_count = atoi(count);
1751553Srgrimes		  if (ioctl(tape, MTIOCTOP, (char *)&mtop) < 0)
1761553Srgrimes			goto ioerror;
1771553Srgrimes		  rval = mtop.mt_count;
1781553Srgrimes		}
1791553Srgrimes		goto respond;
1801553Srgrimes
1811553Srgrimes	case 'S':		/* status */
1821553Srgrimes		DEBUG("rmtd: S\n");
1831553Srgrimes		{ struct mtget mtget;
1841553Srgrimes		  if (ioctl(tape, MTIOCGET, (char *)&mtget) < 0)
1851553Srgrimes			goto ioerror;
1861553Srgrimes		  rval = sizeof (mtget);
18757155Smjacob		  if (rval > 24)	/* original mtget structure size */
18857155Smjacob			rval = 24;
1891553Srgrimes		  (void)sprintf(resp, "A%d\n", rval);
19080381Ssheldonh		  (void)write(STDOUT_FILENO, resp, strlen(resp));
19180381Ssheldonh		  (void)write(STDOUT_FILENO, (char *)&mtget, rval);
1921553Srgrimes		  goto top;
1931553Srgrimes		}
1941553Srgrimes
19539264Sgibbs        case 'V':               /* version */
19639264Sgibbs                getstring(op);
19739264Sgibbs                DEBUG1("rmtd: V %s\n", op);
19839264Sgibbs                rval = 2;
19939264Sgibbs                goto respond;
20039264Sgibbs
2011553Srgrimes	default:
2021553Srgrimes		DEBUG1("rmtd: garbage command %c\n", c);
2031553Srgrimes		exit(3);
2041553Srgrimes	}
2051553Srgrimesrespond:
2061553Srgrimes	DEBUG1("rmtd: A %d\n", rval);
2071553Srgrimes	(void)sprintf(resp, "A%d\n", rval);
20880381Ssheldonh	(void)write(STDOUT_FILENO, resp, strlen(resp));
2091553Srgrimes	goto top;
2101553Srgrimesioerror:
2111553Srgrimes	error(errno);
2121553Srgrimes	goto top;
2131553Srgrimes}
2141553Srgrimes
2151553Srgrimesvoid
2161553Srgrimesgetstring(bp)
2171553Srgrimes	char *bp;
2181553Srgrimes{
2191553Srgrimes	int i;
2201553Srgrimes	char *cp = bp;
2211553Srgrimes
2221553Srgrimes	for (i = 0; i < SSIZE; i++) {
22380381Ssheldonh		if (read(STDIN_FILENO, cp+i, 1) != 1)
2241553Srgrimes			exit(0);
2251553Srgrimes		if (cp[i] == '\n')
2261553Srgrimes			break;
2271553Srgrimes	}
2281553Srgrimes	cp[i] = '\0';
2291553Srgrimes}
2301553Srgrimes
2311553Srgrimeschar *
2321553Srgrimescheckbuf(record, size)
2331553Srgrimes	char *record;
2341553Srgrimes	int size;
2351553Srgrimes{
2361553Srgrimes
2371553Srgrimes	if (size <= maxrecsize)
2381553Srgrimes		return (record);
2391553Srgrimes	if (record != 0)
2401553Srgrimes		free(record);
2411553Srgrimes	record = malloc(size);
2421553Srgrimes	if (record == 0) {
2431553Srgrimes		DEBUG("rmtd: cannot allocate buffer space\n");
2441553Srgrimes		exit(4);
2451553Srgrimes	}
2461553Srgrimes	maxrecsize = size;
2471553Srgrimes	while (size > 1024 &&
2481553Srgrimes	       setsockopt(0, SOL_SOCKET, SO_RCVBUF, &size, sizeof (size)) < 0)
2491553Srgrimes		size -= 1024;
2501553Srgrimes	return (record);
2511553Srgrimes}
2521553Srgrimes
2531553Srgrimesvoid
2541553Srgrimeserror(num)
2551553Srgrimes	int num;
2561553Srgrimes{
2571553Srgrimes
2581553Srgrimes	DEBUG2("rmtd: E %d (%s)\n", num, strerror(num));
25922464Simp	(void)snprintf(resp, sizeof(resp), "E%d\n%s\n", num, strerror(num));
26080381Ssheldonh	(void)write(STDOUT_FILENO, resp, strlen(resp));
2611553Srgrimes}
262