LIB= puffs
SRCS= puffs.c callcontext.c creds.c \
- null.c pnode.c \
+ paths.c pnode.c \
subr.c
MAN= puffs.3 puffs_cc.3 puffs_cred.3 puffs_flush.3 \
puffs_framebuf.3 puffs_node.3 puffs_ops.3 puffs_path.3
LINTFLAGS+=-S -w
.if defined(__MINIX)
-SRCS+= inode.c link.c misc.c mount.c open.c path.c path_puffs.c \
- protect.c read.c stadir.c time.c utility.c table.c
+.PATH: ${NETBSDSRCDIR}/minix/lib/libpuffs
+SRCS+= inode.c link.c main.c misc.c mount.c open.c path.c \
+ protect.c read.c stadir.c time.c utility.c \
+ table.c
-CPPFLAGS+= -D_MINIX_SYSTEM
+CPPFLAGS+= -D_MINIX_SYSTEM -I${.CURDIR} -I${NETBSDSRCDIR}/minix/lib/libpuffs
NOGCCERROR=yes
.endif # defined(__MINIX)
struct puffs_cc *volatile pcc;
void *sp;
size_t stacksize = 1<<pu->pu_cc_stackshift;
+#ifndef __minix
+ const long psize = sysconf(_SC_PAGESIZE);
+#endif /* !__minix */
if (puffs_fakecc)
return &fakecc;
sp = mmap(NULL, stacksize, PROT_READ|PROT_WRITE,
- MAP_ANON|MAP_PRIVATE, -1, 0);
+ MAP_ANON|MAP_PRIVATE|MAP_ALIGNED(pu->pu_cc_stackshift), -1, 0);
if (sp == MAP_FAILED)
return NULL;
pcc = sp;
memset(pcc, 0, sizeof(struct puffs_cc));
+#ifndef __minix
+#ifndef __MACHINE_STACK_GROWS_UP
+ mprotect((uint8_t *)sp + psize, (size_t)psize, PROT_NONE);
+#else
+ mprotect((uint8_t *)sp + stacksize - psize, (size_t)psize, PROT_NONE);
+#endif
+#endif /* !__minix */
+
/* initialize both ucontext's */
if (getcontext(&pcc->pcc_uc) == -1) {
munmap(pcc, stacksize);
pcc->pcc_func = func;
pcc->pcc_farg = pcc;
} else {
+ const long psize = sysconf(_SC_PAGESIZE);
+
/* link context */
pcc->pcc_uc.uc_link = &pcc->pcc_uc_ret;
* swapcontext(). However, it gets lost. So reinit it.
*/
st = &pcc->pcc_uc.uc_stack;
- st->ss_sp = pcc;
- st->ss_size = stacksize;
+ st->ss_sp = ((uint8_t *)(void *)pcc) + psize;
+ st->ss_size = stacksize - psize;
st->ss_flags = 0;
/*
#include <assert.h>
#include <errno.h>
-#if !defined(__minix)
#include <pthread.h>
-#endif /* !defined(__minix) */
#include <puffs.h>
#include <puffsdump.h>
#include <stdio.h>
+++ /dev/null
-/*
- * Copyright (c) 2007 Antti Kantee. 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 AUTHOR ``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 AUTHOR 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 <sys/cdefs.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-
-#include <sys/hash.h>
-
-#include <assert.h>
-#include <errno.h>
-#include <puffs.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include "puffs.h"
-#include "puffs_priv.h"
-
-
-/*
- * Generic routines for pathbuilding code
- */
-
-int
-puffs_path_pcnbuild(struct puffs_usermount *pu, struct puffs_cn *pcn,
- puffs_cookie_t parent)
-{
- struct puffs_node *pn_parent = PU_CMAP(pu, parent);
- struct puffs_cn pcn_orig;
- struct puffs_pathobj po;
- int rv;
-
- assert(pn_parent->pn_po.po_path != NULL);
- assert(pu->pu_flags & PUFFS_FLAG_BUILDPATH);
- pcn_orig = *pcn;
-
- if (pu->pu_pathtransform) {
- rv = pu->pu_pathtransform(pu, &pn_parent->pn_po, pcn, &po);
- if (rv)
- return rv;
- } else {
- po.po_path = pcn->pcn_name;
- po.po_len = pcn->pcn_namelen;
- }
-
- if (pu->pu_namemod) {
- rv = pu->pu_namemod(pu, &pn_parent->pn_po, pcn);
- if (rv)
- return rv;
- }
-
- rv = pu->pu_pathbuild(pu, &pn_parent->pn_po, &po, 0,
- &pcn->pcn_po_full);
- puffs_path_buildhash(pu, &pcn->pcn_po_full);
-
- if (pu->pu_pathtransform)
- pu->pu_pathfree(pu, &po);
-
- if (pu->pu_namemod && rv)
- *pcn = pcn_orig;
-
- return rv;
-}
-
-/*
- * substitute all (child) patch prefixes. called from nodewalk, which
- * in turn is called from rename
- */
-void *
-puffs_path_prefixadj(struct puffs_usermount *pu, struct puffs_node *pn,
- void *arg)
-{
- struct puffs_pathinfo *pi = arg;
- struct puffs_pathobj localpo;
- struct puffs_pathobj oldpo;
- int rv;
-
- /* can't be a path prefix */
- if (pn->pn_po.po_len < pi->pi_old->po_len)
- return NULL;
-
- if (pu->pu_pathcmp(pu, &pn->pn_po, pi->pi_old, pi->pi_old->po_len, 1))
- return NULL;
-
- /* otherwise we'd have two nodes with an equal path */
- assert(pn->pn_po.po_len > pi->pi_old->po_len);
-
- /* found a matching prefix */
- rv = pu->pu_pathbuild(pu, pi->pi_new, &pn->pn_po,
- pi->pi_old->po_len, &localpo);
- /*
- * XXX: technically we shouldn't fail, but this is the only
- * sensible thing to do here. If the buildpath routine fails,
- * we will have paths in an inconsistent state. Should fix this,
- * either by having two separate passes or by doing other tricks
- * to make an invalid path with BUILDPATHS acceptable.
- */
- if (rv != 0)
- abort();
-
- /* adjust hash sum */
- puffs_path_buildhash(pu, &localpo);
-
- /* out with the old and in with the new */
- oldpo = pn->pn_po;
- pn->pn_po = localpo;
- pu->pu_pathfree(pu, &oldpo);
-
- /* continue the walk */
- return NULL;
-}
-
-/*
- * called from nodewalk, checks for exact match
- */
-void *
-puffs_path_walkcmp(struct puffs_usermount *pu, struct puffs_node *pn, void *arg)
-{
- struct puffs_pathobj *po = arg;
- struct puffs_pathobj po2;
-
- if (po->po_len != PNPLEN(pn))
- return NULL;
-
- /*
- * If hashing and the hash doesn't match, we know this is
- * definitely not a match. Otherwise check for collisions.
- */
- if (pu->pu_flags & PUFFS_FLAG_HASHPATH)
- if (pn->pn_po.po_hash != po->po_hash)
- return NULL;
-
- po2.po_path = PNPATH(pn);
- po2.po_len = PNPLEN(pn);
-
- if (pu->pu_pathcmp(pu, po, &po2, PNPLEN(pn), 0) == 0)
- return pn;
- return NULL;
-}
-
-/*
- * Hash sum building routine. Use string hash if the buildpath routine
- * is the standard one, otherwise use binary hashes. A bit whimsical
- * way to choose the routine, but the binary works for strings also,
- * so don't sweat it.
- */
-void
-puffs_path_buildhash(struct puffs_usermount *pu, struct puffs_pathobj *po)
-{
-
- if ((pu->pu_flags & PUFFS_FLAG_HASHPATH) == 0)
- return;
-
- if (pu->pu_pathbuild == puffs_stdpath_buildpath)
- po->po_hash = hash32_strn(po->po_path, po->po_len,
- HASH32_STR_INIT);
- else
- po->po_hash = hash32_buf(po->po_path, po->po_len,
- HASH32_BUF_INIT);
-}
-
-/*
- * Routines provided to file systems which consider a path a tuple of
- * strings and / the component separator.
- */
-
-/*ARGSUSED*/
-int
-puffs_stdpath_cmppath(struct puffs_usermount *pu, struct puffs_pathobj *c1,
- struct puffs_pathobj *c2, size_t clen, int checkprefix)
-{
- char *p;
- int rv;
-
- rv = strncmp(c1->po_path, c2->po_path, clen);
- if (rv)
- return 1;
-
- if (checkprefix == 0)
- return 0;
-
- /* sanity for next step */
- if (!(c1->po_len > c2->po_len))
- return 1;
-
- /* check if it's really a complete path prefix */
- p = c1->po_path;
- if ((*(p + clen)) != '/')
- return 1;
-
- return 0;
-}
-
-/*ARGSUSED*/
-int
-puffs_stdpath_buildpath(struct puffs_usermount *pu,
- const struct puffs_pathobj *po_pre, const struct puffs_pathobj *po_comp,
- size_t offset, struct puffs_pathobj *newpath)
-{
- char *path, *pcomp;
- size_t plen, complen;
- size_t prelen;
- int isdotdot;
-
- complen = po_comp->po_len - offset;
-
- /* seek to correct place & remove all leading '/' from component */
- pcomp = po_comp->po_path;
- pcomp += offset;
- while (*pcomp == '/') {
- pcomp++;
- complen--;
- }
-
- /* todotdot or nottodotdot */
- if (complen == 2 && strcmp(pcomp, "..") == 0)
- isdotdot = 1;
- else
- isdotdot = 0;
-
- /*
- * Strip trailing components from the preceending component.
- * This is an issue only for the root node, which we might want
- * to be at path "/" for some file systems.
- */
- prelen = po_pre->po_len;
- while (prelen > 0 && *((char *)po_pre->po_path + (prelen-1)) == '/') {
- assert(isdotdot == 0);
- prelen--;
- }
-
- if (isdotdot) {
- char *slash; /* sweet char of mine */
-
- slash = strrchr(po_pre->po_path, '/');
- assert(slash != NULL);
-
- plen = slash - (char *)po_pre->po_path;
-
- /*
- * As the converse to not stripping the initial "/" above,
- * don't nuke it here either.
- */
- if (plen == 0)
- plen++;
-
- path = malloc(plen + 1);
- if (path == NULL)
- return errno;
-
- strlcpy(path, po_pre->po_path, plen+1);
- } else {
- /* + '/' + '\0' */
- plen = prelen + 1 + complen;
- path = malloc(plen + 1);
- if (path == NULL)
- return errno;
-
- strlcpy(path, po_pre->po_path, prelen+1);
- strcat(path, "/");
- strncat(path, pcomp, complen);
- }
-
- newpath->po_path = path;
- newpath->po_len = plen;
-
- return 0;
-}
-
-/*ARGSUSED*/
-void
-puffs_stdpath_freepath(struct puffs_usermount *pu, struct puffs_pathobj *po)
-{
-
- free(po->po_path);
-}
void
puffs_pn_remove(struct puffs_node *pn)
{
- struct puffs_usermount *pu = pn->pn_mnt;
- assert(pu != NULL);
LIST_REMOVE(pn, pn_entries);
pn->pn_flags |= PUFFS_NODE_REMOVED;
+#ifdef __minix
if (pn->pn_count != 0) {
+ struct puffs_usermount *pu = pn->pn_mnt;
+ assert(pu != NULL);
+
/* XXX FS removes this pn from the list to prevent further
* lookups from finding node after remove/rm/rename op.
* But VFS still uses it, i.e. pnode is still open, and
*/
LIST_INSERT_HEAD(&pu->pu_pnode_removed_lst, pn, pn_entries);
}
+#endif /* __minix */
}
void
free(pn);
}
-/* walk list, rv can be used either to halt or to return a value
- * XXX (MINIX note): if fn is 0, then arg is ino_t and we search
- * node with ino_t. TODO: modify docs.
- */
+/* walk list, rv can be used either to halt or to return a value */
void *
puffs_pn_nodewalk(struct puffs_usermount *pu, puffs_nodewalk_fn fn, void *arg)
{
pn_cur = LIST_FIRST(&pu->pu_pnodelst);
while (pn_cur) {
pn_next = LIST_NEXT(pn_cur, pn_entries);
- if (fn) {
- rv = fn(pu, pn_cur, arg);
- if (rv)
- return rv;
- } else {
- if (pn_cur->pn_va.va_fileid == *((ino_t*) arg))
- return pn_cur;
- }
+ rv = fn(pu, pn_cur, arg);
+ if (rv)
+ return rv;
pn_cur = pn_next;
}
#include <sys/param.h>
#include <sys/mount.h>
-#if defined(__minix)
-#include "fs.h"
-#endif /* defined(__minix) */
-
#include <assert.h>
#include <err.h>
#include <errno.h>
#include <fcntl.h>
#include <mntopts.h>
#include <paths.h>
+#ifndef __minix
+#include <pthread.h>
+#endif /* !__minix */
#include <puffs.h>
#include <stdio.h>
#include <stdlib.h>
PUFFSMOPT_STD,
MOPT_NULL,
};
-#ifdef PUFFS_WITH_THREADS
-#include <pthread.h>
-pthread_mutex_t pu_lock = PTHREAD_MUTEX_INITIALIZER;
-#endif
-
-#if defined(__minix)
-static message fs_msg;
-static int fs_ipc_status;
-#endif
-
-/* Declare some local functions. */
-static int get_work(message *msg, int *ipc_status);
-
-/* SEF functions and variables. */
-static void sef_local_startup(void);
-static int sef_cb_init_fresh(int type, sef_init_info_t *info);
-static void sef_cb_signal_handler(int signo);
-
-EXTERN int env_argc;
-EXTERN char **env_argv;
-
-
-#define PUFFS_MAX_ARGS 20
-
-int __real_main(int argc, char* argv[]);
-int __wrap_main(int argc, char* argv[]);
-
-int __wrap_main(int argc, char *argv[])
-{
- int i;
- int new_argc = 0;
- static char* new_argv[PUFFS_MAX_ARGS];
- char *name;
-
- /* SEF local startup. */
- env_setargs(argc, argv);
- sef_local_startup();
-
- global_kcred.pkcr_type = PUFFCRED_TYPE_INTERNAL;
-
- if (argc < 3) {
- panic("Unexpected arguments, use:\
- mount -t fs /dev/ /dir [-o option1,option2]\n");
- }
-
- name = argv[0] + strlen(argv[0]);
- while (*name != '/' && name != argv[0])
- name--;
- if (name != argv[0])
- name++;
- strcpy(fs_name, name);
-
- new_argv[new_argc] = argv[0];
- new_argc++;
-
- for (i = 1; i < argc; i++) {
- if (new_argc >= PUFFS_MAX_ARGS) {
- panic("Too many arguments, change PUFFS_MAX_ARGS");
- }
- new_argv[new_argc] = argv[i];
- new_argc++;
- }
-
- assert(new_argc > 0);
-
- /* Get the mount request from VFS, so we can deal with it later. */
- (void)get_work(&fs_msg, &fs_ipc_status);
-
- return __real_main(new_argc, new_argv);
-}
+#ifndef __minix
+pthread_mutex_t pu_lock = PTHREAD_MUTEX_INITIALIZER;
+#endif /* !__minix */
#define FILLOP(lower, upper) \
do { \
FILLOP(print, PRINT);
FILLOP(read, READ);
FILLOP(write, WRITE);
+ FILLOP(advlock, ADVLOCK);
FILLOP(abortop, ABORTOP);
+ FILLOP(pathconf, PATHCONF);
+
+ FILLOP(getextattr, GETEXTATTR);
+ FILLOP(setextattr, SETEXTATTR);
+ FILLOP(listextattr, LISTEXTATTR);
+ FILLOP(deleteextattr, DELETEEXTATTR);
}
#undef FILLOP
+/*
+ * Go over all framev entries and write everything we can. This is
+ * mostly for the benefit of delivering "unmount" to the kernel.
+ */
+static void
+finalpush(struct puffs_usermount *pu)
+{
+#ifndef __minix
+ struct puffs_fctrl_io *fio;
+
+ LIST_FOREACH(fio, &pu->pu_ios, fio_entries) {
+ if (fio->stat & FIO_WRGONE)
+ continue;
+
+ puffs__framev_output(pu, fio->fctrl, fio);
+ }
+#endif /* !__minix */
+}
/*ARGSUSED*/
-__dead static void
-puffs_defaulterror(struct puffs_usermount *pu, uint8_t type,
+void
+puffs_kernerr_abort(struct puffs_usermount *pu, uint8_t type,
int error, const char *str, puffs_cookie_t cookie)
{
+#ifndef __minix
+ fprintf(stderr, "abort: type %d, error %d, cookie %p (%s)\n",
+#else /* __minix */
lpuffs_debug("abort: type %d, error %d, cookie %p (%s)\n",
+#endif /* __minix */
type, error, cookie, str);
abort();
}
+/*ARGSUSED*/
+void
+puffs_kernerr_log(struct puffs_usermount *pu, uint8_t type,
+ int error, const char *str, puffs_cookie_t cookie)
+{
+
+ syslog(LOG_WARNING, "kernel: type %d, error %d, cookie %p (%s)\n",
+ type, error, cookie, str);
+}
+
+#ifndef __minix
+int
+puffs_getselectable(struct puffs_usermount *pu)
+{
+
+ return pu->pu_fd;
+}
+
+uint64_t
+puffs__nextreq(struct puffs_usermount *pu)
+{
+ uint64_t rv;
+
+ PU_LOCK();
+ rv = pu->pu_nextreq++ | (uint64_t)1<<63;
+ PU_UNLOCK();
+
+ return rv;
+}
+
+int
+puffs_setblockingmode(struct puffs_usermount *pu, int mode)
+{
+ int rv, x;
+
+ assert(puffs_getstate(pu) == PUFFS_STATE_RUNNING);
+
+ if (mode != PUFFSDEV_BLOCK && mode != PUFFSDEV_NONBLOCK) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ x = mode;
+ rv = ioctl(pu->pu_fd, FIONBIO, &x);
+
+ if (rv == 0) {
+ if (mode == PUFFSDEV_BLOCK)
+ pu->pu_state &= ~PU_ASYNCFD;
+ else
+ pu->pu_state |= PU_ASYNCFD;
+ }
+
+ return rv;
+}
+#endif /* !__minix */
int
puffs_getstate(struct puffs_usermount *pu)
minsize = 4*psize;
if (ss < (size_t)minsize || ss == PUFFS_STACKSIZE_MIN) {
if (ss != PUFFS_STACKSIZE_MIN)
- lpuffs_debug("puffs_setstacksize: adjusting "
+#ifndef __minix
+ fprintf(stderr, "puffs_setstacksize: adjusting "
"stacksize to minimum %ld\n", minsize);
+#endif /* !__minix */
ss = 4*psize;
}
}
if (bonus > 1) {
stackshift++;
- lpuffs_debug("puffs_setstacksize: using next power of two: "
+#ifndef __minix
+ fprintf(stderr, "puffs_setstacksize: using next power of two: "
"%d\n", 1<<stackshift);
+#endif /* !__minix */
}
pu->pu_cc_stackshift = stackshift;
pu->pu_oppost = pst;
}
+#ifndef __minix
+void
+puffs_setback(struct puffs_cc *pcc, int whatback)
+{
+ struct puffs_req *preq = puffs__framebuf_getdataptr(pcc->pcc_pb);
+
+ assert(PUFFSOP_OPCLASS(preq->preq_opclass) == PUFFSOP_VN && (
+ preq->preq_optype == PUFFS_VN_OPEN ||
+ preq->preq_optype == PUFFS_VN_MMAP ||
+ preq->preq_optype == PUFFS_VN_REMOVE ||
+ preq->preq_optype == PUFFS_VN_RMDIR ||
+ preq->preq_optype == PUFFS_VN_INACTIVE));
+
+ preq->preq_setbacks |= whatback & PUFFS_SETBACK_MASK;
+}
+
+int
+puffs_daemon(struct puffs_usermount *pu, int nochdir, int noclose)
+{
+ long int n;
+ int parent, value, fd;
+
+ if (pipe(pu->pu_dpipe) == -1)
+ return -1;
+
+ switch (fork()) {
+ case -1:
+ return -1;
+ case 0:
+ parent = 0;
+ break;
+ default:
+ parent = 1;
+ break;
+ }
+ pu->pu_state |= PU_PUFFSDAEMON;
+
+ if (parent) {
+ close(pu->pu_dpipe[1]);
+ n = read(pu->pu_dpipe[0], &value, sizeof(int));
+ if (n == -1)
+ err(1, "puffs_daemon");
+ if (n != sizeof(value))
+ errx(1, "puffs_daemon got %ld bytes", n);
+ if (value) {
+ errno = value;
+ err(1, "puffs_daemon");
+ }
+ exit(0);
+ } else {
+ if (setsid() == -1)
+ goto fail;
+
+ if (!nochdir)
+ chdir("/");
+
+ if (!noclose) {
+ fd = open(_PATH_DEVNULL, O_RDWR, 0);
+ if (fd == -1)
+ goto fail;
+ dup2(fd, STDIN_FILENO);
+ dup2(fd, STDOUT_FILENO);
+ dup2(fd, STDERR_FILENO);
+ if (fd > STDERR_FILENO)
+ close(fd);
+ }
+ return 0;
+ }
+
+ fail:
+ n = write(pu->pu_dpipe[1], &errno, sizeof(int));
+ assert(n == 4);
+ return -1;
+}
+#endif /* !__minix */
+
+static void
+shutdaemon(struct puffs_usermount *pu, int error)
+{
+#ifndef __minix
+ ssize_t n;
+
+ n = write(pu->pu_dpipe[1], &error, sizeof(int));
+ assert(n == 4);
+ close(pu->pu_dpipe[0]);
+ close(pu->pu_dpipe[1]);
+#endif /* !__minix */
+ pu->pu_state &= ~PU_PUFFSDAEMON;
+}
+
int
puffs_mount(struct puffs_usermount *pu, const char *dir, int mntflags,
puffs_cookie_t cookie)
{
-#if defined(__minix)
+#ifndef __minix
+ int rv, fd, sverrno;
+ char *comfd;
+#endif /* !__minix */
+
pu->pu_kargp->pa_root_cookie = cookie;
- /* Process the already-received mount request. */
- fsdriver_process(&puffs_table, &fs_msg, fs_ipc_status, FALSE);
+#ifndef __minix
+ /* XXXkludgehere */
+ /* kauth doesn't provide this service any longer */
+ if (geteuid() != 0)
+ mntflags |= MNT_NOSUID | MNT_NODEV;
+
+ /*
+ * Undocumented... Well, documented only here.
+ *
+ * This is used for imaginative purposes. If the env variable is
+ * set, puffs_mount() doesn't do the regular mount procedure.
+ * Rather, it crams the mount data down the comfd and sets comfd as
+ * the puffs descriptor.
+ *
+ * This shouldn't be used unless you can read my mind ( ... or write
+ * it, not to mention execute it, but that's starting to get silly).
+ */
+ if ((comfd = getenv("PUFFS_COMFD")) != NULL) {
+ size_t len;
+
+ if (sscanf(comfd, "%d", &pu->pu_fd) != 1) {
+ errno = EINVAL;
+ rv = -1;
+ goto out;
+ }
+ /* check that what we got at least resembles an fd */
+ if (fcntl(pu->pu_fd, F_GETFL) == -1) {
+ rv = -1;
+ goto out;
+ }
+
+#define allwrite(buf, len) \
+do { \
+ ssize_t al_rv; \
+ al_rv = write(pu->pu_fd, buf, len); \
+ if ((size_t)al_rv != len) { \
+ if (al_rv != -1) \
+ errno = EIO; \
+ rv = -1; \
+ goto out; \
+ } \
+} while (/*CONSTCOND*/0)
+ len = strlen(dir)+1;
+ allwrite(&len, sizeof(len));
+ allwrite(dir, len);
+ len = strlen(pu->pu_kargp->pa_mntfromname)+1;
+ allwrite(&len, sizeof(len));
+ allwrite(pu->pu_kargp->pa_mntfromname, len);
+ allwrite(&mntflags, sizeof(mntflags));
+ len = sizeof(*pu->pu_kargp);
+ allwrite(&len, sizeof(len));
+ allwrite(pu->pu_kargp, sizeof(*pu->pu_kargp));
+ allwrite(&pu->pu_flags, sizeof(pu->pu_flags));
+#undef allwrite
+
+ rv = 0;
+ } else {
+ char rp[MAXPATHLEN];
+
+ if (realpath(dir, rp) == NULL) {
+ rv = -1;
+ goto out;
+ }
- if (!mounted) {
- /* This should never happen, unless VFS misbehaves.. */
+ if (strcmp(dir, rp) != 0) {
+ warnx("puffs_mount: \"%s\" is a relative path.", dir);
+ warnx("puffs_mount: using \"%s\" instead.", rp);
+ }
+
+ fd = open(_PATH_PUFFS, O_RDWR);
+ if (fd == -1) {
+ warnx("puffs_mount: cannot open %s", _PATH_PUFFS);
+ rv = -1;
+ goto out;
+ }
+ if (fd <= 2)
+ warnx("puffs_mount: device fd %d (<= 2), sure this is "
+ "what you want?", fd);
+
+ pu->pu_kargp->pa_fd = pu->pu_fd = fd;
+ if ((rv = mount(MOUNT_PUFFS, rp, mntflags,
+ pu->pu_kargp, sizeof(struct puffs_kargs))) == -1)
+ goto out;
+ }
+#else /* __minix */
+ /* Process the already-received mount request. */
+ if (!lpuffs_pump()) {
+ /* Not mounted? This should never happen.. */
free(pu->pu_kargp);
pu->pu_kargp = NULL;
- errno = -EINVAL;
+ errno = EINVAL;
return -1;
}
+#endif /* __minix */
PU_SETSTATE(pu, PUFFS_STATE_RUNNING);
+
+#ifndef __minix
+ out:
+ if (rv != 0)
+ sverrno = errno;
+ else
+ sverrno = 0;
+ free(pu->pu_kargp);
+ pu->pu_kargp = NULL;
+
+ if (pu->pu_state & PU_PUFFSDAEMON)
+ shutdaemon(pu, sverrno);
+
+ errno = sverrno;
+ return rv;
+#else /* __minix */
return 0;
-#endif /* defined(__minix) */
+#endif /* __minix */
}
-/*ARGSUSED*/
struct puffs_usermount *
puffs_init(struct puffs_ops *pops, const char *mntfromname,
const char *puffsname, void *priv, uint32_t pflags)
pargs->pa_time32 = 0;
pu->pu_flags = pflags;
- buildpath = pu->pu_flags & PUFFS_FLAG_BUILDPATH; /* XXX */
pu->pu_ops = *pops;
free(pops); /* XXX */
pu->pu_privdata = priv;
pu->pu_cc_stackshift = PUFFS_CC_STACKSHIFT_DEFAULT;
LIST_INIT(&pu->pu_pnodelst);
- LIST_INIT(&pu->pu_pnode_removed_lst);
LIST_INIT(&pu->pu_ios);
LIST_INIT(&pu->pu_ios_rmlist);
LIST_INIT(&pu->pu_ccmagazin);
TAILQ_INIT(&pu->pu_sched);
+#ifndef __minix
+ pu->pu_framectrl[PU_FRAMECTRL_FS].rfb = puffs__fsframe_read;
+ pu->pu_framectrl[PU_FRAMECTRL_FS].wfb = puffs__fsframe_write;
+ pu->pu_framectrl[PU_FRAMECTRL_FS].cmpfb = puffs__fsframe_cmp;
+ pu->pu_framectrl[PU_FRAMECTRL_FS].gotfb = puffs__fsframe_gotframe;
+ pu->pu_framectrl[PU_FRAMECTRL_FS].fdnotfn = puffs_framev_unmountonclose;
+#endif /* !__minix */
+
/* defaults for some user-settable translation functions */
pu->pu_cmap = NULL; /* identity translation */
pu->pu_pathtransform = NULL;
pu->pu_namemod = NULL;
- pu->pu_errnotify = puffs_defaulterror;
+ pu->pu_errnotify = puffs_kernerr_log;
PU_SETSTATE(pu, PUFFS_STATE_BEFOREMOUNT);
- global_pu = pu;
+#ifdef __minix
+ /* Do the MINIX3-specific side of the initialization. */
+ lpuffs_init(pu);
+#endif /* __minix */
return pu;
{
assert(puffs_getstate(pu) < PUFFS_STATE_RUNNING);
+ shutdaemon(pu, error);
free(pu);
}
/*ARGSUSED1*/
int
-puffs_exit(struct puffs_usermount *pu, int force)
+puffs_exit(struct puffs_usermount *pu, int unused /* strict compat */)
{
+#ifndef __minix
+ struct puffs_framebuf *pb;
+ struct puffs_req *preq;
+ void *winp;
+ size_t winlen;
+ int sverrno;
+
+ pb = puffs_framebuf_make();
+ if (pb == NULL) {
+ errno = ENOMEM;
+ return -1;
+ }
+
+ winlen = sizeof(struct puffs_req);
+ if (puffs_framebuf_getwindow(pb, 0, &winp, &winlen) == -1) {
+ sverrno = errno;
+ puffs_framebuf_destroy(pb);
+ errno = sverrno;
+ return -1;
+ }
+ preq = winp;
+
+ preq->preq_buflen = sizeof(struct puffs_req);
+ preq->preq_opclass = PUFFSOP_UNMOUNT;
+ preq->preq_id = puffs__nextreq(pu);
+
+ puffs_framev_enqueue_justsend(pu, puffs_getselectable(pu), pb, 1, 0);
+#else /* __minix */
struct puffs_node *pn;
-
- lpuffs_debug("puffs_exit\n");
+
+ lpuffs_debug("puffs_exit\n");
while ((pn = LIST_FIRST(&pu->pu_pnodelst)) != NULL)
puffs_pn_put(pn);
if (pu->pu_state & PU_HASKQ)
close(pu->pu_kq);
free(pu);
+#endif /* __minix */
- return 0; /* always succesful for now, WILL CHANGE */
+ return 0;
}
+#ifndef __minix
+/* no sigset_t static intializer */
+static int sigs[NSIG] = { 0, };
+static int sigcatch = 0;
+
+int
+puffs_unmountonsignal(int sig, bool sigignore)
+{
+
+ if (sig < 0 || sig >= (int)NSIG) {
+ errno = EINVAL;
+ return -1;
+ }
+ if (sigignore)
+ if (signal(sig, SIG_IGN) == SIG_ERR)
+ return -1;
+
+ if (!sigs[sig])
+ sigcatch++;
+ sigs[sig] = 1;
+
+ return 0;
+}
+#endif /* !__minix */
+
/*
* Actual mainloop. This is called from a context which can block.
* It is called either from puffs_mainloop (indirectly, via
puffs__theloop(struct puffs_cc *pcc)
{
struct puffs_usermount *pu = pcc->pcc_pu;
+#ifndef __minix
+ struct puffs_framectrl *pfctrl;
+ struct puffs_fctrl_io *fio;
+ struct kevent *curev;
+ size_t nchanges;
+ int ndone;
+#endif /* !__minix */
+
+#ifndef __minix
+ while (puffs_getstate(pu) != PUFFS_STATE_UNMOUNTED) {
+#else /* __minix */
+ do {
+#endif /* __minix */
- while (mounted || !exitsignaled) {
/*
* Schedule existing requests.
*/
while ((pcc = TAILQ_FIRST(&pu->pu_sched)) != NULL) {
- lpuffs_debug("scheduling existing tasks\n");
TAILQ_REMOVE(&pu->pu_sched, pcc, pcc_schedent);
puffs__goto(pcc);
}
- if (pu->pu_ml_lfn) {
- lpuffs_debug("Calling user mainloop handler\n");
+ if (pu->pu_ml_lfn)
pu->pu_ml_lfn(pu);
+
+#ifndef __minix
+ /* XXX: can we still do these optimizations? */
+#if 0
+ /*
+ * Do this here, because:
+ * a) loopfunc might generate some results
+ * b) it's still "after" event handling (except for round 1)
+ */
+ if (puffs_req_putput(ppr) == -1)
+ goto out;
+ puffs_req_resetput(ppr);
+
+ /* micro optimization: skip kevent syscall if possible */
+ if (pu->pu_nfds == 1 && pu->pu_ml_timep == NULL
+ && (pu->pu_state & PU_ASYNCFD) == 0) {
+ pfctrl = XXX->fctrl;
+ puffs_framev_input(pu, pfctrl, XXX);
+ continue;
}
+#endif
- /* Wait for request message. */
- if (get_work(&fs_msg, &fs_ipc_status) != OK)
- continue; /* recheck loop conditions */
+ /* else: do full processing */
+ /* Don't bother worrying about O(n) for now */
+ LIST_FOREACH(fio, &pu->pu_ios, fio_entries) {
+ if (fio->stat & FIO_WRGONE)
+ continue;
+
+ pfctrl = fio->fctrl;
+
+ /*
+ * Try to write out everything to avoid the
+ * need for enabling EVFILT_WRITE. The likely
+ * case is that we can fit everything into the
+ * socket buffer.
+ */
+ puffs__framev_output(pu, pfctrl, fio);
+ }
- /* Process it, and send a reply. */
- fsdriver_process(&puffs_table, &fs_msg, fs_ipc_status, FALSE);
+ /*
+ * Build list of which to enable/disable in writecheck.
+ */
+ nchanges = 0;
+ LIST_FOREACH(fio, &pu->pu_ios, fio_entries) {
+ if (fio->stat & FIO_WRGONE)
+ continue;
+
+ /* en/disable write checks for kqueue as needed */
+ assert((FIO_EN_WRITE(fio) && FIO_RM_WRITE(fio)) == 0);
+ if (FIO_EN_WRITE(fio)) {
+ EV_SET(&pu->pu_evs[nchanges], fio->io_fd,
+ EVFILT_WRITE, EV_ENABLE, 0, 0,
+ (uintptr_t)fio);
+ fio->stat |= FIO_WR;
+ nchanges++;
+ }
+ if (FIO_RM_WRITE(fio)) {
+ EV_SET(&pu->pu_evs[nchanges], fio->io_fd,
+ EVFILT_WRITE, EV_DISABLE, 0, 0,
+ (uintptr_t)fio);
+ fio->stat &= ~FIO_WR;
+ nchanges++;
+ }
+ }
+
+ ndone = kevent(pu->pu_kq, pu->pu_evs, nchanges,
+ pu->pu_evs, pu->pu_nevs, pu->pu_ml_timep);
+
+ if (ndone == -1) {
+ if (errno != EINTR)
+ break;
+ else
+ continue;
+ }
+
+ /* uoptimize */
+ if (ndone == 0)
+ continue;
+
+ /* iterate over the results */
+ for (curev = pu->pu_evs; ndone--; curev++) {
+ int what;
+
+#if 0
+ /* get & possibly dispatch events from kernel */
+ if (curev->ident == puffsfd) {
+ if (puffs_req_handle(pgr, ppr, 0) == -1)
+ goto out;
+ continue;
+ }
+#endif
+
+ fio = (void *)curev->udata;
+ if (__predict_true(fio))
+ pfctrl = fio->fctrl;
+ else
+ pfctrl = NULL;
+ if (curev->flags & EV_ERROR) {
+ assert(curev->filter == EVFILT_WRITE);
+ fio->stat &= ~FIO_WR;
+
+ /* XXX: how to know if it's a transient error */
+ puffs__framev_writeclose(pu, fio,
+ (int)curev->data);
+ puffs__framev_notify(fio, PUFFS_FBIO_ERROR);
+ continue;
+ }
+
+ what = 0;
+ if (curev->filter == EVFILT_READ) {
+ puffs__framev_input(pu, pfctrl, fio);
+ what |= PUFFS_FBIO_READ;
+ }
+
+ else if (curev->filter == EVFILT_WRITE) {
+ puffs__framev_output(pu, pfctrl, fio);
+ what |= PUFFS_FBIO_WRITE;
+ }
+
+ else if (__predict_false(curev->filter==EVFILT_SIGNAL)){
+ if ((pu->pu_state & PU_DONEXIT) == 0) {
+ PU_SETSFLAG(pu, PU_DONEXIT);
+ puffs_exit(pu, 0);
+ }
+ }
+ if (what)
+ puffs__framev_notify(fio, what);
+ }
+
+ /*
+ * Really free fd's now that we don't have references
+ * to them.
+ */
+ while ((fio = LIST_FIRST(&pu->pu_ios_rmlist)) != NULL) {
+ LIST_REMOVE(fio, fio_entries);
+ free(fio);
+ }
+#endif /* !__minix */
}
+#ifdef __minix
+ while (lpuffs_pump());
+#endif /* __minix */
if (puffs__cc_restoremain(pu) == -1)
warn("cannot restore main context. impending doom");
-
- /* May get here, if puffs_fakecc is set to 1. Currently librefuse sets it.
- * Now we just return to the caller.
- */
}
int
puffs_mainloop(struct puffs_usermount *pu)
{
+#ifndef __minix
+ struct puffs_fctrl_io *fio;
+#endif /* !__minix */
struct puffs_cc *pcc;
+#ifndef __minix
+ struct kevent *curev;
+ size_t nevs;
+ int sverrno, i;
+#else /* __minix */
int sverrno;
+#endif /* !__minix */
assert(puffs_getstate(pu) >= PUFFS_STATE_RUNNING);
- pu->pu_state |= PU_HASKQ | PU_INLOOP;
+#ifndef __minix
+ pu->pu_kq = kqueue();
+ if (pu->pu_kq == -1)
+ goto out;
+#endif /* !__minix */
+ pu->pu_state |= PU_HASKQ;
+
+#ifndef __minix
+ puffs_setblockingmode(pu, PUFFSDEV_NONBLOCK);
+ if (puffs__framev_addfd_ctrl(pu, puffs_getselectable(pu),
+ PUFFS_FBIO_READ | PUFFS_FBIO_WRITE,
+ &pu->pu_framectrl[PU_FRAMECTRL_FS]) == -1)
+ goto out;
+
+ nevs = pu->pu_nevs + sigcatch;
+ curev = realloc(pu->pu_evs, nevs * sizeof(struct kevent));
+ if (curev == NULL)
+ goto out;
+ pu->pu_evs = curev;
+ pu->pu_nevs = nevs;
+
+ LIST_FOREACH(fio, &pu->pu_ios, fio_entries) {
+ EV_SET(curev, fio->io_fd, EVFILT_READ, EV_ADD,
+ 0, 0, (uintptr_t)fio);
+ curev++;
+ EV_SET(curev, fio->io_fd, EVFILT_WRITE, EV_ADD | EV_DISABLE,
+ 0, 0, (uintptr_t)fio);
+ curev++;
+ }
+ for (i = 0; i < NSIG; i++) {
+ if (sigs[i]) {
+ EV_SET(curev, i, EVFILT_SIGNAL, EV_ADD | EV_ENABLE,
+ 0, 0, 0);
+ curev++;
+ }
+ }
+ assert(curev - pu->pu_evs == (ssize_t)pu->pu_nevs);
+ if (kevent(pu->pu_kq, pu->pu_evs, pu->pu_nevs, NULL, 0, NULL) == -1)
+ goto out;
+#endif /* !__minix */
+
+ pu->pu_state |= PU_INLOOP;
/*
* Create alternate execution context and jump to it. Note
if (puffs__cc_create(pu, puffs__theloop, &pcc) == -1) {
goto out;
}
+
+#if 0
if (puffs__cc_savemain(pu) == -1) {
goto out;
}
+#else
+ /*
+ * XXX
+ * puffs__cc_savemain() uses getcontext() and then returns.
+ * the caller (this function) may overwrite the stack frame
+ * of puffs__cc_savemain(), so when we call setcontext() later and
+ * return from puffs__cc_savemain() again, the return address or
+ * saved stack pointer can be garbage.
+ * avoid this by calling getcontext() directly here.
+ */
+ extern int puffs_fakecc;
+ if (!puffs_fakecc) {
+ PU_CLRSFLAG(pu, PU_MAINRESTORE);
+ if (getcontext(&pu->pu_mainctx) == -1) {
+ goto out;
+ }
+ }
+#endif
+
if ((pu->pu_state & PU_MAINRESTORE) == 0)
puffs_cc_continue(pcc);
+ finalpush(pu);
errno = 0;
out:
else
return 0;
}
-
-#if defined(__minix)
-/*===========================================================================*
- * sef_local_startup *
- *===========================================================================*/
-static void sef_local_startup(void)
-{
- /* Register init callbacks. */
- sef_setcb_init_fresh(sef_cb_init_fresh);
-
- /* Register signal callbacks. */
- sef_setcb_signal_handler(sef_cb_signal_handler);
-
- /* Let SEF perform startup. */
- sef_startup();
-}
-
-/*===========================================================================*
- * sef_cb_init_fresh *
- *===========================================================================*/
-static int sef_cb_init_fresh(int type, sef_init_info_t *info)
-{
-/* Initialize the Minix file server. */
- return(OK);
-}
-
-/*===========================================================================*
- * sef_cb_signal_handler *
- *===========================================================================*/
-static void sef_cb_signal_handler(int signo)
-{
- /* Only check for termination signal, ignore anything else. */
- if (signo != SIGTERM) return;
-
- exitsignaled = 1;
- fs_sync();
-
- sef_cancel();
-}
-
-/*===========================================================================*
- * get_work *
- *===========================================================================*/
-static int get_work(message *msg, int *ipc_status)
-{
- int r;
-
- for (;;) {
- if ((r = sef_receive_status(ANY, msg, ipc_status)) != OK) {
- if (r == EINTR) /* sef_cancel from signal handler? */
- break; /* see if we can exit the main loop */
- panic("sef_receive failed: %d", r);
- }
- if (msg->m_source == VFS_PROC_NR)
- break;
- lpuffs_debug("libpuffs: unexpected source %d\n", msg->m_source);
- }
-
- return r;
-}
-#endif /* defined(__minix) */
#include <puffs.h>
#include <ucontext.h>
-#if defined(__minix)
-
-/* XXX: MINIX */
-#define ATIME 002 /* set if atime field needs updating */
-#define CTIME 004 /* set if ctime field needs updating */
-#define MTIME 010 /* set if mtime field needs updating */
-
-#else
+#if !defined(__minix)
extern pthread_mutex_t pu_lock;
#define PU_LOCK() pthread_mutex_lock(&pu_lock)
#define PU_UNLOCK() pthread_mutex_unlock(&pu_lock)
-#endif /* defined(__minix) */
-#if defined(__minix)
+#else /* defined(__minix) */
#define PU_LOCK() /* nothing */
#define PU_UNLOCK() /* nothing */
#endif /* defined(__minix) */
struct puffs_node *pu_pn_root;
LIST_HEAD(, puffs_node) pu_pnodelst;
-#if defined(__minix) // LSC TO KEEP??
+#if defined(__minix)
LIST_HEAD(, puffs_node) pu_pnode_removed_lst;
#endif /* defined(__minix) */
void puffs__fsframe_gotframe(struct puffs_usermount *,
struct puffs_framebuf *);
+uint64_t puffs__nextreq(struct puffs_usermount *pu);
+
+#ifdef __minix
+int lpuffs_pump(void);
+void lpuffs_init(struct puffs_usermount *);
+void lpuffs_debug(const char *format, ...)
+ __attribute__((__format__(__printf__, 1, 2)));
+#endif /* __minix */
+
__END_DECLS
#endif /* _PUFFS_PRIVATE_H_ */
#include <sys/queue.h>
#include <sys/socket.h>
-#if !defined(__minix)
#include <dev/putter/putter.h>
-#endif /* !defined(__minix) */
#include <assert.h>
#include <errno.h>
--- /dev/null
+#ifndef _LIBPUFFS_CONST_H
+#define _LIBPUFFS_CONST_H
+
+#define ATIME 002 /* set if atime field needs updating */
+#define CTIME 004 /* set if ctime field needs updating */
+#define MTIME 010 /* set if mtime field needs updating */
+
+#endif /* !_LIBPUFFS_CONST_H */
#include <minix/fsdriver.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+
+#include "puffs.h"
+#include "puffs_priv.h"
+
+#include "const.h"
#include "proto.h"
#include "glo.h"
*/
#include "fs.h"
-#include <string.h>
-#include <assert.h>
-
-#include "puffs.h"
-#include "puffs_priv.h"
-
void release_node(struct puffs_usermount *pu, struct puffs_node *pn)
{
*/
struct puffs_node *pn;
- if ((pn = puffs_pn_nodewalk(global_pu, 0, &ino_nr)) == NULL) {
+ if ((pn = puffs_pn_nodewalk(global_pu, find_inode_cb, &ino_nr)) == NULL) {
/* XXX Probably removed from the list, see puffs_pn_remove() */
struct puffs_node *pn_cur, *pn_next;
pn_cur = LIST_FIRST(&global_pu->pu_pnode_removed_lst);
#include "fs.h"
-#include <stdlib.h>
-#include <assert.h>
-
-#include "puffs.h"
-#include "puffs_priv.h"
-
-
/*===========================================================================*
* fs_trunc *
*===========================================================================*/
struct puffs_node *pn;
PUFFS_MAKECRED(pcr, &global_kcred);
- if ((pn = puffs_pn_nodewalk(global_pu, 0, &ino_nr)) == NULL)
+ if ((pn = puffs_pn_nodewalk(global_pu, find_inode_cb, &ino_nr)) == NULL)
return(EINVAL);
if (end == 0) {
if (global_pu->pu_ops.puffs_node_setattr == NULL)
return(EINVAL);
-
+
puffs_vattr_null(&va);
va.va_size = start;
struct puffs_cn pcn = {&pkcnp, (struct puffs_cred *) __UNCONST(pcr), {0,0,0}};
if (global_pu->pu_ops.puffs_node_link == NULL)
- return(OK);
+ return(OK);
- if ((pn = puffs_pn_nodewalk(global_pu, 0, &ino_nr)) == NULL)
+ if ((pn = puffs_pn_nodewalk(global_pu, find_inode_cb, &ino_nr)) == NULL)
return(EINVAL);
/* Check to see if the file has maximum number of links already. */
if (S_ISDIR(pn->pn_va.va_mode))
return(EPERM);
- if ((pn_dir = puffs_pn_nodewalk(global_pu, 0, &dir_nr)) == NULL)
+ if ((pn_dir = puffs_pn_nodewalk(global_pu, find_inode_cb, &dir_nr)) == NULL)
return(EINVAL);
if (pn_dir->pn_va.va_nlink == NO_LINK) {
if (buildpath)
global_pu->pu_pathfree(global_pu, &pcn.pcn_po_full);
-
+
if (r != OK) return(EINVAL);
(void)clock_time(&cur_time);
if (bytes > sizeof(path))
bytes = sizeof(path);
-
- if ((pn = puffs_pn_nodewalk(global_pu, 0, &ino_nr)) == NULL)
+
+ if ((pn = puffs_pn_nodewalk(global_pu, find_inode_cb, &ino_nr)) == NULL)
return(EINVAL);
if (!S_ISLNK(pn->pn_va.va_mode))
strcpy(pcn_targ.pcn_name, new_name);
/* Get old dir pnode */
- if ((old_dirp = puffs_pn_nodewalk(global_pu, 0, &old_dir_nr)) == NULL)
+ if ((old_dirp = puffs_pn_nodewalk(global_pu, find_inode_cb,
+ &old_dir_nr)) == NULL)
return(ENOENT);
old_ip = advance(old_dirp, pcn_src.pcn_name);
return(EBUSY);
/* Get new dir pnode */
- if ((new_dirp = puffs_pn_nodewalk(global_pu, 0, &new_dir_nr)) == NULL) {
+ if ((new_dirp = puffs_pn_nodewalk(global_pu, find_inode_cb,
+ &new_dir_nr)) == NULL) {
return(ENOENT);
} else {
if (new_dirp->pn_va.va_nlink == NO_LINK) {
assert(pcn.pcn_namelen <= NAME_MAX);
strcpy(pcn.pcn_name, name);
- if ((pn_dir = puffs_pn_nodewalk(global_pu, 0, &dir_nr)) == NULL)
+ if ((pn_dir = puffs_pn_nodewalk(global_pu, find_inode_cb, &dir_nr)) == NULL)
return(EINVAL);
/* The last directory exists. Does the file also exist? */
*===========================================================================*/
static int remove_dir(
struct puffs_node *pn_dir, /* parent directory */
- struct puffs_node *pn, /* directory to be removed */
- struct puffs_cn *pcn /* Name, creads of directory */
+ struct puffs_node *pn, /* directory to be removed */
+ struct puffs_cn *pcn /* Name, creads of directory */
)
{
/* A directory file has to be removed. Five conditions have to met:
- * - The file must be a directory
+ * - The file must be a directory
* - The directory must be empty (except for . and ..)
* - The final component of the path must not be . or ..
* - The directory must not be the root of a mounted file system (VFS)
if (pn->pn_va.va_fileid == global_pu->pu_pn_root->pn_va.va_fileid)
return(EBUSY); /* can't remove 'root' */
-
+
if (buildpath) {
r = puffs_path_pcnbuild(global_pu, pcn, pn_dir);
if (r) return(EINVAL);
*===========================================================================*/
static int unlink_file(
struct puffs_node *dirp, /* parent directory of file */
- struct puffs_node *pn, /* pnode of file, may be NULL too. */
- struct puffs_cn *pcn /* Name, creads of file */
+ struct puffs_node *pn, /* pnode of file, may be NULL too. */
+ struct puffs_cn *pcn /* Name, creads of file */
)
{
/* Unlink 'file_name'; pn must be the pnode of 'file_name' */
assert(pn != NULL);
if (global_pu->pu_ops.puffs_node_remove == NULL)
- return(EINVAL);
+ return(EINVAL);
if (S_ISDIR(pn->pn_va.va_mode))
return(EPERM);
--- /dev/null
+
+#include "fs.h"
+
+static message fs_msg;
+static int fs_ipc_status;
+static int fs_pending;
+
+#define PUFFS_MAX_ARGS 20
+
+/*===========================================================================*
+ * sef_cb_init_fresh *
+ *===========================================================================*/
+static int sef_cb_init_fresh(int type, sef_init_info_t *info)
+{
+/* Initialize the Minix file server. */
+ return(OK);
+}
+
+/*===========================================================================*
+ * sef_cb_signal_handler *
+ *===========================================================================*/
+static void sef_cb_signal_handler(int signo)
+{
+ /* Only check for termination signal, ignore anything else. */
+ if (signo != SIGTERM) return;
+
+ exitsignaled = 1;
+ if (mounted)
+ fs_sync();
+
+ sef_cancel();
+}
+
+/*===========================================================================*
+ * sef_local_startup *
+ *===========================================================================*/
+static void sef_local_startup(void)
+{
+ /* Register init callbacks. */
+ sef_setcb_init_fresh(sef_cb_init_fresh);
+
+ /* Register signal callbacks. */
+ sef_setcb_signal_handler(sef_cb_signal_handler);
+
+ /* Let SEF perform startup. */
+ sef_startup();
+}
+
+/*===========================================================================*
+ * get_work *
+ *===========================================================================*/
+static int get_work(message *msg, int *ipc_status)
+{
+ int r;
+
+ for (;;) {
+ if ((r = sef_receive_status(ANY, msg, ipc_status)) != OK) {
+ if (r == EINTR) /* sef_cancel from signal handler? */
+ break; /* see if we can exit the main loop */
+ panic("sef_receive failed: %d", r);
+ }
+ if (msg->m_source == VFS_PROC_NR)
+ break;
+ lpuffs_debug("libpuffs: unexpected source %d\n", msg->m_source);
+ }
+
+ return r;
+}
+
+int __wrap_main(int argc, char *argv[]);
+int __real_main(int argc, char* argv[]);
+
+int __wrap_main(int argc, char *argv[])
+{
+ int i;
+ int new_argc = 0;
+ static char* new_argv[PUFFS_MAX_ARGS];
+ char *name;
+
+ /* SEF local startup. */
+ env_setargs(argc, argv);
+ sef_local_startup();
+
+ global_kcred.pkcr_type = PUFFCRED_TYPE_INTERNAL;
+
+ if (argc < 3) {
+ panic("Unexpected arguments, use:\
+ mount -t fs /dev/ /dir [-o option1,option2]\n");
+ }
+
+ name = argv[0] + strlen(argv[0]);
+ while (*name != '/' && name != argv[0])
+ name--;
+ if (name != argv[0])
+ name++;
+ strcpy(fs_name, name);
+
+ new_argv[new_argc] = argv[0];
+ new_argc++;
+
+ for (i = 1; i < argc; i++) {
+ if (new_argc >= PUFFS_MAX_ARGS) {
+ panic("Too many arguments, change PUFFS_MAX_ARGS");
+ }
+ new_argv[new_argc] = argv[i];
+ new_argc++;
+ }
+
+ assert(new_argc > 0);
+
+ /* Get the mount request from VFS, so we can deal with it later. */
+ (void)get_work(&fs_msg, &fs_ipc_status);
+ fs_pending = TRUE;
+
+ return __real_main(new_argc, new_argv);
+}
+
+/*
+ * Receive a message unless one was already pending. Process the message, and
+ * send a reply if necessary. Return whether puffs should keep running.
+ */
+int
+lpuffs_pump(void)
+{
+
+ if (fs_pending == TRUE || get_work(&fs_msg, &fs_ipc_status) == OK) {
+ fs_pending = FALSE;
+
+ fsdriver_process(&puffs_table, &fs_msg, fs_ipc_status, FALSE);
+ }
+
+ return mounted || !exitsignaled;
+}
+
+/*
+ * Initialize MINIX3-specific settings.
+ */
+void
+lpuffs_init(struct puffs_usermount * pu)
+{
+
+ buildpath = pu->pu_flags & PUFFS_FLAG_BUILDPATH; /* XXX */
+
+ LIST_INIT(&pu->pu_pnode_removed_lst);
+
+ global_pu = pu;
+}
*/
#include "fs.h"
-#include <assert.h>
-
-#include "puffs.h"
-#include "puffs_priv.h"
/*===========================================================================*
* fs_sync *
#include "fs.h"
#include <fcntl.h>
-#include <string.h>
#include <minix/vfsif.h>
-#include "puffs_priv.h"
-
/*===========================================================================*
* fs_mount *
*===========================================================================*/
struct puffs_node *pn;
mode_t bits;
- if ((pn = puffs_pn_nodewalk(global_pu, 0, &ino_nr)) == NULL)
+ if ((pn = puffs_pn_nodewalk(global_pu, find_inode_cb, &ino_nr)) == NULL)
return(EINVAL);
if (pn->pn_mountpoint) r = EBUSY;
/* Always force unmounting, as VFS will not tolerate failure. */
error = global_pu->pu_ops.puffs_fs_unmount(global_pu, MNT_FORCE);
if (error) {
- lpuffs_debug("user handler failed to unmount filesystem!\
+ lpuffs_debug("user handler failed to unmount filesystem!\
Force unmount!\n");
- }
-
+ }
+
fs_sync();
/* Finish off the unmount. */
*/
#include "fs.h"
-#include <string.h>
-#include <assert.h>
-
-#include "puffs.h"
-#include "puffs_priv.h"
-
/*===========================================================================*
* fs_create *
struct timespec cur_time;
if (global_pu->pu_ops.puffs_node_create == NULL) {
- lpuffs_debug("No puffs_node_create");
+ lpuffs_debug("No puffs_node_create");
return(ENFILE);
}
strcpy(pcn.pcn_name, name);
/* Get last directory pnode (i.e., directory that will hold the new pnode) */
- if ((pn_dir = puffs_pn_nodewalk(global_pu, 0, &dir_nr)) == NULL)
+ if ((pn_dir = puffs_pn_nodewalk(global_pu, find_inode_cb, &dir_nr)) == NULL)
return(ENOENT);
memset(&pni, 0, sizeof(pni));
pni.pni_cookie = (void** )&pn;
(void)clock_time(&cur_time);
-
+
memset(&va, 0, sizeof(va));
va.va_type = VREG;
va.va_mode = mode;
struct timespec cur_time;
if (global_pu->pu_ops.puffs_node_mknod == NULL) {
- lpuffs_debug("No puffs_node_mknod");
+ lpuffs_debug("No puffs_node_mknod");
return(ENFILE);
}
strcpy(pcn.pcn_name, name);
/* Get last directory pnode */
- if ((pn_dir = puffs_pn_nodewalk(global_pu, 0, &dir_nr)) == NULL)
+ if ((pn_dir = puffs_pn_nodewalk(global_pu, find_inode_cb, &dir_nr)) == NULL)
return(ENOENT);
memset(&pni, 0, sizeof(pni));
struct timespec cur_time;
if (global_pu->pu_ops.puffs_node_mkdir == NULL) {
- lpuffs_debug("No puffs_node_mkdir");
+ lpuffs_debug("No puffs_node_mkdir");
return(ENFILE);
}
strcpy(pcn.pcn_name, name);
/* Get last directory pnode */
- if ((pn_dir = puffs_pn_nodewalk(global_pu, 0, &dir_nr)) == NULL)
+ if ((pn_dir = puffs_pn_nodewalk(global_pu, find_inode_cb, &dir_nr)) == NULL)
return(ENOENT);
-
+
(void)clock_time(&cur_time);
memset(&pni, 0, sizeof(pni));
return(ENAMETOOLONG);
}
- if ((pn_dir = puffs_pn_nodewalk(global_pu, 0, &dir_nr)) == NULL)
+ if ((pn_dir = puffs_pn_nodewalk(global_pu, find_inode_cb, &dir_nr)) == NULL)
return(EINVAL);
memset(&pni, 0, sizeof(pni));
#include <sys/stat.h>
#include <sys/types.h>
-#include <assert.h>
-#include <errno.h>
-#include <puffs.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include "puffs.h"
-#include "puffs_priv.h"
-
-
/*===========================================================================*
* fs_lookup *
*===========================================================================*/
struct puffs_node *pn, *pn_dir;
/* Find the pnode of the directory node. */
- if ((pn_dir = puffs_pn_nodewalk(global_pu, 0, &dir_nr)) == NULL) {
+ if ((pn_dir = puffs_pn_nodewalk(global_pu, find_inode_cb, &dir_nr)) == NULL) {
lpuffs_debug("nodewalk failed\n");
return(EINVAL);
}
if (global_pu->pu_ops.puffs_node_setattr == NULL)
return(EINVAL);
- if ((pn = puffs_pn_nodewalk(global_pu, 0, &ino_nr)) == NULL)
+ if ((pn = puffs_pn_nodewalk(global_pu, find_inode_cb, &ino_nr)) == NULL)
return(EINVAL);
-
+
puffs_vattr_null(&va);
/* Clear setgid bit if file is not in caller's grp */
va.va_mode = (pn->pn_va.va_mode & ~ALL_MODES) | (*mode & ALL_MODES);
struct vattr va;
PUFFS_MAKECRED(pcr, &global_kcred);
- if ((pn = puffs_pn_nodewalk(global_pu, 0, &ino_nr)) == NULL)
+ if ((pn = puffs_pn_nodewalk(global_pu, find_inode_cb, &ino_nr)) == NULL)
return(EINVAL);
puffs_vattr_null(&va);
int fs_utime(ino_t ino_nr, struct timespec *atime, struct timespec *mtime);
/* utility.c */
+void *find_inode_cb(struct puffs_usermount *pu, struct puffs_node *pn,
+ void *arg);
int update_timens(struct puffs_node *pn, int fl, struct timespec *);
-void lpuffs_debug(const char *format, ...)
- __attribute__((__format__(__printf__, 1, 2)));
#endif /* PUFFS_PROTO_H */
#include "fs.h"
#include <stddef.h>
-#include <string.h>
-#include <stdlib.h>
#include <dirent.h>
-#include <assert.h>
#include <sys/param.h>
-#include "puffs.h"
-#include "puffs_priv.h"
-
#define GETDENTS_BUFSIZ 4096
static char getdents_buf[GETDENTS_BUFSIZ];
struct puffs_node *pn;
PUFFS_MAKECRED(pcr, &global_kcred);
- if ((pn = puffs_pn_nodewalk(global_pu, 0, &ino_nr)) == NULL) {
+ if ((pn = puffs_pn_nodewalk(global_pu, find_inode_cb, &ino_nr)) == NULL) {
lpuffs_debug("walk failed...\n");
return(EINVAL);
}
struct timespec cur_time;
PUFFS_MAKECRED(pcr, &global_kcred);
- if ((pn = puffs_pn_nodewalk(global_pu, 0, &ino_nr)) == NULL) {
+ if ((pn = puffs_pn_nodewalk(global_pu, find_inode_cb, &ino_nr)) == NULL) {
lpuffs_debug("walk failed...\n");
return(EINVAL);
}
int eofflag = 0;
PUFFS_MAKECRED(pcr, &global_kcred);
- if ((pn = puffs_pn_nodewalk(global_pu, 0, &ino_nr)) == NULL) {
+ if ((pn = puffs_pn_nodewalk(global_pu, find_inode_cb, &ino_nr)) == NULL) {
lpuffs_debug("walk failed...\n");
return(EINVAL);
}
*/
#include "fs.h"
-#include <sys/stat.h>
-#include <sys/statvfs.h>
-
-#include "puffs.h"
-#include "puffs_priv.h"
-
/*===========================================================================*
* fs_stat *
return(EINVAL);
}
- if ((pn = puffs_pn_nodewalk(global_pu, 0, &ino_nr)) == NULL) {
- lpuffs_debug("walk failed...\n");
+ if ((pn = puffs_pn_nodewalk(global_pu, find_inode_cb, &ino_nr)) == NULL) {
+ lpuffs_debug("walk failed...\n");
return(EINVAL);
}
*/
#include "fs.h"
-#include "puffs.h"
-#include "puffs_priv.h"
/*===========================================================================*
if (global_pu->pu_ops.puffs_node_setattr == NULL)
return(EINVAL);
- if( (pn = puffs_pn_nodewalk(global_pu, 0, &ino_nr)) == NULL)
+ if( (pn = puffs_pn_nodewalk(global_pu, find_inode_cb, &ino_nr)) == NULL)
return(EINVAL);
puffs_vattr_null(&va);
#include "fs.h"
-#include <assert.h>
#include <stdarg.h>
-#include "puffs.h"
-#include "puffs_priv.h"
+/*
+ * Match by inode number in a puffs_pn_nodewalk call. This should not exist.
+ */
+void *
+find_inode_cb(struct puffs_usermount * __unused pu, struct puffs_node * pn,
+ void * arg)
+{
+ if (pn->pn_va.va_fileid == *(ino_t *)arg)
+ return pn;
+ else
+ return NULL;
+}
/*===========================================================================*
* update_timens *
new_time = *t;
else
(void)clock_time(&new_time);
-
+
puffs_vattr_null(&va);
/* librefuse modifies atime and mtime together,
* so set old values to avoid setting either one
* lpuffs_debug *
*===========================================================================*/
void lpuffs_debug(const char *format, ...)
-{
+{
char buffer[256];
va_list args;
va_start (args, format);