return strcmp(fa, fb);
}
+int path_equal_or_inode_same_full(const char *a, const char *b, int flags) {
+ /* Returns true if paths are of the same entry, false if not, <0 on error. */
+
+ if (path_equal(a, b))
+ return 1;
+
+ if (!a || !b)
+ return 0;
+
+ return inode_same(a, b, flags);
+}
+
char* path_extend_internal(char **x, ...) {
size_t sz, old_sz;
char *q, *nx;
* binary. */
p = getenv("PATH");
if (!p)
- p = DEFAULT_PATH;
+ p = default_PATH();
if (exec_search_path) {
STRV_FOREACH(element, exec_search_path) {
*ret = NULL;
return false;
}
+
+ const char* default_PATH(void) {
+ #if HAVE_SPLIT_BIN
+ static int split = -1;
+ int r;
+
+ /* Check whether /usr/sbin is not a symlink and return the appropriate $PATH.
+ * On error fall back to the safe value with both directories as configured… */
+
+ if (split < 0)
+ STRV_FOREACH_PAIR(bin, sbin, STRV_MAKE("/usr/bin", "/usr/sbin",
+ "/usr/local/bin", "/usr/local/sbin")) {
+ r = inode_same(*bin, *sbin, AT_NO_AUTOMOUNT);
+ if (r > 0 || r == -ENOENT)
+ continue;
+ if (r < 0)
+ log_debug_errno(r, "Failed to compare \"%s\" and \"%s\", using compat $PATH: %m",
+ *bin, *sbin);
+ split = true;
+ break;
+ }
+ if (split < 0)
+ split = false;
+ if (split)
+ return DEFAULT_PATH_WITH_SBIN;
+ #endif
+ return DEFAULT_PATH_WITHOUT_SBIN;
+ }
#include "strv.h"
#include "time-util.h"
- #define PATH_SPLIT_SBIN_BIN(x) x "sbin:" x "bin"
- #define PATH_SPLIT_SBIN_BIN_NULSTR(x) x "sbin\0" x "bin\0"
+ #define PATH_SPLIT_BIN(x) x "sbin:" x "bin"
+ #define PATH_SPLIT_BIN_NULSTR(x) x "sbin\0" x "bin\0"
- #define PATH_NORMAL_SBIN_BIN(x) x "bin"
- #define PATH_NORMAL_SBIN_BIN_NULSTR(x) x "bin\0"
+ #define PATH_MERGED_BIN(x) x "bin"
+ #define PATH_MERGED_BIN_NULSTR(x) x "bin\0"
- #if HAVE_SPLIT_BIN
- # define PATH_SBIN_BIN(x) PATH_SPLIT_SBIN_BIN(x)
- # define PATH_SBIN_BIN_NULSTR(x) PATH_SPLIT_SBIN_BIN_NULSTR(x)
- #else
- # define PATH_SBIN_BIN(x) PATH_NORMAL_SBIN_BIN(x)
- # define PATH_SBIN_BIN_NULSTR(x) PATH_NORMAL_SBIN_BIN_NULSTR(x)
- #endif
+ #define DEFAULT_PATH_WITH_SBIN PATH_SPLIT_BIN("/usr/local/") ":" PATH_SPLIT_BIN("/usr/")
+ #define DEFAULT_PATH_WITHOUT_SBIN PATH_MERGED_BIN("/usr/local/") ":" PATH_MERGED_BIN("/usr/")
- #define DEFAULT_PATH PATH_SBIN_BIN("/usr/local/") ":" PATH_SBIN_BIN("/usr/")
- #define DEFAULT_PATH_NULSTR PATH_SBIN_BIN_NULSTR("/usr/local/") PATH_SBIN_BIN_NULSTR("/usr/")
- #define DEFAULT_PATH_COMPAT PATH_SPLIT_SBIN_BIN("/usr/local/") ":" PATH_SPLIT_SBIN_BIN("/usr/") ":" PATH_SPLIT_SBIN_BIN("/")
+ #define DEFAULT_PATH_COMPAT PATH_SPLIT_BIN("/usr/local/") ":" PATH_SPLIT_BIN("/usr/") ":" PATH_SPLIT_BIN("/")
- #ifndef DEFAULT_USER_PATH
- # define DEFAULT_USER_PATH DEFAULT_PATH
+ const char* default_PATH(void);
+
+ static inline const char* default_user_PATH(void) {
+ #ifdef DEFAULT_USER_PATH
+ return DEFAULT_USER_PATH;
+ #else
+ return default_PATH();
#endif
+ }
static inline bool is_path(const char *p) {
if (!p) /* A NULL pointer is definitely not a path */
return path_compare_filename(a, b) == 0;
}
+int path_equal_or_inode_same_full(const char *a, const char *b, int flags);
static inline bool path_equal_or_inode_same(const char *a, const char *b, int flags) {
- return path_equal(a, b) || inode_same(a, b, flags) > 0;
+ return path_equal_or_inode_same_full(a, b, flags) > 0;
}
char* path_extend_internal(char **x, ...);
}
int manager_default_environment(Manager *m) {
- int r;
-
assert(m);
m->transient_environment = strv_free(m->transient_environment);
*
* The initial passed environment is untouched to keep /proc/self/environ valid; it is used
* for tagging the init process inside containers. */
- m->transient_environment = strv_new("PATH=" DEFAULT_PATH);
- if (!m->transient_environment)
+ char *path = strjoin("PATH=", default_PATH());
+ if (!path)
+ return log_oom();
+
+ if (strv_consume(&m->transient_environment, path) < 0)
return log_oom();
/* Import locale variables LC_*= from configuration */
if (!m->transient_environment)
return log_oom();
- r = strv_env_replace_strdup(&m->transient_environment, "PATH=" DEFAULT_USER_PATH);
- if (r < 0)
+ char *path = strjoin("PATH=", default_user_PATH());
+ if (!path)
+ return log_oom();
+
+ if (strv_env_replace_consume(&m->transient_environment, path) < 0)
return log_oom();
/* Envvars set for our 'manager' class session are private and should not be propagated
return log_error_errno(r, "Deserialization failed: %m");
}
+ if (m->previous_objective >= 0) {
+ if (IN_SET(m->previous_objective, MANAGER_REEXECUTE, MANAGER_SOFT_REBOOT, MANAGER_SWITCH_ROOT))
+ log_debug("Launching as effect of a '%s' operation.",
+ manager_objective_to_string(m->previous_objective));
+ else
+ log_warning("Got unexpected previous objective '%s', ignoring.",
+ manager_objective_to_string(m->previous_objective));
+ }
+
/* If we are in a new soft-reboot iteration bump the counter now before starting units, so
* that they can reliably read it. We get the previous objective from serialized state. */
if (m->previous_objective == MANAGER_SOFT_REBOOT)
if (MANAGER_IS_SYSTEM(m) && m->soft_reboots_count > 0) {
/* The soft-reboot case, where we only report data for the last reboot */
firmware_usec = loader_usec = initrd_usec = kernel_usec = 0;
- total_usec = userspace_usec = usec_sub_unsigned(m->timestamps[MANAGER_TIMESTAMP_FINISH].monotonic, m->timestamps[MANAGER_TIMESTAMP_SHUTDOWN_START].monotonic);
+ total_usec = userspace_usec = usec_sub_unsigned(m->timestamps[MANAGER_TIMESTAMP_FINISH].monotonic,
+ m->timestamps[MANAGER_TIMESTAMP_SHUTDOWN_START].monotonic);
log_struct(LOG_INFO,
"MESSAGE_ID=" SD_MESSAGE_STARTUP_FINISHED_STR,
"USERSPACE_USEC="USEC_FMT, userspace_usec,
- LOG_MESSAGE("Soft-reboot finished in %s.",
- FORMAT_TIMESPAN(total_usec, USEC_PER_MSEC)));
+ LOG_MESSAGE("Soft-reboot finished in %s, counter is now at %u.",
+ FORMAT_TIMESPAN(total_usec, USEC_PER_MSEC),
+ m->soft_reboots_count));
} else if (MANAGER_IS_SYSTEM(m) && detect_container() <= 0) {
char buf[FORMAT_TIMESPAN_MAX + STRLEN(" (firmware) + ") + FORMAT_TIMESPAN_MAX + STRLEN(" (loader) + ")]
= {};
set_show_status_marker(show_status_on(mode));
}
-const char *manager_get_confirm_spawn(Manager *m) {
+const char* manager_get_confirm_spawn(Manager *m) {
static int last_errno = 0;
struct stat st;
int r;
return LOG_TARGET_KMSG;
}
-static const char *const manager_state_table[_MANAGER_STATE_MAX] = {
+static const char* const manager_state_table[_MANAGER_STATE_MAX] = {
[MANAGER_INITIALIZING] = "initializing",
[MANAGER_STARTING] = "starting",
[MANAGER_RUNNING] = "running",
DEFINE_STRING_TABLE_LOOKUP(manager_state, ManagerState);
-static const char *const manager_timestamp_table[_MANAGER_TIMESTAMP_MAX] = {
+static const char* const manager_objective_table[_MANAGER_OBJECTIVE_MAX] = {
+ [MANAGER_OK] = "ok",
+ [MANAGER_EXIT] = "exit",
+ [MANAGER_RELOAD] = "reload",
+ [MANAGER_REEXECUTE] = "reexecute",
+ [MANAGER_REBOOT] = "reboot",
+ [MANAGER_SOFT_REBOOT] = "soft-reboot",
+ [MANAGER_POWEROFF] = "poweroff",
+ [MANAGER_HALT] = "halt",
+ [MANAGER_KEXEC] = "kexec",
+ [MANAGER_SWITCH_ROOT] = "switch-root",
+};
+
+DEFINE_STRING_TABLE_LOOKUP(manager_objective, ManagerObjective);
+
+static const char* const manager_timestamp_table[_MANAGER_TIMESTAMP_MAX] = {
[MANAGER_TIMESTAMP_FIRMWARE] = "firmware",
[MANAGER_TIMESTAMP_LOADER] = "loader",
[MANAGER_TIMESTAMP_KERNEL] = "kernel",