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