|
|
@@ -0,0 +1,330 @@ |
|
|
|
/*- |
|
|
|
* 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 <arpa/inet.h> |
|
|
|
#include <signal.h> |
|
|
|
#include <err.h> |
|
|
|
#include <errno.h> |
|
|
|
#include <string.h> |
|
|
|
#include <strings.h> |
|
|
|
#include <libgen.h> |
|
|
|
#include <netdb.h> |
|
|
|
#include <syslog.h> |
|
|
|
#include <stdarg.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) < 0) |
|
|
|
g_gate_xlog("fstat(): %s.", strerror(errno)); |
|
|
|
if (S_ISCHR(sb.st_mode)) { |
|
|
|
if (ioctl(fd, DIOCGMEDIASIZE, &mediasize) < 0) { |
|
|
|
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); |
|
|
|
} |
|
|
|
|
|
|
|
size_t |
|
|
|
g_gate_sectorsize(int fd) |
|
|
|
{ |
|
|
|
size_t secsize; |
|
|
|
struct stat sb; |
|
|
|
|
|
|
|
if (fstat(fd, &sb) < 0) |
|
|
|
g_gate_xlog("fstat(): %s.", strerror(errno)); |
|
|
|
if (S_ISCHR(sb.st_mode)) { |
|
|
|
if (ioctl(fd, DIOCGSECTORSIZE, &secsize) < 0) { |
|
|
|
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, 0); |
|
|
|
if (g_gate_devfd < 0) |
|
|
|
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) < 0) { |
|
|
|
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); |
|
|
|
} |
|
|
|
|
|
|
|
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); |
|
|
|
} |
|
|
|
|
|
|
|
void |
|
|
|
g_gate_load_module(void) |
|
|
|
{ |
|
|
|
|
|
|
|
if (modfind("g_gate") < 0) { |
|
|
|
/* Not present in kernel, try loading it. */ |
|
|
|
if (kldload("geom_gate") < 0 || modfind("g_gate") < 0) { |
|
|
|
if (errno != EEXIST) { |
|
|
|
errx(EXIT_FAILURE, |
|
|
|
"geom_gate module not available!"); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
#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; |
|
|
|
|
|
|
|
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")); |
|
|
|
printf(" mediasize: %jd\n", pp->lg_mediasize); |
|
|
|
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 *)(hp->h_addr))->s_addr); |
|
|
|
} |