1 /* $NetBSD: tcopy.c,v 1.12 2003/08/07 11:16:06 agc Exp $ */ 2 3 /* 4 * Copyright (c) 1985, 1987, 1993, 1995 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. 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 #include <sys/cdefs.h> 33 #ifndef lint 34 __COPYRIGHT("@(#) Copyright (c) 1985, 1987, 1993\n\ 35 The Regents of the University of California. All rights reserved.\n"); 36 #endif /* not lint */ 37 38 #ifndef lint 39 #if 0 40 static char sccsid[] = "@(#)tcopy.c 8.3 (Berkeley) 1/23/95"; 41 #endif 42 __RCSID("$NetBSD: tcopy.c,v 1.12 2003/08/07 11:16:06 agc Exp $"); 43 #endif /* not lint */ 44 45 #include <sys/types.h> 46 #include <sys/stat.h> 47 #include <sys/ioctl.h> 48 #include <sys/mtio.h> 49 50 #include <err.h> 51 #include <errno.h> 52 #include <paths.h> 53 #include <fcntl.h> 54 #include <signal.h> 55 #include <stdio.h> 56 #include <stdlib.h> 57 #include <string.h> 58 #include <unistd.h> 59 60 #define MAXREC (64 * 1024) 61 #define NOCOUNT (-2) 62 63 int filen, guesslen, maxblk = MAXREC; 64 long lastrec, record; 65 off_t size, tsize; 66 FILE *msg = stdout; 67 68 void *getspace __P((int)); 69 void intr __P((int)); 70 int main __P((int, char **)); 71 void usage __P((void)); 72 void verify __P((int, int, char *)); 73 void writeop __P((int, int)); 74 75 int 76 main(argc, argv) 77 int argc; 78 char *argv[]; 79 { 80 int ch, needeof, nw, inp, outp; 81 ssize_t lastnread, nread; 82 enum {READ, VERIFY, COPY, COPYVERIFY} op = READ; 83 sig_t oldsig; 84 char *buff, *inf; 85 86 outp = 0; 87 inf = NULL; 88 guesslen = 1; 89 while ((ch = getopt(argc, argv, "cs:vx")) != -1) 90 switch((char)ch) { 91 case 'c': 92 op = COPYVERIFY; 93 break; 94 case 's': 95 maxblk = atoi(optarg); 96 if (maxblk <= 0) { 97 warnx("illegal block size"); 98 usage(); 99 } 100 guesslen = 0; 101 break; 102 case 'v': 103 op = VERIFY; 104 break; 105 case 'x': 106 msg = stderr; 107 break; 108 case '?': 109 default: 110 usage(); 111 } 112 argc -= optind; 113 argv += optind; 114 115 switch(argc) { 116 case 0: 117 if (op != READ) 118 usage(); 119 inf = _PATH_DEFTAPE; 120 break; 121 case 1: 122 if (op != READ) 123 usage(); 124 inf = argv[0]; 125 break; 126 case 2: 127 if (op == READ) 128 op = COPY; 129 inf = argv[0]; 130 if ((outp = open(argv[1], op == VERIFY ? O_RDONLY : 131 op == COPY ? O_WRONLY : O_RDWR, DEFFILEMODE)) < 0) { 132 err(3, "%s", argv[1]); 133 } 134 break; 135 default: 136 usage(); 137 } 138 139 if ((inp = open(inf, O_RDONLY, 0)) < 0) 140 err(1, "%s", inf); 141 142 buff = getspace(maxblk); 143 144 if (op == VERIFY) { 145 verify(inp, outp, buff); 146 exit(0); 147 } 148 149 if ((oldsig = signal(SIGINT, SIG_IGN)) != SIG_IGN) 150 (void) signal(SIGINT, intr); 151 152 needeof = 0; 153 for (lastnread = NOCOUNT;;) { 154 if ((nread = read(inp, buff, maxblk)) == -1) { 155 while (errno == EINVAL && (maxblk -= 1024)) { 156 nread = read(inp, buff, maxblk); 157 if (nread >= 0) 158 goto r1; 159 } 160 err(1, "read error, file %d, record %ld", 161 filen, record); 162 } else if (nread != lastnread) { 163 if (lastnread != 0 && lastnread != NOCOUNT) { 164 if (lastrec == 0 && nread == 0) 165 fprintf(msg, "%ld records\n", record); 166 else if (record - lastrec > 1) 167 fprintf(msg, "records %ld to %ld\n", 168 lastrec, record); 169 else 170 fprintf(msg, "record %ld\n", lastrec); 171 } 172 if (nread != 0) 173 fprintf(msg, "file %d: block size %ld: ", 174 filen, (long)nread); 175 (void) fflush(stdout); 176 lastrec = record; 177 } 178 r1: guesslen = 0; 179 if (nread > 0) { 180 if (op == COPY || op == COPYVERIFY) { 181 if (needeof) { 182 writeop(outp, MTWEOF); 183 needeof = 0; 184 } 185 nw = write(outp, buff, nread); 186 if (nw != nread) { 187 int error = errno; 188 fprintf(stderr, 189 "write error, file %d, record %ld: ", 190 filen, record); 191 if (nw == -1) 192 fprintf(stderr, 193 ": %s", strerror(error)); 194 else 195 fprintf(stderr, 196 "write (%d) != read (%ld)\n", 197 nw, (long)nread); 198 fprintf(stderr, "copy aborted\n"); 199 exit(5); 200 } 201 } 202 size += nread; 203 record++; 204 } else { 205 if (lastnread <= 0 && lastnread != NOCOUNT) { 206 fprintf(msg, "eot\n"); 207 break; 208 } 209 fprintf(msg, 210 "file %d: eof after %ld records: %lld bytes\n", 211 filen, record, (long long)size); 212 needeof = 1; 213 filen++; 214 tsize += size; 215 size = record = lastrec = 0; 216 lastnread = 0; 217 } 218 lastnread = nread; 219 } 220 fprintf(msg, "total length: %lld bytes\n", (long long)tsize); 221 (void)signal(SIGINT, oldsig); 222 if (op == COPY || op == COPYVERIFY) { 223 writeop(outp, MTWEOF); 224 writeop(outp, MTWEOF); 225 if (op == COPYVERIFY) { 226 writeop(outp, MTREW); 227 writeop(inp, MTREW); 228 verify(inp, outp, buff); 229 } 230 } 231 exit(0); 232 } 233 234 void 235 verify(inp, outp, outb) 236 int inp, outp; 237 char *outb; 238 { 239 int eot, inmaxblk, inn, outmaxblk, outn; 240 char *inb; 241 242 inb = getspace(maxblk); 243 inmaxblk = outmaxblk = maxblk; 244 for (eot = 0;; guesslen = 0) { 245 if ((inn = read(inp, inb, inmaxblk)) == -1) { 246 if (guesslen) 247 while (errno == EINVAL && (inmaxblk -= 1024)) { 248 inn = read(inp, inb, inmaxblk); 249 if (inn >= 0) 250 goto r1; 251 } 252 warn("read error"); 253 break; 254 } 255 r1: if ((outn = read(outp, outb, outmaxblk)) == -1) { 256 if (guesslen) 257 while (errno == EINVAL && (outmaxblk -= 1024)) { 258 outn = read(outp, outb, outmaxblk); 259 if (outn >= 0) 260 goto r2; 261 } 262 warn("read error"); 263 break; 264 } 265 r2: if (inn != outn) { 266 fprintf(msg, 267 "%s: tapes have different block sizes; %d != %d.\n", 268 "tcopy", inn, outn); 269 break; 270 } 271 if (!inn) { 272 if (eot++) { 273 fprintf(msg, "%s: tapes are identical.\n", 274 "tcopy"); 275 return; 276 } 277 } else { 278 if (memcmp(inb, outb, inn)) { 279 fprintf(msg, 280 "%s: tapes have different data.\n", 281 "tcopy"); 282 break; 283 } 284 eot = 0; 285 } 286 } 287 exit(1); 288 } 289 290 void 291 intr(signo) 292 int signo; 293 { 294 if (record) { 295 if (record - lastrec > 1) 296 fprintf(msg, "records %ld to %ld\n", lastrec, record); 297 else 298 fprintf(msg, "record %ld\n", lastrec); 299 } 300 fprintf(msg, "interrupt at file %d: record %ld\n", filen, record); 301 fprintf(msg, "total length: %lld bytes\n", (long long)(tsize + size)); 302 exit(1); 303 } 304 305 void * 306 getspace(blk) 307 int blk; 308 { 309 void *bp; 310 311 if ((bp = malloc((size_t)blk)) == NULL) 312 errx(11, "no memory"); 313 314 return (bp); 315 } 316 317 void 318 writeop(fd, type) 319 int fd, type; 320 { 321 struct mtop op; 322 323 op.mt_op = type; 324 op.mt_count = (daddr_t)1; 325 if (ioctl(fd, MTIOCTOP, (char *)&op) < 0) 326 err(6, "tape op"); 327 } 328 329 void 330 usage() 331 { 332 333 fprintf(stderr, "usage: tcopy [-cvx] [-s maxblk] src [dest]\n"); 334 exit(1); 335 } 336