A clone of btpd with my configuration changes.
Vous ne pouvez pas sélectionner plus de 25 sujets Les noms de sujets doivent commencer par une lettre ou un nombre, peuvent contenir des tirets ('-') et peuvent comporter jusqu'à 35 caractères.

433 lignes
9.0 KiB

  1. #include <err.h>
  2. #include <errno.h>
  3. #include <getopt.h>
  4. #include <stdio.h>
  5. #include <stdlib.h>
  6. #include <string.h>
  7. #include "btpd_if.h"
  8. static const char *btpd_dir = "/usr/btpd";
  9. static struct ipc *ipc;
  10. static void
  11. handle_ipc_res(enum ipc_code code)
  12. {
  13. switch (code) {
  14. case IPC_OK:
  15. return;
  16. case IPC_FAIL:
  17. warnx("Ipc failed.\n");
  18. break;
  19. case IPC_COMMERR:
  20. errx(1, "Communication error.\n");
  21. }
  22. }
  23. static void
  24. btpd_connect(void)
  25. {
  26. if ((errno = ipc_open(btpd_dir, &ipc)) != 0)
  27. errx(1, "Couldn't connect to btpd in %s (%s).\n",
  28. btpd_dir, strerror(errno));
  29. }
  30. void
  31. usage_add(void)
  32. {
  33. printf(
  34. "Add a torrent to btpd.\n"
  35. "\n"
  36. "Usage: add [-a] [-s] [-c dir] -f file\n"
  37. "\n"
  38. "Options:\n"
  39. "-a\n"
  40. "\tAppend the torrent top directory (if any) to the content path.\n"
  41. "\n"
  42. "-c dir\n"
  43. "\tThe directory where the content is (or will be downloaded to).\n"
  44. "\tDefault is the directory containing the torrent file.\n"
  45. "\n"
  46. "-f file\n"
  47. "\tThe torrent to add.\n"
  48. "\n"
  49. "-s\n"
  50. "\tStart the torrent.\n"
  51. "\n"
  52. );
  53. exit(1);
  54. }
  55. void
  56. cmd_add(int argc, char **argv)
  57. {
  58. }
  59. void
  60. usage_del(void)
  61. {
  62. printf(
  63. "Remove torrents from btpd.\n"
  64. "\n"
  65. "Usage: del num ...\n"
  66. "\n"
  67. "Arguments:\n"
  68. "num\n"
  69. "\tThe number of the torrent to remove.\n"
  70. "\n");
  71. exit(1);
  72. }
  73. void
  74. cmd_del(int argc, char **argv)
  75. {
  76. if (argc < 2)
  77. usage_del();
  78. unsigned nums[argc - 1];
  79. char *endptr;
  80. for (int i = 0; i < argc - 1; i++) {
  81. nums[i] = strtoul(argv[i + 1], &endptr, 10);
  82. if (strlen(argv[i + 1]) > endptr - argv[i + 1])
  83. usage_del();
  84. }
  85. btpd_connect();
  86. for (int i = 0; i < argc -1; i++)
  87. handle_ipc_res(btpd_del_num(ipc, nums[i]));
  88. }
  89. void
  90. usage_kill(void)
  91. {
  92. printf(
  93. "Shutdown btpd.\n"
  94. "\n"
  95. "Usage: kill [seconds]\n"
  96. "\n"
  97. "Arguments:\n"
  98. "seconds\n"
  99. "\tThe number of seconds btpd waits before giving up on unresponsive\n"
  100. "\ttrackers.\n"
  101. "\n"
  102. );
  103. exit(1);
  104. }
  105. void
  106. cmd_kill(int argc, char **argv)
  107. {
  108. int seconds = -1;
  109. char *endptr;
  110. if (argc == 1)
  111. ;
  112. else if (argc == 2) {
  113. seconds = strtol(argv[1], &endptr, 10);
  114. if (strlen(argv[1]) > endptr - argv[1] || seconds < 0)
  115. usage_kill();
  116. } else
  117. usage_kill();
  118. btpd_connect();
  119. btpd_die(ipc, seconds);
  120. }
  121. void
  122. usage_list(void)
  123. {
  124. printf(
  125. "List btpd's torrents.\n"
  126. "\n"
  127. "Usage: list\n"
  128. "\n"
  129. );
  130. exit(1);
  131. }
  132. void
  133. cmd_list(int argc, char **argv)
  134. {
  135. struct btstat *st;
  136. if (argc > 1)
  137. usage_list();
  138. btpd_connect();
  139. if ((errno = btpd_stat(ipc, &st)) != 0)
  140. err(1, "btpd_stat");
  141. for (int i = 0; i < st->ntorrents; i++)
  142. printf("%u. %s (%c)\n", st->torrents[i].num, st->torrents[i].name,
  143. st->torrents[i].state);
  144. printf("Listed %u torrent%s.\n", st->ntorrents,
  145. st->ntorrents == 1 ? "" : "s");
  146. }
  147. void
  148. usage_stat(void)
  149. {
  150. printf(
  151. "Display stats for active torrents.\n"
  152. "The stats displayed are:\n"
  153. "%% got, MB down, rate down. MB up, rate up\n"
  154. "peers, %% of pieces seen, tracker errors\n"
  155. "\n"
  156. "Usage: stat [-i] [-w seconds]\n"
  157. "\n"
  158. "Options:\n"
  159. "-i\n"
  160. "\tDisplay indivudal lines for each active torrent.\n"
  161. "\n"
  162. "-w n\n"
  163. "\tDisplay stats every n seconds.\n"
  164. "\n");
  165. exit(1);
  166. }
  167. void
  168. print_stat(struct tpstat *cur)
  169. {
  170. printf("%5.1f%% %6.1fM %7.2fkB/s %6.1fM %7.2fkB/s %4u %5.1f%%",
  171. 100.0 * cur->have / cur->total,
  172. (double)cur->downloaded / (1 << 20),
  173. (double)cur->rate_down / (20 << 10),
  174. (double)cur->uploaded / (1 << 20),
  175. (double)cur->rate_up / (20 << 10),
  176. cur->npeers,
  177. 100.0 * cur->nseen / cur->npieces
  178. );
  179. if (cur->errors > 0)
  180. printf(" E%u", cur->errors);
  181. printf("\n");
  182. }
  183. void
  184. do_stat(int individual, int seconds)
  185. {
  186. struct btstat *st;
  187. struct tpstat tot;
  188. again:
  189. bzero(&tot, sizeof(tot));
  190. tot.num = -1;
  191. if ((errno = btpd_stat(ipc, &st)) != 0)
  192. err(1, "btpd_stat");
  193. for (int i = 0; i < st->ntorrents; i++) {
  194. struct tpstat *cur = &st->torrents[i];
  195. if (cur->state != 'A')
  196. continue;
  197. tot.uploaded += cur->uploaded;
  198. tot.downloaded += cur->downloaded;
  199. tot.rate_up += cur->rate_up;
  200. tot.rate_down += cur->rate_down;
  201. tot.npeers += cur->npeers;
  202. tot.nseen += cur->nseen;
  203. tot.npieces += cur->npieces;
  204. tot.have += cur->have;
  205. tot.total += cur->total;
  206. if (individual) {
  207. printf("%u. %s:\n", cur->num, cur->name);
  208. print_stat(cur);
  209. }
  210. }
  211. free_btstat(st);
  212. if (individual)
  213. printf("Total:\n");
  214. print_stat(&tot);
  215. if (seconds > 0) {
  216. sleep(seconds);
  217. goto again;
  218. }
  219. }
  220. static struct option stat_opts [] = {
  221. { "help", no_argument, NULL, 1 },
  222. {NULL, 0, NULL, 0}
  223. };
  224. void
  225. cmd_stat(int argc, char **argv)
  226. {
  227. int ch;
  228. int wflag = 0, iflag = 0, seconds = 0;
  229. char *endptr;
  230. while ((ch = getopt_long(argc, argv, "iw:", stat_opts, NULL)) != -1) {
  231. switch (ch) {
  232. case 'i':
  233. iflag = 1;
  234. break;
  235. case 'w':
  236. wflag = 1;
  237. seconds = strtol(optarg, &endptr, 10);
  238. if (strlen(optarg) > endptr - optarg || seconds < 1)
  239. usage_stat();
  240. break;
  241. default:
  242. usage_stat();
  243. }
  244. }
  245. argc -= optind;
  246. argv += optind;
  247. if (argc > 0)
  248. usage_stat();
  249. btpd_connect();
  250. do_stat(iflag, seconds);
  251. }
  252. void
  253. usage_start(void)
  254. {
  255. printf(
  256. "Activate torrents.\n"
  257. "\n"
  258. "Usage: start num ...\n"
  259. "\n"
  260. "Arguments:\n"
  261. "num\n"
  262. "\tThe number of the torrent to activate.\n"
  263. "\n");
  264. exit(1);
  265. }
  266. void
  267. cmd_start(int argc, char **argv)
  268. {
  269. if (argc < 2)
  270. usage_start();
  271. unsigned nums[argc - 1];
  272. char *endptr;
  273. for (int i = 0; i < argc - 1; i++) {
  274. nums[i] = strtoul(argv[i + 1], &endptr, 10);
  275. if (strlen(argv[i + 1]) > endptr - argv[i + 1])
  276. usage_start();
  277. }
  278. btpd_connect();
  279. for (int i = 0; i < argc -1; i++)
  280. handle_ipc_res(btpd_start_num(ipc, nums[i]));
  281. }
  282. void
  283. usage_stop(void)
  284. {
  285. printf(
  286. "Deactivate torrents.\n"
  287. "\n"
  288. "Usage: stop num ...\n"
  289. "\n"
  290. "Arguments:\n"
  291. "num\n"
  292. "\tThe number of the torrent to deactivate.\n"
  293. "\n");
  294. exit(1);
  295. }
  296. void
  297. cmd_stop(int argc, char **argv)
  298. {
  299. if (argc < 2)
  300. usage_stop();
  301. unsigned nums[argc - 1];
  302. char *endptr;
  303. for (int i = 0; i < argc - 1; i++) {
  304. nums[i] = strtoul(argv[i + 1], &endptr, 10);
  305. if (strlen(argv[i + 1]) > endptr - argv[i + 1])
  306. usage_stop();
  307. }
  308. btpd_connect();
  309. for (int i = 0; i < argc -1; i++)
  310. handle_ipc_res(btpd_stop_num(ipc, nums[i]));
  311. }
  312. static struct {
  313. const char *name;
  314. void (*fun)(int, char **);
  315. void (*help)(void);
  316. } cmd_table[] = {
  317. { "add", cmd_add, usage_add },
  318. { "del", cmd_del, usage_del },
  319. { "kill", cmd_kill, usage_kill },
  320. { "list", cmd_list, usage_list },
  321. { "start", cmd_start, usage_start },
  322. { "stat", cmd_stat, usage_stat },
  323. { "stop", cmd_stop, usage_stop }
  324. };
  325. static int ncmds = sizeof(cmd_table) / sizeof(cmd_table[0]);
  326. void
  327. usage(void)
  328. {
  329. printf(
  330. "btcli is the btpd command line interface. Use this tool to interact\n"
  331. "with a btpd process.\n"
  332. "\n"
  333. "Usage: btcli [main options] command [command options]\n"
  334. "\n"
  335. "Main options:\n"
  336. "-d dir\n"
  337. "\tThe btpd directory.\n"
  338. "\n"
  339. "--help [command]\n"
  340. "\tShow this text or help for the specified command.\n"
  341. "\n"
  342. "Commands:\n"
  343. "add\n"
  344. "del\n"
  345. "kill\n"
  346. "list\n"
  347. "start\n"
  348. "stat\n"
  349. "stop\n"
  350. "\n");
  351. exit(1);
  352. }
  353. static struct option base_opts [] = {
  354. { "help", no_argument, NULL, 1 },
  355. {NULL, 0, NULL, 0}
  356. };
  357. int
  358. main(int argc, char **argv)
  359. {
  360. int ch, help = 0;
  361. if (argc < 2)
  362. usage();
  363. while ((ch = getopt_long(argc, argv, "+d:", base_opts, NULL)) != -1) {
  364. switch (ch) {
  365. case 'd':
  366. btpd_dir = optarg;
  367. break;
  368. case 1:
  369. help = 1;
  370. break;
  371. default:
  372. usage();
  373. }
  374. }
  375. argc -= optind;
  376. argv += optind;
  377. if (argc == 0)
  378. usage();
  379. optind = 0;
  380. int found = 0;
  381. for (int i = 0; !found && i < ncmds; i++) {
  382. if (strcmp(argv[0], cmd_table[i].name) == 0) {
  383. found = 1;
  384. if (help)
  385. cmd_table[i].help();
  386. else
  387. cmd_table[i].fun(argc, argv);
  388. }
  389. }
  390. if (!found)
  391. usage();
  392. return 0;
  393. }