mirror of
https://github.com/systemd/systemd-stable.git
synced 2025-03-13 12:58:20 +03:00
notify: add support for sending fds with notification messages
This exposes the fd passing we support via sd_pid_notify_with_fds() also via the command line tool systemd-notify.
This commit is contained in:
parent
e829f28c1b
commit
6e4a324574
@ -191,6 +191,29 @@
|
||||
escaped as <literal>\;</literal>.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><option>--fd=</option></term>
|
||||
|
||||
<listitem><para>Send a file descriptor along with the notification message. This is useful when
|
||||
invoked in services that have the <varname>FileDescriptorStoreMax=</varname> setting enabled, see
|
||||
<citerefentry><refentrytitle>systemd.service</refentrytitle><manvolnum>5</manvolnum></citerefentry>
|
||||
for details. The specified file descriptor must be passed to <command>systemd-notify</command> when
|
||||
invoked. This option may be used multiple times to pass multiple file descriptors in a single
|
||||
notification message.</para>
|
||||
|
||||
<para>To use this functionality from a <command>bash</command> shell, use an expression like the following:</para>
|
||||
<programlisting>systemd-notify --fd=4 --fd=5 4</some/file 5</some/other/file</programlisting></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><option>--fdname=</option></term>
|
||||
|
||||
<listitem><para>Set a name to assign to the file descriptors passed via <option>--fd=</option> (see
|
||||
above). This controls the <literal>FDNAME=</literal> field. This setting may only be specified once,
|
||||
and applies to all file descriptors passed. Invoke this tool multiple times in case multiple file
|
||||
descriptors with different file descriptor names shall be submitted.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<xi:include href="standard-options.xml" xpointer="help" />
|
||||
<xi:include href="standard-options.xml" xpointer="version" />
|
||||
</variablelist>
|
||||
|
@ -11,6 +11,8 @@
|
||||
#include "alloc-util.h"
|
||||
#include "build.h"
|
||||
#include "env-util.h"
|
||||
#include "fd-util.h"
|
||||
#include "fdset.h"
|
||||
#include "format-util.h"
|
||||
#include "log.h"
|
||||
#include "main-func.h"
|
||||
@ -33,9 +35,13 @@ static gid_t arg_gid = GID_INVALID;
|
||||
static bool arg_no_block = false;
|
||||
static char **arg_env = NULL;
|
||||
static char **arg_exec = NULL;
|
||||
static FDSet *arg_fds = NULL;
|
||||
static char *arg_fdname = NULL;
|
||||
|
||||
STATIC_DESTRUCTOR_REGISTER(arg_env, strv_freep);
|
||||
STATIC_DESTRUCTOR_REGISTER(arg_exec, strv_freep);
|
||||
STATIC_DESTRUCTOR_REGISTER(arg_fds, fdset_freep);
|
||||
STATIC_DESTRUCTOR_REGISTER(arg_fdname, freep);
|
||||
|
||||
static int help(void) {
|
||||
_cleanup_free_ char *link = NULL;
|
||||
@ -60,6 +66,8 @@ static int help(void) {
|
||||
" --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"
|
||||
" --fd=FD Pass specified file descriptor with along with message\n"
|
||||
" --fdname=NAME Name to assign to passed file descriptor(s)\n"
|
||||
"\nSee the %s for details.\n",
|
||||
program_invocation_short_name,
|
||||
program_invocation_short_name,
|
||||
@ -103,6 +111,8 @@ static int parse_argv(int argc, char *argv[]) {
|
||||
ARG_UID,
|
||||
ARG_NO_BLOCK,
|
||||
ARG_EXEC,
|
||||
ARG_FD,
|
||||
ARG_FDNAME,
|
||||
};
|
||||
|
||||
static const struct option options[] = {
|
||||
@ -117,9 +127,12 @@ static int parse_argv(int argc, char *argv[]) {
|
||||
{ "uid", required_argument, NULL, ARG_UID },
|
||||
{ "no-block", no_argument, NULL, ARG_NO_BLOCK },
|
||||
{ "exec", no_argument, NULL, ARG_EXEC },
|
||||
{ "fd", required_argument, NULL, ARG_FD },
|
||||
{ "fdname", required_argument, NULL, ARG_FDNAME },
|
||||
{}
|
||||
};
|
||||
|
||||
_cleanup_(fdset_freep) FDSet *passed = NULL;
|
||||
bool do_exec = false;
|
||||
int c, r, n_env;
|
||||
|
||||
@ -198,6 +211,60 @@ static int parse_argv(int argc, char *argv[]) {
|
||||
do_exec = true;
|
||||
break;
|
||||
|
||||
case ARG_FD: {
|
||||
_cleanup_close_ int owned_fd = -EBADF;
|
||||
int fdnr;
|
||||
|
||||
r = safe_atoi(optarg, &fdnr);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to parse file descriptor: %s", optarg);
|
||||
if (fdnr < 0)
|
||||
return log_error_errno(SYNTHETIC_ERRNO(ERANGE), "File descriptor can't be negative: %i", fdnr);
|
||||
|
||||
if (!passed) {
|
||||
/* Take possession of all passed fds */
|
||||
r = fdset_new_fill(&passed);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to take possession of passed file descriptors: %m");
|
||||
|
||||
r = fdset_cloexec(passed, true);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to enable O_CLOEXEC for passed file descriptors: %m");
|
||||
}
|
||||
|
||||
if (fdnr < 3) {
|
||||
/* For stdin/stdout/stderr we want to keep the fd, too, hence make a copy */
|
||||
owned_fd = fcntl(fdnr, F_DUPFD_CLOEXEC, 3);
|
||||
if (owned_fd < 0)
|
||||
return log_error_errno(errno, "Failed to duplicate file descriptor: %m");
|
||||
} else {
|
||||
/* Otherwise, move the fd over */
|
||||
owned_fd = fdset_remove(passed, fdnr);
|
||||
if (owned_fd < 0)
|
||||
return log_error_errno(owned_fd, "Specified file descriptor '%i' not passed or specified more than once: %m", fdnr);
|
||||
}
|
||||
|
||||
if (!arg_fds) {
|
||||
arg_fds = fdset_new();
|
||||
if (!arg_fds)
|
||||
return log_oom();
|
||||
}
|
||||
|
||||
r = fdset_consume(arg_fds, TAKE_FD(owned_fd));
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to add file descriptor to set: %m");
|
||||
break;
|
||||
}
|
||||
|
||||
case ARG_FDNAME:
|
||||
if (!fdname_is_valid(optarg))
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "File descriptor name invalid: %s", optarg);
|
||||
|
||||
if (free_and_strdup(&arg_fdname, optarg) < 0)
|
||||
return log_oom();
|
||||
|
||||
break;
|
||||
|
||||
case '?':
|
||||
return -EINVAL;
|
||||
|
||||
@ -212,11 +279,15 @@ static int parse_argv(int argc, char *argv[]) {
|
||||
!arg_reloading &&
|
||||
!arg_status &&
|
||||
!arg_pid &&
|
||||
!arg_booted) {
|
||||
!arg_booted &&
|
||||
fdset_isempty(arg_fds)) {
|
||||
help();
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (arg_fdname && fdset_isempty(arg_fds))
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "No file descriptors passed, but --fdname= set, refusing.");
|
||||
|
||||
if (do_exec) {
|
||||
int i;
|
||||
|
||||
@ -243,13 +314,16 @@ static int parse_argv(int argc, char *argv[]) {
|
||||
return log_oom();
|
||||
}
|
||||
|
||||
if (!fdset_isempty(passed))
|
||||
log_warning("Warning: %u more file descriptors passed than referenced with --fd=.", fdset_size(passed));
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int run(int argc, char* argv[]) {
|
||||
_cleanup_free_ char *status = NULL, *cpid = NULL, *n = NULL, *monotonic_usec = NULL;
|
||||
_cleanup_free_ char *status = NULL, *cpid = NULL, *n = NULL, *monotonic_usec = NULL, *fdn = NULL;
|
||||
_cleanup_strv_free_ char **final_env = NULL;
|
||||
char* our_env[7];
|
||||
char* our_env[9];
|
||||
size_t i = 0;
|
||||
pid_t source_pid;
|
||||
int r;
|
||||
@ -302,6 +376,18 @@ static int run(int argc, char* argv[]) {
|
||||
our_env[i++] = cpid;
|
||||
}
|
||||
|
||||
if (!fdset_isempty(arg_fds)) {
|
||||
our_env[i++] = (char*) "FDSTORE=1";
|
||||
|
||||
if (arg_fdname) {
|
||||
fdn = strjoin("FDNAME=", arg_fdname);
|
||||
if (!fdn)
|
||||
return log_oom();
|
||||
|
||||
our_env[i++] = fdn;
|
||||
}
|
||||
}
|
||||
|
||||
our_env[i++] = NULL;
|
||||
|
||||
final_env = strv_env_merge(our_env, arg_env);
|
||||
@ -338,13 +424,28 @@ static int run(int argc, char* argv[]) {
|
||||
* or the service manager itself */
|
||||
source_pid = 0;
|
||||
}
|
||||
r = sd_pid_notify(source_pid, false, n);
|
||||
|
||||
if (fdset_isempty(arg_fds))
|
||||
r = sd_pid_notify(source_pid, /* unset_environment= */ false, n);
|
||||
else {
|
||||
_cleanup_free_ int *a = NULL;
|
||||
int k;
|
||||
|
||||
k = fdset_to_array(arg_fds, &a);
|
||||
if (k < 0)
|
||||
return log_error_errno(k, "Failed to convert file descriptor set to array: %m");
|
||||
|
||||
r = sd_pid_notify_with_fds(source_pid, /* unset_environment= */ false, n, a, k);
|
||||
|
||||
}
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to notify init system: %m");
|
||||
if (r == 0)
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP),
|
||||
"No status data could be sent: $NOTIFY_SOCKET was not set");
|
||||
|
||||
arg_fds = fdset_free(arg_fds); /* Close before we execute anything */
|
||||
|
||||
if (!arg_no_block) {
|
||||
r = sd_notify_barrier(0, 5 * USEC_PER_SEC);
|
||||
if (r < 0)
|
||||
|
Loading…
x
Reference in New Issue
Block a user