xref: /original-bsd/usr.sbin/rmt/rmt.c (revision 0edb85a7)
1 /*
2  * Copyright (c) 1983 Regents of the University of California.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms are permitted
6  * provided that the above copyright notice and this paragraph are
7  * duplicated in all such forms and that any documentation,
8  * advertising materials, and other materials related to such
9  * distribution and use acknowledge that the software was developed
10  * by the University of California, Berkeley.  The name of the
11  * University may not be used to endorse or promote products derived
12  * from this software without specific prior written permission.
13  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
14  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
15  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
16  */
17 
18 #ifndef lint
19 char copyright[] =
20 "@(#) Copyright (c) 1983 Regents of the University of California.\n\
21  All rights reserved.\n";
22 #endif /* not lint */
23 
24 #ifndef lint
25 static char sccsid[] = "@(#)rmt.c	5.5 (Berkeley) 05/27/90";
26 #endif /* not lint */
27 
28 /*
29  * rmt
30  */
31 #include <stdio.h>
32 #include <sgtty.h>
33 #include <sys/types.h>
34 #include <sys/socket.h>
35 #include <sys/mtio.h>
36 #include <errno.h>
37 #include <string.h>
38 
39 int	tape = -1;
40 
41 char	*record;
42 int	maxrecsize = -1;
43 char	*checkbuf();
44 
45 #define	SSIZE	64
46 char	device[SSIZE];
47 char	count[SSIZE], mode[SSIZE], pos[SSIZE], op[SSIZE];
48 
49 char	resp[BUFSIZ];
50 
51 long	lseek();
52 
53 FILE	*debug;
54 #define	DEBUG(f)	if (debug) fprintf(debug, f)
55 #define	DEBUG1(f,a)	if (debug) fprintf(debug, f, a)
56 #define	DEBUG2(f,a1,a2)	if (debug) fprintf(debug, f, a1, a2)
57 
58 main(argc, argv)
59 	int argc;
60 	char **argv;
61 {
62 	int rval;
63 	char c;
64 	int n, i, cc;
65 
66 	argc--, argv++;
67 	if (argc > 0) {
68 		debug = fopen(*argv, "w");
69 		if (debug == 0)
70 			exit(1);
71 		(void) setbuf(debug, (char *)0);
72 	}
73 top:
74 	errno = 0;
75 	rval = 0;
76 	if (read(0, &c, 1) != 1)
77 		exit(0);
78 	switch (c) {
79 
80 	case 'O':
81 		if (tape >= 0)
82 			(void) close(tape);
83 		getstring(device); getstring(mode);
84 		DEBUG2("rmtd: O %s %s\n", device, mode);
85 		tape = open(device, atoi(mode));
86 		if (tape < 0)
87 			goto ioerror;
88 		goto respond;
89 
90 	case 'C':
91 		DEBUG("rmtd: C\n");
92 		getstring(device);		/* discard */
93 		if (close(tape) < 0)
94 			goto ioerror;
95 		tape = -1;
96 		goto respond;
97 
98 	case 'L':
99 		getstring(count); getstring(pos);
100 		DEBUG2("rmtd: L %s %s\n", count, pos);
101 		rval = lseek(tape, (long) atoi(count), atoi(pos));
102 		if (rval < 0)
103 			goto ioerror;
104 		goto respond;
105 
106 	case 'W':
107 		getstring(count);
108 		n = atoi(count);
109 		DEBUG1("rmtd: W %s\n", count);
110 		record = checkbuf(record, n);
111 		for (i = 0; i < n; i += cc) {
112 			cc = read(0, &record[i], n - i);
113 			if (cc <= 0) {
114 				DEBUG("rmtd: premature eof\n");
115 				exit(2);
116 			}
117 		}
118 		rval = write(tape, record, n);
119 		if (rval < 0)
120 			goto ioerror;
121 		goto respond;
122 
123 	case 'R':
124 		getstring(count);
125 		DEBUG1("rmtd: R %s\n", count);
126 		n = atoi(count);
127 		record = checkbuf(record, n);
128 		rval = read(tape, record, n);
129 		if (rval < 0)
130 			goto ioerror;
131 		(void) sprintf(resp, "A%d\n", rval);
132 		(void) write(1, resp, strlen(resp));
133 		(void) write(1, record, rval);
134 		goto top;
135 
136 	case 'I':
137 		getstring(op); getstring(count);
138 		DEBUG2("rmtd: I %s %s\n", op, count);
139 		{ struct mtop mtop;
140 		  mtop.mt_op = atoi(op);
141 		  mtop.mt_count = atoi(count);
142 		  if (ioctl(tape, MTIOCTOP, (char *)&mtop) < 0)
143 			goto ioerror;
144 		  rval = mtop.mt_count;
145 		}
146 		goto respond;
147 
148 	case 'S':		/* status */
149 		DEBUG("rmtd: S\n");
150 		{ struct mtget mtget;
151 		  if (ioctl(tape, MTIOCGET, (char *)&mtget) < 0)
152 			goto ioerror;
153 		  rval = sizeof (mtget);
154 		  (void) sprintf(resp, "A%d\n", rval);
155 		  (void) write(1, resp, strlen(resp));
156 		  (void) write(1, (char *)&mtget, sizeof (mtget));
157 		  goto top;
158 		}
159 
160 	default:
161 		DEBUG1("rmtd: garbage command %c\n", c);
162 		exit(3);
163 	}
164 respond:
165 	DEBUG1("rmtd: A %d\n", rval);
166 	(void) sprintf(resp, "A%d\n", rval);
167 	(void) write(1, resp, strlen(resp));
168 	goto top;
169 ioerror:
170 	error(errno);
171 	goto top;
172 }
173 
174 getstring(bp)
175 	char *bp;
176 {
177 	int i;
178 	char *cp = bp;
179 
180 	for (i = 0; i < SSIZE; i++) {
181 		if (read(0, cp+i, 1) != 1)
182 			exit(0);
183 		if (cp[i] == '\n')
184 			break;
185 	}
186 	cp[i] = '\0';
187 }
188 
189 char *
190 checkbuf(record, size)
191 	char *record;
192 	int size;
193 {
194 	extern char *malloc();
195 
196 	if (size <= maxrecsize)
197 		return (record);
198 	if (record != 0)
199 		free(record);
200 	record = malloc(size);
201 	if (record == 0) {
202 		DEBUG("rmtd: cannot allocate buffer space\n");
203 		exit(4);
204 	}
205 	maxrecsize = size;
206 	while (size > 1024 &&
207 	       setsockopt(0, SOL_SOCKET, SO_RCVBUF, &size, sizeof (size)) < 0)
208 		size -= 1024;
209 	return (record);
210 }
211 
212 error(num)
213 	int num;
214 {
215 
216 	DEBUG2("rmtd: E %d (%s)\n", num, strerror(num));
217 	(void) sprintf(resp, "E%d\n%s\n", num, strerror(num));
218 	(void) write(1, resp, strlen(resp));
219 }
220