home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Source Code 1993 July / THE_SOURCE_CODE_CD_ROM.iso / bsd_srcs / bin / dd / dd.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-04-28  |  10.3 KB  |  382 lines

  1. /*-
  2.  * Copyright (c) 1991 The Regents of the University of California.
  3.  * All rights reserved.
  4.  *
  5.  * This code is derived from software contributed to Berkeley by
  6.  * Keith Muller of the University of California, San Diego and Lance
  7.  * Visser of Convex Computer Corporation.
  8.  *
  9.  * Redistribution and use in source and binary forms, with or without
  10.  * modification, are permitted provided that the following conditions
  11.  * are met:
  12.  * 1. Redistributions of source code must retain the above copyright
  13.  *    notice, this list of conditions and the following disclaimer.
  14.  * 2. Redistributions in binary form must reproduce the above copyright
  15.  *    notice, this list of conditions and the following disclaimer in the
  16.  *    documentation and/or other materials provided with the distribution.
  17.  * 3. All advertising materials mentioning features or use of this software
  18.  *    must display the following acknowledgement:
  19.  *    This product includes software developed by the University of
  20.  *    California, Berkeley and its contributors.
  21.  * 4. Neither the name of the University nor the names of its contributors
  22.  *    may be used to endorse or promote products derived from this software
  23.  *    without specific prior written permission.
  24.  *
  25.  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  26.  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  27.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  28.  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  29.  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  30.  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  31.  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  32.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  33.  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  34.  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  35.  * SUCH DAMAGE.
  36.  */
  37.  
  38. #ifndef lint
  39. char copyright[] =
  40. "@(#) Copyright (c) 1991 The Regents of the University of California.\n\
  41.  All rights reserved.\n";
  42. #endif /* not lint */
  43.  
  44. #ifndef lint
  45. static char sccsid[] = "@(#)dd.c    5.16 (Berkeley) 4/28/93";
  46. #endif /* not lint */
  47.  
  48. #include <sys/param.h>
  49. #include <sys/stat.h>
  50. #include <sys/ioctl.h>
  51. #include <sys/mtio.h>
  52.  
  53. #include <ctype.h>
  54. #include <errno.h>
  55. #include <fcntl.h>
  56. #include <signal.h>
  57. #include <stdio.h>
  58. #include <stdlib.h>
  59. #include <string.h>
  60. #include <unistd.h>
  61.  
  62. #include "dd.h"
  63. #include "extern.h"
  64.  
  65. static void dd_close __P((void));
  66. static void dd_in __P((void));
  67. static void setup __P((void));
  68.  
  69. IO    in, out;        /* input/output state */
  70. STAT    st;            /* statistics */
  71. void    (*cfunc) __P((void));    /* conversion function */
  72. u_long    cpy_cnt;        /* # of blocks to copy */
  73. u_int    ddflags;        /* conversion options */
  74. u_int    cbsz;            /* conversion block size */
  75. u_int    files_cnt = 1;        /* # of files to copy */
  76. int    errstats;        /* show statistics on error */
  77. u_char    *ctab;            /* conversion table */
  78.  
  79. int
  80. main(argc, argv)
  81.     int argc;
  82.     char *argv[];
  83. {
  84.     jcl(argv);
  85.     setup();
  86.  
  87.     (void)signal(SIGINFO, summary);
  88.     (void)signal(SIGINT, terminate);
  89.  
  90.     for (errstats = 1; files_cnt--;)
  91.         dd_in();
  92.  
  93.     dd_close();
  94.     summary(0);
  95.     exit(0);
  96. }
  97.  
  98. static void
  99. setup()
  100. {
  101.     register u_int cnt;
  102.     struct stat sb;
  103.     struct mtget mt;
  104.  
  105.     if (in.name == NULL) {
  106.         in.name = "stdin";
  107.         in.fd = STDIN_FILENO;
  108.     } else {
  109.         in.fd = open(in.name, O_RDONLY, 0);
  110.         if (in.fd < 0)
  111.             err("%s: %s", in.name, strerror(errno));
  112.     }
  113.  
  114.     if (fstat(in.fd, &sb))
  115.         err("%s: %s", in.name, strerror(errno));
  116.     if (S_ISCHR(sb.st_mode))
  117.         in.flags |= ioctl(in.fd, MTIOCGET, &mt) ? ISCHR : ISTAPE;
  118.     else if (lseek(in.fd, (off_t)0, SEEK_CUR) == -1 && errno == ESPIPE)
  119.         in.flags |= ISPIPE;        /* XXX fixed in 4.4BSD */
  120.  
  121.     if (files_cnt > 1 && !(in.flags & ISTAPE))
  122.         err("files is not supported for non-tape devices");
  123.  
  124.     if (out.name == NULL) {
  125.         /* No way to check for read access here. */
  126.         out.fd = STDOUT_FILENO;
  127.         out.name = "stdout";
  128.     } else {
  129. #define    OFLAGS \
  130.     (O_CREAT | (ddflags & (C_SEEK | C_NOTRUNC) ? 0 : O_TRUNC))
  131.         out.fd = open(out.name, O_RDWR | OFLAGS, DEFFILEMODE);
  132.         /*
  133.          * May not have read access, so try again with write only.
  134.          * Without read we may have a problem if output also does
  135.          * not support seeks.
  136.          */
  137.         if (out.fd < 0) {
  138.             out.fd = open(out.name, O_WRONLY | OFLAGS, DEFFILEMODE);
  139.             out.flags |= NOREAD;
  140.         }
  141.         if (out.fd < 0)
  142.             err("%s: %s", out.name, strerror(errno));
  143.     }
  144.  
  145.     if (fstat(out.fd, &sb))
  146.         err("%s: %s", out.name, strerror(errno));
  147.     if (S_ISCHR(sb.st_mode))
  148.         out.flags |= ioctl(out.fd, MTIOCGET, &mt) ? ISCHR : ISTAPE;
  149.     else if (lseek(out.fd, (off_t)0, SEEK_CUR) == -1 && errno == ESPIPE)
  150.         out.flags |= ISPIPE;        /* XXX fixed in 4.4BSD */
  151.  
  152.     /*
  153.      * Allocate space for the input and output buffers.  If not doing
  154.      * record oriented I/O, only need a single buffer.
  155.      */
  156.     if (!(ddflags & (C_BLOCK|C_UNBLOCK))) {
  157.         if ((in.db = malloc(out.dbsz + in.dbsz - 1)) == NULL)
  158.             err("%s", strerror(errno));
  159.         out.db = in.db;
  160.     } else if ((in.db =
  161.         malloc((u_int)(MAX(in.dbsz, cbsz) + cbsz))) == NULL ||
  162.         (out.db = malloc((u_int)(out.dbsz + cbsz))) == NULL)
  163.         err("%s", strerror(errno));
  164.     in.dbp = in.db;
  165.     out.dbp = out.db;
  166.  
  167.     /* Position the input/output streams. */
  168.     if (in.offset)
  169.         pos_in();
  170.     if (out.offset)
  171.         pos_out();
  172.  
  173.     /*
  174.      * Truncate the output file; ignore errors because it fails on some
  175.      * kinds of output files, tapes, for example.
  176.      */
  177.     if (ddflags & (C_OF | C_SEEK | C_NOTRUNC) == (C_OF | C_SEEK))
  178.         (void)ftruncate(out.fd, (off_t)out.offset * out.dbsz);
  179.  
  180.     /*
  181.      * If converting case at the same time as another conversion, build a
  182.      * table that does both at once.  If just converting case, use the
  183.      * built-in tables.
  184.      */
  185.     if (ddflags & (C_LCASE|C_UCASE))
  186.         if (ddflags & C_ASCII)
  187.             if (ddflags & C_LCASE) {
  188.                 for (cnt = 0; cnt < 0377; ++cnt)
  189.                     if (isupper(ctab[cnt]))
  190.                         ctab[cnt] = tolower(ctab[cnt]);
  191.             } else {
  192.                 for (cnt = 0; cnt < 0377; ++cnt)
  193.                     if (islower(ctab[cnt]))
  194.                         ctab[cnt] = toupper(ctab[cnt]);
  195.             }
  196.         else if (ddflags & C_EBCDIC)
  197.             if (ddflags & C_LCASE) {
  198.                 for (cnt = 0; cnt < 0377; ++cnt)
  199.                     if (isupper(cnt))
  200.                         ctab[cnt] = ctab[tolower(cnt)];
  201.             } else {
  202.                 for (cnt = 0; cnt < 0377; ++cnt)
  203.                     if (islower(cnt))
  204.                         ctab[cnt] = ctab[toupper(cnt)];
  205.             }
  206.         else
  207.             ctab = ddflags & C_LCASE ? u2l : l2u;
  208.     (void)time(&st.start);            /* Statistics timestamp. */
  209. }
  210.  
  211. static void
  212. dd_in()
  213. {
  214.     register int flags, n;
  215.  
  216.     for (flags = ddflags;;) {
  217.         if (cpy_cnt && (st.in_full + st.in_part) >= cpy_cnt)
  218.             return;
  219.  
  220.         /*
  221.          * Zero the buffer first if trying to recover from errors so
  222.          * lose the minimum amount of data.  If doing block operations
  223.          * use spaces.
  224.          */
  225.         if (flags & (C_NOERROR|C_SYNC))
  226.             if (flags & (C_BLOCK|C_UNBLOCK))
  227.                 memset(in.dbp, ' ', in.dbsz);
  228.             else
  229.                 memset(in.dbp, 0, in.dbsz);
  230.  
  231.         n = read(in.fd, in.dbp, in.dbsz);
  232.         if (n == 0) {
  233.             in.dbrcnt = 0;
  234.             return;
  235.         }
  236.  
  237.         /* Read error. */
  238.         if (n < 0) {
  239.             /*
  240.              * If noerror not specified, die.  POSIX requires that
  241.              * the warning message be followed by an I/O display.
  242.              */
  243.             if (!(flags & C_NOERROR))
  244.                 err("%s: %s", in.name, strerror(errno));
  245.             warn("%s: %s", in.name, strerror(errno));
  246.             summary(0);
  247.  
  248.             /*
  249.              * If it's not a tape drive or a pipe, seek past the
  250.              * error.  If your OS doesn't do the right thing for
  251.              * raw disks this section should be modified to re-read
  252.              * in sector size chunks.
  253.              */
  254.             if (!(in.flags & (ISPIPE|ISTAPE)) &&
  255.                 lseek(in.fd, (off_t)in.dbsz, SEEK_CUR))
  256.                 warn("%s: %s", in.name, strerror(errno));
  257.  
  258.             /* If sync not specified, omit block and continue. */
  259.             if (!(ddflags & C_SYNC))
  260.                 continue;
  261.  
  262.             /* Read errors count as full blocks. */
  263.             in.dbcnt += in.dbrcnt = in.dbsz;
  264.             ++st.in_full;
  265.  
  266.         /* Handle full input blocks. */
  267.         } else if (n == in.dbsz) {
  268.             in.dbcnt += in.dbrcnt = n;
  269.             ++st.in_full;
  270.  
  271.         /* Handle partial input blocks. */
  272.         } else {
  273.             /* If sync, use the entire block. */
  274.             if (ddflags & C_SYNC)
  275.                 in.dbcnt += in.dbrcnt = in.dbsz;
  276.             else
  277.                 in.dbcnt += in.dbrcnt = n;
  278.             ++st.in_part;
  279.         }
  280.  
  281.         /*
  282.          * POSIX states that if bs is set and no other conversions
  283.          * than noerror, notrunc or sync are specified, the block
  284.          * is output without buffering as it is read.
  285.          */
  286.         if (ddflags & C_BS) {
  287.             out.dbcnt = in.dbcnt;
  288.             dd_out(1);
  289.             in.dbcnt = 0;
  290.             continue;
  291.         }
  292.  
  293.         if (ddflags & C_SWAB) {
  294.             if ((n = in.dbcnt) & 1) {
  295.                 ++st.swab;
  296.                 --n;
  297.             }
  298.             swab(in.dbp, in.dbp, n);
  299.         }
  300.  
  301.         in.dbp += in.dbrcnt;
  302.         (*cfunc)();
  303.     }
  304. }
  305.  
  306. /*
  307.  * Cleanup any remaining I/O and flush output.  If necesssary, output file
  308.  * is truncated.
  309.  */
  310. static void
  311. dd_close()
  312. {
  313.     if (cfunc == def)
  314.         def_close();
  315.     else if (cfunc == block)
  316.         block_close();
  317.     else if (cfunc == unblock)
  318.         unblock_close();
  319.     if (out.dbcnt)
  320.         dd_out(1);
  321. }
  322.  
  323. void
  324. dd_out(force)
  325.     int force;
  326. {
  327.     static int warned;
  328.     register int cnt, n, nw;
  329.     register u_char *outp;
  330.  
  331.     /*
  332.      * Write one or more blocks out.  The common case is writing a full
  333.      * output block in a single write; increment the full block stats.
  334.      * Otherwise, we're into partial block writes.  If a partial write,
  335.      * and it's a character device, just warn.  If a tape device, quit.
  336.      *
  337.      * The partial writes represent two cases.  1: Where the input block
  338.      * was less than expected so the output block was less than expected.
  339.      * 2: Where the input block was the right size but we were forced to
  340.      * write the block in multiple chunks.  The original versions of dd(1)
  341.      * never wrote a block in more than a single write, so the latter case
  342.      * never happened.
  343.      *
  344.      * One special case is if we're forced to do the write -- in that case
  345.      * we play games with the buffer size, and it's usually a partial write.
  346.      */
  347.     outp = out.db;
  348.     for (n = force ? out.dbcnt : out.dbsz;; n = out.dbsz) {
  349.         for (cnt = n;; cnt -= nw) {
  350.             nw = write(out.fd, outp, cnt);
  351.             if (nw < 0)
  352.                 err("%s: %s", out.name, strerror(errno));
  353.             outp += nw;
  354.             st.bytes += nw;
  355.             if (nw == n) {
  356.                 if (n != out.dbsz)
  357.                     ++st.out_part;
  358.                 else
  359.                     ++st.out_full;
  360.                 break;
  361.             }
  362.             ++st.out_part;
  363.             if (nw == cnt)
  364.                 break;
  365.             if (out.flags & ISCHR && !warned) {
  366.                 warned = 1;
  367.                 warn("%s: short write on character device",
  368.                     out.name);
  369.             }
  370.             if (out.flags & ISTAPE)
  371.                 err("%s: short write on tape device", out.name);
  372.         }
  373.         if ((out.dbcnt -= n) < out.dbsz)
  374.             break;
  375.     }
  376.  
  377.     /* Reassemble the output block. */
  378.     if (out.dbcnt)
  379.         memmove(out.db, out.dbp - out.dbcnt, out.dbcnt);
  380.     out.dbp = out.db + out.dbcnt;
  381. }
  382.