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.
 
 
 
 

511 lines
12 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 <err.h>
  37. #include <errno.h>
  38. #include <sys/param.h>
  39. #include <sys/ioctl.h>
  40. #include <sys/socket.h>
  41. #include <sys/sysctl.h>
  42. #include <sys/syslog.h>
  43. #include <sys/time.h>
  44. #include <sys/bio.h>
  45. #include <netinet/in.h>
  46. #include <netinet/tcp.h>
  47. #include <arpa/inet.h>
  48. #include <geom/gate/g_gate.h>
  49. #include "ggate.h"
  50. enum { UNSET, ATTACH, CREATE, DESTROY, LIST } action = UNSET;
  51. static const char *path = NULL;
  52. static const char *host = NULL;
  53. static int unit = -1;
  54. static unsigned flags = 0;
  55. static int force = 0;
  56. static int nagle = 1;
  57. static unsigned queue_size = G_GATE_QUEUE_SIZE;
  58. static unsigned port = G_GATE_PORT;
  59. static off_t mediasize;
  60. static unsigned sectorsize = 0;
  61. static unsigned timeout = G_GATE_TIMEOUT;
  62. static unsigned rcvbuf = G_GATE_RCVBUF;
  63. static unsigned sndbuf = G_GATE_SNDBUF;
  64. static void
  65. usage(void)
  66. {
  67. fprintf(stderr, "usage: %s create [-nv] [-o <ro|wo|rw>] [-p port] "
  68. "[-q queue_size] [-R rcvbuf] [-S sndbuf] [-s sectorsize] "
  69. "[-t timeout] [-u unit] <host> <path>\n", getprogname());
  70. fprintf(stderr, " %s attach [-nv] [-o <ro|wo|rw>] [-p port] "
  71. "[-R rcvbuf] [-S sndbuf] <-u unit> <host> <path>\n", getprogname());
  72. fprintf(stderr, " %s destroy [-f] <-u unit>\n", getprogname());
  73. fprintf(stderr, " %s list [-v] [-u unit]\n", getprogname());
  74. exit(EXIT_FAILURE);
  75. }
  76. static int
  77. handshake(void)
  78. {
  79. struct g_gate_cinit cinit;
  80. struct g_gate_sinit sinit;
  81. struct sockaddr_in serv;
  82. struct timeval tv;
  83. size_t bsize;
  84. int sfd;
  85. /*
  86. * Do the network stuff.
  87. */
  88. bzero(&serv, sizeof(serv));
  89. serv.sin_family = AF_INET;
  90. serv.sin_addr.s_addr = g_gate_str2ip(host);
  91. if (serv.sin_addr.s_addr == INADDR_NONE) {
  92. g_gate_log(LOG_ERR, "Invalid IP/host name: %s.", host);
  93. return (-1);
  94. }
  95. serv.sin_port = htons(port);
  96. sfd = socket(AF_INET, SOCK_STREAM, 0);
  97. if (sfd == -1)
  98. g_gate_xlog("Can't open socket: %s.", strerror(errno));
  99. /*
  100. * Some trivial network optimalization.
  101. * This should be much more advanced.
  102. */
  103. if (nagle) {
  104. int on = 1;
  105. if (setsockopt(sfd, IPPROTO_TCP, TCP_NODELAY, &on,
  106. sizeof(on)) == -1) {
  107. g_gate_xlog("setsockopt() error: %s.", strerror(errno));
  108. }
  109. }
  110. bsize = rcvbuf;
  111. if (setsockopt(sfd, SOL_SOCKET, SO_RCVBUF, &bsize, sizeof(bsize)) == -1)
  112. g_gate_xlog("setsockopt() error: %s.", strerror(errno));
  113. bsize = sndbuf;
  114. if (setsockopt(sfd, SOL_SOCKET, SO_SNDBUF, &bsize, sizeof(bsize)) == -1)
  115. g_gate_xlog("setsockopt() error: %s.", strerror(errno));
  116. tv.tv_sec = timeout;
  117. tv.tv_usec = 0;
  118. if (setsockopt(sfd, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv)) == -1 ||
  119. setsockopt(sfd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)) == -1) {
  120. g_gate_xlog("setsockopt() error: %s.", strerror(errno));
  121. }
  122. if (connect(sfd, (struct sockaddr *)&serv, sizeof(serv)) == -1) {
  123. g_gate_log(LOG_ERR, "Can't connect to server: %s.",
  124. strerror(errno));
  125. return (-1);
  126. }
  127. g_gate_log(LOG_INFO, "Connected to the server: %s:%d.", host, port);
  128. /*
  129. * Creating and sending initial packet.
  130. */
  131. if (strlcpy(cinit.gc_path, path, sizeof(cinit.gc_path)) >=
  132. sizeof(cinit.gc_path)) {
  133. g_gate_xlog("Path name too long.");
  134. }
  135. cinit.gc_flags = flags;
  136. g_gate_log(LOG_DEBUG, "Sending initial packet.");
  137. g_gate_swap2n_cinit(&cinit);
  138. if (send(sfd, &cinit, sizeof(cinit), 0) == -1) {
  139. g_gate_log(LOG_ERR, "Error while sending initial packet: %s.",
  140. strerror(errno));
  141. return (-1);
  142. }
  143. g_gate_swap2h_cinit(&cinit);
  144. /*
  145. * Receiving initial packet from server.
  146. */
  147. g_gate_log(LOG_DEBUG, "Receiving initial packet.");
  148. if (recv(sfd, &sinit, sizeof(sinit), MSG_WAITALL) == -1) {
  149. g_gate_log(LOG_ERR, "Error while receiving data: %s.",
  150. strerror(errno));
  151. return (-1);
  152. }
  153. g_gate_swap2h_sinit(&sinit);
  154. if (sinit.gs_error != 0)
  155. g_gate_xlog("Error from server: %s.", strerror(sinit.gs_error));
  156. mediasize = sinit.gs_mediasize;
  157. if (sectorsize == 0)
  158. sectorsize = sinit.gs_sectorsize;
  159. return (sfd);
  160. }
  161. static int
  162. serve(int sfd)
  163. {
  164. struct g_gate_ctl_io ggio;
  165. size_t bsize;
  166. char *buf;
  167. bsize = G_GATE_BUFSIZE_START;
  168. buf = malloc(bsize);
  169. if (buf == NULL) {
  170. if (action == CREATE)
  171. g_gate_destroy(unit, 1);
  172. g_gate_xlog("No enough memory");
  173. }
  174. ggio.gctl_version = G_GATE_VERSION;
  175. ggio.gctl_unit = unit;
  176. bsize = sectorsize;
  177. ggio.gctl_data = malloc(bsize);
  178. for (;;) {
  179. struct g_gate_hdr hdr;
  180. int data, error;
  181. once_again:
  182. ggio.gctl_length = bsize;
  183. ggio.gctl_error = 0;
  184. g_gate_ioctl(G_GATE_CMD_START, &ggio);
  185. error = ggio.gctl_error;
  186. switch (error) {
  187. case 0:
  188. break;
  189. case ECANCELED:
  190. /* Exit gracefully. */
  191. free(ggio.gctl_data);
  192. g_gate_close_device();
  193. close(sfd);
  194. exit(EXIT_SUCCESS);
  195. case ENOMEM:
  196. /* Buffer too small. */
  197. ggio.gctl_data = realloc(ggio.gctl_data,
  198. ggio.gctl_length);
  199. if (ggio.gctl_data != NULL) {
  200. bsize = ggio.gctl_length;
  201. goto once_again;
  202. }
  203. /* FALLTHROUGH */
  204. case ENXIO:
  205. default:
  206. g_gate_xlog("ioctl(/dev/%s): %s.", G_GATE_CTL_NAME,
  207. strerror(error));
  208. }
  209. hdr.gh_cmd = ggio.gctl_cmd;
  210. hdr.gh_offset = ggio.gctl_offset;
  211. hdr.gh_length = ggio.gctl_length;
  212. hdr.gh_error = 0;
  213. g_gate_swap2n_hdr(&hdr);
  214. data = send(sfd, &hdr, sizeof(hdr), 0);
  215. g_gate_log(LOG_DEBUG, "Sent hdr packet.");
  216. g_gate_swap2h_hdr(&hdr);
  217. if (data != sizeof(hdr)) {
  218. ggio.gctl_error = EAGAIN;
  219. goto done;
  220. }
  221. if (ggio.gctl_cmd == BIO_DELETE || ggio.gctl_cmd == BIO_WRITE) {
  222. data = send(sfd, ggio.gctl_data, ggio.gctl_length, 0);
  223. g_gate_log(LOG_DEBUG, "Sent data packet.");
  224. if (data != ggio.gctl_length) {
  225. ggio.gctl_error = EAGAIN;
  226. goto done;
  227. }
  228. g_gate_log(LOG_DEBUG, "Sent %d bytes (offset=%llu, "
  229. "size=%u).", data, hdr.gh_offset, hdr.gh_length);
  230. }
  231. data = recv(sfd, &hdr, sizeof(hdr), MSG_WAITALL);
  232. g_gate_log(LOG_DEBUG, "Received hdr packet.");
  233. g_gate_swap2h_hdr(&hdr);
  234. if (data != sizeof(hdr)) {
  235. ggio.gctl_error = EIO;
  236. goto done;
  237. }
  238. if (ggio.gctl_cmd == BIO_READ) {
  239. if (bsize < (size_t)ggio.gctl_length) {
  240. ggio.gctl_data = realloc(ggio.gctl_data,
  241. ggio.gctl_length);
  242. if (ggio.gctl_data != NULL)
  243. bsize = ggio.gctl_length;
  244. else
  245. g_gate_xlog("No memory.");
  246. }
  247. data = recv(sfd, ggio.gctl_data, ggio.gctl_length,
  248. MSG_WAITALL);
  249. g_gate_log(LOG_DEBUG, "Received data packet.");
  250. if (data != ggio.gctl_length) {
  251. ggio.gctl_error = EAGAIN;
  252. goto done;
  253. }
  254. g_gate_log(LOG_DEBUG, "Received %d bytes (offset=%ju, "
  255. "size=%zu).", data, (uintmax_t)hdr.gh_offset,
  256. (size_t)hdr.gh_length);
  257. }
  258. done:
  259. g_gate_ioctl(G_GATE_CMD_DONE, &ggio);
  260. if (ggio.gctl_error == EAGAIN)
  261. return (ggio.gctl_error);
  262. }
  263. /* NOTREACHED */
  264. return (0);
  265. }
  266. static void
  267. serve_loop(int sfd)
  268. {
  269. for (;;) {
  270. int error;
  271. error = serve(sfd);
  272. close(sfd);
  273. if (error != EAGAIN)
  274. g_gate_xlog("%s.", strerror(error));
  275. sfd = handshake();
  276. if (sfd == -1) {
  277. sleep(2);
  278. continue;
  279. }
  280. }
  281. }
  282. static void
  283. mydaemon(void)
  284. {
  285. if (g_gate_verbose > 0)
  286. return;
  287. if (daemon(0, 0) == 0)
  288. return;
  289. if (action == CREATE)
  290. g_gate_destroy(unit, 1);
  291. err(EXIT_FAILURE, "Cannot daemonize");
  292. }
  293. static void
  294. g_gatec_attach(void)
  295. {
  296. int sfd;
  297. sfd = handshake();
  298. g_gate_log(LOG_DEBUG, "Worker created: %u.", getpid());
  299. mydaemon();
  300. serve_loop(sfd);
  301. }
  302. static void
  303. g_gatec_create(void)
  304. {
  305. struct g_gate_ctl_create ggioc;
  306. int sfd;
  307. sfd = handshake();
  308. if (sfd == -1)
  309. exit(EXIT_FAILURE);
  310. ggioc.gctl_version = G_GATE_VERSION;
  311. ggioc.gctl_mediasize = mediasize;
  312. ggioc.gctl_sectorsize = sectorsize;
  313. ggioc.gctl_flags = flags;
  314. ggioc.gctl_maxcount = queue_size;
  315. ggioc.gctl_timeout = timeout;
  316. ggioc.gctl_unit = unit;
  317. snprintf(ggioc.gctl_info, sizeof(ggioc.gctl_info), "%s:%u %s", host,
  318. port, path);
  319. g_gate_ioctl(G_GATE_CMD_CREATE, &ggioc);
  320. g_gate_log(LOG_DEBUG, "Worker created: %u.", getpid());
  321. if (unit == -1)
  322. printf("%s%u\n", G_GATE_PROVIDER_NAME, ggioc.gctl_unit);
  323. unit = ggioc.gctl_unit;
  324. mydaemon();
  325. serve_loop(sfd);
  326. }
  327. int
  328. main(int argc, char *argv[])
  329. {
  330. if (argc < 2)
  331. usage();
  332. if (strcasecmp(argv[1], "attach") == 0)
  333. action = ATTACH;
  334. else if (strcasecmp(argv[1], "create") == 0)
  335. action = CREATE;
  336. else if (strcasecmp(argv[1], "destroy") == 0)
  337. action = DESTROY;
  338. else if (strcasecmp(argv[1], "list") == 0)
  339. action = LIST;
  340. else
  341. usage();
  342. argc -= 1;
  343. argv += 1;
  344. for (;;) {
  345. int ch;
  346. ch = getopt(argc, argv, "fno:p:q:R:S:s:t:u:v");
  347. if (ch == -1)
  348. break;
  349. switch (ch) {
  350. case 'f':
  351. if (action != DESTROY)
  352. usage();
  353. force = 1;
  354. break;
  355. case 'n':
  356. if (action != ATTACH && action != CREATE)
  357. usage();
  358. nagle = 0;
  359. break;
  360. case 'o':
  361. if (action != ATTACH && action != CREATE)
  362. usage();
  363. if (strcasecmp("ro", optarg) == 0)
  364. flags = G_GATE_FLAG_READONLY;
  365. else if (strcasecmp("wo", optarg) == 0)
  366. flags = G_GATE_FLAG_WRITEONLY;
  367. else if (strcasecmp("rw", optarg) == 0)
  368. flags = 0;
  369. else {
  370. errx(EXIT_FAILURE,
  371. "Invalid argument for '-o' option.");
  372. }
  373. break;
  374. case 'p':
  375. if (action != ATTACH && action != CREATE)
  376. usage();
  377. errno = 0;
  378. port = strtoul(optarg, NULL, 10);
  379. if (port == 0 && errno != 0)
  380. errx(EXIT_FAILURE, "Invalid port.");
  381. break;
  382. case 'q':
  383. if (action != CREATE)
  384. usage();
  385. errno = 0;
  386. queue_size = strtoul(optarg, NULL, 10);
  387. if (queue_size == 0 && errno != 0)
  388. errx(EXIT_FAILURE, "Invalid queue_size.");
  389. break;
  390. case 'R':
  391. if (action != ATTACH && action != CREATE)
  392. usage();
  393. errno = 0;
  394. rcvbuf = strtoul(optarg, NULL, 10);
  395. if (rcvbuf == 0 && errno != 0)
  396. errx(EXIT_FAILURE, "Invalid rcvbuf.");
  397. break;
  398. case 'S':
  399. if (action != ATTACH && action != CREATE)
  400. usage();
  401. errno = 0;
  402. sndbuf = strtoul(optarg, NULL, 10);
  403. if (sndbuf == 0 && errno != 0)
  404. errx(EXIT_FAILURE, "Invalid sndbuf.");
  405. break;
  406. case 's':
  407. if (action != CREATE)
  408. usage();
  409. errno = 0;
  410. sectorsize = strtoul(optarg, NULL, 10);
  411. if (sectorsize == 0 && errno != 0)
  412. errx(EXIT_FAILURE, "Invalid sectorsize.");
  413. break;
  414. case 't':
  415. if (action != CREATE)
  416. usage();
  417. errno = 0;
  418. timeout = strtoul(optarg, NULL, 10);
  419. if (timeout == 0 && errno != 0)
  420. errx(EXIT_FAILURE, "Invalid timeout.");
  421. break;
  422. case 'u':
  423. errno = 0;
  424. unit = strtol(optarg, NULL, 10);
  425. if (unit == 0 && errno != 0)
  426. errx(EXIT_FAILURE, "Invalid unit number.");
  427. break;
  428. case 'v':
  429. if (action == DESTROY)
  430. usage();
  431. g_gate_verbose++;
  432. break;
  433. default:
  434. usage();
  435. }
  436. }
  437. argc -= optind;
  438. argv += optind;
  439. switch (action) {
  440. case ATTACH:
  441. if (argc != 2)
  442. usage();
  443. if (unit == -1) {
  444. fprintf(stderr, "Required unit number.\n");
  445. usage();
  446. }
  447. g_gate_open_device();
  448. host = argv[0];
  449. path = argv[1];
  450. g_gatec_attach();
  451. break;
  452. case CREATE:
  453. if (argc != 2)
  454. usage();
  455. g_gate_load_module();
  456. g_gate_open_device();
  457. host = argv[0];
  458. path = argv[1];
  459. g_gatec_create();
  460. break;
  461. case DESTROY:
  462. if (unit == -1) {
  463. fprintf(stderr, "Required unit number.\n");
  464. usage();
  465. }
  466. g_gate_verbose = 1;
  467. g_gate_open_device();
  468. g_gate_destroy(unit, force);
  469. break;
  470. case LIST:
  471. g_gate_list(unit, g_gate_verbose);
  472. break;
  473. case UNSET:
  474. default:
  475. usage();
  476. }
  477. g_gate_close_device();
  478. exit(EXIT_SUCCESS);
  479. }