2 * This Cplant(TM) source code is the property of Sandia National
5 * This Cplant(TM) source code is copyrighted by Sandia National
8 * The redistribution of this Cplant(TM) source code is subject to the
9 * terms of the GNU Lesser General Public License
10 * (see cit/LGPL or http://www.gnu.org/licenses/lgpl.html)
12 * Cplant(TM) Copyright 1998-2005 Sandia Corporation.
13 * Under the terms of Contract DE-AC04-94AL85000, there is a non-exclusive
14 * license for use of this work by or on behalf of the US Government.
15 * Export of this program may require a license from the United States
20 * This library is free software; you can redistribute it and/or
21 * modify it under the terms of the GNU Lesser General Public
22 * License as published by the Free Software Foundation; either
23 * version 2.1 of the License, or (at your option) any later version.
25 * This library is distributed in the hope that it will be useful,
26 * but WITHOUT ANY WARRANTY; without even the implied warranty of
27 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
28 * Lesser General Public License for more details.
30 * You should have received a copy of the GNU Lesser General Public
31 * License along with this library; if not, write to the Free Software
32 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
34 * Questions or comments about this library should be sent to:
37 * Sandia National Laboratories, New Mexico
39 * Albuquerque, NM 87185-1110
51 #include <sys/syscall.h>
61 #include <sys/types.h>
65 #include <sys/queue.h>
85 * Tracing callback record.
87 struct trace_callback {
88 TAILQ_ENTRY(trace_callback) links;
89 void (*f)(const char *file, const char *func, int line);
93 * Initialize a tracing callback record.
95 #define TCB_INIT(__tcb, __f) \
101 * Trace queue head record.
103 TAILQ_HEAD(trace_q, trace_callback);
106 * The entry and exit queue heads, and queue pointers.
108 static struct trace_q _sysio_entry_trace_head;
109 void *_sysio_entry_trace_q = &_sysio_entry_trace_head;
110 static struct trace_q _sysio_exit_trace_head;
111 void *_sysio_exit_trace_q = &_sysio_exit_trace_head;
115 * White space characters.
117 #define IGNORE_WHITE " \t\r\n"
120 * Check if long overflows integer range.
122 #if LONG_MAX <= INT_MAX
123 #define _irecheck(_l, _e) \
124 ((_l) == LONG_MAX && (_e) == ERANGE)
126 #define _irecheck(_l, _e) \
131 * Sysio library initialization. Must be called before anything else in the
139 extern int _sysio_sockets_init(void);
144 * Initialize tracing callback queues.
146 TAILQ_INIT(&_sysio_entry_trace_head);
147 TAILQ_INIT(&_sysio_exit_trace_head);
150 err = _sysio_ioctx_init();
153 err = _sysio_i_init();
156 err = _sysio_mount_init();
160 err = _sysio_dev_init();
164 err = _sysio_stdfd_init();
169 err = _sysio_sockets_init();
179 * Unlike all other _sysio routines, this one returns with errno
180 * set. It also returns the error, as usual.
186 * Sysio library shutdown.
192 if (!(_sysio_fd_close_all() == 0 &&
193 _sysio_unmount_all() == 0))
197 _sysio_fd_shutdown();
199 _sysio_fssw_shutdown();
202 struct trace_callback *tcb;
205 * Empty the trace queues and free the entries.
207 while ((tcb = _sysio_entry_trace_head.tqh_first) != NULL) {
208 TAILQ_REMOVE(&_sysio_entry_trace_head, tcb, links);
211 while ((tcb = _sysio_exit_trace_head.tqh_first) != NULL) {
212 TAILQ_REMOVE(&_sysio_exit_trace_head, tcb, links);
222 #if !(defined(_HAVE_ASPRINTF) && _HAVE_ASPRINTF)
224 * Print a string to allocated memory.
227 vasprintf(char **strp, const char *fmt, va_list ap)
237 if (!(s = malloc(siz))) {
243 n = vsnprintf (s, siz, fmt, aq);
245 if (n > -1 && (size_t )n < siz)
247 if (n > -1) /* glibc 2.1 */
248 siz = n+1; /* precise */
250 siz *= 2; /* twice the old */
251 if (!(s = realloc (s, siz)))
261 asprintf(char **strp, const char *fmt, ...)
267 n = vasprintf(strp, fmt, ap);
272 #endif /* !(defined(_HAVE_ASPRINTF) && _HAVE_ASPRINTF) */
275 _sysio_cwrite(const char *buf, size_t len)
280 (void )syscall(SYSIO_SYS_write, STDERR_FILENO, buf, len);
288 _sysio_cprintf(const char *fmt, ...)
296 len = vasprintf(&buf, fmt, ap);
300 _sysio_cwrite(buf, len);
305 * Register a trace callback.
307 * The pointer to the trace record is returned.
310 _sysio_register_trace(void *q,
311 void (*f)(const char *file,
315 struct trace_callback *tcb;
317 tcb = malloc(sizeof(struct trace_callback));
321 TAILQ_INSERT_TAIL((struct trace_q *)q, tcb, links);
326 * Remove a registered trace callback.
329 _sysio_remove_trace(void *q, void *p)
332 TAILQ_REMOVE((struct trace_q *)q, (struct trace_callback *)p, links);
338 * Run a trace queue, making all the callbacks.
340 _sysio_run_trace_q(void *q,
345 struct trace_callback *tcb;
347 tcb = ((struct trace_q *)q)->tqh_first;
349 (*tcb->f)(file, func, line);
350 tcb = tcb->links.tqe_next;
355 _sysio_trace_entry(const char *file __IS_UNUSED,
357 int line __IS_UNUSED)
360 _sysio_cprintf("+ENTER+ %s\n", func);
364 _sysio_trace_exit(const char *file __IS_UNUSED,
366 int line __IS_UNUSED)
369 _sysio_cprintf("+EXIT+ %s\n", func);
371 #endif /* defined(SYSIO_TRACING) */
374 * (kind of)Duplicates strtok function.
376 * Given a buffer, returns the longest string
377 * that does not contain any delim characters. Will
378 * remove ws and any characters in the ignore string.
381 * The parameter controlling acceptance controls whether a positive
382 * match for some delimiter be made or not. If set, then either a delimiter
383 * or NUL character is success.
387 _sysio_get_token(const char *buf,
397 * Find the first occurance of delim, recording how many
398 * characters lead up to it. Ignore indicated characters.
401 while ((c = *buf) != '\0') {
413 if (strchr(delim, c) != NULL) {
417 if (strchr(ignore, c) != NULL)
426 *tbuf = '\0'; /* NUL term */
431 * Parse and record named arguments given as `name = value', comma-separated
434 * NB: Alters the passed buffer.
437 _sysio_get_args(char *buf, struct option_value_info *vec)
441 struct option_value_info *v;
445 (char *)_sysio_get_token(buf,
451 (nxt != buf && *name == '\0' && buf + strlen(buf) == nxt)) {
458 (char *)_sysio_get_token(nxt,
465 for (v = vec; v->ovi_name; v++)
466 if (strcmp(v->ovi_name, name) == 0)
470 v->ovi_value = value;
477 parse_mm(const char *s, dev_t *devp)
483 ul = strtoul(s, &cp, 0);
484 if (*cp != '+' || ul > USHRT_MAX)
487 s = (const char *)++cp;
488 ul = strtoul(s, &cp, 0);
489 if (*cp != '\0' || ul > USHRT_MAX)
497 * Performs the creat command for the namespace assembly
499 * NB: Alters the passed buffer.
505 struct option_value_info v[] = {
506 { "ft", NULL }, /* file type */
507 { "nm", NULL }, /* name */
508 { "pm", NULL }, /* permissions */
509 { "ow", NULL }, /* owner */
510 { "gr", NULL }, /* group */
511 { "mm", NULL }, /* major + minor */
512 { "str", NULL }, /* file data */
518 struct pnode *dir, *pno;
520 struct intent intent;
525 if (_sysio_get_args(args, v) - args != (ssize_t )len ||
530 perms = strtol(v[2].ovi_value, (char **)&cp, 0);
533 (perms == LONG_MAX && errno == ERANGE) ||
534 ((unsigned)perms & ~07777))
536 if (v[3].ovi_value) {
537 owner = strtol(v[3].ovi_value, (char **)&cp, 0);
539 ((owner == LONG_MIN || owner == LONG_MAX)
544 if (v[4].ovi_value) {
545 group = strtol(v[4].ovi_value, (char **)&cp, 0);
547 ((group == LONG_MIN || group == LONG_MAX) &&
553 if (!(dir = _sysio_cwd) && !(dir = _sysio_root))
557 if (strcmp(v[0].ovi_value, "dir") == 0) {
558 INTENT_INIT(&intent, INT_CREAT, &mode, 0);
560 _sysio_namei(dir, v[1].ovi_value, ND_NEGOK, &intent, &pno);
563 if (pno->p_base->pb_ino)
565 else if (IS_RDONLY(pno->p_parent,
566 pno->p_parent->p_base->pb_ino))
571 ino = pno->p_parent->p_base->pb_ino;
572 err = (*ino->i_ops.inop_mkdir)(pno, mode);
575 } else if (strcmp(v[0].ovi_value, "chr") == 0) {
576 if (!(v[5].ovi_value && parse_mm(v[5].ovi_value, &dev) == 0))
579 INTENT_INIT(&intent, INT_CREAT, &mode, 0);
581 _sysio_namei(dir, v[1].ovi_value, ND_NEGOK, &intent, &pno);
584 if (pno->p_base->pb_ino)
586 else if (IS_RDONLY(pno->p_parent,
587 pno->p_parent->p_base->pb_ino))
592 ino = pno->p_parent->p_base->pb_ino;
593 err = (*ino->i_ops.inop_mknod)(pno, mode, dev);
596 } else if (strcmp(v[0].ovi_value, "blk") == 0) {
598 * We don't support block special files yet.
601 } else if (strcmp(v[0].ovi_value, "file") == 0) {
606 INTENT_INIT(&intent, INT_CREAT, &mode, &i);
608 _sysio_namei(dir, v[1].ovi_value, ND_NEGOK, &intent, &pno);
611 err = _sysio_open(pno, O_CREAT|O_EXCL, mode);
616 ino = pno->p_base->pb_ino;
617 if (!err && v[6].ovi_value) {
619 struct intnl_xtvec xtvec;
620 struct ioctx io_context;
623 * Deposit optional file content.
625 iovec.iov_base = v[6].ovi_value;
626 iovec.iov_len = strlen(v[6].ovi_value);
628 xtvec.xtv_len = iovec.iov_len;
629 IOCTX_INIT(&io_context,
635 _sysio_ioctx_enter(&io_context);
637 (*ino->i_ops.inop_write)(pno->p_base->pb_ino,
642 cc = _sysio_ioctx_wait(&io_context);
645 else if ((size_t )cc != iovec.iov_len)
646 err = -EIO; /* huh? */
648 _sysio_ioctx_complete(&io_context);
650 i = (*ino->i_ops.inop_close)(ino);
663 * NB: The passed buffer is altered.
669 struct option_value_info v[] = {
670 { "dev", NULL }, /* source (type:dev) */
671 { "dir", NULL }, /* target dir */
672 { "fl", NULL }, /* flags */
673 { "da", NULL }, /* mount data */
681 if (_sysio_get_args(args, v) - args != (ssize_t )len ||
682 !(v[0].ovi_value && v[1].ovi_value))
685 (char *)_sysio_get_token(v[0].ovi_value,
689 name = v[0].ovi_value);
691 if (v[2].ovi_value) {
697 flags = strtoul(v[2].ovi_value, &cp, 0);
698 if (*cp || (flags == ULONG_MAX && errno == ERANGE))
702 if (strlen(v[1].ovi_value) == 1 && v[1].ovi_value[0] == PATH_SEPARATOR) {
704 * Aha! It's root they want. Have to do that special.
706 return _sysio_mount_root(ty, name, flags, v[3].ovi_value);
709 if (!(dir = _sysio_cwd) && !(dir = _sysio_root))
711 return _sysio_mount(dir,
724 * NB: Alters the passed buffer.
730 struct option_value_info v[] = {
731 { "dir", NULL }, /* directory */
735 struct pnode *dir, *pno;
738 if (_sysio_get_args(args, v) - args != (ssize_t )len || !v[0].ovi_value)
741 if (!(dir = _sysio_cwd) && !(dir = _sysio_root))
743 err = _sysio_namei(dir, v[0].ovi_value, 0, NULL, &pno);
746 err = _sysio_p_chdir(pno);
756 * NB: Alters passed buffer.
762 struct option_value_info v[] = {
763 { "src", NULL }, /* path */
764 { "pm", NULL }, /* perms */
769 struct intnl_stat stbuf;
771 struct pnode *dir, *pno;
774 if (_sysio_get_args(args, v) - args != (ssize_t )len ||
775 !(v[0].ovi_value && v[1].ovi_value))
777 perms = strtol(v[1].ovi_value, &cp, 0);
780 (perms == LONG_MAX && errno == ERANGE) ||
781 ((unsigned)perms & ~07777))
783 (void )memset(&stbuf, 0, sizeof(stbuf));
784 stbuf.st_mode = (mode_t)perms;
786 if (!(dir = _sysio_cwd) && !(dir = _sysio_root))
788 err = _sysio_namei(dir, v[0].ovi_value, 0, NULL, &pno);
791 err = _sysio_setattr(pno, pno->p_base->pb_ino, SETATTR_MODE, &stbuf);
801 struct option_value_info v[] = {
802 { "nm", NULL }, /* path */
803 { "fd", NULL }, /* fildes */
804 { "m", NULL }, /* mode */
812 struct pnode *dir, *pno;
813 struct intent intent;
818 if (_sysio_get_args(args, v) - args != (ssize_t )len ||
819 !(v[0].ovi_value && v[1].ovi_value && v[2].ovi_value))
821 l = strtol(v[1].ovi_value, (char **)&cp, 0);
822 if (*cp || l < 0 || _irecheck(l, errno))
825 ul = strtoul(v[1].ovi_value, (char **)&cp, 0);
827 (ul == ULONG_MAX && errno == ERANGE))
829 m = (mode_t )ul & (O_RDONLY|O_WRONLY|O_RDWR);
831 if (!(dir = _sysio_cwd) && !(dir = _sysio_root))
833 INTENT_INIT(&intent, INT_OPEN, &m, NULL);
835 err = _sysio_namei(dir, v[0].ovi_value, 0, &intent, &pno);
840 err = _sysio_open(pno, m, 0);
843 fil = _sysio_fnew(pno->p_base->pb_ino, m);
848 err = _sysio_fd_set(fil, fd, 1);
862 * Execute the given cmd.
864 * NB: Buf is altered.
867 do_command(char *buf)
873 args = (char *)_sysio_get_token(buf, 1, ",", IGNORE_WHITE, cmd = buf);
875 if (strcmp("creat", cmd) == 0)
876 return do_creat(args);
877 if (strcmp("mnt", cmd) == 0)
880 if (strcmp("cd", cmd) == 0)
883 if (strcmp("chmd", cmd) == 0)
884 return do_chmd(args);
885 if (strcmp("open", cmd) == 0)
886 return do_open(args);
896 _sysio_boot_tracing(const char *arg)
900 static struct trace_callback
906 l = strtol(arg, (char **)&cp, 0);
907 if (*cp || !(l == 0 || l == 1))
913 _sysio_register_trace(_sysio_entry_trace_q,
919 _sysio_register_trace(_sysio_exit_trace_q,
925 _sysio_remove_trace(_sysio_entry_trace_q, entcb);
928 _sysio_remove_trace(_sysio_exit_trace_q, exitcb);
936 * Initialize the namespace.
939 _sysio_boot_namespace(const char *arg)
946 * Allocate token buffer.
949 tok = malloc(len ? len : 1);
956 * Discard leading white space.
958 while ((c = *arg) != '\0' &&
959 !(c == '{' || strchr(IGNORE_WHITE, c) == NULL))
972 (char *)_sysio_get_token(arg + 1,
985 err = do_command(tok);
991 _sysio_cprintf("+NS init+ failed at expr %u (last = %s): %s\n",
993 tok && *tok ? tok : "NULL",
1002 * Set deferred initial working directory.
1005 _sysio_boot_cwd(const char *arg)
1008 _sysio_init_cwd = arg;
1014 * Given an identifier and it's arguments, perform optional initializations.
1017 _sysio_boot(const char *opt, const char *arg)
1019 struct option_value_info vec[] = {
1021 { "trace", NULL }, /* tracing? */
1023 { "namespace", NULL }, /* init namespace? */
1025 { "cwd", NULL }, /* init working dir */
1029 struct option_value_info *v;
1031 static int (*f[])(const char *) = {
1033 _sysio_boot_tracing,
1035 _sysio_boot_namespace,
1039 NULL /* can't happen */
1042 for (v = vec, u = 0; v->ovi_name; v++, u++)
1043 if (strcmp(v->ovi_name, opt) == 0)
1047 return (*f[u])(arg);