diff --git a/sbin/ggate/ggatel/Makefile b/sbin/ggate/ggatel/Makefile new file mode 100644 index 000000000000..a72a0527e614 --- /dev/null +++ b/sbin/ggate/ggatel/Makefile @@ -0,0 +1,15 @@ +# $FreeBSD$ + +.PATH: ../shared + +BINDIR= /sbin +PROG= ggatel +SRCS= ggatel.c ggate.c +MAN= ggatel.8 +DPADD= ${LIBGEOM} ${LIBSBUF} ${LIBBSDXML} +LDADD= -lgeom -lsbuf -lbsdxml +WARNS= 6 +CFLAGS+=-I../shared +CFLAGS+=-DLIBGEOM + +.include diff --git a/sbin/ggate/ggatel/ggatel.8 b/sbin/ggate/ggatel/ggatel.8 new file mode 100644 index 000000000000..12536da6ccdd --- /dev/null +++ b/sbin/ggate/ggatel/ggatel.8 @@ -0,0 +1,164 @@ +.\" Copyright (c) 2004 Pawel Jakub Dawidek +.\" All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" $FreeBSD$ +.\" +.Dd April 26, 2004 +.Dt GGATEL 8 +.Os +.Sh NAME +.Nm ggatel +.Nd "GEOM Gate local control utility" +.Sh SYNOPSIS +.Nm +.Ar create +.Op Fl v +.Op Fl o Ar ro | wo | rw +.Op Fl q Ar queue_size +.Op Fl s Ar sectorsize +.Op Fl t Ar timeout +.Op Fl u Ar unit +.Ar path +.Nm +.Ar attach +.Op Fl v +.Op Fl o Ar ro | wo | rw +.Fl u Ar unit +.Ar path +.Nm +.Ar destroy +.Op Fl f +.Fl u Ar unit +.Nm +.Ar list +.Op Fl v +.Op Fl u Ar unit +.Sh DESCRIPTION +The +.Nm +utility is a local GEOM Gate class consumer. +It can be used as a replacement for +.Xr md 4 +devices or as a +.Dq GEOMificator +for non GEOM\-aware devices, but it was mainly created as an example +on how to use and how to communicate with the GEOM Gate kernel module. +.Pp +Available commands: +.Bl -tag -width ".Ar destroy" +.It Ar create +Create a +.Nm ggate +provider related to the given regular file or device. +.It Ar attach +Attach a worker process to an existing +.Nm ggate +provider. +.It Ar destroy +Destroy the given +.Nm ggate +provider. +.It Ar list +List +.Nm ggate +providers. +.El +.Pp +Available options: +.Bl -tag -width ".Fl s Ar ro | wo | rw" +.It Fl f +Forcibly destroy +.Nm ggate +provider (cancels all pending requests). +.It Fl o Ar ro | wo | rw +Specify permission to use when opening the file or device: read\-only +.Ar ( ro ) , +write\-only +.Ar ( wo ) , +or read\-write +.Ar ( rw ) . +Default is +.Ar rw . +.It Fl q Ar queue_size +Number of pending I/O requests that can be queued before they will +start to be canceled. +Default is 1024. +.It Fl s Ar sectorsize +Sector size for +.Nm ggate +provider. +If not specified, it is taken from device or set to 512 bytes for files. +.It Fl t Ar timeout +Number of seconds to wait before an I/O request will be canceled. +0 means no timeout. +Default is 30. +.It Fl u Ar unit +Unit number to use. +.It Fl v +Do not fork, run in foreground and print debug informations on standard +output. +.It Ar path +Path to a regular file or device. +.El +.Pp +.Sh EXAMPLES +.Dq GEOMify +the +.Li fd0 +device and use +.Xr gbde 8 +to encrypt data on a floppy. +.Pp +.Bd -literal -offset indent +ggatel -u 5 /dev/fd0 +gbde init /dev/ggate5 +gbde attach ggate5 +newfs /dev/ggate5.bde +mount /dev/ggate5.bde /secret +cp /private/foo /secret/ +umount /secret +gbde detach ggate5 +.Ed +.Pp +.Sh DIAGNOSTICS +Exit status is 0 on success, or 1 if the command fails. +To get details about the failure, +.Nm +should be called with the +.Fl v +option. +.Sh SEE ALSO +.Xr geom 4 , +.Xr gbde 8 , +.Xr ggatec 8 , +.Xr ggated 8 , +.Xr mount 8 , +.Xr newfs 8 +.Sh AUTHORS +The +.Nm +utility as well as this manual page was written by +.An -split +.An Pawel Jakub Dawidek Aq pjd@FreeBSD.org . +.An -nosplit diff --git a/sbin/ggate/ggatel/ggatel.c b/sbin/ggate/ggatel/ggatel.c new file mode 100644 index 000000000000..78b969e5c85a --- /dev/null +++ b/sbin/ggate/ggatel/ggatel.c @@ -0,0 +1,318 @@ +/*- + * Copyright (c) 2004 Pawel Jakub Dawidek + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include "ggate.h" + + +enum { UNSET, ATTACH, CREATE, DESTROY, LIST } action = UNSET; + +static const char *path = NULL; +static int unit = -1; +static unsigned flags = 0; +static int force = 0; +static unsigned queue_size = G_GATE_QUEUE_SIZE; +static unsigned sectorsize = 0; +static unsigned timeout = G_GATE_TIMEOUT; + +static void +usage(void) +{ + + fprintf(stderr, "usage: %s create [-v] [-o ] [-q queue_size] " + "[-s sectorsize] [-t timeout] [-u unit] \n", getprogname()); + fprintf(stderr, " %s attach [-v] [-o ] <-u unit> " + "\n", getprogname()); + fprintf(stderr, " %s destroy [-f] <-u unit>\n", getprogname()); + fprintf(stderr, " %s list [-v] [-u unit]\n", getprogname()); + exit(EXIT_FAILURE); +} + +static void +g_gatel_serve(int fd) +{ + struct g_gate_ctl_io ggio; + size_t bsize; + + if (g_gate_verbose == 0) { + if (daemon(0, 0) < 0) { + g_gate_destroy(unit, 1); + err(EXIT_FAILURE, "Cannot daemonize"); + } + } + g_gate_log(LOG_DEBUG, "Worker created: %u.", getpid()); + ggio.gctl_version = G_GATE_VERSION; + ggio.gctl_unit = unit; + bsize = sectorsize; + ggio.gctl_data = malloc(bsize); + for (;;) { + int error; +once_again: + ggio.gctl_length = bsize; + ggio.gctl_error = 0; + g_gate_ioctl(G_GATE_CMD_START, &ggio); + error = ggio.gctl_error; + switch (error) { + case 0: + break; + case ECANCELED: + /* Exit gracefully. */ + free(ggio.gctl_data); + g_gate_close_device(); + close(fd); + exit(EXIT_SUCCESS); + case ENOMEM: + /* Buffer too small. */ + assert(ggio.gctl_cmd == BIO_DELETE || + ggio.gctl_cmd == BIO_WRITE); + ggio.gctl_data = realloc(ggio.gctl_data, + ggio.gctl_length); + if (ggio.gctl_data != NULL) { + bsize = ggio.gctl_length; + goto once_again; + } + /* FALLTHROUGH */ + case ENXIO: + default: + g_gate_xlog("ioctl(/dev/%s): %s.", G_GATE_CTL_NAME, + strerror(error)); + } + + error = 0; + switch (ggio.gctl_cmd) { + case BIO_READ: + if (ggio.gctl_length > bsize) { + ggio.gctl_data = realloc(ggio.gctl_data, + ggio.gctl_length); + if (ggio.gctl_data != NULL) + bsize = ggio.gctl_length; + else + error = ENOMEM; + } + if (error == 0) { + if (pread(fd, ggio.gctl_data, ggio.gctl_length, + ggio.gctl_offset) == -1) { + error = errno; + } + } + break; + case BIO_DELETE: + case BIO_WRITE: + if (pwrite(fd, ggio.gctl_data, ggio.gctl_length, + ggio.gctl_offset) == -1) { + error = errno; + } + break; + default: + error = EOPNOTSUPP; + } + + ggio.gctl_error = error; + g_gate_ioctl(G_GATE_CMD_DONE, &ggio); + } +} + +static void +g_gatel_create(void) +{ + struct g_gate_ctl_create ggioc; + int fd; + + fd = open(path, g_gate_openflags(flags)); + if (fd < 0) + err(EXIT_FAILURE, "Cannot open %s", path); + ggioc.gctl_version = G_GATE_VERSION; + ggioc.gctl_unit = unit; + ggioc.gctl_mediasize = g_gate_mediasize(fd); + if (sectorsize == 0) + sectorsize = g_gate_sectorsize(fd); + ggioc.gctl_sectorsize = sectorsize; + ggioc.gctl_timeout = timeout; + ggioc.gctl_flags = flags; + ggioc.gctl_maxcount = queue_size; + strlcpy(ggioc.gctl_info, path, sizeof(ggioc.gctl_info)); + g_gate_ioctl(G_GATE_CMD_CREATE, &ggioc); + if (unit == -1) + printf("%s%u\n", G_GATE_PROVIDER_NAME, ggioc.gctl_unit); + unit = ggioc.gctl_unit; + g_gatel_serve(fd); +} + +static void +g_gatel_attach(void) +{ + int fd; + + fd = open(path, g_gate_openflags(flags)); + if (fd < 0) + err(EXIT_FAILURE, "Cannot open %s", path); + g_gatel_serve(fd); +} + +int +main(int argc, char *argv[]) +{ + + if (argc < 2) + usage(); + if (strcasecmp(argv[1], "attach") == 0) + action = ATTACH; + else if (strcasecmp(argv[1], "create") == 0) + action = CREATE; + else if (strcasecmp(argv[1], "destroy") == 0) + action = DESTROY; + else if (strcasecmp(argv[1], "list") == 0) + action = LIST; + else + usage(); + argc -= 1; + argv += 1; + for (;;) { + int ch; + + ch = getopt(argc, argv, "fo:q:s:t:u:v"); + if (ch == -1) + break; + switch (ch) { + case 'f': + if (action != DESTROY) + usage(); + force = 1; + break; + case 'o': + if (action != ATTACH && action != CREATE) + usage(); + if (strcasecmp("ro", optarg) == 0) + flags = G_GATE_FLAG_READONLY; + else if (strcasecmp("wo", optarg) == 0) + flags = G_GATE_FLAG_WRITEONLY; + else if (strcasecmp("rw", optarg) == 0) + flags = 0; + else { + errx(EXIT_FAILURE, + "Invalid argument for '-o' option."); + } + break; + case 'q': + if (action != CREATE) + usage(); + errno = 0; + queue_size = strtoul(optarg, NULL, 10); + if (queue_size == 0 && errno != 0) + errx(EXIT_FAILURE, "Invalid queue_size."); + break; + case 's': + if (action != CREATE) + usage(); + errno = 0; + sectorsize = strtoul(optarg, NULL, 10); + if (sectorsize == 0 && errno != 0) + errx(EXIT_FAILURE, "Invalid sectorsize."); + break; + case 't': + if (action != CREATE) + usage(); + errno = 0; + timeout = strtoul(optarg, NULL, 10); + if (timeout == 0 && errno != 0) + errx(EXIT_FAILURE, "Invalid timeout."); + break; + case 'u': + errno = 0; + unit = strtol(optarg, NULL, 10); + if (unit == 0 && errno != 0) + errx(EXIT_FAILURE, "Invalid unit number."); + break; + case 'v': + if (action == DESTROY) + usage(); + g_gate_verbose++; + break; + default: + usage(); + } + } + argc -= optind; + argv += optind; + + switch (action) { + case ATTACH: + if (argc != 1) + usage(); + if (unit == -1) { + fprintf(stderr, "Required unit number.\n"); + usage(); + } + g_gate_open_device(); + path = argv[0]; + g_gatel_attach(); + break; + case CREATE: + if (argc != 1) + usage(); + g_gate_load_module(); + g_gate_open_device(); + path = argv[0]; + g_gatel_create(); + break; + case DESTROY: + if (unit == -1) { + fprintf(stderr, "Required unit number.\n"); + usage(); + } + g_gate_verbose = 1; + g_gate_open_device(); + g_gate_destroy(unit, force); + break; + case LIST: + g_gate_list(unit, g_gate_verbose); + break; + case UNSET: + default: + usage(); + } + g_gate_close_device(); + exit(EXIT_SUCCESS); +}