+2017-11-14 Colin Watson <cjwatson@debian.org>
+
+ Version: 1.5.0.
+
+ * lib/Makefile.am (libpipeline_la_LDFLAGS): Bump -version-info to 6:0:5.
+
+2017-11-14 Colin Watson <cjwatson@debian.org>
+
+ Add pipecmd_pre_exec function
+
+ * lib/pipeline-private.h (struct pipecmd): Add pre_exec_func,
+ pre_exec_free_func, and pre_exec_data.
+ * lib/pipeline.c (pipecmd_new, pipecmd_new_function,
+ pipecmd_new_sequencev): Initialise cmd->pre_exec_func,
+ cmd->pre_exec_free_func, and cmd->pre_exec_data.
+ (pipecmd_dup): Copy cmd->pre_exec_func, cmd->pre_exec_free_func, and
+ cmd->pre_exec_data if necessary.
+ (pipecmd_pre_exec): New function.
+ (pipecmd_exec): If cmd->pre_exec_func is set, call it immediately before
+ calling execvp or cmd->func.
+ * lib/pipeline.h (pipecmd_pre_exec): Add prototype.
+ (pipeline_install_post_fork): Cross-reference pipecmd_pre_exec in
+ comment.
+ * man/Makefile.am (FUNCTIONS): Add pipecmd_pre_exec.
+ * man/libpipeline.3 (Functions to build individual commands): Document
+ pipecmd_pre_exec.
+ (Functions to run pipelines and handle signals): Cross-reference
+ pipecmd_pre_exec from pipeline_install_post_fork.
+ * tests/basic.c (test_basic_pre_exec): Test pipecmd_pre_exec.
+ * NEWS: Document this.
+ * README: Update copyright years.
+
+2017-07-10 Colin Watson <cjwatson@debian.org>
+
+ tests/read.c: Update program_name
+
2017-07-10 Colin Watson <cjwatson@debian.org>
Version: 1.4.2.
+libpipeline 1.5.0 (14 November 2017)
+====================================
+
+Add `pipecmd_pre_exec' to install a pre-exec handler for a single command.
+
libpipeline 1.4.2 (10 July 2017)
================================
Copyright (C) 1989, 1990, 1991, 1992, 2000, 2001, 2002, 2003, 2004, 2005,
2006, 2007, 2008, 2009, 2010
Free Software Foundation, Inc.
-Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 Colin Watson.
+Copyright (C) 2003-2017 Colin Watson.
libpipeline is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
#! /bin/sh
# Guess values for system-dependent variables and create Makefiles.
-# Generated by GNU Autoconf 2.69 for libpipeline 1.4.2.
+# Generated by GNU Autoconf 2.69 for libpipeline 1.5.0.
#
# Report bugs to <cjwatson@debian.org>.
#
# Identity of this package.
PACKAGE_NAME='libpipeline'
PACKAGE_TARNAME='libpipeline'
-PACKAGE_VERSION='1.4.2'
-PACKAGE_STRING='libpipeline 1.4.2'
+PACKAGE_VERSION='1.5.0'
+PACKAGE_STRING='libpipeline 1.5.0'
PACKAGE_BUGREPORT='cjwatson@debian.org'
PACKAGE_URL=''
# Omit some internal or obsolete options to make the list less imposing.
# This message is too long to be a string in the A/UX 3.1 sh.
cat <<_ACEOF
-\`configure' configures libpipeline 1.4.2 to adapt to many kinds of systems.
+\`configure' configures libpipeline 1.5.0 to adapt to many kinds of systems.
Usage: $0 [OPTION]... [VAR=VALUE]...
if test -n "$ac_init_help"; then
case $ac_init_help in
- short | recursive ) echo "Configuration of libpipeline 1.4.2:";;
+ short | recursive ) echo "Configuration of libpipeline 1.5.0:";;
esac
cat <<\_ACEOF
test -n "$ac_init_help" && exit $ac_status
if $ac_init_version; then
cat <<\_ACEOF
-libpipeline configure 1.4.2
+libpipeline configure 1.5.0
generated by GNU Autoconf 2.69
Copyright (C) 2012 Free Software Foundation, Inc.
This file contains any messages produced by compilers while
running configure, to aid debugging if configure makes a mistake.
-It was created by libpipeline $as_me 1.4.2, which was
+It was created by libpipeline $as_me 1.5.0, which was
generated by GNU Autoconf 2.69. Invocation command line was
$ $0 $@
# Define the identity of the package.
PACKAGE='libpipeline'
- VERSION='1.4.2'
+ VERSION='1.5.0'
cat >>confdefs.h <<_ACEOF
# report actual input values of CONFIG_FILES etc. instead of their
# values after options handling.
ac_log="
-This file was extended by libpipeline $as_me 1.4.2, which was
+This file was extended by libpipeline $as_me 1.5.0, which was
generated by GNU Autoconf 2.69. Invocation command line was
CONFIG_FILES = $CONFIG_FILES
cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
ac_cs_version="\\
-libpipeline config.status 1.4.2
+libpipeline config.status 1.5.0
configured by $0, generated by GNU Autoconf 2.69,
with options \\"\$ac_cs_config\\"
dnl Process this file with autoconf to produce a configure script.
-# Copyright (C) 2010, 2011, 2012, 2013 Colin Watson.
+# Copyright (C) 2010-2017 Colin Watson.
#
# This file is part of libpipeline.
#
m4_pattern_forbid([^PIPELINE_])
# Initialise and check we're in the correct directory.
-AC_INIT([libpipeline], [1.4.2], [cjwatson@debian.org])
+AC_INIT([libpipeline], [1.5.0], [cjwatson@debian.org])
AC_CONFIG_AUX_DIR([build-aux])
AM_INIT_AUTOMAKE([1.10 -Wall -Werror foreign])
AM_MAINTAINER_MODE
## Process this file with automake to produce Makefile.in
-## Copyright (C) 2010 Colin Watson.
+## Copyright (C) 2010-2017 Colin Watson.
##
## This file is part of libpipeline.
##
libpipeline_la_LDFLAGS = \
-export-symbols-regex '^(pipecmd|pipeline)_' \
-no-undefined \
- -version-info 5:2:4
+ -version-info 6:0:5
pkgconfigdir = $(libdir)/pkgconfig
pkgconfig_DATA = libpipeline.pc
libpipeline_la_LDFLAGS = \
-export-symbols-regex '^(pipecmd|pipeline)_' \
-no-undefined \
- -version-info 5:2:4
+ -version-info 6:0:5
pkgconfigdir = $(libdir)/pkgconfig
pkgconfig_DATA = libpipeline.pc
/*
- * Copyright (C) 2001, 2002, 2005, 2007, 2009, 2010 Colin Watson.
+ * Copyright (C) 2001-2017 Colin Watson.
*
* This file is part of libpipeline.
*
int nenv;
int env_max; /* size of allocated array */
struct pipecmd_env *env;
+ pipecmd_function_type *pre_exec_func;
+ pipecmd_function_type *pre_exec_free_func;
+ void *pre_exec_data;
union {
struct pipecmd_process {
int argc;
/* Copyright (C) 1989, 1990, 1991, 1992, 2000, 2001, 2002, 2003
* Free Software Foundation, Inc.
- * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008 Colin Watson.
+ * Copyright (C) 2003-2017 Colin Watson.
* Written for groff by James Clark (jjc@jclark.com)
* Heavily adapted and extended for man-db by Colin Watson.
*
cmd->env_max = 4;
cmd->env = xnmalloc (cmd->env_max, sizeof *cmd->env);
+ cmd->pre_exec_func = NULL;
+ cmd->pre_exec_free_func = NULL;
+ cmd->pre_exec_data = NULL;
+
cmdp = &cmd->u.process;
cmdp->argc = 0;
cmd->env_max = 4;
cmd->env = xnmalloc (cmd->env_max, sizeof *cmd->env);
+ cmd->pre_exec_func = NULL;
+ cmd->pre_exec_free_func = NULL;
+ cmd->pre_exec_data = NULL;
+
cmdf = &cmd->u.function;
cmdf->func = func;
cmd->env_max = 4;
cmd->env = xnmalloc (cmd->env_max, sizeof *cmd->env);
+ cmd->pre_exec_func = NULL;
+ cmd->pre_exec_free_func = NULL;
+ cmd->pre_exec_data = NULL;
+
cmds = &cmd->u.sequence;
cmds->ncommands = 0;
assert (newcmd->nenv <= newcmd->env_max);
newcmd->env = xmalloc (newcmd->env_max * sizeof *newcmd->env);
+ newcmd->pre_exec_func = cmd->pre_exec_func;
+ newcmd->pre_exec_free_func = cmd->pre_exec_free_func;
+ newcmd->pre_exec_data = cmd->pre_exec_data;
+
for (i = 0; i < cmd->nenv; ++i) {
newcmd->env[i].name =
cmd->env[i].name ? xstrdup (cmd->env[i].name) : NULL;
++cmd->nenv;
}
+void pipecmd_pre_exec (pipecmd *cmd,
+ pipecmd_function_type *func,
+ pipecmd_function_free_type *free_func,
+ void *data)
+{
+ cmd->pre_exec_func = func;
+ cmd->pre_exec_free_func = free_func;
+ cmd->pre_exec_data = data;
+}
+
void pipecmd_sequence_command (pipecmd *cmd, pipecmd *child)
{
struct pipecmd_sequence *cmds;
switch (cmd->tag) {
case PIPECMD_PROCESS: {
struct pipecmd_process *cmdp = &cmd->u.process;
+ if (cmd->pre_exec_func)
+ cmd->pre_exec_func (cmd->pre_exec_data);
execvp (cmd->name, cmdp->argv);
break;
}
*/
case PIPECMD_FUNCTION: {
struct pipecmd_function *cmdf = &cmd->u.function;
- (*cmdf->func) (cmdf->data);
+ if (cmd->pre_exec_func)
+ cmd->pre_exec_func (cmd->pre_exec_data);
+ cmdf->func (cmdf->data);
/* pacify valgrind et al */
if (cmdf->free_func)
- (*cmdf->free_func) (cmdf->data);
+ cmdf->free_func (cmdf->data);
+ if (cmd->pre_exec_free_func)
+ cmd->pre_exec_free_func (cmd->pre_exec_data);
exit (0);
}
/* Copyright (C) 1989, 1990, 1991, 1992, 2000, 2002
* Free Software Foundation, Inc.
- * Copyright (C) 2003, 2004, 2005, 2007, 2008 Colin Watson.
+ * Copyright (C) 2003-2017 Colin Watson.
* Written for groff by James Clark (jjc@jclark.com)
* Adapted for man-db by Colin Watson.
*
*/
void pipecmd_clearenv (pipecmd *cmd);
+/* Install a pre-exec handler. This will be run immediately before
+ * executing the command's payload (process or function). Pass NULL to
+ * clear any existing pre-exec handler. The data argument is passed as the
+ * function's only argument, and will be freed before returning using
+ * free_func (if non-NULL).
+ *
+ * This is similar to pipeline_install_post_fork, except that is specific to
+ * a single command rather than installing a global handler, and it runs
+ * slightly later (immediately before exec rather than immediately after
+ * fork).
+ */
+void pipecmd_pre_exec (pipecmd *cmd,
+ pipecmd_function_type *func,
+ pipecmd_function_free_type *free_func,
+ void *data);
+
/* Add a command to a sequence. */
void pipecmd_sequence_command (pipecmd *cmd, pipecmd *child);
* immediately after it is forked. For instance, this may be used for
* cleaning up application-specific signal handlers. Pass NULL to clear any
* existing post-fork handler.
+ *
+ * See pipecmd_pre_exec for a similar facility limited to a single command
+ * rather than global to the calling process.
*/
void pipeline_install_post_fork (pipeline_post_fork_fn *fn);
## Process this file with automake to produce Makefile.in
-## Copyright (C) 2010 Colin Watson.
+## Copyright (C) 2010-2017 Colin Watson.
##
## This file is part of libpipeline.
##
pipecmd_setenv \
pipecmd_unsetenv \
pipecmd_clearenv \
+ pipecmd_pre_exec \
pipecmd_sequence_command \
pipecmd_dump \
pipecmd_tostring \
pipecmd_setenv \
pipecmd_unsetenv \
pipecmd_clearenv \
+ pipecmd_pre_exec \
pipecmd_sequence_command \
pipecmd_dump \
pipecmd_tostring \
-.\" Copyright (C) 2010 Colin Watson.
+.\" Copyright (C) 2010-2017 Colin Watson.
.\"
.\" This file is part of libpipeline.
.\"
contents of the environment are necessary to execute programs at all (say,
.Li PATH ) .
.Pp
+.It Xo Ft void
+.Fo pipecmd_pre_exec
+.Fa "pipecmd *cmd"
+.Fa "pipecmd_function_type *func"
+.Fa "pipecmd_function_free_type *free_func"
+.Fa "void *data"
+.Fc
+.Xc
+.Pp
+Install a pre-exec handler.
+This will be run immediately before executing the command's payload (process
+or function).
+Pass NULL to clear any existing pre-exec handler.
+The data argument is passed as the function's only argument, and will be
+freed before returning using free_func (if non-NULL).
+.Pp
+This is similar to pipeline_install_post_fork, except that is specific to a
+single command rather than installing a global handler, and it runs slightly
+later (immediately before exec rather than immediately after fork).
+.Pp
.It Ft void Fn pipecmd_sequence_command "pipecmd *cmd" "pipecmd *child"
.Pp
Add a command to a sequence created using
.Li NULL
to clear any existing post-fork handler.
.Pp
+See pipecmd_pre_exec for a similar facility limited to a single command
+rather than global to the calling process.
+.Pp
.It Ft void Fn pipeline_start "pipeline *p"
.Pp
Start the processes in a pipeline.
/*
- * Copyright (C) 2010 Colin Watson.
+ * Copyright (C) 2010-2017 Colin Watson.
*
* This file is part of libpipeline.
*
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
+#include <stdlib.h>
#include <string.h>
#include <unistd.h>
}
END_TEST
+/* This is of course better done using pipecmd_setenv, but setting an
+ * environment variable makes for an easy test.
+ */
+static void pre_exec (void *data PIPELINE_ATTR_UNUSED)
+{
+ setenv ("TEST1", "10", 1);
+}
+
+START_TEST (test_basic_pre_exec)
+{
+ pipeline *p;
+
+ p = pipeline_new_command_args (SHELL, "-c", "exit $TEST1", NULL);
+ pipecmd_pre_exec (pipeline_get_command (p, 0), pre_exec, NULL, NULL);
+ fail_unless (pipeline_run (p) == 10, "TEST1 not set properly");
+}
+END_TEST
+
START_TEST (test_basic_sequence)
{
pipeline *p;
TEST_CASE (s, basic, setenv);
TEST_CASE (s, basic, unsetenv);
TEST_CASE (s, basic, clearenv);
+ TEST_CASE (s, basic, pre_exec);
TEST_CASE_WITH_FIXTURE (s, basic, chdir,
temp_dir_setup, temp_dir_teardown);
TEST_CASE_WITH_FIXTURE (s, basic, fchdir,
#include "common.h"
-const char *program_name = "reading_long_line";
+const char *program_name = "read";
/* Must be 8194 or bigger */
#define RANDOM_STR_LEN 9000