Process agent description


Purpose

The Process agent (ag_process) is used to manage multiple subprocesses running in background. It is part of YaST2 SCR, the system configuration repository, used to access configuration data on the target system. The general SCR API allows Read() and Write() access to get and change data.

Implementation

The agent reuses ExternalProgram class from liby2util, class Process is derived from ExternalProgram and adds stderr reading/writing, output buffering and a posibility to send a specified signal.

Interface of the Process agent

The interface is implemented as a SCR agent with the usual Read(), Write() and Dir() interface. The path prefix used is

The complete path description is available in the autodocs/ directory.

Typical use case

// start a subprocess, remember the id
integer id = (integer)(SCR::Execute(.process.start_shell, "/usr/bin/find /usr -type d"));
string line = "";

while(SCR::Read(.process.running, id) == true)
{
    // read stderr
    line = (string)SCR::Read(.process.read_line_stderr, id);
    if (line != nil)
    {
	y2warning("Error: %1", line);
    }

    // read stdout
    line = (string)SCR::Read(.process.read_line, id);


    if (line != nil)
    {
	// process the output here
	...
    }
    else
    {
	// there was no output, wait for a while
	// give the subprocess time to print something
	// NOTE: change the constand in respect to the running command,
	// increase it for processes which print few lines
	sleep(20);
    }

    ret = (symbol) UI::PollInput();

    // check if the abort button was pressed
    if (ret == `abort)
    {
	SCR::Execute(.process.kill, id);	// kill the subprocess
	break;
    }

}

// process the remaining lines in the stdout buffer
while (line != nil);
{
    UI::ChangeWidget(`id(`dir), `Value, line);
    line = (string)SCR::Read(.process.read_line, id);
}

// process the stderr buffer here
...

Details of API

Start in shell vs. direct start

The agent can start a subprocess in two ways

Note that the arguments are passed differently in each case. Shell execution requires the argument in the command, the arguments must be escaped to be processes correctly. The direct execution uses an optional map, the arguments are passed as a list of strings at key "args". In this case the armunets need not to be escpaed.

Example:
Start echo "\"foo bar\"" command:

Reading stdout/stderr to unblock a process

When a subprocess produces too much output which is not read it is stopped when the buffers are full. (In my test it was about after 64kB, but this is system dependent.)

So it is a good idea to read the output regularly. It is possible to read the output (using .process.read(_line) and .process.read_stderr(_line) paths) when the process is running or just read the output to the internal buffers in the agent (using Read(.process.running), in addition to checking the status it read the outputs) and read them later at once when the process is finished.

Ladislav Slezák <lslezak@novell.com>