diff options
author | Sergey Poznyakoff <gray@gnu.org> | 2019-05-31 08:45:23 +0300 |
---|---|---|
committer | Sergey Poznyakoff <gray@gnu.org> | 2019-05-31 08:58:54 +0300 |
commit | 058f256a6f41fc9c36404b2e22580546e4f55b33 (patch) | |
tree | b6afde4271da1d92e5c10e1c50213c2fda7b2831 | |
parent | ca38eef07ac3f9a4825f0046c1d373ed7b2f074b (diff) | |
download | pies-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-- | NEWS | 22 | ||||
-rw-r--r-- | doc/pies.texi | 21 | ||||
-rw-r--r-- | src/comp.c | 24 | ||||
-rw-r--r-- | src/pies.c | 48 | ||||
-rw-r--r-- | src/pies.h | 5 | ||||
-rw-r--r-- | tests/Makefile.am | 1 | ||||
-rwxr-xr-x | tests/aux/respawn | 2 | ||||
-rw-r--r-- | tests/respawn.at | 2 | ||||
-rw-r--r-- | tests/shell.at | 58 | ||||
-rw-r--r-- | tests/testsuite.at | 1 |
10 files changed, 137 insertions, 47 deletions
@@ -1,4 +1,4 @@ | |||
1 | GNU Pies NEWS -- history of user-visible changes. 2019-05-28 | 1 | GNU Pies NEWS -- history of user-visible changes. 2019-05-31 |
2 | See the end of file for copying conditions. | 2 | See the end of file for copying conditions. |
3 | 3 | ||
4 | Please send Pies bug reports to <bug-pies@gnu.org> or | 4 | Please send Pies bug reports to <bug-pies@gnu.org> or |
@@ -25,8 +25,28 @@ configuration file. Such multiple components are run simultaneously, | |||
25 | unless required otherwise by their "prerequisites" and "dependents" | 25 | unless required otherwise by their "prerequisites" and "dependents" |
26 | statements. | 26 | statements. |
27 | 27 | ||
28 | * New component flag: shell | ||
29 | |||
30 | The 'shell' flag instructs pies to run the component via "/bin/sh -c | ||
31 | $command". Use it if the command should undergo variable expansion, | ||
32 | contains 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 | |||
43 | Previous versions applied unnecessary word splitting if given a | ||
44 | single argument. This is now fixed, so that e.g. the following | ||
45 | statement is processed correctly and defines a single variable | ||
46 | X to have the value "foo bar": | ||
47 | |||
48 | env "X=foo bar" | ||
49 | |||
30 | 50 | ||
31 | Version 1.3, 2016-10-01 | 51 | Version 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 |
178 | from its configuration file, starts them, and remains in the | 178 | from its configuration file, starts them, and remains in the |
179 | background, controlling their execution. | 179 | background, controlling their execution. Each component is |
180 | defined by the name of the external program to be run and its | ||
181 | arguments (command line). The program is normally run directly | ||
182 | (via @code{exec}), but you can instruct @command{pies} to run | ||
183 | it 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 |
182 | redirected to a file or to an arbitrary @command{syslog} channel. | 186 | redirected 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}). | |||
870 | Mark this component as @dfn{precious}. Precious components are never | 874 | Mark this component as @dfn{precious}. Precious components are never |
871 | disabled by @command{pies}, even if they respawn too fast. | 875 | disabled by @command{pies}, even if they respawn too fast. |
872 | 876 | ||
877 | @kwindex shell | ||
878 | @item shell | ||
879 | Run command as @code{/bin/sh -c "$command"}. Use this flag if command | ||
880 | contains shell-specific features, such as I/O redirections, pipes, | ||
881 | variables or the like. You can change the shell program using the | ||
882 | @code{program} statement. For example, to use Korn shell: | ||
883 | |||
884 | @example | ||
885 | component 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 |
875 | This flag is valid only for @samp{inetd} components. It has the same | 894 | This flag is valid only for @samp{inetd} components. It has the same |
@@ -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) | |||
747 | void | 748 | void |
748 | component_finish (struct component *comp, grecs_locus_t *locus) | 749 | component_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) |
@@ -524,37 +524,6 @@ config_array_to_argv (grecs_value_t *val, grecs_locus_t *locus, size_t *pargc) | |||
524 | } | 524 | } |
525 | 525 | ||
526 | static int | 526 | static 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 | |||
557 | static 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."), |
@@ -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 |