[BACK]Return to dd.c CVS log [TXT][DIR] Up to [cvs.NetBSD.org] / src / bin / dd

Annotation of src/bin/dd/dd.c, Revision 1.25

1.25    ! enami       1: /*     $NetBSD: dd.c,v 1.24 2001/11/26 00:13:24 lukem 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.
                     19:  * 3. All advertising materials mentioning features or use of this software
                     20:  *    must display the following acknowledgement:
                     21:  *     This product includes software developed by the University of
                     22:  *     California, Berkeley and its contributors.
                     23:  * 4. Neither the name of the University nor the names of its contributors
                     24:  *    may be used to endorse or promote products derived from this software
                     25:  *    without specific prior written permission.
                     26:  *
                     27:  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
                     28:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
                     29:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
                     30:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
                     31:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
                     32:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
                     33:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
                     34:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
                     35:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
                     36:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
                     37:  * SUCH DAMAGE.
                     38:  */
                     39:
1.7       christos   40: #include <sys/cdefs.h>
1.1       glass      41: #ifndef lint
1.7       christos   42: __COPYRIGHT("@(#) Copyright (c) 1991, 1993, 1994\n\
                     43:        The Regents of the University of California.  All rights reserved.\n");
1.1       glass      44: #endif /* not lint */
                     45:
                     46: #ifndef lint
1.4       cgd        47: #if 0
                     48: static char sccsid[] = "@(#)dd.c       8.5 (Berkeley) 4/2/94";
                     49: #else
1.25    ! enami      50: __RCSID("$NetBSD: dd.c,v 1.24 2001/11/26 00:13:24 lukem Exp $");
1.4       cgd        51: #endif
1.1       glass      52: #endif /* not lint */
                     53:
                     54: #include <sys/param.h>
                     55: #include <sys/stat.h>
                     56: #include <sys/ioctl.h>
                     57: #include <sys/mtio.h>
1.20      ross       58: #include <sys/time.h>
1.1       glass      59:
                     60: #include <ctype.h>
1.3       mycroft    61: #include <err.h>
1.1       glass      62: #include <errno.h>
                     63: #include <fcntl.h>
                     64: #include <signal.h>
                     65: #include <stdio.h>
                     66: #include <stdlib.h>
                     67: #include <string.h>
                     68: #include <unistd.h>
                     69:
                     70: #include "dd.h"
                     71: #include "extern.h"
                     72:
1.21      lukem      73: static void dd_close(void);
                     74: static void dd_in(void);
                     75: static void getfdtype(IO *);
                     76: static void setup(void);
1.1       glass      77:
1.21      lukem      78: int main(int, char *[]);
1.7       christos   79:
1.23      lukem      80: IO             in, out;                /* input/output state */
                     81: STAT           st;                     /* statistics */
                     82: void           (*cfunc)(void);         /* conversion function */
1.24      lukem      83: uint64_t       cpy_cnt;                /* # of blocks to copy */
1.23      lukem      84: u_int          ddflags;                /* conversion options */
1.24      lukem      85: uint64_t       cbsz;                   /* conversion block size */
1.23      lukem      86: u_int          files_cnt = 1;          /* # of files to copy */
                     87: int            progress = 0;           /* display sign of life */
                     88: const u_char   *ctab;                  /* conversion table */
                     89: sigset_t       infoset;                /* a set blocking SIGINFO */
1.1       glass      90:
                     91: int
