Article
· Nov 18, 2023 3m read

Add OS command execution to WebTerminal

 I think WebTerminal is an outstanding project, kudos to @Nikita Savchenko 

One useful functionality is missing, the the ability to run Operating System (Linux or Windows) commands.
In many cases WebTerminal is used when access to the OS is difficult, so having the ability do run simple OS commands from WebTerminal would be a big advantage.
Using "normal" terminal, be it Windows IRIS console, Windows Telnet or within "iris session" in linux is simple, from the IRIS terminal prompt just precede the OS command with "$" or "!".
See the article "Terminal tip: Running OS-level commands" from @John Murray for details.

     

Running OS commands from IRIS code is not difficult, so I had a look to WebTerminal code and realized that could be easily implemented hacked in WebTerminal.

At the moment this is more a hack than a fully tested implementation, nevertheless, at least for simple commands I tested, it works just fine.

The implementation hack require to modify one method and to add one method to the class WebTerminal.Core in the USER namespace.

The changed/modified method in the WebTerminal.Core class is WaitCommand(), this is the modified code:

/// Retrieves a command text from the parent process.
/// Terminates itself if the parent process is dead.
ClassMethod WaitCommand() As %String [ ProcedureBlock = 1 ]
{
    for {
        set data = ..ReceiveChunk()
        set flag = $LISTGET(data, 1)
        if (flag = "m") { // message
            set cmd=$LISTGET(data, 2)
            if $e(cmd)="!" || ($e(cmd)="$") {
                set cmd=$e(cmd,2,*)
                if $f(cmd,"""") set cmd=$replace(cmd,"""","""""")
                return "Do ##class(WebTerminal.Core).ExecOS("""_cmd_""")"
            } else {
                return cmd
            }
        } elseif (flag = "a") { // autocomplete
            do ##class(WebTerminal.Common).SendChunk($ZPARENT, "a", ..VarList())
        } else { // end or unexpected
            do $system.Process.Terminate($JOB, 2)
            return ""
        }
    }
}

Then a new method ExecOS() need to be added to the same WebTerminal.Core class:

/// run an operating system command
ClassMethod ExecOS(cmd As %String) [ ProcedureBlock = 1 ]
{
    Set oldzeof=$SYSTEM.Process.SetZEOF(0)
    set io=$IO
    try {
        if cmd="" Quit
        open cmd:"Q"
        for  {
            use cmd read Line
            use 0 write Line,!
        }
    } catch CatchError {
        use 0
        If CatchError.Name'="<ENDOFFILE>" {
            write CatchError.Name
        }
    }
    close cmd
    Do $SYSTEM.Process.SetZEOF(oldzeof)
    Use io
    quit
}

Screenshots for linux & Windows:

 

 

Please note that only single commands are supported, opening an interactive shell using "!" or "$" with no argument does not work.

It would be nice if someone can test it and provide some feedback, then we can see if it's worth adding it to WebTerminal.

Enrico

P.S.: I mentioned IRIS but the code should run just fine in any Caché or Ensemble version supported by WebTerminal

Discussion (1)2
Log in or sign up to continue