diff options
Diffstat (limited to 'cli/stat.c')
| -rw-r--r-- | cli/stat.c | 193 |
1 files changed, 193 insertions, 0 deletions
diff --git a/cli/stat.c b/cli/stat.c new file mode 100644 index 0000000..2af1210 --- /dev/null +++ b/cli/stat.c @@ -0,0 +1,193 @@ +#include <math.h> + +#include "btcli.h" + +void +usage_stat(void) +{ + printf( + "Display stats for active torrents.\n" + "\n" + "Usage: stat [-i] [-w seconds] [file ...]\n" + "\n" + "Arguments:\n" + "file ...\n" + "\tOnly display stats for the given torrent(s).\n" + "\n" + "Options:\n" + "-i\n" + "\tDisplay individual lines for each torrent.\n" + "\n" + "-n\n" + "\tDisplay the name of each torrent. Implies '-i'.\n" + "\n" + "-w n\n" + "\tDisplay stats every n seconds.\n" + "\n"); + exit(1); +} + +struct btstat { + unsigned num; + enum ipc_tstate state; + unsigned peers, tr_errors; + long long content_got, content_size, downloaded, uploaded, rate_up, + rate_down; + uint32_t pieces_seen, torrent_pieces; +}; + +struct cbarg { + int individual, names; + struct btstat tot; +}; + +static enum ipc_tval stkeys[] = { + IPC_TVAL_STATE, + IPC_TVAL_NUM, + IPC_TVAL_NAME, + IPC_TVAL_PCOUNT, + IPC_TVAL_TRERR, + IPC_TVAL_PCCOUNT, + IPC_TVAL_PCSEEN, + IPC_TVAL_SESSUP, + IPC_TVAL_SESSDWN, + IPC_TVAL_RATEUP, + IPC_TVAL_RATEDWN, + IPC_TVAL_CGOT, + IPC_TVAL_CSIZE +}; + +static size_t nstkeys = sizeof(stkeys) / sizeof(stkeys[0]); + +static void +print_stat(struct btstat *st) +{ + printf("%5.1f%% %6.1fM %7.2fkB/s %6.1fM %7.2fkB/s %5u %5.1f%%", + floor(1000.0 * st->content_got / st->content_size) / 10, + (double)st->downloaded / (1 << 20), + (double)st->rate_down / (20 << 10), + (double)st->uploaded / (1 << 20), + (double)st->rate_up / (20 << 10), + st->peers, + floor(1000.0 * st->pieces_seen / st->torrent_pieces) / 10); + if (st->tr_errors > 0) + printf(" E%u", st->tr_errors); + printf("\n"); +} + +void +stat_cb(int obji, enum ipc_err objerr, struct ipc_get_res *res, void *arg) +{ + struct cbarg *cba = arg; + struct btstat st, *tot = &cba->tot; + if (objerr != IPC_OK || res[IPC_TVAL_STATE].v.num == IPC_TSTATE_INACTIVE) + return; + bzero(&st, sizeof(st)); + st.state = res[IPC_TVAL_STATE].v.num; + st.num = res[IPC_TVAL_NUM].v.num; + tot->torrent_pieces += (st.torrent_pieces = res[IPC_TVAL_PCCOUNT].v.num); + tot->pieces_seen += (st.pieces_seen = res[IPC_TVAL_PCSEEN].v.num); + tot->content_got += (st.content_got = res[IPC_TVAL_CGOT].v.num); + tot->content_size += (st.content_size = res[IPC_TVAL_CSIZE].v.num); + tot->downloaded += (st.downloaded = res[IPC_TVAL_SESSDWN].v.num); + tot->uploaded += (st.uploaded = res[IPC_TVAL_SESSUP].v.num); + tot->rate_down += (st.rate_down = res[IPC_TVAL_RATEDWN].v.num); + tot->rate_up += (st.rate_up = res[IPC_TVAL_RATEUP].v.num); + tot->peers += (st.peers = res[IPC_TVAL_PCOUNT].v.num); + if ((st.tr_errors = res[IPC_TVAL_TRERR].v.num) > 0) + tot->tr_errors++; + if (cba->individual) { + if (cba->names) + printf("%.*s\n", (int)res[IPC_TVAL_NAME].v.str.l, + res[IPC_TVAL_NAME].v.str.p); + int n = printf("%u:", st.num); + while (n < 7) { + putchar(' '); + n++; + } + printf("%c. ", tstate_char(st.state)); + print_stat(&st); + } +} + +static void +do_stat(int individual, int names, int seconds, struct ipc_torrent *tps, + int ntps) +{ + enum ipc_err err; + struct cbarg cba; + if (names) + individual = 1; + if (individual) + printf("NUM ST "); + printf(" HAVE DLOAD RTDWN ULOAD RTUP PEERS AVAIL\n"); + cba.individual = individual; + cba.names = names; +again: + bzero(&cba.tot, sizeof(cba.tot)); + cba.tot.state = IPC_TSTATE_INACTIVE; + if (tps == NULL) + err = btpd_tget_wc(ipc, IPC_TWC_ACTIVE, stkeys, nstkeys, + stat_cb, &cba); + else + err = btpd_tget(ipc, tps, ntps, stkeys, nstkeys, stat_cb, &cba); + if (handle_ipc_res(err, "stat") != IPC_OK) + exit(1); + if (names) + printf("-----\n"); + if (individual) + printf("Total: "); + print_stat(&cba.tot); + if (seconds > 0) { + sleep(seconds); + goto again; + } +} + +static struct option stat_opts [] = { + { "help", no_argument, NULL, 'H' }, + {NULL, 0, NULL, 0} +}; + +void +cmd_stat(int argc, char **argv) +{ + int ch; + int wflag = 0, iflag = 0, nflag = 0, seconds = 0; + struct ipc_torrent *tps = NULL; + int ntps = 0; + char *endptr; + while ((ch = getopt_long(argc, argv, "inw:", stat_opts, NULL)) != -1) { + switch (ch) { + case 'i': + iflag = 1; + break; + case 'n': + nflag = 1; + break; + case 'w': + wflag = 1; + seconds = strtol(optarg, &endptr, 10); + if (*endptr != '\0' || seconds < 1) + usage_stat(); + break; + default: + usage_stat(); + } + } + argc -= optind; + argv += optind; + + if (argc > 0) { + tps = malloc(argc * sizeof(*tps)); + for (int i = 0; i < argc; i++) { + if (torrent_spec(argv[i], &tps[ntps])) + ntps++; + else + exit(1); + + } + } + btpd_connect(); + do_stat(iflag, nflag, seconds, tps, ntps); +} |