GSP
Quick Navigator

Search Site

Unix VPS
A - Starter
B - Basic
C - Preferred
D - Commercial
MPS - Dedicated
Previous VPSs
* Sign Up! *

Support
Contact Us
Online Help
Handbooks
Domain Status
Man Pages

FAQ
Virtual Servers
Pricing
Billing
Technical

Network
Facilities
Connectivity
Topology Map

Miscellaneous
Server Agreement
Year 2038
Credits
 

USA Flag

 

 

Man Pages
ORCH(5) FreeBSD File Formats Manual ORCH(5)

orchorchestration script file format

The porch(1) program spawns other command-line utilities and drives them via a pts(4), using scripts referred to as orch scripts.

orch script files are written in Lua with a limited environment available. Notably, absolutely none of the standard environment is included. orch scripts are built around constructing () blocks, sometimes in conjunction with multiplexing one() blocks.

() blocks in the same context are executed in the specified order. When a match is successful, the beginning of the program output buffer is trimmed up to the character just after the successful match. Future match() blocks are left with the trimmed output buffer to match against. The default timeout for a match to succeed is 10 seconds, and may be changed by specifying a timeout parameter in the match configuration. The timeout may also be changed globally for future match blocks with the timeout() function described below. match() blocks may also have a callback specified, which itself may contain any number of match() or one() blocks.

orch imports only some parts of the Lua standard library for use in the scriptfile, to minimize the chance of being able to conduct actions that are inherently incompatible with the queuing model that scripts are executed with. Currently, only the () and () functions, and the “string” and “table” modules are exposed.

The following functions exist for usage within the scriptfile:

(cfg)
Set configuration for the current process using the cfg table. The specified cfg is merged into the current configuration. Currently, the only recognized configuration items are those described for the write() function.
()
Change the directory of the program most recently spawned. This must be called after spawn() and before the process is releeased. There is currently no way to persistly chdir(2) for every spawned process.
(local)
Clear the environment. If local is truthy, then the environment is only cleared for the most recent spawn().
(string)
Writes string out to the stderr of orch, with “DEBUG:” prepended and a newline appended to it.

This directive is enqueued, not processed immediately unless it is called from within a failure handler.

(function)
Add function to the queue to be executed in script order. If enqueue() is used in a context that does not execute the queue, such as from another enqueued callback or from a failure context, then it will immediately call the function instead of enqueueing it.
eof(timeout, termfn)
Check for EOF from the process. If the process has closed its side because it was killed by signal, then orch will crash with an assertion unless it was terminated by a signal that was sent by the user with the signal() function. If timeout is not specified, the default timeout will be used. The timeout is applied both to waiting for an actual EOF, and an additional wait for the process to have terminated.

The termfn callback will be invoked if the process was terminated, with a wait status object as the only argument to the callback. This wait status object has the following methods:

()
Returns a boolean indicating whether the process exited or not.
()
Returns a boolean indicating whether the process was signaled or not.
()
Returns a boolean indicating whether the process was stopped or not.
()
Returns the exit code or signal that resulted in termination or stopping.
()
Returns the raw wait(2) status code.

This directive is enqueued, not processed immediately.

(commandstr, collectfn, termfn)
Execute commandstr without piping its output to a spawned command. Note that, unlike other actions that take commands, the exec() action will only take the command as a string or a table that can be coerced into a command string. The result will be passed directly to ().

The output can be collected by specifying a collectfn that takes a line and will be called for every line until we reach EOF. If a collectfn is not specified, then the output will be discarded. The termfn will be called whether the output is collected or not, and it will be passed a wait status object as described above by the () function.

This directive is enqueued, not processed immediately.

(status)
Exit with the designed status code.

This directive is enqueued, not processed immediately unless it is called from within a failure handler.

(function)
Sets up a failure handler. Pass nil to reset the failure handler. The function will receive one argument, the contents of the buffer, to aide in debugging. By default, orch will exit with a status of 1 when a match block fails. The failure handler prevents the default exit, but may itself call exit(). The return value is ignored.

This directive is enqueued, not processed immediately. The () function is not available as a direct child of a one() block.

(timeout)
Flushes all output received within timeout seconds. If timeout is 0 or unspecified, waits indefinitely for EOF from the process.

This directive is enqueued, not processed immediately.

(key)
Get the value of key from the current environment.

This directive is always processed immediately and may not be used in a queued context. () is expected to mostly be used for debugging purposes.

(string)
Writes an hd(1) style hexdump output to stderr of the input string.

This directive is always processed immediately, and is intended to be used within a failure context to aide in analysis of why a match failed.

