aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSergey Poznyakoff <gray@gnu.org>2019-05-31 08:45:23 +0300
committerSergey Poznyakoff <gray@gnu.org>2019-05-31 08:58:54 +0300
commit058f256a6f41fc9c36404b2e22580546e4f55b33 (patch)
treeb6afde4271da1d92e5c10e1c50213c2fda7b2831
parentca38eef07ac3f9a4825f0046c1d373ed7b2f074b (diff)
downloadpies-058f256a6f41fc9c36404b2e22580546e4f55b33.tar.gz
pies-058f256a6f41fc9c36404b2e22580546e4f55b33.tar.bz2
Provide an option to run commands via sh -c
The new flag "shell" instructs pies to run the command marked with it as '/bin/sh -c $command'. Alternative shell can be supplied ising the 'program' statement. This is useful if the command line uses shell-specific features (command or variable expansion, redirection, pipes, etc.) This commit also fixes a bug in the 'env' statement handling: a single argument with embedded whitespaces was undergoing word splitting and thus incorrectly handled as multiple arguments. * NEWS: Document changes. * doc/pies.texi: Likewise. * src/comp.c (component_free): Free command. (component_finish): Split command into argv/argc as directed by the CF_SHELL flag. * src/pies.c (_cb_command): Remove. Functionality moved to component_finish(). (_cb_env): Bugfix. Don't split arguments. * src/pies.h (CF_SHELL): New flag. (component) <command>: New member. * tests/Makefile.am: Add new tests. * tests/testsuite.at: Add new tests. * tests/aux/respawn: Change default timeout to 1 second. * tests/respawn.at: Minor change. * tests/shell.at: New test.
-rw-r--r--NEWS22
-rw-r--r--doc/pies.texi21
-rw-r--r--src/comp.c24
-rw-r--r--src/pies.c48
-rw-r--r--src/pies.h5
-rw-r--r--tests/Makefile.am1
-rwxr-xr-xtests/aux/respawn2
-rw-r--r--tests/respawn.at2
-rw-r--r--tests/shell.at58
-rw-r--r--tests/testsuite.at1
10 files changed, 137 insertions, 47 deletions
diff --git a/NEWS b/NEWS
index 0840055..f34a6f0 100644
--- a/NEWS
+++ b/NEWS
@@ -1,4 +1,4 @@
1GNU Pies NEWS -- history of user-visible changes. 2019-05-28 1GNU Pies NEWS -- history of user-visible changes. 2019-05-31
2See the end of file for copying conditions. 2See the end of file for copying conditions.
3 3
4Please send Pies bug reports to <bug-pies@gnu.org> or 4Please send Pies bug reports to <bug-pies@gnu.org> or
@@ -25,8 +25,28 @@ configuration file. Such multiple components are run simultaneously,
25unless required otherwise by their "prerequisites" and "dependents" 25unless required otherwise by their "prerequisites" and "dependents"
26statements. 26statements.
27 27
28* New component flag: shell
29
30The 'shell' flag instructs pies to run the component via "/bin/sh -c
31$command". Use it if the command should undergo variable expansion,
32contains redirections, pipes, etc. E.g.
33
34 component X {
35 flags shell;
36 command "if [ -n "$X" ]; then foo; else bar; fi"
37 }
38
28* Improved cyclic dependency diagnostics 39* Improved cyclic dependency diagnostics
29 40
41* Fix a bug in 'env' statement
42
43Previous versions applied unnecessary word splitting if given a
44single argument. This is now fixed, so that e.g. the following
45statement is processed correctly and defines a single variable
46X to have the value "foo bar":
47
48 env "X=foo bar"
49
30 50
31Version 1.3, 2016-10-01 51Version 1.3, 2016-10-01
32 52
diff --git a/doc/pies.texi b/doc/pies.texi
index 012ac88..1a798e1 100644
--- a/doc/pies.texi
+++ b/doc/pies.texi
@@ -176,7 +176,11 @@ foreground.
176 176
177 Upon startup, @command{pies} reads the list of components 177 Upon startup, @command{pies} reads the list of components
178from its configuration file, starts them, and remains in the 178from its configuration file, starts them, and remains in the
179background, controlling their execution. 179background, controlling their execution. Each component is
180defined by the name of the external program to be run and its
181arguments (command line). The program is normally run directly
182(via @code{exec}), but you can instruct @command{pies} to run
183it via @code{sh -c} as well.
180 184
181 The standard output and standard error streams of a component can be 185 The standard output and standard error streams of a component can be
182redirected to a file or to an arbitrary @command{syslog} channel. 186redirected to a file or to an arbitrary @command{syslog} channel.
@@ -870,6 +874,21 @@ their standard input to be open (e.g.@: @command{pppd nodetach}).
870Mark this component as @dfn{precious}. Precious components are never 874Mark this component as @dfn{precious}. Precious components are never
871disabled by @command{pies}, even if they respawn too fast. 875disabled by @command{pies}, even if they respawn too fast.
872 876
877@kwindex shell
878@item shell
879Run command as @code{/bin/sh -c "$command"}. Use this flag if command
880contains shell-specific features, such as I/O redirections, pipes,
881variables or the like. You can change the shell program using the
882@code{program} statement. For example, to use Korn shell:
883
884@example
885component X @{
886 flags shell;
887 program "/bin/ksh";
888 command "myprog $HOME";
889@}
890@end example
891
873@kwindex wait 892@kwindex wait
874@item wait 893@item wait
875This flag is valid only for @samp{inetd} components. It has the same 894This flag is valid only for @samp{inetd} components. It has the same
diff --git a/src/comp.c b/src/comp.c
index 25f2657..499dfe5 100644
--- a/src/comp.c
+++ b/src/comp.c
@@ -171,6 +171,7 @@ component_free (struct component *comp)
171 component_unlink (comp); 171 component_unlink (comp);
172 free (comp->tag); 172 free (comp->tag);
173 free (comp->program); 173 free (comp->program);
174 free (comp->command);
174 if (comp->argv) 175 if (comp->argv)
175 { 176 {
176 for (i = 0; i < comp->argc; i++) 177 for (i = 0; i < comp->argc; i++)
@@ -747,6 +748,29 @@ component_verify (struct component *comp, grecs_locus_t *locus)
747void 748void
748component_finish (struct component *comp, grecs_locus_t *locus) 749component_finish (struct component *comp, grecs_locus_t *locus)
749{ 750{
751 if (comp->flags & CF_SHELL)
752 {
753 comp->argc = 3;
754 comp->argv = grecs_calloc (comp->argc + 1, sizeof (comp->argv[0]));
755 comp->argv[0] = grecs_strdup (comp->program ? comp->program : "/bin/sh");
756 comp->argv[1] = grecs_strdup ("-c");
757 comp->argv[2] = grecs_strdup (comp->command);
758 comp->argv[3] = NULL;
759 }
760 else
761 {
762 struct wordsplit ws;
763 if (wordsplit (comp->command, &ws, WRDSF_DEFFLAGS))
764 {
765 grecs_error (locus, 0, "wordsplit: %s",
766 wordsplit_strerror (&ws));
767 component_free (comp);
768 return;
769 }
770 wordsplit_get_words (&ws, &comp->argc, &comp->argv);
771 wordsplit_free (&ws);
772 }
773
750 if (comp->prereq) 774 if (comp->prereq)
751 comp->prereq->cmp = list_str_cmp; 775 comp->prereq->cmp = list_str_cmp;
752 if (comp->depend) 776 if (comp->depend)
diff --git a/src/pies.c b/src/pies.c
index 98488a6..6105ae6 100644
--- a/src/pies.c
+++ b/src/pies.c
@@ -524,37 +524,6 @@ config_array_to_argv (grecs_value_t *val, grecs_locus_t *locus, size_t *pargc)
524} 524}
525 525
526static int 526static int
527_cb_command (enum grecs_callback_command cmd,
528 grecs_locus_t *locus,
529 void *varptr, grecs_value_t *value, void *cb_data)
530{
531 struct component *comp = varptr;
532 struct wordsplit ws;
533
534 switch (value->type)
535 {
536 case GRECS_TYPE_STRING:
537 if (wordsplit (value->v.string, &ws, WRDSF_DEFFLAGS))
538 {
539 grecs_error (locus, 0, "wordsplit: %s", strerror (errno));
540 return 1;
541 }
542 wordsplit_get_words (&ws, &comp->argc, &comp->argv);
543 wordsplit_free (&ws);
544 break;
545
546 case GRECS_TYPE_ARRAY:
547 comp->argv = config_array_to_argv (value, locus, &comp->argc);
548 break;
549
550 case GRECS_TYPE_LIST:
551 grecs_error (locus, 0, _("unexpected list"));
552 return 1;
553 }
554 return 0;
555}
556
557static int
558_cb_umask (enum grecs_callback_command cmd, 527_cb_umask (enum grecs_callback_command cmd,
559 grecs_locus_t *locus, 528 grecs_locus_t *locus,
560 void *varptr, grecs_value_t *value, void *cb_data) 529 void *varptr, grecs_value_t *value, void *cb_data)
@@ -589,13 +558,9 @@ _cb_env (enum grecs_callback_command cmd,
589 switch (value->type) 558 switch (value->type)
590 { 559 {
591 case GRECS_TYPE_STRING: 560 case GRECS_TYPE_STRING:
592 if (wordsplit (value->v.string, &ws, WRDSF_DEFFLAGS)) 561 argv = grecs_calloc (2, sizeof (argv[0]));
593 { 562 argv[0] = grecs_strdup (value->v.string);
594 grecs_error (locus, 0, "wordsplit: %s", strerror (errno)); 563 argv[1] = NULL;
595 return 1;
596 }
597 wordsplit_get_words (&ws, &argc, &argv);
598 wordsplit_free (&ws);
599 break; 564 break;
600 565
601 case GRECS_TYPE_ARRAY: 566 case GRECS_TYPE_ARRAY:
@@ -887,6 +852,7 @@ str_to_cf (const char *string, int *flags)
887 { "resolve", CF_RESOLVE }, 852 { "resolve", CF_RESOLVE },
888 { "siggroup", CF_SIGGROUP }, 853 { "siggroup", CF_SIGGROUP },
889 { "nullinput", CF_NULLINPUT }, 854 { "nullinput", CF_NULLINPUT },
855 { "shell", CF_SHELL },
890 { NULL } 856 { NULL }
891 }; 857 };
892 858
@@ -1014,9 +980,9 @@ struct grecs_keyword component_keywords[] = {
1014 NULL, 980 NULL,
1015 N_("Command line."), 981 N_("Command line."),
1016 grecs_type_string, GRECS_DFLT, 982 grecs_type_string, GRECS_DFLT,
1017 NULL, 0, 983 NULL, offsetof (struct component, command),
1018 _cb_command, 984 NULL,
1019 }, 985 },
1020 {"prerequisites", 986 {"prerequisites",
1021 N_("list"), 987 N_("list"),
1022 N_("List of prerequisites."), 988 N_("List of prerequisites."),
diff --git a/src/pies.h b/src/pies.h
index 74cb346..2e544e1 100644
--- a/src/pies.h
+++ b/src/pies.h
@@ -206,10 +206,10 @@ enum pies_comp_mode
206 the environment */ 206 the environment */
207#define CF_RESOLVE 0x080 /* Resolve IP addresses */ 207#define CF_RESOLVE 0x080 /* Resolve IP addresses */
208#define CF_SIGGROUP 0x100 /* Send signals to the process group */ 208#define CF_SIGGROUP 0x100 /* Send signals to the process group */
209
210#define CF_NULLINPUT 0x200 /* Provide null input stream */ 209#define CF_NULLINPUT 0x200 /* Provide null input stream */
210#define CF_SHELL 0x400 /* Invoke via sh -c */
211 211
212#define CF_REMOVE 0x400 /* Marked for removal */ 212#define CF_REMOVE 0xf000 /* Marked for removal */
213 213
214#define ISCF_TCPMUX(f) ((f) & (CF_TCPMUX | CF_TCPMUXPLUS)) 214#define ISCF_TCPMUX(f) ((f) & (CF_TCPMUX | CF_TCPMUXPLUS))
215 215
@@ -226,6 +226,7 @@ struct component
226 enum pies_comp_mode mode; 226 enum pies_comp_mode mode;
227 char *tag; /* Entry tag (for diagnostics purposes) */ 227 char *tag; /* Entry tag (for diagnostics purposes) */
228 char *program; /* Program name */ 228 char *program; /* Program name */
229 char *command; /* Full command line */
229 size_t argc; /* Number of command line arguments */ 230 size_t argc; /* Number of command line arguments */
230 char **argv; /* Program command line */ 231 char **argv; /* Program command line */
231 char **env; /* Program environment */ 232 char **env; /* Program environment */
diff --git a/tests/Makefile.am b/tests/Makefile.am
index b404ed4..39899c8 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -52,6 +52,7 @@ TESTSUITE_AT = \
52 redirect.at\ 52 redirect.at\
53 ret-exec.at\ 53 ret-exec.at\
54 ret-notify.at\ 54 ret-notify.at\
55 shell.at\
55 startup.at\ 56 startup.at\
56 shutdown.at\ 57 shutdown.at\
57 version.at 58 version.at
diff --git a/tests/aux/respawn b/tests/aux/respawn
index 11d59f6..cd9687a 100755
--- a/tests/aux/respawn
+++ b/tests/aux/respawn
@@ -5,7 +5,7 @@
5 5
6append=0 6append=0
7unset name 7unset name
8time=10 8time=1
9tag=$0 9tag=$0
10code=0 10code=0
11 11
diff --git a/tests/respawn.at b/tests/respawn.at
index 4a8e3a7..6b51ca6 100644
--- a/tests/respawn.at
+++ b/tests/respawn.at
@@ -34,7 +34,7 @@ while :
34do 34do
35 if test -f $comp_pid_file; then 35 if test -f $comp_pid_file; then
36 lines=`wc -l $comp_pid_file | awk '{print $1}'` 36 lines=`wc -l $comp_pid_file | awk '{print $1}'`
37 if test "$lines" -ge 3 ; then 37 if test "$lines" -ge 2 ; then
38 break 38 break
39 fi 39 fi
40 fi 40 fi
diff --git a/tests/shell.at b/tests/shell.at
new file mode 100644
index 0000000..0ef2271
--- /dev/null
+++ b/tests/shell.at
@@ -0,0 +1,58 @@
1# This file is part of GNU pies testsuite. -*- Autotest -*-
2# Copyright (C) 2016-2019 Sergey Poznyakoff
3#
4# GNU pies is free software; you can redistribute it and/or modify
5# it under the terms of the GNU General Public License as published by
6# the Free Software Foundation; either version 3, or (at your option)
7# any later version.
8#
9# GNU pies is distributed in the hope that it will be useful,
10# but WITHOUT ANY WARRANTY; without even the implied warranty of
11# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12# GNU General Public License for more details.
13#
14# You should have received a copy of the GNU General Public License
15# along with GNU pies. If not, see <http://www.gnu.org/licenses/>.
16
17AT_SETUP([flags shell])
18
19AT_CHECK([
20PIES_XFAIL_CHECK
21PIES_CONTROL_INIT
22outfile=$PWD/respawn.out
23cat > pies.conf <<_EOT
24component test {
25 mode respawn;
26 flags shell;
27 command "$auxdir/respawn -tag respawn > $outfile";
28}
29_EOT
30
31pies --config-file control.conf --config-file pies.conf
32
33n=0
34while :
35do
36 if test -f $outfile; then
37 lines=`wc -l $outfile | awk '{print $1}'`
38 if test "$lines" -ge 2 ; then
39 break
40 fi
41 fi
42 sleep 1
43 n=$(($n + 1))
44 if test $n -gt 35; then
45 echo >&2 "timed out"
46 break
47 fi
48done
49
50PIES_STOP
51head -n3 $outfile
52],
53[0],
54[respawn: start
55respawn: stop
56])
57
58AT_CLEANUP
diff --git a/tests/testsuite.at b/tests/testsuite.at
index 6775ee7..28d1f9d 100644
--- a/tests/testsuite.at
+++ b/tests/testsuite.at
@@ -67,3 +67,4 @@ m4_include([ret-exec.at])
67m4_include([ret-notify.at]) 67m4_include([ret-notify.at])
68m4_include([startup.at]) 68m4_include([startup.at])
69m4_include([shutdown.at]) 69m4_include([shutdown.at])
70m4_include([shell.at])

Return to:

Send suggestions and report system problems to the System administrator.