diff --git a/btpd/Makefile.am b/btpd/Makefile.am
index ab67b5e..ca0a096 100644
--- a/btpd/Makefile.am
+++ b/btpd/Makefile.am
@@ -1,7 +1,7 @@
 bin_PROGRAMS=btpd
 btpd_SOURCES=\
 	btpd.c btpd.h\
-	content.c content.h\
+	cli_if.c content.c content.h\
 	download.c download_subr.c download.h\
 	http.c http.h\
 	main.c\
diff --git a/btpd/btpd.c b/btpd/btpd.c
index 1ecbae8..161c780 100644
--- a/btpd/btpd.c
+++ b/btpd/btpd.c
@@ -216,7 +216,7 @@ btpd_init(void)
     td_init();
     http_init();
     net_init();
-    //ipc_init();
+    ipc_init();
     ul_init();
     cm_init();
 
diff --git a/btpd/cli_if.c b/btpd/cli_if.c
index dd24858..9b699f3 100644
--- a/btpd/cli_if.c
+++ b/btpd/cli_if.c
@@ -36,20 +36,27 @@ cmd_stat(int argc, const char *args, FILE *fp)
     errdie(buf_print(&iob, "9:ntorrentsi%ue", btpd_get_ntorrents()));
     errdie(buf_swrite(&iob, "8:torrentsl"));
     BTPDQ_FOREACH(tp, btpd_get_torrents(), entry) {
+        if (tp->state != T_ACTIVE)
+            continue;
+
         uint32_t seen_npieces = 0;
         for (uint32_t i = 0; i < tp->meta.npieces; i++)
-            if (tp->piece_count[i] > 0)
+            if (tp->net->piece_count[i] > 0)
                 seen_npieces++;
-        errdie(buf_print(&iob, "d4:downi%jue", (intmax_t)tp->downloaded));
+        errdie(buf_print(&iob, "d4:downi%jue", (intmax_t)tp->net->downloaded));
         errdie(buf_swrite(&iob, "4:hash20:"));
         errdie(buf_write(&iob, tp->meta.info_hash, 20));
-        errdie(buf_print(&iob, "12:have npiecesi%ue", tp->have_npieces));
-        errdie(buf_print(&iob, "6:npeersi%ue", tp->npeers));
+        errdie(buf_print(&iob, "4:havei%jde", (intmax_t)cm_get_size(tp)));
+        errdie(buf_print(&iob, "6:npeersi%ue", tp->net->npeers));
         errdie(buf_print(&iob, "7:npiecesi%ue", tp->meta.npieces));
         errdie(buf_print(&iob, "4:path%d:%s",
                          (int)strlen(tp->relpath), tp->relpath));
+        errdie(buf_print(&iob, "2:rdi%lue", tp->net->rate_dwn));
+        errdie(buf_print(&iob, "2:rui%lue", tp->net->rate_up));
         errdie(buf_print(&iob, "12:seen npiecesi%ue", seen_npieces));
-        errdie(buf_print(&iob, "2:upi%juee", (intmax_t)tp->uploaded));
+        errdie(buf_print(&iob, "5:totali%jde",
+                   (intmax_t)tp->meta.total_length));
+        errdie(buf_print(&iob, "2:upi%juee", (intmax_t)tp->net->uploaded));
     }
     errdie(buf_swrite(&iob, "ee"));
 
@@ -59,6 +66,7 @@ cmd_stat(int argc, const char *args, FILE *fp)
     free(iob.buf);
 }
 
+#if 0
 static void
 cmd_add(int argc, const char *args, FILE *fp)
 {
@@ -144,15 +152,18 @@ cmd_die(int argc, const char *args, FILE *fp)
     btpd_log(BTPD_L_BTPD, "Someone wants me dead.\n");
     btpd_shutdown();
 }
+#endif
 
 static struct {
     const char *name;
     int nlen;
     void (*fun)(int, const char *, FILE *);
 } cmd_table[] = {
+#if 0
     { "add",    3, cmd_add },
     { "del",    3, cmd_del },
     { "die",    3, cmd_die },
+#endif
     { "stat",   4, cmd_stat }
 };
 
diff --git a/btpd/main.c b/btpd/main.c
index ba6361b..000757d 100644
--- a/btpd/main.c
+++ b/btpd/main.c
@@ -61,8 +61,13 @@ setup_daemon(const char *dir)
         err(1, "Couldn't create library");
 
     pidfd = open("pid", O_CREAT|O_WRONLY|O_NONBLOCK|O_EXLOCK, 0666);
