/* vi: set sw=4 ts=4: */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include static const char *const app_name = "scopy"; static int intr_flag = 0; static void verror_msg(const char *s, va_list p) { fflush(stdout); fprintf(stderr, "%s: ", app_name); vfprintf(stderr, s, p); } static void vperror_msg(const char *s, va_list p) { int err = errno; if (s == 0) s = ""; verror_msg(s, p); if (*s) s = ": "; fprintf(stderr, "%s%s\n", s, strerror(err)); } static void perror_msg_and_die(const char *s, ...) { va_list p; va_start(p, s); vperror_msg(s, p); va_end(p); exit(EXIT_FAILURE); } static FILE *xfopen(const char *path, const char *mode) { FILE *fp; if ((fp = fopen(path, mode)) == NULL) perror_msg_and_die("%s", path); return fp; } static void show_usage(void) { fprintf(stderr, "Usage: scopy source dest\n"); exit(EXIT_FAILURE); } static void sig_int(int signo) { intr_flag = 1; } int main(int argc, char **argv) { int status = 0; int opt; char *sname, *dname; fd_set rfds, wfds; FILE *source, *dest; int source_fd, dest_fd, n; ssize_t rsize = 0, wsize = 0; char buf[1024 * 1024]; ssize_t bufsiz = sizeof(buf); struct timeval tv = { 0, 250000 }; /* 0.25 seconds */ while ((opt = getopt(argc, argv, "adfipR")) != -1) switch (opt) { default: show_usage(); } if (optind + 2 > argc) show_usage(); /* If there are only two arguments and... */ if (optind + 2 != argc) show_usage(); /* Store filenames for later use */ sname = argv[optind++]; dname = argv[optind]; source = xfopen(sname, "r"); dest = xfopen(dname, "w"); source_fd = fileno(source); dest_fd = fileno(dest); /* Watch to see if things happen */ FD_ZERO(&rfds); FD_ZERO(&wfds); n = (source_fd > dest_fd) ? source_fd + 1 : dest_fd + 1; if (fcntl(source_fd, F_SETFL, O_NONBLOCK) == -1) perror_msg_and_die("Setting O_NONBLOCK on %s", sname); if (fcntl(dest_fd, F_SETFL, O_NONBLOCK) == -1) perror_msg_and_die("Setting O_NONBLOCK on %s", dname); signal(SIGINT, sig_int); /* Ok, do the deed */ while (1) { if (intr_flag) { printf("interrupted... Please wait...\n"); exit(EXIT_FAILURE); } FD_SET(fileno(source), &rfds); FD_SET(fileno(dest), &wfds); status = select(n, &rfds, &wfds, NULL, &tv); if (status < 0) { if (errno == EINTR) { printf("interrupted... Please wait...\n"); exit(EXIT_FAILURE); } else if (errno != EBADF) { perror_msg_and_die("select"); } } if (FD_ISSET(source_fd, &rfds)) { rsize = read(source_fd, buf, bufsiz); if (rsize < 0) perror_msg_and_die("reading %d", sname); if (rsize == 0) exit(EXIT_SUCCESS); } if (FD_ISSET(dest_fd, &wfds)) { wsize = write(dest_fd, buf, rsize); if (wsize < 0) perror_msg_and_die("writing %s", dname); if (wsize == 0) exit(EXIT_SUCCESS); } } return 0; }