]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - usr.bin/tcopy/tcopy.c
Optionally bind ktls threads to NUMA domains
[FreeBSD/FreeBSD.git] / usr.bin / tcopy / tcopy.c
1 /*-
2  * SPDX-License-Identifier: BSD-3-Clause
3  *
4  * Copyright (c) 1985, 1987, 1993
5  *      The Regents of the University of California.  All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  * 3. Neither the name of the University nor the names of its contributors
16  *    may be used to endorse or promote products derived from this software
17  *    without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29  * SUCH DAMAGE.
30  */
31
32 #include <sys/cdefs.h>
33
34 __FBSDID("$FreeBSD$");
35
36 #ifndef lint
37 static const char copyright[] =
38 "@(#) Copyright (c) 1985, 1987, 1993\n\
39         The Regents of the University of California.  All rights reserved.\n";
40 #endif
41
42 #ifndef lint
43 static const char sccsid[] = "@(#)tcopy.c       8.2 (Berkeley) 4/17/94";
44 #endif
45
46 #include <sys/types.h>
47 #include <sys/stat.h>
48 #include <sys/ioctl.h>
49 #include <sys/mtio.h>
50
51 #include <err.h>
52 #include <errno.h>
53 #include <fcntl.h>
54 #include <paths.h>
55 #include <signal.h>
56 #include <stdint.h>
57 #include <stdio.h>
58 #include <stdlib.h>
59 #include <string.h>
60 #include <unistd.h>
61
62 #define MAXREC  (64 * 1024)
63 #define NOCOUNT (-2)
64
65 static int      filen, guesslen, maxblk = MAXREC;
66 static uint64_t lastrec, record, size, tsize;
67 static FILE     *msg;
68
69 static void     *getspace(int);
70 static void      intr(int);
71 static void      usage(void) __dead2;
72 static void      verify(int, int, char *);
73 static void      writeop(int, int);
74 static void      rewind_tape(int);
75
76 int
77 main(int argc, char *argv[])
78 {
79         int lastnread, nread, nw, inp, outp;
80         enum {READ, VERIFY, COPY, COPYVERIFY} op = READ;
81         sig_t oldsig;
82         int ch, needeof;
83         char *buff;
84         const char *inf;
85
86         msg = stdout;
87         guesslen = 1;
88         outp = -1;
89         while ((ch = getopt(argc, argv, "cs:vx")) != -1)
90                 switch((char)ch) {
91                 case 'c':
92                         op = COPYVERIFY;
93                         break;
94                 case 's':
95                         maxblk = atoi(optarg);
96                         if (maxblk <= 0) {
97                                 warnx("illegal block size");
98                                 usage();
99                         }
100                         guesslen = 0;
101                         break;
102                 case 'v':
103                         op = VERIFY;
104                         break;
105                 case 'x':
106                         msg = stderr;
107                         break;
108                 case '?':
109                 default:
110                         usage();
111                 }
112         argc -= optind;
113         argv += optind;
114
115         switch(argc) {
116         case 0:
117                 if (op != READ)
118                         usage();
119                 inf = _PATH_DEFTAPE;
120                 break;
121         case 1:
122                 if (op != READ)
123                         usage();
124                 inf = argv[0];
125                 break;
126         case 2:
127                 if (op == READ)
128                         op = COPY;
129                 inf = argv[0];
130                 if ((outp = open(argv[1], op == VERIFY ? O_RDONLY :
131                     op == COPY ? O_WRONLY : O_RDWR, DEFFILEMODE)) < 0)
132                         err(3, "%s", argv[1]);
133                 break;
134         default:
135                 usage();
136         }
137
138         if ((inp = open(inf, O_RDONLY, 0)) < 0)
139                 err(1, "%s", inf);
140
141         buff = getspace(maxblk);
142
143         if (op == VERIFY) {
144                 verify(inp, outp, buff);
145                 exit(0);
146         }
147
148         if ((oldsig = signal(SIGINT, SIG_IGN)) != SIG_IGN)
149                 (void) signal(SIGINT, intr);
150
151         needeof = 0;
152         for (lastnread = NOCOUNT;;) {
153                 if ((nread = read(inp, buff, maxblk)) == -1) {
154                         while (errno == EINVAL && (maxblk -= 1024)) {
155                                 nread = read(inp, buff, maxblk);
156                                 if (nread >= 0)
157                                         goto r1;
158                         }
159                         err(1, "read error, file %d, record %ju", filen, (intmax_t)record);
160                 } else if (nread != lastnread) {
161                         if (lastnread != 0 && lastnread != NOCOUNT) {
162                                 if (lastrec == 0 && nread == 0)
163                                         fprintf(msg, "%ju records\n", (intmax_t)record);
164                                 else if (record - lastrec > 1)
165                                         fprintf(msg, "records %ju to %ju\n",
166                                             (intmax_t)lastrec, (intmax_t)record);
167                                 else
168                                         fprintf(msg, "record %ju\n", (intmax_t)lastrec);
169                         }
170                         if (nread != 0)
171                                 fprintf(msg, "file %d: block size %d: ",
172                                     filen, nread);
173                         (void) fflush(stdout);
174                         lastrec = record;
175                 }
176 r1:             guesslen = 0;
177                 if (nread > 0) {
178                         if (op == COPY || op == COPYVERIFY) {
179                                 if (needeof) {
180                                         writeop(outp, MTWEOF);
181                                         needeof = 0;
182                                 }
183                                 nw = write(outp, buff, nread);
184                                 if (nw != nread) {
185                                         if (nw == -1) {
186                                                 warn("write error, file %d, record %ju", filen,
187                                                     (intmax_t)record);
188                                         } else {
189                                                 warnx("write error, file %d, record %ju", filen,
190                                                     (intmax_t)record);
191                                                 warnx("write (%d) != read (%d)", nw, nread);
192                                         }
193                                         errx(5, "copy aborted");
194                                 }
195                         }
196                         size += nread;
197                         record++;
198                 } else {
199                         if (lastnread <= 0 && lastnread != NOCOUNT) {
200                                 fprintf(msg, "eot\n");
201                                 break;
202                         }
203                         fprintf(msg,
204                             "file %d: eof after %ju records: %ju bytes\n",
205                             filen, (intmax_t)record, (intmax_t)size);
206                         needeof = 1;
207                         filen++;
208                         tsize += size;
209                         size = record = lastrec = 0;
210                         lastnread = 0;
211                 }
212                 lastnread = nread;
213         }
214         fprintf(msg, "total length: %ju bytes\n", (intmax_t)tsize);
215         (void)signal(SIGINT, oldsig);
216         if (op == COPY || op == COPYVERIFY) {
217                 writeop(outp, MTWEOF);
218                 writeop(outp, MTWEOF);
219                 if (op == COPYVERIFY) {
220                         rewind_tape(outp);
221                         rewind_tape(inp);
222                         verify(inp, outp, buff);
223                 }
224         }
225         exit(0);
226 }
227
228 static void
229 verify(int inp, int outp, char *outb)
230 {
231         int eot, inmaxblk, inn, outmaxblk, outn;
232         char *inb;
233
234         inb = getspace(maxblk);
235         inmaxblk = outmaxblk = maxblk;
236         for (eot = 0;; guesslen = 0) {
237                 if ((inn = read(inp, inb, inmaxblk)) == -1) {
238                         if (guesslen)
239                                 while (errno == EINVAL && (inmaxblk -= 1024)) {
240                                         inn = read(inp, inb, inmaxblk);
241                                         if (inn >= 0)
242                                                 goto r1;
243                                 }
244                         warn("read error");
245                         break;
246                 }
247 r1:             if ((outn = read(outp, outb, outmaxblk)) == -1) {
248                         if (guesslen)
249                                 while (errno == EINVAL && (outmaxblk -= 1024)) {
250                                         outn = read(outp, outb, outmaxblk);
251                                         if (outn >= 0)
252                                                 goto r2;
253                                 }
254                         warn("read error");
255                         break;
256                 }
257 r2:             if (inn != outn) {
258                         fprintf(msg,
259                             "%s: tapes have different block sizes; %d != %d.\n",
260                             "tcopy", inn, outn);
261                         break;
262                 }
263                 if (!inn) {
264                         if (eot++) {
265                                 fprintf(msg, "tcopy: tapes are identical.\n");
266                                 free(inb);
267                                 return;
268                         }
269                 } else {
270                         if (bcmp(inb, outb, inn)) {
271                                 fprintf(msg,
272                                     "tcopy: tapes have different data.\n");
273                                 break;
274                         }
275                         eot = 0;
276                 }
277         }
278         exit(1);
279 }
280
281 static void
282 intr(int signo __unused)
283 {
284         if (record) {
285                 if (record - lastrec > 1)
286                         fprintf(msg, "records %ju to %ju\n", (intmax_t)lastrec, (intmax_t)record);
287                 else
288                         fprintf(msg, "record %ju\n", (intmax_t)lastrec);
289         }
290         fprintf(msg, "interrupt at file %d: record %ju\n", filen, (intmax_t)record);
291         fprintf(msg, "total length: %ju bytes\n", (uintmax_t)(tsize + size));
292         exit(1);
293 }
294
295 static void *
296 getspace(int blk)
297 {
298         void *bp;
299
300         if ((bp = malloc((size_t)blk)) == NULL)
301                 errx(11, "no memory");
302         return (bp);
303 }
304
305 static void
306 writeop(int fd, int type)
307 {
308         struct mtop op;
309
310         op.mt_op = type;
311         op.mt_count = (daddr_t)1;
312         if (ioctl(fd, MTIOCTOP, (char *)&op) < 0)
313                 err(6, "tape op");
314 }
315
316 static void
317 usage(void)
318 {
319         fprintf(stderr, "usage: tcopy [-cvx] [-s maxblk] [src [dest]]\n");
320         exit(1);
321 }
322
323 static void
324 rewind_tape(int fd)
325 {
326         struct stat sp;
327
328         if(fstat(fd, &sp))
329                 errx(12, "fstat in rewind");
330
331         /*
332          * don't want to do tape ioctl on regular files:
333          */
334         if( S_ISREG(sp.st_mode) ) {
335                 if( lseek(fd, 0, SEEK_SET) == -1 )
336                         errx(13, "lseek");
337         } else
338                 /*  assume its a tape   */
339                 writeop(fd, MTREW);
340 }