Skip to main content
Previous sectionNext section

$ZF(-100)

Executes an operating system command or program as a child process.

Synopsis

$ZF(-100,flags,program,args)

Parameters

Argument Description
flags A quoted string containing one or more keyword flags. Multiple keyword flags are separated by blank spaces. A keyword flag can take the format /keyword, /keyword=value, or /keyword+=value. Keywords are not case-sensitive. The flags specify how to execute program.
program An operating system command or a program to be executed as a child process, specified as a quoted string. You can specify a full path, or just a program name. The operating system uses its rules, such as a PATH environment variable, to search for the specified program.
args Optional — A comma-separated list of program options and arguments. You can specify a null argument as "". You can use a local array and indirection .args or the args... syntax to specify a variable number of arguments.

Description

$ZF(-100) permits a Caché process to invoke an executable program or a command of the host operating system. It executes the program or command specified in program as a spawned child process from the current console. $ZF(-100) allows you to invoke a program or command either synchronously or asynchronously, with or without invoking the operating system shell. $ZF(-100) provides similar functionality to $ZF(-1) and $ZF(-2). Its use is preferable to $ZF(-1) or $ZF(-2), which are both deprecated functions.

You can use a local array and indirection to specify a variable number of args, as shown in the following UNIX® example:

  SET args=2
  SET args(1)="-01"
  SET args(2)="myfile.c"
  SET status = $ZF(-100,"/ASYNC", "gcc",.args)
Copy code to clipboard

$ZF(-100) sets $ZCHILD to the PID of the started program.

Keyword Flags

How $ZF(-100) executes depends on the flags string values:

  • /ASYNC: Execute program asynchronously; do not wait for it to complete. The default is to execute synchronously.

    If /ASYNC is not specified and /STDIN, /STDOUT, or /STDERR is not specified, Caché attempts to use the operating systems’ current descriptors or standard handles for these files.

  • /SHELL: Execute program using a shell. The default is to not use a shell.

  • /STDIN=filename: I/O redirection input file.

  • /STDOUT=filename: I/O redirection standard data output file. If filename does not exist, the system will create it. If filename exists, /STDOUT=filename will overwrite existing data; /STDOUT+=filename will append to existing data.

  • /STDERR=filename: I/O redirection standard error output file. If filename does not exist, the system will create it. If filename exists, /STDERR=filename will overwrite existing error log data; /STDERR+=filename will append to existing error log data. If you specify the same file for /STDOUT and /STDERR, both types of data will be written to that file.

  • /LOGCMD: log the resulting command line in cconsole.log. Because sometimes it can be hard to get the arguments for complex commands right, this keyword flag allows developers to check if the arguments passed to the command are being correctly formed (especially with regard to quoting). The log facility does not add any quotes or other delimiters. The cconsole.log entry is truncated at 1000 characters.

  • /NOQUOTE: inhibit automatic quoting of commands, command arguments, or filenames. By default, $ZF(-100) provides automatic quoting, and escaping of spaces in paths that is appropriate for most user-supplied values. When needed, you can override this default by specifying /NOQUOTE; the user is then responsible for providing appropriate quotes. See Quoting User-Specified Values.

To specify $ZF(-100) with no keyword flags, specify the empty string for this parameter:

  SET status = $ZF(-100,"", "ls", "-l")
Copy code to clipboard

I/O Redirection

I/O redirection for /STDIN=filename, /STDOUT=filename, and /STDERR=filename follow UNIX® conventions. On both UNIX and Windows systems:

  • /STDIN=filename: The file with that filename is linked to the stdin file handle given to the process that executes the specified cmd string.

  • /STDOUT=filename: If a file with that filename does not already exist, it is created. For an existing file, /STDOUT=filename truncates the file to zero size; /STDOUT+=filename appends to the existing file data. This file is linked to the stdout handle given to the process that executes the specified cmd string. This creates a new file containing the stdout output of the spawned command.

  • /STDERR=filename: If a file with that filename does not already exist, it is created. For an existing file, /STDERR=filename truncates the file to zero size; /STDERR+=filename appends to the existing file data. This file is linked to the stderr handle given to the process that executes the specified cmd string. This creates a new file containing the stderr output of the spawned command.

If /STDIN, /STDOUT, or /STDERR is not specified:

  • If /ASYNC is specified, the null device is used in place of the unspecified file(s). A handle that references the null device is given to the process that executes the specified cmd string as the unspecified file’s handle.

  • If /ASYNC is not specified, the handle used by the Caché job executing the $ZF(-100) function is copied and is given to the process that executes the specified cmd string as the unspecified file’s handle.

    Note:

    On a Windows system you should never omit both the /ASYNC and /STDIN flags.

If /STDIN, /STDOUT, or /STDERR specifies a file that cannot be created or opened, the null device is used in place of the file.

If /STDOUT=filename and /STDERR=filename (or /STDOUT+=filename and /STDERR+=filename) specify the same filename, the specified file is only opened or created once. The resulting file handle is duplicated and supplied as both the stdout and stderr file handles given to the process that executes the specified cmd string. $ZF(-100) generates an <ILLEGAL VALUE> error if you specify the same file for /STDOUT and /STDERR, and one is specified +=filename and the other is specified =filename.

