1 /* $NetBSD: tcopy.c,v 1.11 2001/01/04 23:05:56 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. All advertising materials mentioning features or use of this software 16 * must display the following acknowledgement: 17 * This product includes software developed by the University of 18 * California, Berkeley and its contributors. 19 * 4. Neither the name of the University nor the names of its contributors 20 * may be used to endorse or promote products derived from this software 21 * without specific prior written permission. 22 * 23 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33 * SUCH DAMAGE. 34 */ 35 36 #include <sys/cdefs.h> 37 #ifndef lint 38 __COPYRIGHT("@(#) Copyright (c) 1985, 1987, 1993\n\ 39 The Regents of the University of California. All rights reserved.\n"); 40 #endif /* not lint */ 41 42 #ifndef lint 43 #if 0 44 static char sccsid[] = "@(#)tcopy.c 8.3 (Berkeley) 1/23/95"; 45 #endif 46 __RCSID("$NetBSD: tcopy.c,v 1.11 2001/01/04 23:05:56 lukem Exp $"); 47 #endif /* not lint */ 48 49 #include <sys/types.h> 50 #include <sys/stat.h> 51 #include <sys/ioctl.h> 52 #include <sys/mtio.h> 53 54 #include <err.h> 55 #include <errno.h> 56 #include <paths.h> 57 #include <fcntl.h> 58 #include <signal.h> 59 #include <stdio.h> 60 #include <stdlib.h> 61 #include <string.h> 62 #include <unistd.h> 63 64 #define MAXREC (64 * 1024) 65 #define NOCOUNT (-2) 66 67 int filen, guesslen, maxblk = MAXREC; 68 long lastrec, record; 69 off_t size, tsize; 70 FILE *msg = stdout; 71 72 void *getspace __P((int)); 73 void intr __P((int)); 74 int main __P((int, char **)); 75 void usage __P((void)); 76 void verify __P((int, int, char *)); 77 void writeop __P((int, int)); 78 79 int 80 main(argc, argv) 81 int argc; 82 char *argv[]; 83 { 84 int ch, needeof, nw, inp, outp; 85 ssize_t lastnread, nread; 86 enum {READ, VERIFY, COPY, COPYVERIFY} op = READ; 87 sig_t oldsig; 88 char *buff, *inf; 89 90 outp = 0; 91 inf = NULL; 92 guesslen = 1; 93 while ((ch = getopt(argc, argv, "cs:vx")) != -1) 94 switch((char)ch) { 95 case 'c': 96 op = COPYVERIFY; 97 break; 98 case 's': 99 maxblk = atoi(optarg); 100 if (maxblk <= 0) { 101 warnx("illegal block size"); 102 usage(); 103 } 104 guesslen = 0; 105 break; 106 case 'v': 107 op = VERIFY; 108 break; 109 case 'x': 110 msg = stderr; 111 break; 112 case '?': 113 default: 114 usage(); 115 } 116 argc -= optind; 117 argv += optind; 118 119 switch(argc) { 120 case 0: 121 if (op != READ) 122 usage(); 123 inf = _PATH_DEFTAPE; 124 break; 125 case 1: 126 if (op != READ) 127 usage(); 128 inf = argv[0]; 129 break; 130 case 2: 131 if (op == READ) 132 op = COPY; 133 inf = argv[0]; 134 if ((outp = open(argv[1], op == VERIFY ? O_RDONLY : 135 op == COPY ? O_WRONLY : O_RDWR, DEFFILEMODE)) < 0) { 136 err(3, "%s", argv[1]); 137 } 138 break; 139 default: 140 usage(); 141 } 142 143 if ((inp = open(inf, O_RDONLY, 0)) < 0) 144 err(1, "%s", inf); 145 146 buff = getspace(maxblk); 147 148 if (op == VERIFY) { 149 verify(inp, outp, buff); 150 exit(0); 151 } 152 153 if ((oldsig = signal(SIGINT, SIG_IGN)) != SIG_IGN) 154 (void) signal(SIGINT, intr); 155 156 needeof = 0; 157 for (lastnread = NOCOUNT;;) { 158 if ((nread = read(inp, buff, maxblk)) == -1) { 159 while (errno == EINVAL && (maxblk -= 1024)) { 160 nread = read(inp, buff, maxblk); 161 if (nread >= 0) 162 goto r1; 163 } 164 err(1, "read error, file %d, record %ld", 165 filen, record); 166 } else if (nread != lastnread) { 167 if (lastnread != 0 && lastnread != NOCOUNT) { 168 if (lastrec == 0 && nread == 0) 169 fprintf(msg, "%ld records\n", record); 170 else if (record - lastrec > 1) 171 fprintf(msg, "records %ld to %ld\n", 172 lastrec, record); 173 else 174 fprintf(msg, "record %ld\n", lastrec); 175 } 176 if (nread != 0) 177 fprintf(msg, "file %d: block size %ld: ", 178 filen, (long)nread); 179 (void) fflush(stdout); 180 lastrec = record; 181 } 182 r1: guesslen = 0; 183 if (nread > 0) { 184 if (op == COPY || op == COPYVERIFY) { 185 if (needeof) { 186 writeop(outp, MTWEOF); 187 needeof = 0; 188 } 189 nw = write(outp, buff, nread); 190 if (nw != nread) { 191 int error = errno; 192 fprintf(stderr, 193 "write error, file %d, record %ld: ", 194 filen, record); 195 if (nw == -1) 196 fprintf(stderr, 197 ": %s", strerror(error)); 198 else 199 fprintf(stderr, 200 "write (%d) != read (%ld)\n", 201 nw, (long)nread); 202 fprintf(stderr, "copy aborted\n"); 203 exit(5); 204 } 205 } 206 size += nread; 207 record++; 208 } else { 209 if (lastnread <= 0 && lastnread != NOCOUNT) { 210 fprintf(msg, "eot\n"); 211 break; 212 } 213 fprintf(msg, 214 "file %d: eof after %ld records: %lld bytes\n", 215 filen, record, (long long)size); 216 needeof = 1; 217 filen++; 218 tsize += size; 219 size = record = lastrec = 0; 220 lastnread = 0; 221 } 222 lastnread = nread; 223 } 224 fprintf(msg, "total length: %lld bytes\n", (long long)tsize); 225 (void)signal(SIGINT, oldsig); 226 if (op == COPY || op == COPYVERIFY) { 227 writeop(outp, MTWEOF); 228 writeop(outp, MTWEOF); 229 if (op == COPYVERIFY) { 230 writeop(outp, MTREW); 231 writeop(inp, MTREW); 232 verify(inp, outp, buff); 233 } 234 } 235 exit(0); 236 } 237 238 void 239 verify(inp, outp, outb) 240 int inp, outp; 241 char *outb; 242 { 243 int eot, inmaxblk, inn, outmaxblk, outn; 244 char *inb; 245 246 inb = getspace(maxblk); 247 inmaxblk = outmaxblk = maxblk; 248 for (eot = 0;; guesslen = 0) { 249 if ((inn = read(inp, inb, inmaxblk)) == -1) { 250 if (guesslen) 251 while (errno == EINVAL && (inmaxblk -= 1024)) { 252 inn = read(inp, inb, inmaxblk); 253 if (inn >= 0) 254 goto r1; 255 } 256 warn("read error"); 257 break; 258 } 259 r1: if ((outn = read(outp, outb, outmaxblk)) == -1) { 260 if (guesslen) 261 while (errno == EINVAL && (outmaxblk -= 1024)) { 262 outn = read(outp, outb, outmaxblk); 263 if (outn >= 0) 264 goto r2; 265 } 266 warn("read error"); 267 break; 268 } 269 r2: if (inn != outn) { 270 fprintf(msg, 271 "%s: tapes have different block sizes; %d != %d.\n", 272 "tcopy", inn, outn); 273 break; 274 } 275 if (!inn) { 276 if (eot++) { 277 fprintf(msg, "%s: tapes are identical.\n", 278 "tcopy"); 279 return; 280 } 281 } else { 282 if (memcmp(inb, outb, inn)) { 283 fprintf(msg, 284 "%s: tapes have different data.\n", 285 "tcopy"); 286 break; 287 } 288 eot = 0; 289 } 290 } 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 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