perfused(8) creates a /dev/fuse socket and performs PUFFS to FUSE relaying.
This is still a work in progress.
This commit is contained in:
parent
7b1d1ee680
commit
a18d4c5a69
|
@ -0,0 +1,13 @@
|
||||||
|
PROG= perfused
|
||||||
|
|
||||||
|
PERFUSE_OPT_DEBUG_FLAGS= -g -DPERFUSE_DEBUG
|
||||||
|
|
||||||
|
CFLAGS= ${PERFUSE_OPT_DEBUG_FLAGS}
|
||||||
|
SRCS= perfused.c msg.c debug.c
|
||||||
|
MAN= perfused.8
|
||||||
|
WARNS= 4
|
||||||
|
|
||||||
|
LDADD+= -lperfuse -lpuffs #-L/usr/pkg/lib -lefence
|
||||||
|
DPADD+= ${LIBPUFFS}
|
||||||
|
|
||||||
|
.include <bsd.prog.mk>
|
|
@ -0,0 +1,74 @@
|
||||||
|
/* $NetBSD: debug.c,v 1.1 2010/08/25 07:18:01 manu Exp $ */
|
||||||
|
|
||||||
|
/*-
|
||||||
|
* Copyright (c) 2010 Emmanuel Dreyfus. 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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.
|
||||||
|
*/
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <ctype.h>
|
||||||
|
|
||||||
|
#include "perfused.h"
|
||||||
|
|
||||||
|
#ifdef PERFUSE_DEBUG
|
||||||
|
void
|
||||||
|
perfuse_hexdump(addr, len)
|
||||||
|
char *addr;
|
||||||
|
size_t len;
|
||||||
|
{
|
||||||
|
unsigned int i, j, k;
|
||||||
|
|
||||||
|
for (i = 0; i < len; i += 16) {
|
||||||
|
DPRINTF("%p ", &addr[i]);
|
||||||
|
for (j = 0; j < 16; j += 4) {
|
||||||
|
for (k = 0; k < 4; k++) {
|
||||||
|
if (i + j + k < len) {
|
||||||
|
DPRINTF("%02x ",
|
||||||
|
*(addr + i + j + k) & 0xff);
|
||||||
|
} else {
|
||||||
|
DPRINTF(" ");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DPRINTF(" ");
|
||||||
|
for (j = 0; j < 16; j++) {
|
||||||
|
char c;
|
||||||
|
|
||||||
|
if (i + j < len) {
|
||||||
|
c = *(addr + i + j);
|
||||||
|
DPRINTF("%c", isprint((int)c) ? c : '.');
|
||||||
|
} else {
|
||||||
|
DPRINTF(" ");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
DPRINTF("\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#endif /* PERFUSE_DEBUG */
|
|
@ -0,0 +1,599 @@
|
||||||
|
/* $NetBSD: msg.c,v 1.1 2010/08/25 07:18:01 manu Exp $ */
|
||||||
|
|
||||||
|
/*-
|
||||||
|
* Copyright (c) 2010 Emmanuel Dreyfus. 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <err.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <sysexits.h>
|
||||||
|
#include <syslog.h>
|
||||||
|
#include <paths.h>
|
||||||
|
#include <puffs.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <sys/un.h>
|
||||||
|
#include <machine/vmparam.h>
|
||||||
|
|
||||||
|
#include "../../lib/libperfuse/perfuse_if.h"
|
||||||
|
#include "perfused.h"
|
||||||
|
|
||||||
|
static int xchg_pb_inloop(struct puffs_usermount *a, struct puffs_framebuf *,
|
||||||
|
int, enum perfuse_xchg_pb_reply);
|
||||||
|
static int xchg_pb_early(struct puffs_usermount *a, struct puffs_framebuf *,
|
||||||
|
int, enum perfuse_xchg_pb_reply);
|
||||||
|
|
||||||
|
int
|
||||||
|
perfuse_open_sock(void)
|
||||||
|
{
|
||||||
|
int s;
|
||||||
|
struct sockaddr_un sun;
|
||||||
|
const struct sockaddr *sa;
|
||||||
|
|
||||||
|
(void)unlink(_PATH_FUSE);
|
||||||
|
|
||||||
|
if ((s = socket(AF_LOCAL, SOCK_STREAM, 0)) == -1)
|
||||||
|
err(EX_OSERR, "socket failed");
|
||||||
|
|
||||||
|
sa = (const struct sockaddr *)(void *)&sun;
|
||||||
|
sun.sun_len = sizeof(sun);
|
||||||
|
sun.sun_family = AF_LOCAL;
|
||||||
|
(void)strcpy(sun.sun_path, _PATH_FUSE);
|
||||||
|
|
||||||
|
if (bind(s, sa, (socklen_t )sun.sun_len) == -1)
|
||||||
|
err(EX_OSERR, "cannot open \"%s\" socket", _PATH_FUSE);
|
||||||
|
|
||||||
|
if (listen(s, 1) == -1)
|
||||||
|
err(EX_OSERR, "listen failed");
|
||||||
|
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void *
|
||||||
|
perfuse_recv_early(fd, len)
|
||||||
|
int fd;
|
||||||
|
size_t len;
|
||||||
|
{
|
||||||
|
char *buf;
|
||||||
|
|
||||||
|
if (len == 0)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
if ((buf = malloc(len + 1)) == NULL)
|
||||||
|
err(EX_OSERR, "malloc(%d) failed", len);
|
||||||
|
|
||||||
|
if (read(fd, buf, len) != len) {
|
||||||
|
DWARN("short read");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
buf[len] = '\0';
|
||||||
|
return buf;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
perfuse_msg_t *
|
||||||
|
perfuse_new_pb (pu, opc, opcode, payload_len, cred)
|
||||||
|
struct puffs_usermount *pu;
|
||||||
|
puffs_cookie_t opc;
|
||||||
|
int opcode;
|
||||||
|
size_t payload_len;
|
||||||
|
const struct puffs_cred *cred;
|
||||||
|
{
|
||||||
|
struct puffs_framebuf *pb;
|
||||||
|
struct fuse_in_header *fih;
|
||||||
|
struct puffs_cc *pcc;
|
||||||
|
uint64_t nodeid;
|
||||||
|
void *data;
|
||||||
|
size_t len;
|
||||||
|
|
||||||
|
if ((pb = puffs_framebuf_make()) == NULL)
|
||||||
|
DERR(EX_OSERR, "puffs_framebuf_make failed");
|
||||||
|
|
||||||
|
len = payload_len + sizeof(*fih);
|
||||||
|
nodeid = (opc != 0) ? perfuse_get_ino(pu, opc) : PERFUSE_UNKNOWN_INO;
|
||||||
|
|
||||||
|
if (puffs_framebuf_reserve_space(pb, len) != 0)
|
||||||
|
DERR(EX_OSERR, "puffs_framebuf_reserve_space failed");
|
||||||
|
|
||||||
|
if (puffs_framebuf_getwindow(pb, 0, &data, &len) != 0)
|
||||||
|
DERR(EX_SOFTWARE, "puffs_framebuf_getwindow failed");
|
||||||
|
if (len != payload_len + sizeof(*fih))
|
||||||
|
DERR(EX_SOFTWARE, "puffs_framebuf_getwindow short len");
|
||||||
|
|
||||||
|
(void)memset(data, 0, len);
|
||||||
|
fih = (struct fuse_in_header *)data;
|
||||||
|
fih->len = len;
|
||||||
|
fih->opcode = opcode;
|
||||||
|
fih->unique = perfuse_next_unique(pu);
|
||||||
|
fih->nodeid = nodeid;
|
||||||
|
fih->uid = (uid_t)-1;
|
||||||
|
fih->gid = (gid_t)-1;
|
||||||
|
fih->pid = 0;
|
||||||
|
if (cred != NULL) {
|
||||||
|
(void)puffs_cred_getuid(cred, &fih->uid);
|
||||||
|
(void)puffs_cred_getuid(cred, &fih->uid);
|
||||||
|
}
|
||||||
|
if ((pcc = puffs_cc_getcc(pu)) != NULL)
|
||||||
|
(void)puffs_cc_getcaller(pcc, (pid_t *)&fih->pid, NULL);
|
||||||
|
|
||||||
|
return (perfuse_msg_t *)(void *)pb;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* framebuf send/receive primitives based on pcc are
|
||||||
|
* not available until puffs mainloop is entered.
|
||||||
|
* This xchg_pb_inloop() variant allow early communication.
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
xchg_pb_early(pu, pb, fd, reply)
|
||||||
|
struct puffs_usermount *pu;
|
||||||
|
struct puffs_framebuf *pb;
|
||||||
|
int fd;
|
||||||
|
enum perfuse_xchg_pb_reply reply;
|
||||||
|
{
|
||||||
|
int done;
|
||||||
|
int error;
|
||||||
|
|
||||||
|
done = 0;
|
||||||
|
while (done == 0) {
|
||||||
|
if ((error = perfuse_writeframe(pu, pb, fd, &done)) != 0)
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (reply == no_reply) {
|
||||||
|
puffs_framebuf_destroy(pb);
|
||||||
|
return 0;
|
||||||
|
} else {
|
||||||
|
puffs_framebuf_recycle(pb);
|
||||||
|
}
|
||||||
|
|
||||||
|
done = 0;
|
||||||
|
while (done == 0) {
|
||||||
|
if ((error = perfuse_readframe(pu, pb, fd, &done)) != 0)
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
xchg_pb_inloop(pu, pb, fd, reply)
|
||||||
|
struct puffs_usermount *pu;
|
||||||
|
struct puffs_framebuf *pb;
|
||||||
|
int fd;
|
||||||
|
enum perfuse_xchg_pb_reply reply;
|
||||||
|
{
|
||||||
|
struct puffs_cc *pcc;
|
||||||
|
int error;
|
||||||
|
|
||||||
|
if (reply == no_reply) {
|
||||||
|
error = puffs_framev_enqueue_justsend(pu, fd, pb, 0, 0);
|
||||||
|
} else {
|
||||||
|
pcc = puffs_cc_getcc(pu);
|
||||||
|
error = puffs_framev_enqueue_cc(pcc, fd, pb, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
perfuse_xchg_pb(pu, pm, expected_len, reply)
|
||||||
|
struct puffs_usermount *pu;
|
||||||
|
perfuse_msg_t *pm;
|
||||||
|
size_t expected_len;
|
||||||
|
enum perfuse_xchg_pb_reply reply;
|
||||||
|
{
|
||||||
|
struct puffs_framebuf *pb = (struct puffs_framebuf *)(void *)pm;
|
||||||
|
int fd;
|
||||||
|
int error;
|
||||||
|
struct fuse_out_header *foh;
|
||||||
|
#ifdef PERFUSE_DEBUG
|
||||||
|
struct fuse_in_header *fih;
|
||||||
|
uint64_t nodeid;
|
||||||
|
int opcode;
|
||||||
|
uint64_t unique_in;
|
||||||
|
uint64_t unique_out;
|
||||||
|
|
||||||
|
fih = perfuse_get_inhdr(pm);
|
||||||
|
unique_in = fih->unique;
|
||||||
|
nodeid = fih->nodeid;
|
||||||
|
opcode = fih->opcode;
|
||||||
|
|
||||||
|
if (perfuse_diagflags & PDF_FUSE)
|
||||||
|
DPRINTF("> unique = %lld, nodeid = %lld, opcode = %s (%d)\n",
|
||||||
|
unique_in, nodeid, perfuse_opname(opcode), opcode);
|
||||||
|
|
||||||
|
if (perfuse_diagflags & PDF_DUMP)
|
||||||
|
perfuse_hexdump((char *)fih, fih->len);
|
||||||
|
|
||||||
|
#endif /* PERFUSE_DEBUG */
|
||||||
|
|
||||||
|
fd = (int)perfuse_getspecific(pu);
|
||||||
|
|
||||||
|
if (perfuse_inloop(pu))
|
||||||
|
error = xchg_pb_inloop(pu, pb, fd, reply);
|
||||||
|
else
|
||||||
|
error = xchg_pb_early(pu, pb, fd, reply);
|
||||||
|
|
||||||
|
if (error)
|
||||||
|
DERR(EX_SOFTWARE, "xchg_pb failed");
|
||||||
|
|
||||||
|
if (reply == no_reply)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
foh = perfuse_get_outhdr((perfuse_msg_t *)(void *)pb);
|
||||||
|
#ifdef PERFUSE_DEBUG
|
||||||
|
unique_out = foh->unique;
|
||||||
|
|
||||||
|
if (perfuse_diagflags & PDF_FUSE)
|
||||||
|
DPRINTF("< unique = %lld, nodeid = %lld, opcode = %s (%d), "
|
||||||
|
"error = %d\n", unique_out, nodeid,
|
||||||
|
perfuse_opname(opcode), opcode, error);
|
||||||
|
|
||||||
|
if (perfuse_diagflags & PDF_DUMP)
|
||||||
|
perfuse_hexdump((char *)foh, foh->len);
|
||||||
|
|
||||||
|
if (unique_in != unique_out) {
|
||||||
|
printf("%s: packet mismatch unique %lld vs %lld\n",
|
||||||
|
__func__, unique_in, unique_out);
|
||||||
|
abort();
|
||||||
|
errx(EX_SOFTWARE, "%s: packet mismatch unique %lld vs %lld\n",
|
||||||
|
__func__, unique_in, unique_out);
|
||||||
|
}
|
||||||
|
#endif /* PERFUSE_DEBUG */
|
||||||
|
|
||||||
|
if ((expected_len != PERFUSE_UNSPEC_REPLY_LEN) &&
|
||||||
|
(foh->len - sizeof(*foh) < expected_len) &&
|
||||||
|
(foh->error == 0)) {
|
||||||
|
DERRX(EX_PROTOCOL,
|
||||||
|
"Unexpected short reply: received %d bytes, expected %d",
|
||||||
|
foh->len - sizeof(*foh), expected_len);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((expected_len != 0) &&
|
||||||
|
(foh->len - sizeof(*foh) > expected_len))
|
||||||
|
DWARNX("Unexpected long reply");
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Negative Linux errno...
|
||||||
|
*/
|
||||||
|
foh->error = -foh->error;
|
||||||
|
|
||||||
|
return foh->error;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
struct fuse_in_header *
|
||||||
|
perfuse_get_inhdr(pm)
|
||||||
|
perfuse_msg_t *pm;
|
||||||
|
{
|
||||||
|
struct puffs_framebuf *pb;
|
||||||
|
struct fuse_in_header *fih;
|
||||||
|
void *hdr;
|
||||||
|
size_t len;
|
||||||
|
|
||||||
|
pb = (struct puffs_framebuf *)(void *)pm;
|
||||||
|
len = sizeof(*fih);
|
||||||
|
if (puffs_framebuf_getwindow(pb, 0, &hdr, &len) != 0)
|
||||||
|
DERR(EX_SOFTWARE, "puffs_framebuf_getwindow failed");
|
||||||
|
if (len != sizeof(*fih))
|
||||||
|
DERR(EX_SOFTWARE, "puffs_framebuf_getwindow short header");
|
||||||
|
|
||||||
|
fih = (struct fuse_in_header *)hdr;
|
||||||
|
|
||||||
|
return fih;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct fuse_out_header *
|
||||||
|
perfuse_get_outhdr(pm)
|
||||||
|
perfuse_msg_t *pm;
|
||||||
|
{
|
||||||
|
struct puffs_framebuf *pb;
|
||||||
|
struct fuse_out_header *foh;
|
||||||
|
void *hdr;
|
||||||
|
size_t len;
|
||||||
|
|
||||||
|
pb = (struct puffs_framebuf *)(void *)pm;
|
||||||
|
len = sizeof(*foh);
|
||||||
|
if (puffs_framebuf_getwindow(pb, 0, &hdr, &len) != 0)
|
||||||
|
DERR(EX_SOFTWARE, "puffs_framebuf_getwindow failed");
|
||||||
|
if (len != sizeof(*foh))
|
||||||
|
DERR(EX_SOFTWARE, "puffs_framebuf_getwindow short header");
|
||||||
|
|
||||||
|
foh = (struct fuse_out_header *)hdr;
|
||||||
|
|
||||||
|
return foh;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *
|
||||||
|
perfuse_get_inpayload(pm)
|
||||||
|
perfuse_msg_t *pm;
|
||||||
|
{
|
||||||
|
struct puffs_framebuf *pb;
|
||||||
|
struct fuse_in_header *fih;
|
||||||
|
void *hdr;
|
||||||
|
void *payload;
|
||||||
|
size_t len;
|
||||||
|
|
||||||
|
pb = (struct puffs_framebuf *)(void *)pm;
|
||||||
|
len = sizeof(*fih);
|
||||||
|
if (puffs_framebuf_getwindow(pb, 0, &hdr, &len) != 0)
|
||||||
|
DERR(EX_SOFTWARE, "puffs_framebuf_getwindow failed");
|
||||||
|
if (len != sizeof(*fih))
|
||||||
|
DERR(EX_SOFTWARE, "puffs_framebuf_getwindow short header");
|
||||||
|
|
||||||
|
fih = (struct fuse_in_header *)hdr;
|
||||||
|
|
||||||
|
len = fih->len - sizeof(*fih);
|
||||||
|
if (puffs_framebuf_getwindow(pb, sizeof(*fih), &payload, &len) != 0)
|
||||||
|
DERR(EX_SOFTWARE, "puffs_framebuf_getwindow failed");
|
||||||
|
if (len != fih->len - sizeof(*fih))
|
||||||
|
DERR(EX_SOFTWARE, "puffs_framebuf_getwindow short header");
|
||||||
|
|
||||||
|
return (char *)payload;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *
|
||||||
|
perfuse_get_outpayload(pm)
|
||||||
|
perfuse_msg_t *pm;
|
||||||
|
{
|
||||||
|
struct puffs_framebuf *pb;
|
||||||
|
struct fuse_out_header *foh;
|
||||||
|
void *hdr;
|
||||||
|
void *payload;
|
||||||
|
size_t len;
|
||||||
|
|
||||||
|
pb = (struct puffs_framebuf *)(void *)pm;
|
||||||
|
len = sizeof(*foh);
|
||||||
|
if (puffs_framebuf_getwindow(pb, 0, &hdr, &len) != 0)
|
||||||
|
DERR(EX_SOFTWARE, "puffs_framebuf_getwindow failed");
|
||||||
|
if (len != sizeof(*foh))
|
||||||
|
DERR(EX_SOFTWARE, "puffs_framebuf_getwindow short header");
|
||||||
|
|
||||||
|
foh = (struct fuse_out_header *)hdr;
|
||||||
|
|
||||||
|
len = foh->len - sizeof(*foh);
|
||||||
|
if (puffs_framebuf_getwindow(pb, sizeof(*foh), &payload, &len) != 0)
|
||||||
|
DERR(EX_SOFTWARE, "puffs_framebuf_getwindow failed");
|
||||||
|
if (len != foh->len - sizeof(*foh))
|
||||||
|
DERR(EX_SOFTWARE, "puffs_framebuf_getwindow short header");
|
||||||
|
|
||||||
|
return (char *)payload;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define PUFFS_FRAMEBUF_GETWINDOW(pb, offset, data, len) \
|
||||||
|
do { \
|
||||||
|
int pfg_error; \
|
||||||
|
size_t pfg_len = *(len); \
|
||||||
|
\
|
||||||
|
pfg_error = puffs_framebuf_getwindow(pb, offset, data, len); \
|
||||||
|
if (pfg_error != 0) \
|
||||||
|
DERR(EX_SOFTWARE, "puffs_framebuf_getwindow failed");\
|
||||||
|
\
|
||||||
|
if (*(len) != pfg_len) \
|
||||||
|
DERRX(EX_SOFTWARE, "puffs_framebuf_getwindow size"); \
|
||||||
|
} while (0 /* CONSTCOND */);
|
||||||
|
|
||||||
|
/* ARGSUSED0 */
|
||||||
|
int
|
||||||
|
perfuse_readframe(pu, pufbuf, fd, done)
|
||||||
|
struct puffs_usermount *pu;
|
||||||
|
struct puffs_framebuf *pufbuf;
|
||||||
|
int fd;
|
||||||
|
int *done;
|
||||||
|
{
|
||||||
|
struct fuse_out_header foh;
|
||||||
|
size_t offset;
|
||||||
|
size_t remain;
|
||||||
|
ssize_t readen;
|
||||||
|
void *data;
|
||||||
|
|
||||||
|
offset = puffs_framebuf_telloff(pufbuf);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Read the header
|
||||||
|
*/
|
||||||
|
while (offset < sizeof(foh)) {
|
||||||
|
remain = sizeof(foh) - offset;
|
||||||
|
PUFFS_FRAMEBUF_GETWINDOW(pufbuf, offset, &data, &remain);
|
||||||
|
|
||||||
|
switch (readen = recv(fd, data, remain, MSG_NOSIGNAL)) {
|
||||||
|
case 0:
|
||||||
|
DWARNX("%s: recv retunred 0", __func__);
|
||||||
|
return ECONNRESET;
|
||||||
|
/* NOTREACHED */
|
||||||
|
break;
|
||||||
|
case -1:
|
||||||
|
if (errno == EAGAIN)
|
||||||
|
return 0;
|
||||||
|
DWARN("%s: recv retunred -1", __func__);
|
||||||
|
return errno;
|
||||||
|
/* NOTREACHED */
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
offset += readen;
|
||||||
|
if (puffs_framebuf_seekset(pufbuf, offset) == -1)
|
||||||
|
DERR(EX_OSERR, "puffs_framebuf_seekset failed");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We have a header, get remaing length to read
|
||||||
|
*/
|
||||||
|
if (puffs_framebuf_getdata_atoff(pufbuf, 0, &foh, sizeof(foh)) != 0)
|
||||||
|
DERR(EX_SOFTWARE, "puffs_framebuf_getdata_atoff failed");
|
||||||
|
;
|
||||||
|
#ifdef PERFUSE_DEBUG
|
||||||
|
if (foh.len > FUSE_BUFSIZE)
|
||||||
|
DERRX(EX_SOFTWARE, "%s: foh.len = %d (this is huge!)",
|
||||||
|
__func__, foh.len);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If we have only readen the header so far,
|
||||||
|
* this is time to reserve space.
|
||||||
|
*/
|
||||||
|
remain = foh.len - offset;
|
||||||
|
if (offset == sizeof(foh))
|
||||||
|
if (puffs_framebuf_reserve_space(pufbuf, remain) == -1)
|
||||||
|
DERR(EX_OSERR, "puffs_framebuf_reserve_space failed");
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* And read the remaining data
|
||||||
|
*/
|
||||||
|
while (remain != 0) {
|
||||||
|
PUFFS_FRAMEBUF_GETWINDOW(pufbuf, offset, &data, &remain);
|
||||||
|
|
||||||
|
switch (readen = recv(fd, data, remain, MSG_NOSIGNAL)) {
|
||||||
|
case 0:
|
||||||
|
DWARNX("%s: recv retunred 0", __func__);
|
||||||
|
return ECONNRESET;
|
||||||
|
/* NOTREACHED */
|
||||||
|
break;
|
||||||
|
case -1:
|
||||||
|
if (errno == EAGAIN)
|
||||||
|
return 0;
|
||||||
|
DWARN("%s: recv retunred -1", __func__);
|
||||||
|
return errno;
|
||||||
|
/* NOTREACHED */
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
offset += readen;
|
||||||
|
remain -= readen;
|
||||||
|
|
||||||
|
if (puffs_framebuf_seekset(pufbuf, offset) == -1)
|
||||||
|
DERR(EX_OSERR, "puffs_framebuf_seekset failed");
|
||||||
|
}
|
||||||
|
|
||||||
|
*done = 1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ARGSUSED0 */
|
||||||
|
int
|
||||||
|
perfuse_writeframe(pu, pufbuf, fd, done)
|
||||||
|
struct puffs_usermount *pu;
|
||||||
|
struct puffs_framebuf *pufbuf;
|
||||||
|
int fd;
|
||||||
|
int *done;
|
||||||
|
{
|
||||||
|
size_t offset;
|
||||||
|
size_t len;
|
||||||
|
ssize_t written;
|
||||||
|
size_t remain;
|
||||||
|
void *data;
|
||||||
|
|
||||||
|
offset = puffs_framebuf_telloff(pufbuf);
|
||||||
|
len = puffs_framebuf_tellsize(pufbuf) - offset;
|
||||||
|
remain = len;
|
||||||
|
|
||||||
|
while (remain != 0) {
|
||||||
|
PUFFS_FRAMEBUF_GETWINDOW(pufbuf, offset, &data, &len);
|
||||||
|
|
||||||
|
switch (written = send(fd, data, remain, MSG_NOSIGNAL)) {
|
||||||
|
case 0:
|
||||||
|
DWARNX("%s: send retunred 0", __func__);
|
||||||
|
return ECONNRESET;
|
||||||
|
/* NOTREACHED */
|
||||||
|
break;
|
||||||
|
case -1:
|
||||||
|
if (errno == EAGAIN)
|
||||||
|
return 0;
|
||||||
|
DWARN("%s: send retunred -1", __func__);
|
||||||
|
return errno;
|
||||||
|
/* NOTREACHED */
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
remain -= written;
|
||||||
|
offset += written;
|
||||||
|
|
||||||
|
if (puffs_framebuf_seekset(pufbuf, offset) == -1)
|
||||||
|
DERR(EX_OSERR, "puffs_framebuf_seekset failed");
|
||||||
|
}
|
||||||
|
|
||||||
|
*done = 1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ARGSUSED0 */
|
||||||
|
int
|
||||||
|
perfuse_cmpframe(pu, pb1, pb2, match)
|
||||||
|
struct puffs_usermount *pu;
|
||||||
|
struct puffs_framebuf *pb1;
|
||||||
|
struct puffs_framebuf *pb2;
|
||||||
|
int *match;
|
||||||
|
{
|
||||||
|
struct fuse_in_header *fih;
|
||||||
|
struct fuse_out_header *foh;
|
||||||
|
uint64_t unique_in;
|
||||||
|
uint64_t unique_out;
|
||||||
|
size_t len;
|
||||||
|
|
||||||
|
len = sizeof(*fih);
|
||||||
|
PUFFS_FRAMEBUF_GETWINDOW(pb1, 0, (void **)&fih, &len);
|
||||||
|
unique_in = fih->unique;
|
||||||
|
|
||||||
|
len = sizeof(*foh);
|
||||||
|
PUFFS_FRAMEBUF_GETWINDOW(pb2, 0, (void **)&foh, &len);
|
||||||
|
unique_out = foh->unique;
|
||||||
|
|
||||||
|
return unique_in != unique_out;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ARGSUSED0 */
|
||||||
|
void
|
||||||
|
perfuse_gotframe(pu, pb)
|
||||||
|
struct puffs_usermount *pu;
|
||||||
|
struct puffs_framebuf *pb;
|
||||||
|
{
|
||||||
|
struct fuse_out_header *foh;
|
||||||
|
size_t len;
|
||||||
|
|
||||||
|
len = sizeof(*foh);
|
||||||
|
PUFFS_FRAMEBUF_GETWINDOW(pb, 0, (void **)&foh, &len);
|
||||||
|
|
||||||
|
DWARNX("Unexpected frame: unique = %lld, error = %d",
|
||||||
|
foh->unique, foh->error);
|
||||||
|
#ifdef PERFUSE_DEBUG
|
||||||
|
perfuse_hexdump((char *)(void *)foh, foh->len);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,121 @@
|
||||||
|
.\" $NetBSD: perfused.8,v 1.1 2010/08/25 07:18:01 manu Exp $
|
||||||
|
.\"
|
||||||
|
.\" Copyright (c) 2010 Emmanuel Dreyfus. 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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.
|
||||||
|
.\"
|
||||||
|
.Dd August 12, 2010
|
||||||
|
.Os
|
||||||
|
.Dt PERFUSED 8
|
||||||
|
.Sh NAME
|
||||||
|
.Nm perfused
|
||||||
|
.Nd "PUFFS Enabled Relay to FUSE Daemon"
|
||||||
|
.Sh SYNOPSIS
|
||||||
|
.Nm
|
||||||
|
.Op Fl f
|
||||||
|
.Op Fl d Ar types
|
||||||
|
.Op Fl s
|
||||||
|
.Sh DESCRIPTION
|
||||||
|
.Nm
|
||||||
|
is a userland daemon mplementing the FUSE kernel level API. It creates a
|
||||||
|
.Pa /dev/fuse
|
||||||
|
socket for FUSE filesystem daemons to conenct to.
|
||||||
|
.Nm
|
||||||
|
takes care of mouting the filesystem using
|
||||||
|
.Xr puffs 3 .
|
||||||
|
.Pp
|
||||||
|
When the kernel sends a
|
||||||
|
.Xr puffs 3
|
||||||
|
operation for the mounted filesystem,
|
||||||
|
.Nm
|
||||||
|
will translate it into a FUSE request, and will send it to the filesystem
|
||||||
|
daemon through
|
||||||
|
.Pa /dev/fuse .
|
||||||
|
The FUSE reply will be converted back into a
|
||||||
|
.Xr puffs 3
|
||||||
|
reply and will be relayed to the kernel.
|
||||||
|
.Pp
|
||||||
|
FUSE filesystems daemons must be modified so that they request
|
||||||
|
.Nm
|
||||||
|
for performing the
|
||||||
|
.Xr mount 2
|
||||||
|
system call instead of doing it on their own. This is done by
|
||||||
|
replacing in the sources
|
||||||
|
.Xr mount 2
|
||||||
|
and the
|
||||||
|
.Xr open 2
|
||||||
|
call for
|
||||||
|
.Pa /dev/fuse
|
||||||
|
by
|
||||||
|
.Fn perfuse_mount
|
||||||
|
and
|
||||||
|
.Fn perfuse_open .
|
||||||
|
.Xr libperfuse 3
|
||||||
|
must be used at link time.
|
||||||
|
Most FUSE filesystem daemons use
|
||||||
|
.Nm libfuse
|
||||||
|
and will work unmodified, provided
|
||||||
|
the modification is done in
|
||||||
|
.Nm libfuse
|
||||||
|
itself .
|
||||||
|
.Pp
|
||||||
|
The following options are availlable:
|
||||||
|
.Bl -tag -width indent
|
||||||
|
.It Fl f
|
||||||
|
Do not fork and stay in the foreground.
|
||||||
|
.It Fl d Ar types
|
||||||
|
Print additionnal debug information.
|
||||||
|
.Ar types
|
||||||
|
is a comma-separated list of informaton type to print:
|
||||||
|
.Bl -tag -width indent
|
||||||
|
.It Ar puffs
|
||||||
|
Display PUFFS requests and replies
|
||||||
|
.It Ar fuse
|
||||||
|
Display FUSE requests and replies
|
||||||
|
.It Ar dump
|
||||||
|
Dump content of FUSE frames
|
||||||
|
.It Ar fh
|
||||||
|
Display filehandles activity
|
||||||
|
.It Ar reclaim
|
||||||
|
Display reclaim activity
|
||||||
|
.It Ar readdir
|
||||||
|
Display readdir activity
|
||||||
|
.It Ar requeue
|
||||||
|
Display requeue activity
|
||||||
|
.El
|
||||||
|
.It Fl s
|
||||||
|
Enable debug output only when receiving SIGINFO.
|
||||||
|
.El
|
||||||
|
.Sh ERRORS
|
||||||
|
The program logs to the syslog daemon as facility
|
||||||
|
.Dq daemon .
|
||||||
|
For detailed debugging use the
|
||||||
|
.Fl d
|
||||||
|
(debug) option.
|
||||||
|
.Sh SEE ALSO
|
||||||
|
.Xr puffs 4 ,
|
||||||
|
.Xr mount 2 ,
|
||||||
|
.Xr perfuse_mount 3
|
||||||
|
.Sh AUTHORS
|
||||||
|
The program was written by
|
||||||
|
.An Emmanuel Dreyfus
|
||||||
|
.Aq manu@NetBSD.org .
|
|
@ -0,0 +1,384 @@
|
||||||
|
/* $NetBSD: perfused.c,v 1.1 2010/08/25 07:18:01 manu Exp $ */
|
||||||
|
|
||||||
|
/*-
|
||||||
|
* Copyright (c) 2010 Emmanuel Dreyfus. 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <syslog.h>
|
||||||
|
#include <ctype.h>
|
||||||
|
#include <paths.h>
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include <err.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <sysexits.h>
|
||||||
|
#include <signal.h>
|
||||||
|
#include <puffs.h>
|
||||||
|
#include <sys/wait.h>
|
||||||
|
#include <sys/param.h>
|
||||||
|
#include <sys/queue.h>
|
||||||
|
#include <sys/uio.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <sys/un.h>
|
||||||
|
#include <machine/vmparam.h>
|
||||||
|
|
||||||
|
#include "../../lib/libperfuse/perfuse_if.h"
|
||||||
|
#include "perfused.h"
|
||||||
|
|
||||||
|
static int getpeerid(int, pid_t *, uid_t *, gid_t *);
|
||||||
|
static int access_mount(const char *, uid_t, int);
|
||||||
|
static int accept_new_mount(int);
|
||||||
|
static int parse_debug(char *);
|
||||||
|
static void siginfo_handler(int);
|
||||||
|
static void parse_options(int, char **);
|
||||||
|
static void get_mount_info(int, struct perfuse_mount_info *);
|
||||||
|
int main(int, char **);
|
||||||
|
|
||||||
|
|
||||||
|
static int
|
||||||
|
getpeerid(s, pidp, uidp, gidp)
|
||||||
|
int s;
|
||||||
|
pid_t *pidp;
|
||||||
|
uid_t *uidp;
|
||||||
|
gid_t *gidp;
|
||||||
|
{
|
||||||
|
struct unpcbid unp;
|
||||||
|
socklen_t len;
|
||||||
|
int error;
|
||||||
|
|
||||||
|
len = sizeof(unp);
|
||||||
|
error = getsockopt(s, 0, LOCAL_PEEREID, &unp, &len);
|
||||||
|
if (error != 0)
|
||||||
|
return error;
|
||||||
|
|
||||||
|
if (pidp != NULL)
|
||||||
|
*pidp = unp.unp_pid;
|
||||||
|
|
||||||
|
if (uidp != NULL)
|
||||||
|
*uidp = unp.unp_euid;
|
||||||
|
|
||||||
|
if (gidp != NULL)
|
||||||
|
*gidp = unp.unp_egid;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
access_mount(mnt, uid, ro)
|
||||||
|
const char *mnt;
|
||||||
|
uid_t uid;
|
||||||
|
int ro;
|
||||||
|
{
|
||||||
|
struct stat st;
|
||||||
|
mode_t mode;
|
||||||
|
|
||||||
|
if (uid == 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (stat(mnt, &st) == -1)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if (st.st_uid != uid)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
mode = S_IRUSR;
|
||||||
|
if (!ro)
|
||||||
|
mode |= S_IWUSR;
|
||||||
|
|
||||||
|
if ((st.st_mode & mode) == mode)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
get_mount_info(fd, pmi)
|
||||||
|
int fd;
|
||||||
|
struct perfuse_mount_info *pmi;
|
||||||
|
{
|
||||||
|
struct perfuse_mount_out *pmo;
|
||||||
|
char *source = NULL;
|
||||||
|
char *target = NULL;
|
||||||
|
char *filesystemtype = NULL;
|
||||||
|
long mountflags = 0;
|
||||||
|
void *data;
|
||||||
|
size_t len;
|
||||||
|
|
||||||
|
pmo = (struct perfuse_mount_out *)perfuse_recv_early(fd, sizeof(*pmo));
|
||||||
|
if (pmo == NULL) {
|
||||||
|
if (shutdown(fd, SHUT_RDWR) != 0)
|
||||||
|
DERR(EX_OSERR, "shutdown failed");
|
||||||
|
exit(EX_PROTOCOL);
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef PERFUSE_DEBUG
|
||||||
|
DPRINTF("perfuse lengths: source = %d, target = %d, "
|
||||||
|
"filesystemtype = %d, data = %d\n",
|
||||||
|
pmo->pmo_source_len,
|
||||||
|
pmo->pmo_target_len,
|
||||||
|
pmo->pmo_filesystemtype_len,
|
||||||
|
pmo->pmo_data_len);
|
||||||
|
#endif
|
||||||
|
len = pmo->pmo_source_len;
|
||||||
|
source = perfuse_recv_early(fd, len);
|
||||||
|
|
||||||
|
len = pmo->pmo_target_len;
|
||||||
|
target = perfuse_recv_early(fd, len);
|
||||||
|
|
||||||
|
len = pmo->pmo_filesystemtype_len;
|
||||||
|
filesystemtype = perfuse_recv_early(fd, len);
|
||||||
|
|
||||||
|
mountflags = pmo->pmo_mountflags;
|
||||||
|
|
||||||
|
len = pmo->pmo_data_len;
|
||||||
|
data = perfuse_recv_early(fd, len);
|
||||||
|
|
||||||
|
#ifdef PERFUSE_DEBUG
|
||||||
|
DPRINTF("%s(\"%s\", \"%s\", \"%s\", 0x%lx, \"%s\")\n", __func__,
|
||||||
|
source, target, filesystemtype, mountflags, (const char *)data);
|
||||||
|
#endif
|
||||||
|
pmi->pmi_source = source;
|
||||||
|
pmi->pmi_target = target;
|
||||||
|
pmi->pmi_filesystemtype = filesystemtype;
|
||||||
|
pmi->pmi_mountflags = mountflags;
|
||||||
|
pmi->pmi_data = data;
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
accept_new_mount(s)
|
||||||
|
int s;
|
||||||
|
{
|
||||||
|
struct puffs_usermount *pu;
|
||||||
|
struct sockaddr_storage ss;
|
||||||
|
socklen_t ss_len;
|
||||||
|
struct sockaddr *sa;
|
||||||
|
struct perfuse_mount_info pmi;
|
||||||
|
struct perfuse_callbacks pc;
|
||||||
|
int ro_flag;
|
||||||
|
pid_t pid;
|
||||||
|
int fd;
|
||||||
|
int flags;
|
||||||
|
|
||||||
|
#ifdef PERFUSE_DEBUG
|
||||||
|
DPRINTF("waiting connexion\n");
|
||||||
|
#endif
|
||||||
|
sa = (struct sockaddr *)(void *)&ss;
|
||||||
|
ss_len = sizeof(ss);
|
||||||
|
if ((fd = accept(s, sa, &ss_len)) == -1)
|
||||||
|
DERR(EX_OSERR, "accept failed");
|
||||||
|
|
||||||
|
#ifdef PERFUSE_DEBUG
|
||||||
|
DPRINTF("connexion accepted\n");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
pid = (perfuse_diagflags & PDF_FOREGROUND) ? 0 : fork();
|
||||||
|
switch(pid) {
|
||||||
|
case -1:
|
||||||
|
DERR(EX_OSERR, "cannot fork");
|
||||||
|
break;
|
||||||
|
case 0:
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return fd;
|
||||||
|
/* NOTREACHED */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Mount information (source, target, mount flags...)
|
||||||
|
*/
|
||||||
|
get_mount_info(fd, &pmi);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Get peer identity
|
||||||
|
*/
|
||||||
|
if (getpeerid(fd, NULL, &pmi.pmi_uid, NULL) != 0)
|
||||||
|
DWARNX("Unable to retreive peer identity");
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Check that peer owns mountpoint and read (and write) on it?
|
||||||
|
*/
|
||||||
|
ro_flag = pmi.pmi_mountflags & MNT_RDONLY;
|
||||||
|
if (access_mount(pmi.pmi_target, pmi.pmi_uid, ro_flag) != 0)
|
||||||
|
DERRX(EX_NOPERM, "insuficient privvileges to mount %s",
|
||||||
|
pmi.pmi_target);
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Initialize libperfuse, which will initialize libpuffs
|
||||||
|
*/
|
||||||
|
pc.pc_new_msg = perfuse_new_pb;
|
||||||
|
pc.pc_xchg_msg = perfuse_xchg_pb;
|
||||||
|
pc.pc_destroy_msg = (perfuse_destroy_msg_fn)puffs_framebuf_destroy;
|
||||||
|
pc.pc_get_inhdr = perfuse_get_inhdr;
|
||||||
|
pc.pc_get_inpayload = perfuse_get_inpayload;
|
||||||
|
pc.pc_get_outhdr = perfuse_get_outhdr;
|
||||||
|
pc.pc_get_outpayload = perfuse_get_outpayload;
|
||||||
|
|
||||||
|
pu = perfuse_init(&pc, &pmi);
|
||||||
|
|
||||||
|
puffs_framev_init(pu, perfuse_readframe, perfuse_writeframe,
|
||||||
|
perfuse_cmpframe, perfuse_gotframe, NULL);
|
||||||
|
|
||||||
|
if (puffs_framev_addfd(pu, fd, PUFFS_FBIO_READ|PUFFS_FBIO_WRITE) == -1)
|
||||||
|
DERR(EX_SOFTWARE, "puffs_framev_addfd failed");
|
||||||
|
|
||||||
|
perfuse_setspecific(pu, (void *)fd);
|
||||||
|
|
||||||
|
setproctitle("perfused %s", pmi.pmi_target);
|
||||||
|
(void)kill(getpid(), SIGINFO); /* This is for -s option */
|
||||||
|
|
||||||
|
perfuse_fs_init(pu);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Non blocking I/O on /dev/fuse
|
||||||
|
* This must be done after perfuse_fs_init
|
||||||
|
*/
|
||||||
|
if ((flags = fcntl(fd, F_GETFL, 0)) == -1)
|
||||||
|
DERR(EX_OSERR, "fcntl failed");
|
||||||
|
if (fcntl(fd, F_SETFL, flags|O_NONBLOCK) != 0)
|
||||||
|
DERR(EX_OSERR, "fcntl failed");
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Hand over control to puffs main loop.
|
||||||
|
*/
|
||||||
|
return perfuse_mainloop(pu);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
parse_debug(optstr)
|
||||||
|
char *optstr;
|
||||||
|
{
|
||||||
|
int retval = PDF_SYSLOG;
|
||||||
|
char *opt;
|
||||||
|
char *lastp;
|
||||||
|
|
||||||
|
for (opt = strtok_r(optstr, ",", &lastp);
|
||||||
|
opt;
|
||||||
|
opt = strtok_r(NULL, ",", &lastp)) {
|
||||||
|
if (strcmp(opt, "fuse") == 0)
|
||||||
|
retval |= PDF_FUSE;
|
||||||
|
else if (strcmp(opt, "puffs") == 0)
|
||||||
|
retval |= PDF_PUFFS;
|
||||||
|
else if (strcmp(opt, "dump") == 0)
|
||||||
|
retval |= PDF_DUMP;
|
||||||
|
else if (strcmp(opt, "fh") == 0)
|
||||||
|
retval |= PDF_FH;
|
||||||
|
else if (strcmp(opt, "readdir") == 0)
|
||||||
|
retval |= PDF_READDIR;
|
||||||
|
else if (strcmp(opt, "reclaim") == 0)
|
||||||
|
retval |= PDF_RECLAIM;
|
||||||
|
else if (strcmp(opt, "requeue") == 0)
|
||||||
|
retval |= PDF_REQUEUE;
|
||||||
|
else if (strcmp(opt, "misc") == 0)
|
||||||
|
retval |= PDF_MISC;
|
||||||
|
else
|
||||||
|
DERRX(EX_USAGE, "unknown debug flag \"%s\"", opt);
|
||||||
|
}
|
||||||
|
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ARGSUSED0 */
|
||||||
|
static void
|
||||||
|
siginfo_handler(sig)
|
||||||
|
int sig;
|
||||||
|
{
|
||||||
|
static int old_flags = 0;
|
||||||
|
int swap;
|
||||||
|
|
||||||
|
swap = perfuse_diagflags;
|
||||||
|
perfuse_diagflags = old_flags;
|
||||||
|
old_flags = swap;
|
||||||
|
|
||||||
|
DWARNX("debug %sabled", old_flags == 0 ? "en" : "dis");
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
parse_options(argc, argv)
|
||||||
|
int argc;
|
||||||
|
char **argv;
|
||||||
|
{
|
||||||
|
int ch;
|
||||||
|
int foreground = 0;
|
||||||
|
|
||||||
|
perfuse_diagflags = PDF_FOREGROUND | PDF_SYSLOG;
|
||||||
|
|
||||||
|
while ((ch = getopt(argc, argv, "d:fs")) != -1) {
|
||||||
|
switch (ch) {
|
||||||
|
case 'd':
|
||||||
|
perfuse_diagflags |= parse_debug(optarg);
|
||||||
|
break;
|
||||||
|
case 's':
|
||||||
|
if (signal(SIGINFO, siginfo_handler) != 0)
|
||||||
|
DERR(EX_OSERR, "signal failed");
|
||||||
|
break;
|
||||||
|
case 'f':
|
||||||
|
foreground = 1;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
DERR(EX_USAGE, "%s [-d level] [-s] [-f]", argv[0]);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!foreground)
|
||||||
|
perfuse_diagflags &= ~PDF_FOREGROUND;
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
main(argc, argv)
|
||||||
|
int argc;
|
||||||
|
char **argv;
|
||||||
|
{
|
||||||
|
int s;
|
||||||
|
|
||||||
|
parse_options(argc, argv);
|
||||||
|
|
||||||
|
if (perfuse_diagflags & PDF_SYSLOG)
|
||||||
|
openlog("perfused", 0, LOG_DAEMON);
|
||||||
|
|
||||||
|
if (!(perfuse_diagflags & PDF_FOREGROUND))
|
||||||
|
if (daemon(0, 0) != 0)
|
||||||
|
DERR(EX_OSERR, "daemon failed");
|
||||||
|
|
||||||
|
s = perfuse_open_sock();
|
||||||
|
|
||||||
|
do {
|
||||||
|
(void)accept_new_mount(s);
|
||||||
|
} while (1 /* CONSTCOND */);
|
||||||
|
|
||||||
|
/* NOTREACHED */
|
||||||
|
return 0;
|
||||||
|
}
|
|
@ -0,0 +1,68 @@
|
||||||
|
/* $NetBSD: perfused.h,v 1.1 2010/08/25 07:18:01 manu Exp $ */
|
||||||
|
|
||||||
|
/*-
|
||||||
|
* Copyright (c) 2010 Emmanuel Dreyfus. 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _PERFUSED_H_
|
||||||
|
#define _PERFUSED_H_
|
||||||
|
|
||||||
|
#include <puffs.h>
|
||||||
|
#include "../../lib/libperfuse/perfuse_if.h"
|
||||||
|
#include "fuse.h"
|
||||||
|
|
||||||
|
#define PERFUSE_MSG_T struct puffs_framebuf
|
||||||
|
|
||||||
|
__BEGIN_DECLS
|
||||||
|
|
||||||
|
#ifdef PERFUSE_DEBUG
|
||||||
|
void perfuse_hexdump(char *, size_t);
|
||||||
|
const char *perfuse_opname(int);
|
||||||
|
extern int perfuse_diagflags;
|
||||||
|
#endif /* PERFUSE_DEBUG */
|
||||||
|
|
||||||
|
int perfuse_open_sock(void);
|
||||||
|
void *perfuse_recv_early(int, size_t);
|
||||||
|
|
||||||
|
int perfuse_readframe(struct puffs_usermount *,
|
||||||
|
struct puffs_framebuf *, int, int *);
|
||||||
|
int perfuse_writeframe(struct puffs_usermount *,
|
||||||
|
struct puffs_framebuf *, int, int *);
|
||||||
|
int perfuse_cmpframe(struct puffs_usermount *,
|
||||||
|
struct puffs_framebuf *, struct puffs_framebuf *, int *);
|
||||||
|
void perfuse_gotframe(struct puffs_usermount *, struct puffs_framebuf *);
|
||||||
|
|
||||||
|
struct fuse_out_header *perfuse_get_outhdr(perfuse_msg_t *);
|
||||||
|
struct fuse_in_header *perfuse_get_inhdr(perfuse_msg_t *);
|
||||||
|
char *perfuse_get_inpayload(perfuse_msg_t *);
|
||||||
|
char *perfuse_get_outpayload(perfuse_msg_t *);
|
||||||
|
|
||||||
|
perfuse_msg_t *perfuse_new_pb(struct puffs_usermount *,
|
||||||
|
puffs_cookie_t, int, size_t, const struct puffs_cred *);
|
||||||
|
int perfuse_xchg_pb(struct puffs_usermount *, perfuse_msg_t *, size_t,
|
||||||
|
enum perfuse_xchg_pb_reply);
|
||||||
|
|
||||||
|
__END_DECLS
|
||||||
|
|
||||||
|
#endif /* _PERFUSED_H_ */
|
Loading…
Reference in New Issue