commit 207ba019fda48ef7d84484afbfd56d327dd5e249
Author: sin <[email protected]>
Date:   Wed Jun 4 11:39:00 2014 +0100

    Add initial version of dd(1).
    
    This code was written by Sebastian Krahmer and you can find
    the original version at https://github.com/stealth/odd.git.
    
    Permission has been granted to release this code under MIT/X
    for ubase.  It has been simplified by [email protected].
    
    Thanks Sebastian!

diff --git a/Makefile b/Makefile
index a2be343..04fe64d 100644
--- a/Makefile
+++ b/Makefile
@@ -22,6 +22,7 @@ SRC = \
        chvt.c              \
        clear.c             \
        ctrlaltdel.c        \
+       dd.c                \
        df.c                \
        dmesg.c             \
        eject.c             \
diff --git a/dd.c b/dd.c
new file mode 100644
index 0000000..9fdf6d9
--- /dev/null
+++ b/dd.c
@@ -0,0 +1,269 @@
+/* (C) 2011-2012 Sebastian Krahmer all rights reserved.
+ *
+ * Optimized dd, to speed up backups etc.
+ *
+ * Permission has been granted to release this code under MIT/X.
+ * The original code is at https://github.com/stealth/odd.  This
+ * version of the code has been modified by [email protected].
+ */
+#include <errno.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <sys/ioctl.h>
+#include <sys/mount.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/vfs.h>
+#include <time.h>
+#include <unistd.h>
+
+struct dd_config {
+       const char *in, *out;
+       uint64_t skip, seek, count, b_in, b_out, rec_in, rec_out;
+       off_t fsize;
+       blksize_t bs;
+       char quiet, nosync, direct;
+       int saved_errno;
+       time_t t_start, t_end;
+};
+
+static int sigint = 0;
+
+static int
+prepare_copy(struct dd_config *ddc, int *ifd, int *ofd)
+{
+       struct stat st;
+       int fli = O_RDONLY|O_LARGEFILE|O_NOCTTY, flo = 
O_WRONLY|O_LARGEFILE|O_NOATIME|O_NOCTTY;
+       uid_t euid = 0;
+
+       if (ddc->direct) {
+               fli |= O_DIRECT;
+               flo |= O_DIRECT;
+       }
+
+       if (stat(ddc->in, &st) < 0) {
+               ddc->saved_errno = errno;
+               return -1;
+       }
+
+       euid = geteuid();
+
+       if (!euid || st.st_uid == euid)
+               fli |= O_NOATIME;
+
+       if ((*ifd = open(ddc->in, fli)) < 0) {
+               ddc->saved_errno = errno;
+               return -1;
+       }
+
+       ddc->fsize = st.st_size;
+
+       /* If "bsize" is not given, use optimum of both FS' */
+       if (!ddc->bs) {
+               struct statfs fst;
+               memset(&fst, 0, sizeof(fst));
+               if (statfs(ddc->out, &fst) < 0 || fst.f_bsize == 0)
+                       fst.f_bsize = 0x1000;
+               if (fst.f_bsize > st.st_blksize)
+                       ddc->bs = fst.f_bsize;
+               else
+                       ddc->bs = st.st_blksize;
+               if (ddc->bs == 0)
+                       ddc->bs = 0x1000;
+       }
+
+       /* check if device or regular file */
+       if (!S_ISREG(st.st_mode)) {
+               if (S_ISBLK(st.st_mode)) {
+                       if (ioctl(*ifd, BLKGETSIZE64, &ddc->fsize) < 0) {
+                               ddc->saved_errno = errno;
+                               close(*ifd);
+                               return -1;
+                       }
+               } else {
+                       ddc->fsize = (off_t)-1;
+                       if (ddc->count)
+                               ddc->fsize = ddc->count*ddc->bs;
+               }
+       }
+
+       /* skip and seek are in block items */
+       ddc->skip *= ddc->bs;
+       ddc->seek *= ddc->bs;
+
+       /* skip more bytes than are inside source file? */
+       if (ddc->fsize != (off_t)-1 && ddc->skip >= (uint64_t)ddc->fsize) {
+               ddc->saved_errno = EINVAL;
+               close(*ifd);
+               return -1;
+       }
+
+       if (!ddc->seek)
+               flo |= O_CREAT|O_TRUNC;
+
+       if ((*ofd = open(ddc->out, flo, st.st_mode)) < 0) {
+               ddc->saved_errno = errno;
+               close(*ifd);
+               return -1;
+       }
+
+       lseek(*ifd, ddc->skip, SEEK_SET);
+       lseek(*ofd, ddc->seek, SEEK_SET);
+       posix_fadvise(*ifd, ddc->skip, 0, POSIX_FADV_SEQUENTIAL);
+       posix_fadvise(*ofd, 0, 0, POSIX_FADV_DONTNEED);
+
+       /* count is in block items too */
+       ddc->count *= ddc->bs;
+
+       /* If no count is given, its the filesize minus skip offset */
+       if (ddc->count == 0)
+               ddc->count = ddc->fsize - ddc->skip;
+
+       return 0;
+}
+
+int copy_splice(struct dd_config *ddc)
+{
+        int ifd, ofd, p[2] = {-1, -1};
+        ssize_t r = 0;
+        size_t n = 0;
+        if (prepare_copy(ddc, &ifd, &ofd) < 0)
+                return -1;
+        if (pipe(p) < 0) {
+                ddc->saved_errno = errno;
+                close(ifd); close(ofd);
+                close(p[0]); close(p[1]);
+                return -1;
+        }
+#ifdef F_SETPIPE_SZ
+        for (n = 29; n >= 20; --n) {
+                if (fcntl(p[0], F_SETPIPE_SZ, 1<<n) != -1)
+                        break;
+        }
+#endif
+        n = ddc->bs;
+        for (;ddc->b_out != ddc->count && !sigint;) {
+                if (n > ddc->count - ddc->b_out)
+                        n = ddc->count - ddc->b_out;
+                r = splice(ifd, NULL, p[1], NULL, n, SPLICE_F_MORE);
+                if (r <= 0) {
+                        ddc->saved_errno = errno;
+                        break;
+                }
+                ++ddc->rec_in;
+                r = splice(p[0], NULL, ofd, NULL, r, SPLICE_F_MORE);
+                if (r <= 0) {
+                        ddc->saved_errno = errno;
+                        break;
+                }
+                ddc->b_out += r;
+                ++ddc->rec_out;
+        }
+        close(ifd);
+        close(ofd);
+        close(p[0]);
+        close(p[1]);
+        if (r < 0)
+                return -1;
+        return 0;
+}
+
+static int
+copy(struct dd_config *ddc)
+{
+       int r = 0;
+
+       ddc->t_start = time(NULL);
+
+       r = copy_splice(ddc);
+       ddc->t_end = time(NULL);
+
+       /* avoid div by zero */
+       if (ddc->t_start == ddc->t_end)
+               ++ddc->t_end;
+       return r;
+}
+
+static void
+usage(void)
+{
+       fprintf(stderr, "Usage: odd [if=F1] [of=F2] [bsize] [skip=N] [count=N] 
[quiet] [nosync]
");
+       exit(EXIT_FAILURE);
+}
+
+static void
+print_stat(const struct dd_config *ddc)
+{
+       if (ddc->quiet)
+               return;
+
+       fprintf(stderr, "%lu records in
%lu records out
%lu bytes (%lu MB) copied, %lu s, %f MB/s [%f mB/s]
",
+               ddc->rec_in, ddc->rec_out, ddc->b_out, ddc->b_out/(1<<20),
+               ddc->t_end - ddc->t_start,
+               ((double)(ddc->b_out/(1<<20)))/(ddc->t_end - ddc->t_start),
+               ((double)(ddc->b_out/(1000*1000)))/(ddc->t_end - ddc->t_start));
+}
+
+static void
+sig_int(int unused)
+{
+       (void) unused;
+       fprintf(stderr, "SIGINT! Aborting ...
");
+       sigint = 1;
+}
+
+int
+main(int argc, char *argv[])
+{
+       int i = 0;
+       char buf[1024];
+       struct dd_config config;
+
+       memset(&config, 0, sizeof(config));
+       config.bs = 1<<16;
+       config.in = "/dev/stdin";
+       config.out = "/dev/stdout";
+
+       /* emulate 'dd' argument parsing */
+       for (i = 1; i < argc; ++i) {
+               memset(buf, 0, sizeof(buf));
+               if (sscanf(argv[i], "if=%1023c", buf) == 1)
+                       config.in = strdup(buf);
+               else if (sscanf(argv[i], "of=%1023c", buf) == 1)
+                       config.out = strdup(buf);
+               else if (sscanf(argv[i], "skip=%1023c", buf) == 1)
+                       config.skip = strtoul(buf, NULL, 10);
+               else if (sscanf(argv[i], "seek=%1023c", buf) == 1)
+                       config.seek = strtoul(buf, NULL, 10);
+               else if (sscanf(argv[i], "count=%1023c", buf) == 1)
+                       config.count = strtoul(buf, NULL, 10);
+               else if (strcmp(argv[i], "direct") == 0)
+                       config.direct = 1;
+               else if (sscanf(argv[i], "bs=%1023c", buf) == 1)
+                       config.bs = strtoul(buf, NULL, 10);
+               else if (strcmp(argv[i], "bs") == 0)
+                       config.bs = 0;
+               else if (strcmp(argv[i], "quiet") == 0)
+                       config.quiet = 1;
+               else if (strcmp(argv[i], "nosync") == 0)
+                       config.nosync = 1;
+       }
+
+       if (!config.in || !config.out)
+               usage();
+
+       signal(SIGPIPE, SIG_IGN);
+       signal(SIGINT, sig_int);
+
+       if (copy(&config) < 0)
+               fprintf(stderr, "Error: %s
", strerror(config.saved_errno));
+       print_stat(&config);
+
+       if (config.nosync == 0)
+               sync(); sync();
+       return EXIT_SUCCESS;
+}


Reply via email to