1128764Spjd/*- 2128764Spjd * Copyright (c) 2004 Pawel Jakub Dawidek <pjd@FreeBSD.org> 3128764Spjd * All rights reserved. 4128764Spjd * 5128764Spjd * Redistribution and use in source and binary forms, with or without 6128764Spjd * modification, are permitted provided that the following conditions 7128764Spjd * are met: 8128764Spjd * 1. Redistributions of source code must retain the above copyright 9128764Spjd * notice, this list of conditions and the following disclaimer. 10128764Spjd * 2. Redistributions in binary form must reproduce the above copyright 11128764Spjd * notice, this list of conditions and the following disclaimer in the 12128764Spjd * documentation and/or other materials provided with the distribution. 13128764Spjd * 14128764Spjd * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND 15128764Spjd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16128764Spjd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17128764Spjd * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE 18128764Spjd * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19128764Spjd * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20128764Spjd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21128764Spjd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22128764Spjd * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23128764Spjd * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24128764Spjd * SUCH DAMAGE. 25128764Spjd * 26128764Spjd * $FreeBSD$ 27128764Spjd */ 28128764Spjd 29128764Spjd#include <stdio.h> 30128764Spjd#include <stdlib.h> 31128764Spjd#include <stdint.h> 32128764Spjd#include <fcntl.h> 33128764Spjd#include <unistd.h> 34128764Spjd#include <string.h> 35128764Spjd#include <err.h> 36128764Spjd#include <errno.h> 37128764Spjd#include <assert.h> 38128764Spjd#include <sys/param.h> 39128764Spjd#include <sys/time.h> 40128764Spjd#include <sys/bio.h> 41128764Spjd#include <sys/disk.h> 42128764Spjd#include <sys/ioctl.h> 43128764Spjd#include <sys/stat.h> 44128764Spjd#include <sys/syslog.h> 45128764Spjd 46128764Spjd#include <geom/gate/g_gate.h> 47128764Spjd#include "ggate.h" 48128764Spjd 49128764Spjd 50241720Sedstatic enum { UNSET, CREATE, DESTROY, LIST, RESCUE } action = UNSET; 51128764Spjd 52128764Spjdstatic const char *path = NULL; 53204076Spjdstatic int unit = G_GATE_UNIT_AUTO; 54128764Spjdstatic unsigned flags = 0; 55128764Spjdstatic int force = 0; 56128764Spjdstatic unsigned sectorsize = 0; 57128764Spjdstatic unsigned timeout = G_GATE_TIMEOUT; 58128764Spjd 59128764Spjdstatic void 60128764Spjdusage(void) 61128764Spjd{ 62128764Spjd 63220265Spjd fprintf(stderr, "usage: %s create [-v] [-o <ro|wo|rw>] " 64128764Spjd "[-s sectorsize] [-t timeout] [-u unit] <path>\n", getprogname()); 65147845Spjd fprintf(stderr, " %s rescue [-v] [-o <ro|wo|rw>] <-u unit> " 66128764Spjd "<path>\n", getprogname()); 67128764Spjd fprintf(stderr, " %s destroy [-f] <-u unit>\n", getprogname()); 68128764Spjd fprintf(stderr, " %s list [-v] [-u unit]\n", getprogname()); 69128764Spjd exit(EXIT_FAILURE); 70128764Spjd} 71128764Spjd 72147845Spjdstatic int 73147845Spjdg_gate_openflags(unsigned ggflags) 74147845Spjd{ 75147845Spjd 76147845Spjd if ((ggflags & G_GATE_FLAG_READONLY) != 0) 77147845Spjd return (O_RDONLY); 78147845Spjd else if ((ggflags & G_GATE_FLAG_WRITEONLY) != 0) 79147845Spjd return (O_WRONLY); 80147845Spjd return (O_RDWR); 81147845Spjd} 82147845Spjd 83128764Spjdstatic void 84128764Spjdg_gatel_serve(int fd) 85128764Spjd{ 86128764Spjd struct g_gate_ctl_io ggio; 87128764Spjd size_t bsize; 88128764Spjd 89128764Spjd if (g_gate_verbose == 0) { 90134937Spjd if (daemon(0, 0) == -1) { 91128764Spjd g_gate_destroy(unit, 1); 92128764Spjd err(EXIT_FAILURE, "Cannot daemonize"); 93128764Spjd } 94128764Spjd } 95128764Spjd g_gate_log(LOG_DEBUG, "Worker created: %u.", getpid()); 96128764Spjd ggio.gctl_version = G_GATE_VERSION; 97128764Spjd ggio.gctl_unit = unit; 98128764Spjd bsize = sectorsize; 99128764Spjd ggio.gctl_data = malloc(bsize); 100128764Spjd for (;;) { 101128764Spjd int error; 102128764Spjdonce_again: 103128764Spjd ggio.gctl_length = bsize; 104128764Spjd ggio.gctl_error = 0; 105128764Spjd g_gate_ioctl(G_GATE_CMD_START, &ggio); 106128764Spjd error = ggio.gctl_error; 107128764Spjd switch (error) { 108128764Spjd case 0: 109128764Spjd break; 110128764Spjd case ECANCELED: 111128764Spjd /* Exit gracefully. */ 112128764Spjd free(ggio.gctl_data); 113128764Spjd g_gate_close_device(); 114128764Spjd close(fd); 115128764Spjd exit(EXIT_SUCCESS); 116128764Spjd case ENOMEM: 117128764Spjd /* Buffer too small. */ 118128764Spjd assert(ggio.gctl_cmd == BIO_DELETE || 119128764Spjd ggio.gctl_cmd == BIO_WRITE); 120128764Spjd ggio.gctl_data = realloc(ggio.gctl_data, 121128764Spjd ggio.gctl_length); 122128764Spjd if (ggio.gctl_data != NULL) { 123128764Spjd bsize = ggio.gctl_length; 124128764Spjd goto once_again; 125128764Spjd } 126128764Spjd /* FALLTHROUGH */ 127128764Spjd case ENXIO: 128128764Spjd default: 129128764Spjd g_gate_xlog("ioctl(/dev/%s): %s.", G_GATE_CTL_NAME, 130128764Spjd strerror(error)); 131128764Spjd } 132128764Spjd 133128764Spjd error = 0; 134128764Spjd switch (ggio.gctl_cmd) { 135128764Spjd case BIO_READ: 136128836Spjd if ((size_t)ggio.gctl_length > bsize) { 137128764Spjd ggio.gctl_data = realloc(ggio.gctl_data, 138128764Spjd ggio.gctl_length); 139128764Spjd if (ggio.gctl_data != NULL) 140128764Spjd bsize = ggio.gctl_length; 141128764Spjd else 142128764Spjd error = ENOMEM; 143128764Spjd } 144128764Spjd if (error == 0) { 145128764Spjd if (pread(fd, ggio.gctl_data, ggio.gctl_length, 146128764Spjd ggio.gctl_offset) == -1) { 147128764Spjd error = errno; 148128764Spjd } 149128764Spjd } 150128764Spjd break; 151128764Spjd case BIO_DELETE: 152128764Spjd case BIO_WRITE: 153128764Spjd if (pwrite(fd, ggio.gctl_data, ggio.gctl_length, 154128764Spjd ggio.gctl_offset) == -1) { 155128764Spjd error = errno; 156128764Spjd } 157128764Spjd break; 158128764Spjd default: 159128764Spjd error = EOPNOTSUPP; 160128764Spjd } 161128764Spjd 162128764Spjd ggio.gctl_error = error; 163128764Spjd g_gate_ioctl(G_GATE_CMD_DONE, &ggio); 164128764Spjd } 165128764Spjd} 166128764Spjd 167128764Spjdstatic void 168128764Spjdg_gatel_create(void) 169128764Spjd{ 170128764Spjd struct g_gate_ctl_create ggioc; 171128764Spjd int fd; 172128764Spjd 173136059Spjd fd = open(path, g_gate_openflags(flags) | O_DIRECT | O_FSYNC); 174134937Spjd if (fd == -1) 175128764Spjd err(EXIT_FAILURE, "Cannot open %s", path); 176128764Spjd ggioc.gctl_version = G_GATE_VERSION; 177128764Spjd ggioc.gctl_unit = unit; 178128764Spjd ggioc.gctl_mediasize = g_gate_mediasize(fd); 179128764Spjd if (sectorsize == 0) 180128764Spjd sectorsize = g_gate_sectorsize(fd); 181128764Spjd ggioc.gctl_sectorsize = sectorsize; 182128764Spjd ggioc.gctl_timeout = timeout; 183128764Spjd ggioc.gctl_flags = flags; 184220265Spjd ggioc.gctl_maxcount = 0; 185128764Spjd strlcpy(ggioc.gctl_info, path, sizeof(ggioc.gctl_info)); 186128764Spjd g_gate_ioctl(G_GATE_CMD_CREATE, &ggioc); 187128764Spjd if (unit == -1) 188128764Spjd printf("%s%u\n", G_GATE_PROVIDER_NAME, ggioc.gctl_unit); 189128764Spjd unit = ggioc.gctl_unit; 190128764Spjd g_gatel_serve(fd); 191128764Spjd} 192128764Spjd 193128764Spjdstatic void 194147845Spjdg_gatel_rescue(void) 195128764Spjd{ 196147845Spjd struct g_gate_ctl_cancel ggioc; 197128764Spjd int fd; 198128764Spjd 199128764Spjd fd = open(path, g_gate_openflags(flags)); 200134937Spjd if (fd == -1) 201128764Spjd err(EXIT_FAILURE, "Cannot open %s", path); 202147845Spjd 203147845Spjd ggioc.gctl_version = G_GATE_VERSION; 204147845Spjd ggioc.gctl_unit = unit; 205147845Spjd ggioc.gctl_seq = 0; 206147845Spjd g_gate_ioctl(G_GATE_CMD_CANCEL, &ggioc); 207147845Spjd 208128764Spjd g_gatel_serve(fd); 209128764Spjd} 210128764Spjd 211128764Spjdint 212128764Spjdmain(int argc, char *argv[]) 213128764Spjd{ 214128764Spjd 215128764Spjd if (argc < 2) 216128764Spjd usage(); 217147845Spjd if (strcasecmp(argv[1], "create") == 0) 218128764Spjd action = CREATE; 219147845Spjd else if (strcasecmp(argv[1], "rescue") == 0) 220147845Spjd action = RESCUE; 221128764Spjd else if (strcasecmp(argv[1], "destroy") == 0) 222128764Spjd action = DESTROY; 223128764Spjd else if (strcasecmp(argv[1], "list") == 0) 224128764Spjd action = LIST; 225128764Spjd else 226128764Spjd usage(); 227128764Spjd argc -= 1; 228128764Spjd argv += 1; 229128764Spjd for (;;) { 230128764Spjd int ch; 231128764Spjd 232220265Spjd ch = getopt(argc, argv, "fo:s:t:u:v"); 233128764Spjd if (ch == -1) 234128764Spjd break; 235128764Spjd switch (ch) { 236128764Spjd case 'f': 237128764Spjd if (action != DESTROY) 238128764Spjd usage(); 239128764Spjd force = 1; 240128764Spjd break; 241128764Spjd case 'o': 242147845Spjd if (action != CREATE && action != RESCUE) 243128764Spjd usage(); 244128764Spjd if (strcasecmp("ro", optarg) == 0) 245128764Spjd flags = G_GATE_FLAG_READONLY; 246128764Spjd else if (strcasecmp("wo", optarg) == 0) 247128764Spjd flags = G_GATE_FLAG_WRITEONLY; 248128764Spjd else if (strcasecmp("rw", optarg) == 0) 249128764Spjd flags = 0; 250128764Spjd else { 251128764Spjd errx(EXIT_FAILURE, 252128764Spjd "Invalid argument for '-o' option."); 253128764Spjd } 254128764Spjd break; 255128764Spjd case 's': 256128764Spjd if (action != CREATE) 257128764Spjd usage(); 258128764Spjd errno = 0; 259128764Spjd sectorsize = strtoul(optarg, NULL, 10); 260128764Spjd if (sectorsize == 0 && errno != 0) 261128764Spjd errx(EXIT_FAILURE, "Invalid sectorsize."); 262128764Spjd break; 263128764Spjd case 't': 264128764Spjd if (action != CREATE) 265128764Spjd usage(); 266128764Spjd errno = 0; 267128764Spjd timeout = strtoul(optarg, NULL, 10); 268128764Spjd if (timeout == 0 && errno != 0) 269128764Spjd errx(EXIT_FAILURE, "Invalid timeout."); 270128764Spjd break; 271128764Spjd case 'u': 272128764Spjd errno = 0; 273128764Spjd unit = strtol(optarg, NULL, 10); 274128764Spjd if (unit == 0 && errno != 0) 275128764Spjd errx(EXIT_FAILURE, "Invalid unit number."); 276128764Spjd break; 277128764Spjd case 'v': 278128764Spjd if (action == DESTROY) 279128764Spjd usage(); 280128764Spjd g_gate_verbose++; 281128764Spjd break; 282128764Spjd default: 283128764Spjd usage(); 284128764Spjd } 285128764Spjd } 286128764Spjd argc -= optind; 287128764Spjd argv += optind; 288128764Spjd 289128764Spjd switch (action) { 290147845Spjd case CREATE: 291128764Spjd if (argc != 1) 292128764Spjd usage(); 293147845Spjd g_gate_load_module(); 294128764Spjd g_gate_open_device(); 295128764Spjd path = argv[0]; 296147845Spjd g_gatel_create(); 297128764Spjd break; 298147845Spjd case RESCUE: 299128764Spjd if (argc != 1) 300128764Spjd usage(); 301147845Spjd if (unit == -1) { 302147845Spjd fprintf(stderr, "Required unit number.\n"); 303147845Spjd usage(); 304147845Spjd } 305128764Spjd g_gate_open_device(); 306128764Spjd path = argv[0]; 307147845Spjd g_gatel_rescue(); 308128764Spjd break; 309128764Spjd case DESTROY: 310128764Spjd if (unit == -1) { 311128764Spjd fprintf(stderr, "Required unit number.\n"); 312128764Spjd usage(); 313128764Spjd } 314128764Spjd g_gate_verbose = 1; 315128764Spjd g_gate_open_device(); 316128764Spjd g_gate_destroy(unit, force); 317128764Spjd break; 318128764Spjd case LIST: 319128764Spjd g_gate_list(unit, g_gate_verbose); 320128764Spjd break; 321128764Spjd case UNSET: 322128764Spjd default: 323128764Spjd usage(); 324128764Spjd } 325128764Spjd g_gate_close_device(); 326128764Spjd exit(EXIT_SUCCESS); 327128764Spjd} 328