(logfile)
Sets a logfile for subsequent input and output to the process. The logfile may be a string specifying a filename or an open file (for lib users). If a filename is specified, then orch will open it in write-append mode and preserve existing contents.
(type)
Changes the default matcher for subsequent match blocks to the type described by type. The default type is the “lua” matcher, which interprets match patterns as lua patterns and executes them accordingly. Note that Lua string processing still applies for every pattern matcher. e.g., “\r” will be interpreted as a carriage return for these non-default pattern matchers.

The following matcher options are available:

“lua”
Uses Lua pattern matching to match patterns.
“plain”
Treats the pattern as a plain old string; no characters are special.
“posix”
Treats the pattern as a POSIX extended regular expression. See re_format(7) for more details.
“default”
An alias for the “lua” matcher.
(commandstr, linefilter)
Execute the command in commandstr and pipe any output from it into the spawned process. Note that, unlike other actions that take commands, the pipe() action will only take the command as a string or a table that can be coerced into a command string. The result will be passed directly to ().

If a linefilter callback is passed, then every line from the given command will be ran through it and the result of the call written to the process instead. If the callback returns nil, then the line is skipped.

(boolean)
Changes the raw write() state on the process.
release()
Releases a spawned process for execution. This is done implicitly when a match() block is first encountered.

This directive is enqueued, not processed immediately.

(key, value, local), setenv(table, local)
Set the environment variable key to value in the environment. If local is truthy, then the value is only set for the most recent spawn(). The table variant may be used to set multiple environment variables at once.
(signo, ...)
Block all signal signo specified. Each signo may either be a signal number or a table with signal numbers as values.

This directive is enqueued, not processed immediately.

(signo, ...)
Catch all signal signo specified. Each signo may either be a signal number or a table with signal numbers as values.

This directive is enqueued, not processed immediately.

()
Clear the signal mask.

This directive is enqueued, not processed immediately.

(signo, ...)
Ignore all signal signo specified. Each signo may either be a signal number or a table with signal numbers as values.

This directive is enqueued, not processed immediately.

(preserve_sigmask)
Resets all signals to be caught and clears the signal mask, unless preserve_sigmask is truthy.

This directive is enqueued, not processed immediately.

(signo, ...)
Unblock all signal signo specified. Each signo may either be a signal number or a table with signal numbers as values.

This directive is enqueued, not processed immediately.

(signal)
Send the specified signal to the current process. The process must have already been released, either implicitly or by explicit (), prior to sending a signal. It is recommended to match at least one known output from the process before sending a signal.

Signal names known on the current platform are exposed in the signals table. The keys of this table are signal names with a “SIG” prefix. Signals not described in this table are also accepted. orch relies on kill(2) to validate the signal for maximum flexibility.

(width, height)
Set or get the size of the terminal associated with the process. If at least one of width or height are not nil, then size() will resize that dimension of the window. The new current size of the window is always returned.

The window will start off on a fresh spawn with a width and height of 0. The size of the window is never persisted across processes.

This directive is always processed immediately, and thus should always be used in either an () or fail context.

sleep(duration)
Sleeps for at least the specified duration, in seconds. Fractional seconds are supported. As implemented, orch may delay execution for a little longer than the specified duration, but not for any less time.

This directive is enqueued, not processed immediately unless it is called from within a failure handler.

(...)
Spawns a new process. The arguments to spawn() are in the traditional argv style. They may either be specified directly as arguments to the function, or they may instead be constructed as a single table. orch will execute a standard PATH search via execvp(3). Note that the script's directory is added to PATH before execution begins. The spawned process will inherit the running environment.

If the process cannot be spawned, then orch will exit. Note that only one process at a time may be matched against. If a new process is spawned, then the previous process will be killed and subsequent matches will be against the new process.

This directive is enqueued, not processed immediately.

(field, set, unset)
Change the specified field as described by set and unset. field should be one of “cflag”, “iflag”, “lflag”, “oflag”, or “cc”, corresponding to the similarly named fields in termios(4). For the flag fields, the bits in set will be set in the new mask, and the bits in unset will be unset in the new mask. Either may be 0 or nil to indicate no bits to be set or unset respectively. The masks for each field may be found in the “tty” table in the script's global environment. For instance, ICANON's mask may be referenced as “tty.lflag.ICANON”.

For “cc”, the unset argument is ignored, and set should be a table whose keys correspond to a defined “V*” constant, and whose values are either the empty string to indicate that the field should be disabled, an integer for VMIN and VTIME, or a string of the form “^X” to indicate ctrl-X.

Supported entries may be found in the “tty” table in the script's global environment. The “tty.cc” table's keys correspond to supported characters, e.g., “tty.cc.VEOF”, and the associated values are all truthy to indicate that they are supported.

This directive is enqueued, not processed immediately.

(val)
Adjust the default timeout to val seconds for subsequent match() blocks. The default timeout at script start is 10 seconds.

