Executing operating system commands on a Caché server
- Tutorial
Based on an article in Developer Connection, he wrote his own implementation of a class for invoking commands from the server operating system where Caché or Ensemble is installed.
A class can come in handy when you need to do something on the host OS from Caché: manage backup files, configure work with the version control system and other useful actions.
The class allows you to execute a command on any host OS and get a response to a global or local variable.
The cmdlist parameter contains a list of allowed commands, separated by commas.
The safeCmd () method combs the command line.
The runCmd () method actually executes the cmd command and puts the result in the indirect address ad.
The above code works on all operating systems supported by Caché, executes commands, receives the result and processes errors. Unlike the implementation described in the article , the work is organized through the CommandPipe device - the “QR” mode for the open command. Read more in the documentation .
An example of the use can be observed here - a small project built on CSP + Twitter Bootstrap.
The server was not sent for slaughter - allowed commands: type, ver,format c, dir.
The class and web project code is posted on the github .
A class can come in handy when you need to do something on the host OS from Caché: manage backup files, configure work with the version control system and other useful actions.
The class allows you to execute a command on any host OS and get a response to a global or local variable.
Class code with comments
Class Server.Manage Extends% RegisteredObject
{
Parameter cmdlist = "dir, type, ver";
/// method removes command sequences from the command line
/// leaves only allowed commands
ClassMethod safeCmd (cmd) As% String
{
set cmd = $ piece (cmd, "&&") // leave one command
set cmd = $ piece (cmd , "|")
for i = 1: 1: $ length (.. # cmdlist, ",") set safe ($ p (.. # cmdlist, ",", i)) = "" // list of allowed commands
if '$ data (safe ($ piece (cmd, ""))) set cmd = ""
quit cmd
}
/// the method executes the cmd command on the server and adds the result to the global ad so that:
ClassMethod runCmd (cmd, ad As% String) As% Status
{
set sc = $$$ OK
do $ SYSTEM.Process.SetZEOF (1) // turn off the error generation mode on EOF
// make the command line safe
set cmd (1) = .. safeCmd (cmd)
quit: cmd (1) = "" $$$ ERROR ($$$ GeneralError, "Invalid command" _cmd)
set cmd = cmd (1)
// clear the sent global
kill @ad
set count = 0
try {
// open the device by running the command line and reading the answer
open cmd: "QR: K \ CP866 \" if '$ test $$$ ThrowStatus ($$$ ERROR ($$$ GeneralError, "Failed to execute the command" _cmd))
the Set the IO = $ // remember the IO current device
// read the result of the command line by line until the end of the file arrives and add it to the global
for {
use cmd
read str quit: $ zeof = -1
set @ad @ ($ Increment (count)) = str
}
set @ ad = count
// close the device
#dim e as% Exception.AbstractException
} Catch e {
set sc = e.AsStatus ()
// do e.Log () //
}
// close the device
close cmd
// return the current device
If $ data (IO) Use IO
quit sc
}
}
{
Parameter cmdlist = "dir, type, ver";
/// method removes command sequences from the command line
/// leaves only allowed commands
ClassMethod safeCmd (cmd) As% String
{
set cmd = $ piece (cmd, "&&") // leave one command
set cmd = $ piece (cmd , "|")
for i = 1: 1: $ length (.. # cmdlist, ",") set safe ($ p (.. # cmdlist, ",", i)) = "" // list of allowed commands
if '$ data (safe ($ piece (cmd, ""))) set cmd = ""
quit cmd
}
/// the method executes the cmd command on the server and adds the result to the global ad so that:
ClassMethod runCmd (cmd, ad As% String) As% Status
{
set sc = $$$ OK
do $ SYSTEM.Process.SetZEOF (1) // turn off the error generation mode on EOF
// make the command line safe
set cmd (1) = .. safeCmd (cmd)
quit: cmd (1) = "" $$$ ERROR ($$$ GeneralError, "Invalid command" _cmd)
set cmd = cmd (1)
// clear the sent global
kill @ad
set count = 0
try {
// open the device by running the command line and reading the answer
open cmd: "QR: K \ CP866 \" if '$ test $$$ ThrowStatus ($$$ ERROR ($$$ GeneralError, "Failed to execute the command" _cmd))
the Set the IO = $ // remember the IO current device
// read the result of the command line by line until the end of the file arrives and add it to the global
for {
use cmd
read str quit: $ zeof = -1
set @ad @ ($ Increment (count)) = str
}
set @ ad = count
// close the device
#dim e as% Exception.AbstractException
} Catch e {
set sc = e.AsStatus ()
// do e.Log () //
}
// close the device
close cmd
// return the current device
If $ data (IO) Use IO
quit sc
}
}
The cmdlist parameter contains a list of allowed commands, separated by commas.
The safeCmd () method combs the command line.
The runCmd () method actually executes the cmd command and puts the result in the indirect address ad.
The above code works on all operating systems supported by Caché, executes commands, receives the result and processes errors. Unlike the implementation described in the article , the work is organized through the CommandPipe device - the “QR” mode for the open command. Read more in the documentation .
Demo
An example of the use can be observed here - a small project built on CSP + Twitter Bootstrap.
The server was not sent for slaughter - allowed commands: type, ver,
The class and web project code is posted on the github .