Using the Callout Gateway
Running Programs or System Commands with $ZF(-100)
[Home] [Back] [Next]
InterSystems: The power behind what matters   
Class Reference   
Search:    

The $ZF(-100) function permits a Caché process to invoke an executable program or a command of the host operating system. This is the only InterSystems Callout function that can be used without a special Callout shared library (see Creating an InterSystems Callout Library). The following topics are discussed in this chapter:

Note:
$ZF(-100) replaces deprecated functions $ZF(-1) and $ZF(-2), and should be preferred in all cases.
Introduction
$ZF(-100) provides functionality similar to that of a command line interface, allowing you to invoke an executable program or a command of the host operating system. The syntax of this function is:
    sc = $ZF(-100, keywords, command, arguments )
The first argument must be a literal -100. The other three arguments specify the following information:
The $ZF(-100) function returns an exit status code determined by the operating system and the program that was invoked.
The following example passes three strings to the echo command and then displays the status code. This example does not use any keywords, so the keywords argument is an empty string. The final command argument specifies a quoted string (following standard ObjectScript string rules):
   USER>set status = $ZF(-100,"","echo","hello","world","""goodbye now""")
   hello world "goodbye now"

   USER>write status
   0
The following sections provide more examples for various $ZF(-100) options. See $ZF(-100): Running Programs or System Commands in the Callout Quick Reference chapter for a summary of keywords and other options.
Program Execution
$ZF(-100) allows you to run a program or command either synchronously or asynchronously, with or without invoking the operating system shell. The default is to execute synchronously without invoking a shell. Default execution can be overridden by specifying optional keywords in the function call.
The following keywords can be used to control program execution:
As mentioned in the last section, you can specify an empty string for the keyword parameter if you don’t want to use either of these options. This example deliberately tries to list nonexistent files so that an error code 1 will be generated:
   USER>set status = $ZF(-100,"", "ls","*.scala")
   ls: cannot access *.scala: No such file or directory

   USER>write st
   1
If we run the same command asynchronously, the output is not displayed and st is undefined because no error code has been returned:
   USER>kill st
   USER>set status = $ZF(-100,"/ASYNC", "ls","*.scala")
   USER>write st

   WRITE st
   ^
   <UNDEFINED> *st
See Using I/O Redirection in the next section for a way to redirect error output in situations like this.
Logging Commands and Redirecting Output
The following keywords control logging and I/O redirection:
Logging Command Arguments
The /LOGCMD keyword causes command arguments and the exit status code to be logged in the console log (<install-dir>\mgr\messages.log). This is intended primarily as a debugging tool that allows you to see how expressions passed to $ZF(-100) were actually evaluated.
In most cases, the command and its arguments are logged on one line, and the return value on the next. For example, set st=$ZF(-100,"/LOGCMD","echo","hello","world") produces the following log entry under Windows:
   03/28/18-11:49:51:898 (26171) 0 $ZF(-100) cmd=echo "hello" "world"
   03/28/18-11:49:51:905 (26171) 0 $ZF(-100) ret=0
However, on UNIX® when /SHELL is not specified, values are logged one per line:
   03/28/18-12:09:22:243 (26171) 0 $ZF(-100) argv[0]=echo
   03/28/18-12:09:22:500 (26171) 0 $ZF(-100) argv[1]=hello
   03/28/18-12:09:22:559 (26171) 0 $ZF(-100) argv[2]=world
   03/28/18-12:09:22:963 (26171) 0 $ZF(-100) ret=0
In either case, arguments are logged exactly as they are received by the program.
Using I/O Redirection
The following keywords and file specifiers control I/O redirection:
I/O redirection keywords are followed by an operator ( = or += ) and a filename or file path. Spaces are permitted around the operators. Standard input should point to an existing file. The standard output and standard error files are created if they don't exist and are truncated if they already exist. Use the = operator to create or truncate a file, or the += operator to append to an existing file. To make standard error and standard output to go to the same file, specify the same file for both keywords.
In the following example, the first line redirects the standard output from the echo command to file temp.txt., and the second line displays the resulting file contents:
   USER>set st = $ZF(-100,"/STDOUT=""temp.txt""","echo","-e","three\ntwo\none\nblastoff")  
   USER>set st = $ZF(-100,"","cat","temp.txt")
   three
   two
   one
   blastoff
In this next example, we display two lines of temp.txt in a different way, by redirecting the file to standard input. The tail command accepts the input and displays the last two lines:
   USER>set st=$ZF(-100,"/STDIN=""temp.txt""","tail","-n2")
   one
   blastoff
This final example redirects standard error to temp.txt, and attempts to display a nonexistent file. It also uses the /ASYNC keyword to run the command asynchronously, causing the $ZF(-100) call to return before the error message can be displayed. The second line (identical to the previous example) again displays the last two lines of the file, which now contain the redirected error message:
   USER>set st = $ZF(-100,"/ASYNC /STDERR+=""temp.txt""","cat","nosuch.file")

   USER>set st=$ZF(-100,"/STDIN=""temp.txt""","tail","-n2")
   blastoff
   cat: nosuch.file: No such file or directory
Adding the %System_Callout:USE Privilege
If your InterSystems security setting is higher than minimal, 0 $ZF(-100) requires the %System_Callout:USE privilege.
The %System_CallOut resource is already assigned to the %Developer Role, which you will have if you selected the Developer setup during installation. The following procedures describe how to assign this resource if you do not already have it:
Assigning a Role to a User
Use the following procedure to assign the %Developer role to a User:
  1. Open the Management Portal, go to [System Administration] > [Security Management] > [Users] and click Edit on the user description you want to use, then select the [Roles] tab.
  2. Move the %Developer role from the Available column to the Selected column and click Assign. The role will appear in the list of roles assigned to this user. (If the %Developer role does not appear in the Available column, check the list of roles to see if you already have this role).
  3. Click the Profile button. The %Developer role should be listed on the Roles: line.
Creating a New Role
In some cases, it may be desirable to have a role that allows use of $ZF(-100) but does not grant any other privileges. Use the following procedure to create a new role that grants only the %System_CallOut:USE privilege:
  1. Open the Management Portal and go to [System Administration] > [Security Management] > [Roles].
  2. Click the Create New Role button to bring up the Edit Roles page.
  3. Fill in the name and description:
    When you click Save, an Add button appears on the form.
  4. Click the Add button to pop up a scrolling list of resources, select %System_CallOut from the list, and click Save. Click Close on the Edit Role form.
  5. On the Roles page, the new UseCallout role is now in the list of role definitions.