xref: /openbsd-src/usr.sbin/rmt/rmt.c (revision a28daedfc357b214be5c701aa8ba8adb29a7f1c2)
1 /*	$OpenBSD: rmt.c,v 1.12 2005/03/07 16:08:19 henning Exp $	*/
2 
3 /*
4  * Copyright (c) 1983 Regents of the University of California.
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  * 3. Neither the name of the University nor the names of its contributors
16  *    may be used to endorse or promote products derived from this software
17  *    without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29  * SUCH DAMAGE.
30  */
31 
32 #ifndef lint
33 char copyright[] =
34 "@(#) Copyright (c) 1983 Regents of the University of California.\n\
35  All rights reserved.\n";
36 #endif /* not lint */
37 
38 #ifndef lint
39 /*static char sccsid[] = "from: @(#)rmt.c	5.6 (Berkeley) 6/1/90";*/
40 static char rcsid[] = "$Id: rmt.c,v 1.12 2005/03/07 16:08:19 henning Exp $";
41 #endif /* not lint */
42 
43 /*
44  * rmt
45  */
46 #include <stdio.h>
47 #include <sgtty.h>
48 #include <sys/types.h>
49 #include <sys/socket.h>
50 #include <sys/file.h>
51 #include <sys/stat.h>
52 #include <sys/mtio.h>
53 #include <sys/param.h>
54 #include <unistd.h>
55 #include <stdlib.h>
56 #include <errno.h>
57 #include <string.h>
58 
59 int	tape = -1;
60 
61 char	*record;
62 int	maxrecsize = -1;
63 
64 #define	STRSIZE	64
65 char	device[MAXPATHLEN];
66 char	count[STRSIZE], mode[STRSIZE], pos[STRSIZE], op[STRSIZE];
67 
68 char	resp[BUFSIZ];
69 
70 FILE	*debug;
71 #define	DEBUG(f)	if (debug) fprintf(debug, f)
72 #define	DEBUG1(f,a)	if (debug) fprintf(debug, f, a)
73 #define	DEBUG2(f,a1,a2)	if (debug) fprintf(debug, f, a1, a2)
74 
75 char	*checkbuf(char *, int);
76 void	getstring(char *, int);
77 void	error(int);
78 
79 int
80 main(int argc, char *argv[])
81 {
82 	off_t orval;
83 	int rval;
84 	char c;
85 	int n, i, cc;
86 
87 	argc--, argv++;
88 	if (argc > 0) {
89 		debug = fopen(*argv, "w");
90 		if (debug == 0)
91 			exit(1);
92 		(void) setbuf(debug, (char *)0);
93 	}
94 top:
95 	errno = 0;
96 	rval = 0;
97 	if (read(STDIN_FILENO, &c, 1) != 1)
98 		exit(0);
99 	switch (c) {
100 
101 	case 'O':
102 		if (tape >= 0)
103 			(void) close(tape);
104 		getstring(device, sizeof(device));
105 		getstring(mode, sizeof(mode));
106 		DEBUG2("rmtd: O %s %s\n", device, mode);
107 		tape = open(device, atoi(mode),
108 		    S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH);
109 		if (tape == -1)
110 			goto ioerror;
111 		goto respond;
112 
113 	case 'C':
114 		DEBUG("rmtd: C\n");
115 		getstring(device, sizeof(device));	/* discard */
116 		if (close(tape) == -1)
117 			goto ioerror;
118 		tape = -1;
119 		goto respond;
120 
121 	case 'L':
122 		getstring(count, sizeof(count));
123 		getstring(pos, sizeof(pos));
124 		DEBUG2("rmtd: L %s %s\n", count, pos);
125 		orval = lseek(tape, strtoq(count, NULL, 0), atoi(pos));
126 		if (orval == -1)
127 			goto ioerror;
128 		goto respond;
129 
130 	case 'W':
131 		getstring(count, sizeof(count));
132 		n = atoi(count);
133 		DEBUG1("rmtd: W %s\n", count);
134 		record = checkbuf(record, n);
135 		for (i = 0; i < n; i += cc) {
136 			cc = read(STDIN_FILENO, &record[i], n - i);
137 			if (cc <= 0) {
138 				DEBUG("rmtd: premature eof\n");
139 				exit(2);
140 			}
141 		}
142 		rval = write(tape, record, n);
143 		if (rval < 0)
144 			goto ioerror;
145 		goto respond;
146 
147 	case 'R':
148 		getstring(count, sizeof(count));
149 		DEBUG1("rmtd: R %s\n", count);
150 		n = atoi(count);
151 		record = checkbuf(record, n);
152 		rval = read(tape, record, n);
153 		if (rval < 0)
154 			goto ioerror;
155 		(void) snprintf(resp, sizeof resp, "A%d\n", rval);
156 		(void) write(STDOUT_FILENO, resp, strlen(resp));
157 		(void) write(STDOUT_FILENO, record, rval);
158 		goto top;
159 
160 	case 'I':
161 		getstring(op, sizeof(op));
162 		getstring(count, sizeof(count));
163 		DEBUG2("rmtd: I %s %s\n", op, count);
164 		{ struct mtop mtop;
165 		  mtop.mt_op = atoi(op);
166 		  mtop.mt_count = atoi(count);
167 		  if (ioctl(tape, MTIOCTOP, (char *)&mtop) == -1)
168 			goto ioerror;
169 		  rval = mtop.mt_count;
170 		}
171 		goto respond;
172 
173 	case 'S':		/* status */
174 		DEBUG("rmtd: S\n");
175 		{ struct mtget mtget;
176 		  if (ioctl(tape, MTIOCGET, (char *)&mtget) == -1)
177 			goto ioerror;
178 		  rval = sizeof (mtget);
179 		  (void) snprintf(resp, sizeof resp, "A%d\n", rval);
180 		  (void) write(STDOUT_FILENO, resp, strlen(resp));
181 		  (void) write(STDOUT_FILENO, (char *)&mtget, sizeof (mtget));
182 		  goto top;
183 		}
184 
185 	default:
186 		DEBUG1("rmtd: garbage command %c\n", c);
187 		exit(3);
188 	}
189 respond:
190 	DEBUG1("rmtd: A %d\n", rval);
191 	(void) snprintf(resp, sizeof resp, "A%d\n", rval);
192 	(void) write(STDOUT_FILENO, resp, strlen(resp));
193 	goto top;
194 ioerror:
195 	error(errno);
196 	goto top;
197 }
198 
199 void
200 getstring(char *bp, int size)
201 {
202 	char *cp = bp;
203 	char *ep = bp + size - 1;
204 
205 	do {
206 		if (read(STDIN_FILENO, cp, 1) != 1)
207 			exit(0);
208 	} while (*cp != '\n' && ++cp < ep);
209 	*cp = '\0';
210 }
211 
212 char *
213 checkbuf(char *record, int size)
214 {
215 	if (size <= maxrecsize)
216 		return (record);
217 	if (record != 0)
218 		free(record);
219 	record = malloc(size);
220 	if (record == 0) {
221 		DEBUG("rmtd: cannot allocate buffer space\n");
222 		exit(4);
223 	}
224 	maxrecsize = size;
225 	while (size > 1024 &&
226 	       setsockopt(0, SOL_SOCKET, SO_RCVBUF, &size, sizeof (size)) == -1)
227 		size -= 1024;
228 	return (record);
229 }
230 
231 void
232 error(int num)
233 {
234 
235 	DEBUG2("rmtd: E %d (%s)\n", num, strerror(num));
236 	(void) snprintf(resp, sizeof (resp), "E%d\n%s\n", num, strerror(num));
237 	(void) write(STDOUT_FILENO, resp, strlen(resp));
238 }
239