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