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.
 
 
 
 

646 lines
15 KiB

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