geom_gate userland utility improvements
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

643 lines
15 KiB

  1. /*-
  2. * Copyright (c) 2004 Pawel Jakub Dawidek <pjd@FreeBSD.org>
  3. * All rights reserved.
  4. *
  5. * Redistribution and use in source and binary forms, with or without
  6. * modification, are permitted provided that the following conditions
  7. * are met:
  8. * 1. Redistributions of source code must retain the above copyright
  9. * notice, this list of conditions and the following disclaimer.
  10. * 2. Redistributions in binary form must reproduce the above copyright
  11. * notice, this list of conditions and the following disclaimer in the
  12. * documentation and/or other materials provided with the distribution.
  13. *
  14. * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
  15. * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  16. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  17. * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
  18. * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  19. * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  20. * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  21. * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  22. * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  23. * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  24. * SUCH DAMAGE.
  25. *
  26. * $FreeBSD$
  27. */
  28. #include <stdio.h>
  29. #include <stdlib.h>
  30. #include <stdint.h>
  31. #include <fcntl.h>
  32. #include <unistd.h>
  33. #include <string.h>
  34. #include <ctype.h>
  35. #include <libgen.h>
  36. #include <pthread.h>
  37. #include <signal.h>
  38. #include <err.h>
  39. #include <errno.h>
  40. #include <assert.h>
  41. #include <sys/param.h>
  42. #include <sys/ioctl.h>
  43. #include <sys/socket.h>
  44. #include <sys/sysctl.h>
  45. #include <sys/syslog.h>
  46. #include <sys/time.h>
  47. #include <sys/bio.h>
  48. #include <netinet/in.h>
  49. #include <netinet/tcp.h>
  50. #include <arpa/inet.h>
  51. #include <geom/gate/g_gate.h>
  52. #include "ggate.h"
  53. static enum { UNSET, CREATE, DESTROY, LIST, RESCUE } action = UNSET;
  54. static const char *path = NULL;
  55. static const char *host = NULL;
  56. static int unit = G_GATE_UNIT_AUTO;
  57. static unsigned flags = 0;
  58. static int force = 0;
  59. static unsigned queue_size = G_GATE_QUEUE_SIZE;
  60. static unsigned port = G_GATE_PORT;
  61. static off_t mediasize;
  62. static unsigned sectorsize = 0;
  63. static unsigned timeout = G_GATE_TIMEOUT;
  64. static int sendfd, recvfd;
  65. static uint32_t token;
  66. static pthread_t sendtd, recvtd;
  67. static int reconnect;
  68. static void
  69. usage(void)
  70. {
  71. fprintf(stderr, "usage: %s create [-nv] [-o <ro|wo|rw>] [-p port] "
  72. "[-q queue_size] [-R rcvbuf] [-S sndbuf] [-s sectorsize] "
  73. "[-t timeout] [-u unit] <host> <path>\n", getprogname());
  74. fprintf(stderr, " %s rescue [-nv] [-o <ro|wo|rw>] [-p port] "
  75. "[-R rcvbuf] [-S sndbuf] <-u unit> <host> <path>\n", getprogname());
  76. fprintf(stderr, " %s destroy [-f] <-u unit>\n", getprogname());
  77. fprintf(stderr, " %s list [-v] [-u unit]\n", getprogname());
  78. exit(EXIT_FAILURE);
  79. }
  80. static void *
  81. send_thread(void *arg __unused)
  82. {
  83. struct g_gate_ctl_io ggio;
  84. struct g_gate_hdr hdr;
  85. char buf[MAXPHYS];
  86. ssize_t data;
  87. int error;
  88. g_gate_log(LOG_NOTICE, "%s: started!", __func__);
  89. ggio.gctl_version = G_GATE_VERSION;
  90. ggio.gctl_unit = unit;
  91. ggio.gctl_data = buf;
  92. for (;;) {
  93. ggio.gctl_length = sizeof(buf);
  94. ggio.gctl_error = 0;
  95. g_gate_ioctl(G_GATE_CMD_START, &ggio);
  96. error = ggio.gctl_error;
  97. switch (error) {
  98. case 0:
  99. break;
  100. case ECANCELED:
  101. if (reconnect)
  102. break;
  103. /* Exit gracefully. */
  104. g_gate_close_device();
  105. exit(EXIT_SUCCESS);
  106. #if 0
  107. case ENOMEM:
  108. /* Buffer too small. */
  109. ggio.gctl_data = realloc(ggio.gctl_data,
  110. ggio.gctl_length);
  111. if (ggio.gctl_data != NULL) {
  112. bsize = ggio.gctl_length;
  113. goto once_again;
  114. }
  115. /* FALLTHROUGH */
  116. #endif
  117. case ENXIO:
  118. default:
  119. g_gate_xlog("ioctl(/dev/%s): %s.", G_GATE_CTL_NAME,
  120. strerror(error));
  121. }
  122. if (reconnect)
  123. break;
  124. switch (ggio.gctl_cmd) {
  125. case BIO_READ:
  126. hdr.gh_cmd = GGATE_CMD_READ;
  127. break;
  128. case BIO_WRITE:
  129. hdr.gh_cmd = GGATE_CMD_WRITE;
  130. break;
  131. }
  132. hdr.gh_seq = ggio.gctl_seq;
  133. hdr.gh_offset = ggio.gctl_offset;
  134. hdr.gh_length = ggio.gctl_length;
  135. hdr.gh_error = 0;
  136. g_gate_swap2n_hdr(&hdr);
  137. data = g_gate_send(sendfd, &hdr, sizeof(hdr), MSG_NOSIGNAL);
  138. g_gate_log(LOG_DEBUG, "Sent hdr packet.");
  139. g_gate_swap2h_hdr(&hdr);
  140. if (reconnect)
  141. break;
  142. if (data != sizeof(hdr)) {
  143. g_gate_log(LOG_ERR, "Lost connection 1.");
  144. reconnect = 1;
  145. pthread_kill(recvtd, SIGUSR1);
  146. break;
  147. }
  148. if (hdr.gh_cmd == GGATE_CMD_WRITE) {
  149. data = g_gate_send(sendfd, ggio.gctl_data,
  150. ggio.gctl_length, MSG_NOSIGNAL);
  151. if (reconnect)
  152. break;
  153. if (data != ggio.gctl_length) {
  154. g_gate_log(LOG_ERR, "Lost connection 2 (%zd != %zd).", data, (ssize_t)ggio.gctl_length);
  155. reconnect = 1;
  156. pthread_kill(recvtd, SIGUSR1);
  157. break;
  158. }
  159. g_gate_log(LOG_DEBUG, "Sent %zd bytes (offset=%llu, "
  160. "size=%u).", data, hdr.gh_offset, hdr.gh_length);
  161. }
  162. }
  163. g_gate_log(LOG_DEBUG, "%s: Died.", __func__);
  164. return (NULL);
  165. }
  166. static void *
  167. recv_thread(void *arg __unused)
  168. {
  169. struct g_gate_ctl_io ggio;
  170. struct g_gate_hdr hdr;
  171. char buf[MAXPHYS];
  172. ssize_t data;
  173. g_gate_log(LOG_NOTICE, "%s: started!", __func__);
  174. ggio.gctl_version = G_GATE_VERSION;
  175. ggio.gctl_unit = unit;
  176. ggio.gctl_data = buf;
  177. for (;;) {
  178. data = g_gate_recv(recvfd, &hdr, sizeof(hdr), MSG_WAITALL);
  179. if (reconnect)
  180. break;
  181. g_gate_swap2h_hdr(&hdr);
  182. if (data != sizeof(hdr)) {
  183. if (data == -1 && errno == EAGAIN)
  184. continue;
  185. g_gate_log(LOG_ERR, "Lost connection 3.");
  186. reconnect = 1;
  187. pthread_kill(sendtd, SIGUSR1);
  188. break;
  189. }
  190. g_gate_log(LOG_DEBUG, "Received hdr packet.");
  191. ggio.gctl_seq = hdr.gh_seq;
  192. ggio.gctl_cmd = hdr.gh_cmd;
  193. ggio.gctl_offset = hdr.gh_offset;
  194. ggio.gctl_length = hdr.gh_length;
  195. ggio.gctl_error = hdr.gh_error;
  196. if (ggio.gctl_error == 0 && ggio.gctl_cmd == GGATE_CMD_READ) {
  197. data = g_gate_recv(recvfd, ggio.gctl_data,
  198. ggio.gctl_length, MSG_WAITALL);
  199. if (reconnect)
  200. break;
  201. g_gate_log(LOG_DEBUG, "Received data packet.");
  202. if (data != ggio.gctl_length) {
  203. g_gate_log(LOG_ERR, "Lost connection 4.");
  204. reconnect = 1;
  205. pthread_kill(sendtd, SIGUSR1);
  206. break;
  207. }
  208. g_gate_log(LOG_DEBUG, "Received %d bytes (offset=%ju, "
  209. "size=%zu).", data, (uintmax_t)hdr.gh_offset,
  210. (size_t)hdr.gh_length);
  211. }
  212. g_gate_ioctl(G_GATE_CMD_DONE, &ggio);
  213. }
  214. g_gate_log(LOG_DEBUG, "%s: Died.", __func__);
  215. pthread_exit(NULL);
  216. }
  217. static int
  218. handshake(int dir)
  219. {
  220. struct g_gate_version ver;
  221. struct g_gate_cinit cinit;
  222. struct g_gate_sinit sinit;
  223. struct sockaddr_in serv;
  224. int sfd;
  225. /*
  226. * Do the network stuff.
  227. */
  228. bzero(&serv, sizeof(serv));
  229. serv.sin_family = AF_INET;
  230. serv.sin_addr.s_addr = g_gate_str2ip(host);
  231. if (serv.sin_addr.s_addr == INADDR_NONE) {
  232. g_gate_log(LOG_DEBUG, "Invalid IP/host name: %s.", host);
  233. return (-1);
  234. }
  235. serv.sin_port = htons(port);
  236. sfd = socket(AF_INET, SOCK_STREAM, 0);
  237. if (sfd == -1) {
  238. g_gate_log(LOG_DEBUG, "Cannot open socket: %s.",
  239. strerror(errno));
  240. return (-1);
  241. }
  242. g_gate_socket_settings(sfd);
  243. if (connect(sfd, (struct sockaddr *)&serv, sizeof(serv)) == -1) {
  244. g_gate_log(LOG_DEBUG, "Cannot connect to server: %s.",
  245. strerror(errno));
  246. close(sfd);
  247. return (-1);
  248. }
  249. g_gate_log(LOG_INFO, "Connected to the server: %s:%d.", host, port);
  250. /*
  251. * Create and send version packet.
  252. */
  253. g_gate_log(LOG_DEBUG, "Sending version packet.");
  254. assert(strlen(GGATE_MAGIC) == sizeof(ver.gv_magic));
  255. bcopy(GGATE_MAGIC, ver.gv_magic, sizeof(ver.gv_magic));
  256. ver.gv_version = GGATE_VERSION;
  257. ver.gv_error = 0;
  258. g_gate_swap2n_version(&ver);
  259. if (g_gate_send(sfd, &ver, sizeof(ver), MSG_NOSIGNAL) == -1) {
  260. g_gate_log(LOG_DEBUG, "Error while sending version packet: %s.",
  261. strerror(errno));
  262. close(sfd);
  263. return (-1);
  264. }
  265. bzero(&ver, sizeof(ver));
  266. if (g_gate_recv(sfd, &ver, sizeof(ver), MSG_WAITALL) == -1) {
  267. g_gate_log(LOG_DEBUG, "Error while receiving data: %s.",
  268. strerror(errno));
  269. close(sfd);
  270. return (-1);
  271. }
  272. if (ver.gv_error != 0) {
  273. g_gate_log(LOG_DEBUG, "Version verification problem: %s.",
  274. strerror(errno));
  275. close(sfd);
  276. return (-1);
  277. }
  278. /*
  279. * Create and send initial packet.
  280. */
  281. g_gate_log(LOG_DEBUG, "Sending initial packet.");
  282. if (strlcpy(cinit.gc_path, path, sizeof(cinit.gc_path)) >=
  283. sizeof(cinit.gc_path)) {
  284. g_gate_log(LOG_DEBUG, "Path name too long.");
  285. close(sfd);
  286. return (-1);
  287. }
  288. cinit.gc_flags = flags | dir;
  289. cinit.gc_token = token;
  290. cinit.gc_nconn = 2;
  291. g_gate_swap2n_cinit(&cinit);
  292. if (g_gate_send(sfd, &cinit, sizeof(cinit), MSG_NOSIGNAL) == -1) {
  293. g_gate_log(LOG_DEBUG, "Error while sending initial packet: %s.",
  294. strerror(errno));
  295. close(sfd);
  296. return (-1);
  297. }
  298. g_gate_swap2h_cinit(&cinit);
  299. /*
  300. * Receiving initial packet from server.
  301. */
  302. g_gate_log(LOG_DEBUG, "Receiving initial packet.");
  303. if (g_gate_recv(sfd, &sinit, sizeof(sinit), MSG_WAITALL) == -1) {
  304. g_gate_log(LOG_DEBUG, "Error while receiving data: %s.",
  305. strerror(errno));
  306. close(sfd);
  307. return (-1);
  308. }
  309. g_gate_swap2h_sinit(&sinit);
  310. if (sinit.gs_error != 0) {
  311. g_gate_log(LOG_DEBUG, "Error from server: %s.",
  312. strerror(sinit.gs_error));
  313. close(sfd);
  314. return (-1);
  315. }
  316. g_gate_log(LOG_DEBUG, "Received initial packet.");
  317. mediasize = sinit.gs_mediasize;
  318. if (sectorsize == 0)
  319. sectorsize = sinit.gs_sectorsize;
  320. return (sfd);
  321. }
  322. static void
  323. mydaemon(void)
  324. {
  325. if (g_gate_verbose > 0)
  326. return;
  327. if (daemon(0, 0) == 0)
  328. return;
  329. if (action == CREATE)
  330. g_gate_destroy(unit, 1);
  331. err(EXIT_FAILURE, "Cannot daemonize");
  332. }
  333. static int
  334. g_gatec_connect(void)
  335. {
  336. token = arc4random();
  337. /*
  338. * Our receive descriptor is connected to the send descriptor on the
  339. * server side.
  340. */
  341. recvfd = handshake(GGATE_FLAG_SEND);
  342. if (recvfd == -1)
  343. return (0);
  344. /*
  345. * Our send descriptor is connected to the receive descriptor on the
  346. * server side.
  347. */
  348. sendfd = handshake(GGATE_FLAG_RECV);
  349. if (sendfd == -1)
  350. return (0);
  351. return (1);
  352. }
  353. static void
  354. g_gatec_start(void)
  355. {
  356. int error;
  357. reconnect = 0;
  358. error = pthread_create(&recvtd, NULL, recv_thread, NULL);
  359. if (error != 0) {
  360. g_gate_destroy(unit, 1);
  361. g_gate_xlog("pthread_create(recv_thread): %s.",
  362. strerror(error));
  363. }
  364. sendtd = pthread_self();
  365. send_thread(NULL);
  366. /* Disconnected. */
  367. close(sendfd);
  368. close(recvfd);
  369. }
  370. static void
  371. signop(int sig __unused)
  372. {
  373. /* Do nothing. */
  374. }
  375. static void
  376. g_gatec_loop(void)
  377. {
  378. struct g_gate_ctl_cancel ggioc;
  379. signal(SIGUSR1, signop);
  380. for (;;) {
  381. g_gatec_start();
  382. g_gate_log(LOG_NOTICE, "Disconnected [%s %s]. Connecting...",
  383. host, path);
  384. while (!g_gatec_connect()) {
  385. sleep(2);
  386. g_gate_log(LOG_NOTICE, "Connecting [%s %s]...", host,
  387. path);
  388. }
  389. ggioc.gctl_version = G_GATE_VERSION;
  390. ggioc.gctl_unit = unit;
  391. ggioc.gctl_seq = 0;
  392. g_gate_ioctl(G_GATE_CMD_CANCEL, &ggioc);
  393. }
  394. }
  395. static void
  396. g_gatec_create(void)
  397. {
  398. struct g_gate_ctl_create ggioc;
  399. if (!g_gatec_connect())
  400. g_gate_xlog("Cannot connect: %s.", strerror(errno));
  401. /*
  402. * Ok, got both sockets, time to create provider.
  403. */
  404. ggioc.gctl_version = G_GATE_VERSION;
  405. ggioc.gctl_mediasize = mediasize;
  406. ggioc.gctl_sectorsize = sectorsize;
  407. ggioc.gctl_flags = flags;
  408. ggioc.gctl_maxcount = queue_size;
  409. ggioc.gctl_timeout = timeout;
  410. ggioc.gctl_unit = unit;
  411. snprintf(ggioc.gctl_info, sizeof(ggioc.gctl_info), "%s:%u %s", host,
  412. port, path);
  413. g_gate_ioctl(G_GATE_CMD_CREATE, &ggioc);
  414. if (unit == -1) {
  415. printf("%s%u\n", G_GATE_PROVIDER_NAME, ggioc.gctl_unit);
  416. fflush(stdout);
  417. }
  418. unit = ggioc.gctl_unit;
  419. mydaemon();
  420. g_gatec_loop();
  421. }
  422. static void
  423. g_gatec_rescue(void)
  424. {
  425. struct g_gate_ctl_cancel ggioc;
  426. if (!g_gatec_connect())
  427. g_gate_xlog("Cannot connect: %s.", strerror(errno));
  428. ggioc.gctl_version = G_GATE_VERSION;
  429. ggioc.gctl_unit = unit;
  430. ggioc.gctl_seq = 0;
  431. g_gate_ioctl(G_GATE_CMD_CANCEL, &ggioc);
  432. mydaemon();
  433. g_gatec_loop();
  434. }
  435. int
  436. main(int argc, char *argv[])
  437. {
  438. if (argc < 2)
  439. usage();
  440. if (strcasecmp(argv[1], "create") == 0)
  441. action = CREATE;
  442. else if (strcasecmp(argv[1], "destroy") == 0)
  443. action = DESTROY;
  444. else if (strcasecmp(argv[1], "list") == 0)
  445. action = LIST;
  446. else if (strcasecmp(argv[1], "rescue") == 0)
  447. action = RESCUE;
  448. else
  449. usage();
  450. argc -= 1;
  451. argv += 1;
  452. for (;;) {
  453. int ch;
  454. ch = getopt(argc, argv, "fno:p:q:R:S:s:t:u:v");
  455. if (ch == -1)
  456. break;
  457. switch (ch) {
  458. case 'f':
  459. if (action != DESTROY)
  460. usage();
  461. force = 1;
  462. break;
  463. case 'n':
  464. if (action != CREATE && action != RESCUE)
  465. usage();
  466. nagle = 0;
  467. break;
  468. case 'o':
  469. if (action != CREATE && action != RESCUE)
  470. usage();
  471. if (strcasecmp("ro", optarg) == 0)
  472. flags = G_GATE_FLAG_READONLY;
  473. else if (strcasecmp("wo", optarg) == 0)
  474. flags = G_GATE_FLAG_WRITEONLY;
  475. else if (strcasecmp("rw", optarg) == 0)
  476. flags = 0;
  477. else {
  478. errx(EXIT_FAILURE,
  479. "Invalid argument for '-o' option.");
  480. }
  481. break;
  482. case 'p':
  483. if (action != CREATE && action != RESCUE)
  484. usage();
  485. errno = 0;
  486. port = strtoul(optarg, NULL, 10);
  487. if (port == 0 && errno != 0)
  488. errx(EXIT_FAILURE, "Invalid port.");
  489. break;
  490. case 'q':
  491. if (action != CREATE)
  492. usage();
  493. errno = 0;
  494. queue_size = strtoul(optarg, NULL, 10);
  495. if (queue_size == 0 && errno != 0)
  496. errx(EXIT_FAILURE, "Invalid queue_size.");
  497. break;
  498. case 'R':
  499. if (action != CREATE && action != RESCUE)
  500. usage();
  501. errno = 0;
  502. rcvbuf = strtoul(optarg, NULL, 10);
  503. if (rcvbuf == 0 && errno != 0)
  504. errx(EXIT_FAILURE, "Invalid rcvbuf.");
  505. break;
  506. case 'S':
  507. if (action != CREATE && action != RESCUE)
  508. usage();
  509. errno = 0;
  510. sndbuf = strtoul(optarg, NULL, 10);
  511. if (sndbuf == 0 && errno != 0)
  512. errx(EXIT_FAILURE, "Invalid sndbuf.");
  513. break;
  514. case 's':
  515. if (action != CREATE)
  516. usage();
  517. errno = 0;
  518. sectorsize = strtoul(optarg, NULL, 10);
  519. if (sectorsize == 0 && errno != 0)
  520. errx(EXIT_FAILURE, "Invalid sectorsize.");
  521. break;
  522. case 't':
  523. if (action != CREATE)
  524. usage();
  525. errno = 0;
  526. timeout = strtoul(optarg, NULL, 10);
  527. if (timeout == 0 && errno != 0)
  528. errx(EXIT_FAILURE, "Invalid timeout.");
  529. break;
  530. case 'u':
  531. errno = 0;
  532. unit = strtol(optarg, NULL, 10);
  533. if (unit == 0 && errno != 0)
  534. errx(EXIT_FAILURE, "Invalid unit number.");
  535. break;
  536. case 'v':
  537. if (action == DESTROY)
  538. usage();
  539. g_gate_verbose++;
  540. break;
  541. default:
  542. usage();
  543. }
  544. }
  545. argc -= optind;
  546. argv += optind;
  547. switch (action) {
  548. case CREATE:
  549. if (argc != 2)
  550. usage();
  551. g_gate_load_module();
  552. g_gate_open_device();
  553. host = argv[0];
  554. path = argv[1];
  555. g_gatec_create();
  556. break;
  557. case DESTROY:
  558. if (unit == -1) {
  559. fprintf(stderr, "Required unit number.\n");
  560. usage();
  561. }
  562. g_gate_verbose = 1;
  563. g_gate_open_device();
  564. g_gate_destroy(unit, force);
  565. break;
  566. case LIST:
  567. g_gate_list(unit, g_gate_verbose);
  568. break;
  569. case RESCUE:
  570. if (argc != 2)
  571. usage();
  572. if (unit == -1) {
  573. fprintf(stderr, "Required unit number.\n");
  574. usage();
  575. }
  576. g_gate_open_device();
  577. host = argv[0];
  578. path = argv[1];
  579. g_gatec_rescue();
  580. break;
  581. case UNSET:
  582. default:
  583. usage();
  584. }
  585. g_gate_close_device();
  586. exit(EXIT_SUCCESS);
  587. }