^/user/gjb/hacking since this is likely to be merged to head/ soon. Sponsored by: The FreeBSD Foundationtags/ggatessh-v1.0.0
| @@ -0,0 +1,14 @@ | |||||
| # $FreeBSD$ | |||||
| .include <bsd.own.mk> | |||||
| SUBDIR= ${_ggatec} \ | |||||
| ${_ggated} \ | |||||
| ggatel | |||||
| .if ${MK_LIBTHR} != "no" | |||||
| _ggatec= ggatec | |||||
| _ggated= ggated | |||||
| .endif | |||||
| .include <bsd.subdir.mk> | |||||
| @@ -0,0 +1,3 @@ | |||||
| # $FreeBSD$ | |||||
| .include "../Makefile.inc" | |||||
| @@ -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 <bsd.prog.mk> | |||||
| @@ -0,0 +1,181 @@ | |||||
| .\" Copyright (c) 2004 Pawel Jakub Dawidek <pjd@FreeBSD.org> | |||||
| .\" 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 . | |||||
| @@ -0,0 +1,642 @@ | |||||
| /*- | |||||
| * Copyright (c) 2004 Pawel Jakub Dawidek <pjd@FreeBSD.org> | |||||
| * 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 <stdio.h> | |||||
| #include <stdlib.h> | |||||
| #include <stdint.h> | |||||
| #include <fcntl.h> | |||||
| #include <unistd.h> | |||||
| #include <string.h> | |||||
| #include <ctype.h> | |||||
| #include <libgen.h> | |||||
| #include <pthread.h> | |||||
| #include <signal.h> | |||||
| #include <err.h> | |||||
| #include <errno.h> | |||||
| #include <assert.h> | |||||
| #include <sys/param.h> | |||||
| #include <sys/ioctl.h> | |||||
| #include <sys/socket.h> | |||||
| #include <sys/sysctl.h> | |||||
| #include <sys/syslog.h> | |||||
| #include <sys/time.h> | |||||
| #include <sys/bio.h> | |||||
| #include <netinet/in.h> | |||||
| #include <netinet/tcp.h> | |||||
| #include <arpa/inet.h> | |||||
| #include <geom/gate/g_gate.h> | |||||
| #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 <ro|wo|rw>] [-p port] " | |||||
| "[-q queue_size] [-R rcvbuf] [-S sndbuf] [-s sectorsize] " | |||||
| "[-t timeout] [-u unit] <host> <path>\n", getprogname()); | |||||
| fprintf(stderr, " %s rescue [-nv] [-o <ro|wo|rw>] [-p port] " | |||||
| "[-R rcvbuf] [-S sndbuf] <-u unit> <host> <path>\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); | |||||
| } | |||||
| @@ -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 <bsd.prog.mk> | |||||
| @@ -0,0 +1,111 @@ | |||||
| .\" Copyright (c) 2004 Pawel Jakub Dawidek <pjd@FreeBSD.org> | |||||
| .\" 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 . | |||||
| @@ -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 <bsd.prog.mk> | |||||
| @@ -0,0 +1,155 @@ | |||||
| .\" Copyright (c) 2004 Pawel Jakub Dawidek <pjd@FreeBSD.org> | |||||
| .\" 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 . | |||||
| @@ -0,0 +1,327 @@ | |||||
| /*- | |||||
| * Copyright (c) 2004 Pawel Jakub Dawidek <pjd@FreeBSD.org> | |||||
| * 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 <stdio.h> | |||||
| #include <stdlib.h> | |||||
| #include <stdint.h> | |||||
| #include <fcntl.h> | |||||
| #include <unistd.h> | |||||
| #include <string.h> | |||||
| #include <err.h> | |||||
| #include <errno.h> | |||||
| #include <assert.h> | |||||
| #include <sys/param.h> | |||||
| #include <sys/time.h> | |||||
| #include <sys/bio.h> | |||||
| #include <sys/disk.h> | |||||
| #include <sys/ioctl.h> | |||||
| #include <sys/stat.h> | |||||
| #include <sys/syslog.h> | |||||
| #include <geom/gate/g_gate.h> | |||||
| #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 <ro|wo|rw>] " | |||||
| "[-s sectorsize] [-t timeout] [-u unit] <path>\n", getprogname()); | |||||
| fprintf(stderr, " %s rescue [-v] [-o <ro|wo|rw>] <-u unit> " | |||||
| "<path>\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); | |||||
| } | |||||
| @@ -0,0 +1,409 @@ | |||||
| /*- | |||||
| * Copyright (c) 2004 Pawel Jakub Dawidek <pjd@FreeBSD.org> | |||||
| * 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 <stdio.h> | |||||
| #include <stdlib.h> | |||||
| #include <unistd.h> | |||||
| #include <fcntl.h> | |||||
| #include <sys/param.h> | |||||
| #include <sys/disk.h> | |||||
| #include <sys/stat.h> | |||||
| #include <sys/endian.h> | |||||
| #include <sys/socket.h> | |||||
| #include <sys/linker.h> | |||||
| #include <sys/module.h> | |||||
| #include <netinet/in.h> | |||||
| #include <netinet/tcp.h> | |||||
| #include <arpa/inet.h> | |||||
| #include <signal.h> | |||||
| #include <err.h> | |||||
| #include <errno.h> | |||||
| #include <string.h> | |||||
| #include <strings.h> | |||||
| #include <libgen.h> | |||||
| #include <libutil.h> | |||||
| #include <netdb.h> | |||||
| #include <syslog.h> | |||||
| #include <stdarg.h> | |||||
| #include <stdint.h> | |||||
| #include <libgeom.h> | |||||
| #include <geom/gate/g_gate.h> | |||||
| #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); | |||||
| } | |||||
| @@ -0,0 +1,196 @@ | |||||
| /*- | |||||
| * Copyright (c) 2004 Pawel Jakub Dawidek <pjd@FreeBSD.org> | |||||
| * 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 <sys/endian.h> | |||||
| #include <stdarg.h> | |||||
| #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_ */ | |||||