-    if (pidfd == -1)
-        err(1, "Couldn't open 'pid'");
+    if (pidfd == -1) {
+        if (errno == EAGAIN)
+            errx(1, "Another instance of btpd is probably running in %s.",
+                dir);
+        else
+            err(1, "Couldn't open 'pid'");
+    }
 
     if (btpd_daemon) {
         if (daemon(1, 1) != 0)
@@ -82,6 +87,10 @@ static void
 usage(void)
 {
     printf("Usage: btpd [options] [dir]\n"
+        "\n"
+        "dir:\n"
+        "\tThe directory in which to run btpd.\n"
+        "\tDefault is '$HOME/.btpd'.\n"
         "\n"
         "Options:\n"
         "\n"
@@ -97,11 +106,22 @@ usage(void)
         "\tKeep the btpd process in the foregorund and log to std{out,err}.\n"
         "\tThis option is intended for debugging purposes.\n"
         "\n"
+        "--downloaders n\n"
+        "\tControls the number of simultaneous uploads.\n"
+        "\tThe possible values are:\n"
+        "\t\tn < -1 : Choose n >= 2 based on --bw-out (default).\n"
+        "\t\tn = -1 : Upload to every interested peer.\n"
+        "\t\tn =  0 : Dont't upload to anyone.\n"
+        "\t\tn >  0 : Upload to at most n peers simultaneosly.\n"
+        "\n"
+        "--max-peers n\n"
+        "\tLimit the amount of peers to n.\n"
+        "\n"
         "-p n, --port n\n"
         "\tListen at port n. Default is 6881.\n"
         "\n"
         "--prealloc n\n"
-        "\tPreallocate disk space in chunks n kB. Default is 1.\n"
+        "\tPreallocate disk space in chunks of n kB. Default is 1.\n"
         "\tNote that n will be rounded up to the closest multiple of the\n"
         "\ttorrent piece size. If n is zero no preallocation will be done.\n"
         "\n"
@@ -118,7 +138,9 @@ static struct option longopts[] = {
     { "bw-in",  required_argument,      &longval,       1 },
     { "bw-out", required_argument,      &longval,       2 },
     { "prealloc", required_argument,    &longval,       3 },
-    { "help",   no_argument,            &longval,       5 },
+    { "downloaders", required_argument, &longval,       4 },
+    { "max-peers", required_argument,   &longval,       5 },
+    { "help",   no_argument,            &longval,       128 },
     { NULL,     0,                      NULL,           0 }
 };
 
@@ -150,6 +172,12 @@ main(int argc, char **argv)
             case 3:
                 cm_alloc_size = atoi(optarg) * 1024;
                 break;
+            case 4:
+                net_max_downloaders = atoi(optarg);
+                break;
+            case 5:
+                net_max_peers = atoi(optarg);
+                break;
             default:
                 usage();
             }
diff --git a/btpd/net.c b/btpd/net.c
index c728efd..43b43f8 100644
--- a/btpd/net.c
+++ b/btpd/net.c
@@ -626,16 +626,9 @@ net_init(void)
     m_bw_bytes_out = net_bw_limit_out;
     m_bw_bytes_in = net_bw_limit_in;
 
-    int nfiles = getdtablesize();
-    if (nfiles <= 20)
-        btpd_err("Too few open files allowed (%d). "
-                 "Check \"ulimit -n\"\n", nfiles);
-    else if (nfiles < 64)
-        btpd_log(BTPD_L_BTPD,
-                 "You have restricted the number of open files to %d. "
-                 "More could be beneficial to the download performance.\n",
-                 nfiles);
-    net_max_peers = nfiles - 20;
+    int safe_fds = min(getdtablesize(), FD_SETSIZE) * 4 / 5;
+    if (net_max_peers == 0 || net_max_peers > safe_fds)
+        net_max_peers = safe_fds;
 
     int sd;
     int flag = 1;
diff --git a/btpd/opts.c b/btpd/opts.c
index 9c68678..7321727 100644
--- a/btpd/opts.c
+++ b/btpd/opts.c
@@ -7,6 +7,7 @@ uint32_t btpd_logmask = BTPD_L_ALL;
 #else
 uint32_t btpd_logmask =  BTPD_L_BTPD | BTPD_L_ERROR;
 #endif
+int net_max_downloaders = -2;
 unsigned net_max_peers;
 unsigned net_bw_limit_in;
 unsigned net_bw_limit_out;
diff --git a/btpd/opts.h b/btpd/opts.h
index 98e2dbd..c47ea63 100644
--- a/btpd/opts.h
+++ b/btpd/opts.h
@@ -4,6 +4,7 @@
 extern short btpd_daemon;
 extern const char *btpd_dir;
 extern uint32_t btpd_logmask;
+extern int net_max_downloaders;
 extern unsigned net_max_peers;
 extern unsigned net_bw_limit_in;
 extern unsigned net_bw_limit_out;
diff --git a/btpd/upload.c b/btpd/upload.c
index c812881..f8403ad 100644
--- a/btpd/upload.c
+++ b/btpd/upload.c
@@ -7,7 +7,7 @@
 static struct event m_choke_timer;
 static unsigned m_npeers;
 static struct peer_tq m_peerq = BTPDQ_HEAD_INITIALIZER(m_peerq);
-static int m_max_downloaders = 4;
+static int m_max_downloaders;
 
 struct peer_sort {
     struct peer *p;
@@ -32,7 +32,7 @@ rate_cmp(const void *arg1, const void *arg2)
 static void
 choke_do(void)
 {
-    if (m_max_downloaders == -1) {
+    if (m_max_downloaders < 0) {
         struct peer *p;
         BTPDQ_FOREACH(p, &m_peerq, ul_entry)
             if (p->flags & PF_I_CHOKE)
@@ -42,7 +42,7 @@ choke_do(void)
         BTPDQ_FOREACH(p, &m_peerq, ul_entry)
             if ((p->flags & PF_I_CHOKE) == 0)
                 peer_choke(p);
-    } else if (m_npeers > 0) {
+    } else {
         struct peer_sort worthy[m_npeers];
         int nworthy = 0;
         int i = 0;
@@ -171,6 +171,21 @@ ul_on_uninterest(struct peer *p)
 void
 ul_init(void)
 {
+    if (net_max_downloaders >= -1)
+        m_max_downloaders = net_max_downloaders;
+    else {
+        if (net_bw_limit_out == 0)
+            m_max_downloaders = 8;
+        else if (net_bw_limit_out < (10 << 10))
+            m_max_downloaders = 2;
+        else if (net_bw_limit_out < (20 << 10))
+            m_max_downloaders = 3;
+        else if (net_bw_limit_out < (40 << 10))
+            m_max_downloaders = 4;
+        else
+            m_max_downloaders = 5 + (net_bw_limit_out / (100 << 10));
+    }
+
     evtimer_set(&m_choke_timer, choke_cb, NULL);
     evtimer_add(&m_choke_timer, CHOKE_INTERVAL);
 }