ggatel.c revision 134937
1132718Skan/*- 2169703Skan * Copyright (c) 2004 Pawel Jakub Dawidek <pjd@FreeBSD.org> 3169703Skan * All rights reserved. 4132718Skan * 5132718Skan * Redistribution and use in source and binary forms, with or without 6132718Skan * modification, are permitted provided that the following conditions 7132718Skan * are met: 8132718Skan * 1. Redistributions of source code must retain the above copyright 9132718Skan * notice, this list of conditions and the following disclaimer. 10132718Skan * 2. Redistributions in binary form must reproduce the above copyright 11132718Skan * notice, this list of conditions and the following disclaimer in the 12132718Skan * documentation and/or other materials provided with the distribution. 13132718Skan * 14132718Skan * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND 15132718Skan * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16132718Skan * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17132718Skan * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE 18132718Skan * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19132718Skan * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20169703Skan * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21169703Skan * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22132718Skan * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23132735Skan * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24132735Skan * SUCH DAMAGE. 25132718Skan * 26132718Skan * $FreeBSD: head/sbin/ggate/ggatel/ggatel.c 134937 2004-09-08 07:57:14Z pjd $ 27132718Skan */ 28132718Skan 29132718Skan#include <stdio.h> 30132718Skan#include <stdlib.h> 31132718Skan#include <stdint.h> 32132718Skan#include <fcntl.h> 33132718Skan#include <unistd.h> 34132718Skan#include <string.h> 35132718Skan#include <err.h> 36132718Skan#include <errno.h> 37132718Skan#include <assert.h> 38132718Skan#include <sys/param.h> 39132718Skan#include <sys/time.h> 40132718Skan#include <sys/bio.h> 41132718Skan#include <sys/disk.h> 42132718Skan#include <sys/ioctl.h> 43169703Skan#include <sys/stat.h> 44169703Skan#include <sys/syslog.h> 45132718Skan 46132718Skan#include <geom/gate/g_gate.h> 47132718Skan#include "ggate.h" 48132718Skan 49132718Skan 50132718Skanenum { UNSET, ATTACH, CREATE, DESTROY, LIST } action = UNSET; 51132718Skan 52132718Skanstatic const char *path = NULL; 53132718Skanstatic int unit = -1; 54132718Skanstatic unsigned flags = 0; 55132718Skanstatic int force = 0; 56132718Skanstatic unsigned queue_size = G_GATE_QUEUE_SIZE; 57132718Skanstatic unsigned sectorsize = 0; 58132718Skanstatic unsigned timeout = G_GATE_TIMEOUT; 59132718Skan 60132718Skanstatic void 61132718Skanusage(void) 62259405Spfg{ 63259405Spfg 64259405Spfg fprintf(stderr, "usage: %s create [-v] [-o <ro|wo|rw>] [-q queue_size] " 65259405Spfg "[-s sectorsize] [-t timeout] [-u unit] <path>\n", getprogname()); 66259405Spfg fprintf(stderr, " %s attach [-v] [-o <ro|wo|rw>] <-u unit> " 67132718Skan "<path>\n", getprogname()); 68132718Skan fprintf(stderr, " %s destroy [-f] <-u unit>\n", getprogname()); 69169703Skan fprintf(stderr, " %s list [-v] [-u unit]\n", getprogname()); 70132718Skan exit(EXIT_FAILURE); 71169703Skan} 72169703Skan 73169703Skanstatic void 74132718Skang_gatel_serve(int fd) 75132718Skan{ 76132718Skan struct g_gate_ctl_io ggio; 77132718Skan size_t bsize; 78132718Skan 79132718Skan if (g_gate_verbose == 0) { 80132718Skan if (daemon(0, 0) == -1) { 81132718Skan g_gate_destroy(unit, 1); 82132718Skan err(EXIT_FAILURE, "Cannot daemonize"); 83132718Skan } 84132718Skan } 85132718Skan g_gate_log(LOG_DEBUG, "Worker created: %u.", getpid()); 86132718Skan ggio.gctl_version = G_GATE_VERSION; 87259268Spfg ggio.gctl_unit = unit; 88259268Spfg bsize = sectorsize; 89259268Spfg ggio.gctl_data = malloc(bsize); 90259268Spfg for (;;) { 91259268Spfg int error; 92259268Spfgonce_again: 93259268Spfg ggio.gctl_length = bsize; 94259268Spfg ggio.gctl_error = 0; 95259268Spfg g_gate_ioctl(G_GATE_CMD_START, &ggio); 96259268Spfg error = ggio.gctl_error; 97259268Spfg switch (error) { 98259268Spfg case 0: 99259268Spfg break; 100259268Spfg case ECANCELED: 101259268Spfg /* Exit gracefully. */ 102259268Spfg free(ggio.gctl_data); 103259268Spfg g_gate_close_device(); 104259268Spfg close(fd); 105259268Spfg exit(EXIT_SUCCESS); 106259268Spfg case ENOMEM: 107259268Spfg /* Buffer too small. */ 108259268Spfg assert(ggio.gctl_cmd == BIO_DELETE || 109259268Spfg ggio.gctl_cmd == BIO_WRITE); 110259268Spfg ggio.gctl_data = realloc(ggio.gctl_data, 111259268Spfg ggio.gctl_length); 112259268Spfg if (ggio.gctl_data != NULL) { 113259268Spfg bsize = ggio.gctl_length; 114259268Spfg goto once_again; 115259268Spfg } 116259268Spfg /* FALLTHROUGH */ 117259268Spfg case ENXIO: 118259268Spfg default: 119259268Spfg g_gate_xlog("ioctl(/dev/%s): %s.", G_GATE_CTL_NAME, 120259268Spfg strerror(error)); 121259268Spfg } 122259268Spfg 123259268Spfg error = 0; 124259268Spfg switch (ggio.gctl_cmd) { 125259268Spfg case BIO_READ: 126259268Spfg if ((size_t)ggio.gctl_length > bsize) { 127259268Spfg ggio.gctl_data = realloc(ggio.gctl_data, 128259268Spfg ggio.gctl_length); 129259268Spfg if (ggio.gctl_data != NULL) 130259268Spfg bsize = ggio.gctl_length; 131259268Spfg else 132259268Spfg error = ENOMEM; 133259268Spfg } 134259268Spfg if (error == 0) { 135259268Spfg if (pread(fd, ggio.gctl_data, ggio.gctl_length, 136259268Spfg ggio.gctl_offset) == -1) { 137259268Spfg error = errno; 138259268Spfg } 139259268Spfg } 140259268Spfg break; 141259268Spfg case BIO_DELETE: 142259268Spfg case BIO_WRITE: 143259268Spfg if (pwrite(fd, ggio.gctl_data, ggio.gctl_length, 144259268Spfg ggio.gctl_offset) == -1) { 145259268Spfg error = errno; 146259268Spfg } 147259268Spfg break; 148259268Spfg default: 149259268Spfg error = EOPNOTSUPP; 150259268Spfg } 151259268Spfg 152259268Spfg ggio.gctl_error = error; 153259268Spfg g_gate_ioctl(G_GATE_CMD_DONE, &ggio); 154259268Spfg } 155259268Spfg} 156259268Spfg 157259268Spfgstatic void 158259268Spfgg_gatel_create(void) 159259268Spfg{ 160259268Spfg struct g_gate_ctl_create ggioc; 161259268Spfg int fd; 162259268Spfg 163259268Spfg fd = open(path, g_gate_openflags(flags)); 164259268Spfg if (fd == -1) 165259268Spfg err(EXIT_FAILURE, "Cannot open %s", path); 166259268Spfg ggioc.gctl_version = G_GATE_VERSION; 167259268Spfg ggioc.gctl_unit = unit; 168259268Spfg ggioc.gctl_mediasize = g_gate_mediasize(fd); 169259268Spfg if (sectorsize == 0) 170259268Spfg sectorsize = g_gate_sectorsize(fd); 171259268Spfg ggioc.gctl_sectorsize = sectorsize; 172259268Spfg ggioc.gctl_timeout = timeout; 173259268Spfg ggioc.gctl_flags = flags; 174259268Spfg ggioc.gctl_maxcount = queue_size; 175259268Spfg strlcpy(ggioc.gctl_info, path, sizeof(ggioc.gctl_info)); 176259268Spfg g_gate_ioctl(G_GATE_CMD_CREATE, &ggioc); 177259268Spfg if (unit == -1) 178259268Spfg printf("%s%u\n", G_GATE_PROVIDER_NAME, ggioc.gctl_unit); 179259268Spfg unit = ggioc.gctl_unit; 180259268Spfg g_gatel_serve(fd); 181259268Spfg} 182259268Spfg 183259268Spfgstatic void 184259268Spfgg_gatel_attach(void) 185259268Spfg{ 186259268Spfg int fd; 187259268Spfg 188259268Spfg fd = open(path, g_gate_openflags(flags)); 189259268Spfg if (fd == -1) 190259268Spfg err(EXIT_FAILURE, "Cannot open %s", path); 191259268Spfg g_gatel_serve(fd); 192259268Spfg} 193259268Spfg 194259268Spfgint 195259268Spfgmain(int argc, char *argv[]) 196259268Spfg{ 197259268Spfg 198259268Spfg if (argc < 2) 199259268Spfg usage(); 200259268Spfg if (strcasecmp(argv[1], "attach") == 0) 201259268Spfg action = ATTACH; 202259268Spfg else if (strcasecmp(argv[1], "create") == 0) 203259268Spfg action = CREATE; 204259268Spfg else if (strcasecmp(argv[1], "destroy") == 0) 205259268Spfg action = DESTROY; 206259268Spfg else if (strcasecmp(argv[1], "list") == 0) 207259268Spfg action = LIST; 208259268Spfg else 209259268Spfg usage(); 210259268Spfg argc -= 1; 211259268Spfg argv += 1; 212259268Spfg for (;;) { 213259268Spfg int ch; 214259268Spfg 215259268Spfg ch = getopt(argc, argv, "fo:q:s:t:u:v"); 216259268Spfg if (ch == -1) 217259268Spfg break; 218259268Spfg switch (ch) { 219259268Spfg case 'f': 220259268Spfg if (action != DESTROY) 221259268Spfg usage(); 222259268Spfg force = 1; 223259268Spfg break; 224259268Spfg case 'o': 225259268Spfg if (action != ATTACH && action != CREATE) 226259268Spfg usage(); 227259268Spfg if (strcasecmp("ro", optarg) == 0) 228259268Spfg flags = G_GATE_FLAG_READONLY; 229259268Spfg else if (strcasecmp("wo", optarg) == 0) 230259268Spfg flags = G_GATE_FLAG_WRITEONLY; 231259268Spfg else if (strcasecmp("rw", optarg) == 0) 232259268Spfg flags = 0; 233259268Spfg else { 234259268Spfg errx(EXIT_FAILURE, 235259268Spfg "Invalid argument for '-o' option."); 236259268Spfg } 237259268Spfg break; 238259268Spfg case 'q': 239259268Spfg if (action != CREATE) 240259268Spfg usage(); 241259268Spfg errno = 0; 242259268Spfg queue_size = strtoul(optarg, NULL, 10); 243259268Spfg if (queue_size == 0 && errno != 0) 244259268Spfg errx(EXIT_FAILURE, "Invalid queue_size."); 245259268Spfg break; 246259268Spfg case 's': 247259268Spfg if (action != CREATE) 248259268Spfg usage(); 249259268Spfg errno = 0; 250259268Spfg sectorsize = strtoul(optarg, NULL, 10); 251259268Spfg if (sectorsize == 0 && errno != 0) 252259268Spfg errx(EXIT_FAILURE, "Invalid sectorsize."); 253259268Spfg break; 254259268Spfg case 't': 255259268Spfg if (action != CREATE) 256259268Spfg usage(); 257259268Spfg errno = 0; 258259268Spfg timeout = strtoul(optarg, NULL, 10); 259259268Spfg if (timeout == 0 && errno != 0) 260259268Spfg errx(EXIT_FAILURE, "Invalid timeout."); 261259268Spfg break; 262259268Spfg case 'u': 263259268Spfg errno = 0; 264259268Spfg unit = strtol(optarg, NULL, 10); 265259268Spfg if (unit == 0 && errno != 0) 266259268Spfg errx(EXIT_FAILURE, "Invalid unit number."); 267259268Spfg break; 268259268Spfg case 'v': 269259268Spfg if (action == DESTROY) 270259268Spfg usage(); 271259268Spfg g_gate_verbose++; 272259268Spfg break; 273259268Spfg default: 274259268Spfg usage(); 275259268Spfg } 276259268Spfg } 277259268Spfg argc -= optind; 278259268Spfg argv += optind; 279259268Spfg 280259268Spfg switch (action) { 281259268Spfg case ATTACH: 282259268Spfg if (argc != 1) 283259268Spfg usage(); 284259268Spfg if (unit == -1) { 285259268Spfg fprintf(stderr, "Required unit number.\n"); 286259268Spfg usage(); 287259268Spfg } 288259268Spfg g_gate_open_device(); 289259268Spfg path = argv[0]; 290259268Spfg g_gatel_attach(); 291259268Spfg break; 292259268Spfg case CREATE: 293259268Spfg if (argc != 1) 294259268Spfg usage(); 295259268Spfg g_gate_load_module(); 296259268Spfg g_gate_open_device(); 297259268Spfg path = argv[0]; 298259268Spfg g_gatel_create(); 299259268Spfg break; 300259268Spfg case DESTROY: 301259268Spfg if (unit == -1) { 302259268Spfg fprintf(stderr, "Required unit number.\n"); 303259268Spfg usage(); 304259268Spfg } 305259268Spfg g_gate_verbose = 1; 306259268Spfg g_gate_open_device(); 307259268Spfg g_gate_destroy(unit, force); 308259268Spfg break; 309259268Spfg case LIST: 310259268Spfg g_gate_list(unit, g_gate_verbose); 311259268Spfg break; 312259268Spfg case UNSET: 313259268Spfg default: 314259268Spfg usage(); 315259268Spfg } 316259268Spfg g_gate_close_device(); 317259268Spfg exit(EXIT_SUCCESS); 318259268Spfg} 319259268Spfg