diff --git a/include/ntux/ntux.h b/include/ntux/ntux.h index d612e6e..d56e795 100644 --- a/include/ntux/ntux.h +++ b/include/ntux/ntux.h @@ -52,6 +52,8 @@ enum ntux_custom_error { enum ntux_cmd { NTUX_CMD_DEFAULT, NTUX_CMD_STAT, + NTUX_CMD_SPAWN, + NTUX_CMD_STRACE, }; struct ntux_source_version { @@ -78,6 +80,9 @@ struct ntux_common_ctx { uint64_t actflags; uint64_t fmtflags; enum ntux_cmd cmd; + uint32_t state; + char ** sargv; + char ** senvp; }; struct ntux_driver_ctx { diff --git a/project/common.mk b/project/common.mk index 4790bc0..bfc901d 100644 --- a/project/common.mk +++ b/project/common.mk @@ -2,6 +2,8 @@ DRIVER_SRCS = \ src/driver/ntux_amain.c \ src/driver/ntux_driver_ctx.c \ src/skin/ntux_skin_default.c \ + src/skin/ntux_skin_spawn.c \ + src/skin/ntux_skin_strace.c \ INTERNAL_SRCS = \ src/internal/nolibc/ntux_compiler.c \ diff --git a/src/driver/ntux_driver_ctx.c b/src/driver/ntux_driver_ctx.c index 95b4186..1b0d8f8 100644 --- a/src/driver/ntux_driver_ctx.c +++ b/src/driver/ntux_driver_ctx.c @@ -70,7 +70,13 @@ static int ntux_driver_usage( snprintf(header,sizeof(header), "Usage: %s [options] ...\n" - "Usage: %s [options] --cmd= ...\n" "Options:\n", + "Usage: %s [options] [--cmd=] ...\n\n" + "Notes: --cmd must precede all non-option arguments, as well as\n" + " all arguments that are specific to the selected command;\n" + " for commands that spawn other programs (e.g. spawn, strace),\n" + " the first non-option argument must specify the name of the\n" + " program to be executed.\n\n" + "Options:\n", program,program); argv_usage(stdout,header,optv,arg); @@ -116,6 +122,55 @@ static struct ntux_driver_ctx_impl * ntux_driver_ctx_alloc( return &ictx->ctx; } +static int ntux_cctx_update( + const char * program, + const struct argv_option ** optv, + struct argv_meta * meta, + uint32_t flags, + struct ntux_common_ctx * cctx, + size_t * nunits) +{ + struct argv_entry * entry; + + /* get options, count units */ + for (entry=meta->entries; entry->fopt || entry->arg; entry++) { + if (entry->fopt) { + switch (entry->tag) { + case TAG_HELP: + if (flags & NTUX_DRIVER_VERBOSITY_USAGE) + return ntux_driver_usage( + program,entry->arg, + optv,0); + + case TAG_VERSION: + cctx->drvflags |= NTUX_DRIVER_VERSION; + break; + + case TAG_CMD: + if (*nunits) + return ntux_driver_usage( + program,entry->arg, + optv,0); + + if (!strcmp(entry->arg,"stat")) + cctx->cmd = NTUX_CMD_STAT; + + else if (!strcmp(entry->arg,"spawn")) + cctx->cmd = NTUX_CMD_SPAWN; + + else if (!strcmp(entry->arg,"strace")) + cctx->cmd = NTUX_CMD_STRACE; + + break; + } + } else { + (*nunits)++; + } + } + + return 0; +} + static int ntux_get_driver_ctx_fail(struct argv_meta * meta) { argv_free(meta); @@ -128,64 +183,125 @@ int ntux_get_driver_ctx( uint32_t flags, struct ntux_driver_ctx ** pctx) { - struct ntux_driver_ctx_impl * ctx; + struct ntux_driver_ctx_impl * ictx; struct ntux_common_ctx cctx; const struct argv_option * optv[NTUX_OPTV_ELEMENTS]; struct argv_meta * meta; - struct argv_entry * entry; size_t nunits; const char * program; - - (void)envp; - - argv_optv_init(ntux_default_options,optv); - + char ** parg; + char ** cmdargv; + char * cmdmark; + char ** execargv; + char * execarg; + struct argv_ctx ctx = {ARGV_VERBOSITY_NONE, + ARGV_MODE_SCAN, + 0,0,0,0,0,0,0}; + + /* init */ if (ntux_init()) return -1; - if (!(meta = argv_get(argv,optv,ntux_argv_flags(flags)))) - return -1; - - nunits = 0; - program = argv_program_name(argv[0]); memset(&cctx,0,sizeof(cctx)); + cctx.drvflags = flags; + program = argv_program_name(argv[0]); + nunits = 0; + execargv = 0; + + /* missing arguments? */ + argv_optv_init(ntux_default_options,optv); if (!argv[1] && (flags & NTUX_DRIVER_VERBOSITY_USAGE)) - return ntux_driver_usage(program,0,optv,meta); + return ntux_driver_usage(program,0,optv,0); + + /* initial argv scan: ... --cmd=xxx ... */ + for (parg=argv, cmdargv=0; *parg && !cmdargv; parg++) { + if (!strcmp(*parg,"--cmd") && parg[1]) { + cmdargv = &parg[2]; + cmdmark = parg[2]; + } else if (!strncmp(*parg,"--cmd=",6)) { + cmdargv = &parg[1]; + cmdmark = parg[1]; + } + } - /* get options, count units */ - for (entry=meta->entries; entry->fopt || entry->arg; entry++) { - if (entry->fopt) { - switch (entry->tag) { - case TAG_HELP: - if (flags & NTUX_DRIVER_VERBOSITY_USAGE) - return ntux_driver_usage(program,entry->arg,optv,meta); + /* process argv entries preceding --cmd */ + if (cmdargv) { + *cmdargv = 0; - case TAG_VERSION: - cctx.drvflags |= NTUX_DRIVER_VERSION; - break; + if (!(meta = argv_get(argv,optv,ntux_argv_flags(flags)))) + return -1; - case TAG_CMD: - if (!strcmp(entry->arg,"stat")) - cctx.cmd = NTUX_CMD_STAT; - break; - } - } else - nunits++; + if (ntux_cctx_update(program,optv,meta,flags,&cctx,&nunits)) { + argv_free(meta); + return -1; + } + + *cmdargv-- = cmdmark; + *cmdargv = argv[0]; + argv = cmdargv; } + /* set option vector by command */ + if (cctx.cmd == NTUX_CMD_SPAWN) + argv_optv_init(ntux_spawn_options,optv); + + else if (cctx.cmd == NTUX_CMD_STRACE) + argv_optv_init(ntux_strace_options,optv); + + /* spawn, strace */ + if ((cctx.cmd == NTUX_CMD_SPAWN) || (cctx.cmd == NTUX_CMD_STRACE)) { + argv_scan(argv,optv,&ctx,0); + + if (ctx.erridx && !ctx.unitidx) { + if (flags & NTUX_DRIVER_VERBOSITY_ERRORS) + argv_get( + argv,optv, + ntux_argv_flags(flags)); + return -1; + } + + if (!ctx.unitidx && (flags & NTUX_DRIVER_VERBOSITY_USAGE)) + ntux_driver_usage(program,0,optv,0); + + if (!ctx.unitidx) + return NTUX_ERROR; + + execargv = &argv[ctx.unitidx]; + execarg = argv[ctx.unitidx]; + *execargv = 0; + } + + /* obtain ntux's own arguments */ + if (!(meta = argv_get(argv,optv,ntux_argv_flags(flags)))) + return -1; + + if (ntux_cctx_update(program,optv,meta,flags,&cctx,&nunits)) { + argv_free(meta); + return -1; + } + + /* spawn, strace: exec argv */ + if (execargv) { + *execargv = execarg; + cctx.sargv = execargv; + cctx.senvp = envp; + nunits = 0; + } + + /* finalize */ if (nunits && !cctx.cmd) return ntux_driver_usage(program,0,optv,meta); - if (!(ctx = ntux_driver_ctx_alloc(meta,&cctx,nunits))) + if (!(ictx = ntux_driver_ctx_alloc(meta,&cctx,nunits))) return ntux_get_driver_ctx_fail(meta); - ctx->ctx.program = program; - ctx->ctx.cctx = &ctx->cctx; + ictx->ctx.program = program; + ictx->ctx.cctx = &ictx->cctx; + *pctx = &ictx->ctx; - *pctx = &ctx->ctx; - return NTUX_OK; + return 0; } int ntux_create_driver_ctx( diff --git a/src/internal/ntux_driver_impl.h b/src/internal/ntux_driver_impl.h index 38d10cc..3f7520f 100644 --- a/src/internal/ntux_driver_impl.h +++ b/src/internal/ntux_driver_impl.h @@ -11,8 +11,10 @@ #define NTUX_OPTV_ELEMENTS 64 -extern const struct argv_option ntux_default_options[]; -extern const ntapi_vtbl * ntux_ntapi; +extern const struct argv_option ntux_default_options[]; +extern const struct argv_option ntux_spawn_options[]; +extern const struct argv_option ntux_strace_options[]; +extern const struct _ntapi_vtbl * ntux_ntapi; #define ntapi ntux_ntapi diff --git a/src/skin/ntux_skin_default.c b/src/skin/ntux_skin_default.c index fa4c33d..73a89bf 100644 --- a/src/skin/ntux_skin_default.c +++ b/src/skin/ntux_skin_default.c @@ -8,8 +8,8 @@ const struct argv_option ntux_default_options[] = { {"help", 'h',TAG_HELP,ARGV_OPTARG_OPTIONAL,0,"short|long",0, "show usage information [listing %s options only]"}, - {"cmd", 0,TAG_CMD,ARGV_OPTARG_REQUIRED,0,"stat",0, - "invoke an internal ntux command"}, + {"cmd", 0,TAG_CMD,ARGV_OPTARG_REQUIRED,0,"stat|spawn|strace",0, + "invoke one of the following ntux commands: %s"}, {0,0,0,0,0,0,0,0} }; diff --git a/src/skin/ntux_skin_spawn.c b/src/skin/ntux_skin_spawn.c new file mode 100644 index 0000000..d7bac9b --- /dev/null +++ b/src/skin/ntux_skin_spawn.c @@ -0,0 +1,12 @@ +#include "ntux_driver_impl.h" +#include "argv/argv.h" + +const struct argv_option ntux_spawn_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]"}, + + {0,0,0,0,0,0,0,0} +}; diff --git a/src/skin/ntux_skin_strace.c b/src/skin/ntux_skin_strace.c new file mode 100644 index 0000000..643c114 --- /dev/null +++ b/src/skin/ntux_skin_strace.c @@ -0,0 +1,12 @@ +#include "ntux_driver_impl.h" +#include "argv/argv.h" + +const struct argv_option ntux_strace_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]"}, + + {0,0,0,0,0,0,0,0} +};