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