This directive is processed immediately.

(str, cfg)
Write str to stdin of the spawned process. If the process is in raw() mode, then write() will write the entire () out as given. If the process is not in raw() mode, which is the default, then escape sequences and control characters will be processed. Note that lua strings are naturally escape-processed in addition to any escaping done by orch. For example, if one wants to send a literal “^D” in non-raw mode, then “\\^D” is the correct sequence to do so. The first backslash escapes the second backslash, then orch sees just a single backslash preceding the circumflex.

This directive is enqueued, not processed immediately. Execution does not continue to the next command until the str has been completely written.

The cfg argument is a table of configuration items for the current send. The following elements are supported:

rate
The rate at which to send str. This is specified as a table with, at a minimum, a bytes item to describe how many bytes to send in a single batch. orch also accepts a delay item to describe how long to wait in between each batch, in seconds. As with the () function, fractional seconds are supported. With a delay of 0, orch will still call into sleep() with no delay. With no delay, orch will send each batch with no delay in between them.

The “match” blocks are the core primitive of orch scripts. Setting them up sounds complicated, but some Lua-supplied sugar actually makes construction of match() blocks relatively elegant. More on this will be demonstrated in the EXAMPLES section.

The () function takes exactly one argument: a pattern to match against. These patterns are Lua patterns, used without modification to check the output buffer. The match() returns an anonymous function that may be called again with a table to describe the properties of the match() block.

The following properties are available:

callback
Specifies a function to call if the match succeeds. The callback function may itself construct additional “match /” “any” blocks, that will then be used for output matching before proceeding after the successfully matched () block.
timeout
Overrides the current global timeout. The timeout value is measured in seconds.

Constructing a “one” block is as simple as calling one(). The one() function takes a callback as its argument, and this function should setup two or more match() blocks to multiplex between. The first matching pattern, as specified in script order, will be used and the rest of the block discarded. The usual rules of match() blocks apply at this point; the callback will be executed, and the callback may also do further matching.

Note that timeout likely does work in a () block as you might expect. orch will effectively wait the full length of the longest timeout for any of the match() blocks that it contains. If some blocks have shorter timeouts than others, then orch will timeout after the shortest timeout it sees in the block at the time. If the shorter timeout block still does not match, it will be removed from consideration and we will wait up until the next shortest timeout would have expired. That is, a match will not be granted if the matching output comes in after the timeout would have elapsed, even if we are still waiting on input for other blocks.

This listing demonstrates the basic features:

-- Literally spawns a new command: "Hello there", that we will be examining.
spawn("echo", "Hello there")

-- Sets a new default for subsequent match blocks
timeout(3)

-- Just matches the initial "Hello", output buffer now contains " there" to
-- match against.
match "Hello"

-- You are also welcome to do this, if it feels more natural to you:
match("t")

-- This is effectively ignored since the only match block after it specifies an
-- explicit timeout.  If we had another match block after that one, though, then
-- it would use a one second timeout by default.
timeout(1)

-- This one will fail to match, but we have configured a higher timeout than the
-- global timeout we configured above (one second).
match "Friend" {
	timeout = 5,
}

This block demonstrates bidirectional communication:

spawn("cat")

-- The tty we setup is in canonical mode by default, so the trailing \r is
-- necessary for the spawned process to read it (unless the process turns off
-- canonical mode).
write "Hello there\r"

match "Hello" {
	callback = function()
		debug("Hello matched")
	end
}

This block demonstrates more complex nested match blocks:

spawn("cat")

write "Hello world\r"

match "Hello" {
	callback = function()
		-- This will match the world sent above...
		match "world" {
			callback = function()
				-- ... and additionally write "FRIENDS" out
				write "FRIENDS\r"
			end
		}
	end
}

match "FRIENDS" {
	callback = function()
		debug "FRIENDS seen!"
	end
}

This block demonstrates one blocks:

spawn("cat")

write "One\r"

-- These might feel a little bit awkward
one(function()
	-- This match block will end up used because it is specified first.
	match "ne" {
		callback = function()
			debug("This one will be called.")

			-- Script execution continues after the one() block that contains
			-- this match.

			write "One\r"
		end
	}

	-- This match block will effectively be thrown away.
	match "One" {
		callback = function()
			debug("This one will not be called")
		end
	}
end)

-- This one will match, because the "ne" block's callback wrote it out.
match "One"

More examples can be found in /usr/share/porch/examples.

porch(1), pts(4), termios(4)

June 4, 2025 FreeBSD 14.3-RELEASE

Search for    or go to Top of page |  Section 5 |  Main Index

Powered by GSP Visit the GSP FreeBSD Man Page Interface.
Output converted with ManDoc.