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.

425 lignes
8.9 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 btpd stats.\n"
  152. "\n"
  153. "Usage: stat [-i] [-w seconds]\n"
  154. "\n"
  155. "Options:\n"
  156. "-i\n"
  157. "\tDisplay indivudal lines for each active torrent.\n"
  158. "\n"
  159. "-w n\n"
  160. "\tDisplay stats every n seconds.\n"
  161. "\n");
  162. exit(1);
  163. }
  164. void
  165. do_stat(int individual, int seconds)
  166. {
  167. struct btstat *st;
  168. struct tpstat tot;
  169. again:
  170. bzero(&tot, sizeof(tot));
  171. if ((errno = btpd_stat(ipc, &st)) != 0)
  172. err(1, "btpd_stat");
  173. for (int i = 0; i < st->ntorrents; i++) {
  174. struct tpstat *cur = &st->torrents[i];
  175. if (cur->state != 'A')
  176. continue;
  177. if (!individual) {
  178. tot.uploaded += cur->uploaded;
  179. tot.downloaded += cur->downloaded;
  180. tot.rate_up += cur->rate_up;
  181. tot.rate_down += cur->rate_down;
  182. tot.npeers += cur->npeers;
  183. continue;
  184. }
  185. printf("%u. %5.1f%% %6.1fM %7.2fkB/s %6.1fM %7.2fkB/s %4u %5.1f%%",
  186. cur->num,
  187. 100.0 * cur->have / cur->total,
  188. (double)cur->downloaded / (1 << 20),
  189. (double)cur->rate_down / (20 << 10),
  190. (double)cur->uploaded / (1 << 20),
  191. (double)cur->rate_up / (20 << 10),
  192. cur->npeers,
  193. 100.0 * cur->nseen / cur->npieces
  194. );
  195. if (cur->errors > 0)
  196. printf(" E%u", cur->errors);
  197. printf("\n");
  198. }
  199. free_btstat(st);
  200. if (!individual) {
  201. printf("%6.1fM %7.2fkB/s %6.1fM %7.2fkB/s %4u\n",
  202. (double)tot.downloaded / (1 << 20),
  203. (double)tot.rate_down / (20 << 10),
  204. (double)tot.uploaded / (1 << 20),
  205. (double)tot.rate_up / (20 << 10),
  206. tot.npeers);
  207. }
  208. if (seconds > 0) {
  209. sleep(seconds);
  210. goto again;
  211. }
  212. }
  213. static struct option stat_opts [] = {
  214. { "help", no_argument, NULL, 1 },
  215. {NULL, 0, NULL, 0}
  216. };
  217. void
  218. cmd_stat(int argc, char **argv)
  219. {
  220. int ch;
  221. int wflag = 0, iflag = 0, seconds = 0;
  222. char *endptr;
  223. while ((ch = getopt_long(argc, argv, "iw:", stat_opts, NULL)) != -1) {
  224. switch (ch) {
  225. case 'i':
  226. iflag = 1;
  227. break;
  228. case 'w':
  229. wflag = 1;
  230. seconds = strtol(optarg, &endptr, 10);
  231. if (strlen(optarg) > endptr - optarg || seconds < 1)
  232. usage_stat();
  233. break;
  234. default:
  235. usage_stat();
  236. }
  237. }
  238. argc -= optind;
  239. argv += optind;
  240. if (argc > 0)
  241. usage_stat();
  242. btpd_connect();
  243. do_stat(iflag, seconds);
  244. }
  245. void
  246. usage_start(void)
  247. {
  248. printf(
  249. "Activate torrents.\n"
  250. "\n"
  251. "Usage: start num ...\n"
  252. "\n"
  253. "Arguments:\n"
  254. "num\n"
  255. "\tThe number of the torrent to activate.\n"
  256. "\n");
  257. exit(1);
  258. }
  259. void
  260. cmd_start(int argc, char **argv)
  261. {
  262. if (argc < 2)
  263. usage_start();
  264. unsigned nums[argc - 1];
  265. char *endptr;
  266. for (int i = 0; i < argc - 1; i++) {
  267. nums[i] = strtoul(argv[i + 1], &endptr, 10);
  268. if (strlen(argv[i + 1]) > endptr - argv[i + 1])
  269. usage_start();
  270. }
  271. btpd_connect();
  272. for (int i = 0; i < argc -1; i++)
  273. handle_ipc_res(btpd_start_num(ipc, nums[i]));
  274. }
  275. void
  276. usage_stop(void)
  277. {
  278. printf(
  279. "Deactivate torrents.\n"
  280. "\n"
  281. "Usage: stop num ...\n"
  282. "\n"
  283. "Arguments:\n"
  284. "num\n"
  285. "\tThe number of the torrent to deactivate.\n"
  286. "\n");
  287. exit(1);
  288. }
  289. void
  290. cmd_stop(int argc, char **argv)
  291. {
  292. if (argc < 2)
  293. usage_stop();
  294. unsigned nums[argc - 1];
  295. char *endptr;
  296. for (int i = 0; i < argc - 1; i++) {
  297. nums[i] = strtoul(argv[i + 1], &endptr, 10);
  298. if (strlen(argv[i + 1]) > endptr - argv[i + 1])
  299. usage_stop();
  300. }
  301. btpd_connect();
  302. for (int i = 0; i < argc -1; i++)
  303. handle_ipc_res(btpd_stop_num(ipc, nums[i]));
  304. }
  305. static struct {
  306. const char *name;
  307. void (*fun)(int, char **);
  308. void (*help)(void);
  309. } cmd_table[] = {
  310. { "add", cmd_add, usage_add },
  311. { "del", cmd_del, usage_del },
  312. { "kill", cmd_kill, usage_kill },
  313. { "list", cmd_list, usage_list },
  314. { "start", cmd_start, usage_start },
  315. { "stat", cmd_stat, usage_stat },
  316. { "stop", cmd_stop, usage_stop }
  317. };
  318. static int ncmds = sizeof(cmd_table) / sizeof(cmd_table[0]);
  319. void
  320. usage(void)
  321. {
  322. printf(
  323. "btcli is the btpd command line interface. Use this tool to interact\n"
  324. "with a btpd process.\n"
  325. "\n"
  326. "Usage: btcli [main options] command [command options]\n"
  327. "\n"
  328. "Main options:\n"
  329. "-d dir\n"
  330. "\tThe btpd directory.\n"
  331. "\n"
  332. "--help [command]\n"
  333. "\tShow this text or help for the specified command.\n"
  334. "\n"
  335. "Commands:\n"
  336. "add\n"
  337. "del\n"
  338. "kill\n"
  339. "list\n"
  340. "start\n"
  341. "stat\n"
  342. "stop\n"
  343. "\n");
  344. exit(1);
  345. }
  346. static struct option base_opts [] = {
  347. { "help", no_argument, NULL, 1 },
  348. {NULL, 0, NULL, 0}
  349. };
  350. int
  351. main(int argc, char **argv)
  352. {
  353. int ch, help = 0;
  354. if (argc < 2)
  355. usage();
  356. while ((ch = getopt_long(argc, argv, "+d:", base_opts, NULL)) != -1) {
  357. switch (ch) {
  358. case 'd':
  359. btpd_dir = optarg;
  360. break;
  361. case 1:
  362. help = 1;
  363. break;
  364. default:
  365. usage();
  366. }
  367. }
  368. argc -= optind;
  369. argv += optind;
  370. if (argc == 0)
  371. usage();
  372. optind = 0;
  373. int found = 0;
  374. for (int i = 0; !found && i < ncmds; i++) {
  375. if (strcmp(argv[0], cmd_table[i].name) == 0) {
  376. found = 1;
  377. if (help)
  378. cmd_table[i].help();
  379. else
  380. cmd_table[i].fun(argc, argv);
  381. }
  382. }
  383. if (!found)
  384. usage();
  385. return 0;
  386. }