From b824c9188a7636b0f8b483ac1ade79885610cca1 Mon Sep 17 00:00:00 2001 From: midipix Date: Oct 30 2022 16:24:17 +0000 Subject: ntux_cmd_bridge(): initial implementation and integration. --- diff --git a/include/ntux/ntux.h b/include/ntux/ntux.h index c7b0078..c29ffa7 100644 --- a/include/ntux/ntux.h +++ b/include/ntux/ntux.h @@ -72,6 +72,7 @@ enum ntux_cmd { NTUX_CMD_CHMOD, NTUX_CMD_ACEIT, NTUX_CMD_FSPATH, + NTUX_CMD_BRIDGE, NTUX_CMD_CAP, }; @@ -117,6 +118,8 @@ struct ntux_common_ctx { const char * strmode; const char * owner; const char * group; + const char * interp; + const char * optarg; uint32_t sysmask[16]; uint32_t dbgmask[16]; uint32_t osmask [32]; @@ -153,6 +156,7 @@ ntux_api int ntux_cmd_fspath (const struct ntux_driver_ctx *, const c ntux_api int ntux_cmd_stat (const struct ntux_driver_ctx *, const char *); ntux_api int ntux_cmd_spawn (const struct ntux_driver_ctx *); ntux_api int ntux_cmd_strace (const struct ntux_driver_ctx *); +ntux_api int ntux_cmd_bridge (const struct ntux_driver_ctx *); /* utility api */ ntux_api int ntux_main (char **, char **, const struct ntux_fd_ctx *); diff --git a/project/common.mk b/project/common.mk index e99c8e0..674323c 100644 --- a/project/common.mk +++ b/project/common.mk @@ -7,6 +7,7 @@ DRIVER_SRCS = \ src/driver/ntux_amain.c \ src/driver/ntux_driver_ctx.c \ src/skin/ntux_skin_aceit.c \ + src/skin/ntux_skin_bridge.c \ src/skin/ntux_skin_chmod.c \ src/skin/ntux_skin_default.c \ src/skin/ntux_skin_fspath.c \ @@ -24,6 +25,7 @@ INTERNAL_SRCS = \ CMD_SRCS = \ src/cmds/ntux_cmd_aceit.c \ + src/cmds/ntux_cmd_bridge.c \ src/cmds/ntux_cmd_chmod.c \ src/cmds/ntux_cmd_fspath.c \ src/cmds/ntux_cmd_spawn.c \ diff --git a/project/extras.mk b/project/extras.mk index 2d65b57..6168adf 100644 --- a/project/extras.mk +++ b/project/extras.mk @@ -33,6 +33,12 @@ install-app-extras: rm -f bin/$(NICKNAME).aceit$(OS_APP_SUFFIX).tmp rm -f bin/$(NICKNAME).fspath$(OS_APP_SUFFIX).tmp + rm -f bin/$(NICKNAME).bridge$(OS_APP_SUFFIX).tmp + rm -f bin/$(NICKNAME).bridge.exe$(OS_APP_SUFFIX).tmp + rm -f bin/$(NICKNAME).bridge.exe.interp$(OS_APP_SUFFIX).tmp + rm -f bin/$(NICKNAME).bridge.exe.interp.abspath$(OS_APP_SUFFIX).tmp + rm -f bin/$(NICKNAME).bridge.exe.interp.cwdpath$(OS_APP_SUFFIX).tmp + ln -s $(NICKNAME)$(OS_APP_SUFFIX) bin/$(NICKNAME).stat$(OS_APP_SUFFIX).tmp ln -s $(NICKNAME)$(OS_APP_SUFFIX) bin/$(NICKNAME).chmod$(OS_APP_SUFFIX).tmp ln -s $(NICKNAME)$(OS_APP_SUFFIX) bin/$(NICKNAME).spawn$(OS_APP_SUFFIX).tmp @@ -40,9 +46,21 @@ install-app-extras: ln -s $(NICKNAME)$(OS_APP_SUFFIX) bin/$(NICKNAME).aceit$(OS_APP_SUFFIX).tmp ln -s $(NICKNAME)$(OS_APP_SUFFIX) bin/$(NICKNAME).fspath$(OS_APP_SUFFIX).tmp + ln -s $(NICKNAME)$(OS_APP_SUFFIX) bin/$(NICKNAME).bridge$(OS_APP_SUFFIX).tmp + ln -s $(NICKNAME)$(OS_APP_SUFFIX) bin/$(NICKNAME).bridge.exe$(OS_APP_SUFFIX).tmp + ln -s $(NICKNAME)$(OS_APP_SUFFIX) bin/$(NICKNAME).bridge.exe.interp$(OS_APP_SUFFIX).tmp + ln -s $(NICKNAME)$(OS_APP_SUFFIX) bin/$(NICKNAME).bridge.exe.interp.abspath$(OS_APP_SUFFIX).tmp + ln -s $(NICKNAME)$(OS_APP_SUFFIX) bin/$(NICKNAME).bridge.exe.interp.cwdpath$(OS_APP_SUFFIX).tmp + mv bin/$(NICKNAME).stat$(OS_APP_SUFFIX).tmp $(DESTDIR)$(BINDIR)/$(NICKNAME).stat$(OS_APP_SUFFIX) mv bin/$(NICKNAME).chmod$(OS_APP_SUFFIX).tmp $(DESTDIR)$(BINDIR)/$(NICKNAME).chmod$(OS_APP_SUFFIX) mv bin/$(NICKNAME).spawn$(OS_APP_SUFFIX).tmp $(DESTDIR)$(BINDIR)/$(NICKNAME).spawn$(OS_APP_SUFFIX) mv bin/$(NICKNAME).strace$(OS_APP_SUFFIX).tmp $(DESTDIR)$(BINDIR)/$(NICKNAME).strace$(OS_APP_SUFFIX) mv bin/$(NICKNAME).aceit$(OS_APP_SUFFIX).tmp $(DESTDIR)$(BINDIR)/$(NICKNAME).aceit$(OS_APP_SUFFIX) mv bin/$(NICKNAME).fspath$(OS_APP_SUFFIX).tmp $(DESTDIR)$(BINDIR)/$(NICKNAME).fspath$(OS_APP_SUFFIX) + + mv bin/$(NICKNAME).bridge$(OS_APP_SUFFIX).tmp $(DESTDIR)$(BINDIR)/$(NICKNAME).bridge$(OS_APP_SUFFIX) + mv bin/$(NICKNAME).bridge.exe$(OS_APP_SUFFIX).tmp $(DESTDIR)$(BINDIR)/$(NICKNAME).bridge.exe$(OS_APP_SUFFIX) + mv bin/$(NICKNAME).bridge.exe.interp$(OS_APP_SUFFIX).tmp $(DESTDIR)$(BINDIR)/$(NICKNAME).bridge.exe.interp$(OS_APP_SUFFIX) + mv bin/$(NICKNAME).bridge.exe.interp.abspath$(OS_APP_SUFFIX).tmp $(DESTDIR)$(BINDIR)/$(NICKNAME).bridge.exe.interp.abspath$(OS_APP_SUFFIX) + mv bin/$(NICKNAME).bridge.exe.interp.cwdpath$(OS_APP_SUFFIX).tmp $(DESTDIR)$(BINDIR)/$(NICKNAME).bridge.exe.interp.cwdpath$(OS_APP_SUFFIX) diff --git a/src/cmds/ntux_cmd_bridge.c b/src/cmds/ntux_cmd_bridge.c new file mode 100644 index 0000000..e187f11 --- /dev/null +++ b/src/cmds/ntux_cmd_bridge.c @@ -0,0 +1,202 @@ +/***********************************************************/ +/* ntux: native translation und extension */ +/* Copyright (C) 2016--2022 SysDeer Technologies, LLC */ +/* Released under GPLv2 and GPLv3; see COPYING.NTUX. */ +/***********************************************************/ + +#include + +#include +#include +#include +#include +#include + +#include +#include "ntux_driver_impl.h" +#include "ntux_nolibc_impl.h" +#include "ntux_errinfo_impl.h" + +int ntux_cmd_bridge(const struct ntux_driver_ctx * dctx) +{ + int ret; + int val; + pid_t pid; + int argc; + const char ** argv; + const char ** envp; + unsigned char * program; + unsigned char * logfile; + ssize_t rbytes; + ssize_t wbytes; + char * ch; + char * script; + char * interp; + const char * usrscript; + char ** sargv; + const char ** pargv; + const char ** aargv; + char buf[2048]; + int fdlog[2]; + int32_t status; + + struct ntux_fd_ctx fdctx; + + /* init */ + ntux_driver_set_ectx( + dctx,0, + dctx->cctx->sargv[0]); + + if (ntux_get_driver_fdctx(dctx,&fdctx) < 0) + if (ntux_errno_set(dctx,fdlog[1])) + return NTUX_SYSTEM_ERROR(dctx); + + if (dctx->cctx->interp) { + ret = __xfi_framework_get_int32_slot_value( + PSX_RTDATA_UDAT32_ARGV1_IS_OPTARG, + &val); + + if (ret < 0) + if (ntux_errno_set(dctx,fdlog[1])) + return NTUX_CUSTOM_ERROR( + dctx, + NTUX_ERR_FLOW_ERROR); + + for (sargv=dctx->cctx->sargv; *sargv; sargv++) + (void)0; + + argc = sargv - dctx->cctx->sargv; + + if (!(aargv = ntux_calloc(argc + 3,sizeof(char *)))) + if (ntux_errno_set(dctx,fdlog[1])) + return NTUX_SYSTEM_ERROR(dctx); + + if (!(script = ntux_calloc(1,NTUX_MAX_PATH))) + if (ntux_errno_set(dctx,fdlog[1])) + return NTUX_SYSTEM_ERROR(dctx); + + if (!(interp = ntux_calloc(1,NTUX_MAX_PATH))) + if (ntux_errno_set(dctx,fdlog[1])) + return NTUX_SYSTEM_ERROR(dctx); + + usrscript = val ? dctx->cctx->sargv[2] : dctx->cctx->sargv[1]; + + if (__sys_fs_npath(fdctx.fdcwd,usrscript,0,script,NTUX_MAX_PATH) < 0) + if (ntux_errno_set(dctx,fdlog[1])) + return NTUX_SYSTEM_ERROR(dctx); + + if (__sys_fs_npath(fdctx.fdcwd,dctx->cctx->interp,0,interp,NTUX_MAX_PATH) < 0) + if (ntux_errno_set(dctx,fdlog[1])) + return NTUX_SYSTEM_ERROR(dctx); + + if (val) { + aargv[0] = interp; + aargv[1] = dctx->cctx->sargv[1]; + aargv[2] = script; + + sargv = &dctx->cctx->sargv[3]; + pargv = &aargv[3]; + } else { + aargv[0] = interp; + aargv[1] = script; + + sargv = &dctx->cctx->sargv[2]; + pargv = &aargv[2]; + } + + for (; *sargv; ) + *pargv++ = *sargv++; + + argv = aargv; + program = (unsigned char *)interp; + } else { + argv = (const char **)dctx->cctx->sargv; + program = (unsigned char *)dctx->cctx->sargv[0]; + } + + envp = (const char **)dctx->cctx->senvp; + logfile = (unsigned char *)dctx->cctx->logfile; + + /* fdlog */ + if (logfile) { + if ((fdlog[1] = __sys_openat( + ntux_driver_fdcwd(dctx), + logfile,O_CREAT|O_TRUNC|O_WRONLY,0)) < 0) + if (ntux_errno_set(dctx,fdlog[1])) + return NTUX_SYSTEM_ERROR(dctx); + } else { + if ((ret = __sys_pipe(fdlog)) < 0) + if (ntux_errno_set(dctx,ret)) + return NTUX_SYSTEM_ERROR(dctx); + } + + /* spawn */ + pid = __sys_vfork(); + + /* failed? */ + if (pid < 0) + if (ntux_errno_set(dctx,pid)) + return NTUX_SYSTEM_ERROR(dctx); + + /* child */ + if (pid == 0) + if ((status = __sys_execve(program,argv,envp))) + if (ntux_errno_set(dctx,status)) + if (NTUX_SYSTEM_ERROR(dctx)) + __sys_exit(0); + + /* parent */ + __sys_close(fdlog[1]); + + if (dctx->cctx->logfile) { + __sys_wait4( + pid,&status, + 0,0); + + return 0; + } + + /* piped bridge output */ + rbytes = __sys_read(fdlog[0],buf,sizeof(buf)); + + while (rbytes == -EINTR) + rbytes = __sys_read(fdlog[0],buf,sizeof(buf)); + + while (rbytes > 0) { + for (ch=buf; rbytes; ch += wbytes) { + wbytes = __sys_write(2,ch,rbytes); + + while (wbytes == -EINTR) + wbytes = __sys_write(2,buf,rbytes); + + if (wbytes < 0) { + __sys_close(fdlog[0]); + ntux_errno_set(dctx,wbytes); + return NTUX_SYSTEM_ERROR(dctx); + } + + rbytes -= wbytes; + } + + rbytes = __sys_read(fdlog[0],buf,sizeof(buf)); + + while (rbytes == -EINTR) + rbytes = __sys_read(fdlog[0],buf,sizeof(buf)); + } + + __sys_close(fdlog[0]); + + if (rbytes < 0) + if (ntux_errno_set(dctx,rbytes)) + return NTUX_SYSTEM_ERROR(dctx); + + /* wait */ + struct ntux_driver_ctx_impl * ictx = ntux_get_driver_ictx(dctx); + + __sys_wait4( + pid, + &ictx->cctx.status, + 0,0); + + return 0; +} diff --git a/src/driver/ntux_amain.c b/src/driver/ntux_amain.c index d103046..a18d67e 100644 --- a/src/driver/ntux_amain.c +++ b/src/driver/ntux_amain.c @@ -105,6 +105,11 @@ int ntux_main(char ** argv, char ** envp, const struct ntux_fd_ctx * fdctx) __xfi_exit(dctx->cctx->status); } + if (dctx->cctx->cmd == NTUX_CMD_BRIDGE) { + ntux_cmd_bridge(dctx); + __xfi_exit(dctx->cctx->status); + } + for (unit=dctx->units; *unit; unit++) ntux_perform_unit_actions(dctx,*unit); diff --git a/src/driver/ntux_driver_ctx.c b/src/driver/ntux_driver_ctx.c index 129992c..09d2142 100644 --- a/src/driver/ntux_driver_ctx.c +++ b/src/driver/ntux_driver_ctx.c @@ -6,10 +6,14 @@ #include #include +#include +#include +#include #include #include #include +#include #include #include "ntux_nolibc_impl.h" @@ -36,6 +40,18 @@ static const char * const ntux_cmd_name[NTUX_CMD_CAP] = { [NTUX_CMD_CHMOD] = "chmod", [NTUX_CMD_ACEIT] = "aceit", [NTUX_CMD_FSPATH] = "fspath", + [NTUX_CMD_BRIDGE] = "bridge", +}; + +/* ntux exec commands */ +static const bool const ntux_cmd_exec[NTUX_CMD_CAP] = { + [NTUX_CMD_STAT] = false, + [NTUX_CMD_SPAWN] = true, + [NTUX_CMD_STRACE] = true, + [NTUX_CMD_CHMOD] = false, + [NTUX_CMD_ACEIT] = false, + [NTUX_CMD_FSPATH] = false, + [NTUX_CMD_BRIDGE] = true, }; /* ntux command options */ @@ -47,6 +63,7 @@ static const struct argv_option * ntux_cmd_options[NTUX_CMD_CAP] = { [NTUX_CMD_CHMOD] = ntux_chmod_options, [NTUX_CMD_ACEIT] = ntux_aceit_options, [NTUX_CMD_FSPATH] = ntux_fspath_options, + [NTUX_CMD_BRIDGE] = ntux_bridge_options, }; /* package info */ @@ -216,6 +233,9 @@ static int ntux_cctx_update( else if (!strcmp(entry->arg,"fspath")) cctx->cmd = NTUX_CMD_FSPATH; + else if (!strcmp(entry->arg,"bridge")) + cctx->cmd = NTUX_CMD_BRIDGE; + break; case TAG_LOADER: @@ -264,6 +284,14 @@ static int ntux_cctx_update( cctx->drvflags |= NTUX_DRIVER_DUMP; break; + case TAG_INTERP: + cctx->interp = entry->arg; + break; + + case TAG_OPTARG: + cctx->optarg = entry->arg; + break; + case TAG_SYNTAX: case TAG_RPATH: case TAG_APATH: @@ -316,6 +344,29 @@ static int ntux_get_driver_ctx_fail(struct argv_meta * meta) return -1; } +static int ntux_cmd_program_is_bridge(const char * program) +{ + const char * slash; + const char * mark; + + mark = (slash = strrchr(program,'/')) + ? ++slash : program; + + if (!strcmp(mark,"ntux.bridge.exe")) + return true; + + else if (!strcmp(mark,"ntux.bridge.exe.interp")) + return true; + + else if (!strcmp(mark,"ntux.bridge.exe.interp.abspath")) + return true; + + else if (!strcmp(mark,"ntux.bridge.exe.interp.cwdpath")) + return true; + + return false; +} + static int ntux_cmd_from_program(const char * program) { const char * dot; @@ -332,20 +383,33 @@ static int ntux_cmd_from_program(const char * program) else mark = program; - if (!strcmp(mark,"stat")) + if (!strcmp(mark,"stat")) { return NTUX_CMD_STAT; - else if (!strcmp(mark,"spawn")) + + } else if (!strcmp(mark,"spawn")) { return NTUX_CMD_SPAWN; - else if (!strcmp(mark,"strace")) + + } else if (!strcmp(mark,"strace")) { return NTUX_CMD_STRACE; - else if (!strcmp(mark,"chmod")) + + } else if (!strcmp(mark,"chmod")) { return NTUX_CMD_CHMOD; - else if (!strcmp(mark,"aceit")) + + } else if (!strcmp(mark,"aceit")) { return NTUX_CMD_ACEIT; - else if (!strcmp(mark,"fspath")) + + } else if (!strcmp(mark,"fspath")) { return NTUX_CMD_FSPATH; - return NTUX_CMD_DEFAULT; + } else if (!strcmp(mark,"bridge")) { + return NTUX_CMD_BRIDGE; + + } else if (ntux_cmd_program_is_bridge(program)) { + return NTUX_CMD_BRIDGE; + + } else { + return NTUX_CMD_DEFAULT; + } } int ntux_get_driver_ctx( @@ -355,6 +419,8 @@ int ntux_get_driver_ctx( const struct ntux_fd_ctx * fdctx, struct ntux_driver_ctx ** pctx) { + int ret; + int val; struct ntux_driver_ctx_impl * ictx; struct ntux_common_ctx cctx; const struct argv_option * optv[NTUX_OPTV_ELEMENTS]; @@ -367,6 +433,9 @@ int ntux_get_driver_ctx( char * cmdmark; char ** execargv; char * execarg; + char * interp; + char * pathbuf; + size_t pathlen; struct argv_ctx ctx = {ARGV_VERBOSITY_NONE, ARGV_MODE_SCAN, 0,0,0,0,0,0,0}; @@ -392,6 +461,58 @@ int ntux_get_driver_ctx( cctx.cmd = ntux_cmd_from_program(program); cctx.drvflags = flags; + switch (cctx.cmd) { + case NTUX_CMD_BRIDGE: + break; + + default: + /* potential .exe bridge setup? */ + pathlen = ntux_strlen(argv[0]); + + if (pathlen + NTUX_EXE_SUFFIX_LEN >= NTUX_MAX_PATH) + break; + + + /* intermediate buffers */ + if (!(pathbuf = ntux_calloc(1,NTUX_MAX_PATH))) + return NTUX_ERROR; + + if (!(interp = ntux_calloc(1,NTUX_MAX_PATH))) { + ntux_free(pathbuf); + return NTUX_ERROR; + } + + /* is argv[0] a symlink to ntux's bridge symlink? */ + ret = __sys_readlinkat( + fdctx->fdcwd, + (const unsigned char *)argv[0], + pathbuf,NTUX_MAX_PATH); + + if ((ret > 0) && (ret < NTUX_MAX_PATH)) { + if (ntux_cmd_program_is_bridge(pathbuf)) { + ntux_strcpy(pathbuf,argv[0]); + ntux_strcpy(&pathbuf[pathlen],NTUX_EXE_SUFFIX); + + ret = __sys_readlinkat( + fdctx->fdcwd, + (const unsigned char *)pathbuf, + interp,NTUX_MAX_PATH); + + ntux_free(pathbuf); + + if ((ret < 0) || (ret >= NTUX_MAX_PATH)) { + ntux_free(interp); + return NTUX_ERROR; + } + + cctx.cmd = NTUX_CMD_BRIDGE; + cctx.interp = interp; + } + } + + break; + } + /* missing arguments? */ argv_optv_init(ntux_cmd_options[cctx.cmd],optv); @@ -488,8 +609,11 @@ int ntux_get_driver_ctx( else if (cctx.cmd == NTUX_CMD_FSPATH) argv_optv_init(ntux_fspath_options,optv); - /* spawn, strace */ - if ((cctx.cmd == NTUX_CMD_SPAWN) || (cctx.cmd == NTUX_CMD_STRACE)) { + else if (cctx.cmd == NTUX_CMD_BRIDGE) + argv_optv_init(ntux_bridge_options,optv); + + /* spawn, strace, bridge */ + if (ntux_cmd_exec[cctx.cmd]) { argv_scan(argv,optv,&ctx,0); if (ctx.erridx && !ctx.unitidx) { @@ -529,12 +653,22 @@ int ntux_get_driver_ctx( return -1; } - /* spawn, strace: exec argv */ - if (execargv) { + /* spawn, strace, bridge: exec argv */ + if (ntux_cmd_exec[cctx.cmd]) { *execargv = execarg; cctx.sargv = execargv; cctx.senvp = envp; nunits = 0; + + ret = __xfi_framework_get_int32_slot_value( + PSX_RTDATA_UDAT32_ARGV0_IS_INTERP, + &val); + + if (ret < 0) + return NTUX_ERROR; + + if (val) + cctx.sargv--; } /* finalize */ @@ -548,6 +682,7 @@ int ntux_get_driver_ctx( if (!(ictx = ntux_driver_ctx_alloc(meta,fdctx,&cctx,nunits))) return ntux_get_driver_ctx_fail(meta); + ictx->interp = interp; ictx->ctx.program = program; ictx->ctx.cctx = &ictx->cctx; *pctx = &ictx->ctx; @@ -557,6 +692,9 @@ int ntux_get_driver_ctx( static void ntux_free_driver_ctx_impl(struct ntux_driver_ctx_alloc * ictx) { + if (ictx->ctx.interp) + ntux_free(ictx->ctx.interp); + argv_free(ictx->meta); free(ictx); } diff --git a/src/internal/ntux_driver_impl.h b/src/internal/ntux_driver_impl.h index 0b8ba26..c3c109c 100644 --- a/src/internal/ntux_driver_impl.h +++ b/src/internal/ntux_driver_impl.h @@ -20,6 +20,14 @@ extern const struct argv_option ntux_strace_options[]; extern const struct argv_option ntux_chmod_options[]; extern const struct argv_option ntux_aceit_options[]; extern const struct argv_option ntux_fspath_options[]; +extern const struct argv_option ntux_bridge_options[]; + +/* bridge functionality */ +#define NTUX_EXE_SUFFIX ".exe" +#define NTUX_EXE_SUFFIX_LEN (4) +#define NTUX_MAX_PATH_UTF8 (32768 / 2 * 3) +#define NTUX_MAX_PATH NTUX_MAX_PATH_UTF8 + enum app_tags { TAG_HELP, @@ -43,6 +51,11 @@ enum app_tags { TAG_APATH, TAG_NPATH, TAG_DPATH, + TAG_INTERP, + TAG_SCRIPT, + TAG_OPTARG, + TAG_CWDPATH, + TAG_ABSPATH, }; struct ntux_driver_ctx_impl { @@ -52,6 +65,7 @@ struct ntux_driver_ctx_impl { struct __psx_context xctx; const struct ntux_unit_ctx *euctx; const char * eunit; + char * interp; struct ntux_error_info ** errinfp; struct ntux_error_info ** erricap; struct ntux_error_info * erriptr[64]; diff --git a/src/skin/ntux_skin_bridge.c b/src/skin/ntux_skin_bridge.c new file mode 100644 index 0000000..d66eac6 --- /dev/null +++ b/src/skin/ntux_skin_bridge.c @@ -0,0 +1,24 @@ +#include "ntux_driver_impl.h" +#include "argv/argv.h" + +const struct argv_option ntux_bridge_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]"}, + + {"interp", 'i',TAG_INTERP,ARGV_OPTARG_REQUIRED,0,0,0, + "script interpreter to execute"}, + + {"script", 's',TAG_SCRIPT,ARGV_OPTARG_REQUIRED,0,0,0, + "script argument to be passed to interpreter"}, + + {"optarg", 's',TAG_OPTARG,ARGV_OPTARG_REQUIRED,0,0,0, + "optional argument to be passed to interpreter"}, + + {"logfile", 'o',TAG_LOGFILE,ARGV_OPTARG_REQUIRED,0,0,"", + "write output to %s"}, + + {0,0,0,0,0,0,0,0} +}; diff --git a/src/skin/ntux_skin_default.c b/src/skin/ntux_skin_default.c index b7fabc6..8daf019 100644 --- a/src/skin/ntux_skin_default.c +++ b/src/skin/ntux_skin_default.c @@ -9,7 +9,7 @@ const struct argv_option ntux_default_options[] = { "show usage information [listing %s options only]"}, {"cmd", 0,TAG_CMD,ARGV_OPTARG_REQUIRED,0, - "stat|spawn|strace|chmod|aceit|fspath",0, + "stat|spawn|strace|chmod|aceit|fspath|bridge",0, "invoke one of the following ntux commands: %s"}, {0,0,0,0,0,0,0,0}