runcap
Table of Contents
1 Overview
The function runcap runs an external command, and waits for its termination, optionally capturing its standard output and standard error streams, and piping data to its standard input.
Upon return from the function, the caller can obtain the termination status of the program and access the captured output data.
2 Usage
The function runcap is defined as follows:
int runcap(struct runcap *rc, int flags);
The rc
argument points to the structure that controls the execution
of the program. It contains the input and output members. The only
member of this structure that must be initialized on input is
rc_argv
, which points to the array of pointers to
null-terminated strings that represent the command name and the
argument list to that program. Initialization of the rest of input
members is optional. For each input member, there is a corresponding
flag in flags
which must be set, if the member is initialized. For
example, if the rc_timeout
member is set (indicating maximum time
the program execution is allowed to take), then the RCF_TIMEOUT
flag
must be set.
Upon return, the function returns the execution status of the
program, and initializes the output members of rc
to hold the
standard output and standard error streams captured from the command.
Special functions are provided to read these streams.
For a detailed description of runcap and accompanying functions, please see the runcap(3) manual. In this chapter we will illustrate the usage of the runcap library by examples.
The example below defines the function runcom with the following prototype:
int runcom(char *cmd, char *in, char **out, char **err);
The function runs the command line given in the cmd
argument
using /bin/sh
and returns the data it printed on its standard output
and error streams in the memory locations pointed to by the arguments
out
and err
, correspondingly. If any of these arguments is
NULL
, capturing of the corresponding stream will be disabled.
The function returns program exit status on success, -1 if the program terminated on signal and -2 on error. This example implements only rudimentary error handling, in order to minimize the amount of irrelevant code.
int runcom(char *cmd, char *in, char **out, char **err) { int status; char *p; char c; char *argv[] = { "/bin/sh", "-c", cmd, NULL }; struct runcap rc; int rcflags = RCF_TIMEOUT; /* Declare the command line to be run. The rc_argv filed is the * only field that must be initialized on input. */ rc.rc_argv = argv; /* Set maximum execution timeout. The presense of this setting is * indicated by the RCF_TIMEOUT flag in rcflags. */ rc.rc_timeout = 10; /* If the input string is supplied, initialize the input stream and * raise the RCF_STDIN flag to indicate that it has been initialized. */ if (in) { rc.rc_cap[RUNCAP_STDIN].sc_base = in; rc.rc_cap[RUNCAP_STDIN].sc_size = strlen(in); rc.rc_cap[RUNCAP_STDIN].sc_fd = -1; rcflags |= RCF_STDIN; } /* If out argument is NULL, disable capturing program's stdout. To * disable capturing a stream, it suffices to initialize its sc_size * field to zero and raise the corresponding RCF_*_SIZE bit in flags. */ if (!out) { rc.rc_cap[RUNCAP_STDOUT].sc_size = 0; rcflags |= RCF_STDOUT_SIZE; } /* Same for the stderr: */ if (!err) { rc.rc_cap[RUNCAP_STDERR].sc_size = 0; rcflags |= RCF_STDERR_SIZE; } /* Run the command. The runcap function returns 0 on success. On * error, it returns -1 and sets the errno variable. Its value is * also duplicated in the rc_errno member of struct runcap. */ if (runcap(&rc, rcflags)) { perror("runcap"); return -2; } /* Upon return, the sc_leng member of the capturing structure for * stdout and stderr contains total amount of bytes in the corresponding * stream. The stream can be read using the runcap_getc and * runcap_getline functions. */ if (rc.rc_cap[RUNCAP_STDOUT].sc_leng) { p = malloc(rc.rc_cap[RUNCAP_STDOUT].sc_leng + 1); assert(p != NULL); *out = p; while (runcap_getc(&rc, RUNCAP_STDOUT, &c)) *p++ = c; *p = 0; } else *out = NULL; if (rc.rc_cap[RUNCAP_STDERR].sc_leng) { p = malloc(rc.rc_cap[RUNCAP_STDERR].sc_leng + 1); assert(p != NULL); *err = p; while (runcap_getc(&rc, RUNCAP_STDERR, &c)) *p++ = c; *p = 0; } else *err = NULL; /* Analyze the exit status of the command */ if (WIFEXITED(rc.rc_status)) { status = WEXITSTATUS(rc.rc_status); } else { status = -1; if (WIFSIGNALED(rc.rc_status)) { fprintf(stderr, "%s terminated on signal %d\n", argv[0], WTERMSIG(rc.rc_status)); } else { fprintf(stderr, "%s terminated with unrecognized status: %d\n", argv[0], rc.rc_status); } } return status; }
3 Downloading
To clone the project from the repository, run
git clone git://git.gnu.org.ua/runcap.git
4 Building
The project can be used either a standalone library, or as a shared
or static convenience library embedded in another project. If you
cloned the project from the git repository, you will need to
bootstrap it first. To do so, change to the runcap
directory and
run
autoreconf -I. -f -i -s
Use the RUNCAP_BUILD
environment variable to indicate the type of
the build you need. Allowed values are:
- install
- Build standalone installable library (default).
- shared
- Build shared convenience library.
- static
- Build static convenience library.
Once bootstrapped, the project can be built with the usual sequence of commands:
- Configure the package
./configure
- Build it
make
- If building installable library, install it (normally run as root).
make install
This will install the files libruncap.so and libruncap.a to the system library directory, and the header file runcap.h to the system include directory.
5 Incorporating as a submodule
To incorporate runcap to your project as a submodule, follow these steps:
- Change to your project's toplevel directory.
- Clone the project.
git submodule add git://git.gnu.org.ua/runcap.git git submodule init
- Add it to git index:
git add runcap
- Add it to your toplevel Makefile.am.
ACLOCAL_AMFLAGS = -I runcap SUBDIRS = runcap
- Edit your configure.ac. Add the following line:
RUNCAP_SETUP
- Add the following to the Makefile.am file which builds the target
that uses on the runcap library:
AM_CPPFLAGS = @RUNCAP_INC@ LDADD = @RUNCAP_LDADD@
6 RUNCAP_SETUP autoconf macro
The RUNCAP_SETUP macro initializes the runcap library. It should be used in the configure.ac file or in one of the files included to it. The macro invocation syntax is:
RUNCAP_SETUP(DIR, TYPE)
Both arguments are optional:
- DIR
- Name of the subdirectory where the runcap sources
reside. If omitted,
runcap
is assumed. When building runcap as a standalone library, it is set to . (a dot). - TYPE
- Build type:
install
,shared
, orstatic
. Defaults tostatic
.
This macro defines the following make variables:
- RUNTIME_INC
- cpp options to access the
runcap.h
include file. Use it in the convenient_CPPFLAGS
make variable. - RUNCAP_LDADD
- Lists the pathname of the runcap
library. Use it in the
LDADD
orprog_LDADD
make variable. - RUNCAP_BUILD_TYPE
- Type of the build.
7 Copyright
Copyright (C) 2017-2019 Sergey Poznyakoff
Permission is granted to anyone to make or distribute verbatim copies of this document as received, in any medium, provided that the copyright notice and this permission notice are preserved, thus giving the recipient permission to redistribute in turn.
Permission is granted to distribute modified versions of this document, or of portions of it, under the above conditions, provided also that they carry prominent notices stating who last changed them.