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