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