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
tape_dev(int file_handle,const char * spec,bool destination)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
read_blk(void * dst,size_t len)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
verify_blk(void * dst,size_t len,size_t expected)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
write_blk(const void * src,size_t len)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
file_mark(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
rewind(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:
tap_file(int file_handle,const char * spec,bool dst)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
full_read(int fd,void * dst,size_t len)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
read_blk(void * dst,size_t len)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
write_blk(const void * src,size_t len)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
file_mark(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
rewind(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:
file_set(int file_handle,const char * spec,bool dst)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
open_next(bool increment)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
read_blk(void * dst,size_t len)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
verify_blk(void * dst,size_t len,size_t expected)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
write_blk(const void * src,size_t len)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
file_mark(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)
390aa0538b9SPoul-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
rewind(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:
flat_file(int file_handle,const char * spec,bool dst)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
read_blk(void * dst,size_t len)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
verify_blk(void * dst,size_t len,size_t expected)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
write_blk(const void * src,size_t len)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
file_mark(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
rewind(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 *
open_arg(const char * arg,enum e_how how,int rawfile)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
report_total(FILE * file)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
sigintr(int signo __unused)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
siginfo(int signo)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
check_want_info(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
check_want_info(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 *
getspace(size_t blk)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
usage(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
progress(ssize_t nread)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
read_or_copy(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
verify(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
main(int argc,char * argv[])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;
71349f92418SPoul-Henning Kamp int64_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 }
741*6582915cSPoul-Henning Kamp if (tmp <= 0) {
7424f766afcSPoul-Henning Kamp warnx("illegal block size");
7434f766afcSPoul-Henning Kamp usage();
7444f766afcSPoul-Henning Kamp }
74549f92418SPoul-Henning Kamp maxblk = tmp;
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