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.
 
 
 
 

711 lines
17 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 <sys/un.h>
  51. #include <netinet/in.h>
  52. #include <netinet/tcp.h>
  53. #include <arpa/inet.h>
  54. #include <geom/gate/g_gate.h>
  55. #include "ggate.h"
  56. static const char *sockprefix = "sock:";
  57. static enum { UNSET, CREATE, DESTROY, LIST, RESCUE } action = UNSET;
  58. static const char *path = NULL;
  59. static const char *host = NULL;
  60. static int unit = G_GATE_UNIT_AUTO;
  61. static unsigned flags = 0;
  62. static int force = 0;
  63. static unsigned queue_size = G_GATE_QUEUE_SIZE;
  64. static unsigned port = G_GATE_PORT;
  65. static off_t mediasize;
  66. static unsigned sectorsize = 0;
  67. static unsigned timeout = G_GATE_TIMEOUT;
  68. static int sendfd, recvfd;
  69. static uint32_t token;
  70. static pthread_t sendtd, recvtd;
  71. static int reconnect;
  72. static void
  73. usage(void)
  74. {
  75. fprintf(stderr, "usage: %s create [-nv] [-o <ro|wo|rw>] [-p port] "
  76. "[-q queue_size] [-R rcvbuf] [-S sndbuf] [-s sectorsize] "
  77. "[-t timeout] [-u unit] <host> <path>\n", getprogname());
  78. fprintf(stderr, " %s rescue [-nv] [-o <ro|wo|rw>] [-p port] "
  79. "[-R rcvbuf] [-S sndbuf] <-u unit> <host> <path>\n", getprogname());
  80. fprintf(stderr, " %s destroy [-f] <-u unit>\n", getprogname());
  81. fprintf(stderr, " %s list [-v] [-u unit]\n", getprogname());
  82. exit(EXIT_FAILURE);
  83. }
  84. static void *
  85. send_thread(void *arg __unused)
  86. {
  87. struct g_gate_ctl_io ggio;
  88. struct g_gate_hdr hdr;
  89. static char *buf;
  90. ssize_t data;
  91. int buflen = 1024*1024;
  92. int error;
  93. if (buf == NULL)
  94. buf = malloc(buflen);
  95. g_gate_log(LOG_NOTICE, "%s: started!", __func__);
  96. ggio.gctl_version = G_GATE_VERSION;
  97. ggio.gctl_unit = unit;
  98. ggio.gctl_data = buf;
  99. for (;;) {
  100. ggio.gctl_length = buflen;
  101. ggio.gctl_error = 0;
  102. g_gate_ioctl(G_GATE_CMD_START, &ggio);
  103. error = ggio.gctl_error;
  104. switch (error) {
  105. case 0:
  106. break;
  107. case ECANCELED:
  108. if (reconnect)
  109. break;
  110. /* Exit gracefully. */
  111. g_gate_close_device();
  112. exit(EXIT_SUCCESS);
  113. #if 0
  114. case ENOMEM:
  115. /* Buffer too small. */
  116. ggio.gctl_data = realloc(ggio.gctl_data,
  117. ggio.gctl_length);
  118. if (ggio.gctl_data != NULL) {
  119. bsize = ggio.gctl_length;
  120. goto once_again;
  121. }
  122. /* FALLTHROUGH */
  123. #endif
  124. case ENXIO:
  125. default:
  126. g_gate_xlog("ioctl(/dev/%s): %s.", G_GATE_CTL_NAME,
  127. strerror(error));
  128. }
  129. if (reconnect)
  130. break;
  131. g_gate_log(LOG_DEBUG, "ggio, ver: %u, unit: %d, seq: %llu, cmd: %u, offset: %llu, len: %llu", ggio.gctl_version, ggio.gctl_unit, ggio.gctl_seq, ggio.gctl_cmd, ggio.gctl_offset, ggio.gctl_length);
  132. switch (ggio.gctl_cmd) {
  133. case BIO_READ:
  134. hdr.gh_cmd = GGATE_CMD_READ;
  135. break;
  136. case BIO_WRITE:
  137. hdr.gh_cmd = GGATE_CMD_WRITE;
  138. break;
  139. case BIO_DELETE:
  140. hdr.gh_cmd = GGATE_CMD_DELETE;
  141. break;
  142. case BIO_FLUSH:
  143. hdr.gh_cmd = GGATE_CMD_FLUSH;
  144. break;
  145. default:
  146. /* XXX - how to handle this? */
  147. g_gate_log(LOG_ERR, "Got unhandled cmd: %d", ggio.gctl_cmd);
  148. reconnect = 1;
  149. pthread_kill(recvtd, SIGUSR1);
  150. break;
  151. }
  152. hdr.gh_seq = ggio.gctl_seq;
  153. hdr.gh_offset = ggio.gctl_offset;
  154. hdr.gh_length = ggio.gctl_length;
  155. hdr.gh_error = 0;
  156. g_gate_log(LOG_DEBUG, "hdr packet, cmd: %hhu, off: %llu, len: %u, seq: %u", hdr.gh_cmd, hdr.gh_offset, hdr.gh_length, hdr.gh_seq);
  157. g_gate_swap2n_hdr(&hdr);
  158. data = g_gate_send(sendfd, &hdr, sizeof(hdr), MSG_NOSIGNAL);
  159. g_gate_log(LOG_DEBUG, "Sent hdr packet.");
  160. g_gate_swap2h_hdr(&hdr);
  161. if (reconnect)
  162. break;
  163. if (data != sizeof(hdr)) {
  164. g_gate_log(LOG_ERR, "Lost connection 1.");
  165. reconnect = 1;
  166. pthread_kill(recvtd, SIGUSR1);
  167. break;
  168. }
  169. if (hdr.gh_cmd == GGATE_CMD_WRITE) {
  170. data = g_gate_send(sendfd, ggio.gctl_data,
  171. ggio.gctl_length, MSG_NOSIGNAL);
  172. if (reconnect)
  173. break;
  174. if (data != ggio.gctl_length) {
  175. g_gate_log(LOG_ERR, "Lost connection 2 (%zd != %zd).", data, (ssize_t)ggio.gctl_length);
  176. reconnect = 1;
  177. pthread_kill(recvtd, SIGUSR1);
  178. break;
  179. }
  180. g_gate_log(LOG_DEBUG, "Sent %zd bytes (offset=%llu, "
  181. "size=%u).", data, hdr.gh_offset, hdr.gh_length);
  182. }
  183. }
  184. g_gate_log(LOG_DEBUG, "%s: Died.", __func__);
  185. return (NULL);
  186. }
  187. static void *
  188. recv_thread(void *arg __unused)
  189. {
  190. struct g_gate_ctl_io ggio;
  191. struct g_gate_hdr hdr;
  192. static char *buf;
  193. int buflen;
  194. ssize_t data;
  195. buflen = 1024*1024;
  196. if (buf == NULL)
  197. buf = malloc(buflen);
  198. g_gate_log(LOG_NOTICE, "%s: started!", __func__);
  199. ggio.gctl_version = G_GATE_VERSION;
  200. ggio.gctl_unit = unit;
  201. ggio.gctl_data = buf;
  202. for (;;) {
  203. data = g_gate_recv(recvfd, &hdr, sizeof(hdr), MSG_WAITALL);
  204. if (reconnect)
  205. break;
  206. g_gate_swap2h_hdr(&hdr);
  207. if (data != sizeof(hdr)) {
  208. if (data == -1 && errno == EAGAIN)
  209. continue;
  210. g_gate_log(LOG_ERR, "Lost connection 3.");
  211. reconnect = 1;
  212. pthread_kill(sendtd, SIGUSR1);
  213. break;
  214. }
  215. g_gate_log(LOG_DEBUG, "Received hdr packet.");
  216. ggio.gctl_seq = hdr.gh_seq;
  217. ggio.gctl_cmd = hdr.gh_cmd;
  218. ggio.gctl_offset = hdr.gh_offset;
  219. ggio.gctl_length = hdr.gh_length;
  220. ggio.gctl_error = hdr.gh_error;
  221. if (ggio.gctl_length > buflen) {
  222. g_gate_log(LOG_ERR, "Received too large data, %llu.", ggio.gctl_length);
  223. reconnect = 1;
  224. pthread_kill(sendtd, SIGUSR1);
  225. break;
  226. }
  227. if (ggio.gctl_error == 0 && ggio.gctl_cmd == GGATE_CMD_READ) {
  228. data = g_gate_recv(recvfd, ggio.gctl_data,
  229. ggio.gctl_length, MSG_WAITALL);
  230. if (reconnect)
  231. break;
  232. g_gate_log(LOG_DEBUG, "Received data packet.");
  233. if (data != ggio.gctl_length) {
  234. g_gate_log(LOG_ERR, "Lost connection 4.");
  235. reconnect = 1;
  236. pthread_kill(sendtd, SIGUSR1);
  237. break;
  238. }
  239. g_gate_log(LOG_DEBUG, "Received %d bytes (offset=%ju, "
  240. "size=%zu).", data, (uintmax_t)hdr.gh_offset,
  241. (size_t)hdr.gh_length);
  242. }
  243. g_gate_ioctl(G_GATE_CMD_DONE, &ggio);
  244. }
  245. g_gate_log(LOG_DEBUG, "%s: Died.", __func__);
  246. pthread_exit(NULL);
  247. }
  248. static int
  249. handshake(int dir)
  250. {
  251. struct g_gate_version ver;
  252. struct g_gate_cinit cinit;
  253. struct g_gate_sinit sinit;
  254. struct sockaddr *serv;
  255. struct sockaddr_in inaddr;
  256. struct sockaddr_un unixaddr;
  257. socklen_t addrlen;
  258. int sfd;
  259. const char *sockname;
  260. sockname = NULL;
  261. /*
  262. * Do the network stuff.
  263. */
  264. if (strncmp(host, sockprefix, strlen(sockprefix)) == 0) {
  265. sockname = host + strlen(sockprefix);
  266. if (strlen(sockname) + 1 > sizeof(unixaddr.sun_path)) {
  267. g_gate_log(LOG_DEBUG, "Socket path is too long.");
  268. return (-1);
  269. }
  270. unixaddr = (struct sockaddr_un) {
  271. .sun_len = sizeof(unixaddr),
  272. .sun_family = AF_UNIX,
  273. };
  274. strncpy(unixaddr.sun_path, sockname, sizeof(unixaddr.sun_path));
  275. sfd = socket(AF_UNIX, SOCK_STREAM, 0);
  276. if (sfd == -1) {
  277. g_gate_log(LOG_DEBUG, "Cannot open socket: %s.",
  278. strerror(errno));
  279. return (-1);
  280. }
  281. serv = (struct sockaddr *)&unixaddr;
  282. addrlen = sizeof unixaddr;
  283. } else {
  284. bzero(&inaddr, sizeof(inaddr));
  285. inaddr.sin_family = AF_INET;
  286. inaddr.sin_addr.s_addr = g_gate_str2ip(host);
  287. if (inaddr.sin_addr.s_addr == INADDR_NONE) {
  288. g_gate_log(LOG_DEBUG, "Invalid IP/host name: %s.", host);
  289. return (-1);
  290. }
  291. inaddr.sin_port = htons(port);
  292. sfd = socket(AF_INET, SOCK_STREAM, 0);
  293. if (sfd == -1) {
  294. g_gate_log(LOG_DEBUG, "Cannot open socket: %s.",
  295. strerror(errno));
  296. return (-1);
  297. }
  298. serv = (struct sockaddr *)&inaddr;
  299. addrlen = sizeof inaddr;
  300. g_gate_socket_settings(sfd);
  301. }
  302. if (connect(sfd, serv, addrlen) == -1) {
  303. g_gate_log(LOG_DEBUG, "Cannot connect to server: %s.",
  304. strerror(errno));
  305. close(sfd);
  306. return (-1);
  307. }
  308. if (sockname != NULL)
  309. g_gate_log(LOG_INFO, "Connected to socket: %s.", sockname);
  310. else
  311. g_gate_log(LOG_INFO, "Connected to the server: %s:%d.", host, port);
  312. /*
  313. * Create and send version packet.
  314. */
  315. g_gate_log(LOG_DEBUG, "Sending version packet.");
  316. assert(strlen(GGATE_MAGIC) == sizeof(ver.gv_magic));
  317. bcopy(GGATE_MAGIC, ver.gv_magic, sizeof(ver.gv_magic));
  318. ver.gv_version = GGATE_VERSION;
  319. ver.gv_error = 0;
  320. g_gate_swap2n_version(&ver);
  321. if (g_gate_send(sfd, &ver, sizeof(ver), MSG_NOSIGNAL) == -1) {
  322. g_gate_log(LOG_DEBUG, "Error while sending version packet: %s.",
  323. strerror(errno));
  324. close(sfd);
  325. return (-1);
  326. }
  327. bzero(&ver, sizeof(ver));
  328. if (g_gate_recv(sfd, &ver, sizeof(ver), MSG_WAITALL) == -1) {
  329. g_gate_log(LOG_DEBUG, "Error while receiving data: %s.",
  330. strerror(errno));
  331. close(sfd);
  332. return (-1);
  333. }
  334. if (ver.gv_error != 0) {
  335. g_gate_log(LOG_DEBUG, "Version verification problem: %s.",
  336. strerror(errno));
  337. close(sfd);
  338. return (-1);
  339. }
  340. /*
  341. * Create and send initial packet.
  342. */
  343. g_gate_log(LOG_DEBUG, "Sending initial packet.");
  344. if (strlcpy(cinit.gc_path, path, sizeof(cinit.gc_path)) >=
  345. sizeof(cinit.gc_path)) {
  346. g_gate_log(LOG_DEBUG, "Path name too long.");
  347. close(sfd);
  348. return (-1);
  349. }
  350. cinit.gc_flags = flags | dir;
  351. cinit.gc_token = token;
  352. cinit.gc_nconn = 2;
  353. g_gate_swap2n_cinit(&cinit);
  354. if (g_gate_send(sfd, &cinit, sizeof(cinit), MSG_NOSIGNAL) == -1) {
  355. g_gate_log(LOG_DEBUG, "Error while sending initial packet: %s.",
  356. strerror(errno));
  357. close(sfd);
  358. return (-1);
  359. }
  360. g_gate_swap2h_cinit(&cinit);
  361. /*
  362. * Receiving initial packet from server.
  363. */
  364. g_gate_log(LOG_DEBUG, "Receiving initial packet.");
  365. if (g_gate_recv(sfd, &sinit, sizeof(sinit), MSG_WAITALL) == -1) {
  366. g_gate_log(LOG_DEBUG, "Error while receiving data: %s.",
  367. strerror(errno));
  368. close(sfd);
  369. return (-1);
  370. }
  371. g_gate_swap2h_sinit(&sinit);
  372. if (sinit.gs_error != 0) {
  373. g_gate_log(LOG_DEBUG, "Error from server: %s.",
  374. strerror(sinit.gs_error));
  375. close(sfd);
  376. return (-1);
  377. }
  378. g_gate_log(LOG_DEBUG, "Received initial packet.");
  379. mediasize = sinit.gs_mediasize;
  380. if (sectorsize == 0)
  381. sectorsize = sinit.gs_sectorsize;
  382. return (sfd);
  383. }
  384. static void
  385. mydaemon(void)
  386. {
  387. if (g_gate_verbose > 0)
  388. return;
  389. if (daemon(0, 0) == 0)
  390. return;
  391. if (action == CREATE)
  392. g_gate_destroy(unit, 1);
  393. err(EXIT_FAILURE, "Cannot daemonize");
  394. }
  395. static int
  396. g_gatec_connect(void)
  397. {
  398. token = arc4random();
  399. /*
  400. * Our receive descriptor is connected to the send descriptor on the
  401. * server side.
  402. */
  403. recvfd = handshake(GGATE_FLAG_SEND);
  404. if (recvfd == -1)
  405. return (0);
  406. /*
  407. * Our send descriptor is connected to the receive descriptor on the
  408. * server side.
  409. */
  410. sendfd = handshake(GGATE_FLAG_RECV);
  411. if (sendfd == -1)
  412. return (0);
  413. return (1);
  414. }
  415. static void
  416. g_gatec_start(void)
  417. {
  418. int error;
  419. reconnect = 0;
  420. error = pthread_create(&recvtd, NULL, recv_thread, NULL);
  421. if (error != 0) {
  422. g_gate_destroy(unit, 1);
  423. g_gate_xlog("pthread_create(recv_thread): %s.",
  424. strerror(error));
  425. }
  426. sendtd = pthread_self();
  427. send_thread(NULL);
  428. /* Disconnected. */
  429. close(sendfd);
  430. close(recvfd);
  431. }
  432. static void
  433. signop(int sig __unused)
  434. {
  435. /* Do nothing. */
  436. }
  437. static void
  438. g_gatec_loop(void)
  439. {
  440. struct g_gate_ctl_cancel ggioc;
  441. signal(SIGUSR1, signop);
  442. for (;;) {
  443. g_gatec_start();
  444. g_gate_log(LOG_NOTICE, "Disconnected [%s %s]. Connecting...",
  445. host, path);
  446. while (!g_gatec_connect()) {
  447. sleep(2);
  448. g_gate_log(LOG_NOTICE, "Connecting [%s %s]...", host,
  449. path);
  450. }
  451. ggioc.gctl_version = G_GATE_VERSION;
  452. ggioc.gctl_unit = unit;
  453. ggioc.gctl_seq = 0;
  454. g_gate_ioctl(G_GATE_CMD_CANCEL, &ggioc);
  455. }
  456. }
  457. static void
  458. g_gatec_create(void)
  459. {
  460. struct g_gate_ctl_create ggioc;
  461. if (!g_gatec_connect())
  462. g_gate_xlog("Cannot connect: %s.", strerror(errno));
  463. /*
  464. * Ok, got both sockets, time to create provider.
  465. */
  466. memset(&ggioc, 0, sizeof(ggioc));
  467. ggioc.gctl_version = G_GATE_VERSION;
  468. ggioc.gctl_mediasize = mediasize;
  469. ggioc.gctl_sectorsize = sectorsize;
  470. ggioc.gctl_flags = flags;
  471. ggioc.gctl_maxcount = queue_size;
  472. ggioc.gctl_timeout = timeout;
  473. ggioc.gctl_unit = unit;
  474. snprintf(ggioc.gctl_info, sizeof(ggioc.gctl_info), "%s:%u %s", host,
  475. port, path);
  476. g_gate_ioctl(G_GATE_CMD_CREATE, &ggioc);
  477. if (unit == -1) {
  478. printf("%s%u\n", G_GATE_PROVIDER_NAME, ggioc.gctl_unit);
  479. fflush(stdout);
  480. }
  481. unit = ggioc.gctl_unit;
  482. mydaemon();
  483. g_gatec_loop();
  484. }
  485. static void
  486. g_gatec_rescue(void)
  487. {
  488. struct g_gate_ctl_cancel ggioc;
  489. if (!g_gatec_connect())
  490. g_gate_xlog("Cannot connect: %s.", strerror(errno));
  491. ggioc.gctl_version = G_GATE_VERSION;
  492. ggioc.gctl_unit = unit;
  493. ggioc.gctl_seq = 0;
  494. g_gate_ioctl(G_GATE_CMD_CANCEL, &ggioc);
  495. mydaemon();
  496. g_gatec_loop();
  497. }
  498. int
  499. main(int argc, char *argv[])
  500. {
  501. if (argc < 2)
  502. usage();
  503. if (strcasecmp(argv[1], "create") == 0)
  504. action = CREATE;
  505. else if (strcasecmp(argv[1], "destroy") == 0)
  506. action = DESTROY;
  507. else if (strcasecmp(argv[1], "list") == 0)
  508. action = LIST;
  509. else if (strcasecmp(argv[1], "rescue") == 0)
  510. action = RESCUE;
  511. else
  512. usage();
  513. argc -= 1;
  514. argv += 1;
  515. for (;;) {
  516. int ch;
  517. ch = getopt(argc, argv, "fno:p:q:R:S:s:t:u:v");
  518. if (ch == -1)
  519. break;
  520. switch (ch) {
  521. case 'f':
  522. if (action != DESTROY)
  523. usage();
  524. force = 1;
  525. break;
  526. case 'n':
  527. if (action != CREATE && action != RESCUE)
  528. usage();
  529. nagle = 0;
  530. break;
  531. case 'o':
  532. if (action != CREATE && action != RESCUE)
  533. usage();
  534. if (strcasecmp("ro", optarg) == 0)
  535. flags = G_GATE_FLAG_READONLY;
  536. else if (strcasecmp("wo", optarg) == 0)
  537. flags = G_GATE_FLAG_WRITEONLY;
  538. else if (strcasecmp("rw", optarg) == 0)
  539. flags = 0;
  540. else {
  541. errx(EXIT_FAILURE,
  542. "Invalid argument for '-o' option.");
  543. }
  544. break;
  545. case 'p':
  546. if (action != CREATE && action != RESCUE)
  547. usage();
  548. errno = 0;
  549. port = strtoul(optarg, NULL, 10);
  550. if (port == 0 && errno != 0)
  551. errx(EXIT_FAILURE, "Invalid port.");
  552. break;
  553. case 'q':
  554. if (action != CREATE)
  555. usage();
  556. errno = 0;
  557. queue_size = strtoul(optarg, NULL, 10);
  558. if (queue_size == 0 && errno != 0)
  559. errx(EXIT_FAILURE, "Invalid queue_size.");
  560. break;
  561. case 'R':
  562. if (action != CREATE && action != RESCUE)
  563. usage();
  564. errno = 0;
  565. rcvbuf = strtoul(optarg, NULL, 10);
  566. if (rcvbuf == 0 && errno != 0)
  567. errx(EXIT_FAILURE, "Invalid rcvbuf.");
  568. break;
  569. case 'S':
  570. if (action != CREATE && action != RESCUE)
  571. usage();
  572. errno = 0;
  573. sndbuf = strtoul(optarg, NULL, 10);
  574. if (sndbuf == 0 && errno != 0)
  575. errx(EXIT_FAILURE, "Invalid sndbuf.");
  576. break;
  577. case 's':
  578. if (action != CREATE)
  579. usage();
  580. errno = 0;
  581. sectorsize = strtoul(optarg, NULL, 10);
  582. if (sectorsize == 0 && errno != 0)
  583. errx(EXIT_FAILURE, "Invalid sectorsize.");
  584. break;
  585. case 't':
  586. if (action != CREATE)
  587. usage();
  588. errno = 0;
  589. timeout = strtoul(optarg, NULL, 10);
  590. if (timeout == 0 && errno != 0)
  591. errx(EXIT_FAILURE, "Invalid timeout.");
  592. break;
  593. case 'u':
  594. errno = 0;
  595. unit = strtol(optarg, NULL, 10);
  596. if (unit == 0 && errno != 0)
  597. errx(EXIT_FAILURE, "Invalid unit number.");
  598. break;
  599. case 'v':
  600. if (action == DESTROY)
  601. usage();
  602. g_gate_verbose++;
  603. break;
  604. default:
  605. usage();
  606. }
  607. }
  608. argc -= optind;
  609. argv += optind;
  610. switch (action) {
  611. case CREATE:
  612. if (argc != 2)
  613. usage();
  614. g_gate_load_module();
  615. g_gate_open_device();
  616. host = argv[0];
  617. path = argv[1];
  618. g_gatec_create();
  619. break;
  620. case DESTROY:
  621. if (unit == -1) {
  622. fprintf(stderr, "Required unit number.\n");
  623. usage();
  624. }
  625. g_gate_verbose = 1;
  626. g_gate_open_device();
  627. g_gate_destroy(unit, force);
  628. break;
  629. case LIST:
  630. g_gate_list(unit, g_gate_verbose);
  631. break;
  632. case RESCUE:
  633. if (argc != 2)
  634. usage();
  635. if (unit == -1) {
  636. fprintf(stderr, "Required unit number.\n");
  637. usage();
  638. }
  639. g_gate_open_device();
  640. host = argv[0];
  641. path = argv[1];
  642. g_gatec_rescue();
  643. break;
  644. case UNSET:
  645. default:
  646. usage();
  647. }
  648. g_gate_close_device();
  649. exit(EXIT_SUCCESS);
  650. }