Quoting User-Specified Values

By default,$ZF(-100) provides automatic quoting of a command and the arguments to the command. It automatically handles blank spaces if your executable is in a directory with spaces in the name or a command argument specifies a file for output that contains a space. $ZF(-100) supplies delimiting double quote characters as needed. This behavior is shown in the following example:

  DO $ZF(-100,"/LOGCMD","c:\sdelete64.exe","-nobanner","c:\dir1\nested directory\deleteme\")
Copy code to clipboard

This logs the following to messages.log; $ZF(-100) quoted the final argument to escape the space in the file path:

06/14/18-14:25:05:988 (3788) 0 $ZF(-100) cmd=c:\sdelete64.exe -nobanner "c:\dir1\nested directory\deleteme\"
06/14/18-14:25:06:020 (3788) 0 $ZF(-100) ret=0

If the automatic quoting provided does not correctly escape what you want escaped, you can override it using /NOQUOTE.

The /NOQUOTE flag suppresses automatic quoting; you must do your own quoting, as needed. If a specified value contains a / character or a blank space, the value must be quoted using doubled double quotes. This is shown in the following example:

  DO $ZF(-100,"/NOQUOTE /LOGCMD","c:\sdelete64.exe","""-nobanner""","""c:\dir2\""")
Copy code to clipboard

This logs the following to messages.log:

06/15/18-09:27:38:619 (3788) 0 $ZF(-100) cmd=c:\sdelete64.exe "-nobanner" "c:\dir2\"
06/15/18-09:27:38:650 (3788) 0 $ZF(-100) ret=0

The behavior differs on UNIX® and Windows systems:

  • On a Windows system, if /SHELL is not specified, a command line is created and passed. In this case, some arguments may need to be quoted.

  • On any system, when /SHELL is specified, a command line is created and passed. In this case some arguments may need to be quoted.

Double quotes found within a command or command argument are escaped. On Windows these double quotes are escaped by doubling them as "" (as shown in the above examples). On UNIX they are escaped as \".

Return Status Codes

$ZF(-100) returns the following status codes:

  • 0 if the child process was successfully launched asynchronously (with /ASYNC flag). Status of program execution unknown.

  • -1 if the child process could not be forked.

  • An integer if launched synchronously (no /ASYNC flag). This integer exit status code value is determined by the application called on the host operating system. Commonly it is a positive integer, but some applications may return a negative integer. For example, for most Windows command syntax errors, $ZF(-100) returns 1.

$ZF(-100) with the /SHELL parameter launches the default operating system shell. For further details, see “Issuing Operating System Commands” in Using the Callout Gateway.

If a pathname supplied in program contains a space character, pathname handling is platform-dependent. Windows and UNIX® permit space characters in pathnames, but the entire pathname containing spaces must be enclosed in an additional set of double quote (") characters. This is in accordance with the Windows cmd /c statement. For further details, specify cmd /? at the Windows command prompt.

You can use the NormalizeFilenameWithSpaces() method of the %Library.File class to handle spaces in pathnames as appropriate for the host platform.

$ZF(-100) requires the %System_Callout:U privilege. See “Adding the %System_Callout:USE Privilege” in Using the Callout Gateway for details.

If $ZF(-100) is unable to spawn a process, it generates a <FUNCTION> error.

Error Handling

$ZF(-100) generates a <NOTOPEN> error if:

  • The /STDIN=filename, /STDOUT=filename, or /STDERR=filename could not be opened.

  • The specified program could not be started.

The error is logged in SYSLOG. The operating system error number and message are available from the %SYSTEM.Process.OSError() method.

Auditing

An OS command audit record is added to the audit log for each $ZF(-100) call. This record includes information such as the following:

Command: /Users/myname/cache/jlc/bin/clmanager 4002 
Flags: /ASYNC/SHELL
Copy code to clipboard

$ZF(-100) , $ZF(-1), and $ZF(-2)

These three functions are in most respects identical. They differ in the following ways:

  • $ZF(-100) can be synchronous or asynchronous. It can execute using the operating system shell or not using the shell. It always sets $ZCHILD. Both $ZF(-1) and $ZF(-2) with no specified parameters launch the operating system shell; $ZF(-100) requires a program parameter (and the /SHELL flag) to launch the operating system shell.

    $ZF(-100) is the preferred function for all purposes, replacing both $ZF(-1) and $ZF(-2).

  • $ZF(-1) executes using the OS shell. It is synchronous; it suspends execution of the current process while awaiting completion of the spawned child process. It receives status information from the spawned process, which it returns as an exit status code (an integer value) when the spawned process completes. $ZF(-1) does not set $ZCHILD.

  • $ZF(-2) executes using the OS shell. It is asynchronous; it does not suspend execution of the current process. It immediately returns a status value upon spawning the child process. Because it does not await completion of the spawned child process it cannot receive status information from that process. $ZF(-2) sets $ZCHILD if its fifth argument is true.

See Also