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

1.9     ! gwr         1: /*     $NetBSD: dd.c,v 1.8 1998/04/01 13:55:23 kleink 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.9     ! gwr        50: __RCSID("$NetBSD: dd.c,v 1.8 1998/04/01 13:55:23 kleink 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>
                     58:
                     59: #include <ctype.h>
1.3       mycroft    60: #include <err.h>
1.1       glass      61: #include <errno.h>
                     62: #include <fcntl.h>
                     63: #include <signal.h>
                     64: #include <stdio.h>
                     65: #include <stdlib.h>
                     66: #include <string.h>
1.8       kleink     67: #include <time.h>
1.1       glass      68: #include <unistd.h>
                     69:
                     70: #include "dd.h"
                     71: #include "extern.h"
                     72:
                     73: static void dd_close __P((void));
                     74: static void dd_in __P((void));
1.3       mycroft    75: static void getfdtype __P((IO *));
1.1       glass      76: static void setup __P((void));
                     77:
1.7       christos   78: int main __P((int, char *[]));
                     79:
1.1       glass      80: IO     in, out;                /* input/output state */
                     81: STAT   st;                     /* statistics */
                     82: void   (*cfunc) __P((void));   /* conversion function */
                     83: u_long cpy_cnt;                /* # of blocks to copy */
                     84: u_int  ddflags;                /* conversion options */
                     85: u_int  cbsz;                   /* conversion block size */
                     86: u_int  files_cnt = 1;          /* # of files to copy */
