authorSergey Poznyakoff <>2017-12-01 06:46:15 (GMT)
committer Sergey Poznyakoff <>2017-12-01 06:47:56 (GMT)
commit048800a78f64808116bb9b943837062a67f586ae (patch) (side-by-side diff)
parent0145de1db25c3840346b9cd9ea44e571812e5516 (diff)
* runcap.3: Update docs. * runcap.c (stream_capture_get,stream_capture_put) (runcap_loop): Handle EINTR. * README: New file.
Diffstat (more/less context) (ignore whitespace changes)
3 files changed, 90 insertions, 13 deletions
diff --git a/README b/README
new file mode 100644
index 0000000..91f5b16
--- a/dev/null
+++ b/README
@@ -0,0 +1,68 @@
+#+TITLE: runcap
+* 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.
+* Building as a standalone library
+The following steps will build the project as a standalone installable
+1. Configure the package
+ #+BEGIN_SRC shell-script
+ ./configure
+2. Build the project.
+ #+BEGIN_SRC shell-script
+ make
+3. Install the files (normally run as root).
+ #+BEGIN_SRC shell-script
+ make install
+ This will install the files ** and *libruncap.a* to the
+ system library directory, and the header file *runcap.h* to the
+ system include directory.
+* Incorporating as a submodule
+To incorporate *runcap* as a submodule to your project, follow these
+1. Change to your project's toplevel directory.
+2. Clone the project.
+ #+BEGIN_SRC shell-script
+ git submodule add git://
+ git submodule init
+3. Add it to *git* index:
+ #+BEGIN_SRC shell-script
+ git add runcap
+4. Add it to your toplevel **.
+ #+BEGIN_SRC make
+ ACLOCAL_AMFLAGS = -I grecs/am
+ SUBDIRS = runcap
+5. Edit your **
+ #+BEGIN_SRC automake
+ #+BEGIN_SRC make
+# Local Variables:
+# mode: org
+# paragraph-separate: "[ ^L]*$"
+# version-control: never
+# End:
diff --git a/runcap.3 b/runcap.3
index 0a5a89c..4a425d6 100644
--- a/runcap.3
+++ b/runcap.3
@@ -10,13 +10,13 @@
.\" but WITHOUT ANY WARRANTY; without even the implied warranty of
.\" GNU General Public License for more details.
.\" You should have received a copy of the GNU General Public License
.\" along with runcap. If not, see <>.
-.TH RUNCAP 2 "August 19, 2017" "RUNCAP" "User Commands"
+.TH RUNCAP 2 "August 22, 2017" "RUNCAP" "User Commands"
runcap \- run external process and capture its stdout and stderr
.B #include <runcap.h>
@@ -75,18 +75,18 @@ struct runcap
int rc_status; /* [\fIOUT\fR] Termination status */
int rc_errno; /* [\fIOUT\fR] System error code */
-The members that may be initialized on input are marked with
+Members that may be initialized on input are marked with
[\fIIN\fR], those that are set upon return from \fBruncap()\fR are
marked with [\fIOUT\fR].
The caller is responsible for initializing the \fBrc_argv\fR member
-with a pointer to the command line arguments array. The other
+with a pointer to the command line arguments array. Other
input fields are:
.B rc_program
Actual pathname of the program to be executed. If initialized, the
\fBRCF_PROGRAM\fR bit must be set in \fIflags\fR. Otherwise, the
value of \fBrc_argv[0]\fR is assumed.
@@ -137,26 +137,27 @@ struct stream_capture
The caller may initialize the following members in
\fBrc_cap[RUNCAP_STDOUT]\fR and \fBrc_cap[RUNCAP_STDERR]\fR:
.B sc_size
Size of the buffer (\fBsize_t\fR). If set, the \fBRCF_STDOUT_SIZE\fR
-\fBRUNCAP_STDERR\fR) bit must be set in \fIflags\fR. 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 \fBsc_size\fR to 0
-disables capturing.
+\fBRUNCAP_STDERR\fR) bit must be set in \fIflags\fR. 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 \fBsc_size\fR to 0 disables capturing.
+Default buffer size is 4096 bytes.
.B sc_linemon
A pointer to the line monitor function. If set, the
\fBRCF_STDERR_LINEMON\fR (for \fBRUNCAP_STDERR\fR) bit must be set in
The line monitor function allows the caller to monitor the arrival of
-the new data in the corresponding stream. Its signature is:
+the new data in the corresponding stream. It is declared as follows:
.BI "void linemon(const char *" line ", size_t " size ", void *" data )
where \fIline\fR is the line that has been read, \fIsize\fR is its
length, and \fIdata\fR is an opaque pointer to application-specific
data, supplied in the \fBsc_monarg\fR member.
@@ -205,13 +206,13 @@ Upon return, the following fields are initialized:
Termination status, as returned by
.BR wait (2).
.B rc_errno
Value of errno, if terminated on error.
-Upon successful return, the following fields are initialized:
+The following fields are defined upon successful return:
.B rc_cap[RUNCAP_STDOUT].sc_leng
Total length of captured stdout.
.B rc_cap[RUNCAP_STDOUT].sc_nlines
Number of lines in the captured stdout.
@@ -224,13 +225,13 @@ Number of lines in the captured stderr.
The actual data can be retrieved using the \fBruncap_getc\fR, and
\fBruncap_getline\fR functions, described below.
.SH Examining output
Upon return from \fBruncap\fR the following functions can be used to
retrieve the captured data from the \fBstruct runcap\fR object pointed
-to by its \fIrc\fR argument. The stream to retrieve the data from is
+to by its \fIrc\fR argument. The stream to retrieve data from is
identified by the \fIstream\fR argument, whose valid values are
\fBRUNCAP_STDOUT\fR (or \fB1\fR) or \fBRUNCAP_STDERR\fR (or \fB2\fR).
The function \fBruncap_getc\fR 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,
diff --git a/runcap.c b/runcap.c
index 26654f8..6790dc4 100644
--- a/runcap.c
+++ b/runcap.c
@@ -134,14 +134,17 @@ stream_capture_get(struct stream_capture *cap, int *feof)
if (cap->sc_level == cap->sc_size) {
if (stream_capture_flush(cap))
return -1;
rc = read(cap->sc_fd, cap->sc_base + cap->sc_level, cap->sc_size - cap->sc_level);
- if (rc == -1)
+ if (rc == -1) {
+ if (errno == EINTR)
+ return 0;
return -1;
+ }
if (rc == 0) {
*feof = 1;
return 0;
} else
*feof = 0;
@@ -167,14 +170,17 @@ stream_capture_get(struct stream_capture *cap, int *feof)
static int
stream_capture_put(struct stream_capture *cap, int *feof)
if (cap->sc_cur < cap->sc_level) {
int n = write(cap->sc_fd, &cap->sc_base[cap->sc_cur], 1);
- if (n == -1)
+ if (n == -1) {
+ if (errno == EINTR)
+ return 0;
return -1;
+ }
if (n == 0) {
errno = ENOSPC;
return -1;
@@ -326,12 +332,14 @@ runcap_loop(struct runcap *rc)
pid_t pid;
if (nfd == 0 && rc->rc_timeout == 0)
flags = 0;
pid = waitpid(rc->rc_pid, &rc->rc_status, flags);
if (pid == -1) {
+ if (errno == EINTR)
+ continue;
rc->rc_errno = errno;
kill(rc->rc_pid, SIGKILL);
if (pid == rc->rc_pid)
rc->rc_pid = (pid_t) -1;

Return to:

Send suggestions and report system problems to the System administrator.