1*4f766afcSPoul-Henning Kamp /*- 2*4f766afcSPoul-Henning Kamp * SPDX-License-Identifier: BSD-2-Clause 3*4f766afcSPoul-Henning Kamp * 4*4f766afcSPoul-Henning Kamp * Copyright (c) 2025 Poul-Henning Kamp, <phk@FreeBSD.org> 5*4f766afcSPoul-Henning Kamp * Copyright (c) 1985, 1987, 1993 6*4f766afcSPoul-Henning Kamp * The Regents of the University of California. All rights reserved. 7*4f766afcSPoul-Henning Kamp * 8*4f766afcSPoul-Henning Kamp * Redistribution and use in source and binary forms, with or without 9*4f766afcSPoul-Henning Kamp * modification, are permitted provided that the following conditions 10*4f766afcSPoul-Henning Kamp * are met: 11*4f766afcSPoul-Henning Kamp * 1. Redistributions of source code must retain the above copyright 12*4f766afcSPoul-Henning Kamp * notice, this list of conditions and the following disclaimer. 13*4f766afcSPoul-Henning Kamp * 2. Redistributions in binary form must reproduce the above copyright 14*4f766afcSPoul-Henning Kamp * notice, this list of conditions and the following disclaimer in the 15*4f766afcSPoul-Henning Kamp * documentation and/or other materials provided with the distribution. 16*4f766afcSPoul-Henning Kamp * 17*4f766afcSPoul-Henning Kamp * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 18*4f766afcSPoul-Henning Kamp * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19*4f766afcSPoul-Henning Kamp * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20*4f766afcSPoul-Henning Kamp * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 21*4f766afcSPoul-Henning Kamp * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22*4f766afcSPoul-Henning Kamp * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23*4f766afcSPoul-Henning Kamp * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24*4f766afcSPoul-Henning Kamp * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25*4f766afcSPoul-Henning Kamp * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26*4f766afcSPoul-Henning Kamp * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27*4f766afcSPoul-Henning Kamp * SUCH DAMAGE. 28*4f766afcSPoul-Henning Kamp */ 29*4f766afcSPoul-Henning Kamp 30*4f766afcSPoul-Henning Kamp #include <assert.h> 31*4f766afcSPoul-Henning Kamp #include <err.h> 32*4f766afcSPoul-Henning Kamp #include <errno.h> 33*4f766afcSPoul-Henning Kamp #include <fcntl.h> 34*4f766afcSPoul-Henning Kamp #include <paths.h> 35*4f766afcSPoul-Henning Kamp #include <signal.h> 36*4f766afcSPoul-Henning Kamp #include <stdint.h> 37*4f766afcSPoul-Henning Kamp #include <stdio.h> 38*4f766afcSPoul-Henning Kamp #include <stdlib.h> 39*4f766afcSPoul-Henning Kamp #include <string.h> 40*4f766afcSPoul-Henning Kamp #include <time.h> 41*4f766afcSPoul-Henning Kamp #include <sysexits.h> 42*4f766afcSPoul-Henning Kamp #include <unistd.h> 43*4f766afcSPoul-Henning Kamp 44*4f766afcSPoul-Henning Kamp #include <sys/endian.h> 45*4f766afcSPoul-Henning Kamp #include <sys/mtio.h> 46*4f766afcSPoul-Henning Kamp #include <sys/stat.h> 47*4f766afcSPoul-Henning Kamp #include <sys/sysctl.h> 48*4f766afcSPoul-Henning Kamp #include <sys/uio.h> 49*4f766afcSPoul-Henning Kamp 50*4f766afcSPoul-Henning Kamp #include <libutil.h> 51*4f766afcSPoul-Henning Kamp 52*4f766afcSPoul-Henning Kamp #define MAXREC (1024 * 1024) 53*4f766afcSPoul-Henning Kamp #define NOCOUNT (-2) 54*4f766afcSPoul-Henning Kamp 55*4f766afcSPoul-Henning Kamp enum operation {READ, VERIFY, COPY, COPYVERIFY}; 56*4f766afcSPoul-Henning Kamp 57*4f766afcSPoul-Henning Kamp // Stuff the tape_devs need to know about 58*4f766afcSPoul-Henning Kamp static int filen; 59*4f766afcSPoul-Henning Kamp static uint64_t record; 60*4f766afcSPoul-Henning Kamp 61*4f766afcSPoul-Henning Kamp //--------------------------------------------------------------------- 62*4f766afcSPoul-Henning Kamp 63*4f766afcSPoul-Henning Kamp class tape_dev { 64*4f766afcSPoul-Henning Kamp size_t max_read_size; 65*4f766afcSPoul-Henning Kamp public: 66*4f766afcSPoul-Henning Kamp int fd; 67*4f766afcSPoul-Henning Kamp char *name; 68*4f766afcSPoul-Henning Kamp enum direction {SRC, DST} direction; 69*4f766afcSPoul-Henning Kamp 70*4f766afcSPoul-Henning Kamp tape_dev(int file_handle, const char *spec, bool destination); 71*4f766afcSPoul-Henning Kamp 72*4f766afcSPoul-Henning Kamp virtual ssize_t read_blk(void *dst, size_t len); 73*4f766afcSPoul-Henning Kamp virtual ssize_t verify_blk(void *dst, size_t len, size_t expected); 74*4f766afcSPoul-Henning Kamp virtual void write_blk(const void *src, size_t len); 75*4f766afcSPoul-Henning Kamp virtual void file_mark(void); 76*4f766afcSPoul-Henning Kamp virtual void rewind(void); 77*4f766afcSPoul-Henning Kamp }; 78*4f766afcSPoul-Henning Kamp 79*4f766afcSPoul-Henning Kamp tape_dev::tape_dev(int file_handle, const char *spec, bool destination) 80*4f766afcSPoul-Henning Kamp { 81*4f766afcSPoul-Henning Kamp assert(file_handle >= 0); 82*4f766afcSPoul-Henning Kamp fd = file_handle; 83*4f766afcSPoul-Henning Kamp name = strdup(spec); 84*4f766afcSPoul-Henning Kamp assert(name != NULL); 85*4f766afcSPoul-Henning Kamp direction = destination ? DST : SRC; 86*4f766afcSPoul-Henning Kamp max_read_size = 0; 87*4f766afcSPoul-Henning Kamp } 88*4f766afcSPoul-Henning Kamp 89*4f766afcSPoul-Henning Kamp ssize_t 90*4f766afcSPoul-Henning Kamp tape_dev::read_blk(void *dst, size_t len) 91*4f766afcSPoul-Henning Kamp { 92*4f766afcSPoul-Henning Kamp ssize_t retval = -1; 93*4f766afcSPoul-Henning Kamp 94*4f766afcSPoul-Henning Kamp if (max_read_size == 0) { 95*4f766afcSPoul-Henning Kamp max_read_size = len; 96*4f766afcSPoul-Henning Kamp while (max_read_size > 0) { 97*4f766afcSPoul-Henning Kamp retval = read(fd, dst, max_read_size); 98*4f766afcSPoul-Henning Kamp if (retval >= 0 || (errno != EINVAL && errno != EFBIG)) 99*4f766afcSPoul-Henning Kamp break; 100*4f766afcSPoul-Henning Kamp if (max_read_size < 512) 101*4f766afcSPoul-Henning Kamp errx(1, "Cannot find a sane max blocksize"); 102*4f766afcSPoul-Henning Kamp 103*4f766afcSPoul-Henning Kamp // Reduce to next lower power of two 104*4f766afcSPoul-Henning Kamp int i = flsl((long)max_read_size - 1L); 105*4f766afcSPoul-Henning Kamp max_read_size = 1UL << (i - 1); 106*4f766afcSPoul-Henning Kamp } 107*4f766afcSPoul-Henning Kamp } else { 108*4f766afcSPoul-Henning Kamp retval = read(fd, dst, (size_t)max_read_size); 109*4f766afcSPoul-Henning Kamp } 110*4f766afcSPoul-Henning Kamp if (retval < 0) { 111*4f766afcSPoul-Henning Kamp err(1, "read error, %s, file %d, record %ju", 112*4f766afcSPoul-Henning Kamp name, filen, (uintmax_t)record); 113*4f766afcSPoul-Henning Kamp } 114*4f766afcSPoul-Henning Kamp return (retval); 115*4f766afcSPoul-Henning Kamp } 116*4f766afcSPoul-Henning Kamp 117*4f766afcSPoul-Henning Kamp ssize_t 118*4f766afcSPoul-Henning Kamp tape_dev::verify_blk(void *dst, size_t len, size_t expected) 119*4f766afcSPoul-Henning Kamp { 120*4f766afcSPoul-Henning Kamp (void)expected; 121*4f766afcSPoul-Henning Kamp return read_blk(dst, len); 122*4f766afcSPoul-Henning Kamp } 123*4f766afcSPoul-Henning Kamp 124*4f766afcSPoul-Henning Kamp void 125*4f766afcSPoul-Henning Kamp tape_dev::write_blk(const void *src, size_t len) 126*4f766afcSPoul-Henning Kamp { 127*4f766afcSPoul-Henning Kamp assert(len > 0); 128*4f766afcSPoul-Henning Kamp ssize_t nwrite = write(fd, src, len); 129*4f766afcSPoul-Henning Kamp if (nwrite < 0 || (size_t) nwrite != len) { 130*4f766afcSPoul-Henning Kamp if (nwrite == -1) { 131*4f766afcSPoul-Henning Kamp warn("write error, file %d, record %ju", 132*4f766afcSPoul-Henning Kamp filen, (intmax_t)record); 133*4f766afcSPoul-Henning Kamp } else { 134*4f766afcSPoul-Henning Kamp warnx("write error, file %d, record %ju", 135*4f766afcSPoul-Henning Kamp filen, (intmax_t)record); 136*4f766afcSPoul-Henning Kamp warnx("write (%zd) != read (%zd)", nwrite, len); 137*4f766afcSPoul-Henning Kamp } 138*4f766afcSPoul-Henning Kamp errx(5, "copy aborted"); 139*4f766afcSPoul-Henning Kamp } 140*4f766afcSPoul-Henning Kamp return; 141*4f766afcSPoul-Henning Kamp } 142*4f766afcSPoul-Henning Kamp 143*4f766afcSPoul-Henning Kamp void 144*4f766afcSPoul-Henning Kamp tape_dev::file_mark(void) 145*4f766afcSPoul-Henning Kamp { 146*4f766afcSPoul-Henning Kamp struct mtop op; 147*4f766afcSPoul-Henning Kamp 148*4f766afcSPoul-Henning Kamp op.mt_op = MTWEOF; 149*4f766afcSPoul-Henning Kamp op.mt_count = (daddr_t)1; 150*4f766afcSPoul-Henning Kamp if (ioctl(fd, MTIOCTOP, (char *)&op) < 0) 151*4f766afcSPoul-Henning Kamp err(6, "tape op (write file mark)"); 152*4f766afcSPoul-Henning Kamp } 153*4f766afcSPoul-Henning Kamp 154*4f766afcSPoul-Henning Kamp void 155*4f766afcSPoul-Henning Kamp tape_dev::rewind(void) 156*4f766afcSPoul-Henning Kamp { 157*4f766afcSPoul-Henning Kamp struct mtop op; 158*4f766afcSPoul-Henning Kamp 159*4f766afcSPoul-Henning Kamp op.mt_op = MTREW; 160*4f766afcSPoul-Henning Kamp op.mt_count = (daddr_t)1; 161*4f766afcSPoul-Henning Kamp if (ioctl(fd, MTIOCTOP, (char *)&op) < 0) 162*4f766afcSPoul-Henning Kamp err(6, "tape op (rewind)"); 163*4f766afcSPoul-Henning Kamp } 164*4f766afcSPoul-Henning Kamp 165*4f766afcSPoul-Henning Kamp //--------------------------------------------------------------------- 166*4f766afcSPoul-Henning Kamp 167*4f766afcSPoul-Henning Kamp class tap_file: public tape_dev { 168*4f766afcSPoul-Henning Kamp public: 169*4f766afcSPoul-Henning Kamp tap_file(int file_handle, const char *spec, bool dst) : 170*4f766afcSPoul-Henning Kamp tape_dev(file_handle, spec, dst) {}; 171*4f766afcSPoul-Henning Kamp ssize_t read_blk(void *dst, size_t len); 172*4f766afcSPoul-Henning Kamp void write_blk(const void *src, size_t len); 173*4f766afcSPoul-Henning Kamp void file_mark(void); 174*4f766afcSPoul-Henning Kamp virtual void rewind(void); 175*4f766afcSPoul-Henning Kamp }; 176*4f766afcSPoul-Henning Kamp 177*4f766afcSPoul-Henning Kamp static 178*4f766afcSPoul-Henning Kamp ssize_t full_read(int fd, void *dst, size_t len) 179*4f766afcSPoul-Henning Kamp { 180*4f766afcSPoul-Henning Kamp // Input may be a socket which returns partial reads 181*4f766afcSPoul-Henning Kamp 182*4f766afcSPoul-Henning Kamp ssize_t retval = read(fd, dst, len); 183*4f766afcSPoul-Henning Kamp if (retval <= 0 || (size_t)retval == len) 184*4f766afcSPoul-Henning Kamp return (retval); 185*4f766afcSPoul-Henning Kamp 186*4f766afcSPoul-Henning Kamp char *ptr = (char *)dst + retval; 187*4f766afcSPoul-Henning Kamp size_t left = len - (size_t)retval; 188*4f766afcSPoul-Henning Kamp while (left > 0) { 189*4f766afcSPoul-Henning Kamp retval = read(fd, ptr, left); 190*4f766afcSPoul-Henning Kamp if (retval <= 0) 191*4f766afcSPoul-Henning Kamp return (retval); 192*4f766afcSPoul-Henning Kamp left -= (size_t)retval; 193*4f766afcSPoul-Henning Kamp ptr += retval; 194*4f766afcSPoul-Henning Kamp } 195*4f766afcSPoul-Henning Kamp return ((ssize_t)len); 196*4f766afcSPoul-Henning Kamp } 197*4f766afcSPoul-Henning Kamp 198*4f766afcSPoul-Henning Kamp ssize_t 199*4f766afcSPoul-Henning Kamp tap_file::read_blk(void *dst, size_t len) 200*4f766afcSPoul-Henning Kamp { 201*4f766afcSPoul-Henning Kamp char lbuf[4]; 202*4f766afcSPoul-Henning Kamp 203*4f766afcSPoul-Henning Kamp ssize_t nread = full_read(fd, lbuf, sizeof lbuf); 204*4f766afcSPoul-Henning Kamp if (nread == 0) 205*4f766afcSPoul-Henning Kamp return (0); 206*4f766afcSPoul-Henning Kamp 207*4f766afcSPoul-Henning Kamp if ((size_t)nread != sizeof lbuf) 208*4f766afcSPoul-Henning Kamp err(EX_DATAERR, "Corrupt tap-file, read hdr1=%zd", nread); 209*4f766afcSPoul-Henning Kamp 210*4f766afcSPoul-Henning Kamp uint32_t u = le32dec(lbuf); 211*4f766afcSPoul-Henning Kamp if (u == 0 || (u >> 24) == 0xff) 212*4f766afcSPoul-Henning Kamp return(0); 213*4f766afcSPoul-Henning Kamp 214*4f766afcSPoul-Henning Kamp if (u > len) 215*4f766afcSPoul-Henning Kamp err(17, "tapfile blocksize too big, 0x%08x", u); 216*4f766afcSPoul-Henning Kamp 217*4f766afcSPoul-Henning Kamp size_t alen = (u + 1) & ~1; 218*4f766afcSPoul-Henning Kamp assert (alen <= len); 219*4f766afcSPoul-Henning Kamp 220*4f766afcSPoul-Henning Kamp ssize_t retval = full_read(fd, dst, alen); 221*4f766afcSPoul-Henning Kamp if (retval < 0 || (size_t)retval != alen) 222*4f766afcSPoul-Henning Kamp err(EX_DATAERR, "Corrupt tap-file, read data=%zd", retval); 223*4f766afcSPoul-Henning Kamp 224*4f766afcSPoul-Henning Kamp nread = full_read(fd, lbuf, sizeof lbuf); 225*4f766afcSPoul-Henning Kamp if ((size_t)nread != sizeof lbuf) 226*4f766afcSPoul-Henning Kamp err(EX_DATAERR, "Corrupt tap-file, read hdr2=%zd", nread); 227*4f766afcSPoul-Henning Kamp 228*4f766afcSPoul-Henning Kamp uint32_t v = le32dec(lbuf); 229*4f766afcSPoul-Henning Kamp if (u == v) 230*4f766afcSPoul-Henning Kamp return (u); 231*4f766afcSPoul-Henning Kamp err(EX_DATAERR, 232*4f766afcSPoul-Henning Kamp "Corrupt tap-file, headers differ (0x%08x != 0x%08x)", u, v); 233*4f766afcSPoul-Henning Kamp } 234*4f766afcSPoul-Henning Kamp 235*4f766afcSPoul-Henning Kamp void 236*4f766afcSPoul-Henning Kamp tap_file::write_blk(const void *src, size_t len) 237*4f766afcSPoul-Henning Kamp { 238*4f766afcSPoul-Henning Kamp struct iovec iov[4]; 239*4f766afcSPoul-Henning Kamp uint8_t zero = 0; 240*4f766afcSPoul-Henning Kamp int niov = 0; 241*4f766afcSPoul-Henning Kamp size_t expect = 0; 242*4f766afcSPoul-Henning Kamp char tbuf[4]; 243*4f766afcSPoul-Henning Kamp 244*4f766afcSPoul-Henning Kamp assert((len & ~0xffffffffULL) == 0); 245*4f766afcSPoul-Henning Kamp le32enc(tbuf, (uint32_t)len); 246*4f766afcSPoul-Henning Kamp 247*4f766afcSPoul-Henning Kamp iov[niov].iov_base = tbuf; 248*4f766afcSPoul-Henning Kamp iov[niov].iov_len = sizeof tbuf; 249*4f766afcSPoul-Henning Kamp expect += iov[niov].iov_len; 250*4f766afcSPoul-Henning Kamp niov += 1; 251*4f766afcSPoul-Henning Kamp 252*4f766afcSPoul-Henning Kamp iov[niov].iov_base = (void*)(uintptr_t)src; 253*4f766afcSPoul-Henning Kamp iov[niov].iov_len = len; 254*4f766afcSPoul-Henning Kamp expect += iov[niov].iov_len; 255*4f766afcSPoul-Henning Kamp niov += 1; 256*4f766afcSPoul-Henning Kamp 257*4f766afcSPoul-Henning Kamp if (len & 1) { 258*4f766afcSPoul-Henning Kamp iov[niov].iov_base = &zero; 259*4f766afcSPoul-Henning Kamp iov[niov].iov_len = 1; 260*4f766afcSPoul-Henning Kamp expect += iov[niov].iov_len; 261*4f766afcSPoul-Henning Kamp niov += 1; 262*4f766afcSPoul-Henning Kamp } 263*4f766afcSPoul-Henning Kamp 264*4f766afcSPoul-Henning Kamp iov[niov].iov_base = tbuf; 265*4f766afcSPoul-Henning Kamp iov[niov].iov_len = sizeof tbuf; 266*4f766afcSPoul-Henning Kamp expect += iov[niov].iov_len; 267*4f766afcSPoul-Henning Kamp niov += 1; 268*4f766afcSPoul-Henning Kamp 269*4f766afcSPoul-Henning Kamp ssize_t nwrite = writev(fd, iov, niov); 270*4f766afcSPoul-Henning Kamp if (nwrite < 0 || (size_t)nwrite != expect) 271*4f766afcSPoul-Henning Kamp errx(17, "write error (%zd != %zd)", nwrite, expect); 272*4f766afcSPoul-Henning Kamp } 273*4f766afcSPoul-Henning Kamp 274*4f766afcSPoul-Henning Kamp void 275*4f766afcSPoul-Henning Kamp tap_file::file_mark(void) 276*4f766afcSPoul-Henning Kamp { 277*4f766afcSPoul-Henning Kamp char tbuf[4]; 278*4f766afcSPoul-Henning Kamp le32enc(tbuf, 0); 279*4f766afcSPoul-Henning Kamp ssize_t nwrite = write(fd, tbuf, sizeof tbuf); 280*4f766afcSPoul-Henning Kamp if ((size_t)nwrite != sizeof tbuf) 281*4f766afcSPoul-Henning Kamp errx(17, "write error (%zd != %zd)", nwrite, sizeof tbuf); 282*4f766afcSPoul-Henning Kamp } 283*4f766afcSPoul-Henning Kamp 284*4f766afcSPoul-Henning Kamp void 285*4f766afcSPoul-Henning Kamp tap_file::rewind(void) 286*4f766afcSPoul-Henning Kamp { 287*4f766afcSPoul-Henning Kamp off_t where; 288*4f766afcSPoul-Henning Kamp if (direction == DST) { 289*4f766afcSPoul-Henning Kamp char tbuf[4]; 290*4f766afcSPoul-Henning Kamp le32enc(tbuf, 0xffffffff); 291*4f766afcSPoul-Henning Kamp ssize_t nwrite = write(fd, tbuf, sizeof tbuf); 292*4f766afcSPoul-Henning Kamp if ((size_t)nwrite != sizeof tbuf) 293*4f766afcSPoul-Henning Kamp errx(17, 294*4f766afcSPoul-Henning Kamp "write error (%zd != %zd)", nwrite, sizeof tbuf); 295*4f766afcSPoul-Henning Kamp } 296*4f766afcSPoul-Henning Kamp where = lseek(fd, 0L, SEEK_SET); 297*4f766afcSPoul-Henning Kamp if (where != 0 && errno == ESPIPE) 298*4f766afcSPoul-Henning Kamp err(EX_USAGE, "Cannot rewind sockets and pipes"); 299*4f766afcSPoul-Henning Kamp if (where != 0) 300*4f766afcSPoul-Henning Kamp err(17, "lseek(0) failed"); 301*4f766afcSPoul-Henning Kamp } 302*4f766afcSPoul-Henning Kamp 303*4f766afcSPoul-Henning Kamp //--------------------------------------------------------------------- 304*4f766afcSPoul-Henning Kamp 305*4f766afcSPoul-Henning Kamp class file_set: public tape_dev { 306*4f766afcSPoul-Henning Kamp public: 307*4f766afcSPoul-Henning Kamp file_set(int file_handle, const char *spec, bool dst) : 308*4f766afcSPoul-Henning Kamp tape_dev(file_handle, spec, dst) {}; 309*4f766afcSPoul-Henning Kamp ssize_t read_blk(void *dst, size_t len); 310*4f766afcSPoul-Henning Kamp ssize_t verify_blk(void *dst, size_t len, size_t expected); 311*4f766afcSPoul-Henning Kamp void write_blk(const void *src, size_t len); 312*4f766afcSPoul-Henning Kamp void file_mark(void); 313*4f766afcSPoul-Henning Kamp void rewind(void); 314*4f766afcSPoul-Henning Kamp void open_next(bool increment); 315*4f766afcSPoul-Henning Kamp }; 316*4f766afcSPoul-Henning Kamp 317*4f766afcSPoul-Henning Kamp void 318*4f766afcSPoul-Henning Kamp file_set::open_next(bool increment) 319*4f766afcSPoul-Henning Kamp { 320*4f766afcSPoul-Henning Kamp if (fd >= 0) { 321*4f766afcSPoul-Henning Kamp assert(close(fd) >= 0); 322*4f766afcSPoul-Henning Kamp fd = -1; 323*4f766afcSPoul-Henning Kamp } 324*4f766afcSPoul-Henning Kamp if (increment) { 325*4f766afcSPoul-Henning Kamp char *p = strchr(name, '\0') - 3; 326*4f766afcSPoul-Henning Kamp if (++p[2] == '9') { 327*4f766afcSPoul-Henning Kamp p[2] = '0'; 328*4f766afcSPoul-Henning Kamp if (++p[1] == '9') { 329*4f766afcSPoul-Henning Kamp p[1] = '0'; 330*4f766afcSPoul-Henning Kamp if (++p[0] == '9') { 331*4f766afcSPoul-Henning Kamp errx(EX_USAGE, 332*4f766afcSPoul-Henning Kamp "file-set sequence overflow"); 333*4f766afcSPoul-Henning Kamp } 334*4f766afcSPoul-Henning Kamp } 335*4f766afcSPoul-Henning Kamp } 336*4f766afcSPoul-Henning Kamp } 337*4f766afcSPoul-Henning Kamp if (direction == DST) { 338*4f766afcSPoul-Henning Kamp fd = open(name, O_RDWR|O_CREAT, DEFFILEMODE); 339*4f766afcSPoul-Henning Kamp if (fd < 0) 340*4f766afcSPoul-Henning Kamp err(1, "Could not open %s", name); 341*4f766afcSPoul-Henning Kamp } else { 342*4f766afcSPoul-Henning Kamp fd = open(name, O_RDONLY, 0); 343*4f766afcSPoul-Henning Kamp } 344*4f766afcSPoul-Henning Kamp } 345*4f766afcSPoul-Henning Kamp 346*4f766afcSPoul-Henning Kamp ssize_t 347*4f766afcSPoul-Henning Kamp file_set::read_blk(void *dst, size_t len) 348*4f766afcSPoul-Henning Kamp { 349*4f766afcSPoul-Henning Kamp (void)dst; 350*4f766afcSPoul-Henning Kamp (void)len; 351*4f766afcSPoul-Henning Kamp errx(EX_SOFTWARE, "That was not supposed to happen"); 352*4f766afcSPoul-Henning Kamp } 353*4f766afcSPoul-Henning Kamp 354*4f766afcSPoul-Henning Kamp ssize_t 355*4f766afcSPoul-Henning Kamp file_set::verify_blk(void *dst, size_t len, size_t expected) 356*4f766afcSPoul-Henning Kamp { 357*4f766afcSPoul-Henning Kamp (void)len; 358*4f766afcSPoul-Henning Kamp if (fd < 0) 359*4f766afcSPoul-Henning Kamp open_next(true); 360*4f766afcSPoul-Henning Kamp if (fd < 0) 361*4f766afcSPoul-Henning Kamp return (0); 362*4f766afcSPoul-Henning Kamp ssize_t retval = read(fd, dst, expected); 363*4f766afcSPoul-Henning Kamp if (retval == 0) { 364*4f766afcSPoul-Henning Kamp assert(close(fd) >= 0); 365*4f766afcSPoul-Henning Kamp fd = -1; 366*4f766afcSPoul-Henning Kamp } 367*4f766afcSPoul-Henning Kamp return (retval); 368*4f766afcSPoul-Henning Kamp } 369*4f766afcSPoul-Henning Kamp 370*4f766afcSPoul-Henning Kamp void 371*4f766afcSPoul-Henning Kamp file_set::write_blk(const void *src, size_t len) 372*4f766afcSPoul-Henning Kamp { 373*4f766afcSPoul-Henning Kamp if (fd < 0) 374*4f766afcSPoul-Henning Kamp open_next(true); 375*4f766afcSPoul-Henning Kamp ssize_t nwrite = write(fd, src, len); 376*4f766afcSPoul-Henning Kamp if (nwrite < 0 || (size_t)nwrite != len) 377*4f766afcSPoul-Henning Kamp errx(17, "write error (%zd != %zd)", nwrite, len); 378*4f766afcSPoul-Henning Kamp } 379*4f766afcSPoul-Henning Kamp 380*4f766afcSPoul-Henning Kamp void 381*4f766afcSPoul-Henning Kamp file_set::file_mark(void) 382*4f766afcSPoul-Henning Kamp { 383*4f766afcSPoul-Henning Kamp if (fd < 0) 384*4f766afcSPoul-Henning Kamp return; 385*4f766afcSPoul-Henning Kamp 386*4f766afcSPoul-Henning Kamp off_t where = lseek(fd, 0UL, SEEK_CUR); 387*4f766afcSPoul-Henning Kamp 388*4f766afcSPoul-Henning Kamp int i = ftruncate(fd, where); 389*4f766afcSPoul-Henning Kamp if (i < 0) 390*4f766afcSPoul-Henning Kamp errx(17, "truncate error, %s to %zd", name, where); 391*4f766afcSPoul-Henning Kamp assert(close(fd) >= 0); 392*4f766afcSPoul-Henning Kamp fd = -1; 393*4f766afcSPoul-Henning Kamp } 394*4f766afcSPoul-Henning Kamp 395*4f766afcSPoul-Henning Kamp void 396*4f766afcSPoul-Henning Kamp file_set::rewind(void) 397*4f766afcSPoul-Henning Kamp { 398*4f766afcSPoul-Henning Kamp char *p = strchr(name, '\0') - 3; 399*4f766afcSPoul-Henning Kamp p[0] = '0'; 400*4f766afcSPoul-Henning Kamp p[1] = '0'; 401*4f766afcSPoul-Henning Kamp p[2] = '0'; 402*4f766afcSPoul-Henning Kamp open_next(false); 403*4f766afcSPoul-Henning Kamp } 404*4f766afcSPoul-Henning Kamp 405*4f766afcSPoul-Henning Kamp //--------------------------------------------------------------------- 406*4f766afcSPoul-Henning Kamp 407*4f766afcSPoul-Henning Kamp class flat_file: public tape_dev { 408*4f766afcSPoul-Henning Kamp public: 409*4f766afcSPoul-Henning Kamp flat_file(int file_handle, const char *spec, bool dst) : 410*4f766afcSPoul-Henning Kamp tape_dev(file_handle, spec, dst) {}; 411*4f766afcSPoul-Henning Kamp ssize_t read_blk(void *dst, size_t len); 412*4f766afcSPoul-Henning Kamp ssize_t verify_blk(void *dst, size_t len, size_t expected); 413*4f766afcSPoul-Henning Kamp void write_blk(const void *src, size_t len); 414*4f766afcSPoul-Henning Kamp void file_mark(void); 415*4f766afcSPoul-Henning Kamp virtual void rewind(void); 416*4f766afcSPoul-Henning Kamp }; 417*4f766afcSPoul-Henning Kamp 418*4f766afcSPoul-Henning Kamp ssize_t 419*4f766afcSPoul-Henning Kamp flat_file::read_blk(void *dst, size_t len) 420*4f766afcSPoul-Henning Kamp { 421*4f766afcSPoul-Henning Kamp (void)dst; 422*4f766afcSPoul-Henning Kamp (void)len; 423*4f766afcSPoul-Henning Kamp errx(EX_SOFTWARE, "That was not supposed to happen"); 424*4f766afcSPoul-Henning Kamp } 425*4f766afcSPoul-Henning Kamp 426*4f766afcSPoul-Henning Kamp ssize_t 427*4f766afcSPoul-Henning Kamp flat_file::verify_blk(void *dst, size_t len, size_t expected) 428*4f766afcSPoul-Henning Kamp { 429*4f766afcSPoul-Henning Kamp (void)len; 430*4f766afcSPoul-Henning Kamp return (read(fd, dst, expected)); 431*4f766afcSPoul-Henning Kamp } 432*4f766afcSPoul-Henning Kamp 433*4f766afcSPoul-Henning Kamp void 434*4f766afcSPoul-Henning Kamp flat_file::write_blk(const void *src, size_t len) 435*4f766afcSPoul-Henning Kamp { 436*4f766afcSPoul-Henning Kamp ssize_t nwrite = write(fd, src, len); 437*4f766afcSPoul-Henning Kamp if (nwrite < 0 || (size_t)nwrite != len) 438*4f766afcSPoul-Henning Kamp errx(17, "write error (%zd != %zd)", nwrite, len); 439*4f766afcSPoul-Henning Kamp } 440*4f766afcSPoul-Henning Kamp 441*4f766afcSPoul-Henning Kamp void 442*4f766afcSPoul-Henning Kamp flat_file::file_mark(void) 443*4f766afcSPoul-Henning Kamp { 444*4f766afcSPoul-Henning Kamp return; 445*4f766afcSPoul-Henning Kamp } 446*4f766afcSPoul-Henning Kamp 447*4f766afcSPoul-Henning Kamp void 448*4f766afcSPoul-Henning Kamp flat_file::rewind(void) 449*4f766afcSPoul-Henning Kamp { 450*4f766afcSPoul-Henning Kamp errx(EX_SOFTWARE, "That was not supposed to happen"); 451*4f766afcSPoul-Henning Kamp } 452*4f766afcSPoul-Henning Kamp 453*4f766afcSPoul-Henning Kamp //--------------------------------------------------------------------- 454*4f766afcSPoul-Henning Kamp 455*4f766afcSPoul-Henning Kamp enum e_how {H_INPUT, H_OUTPUT, H_VERIFY}; 456*4f766afcSPoul-Henning Kamp 457*4f766afcSPoul-Henning Kamp static tape_dev * 458*4f766afcSPoul-Henning Kamp open_arg(const char *arg, enum e_how how, int rawfile) 459*4f766afcSPoul-Henning Kamp { 460*4f766afcSPoul-Henning Kamp int fd; 461*4f766afcSPoul-Henning Kamp 462*4f766afcSPoul-Henning Kamp if (!strcmp(arg, "-") && how == H_OUTPUT) 463*4f766afcSPoul-Henning Kamp fd = STDOUT_FILENO; 464*4f766afcSPoul-Henning Kamp else if (!strcmp(arg, "-")) 465*4f766afcSPoul-Henning Kamp fd = STDIN_FILENO; 466*4f766afcSPoul-Henning Kamp else if (how == H_OUTPUT) 467*4f766afcSPoul-Henning Kamp fd = open(arg, O_RDWR|O_CREAT, DEFFILEMODE); 468*4f766afcSPoul-Henning Kamp else 469*4f766afcSPoul-Henning Kamp fd = open(arg, O_RDONLY); 470*4f766afcSPoul-Henning Kamp 471*4f766afcSPoul-Henning Kamp if (fd < 0) 472*4f766afcSPoul-Henning Kamp err(EX_NOINPUT, "Cannot open %s:", arg); 473*4f766afcSPoul-Henning Kamp 474*4f766afcSPoul-Henning Kamp struct mtop mt; 475*4f766afcSPoul-Henning Kamp mt.mt_op = MTNOP; 476*4f766afcSPoul-Henning Kamp mt.mt_count = 1; 477*4f766afcSPoul-Henning Kamp int i = ioctl(fd, MTIOCTOP, &mt); 478*4f766afcSPoul-Henning Kamp 479*4f766afcSPoul-Henning Kamp if (i >= 0) 480*4f766afcSPoul-Henning Kamp return (new tape_dev(fd, arg, how == H_OUTPUT)); 481*4f766afcSPoul-Henning Kamp 482*4f766afcSPoul-Henning Kamp size_t alen = strlen(arg); 483*4f766afcSPoul-Henning Kamp if (alen >= 5 && !strcmp(arg + (alen - 4), ".000")) { 484*4f766afcSPoul-Henning Kamp if (how == H_INPUT) 485*4f766afcSPoul-Henning Kamp errx(EX_USAGE, 486*4f766afcSPoul-Henning Kamp "File-sets files cannot be used as source"); 487*4f766afcSPoul-Henning Kamp return (new file_set(fd, arg, how == H_OUTPUT)); 488*4f766afcSPoul-Henning Kamp } 489*4f766afcSPoul-Henning Kamp 490*4f766afcSPoul-Henning Kamp if (how != H_INPUT && rawfile) 491*4f766afcSPoul-Henning Kamp return (new flat_file(fd, arg, how == H_OUTPUT)); 492*4f766afcSPoul-Henning Kamp 493*4f766afcSPoul-Henning Kamp return (new tap_file(fd, arg, how == H_OUTPUT)); 494*4f766afcSPoul-Henning Kamp } 495*4f766afcSPoul-Henning Kamp 496*4f766afcSPoul-Henning Kamp //--------------------------------------------------------------------- 497*4f766afcSPoul-Henning Kamp 498*4f766afcSPoul-Henning Kamp static tape_dev *input; 499*4f766afcSPoul-Henning Kamp static tape_dev *output; 500*4f766afcSPoul-Henning Kamp 501*4f766afcSPoul-Henning Kamp static size_t maxblk = MAXREC; 502*4f766afcSPoul-Henning Kamp static uint64_t lastrec, fsize, tsize; 503*4f766afcSPoul-Henning Kamp static FILE *msg; 504*4f766afcSPoul-Henning Kamp static ssize_t lastnread; 505*4f766afcSPoul-Henning Kamp static struct timespec t_start, t_end; 506*4f766afcSPoul-Henning Kamp 507*4f766afcSPoul-Henning Kamp static void 508*4f766afcSPoul-Henning Kamp report_total(FILE *file) 509*4f766afcSPoul-Henning Kamp { 510*4f766afcSPoul-Henning Kamp double dur = (t_end.tv_nsec - t_start.tv_nsec) * 1e-9; 511*4f766afcSPoul-Henning Kamp dur += t_end.tv_sec - t_start.tv_sec; 512*4f766afcSPoul-Henning Kamp uintmax_t tot = tsize + fsize; 513*4f766afcSPoul-Henning Kamp fprintf(file, "total length: %ju bytes", tot); 514*4f766afcSPoul-Henning Kamp fprintf(file, " time: %.0f s", dur); 515*4f766afcSPoul-Henning Kamp tot /= 1024; 516*4f766afcSPoul-Henning Kamp fprintf(file, " rate: %.1f kB/s", (double)tot/dur); 517*4f766afcSPoul-Henning Kamp fprintf(file, "\n"); 518*4f766afcSPoul-Henning Kamp } 519*4f766afcSPoul-Henning Kamp 520*4f766afcSPoul-Henning Kamp static void 521*4f766afcSPoul-Henning Kamp sigintr(int signo __unused) 522*4f766afcSPoul-Henning Kamp { 523*4f766afcSPoul-Henning Kamp (void)signo; 524*4f766afcSPoul-Henning Kamp (void)clock_gettime(CLOCK_MONOTONIC, &t_end); 525*4f766afcSPoul-Henning Kamp if (record) { 526*4f766afcSPoul-Henning Kamp if (record - lastrec > 1) 527*4f766afcSPoul-Henning Kamp fprintf(msg, "records %ju to %ju\n", 528*4f766afcSPoul-Henning Kamp (intmax_t)lastrec, (intmax_t)record); 529*4f766afcSPoul-Henning Kamp else 530*4f766afcSPoul-Henning Kamp fprintf(msg, "record %ju\n", (intmax_t)lastrec); 531*4f766afcSPoul-Henning Kamp } 532*4f766afcSPoul-Henning Kamp fprintf(msg, "interrupt at file %d: record %ju\n", 533*4f766afcSPoul-Henning Kamp filen, (uintmax_t)record); 534*4f766afcSPoul-Henning Kamp report_total(msg); 535*4f766afcSPoul-Henning Kamp exit(1); 536*4f766afcSPoul-Henning Kamp } 537*4f766afcSPoul-Henning Kamp 538*4f766afcSPoul-Henning Kamp #ifdef SIGINFO 539*4f766afcSPoul-Henning Kamp static volatile sig_atomic_t want_info; 540*4f766afcSPoul-Henning Kamp 541*4f766afcSPoul-Henning Kamp static void 542*4f766afcSPoul-Henning Kamp siginfo(int signo) 543*4f766afcSPoul-Henning Kamp { 544*4f766afcSPoul-Henning Kamp (void)signo; 545*4f766afcSPoul-Henning Kamp want_info = 1; 546*4f766afcSPoul-Henning Kamp } 547*4f766afcSPoul-Henning Kamp 548*4f766afcSPoul-Henning Kamp static void 549*4f766afcSPoul-Henning Kamp check_want_info(void) 550*4f766afcSPoul-Henning Kamp { 551*4f766afcSPoul-Henning Kamp if (want_info) { 552*4f766afcSPoul-Henning Kamp (void)clock_gettime(CLOCK_MONOTONIC, &t_end); 553*4f766afcSPoul-Henning Kamp fprintf(stderr, "tcopy: file %d record %ju ", 554*4f766afcSPoul-Henning Kamp filen, (uintmax_t)record); 555*4f766afcSPoul-Henning Kamp report_total(stderr); 556*4f766afcSPoul-Henning Kamp want_info = 0; 557*4f766afcSPoul-Henning Kamp } 558*4f766afcSPoul-Henning Kamp } 559*4f766afcSPoul-Henning Kamp 560*4f766afcSPoul-Henning Kamp #else /* !SIGINFO */ 561*4f766afcSPoul-Henning Kamp 562*4f766afcSPoul-Henning Kamp static void 563*4f766afcSPoul-Henning Kamp check_want_info(void) 564*4f766afcSPoul-Henning Kamp { 565*4f766afcSPoul-Henning Kamp } 566*4f766afcSPoul-Henning Kamp 567*4f766afcSPoul-Henning Kamp #endif 568*4f766afcSPoul-Henning Kamp 569*4f766afcSPoul-Henning Kamp static char * 570*4f766afcSPoul-Henning Kamp getspace(size_t blk) 571*4f766afcSPoul-Henning Kamp { 572*4f766afcSPoul-Henning Kamp void *bp; 573*4f766afcSPoul-Henning Kamp 574*4f766afcSPoul-Henning Kamp assert(blk > 0); 575*4f766afcSPoul-Henning Kamp if ((bp = malloc(blk)) == NULL) 576*4f766afcSPoul-Henning Kamp errx(11, "no memory"); 577*4f766afcSPoul-Henning Kamp return ((char *)bp); 578*4f766afcSPoul-Henning Kamp } 579*4f766afcSPoul-Henning Kamp 580*4f766afcSPoul-Henning Kamp static void 581*4f766afcSPoul-Henning Kamp usage(void) 582*4f766afcSPoul-Henning Kamp { 583*4f766afcSPoul-Henning Kamp fprintf(stderr, "usage: tcopy [-cvx] [-s maxblk] [src [dest]]\n"); 584*4f766afcSPoul-Henning Kamp exit(1); 585*4f766afcSPoul-Henning Kamp } 586*4f766afcSPoul-Henning Kamp 587*4f766afcSPoul-Henning Kamp static void 588*4f766afcSPoul-Henning Kamp progress(ssize_t nread) 589*4f766afcSPoul-Henning Kamp { 590*4f766afcSPoul-Henning Kamp if (nread != lastnread) { 591*4f766afcSPoul-Henning Kamp if (lastnread != 0 && lastnread != NOCOUNT) { 592*4f766afcSPoul-Henning Kamp if (lastrec == 0 && nread == 0) 593*4f766afcSPoul-Henning Kamp fprintf(msg, "%ju records\n", 594*4f766afcSPoul-Henning Kamp (uintmax_t)record); 595*4f766afcSPoul-Henning Kamp else if (record - lastrec > 1) 596*4f766afcSPoul-Henning Kamp fprintf(msg, "records %ju to %ju\n", 597*4f766afcSPoul-Henning Kamp (uintmax_t)lastrec, 598*4f766afcSPoul-Henning Kamp (uintmax_t)record); 599*4f766afcSPoul-Henning Kamp else 600*4f766afcSPoul-Henning Kamp fprintf(msg, "record %ju\n", 601*4f766afcSPoul-Henning Kamp (uintmax_t)lastrec); 602*4f766afcSPoul-Henning Kamp } 603*4f766afcSPoul-Henning Kamp if (nread != 0) 604*4f766afcSPoul-Henning Kamp fprintf(msg, 605*4f766afcSPoul-Henning Kamp "file %d: block size %zd: ", filen, nread); 606*4f766afcSPoul-Henning Kamp (void) fflush(msg); 607*4f766afcSPoul-Henning Kamp lastrec = record; 608*4f766afcSPoul-Henning Kamp } 609*4f766afcSPoul-Henning Kamp if (nread > 0) { 610*4f766afcSPoul-Henning Kamp fsize += (size_t)nread; 611*4f766afcSPoul-Henning Kamp record++; 612*4f766afcSPoul-Henning Kamp } else { 613*4f766afcSPoul-Henning Kamp if (lastnread <= 0 && lastnread != NOCOUNT) { 614*4f766afcSPoul-Henning Kamp fprintf(msg, "eot\n"); 615*4f766afcSPoul-Henning Kamp return; 616*4f766afcSPoul-Henning Kamp } 617*4f766afcSPoul-Henning Kamp fprintf(msg, 618*4f766afcSPoul-Henning Kamp "file %d: eof after %ju records: %ju bytes\n", 619*4f766afcSPoul-Henning Kamp filen, (uintmax_t)record, (uintmax_t)fsize); 620*4f766afcSPoul-Henning Kamp filen++; 621*4f766afcSPoul-Henning Kamp tsize += fsize; 622*4f766afcSPoul-Henning Kamp fsize = record = lastrec = 0; 623*4f766afcSPoul-Henning Kamp lastnread = 0; 624*4f766afcSPoul-Henning Kamp } 625*4f766afcSPoul-Henning Kamp lastnread = nread; 626*4f766afcSPoul-Henning Kamp } 627*4f766afcSPoul-Henning Kamp 628*4f766afcSPoul-Henning Kamp static void 629*4f766afcSPoul-Henning Kamp read_or_copy(void) 630*4f766afcSPoul-Henning Kamp { 631*4f766afcSPoul-Henning Kamp int needeof; 632*4f766afcSPoul-Henning Kamp ssize_t nread, prev_read; 633*4f766afcSPoul-Henning Kamp char *buff = getspace(maxblk); 634*4f766afcSPoul-Henning Kamp 635*4f766afcSPoul-Henning Kamp (void)clock_gettime(CLOCK_MONOTONIC, &t_start); 636*4f766afcSPoul-Henning Kamp needeof = 0; 637*4f766afcSPoul-Henning Kamp for (prev_read = NOCOUNT;;) { 638*4f766afcSPoul-Henning Kamp check_want_info(); 639*4f766afcSPoul-Henning Kamp nread = input->read_blk(buff, maxblk); 640*4f766afcSPoul-Henning Kamp progress(nread); 641*4f766afcSPoul-Henning Kamp if (nread > 0) { 642*4f766afcSPoul-Henning Kamp if (output != NULL) { 643*4f766afcSPoul-Henning Kamp if (needeof) { 644*4f766afcSPoul-Henning Kamp output->file_mark(); 645*4f766afcSPoul-Henning Kamp needeof = 0; 646*4f766afcSPoul-Henning Kamp } 647*4f766afcSPoul-Henning Kamp output->write_blk(buff, (size_t)nread); 648*4f766afcSPoul-Henning Kamp } 649*4f766afcSPoul-Henning Kamp } else { 650*4f766afcSPoul-Henning Kamp if (prev_read <= 0 && prev_read != NOCOUNT) { 651*4f766afcSPoul-Henning Kamp break; 652*4f766afcSPoul-Henning Kamp } 653*4f766afcSPoul-Henning Kamp needeof = 1; 654*4f766afcSPoul-Henning Kamp } 655*4f766afcSPoul-Henning Kamp prev_read = nread; 656*4f766afcSPoul-Henning Kamp } 657*4f766afcSPoul-Henning Kamp (void)clock_gettime(CLOCK_MONOTONIC, &t_end); 658*4f766afcSPoul-Henning Kamp report_total(msg); 659*4f766afcSPoul-Henning Kamp free(buff); 660*4f766afcSPoul-Henning Kamp } 661*4f766afcSPoul-Henning Kamp 662*4f766afcSPoul-Henning Kamp static void 663*4f766afcSPoul-Henning Kamp verify(void) 664*4f766afcSPoul-Henning Kamp { 665*4f766afcSPoul-Henning Kamp char *buf1 = getspace(maxblk); 666*4f766afcSPoul-Henning Kamp char *buf2 = getspace(maxblk); 667*4f766afcSPoul-Henning Kamp int eot = 0; 668*4f766afcSPoul-Henning Kamp ssize_t nread1, nread2; 669*4f766afcSPoul-Henning Kamp filen = 0; 670*4f766afcSPoul-Henning Kamp tsize = 0; 671*4f766afcSPoul-Henning Kamp 672*4f766afcSPoul-Henning Kamp assert(output != NULL); 673*4f766afcSPoul-Henning Kamp (void)clock_gettime(CLOCK_MONOTONIC, &t_start); 674*4f766afcSPoul-Henning Kamp 675*4f766afcSPoul-Henning Kamp while (1) { 676*4f766afcSPoul-Henning Kamp check_want_info(); 677*4f766afcSPoul-Henning Kamp nread1 = input->read_blk(buf1, (size_t)maxblk); 678*4f766afcSPoul-Henning Kamp nread2 = output->verify_blk(buf2, maxblk, (size_t)nread1); 679*4f766afcSPoul-Henning Kamp progress(nread1); 680*4f766afcSPoul-Henning Kamp if (nread1 != nread2) { 681*4f766afcSPoul-Henning Kamp fprintf(msg, 682*4f766afcSPoul-Henning Kamp "tcopy: tapes have different block sizes; " 683*4f766afcSPoul-Henning Kamp "%zd != %zd.\n", nread1, nread2); 684*4f766afcSPoul-Henning Kamp exit(1); 685*4f766afcSPoul-Henning Kamp } 686*4f766afcSPoul-Henning Kamp if (nread1 > 0 && memcmp(buf1, buf2, (size_t)nread1)) { 687*4f766afcSPoul-Henning Kamp fprintf(msg, "tcopy: tapes have different data.\n"); 688*4f766afcSPoul-Henning Kamp exit(1); 689*4f766afcSPoul-Henning Kamp } else if (nread1 > 0) { 690*4f766afcSPoul-Henning Kamp eot = 0; 691*4f766afcSPoul-Henning Kamp } else if (eot++) { 692*4f766afcSPoul-Henning Kamp break; 693*4f766afcSPoul-Henning Kamp } 694*4f766afcSPoul-Henning Kamp } 695*4f766afcSPoul-Henning Kamp (void)clock_gettime(CLOCK_MONOTONIC, &t_end); 696*4f766afcSPoul-Henning Kamp report_total(msg); 697*4f766afcSPoul-Henning Kamp fprintf(msg, "tcopy: tapes are identical.\n"); 698*4f766afcSPoul-Henning Kamp fprintf(msg, "rewinding\n"); 699*4f766afcSPoul-Henning Kamp input->rewind(); 700*4f766afcSPoul-Henning Kamp output->rewind(); 701*4f766afcSPoul-Henning Kamp 702*4f766afcSPoul-Henning Kamp free(buf1); 703*4f766afcSPoul-Henning Kamp free(buf2); 704*4f766afcSPoul-Henning Kamp } 705*4f766afcSPoul-Henning Kamp 706*4f766afcSPoul-Henning Kamp int 707*4f766afcSPoul-Henning Kamp main(int argc, char *argv[]) 708*4f766afcSPoul-Henning Kamp { 709*4f766afcSPoul-Henning Kamp enum operation op = READ; 710*4f766afcSPoul-Henning Kamp int ch; 711*4f766afcSPoul-Henning Kamp unsigned long maxphys = 0; 712*4f766afcSPoul-Henning Kamp size_t l_maxphys = sizeof maxphys; 713*4f766afcSPoul-Henning Kamp uint64_t tmp; 714*4f766afcSPoul-Henning Kamp int rawfile = 0; 715*4f766afcSPoul-Henning Kamp 716*4f766afcSPoul-Henning Kamp setbuf(stderr, NULL); 717*4f766afcSPoul-Henning Kamp 718*4f766afcSPoul-Henning Kamp if (!sysctlbyname("kern.maxphys", &maxphys, &l_maxphys, NULL, 0UL)) 719*4f766afcSPoul-Henning Kamp maxblk = maxphys; 720*4f766afcSPoul-Henning Kamp 721*4f766afcSPoul-Henning Kamp msg = stdout; 722*4f766afcSPoul-Henning Kamp while ((ch = getopt(argc, argv, "cl:rs:vx")) != -1) 723*4f766afcSPoul-Henning Kamp switch((char)ch) { 724*4f766afcSPoul-Henning Kamp case 'c': 725*4f766afcSPoul-Henning Kamp op = COPYVERIFY; 726*4f766afcSPoul-Henning Kamp break; 727*4f766afcSPoul-Henning Kamp case 'l': 728*4f766afcSPoul-Henning Kamp msg = fopen(optarg, "w"); 729*4f766afcSPoul-Henning Kamp if (msg == NULL) 730*4f766afcSPoul-Henning Kamp errx(EX_CANTCREAT, "Cannot open %s", optarg); 731*4f766afcSPoul-Henning Kamp setbuf(msg, NULL); 732*4f766afcSPoul-Henning Kamp break; 733*4f766afcSPoul-Henning Kamp case 'r': 734*4f766afcSPoul-Henning Kamp rawfile = 1; 735*4f766afcSPoul-Henning Kamp break; 736*4f766afcSPoul-Henning Kamp case 's': 737*4f766afcSPoul-Henning Kamp if (expand_number(optarg, &tmp)) { 738*4f766afcSPoul-Henning Kamp warnx("illegal block size"); 739*4f766afcSPoul-Henning Kamp usage(); 740*4f766afcSPoul-Henning Kamp } 741*4f766afcSPoul-Henning Kamp maxblk = tmp; 742*4f766afcSPoul-Henning Kamp if (maxblk == 0) { 743*4f766afcSPoul-Henning Kamp warnx("illegal block size"); 744*4f766afcSPoul-Henning Kamp usage(); 745*4f766afcSPoul-Henning Kamp } 746*4f766afcSPoul-Henning Kamp break; 747*4f766afcSPoul-Henning Kamp case 'v': 748*4f766afcSPoul-Henning Kamp op = VERIFY; 749*4f766afcSPoul-Henning Kamp break; 750*4f766afcSPoul-Henning Kamp case 'x': 751*4f766afcSPoul-Henning Kamp if (msg == stdout) 752*4f766afcSPoul-Henning Kamp msg = stderr; 753*4f766afcSPoul-Henning Kamp break; 754*4f766afcSPoul-Henning Kamp case '?': 755*4f766afcSPoul-Henning Kamp default: 756*4f766afcSPoul-Henning Kamp usage(); 757*4f766afcSPoul-Henning Kamp } 758*4f766afcSPoul-Henning Kamp argc -= optind; 759*4f766afcSPoul-Henning Kamp argv += optind; 760*4f766afcSPoul-Henning Kamp 761*4f766afcSPoul-Henning Kamp switch(argc) { 762*4f766afcSPoul-Henning Kamp case 0: 763*4f766afcSPoul-Henning Kamp if (op != READ) 764*4f766afcSPoul-Henning Kamp usage(); 765*4f766afcSPoul-Henning Kamp break; 766*4f766afcSPoul-Henning Kamp case 1: 767*4f766afcSPoul-Henning Kamp if (op != READ) 768*4f766afcSPoul-Henning Kamp usage(); 769*4f766afcSPoul-Henning Kamp break; 770*4f766afcSPoul-Henning Kamp case 2: 771*4f766afcSPoul-Henning Kamp if (op == READ) 772*4f766afcSPoul-Henning Kamp op = COPY; 773*4f766afcSPoul-Henning Kamp if (!strcmp(argv[1], "-")) { 774*4f766afcSPoul-Henning Kamp if (op == COPYVERIFY) 775*4f766afcSPoul-Henning Kamp errx(EX_USAGE, 776*4f766afcSPoul-Henning Kamp "Cannot copy+verify with '-' destination"); 777*4f766afcSPoul-Henning Kamp if (msg == stdout) 778*4f766afcSPoul-Henning Kamp msg = stderr; 779*4f766afcSPoul-Henning Kamp } 780*4f766afcSPoul-Henning Kamp if (op == VERIFY) 781*4f766afcSPoul-Henning Kamp output = open_arg(argv[1], H_VERIFY, 0); 782*4f766afcSPoul-Henning Kamp else 783*4f766afcSPoul-Henning Kamp output = open_arg(argv[1], H_OUTPUT, rawfile); 784*4f766afcSPoul-Henning Kamp break; 785*4f766afcSPoul-Henning Kamp default: 786*4f766afcSPoul-Henning Kamp usage(); 787*4f766afcSPoul-Henning Kamp } 788*4f766afcSPoul-Henning Kamp 789*4f766afcSPoul-Henning Kamp if (argc == 0) { 790*4f766afcSPoul-Henning Kamp input = open_arg(_PATH_DEFTAPE, H_INPUT, 0); 791*4f766afcSPoul-Henning Kamp } else { 792*4f766afcSPoul-Henning Kamp input = open_arg(argv[0], H_INPUT, 0); 793*4f766afcSPoul-Henning Kamp } 794*4f766afcSPoul-Henning Kamp 795*4f766afcSPoul-Henning Kamp if ((signal(SIGINT, SIG_IGN)) != SIG_IGN) 796*4f766afcSPoul-Henning Kamp (void) signal(SIGINT, sigintr); 797*4f766afcSPoul-Henning Kamp 798*4f766afcSPoul-Henning Kamp #ifdef SIGINFO 799*4f766afcSPoul-Henning Kamp (void)signal(SIGINFO, siginfo); 800*4f766afcSPoul-Henning Kamp #endif 801*4f766afcSPoul-Henning Kamp 802*4f766afcSPoul-Henning Kamp if (op != VERIFY) { 803*4f766afcSPoul-Henning Kamp if (op == COPYVERIFY) { 804*4f766afcSPoul-Henning Kamp assert(output != NULL); 805*4f766afcSPoul-Henning Kamp fprintf(msg, "rewinding\n"); 806*4f766afcSPoul-Henning Kamp input->rewind(); 807*4f766afcSPoul-Henning Kamp output->rewind(); 808*4f766afcSPoul-Henning Kamp } 809*4f766afcSPoul-Henning Kamp 810*4f766afcSPoul-Henning Kamp read_or_copy(); 811*4f766afcSPoul-Henning Kamp 812*4f766afcSPoul-Henning Kamp if (op == COPY || op == COPYVERIFY) { 813*4f766afcSPoul-Henning Kamp assert(output != NULL); 814*4f766afcSPoul-Henning Kamp output->file_mark(); 815*4f766afcSPoul-Henning Kamp output->file_mark(); 816*4f766afcSPoul-Henning Kamp } 817*4f766afcSPoul-Henning Kamp } 818*4f766afcSPoul-Henning Kamp 819*4f766afcSPoul-Henning Kamp if (op == VERIFY || op == COPYVERIFY) { 820*4f766afcSPoul-Henning Kamp 821*4f766afcSPoul-Henning Kamp if (op == COPYVERIFY) { 822*4f766afcSPoul-Henning Kamp assert(output != NULL); 823*4f766afcSPoul-Henning Kamp fprintf(msg, "rewinding\n"); 824*4f766afcSPoul-Henning Kamp input->rewind(); 825*4f766afcSPoul-Henning Kamp output->rewind(); 826*4f766afcSPoul-Henning Kamp input->direction = tape_dev::SRC; 827*4f766afcSPoul-Henning Kamp output->direction = tape_dev::SRC; 828*4f766afcSPoul-Henning Kamp } 829*4f766afcSPoul-Henning Kamp 830*4f766afcSPoul-Henning Kamp verify(); 831*4f766afcSPoul-Henning Kamp } 832*4f766afcSPoul-Henning Kamp 833*4f766afcSPoul-Henning Kamp if (msg != stderr && msg != stdout) 834*4f766afcSPoul-Henning Kamp report_total(stderr); 835*4f766afcSPoul-Henning Kamp 836*4f766afcSPoul-Henning Kamp return(0); 837*4f766afcSPoul-Henning Kamp } 838