1.6       jtc        87: const u_char   *ctab;          /* conversion table */
1.1       glass      88:
                     89: int
                     90: main(argc, argv)
                     91:        int argc;
                     92:        char *argv[];
                     93: {
                     94:        jcl(argv);
                     95:        setup();
                     96:
1.3       mycroft    97:        (void)signal(SIGINFO, summaryx);
1.1       glass      98:        (void)signal(SIGINT, terminate);
                     99:
1.3       mycroft   100:        atexit(summary);
                    101:
                    102:        while (files_cnt--)
1.1       glass     103:                dd_in();
                    104:
                    105:        dd_close();
                    106:        exit(0);
                    107: }
                    108:
                    109: static void
                    110: setup()
                    111: {
1.3       mycroft   112:        u_int cnt;
1.1       glass     113:
                    114:        if (in.name == NULL) {
                    115:                in.name = "stdin";
                    116:                in.fd = STDIN_FILENO;
                    117:        } else {
                    118:                in.fd = open(in.name, O_RDONLY, 0);
                    119:                if (in.fd < 0)
1.3       mycroft   120:                        err(1, "%s", in.name);
1.1       glass     121:        }
                    122:
1.3       mycroft   123:        getfdtype(&in);
1.1       glass     124:
                    125:        if (files_cnt > 1 && !(in.flags & ISTAPE))
1.3       mycroft   126:                errx(1, "files is not supported for non-tape devices");
1.1       glass     127:
                    128:        if (out.name == NULL) {
                    129:                /* No way to check for read access here. */
                    130:                out.fd = STDOUT_FILENO;
                    131:                out.name = "stdout";
                    132:        } else {
                    133: #define        OFLAGS \
                    134:     (O_CREAT | (ddflags & (C_SEEK | C_NOTRUNC) ? 0 : O_TRUNC))
                    135:                out.fd = open(out.name, O_RDWR | OFLAGS, DEFFILEMODE);
                    136:                /*
                    137:                 * May not have read access, so try again with write only.
                    138:                 * Without read we may have a problem if output also does
                    139:                 * not support seeks.
                    140:                 */
                    141:                if (out.fd < 0) {
                    142:                        out.fd = open(out.name, O_WRONLY | OFLAGS, DEFFILEMODE);
                    143:                        out.flags |= NOREAD;
                    144:                }
                    145:                if (out.fd < 0)
1.3       mycroft   146:                        err(1, "%s", out.name);
1.1       glass     147:        }
                    148:
1.3       mycroft   149:        getfdtype(&out);
1.1       glass     150:
                    151:        /*
                    152:         * Allocate space for the input and output buffers.  If not doing
                    153:         * record oriented I/O, only need a single buffer.
                    154:         */
                    155:        if (!(ddflags & (C_BLOCK|C_UNBLOCK))) {
                    156:                if ((in.db = malloc(out.dbsz + in.dbsz - 1)) == NULL)
1.7       christos  157:                        err(1, "%s", "");
1.1       glass     158:                out.db = in.db;
                    159:        } else if ((in.db =
                    160:            malloc((u_int)(MAX(in.dbsz, cbsz) + cbsz))) == NULL ||
                    161:            (out.db = malloc((u_int)(out.dbsz + cbsz))) == NULL)
1.7       christos  162:                err(1, "%s", "");
1.1       glass     163:        in.dbp = in.db;
                    164:        out.dbp = out.db;
                    165:
                    166:        /* Position the input/output streams. */
                    167:        if (in.offset)
                    168:                pos_in();
                    169:        if (out.offset)
                    170:                pos_out();
                    171:
                    172:        /*
                    173:         * Truncate the output file; ignore errors because it fails on some
                    174:         * kinds of output files, tapes, for example.
                    175:         */
1.7       christos  176:        if ((ddflags & (C_OF | C_SEEK | C_NOTRUNC)) == (C_OF | C_SEEK))
1.1       glass     177:                (void)ftruncate(out.fd, (off_t)out.offset * out.dbsz);
                    178:
                    179:        /*
                    180:         * If converting case at the same time as another conversion, build a
                    181:         * table that does both at once.  If just converting case, use the
                    182:         * built-in tables.
                    183:         */
1.5       gwr       184:        if (ddflags & (C_LCASE|C_UCASE)) {
                    185: #ifdef NO_CONV
                    186:                /* Should not get here, but just in case... */
                    187:                errx(1, "case conv and -DNO_CONV");
                    188: #else  /* NO_CONV */
1.6       jtc       189:                if (ddflags & C_ASCII || ddflags & C_EBCDIC) {
1.1       glass     190:                        if (ddflags & C_LCASE) {
                    191:                                for (cnt = 0; cnt < 0377; ++cnt)
1.6       jtc       192:                                        casetab[cnt] = tolower(ctab[cnt]);
1.1       glass     193:                        } else {
                    194:                                for (cnt = 0; cnt < 0377; ++cnt)
1.6       jtc       195:                                        casetab[cnt] = toupper(ctab[cnt]);
1.1       glass     196:                        }
1.6       jtc       197:                } else {
1.1       glass     198:                        if (ddflags & C_LCASE) {
                    199:                                for (cnt = 0; cnt < 0377; ++cnt)
1.6       jtc       200:                                        casetab[cnt] = tolower(cnt);
1.1       glass     201:                        } else {
                    202:                                for (cnt = 0; cnt < 0377; ++cnt)
1.6       jtc       203:                                        casetab[cnt] = toupper(cnt);
1.1       glass     204:                        }
1.6       jtc       205:                }
                    206:
                    207:                ctab = casetab;
1.5       gwr       208: #endif /* NO_CONV */
                    209:        }
                    210:
1.1       glass     211:        (void)time(&st.start);                  /* Statistics timestamp. */
                    212: }
                    213:
                    214: static void
1.3       mycroft   215: getfdtype(io)
                    216:        IO *io;
                    217: {
                    218:        struct mtget mt;
                    219:        struct stat sb;
                    220:
                    221:        if (fstat(io->fd, &sb))
                    222:                err(1, "%s", io->name);
                    223:        if (S_ISCHR(sb.st_mode))
                    224:                io->flags |= ioctl(io->fd, MTIOCGET, &mt) ? ISCHR : ISTAPE;
                    225:        else if (lseek(io->fd, (off_t)0, SEEK_CUR) == -1 && errno == ESPIPE)
                    226:                io->flags |= ISPIPE;            /* XXX fixed in 4.4BSD */
                    227: }
                    228:
                    229: static void
