freebsd-nq/sbin/ggate/shared/ggate.c
2004-09-08 07:57:14 +00:00

336 lines
7.3 KiB
C

/*-
* 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 <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);
}
size_t
g_gate_sectorsize(int fd)
{
size_t 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, 0);
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);
}
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") == -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!");
}
}
}
}
#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);
}