summaryrefslogtreecommitdiff
path: root/src/notify
diff options
context:
space:
mode:
authorLennart Poettering <lennart@poettering.net>2023-02-16 15:42:49 +0100
committerLennart Poettering <lennart@poettering.net>2023-02-17 09:55:35 +0100
commit9175338e09de56c99cebf0b9f215f3e9e0016cb9 (patch)
treee046ae09a02b804d392ede1965f876e03d184713 /src/notify
parent4ea517a6e07f47117348c68c6fe087bf6d401558 (diff)
downloadsystemd-9175338e09de56c99cebf0b9f215f3e9e0016cb9.tar.gz
notify: add new --exec switch for chaining other commands to systemd-notify
This is useful in tests, so that we can first send a READY message and then continue doing something else without changing PID.
Diffstat (limited to 'src/notify')
-rw-r--r--src/notify/notify.c59
1 files changed, 56 insertions, 3 deletions
diff --git a/src/notify/notify.c b/src/notify/notify.c
index b1348383f5..7320ffebde 100644
--- a/src/notify/notify.c
+++ b/src/notify/notify.c
@@ -31,6 +31,11 @@ static bool arg_booted = false;
static uid_t arg_uid = UID_INVALID;
static gid_t arg_gid = GID_INVALID;
static bool arg_no_block = false;
+static char **arg_env = NULL;
+static char **arg_exec = NULL;
+
+STATIC_DESTRUCTOR_REGISTER(arg_env, strv_freep);
+STATIC_DESTRUCTOR_REGISTER(arg_exec, strv_freep);
static int help(void) {
_cleanup_free_ char *link = NULL;
@@ -41,6 +46,7 @@ static int help(void) {
return log_oom();
printf("%s [OPTIONS...] [VARIABLE=VALUE...]\n"
+ "%s [OPTIONS...] --exec [VARIABLE=VALUE...] ; CMDLINE...\n"
"\n%sNotify the init system about service status updates.%s\n\n"
" -h --help Show this help\n"
" --version Show package version\n"
@@ -53,8 +59,10 @@ static int help(void) {
" --status=TEXT Set status text\n"
" --booted Check if the system was booted up with systemd\n"
" --no-block Do not wait until operation finished\n"
+ " --exec Execute command line separated by ';' once done\n"
"\nSee the %s for details.\n",
program_invocation_short_name,
+ program_invocation_short_name,
ansi_highlight(),
ansi_normal(),
link);
@@ -93,7 +101,8 @@ static int parse_argv(int argc, char *argv[]) {
ARG_STATUS,
ARG_BOOTED,
ARG_UID,
- ARG_NO_BLOCK
+ ARG_NO_BLOCK,
+ ARG_EXEC,
};
static const struct option options[] = {
@@ -107,10 +116,12 @@ static int parse_argv(int argc, char *argv[]) {
{ "booted", no_argument, NULL, ARG_BOOTED },
{ "uid", required_argument, NULL, ARG_UID },
{ "no-block", no_argument, NULL, ARG_NO_BLOCK },
+ { "exec", no_argument, NULL, ARG_EXEC },
{}
};
- int c, r;
+ bool do_exec = false;
+ int c, r, n_env;
assert(argc >= 0);
assert(argv);
@@ -183,6 +194,10 @@ static int parse_argv(int argc, char *argv[]) {
arg_no_block = true;
break;
+ case ARG_EXEC:
+ do_exec = true;
+ break;
+
case '?':
return -EINVAL;
@@ -202,6 +217,32 @@ static int parse_argv(int argc, char *argv[]) {
return -EINVAL;
}
+ if (do_exec) {
+ int i;
+
+ for (i = optind; i < argc; i++)
+ if (streq(argv[i], ";"))
+ break;
+
+ if (i >= argc)
+ return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "If --exec is used argument list must contain ';' separator, refusing.");
+ if (i+1 == argc)
+ return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Empty command line specified after ';' separator, refusing");
+
+ arg_exec = strv_copy_n(argv + i + 1, argc - i - 1);
+ if (!arg_exec)
+ return log_oom();
+
+ n_env = i - optind;
+ } else
+ n_env = argc - optind;
+
+ if (n_env > 0) {
+ arg_env = strv_copy_n(argv + optind, n_env);
+ if (!arg_env)
+ return log_oom();
+ }
+
return 1;
}
@@ -263,7 +304,7 @@ static int run(int argc, char* argv[]) {
our_env[i++] = NULL;
- final_env = strv_env_merge(our_env, argv + optind);
+ final_env = strv_env_merge(our_env, arg_env);
if (!final_env)
return log_oom();
@@ -313,6 +354,18 @@ static int run(int argc, char* argv[]) {
"No status data could be sent: $NOTIFY_SOCKET was not set");
}
+ if (arg_exec) {
+ _cleanup_free_ char *cmdline = NULL;
+
+ execvp(arg_exec[0], arg_exec);
+
+ cmdline = strv_join(arg_exec, " ");
+ if (!cmdline)
+ return log_oom();
+
+ return log_error_errno(errno, "Failed to execute command line: %s", cmdline);
+ }
+
return 0;
}