#include <sys/types.h>
#include <sys/mount.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <vfs/hammer2/hammer2_mount.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <dmsg.h>
#include <mntopts.h>
static int cluster_connect(const char *volume);
static void usage(const char *ctl, ...);
static struct mntopt mopts[] = {
MOPT_STDOPTS,
MOPT_UPDATE,
{ "local", 0, HMNT2_LOCAL, 1 },
MOPT_NULL
};
int
main(int ac, char *av[])
{
struct hammer2_mount_info info;
struct vfsconf vfc;
char *mountpt;
char *devpath;
int error;
int ch;
int mount_flags;
int init_flags;
bzero(&info, sizeof(info));
mount_flags = 0;
init_flags = 0;
while ((ch = getopt(ac, av, "o:u")) != -1) {
switch(ch) {
case 'o':
getmntopts(optarg, mopts, &mount_flags, &info.hflags);
break;
case 'u':
init_flags |= MNT_UPDATE;
break;
default:
usage("unknown option: -%c", ch);
}
}
ac -= optind;
av += optind;
mount_flags |= init_flags;
error = getvfsbyname("hammer2", &vfc);
if (error) {
fprintf(stderr, "hammer2 vfs not loaded\n");
exit(1);
}
if (init_flags & MNT_UPDATE) {
if (ac != 1) {
usage("missing parameter (node)");
}
mountpt = av[0];
if (mount(vfc.vfc_name, mountpt, mount_flags, &info))
usage("mount %s: %s", mountpt, strerror(errno));
exit(0);
}
if (ac != 2) {
usage("missing parameter(s) (special[@label] node)");
}
devpath = strdup(av[0]);
mountpt = av[1];
if (devpath[0] == 0) {
fprintf(stderr, "mount_hammer2: empty device path\n");
exit(1);
}
if (strchr(devpath, '@') == NULL) {
char slice = devpath[strlen(devpath)-1];
switch(slice) {
case 'a':
asprintf(&devpath, "%s@BOOT", devpath);
break;
case 'd':
asprintf(&devpath, "%s@ROOT", devpath);
break;
default:
asprintf(&devpath, "%s@DATA", devpath);
break;
}
}
info.cluster_fd = cluster_connect(devpath);
if (info.cluster_fd < 0) {
fprintf(stderr,
"mount_hammer2: cluster_connect(%s) failed\n",
devpath);
}
if (!strchr(devpath, ':') && devpath[0] != '/' && devpath[0] != '@') {
char *p2;
asprintf(&p2, "/dev/%s", devpath);
free(devpath);
devpath = p2;
}
info.volume = devpath;
error = mount(vfc.vfc_name, mountpt, mount_flags, &info);
if (error < 0) {
if (errno == ERANGE) {
fprintf(stderr,
"mount_hammer2: %s integrated with %s\n",
info.volume, mountpt);
} else if (errno == ENOENT) {
fprintf(stderr, "mount_hammer2: %s not found\n",
info.volume);
} else if (errno == ENXIO) {
fprintf(stderr, "mount_hammer2: incorrect volume "
"specification %s\n",
info.volume);
} else {
perror("mount");
}
exit(1);
}
free(devpath);
return (0);
}
static
int
cluster_connect(const char *volume __unused)
{
struct sockaddr_in lsin;
int fd;
system("/sbin/hammer2 -q service");
if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
perror("socket");
return(-1);
}
bzero(&lsin, sizeof(lsin));
lsin.sin_family = AF_INET;
lsin.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
lsin.sin_port = htons(DMSG_LISTEN_PORT);
if (connect(fd, (struct sockaddr *)&lsin, sizeof(lsin)) < 0) {
close(fd);
fprintf(stderr, "mount_hammer2: unable to connect to "
"cluster controller\n");
return(-1);
}
return(fd);
}
static
void
usage(const char *ctl, ...)
{
va_list va;
va_start(va, ctl);
fprintf(stderr, "mount_hammer2: ");
vfprintf(stderr, ctl, va);
va_end(va);
fprintf(stderr, "\n");
fprintf(stderr, " mount_hammer2 [-o options] special[@label] node\n");
fprintf(stderr, " mount_hammer2 [-o options] @label node\n");
fprintf(stderr, " mount_hammer2 -u [-o options] node\n");
fprintf(stderr, "\n");
fprintf(stderr, "options:\n"
" <standard_mount_options>\n"
" local\t- disable PFS clustering for whole device\n"
);
exit(1);
}