1.21      lukem      92: main(int argc, char *argv[])
1.1       glass      93: {
1.18      kleink     94:        int ch;
                     95:
                     96:        while ((ch = getopt(argc, argv, "")) != -1) {
                     97:                switch (ch) {
1.19      kleink     98:                default:
                     99:                        errx(EXIT_FAILURE, "usage: dd [operand ...]");
                    100:                        /* NOTREACHED */
1.18      kleink    101:                }
                    102:        }
                    103:        argc -= (optind - 1);
                    104:        argv += (optind - 1);
                    105:
1.1       glass     106:        jcl(argv);
                    107:        setup();
                    108:
1.3       mycroft   109:        (void)signal(SIGINFO, summaryx);
1.1       glass     110:        (void)signal(SIGINT, terminate);
1.16      christos  111:        (void)sigemptyset(&infoset);
                    112:        (void)sigaddset(&infoset, SIGINFO);
1.1       glass     113:
1.10      mycroft   114:        (void)atexit(summary);
1.3       mycroft   115:
                    116:        while (files_cnt--)
1.1       glass     117:                dd_in();
                    118:
                    119:        dd_close();
                    120:        exit(0);
1.11      mycroft   121:        /* NOTREACHED */
1.1       glass     122: }
                    123:
                    124: static void
1.21      lukem     125: setup(void)
1.1       glass     126: {
1.25    ! enami     127:
1.1       glass     128:        if (in.name == NULL) {
                    129:                in.name = "stdin";
                    130:                in.fd = STDIN_FILENO;
                    131:        } else {
                    132:                in.fd = open(in.name, O_RDONLY, 0);
                    133:                if (in.fd < 0)
1.3       mycroft   134:                        err(1, "%s", in.name);
1.1       glass     135:        }
                    136:
1.3       mycroft   137:        getfdtype(&in);
1.1       glass     138:
                    139:        if (files_cnt > 1 && !(in.flags & ISTAPE))
1.3       mycroft   140:                errx(1, "files is not supported for non-tape devices");
1.1       glass     141:
                    142:        if (out.name == NULL) {
                    143:                /* No way to check for read access here. */
                    144:                out.fd = STDOUT_FILENO;
                    145:                out.name = "stdout";
                    146:        } else {
                    147: #define        OFLAGS \
                    148:     (O_CREAT | (ddflags & (C_SEEK | C_NOTRUNC) ? 0 : O_TRUNC))
                    149:                out.fd = open(out.name, O_RDWR | OFLAGS, DEFFILEMODE);
                    150:                /*
                    151:                 * May not have read access, so try again with write only.
                    152:                 * Without read we may have a problem if output also does
                    153:                 * not support seeks.
                    154:                 */
                    155:                if (out.fd < 0) {
                    156:                        out.fd = open(out.name, O_WRONLY | OFLAGS, DEFFILEMODE);
                    157:                        out.flags |= NOREAD;
                    158:                }
                    159:                if (out.fd < 0)
1.3       mycroft   160:                        err(1, "%s", out.name);
1.1       glass     161:        }
                    162:
1.3       mycroft   163:        getfdtype(&out);
1.1       glass     164:
                    165:        /*
                    166:         * Allocate space for the input and output buffers.  If not doing
                    167:         * record oriented I/O, only need a single buffer.
                    168:         */
                    169:        if (!(ddflags & (C_BLOCK|C_UNBLOCK))) {
                    170:                if ((in.db = malloc(out.dbsz + in.dbsz - 1)) == NULL)
1.14      drochner  171:                        err(1, NULL);
1.1       glass     172:                out.db = in.db;
                    173:        } else if ((in.db =
                    174:            malloc((u_int)(MAX(in.dbsz, cbsz) + cbsz))) == NULL ||
                    175:            (out.db = malloc((u_int)(out.dbsz + cbsz))) == NULL)
1.14      drochner  176:                err(1, NULL);
1.1       glass     177:        in.dbp = in.db;
                    178:        out.dbp = out.db;
                    179:
                    180:        /* Position the input/output streams. */
                    181:        if (in.offset)
                    182:                pos_in();
                    183:        if (out.offset)
                    184:                pos_out();
                    185:
                    186:        /*
                    187:         * Truncate the output file; ignore errors because it fails on some
                    188:         * kinds of output files, tapes, for example.
                    189:         */
1.7       christos  190:        if ((ddflags & (C_OF | C_SEEK | C_NOTRUNC)) == (C_OF | C_SEEK))
1.1       glass     191:                (void)ftruncate(out.fd, (off_t)out.offset * out.dbsz);
                    192:
                    193:        /*
                    194:         * If converting case at the same time as another conversion, build a
                    195:         * table that does both at once.  If just converting case, use the
                    196:         * built-in tables.
                    197:         */
1.5       gwr       198:        if (ddflags & (C_LCASE|C_UCASE)) {
                    199: #ifdef NO_CONV
                    200:                /* Should not get here, but just in case... */
                    201:                errx(1, "case conv and -DNO_CONV");
                    202: #else  /* NO_CONV */
1.22      lukem     203:                u_int cnt;
                    204:
1.6       jtc       205:                if (ddflags & C_ASCII || ddflags & C_EBCDIC) {
1.1       glass     206:                        if (ddflags & C_LCASE) {
                    207:                                for (cnt = 0; cnt < 0377; ++cnt)
1.6       jtc       208:                                        casetab[cnt] = tolower(ctab[cnt]);
1.1       glass     209:                        } else {
                    210:                                for (cnt = 0; cnt < 0377; ++cnt)
1.6       jtc       211:                                        casetab[cnt] = toupper(ctab[cnt]);
1.1       glass     212:                        }
1.6       jtc       213:                } else {
1.1       glass     214:                        if (ddflags & C_LCASE) {
                    215:                                for (cnt = 0; cnt < 0377; ++cnt)
1.6       jtc       216:                                        casetab[cnt] = tolower(cnt);
1.1       glass     217:                        } else {
                    218:                                for (cnt = 0; cnt < 0377; ++cnt)
1.6       jtc       219:                                        casetab[cnt] = toupper(cnt);
1.1       glass     220:                        }
1.6       jtc       221:                }
                    222:
                    223:                ctab = casetab;
1.5       gwr       224: #endif /* NO_CONV */
                    225:        }
                    226:
1.20      ross      227:        (void)gettimeofday(&st.start, NULL);    /* Statistics timestamp. */
1.1       glass     228: }
                    229:
                    230: static void
