mirror of
https://github.com/systemd/systemd.git
synced 2026-07-14 03:20:22 +00:00
Merge pull request #34755 from YHNdnzj/soft-reboot-generator-cmdline
core/manager: pass soft-reboot count to generators
This commit is contained in:
@@ -163,6 +163,15 @@
|
||||
<xi:include href="version-info.xml" xpointer="v251"/></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><varname>$SYSTEMD_SOFT_REBOOTS_COUNT</varname></term>
|
||||
|
||||
<listitem><para>If the system has soft-rebooted, this variable is set to the count of soft-reboots.
|
||||
This environment variable is only set for system generators.</para>
|
||||
|
||||
<xi:include href="version-info.xml" xpointer="v257"/></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><varname>$SYSTEMD_FIRST_BOOT</varname></term>
|
||||
|
||||
|
||||
@@ -157,25 +157,9 @@ int dir_is_empty_at(int dir_fd, const char *path, bool ignore_hidden_or_backup)
|
||||
struct dirent *buf;
|
||||
size_t m;
|
||||
|
||||
if (path) {
|
||||
assert(dir_fd >= 0 || dir_fd == AT_FDCWD);
|
||||
|
||||
fd = openat(dir_fd, path, O_RDONLY|O_DIRECTORY|O_CLOEXEC);
|
||||
if (fd < 0)
|
||||
return -errno;
|
||||
} else if (dir_fd == AT_FDCWD) {
|
||||
fd = open(".", O_RDONLY|O_DIRECTORY|O_CLOEXEC);
|
||||
if (fd < 0)
|
||||
return -errno;
|
||||
} else {
|
||||
/* Note that DUPing is not enough, as the internal pointer would still be shared and moved
|
||||
* getedents64(). */
|
||||
assert(dir_fd >= 0);
|
||||
|
||||
fd = fd_reopen(dir_fd, O_RDONLY|O_DIRECTORY|O_CLOEXEC);
|
||||
if (fd < 0)
|
||||
return fd;
|
||||
}
|
||||
fd = xopenat(dir_fd, path, O_DIRECTORY|O_CLOEXEC);
|
||||
if (fd < 0)
|
||||
return fd;
|
||||
|
||||
/* Allocate space for at least 3 full dirents, since every dir has at least two entries ("." +
|
||||
* ".."), and only once we have seen if there's a third we know whether the dir is empty or not. If
|
||||
|
||||
@@ -4007,30 +4007,26 @@ void manager_send_reloading(Manager *m) {
|
||||
m->ready_sent = false;
|
||||
}
|
||||
|
||||
static bool generator_path_any(const char* const* paths) {
|
||||
bool found = false;
|
||||
static bool generator_path_any(char * const *paths) {
|
||||
|
||||
/* Optimize by skipping the whole process by not creating output directories
|
||||
* if no generators are found. */
|
||||
STRV_FOREACH(path, paths)
|
||||
if (access(*path, F_OK) == 0)
|
||||
found = true;
|
||||
else if (errno != ENOENT)
|
||||
log_warning_errno(errno, "Failed to open generator directory %s: %m", *path);
|
||||
/* Optimize by skipping the whole process by not creating output directories if no generators are found. */
|
||||
|
||||
return found;
|
||||
STRV_FOREACH(i, paths) {
|
||||
if (access(*i, F_OK) >= 0)
|
||||
return true;
|
||||
if (errno != ENOENT)
|
||||
log_warning_errno(errno, "Failed to check if generator dir '%s' exists, assuming not: %m", *i);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static int manager_run_environment_generators(Manager *m) {
|
||||
char **tmp = NULL; /* this is only used in the forked process, no cleanup here */
|
||||
_cleanup_strv_free_ char **paths = NULL;
|
||||
void* args[] = {
|
||||
[STDOUT_GENERATE] = &tmp,
|
||||
[STDOUT_COLLECT] = &tmp,
|
||||
[STDOUT_CONSUME] = &m->transient_environment,
|
||||
};
|
||||
int r;
|
||||
|
||||
assert(m);
|
||||
|
||||
if (MANAGER_IS_TEST_RUN(m) && !(m->test_run_flags & MANAGER_TEST_RUN_ENV_GENERATORS))
|
||||
return 0;
|
||||
|
||||
@@ -4038,9 +4034,16 @@ static int manager_run_environment_generators(Manager *m) {
|
||||
if (!paths)
|
||||
return log_oom();
|
||||
|
||||
if (!generator_path_any((const char* const*) paths))
|
||||
if (!generator_path_any(paths))
|
||||
return 0;
|
||||
|
||||
char **tmp = NULL; /* this is only used in the forked process, no cleanup here */
|
||||
void *args[_STDOUT_CONSUME_MAX] = {
|
||||
[STDOUT_GENERATE] = &tmp,
|
||||
[STDOUT_COLLECT] = &tmp,
|
||||
[STDOUT_CONSUME] = &m->transient_environment,
|
||||
};
|
||||
|
||||
WITH_UMASK(0022)
|
||||
r = execute_directories((const char* const*) paths, DEFAULT_TIMEOUT_USEC, gather_environment,
|
||||
args, NULL, m->transient_environment,
|
||||
@@ -4078,6 +4081,12 @@ static int build_generator_environment(Manager *m, char ***ret) {
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (m->soft_reboots_count > 0) {
|
||||
r = strv_env_assignf(&nl, "SYSTEMD_SOFT_REBOOTS_COUNT", "%u", m->soft_reboots_count);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
if (m->first_boot >= 0) {
|
||||
r = strv_env_assign(&nl, "SYSTEMD_FIRST_BOOT", one_zero(m->first_boot));
|
||||
if (r < 0)
|
||||
@@ -4117,17 +4126,12 @@ static int build_generator_environment(Manager *m, char ***ret) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int manager_execute_generators(Manager *m, char **paths, bool remount_ro) {
|
||||
static int manager_execute_generators(Manager *m, char * const *paths, bool remount_ro) {
|
||||
_cleanup_strv_free_ char **ge = NULL;
|
||||
const char *argv[] = {
|
||||
NULL, /* Leave this empty, execute_directory() will fill something in */
|
||||
m->lookup_paths.generator,
|
||||
m->lookup_paths.generator_early,
|
||||
m->lookup_paths.generator_late,
|
||||
NULL,
|
||||
};
|
||||
int r;
|
||||
|
||||
assert(m);
|
||||
|
||||
r = build_generator_environment(m, &ge);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to build generator environment: %m");
|
||||
@@ -4144,6 +4148,14 @@ static int manager_execute_generators(Manager *m, char **paths, bool remount_ro)
|
||||
log_warning_errno(r, "Read-only bind remount failed, ignoring: %m");
|
||||
}
|
||||
|
||||
const char *argv[] = {
|
||||
NULL, /* Leave this empty, execute_directory() will fill something in */
|
||||
m->lookup_paths.generator,
|
||||
m->lookup_paths.generator_early,
|
||||
m->lookup_paths.generator_late,
|
||||
NULL,
|
||||
};
|
||||
|
||||
BLOCK_WITH_UMASK(0022);
|
||||
return execute_directories(
|
||||
(const char* const*) paths,
|
||||
@@ -4168,7 +4180,7 @@ static int manager_run_generators(Manager *m) {
|
||||
if (!paths)
|
||||
return log_oom();
|
||||
|
||||
if (!generator_path_any((const char* const*) paths))
|
||||
if (!generator_path_any(paths))
|
||||
return 0;
|
||||
|
||||
r = lookup_paths_mkdir_generator(&m->lookup_paths);
|
||||
|
||||
@@ -955,7 +955,7 @@ static int parse_proc_cmdline_item(const char *key, const char *value, void *dat
|
||||
}
|
||||
|
||||
static int run(const char *dest, const char *dest_early, const char *dest_late) {
|
||||
int r, k;
|
||||
int r;
|
||||
|
||||
assert_se(arg_dest = dest_late);
|
||||
|
||||
@@ -975,12 +975,11 @@ static int run(const char *dest, const char *dest_early, const char *dest_late)
|
||||
|
||||
if (arg_root_enabled)
|
||||
r = add_root_mount();
|
||||
else
|
||||
r = 0;
|
||||
|
||||
if (!in_initrd()) {
|
||||
k = add_mounts();
|
||||
if (r >= 0)
|
||||
r = k;
|
||||
}
|
||||
if (!in_initrd())
|
||||
RET_GATHER(r, add_mounts());
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
@@ -107,6 +107,11 @@ static int run(const char *dest, const char *dest_early, const char *dest_late)
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (generator_soft_rebooted()) {
|
||||
log_debug("Running in an initrd entered through soft-reboot, not initiating resume.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
r = proc_cmdline_parse(parse_proc_cmdline_item, NULL, 0);
|
||||
if (r < 0)
|
||||
log_warning_errno(r, "Failed to parse kernel command line, ignoring: %m");
|
||||
|
||||
@@ -50,13 +50,13 @@ static int do_spawn(
|
||||
assert(ret_pid);
|
||||
|
||||
if (null_or_empty_path(path) > 0) {
|
||||
log_debug("%s is empty (a mask).", path);
|
||||
log_debug("%s is masked, skipping.", path);
|
||||
return 0;
|
||||
}
|
||||
|
||||
pid_t pid;
|
||||
r = safe_fork_full(
|
||||
"(direxec)",
|
||||
"(exec-inner)",
|
||||
(const int[]) { STDIN_FILENO, stdout_fd < 0 ? STDOUT_FILENO : stdout_fd, STDERR_FILENO },
|
||||
/* except_fds= */ NULL, /* n_except_fds= */ 0,
|
||||
FORK_DEATHSIG_SIGTERM|FORK_LOG|FORK_RLIMIT_NOFILE_SAFE|FORK_REARRANGE_STDIO|FORK_CLOSE_ALL_FDS,
|
||||
@@ -89,11 +89,11 @@ static int do_spawn(
|
||||
}
|
||||
|
||||
static int do_execute(
|
||||
char* const* paths,
|
||||
char * const *paths,
|
||||
const char *root,
|
||||
usec_t timeout,
|
||||
gather_stdout_callback_t const callbacks[_STDOUT_CONSUME_MAX],
|
||||
void* const callback_args[_STDOUT_CONSUME_MAX],
|
||||
void * const callback_args[_STDOUT_CONSUME_MAX],
|
||||
int output_fd,
|
||||
char *argv[],
|
||||
char *envp[],
|
||||
@@ -103,12 +103,15 @@ static int do_execute(
|
||||
bool parallel_execution;
|
||||
int r;
|
||||
|
||||
/* We fork this all off from a child process so that we can somewhat cleanly make
|
||||
* use of SIGALRM to set a time limit.
|
||||
/* We fork this all off from a child process so that we can somewhat cleanly make use of SIGALRM
|
||||
* to set a time limit.
|
||||
*
|
||||
* We attempt to perform parallel execution if configured by the user, however
|
||||
* if `callbacks` is nonnull, execution must be serial.
|
||||
* We attempt to perform parallel execution if configured by the user, however if `callbacks` is nonnull,
|
||||
* execution must be serial.
|
||||
*/
|
||||
|
||||
assert(!strv_isempty(paths));
|
||||
|
||||
parallel_execution = FLAGS_SET(flags, EXEC_DIR_PARALLEL) && !callbacks;
|
||||
|
||||
if (parallel_execution) {
|
||||
@@ -218,13 +221,12 @@ static int do_execute(
|
||||
while (!hashmap_isempty(pids)) {
|
||||
_cleanup_free_ char *t = NULL;
|
||||
pid_t pid;
|
||||
void *p;
|
||||
|
||||
pid = PTR_TO_PID(hashmap_first_key(pids));
|
||||
t = ASSERT_PTR(hashmap_steal_first_key_and_value(pids, &p));
|
||||
pid = PTR_TO_PID(p);
|
||||
assert(pid > 0);
|
||||
|
||||
t = hashmap_remove(pids, PID_TO_PTR(pid));
|
||||
assert(t);
|
||||
|
||||
r = wait_for_terminate_and_check(t, pid, WAIT_LOG);
|
||||
if (r < 0)
|
||||
return r;
|
||||
@@ -237,11 +239,11 @@ static int do_execute(
|
||||
|
||||
int execute_strv(
|
||||
const char *name,
|
||||
char* const* paths,
|
||||
char * const *paths,
|
||||
const char *root,
|
||||
usec_t timeout,
|
||||
gather_stdout_callback_t const callbacks[_STDOUT_CONSUME_MAX],
|
||||
void* const callback_args[_STDOUT_CONSUME_MAX],
|
||||
void * const callback_args[_STDOUT_CONSUME_MAX],
|
||||
char *argv[],
|
||||
char *envp[],
|
||||
ExecDirFlags flags) {
|
||||
@@ -257,10 +259,10 @@ int execute_strv(
|
||||
|
||||
if (callbacks) {
|
||||
assert(name);
|
||||
assert(callback_args);
|
||||
assert(callbacks[STDOUT_GENERATE]);
|
||||
assert(callbacks[STDOUT_COLLECT]);
|
||||
assert(callbacks[STDOUT_CONSUME]);
|
||||
assert(callback_args);
|
||||
|
||||
fd = open_serialization_fd(name);
|
||||
if (fd < 0)
|
||||
@@ -298,10 +300,10 @@ int execute_strv(
|
||||
}
|
||||
|
||||
int execute_directories(
|
||||
const char* const* directories,
|
||||
const char * const *directories,
|
||||
usec_t timeout,
|
||||
gather_stdout_callback_t const callbacks[_STDOUT_CONSUME_MAX],
|
||||
void* const callback_args[_STDOUT_CONSUME_MAX],
|
||||
void * const callback_args[_STDOUT_CONSUME_MAX],
|
||||
char *argv[],
|
||||
char *envp[],
|
||||
ExecDirFlags flags) {
|
||||
@@ -310,7 +312,7 @@ int execute_directories(
|
||||
_cleanup_free_ char *name = NULL;
|
||||
int r;
|
||||
|
||||
assert(!strv_isempty((char**) directories));
|
||||
assert(!strv_isempty((char* const*) directories));
|
||||
|
||||
r = conf_files_list_strv(&paths, NULL, NULL, CONF_FILES_EXECUTABLE|CONF_FILES_REGULAR|CONF_FILES_FILTER_MASKED, directories);
|
||||
if (r < 0)
|
||||
@@ -327,7 +329,7 @@ int execute_directories(
|
||||
return log_error_errno(r, "Failed to extract file name from '%s': %m", directories[0]);
|
||||
}
|
||||
|
||||
return execute_strv(name, paths, NULL, timeout, callbacks, callback_args, argv, envp, flags);
|
||||
return execute_strv(name, paths, /* root = */ NULL, timeout, callbacks, callback_args, argv, envp, flags);
|
||||
}
|
||||
|
||||
static int gather_environment_generate(int fd, void *arg) {
|
||||
@@ -336,12 +338,14 @@ static int gather_environment_generate(int fd, void *arg) {
|
||||
_cleanup_strv_free_ char **new = NULL;
|
||||
int r;
|
||||
|
||||
/* Read a series of VAR=value assignments from fd, use them to update the list of
|
||||
* variables in env. Also update the exported environment.
|
||||
/* Read a series of VAR=value assignments from fd, use them to update the list of variables in env.
|
||||
* Also update the exported environment.
|
||||
*
|
||||
* fd is always consumed, even on error.
|
||||
*/
|
||||
|
||||
assert(fd >= 0);
|
||||
|
||||
f = fdopen(fd, "r");
|
||||
if (!f) {
|
||||
safe_close(fd);
|
||||
@@ -362,7 +366,7 @@ static int gather_environment_generate(int fd, void *arg) {
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (setenv(*x, *y, true) < 0)
|
||||
if (setenv(*x, *y, /* overwrite = */ true) < 0)
|
||||
return -errno;
|
||||
}
|
||||
|
||||
@@ -370,12 +374,14 @@ static int gather_environment_generate(int fd, void *arg) {
|
||||
}
|
||||
|
||||
static int gather_environment_collect(int fd, void *arg) {
|
||||
_cleanup_fclose_ FILE *f = NULL;
|
||||
char ***env = ASSERT_PTR(arg);
|
||||
_cleanup_fclose_ FILE *f = NULL;
|
||||
int r;
|
||||
|
||||
/* Write out a series of env=cescape(VAR=value) assignments to fd. */
|
||||
|
||||
assert(fd >= 0);
|
||||
|
||||
f = fdopen(fd, "w");
|
||||
if (!f) {
|
||||
safe_close(fd);
|
||||
@@ -394,12 +400,14 @@ static int gather_environment_collect(int fd, void *arg) {
|
||||
}
|
||||
|
||||
static int gather_environment_consume(int fd, void *arg) {
|
||||
_cleanup_fclose_ FILE *f = NULL;
|
||||
char ***env = ASSERT_PTR(arg);
|
||||
int r = 0;
|
||||
_cleanup_fclose_ FILE *f = NULL;
|
||||
int r, ret = 0;
|
||||
|
||||
/* Read a series of env=cescape(VAR=value) assignments from fd into env. */
|
||||
|
||||
assert(fd >= 0);
|
||||
|
||||
f = fdopen(fd, "r");
|
||||
if (!f) {
|
||||
safe_close(fd);
|
||||
@@ -409,35 +417,33 @@ static int gather_environment_consume(int fd, void *arg) {
|
||||
for (;;) {
|
||||
_cleanup_free_ char *line = NULL;
|
||||
const char *v;
|
||||
int k;
|
||||
|
||||
k = read_line(f, LONG_LINE_MAX, &line);
|
||||
if (k < 0)
|
||||
return k;
|
||||
if (k == 0)
|
||||
break;
|
||||
r = read_line(f, LONG_LINE_MAX, &line);
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (r == 0)
|
||||
return ret;
|
||||
|
||||
v = startswith(line, "env=");
|
||||
if (!v) {
|
||||
log_debug("Serialization line \"%s\" unexpectedly didn't start with \"env=\".", line);
|
||||
if (r == 0)
|
||||
r = -EINVAL;
|
||||
|
||||
RET_GATHER(ret, log_debug_errno(SYNTHETIC_ERRNO(EINVAL),
|
||||
"Serialization line unexpectedly didn't start with \"env=\", ignoring: %s",
|
||||
line));
|
||||
continue;
|
||||
}
|
||||
|
||||
k = deserialize_environment(v, env);
|
||||
if (k < 0) {
|
||||
log_debug_errno(k, "Invalid serialization line \"%s\": %m", line);
|
||||
|
||||
if (r == 0)
|
||||
r = k;
|
||||
}
|
||||
r = deserialize_environment(v, env);
|
||||
if (r < 0)
|
||||
RET_GATHER(ret, log_debug_errno(r, "Failed to deserialize line \"%s\": %m", line));
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
const gather_stdout_callback_t gather_environment[_STDOUT_CONSUME_MAX] = {
|
||||
gather_environment_generate,
|
||||
gather_environment_collect,
|
||||
gather_environment_consume,
|
||||
};
|
||||
|
||||
int exec_command_flags_from_strv(char * const *ex_opts, ExecCommandFlags *ret) {
|
||||
ExecCommandFlags flags = 0;
|
||||
|
||||
@@ -478,12 +484,6 @@ int exec_command_flags_to_strv(ExecCommandFlags flags, char ***ret) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
const gather_stdout_callback_t gather_environment[] = {
|
||||
gather_environment_generate,
|
||||
gather_environment_collect,
|
||||
gather_environment_consume,
|
||||
};
|
||||
|
||||
static const char* const exec_command_strings[] = {
|
||||
"ignore-failure", /* EXEC_COMMAND_IGNORE_FAILURE */
|
||||
"privileged", /* EXEC_COMMAND_FULLY_PRIVILEGED */
|
||||
|
||||
@@ -14,8 +14,7 @@ enum {
|
||||
_STDOUT_CONSUME_MAX,
|
||||
};
|
||||
|
||||
typedef enum {
|
||||
EXEC_DIR_NONE = 0, /* No execdir flags */
|
||||
typedef enum ExecDirFlags {
|
||||
EXEC_DIR_PARALLEL = 1 << 0, /* Execute scripts in parallel, if possible */
|
||||
EXEC_DIR_IGNORE_ERRORS = 1 << 1, /* Ignore non-zero exit status of scripts */
|
||||
EXEC_DIR_SET_SYSTEMD_EXEC_PID = 1 << 2, /* Set $SYSTEMD_EXEC_PID environment variable */
|
||||
@@ -23,6 +22,28 @@ typedef enum {
|
||||
EXEC_DIR_WARN_WORLD_WRITABLE = 1 << 4, /* Warn if world writable files are found */
|
||||
} ExecDirFlags;
|
||||
|
||||
int execute_strv(
|
||||
const char *name,
|
||||
char * const *paths,
|
||||
const char *root,
|
||||
usec_t timeout,
|
||||
gather_stdout_callback_t const callbacks[_STDOUT_CONSUME_MAX],
|
||||
void * const callback_args[_STDOUT_CONSUME_MAX],
|
||||
char *argv[],
|
||||
char *envp[],
|
||||
ExecDirFlags flags);
|
||||
|
||||
int execute_directories(
|
||||
const char * const *directories,
|
||||
usec_t timeout,
|
||||
gather_stdout_callback_t const callbacks[_STDOUT_CONSUME_MAX],
|
||||
void * const callback_args[_STDOUT_CONSUME_MAX],
|
||||
char *argv[],
|
||||
char *envp[],
|
||||
ExecDirFlags flags);
|
||||
|
||||
extern const gather_stdout_callback_t gather_environment[_STDOUT_CONSUME_MAX];
|
||||
|
||||
typedef enum ExecCommandFlags {
|
||||
EXEC_COMMAND_IGNORE_FAILURE = 1 << 0,
|
||||
EXEC_COMMAND_FULLY_PRIVILEGED = 1 << 1,
|
||||
@@ -32,31 +53,9 @@ typedef enum ExecCommandFlags {
|
||||
_EXEC_COMMAND_FLAGS_INVALID = -EINVAL,
|
||||
} ExecCommandFlags;
|
||||
|
||||
int execute_strv(
|
||||
const char *name,
|
||||
char* const* paths,
|
||||
const char *root,
|
||||
usec_t timeout,
|
||||
gather_stdout_callback_t const callbacks[_STDOUT_CONSUME_MAX],
|
||||
void* const callback_args[_STDOUT_CONSUME_MAX],
|
||||
char *argv[],
|
||||
char *envp[],
|
||||
ExecDirFlags flags);
|
||||
|
||||
int execute_directories(
|
||||
const char* const* directories,
|
||||
usec_t timeout,
|
||||
gather_stdout_callback_t const callbacks[_STDOUT_CONSUME_MAX],
|
||||
void* const callback_args[_STDOUT_CONSUME_MAX],
|
||||
char *argv[],
|
||||
char *envp[],
|
||||
ExecDirFlags flags);
|
||||
|
||||
int exec_command_flags_from_strv(char * const *ex_opts, ExecCommandFlags *ret);
|
||||
int exec_command_flags_to_strv(ExecCommandFlags flags, char ***ret);
|
||||
|
||||
extern const gather_stdout_callback_t gather_environment[_STDOUT_CONSUME_MAX];
|
||||
|
||||
const char* exec_command_flags_to_string(ExecCommandFlags i);
|
||||
ExecCommandFlags exec_command_flags_from_string(const char *s);
|
||||
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
#include "macro.h"
|
||||
#include "mkdir-label.h"
|
||||
#include "mountpoint-util.h"
|
||||
#include "parse-util.h"
|
||||
#include "path-util.h"
|
||||
#include "process-util.h"
|
||||
#include "special.h"
|
||||
@@ -974,3 +975,25 @@ void log_setup_generator(void) {
|
||||
log_parse_environment();
|
||||
log_open();
|
||||
}
|
||||
|
||||
bool generator_soft_rebooted(void) {
|
||||
static int cached = -1;
|
||||
int r;
|
||||
|
||||
if (cached >= 0)
|
||||
return cached;
|
||||
|
||||
const char *e = secure_getenv("SYSTEMD_SOFT_REBOOTS_COUNT");
|
||||
if (!e)
|
||||
return (cached = false);
|
||||
|
||||
unsigned u;
|
||||
|
||||
r = safe_atou(e, &u);
|
||||
if (r < 0) {
|
||||
log_debug_errno(r, "Failed to parse $SYSTEMD_SOFT_REBOOTS_COUNT, assuming the system hasn't soft-rebooted: %m");
|
||||
return (cached = false);
|
||||
}
|
||||
|
||||
return (cached = u > 0);
|
||||
}
|
||||
|
||||
@@ -100,6 +100,8 @@ int generator_enable_remount_fs_service(const char *dir);
|
||||
|
||||
void log_setup_generator(void);
|
||||
|
||||
bool generator_soft_rebooted(void);
|
||||
|
||||
/* Similar to DEFINE_MAIN_FUNCTION, but initializes logging and assigns positional arguments. */
|
||||
#define DEFINE_MAIN_GENERATOR_FUNCTION(impl) \
|
||||
_DEFINE_MAIN_FUNCTION( \
|
||||
|
||||
@@ -402,7 +402,9 @@ TEST(error_catching) {
|
||||
if (access(name, X_OK) < 0 && ERRNO_IS_PRIVILEGE(errno))
|
||||
return;
|
||||
|
||||
r = execute_directories(dirs, DEFAULT_TIMEOUT_USEC, NULL, NULL, NULL, NULL, EXEC_DIR_NONE);
|
||||
r = execute_directories(dirs, DEFAULT_TIMEOUT_USEC,
|
||||
/* callbacks = */ NULL, /* callback_args = */ NULL,
|
||||
/* argv = */ NULL, /* envp = */ NULL, /* flags = */ 0);
|
||||
|
||||
/* we should exit with the error code of the first script that failed */
|
||||
assert_se(r == 42);
|
||||
|
||||
Reference in New Issue
Block a user