From 58507b1fb45d686e476d995267ae78bff8522274 Mon Sep 17 00:00:00 2001 From: gjb Date: Fri, 27 Dec 2013 04:23:07 +0000 Subject: [PATCH 1/2] Copy head@r259933 -> user/gjb/hacking/release-embedded for initial inclusion of (at least) arm builds with the release. Sponsored by: The FreeBSD Foundation --- Makefile | 14 - Makefile.inc | 3 - ggatec/Makefile | 16 - ggatec/ggatec.8 | 181 -------- ggatec/ggatec.c | 642 ----------------------------- ggated/Makefile | 14 - ggated/ggated.8 | 111 ----- ggated/ggated.c | 1050 ----------------------------------------------- ggatel/Makefile | 15 - ggatel/ggatel.8 | 155 ------- ggatel/ggatel.c | 327 --------------- shared/ggate.c | 409 ------------------ shared/ggate.h | 196 --------- 13 files changed, 3133 deletions(-) delete mode 100644 Makefile delete mode 100644 Makefile.inc delete mode 100644 ggatec/Makefile delete mode 100644 ggatec/ggatec.8 delete mode 100644 ggatec/ggatec.c delete mode 100644 ggated/Makefile delete mode 100644 ggated/ggated.8 delete mode 100644 ggated/ggated.c delete mode 100644 ggatel/Makefile delete mode 100644 ggatel/ggatel.8 delete mode 100644 ggatel/ggatel.c delete mode 100644 shared/ggate.c delete mode 100644 shared/ggate.h diff --git a/Makefile b/Makefile deleted file mode 100644 index 8f889f1..0000000 --- a/Makefile +++ /dev/null @@ -1,14 +0,0 @@ -# $FreeBSD$ - -.include - -SUBDIR= ${_ggatec} \ - ${_ggated} \ - ggatel - -.if ${MK_LIBTHR} != "no" -_ggatec= ggatec -_ggated= ggated -.endif - -.include diff --git a/Makefile.inc b/Makefile.inc deleted file mode 100644 index 265f86d..0000000 --- a/Makefile.inc +++ /dev/null @@ -1,3 +0,0 @@ -# $FreeBSD$ - -.include "../Makefile.inc" diff --git a/ggatec/Makefile b/ggatec/Makefile deleted file mode 100644 index 4d8917f..0000000 --- a/ggatec/Makefile +++ /dev/null @@ -1,16 +0,0 @@ -# $FreeBSD$ - -.PATH: ${.CURDIR}/../shared - -PROG= ggatec -MAN= ggatec.8 -SRCS= ggatec.c ggate.c - -CFLAGS+= -DMAX_SEND_SIZE=32768 -CFLAGS+= -DLIBGEOM -CFLAGS+= -I${.CURDIR}/../shared - -DPADD= ${LIBGEOM} ${LIBSBUF} ${LIBBSDXML} ${LIBUTIL} ${LIBPTHREAD} -LDADD= -lgeom -lsbuf -lbsdxml -lutil -lpthread - -.include diff --git a/ggatec/ggatec.8 b/ggatec/ggatec.8 deleted file mode 100644 index 09f0444..0000000 --- a/ggatec/ggatec.8 +++ /dev/null @@ -1,181 +0,0 @@ -.\" 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 GGATEC 8 -.Os -.Sh NAME -.Nm ggatec -.Nd "GEOM Gate network client and control utility" -.Sh SYNOPSIS -.Nm -.Cm create -.Op Fl n -.Op Fl v -.Op Fl o Cm ro | wo | rw -.Op Fl p Ar port -.Op Fl q Ar queue_size -.Op Fl R Ar rcvbuf -.Op Fl S Ar sndbuf -.Op Fl s Ar sectorsize -.Op Fl t Ar timeout -.Op Fl u Ar unit -.Ar host -.Ar path -.Nm -.Cm rescue -.Op Fl n -.Op Fl v -.Op Fl o Cm ro | wo | rw -.Op Fl p Ar port -.Op Fl R Ar rcvbuf -.Op Fl S Ar sndbuf -.Fl u Ar unit -.Ar host -.Ar path -.Nm -.Cm destroy -.Op Fl f -.Fl u Ar unit -.Nm -.Cm list -.Op Fl v -.Op Fl u Ar unit -.Sh DESCRIPTION -The -.Nm -utility is a network client for GEOM Gate class. -It is responsible for creation of -.Nm ggate -devices and forwarding I/O requests between -.Nm geom_gate.ko -kernel module and -.Xr ggated 8 -network daemon. -Available commands: -.Bl -tag -width ".Cm destroy" -.It Cm create -Connect to given -.Xr ggated 8 -daemon and create a -.Nm ggate -provider related to the given remote file or device. -.It Cm rescue -If -.Nm -process died/has been killed, you can save situation with this -command, which creates new connection to the -.Xr ggated 8 -daemon and will handle pending and future requests. -.It Cm destroy -Destroy the given -.Nm ggate -provider. -.It Cm list -List -.Nm ggate -providers. -.El -.Pp -Available options: -.Bl -tag -width ".Fl s Cm ro | wo | rw" -.It Fl f -Forcibly destroy -.Nm ggate -provider (cancels all pending requests). -.It Fl n -Do not use -.Dv TCP_NODELAY -option on TCP sockets. -.It Fl o Cm ro | wo | rw -Specify permission to use when opening the file or device: read-only -.Pq Cm ro , -write-only -.Pq Cm wo , -or read-write -.Pq Cm rw . -Default is -.Cm rw . -.It Fl p Ar port -Port to connect to on the remote host. -Default is 3080. -.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 R Ar rcvbuf -Size of receive buffer to use. -Default is 131072 (128kB). -.It Fl S Ar sndbuf -Size of send buffer to use. -Default is 131072 (128kB). -.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 0. -.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 host -Remote host to connect to. -.It Ar path -Path to a regular file or device. -.El -.Sh EXIT STATUS -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 EXAMPLES -Make use of CD-ROM device from remote host. -.Bd -literal -offset indent -server# cat /etc/gg.exports -client RO /dev/acd0 -server# ggated - -client# ggatec create -o ro server /dev/acd0 -ggate0 -client# mount_cd9660 /dev/ggate0 /cdrom -.Ed -.Sh SEE ALSO -.Xr geom 4 , -.Xr ggated 8 , -.Xr ggatel 8 , -.Xr mount_cd9660 8 -.Sh AUTHORS -The -.Nm -utility as well as this manual page was written by -.An Pawel Jakub Dawidek Aq pjd@FreeBSD.org . diff --git a/ggatec/ggatec.c b/ggatec/ggatec.c deleted file mode 100644 index 6f9263c..0000000 --- a/ggatec/ggatec.c +++ /dev/null @@ -1,642 +0,0 @@ -/*- - * 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 -#include -#include -#include -#include -#include - -#include -#include "ggate.h" - - -static enum { UNSET, CREATE, DESTROY, LIST, RESCUE } action = UNSET; - -static const char *path = NULL; -static const char *host = NULL; -static int unit = G_GATE_UNIT_AUTO; -static unsigned flags = 0; -static int force = 0; -static unsigned queue_size = G_GATE_QUEUE_SIZE; -static unsigned port = G_GATE_PORT; -static off_t mediasize; -static unsigned sectorsize = 0; -static unsigned timeout = G_GATE_TIMEOUT; -static int sendfd, recvfd; -static uint32_t token; -static pthread_t sendtd, recvtd; -static int reconnect; - -static void -usage(void) -{ - - fprintf(stderr, "usage: %s create [-nv] [-o ] [-p port] " - "[-q queue_size] [-R rcvbuf] [-S sndbuf] [-s sectorsize] " - "[-t timeout] [-u unit] \n", getprogname()); - fprintf(stderr, " %s rescue [-nv] [-o ] [-p port] " - "[-R rcvbuf] [-S sndbuf] <-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 * -send_thread(void *arg __unused) -{ - struct g_gate_ctl_io ggio; - struct g_gate_hdr hdr; - char buf[MAXPHYS]; - ssize_t data; - int error; - - g_gate_log(LOG_NOTICE, "%s: started!", __func__); - - ggio.gctl_version = G_GATE_VERSION; - ggio.gctl_unit = unit; - ggio.gctl_data = buf; - - for (;;) { - ggio.gctl_length = sizeof(buf); - ggio.gctl_error = 0; - g_gate_ioctl(G_GATE_CMD_START, &ggio); - error = ggio.gctl_error; - switch (error) { - case 0: - break; - case ECANCELED: - if (reconnect) - break; - /* Exit gracefully. */ - g_gate_close_device(); - exit(EXIT_SUCCESS); -#if 0 - case ENOMEM: - /* Buffer too small. */ - ggio.gctl_data = realloc(ggio.gctl_data, - ggio.gctl_length); - if (ggio.gctl_data != NULL) { - bsize = ggio.gctl_length; - goto once_again; - } - /* FALLTHROUGH */ -#endif - case ENXIO: - default: - g_gate_xlog("ioctl(/dev/%s): %s.", G_GATE_CTL_NAME, - strerror(error)); - } - - if (reconnect) - break; - - switch (ggio.gctl_cmd) { - case BIO_READ: - hdr.gh_cmd = GGATE_CMD_READ; - break; - case BIO_WRITE: - hdr.gh_cmd = GGATE_CMD_WRITE; - break; - } - hdr.gh_seq = ggio.gctl_seq; - hdr.gh_offset = ggio.gctl_offset; - hdr.gh_length = ggio.gctl_length; - hdr.gh_error = 0; - g_gate_swap2n_hdr(&hdr); - - data = g_gate_send(sendfd, &hdr, sizeof(hdr), MSG_NOSIGNAL); - g_gate_log(LOG_DEBUG, "Sent hdr packet."); - g_gate_swap2h_hdr(&hdr); - if (reconnect) - break; - if (data != sizeof(hdr)) { - g_gate_log(LOG_ERR, "Lost connection 1."); - reconnect = 1; - pthread_kill(recvtd, SIGUSR1); - break; - } - - if (hdr.gh_cmd == GGATE_CMD_WRITE) { - data = g_gate_send(sendfd, ggio.gctl_data, - ggio.gctl_length, MSG_NOSIGNAL); - if (reconnect) - break; - if (data != ggio.gctl_length) { - g_gate_log(LOG_ERR, "Lost connection 2 (%zd != %zd).", data, (ssize_t)ggio.gctl_length); - reconnect = 1; - pthread_kill(recvtd, SIGUSR1); - break; - } - g_gate_log(LOG_DEBUG, "Sent %zd bytes (offset=%llu, " - "size=%u).", data, hdr.gh_offset, hdr.gh_length); - } - } - g_gate_log(LOG_DEBUG, "%s: Died.", __func__); - return (NULL); -} - -static void * -recv_thread(void *arg __unused) -{ - struct g_gate_ctl_io ggio; - struct g_gate_hdr hdr; - char buf[MAXPHYS]; - ssize_t data; - - g_gate_log(LOG_NOTICE, "%s: started!", __func__); - - ggio.gctl_version = G_GATE_VERSION; - ggio.gctl_unit = unit; - ggio.gctl_data = buf; - - for (;;) { - data = g_gate_recv(recvfd, &hdr, sizeof(hdr), MSG_WAITALL); - if (reconnect) - break; - g_gate_swap2h_hdr(&hdr); - if (data != sizeof(hdr)) { - if (data == -1 && errno == EAGAIN) - continue; - g_gate_log(LOG_ERR, "Lost connection 3."); - reconnect = 1; - pthread_kill(sendtd, SIGUSR1); - break; - } - g_gate_log(LOG_DEBUG, "Received hdr packet."); - - ggio.gctl_seq = hdr.gh_seq; - ggio.gctl_cmd = hdr.gh_cmd; - ggio.gctl_offset = hdr.gh_offset; - ggio.gctl_length = hdr.gh_length; - ggio.gctl_error = hdr.gh_error; - - if (ggio.gctl_error == 0 && ggio.gctl_cmd == GGATE_CMD_READ) { - data = g_gate_recv(recvfd, ggio.gctl_data, - ggio.gctl_length, MSG_WAITALL); - if (reconnect) - break; - g_gate_log(LOG_DEBUG, "Received data packet."); - if (data != ggio.gctl_length) { - g_gate_log(LOG_ERR, "Lost connection 4."); - reconnect = 1; - pthread_kill(sendtd, SIGUSR1); - break; - } - g_gate_log(LOG_DEBUG, "Received %d bytes (offset=%ju, " - "size=%zu).", data, (uintmax_t)hdr.gh_offset, - (size_t)hdr.gh_length); - } - - g_gate_ioctl(G_GATE_CMD_DONE, &ggio); - } - g_gate_log(LOG_DEBUG, "%s: Died.", __func__); - pthread_exit(NULL); -} - -static int -handshake(int dir) -{ - struct g_gate_version ver; - struct g_gate_cinit cinit; - struct g_gate_sinit sinit; - struct sockaddr_in serv; - int sfd; - - /* - * Do the network stuff. - */ - bzero(&serv, sizeof(serv)); - serv.sin_family = AF_INET; - serv.sin_addr.s_addr = g_gate_str2ip(host); - if (serv.sin_addr.s_addr == INADDR_NONE) { - g_gate_log(LOG_DEBUG, "Invalid IP/host name: %s.", host); - return (-1); - } - serv.sin_port = htons(port); - sfd = socket(AF_INET, SOCK_STREAM, 0); - if (sfd == -1) { - g_gate_log(LOG_DEBUG, "Cannot open socket: %s.", - strerror(errno)); - return (-1); - } - - g_gate_socket_settings(sfd); - - if (connect(sfd, (struct sockaddr *)&serv, sizeof(serv)) == -1) { - g_gate_log(LOG_DEBUG, "Cannot connect to server: %s.", - strerror(errno)); - close(sfd); - return (-1); - } - - g_gate_log(LOG_INFO, "Connected to the server: %s:%d.", host, port); - - /* - * Create and send version packet. - */ - g_gate_log(LOG_DEBUG, "Sending version packet."); - assert(strlen(GGATE_MAGIC) == sizeof(ver.gv_magic)); - bcopy(GGATE_MAGIC, ver.gv_magic, sizeof(ver.gv_magic)); - ver.gv_version = GGATE_VERSION; - ver.gv_error = 0; - g_gate_swap2n_version(&ver); - if (g_gate_send(sfd, &ver, sizeof(ver), MSG_NOSIGNAL) == -1) { - g_gate_log(LOG_DEBUG, "Error while sending version packet: %s.", - strerror(errno)); - close(sfd); - return (-1); - } - bzero(&ver, sizeof(ver)); - if (g_gate_recv(sfd, &ver, sizeof(ver), MSG_WAITALL) == -1) { - g_gate_log(LOG_DEBUG, "Error while receiving data: %s.", - strerror(errno)); - close(sfd); - return (-1); - } - if (ver.gv_error != 0) { - g_gate_log(LOG_DEBUG, "Version verification problem: %s.", - strerror(errno)); - close(sfd); - return (-1); - } - - /* - * Create and send initial packet. - */ - g_gate_log(LOG_DEBUG, "Sending initial packet."); - if (strlcpy(cinit.gc_path, path, sizeof(cinit.gc_path)) >= - sizeof(cinit.gc_path)) { - g_gate_log(LOG_DEBUG, "Path name too long."); - close(sfd); - return (-1); - } - cinit.gc_flags = flags | dir; - cinit.gc_token = token; - cinit.gc_nconn = 2; - g_gate_swap2n_cinit(&cinit); - if (g_gate_send(sfd, &cinit, sizeof(cinit), MSG_NOSIGNAL) == -1) { - g_gate_log(LOG_DEBUG, "Error while sending initial packet: %s.", - strerror(errno)); - close(sfd); - return (-1); - } - g_gate_swap2h_cinit(&cinit); - - /* - * Receiving initial packet from server. - */ - g_gate_log(LOG_DEBUG, "Receiving initial packet."); - if (g_gate_recv(sfd, &sinit, sizeof(sinit), MSG_WAITALL) == -1) { - g_gate_log(LOG_DEBUG, "Error while receiving data: %s.", - strerror(errno)); - close(sfd); - return (-1); - } - g_gate_swap2h_sinit(&sinit); - if (sinit.gs_error != 0) { - g_gate_log(LOG_DEBUG, "Error from server: %s.", - strerror(sinit.gs_error)); - close(sfd); - return (-1); - } - g_gate_log(LOG_DEBUG, "Received initial packet."); - - mediasize = sinit.gs_mediasize; - if (sectorsize == 0) - sectorsize = sinit.gs_sectorsize; - - return (sfd); -} - -static void -mydaemon(void) -{ - - if (g_gate_verbose > 0) - return; - if (daemon(0, 0) == 0) - return; - if (action == CREATE) - g_gate_destroy(unit, 1); - err(EXIT_FAILURE, "Cannot daemonize"); -} - -static int -g_gatec_connect(void) -{ - - token = arc4random(); - /* - * Our receive descriptor is connected to the send descriptor on the - * server side. - */ - recvfd = handshake(GGATE_FLAG_SEND); - if (recvfd == -1) - return (0); - /* - * Our send descriptor is connected to the receive descriptor on the - * server side. - */ - sendfd = handshake(GGATE_FLAG_RECV); - if (sendfd == -1) - return (0); - return (1); -} - -static void -g_gatec_start(void) -{ - int error; - - reconnect = 0; - error = pthread_create(&recvtd, NULL, recv_thread, NULL); - if (error != 0) { - g_gate_destroy(unit, 1); - g_gate_xlog("pthread_create(recv_thread): %s.", - strerror(error)); - } - sendtd = pthread_self(); - send_thread(NULL); - /* Disconnected. */ - close(sendfd); - close(recvfd); -} - -static void -signop(int sig __unused) -{ - - /* Do nothing. */ -} - -static void -g_gatec_loop(void) -{ - struct g_gate_ctl_cancel ggioc; - - signal(SIGUSR1, signop); - for (;;) { - g_gatec_start(); - g_gate_log(LOG_NOTICE, "Disconnected [%s %s]. Connecting...", - host, path); - while (!g_gatec_connect()) { - sleep(2); - g_gate_log(LOG_NOTICE, "Connecting [%s %s]...", host, - path); - } - ggioc.gctl_version = G_GATE_VERSION; - ggioc.gctl_unit = unit; - ggioc.gctl_seq = 0; - g_gate_ioctl(G_GATE_CMD_CANCEL, &ggioc); - } -} - -static void -g_gatec_create(void) -{ - struct g_gate_ctl_create ggioc; - - if (!g_gatec_connect()) - g_gate_xlog("Cannot connect: %s.", strerror(errno)); - - /* - * Ok, got both sockets, time to create provider. - */ - ggioc.gctl_version = G_GATE_VERSION; - ggioc.gctl_mediasize = mediasize; - ggioc.gctl_sectorsize = sectorsize; - ggioc.gctl_flags = flags; - ggioc.gctl_maxcount = queue_size; - ggioc.gctl_timeout = timeout; - ggioc.gctl_unit = unit; - snprintf(ggioc.gctl_info, sizeof(ggioc.gctl_info), "%s:%u %s", host, - port, path); - g_gate_ioctl(G_GATE_CMD_CREATE, &ggioc); - if (unit == -1) { - printf("%s%u\n", G_GATE_PROVIDER_NAME, ggioc.gctl_unit); - fflush(stdout); - } - unit = ggioc.gctl_unit; - - mydaemon(); - g_gatec_loop(); -} - -static void -g_gatec_rescue(void) -{ - struct g_gate_ctl_cancel ggioc; - - if (!g_gatec_connect()) - g_gate_xlog("Cannot connect: %s.", strerror(errno)); - - ggioc.gctl_version = G_GATE_VERSION; - ggioc.gctl_unit = unit; - ggioc.gctl_seq = 0; - g_gate_ioctl(G_GATE_CMD_CANCEL, &ggioc); - - mydaemon(); - g_gatec_loop(); -} - -int -main(int argc, char *argv[]) -{ - - if (argc < 2) - usage(); - 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 if (strcasecmp(argv[1], "rescue") == 0) - action = RESCUE; - else - usage(); - argc -= 1; - argv += 1; - for (;;) { - int ch; - - ch = getopt(argc, argv, "fno:p:q:R:S:s:t:u:v"); - if (ch == -1) - break; - switch (ch) { - case 'f': - if (action != DESTROY) - usage(); - force = 1; - break; - case 'n': - if (action != CREATE && action != RESCUE) - usage(); - nagle = 0; - break; - case 'o': - if (action != CREATE && action != RESCUE) - 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 'p': - if (action != CREATE && action != RESCUE) - usage(); - errno = 0; - port = strtoul(optarg, NULL, 10); - if (port == 0 && errno != 0) - errx(EXIT_FAILURE, "Invalid port."); - 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 'R': - if (action != CREATE && action != RESCUE) - usage(); - errno = 0; - rcvbuf = strtoul(optarg, NULL, 10); - if (rcvbuf == 0 && errno != 0) - errx(EXIT_FAILURE, "Invalid rcvbuf."); - break; - case 'S': - if (action != CREATE && action != RESCUE) - usage(); - errno = 0; - sndbuf = strtoul(optarg, NULL, 10); - if (sndbuf == 0 && errno != 0) - errx(EXIT_FAILURE, "Invalid sndbuf."); - 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 CREATE: - if (argc != 2) - usage(); - g_gate_load_module(); - g_gate_open_device(); - host = argv[0]; - path = argv[1]; - g_gatec_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 RESCUE: - if (argc != 2) - usage(); - if (unit == -1) { - fprintf(stderr, "Required unit number.\n"); - usage(); - } - g_gate_open_device(); - host = argv[0]; - path = argv[1]; - g_gatec_rescue(); - break; - case UNSET: - default: - usage(); - } - g_gate_close_device(); - exit(EXIT_SUCCESS); -} diff --git a/ggated/Makefile b/ggated/Makefile deleted file mode 100644 index 4e7708e..0000000 --- a/ggated/Makefile +++ /dev/null @@ -1,14 +0,0 @@ -# $FreeBSD$ - -.PATH: ${.CURDIR}/../shared - -PROG= ggated -MAN= ggated.8 -SRCS= ggated.c ggate.c - -DPADD= ${LIBPTHREAD} -LDADD= -lpthread - -CFLAGS+= -I${.CURDIR}/../shared - -.include diff --git a/ggated/ggated.8 b/ggated/ggated.8 deleted file mode 100644 index 3024a04..0000000 --- a/ggated/ggated.8 +++ /dev/null @@ -1,111 +0,0 @@ -.\" 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 29, 2004 -.Dt GGATED 8 -.Os -.Sh NAME -.Nm ggated -.Nd "GEOM Gate network daemon" -.Sh SYNOPSIS -.Nm -.Op Fl h -.Op Fl n -.Op Fl v -.Op Fl a Ar address -.Op Fl p Ar port -.Op Fl R Ar rcvbuf -.Op Fl S Ar sndbuf -.Op Ar "exports file" -.Sh DESCRIPTION -The -.Nm -utility is a network server for GEOM Gate class. -It runs on a server machine to service GEOM Gate requests from workers -placed on a client machine. -Keep in mind, that connection between -.Xr ggatec 8 -and -.Nm -is not encrypted. -.Pp -Available options: -.Bl -tag -width ".Ar exports\ file" -.It Fl a Ar address -Specifies an IP address to bind to. -.It Fl h -Print available options. -.It Fl n -Do not use -.Dv TCP_NODELAY -option on TCP sockets. -.It Fl p Ar port -Port on which -.Nm -listens for connection. -Default is 3080. -.It Fl R Ar rcvbuf -Size of receive buffer to use. -Default is 131072 (128kB). -.It Fl S Ar sndbuf -Size of send buffer to use. -Default is 131072 (128kB). -.It Fl v -Do not fork, run in foreground and print debug informations on standard -output. -.It Ar "exports file" -An alternate location for the exports file. -.El -.Pp -The format of an exports file is as follows: -.Bd -literal -offset indent -1.2.3.4 RO /dev/acd0 -1.2.3.0/24 RW /tmp/test.img -hostname WO /tmp/image -.Ed -.Sh EXIT STATUS -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 EXAMPLES -Export CD-ROM device and a file: -.Bd -literal -offset indent -# echo "1.2.3.0/24 RO /dev/acd0" > /etc/gg.exports -# echo "client RW /image" >> /etc/gg.exports -# ggated -.Ed -.Sh SEE ALSO -.Xr geom 4 , -.Xr ggatec 8 , -.Xr ggatel 8 -.Sh AUTHORS -The -.Nm -utility as well as this manual page was written by -.An Pawel Jakub Dawidek Aq pjd@FreeBSD.org . diff --git a/ggated/ggated.c b/ggated/ggated.c deleted file mode 100644 index 01aa00a..0000000 --- a/ggated/ggated.c +++ /dev/null @@ -1,1050 +0,0 @@ -/*- - * 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 -#include -#include -#include -#include -#include -#include -#include -#include - -#include "ggate.h" - - -#define GGATED_EXPORT_FILE "/etc/gg.exports" - -struct ggd_connection { - off_t c_mediasize; - unsigned c_sectorsize; - unsigned c_flags; /* flags (RO/RW) */ - int c_diskfd; - int c_sendfd; - int c_recvfd; - time_t c_birthtime; - char *c_path; - uint64_t c_token; - in_addr_t c_srcip; - LIST_ENTRY(ggd_connection) c_next; -}; - -struct ggd_request { - struct g_gate_hdr r_hdr; - char *r_data; - TAILQ_ENTRY(ggd_request) r_next; -}; -#define r_cmd r_hdr.gh_cmd -#define r_offset r_hdr.gh_offset -#define r_length r_hdr.gh_length -#define r_error r_hdr.gh_error - -struct ggd_export { - char *e_path; /* path to device/file */ - in_addr_t e_ip; /* remote IP address */ - in_addr_t e_mask; /* IP mask */ - unsigned e_flags; /* flags (RO/RW) */ - SLIST_ENTRY(ggd_export) e_next; -}; - -static const char *exports_file = GGATED_EXPORT_FILE; -static int got_sighup = 0; -static in_addr_t bindaddr; - -static TAILQ_HEAD(, ggd_request) inqueue = TAILQ_HEAD_INITIALIZER(inqueue); -static TAILQ_HEAD(, ggd_request) outqueue = TAILQ_HEAD_INITIALIZER(outqueue); -static pthread_mutex_t inqueue_mtx, outqueue_mtx; -static pthread_cond_t inqueue_cond, outqueue_cond; - -static SLIST_HEAD(, ggd_export) exports = SLIST_HEAD_INITIALIZER(exports); -static LIST_HEAD(, ggd_connection) connections = LIST_HEAD_INITIALIZER(connections); - -static void *recv_thread(void *arg); -static void *disk_thread(void *arg); -static void *send_thread(void *arg); - -static void -usage(void) -{ - - fprintf(stderr, "usage: %s [-nv] [-a address] [-p port] [-R rcvbuf] " - "[-S sndbuf] [exports file]\n", getprogname()); - exit(EXIT_FAILURE); -} - -static char * -ip2str(in_addr_t ip) -{ - static char sip[16]; - - snprintf(sip, sizeof(sip), "%u.%u.%u.%u", - ((ip >> 24) & 0xff), - ((ip >> 16) & 0xff), - ((ip >> 8) & 0xff), - (ip & 0xff)); - return (sip); -} - -static in_addr_t -countmask(unsigned m) -{ - in_addr_t mask; - - if (m == 0) { - mask = 0x0; - } else { - mask = 1 << (32 - m); - mask--; - mask = ~mask; - } - return (mask); -} - -static void -line_parse(char *line, unsigned lineno) -{ - struct ggd_export *ex; - char *word, *path, *sflags; - unsigned flags, i, vmask; - in_addr_t ip, mask; - - ip = mask = flags = vmask = 0; - path = NULL; - sflags = NULL; - - for (i = 0, word = strtok(line, " \t"); word != NULL; - i++, word = strtok(NULL, " \t")) { - switch (i) { - case 0: /* IP address or host name */ - ip = g_gate_str2ip(strsep(&word, "/")); - if (ip == INADDR_NONE) { - g_gate_xlog("Invalid IP/host name at line %u.", - lineno); - } - ip = ntohl(ip); - if (word == NULL) - vmask = 32; - else { - errno = 0; - vmask = strtoul(word, NULL, 10); - if (vmask == 0 && errno != 0) { - g_gate_xlog("Invalid IP mask value at " - "line %u.", lineno); - } - if ((unsigned)vmask > 32) { - g_gate_xlog("Invalid IP mask value at line %u.", - lineno); - } - } - mask = countmask(vmask); - break; - case 1: /* flags */ - if (strcasecmp("rd", word) == 0 || - strcasecmp("ro", word) == 0) { - flags = O_RDONLY; - } else if (strcasecmp("wo", word) == 0) { - flags = O_WRONLY; - } else if (strcasecmp("rw", word) == 0) { - flags = O_RDWR; - } else { - g_gate_xlog("Invalid value in flags field at " - "line %u.", lineno); - } - sflags = word; - break; - case 2: /* path */ - if (strlen(word) >= MAXPATHLEN) { - g_gate_xlog("Path too long at line %u. ", - lineno); - } - path = word; - break; - default: - g_gate_xlog("Too many arguments at line %u. ", lineno); - } - } - if (i != 3) - g_gate_xlog("Too few arguments at line %u.", lineno); - - ex = malloc(sizeof(*ex)); - if (ex == NULL) - g_gate_xlog("Not enough memory."); - ex->e_path = strdup(path); - if (ex->e_path == NULL) - g_gate_xlog("Not enough memory."); - - /* Made 'and' here. */ - ex->e_ip = (ip & mask); - ex->e_mask = mask; - ex->e_flags = flags; - - SLIST_INSERT_HEAD(&exports, ex, e_next); - - g_gate_log(LOG_DEBUG, "Added %s/%u %s %s to exports list.", - ip2str(ex->e_ip), vmask, path, sflags); -} - -static void -exports_clear(void) -{ - struct ggd_export *ex; - - while (!SLIST_EMPTY(&exports)) { - ex = SLIST_FIRST(&exports); - SLIST_REMOVE_HEAD(&exports, e_next); - free(ex); - } -} - -#define EXPORTS_LINE_SIZE 2048 -static void -exports_get(void) -{ - char buf[EXPORTS_LINE_SIZE], *line; - unsigned lineno = 0, objs = 0, len; - FILE *fd; - - exports_clear(); - - fd = fopen(exports_file, "r"); - if (fd == NULL) { - g_gate_xlog("Cannot open exports file (%s): %s.", exports_file, - strerror(errno)); - } - - g_gate_log(LOG_INFO, "Reading exports file (%s).", exports_file); - - for (;;) { - if (fgets(buf, sizeof(buf), fd) == NULL) { - if (feof(fd)) - break; - - g_gate_xlog("Error while reading exports file: %s.", - strerror(errno)); - } - - /* Increase line count. */ - lineno++; - - /* Skip spaces and tabs. */ - for (line = buf; *line == ' ' || *line == '\t'; ++line) - ; - - /* Empty line, comment or empty line at the end of file. */ - if (*line == '\n' || *line == '#' || *line == '\0') - continue; - - len = strlen(line); - if (line[len - 1] == '\n') { - /* Remove new line char. */ - line[len - 1] = '\0'; - } else { - if (!feof(fd)) - g_gate_xlog("Line %u too long.", lineno); - } - - line_parse(line, lineno); - objs++; - } - - fclose(fd); - - if (objs == 0) - g_gate_xlog("There are no objects to export."); - - g_gate_log(LOG_INFO, "Exporting %u object(s).", objs); -} - -static int -exports_check(struct ggd_export *ex, struct g_gate_cinit *cinit, - struct ggd_connection *conn) -{ - char ipmask[32]; /* 32 == strlen("xxx.xxx.xxx.xxx/xxx.xxx.xxx.xxx")+1 */ - int error = 0, flags; - - strlcpy(ipmask, ip2str(ex->e_ip), sizeof(ipmask)); - strlcat(ipmask, "/", sizeof(ipmask)); - strlcat(ipmask, ip2str(ex->e_mask), sizeof(ipmask)); - if ((cinit->gc_flags & GGATE_FLAG_RDONLY) != 0) { - if (ex->e_flags == O_WRONLY) { - g_gate_log(LOG_WARNING, "Read-only access requested, " - "but %s (%s) is exported write-only.", ex->e_path, - ipmask); - return (EPERM); - } else { - conn->c_flags |= GGATE_FLAG_RDONLY; - } - } else if ((cinit->gc_flags & GGATE_FLAG_WRONLY) != 0) { - if (ex->e_flags == O_RDONLY) { - g_gate_log(LOG_WARNING, "Write-only access requested, " - "but %s (%s) is exported read-only.", ex->e_path, - ipmask); - return (EPERM); - } else { - conn->c_flags |= GGATE_FLAG_WRONLY; - } - } else { - if (ex->e_flags == O_RDONLY) { - g_gate_log(LOG_WARNING, "Read-write access requested, " - "but %s (%s) is exported read-only.", ex->e_path, - ipmask); - return (EPERM); - } else if (ex->e_flags == O_WRONLY) { - g_gate_log(LOG_WARNING, "Read-write access requested, " - "but %s (%s) is exported write-only.", ex->e_path, - ipmask); - return (EPERM); - } - } - if ((conn->c_flags & GGATE_FLAG_RDONLY) != 0) - flags = O_RDONLY; - else if ((conn->c_flags & GGATE_FLAG_WRONLY) != 0) - flags = O_WRONLY; - else - flags = O_RDWR; - conn->c_diskfd = open(ex->e_path, flags); - if (conn->c_diskfd == -1) { - error = errno; - g_gate_log(LOG_ERR, "Cannot open %s: %s.", ex->e_path, - strerror(error)); - return (error); - } - return (0); -} - -static struct ggd_export * -exports_find(struct sockaddr *s, struct g_gate_cinit *cinit, - struct ggd_connection *conn) -{ - struct ggd_export *ex; - in_addr_t ip; - int error; - - ip = htonl(((struct sockaddr_in *)(void *)s)->sin_addr.s_addr); - SLIST_FOREACH(ex, &exports, e_next) { - if ((ip & ex->e_mask) != ex->e_ip) { - g_gate_log(LOG_DEBUG, "exports[%s]: IP mismatch.", - ex->e_path); - continue; - } - if (strcmp(cinit->gc_path, ex->e_path) != 0) { - g_gate_log(LOG_DEBUG, "exports[%s]: Path mismatch.", - ex->e_path); - continue; - } - error = exports_check(ex, cinit, conn); - if (error == 0) - return (ex); - else { - errno = error; - return (NULL); - } - } - g_gate_log(LOG_WARNING, "Unauthorized connection from: %s.", - ip2str(ip)); - errno = EPERM; - return (NULL); -} - -/* - * Remove timed out connections. - */ -static void -connection_cleanups(void) -{ - struct ggd_connection *conn, *tconn; - time_t now; - - time(&now); - LIST_FOREACH_SAFE(conn, &connections, c_next, tconn) { - if (now - conn->c_birthtime > 10) { - LIST_REMOVE(conn, c_next); - g_gate_log(LOG_NOTICE, - "Connection from %s [%s] removed.", - ip2str(conn->c_srcip), conn->c_path); - close(conn->c_diskfd); - close(conn->c_sendfd); - close(conn->c_recvfd); - free(conn->c_path); - free(conn); - } - } -} - -static struct ggd_connection * -connection_find(struct g_gate_cinit *cinit) -{ - struct ggd_connection *conn; - - LIST_FOREACH(conn, &connections, c_next) { - if (conn->c_token == cinit->gc_token) - break; - } - return (conn); -} - -static struct ggd_connection * -connection_new(struct g_gate_cinit *cinit, struct sockaddr *s, int sfd) -{ - struct ggd_connection *conn; - in_addr_t ip; - - /* - * First, look for old connections. - * We probably should do it every X seconds, but what for? - * It is only dangerous if an attacker wants to overload connections - * queue, so here is a good place to do the cleanups. - */ - connection_cleanups(); - - conn = malloc(sizeof(*conn)); - if (conn == NULL) - return (NULL); - conn->c_path = strdup(cinit->gc_path); - if (conn->c_path == NULL) { - free(conn); - return (NULL); - } - conn->c_token = cinit->gc_token; - ip = htonl(((struct sockaddr_in *)(void *)s)->sin_addr.s_addr); - conn->c_srcip = ip; - conn->c_sendfd = conn->c_recvfd = -1; - if ((cinit->gc_flags & GGATE_FLAG_SEND) != 0) - conn->c_sendfd = sfd; - else - conn->c_recvfd = sfd; - conn->c_mediasize = 0; - conn->c_sectorsize = 0; - time(&conn->c_birthtime); - conn->c_flags = cinit->gc_flags; - LIST_INSERT_HEAD(&connections, conn, c_next); - g_gate_log(LOG_DEBUG, "Connection created [%s, %s].", ip2str(ip), - conn->c_path); - return (conn); -} - -static int -connection_add(struct ggd_connection *conn, struct g_gate_cinit *cinit, - struct sockaddr *s, int sfd) -{ - in_addr_t ip; - - ip = htonl(((struct sockaddr_in *)(void *)s)->sin_addr.s_addr); - if ((cinit->gc_flags & GGATE_FLAG_SEND) != 0) { - if (conn->c_sendfd != -1) { - g_gate_log(LOG_WARNING, - "Send socket already exists [%s, %s].", ip2str(ip), - conn->c_path); - return (EEXIST); - } - conn->c_sendfd = sfd; - } else { - if (conn->c_recvfd != -1) { - g_gate_log(LOG_WARNING, - "Receive socket already exists [%s, %s].", - ip2str(ip), conn->c_path); - return (EEXIST); - } - conn->c_recvfd = sfd; - } - g_gate_log(LOG_DEBUG, "Connection added [%s, %s].", ip2str(ip), - conn->c_path); - return (0); -} - -/* - * Remove one socket from the given connection or the whole - * connection if sfd == -1. - */ -static void -connection_remove(struct ggd_connection *conn) -{ - - LIST_REMOVE(conn, c_next); - g_gate_log(LOG_DEBUG, "Connection removed [%s %s].", - ip2str(conn->c_srcip), conn->c_path); - if (conn->c_sendfd != -1) - close(conn->c_sendfd); - if (conn->c_recvfd != -1) - close(conn->c_recvfd); - free(conn->c_path); - free(conn); -} - -static int -connection_ready(struct ggd_connection *conn) -{ - - return (conn->c_sendfd != -1 && conn->c_recvfd != -1); -} - -static void -connection_launch(struct ggd_connection *conn) -{ - pthread_t td; - int error, pid; - - pid = fork(); - if (pid > 0) - return; - else if (pid == -1) { - g_gate_log(LOG_ERR, "Cannot fork: %s.", strerror(errno)); - return; - } - g_gate_log(LOG_DEBUG, "Process created [%s].", conn->c_path); - - /* - * Create condition variables and mutexes for in-queue and out-queue - * synchronization. - */ - error = pthread_mutex_init(&inqueue_mtx, NULL); - if (error != 0) { - g_gate_xlog("pthread_mutex_init(inqueue_mtx): %s.", - strerror(error)); - } - error = pthread_cond_init(&inqueue_cond, NULL); - if (error != 0) { - g_gate_xlog("pthread_cond_init(inqueue_cond): %s.", - strerror(error)); - } - error = pthread_mutex_init(&outqueue_mtx, NULL); - if (error != 0) { - g_gate_xlog("pthread_mutex_init(outqueue_mtx): %s.", - strerror(error)); - } - error = pthread_cond_init(&outqueue_cond, NULL); - if (error != 0) { - g_gate_xlog("pthread_cond_init(outqueue_cond): %s.", - strerror(error)); - } - - /* - * Create threads: - * recvtd - thread for receiving I/O request - * diskio - thread for doing I/O request - * sendtd - thread for sending I/O requests back - */ - error = pthread_create(&td, NULL, send_thread, conn); - if (error != 0) { - g_gate_xlog("pthread_create(send_thread): %s.", - strerror(error)); - } - error = pthread_create(&td, NULL, recv_thread, conn); - if (error != 0) { - g_gate_xlog("pthread_create(recv_thread): %s.", - strerror(error)); - } - disk_thread(conn); -} - -static void -sendfail(int sfd, int error, const char *fmt, ...) -{ - struct g_gate_sinit sinit; - va_list ap; - ssize_t data; - - sinit.gs_error = error; - g_gate_swap2n_sinit(&sinit); - data = g_gate_send(sfd, &sinit, sizeof(sinit), 0); - g_gate_swap2h_sinit(&sinit); - if (data != sizeof(sinit)) { - g_gate_log(LOG_WARNING, "Cannot send initial packet: %s.", - strerror(errno)); - return; - } - if (fmt != NULL) { - va_start(ap, fmt); - g_gate_vlog(LOG_WARNING, fmt, ap); - va_end(ap); - } -} - -static void * -malloc_waitok(size_t size) -{ - void *p; - - while ((p = malloc(size)) == NULL) { - g_gate_log(LOG_DEBUG, "Cannot allocate %zu bytes.", size); - sleep(1); - } - return (p); -} - -static void * -recv_thread(void *arg) -{ - struct ggd_connection *conn; - struct ggd_request *req; - ssize_t data; - int error, fd; - - conn = arg; - g_gate_log(LOG_NOTICE, "%s: started [%s]!", __func__, conn->c_path); - fd = conn->c_recvfd; - for (;;) { - /* - * Get header packet. - */ - req = malloc_waitok(sizeof(*req)); - data = g_gate_recv(fd, &req->r_hdr, sizeof(req->r_hdr), - MSG_WAITALL); - if (data == 0) { - g_gate_log(LOG_DEBUG, "Process %u exiting.", getpid()); - exit(EXIT_SUCCESS); - } else if (data == -1) { - g_gate_xlog("Error while receiving hdr packet: %s.", - strerror(errno)); - } else if (data != sizeof(req->r_hdr)) { - g_gate_xlog("Malformed hdr packet received."); - } - g_gate_log(LOG_DEBUG, "Received hdr packet."); - g_gate_swap2h_hdr(&req->r_hdr); - - g_gate_log(LOG_DEBUG, "%s: offset=%jd length=%u", __func__, - (intmax_t)req->r_offset, (unsigned)req->r_length); - - /* - * Allocate memory for data. - */ - req->r_data = malloc_waitok(req->r_length); - - /* - * Receive data to write for WRITE request. - */ - if (req->r_cmd == GGATE_CMD_WRITE) { - g_gate_log(LOG_DEBUG, "Waiting for %u bytes of data...", - req->r_length); - data = g_gate_recv(fd, req->r_data, req->r_length, - MSG_WAITALL); - if (data == -1) { - g_gate_xlog("Error while receiving data: %s.", - strerror(errno)); - } - } - - /* - * Put the request onto the incoming queue. - */ - error = pthread_mutex_lock(&inqueue_mtx); - assert(error == 0); - TAILQ_INSERT_TAIL(&inqueue, req, r_next); - error = pthread_cond_signal(&inqueue_cond); - assert(error == 0); - error = pthread_mutex_unlock(&inqueue_mtx); - assert(error == 0); - } -} - -static void * -disk_thread(void *arg) -{ - struct ggd_connection *conn; - struct ggd_request *req; - ssize_t data; - int error, fd; - - conn = arg; - g_gate_log(LOG_NOTICE, "%s: started [%s]!", __func__, conn->c_path); - fd = conn->c_diskfd; - for (;;) { - /* - * Get a request from the incoming queue. - */ - error = pthread_mutex_lock(&inqueue_mtx); - assert(error == 0); - while ((req = TAILQ_FIRST(&inqueue)) == NULL) { - error = pthread_cond_wait(&inqueue_cond, &inqueue_mtx); - assert(error == 0); - } - TAILQ_REMOVE(&inqueue, req, r_next); - error = pthread_mutex_unlock(&inqueue_mtx); - assert(error == 0); - - /* - * Check the request. - */ - assert(req->r_cmd == GGATE_CMD_READ || req->r_cmd == GGATE_CMD_WRITE); - assert(req->r_offset + req->r_length <= (uintmax_t)conn->c_mediasize); - assert((req->r_offset % conn->c_sectorsize) == 0); - assert((req->r_length % conn->c_sectorsize) == 0); - - g_gate_log(LOG_DEBUG, "%s: offset=%jd length=%u", __func__, - (intmax_t)req->r_offset, (unsigned)req->r_length); - - /* - * Do the request. - */ - data = 0; - switch (req->r_cmd) { - case GGATE_CMD_READ: - data = pread(fd, req->r_data, req->r_length, - req->r_offset); - break; - case GGATE_CMD_WRITE: - data = pwrite(fd, req->r_data, req->r_length, - req->r_offset); - /* Free data memory here - better sooner. */ - free(req->r_data); - req->r_data = NULL; - break; - } - if (data != (ssize_t)req->r_length) { - /* Report short reads/writes as I/O errors. */ - if (errno == 0) - errno = EIO; - g_gate_log(LOG_ERR, "Disk error: %s", strerror(errno)); - req->r_error = errno; - if (req->r_data != NULL) { - free(req->r_data); - req->r_data = NULL; - } - } - - /* - * Put the request onto the outgoing queue. - */ - error = pthread_mutex_lock(&outqueue_mtx); - assert(error == 0); - TAILQ_INSERT_TAIL(&outqueue, req, r_next); - error = pthread_cond_signal(&outqueue_cond); - assert(error == 0); - error = pthread_mutex_unlock(&outqueue_mtx); - assert(error == 0); - } - - /* NOTREACHED */ - return (NULL); -} - -static void * -send_thread(void *arg) -{ - struct ggd_connection *conn; - struct ggd_request *req; - ssize_t data; - int error, fd; - - conn = arg; - g_gate_log(LOG_NOTICE, "%s: started [%s]!", __func__, conn->c_path); - fd = conn->c_sendfd; - for (;;) { - /* - * Get a request from the outgoing queue. - */ - error = pthread_mutex_lock(&outqueue_mtx); - assert(error == 0); - while ((req = TAILQ_FIRST(&outqueue)) == NULL) { - error = pthread_cond_wait(&outqueue_cond, - &outqueue_mtx); - assert(error == 0); - } - TAILQ_REMOVE(&outqueue, req, r_next); - error = pthread_mutex_unlock(&outqueue_mtx); - assert(error == 0); - - g_gate_log(LOG_DEBUG, "%s: offset=%jd length=%u", __func__, - (intmax_t)req->r_offset, (unsigned)req->r_length); - - /* - * Send the request. - */ - g_gate_swap2n_hdr(&req->r_hdr); - if (g_gate_send(fd, &req->r_hdr, sizeof(req->r_hdr), 0) == -1) { - g_gate_xlog("Error while sending hdr packet: %s.", - strerror(errno)); - } - g_gate_log(LOG_DEBUG, "Sent hdr packet."); - g_gate_swap2h_hdr(&req->r_hdr); - if (req->r_data != NULL) { - data = g_gate_send(fd, req->r_data, req->r_length, 0); - if (data != (ssize_t)req->r_length) { - g_gate_xlog("Error while sending data: %s.", - strerror(errno)); - } - g_gate_log(LOG_DEBUG, - "Sent %zd bytes (offset=%ju, size=%zu).", data, - (uintmax_t)req->r_offset, (size_t)req->r_length); - free(req->r_data); - } - free(req); - } - - /* NOTREACHED */ - return (NULL); -} - -static void -log_connection(struct sockaddr *from) -{ - in_addr_t ip; - - ip = htonl(((struct sockaddr_in *)(void *)from)->sin_addr.s_addr); - g_gate_log(LOG_INFO, "Connection from: %s.", ip2str(ip)); -} - -static int -handshake(struct sockaddr *from, int sfd) -{ - struct g_gate_version ver; - struct g_gate_cinit cinit; - struct g_gate_sinit sinit; - struct ggd_connection *conn; - struct ggd_export *ex; - ssize_t data; - - log_connection(from); - /* - * Phase 1: Version verification. - */ - g_gate_log(LOG_DEBUG, "Receiving version packet."); - data = g_gate_recv(sfd, &ver, sizeof(ver), MSG_WAITALL); - g_gate_swap2h_version(&ver); - if (data != sizeof(ver)) { - g_gate_log(LOG_WARNING, "Malformed version packet."); - return (0); - } - g_gate_log(LOG_DEBUG, "Version packet received."); - if (memcmp(ver.gv_magic, GGATE_MAGIC, strlen(GGATE_MAGIC)) != 0) { - g_gate_log(LOG_WARNING, "Invalid magic field."); - return (0); - } - if (ver.gv_version != GGATE_VERSION) { - g_gate_log(LOG_WARNING, "Version %u is not supported.", - ver.gv_version); - return (0); - } - ver.gv_error = 0; - g_gate_swap2n_version(&ver); - data = g_gate_send(sfd, &ver, sizeof(ver), 0); - g_gate_swap2h_version(&ver); - if (data == -1) { - sendfail(sfd, errno, "Error while sending version packet: %s.", - strerror(errno)); - return (0); - } - - /* - * Phase 2: Request verification. - */ - g_gate_log(LOG_DEBUG, "Receiving initial packet."); - data = g_gate_recv(sfd, &cinit, sizeof(cinit), MSG_WAITALL); - g_gate_swap2h_cinit(&cinit); - if (data != sizeof(cinit)) { - g_gate_log(LOG_WARNING, "Malformed initial packet."); - return (0); - } - g_gate_log(LOG_DEBUG, "Initial packet received."); - conn = connection_find(&cinit); - if (conn != NULL) { - /* - * Connection should already exists. - */ - g_gate_log(LOG_DEBUG, "Found existing connection (token=%lu).", - (unsigned long)conn->c_token); - if (connection_add(conn, &cinit, from, sfd) == -1) { - connection_remove(conn); - return (0); - } - } else { - /* - * New connection, allocate space. - */ - conn = connection_new(&cinit, from, sfd); - if (conn == NULL) { - sendfail(sfd, ENOMEM, - "Cannot allocate new connection."); - return (0); - } - g_gate_log(LOG_DEBUG, "New connection created (token=%lu).", - (unsigned long)conn->c_token); - } - - ex = exports_find(from, &cinit, conn); - if (ex == NULL) { - connection_remove(conn); - sendfail(sfd, errno, NULL); - return (0); - } - if (conn->c_mediasize == 0) { - conn->c_mediasize = g_gate_mediasize(conn->c_diskfd); - conn->c_sectorsize = g_gate_sectorsize(conn->c_diskfd); - } - sinit.gs_mediasize = conn->c_mediasize; - sinit.gs_sectorsize = conn->c_sectorsize; - sinit.gs_error = 0; - - g_gate_log(LOG_DEBUG, "Sending initial packet."); - - g_gate_swap2n_sinit(&sinit); - data = g_gate_send(sfd, &sinit, sizeof(sinit), 0); - g_gate_swap2h_sinit(&sinit); - if (data == -1) { - sendfail(sfd, errno, "Error while sending initial packet: %s.", - strerror(errno)); - return (0); - } - - if (connection_ready(conn)) { - connection_launch(conn); - connection_remove(conn); - } - return (1); -} - -static void -huphandler(int sig __unused) -{ - - got_sighup = 1; -} - -int -main(int argc, char *argv[]) -{ - struct sockaddr_in serv; - struct sockaddr from; - socklen_t fromlen; - int sfd, tmpsfd; - unsigned port; - - bindaddr = htonl(INADDR_ANY); - port = G_GATE_PORT; - for (;;) { - int ch; - - ch = getopt(argc, argv, "a:hnp:R:S:v"); - if (ch == -1) - break; - switch (ch) { - case 'a': - bindaddr = g_gate_str2ip(optarg); - if (bindaddr == INADDR_NONE) { - errx(EXIT_FAILURE, - "Invalid IP/host name to bind to."); - } - break; - case 'n': - nagle = 0; - break; - case 'p': - errno = 0; - port = strtoul(optarg, NULL, 10); - if (port == 0 && errno != 0) - errx(EXIT_FAILURE, "Invalid port."); - break; - case 'R': - errno = 0; - rcvbuf = strtoul(optarg, NULL, 10); - if (rcvbuf == 0 && errno != 0) - errx(EXIT_FAILURE, "Invalid rcvbuf."); - break; - case 'S': - errno = 0; - sndbuf = strtoul(optarg, NULL, 10); - if (sndbuf == 0 && errno != 0) - errx(EXIT_FAILURE, "Invalid sndbuf."); - break; - case 'v': - g_gate_verbose++; - break; - case 'h': - default: - usage(); - } - } - argc -= optind; - argv += optind; - - if (argv[0] != NULL) - exports_file = argv[0]; - exports_get(); - - if (!g_gate_verbose) { - /* Run in daemon mode. */ - if (daemon(0, 0) == -1) - g_gate_xlog("Cannot daemonize: %s", strerror(errno)); - } - - signal(SIGCHLD, SIG_IGN); - - sfd = socket(AF_INET, SOCK_STREAM, 0); - if (sfd == -1) - g_gate_xlog("Cannot open stream socket: %s.", strerror(errno)); - bzero(&serv, sizeof(serv)); - serv.sin_family = AF_INET; - serv.sin_addr.s_addr = bindaddr; - serv.sin_port = htons(port); - - g_gate_socket_settings(sfd); - - if (bind(sfd, (struct sockaddr *)&serv, sizeof(serv)) == -1) - g_gate_xlog("bind(): %s.", strerror(errno)); - if (listen(sfd, 5) == -1) - g_gate_xlog("listen(): %s.", strerror(errno)); - - g_gate_log(LOG_INFO, "Listen on port: %d.", port); - - signal(SIGHUP, huphandler); - - for (;;) { - fromlen = sizeof(from); - tmpsfd = accept(sfd, &from, &fromlen); - if (tmpsfd == -1) - g_gate_xlog("accept(): %s.", strerror(errno)); - - if (got_sighup) { - got_sighup = 0; - exports_get(); - } - - if (!handshake(&from, tmpsfd)) - close(tmpsfd); - } - close(sfd); - exit(EXIT_SUCCESS); -} diff --git a/ggatel/Makefile b/ggatel/Makefile deleted file mode 100644 index 604a754..0000000 --- a/ggatel/Makefile +++ /dev/null @@ -1,15 +0,0 @@ -# $FreeBSD$ - -.PATH: ${.CURDIR}/../shared - -PROG= ggatel -MAN= ggatel.8 -SRCS= ggatel.c ggate.c - -CFLAGS+= -DLIBGEOM -CFLAGS+= -I${.CURDIR}/../shared - -DPADD= ${LIBGEOM} ${LIBSBUF} ${LIBBSDXML} ${LIBUTIL} -LDADD= -lgeom -lsbuf -lbsdxml -lutil - -.include diff --git a/ggatel/ggatel.8 b/ggatel/ggatel.8 deleted file mode 100644 index 236e550..0000000 --- a/ggatel/ggatel.8 +++ /dev/null @@ -1,155 +0,0 @@ -.\" 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 2, 2011 -.Dt GGATEL 8 -.Os -.Sh NAME -.Nm ggatel -.Nd "GEOM Gate local control utility" -.Sh SYNOPSIS -.Nm -.Cm create -.Op Fl v -.Op Fl o Cm ro | wo | rw -.Op Fl s Ar sectorsize -.Op Fl t Ar timeout -.Op Fl u Ar unit -.Ar path -.Nm -.Cm attach -.Op Fl v -.Op Fl o Cm ro | wo | rw -.Fl u Ar unit -.Ar path -.Nm -.Cm destroy -.Op Fl f -.Fl u Ar unit -.Nm -.Cm 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 ".Cm destroy" -.It Cm create -Create a -.Nm ggate -provider related to the given regular file or device. -.It Cm attach -Attach a worker process to an existing -.Nm ggate -provider. -.It Cm destroy -Destroy the given -.Nm ggate -provider. -.It Cm list -List -.Nm ggate -providers. -.El -.Pp -Available options: -.Bl -tag -width ".Fl s Cm ro | wo | rw" -.It Fl f -Forcibly destroy -.Nm ggate -provider (cancels all pending requests). -.It Fl o Cm ro | wo | rw -Specify permission to use when opening the file or device: read-only -.Pq Cm ro , -write-only -.Pq Cm wo , -or read-write -.Pq Cm rw . -Default is -.Cm rw . -.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 -.Sh EXIT STATUS -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 EXAMPLES -.Dq GEOMify -the -.Dq Li fd0 -device and use -.Xr gbde 8 -to encrypt data on a floppy. -.Bd -literal -offset indent -ggatel create -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 -ggatel destroy -u 5 -.Ed -.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 Pawel Jakub Dawidek Aq pjd@FreeBSD.org . diff --git a/ggatel/ggatel.c b/ggatel/ggatel.c deleted file mode 100644 index abfe7c1..0000000 --- a/ggatel/ggatel.c +++ /dev/null @@ -1,327 +0,0 @@ -/*- - * 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" - - -static enum { UNSET, CREATE, DESTROY, LIST, RESCUE } action = UNSET; - -static const char *path = NULL; -static int unit = G_GATE_UNIT_AUTO; -static unsigned flags = 0; -static int force = 0; -static unsigned sectorsize = 0; -static unsigned timeout = G_GATE_TIMEOUT; - -static void -usage(void) -{ - - fprintf(stderr, "usage: %s create [-v] [-o ] " - "[-s sectorsize] [-t timeout] [-u unit] \n", getprogname()); - fprintf(stderr, " %s rescue [-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 int -g_gate_openflags(unsigned ggflags) -{ - - if ((ggflags & G_GATE_FLAG_READONLY) != 0) - return (O_RDONLY); - else if ((ggflags & G_GATE_FLAG_WRITEONLY) != 0) - return (O_WRONLY); - return (O_RDWR); -} - -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) == -1) { - 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 ((size_t)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) | O_DIRECT | O_FSYNC); - if (fd == -1) - 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 = 0; - 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_rescue(void) -{ - struct g_gate_ctl_cancel ggioc; - int fd; - - fd = open(path, g_gate_openflags(flags)); - if (fd == -1) - err(EXIT_FAILURE, "Cannot open %s", path); - - ggioc.gctl_version = G_GATE_VERSION; - ggioc.gctl_unit = unit; - ggioc.gctl_seq = 0; - g_gate_ioctl(G_GATE_CMD_CANCEL, &ggioc); - - g_gatel_serve(fd); -} - -int -main(int argc, char *argv[]) -{ - - if (argc < 2) - usage(); - if (strcasecmp(argv[1], "create") == 0) - action = CREATE; - else if (strcasecmp(argv[1], "rescue") == 0) - action = RESCUE; - 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:s:t:u:v"); - if (ch == -1) - break; - switch (ch) { - case 'f': - if (action != DESTROY) - usage(); - force = 1; - break; - case 'o': - if (action != CREATE && action != RESCUE) - 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 '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 CREATE: - if (argc != 1) - usage(); - g_gate_load_module(); - g_gate_open_device(); - path = argv[0]; - g_gatel_create(); - break; - case RESCUE: - if (argc != 1) - usage(); - if (unit == -1) { - fprintf(stderr, "Required unit number.\n"); - usage(); - } - g_gate_open_device(); - path = argv[0]; - g_gatel_rescue(); - 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); -} diff --git a/shared/ggate.c b/shared/ggate.c deleted file mode 100644 index cf9b9ca..0000000 --- a/shared/ggate.c +++ /dev/null @@ -1,409 +0,0 @@ -/*- - * 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 -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include "ggate.h" - - -int g_gate_devfd = -1; -int g_gate_verbose = 0; - - -void -g_gate_vlog(int priority, const char *message, va_list ap) -{ - - if (g_gate_verbose) { - const char *prefix; - - switch (priority) { - case LOG_ERR: - prefix = "error"; - break; - case LOG_WARNING: - prefix = "warning"; - break; - case LOG_NOTICE: - prefix = "notice"; - break; - case LOG_INFO: - prefix = "info"; - break; - case LOG_DEBUG: - prefix = "debug"; - break; - default: - prefix = "unknown"; - } - - printf("%s: ", prefix); - vprintf(message, ap); - printf("\n"); - } else { - if (priority != LOG_DEBUG) - vsyslog(priority, message, ap); - } -} - -void -g_gate_log(int priority, const char *message, ...) -{ - va_list ap; - - va_start(ap, message); - g_gate_vlog(priority, message, ap); - va_end(ap); -} - -void -g_gate_xvlog(const char *message, va_list ap) -{ - - g_gate_vlog(LOG_ERR, message, ap); - g_gate_vlog(LOG_ERR, "Exiting.", ap); - exit(EXIT_FAILURE); -} - -void -g_gate_xlog(const char *message, ...) -{ - va_list ap; - - va_start(ap, message); - g_gate_xvlog(message, ap); - /* NOTREACHED */ - va_end(ap); - exit(EXIT_FAILURE); -} - -off_t -g_gate_mediasize(int fd) -{ - off_t mediasize; - struct stat sb; - - if (fstat(fd, &sb) == -1) - g_gate_xlog("fstat(): %s.", strerror(errno)); - if (S_ISCHR(sb.st_mode)) { - if (ioctl(fd, DIOCGMEDIASIZE, &mediasize) == -1) { - g_gate_xlog("Can't get media size: %s.", - strerror(errno)); - } - } else if (S_ISREG(sb.st_mode)) { - mediasize = sb.st_size; - } else { - g_gate_xlog("Unsupported file system object."); - } - return (mediasize); -} - -unsigned -g_gate_sectorsize(int fd) -{ - unsigned secsize; - struct stat sb; - - if (fstat(fd, &sb) == -1) - g_gate_xlog("fstat(): %s.", strerror(errno)); - if (S_ISCHR(sb.st_mode)) { - if (ioctl(fd, DIOCGSECTORSIZE, &secsize) == -1) { - g_gate_xlog("Can't get sector size: %s.", - strerror(errno)); - } - } else if (S_ISREG(sb.st_mode)) { - secsize = 512; - } else { - g_gate_xlog("Unsupported file system object."); - } - return (secsize); -} - -void -g_gate_open_device(void) -{ - - g_gate_devfd = open("/dev/" G_GATE_CTL_NAME, O_RDWR); - if (g_gate_devfd == -1) - err(EXIT_FAILURE, "open(/dev/%s)", G_GATE_CTL_NAME); -} - -void -g_gate_close_device(void) -{ - - close(g_gate_devfd); -} - -void -g_gate_ioctl(unsigned long req, void *data) -{ - - if (ioctl(g_gate_devfd, req, data) == -1) { - g_gate_xlog("%s: ioctl(/dev/%s): %s.", getprogname(), - G_GATE_CTL_NAME, strerror(errno)); - } -} - -void -g_gate_destroy(int unit, int force) -{ - struct g_gate_ctl_destroy ggio; - - ggio.gctl_version = G_GATE_VERSION; - ggio.gctl_unit = unit; - ggio.gctl_force = force; - g_gate_ioctl(G_GATE_CMD_DESTROY, &ggio); -} - -void -g_gate_load_module(void) -{ - - if (modfind("g_gate") == -1) { - /* Not present in kernel, try loading it. */ - if (kldload("geom_gate") == -1 || modfind("g_gate") == -1) { - if (errno != EEXIST) { - errx(EXIT_FAILURE, - "geom_gate module not available!"); - } - } - } -} - -/* - * When we send from ggatec packets larger than 32kB, performance drops - * significantly (eg. to 256kB/s over 1Gbit/s link). This is not a problem - * when data is send from ggated. I don't know why, so for now I limit - * size of packets send from ggatec to 32kB by defining MAX_SEND_SIZE - * in ggatec Makefile. - */ -#ifndef MAX_SEND_SIZE -#define MAX_SEND_SIZE MAXPHYS -#endif -ssize_t -g_gate_send(int s, const void *buf, size_t len, int flags) -{ - ssize_t done = 0, done2; - const unsigned char *p = buf; - - while (len > 0) { - done2 = send(s, p, MIN(len, MAX_SEND_SIZE), flags); - if (done2 == 0) - break; - else if (done2 == -1) { - if (errno == EAGAIN) { - printf("%s: EAGAIN\n", __func__); - continue; - } - done = -1; - break; - } - done += done2; - p += done2; - len -= done2; - } - return (done); -} - -ssize_t -g_gate_recv(int s, void *buf, size_t len, int flags) -{ - ssize_t done; - - do { - done = recv(s, buf, len, flags); - } while (done == -1 && errno == EAGAIN); - return (done); -} - -int nagle = 1; -unsigned rcvbuf = G_GATE_RCVBUF; -unsigned sndbuf = G_GATE_SNDBUF; - -void -g_gate_socket_settings(int sfd) -{ - struct timeval tv; - int bsize, on; - - /* Socket settings. */ - on = 1; - if (nagle) { - if (setsockopt(sfd, IPPROTO_TCP, TCP_NODELAY, &on, - sizeof(on)) == -1) { - g_gate_xlog("setsockopt() error: %s.", strerror(errno)); - } - } - if (setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) == -1) - g_gate_xlog("setsockopt(SO_REUSEADDR): %s.", strerror(errno)); - bsize = rcvbuf; - if (setsockopt(sfd, SOL_SOCKET, SO_RCVBUF, &bsize, sizeof(bsize)) == -1) - g_gate_xlog("setsockopt(SO_RCVBUF): %s.", strerror(errno)); - bsize = sndbuf; - if (setsockopt(sfd, SOL_SOCKET, SO_SNDBUF, &bsize, sizeof(bsize)) == -1) - g_gate_xlog("setsockopt(SO_SNDBUF): %s.", strerror(errno)); - tv.tv_sec = 8; - tv.tv_usec = 0; - if (setsockopt(sfd, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv)) == -1) { - g_gate_log(LOG_ERR, "setsockopt(SO_SNDTIMEO) error: %s.", - strerror(errno)); - } - if (setsockopt(sfd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)) == -1) { - g_gate_log(LOG_ERR, "setsockopt(SO_RCVTIMEO) error: %s.", - strerror(errno)); - } -} - -#ifdef LIBGEOM -static struct gclass * -find_class(struct gmesh *mesh, const char *name) -{ - struct gclass *class; - - LIST_FOREACH(class, &mesh->lg_class, lg_class) { - if (strcmp(class->lg_name, name) == 0) - return (class); - } - return (NULL); -} - -static const char * -get_conf(struct ggeom *gp, const char *name) -{ - struct gconfig *conf; - - LIST_FOREACH(conf, &gp->lg_config, lg_config) { - if (strcmp(conf->lg_name, name) == 0) - return (conf->lg_val); - } - return (NULL); -} - -static void -show_config(struct ggeom *gp, int verbose) -{ - struct gprovider *pp; - char buf[5]; - - pp = LIST_FIRST(&gp->lg_provider); - if (pp == NULL) - return; - if (!verbose) { - printf("%s\n", pp->lg_name); - return; - } - printf(" NAME: %s\n", pp->lg_name); - printf(" info: %s\n", get_conf(gp, "info")); - printf(" access: %s\n", get_conf(gp, "access")); - printf(" timeout: %s\n", get_conf(gp, "timeout")); - printf("queue_count: %s\n", get_conf(gp, "queue_count")); - printf(" queue_size: %s\n", get_conf(gp, "queue_size")); - printf(" references: %s\n", get_conf(gp, "ref")); - humanize_number(buf, sizeof(buf), (int64_t)pp->lg_mediasize, "", - HN_AUTOSCALE, HN_B | HN_NOSPACE | HN_DECIMAL); - printf(" mediasize: %jd (%s)\n", (intmax_t)pp->lg_mediasize, buf); - printf(" sectorsize: %u\n", pp->lg_sectorsize); - printf(" mode: %s\n", pp->lg_mode); - printf("\n"); -} - -void -g_gate_list(int unit, int verbose) -{ - struct gmesh mesh; - struct gclass *class; - struct ggeom *gp; - char name[64]; - int error; - - error = geom_gettree(&mesh); - if (error != 0) - exit(EXIT_FAILURE); - class = find_class(&mesh, G_GATE_CLASS_NAME); - if (class == NULL) { - geom_deletetree(&mesh); - exit(EXIT_SUCCESS); - } - if (unit >= 0) { - snprintf(name, sizeof(name), "%s%d", G_GATE_PROVIDER_NAME, - unit); - } - LIST_FOREACH(gp, &class->lg_geom, lg_geom) { - if (unit != -1 && strcmp(gp->lg_name, name) != 0) - continue; - show_config(gp, verbose); - } - geom_deletetree(&mesh); - exit(EXIT_SUCCESS); -} -#endif /* LIBGEOM */ - -in_addr_t -g_gate_str2ip(const char *str) -{ - struct hostent *hp; - in_addr_t ip; - - ip = inet_addr(str); - if (ip != INADDR_NONE) { - /* It is a valid IP address. */ - return (ip); - } - /* Check if it is a valid host name. */ - hp = gethostbyname(str); - if (hp == NULL) - return (INADDR_NONE); - return (((struct in_addr *)(void *)hp->h_addr)->s_addr); -} diff --git a/shared/ggate.h b/shared/ggate.h deleted file mode 100644 index 898efea..0000000 --- a/shared/ggate.h +++ /dev/null @@ -1,196 +0,0 @@ -/*- - * 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$ - */ - -#ifndef _GGATE_H_ -#define _GGATE_H_ - -#include -#include - -#define G_GATE_PORT 3080 - -#define G_GATE_RCVBUF 131072 -#define G_GATE_SNDBUF 131072 -#define G_GATE_QUEUE_SIZE 1024 -#define G_GATE_TIMEOUT 0 - -#define GGATE_MAGIC "GEOM_GATE " -#define GGATE_VERSION 0 - -#define GGATE_FLAG_RDONLY 0x0001 -#define GGATE_FLAG_WRONLY 0x0002 -/* - * If GGATE_FLAG_SEND not GGATE_FLAG_RECV flag is set, this is initial - * connection. - * If GGATE_FLAG_SEND flag is set - this is socket to send data. - * If GGATE_FLAG_RECV flag is set - this is socket to receive data. - */ -#define GGATE_FLAG_SEND 0x0004 -#define GGATE_FLAG_RECV 0x0008 - -#define GGATE_CMD_READ 0 -#define GGATE_CMD_WRITE 1 - -extern int g_gate_devfd; -extern int g_gate_verbose; - -extern int nagle; -extern unsigned rcvbuf, sndbuf; - -struct g_gate_version { - char gv_magic[16]; - uint16_t gv_version; - uint16_t gv_error; -} __packed; - -/* Client's initial packet. */ -struct g_gate_cinit { - char gc_path[PATH_MAX + 1]; - uint64_t gc_flags; - uint16_t gc_nconn; - uint32_t gc_token; -} __packed; - -/* Server's initial packet. */ -struct g_gate_sinit { - uint8_t gs_flags; - uint64_t gs_mediasize; - uint32_t gs_sectorsize; - uint16_t gs_error; -} __packed; - -/* Control struct. */ -struct g_gate_hdr { - uint8_t gh_cmd; /* command */ - uint64_t gh_offset; /* device offset */ - uint32_t gh_length; /* size of block */ - uint64_t gh_seq; /* request number */ - uint16_t gh_error; /* error value (0 if ok) */ -} __packed; - -void g_gate_vlog(int priority, const char *message, va_list ap); -void g_gate_log(int priority, const char *message, ...); -void g_gate_xvlog(const char *message, va_list ap) __dead2; -void g_gate_xlog(const char *message, ...) __dead2; -off_t g_gate_mediasize(int fd); -unsigned g_gate_sectorsize(int fd); -void g_gate_open_device(void); -void g_gate_close_device(void); -void g_gate_ioctl(unsigned long req, void *data); -void g_gate_destroy(int unit, int force); -void g_gate_load_module(void); -ssize_t g_gate_recv(int s, void *buf, size_t len, int flags); -ssize_t g_gate_send(int s, const void *buf, size_t len, int flags); -void g_gate_socket_settings(int sfd); -#ifdef LIBGEOM -void g_gate_list(int unit, int verbose); -#endif -in_addr_t g_gate_str2ip(const char *str); - -/* - * g_gate_swap2h_* - functions swap bytes to host byte order (from big endian). - * g_gate_swap2n_* - functions swap bytes to network byte order (actually - * to big endian byte order). - */ - -static __inline void -g_gate_swap2h_version(struct g_gate_version *ver) -{ - - ver->gv_version = be16toh(ver->gv_version); - ver->gv_error = be16toh(ver->gv_error); -} - -static __inline void -g_gate_swap2n_version(struct g_gate_version *ver) -{ - - ver->gv_version = htobe16(ver->gv_version); - ver->gv_error = htobe16(ver->gv_error); -} - -static __inline void -g_gate_swap2h_cinit(struct g_gate_cinit *cinit) -{ - - cinit->gc_flags = be64toh(cinit->gc_flags); - cinit->gc_nconn = be16toh(cinit->gc_nconn); - cinit->gc_token = be32toh(cinit->gc_token); -} - -static __inline void -g_gate_swap2n_cinit(struct g_gate_cinit *cinit) -{ - - cinit->gc_flags = htobe64(cinit->gc_flags); - cinit->gc_nconn = htobe16(cinit->gc_nconn); - cinit->gc_token = htobe32(cinit->gc_token); -} - -static __inline void -g_gate_swap2h_sinit(struct g_gate_sinit *sinit) -{ - - /* Swap only used fields. */ - sinit->gs_mediasize = be64toh(sinit->gs_mediasize); - sinit->gs_sectorsize = be32toh(sinit->gs_sectorsize); - sinit->gs_error = be16toh(sinit->gs_error); -} - -static __inline void -g_gate_swap2n_sinit(struct g_gate_sinit *sinit) -{ - - /* Swap only used fields. */ - sinit->gs_mediasize = htobe64(sinit->gs_mediasize); - sinit->gs_sectorsize = htobe32(sinit->gs_sectorsize); - sinit->gs_error = htobe16(sinit->gs_error); -} - -static __inline void -g_gate_swap2h_hdr(struct g_gate_hdr *hdr) -{ - - /* Swap only used fields. */ - hdr->gh_offset = be64toh(hdr->gh_offset); - hdr->gh_length = be32toh(hdr->gh_length); - hdr->gh_seq = be64toh(hdr->gh_seq); - hdr->gh_error = be16toh(hdr->gh_error); -} - -static __inline void -g_gate_swap2n_hdr(struct g_gate_hdr *hdr) -{ - - /* Swap only used fields. */ - hdr->gh_offset = htobe64(hdr->gh_offset); - hdr->gh_length = htobe32(hdr->gh_length); - hdr->gh_seq = htobe64(hdr->gh_seq); - hdr->gh_error = htobe16(hdr->gh_error); -} -#endif /* _GGATE_H_ */ From ae15d2594a226e1f9cfe7ba27d3c4b2f455529fb Mon Sep 17 00:00:00 2001 From: gjb Date: Fri, 21 Feb 2014 03:35:43 +0000 Subject: [PATCH 2/2] Move ^/user/gjb/hacking/release-embedded up one directory, and remove ^/user/gjb/hacking since this is likely to be merged to head/ soon. Sponsored by: The FreeBSD Foundation --- Makefile | 14 + Makefile.inc | 3 + ggatec/Makefile | 16 + ggatec/ggatec.8 | 181 ++++++++ ggatec/ggatec.c | 642 +++++++++++++++++++++++++++++ ggated/Makefile | 14 + ggated/ggated.8 | 111 +++++ ggated/ggated.c | 1050 +++++++++++++++++++++++++++++++++++++++++++++++ ggatel/Makefile | 15 + ggatel/ggatel.8 | 155 +++++++ ggatel/ggatel.c | 327 +++++++++++++++ shared/ggate.c | 409 ++++++++++++++++++ shared/ggate.h | 196 +++++++++ 13 files changed, 3133 insertions(+) create mode 100644 Makefile create mode 100644 Makefile.inc create mode 100644 ggatec/Makefile create mode 100644 ggatec/ggatec.8 create mode 100644 ggatec/ggatec.c create mode 100644 ggated/Makefile create mode 100644 ggated/ggated.8 create mode 100644 ggated/ggated.c create mode 100644 ggatel/Makefile create mode 100644 ggatel/ggatel.8 create mode 100644 ggatel/ggatel.c create mode 100644 shared/ggate.c create mode 100644 shared/ggate.h diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..8f889f1 --- /dev/null +++ b/Makefile @@ -0,0 +1,14 @@ +# $FreeBSD$ + +.include + +SUBDIR= ${_ggatec} \ + ${_ggated} \ + ggatel + +.if ${MK_LIBTHR} != "no" +_ggatec= ggatec +_ggated= ggated +.endif + +.include diff --git a/Makefile.inc b/Makefile.inc new file mode 100644 index 0000000..265f86d --- /dev/null +++ b/Makefile.inc @@ -0,0 +1,3 @@ +# $FreeBSD$ + +.include "../Makefile.inc" diff --git a/ggatec/Makefile b/ggatec/Makefile new file mode 100644 index 0000000..4d8917f --- /dev/null +++ b/ggatec/Makefile @@ -0,0 +1,16 @@ +# $FreeBSD$ + +.PATH: ${.CURDIR}/../shared + +PROG= ggatec +MAN= ggatec.8 +SRCS= ggatec.c ggate.c + +CFLAGS+= -DMAX_SEND_SIZE=32768 +CFLAGS+= -DLIBGEOM +CFLAGS+= -I${.CURDIR}/../shared + +DPADD= ${LIBGEOM} ${LIBSBUF} ${LIBBSDXML} ${LIBUTIL} ${LIBPTHREAD} +LDADD= -lgeom -lsbuf -lbsdxml -lutil -lpthread + +.include diff --git a/ggatec/ggatec.8 b/ggatec/ggatec.8 new file mode 100644 index 0000000..09f0444 --- /dev/null +++ b/ggatec/ggatec.8 @@ -0,0 +1,181 @@ +.\" 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 GGATEC 8 +.Os +.Sh NAME +.Nm ggatec +.Nd "GEOM Gate network client and control utility" +.Sh SYNOPSIS +.Nm +.Cm create +.Op Fl n +.Op Fl v +.Op Fl o Cm ro | wo | rw +.Op Fl p Ar port +.Op Fl q Ar queue_size +.Op Fl R Ar rcvbuf +.Op Fl S Ar sndbuf +.Op Fl s Ar sectorsize +.Op Fl t Ar timeout +.Op Fl u Ar unit +.Ar host +.Ar path +.Nm +.Cm rescue +.Op Fl n +.Op Fl v +.Op Fl o Cm ro | wo | rw +.Op Fl p Ar port +.Op Fl R Ar rcvbuf +.Op Fl S Ar sndbuf +.Fl u Ar unit +.Ar host +.Ar path +.Nm +.Cm destroy +.Op Fl f +.Fl u Ar unit +.Nm +.Cm list +.Op Fl v +.Op Fl u Ar unit +.Sh DESCRIPTION +The +.Nm +utility is a network client for GEOM Gate class. +It is responsible for creation of +.Nm ggate +devices and forwarding I/O requests between +.Nm geom_gate.ko +kernel module and +.Xr ggated 8 +network daemon. +Available commands: +.Bl -tag -width ".Cm destroy" +.It Cm create +Connect to given +.Xr ggated 8 +daemon and create a +.Nm ggate +provider related to the given remote file or device. +.It Cm rescue +If +.Nm +process died/has been killed, you can save situation with this +command, which creates new connection to the +.Xr ggated 8 +daemon and will handle pending and future requests. +.It Cm destroy +Destroy the given +.Nm ggate +provider. +.It Cm list +List +.Nm ggate +providers. +.El +.Pp +Available options: +.Bl -tag -width ".Fl s Cm ro | wo | rw" +.It Fl f +Forcibly destroy +.Nm ggate +provider (cancels all pending requests). +.It Fl n +Do not use +.Dv TCP_NODELAY +option on TCP sockets. +.It Fl o Cm ro | wo | rw +Specify permission to use when opening the file or device: read-only +.Pq Cm ro , +write-only +.Pq Cm wo , +or read-write +.Pq Cm rw . +Default is +.Cm rw . +.It Fl p Ar port +Port to connect to on the remote host. +Default is 3080. +.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 R Ar rcvbuf +Size of receive buffer to use. +Default is 131072 (128kB). +.It Fl S Ar sndbuf +Size of send buffer to use. +Default is 131072 (128kB). +.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 0. +.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 host +Remote host to connect to. +.It Ar path +Path to a regular file or device. +.El +.Sh EXIT STATUS +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 EXAMPLES +Make use of CD-ROM device from remote host. +.Bd -literal -offset indent +server# cat /etc/gg.exports +client RO /dev/acd0 +server# ggated + +client# ggatec create -o ro server /dev/acd0 +ggate0 +client# mount_cd9660 /dev/ggate0 /cdrom +.Ed +.Sh SEE ALSO +.Xr geom 4 , +.Xr ggated 8 , +.Xr ggatel 8 , +.Xr mount_cd9660 8 +.Sh AUTHORS +The +.Nm +utility as well as this manual page was written by +.An Pawel Jakub Dawidek Aq pjd@FreeBSD.org . diff --git a/ggatec/ggatec.c b/ggatec/ggatec.c new file mode 100644 index 0000000..6f9263c --- /dev/null +++ b/ggatec/ggatec.c @@ -0,0 +1,642 @@ +/*- + * 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 +#include +#include +#include +#include +#include + +#include +#include "ggate.h" + + +static enum { UNSET, CREATE, DESTROY, LIST, RESCUE } action = UNSET; + +static const char *path = NULL; +static const char *host = NULL; +static int unit = G_GATE_UNIT_AUTO; +static unsigned flags = 0; +static int force = 0; +static unsigned queue_size = G_GATE_QUEUE_SIZE; +static unsigned port = G_GATE_PORT; +static off_t mediasize; +static unsigned sectorsize = 0; +static unsigned timeout = G_GATE_TIMEOUT; +static int sendfd, recvfd; +static uint32_t token; +static pthread_t sendtd, recvtd; +static int reconnect; + +static void +usage(void) +{ + + fprintf(stderr, "usage: %s create [-nv] [-o ] [-p port] " + "[-q queue_size] [-R rcvbuf] [-S sndbuf] [-s sectorsize] " + "[-t timeout] [-u unit] \n", getprogname()); + fprintf(stderr, " %s rescue [-nv] [-o ] [-p port] " + "[-R rcvbuf] [-S sndbuf] <-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 * +send_thread(void *arg __unused) +{ + struct g_gate_ctl_io ggio; + struct g_gate_hdr hdr; + char buf[MAXPHYS]; + ssize_t data; + int error; + + g_gate_log(LOG_NOTICE, "%s: started!", __func__); + + ggio.gctl_version = G_GATE_VERSION; + ggio.gctl_unit = unit; + ggio.gctl_data = buf; + + for (;;) { + ggio.gctl_length = sizeof(buf); + ggio.gctl_error = 0; + g_gate_ioctl(G_GATE_CMD_START, &ggio); + error = ggio.gctl_error; + switch (error) { + case 0: + break; + case ECANCELED: + if (reconnect) + break; + /* Exit gracefully. */ + g_gate_close_device(); + exit(EXIT_SUCCESS); +#if 0 + case ENOMEM: + /* Buffer too small. */ + ggio.gctl_data = realloc(ggio.gctl_data, + ggio.gctl_length); + if (ggio.gctl_data != NULL) { + bsize = ggio.gctl_length; + goto once_again; + } + /* FALLTHROUGH */ +#endif + case ENXIO: + default: + g_gate_xlog("ioctl(/dev/%s): %s.", G_GATE_CTL_NAME, + strerror(error)); + } + + if (reconnect) + break; + + switch (ggio.gctl_cmd) { + case BIO_READ: + hdr.gh_cmd = GGATE_CMD_READ; + break; + case BIO_WRITE: + hdr.gh_cmd = GGATE_CMD_WRITE; + break; + } + hdr.gh_seq = ggio.gctl_seq; + hdr.gh_offset = ggio.gctl_offset; + hdr.gh_length = ggio.gctl_length; + hdr.gh_error = 0; + g_gate_swap2n_hdr(&hdr); + + data = g_gate_send(sendfd, &hdr, sizeof(hdr), MSG_NOSIGNAL); + g_gate_log(LOG_DEBUG, "Sent hdr packet."); + g_gate_swap2h_hdr(&hdr); + if (reconnect) + break; + if (data != sizeof(hdr)) { + g_gate_log(LOG_ERR, "Lost connection 1."); + reconnect = 1; + pthread_kill(recvtd, SIGUSR1); + break; + } + + if (hdr.gh_cmd == GGATE_CMD_WRITE) { + data = g_gate_send(sendfd, ggio.gctl_data, + ggio.gctl_length, MSG_NOSIGNAL); + if (reconnect) + break; + if (data != ggio.gctl_length) { + g_gate_log(LOG_ERR, "Lost connection 2 (%zd != %zd).", data, (ssize_t)ggio.gctl_length); + reconnect = 1; + pthread_kill(recvtd, SIGUSR1); + break; + } + g_gate_log(LOG_DEBUG, "Sent %zd bytes (offset=%llu, " + "size=%u).", data, hdr.gh_offset, hdr.gh_length); + } + } + g_gate_log(LOG_DEBUG, "%s: Died.", __func__); + return (NULL); +} + +static void * +recv_thread(void *arg __unused) +{ + struct g_gate_ctl_io ggio; + struct g_gate_hdr hdr; + char buf[MAXPHYS]; + ssize_t data; + + g_gate_log(LOG_NOTICE, "%s: started!", __func__); + + ggio.gctl_version = G_GATE_VERSION; + ggio.gctl_unit = unit; + ggio.gctl_data = buf; + + for (;;) { + data = g_gate_recv(recvfd, &hdr, sizeof(hdr), MSG_WAITALL); + if (reconnect) + break; + g_gate_swap2h_hdr(&hdr); + if (data != sizeof(hdr)) { + if (data == -1 && errno == EAGAIN) + continue; + g_gate_log(LOG_ERR, "Lost connection 3."); + reconnect = 1; + pthread_kill(sendtd, SIGUSR1); + break; + } + g_gate_log(LOG_DEBUG, "Received hdr packet."); + + ggio.gctl_seq = hdr.gh_seq; + ggio.gctl_cmd = hdr.gh_cmd; + ggio.gctl_offset = hdr.gh_offset; + ggio.gctl_length = hdr.gh_length; + ggio.gctl_error = hdr.gh_error; + + if (ggio.gctl_error == 0 && ggio.gctl_cmd == GGATE_CMD_READ) { + data = g_gate_recv(recvfd, ggio.gctl_data, + ggio.gctl_length, MSG_WAITALL); + if (reconnect) + break; + g_gate_log(LOG_DEBUG, "Received data packet."); + if (data != ggio.gctl_length) { + g_gate_log(LOG_ERR, "Lost connection 4."); + reconnect = 1; + pthread_kill(sendtd, SIGUSR1); + break; + } + g_gate_log(LOG_DEBUG, "Received %d bytes (offset=%ju, " + "size=%zu).", data, (uintmax_t)hdr.gh_offset, + (size_t)hdr.gh_length); + } + + g_gate_ioctl(G_GATE_CMD_DONE, &ggio); + } + g_gate_log(LOG_DEBUG, "%s: Died.", __func__); + pthread_exit(NULL); +} + +static int +handshake(int dir) +{ + struct g_gate_version ver; + struct g_gate_cinit cinit; + struct g_gate_sinit sinit; + struct sockaddr_in serv; + int sfd; + + /* + * Do the network stuff. + */ + bzero(&serv, sizeof(serv)); + serv.sin_family = AF_INET; + serv.sin_addr.s_addr = g_gate_str2ip(host); + if (serv.sin_addr.s_addr == INADDR_NONE) { + g_gate_log(LOG_DEBUG, "Invalid IP/host name: %s.", host); + return (-1); + } + serv.sin_port = htons(port); + sfd = socket(AF_INET, SOCK_STREAM, 0); + if (sfd == -1) { + g_gate_log(LOG_DEBUG, "Cannot open socket: %s.", + strerror(errno)); + return (-1); + } + + g_gate_socket_settings(sfd); + + if (connect(sfd, (struct sockaddr *)&serv, sizeof(serv)) == -1) { + g_gate_log(LOG_DEBUG, "Cannot connect to server: %s.", + strerror(errno)); + close(sfd); + return (-1); + } + + g_gate_log(LOG_INFO, "Connected to the server: %s:%d.", host, port); + + /* + * Create and send version packet. + */ + g_gate_log(LOG_DEBUG, "Sending version packet."); + assert(strlen(GGATE_MAGIC) == sizeof(ver.gv_magic)); + bcopy(GGATE_MAGIC, ver.gv_magic, sizeof(ver.gv_magic)); + ver.gv_version = GGATE_VERSION; + ver.gv_error = 0; + g_gate_swap2n_version(&ver); + if (g_gate_send(sfd, &ver, sizeof(ver), MSG_NOSIGNAL) == -1) { + g_gate_log(LOG_DEBUG, "Error while sending version packet: %s.", + strerror(errno)); + close(sfd); + return (-1); + } + bzero(&ver, sizeof(ver)); + if (g_gate_recv(sfd, &ver, sizeof(ver), MSG_WAITALL) == -1) { + g_gate_log(LOG_DEBUG, "Error while receiving data: %s.", + strerror(errno)); + close(sfd); + return (-1); + } + if (ver.gv_error != 0) { + g_gate_log(LOG_DEBUG, "Version verification problem: %s.", + strerror(errno)); + close(sfd); + return (-1); + } + + /* + * Create and send initial packet. + */ + g_gate_log(LOG_DEBUG, "Sending initial packet."); + if (strlcpy(cinit.gc_path, path, sizeof(cinit.gc_path)) >= + sizeof(cinit.gc_path)) { + g_gate_log(LOG_DEBUG, "Path name too long."); + close(sfd); + return (-1); + } + cinit.gc_flags = flags | dir; + cinit.gc_token = token; + cinit.gc_nconn = 2; + g_gate_swap2n_cinit(&cinit); + if (g_gate_send(sfd, &cinit, sizeof(cinit), MSG_NOSIGNAL) == -1) { + g_gate_log(LOG_DEBUG, "Error while sending initial packet: %s.", + strerror(errno)); + close(sfd); + return (-1); + } + g_gate_swap2h_cinit(&cinit); + + /* + * Receiving initial packet from server. + */ + g_gate_log(LOG_DEBUG, "Receiving initial packet."); + if (g_gate_recv(sfd, &sinit, sizeof(sinit), MSG_WAITALL) == -1) { + g_gate_log(LOG_DEBUG, "Error while receiving data: %s.", + strerror(errno)); + close(sfd); + return (-1); + } + g_gate_swap2h_sinit(&sinit); + if (sinit.gs_error != 0) { + g_gate_log(LOG_DEBUG, "Error from server: %s.", + strerror(sinit.gs_error)); + close(sfd); + return (-1); + } + g_gate_log(LOG_DEBUG, "Received initial packet."); + + mediasize = sinit.gs_mediasize; + if (sectorsize == 0) + sectorsize = sinit.gs_sectorsize; + + return (sfd); +} + +static void +mydaemon(void) +{ + + if (g_gate_verbose > 0) + return; + if (daemon(0, 0) == 0) + return; + if (action == CREATE) + g_gate_destroy(unit, 1); + err(EXIT_FAILURE, "Cannot daemonize"); +} + +static int +g_gatec_connect(void) +{ + + token = arc4random(); + /* + * Our receive descriptor is connected to the send descriptor on the + * server side. + */ + recvfd = handshake(GGATE_FLAG_SEND); + if (recvfd == -1) + return (0); + /* + * Our send descriptor is connected to the receive descriptor on the + * server side. + */ + sendfd = handshake(GGATE_FLAG_RECV); + if (sendfd == -1) + return (0); + return (1); +} + +static void +g_gatec_start(void) +{ + int error; + + reconnect = 0; + error = pthread_create(&recvtd, NULL, recv_thread, NULL); + if (error != 0) { + g_gate_destroy(unit, 1); + g_gate_xlog("pthread_create(recv_thread): %s.", + strerror(error)); + } + sendtd = pthread_self(); + send_thread(NULL); + /* Disconnected. */ + close(sendfd); + close(recvfd); +} + +static void +signop(int sig __unused) +{ + + /* Do nothing. */ +} + +static void +g_gatec_loop(void) +{ + struct g_gate_ctl_cancel ggioc; + + signal(SIGUSR1, signop); + for (;;) { + g_gatec_start(); + g_gate_log(LOG_NOTICE, "Disconnected [%s %s]. Connecting...", + host, path); + while (!g_gatec_connect()) { + sleep(2); + g_gate_log(LOG_NOTICE, "Connecting [%s %s]...", host, + path); + } + ggioc.gctl_version = G_GATE_VERSION; + ggioc.gctl_unit = unit; + ggioc.gctl_seq = 0; + g_gate_ioctl(G_GATE_CMD_CANCEL, &ggioc); + } +} + +static void +g_gatec_create(void) +{ + struct g_gate_ctl_create ggioc; + + if (!g_gatec_connect()) + g_gate_xlog("Cannot connect: %s.", strerror(errno)); + + /* + * Ok, got both sockets, time to create provider. + */ + ggioc.gctl_version = G_GATE_VERSION; + ggioc.gctl_mediasize = mediasize; + ggioc.gctl_sectorsize = sectorsize; + ggioc.gctl_flags = flags; + ggioc.gctl_maxcount = queue_size; + ggioc.gctl_timeout = timeout; + ggioc.gctl_unit = unit; + snprintf(ggioc.gctl_info, sizeof(ggioc.gctl_info), "%s:%u %s", host, + port, path); + g_gate_ioctl(G_GATE_CMD_CREATE, &ggioc); + if (unit == -1) { + printf("%s%u\n", G_GATE_PROVIDER_NAME, ggioc.gctl_unit); + fflush(stdout); + } + unit = ggioc.gctl_unit; + + mydaemon(); + g_gatec_loop(); +} + +static void +g_gatec_rescue(void) +{ + struct g_gate_ctl_cancel ggioc; + + if (!g_gatec_connect()) + g_gate_xlog("Cannot connect: %s.", strerror(errno)); + + ggioc.gctl_version = G_GATE_VERSION; + ggioc.gctl_unit = unit; + ggioc.gctl_seq = 0; + g_gate_ioctl(G_GATE_CMD_CANCEL, &ggioc); + + mydaemon(); + g_gatec_loop(); +} + +int +main(int argc, char *argv[]) +{ + + if (argc < 2) + usage(); + 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 if (strcasecmp(argv[1], "rescue") == 0) + action = RESCUE; + else + usage(); + argc -= 1; + argv += 1; + for (;;) { + int ch; + + ch = getopt(argc, argv, "fno:p:q:R:S:s:t:u:v"); + if (ch == -1) + break; + switch (ch) { + case 'f': + if (action != DESTROY) + usage(); + force = 1; + break; + case 'n': + if (action != CREATE && action != RESCUE) + usage(); + nagle = 0; + break; + case 'o': + if (action != CREATE && action != RESCUE) + 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 'p': + if (action != CREATE && action != RESCUE) + usage(); + errno = 0; + port = strtoul(optarg, NULL, 10); + if (port == 0 && errno != 0) + errx(EXIT_FAILURE, "Invalid port."); + 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 'R': + if (action != CREATE && action != RESCUE) + usage(); + errno = 0; + rcvbuf = strtoul(optarg, NULL, 10); + if (rcvbuf == 0 && errno != 0) + errx(EXIT_FAILURE, "Invalid rcvbuf."); + break; + case 'S': + if (action != CREATE && action != RESCUE) + usage(); + errno = 0; + sndbuf = strtoul(optarg, NULL, 10); + if (sndbuf == 0 && errno != 0) + errx(EXIT_FAILURE, "Invalid sndbuf."); + 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 CREATE: + if (argc != 2) + usage(); + g_gate_load_module(); + g_gate_open_device(); + host = argv[0]; + path = argv[1]; + g_gatec_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 RESCUE: + if (argc != 2) + usage(); + if (unit == -1) { + fprintf(stderr, "Required unit number.\n"); + usage(); + } + g_gate_open_device(); + host = argv[0]; + path = argv[1]; + g_gatec_rescue(); + break; + case UNSET: + default: + usage(); + } + g_gate_close_device(); + exit(EXIT_SUCCESS); +} diff --git a/ggated/Makefile b/ggated/Makefile new file mode 100644 index 0000000..4e7708e --- /dev/null +++ b/ggated/Makefile @@ -0,0 +1,14 @@ +# $FreeBSD$ + +.PATH: ${.CURDIR}/../shared + +PROG= ggated +MAN= ggated.8 +SRCS= ggated.c ggate.c + +DPADD= ${LIBPTHREAD} +LDADD= -lpthread + +CFLAGS+= -I${.CURDIR}/../shared + +.include diff --git a/ggated/ggated.8 b/ggated/ggated.8 new file mode 100644 index 0000000..3024a04 --- /dev/null +++ b/ggated/ggated.8 @@ -0,0 +1,111 @@ +.\" 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 29, 2004 +.Dt GGATED 8 +.Os +.Sh NAME +.Nm ggated +.Nd "GEOM Gate network daemon" +.Sh SYNOPSIS +.Nm +.Op Fl h +.Op Fl n +.Op Fl v +.Op Fl a Ar address +.Op Fl p Ar port +.Op Fl R Ar rcvbuf +.Op Fl S Ar sndbuf +.Op Ar "exports file" +.Sh DESCRIPTION +The +.Nm +utility is a network server for GEOM Gate class. +It runs on a server machine to service GEOM Gate requests from workers +placed on a client machine. +Keep in mind, that connection between +.Xr ggatec 8 +and +.Nm +is not encrypted. +.Pp +Available options: +.Bl -tag -width ".Ar exports\ file" +.It Fl a Ar address +Specifies an IP address to bind to. +.It Fl h +Print available options. +.It Fl n +Do not use +.Dv TCP_NODELAY +option on TCP sockets. +.It Fl p Ar port +Port on which +.Nm +listens for connection. +Default is 3080. +.It Fl R Ar rcvbuf +Size of receive buffer to use. +Default is 131072 (128kB). +.It Fl S Ar sndbuf +Size of send buffer to use. +Default is 131072 (128kB). +.It Fl v +Do not fork, run in foreground and print debug informations on standard +output. +.It Ar "exports file" +An alternate location for the exports file. +.El +.Pp +The format of an exports file is as follows: +.Bd -literal -offset indent +1.2.3.4 RO /dev/acd0 +1.2.3.0/24 RW /tmp/test.img +hostname WO /tmp/image +.Ed +.Sh EXIT STATUS +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 EXAMPLES +Export CD-ROM device and a file: +.Bd -literal -offset indent +# echo "1.2.3.0/24 RO /dev/acd0" > /etc/gg.exports +# echo "client RW /image" >> /etc/gg.exports +# ggated +.Ed +.Sh SEE ALSO +.Xr geom 4 , +.Xr ggatec 8 , +.Xr ggatel 8 +.Sh AUTHORS +The +.Nm +utility as well as this manual page was written by +.An Pawel Jakub Dawidek Aq pjd@FreeBSD.org . diff --git a/ggated/ggated.c b/ggated/ggated.c new file mode 100644 index 0000000..01aa00a --- /dev/null +++ b/ggated/ggated.c @@ -0,0 +1,1050 @@ +/*- + * 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 +#include +#include +#include +#include +#include +#include +#include +#include + +#include "ggate.h" + + +#define GGATED_EXPORT_FILE "/etc/gg.exports" + +struct ggd_connection { + off_t c_mediasize; + unsigned c_sectorsize; + unsigned c_flags; /* flags (RO/RW) */ + int c_diskfd; + int c_sendfd; + int c_recvfd; + time_t c_birthtime; + char *c_path; + uint64_t c_token; + in_addr_t c_srcip; + LIST_ENTRY(ggd_connection) c_next; +}; + +struct ggd_request { + struct g_gate_hdr r_hdr; + char *r_data; + TAILQ_ENTRY(ggd_request) r_next; +}; +#define r_cmd r_hdr.gh_cmd +#define r_offset r_hdr.gh_offset +#define r_length r_hdr.gh_length +#define r_error r_hdr.gh_error + +struct ggd_export { + char *e_path; /* path to device/file */ + in_addr_t e_ip; /* remote IP address */ + in_addr_t e_mask; /* IP mask */ + unsigned e_flags; /* flags (RO/RW) */ + SLIST_ENTRY(ggd_export) e_next; +}; + +static const char *exports_file = GGATED_EXPORT_FILE; +static int got_sighup = 0; +static in_addr_t bindaddr; + +static TAILQ_HEAD(, ggd_request) inqueue = TAILQ_HEAD_INITIALIZER(inqueue); +static TAILQ_HEAD(, ggd_request) outqueue = TAILQ_HEAD_INITIALIZER(outqueue); +static pthread_mutex_t inqueue_mtx, outqueue_mtx; +static pthread_cond_t inqueue_cond, outqueue_cond; + +static SLIST_HEAD(, ggd_export) exports = SLIST_HEAD_INITIALIZER(exports); +static LIST_HEAD(, ggd_connection) connections = LIST_HEAD_INITIALIZER(connections); + +static void *recv_thread(void *arg); +static void *disk_thread(void *arg); +static void *send_thread(void *arg); + +static void +usage(void) +{ + + fprintf(stderr, "usage: %s [-nv] [-a address] [-p port] [-R rcvbuf] " + "[-S sndbuf] [exports file]\n", getprogname()); + exit(EXIT_FAILURE); +} + +static char * +ip2str(in_addr_t ip) +{ + static char sip[16]; + + snprintf(sip, sizeof(sip), "%u.%u.%u.%u", + ((ip >> 24) & 0xff), + ((ip >> 16) & 0xff), + ((ip >> 8) & 0xff), + (ip & 0xff)); + return (sip); +} + +static in_addr_t +countmask(unsigned m) +{ + in_addr_t mask; + + if (m == 0) { + mask = 0x0; + } else { + mask = 1 << (32 - m); + mask--; + mask = ~mask; + } + return (mask); +} + +static void +line_parse(char *line, unsigned lineno) +{ + struct ggd_export *ex; + char *word, *path, *sflags; + unsigned flags, i, vmask; + in_addr_t ip, mask; + + ip = mask = flags = vmask = 0; + path = NULL; + sflags = NULL; + + for (i = 0, word = strtok(line, " \t"); word != NULL; + i++, word = strtok(NULL, " \t")) { + switch (i) { + case 0: /* IP address or host name */ + ip = g_gate_str2ip(strsep(&word, "/")); + if (ip == INADDR_NONE) { + g_gate_xlog("Invalid IP/host name at line %u.", + lineno); + } + ip = ntohl(ip); + if (word == NULL) + vmask = 32; + else { + errno = 0; + vmask = strtoul(word, NULL, 10); + if (vmask == 0 && errno != 0) { + g_gate_xlog("Invalid IP mask value at " + "line %u.", lineno); + } + if ((unsigned)vmask > 32) { + g_gate_xlog("Invalid IP mask value at line %u.", + lineno); + } + } + mask = countmask(vmask); + break; + case 1: /* flags */ + if (strcasecmp("rd", word) == 0 || + strcasecmp("ro", word) == 0) { + flags = O_RDONLY; + } else if (strcasecmp("wo", word) == 0) { + flags = O_WRONLY; + } else if (strcasecmp("rw", word) == 0) { + flags = O_RDWR; + } else { + g_gate_xlog("Invalid value in flags field at " + "line %u.", lineno); + } + sflags = word; + break; + case 2: /* path */ + if (strlen(word) >= MAXPATHLEN) { + g_gate_xlog("Path too long at line %u. ", + lineno); + } + path = word; + break; + default: + g_gate_xlog("Too many arguments at line %u. ", lineno); + } + } + if (i != 3) + g_gate_xlog("Too few arguments at line %u.", lineno); + + ex = malloc(sizeof(*ex)); + if (ex == NULL) + g_gate_xlog("Not enough memory."); + ex->e_path = strdup(path); + if (ex->e_path == NULL) + g_gate_xlog("Not enough memory."); + + /* Made 'and' here. */ + ex->e_ip = (ip & mask); + ex->e_mask = mask; + ex->e_flags = flags; + + SLIST_INSERT_HEAD(&exports, ex, e_next); + + g_gate_log(LOG_DEBUG, "Added %s/%u %s %s to exports list.", + ip2str(ex->e_ip), vmask, path, sflags); +} + +static void +exports_clear(void) +{ + struct ggd_export *ex; + + while (!SLIST_EMPTY(&exports)) { + ex = SLIST_FIRST(&exports); + SLIST_REMOVE_HEAD(&exports, e_next); + free(ex); + } +} + +#define EXPORTS_LINE_SIZE 2048 +static void +exports_get(void) +{ + char buf[EXPORTS_LINE_SIZE], *line; + unsigned lineno = 0, objs = 0, len; + FILE *fd; + + exports_clear(); + + fd = fopen(exports_file, "r"); + if (fd == NULL) { + g_gate_xlog("Cannot open exports file (%s): %s.", exports_file, + strerror(errno)); + } + + g_gate_log(LOG_INFO, "Reading exports file (%s).", exports_file); + + for (;;) { + if (fgets(buf, sizeof(buf), fd) == NULL) { + if (feof(fd)) + break; + + g_gate_xlog("Error while reading exports file: %s.", + strerror(errno)); + } + + /* Increase line count. */ + lineno++; + + /* Skip spaces and tabs. */ + for (line = buf; *line == ' ' || *line == '\t'; ++line) + ; + + /* Empty line, comment or empty line at the end of file. */ + if (*line == '\n' || *line == '#' || *line == '\0') + continue; + + len = strlen(line); + if (line[len - 1] == '\n') { + /* Remove new line char. */ + line[len - 1] = '\0'; + } else { + if (!feof(fd)) + g_gate_xlog("Line %u too long.", lineno); + } + + line_parse(line, lineno); + objs++; + } + + fclose(fd); + + if (objs == 0) + g_gate_xlog("There are no objects to export."); + + g_gate_log(LOG_INFO, "Exporting %u object(s).", objs); +} + +static int +exports_check(struct ggd_export *ex, struct g_gate_cinit *cinit, + struct ggd_connection *conn) +{ + char ipmask[32]; /* 32 == strlen("xxx.xxx.xxx.xxx/xxx.xxx.xxx.xxx")+1 */ + int error = 0, flags; + + strlcpy(ipmask, ip2str(ex->e_ip), sizeof(ipmask)); + strlcat(ipmask, "/", sizeof(ipmask)); + strlcat(ipmask, ip2str(ex->e_mask), sizeof(ipmask)); + if ((cinit->gc_flags & GGATE_FLAG_RDONLY) != 0) { + if (ex->e_flags == O_WRONLY) { + g_gate_log(LOG_WARNING, "Read-only access requested, " + "but %s (%s) is exported write-only.", ex->e_path, + ipmask); + return (EPERM); + } else { + conn->c_flags |= GGATE_FLAG_RDONLY; + } + } else if ((cinit->gc_flags & GGATE_FLAG_WRONLY) != 0) { + if (ex->e_flags == O_RDONLY) { + g_gate_log(LOG_WARNING, "Write-only access requested, " + "but %s (%s) is exported read-only.", ex->e_path, + ipmask); + return (EPERM); + } else { + conn->c_flags |= GGATE_FLAG_WRONLY; + } + } else { + if (ex->e_flags == O_RDONLY) { + g_gate_log(LOG_WARNING, "Read-write access requested, " + "but %s (%s) is exported read-only.", ex->e_path, + ipmask); + return (EPERM); + } else if (ex->e_flags == O_WRONLY) { + g_gate_log(LOG_WARNING, "Read-write access requested, " + "but %s (%s) is exported write-only.", ex->e_path, + ipmask); + return (EPERM); + } + } + if ((conn->c_flags & GGATE_FLAG_RDONLY) != 0) + flags = O_RDONLY; + else if ((conn->c_flags & GGATE_FLAG_WRONLY) != 0) + flags = O_WRONLY; + else + flags = O_RDWR; + conn->c_diskfd = open(ex->e_path, flags); + if (conn->c_diskfd == -1) { + error = errno; + g_gate_log(LOG_ERR, "Cannot open %s: %s.", ex->e_path, + strerror(error)); + return (error); + } + return (0); +} + +static struct ggd_export * +exports_find(struct sockaddr *s, struct g_gate_cinit *cinit, + struct ggd_connection *conn) +{ + struct ggd_export *ex; + in_addr_t ip; + int error; + + ip = htonl(((struct sockaddr_in *)(void *)s)->sin_addr.s_addr); + SLIST_FOREACH(ex, &exports, e_next) { + if ((ip & ex->e_mask) != ex->e_ip) { + g_gate_log(LOG_DEBUG, "exports[%s]: IP mismatch.", + ex->e_path); + continue; + } + if (strcmp(cinit->gc_path, ex->e_path) != 0) { + g_gate_log(LOG_DEBUG, "exports[%s]: Path mismatch.", + ex->e_path); + continue; + } + error = exports_check(ex, cinit, conn); + if (error == 0) + return (ex); + else { + errno = error; + return (NULL); + } + } + g_gate_log(LOG_WARNING, "Unauthorized connection from: %s.", + ip2str(ip)); + errno = EPERM; + return (NULL); +} + +/* + * Remove timed out connections. + */ +static void +connection_cleanups(void) +{ + struct ggd_connection *conn, *tconn; + time_t now; + + time(&now); + LIST_FOREACH_SAFE(conn, &connections, c_next, tconn) { + if (now - conn->c_birthtime > 10) { + LIST_REMOVE(conn, c_next); + g_gate_log(LOG_NOTICE, + "Connection from %s [%s] removed.", + ip2str(conn->c_srcip), conn->c_path); + close(conn->c_diskfd); + close(conn->c_sendfd); + close(conn->c_recvfd); + free(conn->c_path); + free(conn); + } + } +} + +static struct ggd_connection * +connection_find(struct g_gate_cinit *cinit) +{ + struct ggd_connection *conn; + + LIST_FOREACH(conn, &connections, c_next) { + if (conn->c_token == cinit->gc_token) + break; + } + return (conn); +} + +static struct ggd_connection * +connection_new(struct g_gate_cinit *cinit, struct sockaddr *s, int sfd) +{ + struct ggd_connection *conn; + in_addr_t ip; + + /* + * First, look for old connections. + * We probably should do it every X seconds, but what for? + * It is only dangerous if an attacker wants to overload connections + * queue, so here is a good place to do the cleanups. + */ + connection_cleanups(); + + conn = malloc(sizeof(*conn)); + if (conn == NULL) + return (NULL); + conn->c_path = strdup(cinit->gc_path); + if (conn->c_path == NULL) { + free(conn); + return (NULL); + } + conn->c_token = cinit->gc_token; + ip = htonl(((struct sockaddr_in *)(void *)s)->sin_addr.s_addr); + conn->c_srcip = ip; + conn->c_sendfd = conn->c_recvfd = -1; + if ((cinit->gc_flags & GGATE_FLAG_SEND) != 0) + conn->c_sendfd = sfd; + else + conn->c_recvfd = sfd; + conn->c_mediasize = 0; + conn->c_sectorsize = 0; + time(&conn->c_birthtime); + conn->c_flags = cinit->gc_flags; + LIST_INSERT_HEAD(&connections, conn, c_next); + g_gate_log(LOG_DEBUG, "Connection created [%s, %s].", ip2str(ip), + conn->c_path); + return (conn); +} + +static int +connection_add(struct ggd_connection *conn, struct g_gate_cinit *cinit, + struct sockaddr *s, int sfd) +{ + in_addr_t ip; + + ip = htonl(((struct sockaddr_in *)(void *)s)->sin_addr.s_addr); + if ((cinit->gc_flags & GGATE_FLAG_SEND) != 0) { + if (conn->c_sendfd != -1) { + g_gate_log(LOG_WARNING, + "Send socket already exists [%s, %s].", ip2str(ip), + conn->c_path); + return (EEXIST); + } + conn->c_sendfd = sfd; + } else { + if (conn->c_recvfd != -1) { + g_gate_log(LOG_WARNING, + "Receive socket already exists [%s, %s].", + ip2str(ip), conn->c_path); + return (EEXIST); + } + conn->c_recvfd = sfd; + } + g_gate_log(LOG_DEBUG, "Connection added [%s, %s].", ip2str(ip), + conn->c_path); + return (0); +} + +/* + * Remove one socket from the given connection or the whole + * connection if sfd == -1. + */ +static void +connection_remove(struct ggd_connection *conn) +{ + + LIST_REMOVE(conn, c_next); + g_gate_log(LOG_DEBUG, "Connection removed [%s %s].", + ip2str(conn->c_srcip), conn->c_path); + if (conn->c_sendfd != -1) + close(conn->c_sendfd); + if (conn->c_recvfd != -1) + close(conn->c_recvfd); + free(conn->c_path); + free(conn); +} + +static int +connection_ready(struct ggd_connection *conn) +{ + + return (conn->c_sendfd != -1 && conn->c_recvfd != -1); +} + +static void +connection_launch(struct ggd_connection *conn) +{ + pthread_t td; + int error, pid; + + pid = fork(); + if (pid > 0) + return; + else if (pid == -1) { + g_gate_log(LOG_ERR, "Cannot fork: %s.", strerror(errno)); + return; + } + g_gate_log(LOG_DEBUG, "Process created [%s].", conn->c_path); + + /* + * Create condition variables and mutexes for in-queue and out-queue + * synchronization. + */ + error = pthread_mutex_init(&inqueue_mtx, NULL); + if (error != 0) { + g_gate_xlog("pthread_mutex_init(inqueue_mtx): %s.", + strerror(error)); + } + error = pthread_cond_init(&inqueue_cond, NULL); + if (error != 0) { + g_gate_xlog("pthread_cond_init(inqueue_cond): %s.", + strerror(error)); + } + error = pthread_mutex_init(&outqueue_mtx, NULL); + if (error != 0) { + g_gate_xlog("pthread_mutex_init(outqueue_mtx): %s.", + strerror(error)); + } + error = pthread_cond_init(&outqueue_cond, NULL); + if (error != 0) { + g_gate_xlog("pthread_cond_init(outqueue_cond): %s.", + strerror(error)); + } + + /* + * Create threads: + * recvtd - thread for receiving I/O request + * diskio - thread for doing I/O request + * sendtd - thread for sending I/O requests back + */ + error = pthread_create(&td, NULL, send_thread, conn); + if (error != 0) { + g_gate_xlog("pthread_create(send_thread): %s.", + strerror(error)); + } + error = pthread_create(&td, NULL, recv_thread, conn); + if (error != 0) { + g_gate_xlog("pthread_create(recv_thread): %s.", + strerror(error)); + } + disk_thread(conn); +} + +static void +sendfail(int sfd, int error, const char *fmt, ...) +{ + struct g_gate_sinit sinit; + va_list ap; + ssize_t data; + + sinit.gs_error = error; + g_gate_swap2n_sinit(&sinit); + data = g_gate_send(sfd, &sinit, sizeof(sinit), 0); + g_gate_swap2h_sinit(&sinit); + if (data != sizeof(sinit)) { + g_gate_log(LOG_WARNING, "Cannot send initial packet: %s.", + strerror(errno)); + return; + } + if (fmt != NULL) { + va_start(ap, fmt); + g_gate_vlog(LOG_WARNING, fmt, ap); + va_end(ap); + } +} + +static void * +malloc_waitok(size_t size) +{ + void *p; + + while ((p = malloc(size)) == NULL) { + g_gate_log(LOG_DEBUG, "Cannot allocate %zu bytes.", size); + sleep(1); + } + return (p); +} + +static void * +recv_thread(void *arg) +{ + struct ggd_connection *conn; + struct ggd_request *req; + ssize_t data; + int error, fd; + + conn = arg; + g_gate_log(LOG_NOTICE, "%s: started [%s]!", __func__, conn->c_path); + fd = conn->c_recvfd; + for (;;) { + /* + * Get header packet. + */ + req = malloc_waitok(sizeof(*req)); + data = g_gate_recv(fd, &req->r_hdr, sizeof(req->r_hdr), + MSG_WAITALL); + if (data == 0) { + g_gate_log(LOG_DEBUG, "Process %u exiting.", getpid()); + exit(EXIT_SUCCESS); + } else if (data == -1) { + g_gate_xlog("Error while receiving hdr packet: %s.", + strerror(errno)); + } else if (data != sizeof(req->r_hdr)) { + g_gate_xlog("Malformed hdr packet received."); + } + g_gate_log(LOG_DEBUG, "Received hdr packet."); + g_gate_swap2h_hdr(&req->r_hdr); + + g_gate_log(LOG_DEBUG, "%s: offset=%jd length=%u", __func__, + (intmax_t)req->r_offset, (unsigned)req->r_length); + + /* + * Allocate memory for data. + */ + req->r_data = malloc_waitok(req->r_length); + + /* + * Receive data to write for WRITE request. + */ + if (req->r_cmd == GGATE_CMD_WRITE) { + g_gate_log(LOG_DEBUG, "Waiting for %u bytes of data...", + req->r_length); + data = g_gate_recv(fd, req->r_data, req->r_length, + MSG_WAITALL); + if (data == -1) { + g_gate_xlog("Error while receiving data: %s.", + strerror(errno)); + } + } + + /* + * Put the request onto the incoming queue. + */ + error = pthread_mutex_lock(&inqueue_mtx); + assert(error == 0); + TAILQ_INSERT_TAIL(&inqueue, req, r_next); + error = pthread_cond_signal(&inqueue_cond); + assert(error == 0); + error = pthread_mutex_unlock(&inqueue_mtx); + assert(error == 0); + } +} + +static void * +disk_thread(void *arg) +{ + struct ggd_connection *conn; + struct ggd_request *req; + ssize_t data; + int error, fd; + + conn = arg; + g_gate_log(LOG_NOTICE, "%s: started [%s]!", __func__, conn->c_path); + fd = conn->c_diskfd; + for (;;) { + /* + * Get a request from the incoming queue. + */ + error = pthread_mutex_lock(&inqueue_mtx); + assert(error == 0); + while ((req = TAILQ_FIRST(&inqueue)) == NULL) { + error = pthread_cond_wait(&inqueue_cond, &inqueue_mtx); + assert(error == 0); + } + TAILQ_REMOVE(&inqueue, req, r_next); + error = pthread_mutex_unlock(&inqueue_mtx); + assert(error == 0); + + /* + * Check the request. + */ + assert(req->r_cmd == GGATE_CMD_READ || req->r_cmd == GGATE_CMD_WRITE); + assert(req->r_offset + req->r_length <= (uintmax_t)conn->c_mediasize); + assert((req->r_offset % conn->c_sectorsize) == 0); + assert((req->r_length % conn->c_sectorsize) == 0); + + g_gate_log(LOG_DEBUG, "%s: offset=%jd length=%u", __func__, + (intmax_t)req->r_offset, (unsigned)req->r_length); + + /* + * Do the request. + */ + data = 0; + switch (req->r_cmd) { + case GGATE_CMD_READ: + data = pread(fd, req->r_data, req->r_length, + req->r_offset); + break; + case GGATE_CMD_WRITE: + data = pwrite(fd, req->r_data, req->r_length, + req->r_offset); + /* Free data memory here - better sooner. */ + free(req->r_data); + req->r_data = NULL; + break; + } + if (data != (ssize_t)req->r_length) { + /* Report short reads/writes as I/O errors. */ + if (errno == 0) + errno = EIO; + g_gate_log(LOG_ERR, "Disk error: %s", strerror(errno)); + req->r_error = errno; + if (req->r_data != NULL) { + free(req->r_data); + req->r_data = NULL; + } + } + + /* + * Put the request onto the outgoing queue. + */ + error = pthread_mutex_lock(&outqueue_mtx); + assert(error == 0); + TAILQ_INSERT_TAIL(&outqueue, req, r_next); + error = pthread_cond_signal(&outqueue_cond); + assert(error == 0); + error = pthread_mutex_unlock(&outqueue_mtx); + assert(error == 0); + } + + /* NOTREACHED */ + return (NULL); +} + +static void * +send_thread(void *arg) +{ + struct ggd_connection *conn; + struct ggd_request *req; + ssize_t data; + int error, fd; + + conn = arg; + g_gate_log(LOG_NOTICE, "%s: started [%s]!", __func__, conn->c_path); + fd = conn->c_sendfd; + for (;;) { + /* + * Get a request from the outgoing queue. + */ + error = pthread_mutex_lock(&outqueue_mtx); + assert(error == 0); + while ((req = TAILQ_FIRST(&outqueue)) == NULL) { + error = pthread_cond_wait(&outqueue_cond, + &outqueue_mtx); + assert(error == 0); + } + TAILQ_REMOVE(&outqueue, req, r_next); + error = pthread_mutex_unlock(&outqueue_mtx); + assert(error == 0); + + g_gate_log(LOG_DEBUG, "%s: offset=%jd length=%u", __func__, + (intmax_t)req->r_offset, (unsigned)req->r_length); + + /* + * Send the request. + */ + g_gate_swap2n_hdr(&req->r_hdr); + if (g_gate_send(fd, &req->r_hdr, sizeof(req->r_hdr), 0) == -1) { + g_gate_xlog("Error while sending hdr packet: %s.", + strerror(errno)); + } + g_gate_log(LOG_DEBUG, "Sent hdr packet."); + g_gate_swap2h_hdr(&req->r_hdr); + if (req->r_data != NULL) { + data = g_gate_send(fd, req->r_data, req->r_length, 0); + if (data != (ssize_t)req->r_length) { + g_gate_xlog("Error while sending data: %s.", + strerror(errno)); + } + g_gate_log(LOG_DEBUG, + "Sent %zd bytes (offset=%ju, size=%zu).", data, + (uintmax_t)req->r_offset, (size_t)req->r_length); + free(req->r_data); + } + free(req); + } + + /* NOTREACHED */ + return (NULL); +} + +static void +log_connection(struct sockaddr *from) +{ + in_addr_t ip; + + ip = htonl(((struct sockaddr_in *)(void *)from)->sin_addr.s_addr); + g_gate_log(LOG_INFO, "Connection from: %s.", ip2str(ip)); +} + +static int +handshake(struct sockaddr *from, int sfd) +{ + struct g_gate_version ver; + struct g_gate_cinit cinit; + struct g_gate_sinit sinit; + struct ggd_connection *conn; + struct ggd_export *ex; + ssize_t data; + + log_connection(from); + /* + * Phase 1: Version verification. + */ + g_gate_log(LOG_DEBUG, "Receiving version packet."); + data = g_gate_recv(sfd, &ver, sizeof(ver), MSG_WAITALL); + g_gate_swap2h_version(&ver); + if (data != sizeof(ver)) { + g_gate_log(LOG_WARNING, "Malformed version packet."); + return (0); + } + g_gate_log(LOG_DEBUG, "Version packet received."); + if (memcmp(ver.gv_magic, GGATE_MAGIC, strlen(GGATE_MAGIC)) != 0) { + g_gate_log(LOG_WARNING, "Invalid magic field."); + return (0); + } + if (ver.gv_version != GGATE_VERSION) { + g_gate_log(LOG_WARNING, "Version %u is not supported.", + ver.gv_version); + return (0); + } + ver.gv_error = 0; + g_gate_swap2n_version(&ver); + data = g_gate_send(sfd, &ver, sizeof(ver), 0); + g_gate_swap2h_version(&ver); + if (data == -1) { + sendfail(sfd, errno, "Error while sending version packet: %s.", + strerror(errno)); + return (0); + } + + /* + * Phase 2: Request verification. + */ + g_gate_log(LOG_DEBUG, "Receiving initial packet."); + data = g_gate_recv(sfd, &cinit, sizeof(cinit), MSG_WAITALL); + g_gate_swap2h_cinit(&cinit); + if (data != sizeof(cinit)) { + g_gate_log(LOG_WARNING, "Malformed initial packet."); + return (0); + } + g_gate_log(LOG_DEBUG, "Initial packet received."); + conn = connection_find(&cinit); + if (conn != NULL) { + /* + * Connection should already exists. + */ + g_gate_log(LOG_DEBUG, "Found existing connection (token=%lu).", + (unsigned long)conn->c_token); + if (connection_add(conn, &cinit, from, sfd) == -1) { + connection_remove(conn); + return (0); + } + } else { + /* + * New connection, allocate space. + */ + conn = connection_new(&cinit, from, sfd); + if (conn == NULL) { + sendfail(sfd, ENOMEM, + "Cannot allocate new connection."); + return (0); + } + g_gate_log(LOG_DEBUG, "New connection created (token=%lu).", + (unsigned long)conn->c_token); + } + + ex = exports_find(from, &cinit, conn); + if (ex == NULL) { + connection_remove(conn); + sendfail(sfd, errno, NULL); + return (0); + } + if (conn->c_mediasize == 0) { + conn->c_mediasize = g_gate_mediasize(conn->c_diskfd); + conn->c_sectorsize = g_gate_sectorsize(conn->c_diskfd); + } + sinit.gs_mediasize = conn->c_mediasize; + sinit.gs_sectorsize = conn->c_sectorsize; + sinit.gs_error = 0; + + g_gate_log(LOG_DEBUG, "Sending initial packet."); + + g_gate_swap2n_sinit(&sinit); + data = g_gate_send(sfd, &sinit, sizeof(sinit), 0); + g_gate_swap2h_sinit(&sinit); + if (data == -1) { + sendfail(sfd, errno, "Error while sending initial packet: %s.", + strerror(errno)); + return (0); + } + + if (connection_ready(conn)) { + connection_launch(conn); + connection_remove(conn); + } + return (1); +} + +static void +huphandler(int sig __unused) +{ + + got_sighup = 1; +} + +int +main(int argc, char *argv[]) +{ + struct sockaddr_in serv; + struct sockaddr from; + socklen_t fromlen; + int sfd, tmpsfd; + unsigned port; + + bindaddr = htonl(INADDR_ANY); + port = G_GATE_PORT; + for (;;) { + int ch; + + ch = getopt(argc, argv, "a:hnp:R:S:v"); + if (ch == -1) + break; + switch (ch) { + case 'a': + bindaddr = g_gate_str2ip(optarg); + if (bindaddr == INADDR_NONE) { + errx(EXIT_FAILURE, + "Invalid IP/host name to bind to."); + } + break; + case 'n': + nagle = 0; + break; + case 'p': + errno = 0; + port = strtoul(optarg, NULL, 10); + if (port == 0 && errno != 0) + errx(EXIT_FAILURE, "Invalid port."); + break; + case 'R': + errno = 0; + rcvbuf = strtoul(optarg, NULL, 10); + if (rcvbuf == 0 && errno != 0) + errx(EXIT_FAILURE, "Invalid rcvbuf."); + break; + case 'S': + errno = 0; + sndbuf = strtoul(optarg, NULL, 10); + if (sndbuf == 0 && errno != 0) + errx(EXIT_FAILURE, "Invalid sndbuf."); + break; + case 'v': + g_gate_verbose++; + break; + case 'h': + default: + usage(); + } + } + argc -= optind; + argv += optind; + + if (argv[0] != NULL) + exports_file = argv[0]; + exports_get(); + + if (!g_gate_verbose) { + /* Run in daemon mode. */ + if (daemon(0, 0) == -1) + g_gate_xlog("Cannot daemonize: %s", strerror(errno)); + } + + signal(SIGCHLD, SIG_IGN); + + sfd = socket(AF_INET, SOCK_STREAM, 0); + if (sfd == -1) + g_gate_xlog("Cannot open stream socket: %s.", strerror(errno)); + bzero(&serv, sizeof(serv)); + serv.sin_family = AF_INET; + serv.sin_addr.s_addr = bindaddr; + serv.sin_port = htons(port); + + g_gate_socket_settings(sfd); + + if (bind(sfd, (struct sockaddr *)&serv, sizeof(serv)) == -1) + g_gate_xlog("bind(): %s.", strerror(errno)); + if (listen(sfd, 5) == -1) + g_gate_xlog("listen(): %s.", strerror(errno)); + + g_gate_log(LOG_INFO, "Listen on port: %d.", port); + + signal(SIGHUP, huphandler); + + for (;;) { + fromlen = sizeof(from); + tmpsfd = accept(sfd, &from, &fromlen); + if (tmpsfd == -1) + g_gate_xlog("accept(): %s.", strerror(errno)); + + if (got_sighup) { + got_sighup = 0; + exports_get(); + } + + if (!handshake(&from, tmpsfd)) + close(tmpsfd); + } + close(sfd); + exit(EXIT_SUCCESS); +} diff --git a/ggatel/Makefile b/ggatel/Makefile new file mode 100644 index 0000000..604a754 --- /dev/null +++ b/ggatel/Makefile @@ -0,0 +1,15 @@ +# $FreeBSD$ + +.PATH: ${.CURDIR}/../shared + +PROG= ggatel +MAN= ggatel.8 +SRCS= ggatel.c ggate.c + +CFLAGS+= -DLIBGEOM +CFLAGS+= -I${.CURDIR}/../shared + +DPADD= ${LIBGEOM} ${LIBSBUF} ${LIBBSDXML} ${LIBUTIL} +LDADD= -lgeom -lsbuf -lbsdxml -lutil + +.include diff --git a/ggatel/ggatel.8 b/ggatel/ggatel.8 new file mode 100644 index 0000000..236e550 --- /dev/null +++ b/ggatel/ggatel.8 @@ -0,0 +1,155 @@ +.\" 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 2, 2011 +.Dt GGATEL 8 +.Os +.Sh NAME +.Nm ggatel +.Nd "GEOM Gate local control utility" +.Sh SYNOPSIS +.Nm +.Cm create +.Op Fl v +.Op Fl o Cm ro | wo | rw +.Op Fl s Ar sectorsize +.Op Fl t Ar timeout +.Op Fl u Ar unit +.Ar path +.Nm +.Cm attach +.Op Fl v +.Op Fl o Cm ro | wo | rw +.Fl u Ar unit +.Ar path +.Nm +.Cm destroy +.Op Fl f +.Fl u Ar unit +.Nm +.Cm 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 ".Cm destroy" +.It Cm create +Create a +.Nm ggate +provider related to the given regular file or device. +.It Cm attach +Attach a worker process to an existing +.Nm ggate +provider. +.It Cm destroy +Destroy the given +.Nm ggate +provider. +.It Cm list +List +.Nm ggate +providers. +.El +.Pp +Available options: +.Bl -tag -width ".Fl s Cm ro | wo | rw" +.It Fl f +Forcibly destroy +.Nm ggate +provider (cancels all pending requests). +.It Fl o Cm ro | wo | rw +Specify permission to use when opening the file or device: read-only +.Pq Cm ro , +write-only +.Pq Cm wo , +or read-write +.Pq Cm rw . +Default is +.Cm rw . +.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 +.Sh EXIT STATUS +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 EXAMPLES +.Dq GEOMify +the +.Dq Li fd0 +device and use +.Xr gbde 8 +to encrypt data on a floppy. +.Bd -literal -offset indent +ggatel create -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 +ggatel destroy -u 5 +.Ed +.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 Pawel Jakub Dawidek Aq pjd@FreeBSD.org . diff --git a/ggatel/ggatel.c b/ggatel/ggatel.c new file mode 100644 index 0000000..abfe7c1 --- /dev/null +++ b/ggatel/ggatel.c @@ -0,0 +1,327 @@ +/*- + * 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" + + +static enum { UNSET, CREATE, DESTROY, LIST, RESCUE } action = UNSET; + +static const char *path = NULL; +static int unit = G_GATE_UNIT_AUTO; +static unsigned flags = 0; +static int force = 0; +static unsigned sectorsize = 0; +static unsigned timeout = G_GATE_TIMEOUT; + +static void +usage(void) +{ + + fprintf(stderr, "usage: %s create [-v] [-o ] " + "[-s sectorsize] [-t timeout] [-u unit] \n", getprogname()); + fprintf(stderr, " %s rescue [-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 int +g_gate_openflags(unsigned ggflags) +{ + + if ((ggflags & G_GATE_FLAG_READONLY) != 0) + return (O_RDONLY); + else if ((ggflags & G_GATE_FLAG_WRITEONLY) != 0) + return (O_WRONLY); + return (O_RDWR); +} + +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) == -1) { + 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 ((size_t)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) | O_DIRECT | O_FSYNC); + if (fd == -1) + 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 = 0; + 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_rescue(void) +{ + struct g_gate_ctl_cancel ggioc; + int fd; + + fd = open(path, g_gate_openflags(flags)); + if (fd == -1) + err(EXIT_FAILURE, "Cannot open %s", path); + + ggioc.gctl_version = G_GATE_VERSION; + ggioc.gctl_unit = unit; + ggioc.gctl_seq = 0; + g_gate_ioctl(G_GATE_CMD_CANCEL, &ggioc); + + g_gatel_serve(fd); +} + +int +main(int argc, char *argv[]) +{ + + if (argc < 2) + usage(); + if (strcasecmp(argv[1], "create") == 0) + action = CREATE; + else if (strcasecmp(argv[1], "rescue") == 0) + action = RESCUE; + 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:s:t:u:v"); + if (ch == -1) + break; + switch (ch) { + case 'f': + if (action != DESTROY) + usage(); + force = 1; + break; + case 'o': + if (action != CREATE && action != RESCUE) + 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 '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 CREATE: + if (argc != 1) + usage(); + g_gate_load_module(); + g_gate_open_device(); + path = argv[0]; + g_gatel_create(); + break; + case RESCUE: + if (argc != 1) + usage(); + if (unit == -1) { + fprintf(stderr, "Required unit number.\n"); + usage(); + } + g_gate_open_device(); + path = argv[0]; + g_gatel_rescue(); + 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); +} diff --git a/shared/ggate.c b/shared/ggate.c new file mode 100644 index 0000000..cf9b9ca --- /dev/null +++ b/shared/ggate.c @@ -0,0 +1,409 @@ +/*- + * 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 +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include "ggate.h" + + +int g_gate_devfd = -1; +int g_gate_verbose = 0; + + +void +g_gate_vlog(int priority, const char *message, va_list ap) +{ + + if (g_gate_verbose) { + const char *prefix; + + switch (priority) { + case LOG_ERR: + prefix = "error"; + break; + case LOG_WARNING: + prefix = "warning"; + break; + case LOG_NOTICE: + prefix = "notice"; + break; + case LOG_INFO: + prefix = "info"; + break; + case LOG_DEBUG: + prefix = "debug"; + break; + default: + prefix = "unknown"; + } + + printf("%s: ", prefix); + vprintf(message, ap); + printf("\n"); + } else { + if (priority != LOG_DEBUG) + vsyslog(priority, message, ap); + } +} + +void +g_gate_log(int priority, const char *message, ...) +{ + va_list ap; + + va_start(ap, message); + g_gate_vlog(priority, message, ap); + va_end(ap); +} + +void +g_gate_xvlog(const char *message, va_list ap) +{ + + g_gate_vlog(LOG_ERR, message, ap); + g_gate_vlog(LOG_ERR, "Exiting.", ap); + exit(EXIT_FAILURE); +} + +void +g_gate_xlog(const char *message, ...) +{ + va_list ap; + + va_start(ap, message); + g_gate_xvlog(message, ap); + /* NOTREACHED */ + va_end(ap); + exit(EXIT_FAILURE); +} + +off_t +g_gate_mediasize(int fd) +{ + off_t mediasize; + struct stat sb; + + if (fstat(fd, &sb) == -1) + g_gate_xlog("fstat(): %s.", strerror(errno)); + if (S_ISCHR(sb.st_mode)) { + if (ioctl(fd, DIOCGMEDIASIZE, &mediasize) == -1) { + g_gate_xlog("Can't get media size: %s.", + strerror(errno)); + } + } else if (S_ISREG(sb.st_mode)) { + mediasize = sb.st_size; + } else { + g_gate_xlog("Unsupported file system object."); + } + return (mediasize); +} + +unsigned +g_gate_sectorsize(int fd) +{ + unsigned secsize; + struct stat sb; + + if (fstat(fd, &sb) == -1) + g_gate_xlog("fstat(): %s.", strerror(errno)); + if (S_ISCHR(sb.st_mode)) { + if (ioctl(fd, DIOCGSECTORSIZE, &secsize) == -1) { + g_gate_xlog("Can't get sector size: %s.", + strerror(errno)); + } + } else if (S_ISREG(sb.st_mode)) { + secsize = 512; + } else { + g_gate_xlog("Unsupported file system object."); + } + return (secsize); +} + +void +g_gate_open_device(void) +{ + + g_gate_devfd = open("/dev/" G_GATE_CTL_NAME, O_RDWR); + if (g_gate_devfd == -1) + err(EXIT_FAILURE, "open(/dev/%s)", G_GATE_CTL_NAME); +} + +void +g_gate_close_device(void) +{ + + close(g_gate_devfd); +} + +void +g_gate_ioctl(unsigned long req, void *data) +{ + + if (ioctl(g_gate_devfd, req, data) == -1) { + g_gate_xlog("%s: ioctl(/dev/%s): %s.", getprogname(), + G_GATE_CTL_NAME, strerror(errno)); + } +} + +void +g_gate_destroy(int unit, int force) +{ + struct g_gate_ctl_destroy ggio; + + ggio.gctl_version = G_GATE_VERSION; + ggio.gctl_unit = unit; + ggio.gctl_force = force; + g_gate_ioctl(G_GATE_CMD_DESTROY, &ggio); +} + +void +g_gate_load_module(void) +{ + + if (modfind("g_gate") == -1) { + /* Not present in kernel, try loading it. */ + if (kldload("geom_gate") == -1 || modfind("g_gate") == -1) { + if (errno != EEXIST) { + errx(EXIT_FAILURE, + "geom_gate module not available!"); + } + } + } +} + +/* + * When we send from ggatec packets larger than 32kB, performance drops + * significantly (eg. to 256kB/s over 1Gbit/s link). This is not a problem + * when data is send from ggated. I don't know why, so for now I limit + * size of packets send from ggatec to 32kB by defining MAX_SEND_SIZE + * in ggatec Makefile. + */ +#ifndef MAX_SEND_SIZE +#define MAX_SEND_SIZE MAXPHYS +#endif +ssize_t +g_gate_send(int s, const void *buf, size_t len, int flags) +{ + ssize_t done = 0, done2; + const unsigned char *p = buf; + + while (len > 0) { + done2 = send(s, p, MIN(len, MAX_SEND_SIZE), flags); + if (done2 == 0) + break; + else if (done2 == -1) { + if (errno == EAGAIN) { + printf("%s: EAGAIN\n", __func__); + continue; + } + done = -1; + break; + } + done += done2; + p += done2; + len -= done2; + } + return (done); +} + +ssize_t +g_gate_recv(int s, void *buf, size_t len, int flags) +{ + ssize_t done; + + do { + done = recv(s, buf, len, flags); + } while (done == -1 && errno == EAGAIN); + return (done); +} + +int nagle = 1; +unsigned rcvbuf = G_GATE_RCVBUF; +unsigned sndbuf = G_GATE_SNDBUF; + +void +g_gate_socket_settings(int sfd) +{ + struct timeval tv; + int bsize, on; + + /* Socket settings. */ + on = 1; + if (nagle) { + if (setsockopt(sfd, IPPROTO_TCP, TCP_NODELAY, &on, + sizeof(on)) == -1) { + g_gate_xlog("setsockopt() error: %s.", strerror(errno)); + } + } + if (setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) == -1) + g_gate_xlog("setsockopt(SO_REUSEADDR): %s.", strerror(errno)); + bsize = rcvbuf; + if (setsockopt(sfd, SOL_SOCKET, SO_RCVBUF, &bsize, sizeof(bsize)) == -1) + g_gate_xlog("setsockopt(SO_RCVBUF): %s.", strerror(errno)); + bsize = sndbuf; + if (setsockopt(sfd, SOL_SOCKET, SO_SNDBUF, &bsize, sizeof(bsize)) == -1) + g_gate_xlog("setsockopt(SO_SNDBUF): %s.", strerror(errno)); + tv.tv_sec = 8; + tv.tv_usec = 0; + if (setsockopt(sfd, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv)) == -1) { + g_gate_log(LOG_ERR, "setsockopt(SO_SNDTIMEO) error: %s.", + strerror(errno)); + } + if (setsockopt(sfd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)) == -1) { + g_gate_log(LOG_ERR, "setsockopt(SO_RCVTIMEO) error: %s.", + strerror(errno)); + } +} + +#ifdef LIBGEOM +static struct gclass * +find_class(struct gmesh *mesh, const char *name) +{ + struct gclass *class; + + LIST_FOREACH(class, &mesh->lg_class, lg_class) { + if (strcmp(class->lg_name, name) == 0) + return (class); + } + return (NULL); +} + +static const char * +get_conf(struct ggeom *gp, const char *name) +{ + struct gconfig *conf; + + LIST_FOREACH(conf, &gp->lg_config, lg_config) { + if (strcmp(conf->lg_name, name) == 0) + return (conf->lg_val); + } + return (NULL); +} + +static void +show_config(struct ggeom *gp, int verbose) +{ + struct gprovider *pp; + char buf[5]; + + pp = LIST_FIRST(&gp->lg_provider); + if (pp == NULL) + return; + if (!verbose) { + printf("%s\n", pp->lg_name); + return; + } + printf(" NAME: %s\n", pp->lg_name); + printf(" info: %s\n", get_conf(gp, "info")); + printf(" access: %s\n", get_conf(gp, "access")); + printf(" timeout: %s\n", get_conf(gp, "timeout")); + printf("queue_count: %s\n", get_conf(gp, "queue_count")); + printf(" queue_size: %s\n", get_conf(gp, "queue_size")); + printf(" references: %s\n", get_conf(gp, "ref")); + humanize_number(buf, sizeof(buf), (int64_t)pp->lg_mediasize, "", + HN_AUTOSCALE, HN_B | HN_NOSPACE | HN_DECIMAL); + printf(" mediasize: %jd (%s)\n", (intmax_t)pp->lg_mediasize, buf); + printf(" sectorsize: %u\n", pp->lg_sectorsize); + printf(" mode: %s\n", pp->lg_mode); + printf("\n"); +} + +void +g_gate_list(int unit, int verbose) +{ + struct gmesh mesh; + struct gclass *class; + struct ggeom *gp; + char name[64]; + int error; + + error = geom_gettree(&mesh); + if (error != 0) + exit(EXIT_FAILURE); + class = find_class(&mesh, G_GATE_CLASS_NAME); + if (class == NULL) { + geom_deletetree(&mesh); + exit(EXIT_SUCCESS); + } + if (unit >= 0) { + snprintf(name, sizeof(name), "%s%d", G_GATE_PROVIDER_NAME, + unit); + } + LIST_FOREACH(gp, &class->lg_geom, lg_geom) { + if (unit != -1 && strcmp(gp->lg_name, name) != 0) + continue; + show_config(gp, verbose); + } + geom_deletetree(&mesh); + exit(EXIT_SUCCESS); +} +#endif /* LIBGEOM */ + +in_addr_t +g_gate_str2ip(const char *str) +{ + struct hostent *hp; + in_addr_t ip; + + ip = inet_addr(str); + if (ip != INADDR_NONE) { + /* It is a valid IP address. */ + return (ip); + } + /* Check if it is a valid host name. */ + hp = gethostbyname(str); + if (hp == NULL) + return (INADDR_NONE); + return (((struct in_addr *)(void *)hp->h_addr)->s_addr); +} diff --git a/shared/ggate.h b/shared/ggate.h new file mode 100644 index 0000000..898efea --- /dev/null +++ b/shared/ggate.h @@ -0,0 +1,196 @@ +/*- + * 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$ + */ + +#ifndef _GGATE_H_ +#define _GGATE_H_ + +#include +#include + +#define G_GATE_PORT 3080 + +#define G_GATE_RCVBUF 131072 +#define G_GATE_SNDBUF 131072 +#define G_GATE_QUEUE_SIZE 1024 +#define G_GATE_TIMEOUT 0 + +#define GGATE_MAGIC "GEOM_GATE " +#define GGATE_VERSION 0 + +#define GGATE_FLAG_RDONLY 0x0001 +#define GGATE_FLAG_WRONLY 0x0002 +/* + * If GGATE_FLAG_SEND not GGATE_FLAG_RECV flag is set, this is initial + * connection. + * If GGATE_FLAG_SEND flag is set - this is socket to send data. + * If GGATE_FLAG_RECV flag is set - this is socket to receive data. + */ +#define GGATE_FLAG_SEND 0x0004 +#define GGATE_FLAG_RECV 0x0008 + +#define GGATE_CMD_READ 0 +#define GGATE_CMD_WRITE 1 + +extern int g_gate_devfd; +extern int g_gate_verbose; + +extern int nagle; +extern unsigned rcvbuf, sndbuf; + +struct g_gate_version { + char gv_magic[16]; + uint16_t gv_version; + uint16_t gv_error; +} __packed; + +/* Client's initial packet. */ +struct g_gate_cinit { + char gc_path[PATH_MAX + 1]; + uint64_t gc_flags; + uint16_t gc_nconn; + uint32_t gc_token; +} __packed; + +/* Server's initial packet. */ +struct g_gate_sinit { + uint8_t gs_flags; + uint64_t gs_mediasize; + uint32_t gs_sectorsize; + uint16_t gs_error; +} __packed; + +/* Control struct. */ +struct g_gate_hdr { + uint8_t gh_cmd; /* command */ + uint64_t gh_offset; /* device offset */ + uint32_t gh_length; /* size of block */ + uint64_t gh_seq; /* request number */ + uint16_t gh_error; /* error value (0 if ok) */ +} __packed; + +void g_gate_vlog(int priority, const char *message, va_list ap); +void g_gate_log(int priority, const char *message, ...); +void g_gate_xvlog(const char *message, va_list ap) __dead2; +void g_gate_xlog(const char *message, ...) __dead2; +off_t g_gate_mediasize(int fd); +unsigned g_gate_sectorsize(int fd); +void g_gate_open_device(void); +void g_gate_close_device(void); +void g_gate_ioctl(unsigned long req, void *data); +void g_gate_destroy(int unit, int force); +void g_gate_load_module(void); +ssize_t g_gate_recv(int s, void *buf, size_t len, int flags); +ssize_t g_gate_send(int s, const void *buf, size_t len, int flags); +void g_gate_socket_settings(int sfd); +#ifdef LIBGEOM +void g_gate_list(int unit, int verbose); +#endif +in_addr_t g_gate_str2ip(const char *str); + +/* + * g_gate_swap2h_* - functions swap bytes to host byte order (from big endian). + * g_gate_swap2n_* - functions swap bytes to network byte order (actually + * to big endian byte order). + */ + +static __inline void +g_gate_swap2h_version(struct g_gate_version *ver) +{ + + ver->gv_version = be16toh(ver->gv_version); + ver->gv_error = be16toh(ver->gv_error); +} + +static __inline void +g_gate_swap2n_version(struct g_gate_version *ver) +{ + + ver->gv_version = htobe16(ver->gv_version); + ver->gv_error = htobe16(ver->gv_error); +} + +static __inline void +g_gate_swap2h_cinit(struct g_gate_cinit *cinit) +{ + + cinit->gc_flags = be64toh(cinit->gc_flags); + cinit->gc_nconn = be16toh(cinit->gc_nconn); + cinit->gc_token = be32toh(cinit->gc_token); +} + +static __inline void +g_gate_swap2n_cinit(struct g_gate_cinit *cinit) +{ + + cinit->gc_flags = htobe64(cinit->gc_flags); + cinit->gc_nconn = htobe16(cinit->gc_nconn); + cinit->gc_token = htobe32(cinit->gc_token); +} + +static __inline void +g_gate_swap2h_sinit(struct g_gate_sinit *sinit) +{ + + /* Swap only used fields. */ + sinit->gs_mediasize = be64toh(sinit->gs_mediasize); + sinit->gs_sectorsize = be32toh(sinit->gs_sectorsize); + sinit->gs_error = be16toh(sinit->gs_error); +} + +static __inline void +g_gate_swap2n_sinit(struct g_gate_sinit *sinit) +{ + + /* Swap only used fields. */ + sinit->gs_mediasize = htobe64(sinit->gs_mediasize); + sinit->gs_sectorsize = htobe32(sinit->gs_sectorsize); + sinit->gs_error = htobe16(sinit->gs_error); +} + +static __inline void +g_gate_swap2h_hdr(struct g_gate_hdr *hdr) +{ + + /* Swap only used fields. */ + hdr->gh_offset = be64toh(hdr->gh_offset); + hdr->gh_length = be32toh(hdr->gh_length); + hdr->gh_seq = be64toh(hdr->gh_seq); + hdr->gh_error = be16toh(hdr->gh_error); +} + +static __inline void +g_gate_swap2n_hdr(struct g_gate_hdr *hdr) +{ + + /* Swap only used fields. */ + hdr->gh_offset = htobe64(hdr->gh_offset); + hdr->gh_length = htobe32(hdr->gh_length); + hdr->gh_seq = htobe64(hdr->gh_seq); + hdr->gh_error = htobe16(hdr->gh_error); +} +#endif /* _GGATE_H_ */