1.21      lukem     231: getfdtype(IO *io)
1.3       mycroft   232: {
                    233:        struct mtget mt;
                    234:        struct stat sb;
                    235:
                    236:        if (fstat(io->fd, &sb))
                    237:                err(1, "%s", io->name);
                    238:        if (S_ISCHR(sb.st_mode))
                    239:                io->flags |= ioctl(io->fd, MTIOCGET, &mt) ? ISCHR : ISTAPE;
                    240:        else if (lseek(io->fd, (off_t)0, SEEK_CUR) == -1 && errno == ESPIPE)
                    241:                io->flags |= ISPIPE;            /* XXX fixed in 4.4BSD */
                    242: }
                    243:
                    244: static void
1.21      lukem     245: dd_in(void)
1.1       glass     246: {
1.23      lukem     247:        int flags;
1.24      lukem     248:        uint64_t n;
1.1       glass     249:
                    250:        for (flags = ddflags;;) {
                    251:                if (cpy_cnt && (st.in_full + st.in_part) >= cpy_cnt)
                    252:                        return;
                    253:
                    254:                /*
1.9       gwr       255:                 * Clear the buffer first if doing "sync" on input.
                    256:                 * If doing block operations use spaces.  This will
                    257:                 * affect not only the C_NOERROR case, but also the
                    258:                 * last partial input block which should be padded
                    259:                 * with zero and not garbage.
1.1       glass     260:                 */
1.12      thorpej   261:                if (flags & C_SYNC) {
1.1       glass     262:                        if (flags & (C_BLOCK|C_UNBLOCK))
1.10      mycroft   263:                                (void)memset(in.dbp, ' ', in.dbsz);
1.1       glass     264:                        else
1.10      mycroft   265:                                (void)memset(in.dbp, 0, in.dbsz);
1.12      thorpej   266:                }
1.1       glass     267:
                    268:                n = read(in.fd, in.dbp, in.dbsz);
                    269:                if (n == 0) {
                    270:                        in.dbrcnt = 0;
                    271:                        return;
                    272:                }
                    273:
                    274:                /* Read error. */
                    275:                if (n < 0) {
                    276:                        /*
                    277:                         * If noerror not specified, die.  POSIX requires that
                    278:                         * the warning message be followed by an I/O display.
                    279:                         */
                    280:                        if (!(flags & C_NOERROR))
1.3       mycroft   281:                                err(1, "%s", in.name);
                    282:                        warn("%s", in.name);
                    283:                        summary();
1.1       glass     284:
                    285:                        /*
                    286:                         * If it's not a tape drive or a pipe, seek past the
                    287:                         * error.  If your OS doesn't do the right thing for
                    288:                         * raw disks this section should be modified to re-read
                    289:                         * in sector size chunks.
                    290:                         */
                    291:                        if (!(in.flags & (ISPIPE|ISTAPE)) &&
                    292:                            lseek(in.fd, (off_t)in.dbsz, SEEK_CUR))
1.3       mycroft   293:                                warn("%s", in.name);
1.1       glass     294:
                    295:                        /* If sync not specified, omit block and continue. */
                    296:                        if (!(ddflags & C_SYNC))
                    297:                                continue;
                    298:
                    299:                        /* Read errors count as full blocks. */
                    300:                        in.dbcnt += in.dbrcnt = in.dbsz;
                    301:                        ++st.in_full;
                    302:
                    303:                /* Handle full input blocks. */
                    304:                } else if (n == in.dbsz) {
                    305:                        in.dbcnt += in.dbrcnt = n;
                    306:                        ++st.in_full;
                    307:
                    308:                /* Handle partial input blocks. */
                    309:                } else {
                    310:                        /* If sync, use the entire block. */
                    311:                        if (ddflags & C_SYNC)
                    312:                                in.dbcnt += in.dbrcnt = in.dbsz;
                    313:                        else
                    314:                                in.dbcnt += in.dbrcnt = n;
                    315:                        ++st.in_part;
                    316:                }
                    317:
                    318:                /*
                    319:                 * POSIX states that if bs is set and no other conversions
                    320:                 * than noerror, notrunc or sync are specified, the block
                    321:                 * is output without buffering as it is read.
                    322:                 */
                    323:                if (ddflags & C_BS) {
                    324:                        out.dbcnt = in.dbcnt;
                    325:                        dd_out(1);
                    326:                        in.dbcnt = 0;
                    327:                        continue;
                    328:                }
                    329:
                    330:                if (ddflags & C_SWAB) {
1.17      matt      331:                        if ((n = in.dbrcnt) & 1) {
1.1       glass     332:                                ++st.swab;
                    333:                                --n;
                    334:                        }
                    335:                        swab(in.dbp, in.dbp, n);
                    336:                }
                    337:
                    338:                in.dbp += in.dbrcnt;
                    339:                (*cfunc)();
                    340:        }
                    341: }
                    342:
                    343: /*
                    344:  * Cleanup any remaining I/O and flush output.  If necesssary, output file
                    345:  * is truncated.
                    346:  */
                    347: static void
