blob: a8c12d285a090d54495c08955fc4523c32538174 [file] [log] [blame]
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -08001/* $NetBSD: dd.c,v 1.37 2004/01/17 21:00:16 dbj Exp $ */
2
3/*-
4 * Copyright (c) 1991, 1993, 1994
5 * The Regents of the University of California. All rights reserved.
6 *
7 * This code is derived from software contributed to Berkeley by
8 * Keith Muller of the University of California, San Diego and Lance
9 * Visser of Convex Computer Corporation.
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
19 * 3. Neither the name of the University nor the names of its contributors
20 * may be used to endorse or promote products derived from this software
21 * without specific prior written permission.
22 *
23 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 * SUCH DAMAGE.
34 */
35
36#include <sys/cdefs.h>
37#ifndef lint
38__COPYRIGHT("@(#) Copyright (c) 1991, 1993, 1994\n\
39 The Regents of the University of California. All rights reserved.\n");
40#endif /* not lint */
41
42#ifndef lint
43#if 0
44static char sccsid[] = "@(#)dd.c 8.5 (Berkeley) 4/2/94";
45#else
46__RCSID("$NetBSD: dd.c,v 1.37 2004/01/17 21:00:16 dbj Exp $");
47#endif
48#endif /* not lint */
49
50#include <sys/param.h>
51#include <sys/stat.h>
52#include <sys/ioctl.h>
53#include <sys/time.h>
54
55#include <ctype.h>
56#include <err.h>
57#include <errno.h>
58#include <fcntl.h>
59#include <signal.h>
60#include <stdio.h>
61#include <stdlib.h>
62#include <string.h>
63#include <unistd.h>
64
65#include "dd.h"
66
Jeff Sharkey393e5592012-05-29 14:25:04 -070067//#define NO_CONV
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080068
69//#include "extern.h"
70void block(void);
71void block_close(void);
72void dd_out(int);
73void def(void);
74void def_close(void);
75void jcl(char **);
76void pos_in(void);
77void pos_out(void);
78void summary(void);
79void summaryx(int);
80void terminate(int);
81void unblock(void);
82void unblock_close(void);
83ssize_t bwrite(int, const void *, size_t);
84
85extern IO in, out;
86extern STAT st;
87extern void (*cfunc)(void);
88extern uint64_t cpy_cnt;
89extern uint64_t cbsz;
90extern u_int ddflags;
91extern u_int files_cnt;
92extern int progress;
93extern const u_char *ctab;
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080094
95
Jeff Sharkey393e5592012-05-29 14:25:04 -070096#define MIN(a, b) ((a) < (b) ? (a) : (b))
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080097#define MAX(a, b) ((a) > (b) ? (a) : (b))
Nick Kralevich3f2b0a52012-06-26 14:59:36 -070098#define DEFFILEMODE (S_IRUSR | S_IWUSR)
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -080099
100static void dd_close(void);
101static void dd_in(void);
102static void getfdtype(IO *);
103static int redup_clean_fd(int);
104static void setup(void);
105
106
107IO in, out; /* input/output state */
108STAT st; /* statistics */
109void (*cfunc)(void); /* conversion function */
110uint64_t cpy_cnt; /* # of blocks to copy */
111static off_t pending = 0; /* pending seek if sparse */
112u_int ddflags; /* conversion options */
113uint64_t cbsz; /* conversion block size */
114u_int files_cnt = 1; /* # of files to copy */
115int progress = 0; /* display sign of life */
116const u_char *ctab; /* conversion table */
117sigset_t infoset; /* a set blocking SIGINFO */
118
119int
120dd_main(int argc, char *argv[])
121{
122 int ch;
123
124 while ((ch = getopt(argc, argv, "")) != -1) {
125 switch (ch) {
126 default:
127 fprintf(stderr, "usage: dd [operand ...]\n");
128 exit(1);
129 /* NOTREACHED */
130 }
131 }
132 argc -= (optind - 1);
133 argv += (optind - 1);
134
135 jcl(argv);
136 setup();
137
138// (void)signal(SIGINFO, summaryx);
139 (void)signal(SIGINT, terminate);
140 (void)sigemptyset(&infoset);
141// (void)sigaddset(&infoset, SIGINFO);
142
143 (void)atexit(summary);
144
145 while (files_cnt--)
146 dd_in();
147
148 dd_close();
149 exit(0);
150 /* NOTREACHED */
151}
152
153static void
154setup(void)
155{
156
157 if (in.name == NULL) {
158 in.name = "stdin";
159 in.fd = STDIN_FILENO;
160 } else {
161 in.fd = open(in.name, O_RDONLY, 0);
162 if (in.fd < 0) {
163 fprintf(stderr, "%s: cannot open for read: %s\n",
164 in.name, strerror(errno));
165 exit(1);
166 /* NOTREACHED */
167 }
168
169 /* Ensure in.fd is outside the stdio descriptor range */
170 in.fd = redup_clean_fd(in.fd);
171 }
172
173 getfdtype(&in);
174
175 if (files_cnt > 1 && !(in.flags & ISTAPE)) {
176 fprintf(stderr,
177 "files is not supported for non-tape devices\n");
178 exit(1);
179 /* NOTREACHED */
180 }
181
182 if (out.name == NULL) {
183 /* No way to check for read access here. */
184 out.fd = STDOUT_FILENO;
185 out.name = "stdout";
186 } else {
187#define OFLAGS \
188 (O_CREAT | (ddflags & (C_SEEK | C_NOTRUNC) ? 0 : O_TRUNC))
Nick Kralevich3f2b0a52012-06-26 14:59:36 -0700189 out.fd = open(out.name, O_RDWR | OFLAGS, DEFFILEMODE);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800190 /*
191 * May not have read access, so try again with write only.
192 * Without read we may have a problem if output also does
193 * not support seeks.
194 */
195 if (out.fd < 0) {
Nick Kralevich3f2b0a52012-06-26 14:59:36 -0700196 out.fd = open(out.name, O_WRONLY | OFLAGS, DEFFILEMODE);
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800197 out.flags |= NOREAD;
198 }
199 if (out.fd < 0) {
200 fprintf(stderr, "%s: cannot open for write: %s\n",
201 out.name, strerror(errno));
202 exit(1);
203 /* NOTREACHED */
204 }
205
206 /* Ensure out.fd is outside the stdio descriptor range */
207 out.fd = redup_clean_fd(out.fd);
208 }
209
210 getfdtype(&out);
211
212 /*
213 * Allocate space for the input and output buffers. If not doing
214 * record oriented I/O, only need a single buffer.
215 */
216 if (!(ddflags & (C_BLOCK|C_UNBLOCK))) {
217 if ((in.db = malloc(out.dbsz + in.dbsz - 1)) == NULL) {
218 exit(1);
219 /* NOTREACHED */
220 }
221 out.db = in.db;
222 } else if ((in.db =
223 malloc((u_int)(MAX(in.dbsz, cbsz) + cbsz))) == NULL ||
224 (out.db = malloc((u_int)(out.dbsz + cbsz))) == NULL) {
225 exit(1);
226 /* NOTREACHED */
227 }
228 in.dbp = in.db;
229 out.dbp = out.db;
230
231 /* Position the input/output streams. */
232 if (in.offset)
233 pos_in();
234 if (out.offset)
235 pos_out();
236
237 /*
238 * Truncate the output file; ignore errors because it fails on some
239 * kinds of output files, tapes, for example.
240 */
241 if ((ddflags & (C_OF | C_SEEK | C_NOTRUNC)) == (C_OF | C_SEEK))
242 (void)ftruncate(out.fd, (off_t)out.offset * out.dbsz);
243
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800244 (void)gettimeofday(&st.start, NULL); /* Statistics timestamp. */
245}
246
247static void
248getfdtype(IO *io)
249{
250// struct mtget mt;
251 struct stat sb;
252
253 if (fstat(io->fd, &sb)) {
254 fprintf(stderr, "%s: cannot fstat: %s\n",
255 io->name, strerror(errno));
256 exit(1);
257 /* NOTREACHED */
258 }
259 if (S_ISCHR(sb.st_mode))
260 io->flags |= /*ioctl(io->fd, MTIOCGET, &mt) ? ISCHR : ISTAPE; */ ISCHR;
261 else if (lseek(io->fd, (off_t)0, SEEK_CUR) == -1 && errno == ESPIPE)
262 io->flags |= ISPIPE; /* XXX fixed in 4.4BSD */
263}
264
265/*
266 * Move the parameter file descriptor to a descriptor that is outside the
267 * stdio descriptor range, if necessary. This is required to avoid
268 * accidentally outputting completion or error messages into the
269 * output file that were intended for the tty.
270 */
271static int
272redup_clean_fd(int fd)
273{
274 int newfd;
275
276 if (fd != STDIN_FILENO && fd != STDOUT_FILENO &&
277 fd != STDERR_FILENO)
278 /* File descriptor is ok, return immediately. */
279 return fd;
280
281 /*
282 * 3 is the first descriptor greater than STD*_FILENO. Any
283 * free descriptor valued 3 or above is acceptable...
284 */
285 newfd = fcntl(fd, F_DUPFD, 3);
286 if (newfd < 0) {
287 fprintf(stderr, "dupfd IO: %s\n", strerror(errno));
288 exit(1);
289 /* NOTREACHED */
290 }
291
292 close(fd);
293
294 return newfd;
295}
296
297static void
298dd_in(void)
299{
300 int flags;
301 int64_t n;
302
303 for (flags = ddflags;;) {
304 if (cpy_cnt && (st.in_full + st.in_part) >= cpy_cnt)
305 return;
306
307 /*
308 * Clear the buffer first if doing "sync" on input.
309 * If doing block operations use spaces. This will
310 * affect not only the C_NOERROR case, but also the
311 * last partial input block which should be padded
312 * with zero and not garbage.
313 */
314 if (flags & C_SYNC) {
315 if (flags & (C_BLOCK|C_UNBLOCK))
316 (void)memset(in.dbp, ' ', in.dbsz);
317 else
318 (void)memset(in.dbp, 0, in.dbsz);
319 }
320
321 n = read(in.fd, in.dbp, in.dbsz);
322 if (n == 0) {
323 in.dbrcnt = 0;
324 return;
325 }
326
327 /* Read error. */
328 if (n < 0) {
329
330 /*
331 * If noerror not specified, die. POSIX requires that
332 * the warning message be followed by an I/O display.
333 */
334 fprintf(stderr, "%s: read error: %s\n",
335 in.name, strerror(errno));
336 if (!(flags & C_NOERROR)) {
337 exit(1);
338 /* NOTREACHED */
339 }
340 summary();
341
342 /*
343 * If it's not a tape drive or a pipe, seek past the
344 * error. If your OS doesn't do the right thing for
345 * raw disks this section should be modified to re-read
346 * in sector size chunks.
347 */
348 if (!(in.flags & (ISPIPE|ISTAPE)) &&
349 lseek(in.fd, (off_t)in.dbsz, SEEK_CUR))
350 fprintf(stderr, "%s: seek error: %s\n",
351 in.name, strerror(errno));
352
353 /* If sync not specified, omit block and continue. */
354 if (!(ddflags & C_SYNC))
355 continue;
356
357 /* Read errors count as full blocks. */
358 in.dbcnt += in.dbrcnt = in.dbsz;
359 ++st.in_full;
360
361 /* Handle full input blocks. */
362 } else if (n == in.dbsz) {
363 in.dbcnt += in.dbrcnt = n;
364 ++st.in_full;
365
366 /* Handle partial input blocks. */
367 } else {
368 /* If sync, use the entire block. */
369 if (ddflags & C_SYNC)
370 in.dbcnt += in.dbrcnt = in.dbsz;
371 else
372 in.dbcnt += in.dbrcnt = n;
373 ++st.in_part;
374 }
375
376 /*
377 * POSIX states that if bs is set and no other conversions
378 * than noerror, notrunc or sync are specified, the block
379 * is output without buffering as it is read.
380 */
381 if (ddflags & C_BS) {
382 out.dbcnt = in.dbcnt;
383 dd_out(1);
384 in.dbcnt = 0;
385 continue;
386 }
387
388/* if (ddflags & C_SWAB) {
389 if ((n = in.dbrcnt) & 1) {
390 ++st.swab;
391 --n;
392 }
393 swab(in.dbp, in.dbp, n);
394 }
395*/
396 in.dbp += in.dbrcnt;
397 (*cfunc)();
398 }
399}
400
401/*
402 * Cleanup any remaining I/O and flush output. If necesssary, output file
403 * is truncated.
404 */
405static void
406dd_close(void)
407{
408
409 if (cfunc == def)
410 def_close();
411 else if (cfunc == block)
412 block_close();
413 else if (cfunc == unblock)
414 unblock_close();
415 if (ddflags & C_OSYNC && out.dbcnt < out.dbsz) {
416 (void)memset(out.dbp, 0, out.dbsz - out.dbcnt);
417 out.dbcnt = out.dbsz;
418 }
419 /* If there are pending sparse blocks, make sure
420 * to write out the final block un-sparse
421 */
422 if ((out.dbcnt == 0) && pending) {
423 memset(out.db, 0, out.dbsz);
424 out.dbcnt = out.dbsz;
425 out.dbp = out.db + out.dbcnt;
426 pending -= out.dbsz;
427 }
428 if (out.dbcnt)
429 dd_out(1);
430
431 /*
432 * Reporting nfs write error may be defered until next
433 * write(2) or close(2) system call. So, we need to do an
434 * extra check. If an output is stdout, the file structure
435 * may be shared among with other processes and close(2) just
436 * decreases the reference count.
437 */
438 if (out.fd == STDOUT_FILENO && fsync(out.fd) == -1 && errno != EINVAL) {
439 fprintf(stderr, "fsync stdout: %s\n", strerror(errno));
440 exit(1);
441 /* NOTREACHED */
442 }
443 if (close(out.fd) == -1) {
444 fprintf(stderr, "close: %s\n", strerror(errno));
445 exit(1);
446 /* NOTREACHED */
447 }
448}
449
450void
451dd_out(int force)
452{
453 static int warned;
454 int64_t cnt, n, nw;
455 u_char *outp;
456
457 /*
458 * Write one or more blocks out. The common case is writing a full
459 * output block in a single write; increment the full block stats.
460 * Otherwise, we're into partial block writes. If a partial write,
461 * and it's a character device, just warn. If a tape device, quit.
462 *
463 * The partial writes represent two cases. 1: Where the input block
464 * was less than expected so the output block was less than expected.
465 * 2: Where the input block was the right size but we were forced to
466 * write the block in multiple chunks. The original versions of dd(1)
467 * never wrote a block in more than a single write, so the latter case
468 * never happened.
469 *
470 * One special case is if we're forced to do the write -- in that case
471 * we play games with the buffer size, and it's usually a partial write.
472 */
473 outp = out.db;
474 for (n = force ? out.dbcnt : out.dbsz;; n = out.dbsz) {
475 for (cnt = n;; cnt -= nw) {
476
477 if (!force && ddflags & C_SPARSE) {
478 int sparse, i;
479 sparse = 1; /* Is buffer sparse? */
480 for (i = 0; i < cnt; i++)
481 if (outp[i] != 0) {
482 sparse = 0;
483 break;
484 }
485 if (sparse) {
486 pending += cnt;
487 outp += cnt;
488 nw = 0;
489 break;
490 }
491 }
492 if (pending != 0) {
493 if (lseek(out.fd, pending, SEEK_CUR) ==
494 -1) {
495 fprintf(stderr,
496 "%s: seek error creating "
497 "sparse file: %s\n",
498 out.name, strerror(errno));
499 exit(1);
500 }
501 }
502 nw = bwrite(out.fd, outp, cnt);
503 if (nw <= 0) {
504 if (nw == 0) {
505 fprintf(stderr, "%s: end of device\n",
506 out.name);
507 exit(1);
508 /* NOTREACHED */
509 }
510 if (errno != EINTR) {
511 fprintf(stderr, "%s: write error: %s\n",
512 out.name, strerror(errno));
513 /* NOTREACHED */
514 exit(1);
515 }
516 nw = 0;
517 }
518 if (pending) {
519 st.bytes += pending;
520 st.sparse += pending/out.dbsz;
521 st.out_full += pending/out.dbsz;
522 pending = 0;
523 }
524 outp += nw;
525 st.bytes += nw;
526 if (nw == n) {
527 if (n != out.dbsz)
528 ++st.out_part;
529 else
530 ++st.out_full;
531 break;
532 }
533 ++st.out_part;
534 if (nw == cnt)
535 break;
536 if (out.flags & ISCHR && !warned) {
537 warned = 1;
538 fprintf(stderr, "%s: short write on character "
539 "device\n", out.name);
540 }
541 if (out.flags & ISTAPE) {
542 fprintf(stderr,
543 "%s: short write on tape device",
544 out.name);
545 exit(1);
546 /* NOTREACHED */
547 }
548 }
549 if ((out.dbcnt -= n) < out.dbsz)
550 break;
551 }
552
553 /* Reassemble the output block. */
554 if (out.dbcnt)
555 (void)memmove(out.db, out.dbp - out.dbcnt, out.dbcnt);
556 out.dbp = out.db + out.dbcnt;
557
558 if (progress)
559 (void)write(STDERR_FILENO, ".", 1);
560}
561
562/*
563 * A protected against SIGINFO write
564 */
565ssize_t
566bwrite(int fd, const void *buf, size_t len)
567{
568 sigset_t oset;
569 ssize_t rv;
570 int oerrno;
571
572 (void)sigprocmask(SIG_BLOCK, &infoset, &oset);
573 rv = write(fd, buf, len);
574 oerrno = errno;
575 (void)sigprocmask(SIG_SETMASK, &oset, NULL);
576 errno = oerrno;
577 return (rv);
578}
579
580/*
581 * Position input/output data streams before starting the copy. Device type
582 * dependent. Seekable devices use lseek, and the rest position by reading.
583 * Seeking past the end of file can cause null blocks to be written to the
584 * output.
585 */
586void
587pos_in(void)
588{
589 int bcnt, cnt, nr, warned;
590
591 /* If not a pipe or tape device, try to seek on it. */
592 if (!(in.flags & (ISPIPE|ISTAPE))) {
Jongrak Kwonc05aae42013-04-16 23:00:35 -0700593 if (lseek64(in.fd,
594 (off64_t)in.offset * (off64_t)in.dbsz, SEEK_CUR) == -1) {
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800595 fprintf(stderr, "%s: seek error: %s",
596 in.name, strerror(errno));
597 exit(1);
598 /* NOTREACHED */
599 }
600 return;
601 /* NOTREACHED */
602 }
603
604 /*
605 * Read the data. If a pipe, read until satisfy the number of bytes
606 * being skipped. No differentiation for reading complete and partial
607 * blocks for other devices.
608 */
609 for (bcnt = in.dbsz, cnt = in.offset, warned = 0; cnt;) {
610 if ((nr = read(in.fd, in.db, bcnt)) > 0) {
611 if (in.flags & ISPIPE) {
612 if (!(bcnt -= nr)) {
613 bcnt = in.dbsz;
614 --cnt;
615 }
616 } else
617 --cnt;
618 continue;
619 }
620
621 if (nr == 0) {
622 if (files_cnt > 1) {
623 --files_cnt;
624 continue;
625 }
626 fprintf(stderr, "skip reached end of input\n");
627 exit(1);
628 /* NOTREACHED */
629 }
630
631 /*
632 * Input error -- either EOF with no more files, or I/O error.
633 * If noerror not set die. POSIX requires that the warning
634 * message be followed by an I/O display.
635 */
636 if (ddflags & C_NOERROR) {
637 if (!warned) {
638
639 fprintf(stderr, "%s: error occurred\n",
640 in.name);
641 warned = 1;
642 summary();
643 }
644 continue;
645 }
646 fprintf(stderr, "%s: read error: %s", in.name, strerror(errno));
647 exit(1);
648 /* NOTREACHED */
649 }
650}
651
652void
653pos_out(void)
654{
655// struct mtop t_op;
656 int cnt, n;
657
658 /*
659 * If not a tape, try seeking on the file. Seeking on a pipe is
660 * going to fail, but don't protect the user -- they shouldn't
661 * have specified the seek operand.
662 */
663 if (!(out.flags & ISTAPE)) {
Jongrak Kwonc05aae42013-04-16 23:00:35 -0700664 if (lseek64(out.fd,
665 (off64_t)out.offset * (off64_t)out.dbsz, SEEK_SET) == -1) {
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800666 fprintf(stderr, "%s: seek error: %s\n",
667 out.name, strerror(errno));
668 exit(1);
669 /* NOTREACHED */
670 }
671 return;
672 }
673
674 /* If no read access, try using mtio. */
675 if (out.flags & NOREAD) {
676/* t_op.mt_op = MTFSR;
677 t_op.mt_count = out.offset;
678
679 if (ioctl(out.fd, MTIOCTOP, &t_op) < 0)*/
680 fprintf(stderr, "%s: cannot read", out.name);
681 exit(1);
682 /* NOTREACHED */
683 return;
684 }
685
686 /* Read it. */
687 for (cnt = 0; cnt < out.offset; ++cnt) {
688 if ((n = read(out.fd, out.db, out.dbsz)) > 0)
689 continue;
690
691 if (n < 0) {
692 fprintf(stderr, "%s: cannot position by reading: %s\n",
693 out.name, strerror(errno));
694 exit(1);
695 /* NOTREACHED */
696 }
697
698 /*
699 * If reach EOF, fill with NUL characters; first, back up over
700 * the EOF mark. Note, cnt has not yet been incremented, so
701 * the EOF read does not count as a seek'd block.
702 */
703/* t_op.mt_op = MTBSR;
704 t_op.mt_count = 1;
705 if (ioctl(out.fd, MTIOCTOP, &t_op) == -1) */ {
706 fprintf(stderr, "%s: cannot position\n", out.name);
707 exit(1);
708 /* NOTREACHED */
709 }
710
711 while (cnt++ < out.offset)
712 if ((n = bwrite(out.fd, out.db, out.dbsz)) != out.dbsz) {
713 fprintf(stderr, "%s: cannot position "
714 "by writing: %s\n",
715 out.name, strerror(errno));
716 exit(1);
717 /* NOTREACHED */
718 }
719 break;
720 }
721}
722
723/*
724 * def --
725 * Copy input to output. Input is buffered until reaches obs, and then
726 * output until less than obs remains. Only a single buffer is used.
727 * Worst case buffer calculation is (ibs + obs - 1).
728 */
729void
730def(void)
731{
732 uint64_t cnt;
733 u_char *inp;
734 const u_char *t;
735
736 if ((t = ctab) != NULL)
737 for (inp = in.dbp - (cnt = in.dbrcnt); cnt--; ++inp)
738 *inp = t[*inp];
739
740 /* Make the output buffer look right. */
741 out.dbp = in.dbp;
742 out.dbcnt = in.dbcnt;
743
744 if (in.dbcnt >= out.dbsz) {
745 /* If the output buffer is full, write it. */
746 dd_out(0);
747
748 /*
749 * Ddout copies the leftover output to the beginning of
750 * the buffer and resets the output buffer. Reset the
751 * input buffer to match it.
752 */
753 in.dbp = out.dbp;
754 in.dbcnt = out.dbcnt;
755 }
756}
757
758void
759def_close(void)
760{
Jeff Sharkey393e5592012-05-29 14:25:04 -0700761 if (ddflags & C_FDATASYNC) {
762 fdatasync(out.fd);
763 }
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -0800764
765 /* Just update the count, everything is already in the buffer. */
766 if (in.dbcnt)
767 out.dbcnt = in.dbcnt;
768}
769
770#ifdef NO_CONV
771/* Build a smaller version (i.e. for a miniroot) */
772/* These can not be called, but just in case... */
773static const char no_block[] = "unblock and -DNO_CONV?\n";
774void block(void) { fprintf(stderr, "%s", no_block + 2); exit(1); }
775void block_close(void) { fprintf(stderr, "%s", no_block + 2); exit(1); }
776void unblock(void) { fprintf(stderr, "%s", no_block); exit(1); }
777void unblock_close(void) { fprintf(stderr, "%s", no_block); exit(1); }
778#else /* NO_CONV */
779
780/*
781 * Copy variable length newline terminated records with a max size cbsz
782 * bytes to output. Records less than cbs are padded with spaces.
783 *
784 * max in buffer: MAX(ibs, cbsz)
785 * max out buffer: obs + cbsz
786 */
787void
788block(void)
789{
790 static int intrunc;
791 int ch = 0; /* pacify gcc */
792 uint64_t cnt, maxlen;
793 u_char *inp, *outp;
794 const u_char *t;
795
796 /*
797 * Record truncation can cross block boundaries. If currently in a
798 * truncation state, keep tossing characters until reach a newline.
799 * Start at the beginning of the buffer, as the input buffer is always
800 * left empty.
801 */
802 if (intrunc) {
803 for (inp = in.db, cnt = in.dbrcnt;
804 cnt && *inp++ != '\n'; --cnt);
805 if (!cnt) {
806 in.dbcnt = 0;
807 in.dbp = in.db;
808 return;
809 }
810 intrunc = 0;
811 /* Adjust the input buffer numbers. */
812 in.dbcnt = cnt - 1;
813 in.dbp = inp + cnt - 1;
814 }
815
816 /*
817 * Copy records (max cbsz size chunks) into the output buffer. The
818 * translation is done as we copy into the output buffer.
819 */
820 for (inp = in.dbp - in.dbcnt, outp = out.dbp; in.dbcnt;) {
821 maxlen = MIN(cbsz, in.dbcnt);
822 if ((t = ctab) != NULL)
823 for (cnt = 0;
824 cnt < maxlen && (ch = *inp++) != '\n'; ++cnt)
825 *outp++ = t[ch];
826 else
827 for (cnt = 0;
828 cnt < maxlen && (ch = *inp++) != '\n'; ++cnt)
829 *outp++ = ch;
830 /*
831 * Check for short record without a newline. Reassemble the
832 * input block.
833 */
834 if (ch != '\n' && in.dbcnt < cbsz) {
835 (void)memmove(in.db, in.dbp - in.dbcnt, in.dbcnt);
836 break;
837 }
838
839 /* Adjust the input buffer numbers. */
840 in.dbcnt -= cnt;
841 if (ch == '\n')
842 --in.dbcnt;
843
844 /* Pad short records with spaces. */
845 if (cnt < cbsz)
846 (void)memset(outp, ctab ? ctab[' '] : ' ', cbsz - cnt);
847 else {
848 /*
849 * If the next character wouldn't have ended the
850 * block, it's a truncation.
851 */
852 if (!in.dbcnt || *inp != '\n')
853 ++st.trunc;
854
855 /* Toss characters to a newline. */
856 for (; in.dbcnt && *inp++ != '\n'; --in.dbcnt);
857 if (!in.dbcnt)
858 intrunc = 1;
859 else
860 --in.dbcnt;
861 }
862
863 /* Adjust output buffer numbers. */
864 out.dbp += cbsz;
865 if ((out.dbcnt += cbsz) >= out.dbsz)
866 dd_out(0);
867 outp = out.dbp;
868 }
869 in.dbp = in.db + in.dbcnt;
870}
871
872void
873block_close(void)
874{
875
876 /*
877 * Copy any remaining data into the output buffer and pad to a record.
878 * Don't worry about truncation or translation, the input buffer is
879 * always empty when truncating, and no characters have been added for
880 * translation. The bottom line is that anything left in the input
881 * buffer is a truncated record. Anything left in the output buffer
882 * just wasn't big enough.
883 */
884 if (in.dbcnt) {
885 ++st.trunc;
886 (void)memmove(out.dbp, in.dbp - in.dbcnt, in.dbcnt);
887 (void)memset(out.dbp + in.dbcnt,
888 ctab ? ctab[' '] : ' ', cbsz - in.dbcnt);
889 out.dbcnt += cbsz;
890 }
891}
892
893/*
894 * Convert fixed length (cbsz) records to variable length. Deletes any
895 * trailing blanks and appends a newline.
896 *
897 * max in buffer: MAX(ibs, cbsz) + cbsz
898 * max out buffer: obs + cbsz
899 */
900void
901unblock(void)
902{
903 uint64_t cnt;
904 u_char *inp;
905 const u_char *t;
906
907 /* Translation and case conversion. */
908 if ((t = ctab) != NULL)
909 for (cnt = in.dbrcnt, inp = in.dbp - 1; cnt--; inp--)
910 *inp = t[*inp];
911 /*
912 * Copy records (max cbsz size chunks) into the output buffer. The
913 * translation has to already be done or we might not recognize the
914 * spaces.
915 */
916 for (inp = in.db; in.dbcnt >= cbsz; inp += cbsz, in.dbcnt -= cbsz) {
917 for (t = inp + cbsz - 1; t >= inp && *t == ' '; --t);
918 if (t >= inp) {
919 cnt = t - inp + 1;
920 (void)memmove(out.dbp, inp, cnt);
921 out.dbp += cnt;
922 out.dbcnt += cnt;
923 }
924 ++out.dbcnt;
925 *out.dbp++ = '\n';
926 if (out.dbcnt >= out.dbsz)
927 dd_out(0);
928 }
929 if (in.dbcnt)
930 (void)memmove(in.db, in.dbp - in.dbcnt, in.dbcnt);
931 in.dbp = in.db + in.dbcnt;
932}
933
934void
935unblock_close(void)
936{
937 uint64_t cnt;
938 u_char *t;
939
940 if (in.dbcnt) {
941 warnx("%s: short input record", in.name);
942 for (t = in.db + in.dbcnt - 1; t >= in.db && *t == ' '; --t);
943 if (t >= in.db) {
944 cnt = t - in.db + 1;
945 (void)memmove(out.dbp, in.db, cnt);
946 out.dbp += cnt;
947 out.dbcnt += cnt;
948 }
949 ++out.dbcnt;
950 *out.dbp++ = '\n';
951 }
952}
953
954#endif /* NO_CONV */
955
956#define tv2mS(tv) ((tv).tv_sec * 1000LL + ((tv).tv_usec + 500) / 1000)
957
958void
959summary(void)
960{
961 char buf[100];
962 int64_t mS;
963 struct timeval tv;
964
965 if (progress)
966 (void)write(STDERR_FILENO, "\n", 1);
967
968 (void)gettimeofday(&tv, NULL);
969 mS = tv2mS(tv) - tv2mS(st.start);
970 if (mS == 0)
971 mS = 1;
972 /* Use snprintf(3) so that we don't reenter stdio(3). */
973 (void)snprintf(buf, sizeof(buf),
974 "%llu+%llu records in\n%llu+%llu records out\n",
975 (unsigned long long)st.in_full, (unsigned long long)st.in_part,
976 (unsigned long long)st.out_full, (unsigned long long)st.out_part);
977 (void)write(STDERR_FILENO, buf, strlen(buf));
978 if (st.swab) {
979 (void)snprintf(buf, sizeof(buf), "%llu odd length swab %s\n",
980 (unsigned long long)st.swab,
981 (st.swab == 1) ? "block" : "blocks");
982 (void)write(STDERR_FILENO, buf, strlen(buf));
983 }
984 if (st.trunc) {
985 (void)snprintf(buf, sizeof(buf), "%llu truncated %s\n",
986 (unsigned long long)st.trunc,
987 (st.trunc == 1) ? "block" : "blocks");
988 (void)write(STDERR_FILENO, buf, strlen(buf));
989 }
990 if (st.sparse) {
991 (void)snprintf(buf, sizeof(buf), "%llu sparse output %s\n",
992 (unsigned long long)st.sparse,
993 (st.sparse == 1) ? "block" : "blocks");
994 (void)write(STDERR_FILENO, buf, strlen(buf));
995 }
996 (void)snprintf(buf, sizeof(buf),
997 "%llu bytes transferred in %lu.%03d secs (%llu bytes/sec)\n",
998 (unsigned long long) st.bytes,
999 (long) (mS / 1000),
1000 (int) (mS % 1000),
1001 (unsigned long long) (st.bytes * 1000LL / mS));
1002 (void)write(STDERR_FILENO, buf, strlen(buf));
1003}
1004
1005void
1006terminate(int notused)
1007{
1008
1009 exit(0);
1010 /* NOTREACHED */
1011}
1012
1013static int c_arg(const void *, const void *);
1014#ifndef NO_CONV
1015static int c_conv(const void *, const void *);
1016#endif
1017static void f_bs(char *);
1018static void f_cbs(char *);
1019static void f_conv(char *);
1020static void f_count(char *);
1021static void f_files(char *);
1022static void f_ibs(char *);
1023static void f_if(char *);
1024static void f_obs(char *);
1025static void f_of(char *);
1026static void f_seek(char *);
1027static void f_skip(char *);
1028static void f_progress(char *);
1029
1030static const struct arg {
1031 const char *name;
1032 void (*f)(char *);
1033 u_int set, noset;
1034} args[] = {
1035 /* the array needs to be sorted by the first column so
1036 bsearch() can be used to find commands quickly */
1037 { "bs", f_bs, C_BS, C_BS|C_IBS|C_OBS|C_OSYNC },
1038 { "cbs", f_cbs, C_CBS, C_CBS },
1039 { "conv", f_conv, 0, 0 },
1040 { "count", f_count, C_COUNT, C_COUNT },
1041 { "files", f_files, C_FILES, C_FILES },
1042 { "ibs", f_ibs, C_IBS, C_BS|C_IBS },
1043 { "if", f_if, C_IF, C_IF },
1044 { "obs", f_obs, C_OBS, C_BS|C_OBS },
1045 { "of", f_of, C_OF, C_OF },
1046 { "progress", f_progress, 0, 0 },
1047 { "seek", f_seek, C_SEEK, C_SEEK },
1048 { "skip", f_skip, C_SKIP, C_SKIP },
1049};
1050
1051/*
1052 * args -- parse JCL syntax of dd.
1053 */
1054void
1055jcl(char **argv)
1056{
1057 struct arg *ap, tmp;
1058 char *oper, *arg;
1059
1060 in.dbsz = out.dbsz = 512;
1061
1062 while ((oper = *++argv) != NULL) {
1063 if ((arg = strchr(oper, '=')) == NULL) {
1064 fprintf(stderr, "unknown operand %s\n", oper);
1065 exit(1);
1066 /* NOTREACHED */
1067 }
1068 *arg++ = '\0';
1069 if (!*arg) {
1070 fprintf(stderr, "no value specified for %s\n", oper);
1071 exit(1);
1072 /* NOTREACHED */
1073 }
1074 tmp.name = oper;
1075 if (!(ap = (struct arg *)bsearch(&tmp, args,
1076 sizeof(args)/sizeof(struct arg), sizeof(struct arg),
1077 c_arg))) {
1078 fprintf(stderr, "unknown operand %s\n", tmp.name);
1079 exit(1);
1080 /* NOTREACHED */
1081 }
1082 if (ddflags & ap->noset) {
1083 fprintf(stderr,
1084 "%s: illegal argument combination or already set\n",
1085 tmp.name);
1086 exit(1);
1087 /* NOTREACHED */
1088 }
1089 ddflags |= ap->set;
1090 ap->f(arg);
1091 }
1092
1093 /* Final sanity checks. */
1094
1095 if (ddflags & C_BS) {
1096 /*
1097 * Bs is turned off by any conversion -- we assume the user
1098 * just wanted to set both the input and output block sizes
1099 * and didn't want the bs semantics, so we don't warn.
1100 */
1101 if (ddflags & (C_BLOCK | C_LCASE | C_SWAB | C_UCASE |
1102 C_UNBLOCK | C_OSYNC | C_ASCII | C_EBCDIC | C_SPARSE)) {
1103 ddflags &= ~C_BS;
1104 ddflags |= C_IBS|C_OBS;
1105 }
1106
1107 /* Bs supersedes ibs and obs. */
1108 if (ddflags & C_BS && ddflags & (C_IBS|C_OBS))
1109 fprintf(stderr, "bs supersedes ibs and obs\n");
1110 }
1111
1112 /*
1113 * Ascii/ebcdic and cbs implies block/unblock.
1114 * Block/unblock requires cbs and vice-versa.
1115 */
1116 if (ddflags & (C_BLOCK|C_UNBLOCK)) {
1117 if (!(ddflags & C_CBS)) {
1118 fprintf(stderr, "record operations require cbs\n");
1119 exit(1);
1120 /* NOTREACHED */
1121 }
1122 cfunc = ddflags & C_BLOCK ? block : unblock;
1123 } else if (ddflags & C_CBS) {
1124 if (ddflags & (C_ASCII|C_EBCDIC)) {
1125 if (ddflags & C_ASCII) {
1126 ddflags |= C_UNBLOCK;
1127 cfunc = unblock;
1128 } else {
1129 ddflags |= C_BLOCK;
1130 cfunc = block;
1131 }
1132 } else {
1133 fprintf(stderr,
1134 "cbs meaningless if not doing record operations\n");
1135 exit(1);
1136 /* NOTREACHED */
1137 }
1138 } else
1139 cfunc = def;
1140
1141 /* Read, write and seek calls take off_t as arguments.
1142 *
1143 * The following check is not done because an off_t is a quad
1144 * for current NetBSD implementations.
1145 *
1146 * if (in.offset > INT_MAX/in.dbsz || out.offset > INT_MAX/out.dbsz)
1147 * errx(1, "seek offsets cannot be larger than %d", INT_MAX);
1148 */
1149}
1150
1151static int
1152c_arg(const void *a, const void *b)
1153{
1154
1155 return (strcmp(((const struct arg *)a)->name,
1156 ((const struct arg *)b)->name));
1157}
1158
1159static long long strsuftoll(const char* name, const char* arg, int def, unsigned int max)
1160{
1161 long long result;
1162
1163 if (sscanf(arg, "%lld", &result) == 0)
1164 result = def;
1165 return result;
1166}
1167
1168static void
1169f_bs(char *arg)
1170{
1171
1172 in.dbsz = out.dbsz = strsuftoll("block size", arg, 1, UINT_MAX);
1173}
1174
1175static void
1176f_cbs(char *arg)
1177{
1178
1179 cbsz = strsuftoll("conversion record size", arg, 1, UINT_MAX);
1180}
1181
1182static void
1183f_count(char *arg)
1184{
1185
1186 cpy_cnt = strsuftoll("block count", arg, 0, LLONG_MAX);
1187 if (!cpy_cnt)
1188 terminate(0);
1189}
1190
1191static void
1192f_files(char *arg)
1193{
1194
1195 files_cnt = (u_int)strsuftoll("file count", arg, 0, UINT_MAX);
1196 if (!files_cnt)
1197 terminate(0);
1198}
1199
1200static void
1201f_ibs(char *arg)
1202{
1203
1204 if (!(ddflags & C_BS))
1205 in.dbsz = strsuftoll("input block size", arg, 1, UINT_MAX);
1206}
1207
1208static void
1209f_if(char *arg)
1210{
1211
1212 in.name = arg;
1213}
1214
1215static void
1216f_obs(char *arg)
1217{
1218
1219 if (!(ddflags & C_BS))
1220 out.dbsz = strsuftoll("output block size", arg, 1, UINT_MAX);
1221}
1222
1223static void
1224f_of(char *arg)
1225{
1226
1227 out.name = arg;
1228}
1229
1230static void
1231f_seek(char *arg)
1232{
1233
1234 out.offset = strsuftoll("seek blocks", arg, 0, LLONG_MAX);
1235}
1236
1237static void
1238f_skip(char *arg)
1239{
1240
1241 in.offset = strsuftoll("skip blocks", arg, 0, LLONG_MAX);
1242}
1243
1244static void
1245f_progress(char *arg)
1246{
1247
1248 if (*arg != '0')
1249 progress = 1;
1250}
1251
1252#ifdef NO_CONV
1253/* Build a small version (i.e. for a ramdisk root) */
1254static void
1255f_conv(char *arg)
1256{
1257
1258 fprintf(stderr, "conv option disabled\n");
1259 exit(1);
1260 /* NOTREACHED */
1261}
1262#else /* NO_CONV */
1263
1264static const struct conv {
1265 const char *name;
1266 u_int set, noset;
1267 const u_char *ctab;
1268} clist[] = {
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -08001269 { "block", C_BLOCK, C_UNBLOCK, NULL },
Jeff Sharkey393e5592012-05-29 14:25:04 -07001270 { "fdatasync", C_FDATASYNC, 0, NULL },
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -08001271 { "noerror", C_NOERROR, 0, NULL },
1272 { "notrunc", C_NOTRUNC, 0, NULL },
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -08001273 { "osync", C_OSYNC, C_BS, NULL },
1274 { "sparse", C_SPARSE, 0, NULL },
1275 { "swab", C_SWAB, 0, NULL },
1276 { "sync", C_SYNC, 0, NULL },
The Android Open Source Projectdd7bc332009-03-03 19:32:55 -08001277 { "unblock", C_UNBLOCK, C_BLOCK, NULL },
1278 /* If you add items to this table, be sure to add the
1279 * conversions to the C_BS check in the jcl routine above.
1280 */
1281};
1282
1283static void
1284f_conv(char *arg)
1285{
1286 struct conv *cp, tmp;
1287
1288 while (arg != NULL) {
1289 tmp.name = strsep(&arg, ",");
1290 if (!(cp = (struct conv *)bsearch(&tmp, clist,
1291 sizeof(clist)/sizeof(struct conv), sizeof(struct conv),
1292 c_conv))) {
1293 errx(EXIT_FAILURE, "unknown conversion %s", tmp.name);
1294 /* NOTREACHED */
1295 }
1296 if (ddflags & cp->noset) {
1297 errx(EXIT_FAILURE, "%s: illegal conversion combination", tmp.name);
1298 /* NOTREACHED */
1299 }
1300 ddflags |= cp->set;
1301 if (cp->ctab)
1302 ctab = cp->ctab;
1303 }
1304}
1305
1306static int
1307c_conv(const void *a, const void *b)
1308{
1309
1310 return (strcmp(((const struct conv *)a)->name,
1311 ((const struct conv *)b)->name));
1312}
1313
1314#endif /* NO_CONV */
1315
1316