| |
| |
| |
| |
| |
| |
| #include <ntapi/ntapi.h> |
| #include <psxscl/psxscl.h> |
| #include <stdint.h> |
| |
| #include <ntux/ntux.h> |
| #include "ntux_init_impl.h" |
| #include "ntux_nolibc_impl.h" |
| |
| #define ARGV_DRIVER |
| |
| #include "ntux_version.h" |
| #include "ntux_driver_impl.h" |
| #include "argv/argv.h" |
| |
| |
| #include <psxtypes/section/midipix.h> |
| |
| __attr_section_decl__(".midipix") |
| static const nt_tty_affiliation tty_affiliation |
| __attr_section__(".midipix") |
| = NT_TTY_AFFILIATION_DEFAULT; |
| |
| |
| const ntapi_vtbl * ntux_ntapi; |
| |
| |
| static const struct ntux_source_version ntux_src_version = { |
| NTUX_TAG_VER_MAJOR, |
| NTUX_TAG_VER_MINOR, |
| NTUX_TAG_VER_PATCH, |
| NTUX_GIT_VERSION |
| }; |
| |
| struct ntux_driver_ctx_alloc { |
| struct argv_meta * meta; |
| struct ntux_driver_ctx_impl ctx; |
| uint64_t guard; |
| const char * units[]; |
| }; |
| |
| static uint32_t ntux_argv_flags(uint32_t flags) |
| { |
| uint32_t ret = 0; |
| |
| if (flags & NTUX_DRIVER_VERBOSITY_NONE) |
| ret |= ARGV_VERBOSITY_NONE; |
| |
| if (flags & NTUX_DRIVER_VERBOSITY_ERRORS) |
| ret |= ARGV_VERBOSITY_ERRORS; |
| |
| if (flags & NTUX_DRIVER_VERBOSITY_STATUS) |
| ret |= ARGV_VERBOSITY_STATUS; |
| |
| return ret; |
| } |
| |
| static int ntux_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" |
| "Usage: %s [options] [--cmd=<command>] <arg> <arg> ...\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); |
| argv_free(meta); |
| |
| return NTUX_USAGE; |
| } |
| |
| static struct ntux_driver_ctx_impl * ntux_driver_ctx_alloc( |
| struct argv_meta * meta, |
| const struct ntux_common_ctx * cctx, |
| size_t nunits) |
| { |
| struct ntux_driver_ctx_alloc * ictx; |
| size_t size; |
| struct argv_entry * entry; |
| const char ** units; |
| int elements; |
| |
| (void)tty_affiliation; |
| |
| size = sizeof(struct ntux_driver_ctx_alloc); |
| size += (nunits+1)*sizeof(const char *); |
| |
| if (!(ictx = calloc(1,size))) |
| return 0; |
| |
| elements = sizeof(ictx->ctx.erribuf) / sizeof(*ictx->ctx.erribuf); |
| |
| ictx->ctx.errinfp = &ictx->ctx.erriptr[0]; |
| ictx->ctx.erricap = &ictx->ctx.erriptr[--elements]; |
| |
| if (cctx) |
| memcpy(&ictx->ctx.cctx,cctx,sizeof(*cctx)); |
| |
| for (entry=meta->entries,units=ictx->units; entry->fopt || entry->arg; entry++) |
| if (!entry->fopt) |
| *units++ = entry->arg; |
| |
| ictx->meta = meta; |
| ictx->ctx.ctx.units = ictx->units; |
| ictx->ctx.ctx.errv = ictx->ctx.errinfp; |
| 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; |
| |
| |
| 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); |
| return -1; |
| } |
| |
| int ntux_get_driver_ctx( |
| char ** argv, |
| char ** envp, |
| uint32_t flags, |
| struct ntux_driver_ctx ** pctx) |
| { |
| struct ntux_driver_ctx_impl * ictx; |
| struct ntux_common_ctx cctx; |
| const struct argv_option * optv[NTUX_OPTV_ELEMENTS]; |
| struct argv_meta * meta; |
| size_t nunits; |
| const char * program; |
| 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}; |
| |
| |
| if (ntux_init()) |
| return -1; |
| |
| memset(&cctx,0,sizeof(cctx)); |
| |
| cctx.drvflags = flags; |
| program = argv_program_name(argv[0]); |
| nunits = 0; |
| execargv = 0; |
| |
| |
| argv_optv_init(ntux_default_options,optv); |
| |
| if (!argv[1] && (flags & NTUX_DRIVER_VERBOSITY_USAGE)) |
| return ntux_driver_usage(program,0,optv,0); |
| |
| |
| 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]; |
| } |
| } |
| |
| |
| if (cmdargv) { |
| *cmdargv = 0; |
| |
| 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; |
| } |
| |
| *cmdargv-- = cmdmark; |
| *cmdargv = argv[0]; |
| argv = cmdargv; |
| } |
| |
| |
| 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); |
| |
| |
| 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; |
| } |
| |
| |
| 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; |
| } |
| |
| |
| if (execargv) { |
| *execargv = execarg; |
| cctx.sargv = execargv; |
| cctx.senvp = envp; |
| nunits = 0; |
| } |
| |
| |
| if (nunits && !cctx.cmd) |
| return ntux_driver_usage(program,0,optv,meta); |
| |
| if (!(ictx = ntux_driver_ctx_alloc(meta,&cctx,nunits))) |
| return ntux_get_driver_ctx_fail(meta); |
| |
| ictx->ctx.program = program; |
| ictx->ctx.cctx = &ictx->cctx; |
| *pctx = &ictx->ctx; |
| |
| return 0; |
| } |
| |
| int ntux_create_driver_ctx( |
| const struct ntux_common_ctx * cctx, |
| struct ntux_driver_ctx ** pctx) |
| { |
| const struct argv_option * optv[NTUX_OPTV_ELEMENTS]; |
| struct argv_meta * meta; |
| struct ntux_driver_ctx_impl * ctx; |
| char * argv[] = {"ntux_driver",0}; |
| |
| if (ntux_init()) |
| return -1; |
| |
| argv_optv_init(ntux_default_options,optv); |
| |
| if (!(meta = argv_get(argv,optv,0))) |
| return -1; |
| |
| if (!(ctx = ntux_driver_ctx_alloc(meta,cctx,0))) |
| return ntux_get_driver_ctx_fail(0); |
| |
| ctx->ctx.cctx = &ctx->cctx; |
| memcpy(&ctx->cctx,cctx,sizeof(*cctx)); |
| *pctx = &ctx->ctx; |
| return NTUX_OK; |
| } |
| |
| static void ntux_free_driver_ctx_impl(struct ntux_driver_ctx_alloc * ictx) |
| { |
| argv_free(ictx->meta); |
| free(ictx); |
| } |
| |
| void ntux_free_driver_ctx(struct ntux_driver_ctx * ctx) |
| { |
| struct ntux_driver_ctx_alloc * ictx; |
| uintptr_t addr; |
| |
| if (ctx) { |
| addr = (uintptr_t)ctx - offsetof(struct ntux_driver_ctx_impl,ctx); |
| addr = addr - offsetof(struct ntux_driver_ctx_alloc,ctx); |
| ictx = (struct ntux_driver_ctx_alloc *)addr; |
| ntux_free_driver_ctx_impl(ictx); |
| } |
| } |
| |
| const struct ntux_source_version * ntux_source_version(void) |
| { |
| return &ntux_src_version; |
| } |