Background agent description

Author: Ladislav Slezak < lslezak@suse.cz>

Changes:


Why was background agent (ag_background) created?

If you need to run program and display progress of its work you can not use target agent, because it waits until subprocess is finished.

Background agent returns result of execution just after subprocess is started and YCP code can continue. Agent stores data from STDOUT until they are read from YCP, which should parse data and refresh status in dialog.

When input buffer in background agent reaches defined value subprocess is stopped until buffer is read. Default buffer size is 500 lines for STDOUT and 200 lines for STDERR output (see .buffer_size or .buffer_size_err paths).

STDERR output can be also read, use .run_output_err command to also store error messages.

Outputs are read by character so it is possible to read output which is not terminated by the new line character. This is usefull if the subprocess uses prompt with. Use .buffer or .buffer_err subpaths for direct access to the internal line buffer. Use this feature carefully - input buffers are cleared after reading!

Limitations

Background agent has these limitations:

Note

Backround agent doesn't use virtual terminals, some programs buffer output when they detect no terminal device. In this case use option to disable buffering (e.g. grep --line-buffered).

Background agent interface

Background agent uses .background root path, subpath determines command.

Read subpaths:

Path nameParamentersResult typeDescription
linesnoneintegertotal number of stdout lines produced by subprocess
newlinesnoneintegernumber of new stdout lines since last reading
lines_errnoneintegertotal number of stderr lines produced by subprocess
newlines_errnoneintegernumber of new stderr lines since last reading
storenonebooleantrue if subprocess was started by run_output or run_output_errcommand
isrunningnonebooleantrue if subprocess is running
statusnoneintegersubprocess exit status
newoutnonelist of stringsreturn stdout output since last reading
newerrnonelist of stringsreturn stderr output since last reading
output_opennonebooleantrue if stdout pipe from subprocess is open
output_open_errnonebooleantrue if stderr pipe from subprocess is open
buffer_sizenoneintegerthe size of stdout input buffer (number of lines)
buffer_size_errnoneintegerthe size of stderr input buffer (number of lines)
buffernonestringread the internal stdout buffer, (note: buffer is cleared after reading!)
buffer_errnonestringread the internal stderr buffer (note: buffer is cleared after reading!)

Example: SCR::Read(.background.newlines) -> 5

Note: if isrunning is false and output_open or output_open_err is true then subprocess exited, but some data are available in the buffer. Isrunning can be used for example to check whether program is running before sending a signal, output_open and newlines are used in loop tests.

Execute subpaths:

Path nameParamentersResult typeDescription
runstring commandboolean start subprocess, do not store output from STDOUT or STDERR, only count number of lines
run_outputstring commandboolean start subprocess, store output from STDOUT, count output from STDERR. On success returns true.
run_output_errstring commandboolean start subprocess, store output from STDOUT and STDERR. On success returns true.
killnilbooleankill subprocess with signal SIGTERM, then with SIGKILL signal, on success returns true

Example: SCR::Execute(.background.run_output, "/bin/rpm -qa") -> true

Write subpaths:

Path nameParamentersResult typeDescription
buffer_sizeinteger linesboolean Set maximum number of stored lines (input buffer size) for STDOUT. When this limit is reached subprocess will be stopped until new lines are read. Parameter lines has to be greater than 0. Returns true if new value was set.
buffer_size_errinteger linesboolean Same as buffer_size, but for STDERR output.
stdinstring inputinteger Write input string to STDIN of the process. Input string can contain multiple lines. Returns number of the written characters. Don't forget to append the new line character at the end of the string, usually it is required.

Example: Set STDOUT buffer size to 100 lines: SCR::Write(.background.buffer_size, 100) -> true

How to use background agent?

Here is YCP code skeleton:

SCR::Read(.background.run_output, "command with parameters");

while(SCR::Read(.background.output_open) || (SCR::Read(.background.newlines) > 0))
{
    list script_out = SCR::Read(.background.newout);

    /* parse lines in script_out and update progress in dialog accordingly */
    
    while (SCR::Read(.background.newlines) == 0 && SCR::Read(.background.output_open))
    {
        sleep(wait_time);

        symbol ret = UI::PollInput();

        /* check if abort button was pressed */
    }
}

You can try example ag_background_example.ycp or YaST2 Backup module which uses background agent too.