diff --git a/cli/btcli.c b/cli/btcli.c
index 78a3313..f1305a2 100644
--- a/cli/btcli.c
+++ b/cli/btcli.c
@@ -24,6 +24,35 @@ handle_ipc_res(enum ipc_err code, const char *cmd, const char *target)
     return code;
 }
 
+void
+print_percent(long long part, long long whole)
+{
+    printf("%5.1f%% ", floor(1000.0 * part / whole) / 10);
+}
+
+void
+print_rate(long long rate)
+{
+    if (rate >= 999.995 * (1 << 10))
+        printf("%6.2fMB/s ", (double)rate / (1 << 20));
+    else
+        printf("%6.2fkB/s ", (double)rate / (1 << 10));
+}
+
+void
+print_size(long long size)
+{
+    if (size >= 999.995 * (1 << 20))
+        printf("%6.2fG ", (double)size / (1 << 30));
+    else
+        printf("%6.2fM ", (double)size / (1 << 20));
+}
+void
+print_ratio(long long part, long long whole)
+{
+    printf("%7.2f ", (double)part / whole);
+}
+
 char
 tstate_char(enum ipc_tstate ts)
 {
diff --git a/cli/btcli.h b/cli/btcli.h
index 96c3f4b..e522f28 100644
--- a/cli/btcli.h
+++ b/cli/btcli.h
@@ -6,6 +6,7 @@
 #include <getopt.h>
 #include <inttypes.h>
 #include <limits.h>
+#include <math.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
@@ -26,6 +27,11 @@ enum ipc_err handle_ipc_res(enum ipc_err err, const char *cmd,
 char tstate_char(enum ipc_tstate ts);
 int torrent_spec(char *arg, struct ipc_torrent *tp);
 
+void print_rate(long long rate);
+void print_size(long long size);
+void print_ratio(long long part, long long whole);
+void print_percent(long long part, long long whole);
+
 void usage_add(void);
 void cmd_add(int argc, char **argv);
 void usage_del(void);
diff --git a/cli/list.c b/cli/list.c
index c0888c2..a6ed9d9 100644
--- a/cli/list.c
+++ b/cli/list.c
@@ -7,6 +7,19 @@ usage_list(void)
         "List torrents.\n"
         "\n"
         "Usage: list [-a] [-i]\n"
+        "       list torrent ...\n"
+        "\n"
+        "Arguments:\n"
+        "torrent ...\n"
+        "\tThe torrents to list. Running 'btcli list' without any arguments\n"
+        "\tor options is equivalent to running 'btcli list -ai'.\n"
+        "\n"
+        "Options:\n"
+        "-a\n"
+        "\tList active torrents.\n"
+        "\n"
+        "-i\n"
+        "\tList inactive torrents.\n"
         "\n"
         );
     exit(1);
@@ -16,11 +29,15 @@ struct item {
     unsigned num;
     char *name;
     char st;
+    long long cgot, csize, totup;
     BTPDQ_ENTRY(item) entry;
 };
 
 struct items {
     int count;
+    char **argv;
+    int ntps;
+    struct ipc_torrent *tps;
     BTPDQ_HEAD(item_tq, item) hd;
 };
 
@@ -29,7 +46,7 @@ itm_insert(struct items *itms, struct item *itm)
 {
     struct item *p;
     BTPDQ_FOREACH(p, &itms->hd, entry)
-        if (itm->num < p->num)
+        if (strcmp(itm->name, p->name) < 0)
             break;
     if (p != NULL)
         BTPDQ_INSERT_BEFORE(p, itm, entry);
@@ -42,6 +59,9 @@ list_cb(int obji, enum ipc_err objerr, struct ipc_get_res *res, void *arg)
 {
     struct items *itms = arg;
     struct item *itm = calloc(1, sizeof(*itm));
+    if (objerr != IPC_OK)
+        errx(1, "list failed for '%s' (%s)", itms->argv[obji],
+            ipc_strerror(objerr));
     itms->count++;
     itm->num = (unsigned)res[IPC_TVAL_NUM].v.num;
     itm->st = tstate_char(res[IPC_TVAL_STATE].v.num);
@@ -50,21 +70,22 @@ list_cb(int obji, enum ipc_err objerr, struct ipc_get_res *res, void *arg)
     else
         asprintf(&itm->name, "%.*s", (int)res[IPC_TVAL_NAME].v.str.l,
             res[IPC_TVAL_NAME].v.str.p);
+    itm->totup = res[IPC_TVAL_TOTUP].v.num;
+    itm->cgot = res[IPC_TVAL_CGOT].v.num;
+    itm->csize = res[IPC_TVAL_CSIZE].v.num;
     itm_insert(itms, itm);
 }
 
 void
 print_items(struct items* itms)
 {
-    int n;
     struct item *p;
     BTPDQ_FOREACH(p, &itms->hd, entry) {
-        n = printf("%u: ", p->num);
-        while (n < 7) {
-            putchar(' ');
-            n++;
-        }
-        printf("%c. %s\n", p->st, p->name);
+        printf("%-40.40s %4u %c. ", p->name, p->num, p->st);
+        print_percent(p->cgot, p->csize);
+        print_size(p->csize);
+        print_ratio(p->totup, p->csize);
+        printf("\n");
     }
 }
 
@@ -79,7 +100,9 @@ cmd_list(int argc, char **argv)
     int ch, inactive = 0, active = 0;
     enum ipc_err code;
     enum ipc_twc twc;
-    enum ipc_tval keys[] = { IPC_TVAL_NUM, IPC_TVAL_STATE, IPC_TVAL_NAME };
+    enum ipc_tval keys[] = { IPC_TVAL_NUM, IPC_TVAL_STATE, IPC_TVAL_NAME,
+       IPC_TVAL_TOTUP, IPC_TVAL_CSIZE, IPC_TVAL_CGOT };
+    size_t nkeys = sizeof(keys) / sizeof(keys[0]);
     struct items itms;
     while ((ch = getopt_long(argc, argv, "ai", list_opts, NULL)) != -1) {
         switch (ch) {
@@ -93,7 +116,22 @@ cmd_list(int argc, char **argv)
             usage_list();
         }
     }
+    argc -= optind;
+    argv += optind;
 
+    if (argc > 0) {
+        if (inactive || active)
+            usage_list();
+        itms.tps = malloc(argc * sizeof(*itms.tps));
+        for (itms.ntps = 0; itms.ntps < argc; itms.ntps++) {
+            if (!torrent_spec(argv[itms.ntps], &itms.tps[itms.ntps]))
+                exit(1);
+
+        }
+    } else {
+        itms.ntps = 0;
+        itms.tps = NULL;
+    }
     if (inactive == active)
         twc = IPC_TWC_ALL;
     else if (inactive)
@@ -102,11 +140,15 @@ cmd_list(int argc, char **argv)
         twc = IPC_TWC_ACTIVE;
 
     btpd_connect();
-    printf("NUM    ST NAME\n");
     itms.count = 0;
+    itms.argv = argv;
     BTPDQ_INIT(&itms.hd);
-    if ((code = btpd_tget_wc(ipc, twc, keys, 3, list_cb, &itms)) != IPC_OK)
+    if (itms.tps == NULL)
+        code = btpd_tget_wc(ipc, twc, keys, nkeys, list_cb, &itms);
+    else
+        code = btpd_tget(ipc, itms.tps, itms.ntps, keys, nkeys, list_cb, &itms);
+    if (code != IPC_OK)
         errx(1, "%s", ipc_strerror(code));
+    printf("%-40.40s  NUM ST   HAVE    SIZE   RATIO\n", "NAME");
     print_items(&itms);
-    printf("Listed %d torrent%s.\n", itms.count, itms.count == 1 ? "" : "s");
 }
diff --git a/cli/stat.c b/cli/stat.c
index 1d1b781..c2846c1 100644
--- a/cli/stat.c
+++ b/cli/stat.c
@@ -1,5 +1,3 @@
-#include <math.h>
-
 #include "btcli.h"
 
 void
@@ -8,11 +6,11 @@ usage_stat(void)
     printf(
         "Display stats for active torrents.\n"
         "\n"
-        "Usage: stat [-i] [-w seconds] [file ...]\n"
+        "Usage: stat [-i] [-w seconds] [torrent ...]\n"
         "\n"
         "Arguments:\n"
-        "file ...\n"
-        "\tOnly display stats for the given torrent(s).\n"
+        "torrent ...\n"
+        "\tOnly display stats for the given torrents.\n"
         "\n"
         "Options:\n"
         "-i\n"
@@ -32,7 +30,7 @@ struct btstat {
     enum ipc_tstate state;
     unsigned peers, tr_errors;
     long long content_got, content_size, downloaded, uploaded, rate_up,
-        rate_down;
+        rate_down, tot_up;
     uint32_t pieces_seen, torrent_pieces;
 };
 
@@ -51,6 +49,7 @@ static enum ipc_tval stkeys[] = {
     IPC_TVAL_PCSEEN,
     IPC_TVAL_SESSUP,
     IPC_TVAL_SESSDWN,
+    IPC_TVAL_TOTUP,
     IPC_TVAL_RATEUP,
     IPC_TVAL_RATEDWN,
     IPC_TVAL_CGOT,
@@ -59,30 +58,6 @@ static enum ipc_tval stkeys[] = {
 
 static size_t nstkeys = sizeof(stkeys) / sizeof(stkeys[0]);
 
-static void
-print_percent(long long part, long long whole)
-{
-    printf("%5.1f%% ", floor(1000.0 * part / whole) / 10);
-}
-
-static void
-print_rate(long long rate)
-{
-    if (rate >= 999.995 * (1 << 10))
-        printf("%6.2fMB/s ", (double)rate / (1 << 20));
-    else
-        printf("%6.2fkB/s ", (double)rate / (1 << 10));
-}
-
-static void
-print_size(long long size)
-{
-    if (size >= 999.995 * (1 << 20))
-        printf("%6.2fG ", (double)size / (1 << 30));
-    else
-        printf("%6.2fM ", (double)size / (1 << 20));
-}
-
 static void
 print_stat(struct btstat *st)
 {
@@ -91,7 +66,8 @@ print_stat(struct btstat *st)
     print_rate(st->rate_down);
     print_size(st->uploaded);
     print_rate(st->rate_up);
-    printf("%5u ", st->peers);
+    print_ratio(st->tot_up, st->content_size);
+    printf("%4u ", st->peers);
     print_percent(st->pieces_seen, st->torrent_pieces);
     if (st->tr_errors > 0)
         printf("E%u", st->tr_errors);
@@ -117,18 +93,14 @@ stat_cb(int obji, enum ipc_err objerr, struct ipc_get_res *res, void *arg)
     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);
+    tot->tot_up += (st.tot_up = res[IPC_TVAL_TOTUP].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));
+        printf("%4u %c. ", st.num, tstate_char(st.state));
         print_stat(&st);
     }
 }
@@ -149,10 +121,11 @@ again:
     if (header == 0) {
         if (individual) {
             header = 1;
-            printf("NUM    ST ");
+            printf(" NUM ST ");
         } else
             header = 20;
-        printf("  HAVE   DLOAD      RTDWN   ULOAD       RTUP PEERS  AVAIL\n");
+        printf("  HAVE   DLOAD      RTDWN   ULOAD       RTUP   RATIO CONN"
+            "  AVAIL\n");
     }
 
     bzero(&cba.tot, sizeof(cba.tot));
@@ -165,9 +138,9 @@ again:
     if (err != IPC_OK)
         errx(1, ipc_strerror(err));
     if (names)
-        printf("-----\n");
+        printf("-------\n");
     if (individual)
-        printf("Total:    ");
+        printf("        ");
     print_stat(&cba.tot);
     if (seconds > 0) {
         sleep(seconds);