dd.c - sbase - suckless unix tools
 (HTM) git clone git://git.suckless.org/sbase
 (DIR) Log
 (DIR) Files
 (DIR) Refs
 (DIR) README
 (DIR) LICENSE
       ---
       dd.c (4895B)
       ---
            1 /* See LICENSE file for copyright and license details. */
            2 #include <ctype.h>
            3 #include <fcntl.h>
            4 #include <inttypes.h>
            5 #include <stdint.h>
            6 #include <string.h>
            7 #include <unistd.h>
            8 
            9 #include "util.h"
           10 
           11 static off_t ifull, ofull, ipart, opart;
           12 
           13 static void
           14 usage(void)
           15 {
           16         eprintf("usage: %s [operand...]\n", argv0);
           17 }
           18 
           19 static size_t
           20 parsesize(char *expr)
           21 {
           22         char *s = expr;
           23         size_t n = 1;
           24 
           25         for (;;) {
           26                 n *= strtoumax(s, &s, 10);
           27                 switch (*s) {
           28                 case 'k': n <<= 10; s++; break;
           29                 case 'b': n <<= 9; s++; break;
           30                 }
           31                 if (*s != 'x' || !s[1])
           32                         break;
           33                 s++;
           34         }
           35         if (*s || n == 0)
           36                 eprintf("invalid block size expression '%s'\n", expr);
           37 
           38         return n;
           39 }
           40 
           41 static void
           42 bswap(unsigned char *buf, size_t len)
           43 {
           44         int c;
           45 
           46         for (len &= ~1; len > 0; buf += 2, len -= 2) {
           47                 c = buf[0];
           48                 buf[0] = buf[1];
           49                 buf[1] = c;
           50         }
           51 }
           52 
           53 static void
           54 lcase(unsigned char *buf, size_t len)
           55 {
           56         for (; len > 0; buf++, len--)
           57                 buf[0] = tolower(buf[0]);
           58 }
           59 
           60 static void
           61 ucase(unsigned char *buf, size_t len)
           62 {
           63         for (; len > 0; buf++, len--)
           64                 buf[0] = toupper(buf[0]);
           65 }
           66 
           67 static void
           68 summary(void)
           69 {
           70         fprintf(stderr, "%"PRIdMAX"+%"PRIdMAX" records in\n", (intmax_t)ifull, (intmax_t)ipart);
           71         fprintf(stderr, "%"PRIdMAX"+%"PRIdMAX" records out\n", (intmax_t)ofull, (intmax_t)opart);
           72 }
           73 
           74 int
           75 main(int argc, char *argv[])
           76 {
           77         enum {
           78                 LCASE   = 1 << 0,
           79                 UCASE   = 1 << 1,
           80                 SWAB    = 1 << 2,
           81                 NOERROR = 1 << 3,
           82                 NOTRUNC = 1 << 4,
           83                 SYNC    = 1 << 5,
           84         } conv = 0;
           85         char *arg, *val, *end;
           86         const char *iname = "-", *oname = "-";
           87         int ifd = 0, ofd = 1, eof = 0;
           88         size_t len, bs = 0, ibs = 512, obs = 512, ipos = 0, opos = 0;
           89         off_t skip = 0, seek = 0, count = -1;
           90         ssize_t ret;
           91         unsigned char *buf;
           92 
           93         argv0 = argc ? (argc--, *argv++) : "dd";
           94         for (; argc > 0; argc--, argv++) {
           95                 arg = *argv;
           96                 val = strchr(arg, '=');
           97                 if (!val)
           98                         usage();
           99                 *val++ = '\0';
          100                 if (strcmp(arg, "if") == 0) {
          101                         iname = val;
          102                 } else if (strcmp(arg, "of") == 0) {
          103                         oname = val;
          104                 } else if (strcmp(arg, "ibs") == 0) {
          105                         ibs = parsesize(val);
          106                 } else if (strcmp(arg, "obs") == 0) {
          107                         obs = parsesize(val);
          108                 } else if (strcmp(arg, "bs") == 0) {
          109                         bs = parsesize(val);
          110                 } else if (strcmp(arg, "skip") == 0) {
          111                         skip = estrtonum(val, 0, LLONG_MAX);
          112                 } else if (strcmp(arg, "seek") == 0) {
          113                         seek = estrtonum(val, 0, LLONG_MAX);
          114                 } else if (strcmp(arg, "count") == 0) {
          115                         count = estrtonum(val, 0, LLONG_MAX);
          116                 } else if (strcmp(arg, "conv") == 0) {
          117                         do {
          118                                 end = strchr(val, ',');
          119                                 if (end)
          120                                         *end++ = '\0';
          121                                 if (strcmp(val, "lcase") == 0)
          122                                         conv |= LCASE;
          123                                 else if (strcmp(val, "ucase") == 0)
          124                                         conv |= UCASE;
          125                                 else if (strcmp(val, "swab") == 0)
          126                                         conv |= SWAB;
          127                                 else if (strcmp(val, "noerror") == 0)
          128                                         conv |= NOERROR;
          129                                 else if (strcmp(val, "notrunc") == 0)
          130                                         conv |= NOTRUNC;
          131                                 else if (strcmp(val, "sync") == 0)
          132                                         conv |= SYNC;
          133                                 else
          134                                         eprintf("unknown conv flag '%s'\n", val);
          135                                 val = end;
          136                         } while (val);
          137                 } else {
          138                         weprintf("unknown operand '%s'\n", arg);
          139                         usage();
          140                 }
          141         }
          142 
          143         if (bs)
          144                 ibs = obs = bs;
          145         if (strcmp(iname, "-") != 0) {
          146                 ifd = open(iname, O_RDONLY);
          147                 if (ifd < 0)
          148                         eprintf("open %s:", iname);
          149         }
          150         if (strcmp(oname, "-") != 0) {
          151                 ofd = open(oname, O_WRONLY | O_CREAT | (conv & NOTRUNC || seek ? 0 : O_TRUNC), 0666);
          152                 if (ofd < 0)
          153                         eprintf("open %s:", oname);
          154         }
          155 
          156         len = MAX(ibs, obs) + ibs;
          157         buf = emalloc(len);
          158         if (skip && lseek(ifd, skip * ibs, SEEK_SET) < 0) {
          159                 while (skip--) {
          160                         ret = read(ifd, buf, ibs);
          161                         if (ret < 0)
          162                                 eprintf("read:");
          163                         if (ret == 0) {
          164                                 eof = 1;
          165                                 break;
          166                         }
          167                 }
          168         }
          169         if (seek) {
          170                 if (!(conv & NOTRUNC) && ftruncate(ofd, seek * ibs) != 0)
          171                         eprintf("ftruncate:");
          172                 if (lseek(ofd, seek * ibs, SEEK_SET) < 0)
          173                         eprintf("lseek:");
          174                 /* XXX: handle non-seekable files */
          175         }
          176         while (!eof) {
          177                 while (ipos - opos < obs) {
          178                         if (ifull + ipart == count) {
          179                                 eof = 1;
          180                                 break;
          181                         }
          182                         ret = read(ifd, buf + ipos, ibs);
          183                         if (ret == 0) {
          184                                 eof = 1;
          185                                 break;
          186                         }
          187                         if (ret < 0) {
          188                                 weprintf("read:");
          189                                 if (!(conv & NOERROR))
          190                                         return 1;
          191                                 summary();
          192                                 if (!(conv & SYNC))
          193                                         continue;
          194                                 ret = 0;
          195                         }
          196                         if (ret < ibs) {
          197                                 ipart++;
          198                                 if (conv & SYNC) {
          199                                         memset(buf + ipos + ret, 0, ibs - ret);
          200                                         ret = ibs;
          201                                 }
          202                         } else {
          203                                 ifull++;
          204                         }
          205                         if (conv & SWAB)
          206                                 bswap(buf + ipos, ret);
          207                         if (conv & LCASE)
          208                                 lcase(buf + ipos, ret);
          209                         if (conv & UCASE)
          210                                 ucase(buf + ipos, ret);
          211                         ipos += ret;
          212                         if (bs && !(conv & (SWAB | LCASE | UCASE)))
          213                                 break;
          214                 }
          215                 if (ipos == opos)
          216                         break;
          217                 do {
          218                         ret = write(ofd, buf + opos, MIN(obs, ipos - opos));
          219                         if (ret < 0)
          220                                 eprintf("write:");
          221                         if (ret == 0)
          222                                 eprintf("write returned 0\n");
          223                         if (ret < obs)
          224                                 opart++;
          225                         else
          226                                 ofull++;
          227                         opos += ret;
          228                 } while (ipos - opos >= (eof ? 1 : obs));
          229                 if (opos < ipos)
          230                         memmove(buf, buf + opos, ipos - opos);
          231                 ipos -= opos;
          232                 opos = 0;
          233         }
          234         summary();
          235 
          236         return 0;
          237 }