X-Git-Url: https://git.whamcloud.com/?a=blobdiff_plain;f=libsysio%2Fsrc%2Finit.c;h=3441d81bb569ddb76c75fa9b8217ce19bbb8becd;hb=5c83bec51d5849977bd5ccf1f031aea382759a5d;hp=5e3e793d79a517c564aded13ee52acd775fbdc16;hpb=8692f4651696ff4324db3ad738d3fa62f68d7347;p=fs%2Flustre-release.git diff --git a/libsysio/src/init.c b/libsysio/src/init.c index 5e3e793..3441d81 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-2005 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 @@ -43,10 +43,19 @@ #define _BSD_SOURCE +#if SYSIO_TRACING +#include +#endif #include +#if SYSIO_TRACING +#include +#endif #include #include #include +#if SYSIO_TRACING +#include +#endif #include #include #include @@ -55,8 +64,11 @@ #include #include -#include "xtio.h" #include "sysio.h" +#include "xtio.h" +#if SYSIO_TRACING +#include "native.h" +#endif #include "inode.h" #include "fs.h" #include "mount.h" @@ -67,22 +79,61 @@ #include "stdfd.h" #endif +#if 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; + void (*f)(const char *file, const char *func, int line); }; /* + * Initialize a tracing callback record. + */ +#define TCB_INIT(__tcb, __f) \ + do { \ + (__tcb)->f = (__f); \ + } 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 '#' + +/* * Sysio library initialization. Must be called before anything else in the * library. */ @@ -91,7 +142,15 @@ _sysio_init() { int err; #ifdef WITH_SOCKETS - int _sysio_sockets_init(void); + extern int _sysio_sockets_init(void); +#endif + +#if 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 +172,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; @@ -144,9 +203,179 @@ _sysio_shutdown() _sysio_fd_shutdown(); _sysio_i_shutdown(); _sysio_fssw_shutdown(); +#if 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); + } + } +#endif #endif } +#if 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)) +{ + struct trace_callback *tcb; + + tcb = malloc(sizeof(struct trace_callback)); + if (!tcb) + return NULL; + TCB_INIT(tcb, f); + TAILQ_INSERT_TAIL((struct trace_q *)q, tcb, links); + return tcb; +} + +/* + * Remove a registered trace callback. + */ +void +_sysio_remove_trace(void *q, void *p) +{ + + TAILQ_REMOVE((struct trace_q *)q, (struct trace_callback *)p, links); + free(p); +} + +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 = tcb->links.tqe_next; + } +} + +static void +_sysio_trace_entry(const char *file __IS_UNUSED, + const char *func, + int line __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) +{ + + _sysio_cprintf("+EXIT+ %s\n", func); +} +#endif /* defined(SYSIO_TRACING) */ + /* * (kind of)Duplicates strtok function. * @@ -160,8 +389,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 +439,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 +460,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 +508,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 */ @@ -289,27 +528,27 @@ do_creat(char *args) int err; 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)) @@ -321,9 +560,10 @@ do_creat(char *args) return -ENOENT; err = 0; mode = perms; - if (strcmp(v[0].value, "dir") == 0) { + if (strcmp(v[0].ovi_value, "dir") == 0) { INTENT_INIT(&intent, INT_CREAT, &mode, 0); - err = _sysio_namei(dir, v[1].value, ND_NEGOK, &intent, &pno); + err = + _sysio_namei(dir, v[1].ovi_value, ND_NEGOK, &intent, &pno); if (err) return err; if (pno->p_base->pb_ino) @@ -338,12 +578,13 @@ do_creat(char *args) 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)) + } else if (strcmp(v[0].ovi_value, "chr") == 0) { + if (!(v[5].ovi_value && parse_mm(v[5].ovi_value, &dev) == 0)) return -EINVAL; mode |= S_IFCHR; INTENT_INIT(&intent, INT_CREAT, &mode, 0); - err = _sysio_namei(dir, v[1].value, ND_NEGOK, &intent, &pno); + err = + _sysio_namei(dir, v[1].ovi_value, ND_NEGOK, &intent, &pno); if (err) return err; if (pno->p_base->pb_ino) @@ -358,18 +599,19 @@ do_creat(char *args) err = (*ino->i_ops.inop_mknod)(pno, mode, dev); } P_RELE(pno); - } else if (strcmp(v[0].value, "blk") == 0) { + } else if (strcmp(v[0].ovi_value, "blk") == 0) { /* * We don't support block special files yet. */ return -EINVAL; - } else if (strcmp(v[0].value, "file") == 0) { + } else if (strcmp(v[0].ovi_value, "file") == 0) { int i; struct inode *ino; i = O_CREAT|O_EXCL; INTENT_INIT(&intent, INT_CREAT, &mode, &i); - err = _sysio_namei(dir, v[1].value, ND_NEGOK, &intent, &pno); + err = + _sysio_namei(dir, v[1].ovi_value, ND_NEGOK, &intent, &pno); if (err) return err; err = _sysio_open(pno, O_CREAT|O_EXCL, mode); @@ -378,7 +620,7 @@ do_creat(char *args) return err; } ino = pno->p_base->pb_ino; - if (!err && v[6].value) { + if (!err && v[6].ovi_value) { struct iovec iovec; struct intnl_xtvec xtvec; struct ioctx io_context; @@ -386,8 +628,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, @@ -430,7 +672,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 +684,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 +733,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 +741,12 @@ 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)) 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 +754,7 @@ do_cd(char *args) P_RELE(pno); return err; } +#endif /* * Does a chmod @@ -511,7 +765,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 +777,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 +791,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, 0, NULL, &pno); if (err) return err; err = _sysio_setattr(pno, pno->p_base->pb_ino, SETATTR_MODE, &stbuf); @@ -550,14 +804,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 +821,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, 0, &intent, &pno); if (err) return err; fil = NULL; @@ -621,14 +876,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 +894,82 @@ do_command(char *buf) return -EINVAL; } +#if 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); + if (entcb == NULL) + return -errno; + if (exitcb == NULL) + exitcb = + _sysio_register_trace(_sysio_exit_trace_q, + _sysio_trace_exit); + 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) { + while (*arg && (*arg != '\n')) { + ++arg; + } + + continue; + } if (c == '\0') break; if (c != '{') { @@ -670,11 +979,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 +998,63 @@ _sysio_boot(const char *buf) if (err) break; } +#if 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; } + +#if 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[] = { +#if SYSIO_TRACING + { "trace", NULL }, /* tracing? */ +#endif + { "namespace", NULL }, /* init namespace? */ +#if 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 + _sysio_boot_tracing, +#endif + _sysio_boot_namespace, +#if 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); +}