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