summary refs log tree commit diff
path: root/cli/btcli.c
diff options
context:
space:
mode:
authorRichard Nyberg <rnyberg@murmeldjur.se>2006-09-13 07:02:07 +0000
committerRichard Nyberg <rnyberg@murmeldjur.se>2006-09-13 07:02:07 +0000
commit86754d7d53b59ce52de51a32f865d4916c119bdb (patch)
treef017a8199a94e675fb50f55876119fe9e9d1944b /cli/btcli.c
parent763cbbb59f40bdfb2478e58a685acfc262876af6 (diff)
downloadbtpd-86754d7d53b59ce52de51a32f865d4916c119bdb.tar.gz
btpd-86754d7d53b59ce52de51a32f865d4916c119bdb.zip
btpd now has a library of torrents indexed by number and info hash.
The add and del commands adds or removes torrents from this library.
The start and stop commands are used to active or deactivate torrents.
Also, a mechanism for qeurying data on torrents has been added. It's
only used by the btcli list and stat commands yet though.

btcli has been split into different files for each command.

Both btpd and btcli now use misc/btpd_if.h for all ipc definitions.

Misc changes:
- struct metainfo is gone. Use the new mi_* functions.
- Add printf format type checking where appropriate.

Diffstat (limited to 'cli/btcli.c')
-rw-r--r--cli/btcli.c403
1 files changed, 34 insertions, 369 deletions
diff --git a/cli/btcli.c b/cli/btcli.c
index 95ae487..f8b6a81 100644
--- a/cli/btcli.c
+++ b/cli/btcli.c
@@ -1,21 +1,4 @@
-#include <sys/types.h>
-#include <sys/stat.h>
-
-#include <err.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <getopt.h>
-#include <inttypes.h>
-#include <limits.h>
-#include <math.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-
-#include "btpd_if.h"
-#include "metainfo.h"
-#include "subr.h"
+#include "btcli.h"
 
 const char *btpd_dir;
 struct ipc *ipc;
@@ -27,377 +10,55 @@ btpd_connect(void)
         err(1, "cannot open connection to btpd in %s", btpd_dir);
 }
 
-enum ipc_code
-handle_ipc_res(enum ipc_code code, const char *target)
+enum ipc_err
+handle_ipc_res(enum ipc_err code, const char *target)
 {
     switch (code) {
     case IPC_OK:
         break;
-    case IPC_FAIL:
-        warnx("btpd couldn't execute the requested operation for %s", target);
-        break;
-    case IPC_ERROR:
-        warnx("btpd encountered an error for %s", target);
-        break;
-    default:
+    case IPC_COMMERR:
         errx(1, "fatal error in communication with btpd");
+    default:
+        warnx("btpd response for '%s': %s", target, ipc_strerror(code));
     }
     return code;
 }
 
 char
