14f766afcSPoul-Henning Kamp /*- 24f766afcSPoul-Henning Kamp * SPDX-License-Identifier: BSD-2-Clause 34f766afcSPoul-Henning Kamp * 44f766afcSPoul-Henning Kamp * Copyright (c) 2025 Poul-Henning Kamp, <phk@FreeBSD.org> 54f766afcSPoul-Henning Kamp * Copyright (c) 1985, 1987, 1993 64f766afcSPoul-Henning Kamp * The Regents of the University of California. All rights reserved. 74f766afcSPoul-Henning Kamp * 84f766afcSPoul-Henning Kamp * Redistribution and use in source and binary forms, with or without 94f766afcSPoul-Henning Kamp * modification, are permitted provided that the following conditions 104f766afcSPoul-Henning Kamp * are met: 114f766afcSPoul-Henning Kamp * 1. Redistributions of source code must retain the above copyright 124f766afcSPoul-Henning Kamp * notice, this list of conditions and the following disclaimer. 134f766afcSPoul-Henning Kamp * 2. Redistributions in binary form must reproduce the above copyright 144f766afcSPoul-Henning Kamp * notice, this list of conditions and the following disclaimer in the 154f766afcSPoul-Henning Kamp * documentation and/or other materials provided with the distribution. 164f766afcSPoul-Henning Kamp * 174f766afcSPoul-Henning Kamp * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 184f766afcSPoul-Henning Kamp * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 194f766afcSPoul-Henning Kamp * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 204f766afcSPoul-Henning Kamp * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 214f766afcSPoul-Henning Kamp * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 224f766afcSPoul-Henning Kamp * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 234f766afcSPoul-Henning Kamp * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 244f766afcSPoul-Henning Kamp * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 254f766afcSPoul-Henning Kamp * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 264f766afcSPoul-Henning Kamp * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 274f766afcSPoul-Henning Kamp * SUCH DAMAGE. 284f766afcSPoul-Henning Kamp */ 294f766afcSPoul-Henning Kamp 304f766afcSPoul-Henning Kamp #include <assert.h> 314f766afcSPoul-Henning Kamp #include <err.h> 324f766afcSPoul-Henning Kamp #include <errno.h> 334f766afcSPoul-Henning Kamp #include <fcntl.h> 344f766afcSPoul-Henning Kamp #include <paths.h> 354f766afcSPoul-Henning Kamp #include <signal.h> 364f766afcSPoul-Henning Kamp #include <stdint.h> 374f766afcSPoul-Henning Kamp #include <stdio.h> 384f766afcSPoul-Henning Kamp #include <stdlib.h> 394f766afcSPoul-Henning Kamp #include <string.h> 404f766afcSPoul-Henning Kamp #include <time.h> 414f766afcSPoul-Henning Kamp #include <sysexits.h> 424f766afcSPoul-Henning Kamp #include <unistd.h> 434f766afcSPoul-Henning Kamp 444f766afcSPoul-Henning Kamp #include <sys/endian.h> 454f766afcSPoul-Henning Kamp #include <sys/mtio.h> 464f766afcSPoul-Henning Kamp #include <sys/stat.h> 474f766afcSPoul-Henning Kamp #include <sys/sysctl.h> 484f766afcSPoul-Henning Kamp #include <sys/uio.h> 494f766afcSPoul-Henning Kamp 504f766afcSPoul-Henning Kamp #include <libutil.h> 514f766afcSPoul-Henning Kamp 524f766afcSPoul-Henning Kamp #define MAXREC (1024 * 1024) 534f766afcSPoul-Henning Kamp #define NOCOUNT (-2) 544f766afcSPoul-Henning Kamp 554f766afcSPoul-Henning Kamp enum operation {READ, VERIFY, COPY, COPYVERIFY}; 564f766afcSPoul-Henning Kamp 574f766afcSPoul-Henning Kamp // Stuff the tape_devs need to know about 584f766afcSPoul-Henning Kamp static int filen; 594f766afcSPoul-Henning Kamp static uint64_t record; 604f766afcSPoul-Henning Kamp 614f766afcSPoul-Henning Kamp //--------------------------------------------------------------------- 624f766afcSPoul-Henning Kamp 634f766afcSPoul-Henning Kamp class tape_dev { 644f766afcSPoul-Henning Kamp size_t max_read_size; 654f766afcSPoul-Henning Kamp public: 664f766afcSPoul-Henning Kamp int fd; 674f766afcSPoul-Henning Kamp char *name; 684f766afcSPoul-Henning Kamp enum direction {SRC, DST} direction; 694f766afcSPoul-Henning Kamp 704f766afcSPoul-Henning Kamp tape_dev(int file_handle, const char *spec, bool destination); 714f766afcSPoul-Henning Kamp 724f766afcSPoul-Henning Kamp virtual ssize_t read_blk(void *dst, size_t len); 734f766afcSPoul-Henning Kamp virtual ssize_t verify_blk(void *dst, size_t len, size_t expected); 744f766afcSPoul-Henning Kamp virtual void write_blk(const void *src, size_t len); 754f766afcSPoul-Henning Kamp virtual void file_mark(void); 764f766afcSPoul-Henning Kamp virtual void rewind(void); 774f766afcSPoul-Henning Kamp }; 784f766afcSPoul-Henning Kamp 794f766afcSPoul-Henning Kamp tape_dev::tape_dev(int file_handle, const char *spec, bool destination) 804f766afcSPoul-Henning Kamp { 814f766afcSPoul-Henning Kamp assert(file_handle >= 0); 824f766afcSPoul-Henning Kamp fd = file_handle; 834f766afcSPoul-Henning Kamp name = strdup(spec); 844f766afcSPoul-Henning Kamp assert(name != NULL); 854f766afcSPoul-Henning Kamp direction = destination ? DST : SRC; 864f766afcSPoul-Henning Kamp max_read_size = 0; 874f766afcSPoul-Henning Kamp } 884f766afcSPoul-Henning Kamp 894f766afcSPoul-Henning Kamp ssize_t 904f766afcSPoul-Henning Kamp tape_dev::read_blk(void *dst, size_t len) 914f766afcSPoul-Henning Kamp { 924f766afcSPoul-Henning Kamp ssize_t retval = -1; 934f766afcSPoul-Henning Kamp 944f766afcSPoul-Henning Kamp if (max_read_size == 0) { 954f766afcSPoul-Henning Kamp max_read_size = len; 964f766afcSPoul-Henning Kamp while (max_read_size > 0) { 974f766afcSPoul-Henning Kamp retval = read(fd, dst, max_read_size); 984f766afcSPoul-Henning Kamp if (retval >= 0 || (errno != EINVAL && errno != EFBIG)) 994f766afcSPoul-Henning Kamp break; 1004f766afcSPoul-Henning Kamp if (max_read_size < 512) 1014f766afcSPoul-Henning Kamp errx(1, "Cannot find a sane max blocksize"); 1024f766afcSPoul-Henning Kamp 1034f766afcSPoul-Henning Kamp // Reduce to next lower power of two 1044f766afcSPoul-Henning Kamp int i = flsl((long)max_read_size - 1L); 1054f766afcSPoul-Henning Kamp max_read_size = 1UL << (i - 1); 1064f766afcSPoul-Henning Kamp } 1074f766afcSPoul-Henning Kamp } else { 1084f766afcSPoul-Henning Kamp retval = read(fd, dst, (size_t)max_read_size); 1094f766afcSPoul-Henning Kamp } 1104f766afcSPoul-Henning Kamp if (retval < 0) { 1114f766afcSPoul-Henning Kamp err(1, "read error, %s, file %d, record %ju", 1124f766afcSPoul-Henning Kamp name, filen, (uintmax_t)record); 1134f766afcSPoul-Henning Kamp } 1144f766afcSPoul-Henning Kamp return (retval); 1154f766afcSPoul-Henning Kamp } 1164f766afcSPoul-Henning Kamp 1174f766afcSPoul-Henning Kamp ssize_t 1184f766afcSPoul-Henning Kamp tape_dev::verify_blk(void *dst, size_t len, size_t expected) 1194f766afcSPoul-Henning Kamp { 1204f766afcSPoul-Henning Kamp (void)expected; 1214f766afcSPoul-Henning Kamp return read_blk(dst, len); 1224f766afcSPoul-Henning Kamp } 1234f766afcSPoul-Henning Kamp 1244f766afcSPoul-Henning Kamp void 1254f766afcSPoul-Henning Kamp tape_dev::write_blk(const void *src, size_t len) 1264f766afcSPoul-Henning Kamp { 1274f766afcSPoul-Henning Kamp assert(len > 0); 1284f766afcSPoul-Henning Kamp ssize_t nwrite = write(fd, src, len); 1294f766afcSPoul-Henning Kamp if (nwrite < 0 || (size_t) nwrite != len) { 1304f766afcSPoul-Henning Kamp if (nwrite == -1) { 1314f766afcSPoul-Henning Kamp warn("write error, file %d, record %ju", 1324f766afcSPoul-Henning Kamp filen, (intmax_t)record); 1334f766afcSPoul-Henning Kamp } else { 1344f766afcSPoul-Henning Kamp warnx("write error, file %d, record %ju", 1354f766afcSPoul-Henning Kamp filen, (intmax_t)record); 1364f766afcSPoul-Henning Kamp warnx("write (%zd) != read (%zd)", nwrite, len); 1374f766afcSPoul-Henning Kamp } 1384f766afcSPoul-Henning Kamp errx(5, "copy aborted"); 1394f766afcSPoul-Henning Kamp } 1404f766afcSPoul-Henning Kamp return; 1414f766afcSPoul-Henning Kamp } 1424f766afcSPoul-Henning Kamp 1434f766afcSPoul-Henning Kamp void 1444f766afcSPoul-Henning Kamp tape_dev::file_mark(void) 1454f766afcSPoul-Henning Kamp { 1464f766afcSPoul-Henning Kamp struct mtop op; 1474f766afcSPoul-Henning Kamp 1484f766afcSPoul-Henning Kamp op.mt_op = MTWEOF; 1494f766afcSPoul-Henning Kamp op.mt_count = (daddr_t)1; 1504f766afcSPoul-Henning Kamp if (ioctl(fd, MTIOCTOP, (char *)&op) < 0) 1514f766afcSPoul-Henning Kamp err(6, "tape op (write file mark)"); 1524f766afcSPoul-Henning Kamp } 1534f766afcSPoul-Henning Kamp 1544f766afcSPoul-Henning Kamp void 1554f766afcSPoul-Henning Kamp tape_dev::rewind(void) 1564f766afcSPoul-Henning Kamp { 1574f766afcSPoul-Henning Kamp struct mtop op; 1584f766afcSPoul-Henning Kamp 1594f766afcSPoul-Henning Kamp op.mt_op = MTREW; 1604f766afcSPoul-Henning Kamp op.mt_count = (daddr_t)1; 1614f766afcSPoul-Henning Kamp if (ioctl(fd, MTIOCTOP, (char *)&op) < 0) 1624f766afcSPoul-Henning Kamp err(6, "tape op (rewind)"); 1634f766afcSPoul-Henning Kamp } 1644f766afcSPoul-Henning Kamp 1654f766afcSPoul-Henning Kamp //--------------------------------------------------------------------- 1664f766afcSPoul-Henning Kamp 1674f766afcSPoul-Henning Kamp class tap_file: public tape_dev { 1684f766afcSPoul-Henning Kamp public: 1694f766afcSPoul-Henning Kamp tap_file(int file_handle, const char *spec, bool dst) : 1704f766afcSPoul-Henning Kamp tape_dev(file_handle, spec, dst) {}; 1714f766afcSPoul-Henning Kamp ssize_t read_blk(void *dst, size_t len); 1724f766afcSPoul-Henning Kamp void write_blk(const void *src, size_t len); 1734f766afcSPoul-Henning Kamp void file_mark(void); 1744f766afcSPoul-Henning Kamp virtual void rewind(void); 1754f766afcSPoul-Henning Kamp }; 1764f766afcSPoul-Henning Kamp 1774f766afcSPoul-Henning Kamp static 1784f766afcSPoul-Henning Kamp ssize_t full_read(int fd, void *dst, size_t len) 1794f766afcSPoul-Henning Kamp { 1804f766afcSPoul-Henning Kamp // Input may be a socket which returns partial reads 1814f766afcSPoul-Henning Kamp 1824f766afcSPoul-Henning Kamp ssize_t retval = read(fd, dst, len); 1834f766afcSPoul-Henning Kamp if (retval <= 0 || (size_t)retval == len) 1844f766afcSPoul-Henning Kamp return (retval); 1854f766afcSPoul-Henning Kamp 1864f766afcSPoul-Henning Kamp char *ptr = (char *)dst + retval; 1874f766afcSPoul-Henning Kamp size_t left = len - (size_t)retval; 1884f766afcSPoul-Henning Kamp while (left > 0) { 1894f766afcSPoul-Henning Kamp retval = read(fd, ptr, left); 1904f766afcSPoul-Henning Kamp if (retval <= 0) 1914f766afcSPoul-Henning Kamp return (retval); 1924f766afcSPoul-Henning Kamp left -= (size_t)retval; 1934f766afcSPoul-Henning Kamp ptr += retval; 1944f766afcSPoul-Henning Kamp } 1954f766afcSPoul-Henning Kamp return ((ssize_t)len); 1964f766afcSPoul-Henning Kamp } 1974f766afcSPoul-Henning Kamp 1984f766afcSPoul-Henning Kamp ssize_t 1994f766afcSPoul-Henning Kamp tap_file::read_blk(void *dst, size_t len) 2004f766afcSPoul-Henning Kamp { 2014f766afcSPoul-Henning Kamp char lbuf[4]; 2024f766afcSPoul-Henning Kamp 2034f766afcSPoul-Henning Kamp ssize_t nread = full_read(fd, lbuf, sizeof lbuf); 2044f766afcSPoul-Henning Kamp if (nread == 0) 2054f766afcSPoul-Henning Kamp return (0); 2064f766afcSPoul-Henning Kamp 2074f766afcSPoul-Henning Kamp if ((size_t)nread != sizeof lbuf) 2084f766afcSPoul-Henning Kamp err(EX_DATAERR, "Corrupt tap-file, read hdr1=%zd", nread); 2094f766afcSPoul-Henning Kamp 2104f766afcSPoul-Henning Kamp uint32_t u = le32dec(lbuf); 2114f766afcSPoul-Henning Kamp if (u == 0 || (u >> 24) == 0xff) 2124f766afcSPoul-Henning Kamp return(0); 2134f766afcSPoul-Henning Kamp 2144f766afcSPoul-Henning Kamp if (u > len) 2154f766afcSPoul-Henning Kamp err(17, "tapfile blocksize too big, 0x%08x", u); 2164f766afcSPoul-Henning Kamp 2174f766afcSPoul-Henning Kamp size_t alen = (u + 1) & ~1; 2184f766afcSPoul-Henning Kamp assert (alen <= len); 2194f766afcSPoul-Henning Kamp 2204f766afcSPoul-Henning Kamp ssize_t retval = full_read(fd, dst, alen); 2214f766afcSPoul-Henning Kamp if (retval < 0 || (size_t)retval != alen) 2224f766afcSPoul-Henning Kamp err(EX_DATAERR, "Corrupt tap-file, read data=%zd", retval); 2234f766afcSPoul-Henning Kamp 2244f766afcSPoul-Henning Kamp nread = full_read(fd, lbuf, sizeof lbuf); 2254f766afcSPoul-Henning Kamp if ((size_t)nread != sizeof lbuf) 2264f766afcSPoul-Henning Kamp err(EX_DATAERR, "Corrupt tap-file, read hdr2=%zd", nread); 2274f766afcSPoul-Henning Kamp 2284f766afcSPoul-Henning Kamp uint32_t v = le32dec(lbuf); 2294f766afcSPoul-Henning Kamp if (u == v) 2304f766afcSPoul-Henning Kamp return (u); 2314f766afcSPoul-Henning Kamp err(EX_DATAERR, 2324f766afcSPoul-Henning Kamp "Corrupt tap-file, headers differ (0x%08x != 0x%08x)", u, v); 2334f766afcSPoul-Henning Kamp } 2344f766afcSPoul-Henning Kamp 2354f766afcSPoul-Henning Kamp void 2364f766afcSPoul-Henning Kamp tap_file::write_blk(const void *src, size_t len) 2374f766afcSPoul-Henning Kamp { 2384f766afcSPoul-Henning Kamp struct iovec iov[4]; 2394f766afcSPoul-Henning Kamp uint8_t zero = 0; 2404f766afcSPoul-Henning Kamp int niov = 0; 2414f766afcSPoul-Henning Kamp size_t expect = 0; 2424f766afcSPoul-Henning Kamp char tbuf[4]; 2434f766afcSPoul-Henning Kamp 2444f766afcSPoul-Henning Kamp assert((len & ~0xffffffffULL) == 0); 2454f766afcSPoul-Henning Kamp le32enc(tbuf, (uint32_t)len); 2464f766afcSPoul-Henning Kamp 2474f766afcSPoul-Henning Kamp iov[niov].iov_base = tbuf; 2484f766afcSPoul-Henning Kamp iov[niov].iov_len = sizeof tbuf; 2494f766afcSPoul-Henning Kamp expect += iov[niov].iov_len; 2504f766afcSPoul-Henning Kamp niov += 1; 2514f766afcSPoul-Henning Kamp 2524f766afcSPoul-Henning Kamp iov[niov].iov_base = (void*)(uintptr_t)src; 2534f766afcSPoul-Henning Kamp iov[niov].iov_len = len; 2544f766afcSPoul-Henning Kamp expect += iov[niov].iov_len; 2554f766afcSPoul-Henning Kamp niov += 1; 2564f766afcSPoul-Henning Kamp 2574f766afcSPoul-Henning Kamp if (len & 1) { 2584f766afcSPoul-Henning Kamp iov[niov].iov_base = &zero; 2594f766afcSPoul-Henning Kamp iov[niov].iov_len = 1; 2604f766afcSPoul-Henning Kamp expect += iov[niov].iov_len; 2614f766afcSPoul-Henning Kamp niov += 1; 2624f766afcSPoul-Henning Kamp } 2634f766afcSPoul-Henning Kamp 2644f766afcSPoul-Henning Kamp iov[niov].iov_base = tbuf; 2654f766afcSPoul-Henning Kamp iov[niov].iov_len = sizeof tbuf; 2664f766afcSPoul-Henning Kamp expect += iov[niov].iov_len; 2674f766afcSPoul-Henning Kamp niov += 1; 2684f766afcSPoul-Henning Kamp 2694f766afcSPoul-Henning Kamp ssize_t nwrite = writev(fd, iov, niov); 2704f766afcSPoul-Henning Kamp if (nwrite < 0 || (size_t)nwrite != expect) 2714f766afcSPoul-Henning Kamp errx(17, "write error (%zd != %zd)", nwrite, expect); 2724f766afcSPoul-Henning Kamp } 2734f766afcSPoul-Henning Kamp 2744f766afcSPoul-Henning Kamp void 2754f766afcSPoul-Henning Kamp tap_file::file_mark(void) 2764f766afcSPoul-Henning Kamp { 2774f766afcSPoul-Henning Kamp char tbuf[4]; 2784f766afcSPoul-Henning Kamp le32enc(tbuf, 0); 2794f766afcSPoul-Henning Kamp ssize_t nwrite = write(fd, tbuf, sizeof tbuf); 2804f766afcSPoul-Henning Kamp if ((size_t)nwrite != sizeof tbuf) 2814f766afcSPoul-Henning Kamp errx(17, "write error (%zd != %zd)", nwrite, sizeof tbuf); 2824f766afcSPoul-Henning Kamp } 2834f766afcSPoul-Henning Kamp 2844f766afcSPoul-Henning Kamp void 2854f766afcSPoul-Henning Kamp tap_file::rewind(void) 2864f766afcSPoul-Henning Kamp { 2874f766afcSPoul-Henning Kamp off_t where; 2884f766afcSPoul-Henning Kamp if (direction == DST) { 2894f766afcSPoul-Henning Kamp char tbuf[4]; 2904f766afcSPoul-Henning Kamp le32enc(tbuf, 0xffffffff); 2914f766afcSPoul-Henning Kamp ssize_t nwrite = write(fd, tbuf, sizeof tbuf); 2924f766afcSPoul-Henning Kamp if ((size_t)nwrite != sizeof tbuf) 2934f766afcSPoul-Henning Kamp errx(17, 2944f766afcSPoul-Henning Kamp "write error (%zd != %zd)", nwrite, sizeof tbuf); 2954f766afcSPoul-Henning Kamp } 2964f766afcSPoul-Henning Kamp where = lseek(fd, 0L, SEEK_SET); 2974f766afcSPoul-Henning Kamp if (where != 0 && errno == ESPIPE) 2984f766afcSPoul-Henning Kamp err(EX_USAGE, "Cannot rewind sockets and pipes"); 2994f766afcSPoul-Henning Kamp if (where != 0) 3004f766afcSPoul-Henning Kamp err(17, "lseek(0) failed"); 3014f766afcSPoul-Henning Kamp } 3024f766afcSPoul-Henning Kamp 3034f766afcSPoul-Henning Kamp //--------------------------------------------------------------------- 3044f766afcSPoul-Henning Kamp 3054f766afcSPoul-Henning Kamp class file_set: public tape_dev { 3064f766afcSPoul-Henning Kamp public: 3074f766afcSPoul-Henning Kamp file_set(int file_handle, const char *spec, bool dst) : 3084f766afcSPoul-Henning Kamp tape_dev(file_handle, spec, dst) {}; 3094f766afcSPoul-Henning Kamp ssize_t read_blk(void *dst, size_t len); 3104f766afcSPoul-Henning Kamp ssize_t verify_blk(void *dst, size_t len, size_t expected); 3114f766afcSPoul-Henning Kamp void write_blk(const void *src, size_t len); 3124f766afcSPoul-Henning Kamp void file_mark(void); 3134f766afcSPoul-Henning Kamp void rewind(void); 3144f766afcSPoul-Henning Kamp void open_next(bool increment); 3154f766afcSPoul-Henning Kamp }; 3164f766afcSPoul-Henning Kamp 3174f766afcSPoul-Henning Kamp void 3184f766afcSPoul-Henning Kamp file_set::open_next(bool increment) 3194f766afcSPoul-Henning Kamp { 3204f766afcSPoul-Henning Kamp if (fd >= 0) { 3214f766afcSPoul-Henning Kamp assert(close(fd) >= 0); 3224f766afcSPoul-Henning Kamp fd = -1; 3234f766afcSPoul-Henning Kamp } 3244f766afcSPoul-Henning Kamp if (increment) { 3254f766afcSPoul-Henning Kamp char *p = strchr(name, '\0') - 3; 3264f766afcSPoul-Henning Kamp if (++p[2] == '9') { 3274f766afcSPoul-Henning Kamp p[2] = '0'; 3284f766afcSPoul-Henning Kamp if (++p[1] == '9') { 3294f766afcSPoul-Henning Kamp p[1] = '0'; 3304f766afcSPoul-Henning Kamp if (++p[0] == '9') { 3314f766afcSPoul-Henning Kamp errx(EX_USAGE, 3324f766afcSPoul-Henning Kamp "file-set sequence overflow"); 3334f766afcSPoul-Henning Kamp } 3344f766afcSPoul-Henning Kamp } 3354f766afcSPoul-Henning Kamp } 3364f766afcSPoul-Henning Kamp } 3374f766afcSPoul-Henning Kamp if (direction == DST) { 3384f766afcSPoul-Henning Kamp fd = open(name, O_RDWR|O_CREAT, DEFFILEMODE); 3394f766afcSPoul-Henning Kamp if (fd < 0) 3404f766afcSPoul-Henning Kamp err(1, "Could not open %s", name); 3414f766afcSPoul-Henning Kamp } else { 3424f766afcSPoul-Henning Kamp fd = open(name, O_RDONLY, 0); 3434f766afcSPoul-Henning Kamp } 3444f766afcSPoul-Henning Kamp } 3454f766afcSPoul-Henning Kamp 3464f766afcSPoul-Henning Kamp ssize_t 3474f766afcSPoul-Henning Kamp file_set::read_blk(void *dst, size_t len) 3484f766afcSPoul-Henning Kamp { 3494f766afcSPoul-Henning Kamp (void)dst; 3504f766afcSPoul-Henning Kamp (void)len; 3514f766afcSPoul-Henning Kamp errx(EX_SOFTWARE, "That was not supposed to happen"); 3524f766afcSPoul-Henning Kamp } 3534f766afcSPoul-Henning Kamp 3544f766afcSPoul-Henning Kamp ssize_t 3554f766afcSPoul-Henning Kamp file_set::verify_blk(void *dst, size_t len, size_t expected) 3564f766afcSPoul-Henning Kamp { 3574f766afcSPoul-Henning Kamp (void)len; 3584f766afcSPoul-Henning Kamp if (fd < 0) 3594f766afcSPoul-Henning Kamp open_next(true); 3604f766afcSPoul-Henning Kamp if (fd < 0) 3614f766afcSPoul-Henning Kamp return (0); 3624f766afcSPoul-Henning Kamp ssize_t retval = read(fd, dst, expected); 3634f766afcSPoul-Henning Kamp if (retval == 0) { 3644f766afcSPoul-Henning Kamp assert(close(fd) >= 0); 3654f766afcSPoul-Henning Kamp fd = -1; 3664f766afcSPoul-Henning Kamp } 3674f766afcSPoul-Henning Kamp return (retval); 3684f766afcSPoul-Henning Kamp } 3694f766afcSPoul-Henning Kamp 3704f766afcSPoul-Henning Kamp void 3714f766afcSPoul-Henning Kamp file_set::write_blk(const void *src, size_t len) 3724f766afcSPoul-Henning Kamp { 3734f766afcSPoul-Henning Kamp if (fd < 0) 3744f766afcSPoul-Henning Kamp open_next(true); 3754f766afcSPoul-Henning Kamp ssize_t nwrite = write(fd, src, len); 3764f766afcSPoul-Henning Kamp if (nwrite < 0 || (size_t)nwrite != len) 3774f766afcSPoul-Henning Kamp errx(17, "write error (%zd != %zd)", nwrite, len); 3784f766afcSPoul-Henning Kamp } 3794f766afcSPoul-Henning Kamp 3804f766afcSPoul-Henning Kamp void 3814f766afcSPoul-Henning Kamp file_set::file_mark(void) 3824f766afcSPoul-Henning Kamp { 3834f766afcSPoul-Henning Kamp if (fd < 0) 3844f766afcSPoul-Henning Kamp return; 3854f766afcSPoul-Henning Kamp 3864f766afcSPoul-Henning Kamp off_t where = lseek(fd, 0UL, SEEK_CUR); 3874f766afcSPoul-Henning Kamp 3884f766afcSPoul-Henning Kamp int i = ftruncate(fd, where); 3894f766afcSPoul-Henning Kamp if (i < 0) 390*aa0538b9SPoul-Henning Kamp errx(17, "truncate error, %s to %jd", name, (intmax_t)where); 3914f766afcSPoul-Henning Kamp assert(close(fd) >= 0); 3924f766afcSPoul-Henning Kamp fd = -1; 3934f766afcSPoul-Henning Kamp } 3944f766afcSPoul-Henning Kamp 3954f766afcSPoul-Henning Kamp void 3964f766afcSPoul-Henning Kamp file_set::rewind(void) 3974f766afcSPoul-Henning Kamp { 3984f766afcSPoul-Henning Kamp char *p = strchr(name, '\0') - 3; 3994f766afcSPoul-Henning Kamp p[0] = '0'; 4004f766afcSPoul-Henning Kamp p[1] = '0'; 4014f766afcSPoul-Henning Kamp p[2] = '0'; 4024f766afcSPoul-Henning Kamp open_next(false); 4034f766afcSPoul-Henning Kamp } 4044f766afcSPoul-Henning Kamp 4054f766afcSPoul-Henning Kamp //--------------------------------------------------------------------- 4064f766afcSPoul-Henning Kamp 4074f766afcSPoul-Henning Kamp class flat_file: public tape_dev { 4084f766afcSPoul-Henning Kamp public: 4094f766afcSPoul-Henning Kamp flat_file(int file_handle, const char *spec, bool dst) : 4104f766afcSPoul-Henning Kamp tape_dev(file_handle, spec, dst) {}; 4114f766afcSPoul-Henning Kamp ssize_t read_blk(void *dst, size_t len); 4124f766afcSPoul-Henning Kamp ssize_t verify_blk(void *dst, size_t len, size_t expected); 4134f766afcSPoul-Henning Kamp void write_blk(const void *src, size_t len); 4144f766afcSPoul-Henning Kamp void file_mark(void); 4154f766afcSPoul-Henning Kamp virtual void rewind(void); 4164f766afcSPoul-Henning Kamp }; 4174f766afcSPoul-Henning Kamp 4184f766afcSPoul-Henning Kamp ssize_t 4194f766afcSPoul-Henning Kamp flat_file::read_blk(void *dst, size_t len) 4204f766afcSPoul-Henning Kamp { 4214f766afcSPoul-Henning Kamp (void)dst; 4224f766afcSPoul-Henning Kamp (void)len; 4234f766afcSPoul-Henning Kamp errx(EX_SOFTWARE, "That was not supposed to happen"); 4244f766afcSPoul-Henning Kamp } 4254f766afcSPoul-Henning Kamp 4264f766afcSPoul-Henning Kamp ssize_t 4274f766afcSPoul-Henning Kamp flat_file::verify_blk(void *dst, size_t len, size_t expected) 4284f766afcSPoul-Henning Kamp { 4294f766afcSPoul-Henning Kamp (void)len; 4304f766afcSPoul-Henning Kamp return (read(fd, dst, expected)); 4314f766afcSPoul-Henning Kamp } 4324f766afcSPoul-Henning Kamp 4334f766afcSPoul-Henning Kamp void 4344f766afcSPoul-Henning Kamp flat_file::write_blk(const void *src, size_t len) 4354f766afcSPoul-Henning Kamp { 4364f766afcSPoul-Henning Kamp ssize_t nwrite = write(fd, src, len); 4374f766afcSPoul-Henning Kamp if (nwrite < 0 || (size_t)nwrite != len) 4384f766afcSPoul-Henning Kamp errx(17, "write error (%zd != %zd)", nwrite, len); 4394f766afcSPoul-Henning Kamp } 4404f766afcSPoul-Henning Kamp 4414f766afcSPoul-Henning Kamp void 4424f766afcSPoul-Henning Kamp flat_file::file_mark(void) 4434f766afcSPoul-Henning Kamp { 4444f766afcSPoul-Henning Kamp return; 4454f766afcSPoul-Henning Kamp } 4464f766afcSPoul-Henning Kamp 4474f766afcSPoul-Henning Kamp void 4484f766afcSPoul-Henning Kamp flat_file::rewind(void) 4494f766afcSPoul-Henning Kamp { 4504f766afcSPoul-Henning Kamp errx(EX_SOFTWARE, "That was not supposed to happen"); 4514f766afcSPoul-Henning Kamp } 4524f766afcSPoul-Henning Kamp 4534f766afcSPoul-Henning Kamp //--------------------------------------------------------------------- 4544f766afcSPoul-Henning Kamp 4554f766afcSPoul-Henning Kamp enum e_how {H_INPUT, H_OUTPUT, H_VERIFY}; 4564f766afcSPoul-Henning Kamp 4574f766afcSPoul-Henning Kamp static tape_dev * 4584f766afcSPoul-Henning Kamp open_arg(const char *arg, enum e_how how, int rawfile) 4594f766afcSPoul-Henning Kamp { 4604f766afcSPoul-Henning Kamp int fd; 4614f766afcSPoul-Henning Kamp 4624f766afcSPoul-Henning Kamp if (!strcmp(arg, "-") && how == H_OUTPUT) 4634f766afcSPoul-Henning Kamp fd = STDOUT_FILENO; 4644f766afcSPoul-Henning Kamp else if (!strcmp(arg, "-")) 4654f766afcSPoul-Henning Kamp fd = STDIN_FILENO; 4664f766afcSPoul-Henning Kamp else if (how == H_OUTPUT) 4674f766afcSPoul-Henning Kamp fd = open(arg, O_RDWR|O_CREAT, DEFFILEMODE); 4684f766afcSPoul-Henning Kamp else 4694f766afcSPoul-Henning Kamp fd = open(arg, O_RDONLY); 4704f766afcSPoul-Henning Kamp 4714f766afcSPoul-Henning Kamp if (fd < 0) 4724f766afcSPoul-Henning Kamp err(EX_NOINPUT, "Cannot open %s:", arg); 4734f766afcSPoul-Henning Kamp 4744f766afcSPoul-Henning Kamp struct mtop mt; 4754f766afcSPoul-Henning Kamp mt.mt_op = MTNOP; 4764f766afcSPoul-Henning Kamp mt.mt_count = 1; 4774f766afcSPoul-Henning Kamp int i = ioctl(fd, MTIOCTOP, &mt); 4784f766afcSPoul-Henning Kamp 4794f766afcSPoul-Henning Kamp if (i >= 0) 4804f766afcSPoul-Henning Kamp return (new tape_dev(fd, arg, how == H_OUTPUT)); 4814f766afcSPoul-Henning Kamp 4824f766afcSPoul-Henning Kamp size_t alen = strlen(arg); 4834f766afcSPoul-Henning Kamp if (alen >= 5 && !strcmp(arg + (alen - 4), ".000")) { 4844f766afcSPoul-Henning Kamp if (how == H_INPUT) 4854f766afcSPoul-Henning Kamp errx(EX_USAGE, 4864f766afcSPoul-Henning Kamp "File-sets files cannot be used as source"); 4874f766afcSPoul-Henning Kamp return (new file_set(fd, arg, how == H_OUTPUT)); 4884f766afcSPoul-Henning Kamp } 4894f766afcSPoul-Henning Kamp 4904f766afcSPoul-Henning Kamp if (how != H_INPUT && rawfile) 4914f766afcSPoul-Henning Kamp return (new flat_file(fd, arg, how == H_OUTPUT)); 4924f766afcSPoul-Henning Kamp 4934f766afcSPoul-Henning Kamp return (new tap_file(fd, arg, how == H_OUTPUT)); 4944f766afcSPoul-Henning Kamp } 4954f766afcSPoul-Henning Kamp 4964f766afcSPoul-Henning Kamp //--------------------------------------------------------------------- 4974f766afcSPoul-Henning Kamp 4984f766afcSPoul-Henning Kamp static tape_dev *input; 4994f766afcSPoul-Henning Kamp static tape_dev *output; 5004f766afcSPoul-Henning Kamp 5014f766afcSPoul-Henning Kamp static size_t maxblk = MAXREC; 5024f766afcSPoul-Henning Kamp static uint64_t lastrec, fsize, tsize; 5034f766afcSPoul-Henning Kamp static FILE *msg; 5044f766afcSPoul-Henning Kamp static ssize_t lastnread; 5054f766afcSPoul-Henning Kamp static struct timespec t_start, t_end; 5064f766afcSPoul-Henning Kamp 5074f766afcSPoul-Henning Kamp static void 5084f766afcSPoul-Henning Kamp report_total(FILE *file) 5094f766afcSPoul-Henning Kamp { 5104f766afcSPoul-Henning Kamp double dur = (t_end.tv_nsec - t_start.tv_nsec) * 1e-9; 5114f766afcSPoul-Henning Kamp dur += t_end.tv_sec - t_start.tv_sec; 5124f766afcSPoul-Henning Kamp uintmax_t tot = tsize + fsize; 5134f766afcSPoul-Henning Kamp fprintf(file, "total length: %ju bytes", tot); 5144f766afcSPoul-Henning Kamp fprintf(file, " time: %.0f s", dur); 5154f766afcSPoul-Henning Kamp tot /= 1024; 5164f766afcSPoul-Henning Kamp fprintf(file, " rate: %.1f kB/s", (double)tot/dur); 5174f766afcSPoul-Henning Kamp fprintf(file, "\n"); 5184f766afcSPoul-Henning Kamp } 5194f766afcSPoul-Henning Kamp 5204f766afcSPoul-Henning Kamp static void 5214f766afcSPoul-Henning Kamp sigintr(int signo __unused) 5224f766afcSPoul-Henning Kamp { 5234f766afcSPoul-Henning Kamp (void)signo; 5244f766afcSPoul-Henning Kamp (void)clock_gettime(CLOCK_MONOTONIC, &t_end); 5254f766afcSPoul-Henning Kamp if (record) { 5264f766afcSPoul-Henning Kamp if (record - lastrec > 1) 5274f766afcSPoul-Henning Kamp fprintf(msg, "records %ju to %ju\n", 5284f766afcSPoul-Henning Kamp (intmax_t)lastrec, (intmax_t)record); 5294f766afcSPoul-Henning Kamp else 5304f766afcSPoul-Henning Kamp fprintf(msg, "record %ju\n", (intmax_t)lastrec); 5314f766afcSPoul-Henning Kamp } 5324f766afcSPoul-Henning Kamp fprintf(msg, "interrupt at file %d: record %ju\n", 5334f766afcSPoul-Henning Kamp filen, (uintmax_t)record); 5344f766afcSPoul-Henning Kamp report_total(msg); 5354f766afcSPoul-Henning Kamp exit(1); 5364f766afcSPoul-Henning Kamp } 5374f766afcSPoul-Henning Kamp 5384f766afcSPoul-Henning Kamp #ifdef SIGINFO 5394f766afcSPoul-Henning Kamp static volatile sig_atomic_t want_info; 5404f766afcSPoul-Henning Kamp 5414f766afcSPoul-Henning Kamp static void 5424f766afcSPoul-Henning Kamp siginfo(int signo) 5434f766afcSPoul-Henning Kamp { 5444f766afcSPoul-Henning Kamp (void)signo; 5454f766afcSPoul-Henning Kamp want_info = 1; 5464f766afcSPoul-Henning Kamp } 5474f766afcSPoul-Henning Kamp 5484f766afcSPoul-Henning Kamp static void 5494f766afcSPoul-Henning Kamp check_want_info(void) 5504f766afcSPoul-Henning Kamp { 5514f766afcSPoul-Henning Kamp if (want_info) { 5524f766afcSPoul-Henning Kamp (void)clock_gettime(CLOCK_MONOTONIC, &t_end); 5534f766afcSPoul-Henning Kamp fprintf(stderr, "tcopy: file %d record %ju ", 5544f766afcSPoul-Henning Kamp filen, (uintmax_t)record); 5554f766afcSPoul-Henning Kamp report_total(stderr); 5564f766afcSPoul-Henning Kamp want_info = 0; 5574f766afcSPoul-Henning Kamp } 5584f766afcSPoul-Henning Kamp } 5594f766afcSPoul-Henning Kamp 5604f766afcSPoul-Henning Kamp #else /* !SIGINFO */ 5614f766afcSPoul-Henning Kamp 5624f766afcSPoul-Henning Kamp static void 5634f766afcSPoul-Henning Kamp check_want_info(void) 5644f766afcSPoul-Henning Kamp { 5654f766afcSPoul-Henning Kamp } 5664f766afcSPoul-Henning Kamp 5674f766afcSPoul-Henning Kamp #endif 5684f766afcSPoul-Henning Kamp 5694f766afcSPoul-Henning Kamp static char * 5704f766afcSPoul-Henning Kamp getspace(size_t blk) 5714f766afcSPoul-Henning Kamp { 5724f766afcSPoul-Henning Kamp void *bp; 5734f766afcSPoul-Henning Kamp 5744f766afcSPoul-Henning Kamp assert(blk > 0); 5754f766afcSPoul-Henning Kamp if ((bp = malloc(blk)) == NULL) 5764f766afcSPoul-Henning Kamp errx(11, "no memory"); 5774f766afcSPoul-Henning Kamp return ((char *)bp); 5784f766afcSPoul-Henning Kamp } 5794f766afcSPoul-Henning Kamp 5804f766afcSPoul-Henning Kamp static void 5814f766afcSPoul-Henning Kamp usage(void) 5824f766afcSPoul-Henning Kamp { 5834f766afcSPoul-Henning Kamp fprintf(stderr, "usage: tcopy [-cvx] [-s maxblk] [src [dest]]\n"); 5844f766afcSPoul-Henning Kamp exit(1); 5854f766afcSPoul-Henning Kamp } 5864f766afcSPoul-Henning Kamp 5874f766afcSPoul-Henning Kamp static void 5884f766afcSPoul-Henning Kamp progress(ssize_t nread) 5894f766afcSPoul-Henning Kamp { 5904f766afcSPoul-Henning Kamp if (nread != lastnread) { 5914f766afcSPoul-Henning Kamp if (lastnread != 0 && lastnread != NOCOUNT) { 5924f766afcSPoul-Henning Kamp if (lastrec == 0 && nread == 0) 5934f766afcSPoul-Henning Kamp fprintf(msg, "%ju records\n", 5944f766afcSPoul-Henning Kamp (uintmax_t)record); 5954f766afcSPoul-Henning Kamp else if (record - lastrec > 1) 5964f766afcSPoul-Henning Kamp fprintf(msg, "records %ju to %ju\n", 5974f766afcSPoul-Henning Kamp (uintmax_t)lastrec, 5984f766afcSPoul-Henning Kamp (uintmax_t)record); 5994f766afcSPoul-Henning Kamp else 6004f766afcSPoul-Henning Kamp fprintf(msg, "record %ju\n", 6014f766afcSPoul-Henning Kamp (uintmax_t)lastrec); 6024f766afcSPoul-Henning Kamp } 6034f766afcSPoul-Henning Kamp if (nread != 0) 6044f766afcSPoul-Henning Kamp fprintf(msg, 6054f766afcSPoul-Henning Kamp "file %d: block size %zd: ", filen, nread); 6064f766afcSPoul-Henning Kamp (void) fflush(msg); 6074f766afcSPoul-Henning Kamp lastrec = record; 6084f766afcSPoul-Henning Kamp } 6094f766afcSPoul-Henning Kamp if (nread > 0) { 6104f766afcSPoul-Henning Kamp fsize += (size_t)nread; 6114f766afcSPoul-Henning Kamp record++; 6124f766afcSPoul-Henning Kamp } else { 6134f766afcSPoul-Henning Kamp if (lastnread <= 0 && lastnread != NOCOUNT) { 6144f766afcSPoul-Henning Kamp fprintf(msg, "eot\n"); 6154f766afcSPoul-Henning Kamp return; 6164f766afcSPoul-Henning Kamp } 6174f766afcSPoul-Henning Kamp fprintf(msg, 6184f766afcSPoul-Henning Kamp "file %d: eof after %ju records: %ju bytes\n", 6194f766afcSPoul-Henning Kamp filen, (uintmax_t)record, (uintmax_t)fsize); 6204f766afcSPoul-Henning Kamp filen++; 6214f766afcSPoul-Henning Kamp tsize += fsize; 6224f766afcSPoul-Henning Kamp fsize = record = lastrec = 0; 6234f766afcSPoul-Henning Kamp lastnread = 0; 6244f766afcSPoul-Henning Kamp } 6254f766afcSPoul-Henning Kamp lastnread = nread; 6264f766afcSPoul-Henning Kamp } 6274f766afcSPoul-Henning Kamp 6284f766afcSPoul-Henning Kamp static void 6294f766afcSPoul-Henning Kamp read_or_copy(void) 6304f766afcSPoul-Henning Kamp { 6314f766afcSPoul-Henning Kamp int needeof; 6324f766afcSPoul-Henning Kamp ssize_t nread, prev_read; 6334f766afcSPoul-Henning Kamp char *buff = getspace(maxblk); 6344f766afcSPoul-Henning Kamp 6354f766afcSPoul-Henning Kamp (void)clock_gettime(CLOCK_MONOTONIC, &t_start); 6364f766afcSPoul-Henning Kamp needeof = 0; 6374f766afcSPoul-Henning Kamp for (prev_read = NOCOUNT;;) { 6384f766afcSPoul-Henning Kamp check_want_info(); 6394f766afcSPoul-Henning Kamp nread = input->read_blk(buff, maxblk); 6404f766afcSPoul-Henning Kamp progress(nread); 6414f766afcSPoul-Henning Kamp if (nread > 0) { 6424f766afcSPoul-Henning Kamp if (output != NULL) { 6434f766afcSPoul-Henning Kamp if (needeof) { 6444f766afcSPoul-Henning Kamp output->file_mark(); 6454f766afcSPoul-Henning Kamp needeof = 0; 6464f766afcSPoul-Henning Kamp } 6474f766afcSPoul-Henning Kamp output->write_blk(buff, (size_t)nread); 6484f766afcSPoul-Henning Kamp } 6494f766afcSPoul-Henning Kamp } else { 6504f766afcSPoul-Henning Kamp if (prev_read <= 0 && prev_read != NOCOUNT) { 6514f766afcSPoul-Henning Kamp break; 6524f766afcSPoul-Henning Kamp } 6534f766afcSPoul-Henning Kamp needeof = 1; 6544f766afcSPoul-Henning Kamp } 6554f766afcSPoul-Henning Kamp prev_read = nread; 6564f766afcSPoul-Henning Kamp } 6574f766afcSPoul-Henning Kamp (void)clock_gettime(CLOCK_MONOTONIC, &t_end); 6584f766afcSPoul-Henning Kamp report_total(msg); 6594f766afcSPoul-Henning Kamp free(buff); 6604f766afcSPoul-Henning Kamp } 6614f766afcSPoul-Henning Kamp 6624f766afcSPoul-Henning Kamp static void 6634f766afcSPoul-Henning Kamp verify(void) 6644f766afcSPoul-Henning Kamp { 6654f766afcSPoul-Henning Kamp char *buf1 = getspace(maxblk); 6664f766afcSPoul-Henning Kamp char *buf2 = getspace(maxblk); 6674f766afcSPoul-Henning Kamp int eot = 0; 6684f766afcSPoul-Henning Kamp ssize_t nread1, nread2; 6694f766afcSPoul-Henning Kamp filen = 0; 6704f766afcSPoul-Henning Kamp tsize = 0; 6714f766afcSPoul-Henning Kamp 6724f766afcSPoul-Henning Kamp assert(output != NULL); 6734f766afcSPoul-Henning Kamp (void)clock_gettime(CLOCK_MONOTONIC, &t_start); 6744f766afcSPoul-Henning Kamp 6754f766afcSPoul-Henning Kamp while (1) { 6764f766afcSPoul-Henning Kamp check_want_info(); 6774f766afcSPoul-Henning Kamp nread1 = input->read_blk(buf1, (size_t)maxblk); 6784f766afcSPoul-Henning Kamp nread2 = output->verify_blk(buf2, maxblk, (size_t)nread1); 6794f766afcSPoul-Henning Kamp progress(nread1); 6804f766afcSPoul-Henning Kamp if (nread1 != nread2) { 6814f766afcSPoul-Henning Kamp fprintf(msg, 6824f766afcSPoul-Henning Kamp "tcopy: tapes have different block sizes; " 6834f766afcSPoul-Henning Kamp "%zd != %zd.\n", nread1, nread2); 6844f766afcSPoul-Henning Kamp exit(1); 6854f766afcSPoul-Henning Kamp } 6864f766afcSPoul-Henning Kamp if (nread1 > 0 && memcmp(buf1, buf2, (size_t)nread1)) { 6874f766afcSPoul-Henning Kamp fprintf(msg, "tcopy: tapes have different data.\n"); 6884f766afcSPoul-Henning Kamp exit(1); 6894f766afcSPoul-Henning Kamp } else if (nread1 > 0) { 6904f766afcSPoul-Henning Kamp eot = 0; 6914f766afcSPoul-Henning Kamp } else if (eot++) { 6924f766afcSPoul-Henning Kamp break; 6934f766afcSPoul-Henning Kamp } 6944f766afcSPoul-Henning Kamp } 6954f766afcSPoul-Henning Kamp (void)clock_gettime(CLOCK_MONOTONIC, &t_end); 6964f766afcSPoul-Henning Kamp report_total(msg); 6974f766afcSPoul-Henning Kamp fprintf(msg, "tcopy: tapes are identical.\n"); 6984f766afcSPoul-Henning Kamp fprintf(msg, "rewinding\n"); 6994f766afcSPoul-Henning Kamp input->rewind(); 7004f766afcSPoul-Henning Kamp output->rewind(); 7014f766afcSPoul-Henning Kamp 7024f766afcSPoul-Henning Kamp free(buf1); 7034f766afcSPoul-Henning Kamp free(buf2); 7044f766afcSPoul-Henning Kamp } 7054f766afcSPoul-Henning Kamp 7064f766afcSPoul-Henning Kamp int 7074f766afcSPoul-Henning Kamp main(int argc, char *argv[]) 7084f766afcSPoul-Henning Kamp { 7094f766afcSPoul-Henning Kamp enum operation op = READ; 7104f766afcSPoul-Henning Kamp int ch; 7114f766afcSPoul-Henning Kamp unsigned long maxphys = 0; 7124f766afcSPoul-Henning Kamp size_t l_maxphys = sizeof maxphys; 7134f766afcSPoul-Henning Kamp uint64_t tmp; 7144f766afcSPoul-Henning Kamp int rawfile = 0; 7154f766afcSPoul-Henning Kamp 7164f766afcSPoul-Henning Kamp setbuf(stderr, NULL); 7174f766afcSPoul-Henning Kamp 7184f766afcSPoul-Henning Kamp if (!sysctlbyname("kern.maxphys", &maxphys, &l_maxphys, NULL, 0UL)) 7194f766afcSPoul-Henning Kamp maxblk = maxphys; 7204f766afcSPoul-Henning Kamp 7214f766afcSPoul-Henning Kamp msg = stdout; 7224f766afcSPoul-Henning Kamp while ((ch = getopt(argc, argv, "cl:rs:vx")) != -1) 7234f766afcSPoul-Henning Kamp switch((char)ch) { 7244f766afcSPoul-Henning Kamp case 'c': 7254f766afcSPoul-Henning Kamp op = COPYVERIFY; 7264f766afcSPoul-Henning Kamp break; 7274f766afcSPoul-Henning Kamp case 'l': 7284f766afcSPoul-Henning Kamp msg = fopen(optarg, "w"); 7294f766afcSPoul-Henning Kamp if (msg == NULL) 7304f766afcSPoul-Henning Kamp errx(EX_CANTCREAT, "Cannot open %s", optarg); 7314f766afcSPoul-Henning Kamp setbuf(msg, NULL); 7324f766afcSPoul-Henning Kamp break; 7334f766afcSPoul-Henning Kamp case 'r': 7344f766afcSPoul-Henning Kamp rawfile = 1; 7354f766afcSPoul-Henning Kamp break; 7364f766afcSPoul-Henning Kamp case 's': 7374f766afcSPoul-Henning Kamp if (expand_number(optarg, &tmp)) { 7384f766afcSPoul-Henning Kamp warnx("illegal block size"); 7394f766afcSPoul-Henning Kamp usage(); 7404f766afcSPoul-Henning Kamp } 7414f766afcSPoul-Henning Kamp maxblk = tmp; 7424f766afcSPoul-Henning Kamp if (maxblk == 0) { 7434f766afcSPoul-Henning Kamp warnx("illegal block size"); 7444f766afcSPoul-Henning Kamp usage(); 7454f766afcSPoul-Henning Kamp } 7464f766afcSPoul-Henning Kamp break; 7474f766afcSPoul-Henning Kamp case 'v': 7484f766afcSPoul-Henning Kamp op = VERIFY; 7494f766afcSPoul-Henning Kamp break; 7504f766afcSPoul-Henning Kamp case 'x': 7514f766afcSPoul-Henning Kamp if (msg == stdout) 7524f766afcSPoul-Henning Kamp msg = stderr; 7534f766afcSPoul-Henning Kamp break; 7544f766afcSPoul-Henning Kamp case '?': 7554f766afcSPoul-Henning Kamp default: 7564f766afcSPoul-Henning Kamp usage(); 7574f766afcSPoul-Henning Kamp } 7584f766afcSPoul-Henning Kamp argc -= optind; 7594f766afcSPoul-Henning Kamp argv += optind; 7604f766afcSPoul-Henning Kamp 7614f766afcSPoul-Henning Kamp switch(argc) { 7624f766afcSPoul-Henning Kamp case 0: 7634f766afcSPoul-Henning Kamp if (op != READ) 7644f766afcSPoul-Henning Kamp usage(); 7654f766afcSPoul-Henning Kamp break; 7664f766afcSPoul-Henning Kamp case 1: 7674f766afcSPoul-Henning Kamp if (op != READ) 7684f766afcSPoul-Henning Kamp usage(); 7694f766afcSPoul-Henning Kamp break; 7704f766afcSPoul-Henning Kamp case 2: 7714f766afcSPoul-Henning Kamp if (op == READ) 7724f766afcSPoul-Henning Kamp op = COPY; 7734f766afcSPoul-Henning Kamp if (!strcmp(argv[1], "-")) { 7744f766afcSPoul-Henning Kamp if (op == COPYVERIFY) 7754f766afcSPoul-Henning Kamp errx(EX_USAGE, 7764f766afcSPoul-Henning Kamp "Cannot copy+verify with '-' destination"); 7774f766afcSPoul-Henning Kamp if (msg == stdout) 7784f766afcSPoul-Henning Kamp msg = stderr; 7794f766afcSPoul-Henning Kamp } 7804f766afcSPoul-Henning Kamp if (op == VERIFY) 7814f766afcSPoul-Henning Kamp output = open_arg(argv[1], H_VERIFY, 0); 7824f766afcSPoul-Henning Kamp else 7834f766afcSPoul-Henning Kamp output = open_arg(argv[1], H_OUTPUT, rawfile); 7844f766afcSPoul-Henning Kamp break; 7854f766afcSPoul-Henning Kamp default: 7864f766afcSPoul-Henning Kamp usage(); 7874f766afcSPoul-Henning Kamp } 7884f766afcSPoul-Henning Kamp 7894f766afcSPoul-Henning Kamp if (argc == 0) { 7904f766afcSPoul-Henning Kamp input = open_arg(_PATH_DEFTAPE, H_INPUT, 0); 7914f766afcSPoul-Henning Kamp } else { 7924f766afcSPoul-Henning Kamp input = open_arg(argv[0], H_INPUT, 0); 7934f766afcSPoul-Henning Kamp } 7944f766afcSPoul-Henning Kamp 7954f766afcSPoul-Henning Kamp if ((signal(SIGINT, SIG_IGN)) != SIG_IGN) 7964f766afcSPoul-Henning Kamp (void) signal(SIGINT, sigintr); 7974f766afcSPoul-Henning Kamp 7984f766afcSPoul-Henning Kamp #ifdef SIGINFO 7994f766afcSPoul-Henning Kamp (void)signal(SIGINFO, siginfo); 8004f766afcSPoul-Henning Kamp #endif 8014f766afcSPoul-Henning Kamp 8024f766afcSPoul-Henning Kamp if (op != VERIFY) { 8034f766afcSPoul-Henning Kamp if (op == COPYVERIFY) { 8044f766afcSPoul-Henning Kamp assert(output != NULL); 8054f766afcSPoul-Henning Kamp fprintf(msg, "rewinding\n"); 8064f766afcSPoul-Henning Kamp input->rewind(); 8074f766afcSPoul-Henning Kamp output->rewind(); 8084f766afcSPoul-Henning Kamp } 8094f766afcSPoul-Henning Kamp 8104f766afcSPoul-Henning Kamp read_or_copy(); 8114f766afcSPoul-Henning Kamp 8124f766afcSPoul-Henning Kamp if (op == COPY || op == COPYVERIFY) { 8134f766afcSPoul-Henning Kamp assert(output != NULL); 8144f766afcSPoul-Henning Kamp output->file_mark(); 8154f766afcSPoul-Henning Kamp output->file_mark(); 8164f766afcSPoul-Henning Kamp } 8174f766afcSPoul-Henning Kamp } 8184f766afcSPoul-Henning Kamp 8194f766afcSPoul-Henning Kamp if (op == VERIFY || op == COPYVERIFY) { 8204f766afcSPoul-Henning Kamp 8214f766afcSPoul-Henning Kamp if (op == COPYVERIFY) { 8224f766afcSPoul-Henning Kamp assert(output != NULL); 8234f766afcSPoul-Henning Kamp fprintf(msg, "rewinding\n"); 8244f766afcSPoul-Henning Kamp input->rewind(); 8254f766afcSPoul-Henning Kamp output->rewind(); 8264f766afcSPoul-Henning Kamp input->direction = tape_dev::SRC; 8274f766afcSPoul-Henning Kamp output->direction = tape_dev::SRC; 8284f766afcSPoul-Henning Kamp } 8294f766afcSPoul-Henning Kamp 8304f766afcSPoul-Henning Kamp verify(); 8314f766afcSPoul-Henning Kamp } 8324f766afcSPoul-Henning Kamp 8334f766afcSPoul-Henning Kamp if (msg != stderr && msg != stdout) 8344f766afcSPoul-Henning Kamp report_total(stderr); 8354f766afcSPoul-Henning Kamp 8364f766afcSPoul-Henning Kamp return(0); 8374f766afcSPoul-Henning Kamp } 838