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