-state_char(struct tpstat *ts)
+tstate_char(enum ipc_tstate ts)
 {
-    switch (ts->state) {
-    case T_STARTING:
+    switch (ts) {
+    case IPC_TSTATE_INACTIVE:
+        return 'I';
+    case IPC_TSTATE_START:
         return '+';
-    case T_ACTIVE:
-        return ts->pieces_got == ts->torrent_pieces ? 'S' : 'L';
-    case T_STOPPING:
+    case IPC_TSTATE_STOP:
         return '-';
-    default:
-        return ' ';
+    case IPC_TSTATE_LEECH:
+        return 'L';
+    case IPC_TSTATE_SEED:
+        return 'S';
     }
+    errx(1, "bad state");
 }
 
-void
-print_stat(struct tpstat *ts)
-{
-    printf("%c %5.1f%% %6.1fM %7.2fkB/s %6.1fM %7.2fkB/s %4u %5.1f%%",
-        state_char(ts),
-        floor(1000.0 * ts->content_got / ts->content_size) / 10,
-        (double)ts->downloaded / (1 << 20),
-        (double)ts->rate_down / (20 << 10),
-        (double)ts->uploaded / (1 << 20),
-        (double)ts->rate_up / (20 << 10),
-        ts->peers,
-        floor(1000.0 * ts->pieces_seen / ts->torrent_pieces) / 10);
-    if (ts->tr_errors > 0)
-        printf(" E%u", ts->tr_errors);
-    printf("\n");
-}
-
-void
-usage_add(void)
-{
-    printf(
-        "Add torrents to btpd.\n"
-        "\n"
-        "Usage: add [--topdir] -d dir file\n"
-        "       add file ...\n"
-        "\n"
-        "Arguments:\n"
-        "file ...\n"
-        "\tOne or more torrents to add.\n"
-        "\n"
-        "Options:\n"
-        "-d dir\n"
-        "\tUse the dir for content.\n"
-        "\n"
-        "--topdir\n"
-        "\tAppend the torrent top directory (if any) to the content path.\n"
-        "\tThis option cannot be used without the '-d' option.\n"
-        "\n"
-        );
-    exit(1);
-}
-
-struct option add_opts [] = {
-    { "help", no_argument, NULL, 'H' },
-    { "topdir", no_argument, NULL, 'T'},
-    {NULL, 0, NULL, 0}
-};
-
 int
-content_link(uint8_t *hash, char *buf)
-{
-    int n;
-    char relpath[41];
-    char path[PATH_MAX];
-    for (int i = 0; i < 20; i++)
-        snprintf(relpath + i * 2, 3, "%.2x", hash[i]);
-    snprintf(path, PATH_MAX, "%s/torrents/%s/content", btpd_dir, relpath);
-    if ((n = readlink(path, buf, PATH_MAX)) == -1)
-        return errno;
-    buf[min(n, PATH_MAX)] = '\0';
-    return 0;
-}
-
-void
-cmd_add(int argc, char **argv)
-{
-    int ch, topdir = 0;
-    char *dir = NULL;
-
-    while ((ch = getopt_long(argc, argv, "d:", add_opts, NULL)) != -1) {
-        switch (ch) {
-        case 'T':
-            topdir = 1;
-            break;
-        case 'd':
-            dir = optarg;
-            break;
-        default:
-            usage_add();
-        }
-    }
-    argc -= optind;
-    argv += optind;
-
-    if (argc < 1 || (topdir == 1 && dir == NULL) || (dir != NULL && argc > 1))
-        usage_add();
-
-    btpd_connect();
-    for (int i = 0; i < argc; i++) {
-        struct metainfo *mi;
-        char rdpath[PATH_MAX], dpath[PATH_MAX], fpath[PATH_MAX];
-
-        if ((errno = load_metainfo(argv[i], -1, 0, &mi)) != 0) {
-            warn("error loading torrent %s", argv[i]);
-            continue;
-        }
-
-        if ((topdir &&
-                !(mi->nfiles == 1
-                    && strcmp(mi->name, mi->files[0].path) == 0)))
-            snprintf(dpath, PATH_MAX, "%s/%s", dir, mi->name);
-        else if (dir != NULL)
-            strncpy(dpath, dir, PATH_MAX);
-        else {
-            if (content_link(mi->info_hash, dpath) != 0) {
-                warnx("unknown content dir for %s", argv[i]);
-                errx(1, "use the '-d' option");
-            }
-        }
-
-        if (mkdir(dpath, 0777) != 0 && errno != EEXIST)
-            err(1, "couldn't create directory %s", dpath);
-
-        if (realpath(dpath, rdpath) == NULL)
-            err(1, "path error on %s", dpath);
-
-        if (realpath(argv[i], fpath) == NULL)
-            err(1, "path error on %s", fpath);
-
-        handle_ipc_res(btpd_add(ipc, mi->info_hash, fpath, rdpath), argv[i]);
-        clear_metainfo(mi);
-        free(mi);
-    }
-}
-
-void
-usage_del(void)
-{
-    printf(
-        "Remove torrents from btpd.\n"
-        "\n"
-        "Usage: del file ...\n"
-        "\n"
-        "Arguments:\n"
-        "file ...\n"
-        "\tThe torrents to remove.\n"
-        "\n");
-    exit(1);
-}
-
-void
-cmd_del(int argc, char **argv)
-{
-    if (argc < 2)
-        usage_del();
-
-    btpd_connect();
-    for (int i = 1; i < argc; i++) {
-        struct metainfo *mi;
-        if ((errno = load_metainfo(argv[i], -1, 0, &mi)) != 0) {
-            warn("error loading torrent %s", argv[i]);
-            continue;
-        }
-        handle_ipc_res(btpd_del(ipc, mi->info_hash), argv[i]);
-        clear_metainfo(mi);
-        free(mi);
-    }
-}
-
-void
-usage_kill(void)
-{
-    printf(
-        "Shutdown btpd.\n"
-        "\n"
-        "Usage: kill [seconds]\n"
-        "\n"
-        "Arguments:\n"
-        "seconds\n"
-        "\tThe number of seconds btpd waits before giving up on unresponsive\n"
-        "\ttrackers.\n"
-        "\n"
-        );
-    exit(1);
-}
-
-void
-cmd_kill(int argc, char **argv)
-{
-    int seconds = -1;
-    char *endptr;
-
-    if (argc == 2) {
-        seconds = strtol(argv[1], &endptr, 10);
-        if (strlen(argv[1]) > endptr - argv[1] || seconds < 0)
-            usage_kill();
-    } else if (argc > 2)
-        usage_kill();
-
-    btpd_connect();
-    handle_ipc_res(btpd_die(ipc, seconds), "kill");
-}
-
-void
-usage_list(void)
-{
-    printf(
-        "List active torrents.\n"
-        "\n"
-        "Usage: list\n"
-        "\n"
-        );
-    exit(1);
-}
-
-void
-cmd_list(int argc, char **argv)
-{
-    struct btstat *st;
-
-    if (argc > 1)
-        usage_list();
-
-    btpd_connect();
-    if (handle_ipc_res(btpd_stat(ipc, &st), "list") != IPC_OK)
-        exit(1);
-    for (int i = 0; i < st->ntorrents; i++) {
-        struct tpstat *ts = &st->torrents[i];
-        printf("%c. %s\n", state_char(ts), ts->name);
-    }
-    printf("%u torrent%s.\n", st->ntorrents,
-        st->ntorrents == 1 ? "" : "s");
-}
-
-void
-usage_stat(void)
-{
-    printf(
-        "Display stats for active torrents.\n"
-        "The displayed stats are:\n"
-        "%% got, MB down, rate down. MB up, rate up\n"
-        "peer count, %% of pieces seen, tracker errors\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"
-        "-w n\n"
-        "\tDisplay stats every n seconds.\n"
-        "\n");
-    exit(1);
-}
-
-void
-do_stat(int individual, int seconds, int hash_count, uint8_t (*hashes)[20])
-{
-    struct btstat *st;
-    struct tpstat tot;
-again:
-    bzero(&tot, sizeof(tot));
-    tot.state = -1;
-    if (handle_ipc_res(btpd_stat(ipc, &st), "stat") != IPC_OK)
-        exit(1);
-    for (int i = 0; i < st->ntorrents; i++) {
-        struct tpstat *cur = &st->torrents[i];
-        if (hash_count > 0) {
-            int found = 0;
-            for (int h = 0; !found && h < hash_count; h++)
-                if (bcmp(cur->hash, hashes[h], 20) == 0)
-                    found = 1;
-            if (!found)
-                continue;
-        }
-        tot.uploaded += cur->uploaded;
-        tot.downloaded += cur->downloaded;
-        tot.rate_up += cur->rate_up;
-        tot.rate_down += cur->rate_down;
-        tot.peers += cur->peers;
-        tot.pieces_seen += cur->pieces_seen;
-        tot.torrent_pieces += cur->torrent_pieces;
-        tot.content_got += cur->content_got;
-        tot.content_size += cur->content_size;
-        if (cur->tr_errors > 0)
-            tot.tr_errors++;
-        if (individual) {
-            printf("%s:\n", cur->name);
-            print_stat(cur);
-        }
-    }
-    free_btstat(st);
-    if (individual)
-        printf("Total:\n");
-    print_stat(&tot);
-    if (seconds > 0) {
-        sleep(seconds);
-        goto again;
-    }
-}
-
-struct option stat_opts [] = {
-    { "help", no_argument, NULL, 'H' },
-    {NULL, 0, NULL, 0}
-};
-
-void
-cmd_stat(int argc, char **argv)
+torrent_spec(char *arg, struct ipc_torrent *tp)
 {
-    int ch;
-    int wflag = 0, iflag = 0, seconds = 0;
-    uint8_t (*hashes)[20] = NULL;
-    char *endptr;
-    while ((ch = getopt_long(argc, argv, "iw:", stat_opts, NULL)) != -1) {
-        switch (ch) {
-        case 'i':
-            iflag = 1;
-            break;
-        case 'w':
-            wflag = 1;
-            seconds = strtol(optarg, &endptr, 10);
-            if (strlen(optarg) > endptr - optarg || seconds < 1)
-                usage_stat();
-            break;
-        default:
-            usage_stat();
-        }
+    char *p;
+    tp->u.num = strtoul(arg, &p, 10);
+    if (*p == '\0') {
+        tp->by_hash = 0;
+        return 1;
     }
-    argc -= optind;
-    argv += optind;
-
-    if (argc > 0) {
-        hashes = malloc(argc * 20);
-        for (int i = 0; i < argc; i++) {
-            struct metainfo *mi;
-            if ((errno = load_metainfo(argv[i], -1, 0, &mi)) != 0)
-                err(1, "error loading torrent %s", argv[i]);
-            bcopy(mi->info_hash, hashes[i], 20);
-            clear_metainfo(mi);
-            free(mi);
-        }
+    if ((p = mi_load(arg, NULL)) == NULL) {
+        warnx("bad torrent '%s' (%s)", arg, strerror(errno));
+        return 0;
     }
-    btpd_connect();
-    do_stat(iflag, seconds, argc, hashes);
+    tp->by_hash = 1;
+    mi_info_hash(p, tp->u.hash);
+    free(p);
+    return 1;
 }
 
 struct {
@@ -409,6 +70,8 @@ struct {
     { "del", cmd_del, usage_del },
     { "kill", cmd_kill, usage_kill },
     { "list", cmd_list, usage_list },
+    { "start", cmd_start, usage_start },
+    { "stop", cmd_stop, usage_stop },
     { "stat", cmd_stat, usage_stat }
 };
 
@@ -434,7 +97,9 @@ usage(void)
         "del\n"
         "kill\n"
         "list\n"
+        "start\n"
         "stat\n"
+        "stop\n"
         "\n");
     exit(1);
 }