commit 9e7dd230e2eed399dd25ba034363eb1de5db66e9 from: Omar Polo date: Wed Jan 12 19:00:52 2022 UTC ftp: add `page' command The `page' command fetches a file and displays it using less(1). To do this, refactor fetch_fid to accept a file descriptor and add a spawn utility function. commit - 7c94ab42ffb47df7759085b11fcbc04cbe8e453f commit + 9e7dd230e2eed399dd25ba034363eb1de5db66e9 blob - ddd46f7118bbf35840a9b1630c384efa7015dea1 blob + d765c56dd04460ba921ebedf59bbce6c7623f18c --- kamiftp/ftp.c +++ kamiftp/ftp.c @@ -19,12 +19,14 @@ #include #include #include +#include #include #include #include #include #include +#include #include #include #include @@ -132,6 +134,40 @@ again: add_history(line); return line; +} + +static void +spawn(const char *argv0, ...) +{ + pid_t pid; + size_t i; + int status; + const char *argv[16], *last; + va_list ap; + + memset(argv, 0, sizeof(argv)); + + va_start(ap, argv0); + argv[0] = argv0; + for (i = 1; i < nitems(argv); ++i) { + last = va_arg(ap, const char *); + if (last == NULL) + break; + argv[i] = last; + } + va_end(ap); + + assert(last == NULL); + + switch (pid = fork()) { + case -1: + err(1, "fork"); + case 0: /* child */ + execvp(argv[0], (char *const *)argv); + err(1, "execvp"); + default: + waitpid(pid, &status, 0); + } } static void @@ -549,23 +585,17 @@ draw_progress(const char *pre, const struct progress * fflush(stdout); } -static int -fetch_fid(int fid, const char *path) +static void +fetch_fid_in_fd(int fid, int fd, const char *name) { struct progress p = {0}; struct np_stat st; size_t r; - int fd; char buf[BUFSIZ]; do_stat(fid, &st); do_open(fid, KOREAD); - if ((fd = open(path, O_WRONLY|O_CREAT|O_TRUNC, 0644)) == -1) { - warn("can't open %s", path); - return -1; - } - p.max = st.length; for (;;) { size_t siz, off; @@ -582,7 +612,7 @@ fetch_fid(int fid, const char *path) err(1, "write"); p.done += r; - draw_progress(path, &p); + draw_progress(name, &p); #if 0 /* throttle, for debugging purpose */ @@ -594,7 +624,19 @@ fetch_fid(int fid, const char *path) } putchar('\n'); +} + +static int +fetch_fid(int fid, const char *path) +{ + int fd; + + if ((fd = open(path, O_WRONLY|O_CREAT|O_TRUNC, 0644)) == -1) { + warn("can't open %s", path); + return -1; + } + fetch_fid_in_fd(fid, fd, path); close(fd); do_clunk(fid); return 0; @@ -883,6 +925,45 @@ cmd_ls(int argc, const char **argv) } static void +cmd_page(int argc, const char **argv) +{ + struct qid qid; + int nfid, tmpfd; + char sfn[24], p[PATH_MAX], *name; + + if (argc != 1) { + puts("usage: page file"); + return; + } + + nfid = pwdfid+1; + if (walk_path(pwdfid, nfid, *argv, &qid) == -1) { + printf("can't fetch %s\n", *argv); + return; + } + + if (qid.type != 0) { + printf("can't page file type %s\n", pp_qid_type(qid.type)); + do_clunk(nfid); + return; + } + + strlcpy(sfn, "/tmp/kamiftp.XXXXXXXXXX", sizeof(sfn)); + if ((tmpfd = mkstemp(sfn)) == -1) { + warn("mkstemp %s", sfn); + do_clunk(nfid); + return; + } + + strlcpy(p, *argv, sizeof(p)); + name = basename(p); + fetch_fid_in_fd(nfid, tmpfd, name); + close(tmpfd); + spawn("less", sfn, NULL); + unlink(sfn); +} + +static void cmd_verbose(int argc, const char **argv) { if (argc == 0) { @@ -927,6 +1008,7 @@ excmd(int argc, const char **argv) {"lcd", cmd_lcd}, {"lpwd", cmd_lpwd}, {"ls", cmd_ls}, + {"page", cmd_page}, {"quit", cmd_bye}, {"verbose", cmd_verbose}, };