Annotation of src/bin/dd/dd.c, Revision 1.41
1.41 ! christos 1: /* $NetBSD: dd.c,v 1.40 2007/04/29 20:23:34 msaitoh Exp $ */
1.4 cgd 2:
1.1 glass 3: /*-
1.3 mycroft 4: * Copyright (c) 1991, 1993, 1994
5: * The Regents of the University of California. All rights reserved.
1.1 glass 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.
1.31 agc 19: * 3. Neither the name of the University nor the names of its contributors
1.1 glass 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:
1.7 christos 36: #include <sys/cdefs.h>
1.1 glass 37: #ifndef lint
1.7 christos 38: __COPYRIGHT("@(#) Copyright (c) 1991, 1993, 1994\n\
39: The Regents of the University of California. All rights reserved.\n");
1.1 glass 40: #endif /* not lint */
41:
42: #ifndef lint
1.4 cgd 43: #if 0
44: static char sccsid[] = "@(#)dd.c 8.5 (Berkeley) 4/2/94";
45: #else
1.41 ! christos 46: __RCSID("$NetBSD: dd.c,v 1.40 2007/04/29 20:23:34 msaitoh Exp $");
1.4 cgd 47: #endif
1.1 glass 48: #endif /* not lint */
49:
50: #include <sys/param.h>
51: #include <sys/stat.h>
52: #include <sys/ioctl.h>
53: #include <sys/mtio.h>
1.20 ross 54: #include <sys/time.h>
1.1 glass 55:
56: #include <ctype.h>
1.3 mycroft 57: #include <err.h>
1.1 glass 58: #include <errno.h>
59: #include <fcntl.h>
1.41 ! christos 60: #include <locale.h>
1.1 glass 61: #include <signal.h>
62: #include <stdio.h>
63: #include <stdlib.h>
64: #include <string.h>
65: #include <unistd.h>
66:
67: #include "dd.h"
68: #include "extern.h"
69:
1.21 lukem 70: static void dd_close(void);
71: static void dd_in(void);
72: static void getfdtype(IO *);
1.34 dsainty 73: static int redup_clean_fd(int);
1.21 lukem 74: static void setup(void);
1.1 glass 75:
1.21 lukem 76: int main(int, char *[]);
1.7 christos 77:
1.23 lukem 78: IO in, out; /* input/output state */
79: STAT st; /* statistics */
80: void (*cfunc)(void); /* conversion function */
1.24 lukem 81: uint64_t cpy_cnt; /* # of blocks to copy */
1.36 dbj 82: static off_t pending = 0; /* pending seek if sparse */
1.23 lukem 83: u_int ddflags; /* conversion options */
1.24 lukem 84: uint64_t cbsz; /* conversion block size */
1.23 lukem 85: u_int files_cnt = 1; /* # of files to copy */
1.39 apb 86: uint64_t progress = 0; /* display sign of life */
1.23 lukem 87: const u_char *ctab; /* conversion table */
88: sigset_t infoset; /* a set blocking SIGINFO */
1.1 glass 89:
90: int
1.21 lukem 91: main(int argc, char *argv[])
1.1 glass 92: {
1.18 kleink 93: int ch;
94:
1.41 ! christos 95: setprogname(argv[0]);
! 96: (void)setlocale(LC_ALL, "");
! 97:
1.18 kleink 98: while ((ch = getopt(argc, argv, "")) != -1) {
99: switch (ch) {
1.19 kleink 100: default:
101: errx(EXIT_FAILURE, "usage: dd [operand ...]");
102: /* NOTREACHED */
1.18 kleink 103: }
104: }
105: argc -= (optind - 1);
106: argv += (optind - 1);
107:
1.1 glass 108: jcl(argv);
109: setup();
110:
1.3 mycroft 111: (void)signal(SIGINFO, summaryx);
1.1 glass 112: (void)signal(SIGINT, terminate);
1.16 christos 113: (void)sigemptyset(&infoset);
114: (void)sigaddset(&infoset, SIGINFO);
1.1 glass 115:
1.10 mycroft 116: (void)atexit(summary);
1.3 mycroft 117:
118: while (files_cnt--)
1.1 glass 119: dd_in();
120:
121: dd_close();
122: exit(0);
1.11 mycroft 123: /* NOTREACHED */
1.1 glass 124: }
125:
126: static void
1.21 lukem 127: setup(void)
1.1 glass 128: {
1.25 enami 129:
1.1 glass 130: if (in.name == NULL) {
131: in.name = "stdin";
132: in.fd = STDIN_FILENO;
133: } else {
134: in.fd = open(in.name, O_RDONLY, 0);
135: if (in.fd < 0)
1.33 jschauma 136: err(EXIT_FAILURE, "%s", in.name);
1.30 jschauma 137: /* NOTREACHED */
1.34 dsainty 138:
139: /* Ensure in.fd is outside the stdio descriptor range */
140: in.fd = redup_clean_fd(in.fd);
1.1 glass 141: }
142:
1.3 mycroft 143: getfdtype(&in);
1.1 glass 144:
1.30 jschauma 145: if (files_cnt > 1 && !(in.flags & ISTAPE)) {
146: errx(EXIT_FAILURE, "files is not supported for non-tape devices");
147: /* NOTREACHED */
148: }
1.1 glass 149:
150: if (out.name == NULL) {
151: /* No way to check for read access here. */
152: out.fd = STDOUT_FILENO;
153: out.name = "stdout";
154: } else {
155: #define OFLAGS \
156: (O_CREAT | (ddflags & (C_SEEK | C_NOTRUNC) ? 0 : O_TRUNC))
157: out.fd = open(out.name, O_RDWR | OFLAGS, DEFFILEMODE);
158: /*
159: * May not have read access, so try again with write only.
160: * Without read we may have a problem if output also does
161: * not support seeks.
162: */
163: if (out.fd < 0) {
164: out.fd = open(out.name, O_WRONLY | OFLAGS, DEFFILEMODE);
165: out.flags |= NOREAD;
166: }
1.30 jschauma 167: if (out.fd < 0) {
1.33 jschauma 168: err(EXIT_FAILURE, "%s", out.name);
1.30 jschauma 169: /* NOTREACHED */
170: }
1.34 dsainty 171:
172: /* Ensure out.fd is outside the stdio descriptor range */
173: out.fd = redup_clean_fd(out.fd);
1.1 glass 174: }
175:
1.3 mycroft 176: getfdtype(&out);
1.1 glass 177:
178: /*
179: * Allocate space for the input and output buffers. If not doing
180: * record oriented I/O, only need a single buffer.
181: */
182: if (!(ddflags & (C_BLOCK|C_UNBLOCK))) {
1.30 jschauma 183: if ((in.db = malloc(out.dbsz + in.dbsz - 1)) == NULL) {
184: err(EXIT_FAILURE, NULL);
185: /* NOTREACHED */
186: }
1.1 glass 187: out.db = in.db;
188: } else if ((in.db =
189: malloc((u_int)(MAX(in.dbsz, cbsz) + cbsz))) == NULL ||
1.30 jschauma 190: (out.db = malloc((u_int)(out.dbsz + cbsz))) == NULL) {
191: err(EXIT_FAILURE, NULL);
192: /* NOTREACHED */
193: }
1.1 glass 194: in.dbp = in.db;
195: out.dbp = out.db;
196:
197: /* Position the input/output streams. */
198: if (in.offset)
199: pos_in();
200: if (out.offset)
201: pos_out();
202:
203: /*
204: * Truncate the output file; ignore errors because it fails on some
205: * kinds of output files, tapes, for example.
206: */
1.7 christos 207: if ((ddflags & (C_OF | C_SEEK | C_NOTRUNC)) == (C_OF | C_SEEK))
1.1 glass 208: (void)ftruncate(out.fd, (off_t)out.offset * out.dbsz);
209:
210: /*
211: * If converting case at the same time as another conversion, build a
212: * table that does both at once. If just converting case, use the
213: * built-in tables.
214: */
1.5 gwr 215: if (ddflags & (C_LCASE|C_UCASE)) {
216: #ifdef NO_CONV
217: /* Should not get here, but just in case... */
1.30 jschauma 218: errx(EXIT_FAILURE, "case conv and -DNO_CONV");
219: /* NOTREACHED */
1.5 gwr 220: #else /* NO_CONV */
1.22 lukem 221: u_int cnt;
222:
1.6 jtc 223: if (ddflags & C_ASCII || ddflags & C_EBCDIC) {
1.1 glass 224: if (ddflags & C_LCASE) {
1.38 rillig 225: for (cnt = 0; cnt < 256; ++cnt)
1.6 jtc 226: casetab[cnt] = tolower(ctab[cnt]);
1.1 glass 227: } else {
1.38 rillig 228: for (cnt = 0; cnt < 256; ++cnt)
1.6 jtc 229: casetab[cnt] = toupper(ctab[cnt]);
1.1 glass 230: }
1.6 jtc 231: } else {
1.1 glass 232: if (ddflags & C_LCASE) {
1.38 rillig 233: for (cnt = 0; cnt < 256; ++cnt)
1.6 jtc 234: casetab[cnt] = tolower(cnt);
1.1 glass 235: } else {
1.38 rillig 236: for (cnt = 0; cnt < 256; ++cnt)
1.6 jtc 237: casetab[cnt] = toupper(cnt);
1.1 glass 238: }
1.6 jtc 239: }
240:
241: ctab = casetab;
1.5 gwr 242: #endif /* NO_CONV */
243: }
244:
1.20 ross 245: (void)gettimeofday(&st.start, NULL); /* Statistics timestamp. */
1.1 glass 246: }
247:
248: static void
1.21 lukem 249: getfdtype(IO *io)
1.3 mycroft 250: {
251: struct mtget mt;
252: struct stat sb;
253:
1.30 jschauma 254: if (fstat(io->fd, &sb)) {
1.33 jschauma 255: err(EXIT_FAILURE, "%s", io->name);
1.30 jschauma 256: /* NOTREACHED */
257: }
1.3 mycroft 258: if (S_ISCHR(sb.st_mode))
259: io->flags |= ioctl(io->fd, MTIOCGET, &mt) ? ISCHR : ISTAPE;
260: else if (lseek(io->fd, (off_t)0, SEEK_CUR) == -1 && errno == ESPIPE)
261: io->flags |= ISPIPE; /* XXX fixed in 4.4BSD */
1.34 dsainty 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: */
270: static int
271: redup_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:
1.35 dsainty 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);
1.34 dsainty 285: if (newfd < 0) {
1.35 dsainty 286: err(EXIT_FAILURE, "dupfd IO");
1.34 dsainty 287: /* NOTREACHED */
288: }
289:
290: close(fd);
291:
292: return newfd;
1.3 mycroft 293: }
294:
295: static void
1.21 lukem 296: dd_in(void)
1.1 glass 297: {
1.23 lukem 298: int flags;
1.26 lukem 299: int64_t n;
1.1 glass 300:
301: for (flags = ddflags;;) {
302: if (cpy_cnt && (st.in_full + st.in_part) >= cpy_cnt)
303: return;
304:
305: /*
1.9 gwr 306: * Clear the buffer first if doing "sync" on input.
307: * If doing block operations use spaces. This will
308: * affect not only the C_NOERROR case, but also the
309: * last partial input block which should be padded
310: * with zero and not garbage.
1.1 glass 311: */
1.12 thorpej 312: if (flags & C_SYNC) {
1.1 glass 313: if (flags & (C_BLOCK|C_UNBLOCK))
1.10 mycroft 314: (void)memset(in.dbp, ' ', in.dbsz);
1.1 glass 315: else
1.10 mycroft 316: (void)memset(in.dbp, 0, in.dbsz);
1.12 thorpej 317: }
1.1 glass 318:
319: n = read(in.fd, in.dbp, in.dbsz);
320: if (n == 0) {
321: in.dbrcnt = 0;
322: return;
323: }
324:
325: /* Read error. */
326: if (n < 0) {
1.30 jschauma 327:
1.1 glass 328: /*
329: * If noerror not specified, die. POSIX requires that
330: * the warning message be followed by an I/O display.
331: */
1.30 jschauma 332: if (!(flags & C_NOERROR)) {
1.33 jschauma 333: err(EXIT_FAILURE, "%s", in.name);
1.30 jschauma 334: /* NOTREACHED */
335: }
1.33 jschauma 336: warn("%s", in.name);
1.3 mycroft 337: summary();
1.1 glass 338:
339: /*
340: * If it's not a tape drive or a pipe, seek past the
341: * error. If your OS doesn't do the right thing for
342: * raw disks this section should be modified to re-read
343: * in sector size chunks.
344: */
345: if (!(in.flags & (ISPIPE|ISTAPE)) &&
346: lseek(in.fd, (off_t)in.dbsz, SEEK_CUR))
1.33 jschauma 347: warn("%s", in.name);
1.32 jschauma 348:
1.1 glass 349: /* If sync not specified, omit block and continue. */
350: if (!(ddflags & C_SYNC))
351: continue;
352:
353: /* Read errors count as full blocks. */
354: in.dbcnt += in.dbrcnt = in.dbsz;
355: ++st.in_full;
356:
357: /* Handle full input blocks. */
358: } else if (n == in.dbsz) {
359: in.dbcnt += in.dbrcnt = n;
360: ++st.in_full;
361:
362: /* Handle partial input blocks. */
363: } else {
364: /* If sync, use the entire block. */
365: if (ddflags & C_SYNC)
366: in.dbcnt += in.dbrcnt = in.dbsz;
367: else
368: in.dbcnt += in.dbrcnt = n;
369: ++st.in_part;
370: }
371:
372: /*
373: * POSIX states that if bs is set and no other conversions
374: * than noerror, notrunc or sync are specified, the block
375: * is output without buffering as it is read.
376: */
377: if (ddflags & C_BS) {
378: out.dbcnt = in.dbcnt;
379: dd_out(1);
380: in.dbcnt = 0;
381: continue;
382: }
383:
384: if (ddflags & C_SWAB) {
1.17 matt 385: if ((n = in.dbrcnt) & 1) {
1.1 glass 386: ++st.swab;
387: --n;
388: }
389: swab(in.dbp, in.dbp, n);
390: }
391:
392: in.dbp += in.dbrcnt;
393: (*cfunc)();
394: }
395: }
396:
397: /*
1.40 msaitoh 398: * Cleanup any remaining I/O and flush output. If necessary, output file
1.1 glass 399: * is truncated.
400: */
401: static void
1.21 lukem 402: dd_close(void)
1.1 glass 403: {
1.21 lukem 404:
1.1 glass 405: if (cfunc == def)
406: def_close();
407: else if (cfunc == block)
408: block_close();
409: else if (cfunc == unblock)
410: unblock_close();
1.3 mycroft 411: if (ddflags & C_OSYNC && out.dbcnt < out.dbsz) {
1.10 mycroft 412: (void)memset(out.dbp, 0, out.dbsz - out.dbcnt);
1.3 mycroft 413: out.dbcnt = out.dbsz;
414: }
1.36 dbj 415: /* If there are pending sparse blocks, make sure
416: * to write out the final block un-sparse
417: */
418: if ((out.dbcnt == 0) && pending) {
419: memset(out.db, 0, out.dbsz);
420: out.dbcnt = out.dbsz;
1.37 dbj 421: out.dbp = out.db + out.dbcnt;
1.36 dbj 422: pending -= out.dbsz;
423: }
1.1 glass 424: if (out.dbcnt)
425: dd_out(1);
1.29 enami 426:
427: /*
428: * Reporting nfs write error may be defered until next
429: * write(2) or close(2) system call. So, we need to do an
430: * extra check. If an output is stdout, the file structure
431: * may be shared among with other processes and close(2) just
432: * decreases the reference count.
433: */
1.30 jschauma 434: if (out.fd == STDOUT_FILENO && fsync(out.fd) == -1 && errno != EINVAL) {
435: err(EXIT_FAILURE, "fsync stdout");
436: /* NOTREACHED */
437: }
438: if (close(out.fd) == -1) {
439: err(EXIT_FAILURE, "close");
440: /* NOTREACHED */
441: }
1.1 glass 442: }
443:
444: void
1.21 lukem 445: dd_out(int force)
1.1 glass 446: {
447: static int warned;
1.26 lukem 448: int64_t cnt, n, nw;
1.3 mycroft 449: u_char *outp;
1.1 glass 450:
451: /*
452: * Write one or more blocks out. The common case is writing a full
453: * output block in a single write; increment the full block stats.
454: * Otherwise, we're into partial block writes. If a partial write,
455: * and it's a character device, just warn. If a tape device, quit.
456: *
457: * The partial writes represent two cases. 1: Where the input block
458: * was less than expected so the output block was less than expected.
459: * 2: Where the input block was the right size but we were forced to
460: * write the block in multiple chunks. The original versions of dd(1)
461: * never wrote a block in more than a single write, so the latter case
462: * never happened.
463: *
464: * One special case is if we're forced to do the write -- in that case
465: * we play games with the buffer size, and it's usually a partial write.
466: */
467: outp = out.db;
468: for (n = force ? out.dbcnt : out.dbsz;; n = out.dbsz) {
469: for (cnt = n;; cnt -= nw) {
1.30 jschauma 470:
1.36 dbj 471: if (!force && ddflags & C_SPARSE) {
472: int sparse, i;
473: sparse = 1; /* Is buffer sparse? */
474: for (i = 0; i < cnt; i++)
475: if (outp[i] != 0) {
476: sparse = 0;
477: break;
478: }
479: if (sparse) {
480: pending += cnt;
481: outp += cnt;
482: nw = 0;
483: break;
484: }
485: }
486: if (pending != 0) {
487: if (lseek(out.fd, pending, SEEK_CUR) ==
488: -1)
489: err(EXIT_FAILURE, "%s: seek error creating sparse file",
490: out.name);
491: }
1.15 christos 492: nw = bwrite(out.fd, outp, cnt);
1.3 mycroft 493: if (nw <= 0) {
494: if (nw == 0)
1.30 jschauma 495: errx(EXIT_FAILURE,
1.33 jschauma 496: "%s: end of device", out.name);
1.30 jschauma 497: /* NOTREACHED */
1.3 mycroft 498: if (errno != EINTR)
1.33 jschauma 499: err(EXIT_FAILURE, "%s", out.name);
1.30 jschauma 500: /* NOTREACHED */
1.3 mycroft 501: nw = 0;
502: }
1.36 dbj 503: if (pending) {
504: st.bytes += pending;
505: st.sparse += pending/out.dbsz;
506: st.out_full += pending/out.dbsz;
507: pending = 0;
508: }
1.1 glass 509: outp += nw;
510: st.bytes += nw;
511: if (nw == n) {
512: if (n != out.dbsz)
513: ++st.out_part;
514: else
515: ++st.out_full;
516: break;
517: }
518: ++st.out_part;
1.33 jschauma 519: if (nw == cnt)
1.1 glass 520: break;
521: if (out.flags & ISCHR && !warned) {
522: warned = 1;
1.33 jschauma 523: warnx("%s: short write on character device", out.name);
1.1 glass 524: }
525: if (out.flags & ISTAPE)
1.30 jschauma 526: errx(EXIT_FAILURE,
1.33 jschauma 527: "%s: short write on tape device", out.name);
1.30 jschauma 528: /* NOTREACHED */
529:
1.1 glass 530: }
531: if ((out.dbcnt -= n) < out.dbsz)
532: break;
533: }
534:
535: /* Reassemble the output block. */
536: if (out.dbcnt)
1.10 mycroft 537: (void)memmove(out.db, out.dbp - out.dbcnt, out.dbcnt);
1.1 glass 538: out.dbp = out.db + out.dbcnt;
1.13 hubertf 539:
1.39 apb 540: if (progress && (st.out_full + st.out_part) % progress == 0)
1.13 hubertf 541: (void)write(STDERR_FILENO, ".", 1);
1.15 christos 542: }
543:
544: /*
545: * A protected against SIGINFO write
546: */
547: ssize_t
1.21 lukem 548: bwrite(int fd, const void *buf, size_t len)
1.15 christos 549: {
550: sigset_t oset;
551: ssize_t rv;
552: int oerrno;
553:
1.16 christos 554: (void)sigprocmask(SIG_BLOCK, &infoset, &oset);
1.15 christos 555: rv = write(fd, buf, len);
556: oerrno = errno;
557: (void)sigprocmask(SIG_SETMASK, &oset, NULL);
558: errno = oerrno;
1.25 enami 559: return (rv);
1.1 glass 560: }
CVSweb <webmaster@jp.NetBSD.org>