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.
 
 
 
 

331 lines
7.7 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 <err.h>
  37. #include <errno.h>
  38. #include <assert.h>
  39. #include <sys/param.h>
  40. #include <sys/time.h>
  41. #include <sys/bio.h>
  42. #include <sys/disk.h>
  43. #include <sys/ioctl.h>
  44. #include <sys/stat.h>
  45. #include <sys/syslog.h>
  46. #include <geom/gate/g_gate.h>
  47. #include "ggate.h"
  48. static enum { UNSET, CREATE, DESTROY, LIST, RESCUE } action = UNSET;
  49. static const char *path = NULL;
  50. static int unit = G_GATE_UNIT_AUTO;
  51. static unsigned flags = 0;
  52. static int force = 0;
  53. static unsigned sectorsize = 0;
  54. static unsigned timeout = G_GATE_TIMEOUT;
  55. static void
  56. usage(void)
  57. {
  58. fprintf(stderr, "usage: %s create [-v] [-o <ro|wo|rw>] "
  59. "[-s sectorsize] [-t timeout] [-u unit] <path>\n", getprogname());
  60. fprintf(stderr, " %s rescue [-v] [-o <ro|wo|rw>] <-u unit> "
  61. "<path>\n", getprogname());
  62. fprintf(stderr, " %s destroy [-f] <-u unit>\n", getprogname());
  63. fprintf(stderr, " %s list [-v] [-u unit]\n", getprogname());
  64. exit(EXIT_FAILURE);
  65. }
  66. static int
  67. g_gate_openflags(unsigned ggflags)
  68. {
  69. if ((ggflags & G_GATE_FLAG_READONLY) != 0)
  70. return (O_RDONLY);
  71. else if ((ggflags & G_GATE_FLAG_WRITEONLY) != 0)
  72. return (O_WRONLY);
  73. return (O_RDWR);
  74. }
  75. static void
  76. g_gatel_serve(int fd)
  77. {
  78. struct g_gate_ctl_io ggio;
  79. size_t bsize;
  80. if (g_gate_verbose == 0) {
  81. if (daemon(0, 0) == -1) {
  82. g_gate_destroy(unit, 1);
  83. err(EXIT_FAILURE, "Cannot daemonize");
  84. }
  85. }
  86. g_gate_log(LOG_DEBUG, "Worker created: %u.", getpid());
  87. ggio.gctl_version = G_GATE_VERSION;
  88. ggio.gctl_unit = unit;
  89. bsize = sectorsize;
  90. ggio.gctl_data = malloc(bsize);
  91. for (;;) {
  92. int error;
  93. once_again:
  94. ggio.gctl_length = bsize;
  95. ggio.gctl_error = 0;
  96. g_gate_ioctl(G_GATE_CMD_START, &ggio);
  97. error = ggio.gctl_error;
  98. switch (error) {
  99. case 0:
  100. break;
  101. case ECANCELED:
  102. /* Exit gracefully. */
  103. free(ggio.gctl_data);
  104. g_gate_close_device();
  105. close(fd);
  106. exit(EXIT_SUCCESS);
  107. case ENOMEM:
  108. /* Buffer too small. */
  109. assert(ggio.gctl_cmd == BIO_DELETE ||
  110. ggio.gctl_cmd == BIO_WRITE);
  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. case ENXIO:
  119. default:
  120. g_gate_xlog("ioctl(/dev/%s): %s.", G_GATE_CTL_NAME,
  121. strerror(error));
  122. }
  123. error = 0;
  124. switch (ggio.gctl_cmd) {
  125. case BIO_READ:
  126. if ((size_t)ggio.gctl_length > bsize) {
  127. ggio.gctl_data = realloc(ggio.gctl_data,
  128. ggio.gctl_length);
  129. if (ggio.gctl_data != NULL)
  130. bsize = ggio.gctl_length;
  131. else
  132. error = ENOMEM;
  133. }
  134. if (error == 0) {
  135. if (pread(fd, ggio.gctl_data, ggio.gctl_length,
  136. ggio.gctl_offset) == -1) {
  137. error = errno;
  138. }
  139. }
  140. break;
  141. case BIO_DELETE:
  142. case BIO_WRITE:
  143. if (pwrite(fd, ggio.gctl_data, ggio.gctl_length,
  144. ggio.gctl_offset) == -1) {
  145. error = errno;
  146. }
  147. break;
  148. default:
  149. error = EOPNOTSUPP;
  150. }
  151. ggio.gctl_error = error;
  152. g_gate_ioctl(G_GATE_CMD_DONE, &ggio);
  153. }
  154. }
  155. static void
  156. g_gatel_create(void)
  157. {
  158. struct g_gate_ctl_create ggioc;
  159. int fd;
  160. fd = open(path, g_gate_openflags(flags) | O_DIRECT | O_FSYNC);
  161. if (fd == -1)
  162. err(EXIT_FAILURE, "Cannot open %s", path);
  163. memset(&ggioc, 0, sizeof(ggioc));
  164. ggioc.gctl_version = G_GATE_VERSION;
  165. ggioc.gctl_unit = unit;
  166. ggioc.gctl_mediasize = g_gate_mediasize(fd);
  167. if (sectorsize == 0)
  168. sectorsize = g_gate_sectorsize(fd);
  169. ggioc.gctl_sectorsize = sectorsize;
  170. ggioc.gctl_timeout = timeout;
  171. ggioc.gctl_flags = flags;
  172. ggioc.gctl_maxcount = 0;
  173. strlcpy(ggioc.gctl_info, path, sizeof(ggioc.gctl_info));
  174. g_gate_ioctl(G_GATE_CMD_CREATE, &ggioc);
  175. if (unit == -1)
  176. printf("%s%u\n", G_GATE_PROVIDER_NAME, ggioc.gctl_unit);
  177. unit = ggioc.gctl_unit;
  178. g_gatel_serve(fd);
  179. }
  180. static void
  181. g_gatel_rescue(void)
  182. {
  183. struct g_gate_ctl_cancel ggioc;
  184. int fd;
  185. fd = open(path, g_gate_openflags(flags));
  186. if (fd == -1)
  187. err(EXIT_FAILURE, "Cannot open %s", path);
  188. ggioc.gctl_version = G_GATE_VERSION;
  189. ggioc.gctl_unit = unit;
  190. ggioc.gctl_seq = 0;
  191. g_gate_ioctl(G_GATE_CMD_CANCEL, &ggioc);
  192. g_gatel_serve(fd);
  193. }
  194. int
  195. main(int argc, char *argv[])
  196. {
  197. if (argc < 2)
  198. usage();
  199. if (strcasecmp(argv[1], "create") == 0)
  200. action = CREATE;
  201. else if (strcasecmp(argv[1], "rescue") == 0)
  202. action = RESCUE;
  203. else if (strcasecmp(argv[1], "destroy") == 0)
  204. action = DESTROY;
  205. else if (strcasecmp(argv[1], "list") == 0)
  206. action = LIST;
  207. else
  208. usage();
  209. argc -= 1;
  210. argv += 1;
  211. for (;;) {
  212. int ch;
  213. ch = getopt(argc, argv, "fo:s:t:u:v");
  214. if (ch == -1)
  215. break;
  216. switch (ch) {
  217. case 'f':
  218. if (action != DESTROY)
  219. usage();
  220. force = 1;
  221. break;
  222. case 'o':
  223. if (action != CREATE && action != RESCUE)
  224. usage();
  225. if (strcasecmp("ro", optarg) == 0)
  226. flags = G_GATE_FLAG_READONLY;
  227. else if (strcasecmp("wo", optarg) == 0)
  228. flags = G_GATE_FLAG_WRITEONLY;
  229. else if (strcasecmp("rw", optarg) == 0)
  230. flags = 0;
  231. else {
  232. errx(EXIT_FAILURE,
  233. "Invalid argument for '-o' option.");
  234. }
  235. break;
  236. case 's':
  237. if (action != CREATE)
  238. usage();
  239. errno = 0;
  240. sectorsize = strtoul(optarg, NULL, 10);
  241. if (sectorsize == 0 && errno != 0)
  242. errx(EXIT_FAILURE, "Invalid sectorsize.");
  243. break;
  244. case 't':
  245. if (action != CREATE)
  246. usage();
  247. errno = 0;
  248. timeout = strtoul(optarg, NULL, 10);
  249. if (timeout == 0 && errno != 0)
  250. errx(EXIT_FAILURE, "Invalid timeout.");
  251. break;
  252. case 'u':
  253. errno = 0;
  254. unit = strtol(optarg, NULL, 10);
  255. if (unit == 0 && errno != 0)
  256. errx(EXIT_FAILURE, "Invalid unit number.");
  257. break;
  258. case 'v':
  259. if (action == DESTROY)
  260. usage();
  261. g_gate_verbose++;
  262. break;
  263. default:
  264. usage();
  265. }
  266. }
  267. argc -= optind;
  268. argv += optind;
  269. switch (action) {
  270. case CREATE:
  271. if (argc != 1)
  272. usage();
  273. g_gate_load_module();
  274. g_gate_open_device();
  275. path = argv[0];
  276. g_gatel_create();
  277. break;
  278. case RESCUE:
  279. if (argc != 1)
  280. usage();
  281. if (unit == -1) {
  282. fprintf(stderr, "Required unit number.\n");
  283. usage();
  284. }
  285. g_gate_open_device();
  286. path = argv[0];
  287. g_gatel_rescue();
  288. break;
  289. case DESTROY:
  290. if (unit == -1) {
  291. fprintf(stderr, "Required unit number.\n");
  292. usage();
  293. }
  294. g_gate_verbose = 1;
  295. g_gate_open_device();
  296. g_gate_destroy(unit, force);
  297. break;
  298. case LIST:
  299. g_gate_list(unit, g_gate_verbose);
  300. break;
  301. case UNSET:
  302. default:
  303. usage();
  304. }
  305. g_gate_close_device();
  306. exit(EXIT_SUCCESS);
  307. }