Browse Source

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
tags/ggatessh-v1.0.0
gjb 10 years ago
parent
commit
ae15d2594a
13 changed files with 3133 additions and 0 deletions
  1. +14
    -0
      Makefile
  2. +3
    -0
      Makefile.inc
  3. +16
    -0
      ggatec/Makefile
  4. +181
    -0
      ggatec/ggatec.8
  5. +642
    -0
      ggatec/ggatec.c
  6. +14
    -0
      ggated/Makefile
  7. +111
    -0
      ggated/ggated.8
  8. +1050
    -0
      ggated/ggated.c
  9. +15
    -0
      ggatel/Makefile
  10. +155
    -0
      ggatel/ggatel.8
  11. +327
    -0
      ggatel/ggatel.c
  12. +409
    -0
      shared/ggate.c
  13. +196
    -0
      shared/ggate.h

+ 14
- 0
Makefile View File

@@ -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>

+ 3
- 0
Makefile.inc View File

@@ -0,0 +1,3 @@
# $FreeBSD$

.include "../Makefile.inc"

+ 16
- 0
ggatec/Makefile View File

@@ -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>

+ 181
- 0
ggatec/ggatec.8 View File

@@ -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 .

+ 642
- 0
ggatec/ggatec.c View File

@@ -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);
}

+ 14
- 0
ggated/Makefile View File

@@ -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>

+ 111
- 0
ggated/ggated.8 View File

@@ -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 .

+ 1050
- 0
ggated/ggated.c
File diff suppressed because it is too large
View File


+ 15
- 0
ggatel/Makefile View File

@@ -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>

+ 155
- 0
ggatel/ggatel.8 View File

@@ -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 .

+ 327
- 0
ggatel/ggatel.c View File

@@ -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);
}

+ 409
- 0
shared/ggate.c View File

@@ -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);
}

+ 196
- 0
shared/ggate.h View File

@@ -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_ */

Loading…
Cancel
Save