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 +2