RUNCAP

NAME
SYNOPSIS
DESCRIPTION
Examining output
RETURN VALUE
EXAMPLE
AUTHORS
COPYRIGHT

NAME

runcap - run external process and capture its stdout and stderr

SYNOPSIS

#include <runcap.h>

int runcap(struct runcap *rc, int flags);
void runcap_free(struct runcap *
rc);

int runcap_getc(struct runcap *rc, int stream, char *cp);
ssize_t runcap_getline(struct runcap *
rc, int stream,
char **
pstr, size_t *psize);

off_t runcap_tell(struct runcap *rc, int stream);
int runcap_seek(struct runcap *
rc, int stream, off_t off, int whence);
int runcap_rewind(struct runcap *
rc, int stream);

DESCRIPTION

The function runcap runs an external command, and waits for its termination, capturing its standard output and standard error streams, and optionally supplying data at its standard input.

The rc argument points to struct runcap, which serves two purposes. On input, it supplies the necessary data for running the command. The caller is responsible for pointing the rc_argv member to the vector of command line arguments. This member must always be initialized. If any of the remaining members are initialized, the caller must inform the runcap function about it by setting appropriate bit in the flags argument.

The function returns 0 on success, and -1 on error.

Upon return from runcap, the remaining members of the structure will be filled with the information about the termination status of the program and the captured content of its standard output and standard error streams.

Whatever the return status, when no longer used the structure must be freed using runcap_free.

The struct runcap argument
The struct runcap is defined as follows:

struct runcap
{
char *rc_program; /* [IN] (Path)name of the program to run */
char **rc_argv; /* [IN] Argument vector */
unsigned rc_timeout; /* [IN] Execution timeout */
struct stream_capture rc_cap[3];
pid_t rc_pid; /* [OUT] PID of the process */
int rc_status; /* [OUT] Termination status */
int rc_errno; /* [OUT] System error code */
};

The members that may be initialized on input are marked with [IN], those that are set upon return from runcap() are marked with [OUT].

The caller is responsible for initializing the rc_argv member with a pointer to the command line arguments array. The other input fields are:
rc_program

Actual pathname of the program to be executed. If initialized, the RCF_PROGRAM bit must be set in flags. Otherwise, the value of rc_argv[0] is assumed.

rc_timeout

Time to wait for the program termination, in seconds. If initialized, the RCF_TIMEOUT bit must be set in flags. If not set, runcap will wait indefinitely.

The three streams associated with the running command are described by the rc_cap array. Its elements correspond to the standard input, output and error streams. Upon successful return, the captured data from stdin and stdout can be retrieved using the runcap_getc, and runcap_getline functions (see below). For convenience, the following constants are defined in runcap.h to refer to the corresponding streams: RUNCAP_STDIN, RUNCAP_STDOUT, RUNCAP_STDERR.

The following fields are warranted to be present in struct stream_capture:

struct stream_capture
{
size_t sc_size; /* [IN] size of the buffer */
void (*sc_linemon)(const char *, size_t, void *);
/* [IN] Line monitor function */
void *sc_monarg; /* [IN] Value for its 3rd parameter */

off_t sc_leng; /* [OUT] total length of captured data */
size_t sc_nlines; /* [OUT] number of captured lines */

/* The following two are available only in rc_cap[RUNCAP_STDIN],
see the subsection Supplying standard input below, for
details). */
size_t sc_fd; /* Input file descriptor */
char *sc_base; /* Input data */
};

The caller may initialize the following members in rc_cap[RUNCAP_STDOUT] and rc_cap[RUNCAP_STDERR]:
sc_size

Size of the buffer (size_t). If set, the RCF_STDOUT_SIZE (for RUNCAP_STDOUT) or RCF_STDERR_SIZE (for RUNCAP_STDERR) bit must be set in flags. The default buffer size is 4096 bytes. If the amount of input data exceeds the buffer size, the data are saved in the disk file, therefore setting a larger buffer can improve performance. Setting sc_size to 0 disables capturing.

sc_linemon

A pointer to the line monitor function. If set, the RCF_STDOUT_LINEMON (for RUNCAP_STDOUT), or RCF_STDERR_LINEMON (for RUNCAP_STDERR) bit must be set in flags.

The line monitor function allows the caller to monitor the arrival of the new data in the corresponding stream. Its signature is:

void linemon(const char *line, size_t size, void *data)

where line is the line that has been read, size is its length, and data is an opaque pointer to application-specific data, supplied in the sc_monarg member.

The line monitor function is invoked each time a newline character is encountered in the stream, or when the stream buffer becomes full (and, therefore is about to be flushed into the storage file) and some characters remain unreported. This means that, if the sc_linemon function is designed to log each input line, it should keep the state of processing (e.g. in the data argument), and concatenate the line parameters until line[size-1] == ’\n’.

sc_monarg

The value of the data parameter for the sc_linemon function. It can be initialized only if sc_linemon is initialized as well.

