X-Git-Url: https://git.whamcloud.com/?a=blobdiff_plain;f=libsysio%2Fsrc%2Finit.c;h=6dc4f291e19546777f5ea16b69e6f9719df9159f;hb=6e17f3dceb11704d15bafc6b80f5973ced3235df;hp=5e3e793d79a517c564aded13ee52acd775fbdc16;hpb=8692f4651696ff4324db3ad738d3fa62f68d7347;p=fs%2Flustre-release.git diff --git a/libsysio/src/init.c b/libsysio/src/init.c index 5e3e793..6dc4f29 100644 --- a/libsysio/src/init.c +++ b/libsysio/src/init.c @@ -9,7 +9,7 @@ * 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 @@ -41,12 +41,23 @@ * lee@sandia.gov */ +#ifdef __linux__ #define _BSD_SOURCE +#endif +#ifdef SYSIO_TRACING +#include +#endif #include +#if defined(_BSD_SOURCE) || defined(SYSIO_TRACING) +#include +#endif #include #include #include +#ifdef SYSIO_TRACING +#include +#endif #include #include #include @@ -55,8 +66,11 @@ #include #include -#include "xtio.h" #include "sysio.h" +#include "xtio.h" +#ifdef SYSIO_TRACING +#include "native.h" +#endif #include "inode.h" #include "fs.h" #include "mount.h" @@ -67,22 +81,74 @@ #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. */ @@ -91,7 +157,15 @@ _sysio_init() { 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(); @@ -113,9 +187,9 @@ _sysio_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; @@ -140,13 +214,191 @@ _sysio_shutdown() _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. * @@ -160,8 +412,8 @@ _sysio_shutdown() * 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, @@ -210,15 +462,20 @@ get_token(const char *buf, * * 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; @@ -226,15 +483,20 @@ get_args(char *buf, struct named_argument *vec) } 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; @@ -269,7 +531,7 @@ static int 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 */ @@ -287,29 +549,38 @@ do_creat(char *args) 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)) @@ -319,66 +590,66 @@ do_creat(char *args) 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; @@ -386,8 +657,8 @@ do_creat(char *args) /* * 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, @@ -414,10 +685,12 @@ do_creat(char *args) 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; } @@ -430,7 +703,7 @@ static int 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 */ @@ -442,35 +715,46 @@ do_mnt(char *args) 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 * @@ -480,7 +764,7 @@ static int do_cd(char *args) { size_t len; - struct named_argument v[] = { + struct option_value_info v[] = { { "dir", NULL }, /* directory */ { NULL, NULL } }; @@ -488,12 +772,17 @@ do_cd(char *args) 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); @@ -501,6 +790,7 @@ do_cd(char *args) P_RELE(pno); return err; } +#endif /* * Does a chmod @@ -511,7 +801,7 @@ static int do_chmd(char *args) { size_t len; - struct named_argument v[] = { + struct option_value_info v[] = { { "src", NULL }, /* path */ { "pm", NULL }, /* perms */ { NULL, NULL } @@ -523,10 +813,10 @@ do_chmd(char *args) 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) || @@ -537,7 +827,7 @@ do_chmd(char *args) 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); @@ -550,14 +840,16 @@ static int do_open(char *args) { size_t len; - struct named_argument v[] = { - { "nm", NULL }, /* path */ + 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; @@ -565,25 +857,24 @@ do_open(char *args) struct file *fil; 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; - fd = strtol(v[1].value, (char **)&cp, 0); - if (*cp || - (((fd == LONG_MIN || fd == LONG_MAX) && errno == ERANGE)) || - fd < 0) + l = strtol(v[1].ovi_value, (char **)&cp, 0); + if (*cp || l < 0 || _irecheck(l, errno)) return -EINVAL; - m = strtoul(v[1].value, (char **)&cp, 0); + fd = (int )l; + ul = strtoul(v[1].ovi_value, (char **)&cp, 0); if (*cp || - (m == LONG_MAX && errno == ERANGE)) + (ul == ULONG_MAX && errno == ERANGE)) return -EINVAL; - m &= O_RDONLY|O_WRONLY|O_RDWR; + 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].value, 0, &intent, &pno); + err = _sysio_namei(dir, v[0].ovi_value, ND_NOPERMCHECK, &intent, &pno); if (err) return err; fil = NULL; @@ -621,14 +912,16 @@ do_command(char *buf) 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) @@ -637,30 +930,89 @@ do_command(char *buf) return -EINVAL; } +#ifdef SYSIO_TRACING /* - * Given a command sequence buffer, parse it and run the given - * commands + * Set/Unset tracing. */ -int -_sysio_boot(const char *buf) +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 + +/* + * Initialize the namespace. + */ +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 != '{') { @@ -670,11 +1022,18 @@ _sysio_boot(const char *buf) /* * 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. */ @@ -682,6 +1041,63 @@ _sysio_boot(const char *buf) 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); +}