Using the Caché Callout Gateway
Issuing Operating System Commands
[Home] [Back] [Next]
InterSystems: The power behind what matters   
Class Reference   

The Caché $ZF(-1) and $ZF(-2) functions allow you to issue operating systems commands from Caché. These are the only Caché Callout functions that can be used without a special Callout shared library (see Creating a Caché Callout Library). The following topics are discussed in this section:

Issuing System Commands with $ZF(-1)
$ZF(-1) permits a command of the host operating system to be invoked. The specified command is executed as a spawned child process from the current console. $ZF(-1) waits for the process to end, and will not allow the parent Caché process to exit while the child process is executing.
After the child process exits, $ZF(-1) returns the exit status code issued by the operating system shell. Possible values are 0 if the function call is successful, 1 if an error occurs, or -1 if a child process could not be spawned.
On Windows, the following ObjectScript code creates a directory named test folder under the current directory (the extra quotes around the directory name are required in Windows because the name contains a space):
   SET status = $ZF(-1,"mkdir ""test folder""")
UNIX® and related operating systems
The following example executes a pwd command:
   SET status = $ZF(-1,"pwd") 
The shell window displays output similar to the following:
The following example executes a DCL SHOW DEF command:
   SET status = $ZF(-1,"SHOW DEF")
The shell window displays output similar to the following:
Whatever the privilege level required for the DCL call, the process making the call returns to its original privilege level after the command is completed.
In most cases, $ZF(-1) should be used only with commands that have their effect in the background. If a command requires user input (as in the following example, which requires the user to close Notepad), the child process may hang.
The commands in the following example use the default application for .txt files to open the specified file:
Opening a text file with $ZF(-1)
   SET fname="""C:\My Test.txt"""
   WRITE fname,!
   SET status=$ZF(-1,fname)
   WRITE status

Using $ZF(-1) in the Terminal
$ZF(-1) can also be used load an interactive operating system shell in the Terminal (see Operating System Shells in Using the Terminal). It works just like the ! terminal command except that $ZF(-1) executes in a separate window, while ! works entirely within the Terminal window.
Using OpenVMS Device Parameters
On OpenVMS, a $ZF(-1) command can take optional device input and output parameters, as follows:
   SET status = $ZF(-1,DCLcommand[,outdev[,indev]])
where outdev specifies SYS$OUTPUT and indev specifies SYS$INPUT for the child process.
If the OpenVMS process created when you issue $ZF(-1) is killed or stopped, the return code is -1. In some cases, this may be caused by the child process trying to use the same SYS$INPUT as the parent process, and can be handled by specifying a value for the indev parameter. The OpenVMS error code may be seen using the SYSLOG utility.
Spawning Concurrent Child Processes with $ZF(-2)
$ZF(-2) executes the specified program as a spawned child process from the current console. It returns immediately after spawning the child process and does not wait for the process to terminate. Input and output devices default to the null device.
Commands initiated via $ZF(-2) should not perform I/O on the principal device. Typically, Caché equates the principal device to the null device.
$ZF(-2) does not return the child process exit status. Instead, it returns zero if the child process was created successfully, or -1 if a child process could not be forked. $ZF(-2) permits a program invoked from Caché to continue execution even if Caché is terminated.
$ZF(-2) closes the parent process principal device (specified in Caché special variable $PRINCIPAL) before executing the command. This is done because the child process executes concurrently with the parent. If $ZF(-2) did not close $PRINCIPAL, output from the parent and the child would become intermingled. When using $ZF(-2) you should redirect I/O in the command if you wish to recover output from the child process. For example:
   SET x=$ZF(-2,"ls -l > mydir.txt")
If the pathname supplied in progname contains a space character, pathname handling is platform-dependent. OpenVMS permits space characters in pathnames; no special processing is required. UNIX® permits space characters in pathnames, but a pathname containing spaces must be enclosed in double quote (") characters. Windows requires that you either strip out blank spaces, or supply an additional set of quotes around a pathname that contains spaces, as shown in the following examples. With no spaces "C:/MyDocuments"; with spaces ""C:/My Documents"". You can use the NormalizeFilenameWithSpaces() method of the %Library.File class to handle spaces in pathnames as appropriate for the host platform.
Adding the %System_Callout:USE Privilege
If your Caché security setting is higher than minimal, both $ZF(-1) and $ZF(-2) require 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 Caché installation. The following sections 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:
  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(-1) and $ZF(-2) 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.