Supplying standard input
The rc_cap[RUNCAP_STDIN] field can be used to supply standard input for the command. The input can be supplied either as a character string, or as a file descriptor. To use the first method, initialize rc_cap[RUNCAP_STDIN].sc_base with the pointer to the string, rc_size with its length, and set sc_fd to -1.

To use the second method, set rc_cap[RUNCAP_STDIN].sc_fd to the file descriptor opened for reading, and set rc_cap[RUNCAP_STDIN].sc_base to NULL.

Whichever approach is used, set the RCF_STDIN bit in flags to inform runcap() about the fact.

Output
Upon return, the following fields are initialized:
rc_status

Termination status, as returned by wait(2).

rc_errno

Value of errno, if terminated on error.

Upon successful return, the following fields are initialized:
rc_cap[RUNCAP_STDOUT].sc_leng

Total length of captured stdout.

rc_cap[RUNCAP_STDOUT].sc_nlines

Number of lines in the captured stdout.

rc_cap[RUNCAP_STDERR].sc_leng

Total length of captured stderr.

rc_cap[RUNCAP_STDERR].sc_nlines

Number of lines in the captured stderr.

The actual data can be retrieved using the runcap_getc, and runcap_getline functions, described below.

Examining output

Upon return from runcap the following functions can be used to retrieve the captured data from the struct runcap object pointed to by its rc argument. The stream to retrieve the data from is identified by the stream argument, whose valid values are RUNCAP_STDOUT (or 1) or RUNCAP_STDERR (or 2).

The function runcap_getc reads the next character from the captured stream and returns it as an unsigned char cast to an int. It returns 0 on end of stream, and -1 on error. In the latter case, the errno variable contains the error code, as usual.

The function runcap_getline reads all characters from the current position in the stream up to and including the next newline character (ASCII 10). It will allocate the buffer for the characters as necessary and will store the address of the buffer into *pstr, and its allocated size in *psize. The buffer is null-terminated and includes the newline character, if one was found.

If *pstr is NULL, the function will allocate a buffer of sufficient size for storing the line.

Otherwise, *pstr should contain a pointer to a buffer *psize bytes in size, allocated using malloc(3). If the buffer is not large enough to hold the characters, runcap_getline will resize it using realloc(3), updating *pstr and *psize as necessary.

On success, runcap_getline returns the number of characters (including the newline) stored in the buffer, or 0 if end of stream is reached. On error, it returns -1 and sets errno.

The function runcap_tell returns offset in bytes to the current position in the requested stream.

The function runcap_seek repositions the offset of the requested stream to the argument offset according to the directive whence as follows:
SEEK_SET

The offset is set to offset bytes.

SEEK_CUR

The offset is set to its current location plus offset bytes.

SEEK_END

The offset is set to the size of the stream (sc_leng) plus offset bytes.

The function returns 0 on success. On error, it returns -1 and sets errno.

The function runcap_rewind repositions the current offset of stream to 0.

The following pairs of calls are equivalent:

runcap_tell(rc, stream) <=> runcap_seek(rc, stream, 0, SEEK_CUR)

and

runcap_rewind(rc, stream) <=> runcap_seek(rc, stream, 0, SEEK_SET)

RETURN VALUE

Upon successful completion, runcap() returns 0. The rc.rc_status value should be inspected to see if the program terminated successfully. On error, it sets the rc.rc_errno and returns -1.

The runcap_getc() returns the retrieved character on success, 0 if end of stream is hit, and -1 on error.

The function runcap_getline() returns the number of retrieved characters (including the newline) on success, 0 on end of stream, and -1 on error.

runcap_tell() returns the current offset (a non-negative value) on success, and -1 on error.

runcap_seek() and runcap_rewind() return 0 on success and -1 on error.

When returning an error (-1), all functions set the global errno variable to the code describing the error.

EXAMPLE

char **
archive(void)
{
struct runcap rc;
int res;
char *av[] = { "tar", "cfv", "src.tar", "src", NULL };
char **ret = NULL;

rc.rc_program = "/bin/tar";
rc.rc_argv = av;
res = runcap(&rc, RCF_PROGRAM);
if (res == -1) {
perror("runcap");
abort();
}

if (WIFEXITED(rc.rc_status) && WEXITSTATUS(rc.rc_status) == 0) {
char **ret;
size_t nlines = rc.rc_cap[RUNCAP_STDOUT].sc_nlines;
ret = malloc(nlines + 1);
for (i = 0; i < nlines; i++) {
char *p = NULL;
size_t sz = 0;
ssize_t n;

n = runcap_getline(rc, stream, p, &sz);
if (n == -1) {
perror("runcap_getline");
abort();
}
ret[i] = realloc(p, n + 1);
}
ret[i] = NULL;
}
runcap_free(&rc);
return ret;
}

AUTHORS

Sergey Poznyakoff

COPYRIGHT

Copyright © 2017 Sergey Poznyakoff
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it. There is NO WARRANTY, to the extent permitted by law.


Manpage server at man.gnu.org.ua.

Powered by mansrv 1.1