diff options
author | Zbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl> | 2013-09-08 07:51:39 -0400 |
---|---|---|
committer | Zbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl> | 2013-09-09 13:49:30 -0400 |
commit | c9d954b27ee125c3c90a6d2951c62eec4abb160b (patch) | |
tree | 2a1e3a376ce997b95c5dfa41e50ca48bf2f347df | |
parent | 116cc028742836e61abce7582ec9ecf9f0aaeb53 (diff) |
run: allow non-absolute paths as command
-rw-r--r-- | TODO | 2 | ||||
-rw-r--r-- | man/systemd-run.xml | 17 | ||||
-rw-r--r-- | src/core/manager.c | 6 | ||||
-rw-r--r-- | src/run/run.c | 11 | ||||
-rw-r--r-- | src/shared/path-util.c | 48 | ||||
-rw-r--r-- | src/shared/path-util.h | 8 | ||||
-rw-r--r-- | src/test/test-path-util.c | 24 |
7 files changed, 109 insertions, 7 deletions
@@ -715,6 +715,8 @@ Features: - document initcall_debug - kernel cmdline "bootchart" option for simplicity? +* systemd-run is missing completion scripts + External: * dbus: diff --git a/man/systemd-run.xml b/man/systemd-run.xml index 6b0189c25d..e76a402003 100644 --- a/man/systemd-run.xml +++ b/man/systemd-run.xml @@ -188,6 +188,23 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. </refsect1> <refsect1> + <title>Example</title> + + <para>The following command will log the environment variables + provided by systemd to services:</para> + + <programlisting># systemd-run env +Running as unit run-19945.service. +# journalctl -u run-19945.service +Sep 08 07:37:21 bupkis systemd[1]: Starting /usr/bin/env... +Sep 08 07:37:21 bupkis systemd[1]: Started /usr/bin/env. +Sep 08 07:37:21 bupkis env[19948]: PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin +Sep 08 07:37:21 bupkis env[19948]: LANG=en_US.UTF-8 +Sep 08 07:37:21 bupkis env[19948]: BOOT_IMAGE=/vmlinuz-3.11.0-0.rc5.git6.2.fc20.x86_64 + </programlisting> + </refsect1> + + <refsect1> <title>See Also</title> <para> <citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>, diff --git a/src/core/manager.c b/src/core/manager.c index 10ccffb404..669af1524f 100644 --- a/src/core/manager.c +++ b/src/core/manager.c @@ -456,11 +456,7 @@ static int manager_setup_signals(Manager *m) { } static int manager_default_environment(Manager *m) { -#ifdef HAVE_SPLIT_USR - const char *path = "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"; -#else - const char *path = "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin"; -#endif + const char *path = "PATH=" DEFAULT_PATH; assert(m); diff --git a/src/run/run.c b/src/run/run.c index c5d314bdf1..da8c788eea 100644 --- a/src/run/run.c +++ b/src/run/run.c @@ -39,7 +39,7 @@ static bool arg_send_sighup = false; static int help(void) { - printf("%s [OPTIONS...] [COMMAND LINE...]\n\n" + printf("%s [OPTIONS...] COMMAND [ARGS...]\n\n" "Run the specified command in a transient scope or service unit.\n\n" " -h --help Show this help\n" " --version Show package version\n" @@ -324,7 +324,7 @@ static int start_transient_scope( int main(int argc, char* argv[]) { sd_bus_error error = SD_BUS_ERROR_NULL; _cleanup_bus_unref_ sd_bus *bus = NULL; - _cleanup_free_ char *description = NULL; + _cleanup_free_ char *description = NULL, *command = NULL; int r; log_parse_environment(); @@ -334,6 +334,13 @@ int main(int argc, char* argv[]) { if (r <= 0) goto fail; + r = find_binary(argv[optind], &command); + if (r < 0) { + log_error("Failed to find executable %s: %s", argv[optind], strerror(-r)); + goto fail; + } + argv[optind] = command; + if (!arg_description) { description = strv_join(argv + optind, " "); if (!description) { diff --git a/src/shared/path-util.c b/src/shared/path-util.c index 6888135778..8e108db531 100644 --- a/src/shared/path-util.c +++ b/src/shared/path-util.c @@ -425,3 +425,51 @@ int path_is_os_tree(const char *path) { return r < 0 ? 0 : 1; } + +int find_binary(const char *name, char **filename) { + assert(name); + if (strchr(name, '/')) { + char *p; + + if (path_is_absolute(name)) + p = strdup(name); + else + p = path_make_absolute_cwd(name); + if (!p) + return -ENOMEM; + + *filename = p; + return 0; + } else { + const char *path; + char *state, *w; + size_t l; + + /** + * Plain getenv, not secure_getenv, because we want + * to actually allow the user to pick the binary. + */ + path = getenv("PATH"); + if (!path) + path = DEFAULT_PATH; + + FOREACH_WORD_SEPARATOR(w, l, path, ":", state) { + char *p; + + if (asprintf(&p, "%.*s/%s", l, w, name) < 0) + return -ENOMEM; + + if (access(p, X_OK) < 0) { + free(p); + continue; + } + + path_kill_slashes(p); + *filename = p; + + return 0; + } + + return -ENOENT; + } +} diff --git a/src/shared/path-util.h b/src/shared/path-util.h index d187743769..9452931586 100644 --- a/src/shared/path-util.h +++ b/src/shared/path-util.h @@ -25,6 +25,12 @@ #include "macro.h" +#ifdef HAVE_SPLIT_USR +# define DEFAULT_PATH "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" +#else +# define DEFAULT_PATH "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin" +#endif + bool is_path(const char *p) _pure_; char** path_split_and_make_absolute(const char *p); char* path_get_file_name(const char *p) _pure_; @@ -43,3 +49,5 @@ char** path_strv_canonicalize_uniq(char **l); int path_is_mount_point(const char *path, bool allow_symlink); int path_is_read_only_fs(const char *path); int path_is_os_tree(const char *path); + +int find_binary(const char *name, char **filename); diff --git a/src/test/test-path-util.c b/src/test/test-path-util.c index f396b32ffe..b0aeb11a63 100644 --- a/src/test/test-path-util.c +++ b/src/test/test-path-util.c @@ -83,7 +83,31 @@ static void test_path(void) { } } +static void test_find_binary(void) { + char *p; + + assert(find_binary("/bin/sh", &p) == 0); + puts(p); + assert(streq(p, "/bin/sh")); + free(p); + + assert(find_binary("./test-path-util", &p) == 0); + puts(p); + assert(endswith(p, "/test-path-util")); + assert(path_is_absolute(p)); + free(p); + + assert(find_binary("sh", &p) == 0); + puts(p); + assert(endswith(p, "/sh")); + assert(path_is_absolute(p)); + free(p); + + assert(find_binary("xxxx-xxxx", &p) == -ENOENT); +} + int main(void) { test_path(); + test_find_binary(); return 0; } |