* terms of the GNU Lesser General Public License
* (see cit/LGPL or http://www.gnu.org/licenses/lgpl.html)
*
- * Cplant(TM) Copyright 1998-2005 Sandia Corporation.
+ * Cplant(TM) Copyright 1998-2006 Sandia Corporation.
* Under the terms of Contract DE-AC04-94AL85000, there is a non-exclusive
* license for use of this work by or on behalf of the US Government.
* Export of this program may require a license from the United States
* lee@sandia.gov
*/
+#ifdef __linux__
#define _BSD_SOURCE
+#endif
-#if SYSIO_TRACING
+#ifdef SYSIO_TRACING
#include <stdio.h>
#endif
#include <stdlib.h>
-#if SYSIO_TRACING
+#if defined(_BSD_SOURCE) || defined(SYSIO_TRACING)
#include <sys/syscall.h>
#endif
#include <unistd.h>
#include <string.h>
#include <errno.h>
-#if SYSIO_TRACING
+#ifdef SYSIO_TRACING
#include <stdarg.h>
#endif
#include <limits.h>
#include "sysio.h"
#include "xtio.h"
-#if SYSIO_TRACING
+#ifdef SYSIO_TRACING
#include "native.h"
#endif
#include "inode.h"
#include "stdfd.h"
#endif
-#if SYSIO_TRACING
+#ifdef SYSIO_TRACING
/*
* Tracing callback record.
*/
struct trace_callback {
- TAILQ_ENTRY(trace_callback) links;
- void (*f)(const char *file, const char *func, int line);
+ TAILQ_ENTRY(trace_callback) links; /* trace list links */
+ void (*f)(const char *file, /* callback function */
+ const char *func,
+ int line,
+ void *data);
+ void *data; /* callback data */
+ void (*destructor)(void *data); /* data destructor */
};
/*
* Initialize a tracing callback record.
*/
-#define TCB_INIT(__tcb, __f) \
+#define TCB_INIT(__tcb, __f, __d, __destroy) \
do { \
(__tcb)->f = (__f); \
- } while (0);
+ (__tcb)->data = (__d); \
+ (__tcb)->destructor = (__destroy); \
+ } while (0)
/*
* Trace queue head record.
#endif
/*
+ * In sysio_init we'll allow simple comments, strings outside {}
+ * delimited by COMMENT_INTRO, and '\n' or '\0'
+ */
+#define COMMENT_INTRO '#'
+
+/*
+ * In sysio_init we'll allow simple comments, strings outside {}
+ * delimited by COMMENT_INTRO, and '\n' or '\0'
+ */
+#define COMMENT_INTRO '#'
+
+/*
* Sysio library initialization. Must be called before anything else in the
* library.
*/
extern int _sysio_sockets_init(void);
#endif
-#if SYSIO_TRACING
+#ifdef SYSIO_TRACING
/*
* Initialize tracing callback queues.
*/
_sysio_unmount_all() == 0))
abort();
-#if ZERO_SUM_MEMORY
+#ifdef ZERO_SUM_MEMORY
_sysio_fd_shutdown();
_sysio_i_shutdown();
_sysio_fssw_shutdown();
-#if SYSIO_TRACING
+ _sysio_access_shutdown();
+#ifdef SYSIO_TRACING
{
struct trace_callback *tcb;
/*
* Empty the trace queues and free the entries.
*/
- while ((tcb = _sysio_entry_trace_head.tqh_first) != NULL) {
- TAILQ_REMOVE(&_sysio_entry_trace_head, tcb, links);
- free(tcb);
- }
- while ((tcb = _sysio_exit_trace_head.tqh_first) != NULL) {
- TAILQ_REMOVE(&_sysio_exit_trace_head, tcb, links);
- free(tcb);
- }
+ while ((tcb = _sysio_entry_trace_head.tqh_first) != NULL)
+ _sysio_remove_trace(&_sysio_entry_trace_head, tcb);
+ while ((tcb = _sysio_exit_trace_head.tqh_first) != NULL)
+ _sysio_remove_trace(&_sysio_exit_trace_head, tcb);
}
#endif
#endif
}
-#if SYSIO_TRACING
+#ifdef SYSIO_TRACING
#if !(defined(_HAVE_ASPRINTF) && _HAVE_ASPRINTF)
/*
_sysio_register_trace(void *q,
void (*f)(const char *file,
const char *func,
- int line))
+ int line,
+ void *data),
+ void *data,
+ void (*destructor)(void *data))
{
struct trace_callback *tcb;
tcb = malloc(sizeof(struct trace_callback));
if (!tcb)
return NULL;
- TCB_INIT(tcb, f);
+ TCB_INIT(tcb, f, data, destructor);
TAILQ_INSERT_TAIL((struct trace_q *)q, tcb, links);
return tcb;
}
void
_sysio_remove_trace(void *q, void *p)
{
+ struct trace_callback *tcb;
+
+ tcb = (struct trace_callback *)p;
- TAILQ_REMOVE((struct trace_q *)q, (struct trace_callback *)p, links);
- free(p);
+ if (tcb->destructor)
+ (*tcb->destructor)(tcb->data);
+ TAILQ_REMOVE((struct trace_q *)q, tcb, links);
+ free(tcb);
}
void
tcb = ((struct trace_q *)q)->tqh_first;
while (tcb) {
- (*tcb->f)(file, func, line);
+ (*tcb->f)(file, func, line, tcb->data);
tcb = tcb->links.tqe_next;
}
}
static void
_sysio_trace_entry(const char *file __IS_UNUSED,
const char *func,
- int line __IS_UNUSED)
+ int line __IS_UNUSED,
+ void *data __IS_UNUSED)
{
_sysio_cprintf("+ENTER+ %s\n", func);
static void
_sysio_trace_exit(const char *file __IS_UNUSED,
const char *func,
- int line __IS_UNUSED)
+ int line __IS_UNUSED,
+ void *data __IS_UNUSED)
{
_sysio_cprintf("+EXIT+ %s\n", func);
struct intent intent;
dev_t dev;
int err;
+ enum {
+ CREATE_DIR = 1,
+ CREATE_CHR = 2,
+ CREATE_BLK = 3,
+ CREATE_FILE = 4
+ } op;
+ int intent_mode;
+ struct inode *ino;
+ int i;
len = strlen(args);
if (_sysio_get_args(args, v) - args != (ssize_t )len ||
if (!(dir = _sysio_cwd) && !(dir = _sysio_root))
return -ENOENT;
+
+ /*
+ * Init, get the operation, setup the intent.
+ */
err = 0;
mode = perms;
+ op = 0;
if (strcmp(v[0].ovi_value, "dir") == 0) {
- INTENT_INIT(&intent, INT_CREAT, &mode, 0);
- err =
- _sysio_namei(dir, v[1].ovi_value, ND_NEGOK, &intent, &pno);
- if (err)
- return err;
- if (pno->p_base->pb_ino)
- err = -EEXIST;
- else if (IS_RDONLY(pno->p_parent,
- pno->p_parent->p_base->pb_ino))
- err = -EROFS;
- else {
- struct inode *ino;
-
- ino = pno->p_parent->p_base->pb_ino;
- err = (*ino->i_ops.inop_mkdir)(pno, mode);
- }
- P_RELE(pno);
+ op = CREATE_DIR;
+ INTENT_INIT(&intent, INT_CREAT, &mode, NULL);
} else if (strcmp(v[0].ovi_value, "chr") == 0) {
- if (!(v[5].ovi_value && parse_mm(v[5].ovi_value, &dev) == 0))
- return -EINVAL;
+ op = CREATE_CHR;
mode |= S_IFCHR;
- INTENT_INIT(&intent, INT_CREAT, &mode, 0);
- err =
- _sysio_namei(dir, v[1].ovi_value, ND_NEGOK, &intent, &pno);
- if (err)
- return err;
- if (pno->p_base->pb_ino)
- err = -EEXIST;
- else if (IS_RDONLY(pno->p_parent,
- pno->p_parent->p_base->pb_ino))
- err = -EROFS;
- else {
- struct inode *ino;
-
- ino = pno->p_parent->p_base->pb_ino;
- err = (*ino->i_ops.inop_mknod)(pno, mode, dev);
- }
- P_RELE(pno);
+ INTENT_INIT(&intent, INT_CREAT, &mode, NULL);
+ if (!(v[5].ovi_value && parse_mm(v[5].ovi_value, &dev) == 0))
+ err = -EINVAL;
} else if (strcmp(v[0].ovi_value, "blk") == 0) {
- /*
- * We don't support block special files yet.
- */
- return -EINVAL;
+ op = CREATE_BLK;
+ mode |= S_IFBLK;
+ INTENT_INIT(&intent, INT_CREAT, &mode, NULL);
+ if (!(v[5].ovi_value && parse_mm(v[5].ovi_value, &dev) == 0))
+ err = -EINVAL;
} else if (strcmp(v[0].ovi_value, "file") == 0) {
- int i;
- struct inode *ino;
+ op = CREATE_FILE;
+ intent_mode = O_CREAT|O_EXCL;
+ INTENT_INIT(&intent, INT_CREAT, &mode, &intent_mode);
+ } else
+ err = -EINVAL;
+ if (err)
+ return err;
- i = O_CREAT|O_EXCL;
- INTENT_INIT(&intent, INT_CREAT, &mode, &i);
- err =
- _sysio_namei(dir, v[1].ovi_value, ND_NEGOK, &intent, &pno);
- if (err)
- return err;
+ /*
+ * Lookup the given path.
+ */
+ err =
+ _sysio_namei(dir,
+ v[1].ovi_value,
+ ND_NEGOK|ND_NOPERMCHECK,
+ &intent,
+ &pno);
+ if (err)
+ return err;
+
+ /*
+ * Perform.
+ */
+ switch (op) {
+ case CREATE_DIR:
+ err = _sysio_mkdir(pno, mode);
+ break;
+ case CREATE_CHR:
+ case CREATE_BLK:
+ err = _sysio_mknod(pno, mode, dev);
+ break;
+ case CREATE_FILE:
err = _sysio_open(pno, O_CREAT|O_EXCL, mode);
- if (err) {
- P_RELE(pno);
- return err;
- }
+ if (err)
+ break;
ino = pno->p_base->pb_ino;
- if (!err && v[6].ovi_value) {
+ if (v[6].ovi_value) {
struct iovec iovec;
struct intnl_xtvec xtvec;
struct ioctx io_context;
i = (*ino->i_ops.inop_close)(ino);
if (!err)
err = i;
- P_RELE(pno);
- } else
- err = -EINVAL;
+ break;
+ default:
+ abort();
+ }
+ P_RELE(pno);
return err;
}
if (_sysio_get_args(args, v) - args != (ssize_t )len || !v[0].ovi_value)
return -EINVAL;
- if (!(dir = _sysio_cwd) && !(dir = _sysio_root))
+ if (!(dir = _sysio_cwd) && !(dir = _sysio_root)) {
+ /*
+ * We have no namespace yet. They really need to give us
+ * something to work with.
+ */
return -ENOENT;
+ }
err = _sysio_namei(dir, v[0].ovi_value, 0, NULL, &pno);
if (err)
return err;
if (!(dir = _sysio_cwd) && !(dir = _sysio_root))
return -ENOENT;
- err = _sysio_namei(dir, v[0].ovi_value, 0, NULL, &pno);
+ err = _sysio_namei(dir, v[0].ovi_value, ND_NOPERMCHECK, NULL, &pno);
if (err)
return err;
err = _sysio_setattr(pno, pno->p_base->pb_ino, SETATTR_MODE, &stbuf);
return -ENOENT;
INTENT_INIT(&intent, INT_OPEN, &m, NULL);
pno = NULL;
- err = _sysio_namei(dir, v[0].ovi_value, 0, &intent, &pno);
+ err = _sysio_namei(dir, v[0].ovi_value, ND_NOPERMCHECK, &intent, &pno);
if (err)
return err;
fil = NULL;
return -EINVAL;
}
-#if SYSIO_TRACING
+#ifdef SYSIO_TRACING
/*
* Set/Unset tracing.
*/
if (entcb == NULL)
entcb =
_sysio_register_trace(_sysio_entry_trace_q,
- _sysio_trace_entry);
+ _sysio_trace_entry,
+ NULL,
+ NULL);
if (entcb == NULL)
return -errno;
if (exitcb == NULL)
exitcb =
_sysio_register_trace(_sysio_exit_trace_q,
- _sysio_trace_exit);
+ _sysio_trace_exit,
+ NULL,
+ NULL);
if (exitcb == NULL)
return -errno;
} else {
/*
* Discard leading white space.
*/
- while ((c = *arg) != '\0' &&
- !(c == '{' || strchr(IGNORE_WHITE, c) == NULL))
+ while ((c = *arg) != '\0' && strchr(IGNORE_WHITE, c))
arg++;
+ if (COMMENT_INTRO == c) {
+ /*
+ * Discard comment.
+ */
+ while (*arg && (*arg != '\n')) {
+ ++arg;
+ }
+ continue;
+ }
+
if (c == '\0')
break;
if (c != '{') {
if (err)
break;
}
-#if SYSIO_TRACING
+#ifdef SYSIO_TRACING
if (err)
_sysio_cprintf("+NS init+ failed at expr %u (last = %s): %s\n",
count,
return err;
}
-#if DEFER_INIT_CWD
+#ifdef DEFER_INIT_CWD
/*
* Set deferred initial working directory.
*/
/*
* Given an identifier and it's arguments, perform optional initializations.
*/
-int
+int
_sysio_boot(const char *opt, const char *arg)
{
struct option_value_info vec[] = {
-#if SYSIO_TRACING
+#ifdef SYSIO_TRACING
{ "trace", NULL }, /* tracing? */
#endif
{ "namespace", NULL }, /* init namespace? */
-#if DEFER_INIT_CWD
+#ifdef DEFER_INIT_CWD
{ "cwd", NULL }, /* init working dir */
#endif
{ NULL, NULL }
struct option_value_info *v;
unsigned u;
static int (*f[])(const char *) = {
-#if SYSIO_TRACING
+#ifdef SYSIO_TRACING
_sysio_boot_tracing,
#endif
_sysio_boot_namespace,
-#if DEFER_INIT_CWD
+#ifdef DEFER_INIT_CWD
_sysio_boot_cwd,
#endif
NULL /* can't happen */