xref: /openbsd-src/usr.sbin/rmt/rmt.c (revision 91f110e064cd7c194e59e019b83bb7496c1c84d4)
1 /*	$OpenBSD: rmt.c,v 1.14 2013/12/03 00:20:03 deraadt 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 /*
33  * rmt
34  */
35 #include <sys/types.h>
36 #include <sys/socket.h>
37 #include <sys/file.h>
38 #include <sys/stat.h>
39 #include <sys/ioctl.h>
40 #include <sys/mtio.h>
41 #include <sys/param.h>
42 #include <unistd.h>
43 #include <stdio.h>
44 #include <stdlib.h>
45 #include <errno.h>
46 #include <string.h>
47 
48 int	tape = -1;
49 
50 char	*record;
51 int	maxrecsize = -1;
52 
53 #define	STRSIZE	64
54 char	device[MAXPATHLEN];
55 char	count[STRSIZE], mode[STRSIZE], pos[STRSIZE], op[STRSIZE];
56 
57 char	resp[BUFSIZ];
58 
59 FILE	*debug;
60 #define	DEBUG(f)	if (debug) fprintf(debug, f)
61 #define	DEBUG1(f,a)	if (debug) fprintf(debug, f, a)
62 #define	DEBUG2(f,a1,a2)	if (debug) fprintf(debug, f, a1, a2)
63 
64 char	*checkbuf(char *, int);
65 void	getstring(char *, int);
66 void	error(int);
67 
68 int
69 main(int argc, char *argv[])
70 {
71 	off_t orval;
72 	int rval;
73 	char c;
74 	int n, i, cc;
75 
76 	argc--, argv++;
77 	if (argc > 0) {
78 		debug = fopen(*argv, "w");
79 		if (debug == 0)
80 			exit(1);
81 		(void) setbuf(debug, (char *)0);
82 	}
83 top:
84 	errno = 0;
85 	rval = 0;
86 	if (read(STDIN_FILENO, &c, 1) != 1)
87 		exit(0);
88 	switch (c) {
89 
90 	case 'O':
91 		if (tape >= 0)
92 			(void) close(tape);
93 		getstring(device, sizeof(device));
94 		getstring(mode, sizeof(mode));
95 		DEBUG2("rmtd: O %s %s\n", device, mode);
96 		tape = open(device, atoi(mode),
97 		    S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH);
98 		if (tape == -1)
99 			goto ioerror;
100 		goto respond;
101 
102 	case 'C':
103 		DEBUG("rmtd: C\n");
104 		getstring(device, sizeof(device));	/* discard */
105 		if (close(tape) == -1)
106 			goto ioerror;
107 		tape = -1;
108 		goto respond;
109 
110 	case 'L':
111 		getstring(count, sizeof(count));
112 		getstring(pos, sizeof(pos));
113 		DEBUG2("rmtd: L %s %s\n", count, pos);
114 		orval = lseek(tape, strtoq(count, NULL, 0), atoi(pos));
115 		if (orval == -1)
116 			goto ioerror;
117 		goto respond;
118 
119 	case 'W':
120 		getstring(count, sizeof(count));
121 		n = atoi(count);
122 		DEBUG1("rmtd: W %s\n", count);
123 		record = checkbuf(record, n);
124 		for (i = 0; i < n; i += cc) {
125 			cc = read(STDIN_FILENO, &record[i], n - i);
126 			if (cc <= 0) {
127 				DEBUG("rmtd: premature eof\n");
128 				exit(2);
129 			}
130 		}
131 		rval = write(tape, record, n);
132 		if (rval < 0)
133 			goto ioerror;
134 		goto respond;
135 
136 	case 'R':
137 		getstring(count, sizeof(count));
138 		DEBUG1("rmtd: R %s\n", count);
139 		n = atoi(count);
140 		record = checkbuf(record, n);
141 		rval = read(tape, record, n);
142 		if (rval < 0)
143 			goto ioerror;
144 		(void) snprintf(resp, sizeof resp, "A%d\n", rval);
145 		(void) write(STDOUT_FILENO, resp, strlen(resp));
146 		(void) write(STDOUT_FILENO, record, rval);
147 		goto top;
148 
149 	case 'I':
150 		getstring(op, sizeof(op));
151 		getstring(count, sizeof(count));
152 		DEBUG2("rmtd: I %s %s\n", op, count);
153 		{ struct mtop mtop;
154 		  mtop.mt_op = atoi(op);
155 		  mtop.mt_count = atoi(count);
156 		  if (ioctl(tape, MTIOCTOP, (char *)&mtop) == -1)
157 			goto ioerror;
158 		  rval = mtop.mt_count;
159 		}
160 		goto respond;
161 
162 	case 'S':		/* status */
163 		DEBUG("rmtd: S\n");
164 		{ struct mtget mtget;
165 		  if (ioctl(tape, MTIOCGET, (char *)&mtget) == -1)
166 			goto ioerror;
167 		  rval = sizeof (mtget);
168 		  (void) snprintf(resp, sizeof resp, "A%d\n", rval);
169 		  (void) write(STDOUT_FILENO, resp, strlen(resp));
170 		  (void) write(STDOUT_FILENO, (char *)&mtget, sizeof (mtget));
171 		  goto top;
172 		}
173 
174 	default:
175 		DEBUG1("rmtd: garbage command %c\n", c);
176 		exit(3);
177 	}
178 respond:
179 	DEBUG1("rmtd: A %d\n", rval);
180 	(void) snprintf(resp, sizeof resp, "A%d\n", rval);
181 	(void) write(STDOUT_FILENO, resp, strlen(resp));
182 	goto top;
183 ioerror:
184 	error(errno);
185 	goto top;
186 }
187 
188 void
189 getstring(char *bp, int size)
190 {
191 	char *cp = bp;
192 	char *ep = bp + size - 1;
193 
194 	do {
195 		if (read(STDIN_FILENO, cp, 1) != 1)
196 			exit(0);
197 	} while (*cp != '\n' && ++cp < ep);
198 	*cp = '\0';
199 }
200 
201 char *
202 checkbuf(char *record, int size)
203 {
204 	if (size <= maxrecsize)
205 		return (record);
206 	if (record != 0)
207 		free(record);
208 	record = malloc(size);
209 	if (record == 0) {
210 		DEBUG("rmtd: cannot allocate buffer space\n");
211 		exit(4);
212 	}
213 	maxrecsize = size;
214 	while (size > 1024 &&
215 	       setsockopt(0, SOL_SOCKET, SO_RCVBUF, &size, sizeof (size)) == -1)
216 		size -= 1024;
217 	return (record);
218 }
219 
220 void
221 error(int num)
222 {
223 
224 	DEBUG2("rmtd: E %d (%s)\n", num, strerror(num));
225 	(void) snprintf(resp, sizeof (resp), "E%d\n%s\n", num, strerror(num));
226 	(void) write(STDOUT_FILENO, resp, strlen(resp));
227 }
228