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