Commit be7edd06 authored by Colin Watson's avatar Colin Watson
Browse files

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.
parent 34fd4ab4
libpipeline 1.5.0
=================
Add `pipecmd_pre_exec' to install a pre-exec handler for a single command.
libpipeline 1.4.2 (10 July 2017)
================================
......
......@@ -59,7 +59,7 @@ Copyright (C) 1994 Markus Armbruster.
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
......
/*
* Copyright (C) 2001, 2002, 2005, 2007, 2009, 2010 Colin Watson.
* Copyright (C) 2001-2017 Colin Watson.
*
* This file is part of libpipeline.
*
......@@ -61,6 +61,9 @@ struct pipecmd {
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.
*
......@@ -110,6 +110,10 @@ pipecmd *pipecmd_new (const char *name)
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;
......@@ -306,6 +310,10 @@ pipecmd *pipecmd_new_function (const char *name,
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;
......@@ -332,6 +340,10 @@ pipecmd *pipecmd_new_sequencev (const char *name, va_list cmdv)
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;
......@@ -396,6 +408,10 @@ pipecmd *pipecmd_dup (pipecmd *cmd)
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;
......@@ -589,6 +605,16 @@ void pipecmd_clearenv (pipecmd *cmd)
++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;
......@@ -772,6 +798,8 @@ void pipecmd_exec (pipecmd *cmd)
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;
}
......@@ -782,10 +810,14 @@ void pipecmd_exec (pipecmd *cmd)
*/
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.
*
......@@ -196,6 +196,22 @@ void pipecmd_unsetenv (pipecmd *cmd, const char *name);
*/
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);
......@@ -358,6 +374,9 @@ typedef void pipeline_post_fork_fn (void);
* 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.
##
......@@ -44,6 +44,7 @@ FUNCTIONS = \
pipecmd_setenv \
pipecmd_unsetenv \
pipecmd_clearenv \
pipecmd_pre_exec \
pipecmd_sequence_command \
pipecmd_dump \
pipecmd_tostring \
......
......@@ -1047,6 +1047,7 @@ FUNCTIONS = \
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.
.\"
......@@ -243,6 +243,26 @@ Beware that this may cause unexpected failures, for example if some of the
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
......@@ -514,6 +534,9 @@ Pass
.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.
*
......@@ -26,6 +26,7 @@
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
......@@ -296,6 +297,24 @@ START_TEST (test_basic_fchdir)
}
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;
......@@ -330,6 +349,7 @@ Suite *basic_suite (void)
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,
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment