[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.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>