1.1       glass     230: dd_in()
                    231: {
1.3       mycroft   232:        int flags, n;
1.1       glass     233:
                    234:        for (flags = ddflags;;) {
                    235:                if (cpy_cnt && (st.in_full + st.in_part) >= cpy_cnt)
                    236:                        return;
                    237:
                    238:                /*
1.9     ! gwr       239:                 * Clear the buffer first if doing "sync" on input.
        !           240:                 * If doing block operations use spaces.  This will
        !           241:                 * affect not only the C_NOERROR case, but also the
        !           242:                 * last partial input block which should be padded
        !           243:                 * with zero and not garbage.
1.1       glass     244:                 */
1.9     ! gwr       245:                if (flags & C_SYNC)
1.1       glass     246:                        if (flags & (C_BLOCK|C_UNBLOCK))
                    247:                                memset(in.dbp, ' ', in.dbsz);
                    248:                        else
                    249:                                memset(in.dbp, 0, in.dbsz);
                    250:
                    251:                n = read(in.fd, in.dbp, in.dbsz);
                    252:                if (n == 0) {
                    253:                        in.dbrcnt = 0;
                    254:                        return;
                    255:                }
                    256:
                    257:                /* Read error. */
                    258:                if (n < 0) {
                    259:                        /*
                    260:                         * If noerror not specified, die.  POSIX requires that
                    261:                         * the warning message be followed by an I/O display.
                    262:                         */
                    263:                        if (!(flags & C_NOERROR))
1.3       mycroft   264:                                err(1, "%s", in.name);
                    265:                        warn("%s", in.name);
                    266:                        summary();
1.1       glass     267:
                    268:                        /*
                    269:                         * If it's not a tape drive or a pipe, seek past the
                    270:                         * error.  If your OS doesn't do the right thing for
                    271:                         * raw disks this section should be modified to re-read
                    272:                         * in sector size chunks.
                    273:                         */
                    274:                        if (!(in.flags & (ISPIPE|ISTAPE)) &&
                    275:                            lseek(in.fd, (off_t)in.dbsz, SEEK_CUR))
1.3       mycroft   276:                                warn("%s", in.name);
1.1       glass     277:
                    278:                        /* If sync not specified, omit block and continue. */
                    279:                        if (!(ddflags & C_SYNC))
                    280:                                continue;
                    281:
                    282:                        /* Read errors count as full blocks. */
                    283:                        in.dbcnt += in.dbrcnt = in.dbsz;
                    284:                        ++st.in_full;
                    285:
                    286:                /* Handle full input blocks. */
                    287:                } else if (n == in.dbsz) {
                    288:                        in.dbcnt += in.dbrcnt = n;
                    289:                        ++st.in_full;
                    290:
                    291:                /* Handle partial input blocks. */
                    292:                } else {
                    293:                        /* If sync, use the entire block. */
                    294:                        if (ddflags & C_SYNC)
                    295:                                in.dbcnt += in.dbrcnt = in.dbsz;
                    296:                        else
                    297:                                in.dbcnt += in.dbrcnt = n;
                    298:                        ++st.in_part;
                    299:                }
                    300:
                    301:                /*
                    302:                 * POSIX states that if bs is set and no other conversions
                    303:                 * than noerror, notrunc or sync are specified, the block
                    304:                 * is output without buffering as it is read.
                    305:                 */
                    306:                if (ddflags & C_BS) {
                    307:                        out.dbcnt = in.dbcnt;
                    308:                        dd_out(1);
                    309:                        in.dbcnt = 0;
                    310:                        continue;
                    311:                }
                    312:
                    313:                if (ddflags & C_SWAB) {
                    314:                        if ((n = in.dbcnt) & 1) {
                    315:                                ++st.swab;
                    316:                                --n;
                    317:                        }
                    318:                        swab(in.dbp, in.dbp, n);
                    319:                }
                    320:
                    321:                in.dbp += in.dbrcnt;
                    322:                (*cfunc)();
                    323:        }
                    324: }
                    325:
                    326: /*
                    327:  * Cleanup any remaining I/O and flush output.  If necesssary, output file
                    328:  * is truncated.
                    329:  */
                    330: static void
                    331: dd_close()
                    332: {
                    333:        if (cfunc == def)
                    334:                def_close();
                    335:        else if (cfunc == block)
                    336:                block_close();
                    337:        else if (cfunc == unblock)
                    338:                unblock_close();
1.3       mycroft   339:        if (ddflags & C_OSYNC && out.dbcnt < out.dbsz) {
                    340:                memset(out.dbp, 0, out.dbsz - out.dbcnt);
                    341:                out.dbcnt = out.dbsz;
                    342:        }
1.1       glass     343:        if (out.dbcnt)
                    344:                dd_out(1);
                    345: }
                    346:
                    347: void
                    348: dd_out(force)
                    349:        int force;
                    350: {
                    351:        static int warned;
1.3       mycroft   352:        int cnt, n, nw;
                    353:        u_char *outp;
1.1       glass     354:
                    355:        /*
                    356:         * Write one or more blocks out.  The common case is writing a full
                    357:         * output block in a single write; increment the full block stats.
                    358:         * Otherwise, we're into partial block writes.  If a partial write,
                    359:         * and it's a character device, just warn.  If a tape device, quit.
                    360:         *
                    361:         * The partial writes represent two cases.  1: Where the input block
                    362:         * was less than expected so the output block was less than expected.
                    363:         * 2: Where the input block was the right size but we were forced to
                    364:         * write the block in multiple chunks.  The original versions of dd(1)
                    365:         * never wrote a block in more than a single write, so the latter case
                    366:         * never happened.
                    367:         *
                    368:         * One special case is if we're forced to do the write -- in that case
                    369:         * we play games with the buffer size, and it's usually a partial write.
                    370:         */
                    371:        outp = out.db;
                    372:        for (n = force ? out.dbcnt : out.dbsz;; n = out.dbsz) {
                    373:                for (cnt = n;; cnt -= nw) {
                    374:                        nw = write(out.fd, outp, cnt);
1.3       mycroft   375:                        if (nw <= 0) {
                    376:                                if (nw == 0)
                    377:                                        errx(1, "%s: end of device", out.name);
                    378:                                if (errno != EINTR)
                    379:                                        err(1, "%s", out.name);
                    380:                                nw = 0;
                    381:                        }
1.1       glass     382:                        outp += nw;
                    383:                        st.bytes += nw;
                    384:                        if (nw == n) {
                    385:                                if (n != out.dbsz)
                    386:                                        ++st.out_part;
                    387:                                else
                    388:                                        ++st.out_full;
                    389:                                break;
                    390:                        }
                    391:                        ++st.out_part;
                    392:                        if (nw == cnt)
                    393:                                break;
                    394:                        if (out.flags & ISCHR && !warned) {
                    395:                                warned = 1;
1.3       mycroft   396:                                warnx("%s: short write on character device",
1.1       glass     397:                                    out.name);
                    398:                        }
                    399:                        if (out.flags & ISTAPE)
1.3       mycroft   400:                                errx(1, "%s: short write on tape device", out.name);
1.1       glass     401:                }
                    402:                if ((out.dbcnt -= n) < out.dbsz)
                    403:                        break;
                    404:        }
                    405:
                    406:        /* Reassemble the output block. */
                    407:        if (out.dbcnt)
                    408:                memmove(out.db, out.dbp - out.dbcnt, out.dbcnt);
                    409:        out.dbp = out.db + out.dbcnt;
                    410: }

CVSweb <webmaster@jp.NetBSD.org>