From 74193471881b86f743cd33014236c54fe2cc4a2b Mon Sep 17 00:00:00 2001 From: Rob Landley Date: Sun, 21 Aug 2016 23:45:19 -0500 Subject: A round of dd cleanup. --- toys/pending/dd.c | 149 +++++++++++++++++++++--------------------------------- 1 file changed, 58 insertions(+), 91 deletions(-) diff --git a/toys/pending/dd.c b/toys/pending/dd.c index c3e51cfa..0bb48494 100644 --- a/toys/pending/dd.c +++ b/toys/pending/dd.c @@ -4,6 +4,8 @@ * Copyright 2013 Kyungwan Han * * See http://opengroup.org/onlinepubs/9699919799/utilities/dd.html + * + * todo: ctrl-c doesn't work, the read() is restarting. USE_DD(NEWTOY(dd, NULL, TOYFLAG_USR|TOYFLAG_BIN)) @@ -51,20 +53,10 @@ GLOBALS( } in, out; ); -#define C_CONV 0x0000 -#define C_BS 0x0001 -#define C_COUNT 0x0002 -#define C_IBS 0x0004 -#define C_OBS 0x0008 -#define C_IF 0x0010 -#define C_OF 0x0020 -#define C_SEEK 0x0040 -#define C_SKIP 0x0080 #define C_SYNC 0x0100 #define C_FSYNC 0x0200 #define C_NOERROR 0x0400 #define C_NOTRUNC 0x0800 -#define C_STATUS 0x1000 struct pair { char *name; @@ -85,20 +77,6 @@ static struct pair clist[] = { { "sync", C_SYNC }, }; -static struct pair operands[] = { - // keep the array sorted by name, bsearch() can be used. - { "bs", C_BS }, - { "conv", C_CONV }, - { "count", C_COUNT }, - { "ibs", C_IBS }, - { "if", C_IF }, - { "obs", C_OBS }, - { "of", C_OF }, - { "seek", C_SEEK }, - { "skip", C_SKIP }, - { "status", C_STATUS}, -}; - static unsigned long long strsuftoll(char *arg, int def, unsigned long long max) { unsigned long long result; @@ -161,6 +139,17 @@ static void write_out(int all) if (TT.out.count) memmove(TT.out.buff, TT.out.bp, TT.out.count); //move remainder to front } +int strstarteq(char **a, char *b) +{ + char *aa = *a; + + if (!strstart(&aa, b)) return 0; + if (*aa != '=') return 0; + *a = ++aa; + + return 1; +} + static int comp(const void *a, const void *b) //const to shut compiler up { return strcmp(((struct pair*)a)->name, ((struct pair*)b)->name); @@ -169,87 +158,65 @@ static int comp(const void *a, const void *b) //const to shut compiler up void dd_main() { struct pair *res, key; - char *arg; - long sz; + char **args; + unsigned long long bs = 0; + int trunc = O_TRUNC; TT.show_xfer = TT.show_records = 1; + TT.c_count = ULLONG_MAX; TT.in.sz = TT.out.sz = 512; //default io block size - while (*toys.optargs) { - if (!(arg = strchr(*toys.optargs, '='))) error_exit("unknown arg %s", *toys.optargs); - *arg++ = '\0'; - if (!*arg) help_exit(0); - key.name = *toys.optargs; - if (!(res = bsearch(&key, operands, ARRAY_LEN(operands), sizeof(struct pair), - comp))) error_exit("unknown arg %s", key.name); - - toys.optflags |= res->val; - switch (res->val) { - case C_BS: - TT.in.sz = TT.out.sz = strsuftoll(arg, 1, LONG_MAX); - break; - case C_IBS: - sz = strsuftoll(arg, 1, LONG_MAX); - if (!(toys.optflags & C_BS)) TT.in.sz = sz; - break; - case C_OBS: - sz = strsuftoll(arg, 1, LONG_MAX); - if (!(toys.optflags & C_BS)) TT.out.sz = sz; - break; - case C_COUNT: - TT.c_count = strsuftoll(arg, 0, ULLONG_MAX); - break; - case C_IF: - TT.in.name = arg; - break; - case C_OF: - TT.out.name = arg; - break; - case C_SEEK: - TT.out.offset = strsuftoll(arg, 0, ULLONG_MAX); - break; - case C_SKIP: - TT.in.offset = strsuftoll(arg, 0, ULLONG_MAX); - break; - case C_STATUS: - if (!strcmp(arg, "noxfer")) TT.show_xfer = 0; - else if (!strcmp(arg, "none")) TT.show_xfer = TT.show_records = 0; - else error_exit("unknown status '%s'", arg); - break; - case C_CONV: - while (arg) { - key.name = strsep(&arg, ","); - if (!(res = bsearch(&key, clist, ARRAY_LEN(clist), - sizeof(struct pair), comp))) - error_exit("unknown conversion %s", key.name); - - toys.optflags |= res->val; - } - break; - } - toys.optargs++; + for (args = toys.optargs; *args; args++) { + char *arg = *args; + + if (strstarteq(&arg, "bs")) bs = strsuftoll(arg, 1, LONG_MAX); + else if (strstarteq(&arg, "ibs")) TT.in.sz = strsuftoll(arg, 1, LONG_MAX); + else if (strstarteq(&arg, "obs")) TT.out.sz = strsuftoll(arg, 1, LONG_MAX); + else if (strstarteq(&arg, "count")) TT.c_count = strsuftoll(arg, 0, ULLONG_MAX-1); + else if (strstarteq(&arg, "if")) TT.in.name = arg; + else if (strstarteq(&arg, "of")) TT.out.name = arg; + else if (strstarteq(&arg, "seek")) + TT.out.offset = strsuftoll(arg, 0, ULLONG_MAX); + else if (strstarteq(&arg, "skip")) + TT.in.offset = strsuftoll(arg, 0, ULLONG_MAX); + else if (strstarteq(&arg, "status")) { + if (!strcmp(arg, "noxfer")) TT.show_xfer = 0; + else if (!strcmp(arg, "none")) TT.show_xfer = TT.show_records = 0; + else error_exit("unknown status '%s'", arg); + } else if (strstarteq(&arg, "conv")) { + while (arg) { + key.name = strsep(&arg, ","); + if (!(res = bsearch(&key, clist, ARRAY_LEN(clist), + sizeof(struct pair), comp))) + error_exit("unknown conversion %s", key.name); + + toys.optflags |= res->val; + } + } else error_exit("bad arg %s", arg); } + if (bs) TT.in.sz = TT.out.sz = bs; signal(SIGINT, generic_signal); signal(SIGUSR1, generic_signal); gettimeofday(&TT.start, NULL); - /* for C_BS, in/out is done as it is. so only in.sz is enough. + /* for bs=, in/out is done as it is. so only in.sz is enough. * With Single buffer there will be overflow in a read following partial read */ - TT.in.buff = TT.out.buff = xmalloc(TT.in.sz - + ((toys.optflags & C_BS) ? 0 : TT.out.sz)); + TT.in.buff = TT.out.buff = xmalloc(TT.in.sz + (bs ? 0 : TT.out.sz)); TT.in.bp = TT.out.bp = TT.in.buff; //setup input if (!TT.in.name) TT.in.name = "stdin"; else TT.in.fd = xopenro(TT.in.name); + if (toys.optflags&C_NOTRUNC) trunc = 0; + //setup output if (!TT.out.name) { TT.out.name = "stdout"; TT.out.fd = 1; } else TT.out.fd = xcreate(TT.out.name, - O_WRONLY|O_CREAT|(O_TRUNC*!(toys.optflags&C_NOTRUNC)), 0666); + O_WRONLY|O_CREAT|(trunc*!TT.out.offset), 0666); // Implement skip= if (TT.in.offset) { @@ -269,14 +236,14 @@ void dd_main() } } - if (TT.out.offset) - xlseek(TT.out.fd, TT.out.offset * (off_t)TT.out.sz, SEEK_CUR); - - if ((toys.optflags&C_SEEK) && !(toys.optflags & C_NOTRUNC)) - if (ftruncate(TT.out.fd, TT.out.offset * TT.out.sz)) - perror_exit("ftruncate"); + // seek/truncate as necessary. We handled position zero truncate with + // O_TRUNC on open, so output to /dev/null and such doesn't error. + if (TT.out.fd!=1 && (bs = TT.out.offset*TT.out.sz)) { + xlseek(TT.out.fd, bs, SEEK_CUR); + if (trunc && ftruncate(TT.out.fd, bs)) perror_exit("ftruncate"); + } - while (!(toys.optflags & C_COUNT) || (TT.in_full + TT.in_part) < TT.c_count) { + while (TT.c_count==ULLONG_MAX || (TT.in_full + TT.in_part) < TT.c_count) { ssize_t n; // Show progress and exit on SIGINT or just continue on SIGUSR1. @@ -310,7 +277,7 @@ void dd_main() } TT.out.count = TT.in.count; - if (toys.optflags & C_BS) { + if (bs) { write_out(1); TT.in.count = 0; continue; -- cgit v1.2.3