1128765Spjd/*- 2128765Spjd * Copyright (c) 2004 Pawel Jakub Dawidek <pjd@FreeBSD.org> 3128765Spjd * All rights reserved. 4128765Spjd * 5128765Spjd * Redistribution and use in source and binary forms, with or without 6128765Spjd * modification, are permitted provided that the following conditions 7128765Spjd * are met: 8128765Spjd * 1. Redistributions of source code must retain the above copyright 9128765Spjd * notice, this list of conditions and the following disclaimer. 10128765Spjd * 2. Redistributions in binary form must reproduce the above copyright 11128765Spjd * notice, this list of conditions and the following disclaimer in the 12128765Spjd * documentation and/or other materials provided with the distribution. 13128765Spjd * 14128765Spjd * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND 15128765Spjd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16128765Spjd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17128765Spjd * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE 18128765Spjd * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19128765Spjd * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20128765Spjd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21128765Spjd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22128765Spjd * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23128765Spjd * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24128765Spjd * SUCH DAMAGE. 25128765Spjd * 26128765Spjd * $FreeBSD$ 27128765Spjd */ 28128765Spjd 29128765Spjd#include <stdio.h> 30128765Spjd#include <stdlib.h> 31128765Spjd#include <stdint.h> 32128765Spjd#include <fcntl.h> 33128765Spjd#include <unistd.h> 34128765Spjd#include <string.h> 35128765Spjd#include <ctype.h> 36128765Spjd#include <libgen.h> 37147844Spjd#include <pthread.h> 38147844Spjd#include <signal.h> 39128765Spjd#include <err.h> 40128765Spjd#include <errno.h> 41147844Spjd#include <assert.h> 42147844Spjd 43128765Spjd#include <sys/param.h> 44128765Spjd#include <sys/ioctl.h> 45128765Spjd#include <sys/socket.h> 46128765Spjd#include <sys/sysctl.h> 47128765Spjd#include <sys/syslog.h> 48128765Spjd#include <sys/time.h> 49128765Spjd#include <sys/bio.h> 50128765Spjd#include <netinet/in.h> 51128765Spjd#include <netinet/tcp.h> 52128765Spjd#include <arpa/inet.h> 53128765Spjd 54128765Spjd#include <geom/gate/g_gate.h> 55128765Spjd#include "ggate.h" 56128765Spjd 57128765Spjd 58241720Sedstatic enum { UNSET, CREATE, DESTROY, LIST, RESCUE } action = UNSET; 59128765Spjd 60128765Spjdstatic const char *path = NULL; 61128765Spjdstatic const char *host = NULL; 62204076Spjdstatic int unit = G_GATE_UNIT_AUTO; 63128765Spjdstatic unsigned flags = 0; 64128765Spjdstatic int force = 0; 65128765Spjdstatic unsigned queue_size = G_GATE_QUEUE_SIZE; 66128765Spjdstatic unsigned port = G_GATE_PORT; 67128765Spjdstatic off_t mediasize; 68128765Spjdstatic unsigned sectorsize = 0; 69128765Spjdstatic unsigned timeout = G_GATE_TIMEOUT; 70147844Spjdstatic int sendfd, recvfd; 71147844Spjdstatic uint32_t token; 72147844Spjdstatic pthread_t sendtd, recvtd; 73147844Spjdstatic int reconnect; 74128765Spjd 75128765Spjdstatic void 76128765Spjdusage(void) 77128765Spjd{ 78128765Spjd 79128765Spjd fprintf(stderr, "usage: %s create [-nv] [-o <ro|wo|rw>] [-p port] " 80128765Spjd "[-q queue_size] [-R rcvbuf] [-S sndbuf] [-s sectorsize] " 81128765Spjd "[-t timeout] [-u unit] <host> <path>\n", getprogname()); 82147844Spjd fprintf(stderr, " %s rescue [-nv] [-o <ro|wo|rw>] [-p port] " 83128765Spjd "[-R rcvbuf] [-S sndbuf] <-u unit> <host> <path>\n", getprogname()); 84128765Spjd fprintf(stderr, " %s destroy [-f] <-u unit>\n", getprogname()); 85128765Spjd fprintf(stderr, " %s list [-v] [-u unit]\n", getprogname()); 86128765Spjd exit(EXIT_FAILURE); 87128765Spjd} 88128765Spjd 89147844Spjdstatic void * 90147844Spjdsend_thread(void *arg __unused) 91128765Spjd{ 92128765Spjd struct g_gate_ctl_io ggio; 93147844Spjd struct g_gate_hdr hdr; 94147844Spjd char buf[MAXPHYS]; 95147844Spjd ssize_t data; 96147844Spjd int error; 97128765Spjd 98147844Spjd g_gate_log(LOG_NOTICE, "%s: started!", __func__); 99128765Spjd 100128765Spjd ggio.gctl_version = G_GATE_VERSION; 101128765Spjd ggio.gctl_unit = unit; 102147844Spjd ggio.gctl_data = buf; 103147844Spjd 104128765Spjd for (;;) { 105147844Spjd ggio.gctl_length = sizeof(buf); 106128765Spjd ggio.gctl_error = 0; 107128765Spjd g_gate_ioctl(G_GATE_CMD_START, &ggio); 108128765Spjd error = ggio.gctl_error; 109128765Spjd switch (error) { 110128765Spjd case 0: 111128765Spjd break; 112128765Spjd case ECANCELED: 113147844Spjd if (reconnect) 114147844Spjd break; 115128765Spjd /* Exit gracefully. */ 116128765Spjd g_gate_close_device(); 117128765Spjd exit(EXIT_SUCCESS); 118147844Spjd#if 0 119128765Spjd case ENOMEM: 120128765Spjd /* Buffer too small. */ 121128765Spjd ggio.gctl_data = realloc(ggio.gctl_data, 122128765Spjd ggio.gctl_length); 123128765Spjd if (ggio.gctl_data != NULL) { 124128765Spjd bsize = ggio.gctl_length; 125128765Spjd goto once_again; 126128765Spjd } 127128765Spjd /* FALLTHROUGH */ 128147844Spjd#endif 129128765Spjd case ENXIO: 130128765Spjd default: 131128765Spjd g_gate_xlog("ioctl(/dev/%s): %s.", G_GATE_CTL_NAME, 132128765Spjd strerror(error)); 133128765Spjd } 134128765Spjd 135147844Spjd if (reconnect) 136147844Spjd break; 137147844Spjd 138147844Spjd switch (ggio.gctl_cmd) { 139147844Spjd case BIO_READ: 140147844Spjd hdr.gh_cmd = GGATE_CMD_READ; 141147844Spjd break; 142147844Spjd case BIO_WRITE: 143147844Spjd hdr.gh_cmd = GGATE_CMD_WRITE; 144147844Spjd break; 145147844Spjd } 146147844Spjd hdr.gh_seq = ggio.gctl_seq; 147128765Spjd hdr.gh_offset = ggio.gctl_offset; 148128765Spjd hdr.gh_length = ggio.gctl_length; 149128765Spjd hdr.gh_error = 0; 150128765Spjd g_gate_swap2n_hdr(&hdr); 151147844Spjd 152147844Spjd data = g_gate_send(sendfd, &hdr, sizeof(hdr), MSG_NOSIGNAL); 153128765Spjd g_gate_log(LOG_DEBUG, "Sent hdr packet."); 154128765Spjd g_gate_swap2h_hdr(&hdr); 155147844Spjd if (reconnect) 156147844Spjd break; 157128765Spjd if (data != sizeof(hdr)) { 158147844Spjd g_gate_log(LOG_ERR, "Lost connection 1."); 159147844Spjd reconnect = 1; 160147844Spjd pthread_kill(recvtd, SIGUSR1); 161147844Spjd break; 162128765Spjd } 163147844Spjd 164147844Spjd if (hdr.gh_cmd == GGATE_CMD_WRITE) { 165147844Spjd data = g_gate_send(sendfd, ggio.gctl_data, 166147844Spjd ggio.gctl_length, MSG_NOSIGNAL); 167147844Spjd if (reconnect) 168147844Spjd break; 169128765Spjd if (data != ggio.gctl_length) { 170147844Spjd g_gate_log(LOG_ERR, "Lost connection 2 (%zd != %zd).", data, (ssize_t)ggio.gctl_length); 171147844Spjd reconnect = 1; 172147844Spjd pthread_kill(recvtd, SIGUSR1); 173147844Spjd break; 174128765Spjd } 175147844Spjd g_gate_log(LOG_DEBUG, "Sent %zd bytes (offset=%llu, " 176128765Spjd "size=%u).", data, hdr.gh_offset, hdr.gh_length); 177128765Spjd } 178147844Spjd } 179147844Spjd g_gate_log(LOG_DEBUG, "%s: Died.", __func__); 180147844Spjd return (NULL); 181147844Spjd} 182147844Spjd 183147844Spjdstatic void * 184147844Spjdrecv_thread(void *arg __unused) 185147844Spjd{ 186147844Spjd struct g_gate_ctl_io ggio; 187147844Spjd struct g_gate_hdr hdr; 188147844Spjd char buf[MAXPHYS]; 189147844Spjd ssize_t data; 190147844Spjd 191147844Spjd g_gate_log(LOG_NOTICE, "%s: started!", __func__); 192147844Spjd 193147844Spjd ggio.gctl_version = G_GATE_VERSION; 194147844Spjd ggio.gctl_unit = unit; 195147844Spjd ggio.gctl_data = buf; 196147844Spjd 197147844Spjd for (;;) { 198147844Spjd data = g_gate_recv(recvfd, &hdr, sizeof(hdr), MSG_WAITALL); 199147844Spjd if (reconnect) 200147844Spjd break; 201128765Spjd g_gate_swap2h_hdr(&hdr); 202128765Spjd if (data != sizeof(hdr)) { 203147844Spjd if (data == -1 && errno == EAGAIN) 204147844Spjd continue; 205147844Spjd g_gate_log(LOG_ERR, "Lost connection 3."); 206147844Spjd reconnect = 1; 207147844Spjd pthread_kill(sendtd, SIGUSR1); 208147844Spjd break; 209128765Spjd } 210147844Spjd g_gate_log(LOG_DEBUG, "Received hdr packet."); 211147844Spjd 212147844Spjd ggio.gctl_seq = hdr.gh_seq; 213147844Spjd ggio.gctl_cmd = hdr.gh_cmd; 214147844Spjd ggio.gctl_offset = hdr.gh_offset; 215147844Spjd ggio.gctl_length = hdr.gh_length; 216147844Spjd ggio.gctl_error = hdr.gh_error; 217147844Spjd 218147844Spjd if (ggio.gctl_error == 0 && ggio.gctl_cmd == GGATE_CMD_READ) { 219147844Spjd data = g_gate_recv(recvfd, ggio.gctl_data, 220147844Spjd ggio.gctl_length, MSG_WAITALL); 221147844Spjd if (reconnect) 222147844Spjd break; 223128765Spjd g_gate_log(LOG_DEBUG, "Received data packet."); 224128765Spjd if (data != ggio.gctl_length) { 225147844Spjd g_gate_log(LOG_ERR, "Lost connection 4."); 226147844Spjd reconnect = 1; 227147844Spjd pthread_kill(sendtd, SIGUSR1); 228147844Spjd break; 229128765Spjd } 230128765Spjd g_gate_log(LOG_DEBUG, "Received %d bytes (offset=%ju, " 231128765Spjd "size=%zu).", data, (uintmax_t)hdr.gh_offset, 232128765Spjd (size_t)hdr.gh_length); 233128765Spjd } 234147844Spjd 235128765Spjd g_gate_ioctl(G_GATE_CMD_DONE, &ggio); 236128765Spjd } 237147844Spjd g_gate_log(LOG_DEBUG, "%s: Died.", __func__); 238147844Spjd pthread_exit(NULL); 239128765Spjd} 240128765Spjd 241147844Spjdstatic int 242147844Spjdhandshake(int dir) 243128765Spjd{ 244147844Spjd struct g_gate_version ver; 245147844Spjd struct g_gate_cinit cinit; 246147844Spjd struct g_gate_sinit sinit; 247147844Spjd struct sockaddr_in serv; 248147844Spjd int sfd; 249128765Spjd 250147844Spjd /* 251147844Spjd * Do the network stuff. 252147844Spjd */ 253147844Spjd bzero(&serv, sizeof(serv)); 254147844Spjd serv.sin_family = AF_INET; 255147844Spjd serv.sin_addr.s_addr = g_gate_str2ip(host); 256147844Spjd if (serv.sin_addr.s_addr == INADDR_NONE) { 257147844Spjd g_gate_log(LOG_DEBUG, "Invalid IP/host name: %s.", host); 258147844Spjd return (-1); 259147844Spjd } 260147844Spjd serv.sin_port = htons(port); 261147844Spjd sfd = socket(AF_INET, SOCK_STREAM, 0); 262147844Spjd if (sfd == -1) { 263147844Spjd g_gate_log(LOG_DEBUG, "Cannot open socket: %s.", 264147844Spjd strerror(errno)); 265147844Spjd return (-1); 266147844Spjd } 267128765Spjd 268147844Spjd g_gate_socket_settings(sfd); 269147844Spjd 270147844Spjd if (connect(sfd, (struct sockaddr *)&serv, sizeof(serv)) == -1) { 271147844Spjd g_gate_log(LOG_DEBUG, "Cannot connect to server: %s.", 272147844Spjd strerror(errno)); 273128882Spjd close(sfd); 274147844Spjd return (-1); 275128765Spjd } 276147844Spjd 277147844Spjd g_gate_log(LOG_INFO, "Connected to the server: %s:%d.", host, port); 278147844Spjd 279147844Spjd /* 280147844Spjd * Create and send version packet. 281147844Spjd */ 282147844Spjd g_gate_log(LOG_DEBUG, "Sending version packet."); 283147844Spjd assert(strlen(GGATE_MAGIC) == sizeof(ver.gv_magic)); 284147844Spjd bcopy(GGATE_MAGIC, ver.gv_magic, sizeof(ver.gv_magic)); 285147844Spjd ver.gv_version = GGATE_VERSION; 286147844Spjd ver.gv_error = 0; 287147844Spjd g_gate_swap2n_version(&ver); 288147844Spjd if (g_gate_send(sfd, &ver, sizeof(ver), MSG_NOSIGNAL) == -1) { 289147844Spjd g_gate_log(LOG_DEBUG, "Error while sending version packet: %s.", 290147844Spjd strerror(errno)); 291147844Spjd close(sfd); 292147844Spjd return (-1); 293147844Spjd } 294147844Spjd bzero(&ver, sizeof(ver)); 295147844Spjd if (g_gate_recv(sfd, &ver, sizeof(ver), MSG_WAITALL) == -1) { 296147844Spjd g_gate_log(LOG_DEBUG, "Error while receiving data: %s.", 297147844Spjd strerror(errno)); 298147844Spjd close(sfd); 299147844Spjd return (-1); 300147844Spjd } 301147844Spjd if (ver.gv_error != 0) { 302147844Spjd g_gate_log(LOG_DEBUG, "Version verification problem: %s.", 303147844Spjd strerror(errno)); 304147844Spjd close(sfd); 305147844Spjd return (-1); 306147844Spjd } 307147844Spjd 308147844Spjd /* 309147844Spjd * Create and send initial packet. 310147844Spjd */ 311147844Spjd g_gate_log(LOG_DEBUG, "Sending initial packet."); 312147844Spjd if (strlcpy(cinit.gc_path, path, sizeof(cinit.gc_path)) >= 313147844Spjd sizeof(cinit.gc_path)) { 314147844Spjd g_gate_log(LOG_DEBUG, "Path name too long."); 315147844Spjd close(sfd); 316147844Spjd return (-1); 317147844Spjd } 318147844Spjd cinit.gc_flags = flags | dir; 319147844Spjd cinit.gc_token = token; 320147844Spjd cinit.gc_nconn = 2; 321147844Spjd g_gate_swap2n_cinit(&cinit); 322147844Spjd if (g_gate_send(sfd, &cinit, sizeof(cinit), MSG_NOSIGNAL) == -1) { 323147844Spjd g_gate_log(LOG_DEBUG, "Error while sending initial packet: %s.", 324147844Spjd strerror(errno)); 325147844Spjd close(sfd); 326147844Spjd return (-1); 327147844Spjd } 328147844Spjd g_gate_swap2h_cinit(&cinit); 329147844Spjd 330147844Spjd /* 331147844Spjd * Receiving initial packet from server. 332147844Spjd */ 333147844Spjd g_gate_log(LOG_DEBUG, "Receiving initial packet."); 334147844Spjd if (g_gate_recv(sfd, &sinit, sizeof(sinit), MSG_WAITALL) == -1) { 335147844Spjd g_gate_log(LOG_DEBUG, "Error while receiving data: %s.", 336147844Spjd strerror(errno)); 337147844Spjd close(sfd); 338147844Spjd return (-1); 339147844Spjd } 340147844Spjd g_gate_swap2h_sinit(&sinit); 341147844Spjd if (sinit.gs_error != 0) { 342147844Spjd g_gate_log(LOG_DEBUG, "Error from server: %s.", 343147844Spjd strerror(sinit.gs_error)); 344147844Spjd close(sfd); 345147844Spjd return (-1); 346147844Spjd } 347147844Spjd g_gate_log(LOG_DEBUG, "Received initial packet."); 348147844Spjd 349147844Spjd mediasize = sinit.gs_mediasize; 350147844Spjd if (sectorsize == 0) 351147844Spjd sectorsize = sinit.gs_sectorsize; 352147844Spjd 353147844Spjd return (sfd); 354128765Spjd} 355128765Spjd 356128765Spjdstatic void 357128765Spjdmydaemon(void) 358128765Spjd{ 359128765Spjd 360128765Spjd if (g_gate_verbose > 0) 361128765Spjd return; 362128765Spjd if (daemon(0, 0) == 0) 363128765Spjd return; 364128765Spjd if (action == CREATE) 365128765Spjd g_gate_destroy(unit, 1); 366128765Spjd err(EXIT_FAILURE, "Cannot daemonize"); 367128765Spjd} 368128765Spjd 369147844Spjdstatic int 370147844Spjdg_gatec_connect(void) 371147844Spjd{ 372147844Spjd 373147844Spjd token = arc4random(); 374147844Spjd /* 375147844Spjd * Our receive descriptor is connected to the send descriptor on the 376147844Spjd * server side. 377147844Spjd */ 378147844Spjd recvfd = handshake(GGATE_FLAG_SEND); 379147844Spjd if (recvfd == -1) 380147844Spjd return (0); 381147844Spjd /* 382147844Spjd * Our send descriptor is connected to the receive descriptor on the 383147844Spjd * server side. 384147844Spjd */ 385147844Spjd sendfd = handshake(GGATE_FLAG_RECV); 386147844Spjd if (sendfd == -1) 387147844Spjd return (0); 388147844Spjd return (1); 389147844Spjd} 390147844Spjd 391128765Spjdstatic void 392147844Spjdg_gatec_start(void) 393128765Spjd{ 394147844Spjd int error; 395128765Spjd 396147844Spjd reconnect = 0; 397147844Spjd error = pthread_create(&recvtd, NULL, recv_thread, NULL); 398147844Spjd if (error != 0) { 399147844Spjd g_gate_destroy(unit, 1); 400147844Spjd g_gate_xlog("pthread_create(recv_thread): %s.", 401147844Spjd strerror(error)); 402147844Spjd } 403147844Spjd sendtd = pthread_self(); 404147844Spjd send_thread(NULL); 405147844Spjd /* Disconnected. */ 406147844Spjd close(sendfd); 407147844Spjd close(recvfd); 408128765Spjd} 409128765Spjd 410128765Spjdstatic void 411147844Spjdsignop(int sig __unused) 412147844Spjd{ 413147844Spjd 414147844Spjd /* Do nothing. */ 415147844Spjd} 416147844Spjd 417147844Spjdstatic void 418147844Spjdg_gatec_loop(void) 419147844Spjd{ 420147844Spjd struct g_gate_ctl_cancel ggioc; 421147844Spjd 422147844Spjd signal(SIGUSR1, signop); 423147844Spjd for (;;) { 424147844Spjd g_gatec_start(); 425147844Spjd g_gate_log(LOG_NOTICE, "Disconnected [%s %s]. Connecting...", 426147844Spjd host, path); 427147844Spjd while (!g_gatec_connect()) { 428147844Spjd sleep(2); 429147844Spjd g_gate_log(LOG_NOTICE, "Connecting [%s %s]...", host, 430147844Spjd path); 431147844Spjd } 432147844Spjd ggioc.gctl_version = G_GATE_VERSION; 433147844Spjd ggioc.gctl_unit = unit; 434147844Spjd ggioc.gctl_seq = 0; 435147844Spjd g_gate_ioctl(G_GATE_CMD_CANCEL, &ggioc); 436147844Spjd } 437147844Spjd} 438147844Spjd 439147844Spjdstatic void 440128765Spjdg_gatec_create(void) 441128765Spjd{ 442128765Spjd struct g_gate_ctl_create ggioc; 443128765Spjd 444147844Spjd if (!g_gatec_connect()) 445147844Spjd g_gate_xlog("Cannot connect: %s.", strerror(errno)); 446147844Spjd 447147844Spjd /* 448147844Spjd * Ok, got both sockets, time to create provider. 449147844Spjd */ 450285748Sbrueffer memset(&ggioc, 0, sizeof(ggioc)); 451128765Spjd ggioc.gctl_version = G_GATE_VERSION; 452128765Spjd ggioc.gctl_mediasize = mediasize; 453128765Spjd ggioc.gctl_sectorsize = sectorsize; 454128765Spjd ggioc.gctl_flags = flags; 455128765Spjd ggioc.gctl_maxcount = queue_size; 456128765Spjd ggioc.gctl_timeout = timeout; 457128765Spjd ggioc.gctl_unit = unit; 458128765Spjd snprintf(ggioc.gctl_info, sizeof(ggioc.gctl_info), "%s:%u %s", host, 459128765Spjd port, path); 460128765Spjd g_gate_ioctl(G_GATE_CMD_CREATE, &ggioc); 461156590Spjd if (unit == -1) { 462128765Spjd printf("%s%u\n", G_GATE_PROVIDER_NAME, ggioc.gctl_unit); 463156590Spjd fflush(stdout); 464156590Spjd } 465128765Spjd unit = ggioc.gctl_unit; 466147844Spjd 467128765Spjd mydaemon(); 468147844Spjd g_gatec_loop(); 469128765Spjd} 470128765Spjd 471147844Spjdstatic void 472147844Spjdg_gatec_rescue(void) 473147844Spjd{ 474147844Spjd struct g_gate_ctl_cancel ggioc; 475147844Spjd 476147844Spjd if (!g_gatec_connect()) 477147844Spjd g_gate_xlog("Cannot connect: %s.", strerror(errno)); 478147844Spjd 479147844Spjd ggioc.gctl_version = G_GATE_VERSION; 480147844Spjd ggioc.gctl_unit = unit; 481147844Spjd ggioc.gctl_seq = 0; 482147844Spjd g_gate_ioctl(G_GATE_CMD_CANCEL, &ggioc); 483147844Spjd 484147844Spjd mydaemon(); 485147844Spjd g_gatec_loop(); 486147844Spjd} 487147844Spjd 488128765Spjdint 489128765Spjdmain(int argc, char *argv[]) 490128765Spjd{ 491128765Spjd 492128765Spjd if (argc < 2) 493128765Spjd usage(); 494147844Spjd if (strcasecmp(argv[1], "create") == 0) 495128765Spjd action = CREATE; 496128765Spjd else if (strcasecmp(argv[1], "destroy") == 0) 497128765Spjd action = DESTROY; 498128765Spjd else if (strcasecmp(argv[1], "list") == 0) 499128765Spjd action = LIST; 500147844Spjd else if (strcasecmp(argv[1], "rescue") == 0) 501147844Spjd action = RESCUE; 502128765Spjd else 503128765Spjd usage(); 504128765Spjd argc -= 1; 505128765Spjd argv += 1; 506128765Spjd for (;;) { 507128765Spjd int ch; 508128765Spjd 509128765Spjd ch = getopt(argc, argv, "fno:p:q:R:S:s:t:u:v"); 510128765Spjd if (ch == -1) 511128765Spjd break; 512128765Spjd switch (ch) { 513128765Spjd case 'f': 514128765Spjd if (action != DESTROY) 515128765Spjd usage(); 516128765Spjd force = 1; 517128765Spjd break; 518128765Spjd case 'n': 519147844Spjd if (action != CREATE && action != RESCUE) 520128765Spjd usage(); 521128765Spjd nagle = 0; 522128765Spjd break; 523128765Spjd case 'o': 524147844Spjd if (action != CREATE && action != RESCUE) 525128765Spjd usage(); 526128765Spjd if (strcasecmp("ro", optarg) == 0) 527128765Spjd flags = G_GATE_FLAG_READONLY; 528128765Spjd else if (strcasecmp("wo", optarg) == 0) 529128765Spjd flags = G_GATE_FLAG_WRITEONLY; 530128765Spjd else if (strcasecmp("rw", optarg) == 0) 531128765Spjd flags = 0; 532128765Spjd else { 533128765Spjd errx(EXIT_FAILURE, 534128765Spjd "Invalid argument for '-o' option."); 535128765Spjd } 536128765Spjd break; 537128765Spjd case 'p': 538147844Spjd if (action != CREATE && action != RESCUE) 539128765Spjd usage(); 540128765Spjd errno = 0; 541128765Spjd port = strtoul(optarg, NULL, 10); 542128765Spjd if (port == 0 && errno != 0) 543128765Spjd errx(EXIT_FAILURE, "Invalid port."); 544128765Spjd break; 545128765Spjd case 'q': 546128765Spjd if (action != CREATE) 547128765Spjd usage(); 548128765Spjd errno = 0; 549128765Spjd queue_size = strtoul(optarg, NULL, 10); 550128765Spjd if (queue_size == 0 && errno != 0) 551128765Spjd errx(EXIT_FAILURE, "Invalid queue_size."); 552128765Spjd break; 553128765Spjd case 'R': 554147844Spjd if (action != CREATE && action != RESCUE) 555128765Spjd usage(); 556128765Spjd errno = 0; 557128765Spjd rcvbuf = strtoul(optarg, NULL, 10); 558128765Spjd if (rcvbuf == 0 && errno != 0) 559128765Spjd errx(EXIT_FAILURE, "Invalid rcvbuf."); 560128765Spjd break; 561128765Spjd case 'S': 562147844Spjd if (action != CREATE && action != RESCUE) 563128765Spjd usage(); 564128765Spjd errno = 0; 565128765Spjd sndbuf = strtoul(optarg, NULL, 10); 566128765Spjd if (sndbuf == 0 && errno != 0) 567128765Spjd errx(EXIT_FAILURE, "Invalid sndbuf."); 568128765Spjd break; 569128765Spjd case 's': 570128765Spjd if (action != CREATE) 571128765Spjd usage(); 572128765Spjd errno = 0; 573128765Spjd sectorsize = strtoul(optarg, NULL, 10); 574128765Spjd if (sectorsize == 0 && errno != 0) 575128765Spjd errx(EXIT_FAILURE, "Invalid sectorsize."); 576128765Spjd break; 577128765Spjd case 't': 578128765Spjd if (action != CREATE) 579128765Spjd usage(); 580128765Spjd errno = 0; 581128765Spjd timeout = strtoul(optarg, NULL, 10); 582128765Spjd if (timeout == 0 && errno != 0) 583128765Spjd errx(EXIT_FAILURE, "Invalid timeout."); 584128765Spjd break; 585128765Spjd case 'u': 586128765Spjd errno = 0; 587128765Spjd unit = strtol(optarg, NULL, 10); 588128765Spjd if (unit == 0 && errno != 0) 589128765Spjd errx(EXIT_FAILURE, "Invalid unit number."); 590128765Spjd break; 591128765Spjd case 'v': 592128765Spjd if (action == DESTROY) 593128765Spjd usage(); 594128765Spjd g_gate_verbose++; 595128765Spjd break; 596128765Spjd default: 597128765Spjd usage(); 598128765Spjd } 599128765Spjd } 600128765Spjd argc -= optind; 601128765Spjd argv += optind; 602128765Spjd 603128765Spjd switch (action) { 604128765Spjd case CREATE: 605128765Spjd if (argc != 2) 606128765Spjd usage(); 607128765Spjd g_gate_load_module(); 608128765Spjd g_gate_open_device(); 609128765Spjd host = argv[0]; 610128765Spjd path = argv[1]; 611128765Spjd g_gatec_create(); 612128765Spjd break; 613128765Spjd case DESTROY: 614128765Spjd if (unit == -1) { 615128765Spjd fprintf(stderr, "Required unit number.\n"); 616128765Spjd usage(); 617128765Spjd } 618128765Spjd g_gate_verbose = 1; 619128765Spjd g_gate_open_device(); 620128765Spjd g_gate_destroy(unit, force); 621128765Spjd break; 622128765Spjd case LIST: 623128765Spjd g_gate_list(unit, g_gate_verbose); 624128765Spjd break; 625147844Spjd case RESCUE: 626147844Spjd if (argc != 2) 627147844Spjd usage(); 628147844Spjd if (unit == -1) { 629147844Spjd fprintf(stderr, "Required unit number.\n"); 630147844Spjd usage(); 631147844Spjd } 632147844Spjd g_gate_open_device(); 633147844Spjd host = argv[0]; 634147844Spjd path = argv[1]; 635147844Spjd g_gatec_rescue(); 636147844Spjd break; 637128765Spjd case UNSET: 638128765Spjd default: 639128765Spjd usage(); 640128765Spjd } 641128765Spjd g_gate_close_device(); 642128765Spjd exit(EXIT_SUCCESS); 643128765Spjd} 644