diff --git a/project/common.mk b/project/common.mk index adb5eb2..f880226 100644 --- a/project/common.mk +++ b/project/common.mk @@ -5,11 +5,14 @@ INTERNAL_SRCS = \ src/daemon/toks_daemon_init.c \ src/daemon/toks_daemon_loop.c \ src/daemon/toks_daemon_signal.c \ + src/driver/toks_driver_ctx.c \ src/internal/nolibc/toksvc_compiler.c \ src/internal/toksvc_dprintf_impl.c \ src/internal/toksvc_memfn_impl.c \ src/internal/toksvc_nolibc_impl.c \ src/internal/toksvc_ntaio_impl.c \ + src/internal/toksvc_open_impl.c \ + src/skin/toks_skin_default.c \ APP_SRCS = \ src/toksvc.c diff --git a/project/extras.mk b/project/extras.mk index 5cf78f7..a93255d 100644 --- a/project/extras.mk +++ b/project/extras.mk @@ -19,3 +19,7 @@ LDFLAGS_COMMON += -nostdlib -lntapi -lpemagine -ldalist LDFLAGS_COMMON += -Wl,--entry -Wl,$(HOST_UNDERSCORE)$(PACKAGE)_entry_point LDFLAGS_SHARED += -Wl,--exclude-all-symbols + + +src/driver/toks_driver_ctx.o: version.tag +src/driver/toks_driver_ctx.lo: version.tag diff --git a/project/headers.mk b/project/headers.mk index 9ea381f..ea6bb0c 100644 --- a/project/headers.mk +++ b/project/headers.mk @@ -12,6 +12,7 @@ INTERNAL_HEADERS = \ $(SOURCE_DIR)/src/internal/nolibc/string.h \ $(SOURCE_DIR)/src/internal/nolibc/unistd.h \ $(SOURCE_DIR)/src/internal/toksvc_daemon_impl.h \ + $(SOURCE_DIR)/src/internal/toksvc_driver_impl.h \ $(SOURCE_DIR)/src/internal/toksvc_dprintf_impl.h \ $(SOURCE_DIR)/src/internal/toksvc_init_impl.h \ $(SOURCE_DIR)/src/internal/toksvc_memfn_impl.h \ diff --git a/project/tree.mk b/project/tree.mk index 2d04bf6..aa3220c 100644 --- a/project/tree.mk +++ b/project/tree.mk @@ -1,7 +1,9 @@ TREE_DIRS = bin src lib \ src/daemon \ + src/driver \ src/internal \ src/internal/nolibc \ + src/skin \ tree.tag: mkdir -p $(TREE_DIRS) diff --git a/src/driver/toks_driver_ctx.c b/src/driver/toks_driver_ctx.c new file mode 100644 index 0000000..713d8f9 --- /dev/null +++ b/src/driver/toks_driver_ctx.c @@ -0,0 +1,274 @@ +/*********************************************************/ +/* toksvc: a framework-native token broker service */ +/* Copyright (C) 2020 Z. Gilboa */ +/* Released under GPLv2 and GPLv3; see COPYING.TOKSVC. */ +/*********************************************************/ + +#include +#include + +#include + +#include +#include "toksvc_init_impl.h" +#include "toksvc_nolibc_impl.h" + +#define ARGV_DRIVER + +#include "toksvc_version.h" +#include "toksvc_daemon_impl.h" +#include "toksvc_dprintf_impl.h" +#include "toksvc_driver_impl.h" +#include "argv/argv.h" + +/* pty integration */ +#include + +__attr_section_decl__(".freestd") +static const nt_tty_affiliation tty_affiliation + __attr_section__(".freestd") + = NT_TTY_AFFILIATION_DEFAULT; + +/* ntapi accessor table */ +const ntapi_vtbl * toks_ntapi; + +/* daemon */ +static struct toks_daemon_ctx toks_daemon_ctx; + +/* package info */ +static const struct toks_source_version toks_src_version = { + TOKS_TAG_VER_MAJOR, + TOKS_TAG_VER_MINOR, + TOKS_TAG_VER_PATCH, + TOKSVC_GIT_VERSION +}; + +struct toks_driver_ctx_alloc { + struct argv_meta * meta; + struct toks_driver_ctx_impl ctx; + uint64_t guard; +}; + +struct toks_split_vector { + char ** targv; + char ** eargv; +}; + +static uint32_t toks_argv_flags(uint32_t flags) +{ + uint32_t ret = ARGV_CLONE_VECTOR; + + if (flags & TOKS_DRIVER_VERBOSITY_NONE) + ret |= ARGV_VERBOSITY_NONE; + + if (flags & TOKS_DRIVER_VERBOSITY_ERRORS) + ret |= ARGV_VERBOSITY_ERRORS; + + if (flags & TOKS_DRIVER_VERBOSITY_STATUS) + ret |= ARGV_VERBOSITY_STATUS; + + return ret; +} + +static int toks_driver_usage( + const char * program, + const char * arg, + const struct argv_option ** optv, + struct argv_meta * meta) +{ + char header[512]; + + snprintf(header,sizeof(header), + "Usage: %s [options] ...\n" "Options:\n", + program); + + argv_usage(STDOUT_FILENO,header,optv,arg); + argv_free(meta); + + return TOKS_USAGE; +} + +static struct toks_driver_ctx_impl * toks_driver_ctx_alloc( + struct argv_meta * meta, + const struct toks_common_ctx * cctx) +{ + struct toks_driver_ctx_alloc * ictx; + size_t size; + nt_runtime_data * rtdata; + + if (ntapi->tt_get_runtime_data(&rtdata,0)) + return 0; + + size = sizeof(struct toks_driver_ctx_alloc); + + if (!(ictx = calloc(1,size))) + return 0; + + if (cctx) + memcpy(&ictx->ctx.cctx,cctx,sizeof(*cctx)); + + ictx->meta = meta; + ictx->ctx.rtdata = rtdata; + return &ictx->ctx; +} + +static int toks_get_driver_ctx_fail(struct argv_meta * meta) +{ + argv_free(meta); + return -1; +} + +#define TOKS_SARGV_ELEMENTS 1024 + +static int toks_split_argv( + char ** argv, + struct toks_split_vector * sargv) +{ + ptrdiff_t argc; + char ** parg; + + /* argc */ + for (parg=argv; *parg; ) + parg++; + + if ((argc = parg - argv) >= TOKS_SARGV_ELEMENTS) + return -1; + + /* clone argv into targv */ + ntapi->tt_aligned_block_memset( + (uintptr_t *)sargv->targv, + 0,TOKS_SARGV_ELEMENTS*sizeof(char *)); + + ntapi->tt_aligned_block_memcpy( + (uintptr_t *)sargv->targv, + (uintptr_t *)argv, + argc*sizeof(char *)); + + /* eargv */ + for (parg=sargv->targv; *parg; parg++) { + if (!(strcmp(*parg,"-e")) || !(strcmp(*parg,"--exec"))) { + sargv->eargv = &argv[parg-sargv->targv]; + sargv->eargv++; + *parg = 0; + return 0; + } + } + + return 0; +} + +int toks_get_driver_ctx( + char ** argv, + char ** envp, + uint32_t flags, + struct toks_driver_ctx ** pctx) +{ + struct toks_driver_ctx_impl * ctx; + struct toks_common_ctx cctx; + struct toks_split_vector sargv; + const struct argv_option * optv[TOKS_OPTV_ELEMENTS]; + struct argv_meta * meta; + struct argv_entry * entry; + const char * program; + char * targv[TOKS_SARGV_ELEMENTS]; + + (void)envp; + + if (toks_init()) + return -1; + + argv_optv_init(toks_default_options,optv); + + sargv.targv = targv; + sargv.eargv = 0; + + if (toks_split_argv(argv,&sargv)) + return -1; + + if (!(meta = argv_get( + sargv.targv,optv, + toks_argv_flags(flags), + STDERR_FILENO))) + return -1; + + program = argv_program_name(argv[0]); + memset(&cctx,0,sizeof(cctx)); + cctx.drvflags = flags; + cctx.eargv = sargv.eargv; + + if (!argv[1] && (flags & TOKS_DRIVER_VERBOSITY_USAGE)) + return toks_driver_usage(program,0,optv,meta); + + for (entry=meta->entries; entry->fopt || entry->arg; entry++) { + if (entry->fopt) { + switch (entry->tag) { + case TAG_HELP: + if (flags & TOKS_DRIVER_VERBOSITY_USAGE) + return toks_driver_usage(program,entry->arg,optv,meta); + + case TAG_VERSION: + cctx.drvflags |= TOKS_DRIVER_VERSION; + break; + + case TAG_DAEMON: + if (!strcmp("always",entry->arg)) + cctx.drvflags |= TOKS_DRIVER_DAEMON_ALWAYS; + + else if (!strcmp("never",entry->arg)) + cctx.drvflags |= TOKS_DRIVER_DAEMON_NEVER; + + break; + + case TAG_SYSROOT: + cctx.sysroot = entry->arg; + break; + } + } else + /* strict */ + return toks_driver_usage(program,0,optv,meta); + } + + if (cctx.sysroot && toks_open_dir(&cctx.hroot,0,cctx.sysroot,false)) { + if (flags & TOKS_DRIVER_VERBOSITY_ERRORS) + toks_dprintf(STDERR_FILENO, + "%s: error: could not open sysroot directory '%s'", + program,cctx.sysroot); + return toks_get_driver_ctx_fail(meta); + } + + if (!(ctx = toks_driver_ctx_alloc(meta,&cctx))) + return toks_get_driver_ctx_fail(meta); + + if (toks_daemon_init(&toks_daemon_ctx,cctx.drvflags)) + return toks_get_driver_ctx_fail(meta); + + ctx->ctx.program = program; + ctx->ctx.cctx = &ctx->cctx; + + *pctx = &ctx->ctx; + return TOKS_OK; +} + +static void toks_free_driver_ctx_impl(struct toks_driver_ctx_alloc * ictx) +{ + argv_free(ictx->meta); + free(ictx); +} + +void toks_free_driver_ctx(struct toks_driver_ctx * ctx) +{ + struct toks_driver_ctx_alloc * ictx; + uintptr_t addr; + + if (ctx) { + addr = (uintptr_t)ctx - offsetof(struct toks_driver_ctx_impl,ctx); + addr = addr - offsetof(struct toks_driver_ctx_alloc,ctx); + ictx = (struct toks_driver_ctx_alloc *)addr; + toks_free_driver_ctx_impl(ictx); + } +} + +const struct toks_source_version * toks_source_version(void) +{ + return &toks_src_version; +} diff --git a/src/skin/toks_skin_default.c b/src/skin/toks_skin_default.c new file mode 100644 index 0000000..4356438 --- /dev/null +++ b/src/skin/toks_skin_default.c @@ -0,0 +1,23 @@ +#include "toksvc_driver_impl.h" +#include "argv/argv.h" + +const struct argv_option toks_default_options[] = { + {"version", 'v',TAG_VERSION,ARGV_OPTARG_NONE,0,0,0, + "show version information"}, + + {"help", 'h',TAG_HELP,ARGV_OPTARG_OPTIONAL,0,"short|long",0, + "show usage information [listing %s options only]"}, + + {"sysroot", 0,TAG_SYSROOT,ARGV_OPTARG_REQUIRED,0,0,"", + "pass a handle to %s to the spawned child process, " + "and set it to be the child's intial root directory."}, + + {"daemon", 0,TAG_DAEMON,ARGV_OPTARG_OPTIONAL,0,"default|always|never",0, + "create a daemon thread and handle signals sent by the " + "application's own controlling terminal. The default is " + "to create a daemon thread when toksvc runs as a stand-alone " + "program, and defer the task to the main utility in all other " + "cases."}, + + {0,0,0,0,0,0,0,0} +};