* terms of the GNU Lesser General Public License
* (see cit/LGPL or http://www.gnu.org/licenses/lgpl.html)
*
- * Cplant(TM) Copyright 1998-2004 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
+#ifdef SYSIO_TRACING
+#include <stdio.h>
+#endif
#include <stdlib.h>
+#if defined(_BSD_SOURCE) || defined(SYSIO_TRACING)
+#include <sys/syscall.h>
+#endif
#include <unistd.h>
#include <string.h>
#include <errno.h>
+#ifdef SYSIO_TRACING
+#include <stdarg.h>
+#endif
#include <limits.h>
#include <assert.h>
#include <sys/types.h>
#include <sys/stat.h>
-#include <sys/queue.h>
-#include <sys/uio.h>
-
-#include <sys/stat.h>
#include <fcntl.h>
+#include <sys/uio.h>
+#include <sys/queue.h>
#include "sysio.h"
+#include "xtio.h"
+#ifdef SYSIO_TRACING
+#include "native.h"
+#endif
#include "inode.h"
#include "fs.h"
#include "mount.h"
#include "file.h"
#include "dev.h"
-#include "xtio.h"
#ifdef STDFD_DEV
#include "stdfd.h"
#endif
+#ifdef SYSIO_TRACING
+
/*
- * The namespace assembly buffer passes args with a `name'=`value'
- * syntax. We use the following to record that in various
- * routines below.
+ * Tracing callback record.
*/
-struct named_argument {
- const char *name; /* arg name */
- char *value; /* arg value */
+struct trace_callback {
+ 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, __d, __destroy) \
+ do { \
+ (__tcb)->f = (__f); \
+ (__tcb)->data = (__d); \
+ (__tcb)->destructor = (__destroy); \
+ } while (0)
+
+/*
+ * Trace queue head record.
+ */
+TAILQ_HEAD(trace_q, trace_callback);
+
+/*
+ * The entry and exit queue heads, and queue pointers.
+ */
+static struct trace_q _sysio_entry_trace_head;
+void *_sysio_entry_trace_q = &_sysio_entry_trace_head;
+static struct trace_q _sysio_exit_trace_head;
+void *_sysio_exit_trace_q = &_sysio_exit_trace_head;
+#endif
+
+/*
* White space characters.
*/
#define IGNORE_WHITE " \t\r\n"
/*
+ * Check if long overflows integer range.
+ */
+#if LONG_MAX <= INT_MAX
+#define _irecheck(_l, _e) \
+ ((_l) == LONG_MAX && (_e) == ERANGE)
+#else
+#define _irecheck(_l, _e) \
+ ((_l) > INT_MAX)
+#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.
*/
{
int err;
#ifdef WITH_SOCKETS
- int _sysio_sockets_init(void);
+ extern int _sysio_sockets_init(void);
+#endif
+
+#ifdef SYSIO_TRACING
+ /*
+ * Initialize tracing callback queues.
+ */
+ TAILQ_INIT(&_sysio_entry_trace_head);
+ TAILQ_INIT(&_sysio_exit_trace_head);
#endif
err = _sysio_ioctx_init();
goto error;
#endif
#ifdef WITH_SOCKETS
- err = _sysio_sockets_init();
- if (err)
- goto error;
+ err = _sysio_sockets_init();
+ if (err)
+ goto error;
#endif
goto out;
_sysio_unmount_all() == 0))
abort();
-#if ZERO_SUM_MEMORY
+#ifdef ZERO_SUM_MEMORY
_sysio_fd_shutdown();
_sysio_i_shutdown();
_sysio_fssw_shutdown();
+ _sysio_access_shutdown();
+ free(incore_dir_template);
+#ifdef SYSIO_TRACING
+ {
+ struct trace_callback *tcb;
+
+ /*
+ * Empty the trace queues and free the entries.
+ */
+ 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
}
+#ifdef SYSIO_TRACING
+
+#if !(defined(_HAVE_ASPRINTF) && _HAVE_ASPRINTF)
+/*
+ * Print a string to allocated memory.
+ */
+static int
+vasprintf(char **strp, const char *fmt, va_list ap)
+{
+ size_t siz;
+ int oerrno;
+ char *s;
+ va_list aq;
+ int n;
+
+ siz = 50;
+ oerrno = errno;
+ if (!(s = malloc(siz))) {
+ errno = oerrno;
+ return -1;
+ }
+ for (;;) {
+ va_copy(aq, ap);
+ n = vsnprintf (s, siz, fmt, aq);
+ va_end(aq);
+ if (n > -1 && (size_t )n < siz)
+ break;
+ if (n > -1) /* glibc 2.1 */
+ siz = n+1; /* precise */
+ else /* glibc 2.0 */
+ siz *= 2; /* twice the old */
+ if (!(s = realloc (s, siz)))
+ break;
+ }
+ *strp = s;
+ errno = oerrno;
+ return n;
+}
+
+#if 0
+static int
+asprintf(char **strp, const char *fmt, ...)
+{
+ va_list ap;
+ int n;
+
+ va_start(ap, fmt);
+ n = vasprintf(strp, fmt, ap);
+ va_end(ap);
+ return n;
+}
+#endif
+#endif /* !(defined(_HAVE_ASPRINTF) && _HAVE_ASPRINTF) */
+
+static void
+_sysio_cwrite(const char *buf, size_t len)
+{
+ int oerrno;
+
+ oerrno = errno;
+ (void )syscall(SYSIO_SYS_write, STDERR_FILENO, buf, len);
+ errno = oerrno;
+}
+
+/*
+ * Console printf.
+ */
+void
+_sysio_cprintf(const char *fmt, ...)
+{
+ va_list ap;
+ int len;
+ char *buf;
+
+ va_start(ap, fmt);
+ buf = NULL;
+ len = vasprintf(&buf, fmt, ap);
+ va_end(ap);
+ if (len < 0)
+ return;
+ _sysio_cwrite(buf, len);
+ free(buf);
+}
+
+/*
+ * Register a trace callback.
+ *
+ * The pointer to the trace record is returned.
+ */
+void *
+_sysio_register_trace(void *q,
+ void (*f)(const char *file,
+ const char *func,
+ 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, data, destructor);
+ TAILQ_INSERT_TAIL((struct trace_q *)q, tcb, links);
+ return tcb;
+}
+
+/*
+ * Remove a registered trace callback.
+ */
+void
+_sysio_remove_trace(void *q, void *p)
+{
+ struct trace_callback *tcb;
+
+ tcb = (struct trace_callback *)p;
+
+ if (tcb->destructor)
+ (*tcb->destructor)(tcb->data);
+ TAILQ_REMOVE((struct trace_q *)q, tcb, links);
+ free(tcb);
+}
+
+void
+/*
+ * Run a trace queue, making all the callbacks.
+ */
+_sysio_run_trace_q(void *q,
+ const char *file,
+ const char *func,
+ int line)
+{
+ struct trace_callback *tcb;
+
+ tcb = ((struct trace_q *)q)->tqh_first;
+ while (tcb) {
+ (*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,
+ 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,
+ void *data __IS_UNUSED)
+{
+
+ _sysio_cprintf("+EXIT+ %s\n", func);
+}
+#endif /* defined(SYSIO_TRACING) */
+
/*
* (kind of)Duplicates strtok function.
*
* or NUL character is success.
*
*/
-static const char *
-get_token(const char *buf,
+const char *
+_sysio_get_token(const char *buf,
int accepts,
const char *delim,
const char *ignore,
*
* NB: Alters the passed buffer.
*/
-static char *
-get_args(char *buf, struct named_argument *vec)
+char *
+_sysio_get_args(char *buf, struct option_value_info *vec)
{
char *nxt;
char *name, *value;
- struct named_argument *v;
+ struct option_value_info *v;
for (;;) {
- nxt = (char *)get_token(buf, 1, "=,", IGNORE_WHITE, name = buf);
+ nxt =
+ (char *)_sysio_get_token(buf,
+ 1,
+ "=,",
+ IGNORE_WHITE,
+ name = buf);
if (!nxt ||
(nxt != buf && *name == '\0' && buf + strlen(buf) == nxt)) {
buf = NULL;
}
if (*name == '\0')
break;
- buf = (char *)get_token(nxt, 1, ",", IGNORE_WHITE, value = nxt);
+ buf =
+ (char *)_sysio_get_token(nxt,
+ 1,
+ ",",
+ IGNORE_WHITE,
+ value = nxt);
if (*value == '\0')
value = NULL;
- for (v = vec; v->name; v++)
- if (strcmp(v->name, name) == 0)
+ for (v = vec; v->ovi_name; v++)
+ if (strcmp(v->ovi_name, name) == 0)
break;
- if (!v->name)
+ if (!v->ovi_name)
return NULL;
- v->value = value;
+ v->ovi_value = value;
}
return buf;
do_creat(char *args)
{
size_t len;
- struct named_argument v[] = {
+ struct option_value_info v[] = {
{ "ft", NULL }, /* file type */
{ "nm", NULL }, /* name */
{ "pm", NULL }, /* permissions */
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 (get_args(args, v) - args != (ssize_t )len ||
- !(v[0].value &&
- v[1].value &&
- v[2].value))
+ if (_sysio_get_args(args, v) - args != (ssize_t )len ||
+ !(v[0].ovi_value &&
+ v[1].ovi_value &&
+ v[2].ovi_value))
return -EINVAL;
- perms = strtol(v[2].value, (char **)&cp, 0);
+ perms = strtol(v[2].ovi_value, (char **)&cp, 0);
if (*cp ||
perms < 0 ||
(perms == LONG_MAX && errno == ERANGE) ||
((unsigned)perms & ~07777))
return -EINVAL;
- if (v[3].value) {
- owner = strtol(v[3].value, (char **)&cp, 0);
+ if (v[3].ovi_value) {
+ owner = strtol(v[3].ovi_value, (char **)&cp, 0);
if (*cp ||
((owner == LONG_MIN || owner == LONG_MAX)
&& errno == ERANGE))
return -EINVAL;
} else
owner = getuid();
- if (v[4].value) {
- group = strtol(v[4].value, (char **)&cp, 0);
+ if (v[4].ovi_value) {
+ group = strtol(v[4].ovi_value, (char **)&cp, 0);
if (*cp ||
((group == LONG_MIN || group == LONG_MAX) &&
errno == ERANGE))
if (!(dir = _sysio_cwd) && !(dir = _sysio_root))
return -ENOENT;
+
+ /*
+ * Init, get the operation, setup the intent.
+ */
err = 0;
mode = perms;
- if (strcmp(v[0].value, "dir") == 0) {
- INTENT_INIT(&intent, INT_CREAT, &mode, 0);
- err = _sysio_namei(dir, v[1].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);
- } else if (strcmp(v[0].value, "chr") == 0) {
- if (!(v[5].value && parse_mm(v[5].value, &dev) == 0))
- return -EINVAL;
+ op = 0;
+ if (strcmp(v[0].ovi_value, "dir") == 0) {
+ op = CREATE_DIR;
+ INTENT_INIT(&intent, INT_CREAT, &mode, NULL);
+ } else if (strcmp(v[0].ovi_value, "chr") == 0) {
+ op = CREATE_CHR;
mode |= S_IFCHR;
- INTENT_INIT(&intent, INT_CREAT, &mode, 0);
- err = _sysio_namei(dir, v[1].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);
- } else if (strcmp(v[0].value, "blk") == 0) {
- /*
- * We don't support block special files yet.
- */
- return -EINVAL;
- } else if (strcmp(v[0].value, "file") == 0) {
- int i;
- struct inode *ino;
+ 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) {
+ 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) {
+ 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].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].value) {
+ if (v[6].ovi_value) {
struct iovec iovec;
struct intnl_xtvec xtvec;
struct ioctx io_context;
/*
* Deposit optional file content.
*/
- iovec.iov_base = v[6].value;
- iovec.iov_len = strlen(v[6].value);
+ iovec.iov_base = v[6].ovi_value;
+ iovec.iov_len = strlen(v[6].ovi_value);
xtvec.xtv_off = 0;
xtvec.xtv_len = iovec.iov_len;
IOCTX_INIT(&io_context,
1,
- (ioid_t )&io_context,
1,
ino,
&iovec, 1,
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;
}
do_mnt(char *args)
{
size_t len;
- struct named_argument v[] = {
+ struct option_value_info v[] = {
{ "dev", NULL }, /* source (type:dev) */
{ "dir", NULL }, /* target dir */
{ "fl", NULL }, /* flags */
struct pnode *dir;
len = strlen(args);
- if (get_args(args, v) - args != (ssize_t )len ||
- !(v[0].value && v[1].value))
+ if (_sysio_get_args(args, v) - args != (ssize_t )len ||
+ !(v[0].ovi_value && v[1].ovi_value))
return -EINVAL;
- ty = (char *)get_token(v[0].value, 1, ":", "", name = v[0].value);
+ ty =
+ (char *)_sysio_get_token(v[0].ovi_value,
+ 1,
+ ":",
+ "",
+ name = v[0].ovi_value);
flags = 0;
- if (v[2].value) {
+ if (v[2].ovi_value) {
char *cp;
/*
* Optional flags.
*/
- flags = strtoul(v[2].value, &cp, 0);
+ flags = strtoul(v[2].ovi_value, &cp, 0);
if (*cp || (flags == ULONG_MAX && errno == ERANGE))
return -EINVAL;
}
- if (strlen(v[1].value) == 1 && v[1].value[0] == PATH_SEPARATOR) {
+ if (strlen(v[1].ovi_value) == 1 && v[1].ovi_value[0] == PATH_SEPARATOR) {
/*
* Aha! It's root they want. Have to do that special.
*/
- return _sysio_mount_root(ty, name, flags, v[3].value);
+ return _sysio_mount_root(ty, name, flags, v[3].ovi_value);
}
if (!(dir = _sysio_cwd) && !(dir = _sysio_root))
return -ENOENT;
- return _sysio_mount(dir, ty, v[1].value, name, flags, v[3].value);
+ return _sysio_mount(dir,
+ ty,
+ v[1].ovi_value,
+ name,
+ flags,
+ v[3].ovi_value);
}
+#if 0
/*
* Chdir
*
do_cd(char *args)
{
size_t len;
- struct named_argument v[] = {
+ struct option_value_info v[] = {
{ "dir", NULL }, /* directory */
{ NULL, NULL }
};
struct pnode *dir, *pno;
len = strlen(args);
- if (get_args(args, v) - args != (ssize_t )len || !v[0].value)
+ 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].value, 0, NULL, &pno);
+ }
+ err = _sysio_namei(dir, v[0].ovi_value, 0, NULL, &pno);
if (err)
return err;
err = _sysio_p_chdir(pno);
P_RELE(pno);
return err;
}
+#endif
/*
* Does a chmod
do_chmd(char *args)
{
size_t len;
- struct named_argument v[] = {
+ struct option_value_info v[] = {
{ "src", NULL }, /* path */
{ "pm", NULL }, /* perms */
{ NULL, NULL }
struct pnode *dir, *pno;
len = strlen(args);
- if (get_args(args, v) - args != (ssize_t )len ||
- !(v[0].value && v[1].value))
+ if (_sysio_get_args(args, v) - args != (ssize_t )len ||
+ !(v[0].ovi_value && v[1].ovi_value))
return -EINVAL;
- perms = strtol(v[1].value, &cp, 0);
+ perms = strtol(v[1].ovi_value, &cp, 0);
if (*cp ||
perms < 0 ||
(perms == LONG_MAX && errno == ERANGE) ||
if (!(dir = _sysio_cwd) && !(dir = _sysio_root))
return -ENOENT;
- err = _sysio_namei(dir, v[0].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 err;
}
+static int
+do_open(char *args)
+{
+ size_t len;
+ struct option_value_info v[] = {
+ { "nm", NULL }, /* path */
+ { "fd", NULL }, /* fildes */
+ { "m", NULL }, /* mode */
+ { NULL, NULL }
+ };
+ char *cp;
+ long l;
+ int fd;
+ unsigned long ul;
+ mode_t m;
+ struct pnode *dir, *pno;
+ struct intent intent;
+ int err;
+ struct file *fil;
+
+ len = strlen(args);
+ if (_sysio_get_args(args, v) - args != (ssize_t )len ||
+ !(v[0].ovi_value && v[1].ovi_value && v[2].ovi_value))
+ return -EINVAL;
+ l = strtol(v[1].ovi_value, (char **)&cp, 0);
+ if (*cp || l < 0 || _irecheck(l, errno))
+ return -EINVAL;
+ fd = (int )l;
+ ul = strtoul(v[1].ovi_value, (char **)&cp, 0);
+ if (*cp ||
+ (ul == ULONG_MAX && errno == ERANGE))
+ return -EINVAL;
+ m = (mode_t )ul & (O_RDONLY|O_WRONLY|O_RDWR);
+
+ if (!(dir = _sysio_cwd) && !(dir = _sysio_root))
+ return -ENOENT;
+ INTENT_INIT(&intent, INT_OPEN, &m, NULL);
+ pno = NULL;
+ err = _sysio_namei(dir, v[0].ovi_value, ND_NOPERMCHECK, &intent, &pno);
+ if (err)
+ return err;
+ fil = NULL;
+ do {
+ err = _sysio_open(pno, m, 0);
+ if (err)
+ break;
+ fil = _sysio_fnew(pno->p_base->pb_ino, m);
+ if (!fil) {
+ err = -ENOMEM;
+ break;
+ }
+ err = _sysio_fd_set(fil, fd, 1);
+ if (err < 0)
+ break;
+ P_RELE(pno);
+ return 0;
+ } while (0);
+ if (fil)
+ F_RELE(fil);
+ if (pno)
+ P_RELE(pno);
+ return err;
+}
+
/*
* Execute the given cmd.
*
char *args, *cmd;
len = strlen(buf);
- args = (char *)get_token(buf, 1, ",", IGNORE_WHITE, cmd = buf);
+ args = (char *)_sysio_get_token(buf, 1, ",", IGNORE_WHITE, cmd = buf);
if (args) {
if (strcmp("creat", cmd) == 0)
return do_creat(args);
if (strcmp("mnt", cmd) == 0)
return do_mnt(args);
+#if 0
if (strcmp("cd", cmd) == 0)
return do_cd(args);
+#endif
if (strcmp("chmd", cmd) == 0)
return do_chmd(args);
+ if (strcmp("open", cmd) == 0)
+ return do_open(args);
}
return -EINVAL;
}
+#ifdef SYSIO_TRACING
+/*
+ * Set/Unset tracing.
+ */
+static int
+_sysio_boot_tracing(const char *arg)
+{
+ long l;
+ char *cp;
+ static struct trace_callback
+ *entcb = NULL,
+ *exitcb = NULL;
+
+ l = 0;
+ if (arg) {
+ l = strtol(arg, (char **)&cp, 0);
+ if (*cp || !(l == 0 || l == 1))
+ return -EINVAL;
+ }
+ if (l) {
+ if (entcb == NULL)
+ entcb =
+ _sysio_register_trace(_sysio_entry_trace_q,
+ _sysio_trace_entry,
+ NULL,
+ NULL);
+ if (entcb == NULL)
+ return -errno;
+ if (exitcb == NULL)
+ exitcb =
+ _sysio_register_trace(_sysio_exit_trace_q,
+ _sysio_trace_exit,
+ NULL,
+ NULL);
+ if (exitcb == NULL)
+ return -errno;
+ } else {
+ if (entcb != NULL)
+ _sysio_remove_trace(_sysio_entry_trace_q, entcb);
+ entcb = NULL;
+ if (exitcb != NULL)
+ _sysio_remove_trace(_sysio_exit_trace_q, exitcb);
+ exitcb = NULL;
+ }
+ return 0;
+}
+#endif
+
/*
- * Given a command sequence buffer, parse it and run the given
- * commands
+ * Initialize the namespace.
*/
-int
-_sysio_boot(const char *buf)
+static int
+_sysio_boot_namespace(const char *arg)
{
char c, *tok;
+ ssize_t len;
int err;
-
+ unsigned count;
/*
* Allocate token buffer.
*/
- tok = malloc(strlen(buf));
+ len = strlen(arg);
+ tok = malloc(len ? len : 1);
if (!tok)
return -ENOMEM;
err = 0;
+ count = 0;
while (1) {
/*
* Discard leading white space.
*/
- while ((c = *buf) != '\0' &&
- !(c == '{' || strchr(IGNORE_WHITE, c) == NULL))
- buf++;
+ 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 != '{') {
/*
* Get the command.
*/
- buf = (char *)get_token(buf + 1, 0, "}", IGNORE_WHITE, tok);
- if (!buf) {
+ *tok = '\0';
+ arg =
+ (char *)_sysio_get_token(arg + 1,
+ 0,
+ "}",
+ IGNORE_WHITE,
+ tok);
+ if (!arg) {
err = -EINVAL;
break;
}
+ count++;
/*
* Perform.
*/
if (err)
break;
}
+#ifdef SYSIO_TRACING
+ if (err)
+ _sysio_cprintf("+NS init+ failed at expr %u (last = %s): %s\n",
+ count,
+ tok && *tok ? tok : "NULL",
+ strerror(-err));
+#endif
free(tok);
return err;
}
+
+#ifdef DEFER_INIT_CWD
+/*
+ * Set deferred initial working directory.
+ */
+static int
+_sysio_boot_cwd(const char *arg)
+{
+
+ _sysio_init_cwd = arg;
+ return 0;
+}
+#endif
+
+/*
+ * Given an identifier and it's arguments, perform optional initializations.
+ */
+int
+_sysio_boot(const char *opt, const char *arg)
+{
+ struct option_value_info vec[] = {
+#ifdef SYSIO_TRACING
+ { "trace", NULL }, /* tracing? */
+#endif
+ { "namespace", NULL }, /* init namespace? */
+#ifdef DEFER_INIT_CWD
+ { "cwd", NULL }, /* init working dir */
+#endif
+ { NULL, NULL }
+ };
+ struct option_value_info *v;
+ unsigned u;
+ static int (*f[])(const char *) = {
+#ifdef SYSIO_TRACING
+ _sysio_boot_tracing,
+#endif
+ _sysio_boot_namespace,
+#ifdef DEFER_INIT_CWD
+ _sysio_boot_cwd,
+#endif
+ NULL /* can't happen */
+ };
+
+ for (v = vec, u = 0; v->ovi_name; v++, u++)
+ if (strcmp(v->ovi_name, opt) == 0)
+ break;
+ if (!v->ovi_name)
+ return -EINVAL;
+ return (*f[u])(arg);
+}