1.21      lukem     348: dd_close(void)
1.1       glass     349: {
1.21      lukem     350:
1.1       glass     351:        if (cfunc == def)
                    352:                def_close();
                    353:        else if (cfunc == block)
                    354:                block_close();
                    355:        else if (cfunc == unblock)
                    356:                unblock_close();
1.3       mycroft   357:        if (ddflags & C_OSYNC && out.dbcnt < out.dbsz) {
1.10      mycroft   358:                (void)memset(out.dbp, 0, out.dbsz - out.dbcnt);
1.3       mycroft   359:                out.dbcnt = out.dbsz;
                    360:        }
1.1       glass     361:        if (out.dbcnt)
                    362:                dd_out(1);
                    363: }
                    364:
                    365: void
1.21      lukem     366: dd_out(int force)
1.1       glass     367: {
                    368:        static int warned;
1.24      lukem     369:        uint64_t cnt, n, nw;
1.3       mycroft   370:        u_char *outp;
1.1       glass     371:
                    372:        /*
                    373:         * Write one or more blocks out.  The common case is writing a full
                    374:         * output block in a single write; increment the full block stats.
                    375:         * Otherwise, we're into partial block writes.  If a partial write,
                    376:         * and it's a character device, just warn.  If a tape device, quit.
                    377:         *
                    378:         * The partial writes represent two cases.  1: Where the input block
                    379:         * was less than expected so the output block was less than expected.
                    380:         * 2: Where the input block was the right size but we were forced to
                    381:         * write the block in multiple chunks.  The original versions of dd(1)
                    382:         * never wrote a block in more than a single write, so the latter case
                    383:         * never happened.
                    384:         *
                    385:         * One special case is if we're forced to do the write -- in that case
                    386:         * we play games with the buffer size, and it's usually a partial write.
                    387:         */
                    388:        outp = out.db;
                    389:        for (n = force ? out.dbcnt : out.dbsz;; n = out.dbsz) {
                    390:                for (cnt = n;; cnt -= nw) {
1.15      christos  391:                        nw = bwrite(out.fd, outp, cnt);
1.3       mycroft   392:                        if (nw <= 0) {
                    393:                                if (nw == 0)
                    394:                                        errx(1, "%s: end of device", out.name);
                    395:                                if (errno != EINTR)
                    396:                                        err(1, "%s", out.name);
                    397:                                nw = 0;
                    398:                        }
1.1       glass     399:                        outp += nw;
                    400:                        st.bytes += nw;
                    401:                        if (nw == n) {
                    402:                                if (n != out.dbsz)
                    403:                                        ++st.out_part;
                    404:                                else
                    405:                                        ++st.out_full;
                    406:                                break;
                    407:                        }
                    408:                        ++st.out_part;
                    409:                        if (nw == cnt)
                    410:                                break;
                    411:                        if (out.flags & ISCHR && !warned) {
                    412:                                warned = 1;
1.3       mycroft   413:                                warnx("%s: short write on character device",
1.1       glass     414:                                    out.name);
                    415:                        }
                    416:                        if (out.flags & ISTAPE)
1.25    ! enami     417:                                errx(1, "%s: short write on tape device",
        !           418:                                    out.name);
1.1       glass     419:                }
                    420:                if ((out.dbcnt -= n) < out.dbsz)
                    421:                        break;
                    422:        }
                    423:
                    424:        /* Reassemble the output block. */
                    425:        if (out.dbcnt)
1.10      mycroft   426:                (void)memmove(out.db, out.dbp - out.dbcnt, out.dbcnt);
1.1       glass     427:        out.dbp = out.db + out.dbcnt;
1.13      hubertf   428:
                    429:        if (progress)
                    430:                (void)write(STDERR_FILENO, ".", 1);
1.15      christos  431: }
                    432:
                    433: /*
                    434:  * A protected against SIGINFO write
                    435:  */
                    436: ssize_t
1.21      lukem     437: bwrite(int fd, const void *buf, size_t len)
1.15      christos  438: {
                    439:        sigset_t oset;
                    440:        ssize_t rv;
                    441:        int oerrno;
                    442:
1.16      christos  443:        (void)sigprocmask(SIG_BLOCK, &infoset, &oset);
1.15      christos  444:        rv = write(fd, buf, len);
                    445:        oerrno = errno;
                    446:        (void)sigprocmask(SIG_SETMASK, &oset, NULL);
                    447:        errno = oerrno;
1.25    ! enami     448:        return (rv);
1.1       glass     449: }

CVSweb <webmaster@jp.NetBSD.org>