2020-11-09 13:23:58 +09:00
|
|
|
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
2013-06-28 04:12:58 +02:00
|
|
|
|
2013-07-01 00:03:57 +02:00
|
|
|
#include <getopt.h>
|
2015-09-23 03:01:06 +02:00
|
|
|
#include <stdio.h>
|
2019-03-27 11:32:41 +01:00
|
|
|
#include <fcntl.h>
|
|
|
|
|
#include <sys/stat.h>
|
|
|
|
|
#include <sys/types.h>
|
2013-06-28 04:12:58 +02:00
|
|
|
|
|
|
|
|
#include "sd-bus.h"
|
2014-12-22 19:45:32 +01:00
|
|
|
#include "sd-event.h"
|
2024-08-12 15:15:15 +02:00
|
|
|
#include "sd-json.h"
|
2015-09-23 03:01:06 +02:00
|
|
|
|
2015-10-27 03:01:06 +01:00
|
|
|
#include "alloc-util.h"
|
2022-11-06 16:30:58 +01:00
|
|
|
#include "build.h"
|
2015-09-23 03:01:06 +02:00
|
|
|
#include "bus-error.h"
|
2020-06-28 15:59:37 +02:00
|
|
|
#include "bus-locator.h"
|
2020-06-28 16:08:37 +02:00
|
|
|
#include "bus-map-properties.h"
|
2016-04-20 17:43:13 +02:00
|
|
|
#include "bus-unit-util.h"
|
2019-03-06 19:38:45 +01:00
|
|
|
#include "bus-wait-for-jobs.h"
|
2015-09-23 03:01:06 +02:00
|
|
|
#include "calendarspec.h"
|
2023-10-26 09:19:04 +02:00
|
|
|
#include "capsule-util.h"
|
|
|
|
|
#include "chase.h"
|
2014-03-05 18:57:21 +01:00
|
|
|
#include "env-util.h"
|
2023-11-25 01:05:41 +09:00
|
|
|
#include "escape.h"
|
2024-07-10 22:27:21 +02:00
|
|
|
#include "exec-util.h"
|
2019-10-29 18:07:07 +01:00
|
|
|
#include "exit-status.h"
|
2015-10-25 13:14:12 +01:00
|
|
|
#include "fd-util.h"
|
2016-11-07 10:14:59 -05:00
|
|
|
#include "format-util.h"
|
2023-10-26 09:19:04 +02:00
|
|
|
#include "fs-util.h"
|
2024-02-01 10:43:44 +01:00
|
|
|
#include "hostname-util.h"
|
2018-11-22 19:30:03 +01:00
|
|
|
#include "main-func.h"
|
2021-02-14 11:39:48 +01:00
|
|
|
#include "parse-argument.h"
|
2015-11-16 22:09:36 +01:00
|
|
|
#include "parse-util.h"
|
2013-09-09 17:31:10 -04:00
|
|
|
#include "path-util.h"
|
2024-06-26 12:07:36 +02:00
|
|
|
#include "polkit-agent.h"
|
2018-11-20 15:42:57 +01:00
|
|
|
#include "pretty-print.h"
|
2016-08-17 14:24:17 +02:00
|
|
|
#include "process-util.h"
|
2014-12-22 19:45:32 +01:00
|
|
|
#include "ptyfwd.h"
|
2015-05-29 20:14:11 +02:00
|
|
|
#include "signal-util.h"
|
2024-01-04 15:22:54 +01:00
|
|
|
#include "special.h"
|
2015-09-23 03:01:06 +02:00
|
|
|
#include "strv.h"
|
2015-10-07 22:45:48 +02:00
|
|
|
#include "terminal-util.h"
|
2023-10-26 09:19:04 +02:00
|
|
|
#include "uid-classification.h"
|
2017-12-23 16:59:56 +09:00
|
|
|
#include "unit-def.h"
|
2015-09-23 03:01:06 +02:00
|
|
|
#include "unit-name.h"
|
2015-10-25 22:32:30 +01:00
|
|
|
#include "user-util.h"
|
2013-06-28 04:12:58 +02:00
|
|
|
|
2015-09-01 16:43:08 +00:00
|
|
|
static bool arg_ask_password = true;
|
2013-07-01 00:03:57 +02:00
|
|
|
static bool arg_scope = false;
|
2013-07-26 16:09:25 +02:00
|
|
|
static bool arg_remain_after_exit = false;
|
2015-04-28 12:33:19 +02:00
|
|
|
static bool arg_no_block = false;
|
2016-08-17 14:24:17 +02:00
|
|
|
static bool arg_wait = false;
|
2013-07-01 00:03:57 +02:00
|
|
|
static const char *arg_unit = NULL;
|
run: fix bad escaping and memory ownership confusion
arg_description was either set to arg_unit (i.e. a const char*), or to
char *description, the result of allocation in run(). But description
was decorated with _cleanup_, so it would be freed when going out of the
function. Nothing bad would happen, because the program would exit after
exiting from run(), but this is just all too messy.
Also, strv_join(" ") + shell_escape() is not a good way to escape command
lines. In particular, one the join has happened, we cannot distinguish
empty arguments, or arguments with whitespace, etc. We have a helper
function to do the escaping properly, so let's use that.
Fixup for 2c29813da3421b77eca5e5cdc3b9a863cad473b9.
2023-11-29 14:13:33 +01:00
|
|
|
static char *arg_description = NULL;
|
2013-07-01 03:02:42 +02:00
|
|
|
static const char *arg_slice = NULL;
|
2020-04-08 14:57:52 +02:00
|
|
|
static bool arg_slice_inherit = false;
|
2023-07-19 22:56:02 +01:00
|
|
|
static int arg_expand_environment = -1;
|
2013-07-30 02:28:22 +02:00
|
|
|
static bool arg_send_sighup = false;
|
2013-10-30 16:44:55 +01:00
|
|
|
static BusTransport arg_transport = BUS_TRANSPORT_LOCAL;
|
2014-03-05 03:38:36 +01:00
|
|
|
static const char *arg_host = NULL;
|
2023-03-10 09:47:10 +01:00
|
|
|
static RuntimeScope arg_runtime_scope = RUNTIME_SCOPE_SYSTEM;
|
2014-02-05 02:02:00 +01:00
|
|
|
static const char *arg_service_type = NULL;
|
|
|
|
|
static const char *arg_exec_user = NULL;
|
|
|
|
|
static const char *arg_exec_group = NULL;
|
|
|
|
|
static int arg_nice = 0;
|
|
|
|
|
static bool arg_nice_set = false;
|
|
|
|
|
static char **arg_environment = NULL;
|
2014-03-05 03:36:22 +01:00
|
|
|
static char **arg_property = NULL;
|
2017-09-08 15:38:40 +02:00
|
|
|
static enum {
|
|
|
|
|
ARG_STDIO_NONE, /* The default, as it is for normal services, stdin connected to /dev/null, and stdout+stderr to the journal */
|
|
|
|
|
ARG_STDIO_PTY, /* Interactive behaviour, requested by --pty: we allocate a pty and connect it to the TTY we are invoked from */
|
|
|
|
|
ARG_STDIO_DIRECT, /* Directly pass our stdin/stdout/stderr to the activated service, useful for usage in shell pipelines, requested by --pipe */
|
|
|
|
|
ARG_STDIO_AUTO, /* If --pipe and --pty are used together we use --pty when invoked on a TTY, and --pipe otherwise */
|
|
|
|
|
} arg_stdio = ARG_STDIO_NONE;
|
2017-12-18 23:46:45 +09:00
|
|
|
static char **arg_path_property = NULL;
|
|
|
|
|
static char **arg_socket_property = NULL;
|
run: introduce timer support option
Support timer options --on-active=, --on-boot=, --on-startup=,
--on-unit-active=, --on-unit-inactive=, --on-calendar=. Each options
corresponding with OnActiveSec=, OnBootSec=, OnStartupSec=,
OnUnitActiveSec=, OnUnitInactiveSec=, OnCalendar= of timer
respectively. And OnCalendar= and WakeSystem= supported by
--timer-property= option like --property= of systemd-run.
And if --unit= option and timer options are specified the command can
be omitted. In this case, systemd-run assumes the target service is
already loaded. And just try to generate transient timer unit only.
2014-12-09 16:07:16 +09:00
|
|
|
static char **arg_timer_property = NULL;
|
2019-03-14 19:55:29 +01:00
|
|
|
static bool arg_with_timer = false;
|
2014-12-22 20:39:10 +01:00
|
|
|
static bool arg_quiet = false;
|
2017-11-13 17:17:53 +01:00
|
|
|
static bool arg_aggressive_gc = false;
|
2018-11-22 12:07:25 +01:00
|
|
|
static char *arg_working_directory = NULL;
|
2018-11-22 19:24:48 +01:00
|
|
|
static bool arg_shell = false;
|
|
|
|
|
static char **arg_cmdline = NULL;
|
2023-12-19 19:10:52 +01:00
|
|
|
static char *arg_exec_path = NULL;
|
2023-12-19 21:39:50 +01:00
|
|
|
static bool arg_ignore_failure = false;
|
2023-12-20 12:09:27 +01:00
|
|
|
static char *arg_background = NULL;
|
2024-08-12 15:15:15 +02:00
|
|
|
static sd_json_format_flags_t arg_json_format_flags = SD_JSON_FORMAT_OFF;
|
2013-06-28 04:12:58 +02:00
|
|
|
|
run: fix bad escaping and memory ownership confusion
arg_description was either set to arg_unit (i.e. a const char*), or to
char *description, the result of allocation in run(). But description
was decorated with _cleanup_, so it would be freed when going out of the
function. Nothing bad would happen, because the program would exit after
exiting from run(), but this is just all too messy.
Also, strv_join(" ") + shell_escape() is not a good way to escape command
lines. In particular, one the join has happened, we cannot distinguish
empty arguments, or arguments with whitespace, etc. We have a helper
function to do the escaping properly, so let's use that.
Fixup for 2c29813da3421b77eca5e5cdc3b9a863cad473b9.
2023-11-29 14:13:33 +01:00
|
|
|
STATIC_DESTRUCTOR_REGISTER(arg_description, freep);
|
2018-11-22 19:34:15 +01:00
|
|
|
STATIC_DESTRUCTOR_REGISTER(arg_environment, strv_freep);
|
|
|
|
|
STATIC_DESTRUCTOR_REGISTER(arg_property, strv_freep);
|
|
|
|
|
STATIC_DESTRUCTOR_REGISTER(arg_path_property, strv_freep);
|
|
|
|
|
STATIC_DESTRUCTOR_REGISTER(arg_socket_property, strv_freep);
|
|
|
|
|
STATIC_DESTRUCTOR_REGISTER(arg_timer_property, strv_freep);
|
|
|
|
|
STATIC_DESTRUCTOR_REGISTER(arg_working_directory, freep);
|
|
|
|
|
STATIC_DESTRUCTOR_REGISTER(arg_cmdline, strv_freep);
|
2023-12-19 19:10:52 +01:00
|
|
|
STATIC_DESTRUCTOR_REGISTER(arg_exec_path, freep);
|
2023-12-20 12:09:27 +01:00
|
|
|
STATIC_DESTRUCTOR_REGISTER(arg_background, freep);
|
2018-11-22 19:34:15 +01:00
|
|
|
|
2018-08-09 10:32:31 +02:00
|
|
|
static int help(void) {
|
|
|
|
|
_cleanup_free_ char *link = NULL;
|
|
|
|
|
int r;
|
|
|
|
|
|
|
|
|
|
r = terminal_urlify_man("systemd-run", "1", &link);
|
|
|
|
|
if (r < 0)
|
|
|
|
|
return log_oom();
|
|
|
|
|
|
2023-12-19 19:09:59 +01:00
|
|
|
printf("%1$s [OPTIONS...] COMMAND [ARGUMENTS...]\n"
|
|
|
|
|
"\n%5$sRun the specified command in a transient scope or service.%6$s\n\n"
|
run: introduce timer support option
Support timer options --on-active=, --on-boot=, --on-startup=,
--on-unit-active=, --on-unit-inactive=, --on-calendar=. Each options
corresponding with OnActiveSec=, OnBootSec=, OnStartupSec=,
OnUnitActiveSec=, OnUnitInactiveSec=, OnCalendar= of timer
respectively. And OnCalendar= and WakeSystem= supported by
--timer-property= option like --property= of systemd-run.
And if --unit= option and timer options are specified the command can
be omitted. In this case, systemd-run assumes the target service is
already loaded. And just try to generate transient timer unit only.
2014-12-09 16:07:16 +09:00
|
|
|
" -h --help Show this help\n"
|
|
|
|
|
" --version Show package version\n"
|
2015-09-01 16:43:08 +00:00
|
|
|
" --no-ask-password Do not prompt for password\n"
|
run: introduce timer support option
Support timer options --on-active=, --on-boot=, --on-startup=,
--on-unit-active=, --on-unit-inactive=, --on-calendar=. Each options
corresponding with OnActiveSec=, OnBootSec=, OnStartupSec=,
OnUnitActiveSec=, OnUnitInactiveSec=, OnCalendar= of timer
respectively. And OnCalendar= and WakeSystem= supported by
--timer-property= option like --property= of systemd-run.
And if --unit= option and timer options are specified the command can
be omitted. In this case, systemd-run assumes the target service is
already loaded. And just try to generate transient timer unit only.
2014-12-09 16:07:16 +09:00
|
|
|
" --user Run as user unit\n"
|
|
|
|
|
" -H --host=[USER@]HOST Operate on remote host\n"
|
|
|
|
|
" -M --machine=CONTAINER Operate on local container\n"
|
|
|
|
|
" --scope Run this as scope rather than service\n"
|
2019-10-23 09:13:15 +02:00
|
|
|
" -u --unit=UNIT Run under the specified unit name\n"
|
2016-08-06 00:30:12 +02:00
|
|
|
" -p --property=NAME=VALUE Set service or scope unit property\n"
|
run: introduce timer support option
Support timer options --on-active=, --on-boot=, --on-startup=,
--on-unit-active=, --on-unit-inactive=, --on-calendar=. Each options
corresponding with OnActiveSec=, OnBootSec=, OnStartupSec=,
OnUnitActiveSec=, OnUnitInactiveSec=, OnCalendar= of timer
respectively. And OnCalendar= and WakeSystem= supported by
--timer-property= option like --property= of systemd-run.
And if --unit= option and timer options are specified the command can
be omitted. In this case, systemd-run assumes the target service is
already loaded. And just try to generate transient timer unit only.
2014-12-09 16:07:16 +09:00
|
|
|
" --description=TEXT Description for unit\n"
|
|
|
|
|
" --slice=SLICE Run in the specified slice\n"
|
2023-12-20 15:01:52 +01:00
|
|
|
" --slice-inherit Inherit the slice from the caller\n"
|
2023-04-04 21:18:33 +02:00
|
|
|
" --expand-environment=BOOL Control expansion of environment variables\n"
|
2015-04-28 12:33:19 +02:00
|
|
|
" --no-block Do not wait until operation finished\n"
|
run: introduce timer support option
Support timer options --on-active=, --on-boot=, --on-startup=,
--on-unit-active=, --on-unit-inactive=, --on-calendar=. Each options
corresponding with OnActiveSec=, OnBootSec=, OnStartupSec=,
OnUnitActiveSec=, OnUnitInactiveSec=, OnCalendar= of timer
respectively. And OnCalendar= and WakeSystem= supported by
--timer-property= option like --property= of systemd-run.
And if --unit= option and timer options are specified the command can
be omitted. In this case, systemd-run assumes the target service is
already loaded. And just try to generate transient timer unit only.
2014-12-09 16:07:16 +09:00
|
|
|
" -r --remain-after-exit Leave service around until explicitly stopped\n"
|
2016-08-17 14:24:17 +02:00
|
|
|
" --wait Wait until service stopped again\n"
|
run: introduce timer support option
Support timer options --on-active=, --on-boot=, --on-startup=,
--on-unit-active=, --on-unit-inactive=, --on-calendar=. Each options
corresponding with OnActiveSec=, OnBootSec=, OnStartupSec=,
OnUnitActiveSec=, OnUnitInactiveSec=, OnCalendar= of timer
respectively. And OnCalendar= and WakeSystem= supported by
--timer-property= option like --property= of systemd-run.
And if --unit= option and timer options are specified the command can
be omitted. In this case, systemd-run assumes the target service is
already loaded. And just try to generate transient timer unit only.
2014-12-09 16:07:16 +09:00
|
|
|
" --send-sighup Send SIGHUP when terminating\n"
|
|
|
|
|
" --service-type=TYPE Service type\n"
|
|
|
|
|
" --uid=USER Run as system user\n"
|
|
|
|
|
" --gid=GROUP Run as system group\n"
|
|
|
|
|
" --nice=NICE Nice level\n"
|
2018-11-22 12:07:25 +01:00
|
|
|
" --working-directory=PATH Set working directory\n"
|
|
|
|
|
" -d --same-dir Inherit working directory from caller\n"
|
2021-08-10 17:25:47 +02:00
|
|
|
" -E --setenv=NAME[=VALUE] Set environment variable\n"
|
2017-09-08 15:38:40 +02:00
|
|
|
" -t --pty Run service on pseudo TTY as STDIN/STDOUT/\n"
|
|
|
|
|
" STDERR\n"
|
|
|
|
|
" -P --pipe Pass STDIN/STDOUT/STDERR directly to service\n"
|
2017-11-13 17:17:53 +01:00
|
|
|
" -q --quiet Suppress information messages during runtime\n"
|
2024-08-12 15:15:15 +02:00
|
|
|
" --json=pretty|short|off Print unit name and invocation id as JSON\n"
|
2018-11-22 19:24:48 +01:00
|
|
|
" -G --collect Unload unit after it ran, even when failed\n"
|
2023-12-19 19:09:59 +01:00
|
|
|
" -S --shell Invoke a $SHELL interactively\n"
|
2023-12-19 21:39:50 +01:00
|
|
|
" --ignore-failure Ignore the exit status of the invoked process\n"
|
2023-12-20 12:09:27 +01:00
|
|
|
" --background=COLOR Set ANSI color for background\n"
|
2023-12-19 19:09:59 +01:00
|
|
|
"\n%3$sPath options:%4$s\n"
|
|
|
|
|
" --path-property=NAME=VALUE Set path unit property\n"
|
|
|
|
|
"\n%3$sSocket options:%4$s\n"
|
|
|
|
|
" --socket-property=NAME=VALUE Set socket unit property\n"
|
|
|
|
|
"\n%3$sTimer options:%4$s\n"
|
2015-01-27 21:22:57 -05:00
|
|
|
" --on-active=SECONDS Run after SECONDS delay\n"
|
|
|
|
|
" --on-boot=SECONDS Run SECONDS after machine was booted up\n"
|
|
|
|
|
" --on-startup=SECONDS Run SECONDS after systemd activation\n"
|
|
|
|
|
" --on-unit-active=SECONDS Run SECONDS after the last activation\n"
|
|
|
|
|
" --on-unit-inactive=SECONDS Run SECONDS after the last deactivation\n"
|
run: introduce timer support option
Support timer options --on-active=, --on-boot=, --on-startup=,
--on-unit-active=, --on-unit-inactive=, --on-calendar=. Each options
corresponding with OnActiveSec=, OnBootSec=, OnStartupSec=,
OnUnitActiveSec=, OnUnitInactiveSec=, OnCalendar= of timer
respectively. And OnCalendar= and WakeSystem= supported by
--timer-property= option like --property= of systemd-run.
And if --unit= option and timer options are specified the command can
be omitted. In this case, systemd-run assumes the target service is
already loaded. And just try to generate transient timer unit only.
2014-12-09 16:07:16 +09:00
|
|
|
" --on-calendar=SPEC Realtime timer\n"
|
2019-03-14 21:36:47 +01:00
|
|
|
" --on-timezone-change Run when the timezone changes\n"
|
|
|
|
|
" --on-clock-change Run when the realtime clock jumps\n"
|
2016-08-06 00:30:12 +02:00
|
|
|
" --timer-property=NAME=VALUE Set timer unit property\n"
|
2023-12-19 19:09:59 +01:00
|
|
|
"\nSee the %2$s for details.\n",
|
2021-01-30 14:13:04 +00:00
|
|
|
program_invocation_short_name,
|
2023-12-19 19:09:59 +01:00
|
|
|
link,
|
|
|
|
|
ansi_underline(), ansi_normal(),
|
|
|
|
|
ansi_highlight(), ansi_normal());
|
2018-08-09 10:32:31 +02:00
|
|
|
|
|
|
|
|
return 0;
|
2013-07-01 00:03:57 +02:00
|
|
|
}
|
|
|
|
|
|
2023-12-19 19:10:52 +01:00
|
|
|
static int help_sudo_mode(void) {
|
|
|
|
|
_cleanup_free_ char *link = NULL;
|
|
|
|
|
int r;
|
|
|
|
|
|
2024-03-19 11:14:55 +01:00
|
|
|
r = terminal_urlify_man("run0", "1", &link);
|
2023-12-19 19:10:52 +01:00
|
|
|
if (r < 0)
|
|
|
|
|
return log_oom();
|
|
|
|
|
|
2024-10-24 23:27:59 +02:00
|
|
|
/* NB: Let's not go overboard with short options: we try to keep a modicum of compatibility with
|
|
|
|
|
* sudo's short switches, hence please do not introduce new short switches unless they have a roughly
|
|
|
|
|
* equivalent purpose on sudo. Use long options for everything private to run0. */
|
|
|
|
|
|
2023-12-19 19:10:52 +01:00
|
|
|
printf("%s [OPTIONS...] COMMAND [ARGUMENTS...]\n"
|
|
|
|
|
"\n%sElevate privileges interactively.%s\n\n"
|
|
|
|
|
" -h --help Show this help\n"
|
|
|
|
|
" -V --version Show package version\n"
|
|
|
|
|
" --no-ask-password Do not prompt for password\n"
|
|
|
|
|
" --machine=CONTAINER Operate on local container\n"
|
|
|
|
|
" --unit=UNIT Run under the specified unit name\n"
|
|
|
|
|
" --property=NAME=VALUE Set service or scope unit property\n"
|
|
|
|
|
" --description=TEXT Description for unit\n"
|
|
|
|
|
" --slice=SLICE Run in the specified slice\n"
|
|
|
|
|
" --slice-inherit Inherit the slice\n"
|
|
|
|
|
" -u --user=USER Run as system user\n"
|
|
|
|
|
" -g --group=GROUP Run as system group\n"
|
|
|
|
|
" --nice=NICE Nice level\n"
|
|
|
|
|
" -D --chdir=PATH Set working directory\n"
|
|
|
|
|
" --setenv=NAME[=VALUE] Set environment variable\n"
|
2023-12-20 12:09:27 +01:00
|
|
|
" --background=COLOR Set ANSI color for background\n"
|
2024-10-24 23:27:59 +02:00
|
|
|
" --pty Request allocation of a pseudo TTY for stdio\n"
|
|
|
|
|
" --pipe Request direct pipe for stdio\n"
|
2023-12-19 19:10:52 +01:00
|
|
|
"\nSee the %s for details.\n",
|
|
|
|
|
program_invocation_short_name,
|
|
|
|
|
ansi_highlight(),
|
|
|
|
|
ansi_normal(),
|
|
|
|
|
link);
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2024-02-01 10:43:44 +01:00
|
|
|
static bool privileged_execution(void) {
|
|
|
|
|
if (arg_runtime_scope != RUNTIME_SCOPE_SYSTEM)
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
return !arg_exec_user || STR_IN_SET(arg_exec_user, "root", "0");
|
|
|
|
|
}
|
|
|
|
|
|
2017-12-11 21:21:10 +09:00
|
|
|
static int add_timer_property(const char *name, const char *val) {
|
2018-01-04 11:12:57 +01:00
|
|
|
char *p;
|
2017-12-11 21:21:10 +09:00
|
|
|
|
|
|
|
|
assert(name);
|
|
|
|
|
assert(val);
|
|
|
|
|
|
|
|
|
|
p = strjoin(name, "=", val);
|
|
|
|
|
if (!p)
|
|
|
|
|
return log_oom();
|
|
|
|
|
|
|
|
|
|
if (strv_consume(&arg_timer_property, p) < 0)
|
|
|
|
|
return log_oom();
|
|
|
|
|
|
|
|
|
|
return 0;
|
run: introduce timer support option
Support timer options --on-active=, --on-boot=, --on-startup=,
--on-unit-active=, --on-unit-inactive=, --on-calendar=. Each options
corresponding with OnActiveSec=, OnBootSec=, OnStartupSec=,
OnUnitActiveSec=, OnUnitInactiveSec=, OnCalendar= of timer
respectively. And OnCalendar= and WakeSystem= supported by
--timer-property= option like --property= of systemd-run.
And if --unit= option and timer options are specified the command can
be omitted. In this case, systemd-run assumes the target service is
already loaded. And just try to generate transient timer unit only.
2014-12-09 16:07:16 +09:00
|
|
|
}
|
|
|
|
|
|
2023-12-19 19:10:52 +01:00
|
|
|
static char **make_login_shell_cmdline(const char *shell) {
|
|
|
|
|
_cleanup_free_ char *argv0 = NULL;
|
|
|
|
|
|
|
|
|
|
assert(shell);
|
|
|
|
|
|
|
|
|
|
argv0 = strjoin("-", shell); /* The - is how shells determine if they shall be consider login shells */
|
|
|
|
|
if (!argv0)
|
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
|
|
return strv_new(argv0);
|
|
|
|
|
}
|
|
|
|
|
|
2013-07-01 00:03:57 +02:00
|
|
|
static int parse_argv(int argc, char *argv[]) {
|
|
|
|
|
|
|
|
|
|
enum {
|
|
|
|
|
ARG_VERSION = 0x100,
|
|
|
|
|
ARG_USER,
|
2013-11-06 17:31:20 +01:00
|
|
|
ARG_SYSTEM,
|
2013-07-01 00:03:57 +02:00
|
|
|
ARG_SCOPE,
|
2013-07-01 03:02:42 +02:00
|
|
|
ARG_DESCRIPTION,
|
2013-07-30 02:28:22 +02:00
|
|
|
ARG_SLICE,
|
2020-04-08 14:57:52 +02:00
|
|
|
ARG_SLICE_INHERIT,
|
2023-04-02 23:17:58 +02:00
|
|
|
ARG_EXPAND_ENVIRONMENT,
|
2013-07-30 02:28:22 +02:00
|
|
|
ARG_SEND_SIGHUP,
|
2016-04-17 20:46:00 -04:00
|
|
|
ARG_SERVICE_TYPE,
|
2014-02-05 02:02:00 +01:00
|
|
|
ARG_EXEC_USER,
|
|
|
|
|
ARG_EXEC_GROUP,
|
|
|
|
|
ARG_NICE,
|
run: introduce timer support option
Support timer options --on-active=, --on-boot=, --on-startup=,
--on-unit-active=, --on-unit-inactive=, --on-calendar=. Each options
corresponding with OnActiveSec=, OnBootSec=, OnStartupSec=,
OnUnitActiveSec=, OnUnitInactiveSec=, OnCalendar= of timer
respectively. And OnCalendar= and WakeSystem= supported by
--timer-property= option like --property= of systemd-run.
And if --unit= option and timer options are specified the command can
be omitted. In this case, systemd-run assumes the target service is
already loaded. And just try to generate transient timer unit only.
2014-12-09 16:07:16 +09:00
|
|
|
ARG_ON_ACTIVE,
|
|
|
|
|
ARG_ON_BOOT,
|
|
|
|
|
ARG_ON_STARTUP,
|
|
|
|
|
ARG_ON_UNIT_ACTIVE,
|
|
|
|
|
ARG_ON_UNIT_INACTIVE,
|
|
|
|
|
ARG_ON_CALENDAR,
|
2019-03-14 21:36:47 +01:00
|
|
|
ARG_ON_TIMEZONE_CHANGE,
|
|
|
|
|
ARG_ON_CLOCK_CHANGE,
|
2015-04-28 12:33:19 +02:00
|
|
|
ARG_TIMER_PROPERTY,
|
2017-12-18 23:46:45 +09:00
|
|
|
ARG_PATH_PROPERTY,
|
|
|
|
|
ARG_SOCKET_PROPERTY,
|
2015-04-28 12:33:19 +02:00
|
|
|
ARG_NO_BLOCK,
|
2016-04-17 20:46:00 -04:00
|
|
|
ARG_NO_ASK_PASSWORD,
|
2016-08-17 14:24:17 +02:00
|
|
|
ARG_WAIT,
|
2018-11-22 12:07:25 +01:00
|
|
|
ARG_WORKING_DIRECTORY,
|
2018-11-22 19:24:48 +01:00
|
|
|
ARG_SHELL,
|
2023-12-19 21:39:50 +01:00
|
|
|
ARG_IGNORE_FAILURE,
|
2023-12-20 12:09:27 +01:00
|
|
|
ARG_BACKGROUND,
|
2024-08-12 15:15:15 +02:00
|
|
|
ARG_JSON,
|
2013-07-01 00:03:57 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static const struct option options[] = {
|
2023-04-02 23:17:58 +02:00
|
|
|
{ "help", no_argument, NULL, 'h' },
|
|
|
|
|
{ "version", no_argument, NULL, ARG_VERSION },
|
|
|
|
|
{ "user", no_argument, NULL, ARG_USER },
|
|
|
|
|
{ "system", no_argument, NULL, ARG_SYSTEM },
|
2023-10-26 09:19:04 +02:00
|
|
|
{ "capsule", required_argument, NULL, 'C' },
|
2023-04-02 23:17:58 +02:00
|
|
|
{ "scope", no_argument, NULL, ARG_SCOPE },
|
|
|
|
|
{ "unit", required_argument, NULL, 'u' },
|
|
|
|
|
{ "description", required_argument, NULL, ARG_DESCRIPTION },
|
|
|
|
|
{ "slice", required_argument, NULL, ARG_SLICE },
|
|
|
|
|
{ "slice-inherit", no_argument, NULL, ARG_SLICE_INHERIT },
|
|
|
|
|
{ "remain-after-exit", no_argument, NULL, 'r' },
|
|
|
|
|
{ "expand-environment", required_argument, NULL, ARG_EXPAND_ENVIRONMENT },
|
|
|
|
|
{ "send-sighup", no_argument, NULL, ARG_SEND_SIGHUP },
|
|
|
|
|
{ "host", required_argument, NULL, 'H' },
|
|
|
|
|
{ "machine", required_argument, NULL, 'M' },
|
|
|
|
|
{ "service-type", required_argument, NULL, ARG_SERVICE_TYPE },
|
|
|
|
|
{ "wait", no_argument, NULL, ARG_WAIT },
|
|
|
|
|
{ "uid", required_argument, NULL, ARG_EXEC_USER },
|
|
|
|
|
{ "gid", required_argument, NULL, ARG_EXEC_GROUP },
|
|
|
|
|
{ "nice", required_argument, NULL, ARG_NICE },
|
|
|
|
|
{ "setenv", required_argument, NULL, 'E' },
|
|
|
|
|
{ "property", required_argument, NULL, 'p' },
|
|
|
|
|
{ "tty", no_argument, NULL, 't' }, /* deprecated alias */
|
|
|
|
|
{ "pty", no_argument, NULL, 't' },
|
|
|
|
|
{ "pipe", no_argument, NULL, 'P' },
|
|
|
|
|
{ "quiet", no_argument, NULL, 'q' },
|
|
|
|
|
{ "on-active", required_argument, NULL, ARG_ON_ACTIVE },
|
|
|
|
|
{ "on-boot", required_argument, NULL, ARG_ON_BOOT },
|
|
|
|
|
{ "on-startup", required_argument, NULL, ARG_ON_STARTUP },
|
|
|
|
|
{ "on-unit-active", required_argument, NULL, ARG_ON_UNIT_ACTIVE },
|
|
|
|
|
{ "on-unit-inactive", required_argument, NULL, ARG_ON_UNIT_INACTIVE },
|
|
|
|
|
{ "on-calendar", required_argument, NULL, ARG_ON_CALENDAR },
|
|
|
|
|
{ "on-timezone-change", no_argument, NULL, ARG_ON_TIMEZONE_CHANGE },
|
|
|
|
|
{ "on-clock-change", no_argument, NULL, ARG_ON_CLOCK_CHANGE },
|
|
|
|
|
{ "timer-property", required_argument, NULL, ARG_TIMER_PROPERTY },
|
|
|
|
|
{ "path-property", required_argument, NULL, ARG_PATH_PROPERTY },
|
|
|
|
|
{ "socket-property", required_argument, NULL, ARG_SOCKET_PROPERTY },
|
|
|
|
|
{ "no-block", no_argument, NULL, ARG_NO_BLOCK },
|
|
|
|
|
{ "no-ask-password", no_argument, NULL, ARG_NO_ASK_PASSWORD },
|
|
|
|
|
{ "collect", no_argument, NULL, 'G' },
|
|
|
|
|
{ "working-directory", required_argument, NULL, ARG_WORKING_DIRECTORY },
|
|
|
|
|
{ "same-dir", no_argument, NULL, 'd' },
|
|
|
|
|
{ "shell", no_argument, NULL, 'S' },
|
2023-12-19 21:39:50 +01:00
|
|
|
{ "ignore-failure", no_argument, NULL, ARG_IGNORE_FAILURE },
|
2024-01-19 23:41:24 +01:00
|
|
|
{ "background", required_argument, NULL, ARG_BACKGROUND },
|
2024-08-12 15:15:15 +02:00
|
|
|
{ "json", required_argument, NULL, ARG_JSON },
|
2013-11-06 18:28:39 +01:00
|
|
|
{},
|
2013-07-01 00:03:57 +02:00
|
|
|
};
|
|
|
|
|
|
2017-12-18 23:46:45 +09:00
|
|
|
bool with_trigger = false;
|
2014-02-05 02:02:00 +01:00
|
|
|
int r, c;
|
2013-07-01 00:03:57 +02:00
|
|
|
|
|
|
|
|
assert(argc >= 0);
|
|
|
|
|
assert(argv);
|
|
|
|
|
|
2023-03-21 10:05:33 +09:00
|
|
|
/* Resetting to 0 forces the invocation of an internal initialization routine of getopt_long()
|
|
|
|
|
* that checks for GNU extensions in optstring ('-' or '+' at the beginning). */
|
|
|
|
|
optind = 0;
|
2023-10-26 09:19:04 +02:00
|
|
|
while ((c = getopt_long(argc, argv, "+hrC:H:M:E:p:tPqGdSu:", options, NULL)) >= 0)
|
2013-07-01 00:03:57 +02:00
|
|
|
|
|
|
|
|
switch (c) {
|
|
|
|
|
|
|
|
|
|
case 'h':
|
2018-08-09 10:32:31 +02:00
|
|
|
return help();
|
2013-07-01 00:03:57 +02:00
|
|
|
|
2016-08-06 00:30:12 +02:00
|
|
|
case ARG_VERSION:
|
|
|
|
|
return version();
|
|
|
|
|
|
2015-09-01 16:43:08 +00:00
|
|
|
case ARG_NO_ASK_PASSWORD:
|
|
|
|
|
arg_ask_password = false;
|
|
|
|
|
break;
|
|
|
|
|
|
2013-07-01 00:03:57 +02:00
|
|
|
case ARG_USER:
|
2023-03-10 09:47:10 +01:00
|
|
|
arg_runtime_scope = RUNTIME_SCOPE_USER;
|
2013-07-01 00:03:57 +02:00
|
|
|
break;
|
|
|
|
|
|
2013-11-06 17:31:20 +01:00
|
|
|
case ARG_SYSTEM:
|
2023-03-10 09:47:10 +01:00
|
|
|
arg_runtime_scope = RUNTIME_SCOPE_SYSTEM;
|
2013-11-06 17:31:20 +01:00
|
|
|
break;
|
|
|
|
|
|
2023-10-26 09:19:04 +02:00
|
|
|
case 'C':
|
|
|
|
|
r = capsule_name_is_valid(optarg);
|
|
|
|
|
if (r < 0)
|
|
|
|
|
return log_error_errno(r, "Unable to validate capsule name '%s': %m", optarg);
|
|
|
|
|
if (r == 0)
|
|
|
|
|
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Invalid capsule name: %s", optarg);
|
|
|
|
|
|
|
|
|
|
arg_host = optarg;
|
|
|
|
|
arg_transport = BUS_TRANSPORT_CAPSULE;
|
|
|
|
|
arg_runtime_scope = RUNTIME_SCOPE_USER;
|
|
|
|
|
break;
|
|
|
|
|
|
2013-07-01 00:03:57 +02:00
|
|
|
case ARG_SCOPE:
|
|
|
|
|
arg_scope = true;
|
|
|
|
|
break;
|
|
|
|
|
|
2019-10-23 09:13:15 +02:00
|
|
|
case 'u':
|
2013-07-01 00:03:57 +02:00
|
|
|
arg_unit = optarg;
|
|
|
|
|
break;
|
|
|
|
|
|
2013-07-01 00:40:56 +02:00
|
|
|
case ARG_DESCRIPTION:
|
2023-12-20 12:09:27 +01:00
|
|
|
r = free_and_strdup_warn(&arg_description, optarg);
|
run: fix bad escaping and memory ownership confusion
arg_description was either set to arg_unit (i.e. a const char*), or to
char *description, the result of allocation in run(). But description
was decorated with _cleanup_, so it would be freed when going out of the
function. Nothing bad would happen, because the program would exit after
exiting from run(), but this is just all too messy.
Also, strv_join(" ") + shell_escape() is not a good way to escape command
lines. In particular, one the join has happened, we cannot distinguish
empty arguments, or arguments with whitespace, etc. We have a helper
function to do the escaping properly, so let's use that.
Fixup for 2c29813da3421b77eca5e5cdc3b9a863cad473b9.
2023-11-29 14:13:33 +01:00
|
|
|
if (r < 0)
|
|
|
|
|
return r;
|
2013-07-01 00:40:56 +02:00
|
|
|
break;
|
|
|
|
|
|
2013-07-01 03:02:42 +02:00
|
|
|
case ARG_SLICE:
|
|
|
|
|
arg_slice = optarg;
|
|
|
|
|
break;
|
|
|
|
|
|
2020-04-08 14:57:52 +02:00
|
|
|
case ARG_SLICE_INHERIT:
|
|
|
|
|
arg_slice_inherit = true;
|
|
|
|
|
break;
|
|
|
|
|
|
2023-07-19 22:56:02 +01:00
|
|
|
case ARG_EXPAND_ENVIRONMENT: {
|
|
|
|
|
bool b;
|
|
|
|
|
|
|
|
|
|
r = parse_boolean_argument("--expand-environment=", optarg, &b);
|
2023-04-02 23:17:58 +02:00
|
|
|
if (r < 0)
|
|
|
|
|
return r;
|
2023-07-19 22:56:02 +01:00
|
|
|
|
|
|
|
|
arg_expand_environment = b;
|
|
|
|
|
|
2023-04-02 23:17:58 +02:00
|
|
|
break;
|
2023-07-19 22:56:02 +01:00
|
|
|
}
|
2023-04-02 23:17:58 +02:00
|
|
|
|
2013-07-30 02:28:22 +02:00
|
|
|
case ARG_SEND_SIGHUP:
|
|
|
|
|
arg_send_sighup = true;
|
|
|
|
|
break;
|
|
|
|
|
|
2013-07-26 16:09:25 +02:00
|
|
|
case 'r':
|
|
|
|
|
arg_remain_after_exit = true;
|
|
|
|
|
break;
|
|
|
|
|
|
2013-10-30 16:44:55 +01:00
|
|
|
case 'H':
|
|
|
|
|
arg_transport = BUS_TRANSPORT_REMOTE;
|
|
|
|
|
arg_host = optarg;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case 'M':
|
2014-12-23 23:38:13 +01:00
|
|
|
arg_transport = BUS_TRANSPORT_MACHINE;
|
2013-10-30 16:44:55 +01:00
|
|
|
arg_host = optarg;
|
|
|
|
|
break;
|
|
|
|
|
|
2014-02-05 02:02:00 +01:00
|
|
|
case ARG_SERVICE_TYPE:
|
|
|
|
|
arg_service_type = optarg;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case ARG_EXEC_USER:
|
|
|
|
|
arg_exec_user = optarg;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case ARG_EXEC_GROUP:
|
|
|
|
|
arg_exec_group = optarg;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case ARG_NICE:
|
2016-08-05 11:17:08 +02:00
|
|
|
r = parse_nice(optarg, &arg_nice);
|
|
|
|
|
if (r < 0)
|
|
|
|
|
return log_error_errno(r, "Failed to parse nice value: %s", optarg);
|
2014-02-05 02:02:00 +01:00
|
|
|
|
|
|
|
|
arg_nice_set = true;
|
|
|
|
|
break;
|
|
|
|
|
|
2016-04-20 08:38:01 -04:00
|
|
|
case 'E':
|
2021-08-10 17:25:47 +02:00
|
|
|
r = strv_env_replace_strdup_passthrough(&arg_environment, optarg);
|
|
|
|
|
if (r < 0)
|
|
|
|
|
return log_error_errno(r, "Cannot assign environment variable %s: %m", optarg);
|
2014-02-05 02:02:00 +01:00
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
2014-03-05 03:36:22 +01:00
|
|
|
case 'p':
|
|
|
|
|
if (strv_extend(&arg_property, optarg) < 0)
|
|
|
|
|
return log_oom();
|
|
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
2017-09-08 15:38:40 +02:00
|
|
|
case 't': /* --pty */
|
|
|
|
|
if (IN_SET(arg_stdio, ARG_STDIO_DIRECT, ARG_STDIO_AUTO)) /* if --pipe is already used, upgrade to auto mode */
|
|
|
|
|
arg_stdio = ARG_STDIO_AUTO;
|
|
|
|
|
else
|
|
|
|
|
arg_stdio = ARG_STDIO_PTY;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case 'P': /* --pipe */
|
|
|
|
|
if (IN_SET(arg_stdio, ARG_STDIO_PTY, ARG_STDIO_AUTO)) /* If --pty is already used, upgrade to auto mode */
|
|
|
|
|
arg_stdio = ARG_STDIO_AUTO;
|
|
|
|
|
else
|
|
|
|
|
arg_stdio = ARG_STDIO_DIRECT;
|
2014-12-22 19:45:32 +01:00
|
|
|
break;
|
|
|
|
|
|
2014-12-22 20:39:10 +01:00
|
|
|
case 'q':
|
|
|
|
|
arg_quiet = true;
|
|
|
|
|
break;
|
|
|
|
|
|
run: introduce timer support option
Support timer options --on-active=, --on-boot=, --on-startup=,
--on-unit-active=, --on-unit-inactive=, --on-calendar=. Each options
corresponding with OnActiveSec=, OnBootSec=, OnStartupSec=,
OnUnitActiveSec=, OnUnitInactiveSec=, OnCalendar= of timer
respectively. And OnCalendar= and WakeSystem= supported by
--timer-property= option like --property= of systemd-run.
And if --unit= option and timer options are specified the command can
be omitted. In this case, systemd-run assumes the target service is
already loaded. And just try to generate transient timer unit only.
2014-12-09 16:07:16 +09:00
|
|
|
case ARG_ON_ACTIVE:
|
2017-12-11 21:21:10 +09:00
|
|
|
r = add_timer_property("OnActiveSec", optarg);
|
|
|
|
|
if (r < 0)
|
run: introduce timer support option
Support timer options --on-active=, --on-boot=, --on-startup=,
--on-unit-active=, --on-unit-inactive=, --on-calendar=. Each options
corresponding with OnActiveSec=, OnBootSec=, OnStartupSec=,
OnUnitActiveSec=, OnUnitInactiveSec=, OnCalendar= of timer
respectively. And OnCalendar= and WakeSystem= supported by
--timer-property= option like --property= of systemd-run.
And if --unit= option and timer options are specified the command can
be omitted. In this case, systemd-run assumes the target service is
already loaded. And just try to generate transient timer unit only.
2014-12-09 16:07:16 +09:00
|
|
|
return r;
|
|
|
|
|
|
2019-03-14 19:55:29 +01:00
|
|
|
arg_with_timer = true;
|
run: introduce timer support option
Support timer options --on-active=, --on-boot=, --on-startup=,
--on-unit-active=, --on-unit-inactive=, --on-calendar=. Each options
corresponding with OnActiveSec=, OnBootSec=, OnStartupSec=,
OnUnitActiveSec=, OnUnitInactiveSec=, OnCalendar= of timer
respectively. And OnCalendar= and WakeSystem= supported by
--timer-property= option like --property= of systemd-run.
And if --unit= option and timer options are specified the command can
be omitted. In this case, systemd-run assumes the target service is
already loaded. And just try to generate transient timer unit only.
2014-12-09 16:07:16 +09:00
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case ARG_ON_BOOT:
|
2017-12-11 21:21:10 +09:00
|
|
|
r = add_timer_property("OnBootSec", optarg);
|
|
|
|
|
if (r < 0)
|
run: introduce timer support option
Support timer options --on-active=, --on-boot=, --on-startup=,
--on-unit-active=, --on-unit-inactive=, --on-calendar=. Each options
corresponding with OnActiveSec=, OnBootSec=, OnStartupSec=,
OnUnitActiveSec=, OnUnitInactiveSec=, OnCalendar= of timer
respectively. And OnCalendar= and WakeSystem= supported by
--timer-property= option like --property= of systemd-run.
And if --unit= option and timer options are specified the command can
be omitted. In this case, systemd-run assumes the target service is
already loaded. And just try to generate transient timer unit only.
2014-12-09 16:07:16 +09:00
|
|
|
return r;
|
|
|
|
|
|
2019-03-14 19:55:29 +01:00
|
|
|
arg_with_timer = true;
|
run: introduce timer support option
Support timer options --on-active=, --on-boot=, --on-startup=,
--on-unit-active=, --on-unit-inactive=, --on-calendar=. Each options
corresponding with OnActiveSec=, OnBootSec=, OnStartupSec=,
OnUnitActiveSec=, OnUnitInactiveSec=, OnCalendar= of timer
respectively. And OnCalendar= and WakeSystem= supported by
--timer-property= option like --property= of systemd-run.
And if --unit= option and timer options are specified the command can
be omitted. In this case, systemd-run assumes the target service is
already loaded. And just try to generate transient timer unit only.
2014-12-09 16:07:16 +09:00
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case ARG_ON_STARTUP:
|
2017-12-11 21:21:10 +09:00
|
|
|
r = add_timer_property("OnStartupSec", optarg);
|
|
|
|
|
if (r < 0)
|
run: introduce timer support option
Support timer options --on-active=, --on-boot=, --on-startup=,
--on-unit-active=, --on-unit-inactive=, --on-calendar=. Each options
corresponding with OnActiveSec=, OnBootSec=, OnStartupSec=,
OnUnitActiveSec=, OnUnitInactiveSec=, OnCalendar= of timer
respectively. And OnCalendar= and WakeSystem= supported by
--timer-property= option like --property= of systemd-run.
And if --unit= option and timer options are specified the command can
be omitted. In this case, systemd-run assumes the target service is
already loaded. And just try to generate transient timer unit only.
2014-12-09 16:07:16 +09:00
|
|
|
return r;
|
|
|
|
|
|
2019-03-14 19:55:29 +01:00
|
|
|
arg_with_timer = true;
|
run: introduce timer support option
Support timer options --on-active=, --on-boot=, --on-startup=,
--on-unit-active=, --on-unit-inactive=, --on-calendar=. Each options
corresponding with OnActiveSec=, OnBootSec=, OnStartupSec=,
OnUnitActiveSec=, OnUnitInactiveSec=, OnCalendar= of timer
respectively. And OnCalendar= and WakeSystem= supported by
--timer-property= option like --property= of systemd-run.
And if --unit= option and timer options are specified the command can
be omitted. In this case, systemd-run assumes the target service is
already loaded. And just try to generate transient timer unit only.
2014-12-09 16:07:16 +09:00
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case ARG_ON_UNIT_ACTIVE:
|
2017-12-11 21:21:10 +09:00
|
|
|
r = add_timer_property("OnUnitActiveSec", optarg);
|
|
|
|
|
if (r < 0)
|
run: introduce timer support option
Support timer options --on-active=, --on-boot=, --on-startup=,
--on-unit-active=, --on-unit-inactive=, --on-calendar=. Each options
corresponding with OnActiveSec=, OnBootSec=, OnStartupSec=,
OnUnitActiveSec=, OnUnitInactiveSec=, OnCalendar= of timer
respectively. And OnCalendar= and WakeSystem= supported by
--timer-property= option like --property= of systemd-run.
And if --unit= option and timer options are specified the command can
be omitted. In this case, systemd-run assumes the target service is
already loaded. And just try to generate transient timer unit only.
2014-12-09 16:07:16 +09:00
|
|
|
return r;
|
|
|
|
|
|
2019-03-14 19:55:29 +01:00
|
|
|
arg_with_timer = true;
|
run: introduce timer support option
Support timer options --on-active=, --on-boot=, --on-startup=,
--on-unit-active=, --on-unit-inactive=, --on-calendar=. Each options
corresponding with OnActiveSec=, OnBootSec=, OnStartupSec=,
OnUnitActiveSec=, OnUnitInactiveSec=, OnCalendar= of timer
respectively. And OnCalendar= and WakeSystem= supported by
--timer-property= option like --property= of systemd-run.
And if --unit= option and timer options are specified the command can
be omitted. In this case, systemd-run assumes the target service is
already loaded. And just try to generate transient timer unit only.
2014-12-09 16:07:16 +09:00
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case ARG_ON_UNIT_INACTIVE:
|
2017-12-11 21:21:10 +09:00
|
|
|
r = add_timer_property("OnUnitInactiveSec", optarg);
|
|
|
|
|
if (r < 0)
|
run: introduce timer support option
Support timer options --on-active=, --on-boot=, --on-startup=,
--on-unit-active=, --on-unit-inactive=, --on-calendar=. Each options
corresponding with OnActiveSec=, OnBootSec=, OnStartupSec=,
OnUnitActiveSec=, OnUnitInactiveSec=, OnCalendar= of timer
respectively. And OnCalendar= and WakeSystem= supported by
--timer-property= option like --property= of systemd-run.
And if --unit= option and timer options are specified the command can
be omitted. In this case, systemd-run assumes the target service is
already loaded. And just try to generate transient timer unit only.
2014-12-09 16:07:16 +09:00
|
|
|
return r;
|
|
|
|
|
|
2019-03-14 19:55:29 +01:00
|
|
|
arg_with_timer = true;
|
run: introduce timer support option
Support timer options --on-active=, --on-boot=, --on-startup=,
--on-unit-active=, --on-unit-inactive=, --on-calendar=. Each options
corresponding with OnActiveSec=, OnBootSec=, OnStartupSec=,
OnUnitActiveSec=, OnUnitInactiveSec=, OnCalendar= of timer
respectively. And OnCalendar= and WakeSystem= supported by
--timer-property= option like --property= of systemd-run.
And if --unit= option and timer options are specified the command can
be omitted. In this case, systemd-run assumes the target service is
already loaded. And just try to generate transient timer unit only.
2014-12-09 16:07:16 +09:00
|
|
|
break;
|
|
|
|
|
|
2019-04-12 20:57:51 +02:00
|
|
|
case ARG_ON_CALENDAR: {
|
|
|
|
|
_cleanup_(calendar_spec_freep) CalendarSpec *cs = NULL;
|
|
|
|
|
|
|
|
|
|
r = calendar_spec_from_string(optarg, &cs);
|
|
|
|
|
if (r < 0)
|
2019-04-25 13:22:55 +02:00
|
|
|
return log_error_errno(r, "Failed to parse calendar event specification: %m");
|
|
|
|
|
|
2019-07-16 12:22:37 +02:00
|
|
|
/* Let's make sure the given calendar event is not in the past */
|
2019-04-25 13:22:55 +02:00
|
|
|
r = calendar_spec_next_usec(cs, now(CLOCK_REALTIME), NULL);
|
|
|
|
|
if (r == -ENOENT)
|
2019-04-26 08:46:01 +02:00
|
|
|
/* The calendar event is in the past — let's warn about this, but install it
|
|
|
|
|
* anyway as is. The service manager will trigger the service right away.
|
|
|
|
|
* Moreover, the server side might have a different clock or timezone than we
|
|
|
|
|
* do, hence it should decide when or whether to run something. */
|
2019-04-25 13:22:55 +02:00
|
|
|
log_warning("Specified calendar expression is in the past, proceeding anyway.");
|
|
|
|
|
else if (r < 0)
|
|
|
|
|
return log_error_errno(r, "Failed to calculate next time calendar expression elapses: %m");
|
2019-04-12 20:57:51 +02:00
|
|
|
|
2017-12-11 21:21:10 +09:00
|
|
|
r = add_timer_property("OnCalendar", optarg);
|
|
|
|
|
if (r < 0)
|
2019-03-14 21:36:47 +01:00
|
|
|
return r;
|
|
|
|
|
|
|
|
|
|
arg_with_timer = true;
|
|
|
|
|
break;
|
2019-04-12 20:57:51 +02:00
|
|
|
}
|
2019-03-14 21:36:47 +01:00
|
|
|
|
|
|
|
|
case ARG_ON_TIMEZONE_CHANGE:
|
|
|
|
|
r = add_timer_property("OnTimezoneChange", "yes");
|
|
|
|
|
if (r < 0)
|
|
|
|
|
return r;
|
|
|
|
|
|
|
|
|
|
arg_with_timer = true;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case ARG_ON_CLOCK_CHANGE:
|
|
|
|
|
r = add_timer_property("OnClockChange", "yes");
|
|
|
|
|
if (r < 0)
|
run: introduce timer support option
Support timer options --on-active=, --on-boot=, --on-startup=,
--on-unit-active=, --on-unit-inactive=, --on-calendar=. Each options
corresponding with OnActiveSec=, OnBootSec=, OnStartupSec=,
OnUnitActiveSec=, OnUnitInactiveSec=, OnCalendar= of timer
respectively. And OnCalendar= and WakeSystem= supported by
--timer-property= option like --property= of systemd-run.
And if --unit= option and timer options are specified the command can
be omitted. In this case, systemd-run assumes the target service is
already loaded. And just try to generate transient timer unit only.
2014-12-09 16:07:16 +09:00
|
|
|
return r;
|
2015-10-08 15:01:42 +02:00
|
|
|
|
2019-03-14 19:55:29 +01:00
|
|
|
arg_with_timer = true;
|
run: introduce timer support option
Support timer options --on-active=, --on-boot=, --on-startup=,
--on-unit-active=, --on-unit-inactive=, --on-calendar=. Each options
corresponding with OnActiveSec=, OnBootSec=, OnStartupSec=,
OnUnitActiveSec=, OnUnitInactiveSec=, OnCalendar= of timer
respectively. And OnCalendar= and WakeSystem= supported by
--timer-property= option like --property= of systemd-run.
And if --unit= option and timer options are specified the command can
be omitted. In this case, systemd-run assumes the target service is
already loaded. And just try to generate transient timer unit only.
2014-12-09 16:07:16 +09:00
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case ARG_TIMER_PROPERTY:
|
|
|
|
|
|
|
|
|
|
if (strv_extend(&arg_timer_property, optarg) < 0)
|
|
|
|
|
return log_oom();
|
|
|
|
|
|
2019-03-14 19:55:29 +01:00
|
|
|
arg_with_timer = arg_with_timer ||
|
2018-11-23 16:30:23 +01:00
|
|
|
STARTSWITH_SET(optarg,
|
|
|
|
|
"OnActiveSec=",
|
|
|
|
|
"OnBootSec=",
|
|
|
|
|
"OnStartupSec=",
|
|
|
|
|
"OnUnitActiveSec=",
|
|
|
|
|
"OnUnitInactiveSec=",
|
|
|
|
|
"OnCalendar=");
|
run: introduce timer support option
Support timer options --on-active=, --on-boot=, --on-startup=,
--on-unit-active=, --on-unit-inactive=, --on-calendar=. Each options
corresponding with OnActiveSec=, OnBootSec=, OnStartupSec=,
OnUnitActiveSec=, OnUnitInactiveSec=, OnCalendar= of timer
respectively. And OnCalendar= and WakeSystem= supported by
--timer-property= option like --property= of systemd-run.
And if --unit= option and timer options are specified the command can
be omitted. In this case, systemd-run assumes the target service is
already loaded. And just try to generate transient timer unit only.
2014-12-09 16:07:16 +09:00
|
|
|
break;
|
|
|
|
|
|
2017-12-18 23:46:45 +09:00
|
|
|
case ARG_PATH_PROPERTY:
|
|
|
|
|
|
|
|
|
|
if (strv_extend(&arg_path_property, optarg) < 0)
|
|
|
|
|
return log_oom();
|
|
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case ARG_SOCKET_PROPERTY:
|
|
|
|
|
|
|
|
|
|
if (strv_extend(&arg_socket_property, optarg) < 0)
|
|
|
|
|
return log_oom();
|
|
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
2015-04-28 12:33:19 +02:00
|
|
|
case ARG_NO_BLOCK:
|
|
|
|
|
arg_no_block = true;
|
|
|
|
|
break;
|
|
|
|
|
|
2016-08-17 14:24:17 +02:00
|
|
|
case ARG_WAIT:
|
|
|
|
|
arg_wait = true;
|
|
|
|
|
break;
|
|
|
|
|
|
2018-11-22 12:07:25 +01:00
|
|
|
case ARG_WORKING_DIRECTORY:
|
2021-02-14 11:39:48 +01:00
|
|
|
r = parse_path_argument(optarg, true, &arg_working_directory);
|
2018-11-22 12:07:25 +01:00
|
|
|
if (r < 0)
|
|
|
|
|
return r;
|
|
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case 'd': {
|
|
|
|
|
_cleanup_free_ char *p = NULL;
|
|
|
|
|
|
|
|
|
|
r = safe_getcwd(&p);
|
|
|
|
|
if (r < 0)
|
|
|
|
|
return log_error_errno(r, "Failed to get current working directory: %m");
|
|
|
|
|
|
|
|
|
|
if (empty_or_root(p))
|
|
|
|
|
arg_working_directory = mfree(arg_working_directory);
|
|
|
|
|
else
|
|
|
|
|
free_and_replace(arg_working_directory, p);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
2017-11-13 17:17:53 +01:00
|
|
|
case 'G':
|
|
|
|
|
arg_aggressive_gc = true;
|
|
|
|
|
break;
|
|
|
|
|
|
2018-11-22 19:24:48 +01:00
|
|
|
case 'S':
|
|
|
|
|
arg_shell = true;
|
|
|
|
|
break;
|
|
|
|
|
|
2023-12-19 21:39:50 +01:00
|
|
|
case ARG_IGNORE_FAILURE:
|
|
|
|
|
arg_ignore_failure = true;
|
|
|
|
|
break;
|
|
|
|
|
|
2023-12-20 12:09:27 +01:00
|
|
|
case ARG_BACKGROUND:
|
|
|
|
|
r = free_and_strdup_warn(&arg_background, optarg);
|
|
|
|
|
if (r < 0)
|
|
|
|
|
return r;
|
|
|
|
|
break;
|
|
|
|
|
|
2024-08-12 15:15:15 +02:00
|
|
|
case ARG_JSON:
|
|
|
|
|
r = parse_json_argument(optarg, &arg_json_format_flags);
|
|
|
|
|
if (r <= 0)
|
|
|
|
|
return r;
|
|
|
|
|
break;
|
|
|
|
|
|
2013-07-01 00:03:57 +02:00
|
|
|
case '?':
|
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
|
|
default:
|
Drop the text argument from assert_not_reached()
In general we almost never hit those asserts in production code, so users see
them very rarely, if ever. But either way, we just need something that users
can pass to the developers.
We have quite a few of those asserts, and some have fairly nice messages, but
many are like "WTF?" or "???" or "unexpected something". The error that is
printed includes the file location, and function name. In almost all functions
there's at most one assert, so the function name alone is enough to identify
the failure for a developer. So we don't get much extra from the message, and
we might just as well drop them.
Dropping them makes our code a tiny bit smaller, and most importantly, improves
development experience by making it easy to insert such an assert in the code
without thinking how to phrase the argument.
2021-07-27 12:27:28 +02:00
|
|
|
assert_not_reached();
|
2013-07-01 00:03:57 +02:00
|
|
|
}
|
|
|
|
|
|
2021-08-30 13:21:55 +02:00
|
|
|
/* If we are talking to the per-user instance PolicyKit isn't going to help */
|
2023-03-10 09:47:10 +01:00
|
|
|
if (arg_runtime_scope == RUNTIME_SCOPE_USER)
|
2021-08-30 13:21:55 +02:00
|
|
|
arg_ask_password = false;
|
|
|
|
|
|
2019-03-14 19:55:29 +01:00
|
|
|
with_trigger = !!arg_path_property || !!arg_socket_property || arg_with_timer;
|
2017-12-18 23:46:45 +09:00
|
|
|
|
|
|
|
|
/* currently, only single trigger (path, socket, timer) unit can be created simultaneously */
|
2019-03-14 19:55:29 +01:00
|
|
|
if ((int) !!arg_path_property + (int) !!arg_socket_property + (int) arg_with_timer > 1)
|
2018-11-20 23:40:44 +01:00
|
|
|
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
|
|
|
|
|
"Only single trigger (path, socket, timer) unit can be created.");
|
2017-09-08 15:38:40 +02:00
|
|
|
|
2018-11-22 19:24:48 +01:00
|
|
|
if (arg_shell) {
|
|
|
|
|
/* If --shell is imply --pty --pipe --same-dir --service-type=exec --wait --collect, unless otherwise
|
|
|
|
|
* specified. */
|
|
|
|
|
|
|
|
|
|
if (!arg_scope) {
|
|
|
|
|
if (arg_stdio == ARG_STDIO_NONE)
|
|
|
|
|
arg_stdio = ARG_STDIO_AUTO;
|
|
|
|
|
|
|
|
|
|
if (!arg_working_directory) {
|
|
|
|
|
r = safe_getcwd(&arg_working_directory);
|
|
|
|
|
if (r < 0)
|
|
|
|
|
return log_error_errno(r, "Failed to get current working directory: %m");
|
|
|
|
|
}
|
|
|
|
|
|
2023-12-19 19:10:36 +01:00
|
|
|
if (!arg_service_type)
|
|
|
|
|
arg_service_type = "exec";
|
2018-11-22 19:24:48 +01:00
|
|
|
|
|
|
|
|
arg_wait = true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
arg_aggressive_gc = true;
|
|
|
|
|
}
|
|
|
|
|
|
2020-10-09 15:06:34 +02:00
|
|
|
if (arg_stdio == ARG_STDIO_AUTO)
|
2017-09-08 15:38:40 +02:00
|
|
|
/* If we both --pty and --pipe are specified we'll automatically pick --pty if we are connected fully
|
|
|
|
|
* to a TTY and pick direct fd passing otherwise. This way, we automatically adapt to usage in a shell
|
|
|
|
|
* pipeline, but we are neatly interactive with tty-level isolation otherwise. */
|
2024-10-24 23:12:31 +02:00
|
|
|
arg_stdio = isatty_safe(STDIN_FILENO) && isatty_safe(STDOUT_FILENO) && isatty_safe(STDERR_FILENO) ?
|
2017-09-08 15:38:40 +02:00
|
|
|
ARG_STDIO_PTY :
|
|
|
|
|
ARG_STDIO_DIRECT;
|
|
|
|
|
|
2018-11-22 19:24:48 +01:00
|
|
|
if (argc > optind) {
|
|
|
|
|
char **l;
|
|
|
|
|
|
|
|
|
|
if (arg_shell)
|
|
|
|
|
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "If --shell is used, no command line is expected.");
|
|
|
|
|
|
|
|
|
|
l = strv_copy(argv + optind);
|
|
|
|
|
if (!l)
|
|
|
|
|
return log_oom();
|
|
|
|
|
|
|
|
|
|
strv_free_and_replace(arg_cmdline, l);
|
|
|
|
|
|
|
|
|
|
} else if (arg_shell) {
|
|
|
|
|
_cleanup_free_ char *s = NULL;
|
|
|
|
|
char **l;
|
|
|
|
|
|
|
|
|
|
r = get_shell(&s);
|
|
|
|
|
if (r < 0)
|
|
|
|
|
return log_error_errno(r, "Failed to determine shell: %m");
|
|
|
|
|
|
|
|
|
|
l = strv_new(s);
|
|
|
|
|
if (!l)
|
|
|
|
|
return log_oom();
|
|
|
|
|
|
|
|
|
|
strv_free_and_replace(arg_cmdline, l);
|
|
|
|
|
|
|
|
|
|
} else if (!arg_unit || !with_trigger)
|
|
|
|
|
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Command line to execute required.");
|
2013-07-01 00:03:57 +02:00
|
|
|
|
2023-03-10 09:47:10 +01:00
|
|
|
if (arg_runtime_scope == RUNTIME_SCOPE_USER && arg_transport == BUS_TRANSPORT_REMOTE)
|
2018-11-20 23:40:44 +01:00
|
|
|
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
|
2021-05-13 01:17:51 -07:00
|
|
|
"Execution in user context is not supported on remote systems.");
|
2013-10-30 16:44:55 +01:00
|
|
|
|
2021-05-13 01:17:51 -07:00
|
|
|
if (arg_scope && arg_transport == BUS_TRANSPORT_REMOTE)
|
2018-11-20 23:40:44 +01:00
|
|
|
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
|
2021-05-13 01:17:51 -07:00
|
|
|
"Scope execution is not supported on remote systems.");
|
2013-10-30 16:44:55 +01:00
|
|
|
|
2018-11-20 23:40:44 +01:00
|
|
|
if (arg_scope && (arg_remain_after_exit || arg_service_type))
|
|
|
|
|
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
|
|
|
|
|
"--remain-after-exit and --service-type= are not supported in --scope mode.");
|
2014-02-05 02:02:00 +01:00
|
|
|
|
2018-11-20 23:40:44 +01:00
|
|
|
if (arg_stdio != ARG_STDIO_NONE && (with_trigger || arg_scope))
|
|
|
|
|
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
|
|
|
|
|
"--pty/--pipe is not compatible in timer or --scope mode.");
|
2014-12-22 19:45:32 +01:00
|
|
|
|
2018-11-20 23:40:44 +01:00
|
|
|
if (arg_stdio != ARG_STDIO_NONE && arg_transport == BUS_TRANSPORT_REMOTE)
|
|
|
|
|
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
|
|
|
|
|
"--pty/--pipe is only supported when connecting to the local system or containers.");
|
2015-10-08 15:01:42 +02:00
|
|
|
|
2018-11-20 23:40:44 +01:00
|
|
|
if (arg_stdio != ARG_STDIO_NONE && arg_no_block)
|
|
|
|
|
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
|
|
|
|
|
"--pty/--pipe is not compatible with --no-block.");
|
2016-12-24 00:30:49 +01:00
|
|
|
|
2018-11-20 23:40:44 +01:00
|
|
|
if (arg_scope && with_trigger)
|
|
|
|
|
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
|
|
|
|
|
"Path, socket or timer options are not supported in --scope mode.");
|
run: introduce timer support option
Support timer options --on-active=, --on-boot=, --on-startup=,
--on-unit-active=, --on-unit-inactive=, --on-calendar=. Each options
corresponding with OnActiveSec=, OnBootSec=, OnStartupSec=,
OnUnitActiveSec=, OnUnitInactiveSec=, OnCalendar= of timer
respectively. And OnCalendar= and WakeSystem= supported by
--timer-property= option like --property= of systemd-run.
And if --unit= option and timer options are specified the command can
be omitted. In this case, systemd-run assumes the target service is
already loaded. And just try to generate transient timer unit only.
2014-12-09 16:07:16 +09:00
|
|
|
|
2019-03-14 19:55:29 +01:00
|
|
|
if (arg_timer_property && !arg_with_timer)
|
2018-11-20 23:40:44 +01:00
|
|
|
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
|
|
|
|
|
"--timer-property= has no effect without any other timer options.");
|
run: introduce timer support option
Support timer options --on-active=, --on-boot=, --on-startup=,
--on-unit-active=, --on-unit-inactive=, --on-calendar=. Each options
corresponding with OnActiveSec=, OnBootSec=, OnStartupSec=,
OnUnitActiveSec=, OnUnitInactiveSec=, OnCalendar= of timer
respectively. And OnCalendar= and WakeSystem= supported by
--timer-property= option like --property= of systemd-run.
And if --unit= option and timer options are specified the command can
be omitted. In this case, systemd-run assumes the target service is
already loaded. And just try to generate transient timer unit only.
2014-12-09 16:07:16 +09:00
|
|
|
|
2016-08-17 14:24:17 +02:00
|
|
|
if (arg_wait) {
|
2018-11-20 23:40:44 +01:00
|
|
|
if (arg_no_block)
|
|
|
|
|
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
|
|
|
|
|
"--wait may not be combined with --no-block.");
|
2016-08-17 14:24:17 +02:00
|
|
|
|
2018-11-20 23:40:44 +01:00
|
|
|
if (with_trigger)
|
|
|
|
|
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
|
|
|
|
|
"--wait may not be combined with path, socket or timer operations.");
|
2016-08-17 14:24:17 +02:00
|
|
|
|
2018-11-20 23:40:44 +01:00
|
|
|
if (arg_scope)
|
|
|
|
|
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
|
|
|
|
|
"--wait may not be combined with --scope.");
|
2016-08-17 14:24:17 +02:00
|
|
|
}
|
|
|
|
|
|
2013-07-01 00:03:57 +02:00
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
2023-12-19 19:10:52 +01:00
|
|
|
static int parse_argv_sudo_mode(int argc, char *argv[]) {
|
|
|
|
|
|
|
|
|
|
enum {
|
|
|
|
|
ARG_NO_ASK_PASSWORD = 0x100,
|
|
|
|
|
ARG_HOST,
|
|
|
|
|
ARG_MACHINE,
|
|
|
|
|
ARG_UNIT,
|
|
|
|
|
ARG_PROPERTY,
|
|
|
|
|
ARG_DESCRIPTION,
|
|
|
|
|
ARG_SLICE,
|
|
|
|
|
ARG_SLICE_INHERIT,
|
|
|
|
|
ARG_NICE,
|
|
|
|
|
ARG_SETENV,
|
2023-12-20 12:09:27 +01:00
|
|
|
ARG_BACKGROUND,
|
2024-10-24 23:27:59 +02:00
|
|
|
ARG_PTY,
|
|
|
|
|
ARG_PIPE,
|
2023-12-19 19:10:52 +01:00
|
|
|
};
|
|
|
|
|
|
2024-03-19 11:14:55 +01:00
|
|
|
/* If invoked as "run0" binary, let's expose a more sudo-like interface. We add various extensions
|
2023-12-19 19:10:52 +01:00
|
|
|
* though (but limit the extension to long options). */
|
|
|
|
|
|
|
|
|
|
static const struct option options[] = {
|
|
|
|
|
{ "help", no_argument, NULL, 'h' },
|
|
|
|
|
{ "version", no_argument, NULL, 'V' },
|
|
|
|
|
{ "no-ask-password", no_argument, NULL, ARG_NO_ASK_PASSWORD },
|
|
|
|
|
{ "machine", required_argument, NULL, ARG_MACHINE },
|
|
|
|
|
{ "unit", required_argument, NULL, ARG_UNIT },
|
|
|
|
|
{ "property", required_argument, NULL, ARG_PROPERTY },
|
|
|
|
|
{ "description", required_argument, NULL, ARG_DESCRIPTION },
|
|
|
|
|
{ "slice", required_argument, NULL, ARG_SLICE },
|
|
|
|
|
{ "slice-inherit", no_argument, NULL, ARG_SLICE_INHERIT },
|
|
|
|
|
{ "user", required_argument, NULL, 'u' },
|
|
|
|
|
{ "group", required_argument, NULL, 'g' },
|
|
|
|
|
{ "nice", required_argument, NULL, ARG_NICE },
|
|
|
|
|
{ "chdir", required_argument, NULL, 'D' },
|
|
|
|
|
{ "setenv", required_argument, NULL, ARG_SETENV },
|
2023-12-20 12:09:27 +01:00
|
|
|
{ "background", required_argument, NULL, ARG_BACKGROUND },
|
2024-10-24 23:27:59 +02:00
|
|
|
{ "pty", no_argument, NULL, ARG_PTY },
|
|
|
|
|
{ "pipe", no_argument, NULL, ARG_PIPE },
|
2023-12-19 19:10:52 +01:00
|
|
|
{},
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
int r, c;
|
|
|
|
|
|
|
|
|
|
assert(argc >= 0);
|
|
|
|
|
assert(argv);
|
|
|
|
|
|
|
|
|
|
/* Resetting to 0 forces the invocation of an internal initialization routine of getopt_long()
|
|
|
|
|
* that checks for GNU extensions in optstring ('-' or '+' at the beginning). */
|
|
|
|
|
optind = 0;
|
|
|
|
|
while ((c = getopt_long(argc, argv, "+hVu:g:D:", options, NULL)) >= 0)
|
|
|
|
|
|
|
|
|
|
switch (c) {
|
|
|
|
|
|
|
|
|
|
case 'h':
|
|
|
|
|
return help_sudo_mode();
|
|
|
|
|
|
|
|
|
|
case 'V':
|
|
|
|
|
return version();
|
|
|
|
|
|
|
|
|
|
case ARG_NO_ASK_PASSWORD:
|
|
|
|
|
arg_ask_password = false;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case ARG_MACHINE:
|
|
|
|
|
arg_transport = BUS_TRANSPORT_MACHINE;
|
|
|
|
|
arg_host = optarg;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case ARG_UNIT:
|
|
|
|
|
arg_unit = optarg;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case ARG_PROPERTY:
|
|
|
|
|
if (strv_extend(&arg_property, optarg) < 0)
|
|
|
|
|
return log_oom();
|
|
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case ARG_DESCRIPTION:
|
|
|
|
|
r = free_and_strdup_warn(&arg_description, optarg);
|
|
|
|
|
if (r < 0)
|
|
|
|
|
return r;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case ARG_SLICE:
|
|
|
|
|
arg_slice = optarg;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case ARG_SLICE_INHERIT:
|
|
|
|
|
arg_slice_inherit = true;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case 'u':
|
|
|
|
|
arg_exec_user = optarg;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case 'g':
|
|
|
|
|
arg_exec_group = optarg;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case ARG_NICE:
|
|
|
|
|
r = parse_nice(optarg, &arg_nice);
|
|
|
|
|
if (r < 0)
|
|
|
|
|
return log_error_errno(r, "Failed to parse nice value: %s", optarg);
|
|
|
|
|
|
|
|
|
|
arg_nice_set = true;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case 'D':
|
2024-10-15 00:57:52 -04:00
|
|
|
/* Root will be manually suppressed later. */
|
|
|
|
|
r = parse_path_argument(optarg, /* suppress_root= */ false, &arg_working_directory);
|
2023-12-19 19:10:52 +01:00
|
|
|
if (r < 0)
|
|
|
|
|
return r;
|
|
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case ARG_SETENV:
|
|
|
|
|
r = strv_env_replace_strdup_passthrough(&arg_environment, optarg);
|
|
|
|
|
if (r < 0)
|
|
|
|
|
return log_error_errno(r, "Cannot assign environment variable %s: %m", optarg);
|
|
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
2023-12-20 12:09:27 +01:00
|
|
|
case ARG_BACKGROUND:
|
|
|
|
|
r = free_and_strdup_warn(&arg_background, optarg);
|
|
|
|
|
if (r < 0)
|
|
|
|
|
return r;
|
|
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
2024-10-24 23:27:59 +02:00
|
|
|
case ARG_PTY:
|
|
|
|
|
if (IN_SET(arg_stdio, ARG_STDIO_DIRECT, ARG_STDIO_AUTO)) /* if --pipe is already used, upgrade to auto mode */
|
|
|
|
|
arg_stdio = ARG_STDIO_AUTO;
|
|
|
|
|
else
|
|
|
|
|
arg_stdio = ARG_STDIO_PTY;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case ARG_PIPE:
|
|
|
|
|
if (IN_SET(arg_stdio, ARG_STDIO_PTY, ARG_STDIO_AUTO)) /* If --pty is already used, upgrade to auto mode */
|
|
|
|
|
arg_stdio = ARG_STDIO_AUTO;
|
|
|
|
|
else
|
|
|
|
|
arg_stdio = ARG_STDIO_DIRECT;
|
|
|
|
|
break;
|
|
|
|
|
|
2023-12-19 19:10:52 +01:00
|
|
|
case '?':
|
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
assert_not_reached();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!arg_working_directory) {
|
|
|
|
|
if (arg_exec_user) {
|
|
|
|
|
/* When switching to a specific user, also switch to its home directory. */
|
|
|
|
|
arg_working_directory = strdup("~");
|
|
|
|
|
if (!arg_working_directory)
|
|
|
|
|
return log_oom();
|
|
|
|
|
} else {
|
|
|
|
|
/* When switching to root without this being specified, then stay in the current directory */
|
|
|
|
|
r = safe_getcwd(&arg_working_directory);
|
|
|
|
|
if (r < 0)
|
|
|
|
|
return log_error_errno(r, "Failed to get current working directory: %m");
|
|
|
|
|
}
|
2024-10-15 00:57:52 -04:00
|
|
|
} else {
|
|
|
|
|
/* Root was not suppressed earlier, to allow the above check to work properly. */
|
|
|
|
|
if (empty_or_root(arg_working_directory))
|
|
|
|
|
arg_working_directory = mfree(arg_working_directory);
|
2023-12-19 19:10:52 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
arg_service_type = "exec";
|
|
|
|
|
arg_quiet = true;
|
|
|
|
|
arg_wait = true;
|
|
|
|
|
arg_aggressive_gc = true;
|
|
|
|
|
|
2024-10-24 23:27:59 +02:00
|
|
|
if (IN_SET(arg_stdio, ARG_STDIO_NONE, ARG_STDIO_AUTO))
|
|
|
|
|
arg_stdio = isatty_safe(STDIN_FILENO) && isatty_safe(STDOUT_FILENO) && isatty_safe(STDERR_FILENO) ? ARG_STDIO_PTY : ARG_STDIO_DIRECT;
|
|
|
|
|
|
2023-12-19 19:10:52 +01:00
|
|
|
arg_expand_environment = false;
|
|
|
|
|
arg_send_sighup = true;
|
|
|
|
|
|
|
|
|
|
_cleanup_strv_free_ char **l = NULL;
|
|
|
|
|
if (argc > optind)
|
|
|
|
|
l = strv_copy(argv + optind);
|
|
|
|
|
else {
|
|
|
|
|
const char *e;
|
|
|
|
|
|
|
|
|
|
e = strv_env_get(arg_environment, "SHELL");
|
|
|
|
|
if (e)
|
|
|
|
|
arg_exec_path = strdup(e);
|
|
|
|
|
else {
|
|
|
|
|
if (arg_transport == BUS_TRANSPORT_LOCAL) {
|
|
|
|
|
r = get_shell(&arg_exec_path);
|
|
|
|
|
if (r < 0)
|
|
|
|
|
return log_error_errno(r, "Failed to determine shell: %m");
|
|
|
|
|
} else
|
|
|
|
|
arg_exec_path = strdup("/bin/sh");
|
|
|
|
|
}
|
|
|
|
|
if (!arg_exec_path)
|
|
|
|
|
return log_oom();
|
|
|
|
|
|
|
|
|
|
l = make_login_shell_cmdline(arg_exec_path);
|
|
|
|
|
}
|
|
|
|
|
if (!l)
|
|
|
|
|
return log_oom();
|
|
|
|
|
|
|
|
|
|
strv_free_and_replace(arg_cmdline, l);
|
|
|
|
|
|
|
|
|
|
if (!arg_slice) {
|
2024-01-04 15:22:54 +01:00
|
|
|
arg_slice = strdup(SPECIAL_USER_SLICE);
|
2023-12-19 19:10:52 +01:00
|
|
|
if (!arg_slice)
|
|
|
|
|
return log_oom();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
_cleanup_free_ char *un = NULL;
|
|
|
|
|
un = getusername_malloc();
|
|
|
|
|
if (!un)
|
|
|
|
|
return log_oom();
|
|
|
|
|
|
|
|
|
|
/* Set a bunch of environment variables in a roughly sudo-compatible way */
|
|
|
|
|
r = strv_env_assign(&arg_environment, "SUDO_USER", un);
|
|
|
|
|
if (r < 0)
|
|
|
|
|
return log_error_errno(r, "Failed to set $SUDO_USER environment variable: %m");
|
|
|
|
|
|
|
|
|
|
r = strv_env_assignf(&arg_environment, "SUDO_UID", UID_FMT, getuid());
|
|
|
|
|
if (r < 0)
|
|
|
|
|
return log_error_errno(r, "Failed to set $SUDO_UID environment variable: %m");
|
|
|
|
|
|
|
|
|
|
r = strv_env_assignf(&arg_environment, "SUDO_GID", GID_FMT, getgid());
|
|
|
|
|
if (r < 0)
|
|
|
|
|
return log_error_errno(r, "Failed to set $SUDO_GID environment variable: %m");
|
|
|
|
|
|
|
|
|
|
if (strv_extendf(&arg_property, "LogExtraFields=ELEVATED_UID=" UID_FMT, getuid()) < 0)
|
|
|
|
|
return log_oom();
|
|
|
|
|
|
|
|
|
|
if (strv_extendf(&arg_property, "LogExtraFields=ELEVATED_GID=" GID_FMT, getgid()) < 0)
|
|
|
|
|
return log_oom();
|
|
|
|
|
|
|
|
|
|
if (strv_extendf(&arg_property, "LogExtraFields=ELEVATED_USER=%s", un) < 0)
|
|
|
|
|
return log_oom();
|
|
|
|
|
|
2024-03-19 11:14:55 +01:00
|
|
|
if (strv_extend(&arg_property, "PAMName=systemd-run0") < 0)
|
2023-12-19 19:10:52 +01:00
|
|
|
return log_oom();
|
|
|
|
|
|
2024-05-02 17:07:51 +02:00
|
|
|
if (!arg_background && arg_stdio == ARG_STDIO_PTY && shall_tint_background()) {
|
2024-01-19 23:59:54 +01:00
|
|
|
double hue;
|
2023-12-20 12:09:27 +01:00
|
|
|
|
2024-02-01 10:43:44 +01:00
|
|
|
if (privileged_execution())
|
2024-01-19 23:59:54 +01:00
|
|
|
hue = 0; /* red */
|
|
|
|
|
else
|
|
|
|
|
hue = 60 /* yellow */;
|
|
|
|
|
|
|
|
|
|
r = terminal_tint_color(hue, &arg_background);
|
2023-12-20 12:09:27 +01:00
|
|
|
if (r < 0)
|
|
|
|
|
log_debug_errno(r, "Unable to get terminal background color, not tinting background: %m");
|
|
|
|
|
}
|
|
|
|
|
|
2023-12-19 19:10:52 +01:00
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
2017-12-23 16:59:56 +09:00
|
|
|
static int transient_unit_set_properties(sd_bus_message *m, UnitType t, char **properties) {
|
2013-06-28 04:12:58 +02:00
|
|
|
int r;
|
|
|
|
|
|
2023-10-16 11:31:38 +02:00
|
|
|
assert(m);
|
|
|
|
|
|
2014-12-22 19:45:32 +01:00
|
|
|
r = sd_bus_message_append(m, "(sv)", "Description", "s", arg_description);
|
|
|
|
|
if (r < 0)
|
2017-11-29 20:05:22 +01:00
|
|
|
return bus_log_create_error(r);
|
2014-12-22 19:45:32 +01:00
|
|
|
|
2017-11-13 17:17:53 +01:00
|
|
|
if (arg_aggressive_gc) {
|
|
|
|
|
r = sd_bus_message_append(m, "(sv)", "CollectMode", "s", "inactive-or-failed");
|
|
|
|
|
if (r < 0)
|
2017-11-29 20:05:22 +01:00
|
|
|
return bus_log_create_error(r);
|
2017-11-13 17:17:53 +01:00
|
|
|
}
|
|
|
|
|
|
2023-10-16 11:31:38 +02:00
|
|
|
r = sd_bus_is_bus_client(sd_bus_message_get_bus(m));
|
|
|
|
|
if (r < 0)
|
|
|
|
|
return log_error_errno(r, "Can't determine if bus connection is direct or to broker: %m");
|
|
|
|
|
if (r > 0) {
|
|
|
|
|
/* Pin the object as least as long as we are around. Note that AddRef (currently) only works
|
|
|
|
|
* if we talk via the bus though. */
|
|
|
|
|
r = sd_bus_message_append(m, "(sv)", "AddRef", "b", 1);
|
|
|
|
|
if (r < 0)
|
|
|
|
|
return bus_log_create_error(r);
|
|
|
|
|
}
|
|
|
|
|
|
2022-08-16 18:41:00 +02:00
|
|
|
return bus_append_unit_property_assignment_many(m, t, properties);
|
2014-12-22 19:45:32 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int transient_cgroup_set_properties(sd_bus_message *m) {
|
2020-04-08 14:57:52 +02:00
|
|
|
_cleanup_free_ char *name = NULL;
|
|
|
|
|
_cleanup_free_ char *slice = NULL;
|
2014-12-22 19:45:32 +01:00
|
|
|
int r;
|
|
|
|
|
assert(m);
|
2013-06-28 04:12:58 +02:00
|
|
|
|
2020-04-08 14:57:52 +02:00
|
|
|
if (arg_slice_inherit) {
|
|
|
|
|
char *end;
|
2013-07-01 03:02:42 +02:00
|
|
|
|
2023-03-10 09:47:10 +01:00
|
|
|
switch (arg_runtime_scope) {
|
|
|
|
|
|
|
|
|
|
case RUNTIME_SCOPE_USER:
|
2020-04-08 14:57:52 +02:00
|
|
|
r = cg_pid_get_user_slice(0, &name);
|
2023-03-10 09:47:10 +01:00
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case RUNTIME_SCOPE_SYSTEM:
|
2020-04-08 14:57:52 +02:00
|
|
|
r = cg_pid_get_slice(0, &name);
|
2023-03-10 09:47:10 +01:00
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
assert_not_reached();
|
|
|
|
|
}
|
|
|
|
|
|
2015-04-30 20:21:00 +02:00
|
|
|
if (r < 0)
|
2020-04-08 14:57:52 +02:00
|
|
|
return log_error_errno(r, "Failed to get PID slice: %m");
|
2013-07-01 03:02:42 +02:00
|
|
|
|
2020-04-08 14:57:52 +02:00
|
|
|
end = endswith(name, ".slice");
|
|
|
|
|
if (!end)
|
|
|
|
|
return -ENXIO;
|
|
|
|
|
*end = 0;
|
2013-07-01 03:02:42 +02:00
|
|
|
}
|
|
|
|
|
|
2021-05-20 14:41:48 +09:00
|
|
|
if (!isempty(arg_slice) && !strextend_with_separator(&name, "-", arg_slice))
|
|
|
|
|
return log_oom();
|
2020-04-08 14:57:52 +02:00
|
|
|
|
|
|
|
|
if (!name)
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
r = unit_name_mangle_with_suffix(name, "as slice",
|
|
|
|
|
arg_quiet ? 0 : UNIT_NAME_MANGLE_WARN,
|
|
|
|
|
".slice", &slice);
|
|
|
|
|
if (r < 0)
|
|
|
|
|
return log_error_errno(r, "Failed to mangle name '%s': %m", arg_slice);
|
|
|
|
|
|
|
|
|
|
r = sd_bus_message_append(m, "(sv)", "Slice", "s", slice);
|
|
|
|
|
if (r < 0)
|
|
|
|
|
return bus_log_create_error(r);
|
|
|
|
|
|
2014-12-22 19:45:32 +01:00
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int transient_kill_set_properties(sd_bus_message *m) {
|
2017-11-29 20:05:22 +01:00
|
|
|
int r;
|
|
|
|
|
|
2014-12-22 19:45:32 +01:00
|
|
|
assert(m);
|
|
|
|
|
|
2017-11-29 20:05:22 +01:00
|
|
|
if (arg_send_sighup) {
|
|
|
|
|
r = sd_bus_message_append(m, "(sv)", "SendSIGHUP", "b", arg_send_sighup);
|
|
|
|
|
if (r < 0)
|
|
|
|
|
return bus_log_create_error(r);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return 0;
|
2013-07-01 00:03:57 +02:00
|
|
|
}
|
|
|
|
|
|
2024-06-06 13:30:09 +02:00
|
|
|
static int transient_service_set_properties(sd_bus_message *m, const char *pty_path, int pty_fd) {
|
2017-09-08 15:38:40 +02:00
|
|
|
bool send_term = false;
|
2013-07-01 00:03:57 +02:00
|
|
|
int r;
|
|
|
|
|
|
2023-04-02 23:17:58 +02:00
|
|
|
/* We disable environment expansion on the server side via ExecStartEx=:.
|
|
|
|
|
* ExecStartEx was added relatively recently (v243), and some bugs were fixed only later.
|
|
|
|
|
* So use that feature only if required. It will fail with older systemds. */
|
2023-07-19 22:56:02 +01:00
|
|
|
bool use_ex_prop = arg_expand_environment == 0;
|
2023-04-02 23:17:58 +02:00
|
|
|
|
2013-11-08 19:49:49 +01:00
|
|
|
assert(m);
|
2024-06-06 13:30:09 +02:00
|
|
|
assert(pty_path || pty_fd < 0);
|
2013-11-08 19:49:49 +01:00
|
|
|
|
2017-12-23 16:59:56 +09:00
|
|
|
r = transient_unit_set_properties(m, UNIT_SERVICE, arg_property);
|
2014-12-22 19:45:32 +01:00
|
|
|
if (r < 0)
|
|
|
|
|
return r;
|
|
|
|
|
|
|
|
|
|
r = transient_kill_set_properties(m);
|
|
|
|
|
if (r < 0)
|
|
|
|
|
return r;
|
|
|
|
|
|
|
|
|
|
r = transient_cgroup_set_properties(m);
|
2013-11-21 20:05:49 +01:00
|
|
|
if (r < 0)
|
|
|
|
|
return r;
|
|
|
|
|
|
2014-03-05 03:36:22 +01:00
|
|
|
if (arg_remain_after_exit) {
|
|
|
|
|
r = sd_bus_message_append(m, "(sv)", "RemainAfterExit", "b", arg_remain_after_exit);
|
|
|
|
|
if (r < 0)
|
2017-11-29 20:05:22 +01:00
|
|
|
return bus_log_create_error(r);
|
2014-03-05 03:36:22 +01:00
|
|
|
}
|
2013-07-26 16:09:25 +02:00
|
|
|
|
2014-02-05 02:02:00 +01:00
|
|
|
if (arg_service_type) {
|
|
|
|
|
r = sd_bus_message_append(m, "(sv)", "Type", "s", arg_service_type);
|
|
|
|
|
if (r < 0)
|
2017-11-29 20:05:22 +01:00
|
|
|
return bus_log_create_error(r);
|
2014-02-05 02:02:00 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (arg_exec_user) {
|
|
|
|
|
r = sd_bus_message_append(m, "(sv)", "User", "s", arg_exec_user);
|
|
|
|
|
if (r < 0)
|
2017-11-29 20:05:22 +01:00
|
|
|
return bus_log_create_error(r);
|
2014-02-05 02:02:00 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (arg_exec_group) {
|
|
|
|
|
r = sd_bus_message_append(m, "(sv)", "Group", "s", arg_exec_group);
|
|
|
|
|
if (r < 0)
|
2017-11-29 20:05:22 +01:00
|
|
|
return bus_log_create_error(r);
|
2014-02-05 02:02:00 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (arg_nice_set) {
|
|
|
|
|
r = sd_bus_message_append(m, "(sv)", "Nice", "i", arg_nice);
|
|
|
|
|
if (r < 0)
|
2017-11-29 20:05:22 +01:00
|
|
|
return bus_log_create_error(r);
|
2014-02-05 02:02:00 +01:00
|
|
|
}
|
|
|
|
|
|
2018-11-22 12:07:25 +01:00
|
|
|
if (arg_working_directory) {
|
|
|
|
|
r = sd_bus_message_append(m, "(sv)", "WorkingDirectory", "s", arg_working_directory);
|
|
|
|
|
if (r < 0)
|
|
|
|
|
return bus_log_create_error(r);
|
|
|
|
|
}
|
|
|
|
|
|
2014-12-22 19:45:32 +01:00
|
|
|
if (pty_path) {
|
2024-06-06 13:30:09 +02:00
|
|
|
r = sd_bus_message_append(m, "(sv)", "TTYPath", "s", pty_path);
|
|
|
|
|
if (r < 0)
|
|
|
|
|
return bus_log_create_error(r);
|
2024-05-19 09:07:21 +08:00
|
|
|
|
2024-06-06 13:30:09 +02:00
|
|
|
if (pty_fd >= 0)
|
|
|
|
|
r = sd_bus_message_append(m,
|
|
|
|
|
"(sv)(sv)(sv)",
|
|
|
|
|
"StandardInputFileDescriptor", "h", pty_fd,
|
|
|
|
|
"StandardOutputFileDescriptor", "h", pty_fd,
|
|
|
|
|
"StandardErrorFileDescriptor", "h", pty_fd);
|
|
|
|
|
else
|
|
|
|
|
r = sd_bus_message_append(m,
|
|
|
|
|
"(sv)(sv)(sv)",
|
|
|
|
|
"StandardInput", "s", "tty",
|
|
|
|
|
"StandardOutput", "s", "tty",
|
|
|
|
|
"StandardError", "s", "tty");
|
2014-12-22 19:45:32 +01:00
|
|
|
if (r < 0)
|
2017-11-29 20:05:22 +01:00
|
|
|
return bus_log_create_error(r);
|
2014-12-22 19:45:32 +01:00
|
|
|
|
2017-09-08 15:38:40 +02:00
|
|
|
send_term = true;
|
|
|
|
|
|
|
|
|
|
} else if (arg_stdio == ARG_STDIO_DIRECT) {
|
|
|
|
|
r = sd_bus_message_append(m,
|
|
|
|
|
"(sv)(sv)(sv)",
|
|
|
|
|
"StandardInputFileDescriptor", "h", STDIN_FILENO,
|
|
|
|
|
"StandardOutputFileDescriptor", "h", STDOUT_FILENO,
|
|
|
|
|
"StandardErrorFileDescriptor", "h", STDERR_FILENO);
|
|
|
|
|
if (r < 0)
|
2017-11-29 20:05:22 +01:00
|
|
|
return bus_log_create_error(r);
|
2017-09-08 15:38:40 +02:00
|
|
|
|
2024-10-24 23:12:31 +02:00
|
|
|
send_term = isatty_safe(STDIN_FILENO) || isatty_safe(STDOUT_FILENO) || isatty_safe(STDERR_FILENO);
|
2017-09-08 15:38:40 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (send_term) {
|
|
|
|
|
const char *e;
|
|
|
|
|
|
2014-12-22 19:45:32 +01:00
|
|
|
e = getenv("TERM");
|
|
|
|
|
if (e) {
|
2022-01-26 10:53:40 -08:00
|
|
|
_cleanup_free_ char *n = NULL;
|
|
|
|
|
|
|
|
|
|
n = strjoin("TERM=", e);
|
|
|
|
|
if (!n)
|
|
|
|
|
return log_oom();
|
2014-12-22 19:45:32 +01:00
|
|
|
|
|
|
|
|
r = sd_bus_message_append(m,
|
|
|
|
|
"(sv)",
|
|
|
|
|
"Environment", "as", 1, n);
|
|
|
|
|
if (r < 0)
|
2017-11-29 20:05:22 +01:00
|
|
|
return bus_log_create_error(r);
|
2014-12-22 19:45:32 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2014-02-05 02:02:00 +01:00
|
|
|
if (!strv_isempty(arg_environment)) {
|
|
|
|
|
r = sd_bus_message_open_container(m, 'r', "sv");
|
|
|
|
|
if (r < 0)
|
2017-11-29 20:05:22 +01:00
|
|
|
return bus_log_create_error(r);
|
2014-02-05 02:02:00 +01:00
|
|
|
|
|
|
|
|
r = sd_bus_message_append(m, "s", "Environment");
|
|
|
|
|
if (r < 0)
|
2017-11-29 20:05:22 +01:00
|
|
|
return bus_log_create_error(r);
|
2014-02-05 02:02:00 +01:00
|
|
|
|
|
|
|
|
r = sd_bus_message_open_container(m, 'v', "as");
|
|
|
|
|
if (r < 0)
|
2017-11-29 20:05:22 +01:00
|
|
|
return bus_log_create_error(r);
|
2014-02-05 02:02:00 +01:00
|
|
|
|
|
|
|
|
r = sd_bus_message_append_strv(m, arg_environment);
|
|
|
|
|
if (r < 0)
|
2017-11-29 20:05:22 +01:00
|
|
|
return bus_log_create_error(r);
|
2014-02-05 02:02:00 +01:00
|
|
|
|
|
|
|
|
r = sd_bus_message_close_container(m);
|
|
|
|
|
if (r < 0)
|
2017-11-29 20:05:22 +01:00
|
|
|
return bus_log_create_error(r);
|
2014-02-05 02:02:00 +01:00
|
|
|
|
|
|
|
|
r = sd_bus_message_close_container(m);
|
|
|
|
|
if (r < 0)
|
2017-11-29 20:05:22 +01:00
|
|
|
return bus_log_create_error(r);
|
run: introduce timer support option
Support timer options --on-active=, --on-boot=, --on-startup=,
--on-unit-active=, --on-unit-inactive=, --on-calendar=. Each options
corresponding with OnActiveSec=, OnBootSec=, OnStartupSec=,
OnUnitActiveSec=, OnUnitInactiveSec=, OnCalendar= of timer
respectively. And OnCalendar= and WakeSystem= supported by
--timer-property= option like --property= of systemd-run.
And if --unit= option and timer options are specified the command can
be omitted. In this case, systemd-run assumes the target service is
already loaded. And just try to generate transient timer unit only.
2014-12-09 16:07:16 +09:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Exec container */
|
2018-11-22 19:24:48 +01:00
|
|
|
if (!strv_isempty(arg_cmdline)) {
|
run: introduce timer support option
Support timer options --on-active=, --on-boot=, --on-startup=,
--on-unit-active=, --on-unit-inactive=, --on-calendar=. Each options
corresponding with OnActiveSec=, OnBootSec=, OnStartupSec=,
OnUnitActiveSec=, OnUnitInactiveSec=, OnCalendar= of timer
respectively. And OnCalendar= and WakeSystem= supported by
--timer-property= option like --property= of systemd-run.
And if --unit= option and timer options are specified the command can
be omitted. In this case, systemd-run assumes the target service is
already loaded. And just try to generate transient timer unit only.
2014-12-09 16:07:16 +09:00
|
|
|
r = sd_bus_message_open_container(m, 'r', "sv");
|
|
|
|
|
if (r < 0)
|
2017-11-29 20:05:22 +01:00
|
|
|
return bus_log_create_error(r);
|
run: introduce timer support option
Support timer options --on-active=, --on-boot=, --on-startup=,
--on-unit-active=, --on-unit-inactive=, --on-calendar=. Each options
corresponding with OnActiveSec=, OnBootSec=, OnStartupSec=,
OnUnitActiveSec=, OnUnitInactiveSec=, OnCalendar= of timer
respectively. And OnCalendar= and WakeSystem= supported by
--timer-property= option like --property= of systemd-run.
And if --unit= option and timer options are specified the command can
be omitted. In this case, systemd-run assumes the target service is
already loaded. And just try to generate transient timer unit only.
2014-12-09 16:07:16 +09:00
|
|
|
|
2023-04-02 23:17:58 +02:00
|
|
|
r = sd_bus_message_append(m, "s",
|
|
|
|
|
use_ex_prop ? "ExecStartEx" : "ExecStart");
|
run: introduce timer support option
Support timer options --on-active=, --on-boot=, --on-startup=,
--on-unit-active=, --on-unit-inactive=, --on-calendar=. Each options
corresponding with OnActiveSec=, OnBootSec=, OnStartupSec=,
OnUnitActiveSec=, OnUnitInactiveSec=, OnCalendar= of timer
respectively. And OnCalendar= and WakeSystem= supported by
--timer-property= option like --property= of systemd-run.
And if --unit= option and timer options are specified the command can
be omitted. In this case, systemd-run assumes the target service is
already loaded. And just try to generate transient timer unit only.
2014-12-09 16:07:16 +09:00
|
|
|
if (r < 0)
|
2017-11-29 20:05:22 +01:00
|
|
|
return bus_log_create_error(r);
|
run: introduce timer support option
Support timer options --on-active=, --on-boot=, --on-startup=,
--on-unit-active=, --on-unit-inactive=, --on-calendar=. Each options
corresponding with OnActiveSec=, OnBootSec=, OnStartupSec=,
OnUnitActiveSec=, OnUnitInactiveSec=, OnCalendar= of timer
respectively. And OnCalendar= and WakeSystem= supported by
--timer-property= option like --property= of systemd-run.
And if --unit= option and timer options are specified the command can
be omitted. In this case, systemd-run assumes the target service is
already loaded. And just try to generate transient timer unit only.
2014-12-09 16:07:16 +09:00
|
|
|
|
2023-04-02 23:17:58 +02:00
|
|
|
r = sd_bus_message_open_container(m, 'v',
|
|
|
|
|
use_ex_prop ? "a(sasas)" : "a(sasb)");
|
run: introduce timer support option
Support timer options --on-active=, --on-boot=, --on-startup=,
--on-unit-active=, --on-unit-inactive=, --on-calendar=. Each options
corresponding with OnActiveSec=, OnBootSec=, OnStartupSec=,
OnUnitActiveSec=, OnUnitInactiveSec=, OnCalendar= of timer
respectively. And OnCalendar= and WakeSystem= supported by
--timer-property= option like --property= of systemd-run.
And if --unit= option and timer options are specified the command can
be omitted. In this case, systemd-run assumes the target service is
already loaded. And just try to generate transient timer unit only.
2014-12-09 16:07:16 +09:00
|
|
|
if (r < 0)
|
2017-11-29 20:05:22 +01:00
|
|
|
return bus_log_create_error(r);
|
run: introduce timer support option
Support timer options --on-active=, --on-boot=, --on-startup=,
--on-unit-active=, --on-unit-inactive=, --on-calendar=. Each options
corresponding with OnActiveSec=, OnBootSec=, OnStartupSec=,
OnUnitActiveSec=, OnUnitInactiveSec=, OnCalendar= of timer
respectively. And OnCalendar= and WakeSystem= supported by
--timer-property= option like --property= of systemd-run.
And if --unit= option and timer options are specified the command can
be omitted. In this case, systemd-run assumes the target service is
already loaded. And just try to generate transient timer unit only.
2014-12-09 16:07:16 +09:00
|
|
|
|
2023-04-02 23:17:58 +02:00
|
|
|
r = sd_bus_message_open_container(m, 'a',
|
|
|
|
|
use_ex_prop ? "(sasas)" : "(sasb)");
|
run: introduce timer support option
Support timer options --on-active=, --on-boot=, --on-startup=,
--on-unit-active=, --on-unit-inactive=, --on-calendar=. Each options
corresponding with OnActiveSec=, OnBootSec=, OnStartupSec=,
OnUnitActiveSec=, OnUnitInactiveSec=, OnCalendar= of timer
respectively. And OnCalendar= and WakeSystem= supported by
--timer-property= option like --property= of systemd-run.
And if --unit= option and timer options are specified the command can
be omitted. In this case, systemd-run assumes the target service is
already loaded. And just try to generate transient timer unit only.
2014-12-09 16:07:16 +09:00
|
|
|
if (r < 0)
|
2017-11-29 20:05:22 +01:00
|
|
|
return bus_log_create_error(r);
|
run: introduce timer support option
Support timer options --on-active=, --on-boot=, --on-startup=,
--on-unit-active=, --on-unit-inactive=, --on-calendar=. Each options
corresponding with OnActiveSec=, OnBootSec=, OnStartupSec=,
OnUnitActiveSec=, OnUnitInactiveSec=, OnCalendar= of timer
respectively. And OnCalendar= and WakeSystem= supported by
--timer-property= option like --property= of systemd-run.
And if --unit= option and timer options are specified the command can
be omitted. In this case, systemd-run assumes the target service is
already loaded. And just try to generate transient timer unit only.
2014-12-09 16:07:16 +09:00
|
|
|
|
2023-04-02 23:17:58 +02:00
|
|
|
r = sd_bus_message_open_container(m, 'r',
|
|
|
|
|
use_ex_prop ? "sasas" : "sasb");
|
run: introduce timer support option
Support timer options --on-active=, --on-boot=, --on-startup=,
--on-unit-active=, --on-unit-inactive=, --on-calendar=. Each options
corresponding with OnActiveSec=, OnBootSec=, OnStartupSec=,
OnUnitActiveSec=, OnUnitInactiveSec=, OnCalendar= of timer
respectively. And OnCalendar= and WakeSystem= supported by
--timer-property= option like --property= of systemd-run.
And if --unit= option and timer options are specified the command can
be omitted. In this case, systemd-run assumes the target service is
already loaded. And just try to generate transient timer unit only.
2014-12-09 16:07:16 +09:00
|
|
|
if (r < 0)
|
2017-11-29 20:05:22 +01:00
|
|
|
return bus_log_create_error(r);
|
run: introduce timer support option
Support timer options --on-active=, --on-boot=, --on-startup=,
--on-unit-active=, --on-unit-inactive=, --on-calendar=. Each options
corresponding with OnActiveSec=, OnBootSec=, OnStartupSec=,
OnUnitActiveSec=, OnUnitInactiveSec=, OnCalendar= of timer
respectively. And OnCalendar= and WakeSystem= supported by
--timer-property= option like --property= of systemd-run.
And if --unit= option and timer options are specified the command can
be omitted. In this case, systemd-run assumes the target service is
already loaded. And just try to generate transient timer unit only.
2014-12-09 16:07:16 +09:00
|
|
|
|
2023-12-19 19:10:52 +01:00
|
|
|
r = sd_bus_message_append(m, "s", arg_exec_path ?: arg_cmdline[0]);
|
run: introduce timer support option
Support timer options --on-active=, --on-boot=, --on-startup=,
--on-unit-active=, --on-unit-inactive=, --on-calendar=. Each options
corresponding with OnActiveSec=, OnBootSec=, OnStartupSec=,
OnUnitActiveSec=, OnUnitInactiveSec=, OnCalendar= of timer
respectively. And OnCalendar= and WakeSystem= supported by
--timer-property= option like --property= of systemd-run.
And if --unit= option and timer options are specified the command can
be omitted. In this case, systemd-run assumes the target service is
already loaded. And just try to generate transient timer unit only.
2014-12-09 16:07:16 +09:00
|
|
|
if (r < 0)
|
2017-11-29 20:05:22 +01:00
|
|
|
return bus_log_create_error(r);
|
run: introduce timer support option
Support timer options --on-active=, --on-boot=, --on-startup=,
--on-unit-active=, --on-unit-inactive=, --on-calendar=. Each options
corresponding with OnActiveSec=, OnBootSec=, OnStartupSec=,
OnUnitActiveSec=, OnUnitInactiveSec=, OnCalendar= of timer
respectively. And OnCalendar= and WakeSystem= supported by
--timer-property= option like --property= of systemd-run.
And if --unit= option and timer options are specified the command can
be omitted. In this case, systemd-run assumes the target service is
already loaded. And just try to generate transient timer unit only.
2014-12-09 16:07:16 +09:00
|
|
|
|
2018-11-22 19:24:48 +01:00
|
|
|
r = sd_bus_message_append_strv(m, arg_cmdline);
|
run: introduce timer support option
Support timer options --on-active=, --on-boot=, --on-startup=,
--on-unit-active=, --on-unit-inactive=, --on-calendar=. Each options
corresponding with OnActiveSec=, OnBootSec=, OnStartupSec=,
OnUnitActiveSec=, OnUnitInactiveSec=, OnCalendar= of timer
respectively. And OnCalendar= and WakeSystem= supported by
--timer-property= option like --property= of systemd-run.
And if --unit= option and timer options are specified the command can
be omitted. In this case, systemd-run assumes the target service is
already loaded. And just try to generate transient timer unit only.
2014-12-09 16:07:16 +09:00
|
|
|
if (r < 0)
|
2017-11-29 20:05:22 +01:00
|
|
|
return bus_log_create_error(r);
|
run: introduce timer support option
Support timer options --on-active=, --on-boot=, --on-startup=,
--on-unit-active=, --on-unit-inactive=, --on-calendar=. Each options
corresponding with OnActiveSec=, OnBootSec=, OnStartupSec=,
OnUnitActiveSec=, OnUnitInactiveSec=, OnCalendar= of timer
respectively. And OnCalendar= and WakeSystem= supported by
--timer-property= option like --property= of systemd-run.
And if --unit= option and timer options are specified the command can
be omitted. In this case, systemd-run assumes the target service is
already loaded. And just try to generate transient timer unit only.
2014-12-09 16:07:16 +09:00
|
|
|
|
2024-07-10 22:27:21 +02:00
|
|
|
if (use_ex_prop) {
|
|
|
|
|
_cleanup_strv_free_ char **opts = NULL;
|
|
|
|
|
|
|
|
|
|
r = exec_command_flags_to_strv(
|
|
|
|
|
(arg_expand_environment > 0 ? 0 : EXEC_COMMAND_NO_ENV_EXPAND)|(arg_ignore_failure ? EXEC_COMMAND_IGNORE_FAILURE : 0),
|
|
|
|
|
&opts);
|
|
|
|
|
if (r < 0)
|
|
|
|
|
return log_error_errno(r, "Failed to format execute flags: %m");
|
|
|
|
|
|
|
|
|
|
r = sd_bus_message_append_strv(m, opts);
|
|
|
|
|
} else
|
2023-12-19 21:39:50 +01:00
|
|
|
r = sd_bus_message_append(m, "b", arg_ignore_failure);
|
run: introduce timer support option
Support timer options --on-active=, --on-boot=, --on-startup=,
--on-unit-active=, --on-unit-inactive=, --on-calendar=. Each options
corresponding with OnActiveSec=, OnBootSec=, OnStartupSec=,
OnUnitActiveSec=, OnUnitInactiveSec=, OnCalendar= of timer
respectively. And OnCalendar= and WakeSystem= supported by
--timer-property= option like --property= of systemd-run.
And if --unit= option and timer options are specified the command can
be omitted. In this case, systemd-run assumes the target service is
already loaded. And just try to generate transient timer unit only.
2014-12-09 16:07:16 +09:00
|
|
|
if (r < 0)
|
2017-11-29 20:05:22 +01:00
|
|
|
return bus_log_create_error(r);
|
run: introduce timer support option
Support timer options --on-active=, --on-boot=, --on-startup=,
--on-unit-active=, --on-unit-inactive=, --on-calendar=. Each options
corresponding with OnActiveSec=, OnBootSec=, OnStartupSec=,
OnUnitActiveSec=, OnUnitInactiveSec=, OnCalendar= of timer
respectively. And OnCalendar= and WakeSystem= supported by
--timer-property= option like --property= of systemd-run.
And if --unit= option and timer options are specified the command can
be omitted. In this case, systemd-run assumes the target service is
already loaded. And just try to generate transient timer unit only.
2014-12-09 16:07:16 +09:00
|
|
|
|
|
|
|
|
r = sd_bus_message_close_container(m);
|
|
|
|
|
if (r < 0)
|
2017-11-29 20:05:22 +01:00
|
|
|
return bus_log_create_error(r);
|
run: introduce timer support option
Support timer options --on-active=, --on-boot=, --on-startup=,
--on-unit-active=, --on-unit-inactive=, --on-calendar=. Each options
corresponding with OnActiveSec=, OnBootSec=, OnStartupSec=,
OnUnitActiveSec=, OnUnitInactiveSec=, OnCalendar= of timer
respectively. And OnCalendar= and WakeSystem= supported by
--timer-property= option like --property= of systemd-run.
And if --unit= option and timer options are specified the command can
be omitted. In this case, systemd-run assumes the target service is
already loaded. And just try to generate transient timer unit only.
2014-12-09 16:07:16 +09:00
|
|
|
|
|
|
|
|
r = sd_bus_message_close_container(m);
|
|
|
|
|
if (r < 0)
|
2017-11-29 20:05:22 +01:00
|
|
|
return bus_log_create_error(r);
|
run: introduce timer support option
Support timer options --on-active=, --on-boot=, --on-startup=,
--on-unit-active=, --on-unit-inactive=, --on-calendar=. Each options
corresponding with OnActiveSec=, OnBootSec=, OnStartupSec=,
OnUnitActiveSec=, OnUnitInactiveSec=, OnCalendar= of timer
respectively. And OnCalendar= and WakeSystem= supported by
--timer-property= option like --property= of systemd-run.
And if --unit= option and timer options are specified the command can
be omitted. In this case, systemd-run assumes the target service is
already loaded. And just try to generate transient timer unit only.
2014-12-09 16:07:16 +09:00
|
|
|
|
|
|
|
|
r = sd_bus_message_close_container(m);
|
|
|
|
|
if (r < 0)
|
2017-11-29 20:05:22 +01:00
|
|
|
return bus_log_create_error(r);
|
run: introduce timer support option
Support timer options --on-active=, --on-boot=, --on-startup=,
--on-unit-active=, --on-unit-inactive=, --on-calendar=. Each options
corresponding with OnActiveSec=, OnBootSec=, OnStartupSec=,
OnUnitActiveSec=, OnUnitInactiveSec=, OnCalendar= of timer
respectively. And OnCalendar= and WakeSystem= supported by
--timer-property= option like --property= of systemd-run.
And if --unit= option and timer options are specified the command can
be omitted. In this case, systemd-run assumes the target service is
already loaded. And just try to generate transient timer unit only.
2014-12-09 16:07:16 +09:00
|
|
|
|
|
|
|
|
r = sd_bus_message_close_container(m);
|
|
|
|
|
if (r < 0)
|
2017-11-29 20:05:22 +01:00
|
|
|
return bus_log_create_error(r);
|
run: introduce timer support option
Support timer options --on-active=, --on-boot=, --on-startup=,
--on-unit-active=, --on-unit-inactive=, --on-calendar=. Each options
corresponding with OnActiveSec=, OnBootSec=, OnStartupSec=,
OnUnitActiveSec=, OnUnitInactiveSec=, OnCalendar= of timer
respectively. And OnCalendar= and WakeSystem= supported by
--timer-property= option like --property= of systemd-run.
And if --unit= option and timer options are specified the command can
be omitted. In this case, systemd-run assumes the target service is
already loaded. And just try to generate transient timer unit only.
2014-12-09 16:07:16 +09:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2023-10-12 12:02:03 +02:00
|
|
|
static int transient_scope_set_properties(sd_bus_message *m, bool allow_pidfd) {
|
2014-12-22 19:45:32 +01:00
|
|
|
int r;
|
|
|
|
|
|
|
|
|
|
assert(m);
|
|
|
|
|
|
2017-12-23 16:59:56 +09:00
|
|
|
r = transient_unit_set_properties(m, UNIT_SCOPE, arg_property);
|
2014-12-22 19:45:32 +01:00
|
|
|
if (r < 0)
|
|
|
|
|
return r;
|
|
|
|
|
|
|
|
|
|
r = transient_kill_set_properties(m);
|
|
|
|
|
if (r < 0)
|
|
|
|
|
return r;
|
|
|
|
|
|
2016-04-22 17:31:40 +02:00
|
|
|
r = transient_cgroup_set_properties(m);
|
|
|
|
|
if (r < 0)
|
|
|
|
|
return r;
|
|
|
|
|
|
2024-03-22 17:03:35 +01:00
|
|
|
_cleanup_(pidref_done) PidRef pidref = PIDREF_NULL;
|
2023-10-05 09:55:28 +02:00
|
|
|
|
2024-03-22 17:03:35 +01:00
|
|
|
r = pidref_set_self(&pidref);
|
|
|
|
|
if (r < 0)
|
|
|
|
|
return r;
|
2023-10-12 12:02:03 +02:00
|
|
|
|
2024-03-22 17:03:35 +01:00
|
|
|
r = bus_append_scope_pidref(m, &pidref, allow_pidfd);
|
2014-12-22 19:45:32 +01:00
|
|
|
if (r < 0)
|
2017-11-29 20:05:22 +01:00
|
|
|
return bus_log_create_error(r);
|
2014-12-22 19:45:32 +01:00
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
run: introduce timer support option
Support timer options --on-active=, --on-boot=, --on-startup=,
--on-unit-active=, --on-unit-inactive=, --on-calendar=. Each options
corresponding with OnActiveSec=, OnBootSec=, OnStartupSec=,
OnUnitActiveSec=, OnUnitInactiveSec=, OnCalendar= of timer
respectively. And OnCalendar= and WakeSystem= supported by
--timer-property= option like --property= of systemd-run.
And if --unit= option and timer options are specified the command can
be omitted. In this case, systemd-run assumes the target service is
already loaded. And just try to generate transient timer unit only.
2014-12-09 16:07:16 +09:00
|
|
|
static int transient_timer_set_properties(sd_bus_message *m) {
|
|
|
|
|
int r;
|
|
|
|
|
|
|
|
|
|
assert(m);
|
|
|
|
|
|
2017-12-23 16:59:56 +09:00
|
|
|
r = transient_unit_set_properties(m, UNIT_TIMER, arg_timer_property);
|
run: introduce timer support option
Support timer options --on-active=, --on-boot=, --on-startup=,
--on-unit-active=, --on-unit-inactive=, --on-calendar=. Each options
corresponding with OnActiveSec=, OnBootSec=, OnStartupSec=,
OnUnitActiveSec=, OnUnitInactiveSec=, OnCalendar= of timer
respectively. And OnCalendar= and WakeSystem= supported by
--timer-property= option like --property= of systemd-run.
And if --unit= option and timer options are specified the command can
be omitted. In this case, systemd-run assumes the target service is
already loaded. And just try to generate transient timer unit only.
2014-12-09 16:07:16 +09:00
|
|
|
if (r < 0)
|
|
|
|
|
return r;
|
|
|
|
|
|
2015-11-17 20:38:12 +01:00
|
|
|
/* Automatically clean up our transient timers */
|
|
|
|
|
r = sd_bus_message_append(m, "(sv)", "RemainAfterElapse", "b", false);
|
|
|
|
|
if (r < 0)
|
2017-11-29 20:05:22 +01:00
|
|
|
return bus_log_create_error(r);
|
2015-11-17 20:38:12 +01:00
|
|
|
|
run: introduce timer support option
Support timer options --on-active=, --on-boot=, --on-startup=,
--on-unit-active=, --on-unit-inactive=, --on-calendar=. Each options
corresponding with OnActiveSec=, OnBootSec=, OnStartupSec=,
OnUnitActiveSec=, OnUnitInactiveSec=, OnCalendar= of timer
respectively. And OnCalendar= and WakeSystem= supported by
--timer-property= option like --property= of systemd-run.
And if --unit= option and timer options are specified the command can
be omitted. In this case, systemd-run assumes the target service is
already loaded. And just try to generate transient timer unit only.
2014-12-09 16:07:16 +09:00
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
run: when automatically generating names for transient units, use unique bus ID, fallback to random
Previously we used the process ID to generate transient unit names.
However, that is problematic as PIDs get reused easily, and applying
them to remote systems makes little sense.
Fortunately, each bus peer gets a unique, non-reusable ID assigned when
attaching to a bus, hence let's use that, if we can. In some cases we
cannot however, because we connect directly to PID's private socket, and
thus are not a proper bus peer with a unique ID. In that case generate a
random UUID to name the unit after.
2015-11-17 14:11:12 +01:00
|
|
|
static int make_unit_name(sd_bus *bus, UnitType t, char **ret) {
|
2024-03-27 21:14:15 +00:00
|
|
|
unsigned soft_reboots_count = 0;
|
run: when automatically generating names for transient units, use unique bus ID, fallback to random
Previously we used the process ID to generate transient unit names.
However, that is problematic as PIDs get reused easily, and applying
them to remote systems makes little sense.
Fortunately, each bus peer gets a unique, non-reusable ID assigned when
attaching to a bus, hence let's use that, if we can. In some cases we
cannot however, because we connect directly to PID's private socket, and
thus are not a proper bus peer with a unique ID. In that case generate a
random UUID to name the unit after.
2015-11-17 14:11:12 +01:00
|
|
|
const char *unique, *id;
|
|
|
|
|
char *p;
|
|
|
|
|
int r;
|
|
|
|
|
|
|
|
|
|
assert(bus);
|
|
|
|
|
assert(t >= 0);
|
|
|
|
|
assert(t < _UNIT_TYPE_MAX);
|
2024-04-06 00:00:41 +01:00
|
|
|
assert(ret);
|
run: when automatically generating names for transient units, use unique bus ID, fallback to random
Previously we used the process ID to generate transient unit names.
However, that is problematic as PIDs get reused easily, and applying
them to remote systems makes little sense.
Fortunately, each bus peer gets a unique, non-reusable ID assigned when
attaching to a bus, hence let's use that, if we can. In some cases we
cannot however, because we connect directly to PID's private socket, and
thus are not a proper bus peer with a unique ID. In that case generate a
random UUID to name the unit after.
2015-11-17 14:11:12 +01:00
|
|
|
|
|
|
|
|
r = sd_bus_get_unique_name(bus, &unique);
|
|
|
|
|
if (r < 0) {
|
|
|
|
|
sd_id128_t rnd;
|
|
|
|
|
|
|
|
|
|
/* We couldn't get the unique name, which is a pretty
|
|
|
|
|
* common case if we are connected to systemd
|
|
|
|
|
* directly. In that case, just pick a random uuid as
|
|
|
|
|
* name */
|
|
|
|
|
|
|
|
|
|
r = sd_id128_randomize(&rnd);
|
|
|
|
|
if (r < 0)
|
|
|
|
|
return log_error_errno(r, "Failed to generate random run unit name: %m");
|
|
|
|
|
|
|
|
|
|
if (asprintf(ret, "run-r" SD_ID128_FORMAT_STR ".%s", SD_ID128_FORMAT_VAL(rnd), unit_type_to_string(t)) < 0)
|
|
|
|
|
return log_oom();
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2021-03-04 16:23:46 +01:00
|
|
|
/* We managed to get the unique name, then let's use that to name our transient units. */
|
run: when automatically generating names for transient units, use unique bus ID, fallback to random
Previously we used the process ID to generate transient unit names.
However, that is problematic as PIDs get reused easily, and applying
them to remote systems makes little sense.
Fortunately, each bus peer gets a unique, non-reusable ID assigned when
attaching to a bus, hence let's use that, if we can. In some cases we
cannot however, because we connect directly to PID's private socket, and
thus are not a proper bus peer with a unique ID. In that case generate a
random UUID to name the unit after.
2015-11-17 14:11:12 +01:00
|
|
|
|
2021-03-04 16:23:46 +01:00
|
|
|
id = startswith(unique, ":1."); /* let' strip the usual prefix */
|
|
|
|
|
if (!id)
|
|
|
|
|
id = startswith(unique, ":"); /* the spec only requires things to start with a colon, hence
|
|
|
|
|
* let's add a generic fallback for that. */
|
2018-11-20 23:40:44 +01:00
|
|
|
if (!id)
|
|
|
|
|
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
|
|
|
|
|
"Unique name %s has unexpected format.",
|
|
|
|
|
unique);
|
run: when automatically generating names for transient units, use unique bus ID, fallback to random
Previously we used the process ID to generate transient unit names.
However, that is problematic as PIDs get reused easily, and applying
them to remote systems makes little sense.
Fortunately, each bus peer gets a unique, non-reusable ID assigned when
attaching to a bus, hence let's use that, if we can. In some cases we
cannot however, because we connect directly to PID's private socket, and
thus are not a proper bus peer with a unique ID. In that case generate a
random UUID to name the unit after.
2015-11-17 14:11:12 +01:00
|
|
|
|
2024-03-27 21:14:15 +00:00
|
|
|
/* The unique D-Bus names are actually unique per D-Bus instance, so on soft-reboot they will wrap
|
|
|
|
|
* and start over since the D-Bus broker is restarted. If there's a failed unit left behind that
|
|
|
|
|
* hasn't been garbage collected, we'll conflict. Append the soft-reboot counter to avoid clashing. */
|
2024-04-06 00:00:41 +01:00
|
|
|
if (arg_runtime_scope == RUNTIME_SCOPE_SYSTEM) {
|
|
|
|
|
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
|
|
|
|
|
r = bus_get_property_trivial(
|
|
|
|
|
bus, bus_systemd_mgr, "SoftRebootsCount", &error, 'u', &soft_reboots_count);
|
|
|
|
|
if (r < 0)
|
|
|
|
|
log_debug_errno(r,
|
|
|
|
|
"Failed to get SoftRebootsCount property, ignoring: %s",
|
|
|
|
|
bus_error_message(&error, r));
|
|
|
|
|
}
|
2024-03-27 21:14:15 +00:00
|
|
|
|
|
|
|
|
if (soft_reboots_count > 0) {
|
|
|
|
|
if (asprintf(&p, "run-u%s-s%u.%s", id, soft_reboots_count, unit_type_to_string(t)) < 0)
|
|
|
|
|
return log_oom();
|
|
|
|
|
} else {
|
|
|
|
|
p = strjoin("run-u", id, ".", unit_type_to_string(t));
|
|
|
|
|
if (!p)
|
|
|
|
|
return log_oom();
|
|
|
|
|
}
|
run: when automatically generating names for transient units, use unique bus ID, fallback to random
Previously we used the process ID to generate transient unit names.
However, that is problematic as PIDs get reused easily, and applying
them to remote systems makes little sense.
Fortunately, each bus peer gets a unique, non-reusable ID assigned when
attaching to a bus, hence let's use that, if we can. In some cases we
cannot however, because we connect directly to PID's private socket, and
thus are not a proper bus peer with a unique ID. In that case generate a
random UUID to name the unit after.
2015-11-17 14:11:12 +01:00
|
|
|
|
|
|
|
|
*ret = p;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2016-08-17 14:24:17 +02:00
|
|
|
typedef struct RunContext {
|
|
|
|
|
sd_bus *bus;
|
|
|
|
|
sd_event *event;
|
|
|
|
|
PTYForward *forward;
|
|
|
|
|
sd_bus_slot *match;
|
|
|
|
|
|
2020-05-26 16:22:36 +02:00
|
|
|
/* Current state of the unit */
|
2016-08-17 14:24:17 +02:00
|
|
|
char *active_state;
|
2020-05-26 16:22:36 +02:00
|
|
|
bool has_job;
|
|
|
|
|
|
|
|
|
|
/* The exit data of the unit */
|
2016-08-17 14:24:17 +02:00
|
|
|
uint64_t inactive_exit_usec;
|
|
|
|
|
uint64_t inactive_enter_usec;
|
|
|
|
|
char *result;
|
|
|
|
|
uint64_t cpu_usage_nsec;
|
2023-11-06 17:28:41 +01:00
|
|
|
uint64_t memory_peak;
|
2023-11-08 19:22:06 +01:00
|
|
|
uint64_t memory_swap_peak;
|
2017-09-26 16:33:03 +02:00
|
|
|
uint64_t ip_ingress_bytes;
|
|
|
|
|
uint64_t ip_egress_bytes;
|
2019-03-22 12:18:19 +01:00
|
|
|
uint64_t io_read_bytes;
|
|
|
|
|
uint64_t io_write_bytes;
|
2016-08-17 14:24:17 +02:00
|
|
|
uint32_t exit_code;
|
|
|
|
|
uint32_t exit_status;
|
|
|
|
|
} RunContext;
|
|
|
|
|
|
|
|
|
|
static void run_context_free(RunContext *c) {
|
|
|
|
|
assert(c);
|
|
|
|
|
|
|
|
|
|
c->forward = pty_forward_free(c->forward);
|
|
|
|
|
c->match = sd_bus_slot_unref(c->match);
|
|
|
|
|
c->bus = sd_bus_unref(c->bus);
|
|
|
|
|
c->event = sd_event_unref(c->event);
|
|
|
|
|
|
|
|
|
|
free(c->active_state);
|
|
|
|
|
free(c->result);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void run_context_check_done(RunContext *c) {
|
2016-12-24 00:35:58 +01:00
|
|
|
bool done;
|
2016-08-17 14:24:17 +02:00
|
|
|
|
|
|
|
|
assert(c);
|
|
|
|
|
|
|
|
|
|
if (c->match)
|
2020-05-26 16:22:36 +02:00
|
|
|
done = STRPTR_IN_SET(c->active_state, "inactive", "failed") && !c->has_job;
|
2016-12-24 00:35:58 +01:00
|
|
|
else
|
|
|
|
|
done = true;
|
2016-08-17 14:24:17 +02:00
|
|
|
|
2024-05-21 20:10:24 +08:00
|
|
|
if (c->forward && !pty_forward_is_done(c->forward) && done) /* If the service is gone, it's time to drain the output */
|
2016-12-24 00:35:58 +01:00
|
|
|
done = pty_forward_drain(c->forward);
|
2016-08-17 14:24:17 +02:00
|
|
|
|
|
|
|
|
if (done)
|
|
|
|
|
sd_event_exit(c->event, EXIT_SUCCESS);
|
|
|
|
|
}
|
|
|
|
|
|
2020-05-26 16:22:36 +02:00
|
|
|
static int map_job(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) {
|
|
|
|
|
bool *b = userdata;
|
|
|
|
|
const char *job;
|
|
|
|
|
uint32_t id;
|
|
|
|
|
int r;
|
|
|
|
|
|
|
|
|
|
r = sd_bus_message_read(m, "(uo)", &id, &job);
|
|
|
|
|
if (r < 0)
|
|
|
|
|
return r;
|
|
|
|
|
|
|
|
|
|
*b = id != 0 || !streq(job, "/");
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2016-12-23 22:56:39 +01:00
|
|
|
static int run_context_update(RunContext *c, const char *path) {
|
2016-08-17 14:24:17 +02:00
|
|
|
|
|
|
|
|
static const struct bus_properties_map map[] = {
|
2020-05-26 16:22:36 +02:00
|
|
|
{ "ActiveState", "s", NULL, offsetof(RunContext, active_state) },
|
|
|
|
|
{ "InactiveExitTimestampMonotonic", "t", NULL, offsetof(RunContext, inactive_exit_usec) },
|
|
|
|
|
{ "InactiveEnterTimestampMonotonic", "t", NULL, offsetof(RunContext, inactive_enter_usec) },
|
|
|
|
|
{ "Result", "s", NULL, offsetof(RunContext, result) },
|
|
|
|
|
{ "ExecMainCode", "i", NULL, offsetof(RunContext, exit_code) },
|
|
|
|
|
{ "ExecMainStatus", "i", NULL, offsetof(RunContext, exit_status) },
|
|
|
|
|
{ "CPUUsageNSec", "t", NULL, offsetof(RunContext, cpu_usage_nsec) },
|
2023-11-06 17:28:41 +01:00
|
|
|
{ "MemoryPeak", "t", NULL, offsetof(RunContext, memory_peak) },
|
2023-11-08 19:22:06 +01:00
|
|
|
{ "MemorySwapPeak", "t", NULL, offsetof(RunContext, memory_swap_peak) },
|
2020-05-26 16:22:36 +02:00
|
|
|
{ "IPIngressBytes", "t", NULL, offsetof(RunContext, ip_ingress_bytes) },
|
|
|
|
|
{ "IPEgressBytes", "t", NULL, offsetof(RunContext, ip_egress_bytes) },
|
|
|
|
|
{ "IOReadBytes", "t", NULL, offsetof(RunContext, io_read_bytes) },
|
|
|
|
|
{ "IOWriteBytes", "t", NULL, offsetof(RunContext, io_write_bytes) },
|
|
|
|
|
{ "Job", "(uo)", map_job, offsetof(RunContext, has_job) },
|
2016-08-17 14:24:17 +02:00
|
|
|
{}
|
|
|
|
|
};
|
|
|
|
|
|
2017-02-08 17:59:58 +01:00
|
|
|
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
|
2016-08-17 14:24:17 +02:00
|
|
|
int r;
|
|
|
|
|
|
|
|
|
|
r = bus_map_all_properties(c->bus,
|
|
|
|
|
"org.freedesktop.systemd1",
|
2016-12-23 22:56:39 +01:00
|
|
|
path,
|
2016-08-17 14:24:17 +02:00
|
|
|
map,
|
2018-03-28 20:37:27 +09:00
|
|
|
BUS_MAP_STRDUP,
|
2017-02-08 17:59:58 +01:00
|
|
|
&error,
|
2018-03-19 23:46:29 +09:00
|
|
|
NULL,
|
2016-08-17 14:24:17 +02:00
|
|
|
c);
|
|
|
|
|
if (r < 0) {
|
|
|
|
|
sd_event_exit(c->event, EXIT_FAILURE);
|
2017-02-08 17:59:58 +01:00
|
|
|
return log_error_errno(r, "Failed to query unit state: %s", bus_error_message(&error, r));
|
2016-08-17 14:24:17 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
run_context_check_done(c);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2016-12-23 22:56:39 +01:00
|
|
|
static int on_properties_changed(sd_bus_message *m, void *userdata, sd_bus_error *error) {
|
2022-08-09 14:35:15 +02:00
|
|
|
RunContext *c = ASSERT_PTR(userdata);
|
2016-12-23 22:56:39 +01:00
|
|
|
|
|
|
|
|
assert(m);
|
|
|
|
|
|
|
|
|
|
return run_context_update(c, sd_bus_message_get_path(m));
|
|
|
|
|
}
|
|
|
|
|
|
2016-08-17 14:24:17 +02:00
|
|
|
static int pty_forward_handler(PTYForward *f, int rcode, void *userdata) {
|
2024-05-19 08:53:07 +08:00
|
|
|
RunContext *c = ASSERT_PTR(userdata);
|
2016-08-17 14:24:17 +02:00
|
|
|
|
|
|
|
|
assert(f);
|
|
|
|
|
|
2024-05-21 20:10:24 +08:00
|
|
|
if (rcode == -ECANCELED) {
|
2024-05-19 08:53:07 +08:00
|
|
|
log_debug_errno(rcode, "PTY forwarder disconnected.");
|
2024-05-21 20:10:24 +08:00
|
|
|
if (!arg_wait)
|
|
|
|
|
return sd_event_exit(c->event, EXIT_SUCCESS);
|
|
|
|
|
|
|
|
|
|
/* If --wait is specified, we'll only exit the pty forwarding, but will continue to wait
|
|
|
|
|
* for the service to end. If the user hits ^C we'll exit too. */
|
|
|
|
|
} else if (rcode < 0) {
|
2016-08-17 14:24:17 +02:00
|
|
|
sd_event_exit(c->event, EXIT_FAILURE);
|
|
|
|
|
return log_error_errno(rcode, "Error on PTY forwarding logic: %m");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
run_context_check_done(c);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2023-04-02 22:27:58 +02:00
|
|
|
static int make_transient_service_unit(
|
|
|
|
|
sd_bus *bus,
|
|
|
|
|
sd_bus_message **message,
|
|
|
|
|
const char *service,
|
2024-06-06 13:30:09 +02:00
|
|
|
const char *pty_path,
|
|
|
|
|
int pty_fd) {
|
2023-04-02 22:27:58 +02:00
|
|
|
|
|
|
|
|
_cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
|
|
|
|
|
int r;
|
|
|
|
|
|
|
|
|
|
assert(bus);
|
|
|
|
|
assert(message);
|
|
|
|
|
assert(service);
|
|
|
|
|
|
|
|
|
|
r = bus_message_new_method_call(bus, &m, bus_systemd_mgr, "StartTransientUnit");
|
|
|
|
|
if (r < 0)
|
|
|
|
|
return bus_log_create_error(r);
|
|
|
|
|
|
|
|
|
|
/* Name and mode */
|
|
|
|
|
r = sd_bus_message_append(m, "ss", service, "fail");
|
|
|
|
|
if (r < 0)
|
|
|
|
|
return bus_log_create_error(r);
|
|
|
|
|
|
|
|
|
|
/* Properties */
|
|
|
|
|
r = sd_bus_message_open_container(m, 'a', "(sv)");
|
|
|
|
|
if (r < 0)
|
|
|
|
|
return bus_log_create_error(r);
|
|
|
|
|
|
2024-06-06 13:30:09 +02:00
|
|
|
r = transient_service_set_properties(m, pty_path, pty_fd);
|
2023-04-02 22:27:58 +02:00
|
|
|
if (r < 0)
|
|
|
|
|
return r;
|
|
|
|
|
|
|
|
|
|
r = sd_bus_message_close_container(m);
|
|
|
|
|
if (r < 0)
|
|
|
|
|
return bus_log_create_error(r);
|
|
|
|
|
|
|
|
|
|
/* Auxiliary units */
|
|
|
|
|
r = sd_bus_message_append(m, "a(sa(sv))", 0);
|
|
|
|
|
if (r < 0)
|
|
|
|
|
return bus_log_create_error(r);
|
|
|
|
|
|
|
|
|
|
*message = TAKE_PTR(m);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2023-04-02 23:17:58 +02:00
|
|
|
static int bus_call_with_hint(
|
run: introduce timer support option
Support timer options --on-active=, --on-boot=, --on-startup=,
--on-unit-active=, --on-unit-inactive=, --on-calendar=. Each options
corresponding with OnActiveSec=, OnBootSec=, OnStartupSec=,
OnUnitActiveSec=, OnUnitInactiveSec=, OnCalendar= of timer
respectively. And OnCalendar= and WakeSystem= supported by
--timer-property= option like --property= of systemd-run.
And if --unit= option and timer options are specified the command can
be omitted. In this case, systemd-run assumes the target service is
already loaded. And just try to generate transient timer unit only.
2014-12-09 16:07:16 +09:00
|
|
|
sd_bus *bus,
|
2023-04-02 23:17:58 +02:00
|
|
|
sd_bus_message *message,
|
|
|
|
|
const char *name,
|
|
|
|
|
sd_bus_message **reply) {
|
|
|
|
|
|
|
|
|
|
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
|
|
|
|
|
int r;
|
run: introduce timer support option
Support timer options --on-active=, --on-boot=, --on-startup=,
--on-unit-active=, --on-unit-inactive=, --on-calendar=. Each options
corresponding with OnActiveSec=, OnBootSec=, OnStartupSec=,
OnUnitActiveSec=, OnUnitInactiveSec=, OnCalendar= of timer
respectively. And OnCalendar= and WakeSystem= supported by
--timer-property= option like --property= of systemd-run.
And if --unit= option and timer options are specified the command can
be omitted. In this case, systemd-run assumes the target service is
already loaded. And just try to generate transient timer unit only.
2014-12-09 16:07:16 +09:00
|
|
|
|
2023-04-02 23:17:58 +02:00
|
|
|
r = sd_bus_call(bus, message, 0, &error, reply);
|
|
|
|
|
if (r < 0) {
|
|
|
|
|
log_error_errno(r, "Failed to start transient %s unit: %s", name, bus_error_message(&error, r));
|
|
|
|
|
|
2023-07-19 22:56:02 +01:00
|
|
|
if (arg_expand_environment == 0 &&
|
2023-04-02 23:17:58 +02:00
|
|
|
sd_bus_error_has_names(&error,
|
|
|
|
|
SD_BUS_ERROR_UNKNOWN_PROPERTY,
|
|
|
|
|
SD_BUS_ERROR_PROPERTY_READ_ONLY))
|
|
|
|
|
log_notice_errno(r, "Hint: --expand-environment=no is not supported by old systemd");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return r;
|
|
|
|
|
}
|
|
|
|
|
|
2023-10-12 12:03:03 +02:00
|
|
|
static int acquire_invocation_id(sd_bus *bus, const char *unit, sd_id128_t *ret) {
|
|
|
|
|
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
|
|
|
|
|
_cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
|
|
|
|
|
_cleanup_free_ char *object = NULL;
|
|
|
|
|
int r;
|
|
|
|
|
|
|
|
|
|
assert(bus);
|
|
|
|
|
assert(ret);
|
|
|
|
|
|
|
|
|
|
if (unit) {
|
|
|
|
|
object = unit_dbus_path_from_name(unit);
|
|
|
|
|
if (!object)
|
|
|
|
|
return log_oom();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
r = sd_bus_get_property(bus,
|
|
|
|
|
"org.freedesktop.systemd1",
|
|
|
|
|
object ?: "/org/freedesktop/systemd1/unit/self",
|
|
|
|
|
"org.freedesktop.systemd1.Unit",
|
|
|
|
|
"InvocationID",
|
|
|
|
|
&error,
|
|
|
|
|
&reply,
|
|
|
|
|
"ay");
|
|
|
|
|
if (r < 0)
|
|
|
|
|
return log_error_errno(r, "Failed to request invocation ID for unit: %s", bus_error_message(&error, r));
|
|
|
|
|
|
2024-03-01 14:47:52 +01:00
|
|
|
r = bus_message_read_id128(reply, ret);
|
2023-10-12 12:03:03 +02:00
|
|
|
if (r < 0)
|
|
|
|
|
return bus_log_parse_error(r);
|
|
|
|
|
|
2024-04-24 14:58:07 +09:00
|
|
|
return r; /* Return true when we get a non-null invocation ID. */
|
2023-10-12 12:03:03 +02:00
|
|
|
}
|
|
|
|
|
|
2024-02-01 10:43:44 +01:00
|
|
|
static void set_window_title(PTYForward *f) {
|
|
|
|
|
_cleanup_free_ char *hn = NULL, *cl = NULL, *dot = NULL;
|
2024-06-19 09:23:03 +03:00
|
|
|
|
2024-02-01 10:43:44 +01:00
|
|
|
assert(f);
|
|
|
|
|
|
2024-06-19 09:23:03 +03:00
|
|
|
if (!shall_set_terminal_title())
|
|
|
|
|
return;
|
|
|
|
|
|
2024-02-01 10:43:44 +01:00
|
|
|
if (!arg_host)
|
|
|
|
|
(void) gethostname_strict(&hn);
|
|
|
|
|
|
|
|
|
|
cl = strv_join(arg_cmdline, " ");
|
|
|
|
|
if (!cl)
|
|
|
|
|
return (void) log_oom();
|
|
|
|
|
|
|
|
|
|
if (emoji_enabled())
|
|
|
|
|
dot = strjoin(special_glyph(privileged_execution() ? SPECIAL_GLYPH_RED_CIRCLE : SPECIAL_GLYPH_YELLOW_CIRCLE), " ");
|
|
|
|
|
|
|
|
|
|
if (arg_host || hn)
|
|
|
|
|
(void) pty_forward_set_titlef(f, "%s%s on %s", strempty(dot), cl, arg_host ?: hn);
|
|
|
|
|
else
|
|
|
|
|
(void) pty_forward_set_titlef(f, "%s%s", strempty(dot), cl);
|
2024-02-23 15:54:22 +01:00
|
|
|
|
|
|
|
|
(void) pty_forward_set_title_prefix(f, dot);
|
2024-02-01 10:43:44 +01:00
|
|
|
}
|
|
|
|
|
|
2023-10-26 09:19:04 +02:00
|
|
|
static int chown_to_capsule(const char *path, const char *capsule) {
|
|
|
|
|
_cleanup_free_ char *p = NULL;
|
|
|
|
|
int r;
|
|
|
|
|
|
|
|
|
|
assert(path);
|
|
|
|
|
assert(capsule);
|
|
|
|
|
|
|
|
|
|
p = path_join("/run/capsules/", capsule);
|
|
|
|
|
if (!p)
|
|
|
|
|
return -ENOMEM;
|
|
|
|
|
|
|
|
|
|
struct stat st;
|
|
|
|
|
r = chase_and_stat(p, /* root= */ NULL, CHASE_SAFE|CHASE_PROHIBIT_SYMLINKS, /* ret_path= */ NULL, &st);
|
|
|
|
|
if (r < 0)
|
|
|
|
|
return r;
|
|
|
|
|
|
|
|
|
|
if (uid_is_system(st.st_uid) || gid_is_system(st.st_gid)) /* paranoid safety check */
|
|
|
|
|
return -EPERM;
|
|
|
|
|
|
|
|
|
|
return chmod_and_chown(path, 0600, st.st_uid, st.st_gid);
|
|
|
|
|
}
|
|
|
|
|
|
2024-08-12 15:15:15 +02:00
|
|
|
static int print_unit_invocation(const char *unit, sd_id128_t invocation_id) {
|
|
|
|
|
_cleanup_(sd_json_variant_unrefp) sd_json_variant *v = NULL;
|
|
|
|
|
int r;
|
|
|
|
|
|
|
|
|
|
assert(unit);
|
|
|
|
|
|
|
|
|
|
if (FLAGS_SET(arg_json_format_flags, SD_JSON_FORMAT_OFF)) {
|
|
|
|
|
if (sd_id128_is_null(invocation_id))
|
|
|
|
|
log_info("Running as unit: %s", unit);
|
|
|
|
|
else
|
|
|
|
|
log_info("Running as unit: %s; invocation ID: " SD_ID128_FORMAT_STR, unit, SD_ID128_FORMAT_VAL(invocation_id));
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
r = sd_json_variant_set_field_string(&v, "unit", unit);
|
|
|
|
|
if (r < 0)
|
|
|
|
|
return r;
|
|
|
|
|
|
|
|
|
|
if (!sd_id128_is_null(invocation_id)) {
|
2024-08-14 15:53:42 +09:00
|
|
|
r = sd_json_variant_set_field_id128(&v, "invocation_id", invocation_id);
|
2024-08-12 15:15:15 +02:00
|
|
|
if (r < 0)
|
|
|
|
|
return r;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return sd_json_variant_dump(v, arg_json_format_flags, stdout, NULL);
|
|
|
|
|
}
|
|
|
|
|
|
2023-04-02 21:50:19 +02:00
|
|
|
static int start_transient_service(sd_bus *bus) {
|
tree-wide: expose "p"-suffix unref calls in public APIs to make gcc cleanup easy
GLIB has recently started to officially support the gcc cleanup
attribute in its public API, hence let's do the same for our APIs.
With this patch we'll define an xyz_unrefp() call for each public
xyz_unref() call, to make it easy to use inside a
__attribute__((cleanup())) expression. Then, all code is ported over to
make use of this.
The new calls are also documented in the man pages, with examples how to
use them (well, I only added docs where the _unref() call itself already
had docs, and the examples, only cover sd_bus_unrefp() and
sd_event_unrefp()).
This also renames sd_lldp_free() to sd_lldp_unref(), since that's how we
tend to call our destructors these days.
Note that this defines no public macro that wraps gcc's attribute and
makes it easier to use. While I think it's our duty in the library to
make our stuff easy to use, I figure it's not our duty to make gcc's own
features easy to use on its own. Most likely, client code which wants to
make use of this should define its own:
#define _cleanup_(function) __attribute__((cleanup(function)))
Or similar, to make the gcc feature easier to use.
Making this logic public has the benefit that we can remove three header
files whose only purpose was to define these functions internally.
See #2008.
2015-11-27 19:13:45 +01:00
|
|
|
_cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL, *reply = NULL;
|
|
|
|
|
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
|
2015-04-28 12:33:19 +02:00
|
|
|
_cleanup_(bus_wait_for_jobs_freep) BusWaitForJobs *w = NULL;
|
2014-12-23 01:58:49 +01:00
|
|
|
_cleanup_free_ char *service = NULL, *pty_path = NULL;
|
2024-06-06 13:30:09 +02:00
|
|
|
_cleanup_close_ int master = -EBADF, slave = -EBADF;
|
run: introduce timer support option
Support timer options --on-active=, --on-boot=, --on-startup=,
--on-unit-active=, --on-unit-inactive=, --on-calendar=. Each options
corresponding with OnActiveSec=, OnBootSec=, OnStartupSec=,
OnUnitActiveSec=, OnUnitInactiveSec=, OnCalendar= of timer
respectively. And OnCalendar= and WakeSystem= supported by
--timer-property= option like --property= of systemd-run.
And if --unit= option and timer options are specified the command can
be omitted. In this case, systemd-run assumes the target service is
already loaded. And just try to generate transient timer unit only.
2014-12-09 16:07:16 +09:00
|
|
|
int r;
|
|
|
|
|
|
|
|
|
|
assert(bus);
|
|
|
|
|
|
2024-08-16 20:00:25 +09:00
|
|
|
(void) polkit_agent_open_if_enabled(arg_transport, arg_ask_password);
|
|
|
|
|
|
2017-09-08 15:38:40 +02:00
|
|
|
if (arg_stdio == ARG_STDIO_PTY) {
|
2014-12-22 19:45:32 +01:00
|
|
|
|
2023-10-26 09:19:04 +02:00
|
|
|
if (IN_SET(arg_transport, BUS_TRANSPORT_LOCAL, BUS_TRANSPORT_CAPSULE)) {
|
2018-05-31 12:04:37 +02:00
|
|
|
master = posix_openpt(O_RDWR|O_NOCTTY|O_CLOEXEC|O_NONBLOCK);
|
2014-12-23 01:58:49 +01:00
|
|
|
if (master < 0)
|
|
|
|
|
return log_error_errno(errno, "Failed to acquire pseudo tty: %m");
|
|
|
|
|
|
|
|
|
|
r = ptsname_malloc(master, &pty_path);
|
|
|
|
|
if (r < 0)
|
|
|
|
|
return log_error_errno(r, "Failed to determine tty name: %m");
|
|
|
|
|
|
2023-10-26 09:19:04 +02:00
|
|
|
if (arg_transport == BUS_TRANSPORT_CAPSULE) {
|
|
|
|
|
/* If we are in capsule mode, we must give the capsule UID/GID access to the PTY we just allocated first. */
|
|
|
|
|
|
|
|
|
|
r = chown_to_capsule(pty_path, arg_host);
|
|
|
|
|
if (r < 0)
|
|
|
|
|
return log_error_errno(r, "Failed to chown tty to capsule UID/GID: %m");
|
|
|
|
|
}
|
|
|
|
|
|
2015-09-01 19:39:14 +02:00
|
|
|
if (unlockpt(master) < 0)
|
|
|
|
|
return log_error_errno(errno, "Failed to unlock tty: %m");
|
|
|
|
|
|
2024-06-06 13:30:09 +02:00
|
|
|
slave = open_terminal(pty_path, O_RDWR|O_NOCTTY|O_CLOEXEC);
|
|
|
|
|
if (slave < 0)
|
|
|
|
|
return log_error_errno(slave, "Failed to open pty slave: %m");
|
|
|
|
|
|
2014-12-23 23:38:13 +01:00
|
|
|
} else if (arg_transport == BUS_TRANSPORT_MACHINE) {
|
tree-wide: expose "p"-suffix unref calls in public APIs to make gcc cleanup easy
GLIB has recently started to officially support the gcc cleanup
attribute in its public API, hence let's do the same for our APIs.
With this patch we'll define an xyz_unrefp() call for each public
xyz_unref() call, to make it easy to use inside a
__attribute__((cleanup())) expression. Then, all code is ported over to
make use of this.
The new calls are also documented in the man pages, with examples how to
use them (well, I only added docs where the _unref() call itself already
had docs, and the examples, only cover sd_bus_unrefp() and
sd_event_unrefp()).
This also renames sd_lldp_free() to sd_lldp_unref(), since that's how we
tend to call our destructors these days.
Note that this defines no public macro that wraps gcc's attribute and
makes it easier to use. While I think it's our duty in the library to
make our stuff easy to use, I figure it's not our duty to make gcc's own
features easy to use on its own. Most likely, client code which wants to
make use of this should define its own:
#define _cleanup_(function) __attribute__((cleanup(function)))
Or similar, to make the gcc feature easier to use.
Making this logic public has the benefit that we can remove three header
files whose only purpose was to define these functions internally.
See #2008.
2015-11-27 19:13:45 +01:00
|
|
|
_cleanup_(sd_bus_unrefp) sd_bus *system_bus = NULL;
|
2016-05-21 18:30:33 -04:00
|
|
|
_cleanup_(sd_bus_message_unrefp) sd_bus_message *pty_reply = NULL;
|
2014-12-23 01:58:49 +01:00
|
|
|
const char *s;
|
|
|
|
|
|
2015-10-08 15:01:42 +02:00
|
|
|
r = sd_bus_default_system(&system_bus);
|
2014-12-23 01:58:49 +01:00
|
|
|
if (r < 0)
|
2015-10-08 15:01:42 +02:00
|
|
|
return log_error_errno(r, "Failed to connect to system bus: %m");
|
2014-12-23 01:58:49 +01:00
|
|
|
|
2024-08-16 20:00:25 +09:00
|
|
|
(void) sd_bus_set_allow_interactive_authorization(system_bus, arg_ask_password);
|
|
|
|
|
|
2023-05-03 18:41:10 -07:00
|
|
|
r = bus_call_method(system_bus,
|
|
|
|
|
bus_machine_mgr,
|
|
|
|
|
"OpenMachinePTY",
|
|
|
|
|
&error,
|
|
|
|
|
&pty_reply,
|
|
|
|
|
"s", arg_host);
|
2018-08-07 10:14:30 +09:00
|
|
|
if (r < 0)
|
2020-09-14 18:16:54 +02:00
|
|
|
return log_error_errno(r, "Failed to get machine PTY: %s", bus_error_message(&error, r));
|
2014-12-23 01:58:49 +01:00
|
|
|
|
2016-05-21 18:30:33 -04:00
|
|
|
r = sd_bus_message_read(pty_reply, "hs", &master, &s);
|
2014-12-23 01:58:49 +01:00
|
|
|
if (r < 0)
|
|
|
|
|
return bus_log_parse_error(r);
|
|
|
|
|
|
|
|
|
|
master = fcntl(master, F_DUPFD_CLOEXEC, 3);
|
|
|
|
|
if (master < 0)
|
|
|
|
|
return log_error_errno(errno, "Failed to duplicate master fd: %m");
|
|
|
|
|
|
|
|
|
|
pty_path = strdup(s);
|
|
|
|
|
if (!pty_path)
|
|
|
|
|
return log_oom();
|
2024-06-06 13:30:09 +02:00
|
|
|
|
|
|
|
|
// FIXME: Introduce OpenMachinePTYEx() that accepts ownership/permission as param
|
|
|
|
|
// and additionally returns the pty fd, for #33216 and #32999
|
2014-12-23 01:58:49 +01:00
|
|
|
} else
|
Drop the text argument from assert_not_reached()
In general we almost never hit those asserts in production code, so users see
them very rarely, if ever. But either way, we just need something that users
can pass to the developers.
We have quite a few of those asserts, and some have fairly nice messages, but
many are like "WTF?" or "???" or "unexpected something". The error that is
printed includes the file location, and function name. In almost all functions
there's at most one assert, so the function name alone is enough to identify
the failure for a developer. So we don't get much extra from the message, and
we might just as well drop them.
Dropping them makes our code a tiny bit smaller, and most importantly, improves
development experience by making it easy to insert such an assert in the code
without thinking how to phrase the argument.
2021-07-27 12:27:28 +02:00
|
|
|
assert_not_reached();
|
2014-12-22 19:45:32 +01:00
|
|
|
}
|
|
|
|
|
|
2020-04-22 20:08:34 +02:00
|
|
|
/* Optionally, wait for the start job to complete. If we are supposed to read the service's stdin
|
|
|
|
|
* lets skip this however, because we should start that already when the start job is running, and
|
|
|
|
|
* there's little point in waiting for the start job to complete in that case anyway, as we'll wait
|
|
|
|
|
* for EOF anyway, which is going to be much later. */
|
|
|
|
|
if (!arg_no_block && arg_stdio == ARG_STDIO_NONE) {
|
2015-04-28 12:33:19 +02:00
|
|
|
r = bus_wait_for_jobs_new(bus, &w);
|
|
|
|
|
if (r < 0)
|
|
|
|
|
return log_error_errno(r, "Could not watch jobs: %m");
|
|
|
|
|
}
|
|
|
|
|
|
run: introduce timer support option
Support timer options --on-active=, --on-boot=, --on-startup=,
--on-unit-active=, --on-unit-inactive=, --on-calendar=. Each options
corresponding with OnActiveSec=, OnBootSec=, OnStartupSec=,
OnUnitActiveSec=, OnUnitInactiveSec=, OnCalendar= of timer
respectively. And OnCalendar= and WakeSystem= supported by
--timer-property= option like --property= of systemd-run.
And if --unit= option and timer options are specified the command can
be omitted. In this case, systemd-run assumes the target service is
already loaded. And just try to generate transient timer unit only.
2014-12-09 16:07:16 +09:00
|
|
|
if (arg_unit) {
|
2019-10-24 14:09:11 +02:00
|
|
|
r = unit_name_mangle_with_suffix(arg_unit, "as unit",
|
|
|
|
|
arg_quiet ? 0 : UNIT_NAME_MANGLE_WARN,
|
|
|
|
|
".service", &service);
|
2015-04-30 20:21:00 +02:00
|
|
|
if (r < 0)
|
|
|
|
|
return log_error_errno(r, "Failed to mangle unit name: %m");
|
run: when automatically generating names for transient units, use unique bus ID, fallback to random
Previously we used the process ID to generate transient unit names.
However, that is problematic as PIDs get reused easily, and applying
them to remote systems makes little sense.
Fortunately, each bus peer gets a unique, non-reusable ID assigned when
attaching to a bus, hence let's use that, if we can. In some cases we
cannot however, because we connect directly to PID's private socket, and
thus are not a proper bus peer with a unique ID. In that case generate a
random UUID to name the unit after.
2015-11-17 14:11:12 +01:00
|
|
|
} else {
|
|
|
|
|
r = make_unit_name(bus, UNIT_SERVICE, &service);
|
|
|
|
|
if (r < 0)
|
|
|
|
|
return r;
|
|
|
|
|
}
|
run: introduce timer support option
Support timer options --on-active=, --on-boot=, --on-startup=,
--on-unit-active=, --on-unit-inactive=, --on-calendar=. Each options
corresponding with OnActiveSec=, OnBootSec=, OnStartupSec=,
OnUnitActiveSec=, OnUnitInactiveSec=, OnCalendar= of timer
respectively. And OnCalendar= and WakeSystem= supported by
--timer-property= option like --property= of systemd-run.
And if --unit= option and timer options are specified the command can
be omitted. In this case, systemd-run assumes the target service is
already loaded. And just try to generate transient timer unit only.
2014-12-09 16:07:16 +09:00
|
|
|
|
2024-06-06 13:30:09 +02:00
|
|
|
r = make_transient_service_unit(bus, &m, service, pty_path, slave);
|
2013-06-28 04:12:58 +02:00
|
|
|
if (r < 0)
|
2017-11-29 20:05:22 +01:00
|
|
|
return r;
|
2024-06-06 13:30:09 +02:00
|
|
|
slave = safe_close(slave);
|
2013-06-28 04:12:58 +02:00
|
|
|
|
2023-04-02 23:17:58 +02:00
|
|
|
r = bus_call_with_hint(bus, m, "service", &reply);
|
2015-10-08 15:01:42 +02:00
|
|
|
if (r < 0)
|
2023-04-02 23:17:58 +02:00
|
|
|
return r;
|
2013-06-28 04:12:58 +02:00
|
|
|
|
2015-04-28 12:33:19 +02:00
|
|
|
if (w) {
|
|
|
|
|
const char *object;
|
|
|
|
|
|
|
|
|
|
r = sd_bus_message_read(reply, "o", &object);
|
|
|
|
|
if (r < 0)
|
|
|
|
|
return bus_log_parse_error(r);
|
|
|
|
|
|
2023-11-29 14:01:13 +01:00
|
|
|
r = bus_wait_for_jobs_one(w,
|
|
|
|
|
object,
|
2023-12-14 15:22:14 +01:00
|
|
|
arg_quiet ? 0 : BUS_WAIT_JOBS_LOG_ERROR,
|
2023-11-29 14:01:13 +01:00
|
|
|
arg_runtime_scope == RUNTIME_SCOPE_USER ? STRV_MAKE_CONST("--user") : NULL);
|
2015-04-28 12:33:19 +02:00
|
|
|
if (r < 0)
|
|
|
|
|
return r;
|
|
|
|
|
}
|
|
|
|
|
|
2023-10-12 12:03:03 +02:00
|
|
|
if (!arg_quiet) {
|
2024-08-14 15:45:31 +09:00
|
|
|
sd_id128_t invocation_id;
|
2023-10-12 12:03:03 +02:00
|
|
|
|
|
|
|
|
r = acquire_invocation_id(bus, service, &invocation_id);
|
|
|
|
|
if (r < 0)
|
|
|
|
|
return r;
|
2024-08-12 15:15:15 +02:00
|
|
|
|
|
|
|
|
r = print_unit_invocation(service, invocation_id);
|
|
|
|
|
if (r < 0)
|
|
|
|
|
return r;
|
2023-10-12 12:03:03 +02:00
|
|
|
}
|
2016-08-17 14:24:17 +02:00
|
|
|
|
2017-09-08 15:38:40 +02:00
|
|
|
if (arg_wait || arg_stdio != ARG_STDIO_NONE) {
|
2017-09-26 16:33:03 +02:00
|
|
|
_cleanup_(run_context_free) RunContext c = {
|
|
|
|
|
.cpu_usage_nsec = NSEC_INFINITY,
|
2023-11-06 17:28:41 +01:00
|
|
|
.memory_peak = UINT64_MAX,
|
2023-11-08 19:22:06 +01:00
|
|
|
.memory_swap_peak = UINT64_MAX,
|
2017-09-26 16:33:03 +02:00
|
|
|
.ip_ingress_bytes = UINT64_MAX,
|
|
|
|
|
.ip_egress_bytes = UINT64_MAX,
|
2019-03-22 12:18:19 +01:00
|
|
|
.io_read_bytes = UINT64_MAX,
|
|
|
|
|
.io_write_bytes = UINT64_MAX,
|
2017-09-26 16:33:03 +02:00
|
|
|
.inactive_exit_usec = USEC_INFINITY,
|
|
|
|
|
.inactive_enter_usec = USEC_INFINITY,
|
|
|
|
|
};
|
2016-12-24 00:35:58 +01:00
|
|
|
_cleanup_free_ char *path = NULL;
|
run: introduce timer support option
Support timer options --on-active=, --on-boot=, --on-startup=,
--on-unit-active=, --on-unit-inactive=, --on-calendar=. Each options
corresponding with OnActiveSec=, OnBootSec=, OnStartupSec=,
OnUnitActiveSec=, OnUnitInactiveSec=, OnCalendar= of timer
respectively. And OnCalendar= and WakeSystem= supported by
--timer-property= option like --property= of systemd-run.
And if --unit= option and timer options are specified the command can
be omitted. In this case, systemd-run assumes the target service is
already loaded. And just try to generate transient timer unit only.
2014-12-09 16:07:16 +09:00
|
|
|
|
2016-08-17 14:24:17 +02:00
|
|
|
c.bus = sd_bus_ref(bus);
|
|
|
|
|
|
|
|
|
|
r = sd_event_default(&c.event);
|
run: introduce timer support option
Support timer options --on-active=, --on-boot=, --on-startup=,
--on-unit-active=, --on-unit-inactive=, --on-calendar=. Each options
corresponding with OnActiveSec=, OnBootSec=, OnStartupSec=,
OnUnitActiveSec=, OnUnitInactiveSec=, OnCalendar= of timer
respectively. And OnCalendar= and WakeSystem= supported by
--timer-property= option like --property= of systemd-run.
And if --unit= option and timer options are specified the command can
be omitted. In this case, systemd-run assumes the target service is
already loaded. And just try to generate transient timer unit only.
2014-12-09 16:07:16 +09:00
|
|
|
if (r < 0)
|
2014-12-22 19:45:32 +01:00
|
|
|
return log_error_errno(r, "Failed to get event loop: %m");
|
run: introduce timer support option
Support timer options --on-active=, --on-boot=, --on-startup=,
--on-unit-active=, --on-unit-inactive=, --on-calendar=. Each options
corresponding with OnActiveSec=, OnBootSec=, OnStartupSec=,
OnUnitActiveSec=, OnUnitInactiveSec=, OnCalendar= of timer
respectively. And OnCalendar= and WakeSystem= supported by
--timer-property= option like --property= of systemd-run.
And if --unit= option and timer options are specified the command can
be omitted. In this case, systemd-run assumes the target service is
already loaded. And just try to generate transient timer unit only.
2014-12-09 16:07:16 +09:00
|
|
|
|
2016-08-17 14:24:17 +02:00
|
|
|
if (master >= 0) {
|
2024-02-23 12:19:43 +01:00
|
|
|
(void) sd_event_set_signal_exit(c.event, true);
|
2016-08-17 14:24:17 +02:00
|
|
|
|
|
|
|
|
if (!arg_quiet)
|
|
|
|
|
log_info("Press ^] three times within 1s to disconnect TTY.");
|
run: introduce timer support option
Support timer options --on-active=, --on-boot=, --on-startup=,
--on-unit-active=, --on-unit-inactive=, --on-calendar=. Each options
corresponding with OnActiveSec=, OnBootSec=, OnStartupSec=,
OnUnitActiveSec=, OnUnitInactiveSec=, OnCalendar= of timer
respectively. And OnCalendar= and WakeSystem= supported by
--timer-property= option like --property= of systemd-run.
And if --unit= option and timer options are specified the command can
be omitted. In this case, systemd-run assumes the target service is
already loaded. And just try to generate transient timer unit only.
2014-12-09 16:07:16 +09:00
|
|
|
|
2016-08-17 14:24:17 +02:00
|
|
|
r = pty_forward_new(c.event, master, PTY_FORWARD_IGNORE_INITIAL_VHANGUP, &c.forward);
|
|
|
|
|
if (r < 0)
|
|
|
|
|
return log_error_errno(r, "Failed to create PTY forwarder: %m");
|
|
|
|
|
|
|
|
|
|
pty_forward_set_handler(c.forward, pty_forward_handler, &c);
|
2017-12-05 18:31:32 +01:00
|
|
|
|
|
|
|
|
/* Make sure to process any TTY events before we process bus events */
|
|
|
|
|
(void) pty_forward_set_priority(c.forward, SD_EVENT_PRIORITY_IMPORTANT);
|
2023-12-20 12:09:27 +01:00
|
|
|
|
|
|
|
|
if (!isempty(arg_background))
|
|
|
|
|
(void) pty_forward_set_background_color(c.forward, arg_background);
|
2024-02-01 10:43:44 +01:00
|
|
|
|
|
|
|
|
set_window_title(c.forward);
|
2016-08-17 14:24:17 +02:00
|
|
|
}
|
run: introduce timer support option
Support timer options --on-active=, --on-boot=, --on-startup=,
--on-unit-active=, --on-unit-inactive=, --on-calendar=. Each options
corresponding with OnActiveSec=, OnBootSec=, OnStartupSec=,
OnUnitActiveSec=, OnUnitInactiveSec=, OnCalendar= of timer
respectively. And OnCalendar= and WakeSystem= supported by
--timer-property= option like --property= of systemd-run.
And if --unit= option and timer options are specified the command can
be omitted. In this case, systemd-run assumes the target service is
already loaded. And just try to generate transient timer unit only.
2014-12-09 16:07:16 +09:00
|
|
|
|
2016-12-24 00:35:58 +01:00
|
|
|
path = unit_dbus_path_from_name(service);
|
|
|
|
|
if (!path)
|
|
|
|
|
return log_oom();
|
2016-08-17 14:24:17 +02:00
|
|
|
|
2017-12-19 12:29:04 +01:00
|
|
|
r = sd_bus_match_signal_async(
|
|
|
|
|
bus,
|
|
|
|
|
&c.match,
|
|
|
|
|
"org.freedesktop.systemd1",
|
|
|
|
|
path,
|
|
|
|
|
"org.freedesktop.DBus.Properties",
|
|
|
|
|
"PropertiesChanged",
|
|
|
|
|
on_properties_changed, NULL, &c);
|
2016-12-24 00:35:58 +01:00
|
|
|
if (r < 0)
|
2017-12-19 12:29:04 +01:00
|
|
|
return log_error_errno(r, "Failed to request properties changed signal match: %m");
|
run: introduce timer support option
Support timer options --on-active=, --on-boot=, --on-startup=,
--on-unit-active=, --on-unit-inactive=, --on-calendar=. Each options
corresponding with OnActiveSec=, OnBootSec=, OnStartupSec=,
OnUnitActiveSec=, OnUnitInactiveSec=, OnCalendar= of timer
respectively. And OnCalendar= and WakeSystem= supported by
--timer-property= option like --property= of systemd-run.
And if --unit= option and timer options are specified the command can
be omitted. In this case, systemd-run assumes the target service is
already loaded. And just try to generate transient timer unit only.
2014-12-09 16:07:16 +09:00
|
|
|
|
2017-12-05 18:31:32 +01:00
|
|
|
r = sd_bus_attach_event(bus, c.event, SD_EVENT_PRIORITY_NORMAL);
|
2016-12-24 00:35:58 +01:00
|
|
|
if (r < 0)
|
2017-12-19 12:29:04 +01:00
|
|
|
return log_error_errno(r, "Failed to attach bus to event loop: %m");
|
2016-12-23 22:56:39 +01:00
|
|
|
|
2016-12-24 00:35:58 +01:00
|
|
|
r = run_context_update(&c, path);
|
|
|
|
|
if (r < 0)
|
|
|
|
|
return r;
|
2016-08-17 14:24:17 +02:00
|
|
|
|
|
|
|
|
r = sd_event_loop(c.event);
|
run: introduce timer support option
Support timer options --on-active=, --on-boot=, --on-startup=,
--on-unit-active=, --on-unit-inactive=, --on-calendar=. Each options
corresponding with OnActiveSec=, OnBootSec=, OnStartupSec=,
OnUnitActiveSec=, OnUnitInactiveSec=, OnCalendar= of timer
respectively. And OnCalendar= and WakeSystem= supported by
--timer-property= option like --property= of systemd-run.
And if --unit= option and timer options are specified the command can
be omitted. In this case, systemd-run assumes the target service is
already loaded. And just try to generate transient timer unit only.
2014-12-09 16:07:16 +09:00
|
|
|
if (r < 0)
|
2014-12-22 19:45:32 +01:00
|
|
|
return log_error_errno(r, "Failed to run event loop: %m");
|
run: introduce timer support option
Support timer options --on-active=, --on-boot=, --on-startup=,
--on-unit-active=, --on-unit-inactive=, --on-calendar=. Each options
corresponding with OnActiveSec=, OnBootSec=, OnStartupSec=,
OnUnitActiveSec=, OnUnitInactiveSec=, OnCalendar= of timer
respectively. And OnCalendar= and WakeSystem= supported by
--timer-property= option like --property= of systemd-run.
And if --unit= option and timer options are specified the command can
be omitted. In this case, systemd-run assumes the target service is
already loaded. And just try to generate transient timer unit only.
2014-12-09 16:07:16 +09:00
|
|
|
|
2016-08-17 14:24:17 +02:00
|
|
|
if (c.forward) {
|
|
|
|
|
char last_char = 0;
|
run: introduce timer support option
Support timer options --on-active=, --on-boot=, --on-startup=,
--on-unit-active=, --on-unit-inactive=, --on-calendar=. Each options
corresponding with OnActiveSec=, OnBootSec=, OnStartupSec=,
OnUnitActiveSec=, OnUnitInactiveSec=, OnCalendar= of timer
respectively. And OnCalendar= and WakeSystem= supported by
--timer-property= option like --property= of systemd-run.
And if --unit= option and timer options are specified the command can
be omitted. In this case, systemd-run assumes the target service is
already loaded. And just try to generate transient timer unit only.
2014-12-09 16:07:16 +09:00
|
|
|
|
2016-08-17 14:24:17 +02:00
|
|
|
r = pty_forward_get_last_char(c.forward, &last_char);
|
|
|
|
|
if (r >= 0 && !arg_quiet && last_char != '\n')
|
|
|
|
|
fputc('\n', stdout);
|
|
|
|
|
}
|
run: introduce timer support option
Support timer options --on-active=, --on-boot=, --on-startup=,
--on-unit-active=, --on-unit-inactive=, --on-calendar=. Each options
corresponding with OnActiveSec=, OnBootSec=, OnStartupSec=,
OnUnitActiveSec=, OnUnitInactiveSec=, OnCalendar= of timer
respectively. And OnCalendar= and WakeSystem= supported by
--timer-property= option like --property= of systemd-run.
And if --unit= option and timer options are specified the command can
be omitted. In this case, systemd-run assumes the target service is
already loaded. And just try to generate transient timer unit only.
2014-12-09 16:07:16 +09:00
|
|
|
|
2016-12-24 00:35:58 +01:00
|
|
|
if (arg_wait && !arg_quiet) {
|
2016-12-24 00:34:34 +01:00
|
|
|
|
2019-10-29 17:30:36 +01:00
|
|
|
/* Explicitly destroy the PTY forwarder, so that the PTY device is usable again, with its
|
2016-12-24 00:34:34 +01:00
|
|
|
* original settings (i.e. proper line breaks), so that we can show the summary in a pretty
|
|
|
|
|
* way. */
|
|
|
|
|
c.forward = pty_forward_free(c.forward);
|
|
|
|
|
|
2016-08-17 14:24:17 +02:00
|
|
|
if (!isempty(c.result))
|
|
|
|
|
log_info("Finished with result: %s", strna(c.result));
|
2013-07-01 00:40:56 +02:00
|
|
|
|
2024-05-26 10:33:59 +08:00
|
|
|
if (c.exit_code > 0)
|
|
|
|
|
log_info("Main processes terminated with: code=%s, status=%u/%s",
|
|
|
|
|
sigchld_code_to_string(c.exit_code),
|
|
|
|
|
c.exit_status,
|
|
|
|
|
strna(c.exit_code == CLD_EXITED ?
|
|
|
|
|
exit_status_to_string(c.exit_status, EXIT_STATUS_FULL) :
|
|
|
|
|
signal_to_string(c.exit_status)));
|
2016-08-17 14:24:17 +02:00
|
|
|
|
2019-07-04 19:10:11 +02:00
|
|
|
if (timestamp_is_set(c.inactive_enter_usec) &&
|
|
|
|
|
timestamp_is_set(c.inactive_exit_usec) &&
|
2021-07-01 14:32:46 +02:00
|
|
|
c.inactive_enter_usec > c.inactive_exit_usec)
|
2019-10-29 17:30:36 +01:00
|
|
|
log_info("Service runtime: %s",
|
2021-07-01 14:32:46 +02:00
|
|
|
FORMAT_TIMESPAN(c.inactive_enter_usec - c.inactive_exit_usec, USEC_PER_MSEC));
|
2016-08-17 14:24:17 +02:00
|
|
|
|
2021-07-01 14:32:46 +02:00
|
|
|
if (c.cpu_usage_nsec != NSEC_INFINITY)
|
2019-10-29 17:30:36 +01:00
|
|
|
log_info("CPU time consumed: %s",
|
2021-07-01 14:32:46 +02:00
|
|
|
FORMAT_TIMESPAN(DIV_ROUND_UP(c.cpu_usage_nsec, NSEC_PER_USEC), USEC_PER_MSEC));
|
2017-09-26 16:33:03 +02:00
|
|
|
|
2024-01-12 16:57:13 +08:00
|
|
|
if (c.memory_peak != UINT64_MAX) {
|
|
|
|
|
const char *swap;
|
2023-11-06 17:28:41 +01:00
|
|
|
|
2024-01-12 16:57:13 +08:00
|
|
|
if (c.memory_swap_peak != UINT64_MAX)
|
2024-01-17 21:35:47 +08:00
|
|
|
swap = strjoina(" (swap: ", FORMAT_BYTES(c.memory_swap_peak), ")");
|
2024-01-12 16:57:13 +08:00
|
|
|
else
|
|
|
|
|
swap = "";
|
2023-11-08 19:22:06 +01:00
|
|
|
|
2024-01-12 16:57:13 +08:00
|
|
|
log_info("Memory peak: %s%s", FORMAT_BYTES(c.memory_peak), swap);
|
|
|
|
|
}
|
2021-07-06 09:14:01 +02:00
|
|
|
|
2024-01-12 16:57:13 +08:00
|
|
|
const char *ip_ingress = NULL, *ip_egress = NULL;
|
|
|
|
|
|
2024-01-12 17:35:21 +08:00
|
|
|
if (!IN_SET(c.ip_ingress_bytes, 0, UINT64_MAX))
|
2024-01-12 16:57:13 +08:00
|
|
|
ip_ingress = strjoina(" received: ", FORMAT_BYTES(c.ip_ingress_bytes));
|
2024-01-12 17:35:21 +08:00
|
|
|
if (!IN_SET(c.ip_egress_bytes, 0, UINT64_MAX))
|
2024-01-12 16:57:13 +08:00
|
|
|
ip_egress = strjoina(" sent: ", FORMAT_BYTES(c.ip_egress_bytes));
|
2021-07-06 09:14:01 +02:00
|
|
|
|
2024-01-12 16:57:13 +08:00
|
|
|
if (ip_ingress || ip_egress)
|
|
|
|
|
log_info("IP traffic%s%s", strempty(ip_ingress), strempty(ip_egress));
|
|
|
|
|
|
|
|
|
|
const char *io_read = NULL, *io_write = NULL;
|
2021-07-06 09:14:01 +02:00
|
|
|
|
2024-01-12 17:35:21 +08:00
|
|
|
if (!IN_SET(c.io_read_bytes, 0, UINT64_MAX))
|
2024-01-17 21:35:47 +08:00
|
|
|
io_read = strjoina(" read: ", FORMAT_BYTES(c.io_read_bytes));
|
2024-01-12 17:35:21 +08:00
|
|
|
if (!IN_SET(c.io_write_bytes, 0, UINT64_MAX))
|
2024-01-17 21:35:47 +08:00
|
|
|
io_write = strjoina(" written: ", FORMAT_BYTES(c.io_write_bytes));
|
2024-01-12 16:57:13 +08:00
|
|
|
|
|
|
|
|
if (io_read || io_write)
|
|
|
|
|
log_info("IO bytes%s%s", strempty(io_read), strempty(io_write));
|
2016-08-17 14:24:17 +02:00
|
|
|
}
|
|
|
|
|
|
2019-10-29 18:07:07 +01:00
|
|
|
/* Try to propagate the service's return value. But if the service defines
|
|
|
|
|
* e.g. SuccessExitStatus, honour this, and return 0 to mean "success". */
|
|
|
|
|
if (streq_ptr(c.result, "success"))
|
2023-04-02 21:50:19 +02:00
|
|
|
return EXIT_SUCCESS;
|
|
|
|
|
if (streq_ptr(c.result, "exit-code") && c.exit_status > 0)
|
|
|
|
|
return c.exit_status;
|
|
|
|
|
if (streq_ptr(c.result, "signal"))
|
|
|
|
|
return EXIT_EXCEPTION;
|
|
|
|
|
return EXIT_FAILURE;
|
2016-08-17 14:24:17 +02:00
|
|
|
}
|
2014-03-05 19:02:53 +01:00
|
|
|
|
2023-04-02 21:50:19 +02:00
|
|
|
return EXIT_SUCCESS;
|
2013-07-01 00:03:57 +02:00
|
|
|
}
|
|
|
|
|
|
2018-11-22 20:40:00 +01:00
|
|
|
static int start_transient_scope(sd_bus *bus) {
|
2023-10-12 12:02:03 +02:00
|
|
|
_cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
|
2015-04-28 12:21:31 +02:00
|
|
|
_cleanup_(bus_wait_for_jobs_freep) BusWaitForJobs *w = NULL;
|
2023-06-26 17:20:49 +02:00
|
|
|
_cleanup_strv_free_ char **env = NULL, **user_env = NULL;
|
run: introduce timer support option
Support timer options --on-active=, --on-boot=, --on-startup=,
--on-unit-active=, --on-unit-inactive=, --on-calendar=. Each options
corresponding with OnActiveSec=, OnBootSec=, OnStartupSec=,
OnUnitActiveSec=, OnUnitInactiveSec=, OnCalendar= of timer
respectively. And OnCalendar= and WakeSystem= supported by
--timer-property= option like --property= of systemd-run.
And if --unit= option and timer options are specified the command can
be omitted. In this case, systemd-run assumes the target service is
already loaded. And just try to generate transient timer unit only.
2014-12-09 16:07:16 +09:00
|
|
|
_cleanup_free_ char *scope = NULL;
|
2015-04-28 12:21:31 +02:00
|
|
|
const char *object = NULL;
|
2024-08-14 15:45:31 +09:00
|
|
|
sd_id128_t invocation_id;
|
2023-10-12 12:02:03 +02:00
|
|
|
bool allow_pidfd = true;
|
2013-07-01 00:03:57 +02:00
|
|
|
int r;
|
|
|
|
|
|
2013-11-08 19:49:49 +01:00
|
|
|
assert(bus);
|
2018-11-22 19:24:48 +01:00
|
|
|
assert(!strv_isempty(arg_cmdline));
|
2013-11-08 19:49:49 +01:00
|
|
|
|
2015-04-28 12:21:31 +02:00
|
|
|
r = bus_wait_for_jobs_new(bus, &w);
|
|
|
|
|
if (r < 0)
|
2023-05-26 15:09:03 +02:00
|
|
|
return log_error_errno(r, "Could not watch jobs: %m");
|
2015-04-28 12:21:31 +02:00
|
|
|
|
2014-07-25 15:38:31 +02:00
|
|
|
if (arg_unit) {
|
2019-10-24 14:09:11 +02:00
|
|
|
r = unit_name_mangle_with_suffix(arg_unit, "as unit",
|
|
|
|
|
arg_quiet ? 0 : UNIT_NAME_MANGLE_WARN,
|
|
|
|
|
".scope", &scope);
|
2015-04-30 20:21:00 +02:00
|
|
|
if (r < 0)
|
|
|
|
|
return log_error_errno(r, "Failed to mangle scope name: %m");
|
run: when automatically generating names for transient units, use unique bus ID, fallback to random
Previously we used the process ID to generate transient unit names.
However, that is problematic as PIDs get reused easily, and applying
them to remote systems makes little sense.
Fortunately, each bus peer gets a unique, non-reusable ID assigned when
attaching to a bus, hence let's use that, if we can. In some cases we
cannot however, because we connect directly to PID's private socket, and
thus are not a proper bus peer with a unique ID. In that case generate a
random UUID to name the unit after.
2015-11-17 14:11:12 +01:00
|
|
|
} else {
|
|
|
|
|
r = make_unit_name(bus, UNIT_SCOPE, &scope);
|
|
|
|
|
if (r < 0)
|
|
|
|
|
return r;
|
|
|
|
|
}
|
2013-07-01 00:03:57 +02:00
|
|
|
|
2024-08-16 19:33:41 +09:00
|
|
|
(void) polkit_agent_open_if_enabled(arg_transport, arg_ask_password);
|
2013-06-28 04:12:58 +02:00
|
|
|
|
2023-10-12 12:02:03 +02:00
|
|
|
for (;;) {
|
|
|
|
|
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
|
|
|
|
|
_cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
|
2015-09-01 16:43:08 +00:00
|
|
|
|
2023-10-12 12:02:03 +02:00
|
|
|
r = bus_message_new_method_call(bus, &m, bus_systemd_mgr, "StartTransientUnit");
|
|
|
|
|
if (r < 0)
|
|
|
|
|
return bus_log_create_error(r);
|
run: introduce timer support option
Support timer options --on-active=, --on-boot=, --on-startup=,
--on-unit-active=, --on-unit-inactive=, --on-calendar=. Each options
corresponding with OnActiveSec=, OnBootSec=, OnStartupSec=,
OnUnitActiveSec=, OnUnitInactiveSec=, OnCalendar= of timer
respectively. And OnCalendar= and WakeSystem= supported by
--timer-property= option like --property= of systemd-run.
And if --unit= option and timer options are specified the command can
be omitted. In this case, systemd-run assumes the target service is
already loaded. And just try to generate transient timer unit only.
2014-12-09 16:07:16 +09:00
|
|
|
|
2023-10-12 12:02:03 +02:00
|
|
|
/* Name and Mode */
|
|
|
|
|
r = sd_bus_message_append(m, "ss", scope, "fail");
|
|
|
|
|
if (r < 0)
|
|
|
|
|
return bus_log_create_error(r);
|
run: introduce timer support option
Support timer options --on-active=, --on-boot=, --on-startup=,
--on-unit-active=, --on-unit-inactive=, --on-calendar=. Each options
corresponding with OnActiveSec=, OnBootSec=, OnStartupSec=,
OnUnitActiveSec=, OnUnitInactiveSec=, OnCalendar= of timer
respectively. And OnCalendar= and WakeSystem= supported by
--timer-property= option like --property= of systemd-run.
And if --unit= option and timer options are specified the command can
be omitted. In this case, systemd-run assumes the target service is
already loaded. And just try to generate transient timer unit only.
2014-12-09 16:07:16 +09:00
|
|
|
|
2023-10-12 12:02:03 +02:00
|
|
|
/* Properties */
|
|
|
|
|
r = sd_bus_message_open_container(m, 'a', "(sv)");
|
|
|
|
|
if (r < 0)
|
|
|
|
|
return bus_log_create_error(r);
|
run: introduce timer support option
Support timer options --on-active=, --on-boot=, --on-startup=,
--on-unit-active=, --on-unit-inactive=, --on-calendar=. Each options
corresponding with OnActiveSec=, OnBootSec=, OnStartupSec=,
OnUnitActiveSec=, OnUnitInactiveSec=, OnCalendar= of timer
respectively. And OnCalendar= and WakeSystem= supported by
--timer-property= option like --property= of systemd-run.
And if --unit= option and timer options are specified the command can
be omitted. In this case, systemd-run assumes the target service is
already loaded. And just try to generate transient timer unit only.
2014-12-09 16:07:16 +09:00
|
|
|
|
2023-10-12 12:02:03 +02:00
|
|
|
r = transient_scope_set_properties(m, allow_pidfd);
|
|
|
|
|
if (r < 0)
|
|
|
|
|
return r;
|
2013-07-01 00:03:57 +02:00
|
|
|
|
2023-10-12 12:02:03 +02:00
|
|
|
r = sd_bus_message_close_container(m);
|
|
|
|
|
if (r < 0)
|
|
|
|
|
return bus_log_create_error(r);
|
2015-09-01 16:43:08 +00:00
|
|
|
|
2023-10-12 12:02:03 +02:00
|
|
|
/* Auxiliary units */
|
|
|
|
|
r = sd_bus_message_append(m, "a(sa(sv))", 0);
|
|
|
|
|
if (r < 0)
|
|
|
|
|
return bus_log_create_error(r);
|
|
|
|
|
|
|
|
|
|
r = sd_bus_call(bus, m, 0, &error, &reply);
|
|
|
|
|
if (r < 0) {
|
|
|
|
|
if (sd_bus_error_has_names(&error, SD_BUS_ERROR_UNKNOWN_PROPERTY, SD_BUS_ERROR_PROPERTY_READ_ONLY) && allow_pidfd) {
|
|
|
|
|
log_debug("Retrying with classic PIDs.");
|
|
|
|
|
allow_pidfd = false;
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return log_error_errno(r, "Failed to start transient scope unit: %s", bus_error_message(&error, r));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
}
|
2013-06-28 04:12:58 +02:00
|
|
|
|
2018-11-22 20:40:00 +01:00
|
|
|
r = sd_bus_message_read(reply, "o", &object);
|
|
|
|
|
if (r < 0)
|
|
|
|
|
return bus_log_parse_error(r);
|
|
|
|
|
|
2023-12-14 15:22:14 +01:00
|
|
|
r = bus_wait_for_jobs_one(w, object, arg_quiet ? 0 : BUS_WAIT_JOBS_LOG_ERROR,
|
|
|
|
|
arg_runtime_scope == RUNTIME_SCOPE_USER ? STRV_MAKE_CONST("--user") : NULL);
|
2018-11-22 20:40:00 +01:00
|
|
|
if (r < 0)
|
|
|
|
|
return r;
|
|
|
|
|
|
2023-10-12 12:03:03 +02:00
|
|
|
r = acquire_invocation_id(bus, NULL, &invocation_id);
|
2018-11-22 20:40:00 +01:00
|
|
|
if (r < 0)
|
|
|
|
|
return r;
|
2023-10-12 12:03:03 +02:00
|
|
|
if (r == 0)
|
|
|
|
|
log_debug("No invocation ID set.");
|
|
|
|
|
else {
|
|
|
|
|
if (strv_extendf(&user_env, "INVOCATION_ID=" SD_ID128_FORMAT_STR, SD_ID128_FORMAT_VAL(invocation_id)) < 0)
|
|
|
|
|
return log_oom();
|
|
|
|
|
}
|
2018-11-22 20:40:00 +01:00
|
|
|
|
2014-03-05 18:57:21 +01:00
|
|
|
if (arg_nice_set) {
|
2014-11-28 19:57:32 +01:00
|
|
|
if (setpriority(PRIO_PROCESS, 0, arg_nice) < 0)
|
|
|
|
|
return log_error_errno(errno, "Failed to set nice level: %m");
|
2014-03-05 18:57:21 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (arg_exec_group) {
|
|
|
|
|
gid_t gid;
|
|
|
|
|
|
2018-08-02 18:36:47 +02:00
|
|
|
r = get_group_creds(&arg_exec_group, &gid, 0);
|
2014-11-28 18:50:43 +01:00
|
|
|
if (r < 0)
|
|
|
|
|
return log_error_errno(r, "Failed to resolve group %s: %m", arg_exec_group);
|
2014-03-05 18:57:21 +01:00
|
|
|
|
2014-11-28 19:57:32 +01:00
|
|
|
if (setresgid(gid, gid, gid) < 0)
|
|
|
|
|
return log_error_errno(errno, "Failed to change GID to " GID_FMT ": %m", gid);
|
2014-03-05 18:57:21 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (arg_exec_user) {
|
|
|
|
|
const char *home, *shell;
|
|
|
|
|
uid_t uid;
|
|
|
|
|
gid_t gid;
|
|
|
|
|
|
2018-08-20 16:06:41 +02:00
|
|
|
r = get_user_creds(&arg_exec_user, &uid, &gid, &home, &shell, USER_CREDS_CLEAN|USER_CREDS_PREFER_NSS);
|
2014-11-28 18:50:43 +01:00
|
|
|
if (r < 0)
|
|
|
|
|
return log_error_errno(r, "Failed to resolve user %s: %m", arg_exec_user);
|
2014-03-05 18:57:21 +01:00
|
|
|
|
2016-08-25 10:24:10 +02:00
|
|
|
if (home) {
|
|
|
|
|
r = strv_extendf(&user_env, "HOME=%s", home);
|
|
|
|
|
if (r < 0)
|
|
|
|
|
return log_oom();
|
|
|
|
|
}
|
2014-03-05 18:57:21 +01:00
|
|
|
|
2016-08-25 10:24:10 +02:00
|
|
|
if (shell) {
|
|
|
|
|
r = strv_extendf(&user_env, "SHELL=%s", shell);
|
|
|
|
|
if (r < 0)
|
|
|
|
|
return log_oom();
|
|
|
|
|
}
|
2014-03-05 18:57:21 +01:00
|
|
|
|
|
|
|
|
r = strv_extendf(&user_env, "USER=%s", arg_exec_user);
|
|
|
|
|
if (r < 0)
|
|
|
|
|
return log_oom();
|
|
|
|
|
|
|
|
|
|
r = strv_extendf(&user_env, "LOGNAME=%s", arg_exec_user);
|
|
|
|
|
if (r < 0)
|
|
|
|
|
return log_oom();
|
|
|
|
|
|
|
|
|
|
if (!arg_exec_group) {
|
2014-11-28 19:57:32 +01:00
|
|
|
if (setresgid(gid, gid, gid) < 0)
|
|
|
|
|
return log_error_errno(errno, "Failed to change GID to " GID_FMT ": %m", gid);
|
2014-03-05 18:57:21 +01:00
|
|
|
}
|
|
|
|
|
|
2014-11-28 19:57:32 +01:00
|
|
|
if (setresuid(uid, uid, uid) < 0)
|
|
|
|
|
return log_error_errno(errno, "Failed to change UID to " UID_FMT ": %m", uid);
|
2014-03-05 18:57:21 +01:00
|
|
|
}
|
|
|
|
|
|
2022-09-22 14:21:46 +02:00
|
|
|
if (arg_working_directory && chdir(arg_working_directory) < 0)
|
|
|
|
|
return log_error_errno(errno, "Failed to change directory to '%s': %m", arg_working_directory);
|
|
|
|
|
|
2021-08-07 10:16:19 +02:00
|
|
|
env = strv_env_merge(environ, user_env, arg_environment);
|
2014-03-05 18:57:21 +01:00
|
|
|
if (!env)
|
|
|
|
|
return log_oom();
|
|
|
|
|
|
2023-10-12 12:03:03 +02:00
|
|
|
if (!arg_quiet) {
|
2024-08-12 15:15:15 +02:00
|
|
|
r = print_unit_invocation(scope, invocation_id);
|
|
|
|
|
if (r < 0)
|
|
|
|
|
return r;
|
2023-10-12 12:03:03 +02:00
|
|
|
}
|
2014-03-05 19:02:53 +01:00
|
|
|
|
2023-07-19 22:56:02 +01:00
|
|
|
if (arg_expand_environment > 0) {
|
2023-06-26 17:20:49 +02:00
|
|
|
_cleanup_strv_free_ char **expanded_cmdline = NULL, **unset_variables = NULL, **bad_variables = NULL;
|
|
|
|
|
|
|
|
|
|
r = replace_env_argv(arg_cmdline, env, &expanded_cmdline, &unset_variables, &bad_variables);
|
|
|
|
|
if (r < 0)
|
|
|
|
|
return log_error_errno(r, "Failed to expand environment variables: %m");
|
|
|
|
|
|
|
|
|
|
free_and_replace(arg_cmdline, expanded_cmdline);
|
|
|
|
|
|
|
|
|
|
if (!strv_isempty(unset_variables)) {
|
|
|
|
|
_cleanup_free_ char *ju = strv_join(unset_variables, ", ");
|
|
|
|
|
log_warning("Referenced but unset environment variable evaluates to an empty string: %s", strna(ju));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!strv_isempty(bad_variables)) {
|
|
|
|
|
_cleanup_free_ char *jb = strv_join(bad_variables, ", ");
|
|
|
|
|
log_warning("Invalid environment variable name evaluates to an empty string: %s", strna(jb));
|
|
|
|
|
}
|
2023-04-04 21:18:33 +02:00
|
|
|
}
|
|
|
|
|
|
2018-11-22 19:24:48 +01:00
|
|
|
execvpe(arg_cmdline[0], arg_cmdline, env);
|
2014-12-22 19:45:32 +01:00
|
|
|
|
|
|
|
|
return log_error_errno(errno, "Failed to execute: %m");
|
|
|
|
|
}
|
|
|
|
|
|
2023-04-02 22:27:58 +02:00
|
|
|
static int make_transient_trigger_unit(
|
2014-12-22 19:45:32 +01:00
|
|
|
sd_bus *bus,
|
2023-04-02 22:27:58 +02:00
|
|
|
sd_bus_message **message,
|
|
|
|
|
const char *suffix,
|
|
|
|
|
const char *trigger,
|
|
|
|
|
const char *service) {
|
2014-12-22 19:45:32 +01:00
|
|
|
|
2023-04-02 22:27:58 +02:00
|
|
|
_cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
|
2014-12-22 19:45:32 +01:00
|
|
|
int r;
|
|
|
|
|
|
|
|
|
|
assert(bus);
|
2023-04-02 22:27:58 +02:00
|
|
|
assert(message);
|
|
|
|
|
assert(suffix);
|
|
|
|
|
assert(trigger);
|
|
|
|
|
assert(service);
|
2014-12-22 19:45:32 +01:00
|
|
|
|
2020-05-02 23:41:14 -07:00
|
|
|
r = bus_message_new_method_call(bus, &m, bus_systemd_mgr, "StartTransientUnit");
|
2014-12-22 19:45:32 +01:00
|
|
|
if (r < 0)
|
|
|
|
|
return bus_log_create_error(r);
|
|
|
|
|
|
|
|
|
|
/* Name and Mode */
|
2017-12-18 23:46:45 +09:00
|
|
|
r = sd_bus_message_append(m, "ss", trigger, "fail");
|
2014-12-22 19:45:32 +01:00
|
|
|
if (r < 0)
|
|
|
|
|
return bus_log_create_error(r);
|
|
|
|
|
|
|
|
|
|
/* Properties */
|
|
|
|
|
r = sd_bus_message_open_container(m, 'a', "(sv)");
|
|
|
|
|
if (r < 0)
|
|
|
|
|
return bus_log_create_error(r);
|
|
|
|
|
|
2017-12-18 23:46:45 +09:00
|
|
|
if (streq(suffix, ".path"))
|
|
|
|
|
r = transient_unit_set_properties(m, UNIT_PATH, arg_path_property);
|
|
|
|
|
else if (streq(suffix, ".socket"))
|
|
|
|
|
r = transient_unit_set_properties(m, UNIT_SOCKET, arg_socket_property);
|
|
|
|
|
else if (streq(suffix, ".timer"))
|
|
|
|
|
r = transient_timer_set_properties(m);
|
|
|
|
|
else
|
Drop the text argument from assert_not_reached()
In general we almost never hit those asserts in production code, so users see
them very rarely, if ever. But either way, we just need something that users
can pass to the developers.
We have quite a few of those asserts, and some have fairly nice messages, but
many are like "WTF?" or "???" or "unexpected something". The error that is
printed includes the file location, and function name. In almost all functions
there's at most one assert, so the function name alone is enough to identify
the failure for a developer. So we don't get much extra from the message, and
we might just as well drop them.
Dropping them makes our code a tiny bit smaller, and most importantly, improves
development experience by making it easy to insert such an assert in the code
without thinking how to phrase the argument.
2021-07-27 12:27:28 +02:00
|
|
|
assert_not_reached();
|
2014-12-22 19:45:32 +01:00
|
|
|
if (r < 0)
|
2017-11-29 20:05:22 +01:00
|
|
|
return r;
|
2014-12-22 19:45:32 +01:00
|
|
|
|
|
|
|
|
r = sd_bus_message_close_container(m);
|
|
|
|
|
if (r < 0)
|
|
|
|
|
return bus_log_create_error(r);
|
|
|
|
|
|
|
|
|
|
r = sd_bus_message_open_container(m, 'a', "(sa(sv))");
|
|
|
|
|
if (r < 0)
|
|
|
|
|
return bus_log_create_error(r);
|
|
|
|
|
|
2018-11-22 19:24:48 +01:00
|
|
|
if (!strv_isempty(arg_cmdline)) {
|
2014-12-22 19:45:32 +01:00
|
|
|
r = sd_bus_message_open_container(m, 'r', "sa(sv)");
|
|
|
|
|
if (r < 0)
|
|
|
|
|
return bus_log_create_error(r);
|
|
|
|
|
|
|
|
|
|
r = sd_bus_message_append(m, "s", service);
|
|
|
|
|
if (r < 0)
|
|
|
|
|
return bus_log_create_error(r);
|
|
|
|
|
|
|
|
|
|
r = sd_bus_message_open_container(m, 'a', "(sv)");
|
|
|
|
|
if (r < 0)
|
|
|
|
|
return bus_log_create_error(r);
|
|
|
|
|
|
2024-06-06 13:30:09 +02:00
|
|
|
r = transient_service_set_properties(m, /* pty_path = */ NULL, /* pty_fd = */ -EBADF);
|
2014-12-22 19:45:32 +01:00
|
|
|
if (r < 0)
|
2017-11-29 20:05:22 +01:00
|
|
|
return r;
|
2014-12-22 19:45:32 +01:00
|
|
|
|
|
|
|
|
r = sd_bus_message_close_container(m);
|
|
|
|
|
if (r < 0)
|
|
|
|
|
return bus_log_create_error(r);
|
|
|
|
|
|
|
|
|
|
r = sd_bus_message_close_container(m);
|
|
|
|
|
if (r < 0)
|
|
|
|
|
return bus_log_create_error(r);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
r = sd_bus_message_close_container(m);
|
|
|
|
|
if (r < 0)
|
|
|
|
|
return bus_log_create_error(r);
|
|
|
|
|
|
2023-04-02 22:27:58 +02:00
|
|
|
*message = TAKE_PTR(m);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int start_transient_trigger(sd_bus *bus, const char *suffix) {
|
|
|
|
|
_cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL, *reply = NULL;
|
|
|
|
|
_cleanup_(bus_wait_for_jobs_freep) BusWaitForJobs *w = NULL;
|
|
|
|
|
_cleanup_free_ char *trigger = NULL, *service = NULL;
|
|
|
|
|
const char *object = NULL;
|
|
|
|
|
int r;
|
|
|
|
|
|
|
|
|
|
assert(bus);
|
|
|
|
|
assert(suffix);
|
|
|
|
|
|
|
|
|
|
r = bus_wait_for_jobs_new(bus, &w);
|
|
|
|
|
if (r < 0)
|
2023-05-26 15:09:03 +02:00
|
|
|
return log_error_errno(r, "Could not watch jobs: %m");
|
2023-04-02 22:27:58 +02:00
|
|
|
|
|
|
|
|
if (arg_unit) {
|
|
|
|
|
switch (unit_name_to_type(arg_unit)) {
|
|
|
|
|
|
|
|
|
|
case UNIT_SERVICE:
|
|
|
|
|
service = strdup(arg_unit);
|
|
|
|
|
if (!service)
|
|
|
|
|
return log_oom();
|
|
|
|
|
|
|
|
|
|
r = unit_name_change_suffix(service, suffix, &trigger);
|
|
|
|
|
if (r < 0)
|
|
|
|
|
return log_error_errno(r, "Failed to change unit suffix: %m");
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case UNIT_TIMER:
|
|
|
|
|
trigger = strdup(arg_unit);
|
|
|
|
|
if (!trigger)
|
|
|
|
|
return log_oom();
|
|
|
|
|
|
|
|
|
|
r = unit_name_change_suffix(trigger, ".service", &service);
|
|
|
|
|
if (r < 0)
|
|
|
|
|
return log_error_errno(r, "Failed to change unit suffix: %m");
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
r = unit_name_mangle_with_suffix(arg_unit, "as unit",
|
|
|
|
|
arg_quiet ? 0 : UNIT_NAME_MANGLE_WARN,
|
|
|
|
|
".service", &service);
|
|
|
|
|
if (r < 0)
|
|
|
|
|
return log_error_errno(r, "Failed to mangle unit name: %m");
|
|
|
|
|
|
|
|
|
|
r = unit_name_mangle_with_suffix(arg_unit, "as trigger",
|
|
|
|
|
arg_quiet ? 0 : UNIT_NAME_MANGLE_WARN,
|
|
|
|
|
suffix, &trigger);
|
|
|
|
|
if (r < 0)
|
|
|
|
|
return log_error_errno(r, "Failed to mangle unit name: %m");
|
|
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
r = make_unit_name(bus, UNIT_SERVICE, &service);
|
|
|
|
|
if (r < 0)
|
|
|
|
|
return r;
|
|
|
|
|
|
|
|
|
|
r = unit_name_change_suffix(service, suffix, &trigger);
|
|
|
|
|
if (r < 0)
|
|
|
|
|
return log_error_errno(r, "Failed to change unit suffix: %m");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
r = make_transient_trigger_unit(bus, &m, suffix, trigger, service);
|
|
|
|
|
if (r < 0)
|
|
|
|
|
return r;
|
|
|
|
|
|
2024-08-16 19:33:41 +09:00
|
|
|
(void) polkit_agent_open_if_enabled(arg_transport, arg_ask_password);
|
2015-09-01 16:43:08 +00:00
|
|
|
|
2023-04-02 23:17:58 +02:00
|
|
|
r = bus_call_with_hint(bus, m, suffix + 1, &reply);
|
2018-08-07 10:14:30 +09:00
|
|
|
if (r < 0)
|
2023-04-02 23:17:58 +02:00
|
|
|
return r;
|
2014-12-22 19:45:32 +01:00
|
|
|
|
2015-04-28 12:21:31 +02:00
|
|
|
r = sd_bus_message_read(reply, "o", &object);
|
|
|
|
|
if (r < 0)
|
|
|
|
|
return bus_log_parse_error(r);
|
|
|
|
|
|
2023-12-14 15:22:14 +01:00
|
|
|
r = bus_wait_for_jobs_one(w, object, arg_quiet ? 0 : BUS_WAIT_JOBS_LOG_ERROR,
|
|
|
|
|
arg_runtime_scope == RUNTIME_SCOPE_USER ? STRV_MAKE_CONST("--user") : NULL);
|
2015-04-28 12:21:31 +02:00
|
|
|
if (r < 0)
|
|
|
|
|
return r;
|
|
|
|
|
|
2016-08-24 03:12:18 -07:00
|
|
|
if (!arg_quiet) {
|
2017-12-18 23:46:45 +09:00
|
|
|
log_info("Running %s as unit: %s", suffix + 1, trigger);
|
2018-11-22 19:24:48 +01:00
|
|
|
if (!strv_isempty(arg_cmdline))
|
2016-08-24 03:12:18 -07:00
|
|
|
log_info("Will run service as unit: %s", service);
|
|
|
|
|
}
|
2014-12-22 19:45:32 +01:00
|
|
|
|
2023-04-02 21:50:19 +02:00
|
|
|
return EXIT_SUCCESS;
|
2013-06-28 04:12:58 +02:00
|
|
|
}
|
|
|
|
|
|
2021-10-27 11:59:19 +01:00
|
|
|
static bool shall_make_executable_absolute(void) {
|
2023-12-19 19:10:52 +01:00
|
|
|
if (arg_exec_path)
|
|
|
|
|
return false;
|
2021-10-27 11:59:19 +01:00
|
|
|
if (strv_isempty(arg_cmdline))
|
|
|
|
|
return false;
|
|
|
|
|
if (arg_transport != BUS_TRANSPORT_LOCAL)
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
FOREACH_STRING(f, "RootDirectory=", "RootImage=", "ExecSearchPath=", "MountImages=", "ExtensionImages=")
|
|
|
|
|
if (strv_find_startswith(arg_property, f))
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2018-11-22 19:30:03 +01:00
|
|
|
static int run(int argc, char* argv[]) {
|
tree-wide: expose "p"-suffix unref calls in public APIs to make gcc cleanup easy
GLIB has recently started to officially support the gcc cleanup
attribute in its public API, hence let's do the same for our APIs.
With this patch we'll define an xyz_unrefp() call for each public
xyz_unref() call, to make it easy to use inside a
__attribute__((cleanup())) expression. Then, all code is ported over to
make use of this.
The new calls are also documented in the man pages, with examples how to
use them (well, I only added docs where the _unref() call itself already
had docs, and the examples, only cover sd_bus_unrefp() and
sd_event_unrefp()).
This also renames sd_lldp_free() to sd_lldp_unref(), since that's how we
tend to call our destructors these days.
Note that this defines no public macro that wraps gcc's attribute and
makes it easier to use. While I think it's our duty in the library to
make our stuff easy to use, I figure it's not our duty to make gcc's own
features easy to use on its own. Most likely, client code which wants to
make use of this should define its own:
#define _cleanup_(function) __attribute__((cleanup(function)))
Or similar, to make the gcc feature easier to use.
Making this logic public has the benefit that we can remove three header
files whose only purpose was to define these functions internally.
See #2008.
2015-11-27 19:13:45 +01:00
|
|
|
_cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
|
2023-04-02 21:50:19 +02:00
|
|
|
int r;
|
2013-06-28 04:12:58 +02:00
|
|
|
|
2024-04-25 14:09:09 +02:00
|
|
|
log_setup();
|
2013-06-28 04:12:58 +02:00
|
|
|
|
2024-03-19 11:14:55 +01:00
|
|
|
if (invoked_as(argv, "run0"))
|
2023-12-19 19:10:52 +01:00
|
|
|
r = parse_argv_sudo_mode(argc, argv);
|
|
|
|
|
else
|
|
|
|
|
r = parse_argv(argc, argv);
|
2013-07-01 00:03:57 +02:00
|
|
|
if (r <= 0)
|
2018-11-22 19:34:15 +01:00
|
|
|
return r;
|
2013-06-28 04:12:58 +02:00
|
|
|
|
2021-10-27 11:59:19 +01:00
|
|
|
if (shall_make_executable_absolute()) {
|
2020-09-17 15:44:59 +02:00
|
|
|
/* Patch in an absolute path to fail early for user convenience, but only when we can do it
|
|
|
|
|
* (i.e. we will be running from the same file system). This also uses the user's $PATH,
|
|
|
|
|
* while we use a fixed search path in the manager. */
|
2015-10-22 18:24:59 +02:00
|
|
|
|
2020-09-17 15:44:59 +02:00
|
|
|
_cleanup_free_ char *command = NULL;
|
2020-09-17 13:44:12 +02:00
|
|
|
r = find_executable(arg_cmdline[0], &command);
|
2018-11-22 19:34:15 +01:00
|
|
|
if (r < 0)
|
|
|
|
|
return log_error_errno(r, "Failed to find executable %s: %m", arg_cmdline[0]);
|
2015-10-22 18:24:59 +02:00
|
|
|
|
2018-11-22 19:24:48 +01:00
|
|
|
free_and_replace(arg_cmdline[0], command);
|
2013-09-08 07:51:39 -04:00
|
|
|
}
|
|
|
|
|
|
2013-07-01 00:40:56 +02:00
|
|
|
if (!arg_description) {
|
run: fix bad escaping and memory ownership confusion
arg_description was either set to arg_unit (i.e. a const char*), or to
char *description, the result of allocation in run(). But description
was decorated with _cleanup_, so it would be freed when going out of the
function. Nothing bad would happen, because the program would exit after
exiting from run(), but this is just all too messy.
Also, strv_join(" ") + shell_escape() is not a good way to escape command
lines. In particular, one the join has happened, we cannot distinguish
empty arguments, or arguments with whitespace, etc. We have a helper
function to do the escaping properly, so let's use that.
Fixup for 2c29813da3421b77eca5e5cdc3b9a863cad473b9.
2023-11-29 14:13:33 +01:00
|
|
|
char *t;
|
2013-07-01 00:40:56 +02:00
|
|
|
|
run: fix bad escaping and memory ownership confusion
arg_description was either set to arg_unit (i.e. a const char*), or to
char *description, the result of allocation in run(). But description
was decorated with _cleanup_, so it would be freed when going out of the
function. Nothing bad would happen, because the program would exit after
exiting from run(), but this is just all too messy.
Also, strv_join(" ") + shell_escape() is not a good way to escape command
lines. In particular, one the join has happened, we cannot distinguish
empty arguments, or arguments with whitespace, etc. We have a helper
function to do the escaping properly, so let's use that.
Fixup for 2c29813da3421b77eca5e5cdc3b9a863cad473b9.
2023-11-29 14:13:33 +01:00
|
|
|
if (strv_isempty(arg_cmdline))
|
|
|
|
|
t = strdup(arg_unit);
|
|
|
|
|
else
|
|
|
|
|
t = quote_command_line(arg_cmdline, SHELL_ESCAPE_EMPTY);
|
|
|
|
|
if (!t)
|
|
|
|
|
return log_oom();
|
run: introduce timer support option
Support timer options --on-active=, --on-boot=, --on-startup=,
--on-unit-active=, --on-unit-inactive=, --on-calendar=. Each options
corresponding with OnActiveSec=, OnBootSec=, OnStartupSec=,
OnUnitActiveSec=, OnUnitInactiveSec=, OnCalendar= of timer
respectively. And OnCalendar= and WakeSystem= supported by
--timer-property= option like --property= of systemd-run.
And if --unit= option and timer options are specified the command can
be omitted. In this case, systemd-run assumes the target service is
already loaded. And just try to generate transient timer unit only.
2014-12-09 16:07:16 +09:00
|
|
|
|
run: fix bad escaping and memory ownership confusion
arg_description was either set to arg_unit (i.e. a const char*), or to
char *description, the result of allocation in run(). But description
was decorated with _cleanup_, so it would be freed when going out of the
function. Nothing bad would happen, because the program would exit after
exiting from run(), but this is just all too messy.
Also, strv_join(" ") + shell_escape() is not a good way to escape command
lines. In particular, one the join has happened, we cannot distinguish
empty arguments, or arguments with whitespace, etc. We have a helper
function to do the escaping properly, so let's use that.
Fixup for 2c29813da3421b77eca5e5cdc3b9a863cad473b9.
2023-11-29 14:13:33 +01:00
|
|
|
free_and_replace(arg_description, t);
|
2013-07-01 00:40:56 +02:00
|
|
|
}
|
|
|
|
|
|
2023-07-19 22:56:02 +01:00
|
|
|
/* For backward compatibility reasons env var expansion is disabled by default for scopes, and
|
|
|
|
|
* enabled by default for everything else. Try to detect it and print a warning, so that we can
|
|
|
|
|
* change it in the future and harmonize it. */
|
|
|
|
|
if (arg_expand_environment < 0) {
|
|
|
|
|
arg_expand_environment = !arg_scope;
|
|
|
|
|
|
|
|
|
|
if (!arg_quiet && arg_scope && strchr(arg_description, '$'))
|
|
|
|
|
log_warning("Scope command line contains environment variable, which is not expanded"
|
|
|
|
|
" by default for now, but will be expanded by default in the future."
|
|
|
|
|
" Use --expand-environment=yes/no to explicitly control it as needed.");
|
|
|
|
|
}
|
|
|
|
|
|
2023-11-29 14:01:13 +01:00
|
|
|
/* If --wait is used connect via the bus, unconditionally, as ref/unref is not supported via the
|
|
|
|
|
* limited direct connection */
|
|
|
|
|
if (arg_wait ||
|
|
|
|
|
arg_stdio != ARG_STDIO_NONE ||
|
2023-10-26 09:19:04 +02:00
|
|
|
(arg_runtime_scope == RUNTIME_SCOPE_USER && !IN_SET(arg_transport, BUS_TRANSPORT_LOCAL, BUS_TRANSPORT_CAPSULE)))
|
2023-03-10 09:47:10 +01:00
|
|
|
r = bus_connect_transport(arg_transport, arg_host, arg_runtime_scope, &bus);
|
2016-08-17 14:24:17 +02:00
|
|
|
else
|
2023-03-10 09:47:10 +01:00
|
|
|
r = bus_connect_transport_systemd(arg_transport, arg_host, arg_runtime_scope, &bus);
|
2018-11-22 19:34:15 +01:00
|
|
|
if (r < 0)
|
2024-10-08 16:22:58 +02:00
|
|
|
return bus_log_connect_error(r, arg_transport, arg_runtime_scope);
|
2013-06-28 04:12:58 +02:00
|
|
|
|
2024-08-16 19:59:30 +09:00
|
|
|
(void) sd_bus_set_allow_interactive_authorization(bus, arg_ask_password);
|
|
|
|
|
|
2013-07-01 00:03:57 +02:00
|
|
|
if (arg_scope)
|
2023-04-02 21:50:19 +02:00
|
|
|
return start_transient_scope(bus);
|
|
|
|
|
if (arg_path_property)
|
|
|
|
|
return start_transient_trigger(bus, ".path");
|
|
|
|
|
if (arg_socket_property)
|
|
|
|
|
return start_transient_trigger(bus, ".socket");
|
|
|
|
|
if (arg_with_timer)
|
|
|
|
|
return start_transient_trigger(bus, ".timer");
|
|
|
|
|
return start_transient_service(bus);
|
2013-06-28 04:12:58 +02:00
|
|
|
}
|
2018-11-22 19:30:03 +01:00
|
|
|
|
|
|
|
|
DEFINE_MAIN_FUNCTION_WITH_POSITIVE_FAILURE(run);
|