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 */ 450128765Spjd ggioc.gctl_version = G_GATE_VERSION; 451128765Spjd ggioc.gctl_mediasize = mediasize; 452128765Spjd ggioc.gctl_sectorsize = sectorsize; 453128765Spjd ggioc.gctl_flags = flags; 454128765Spjd ggioc.gctl_maxcount = queue_size; 455128765Spjd ggioc.gctl_timeout = timeout; 456128765Spjd ggioc.gctl_unit = unit; 457128765Spjd snprintf(ggioc.gctl_info, sizeof(ggioc.gctl_info), "%s:%u %s", host, 458128765Spjd port, path); 459128765Spjd g_gate_ioctl(G_GATE_CMD_CREATE, &ggioc); 460156590Spjd if (unit == -1) { 461128765Spjd printf("%s%u\n", G_GATE_PROVIDER_NAME, ggioc.gctl_unit); 462156590Spjd fflush(stdout); 463156590Spjd } 464128765Spjd unit = ggioc.gctl_unit; 465147844Spjd 466128765Spjd mydaemon(); 467147844Spjd g_gatec_loop(); 468128765Spjd} 469128765Spjd 470147844Spjdstatic void 471147844Spjdg_gatec_rescue(void) 472147844Spjd{ 473147844Spjd struct g_gate_ctl_cancel ggioc; 474147844Spjd 475147844Spjd if (!g_gatec_connect()) 476147844Spjd g_gate_xlog("Cannot connect: %s.", strerror(errno)); 477147844Spjd 478147844Spjd ggioc.gctl_version = G_GATE_VERSION; 479147844Spjd ggioc.gctl_unit = unit; 480147844Spjd ggioc.gctl_seq = 0; 481147844Spjd g_gate_ioctl(G_GATE_CMD_CANCEL, &ggioc); 482147844Spjd 483147844Spjd mydaemon(); 484147844Spjd g_gatec_loop(); 485147844Spjd} 486147844Spjd 487128765Spjdint 488128765Spjdmain(int argc, char *argv[]) 489128765Spjd{ 490128765Spjd 491128765Spjd if (argc < 2) 492128765Spjd usage(); 493147844Spjd if (strcasecmp(argv[1], "create") == 0) 494128765Spjd action = CREATE; 495128765Spjd else if (strcasecmp(argv[1], "destroy") == 0) 496128765Spjd action = DESTROY; 497128765Spjd else if (strcasecmp(argv[1], "list") == 0) 498128765Spjd action = LIST; 499147844Spjd else if (strcasecmp(argv[1], "rescue") == 0) 500147844Spjd action = RESCUE; 501128765Spjd else 502128765Spjd usage(); 503128765Spjd argc -= 1; 504128765Spjd argv += 1; 505128765Spjd for (;;) { 506128765Spjd int ch; 507128765Spjd 508128765Spjd ch = getopt(argc, argv, "fno:p:q:R:S:s:t:u:v"); 509128765Spjd if (ch == -1) 510128765Spjd break; 511128765Spjd switch (ch) { 512128765Spjd case 'f': 513128765Spjd if (action != DESTROY) 514128765Spjd usage(); 515128765Spjd force = 1; 516128765Spjd break; 517128765Spjd case 'n': 518147844Spjd if (action != CREATE && action != RESCUE) 519128765Spjd usage(); 520128765Spjd nagle = 0; 521128765Spjd break; 522128765Spjd case 'o': 523147844Spjd if (action != CREATE && action != RESCUE) 524128765Spjd usage(); 525128765Spjd if (strcasecmp("ro", optarg) == 0) 526128765Spjd flags = G_GATE_FLAG_READONLY; 527128765Spjd else if (strcasecmp("wo", optarg) == 0) 528128765Spjd flags = G_GATE_FLAG_WRITEONLY; 529128765Spjd else if (strcasecmp("rw", optarg) == 0) 530128765Spjd flags = 0; 531128765Spjd else { 532128765Spjd errx(EXIT_FAILURE, 533128765Spjd "Invalid argument for '-o' option."); 534128765Spjd } 535128765Spjd break; 536128765Spjd case 'p': 537147844Spjd if (action != CREATE && action != RESCUE) 538128765Spjd usage(); 539128765Spjd errno = 0; 540128765Spjd port = strtoul(optarg, NULL, 10); 541128765Spjd if (port == 0 && errno != 0) 542128765Spjd errx(EXIT_FAILURE, "Invalid port."); 543128765Spjd break; 544128765Spjd case 'q': 545128765Spjd if (action != CREATE) 546128765Spjd usage(); 547128765Spjd errno = 0; 548128765Spjd queue_size = strtoul(optarg, NULL, 10); 549128765Spjd if (queue_size == 0 && errno != 0) 550128765Spjd errx(EXIT_FAILURE, "Invalid queue_size."); 551128765Spjd break; 552128765Spjd case 'R': 553147844Spjd if (action != CREATE && action != RESCUE) 554128765Spjd usage(); 555128765Spjd errno = 0; 556128765Spjd rcvbuf = strtoul(optarg, NULL, 10); 557128765Spjd if (rcvbuf == 0 && errno != 0) 558128765Spjd errx(EXIT_FAILURE, "Invalid rcvbuf."); 559128765Spjd break; 560128765Spjd case 'S': 561147844Spjd if (action != CREATE && action != RESCUE) 562128765Spjd usage(); 563128765Spjd errno = 0; 564128765Spjd sndbuf = strtoul(optarg, NULL, 10); 565128765Spjd if (sndbuf == 0 && errno != 0) 566128765Spjd errx(EXIT_FAILURE, "Invalid sndbuf."); 567128765Spjd break; 568128765Spjd case 's': 569128765Spjd if (action != CREATE) 570128765Spjd usage(); 571128765Spjd errno = 0; 572128765Spjd sectorsize = strtoul(optarg, NULL, 10); 573128765Spjd if (sectorsize == 0 && errno != 0) 574128765Spjd errx(EXIT_FAILURE, "Invalid sectorsize."); 575128765Spjd break; 576128765Spjd case 't': 577128765Spjd if (action != CREATE) 578128765Spjd usage(); 579128765Spjd errno = 0; 580128765Spjd timeout = strtoul(optarg, NULL, 10); 581128765Spjd if (timeout == 0 && errno != 0) 582128765Spjd errx(EXIT_FAILURE, "Invalid timeout."); 583128765Spjd break; 584128765Spjd case 'u': 585128765Spjd errno = 0; 586128765Spjd unit = strtol(optarg, NULL, 10); 587128765Spjd if (unit == 0 && errno != 0) 588128765Spjd errx(EXIT_FAILURE, "Invalid unit number."); 589128765Spjd break; 590128765Spjd case 'v': 591128765Spjd if (action == DESTROY) 592128765Spjd usage(); 593128765Spjd g_gate_verbose++; 594128765Spjd break; 595128765Spjd default: 596128765Spjd usage(); 597128765Spjd } 598128765Spjd } 599128765Spjd argc -= optind; 600128765Spjd argv += optind; 601128765Spjd 602128765Spjd switch (action) { 603128765Spjd case CREATE: 604128765Spjd if (argc != 2) 605128765Spjd usage(); 606128765Spjd g_gate_load_module(); 607128765Spjd g_gate_open_device(); 608128765Spjd host = argv[0]; 609128765Spjd path = argv[1]; 610128765Spjd g_gatec_create(); 611128765Spjd break; 612128765Spjd case DESTROY: 613128765Spjd if (unit == -1) { 614128765Spjd fprintf(stderr, "Required unit number.\n"); 615128765Spjd usage(); 616128765Spjd } 617128765Spjd g_gate_verbose = 1; 618128765Spjd g_gate_open_device(); 619128765Spjd g_gate_destroy(unit, force); 620128765Spjd break; 621128765Spjd case LIST: 622128765Spjd g_gate_list(unit, g_gate_verbose); 623128765Spjd break; 624147844Spjd case RESCUE: 625147844Spjd if (argc != 2) 626147844Spjd usage(); 627147844Spjd if (unit == -1) { 628147844Spjd fprintf(stderr, "Required unit number.\n"); 629147844Spjd usage(); 630147844Spjd } 631147844Spjd g_gate_open_device(); 632147844Spjd host = argv[0]; 633147844Spjd path = argv[1]; 634147844Spjd g_gatec_rescue(); 635147844Spjd break; 636128765Spjd case UNSET: 637128765Spjd default: 638128765Spjd usage(); 639128765Spjd } 640128765Spjd g_gate_close_device(); 641128765Spjd exit(EXIT_SUCCESS); 642128765Spjd} 643