1
1
mirror of https://github.com/systemd/systemd-stable.git synced 2025-02-10 13:57:25 +03:00

Merge pull request #3078 from poettering/get-processes

A variety of fixes and additions
This commit is contained in:
Zbigniew Jędrzejewski-Szmek 2016-04-22 14:03:33 -04:00
commit 47cb7f723a
52 changed files with 2094 additions and 1106 deletions

View File

@ -962,6 +962,7 @@ noinst_LTLIBRARIES += \
libshared_la_SOURCES = \
src/shared/output-mode.h \
src/shared/output-mode.c \
src/shared/gpt.h \
src/shared/udev-util.h \
src/shared/linux/auto_dev-ioctl.h \
@ -1037,6 +1038,8 @@ libshared_la_SOURCES = \
src/shared/machine-pool.h \
src/shared/resolve-util.c \
src/shared/resolve-util.h \
src/shared/bus-unit-util.c \
src/shared/bus-unit-util.h \
src/shared/tests.h \
src/shared/tests.c

9
TODO
View File

@ -33,11 +33,16 @@ Janitorial Clean-ups:
Features:
* rework fopen_temporary() to make use of open_tmpfile_linkable() (problem: the
kernel doesn't support linkat() that replaces existing files, currently)
* journalctl -f --no-tail fails for Lennart
* check if DeviceAllow= should split first, resolve specifiers later
* transient units: don't bother with actually setting unit properties, we
reload the unit file anyway
* https://github.com/systemd/systemd/pull/2886 is fucked
* make sure resolved can be restarted without losing pushed-in dns config
* fix https://github.com/systemd/systemd/pull/2890, this shouldn't be exported

View File

@ -180,14 +180,12 @@
functionality of the init system, it is recommended not to
execute them when run as new-style service.</para>
<para>Note that new-style init systems guarantee execution of
daemon processes in a clean process context: it is guaranteed
that the environment block is sanitized, that the signal
handlers and mask is reset and that no left-over file
descriptors are passed. Daemons will be executed in their own
session, with standard input/output/error connected to
<filename>/dev/null</filename> unless otherwise configured. The
umask is reset.
<para>Note that new-style init systems guarantee execution of daemon processes in a clean process context: it is
guaranteed that the environment block is sanitized, that the signal handlers and mask is reset and that no
left-over file descriptors are passed. Daemons will be executed in their own session, with standard input
connected to <filename>/dev/null</filename> and standard output/error connected to the
<citerefentry><refentrytitle>systemd-journald.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>
logging service, unless otherwise configured. The umask is reset.
</para>
<para>It is recommended for new-style daemons to implement the

View File

@ -270,6 +270,16 @@
</listitem>
</varlistentry>
<varlistentry>
<term>
<option>short-unix</option>
</term>
<listitem>
<para>is very similar, but shows seconds passed since January 1st 1970 UTC instead of wallclock
timestamps ("UNIX time"). The time is shown with microsecond accuracy.</para>
</listitem>
</varlistentry>
<varlistentry>
<term>
<option>verbose</option>
@ -349,6 +359,13 @@
(UTC).</para></listitem>
</varlistentry>
<varlistentry>
<term><option>--no-hostname</option></term>
<listitem><para>Don't show the hostname field of log messages originating from the local host. This switch only
has an effect on the <option>short</option> family of output modes (see above).</para></listitem>
</varlistentry>
<varlistentry>
<term><option>-x</option></term>
<term><option>--catalog</option></term>

View File

@ -28,6 +28,7 @@
#include "alloc-util.h"
#include "analyze-verify.h"
#include "bus-error.h"
#include "bus-unit-util.h"
#include "bus-util.h"
#include "glob-util.h"
#include "hashmap.h"

View File

@ -1083,30 +1083,6 @@ int mkostemp_safe(char *pattern, int flags) {
return fd;
}
int open_tmpfile(const char *path, int flags) {
char *p;
int fd;
assert(path);
#ifdef O_TMPFILE
/* Try O_TMPFILE first, if it is supported */
fd = open(path, flags|O_TMPFILE|O_EXCL, S_IRUSR|S_IWUSR);
if (fd >= 0)
return fd;
#endif
/* Fall back to unguessable name + unlinking */
p = strjoina(path, "/systemd-tmp-XXXXXX");
fd = mkostemp_safe(p, flags);
if (fd < 0)
return fd;
unlink(p);
return fd;
}
int tempfn_xxxxxx(const char *p, const char *extra, char **ret) {
const char *fn;
char *t;
@ -1278,3 +1254,103 @@ int fputs_with_space(FILE *f, const char *s, const char *separator, bool *space)
return fputs(s, f);
}
int open_tmpfile_unlinkable(const char *directory, int flags) {
char *p;
int fd;
assert(directory);
/* Returns an unlinked temporary file that cannot be linked into the file system anymore */
#ifdef O_TMPFILE
/* Try O_TMPFILE first, if it is supported */
fd = open(directory, flags|O_TMPFILE|O_EXCL, S_IRUSR|S_IWUSR);
if (fd >= 0)
return fd;
#endif
/* Fall back to unguessable name + unlinking */
p = strjoina(directory, "/systemd-tmp-XXXXXX");
fd = mkostemp_safe(p, flags);
if (fd < 0)
return fd;
(void) unlink(p);
return fd;
}
int open_tmpfile_linkable(const char *target, int flags, char **ret_path) {
_cleanup_free_ char *tmp = NULL;
int r, fd;
assert(target);
assert(ret_path);
/* Don't allow O_EXCL, as that has a special meaning for O_TMPFILE */
assert((flags & O_EXCL) == 0);
/* Creates a temporary file, that shall be renamed to "target" later. If possible, this uses O_TMPFILE in
* which case "ret_path" will be returned as NULL. If not possible a the tempoary path name used is returned in
* "ret_path". Use link_tmpfile() below to rename the result after writing the file in full. */
#ifdef O_TMPFILE
{
_cleanup_free_ char *dn = NULL;
dn = dirname_malloc(target);
if (!dn)
return -ENOMEM;
fd = open(dn, O_TMPFILE|flags, 0640);
if (fd >= 0) {
*ret_path = NULL;
return fd;
}
log_debug_errno(errno, "Failed to use O_TMPFILE on %s: %m", dn);
}
#endif
r = tempfn_random(target, NULL, &tmp);
if (r < 0)
return r;
fd = open(tmp, O_CREAT|O_EXCL|O_NOFOLLOW|O_NOCTTY|flags, 0640);
if (fd < 0)
return -errno;
*ret_path = tmp;
tmp = NULL;
return fd;
}
int link_tmpfile(int fd, const char *path, const char *target) {
assert(fd >= 0);
assert(target);
/* Moves a temporary file created with open_tmpfile() above into its final place. if "path" is NULL an fd
* created with O_TMPFILE is assumed, and linkat() is used. Otherwise it is assumed O_TMPFILE is not supported
* on the directory, and renameat2() is used instead.
*
* Note that in both cases we will not replace existing files. This is because linkat() dos not support this
* operation currently (renameat2() does), and there is no nice way to emulate this. */
if (path) {
if (rename_noreplace(AT_FDCWD, path, AT_FDCWD, target) < 0)
return -errno;
} else {
char proc_fd_path[strlen("/proc/self/fd/") + DECIMAL_STR_MAX(fd) + 1];
xsprintf(proc_fd_path, "/proc/self/fd/%i", fd);
if (linkat(AT_FDCWD, proc_fd_path, AT_FDCWD, target, AT_SYMLINK_FOLLOW) < 0)
return -errno;
}
return 0;
}

View File

@ -72,7 +72,6 @@ int fflush_and_check(FILE *f);
int fopen_temporary(const char *path, FILE **_f, char **_temp_path);
int mkostemp_safe(char *pattern, int flags);
int open_tmpfile(const char *path, int flags);
int tempfn_xxxxxx(const char *p, const char *extra, char **ret);
int tempfn_random(const char *p, const char *extra, char **ret);
@ -82,3 +81,8 @@ int write_timestamp_file_atomic(const char *fn, usec_t n);
int read_timestamp_file(const char *fn, usec_t *ret);
int fputs_with_space(FILE *f, const char *s, const char *separator, bool *space);
int open_tmpfile_unlinkable(const char *directory, int flags);
int open_tmpfile_linkable(const char *target, int flags, char **ret_path);
int link_tmpfile(int fd, const char *path, const char *target);

View File

@ -731,6 +731,18 @@ void valgrind_summary_hack(void) {
#endif
}
int pid_compare_func(const void *a, const void *b) {
const pid_t *p = a, *q = b;
/* Suitable for usage in qsort() */
if (*p < *q)
return -1;
if (*p > *q)
return 1;
return 0;
}
static const char *const ioprio_class_table[] = {
[IOPRIO_CLASS_NONE] = "none",
[IOPRIO_CLASS_RT] = "realtime",

View File

@ -101,3 +101,5 @@ int sched_policy_from_string(const char *s);
#define PID_TO_PTR(p) ((void*) ((uintptr_t) p))
void valgrind_summary_hack(void);
int pid_compare_func(const void *a, const void *b);

View File

@ -1080,22 +1080,31 @@ bool timezone_is_valid(const char *name) {
return true;
}
clockid_t clock_boottime_or_monotonic(void) {
static clockid_t clock = -1;
int fd;
bool clock_boottime_supported(void) {
static int supported = -1;
if (clock != -1)
return clock;
/* Note that this checks whether CLOCK_BOOTTIME is available in general as well as available for timerfds()! */
fd = timerfd_create(CLOCK_BOOTTIME, TFD_NONBLOCK|TFD_CLOEXEC);
if (fd < 0)
clock = CLOCK_MONOTONIC;
else {
safe_close(fd);
clock = CLOCK_BOOTTIME;
if (supported < 0) {
int fd;
fd = timerfd_create(CLOCK_BOOTTIME, TFD_NONBLOCK|TFD_CLOEXEC);
if (fd < 0)
supported = false;
else {
safe_close(fd);
supported = true;
}
}
return clock;
return supported;
}
clockid_t clock_boottime_or_monotonic(void) {
if (clock_boottime_supported())
return CLOCK_BOOTTIME;
else
return CLOCK_MONOTONIC;
}
int get_timezone(char **tz) {

View File

@ -112,6 +112,7 @@ bool ntp_synced(void);
int get_timezones(char ***l);
bool timezone_is_valid(const char *name);
bool clock_boottime_supported(void);
clockid_t clock_boottime_or_monotonic(void);
#define xstrftime(buf, fmt, tm) \

View File

@ -191,7 +191,8 @@ int main(int argc, char *argv[]) {
output_flags =
arg_all * OUTPUT_SHOW_ALL |
(arg_full > 0) * OUTPUT_FULL_WIDTH;
(arg_full > 0) * OUTPUT_FULL_WIDTH |
arg_kernel_threads * OUTPUT_KERNEL_THREADS;
if (optind < argc) {
_cleanup_free_ char *root = NULL;
@ -209,7 +210,7 @@ int main(int argc, char *argv[]) {
printf("Directory %s:\n", argv[i]);
fflush(stdout);
q = show_cgroup_by_path(argv[i], NULL, 0, arg_kernel_threads, output_flags);
q = show_cgroup_by_path(argv[i], NULL, 0, output_flags);
} else {
_cleanup_free_ char *c = NULL, *p = NULL, *j = NULL;
const char *controller, *path;
@ -235,7 +236,7 @@ int main(int argc, char *argv[]) {
show_cg_info(controller, path);
q = show_cgroup(controller, path, NULL, 0, arg_kernel_threads, output_flags);
q = show_cgroup(controller, path, NULL, 0, output_flags);
}
if (q < 0)
@ -258,7 +259,7 @@ int main(int argc, char *argv[]) {
printf("Working directory %s:\n", cwd);
fflush(stdout);
r = show_cgroup_by_path(cwd, NULL, 0, arg_kernel_threads, output_flags);
r = show_cgroup_by_path(cwd, NULL, 0, output_flags);
done = true;
}
}
@ -273,7 +274,7 @@ int main(int argc, char *argv[]) {
show_cg_info(SYSTEMD_CGROUP_CONTROLLER, root);
printf("-.slice\n");
r = show_cgroup(SYSTEMD_CGROUP_CONTROLLER, root, NULL, 0, arg_kernel_threads, output_flags);
r = show_cgroup(SYSTEMD_CGROUP_CONTROLLER, root, NULL, 0, output_flags);
}
}

View File

@ -999,6 +999,14 @@ static bool busname_supported(void) {
return supported;
}
static int busname_control_pid(Unit *u) {
BusName *n = BUSNAME(u);
assert(n);
return n->control_pid;
}
static const char* const busname_result_table[_BUSNAME_RESULT_MAX] = {
[BUSNAME_SUCCESS] = "success",
[BUSNAME_FAILURE_RESOURCES] = "resources",
@ -1052,6 +1060,8 @@ const UnitVTable busname_vtable = {
.supported = busname_supported,
.control_pid = busname_control_pid,
.bus_vtable = bus_busname_vtable,
.status_message_formats = {

View File

@ -642,6 +642,30 @@ static int method_set_unit_properties(sd_bus_message *message, void *userdata, s
return bus_unit_method_set_properties(message, u, error);
}
static int method_get_unit_processes(sd_bus_message *message, void *userdata, sd_bus_error *error) {
Manager *m = userdata;
const char *name;
Unit *u;
int r;
assert(message);
assert(m);
r = sd_bus_message_read(message, "s", &name);
if (r < 0)
return r;
r = manager_load_unit(m, name, NULL, error, &u);
if (r < 0)
return r;
r = bus_unit_check_load_state(u, error);
if (r < 0)
return r;
return bus_unit_method_get_processes(message, u, error);
}
static int transient_unit_from_message(
Manager *m,
sd_bus_message *message,
@ -2042,6 +2066,7 @@ const sd_bus_vtable bus_manager_vtable[] = {
SD_BUS_METHOD("ResetFailedUnit", "s", NULL, method_reset_failed_unit, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("SetUnitProperties", "sba(sv)", NULL, method_set_unit_properties, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("StartTransientUnit", "ssa(sv)a(sa(sv))", "o", method_start_transient_unit, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("GetUnitProcesses", "s", "a(sus)", method_get_unit_processes, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("GetJob", "u", "o", method_get_job, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("CancelJob", "u", NULL, method_cancel_job, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("ClearJobs", NULL, NULL, method_clear_jobs, SD_BUS_VTABLE_UNPRIVILEGED),

View File

@ -24,8 +24,10 @@
#include "cgroup-util.h"
#include "dbus-unit.h"
#include "dbus.h"
#include "fd-util.h"
#include "locale-util.h"
#include "log.h"
#include "process-util.h"
#include "selinux-access.h"
#include "signal-util.h"
#include "special.h"
@ -841,6 +843,146 @@ static int property_get_cgroup(
return sd_bus_message_append(reply, "s", t);
}
static int append_process(sd_bus_message *reply, const char *p, pid_t pid, Set *pids) {
_cleanup_free_ char *buf = NULL, *cmdline = NULL;
int r;
assert(reply);
assert(pid > 0);
r = set_put(pids, PID_TO_PTR(pid));
if (r == -EEXIST || r == 0)
return 0;
if (r < 0)
return r;
if (!p) {
r = cg_pid_get_path(SYSTEMD_CGROUP_CONTROLLER, pid, &buf);
if (r == -ESRCH)
return 0;
if (r < 0)
return r;
p = buf;
}
(void) get_process_cmdline(pid, 0, true, &cmdline);
return sd_bus_message_append(reply,
"(sus)",
p,
(uint32_t) pid,
cmdline);
}
static int append_cgroup(sd_bus_message *reply, const char *p, Set *pids) {
_cleanup_closedir_ DIR *d = NULL;
_cleanup_fclose_ FILE *f = NULL;
int r;
assert(reply);
assert(p);
r = cg_enumerate_processes(SYSTEMD_CGROUP_CONTROLLER, p, &f);
if (r == ENOENT)
return 0;
if (r < 0)
return r;
for (;;) {
pid_t pid;
r = cg_read_pid(f, &pid);
if (r < 0)
return r;
if (r == 0)
break;
if (is_kernel_thread(pid) > 0)
continue;
r = append_process(reply, p, pid, pids);
if (r < 0)
return r;
}
r = cg_enumerate_subgroups(SYSTEMD_CGROUP_CONTROLLER, p, &d);
if (r == -ENOENT)
return 0;
if (r < 0)
return r;
for (;;) {
_cleanup_free_ char *g = NULL, *j = NULL;
r = cg_read_subgroup(d, &g);
if (r < 0)
return r;
if (r == 0)
break;
j = strjoin(p, "/", g, NULL);
if (!j)
return -ENOMEM;
r = append_cgroup(reply, j, pids);
if (r < 0)
return r;
}
return 0;
}
int bus_unit_method_get_processes(sd_bus_message *message, void *userdata, sd_bus_error *error) {
_cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
_cleanup_(set_freep) Set *pids = NULL;
_cleanup_free_ char *p = NULL;
Unit *u = userdata;
pid_t pid;
int r;
assert(message);
pids = set_new(NULL);
if (!pids)
return -ENOMEM;
r = sd_bus_message_new_method_return(message, &reply);
if (r < 0)
return r;
r = sd_bus_message_open_container(reply, 'a', "(sus)");
if (r < 0)
return r;
if (u->cgroup_path) {
r = append_cgroup(reply, u->cgroup_path, pids);
if (r < 0)
return r;
}
/* The main and control pids might live outside of the cgroup, hence fetch them separately */
pid = unit_main_pid(u);
if (pid > 0) {
r = append_process(reply, NULL, pid, pids);
if (r < 0)
return r;
}
pid = unit_control_pid(u);
if (pid > 0) {
r = append_process(reply, NULL, pid, pids);
if (r < 0)
return r;
}
r = sd_bus_message_close_container(reply);
if (r < 0)
return r;
return sd_bus_send(NULL, reply, NULL);
}
const sd_bus_vtable bus_unit_cgroup_vtable[] = {
SD_BUS_VTABLE_START(0),
SD_BUS_PROPERTY("Slice", "s", property_get_slice, 0, 0),
@ -848,6 +990,7 @@ const sd_bus_vtable bus_unit_cgroup_vtable[] = {
SD_BUS_PROPERTY("MemoryCurrent", "t", property_get_current_memory, 0, 0),
SD_BUS_PROPERTY("CPUUsageNSec", "t", property_get_cpu_usage, 0, 0),
SD_BUS_PROPERTY("TasksCurrent", "t", property_get_current_tasks, 0, 0),
SD_BUS_METHOD("GetProcesses", NULL, "a(sus)", bus_unit_method_get_processes, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_VTABLE_END
};

View File

@ -36,5 +36,6 @@ int bus_unit_method_reset_failed(sd_bus_message *message, void *userdata, sd_bus
int bus_unit_queue_job(sd_bus_message *message, Unit *u, JobType type, JobMode mode, bool reload_if_possible, sd_bus_error *error);
int bus_unit_set_properties(Unit *u, sd_bus_message *message, UnitSetPropertiesMode mode, bool commit, sd_bus_error *error);
int bus_unit_method_set_properties(sd_bus_message *message, void *userdata, sd_bus_error *error);
int bus_unit_method_get_processes(sd_bus_message *message, void *userdata, sd_bus_error *error);
int bus_unit_check_load_state(Unit *u, sd_bus_error *error);

View File

@ -101,14 +101,23 @@ static int read_machine_id(int fd, char id[34]) {
return 0;
}
static int write_machine_id(int fd, char id[34]) {
static int write_machine_id(int fd, const char id[34]) {
int r;
assert(fd >= 0);
assert(id);
if (lseek(fd, 0, SEEK_SET) < 0)
return -errno;
return loop_write(fd, id, 33, false);
r = loop_write(fd, id, 33, false);
if (r < 0)
return r;
if (fsync(fd) < 0)
return -errno;
return 0;
}
static int generate_machine_id(char id[34], const char *root) {

View File

@ -2191,7 +2191,7 @@ int manager_open_serialization(Manager *m, FILE **_f) {
assert(_f);
path = MANAGER_IS_SYSTEM(m) ? "/run/systemd" : "/tmp";
fd = open_tmpfile(path, O_RDWR|O_CLOEXEC);
fd = open_tmpfile_unlinkable(path, O_RDWR|O_CLOEXEC);
if (fd < 0)
return -errno;

View File

@ -1790,6 +1790,14 @@ static int mount_kill(Unit *u, KillWho who, int signo, sd_bus_error *error) {
return unit_kill_common(u, who, signo, -1, MOUNT(u)->control_pid, error);
}
static int mount_control_pid(Unit *u) {
Mount *m = MOUNT(u);
assert(m);
return m->control_pid;
}
static const char* const mount_exec_command_table[_MOUNT_EXEC_COMMAND_MAX] = {
[MOUNT_EXEC_MOUNT] = "ExecMount",
[MOUNT_EXEC_UNMOUNT] = "ExecUnmount",
@ -1851,6 +1859,8 @@ const UnitVTable mount_vtable = {
.reset_failed = mount_reset_failed,
.control_pid = mount_control_pid,
.bus_vtable = bus_mount_vtable,
.bus_set_property = bus_mount_set_property,
.bus_commit_properties = bus_mount_commit_properties,

View File

@ -76,6 +76,10 @@
send_interface="org.freedesktop.systemd1.Manager"
send_member="GetUnitFileState"/>
<allow send_destination="org.freedesktop.systemd1"
send_interface="org.freedesktop.systemd1.Manager"
send_member="GetUnitProcesses"/>
<allow send_destination="org.freedesktop.systemd1"
send_interface="org.freedesktop.systemd1.Manager"
send_member="ListJobs"/>

View File

@ -3195,6 +3195,22 @@ static int service_kill(Unit *u, KillWho who, int signo, sd_bus_error *error) {
return unit_kill_common(u, who, signo, s->main_pid, s->control_pid, error);
}
static int service_main_pid(Unit *u) {
Service *s = SERVICE(u);
assert(s);
return s->main_pid;
}
static int service_control_pid(Unit *u) {
Service *s = SERVICE(u);
assert(s);
return s->control_pid;
}
static const char* const service_restart_table[_SERVICE_RESTART_MAX] = {
[SERVICE_RESTART_NO] = "no",
[SERVICE_RESTART_ON_SUCCESS] = "on-success",
@ -3303,6 +3319,9 @@ const UnitVTable service_vtable = {
.notify_cgroup_empty = service_notify_cgroup_empty_event,
.notify_message = service_notify_message,
.main_pid = service_main_pid,
.control_pid = service_control_pid,
.bus_name_owner_change = service_bus_name_owner_change,
.bus_vtable = bus_service_vtable,

View File

@ -2781,6 +2781,14 @@ char *socket_fdname(Socket *s) {
return UNIT(s)->id;
}
static int socket_control_pid(Unit *u) {
Socket *s = SOCKET(u);
assert(s);
return s->control_pid;
}
static const char* const socket_exec_command_table[_SOCKET_EXEC_COMMAND_MAX] = {
[SOCKET_EXEC_START_PRE] = "StartPre",
[SOCKET_EXEC_START_CHOWN] = "StartChown",
@ -2846,6 +2854,8 @@ const UnitVTable socket_vtable = {
.reset_failed = socket_reset_failed,
.control_pid = socket_control_pid,
.bus_vtable = bus_socket_vtable,
.bus_set_property = bus_socket_set_property,
.bus_commit_properties = bus_socket_commit_properties,

View File

@ -1426,6 +1426,14 @@ static bool swap_supported(void) {
return supported;
}
static int swap_control_pid(Unit *u) {
Swap *s = SWAP(u);
assert(s);
return s->control_pid;
}
static const char* const swap_exec_command_table[_SWAP_EXEC_COMMAND_MAX] = {
[SWAP_EXEC_ACTIVATE] = "ExecActivate",
[SWAP_EXEC_DEACTIVATE] = "ExecDeactivate",
@ -1487,6 +1495,8 @@ const UnitVTable swap_vtable = {
.reset_failed = swap_reset_failed,
.control_pid = swap_control_pid,
.bus_vtable = bus_swap_vtable,
.bus_set_property = bus_swap_set_property,
.bus_commit_properties = bus_swap_commit_properties,

View File

@ -373,7 +373,7 @@ static void timer_enter_waiting(Timer *t, bool initial) {
* rather than the monotonic clock. */
ts_realtime = now(CLOCK_REALTIME);
ts_monotonic = now(t->wake_system ? CLOCK_BOOTTIME : CLOCK_MONOTONIC);
ts_monotonic = now(t->wake_system ? clock_boottime_or_monotonic() : CLOCK_MONOTONIC);
t->next_elapse_monotonic_or_boottime = t->next_elapse_realtime = 0;
LIST_FOREACH(value, v, t->values) {

View File

@ -3801,3 +3801,21 @@ bool unit_is_pristine(Unit *u) {
u->job ||
u->merged_into);
}
pid_t unit_control_pid(Unit *u) {
assert(u);
if (UNIT_VTABLE(u)->control_pid)
return UNIT_VTABLE(u)->control_pid(u);
return 0;
}
pid_t unit_main_pid(Unit *u) {
assert(u);
if (UNIT_VTABLE(u)->main_pid)
return UNIT_VTABLE(u)->main_pid(u);
return 0;
}

View File

@ -390,6 +390,12 @@ struct UnitVTable {
/* Returns the next timeout of a unit */
int (*get_timeout)(Unit *u, usec_t *timeout);
/* Returns the main PID if there is any defined, or 0. */
pid_t (*main_pid)(Unit *u);
/* Returns the main PID if there is any defined, or 0. */
pid_t (*control_pid)(Unit *u);
/* This is called for each unit type and should be used to
* enumerate existing devices and load them. However,
* everything that is loaded here should still stay in
@ -601,6 +607,9 @@ bool unit_type_supported(UnitType t);
bool unit_is_pristine(Unit *u);
pid_t unit_control_pid(Unit *u);
pid_t unit_main_pid(Unit *u);
static inline bool unit_supported(Unit *u) {
return unit_type_supported(u->type);
}

View File

@ -224,6 +224,8 @@ static int fix_permissions(
const char *context[_CONTEXT_MAX],
uid_t uid) {
int r;
assert(fd >= 0);
assert(target);
assert(context);
@ -236,18 +238,9 @@ static int fix_permissions(
if (fsync(fd) < 0)
return log_error_errno(errno, "Failed to sync coredump %s: %m", coredump_tmpfile_name(filename));
if (filename) {
if (rename(filename, target) < 0)
return log_error_errno(errno, "Failed to rename coredump %s -> %s: %m", filename, target);
} else {
_cleanup_free_ char *proc_fd_path = NULL;
if (asprintf(&proc_fd_path, "/proc/self/fd/%d", fd) < 0)
return log_oom();
if (linkat(AT_FDCWD, proc_fd_path, AT_FDCWD, target, AT_SYMLINK_FOLLOW) < 0)
return log_error_errno(errno, "Failed to create coredump %s: %m", target);
}
r = link_tmpfile(fd, filename, target);
if (r < 0)
return log_error_errno(r, "Failed to move coredump %s into place: %m", target);
return 0;
}
@ -308,33 +301,6 @@ static int make_filename(const char *context[_CONTEXT_MAX], char **ret) {
return 0;
}
static int open_coredump_tmpfile(const char *target, char **ret_filename) {
_cleanup_free_ char *tmp = NULL;
int fd;
int r;
assert(target);
assert(ret_filename);
fd = open("/var/lib/systemd/coredump", O_TMPFILE|O_CLOEXEC|O_NOCTTY|O_RDWR, 0640);
if (fd < 0) {
log_debug_errno(errno, "Failed to use O_TMPFILE: %m");
r = tempfn_random(target, NULL, &tmp);
if (r < 0)
return log_error_errno(r, "Failed to determine temporary file name: %m");
fd = open(tmp, O_CREAT|O_EXCL|O_RDWR|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW, 0640);
if (fd < 0)
return log_error_errno(errno, "Failed to create coredump file %s: %m", tmp);
}
*ret_filename = tmp;
tmp = NULL;
return fd;
}
static int save_external_coredump(
const char *context[_CONTEXT_MAX],
int input_fd,
@ -378,9 +344,9 @@ static int save_external_coredump(
mkdir_p_label("/var/lib/systemd/coredump", 0755);
fd = open_coredump_tmpfile(fn, &tmp);
fd = open_tmpfile_linkable(fn, O_RDWR|O_CLOEXEC, &tmp);
if (fd < 0)
return fd;
return log_error_errno(fd, "Failed to create temporary file for coredump %s: %m", fn);
r = copy_bytes(input_fd, fd, max_size, false);
if (r == -EFBIG) {
@ -418,9 +384,11 @@ static int save_external_coredump(
goto uncompressed;
}
fd_compressed = open_coredump_tmpfile(fn_compressed, &tmp_compressed);
if (fd_compressed < 0)
fd_compressed = open_tmpfile_linkable(fn_compressed, O_RDWR|O_CLOEXEC, &tmp_compressed);
if (fd_compressed < 0) {
log_error_errno(fd_compressed, "Failed to create temporary file for coredump %s: %m", fn_compressed);
goto uncompressed;
}
r = compress_stream(fd, fd_compressed, -1);
if (r < 0) {

View File

@ -122,12 +122,14 @@ static int open_journal(RequestMeta *m) {
}
static int request_meta_ensure_tmp(RequestMeta *m) {
assert(m);
if (m->tmp)
rewind(m->tmp);
else {
int fd;
fd = open_tmpfile("/tmp", O_RDWR|O_CLOEXEC);
fd = open_tmpfile_unlinkable("/tmp", O_RDWR|O_CLOEXEC);
if (fd < 0)
return fd;

View File

@ -316,7 +316,7 @@ _public_ int sd_journal_sendv(const struct iovec *iov, int n) {
buffer_fd = memfd_new(NULL);
if (buffer_fd < 0) {
if (buffer_fd == -ENOSYS) {
buffer_fd = open_tmpfile("/dev/shm", O_RDWR | O_CLOEXEC);
buffer_fd = open_tmpfile_unlinkable("/dev/shm", O_RDWR | O_CLOEXEC);
if (buffer_fd < 0)
return buffer_fd;

View File

@ -838,19 +838,19 @@ int journal_file_verify(
} else if (f->seal)
return -ENOKEY;
data_fd = open_tmpfile("/var/tmp", O_RDWR | O_CLOEXEC);
data_fd = open_tmpfile_unlinkable("/var/tmp", O_RDWR | O_CLOEXEC);
if (data_fd < 0) {
r = log_error_errno(data_fd, "Failed to create data file: %m");
goto fail;
}
entry_fd = open_tmpfile("/var/tmp", O_RDWR | O_CLOEXEC);
entry_fd = open_tmpfile_unlinkable("/var/tmp", O_RDWR | O_CLOEXEC);
if (entry_fd < 0) {
r = log_error_errno(entry_fd, "Failed to create entry file: %m");
goto fail;
}
entry_array_fd = open_tmpfile("/var/tmp", O_RDWR | O_CLOEXEC);
entry_array_fd = open_tmpfile_unlinkable("/var/tmp", O_RDWR | O_CLOEXEC);
if (entry_array_fd < 0) {
r = log_error_errno(entry_array_fd,
"Failed to create entry array file: %m");

View File

@ -95,6 +95,7 @@ static bool arg_boot = false;
static sd_id128_t arg_boot_id = {};
static int arg_boot_offset = 0;
static bool arg_dmesg = false;
static bool arg_no_hostname = false;
static const char *arg_cursor = NULL;
static const char *arg_after_cursor = NULL;
static bool arg_show_cursor = false;
@ -304,6 +305,7 @@ static void help(void) {
" -a --all Show all fields, including long and unprintable\n"
" -q --quiet Do not show info messages and privilege warning\n"
" --no-pager Do not pipe output into a pager\n"
" --no-hostname Suppress output of hostname field\n"
" -m --merge Show entries from all available journals\n"
" -D --directory=PATH Show journal files from directory\n"
" --file=PATH Show journal file\n"
@ -370,6 +372,7 @@ static int parse_argv(int argc, char *argv[]) {
ARG_VACUUM_SIZE,
ARG_VACUUM_FILES,
ARG_VACUUM_TIME,
ARG_NO_HOSTNAME,
};
static const struct option options[] = {
@ -427,6 +430,7 @@ static int parse_argv(int argc, char *argv[]) {
{ "vacuum-size", required_argument, NULL, ARG_VACUUM_SIZE },
{ "vacuum-files", required_argument, NULL, ARG_VACUUM_FILES },
{ "vacuum-time", required_argument, NULL, ARG_VACUUM_TIME },
{ "no-hostname", no_argument, NULL, ARG_NO_HOSTNAME },
{}
};
@ -780,6 +784,10 @@ static int parse_argv(int argc, char *argv[]) {
arg_action = ACTION_LIST_FIELD_NAMES;
break;
case ARG_NO_HOSTNAME:
arg_no_hostname = true;
break;
case 'x':
arg_catalog = true;
break;
@ -2444,7 +2452,8 @@ int main(int argc, char *argv[]) {
arg_full * OUTPUT_FULL_WIDTH |
colors_enabled() * OUTPUT_COLOR |
arg_catalog * OUTPUT_CATALOG |
arg_utc * OUTPUT_UTC;
arg_utc * OUTPUT_UTC |
arg_no_hostname * OUTPUT_NO_HOSTNAME;
r = output_journal(stdout, j, arg_output, 0, flags, &ellipsized);
need_seek = true;

View File

@ -1072,6 +1072,10 @@ _public_ int sd_event_add_time(
assert_return(e->state != SD_EVENT_FINISHED, -ESTALE);
assert_return(!event_pid_changed(e), -ECHILD);
if (IN_SET(clock, CLOCK_BOOTTIME, CLOCK_BOOTTIME_ALARM) &&
!clock_boottime_supported())
return -EOPNOTSUPP;
if (!callback)
callback = time_exit_callback;
@ -2527,7 +2531,8 @@ _public_ int sd_event_wait(sd_event *e, uint64_t timeout) {
}
dual_timestamp_get(&e->timestamp);
e->timestamp_boottime = now(clock_boottime_or_monotonic());
if (clock_boottime_supported())
e->timestamp_boottime = now(CLOCK_BOOTTIME);
for (i = 0; i < m; i++) {
@ -2761,6 +2766,9 @@ _public_ int sd_event_now(sd_event *e, clockid_t clock, uint64_t *usec) {
CLOCK_BOOTTIME,
CLOCK_BOOTTIME_ALARM), -EOPNOTSUPP);
if (IN_SET(clock, CLOCK_BOOTTIME, CLOCK_BOOTTIME_ALARM) && !clock_boottime_supported())
return -EOPNOTSUPP;
if (!dual_timestamp_is_set(&e->timestamp)) {
/* Implicitly fall back to now() if we never ran
* before and thus have no cached time. */

View File

@ -270,8 +270,10 @@ static void test_sd_event_now(void) {
assert_se(sd_event_now(e, CLOCK_MONOTONIC, &event_now) > 0);
assert_se(sd_event_now(e, CLOCK_REALTIME, &event_now) > 0);
assert_se(sd_event_now(e, CLOCK_REALTIME_ALARM, &event_now) > 0);
assert_se(sd_event_now(e, CLOCK_BOOTTIME, &event_now) > 0);
assert_se(sd_event_now(e, CLOCK_BOOTTIME_ALARM, &event_now) > 0);
if (clock_boottime_supported()) {
assert_se(sd_event_now(e, CLOCK_BOOTTIME, &event_now) > 0);
assert_se(sd_event_now(e, CLOCK_BOOTTIME_ALARM, &event_now) > 0);
}
assert_se(sd_event_now(e, -1, &event_now) == -EOPNOTSUPP);
assert_se(sd_event_now(e, 900 /* arbitrary big number */, &event_now) == -EOPNOTSUPP);
@ -280,8 +282,10 @@ static void test_sd_event_now(void) {
assert_se(sd_event_now(e, CLOCK_MONOTONIC, &event_now) == 0);
assert_se(sd_event_now(e, CLOCK_REALTIME, &event_now) == 0);
assert_se(sd_event_now(e, CLOCK_REALTIME_ALARM, &event_now) == 0);
assert_se(sd_event_now(e, CLOCK_BOOTTIME, &event_now) == 0);
assert_se(sd_event_now(e, CLOCK_BOOTTIME_ALARM, &event_now) == 0);
if (clock_boottime_supported()) {
assert_se(sd_event_now(e, CLOCK_BOOTTIME, &event_now) == 0);
assert_se(sd_event_now(e, CLOCK_BOOTTIME_ALARM, &event_now) == 0);
}
assert_se(sd_event_now(e, -1, &event_now) == -EOPNOTSUPP);
assert_se(sd_event_now(e, 900 /* arbitrary big number */, &event_now) == -EOPNOTSUPP);
}

View File

@ -27,6 +27,7 @@
#include "alloc-util.h"
#include "bus-error.h"
#include "bus-unit-util.h"
#include "bus-util.h"
#include "cgroup-show.h"
#include "cgroup-util.h"
@ -227,18 +228,15 @@ static int show_unit_cgroup(sd_bus *bus, const char *interface, const char *unit
_cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
_cleanup_free_ char *path = NULL;
const char *cgroup;
int r;
unsigned c;
int r;
assert(bus);
assert(unit);
if (arg_transport != BUS_TRANSPORT_LOCAL)
return 0;
path = unit_dbus_path_from_name(unit);
if (!path)
return -ENOMEM;
return log_oom();
r = sd_bus_get_property(
bus,
@ -246,27 +244,40 @@ static int show_unit_cgroup(sd_bus *bus, const char *interface, const char *unit
path,
interface,
"ControlGroup",
&error, &reply, "s");
&error,
&reply,
"s");
if (r < 0)
return r;
return log_error_errno(r, "Failed to query ControlGroup: %s", bus_error_message(&error, r));
r = sd_bus_message_read(reply, "s", &cgroup);
if (r < 0)
return r;
return bus_log_parse_error(r);
if (isempty(cgroup))
return 0;
if (cg_is_empty_recursive(SYSTEMD_CGROUP_CONTROLLER, cgroup) != 0 && leader <= 0)
return 0;
c = columns();
if (c > 18)
c -= 18;
else
c = 0;
show_cgroup_and_extra(SYSTEMD_CGROUP_CONTROLLER, cgroup, "\t\t ", c, false, &leader, leader > 0, get_output_flags());
r = unit_show_processes(bus, unit, cgroup, "\t\t ", c, get_output_flags(), &error);
if (r == -EBADR) {
if (arg_transport == BUS_TRANSPORT_REMOTE)
return 0;
/* Fallback for older systemd versions where the GetUnitProcesses() call is not yet available */
if (cg_is_empty_recursive(SYSTEMD_CGROUP_CONTROLLER, cgroup) != 0 && leader <= 0)
return 0;
show_cgroup_and_extra(SYSTEMD_CGROUP_CONTROLLER, cgroup, "\t\t ", c, &leader, leader > 0, get_output_flags());
} else if (r < 0)
return log_error_errno(r, "Failed to dump process list: %s", bus_error_message(&error, r));
return 0;
}

View File

@ -33,6 +33,7 @@
#include "alloc-util.h"
#include "bus-error.h"
#include "bus-unit-util.h"
#include "bus-util.h"
#include "cgroup-show.h"
#include "cgroup-util.h"
@ -331,8 +332,8 @@ static int list_images(int argc, char *argv[], void *userdata) {
}
static int show_unit_cgroup(sd_bus *bus, const char *unit, pid_t leader) {
_cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
_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 *path = NULL;
const char *cgroup;
int r;
@ -341,9 +342,6 @@ static int show_unit_cgroup(sd_bus *bus, const char *unit, pid_t leader) {
assert(bus);
assert(unit);
if (arg_transport == BUS_TRANSPORT_REMOTE)
return 0;
path = unit_dbus_path_from_name(unit);
if (!path)
return log_oom();
@ -357,16 +355,14 @@ static int show_unit_cgroup(sd_bus *bus, const char *unit, pid_t leader) {
&error,
&reply,
"s");
if (r < 0) {
log_error("Failed to query ControlGroup: %s", bus_error_message(&error, -r));
return r;
}
if (r < 0)
return log_error_errno(r, "Failed to query ControlGroup: %s", bus_error_message(&error, r));
r = sd_bus_message_read(reply, "s", &cgroup);
if (r < 0)
return bus_log_parse_error(r);
if (cg_is_empty_recursive(SYSTEMD_CGROUP_CONTROLLER, cgroup) != 0 && leader <= 0)
if (isempty(cgroup))
return 0;
c = columns();
@ -375,7 +371,21 @@ static int show_unit_cgroup(sd_bus *bus, const char *unit, pid_t leader) {
else
c = 0;
show_cgroup_and_extra(SYSTEMD_CGROUP_CONTROLLER, cgroup, "\t\t ", c, false, &leader, leader > 0, get_output_flags());
r = unit_show_processes(bus, unit, cgroup, "\t\t ", c, get_output_flags(), &error);
if (r == -EBADR) {
if (arg_transport == BUS_TRANSPORT_REMOTE)
return 0;
/* Fallback for older systemd versions where the GetUnitProcesses() call is not yet available */
if (cg_is_empty_recursive(SYSTEMD_CGROUP_CONTROLLER, cgroup) != 0 && leader <= 0)
return 0;
show_cgroup_and_extra(SYSTEMD_CGROUP_CONTROLLER, cgroup, "\t\t ", c, &leader, leader > 0, get_output_flags());
} else if (r < 0)
return log_error_errno(r, "Failed to dump process list: %s", bus_error_message(&error, r));
return 0;
}

View File

@ -42,6 +42,9 @@
static bool link_dhcp6_enabled(Link *link) {
assert(link);
if (!socket_ipv6_is_supported())
return false;
if (link->flags & IFF_LOOPBACK)
return false;
@ -90,6 +93,9 @@ static bool link_ipv4ll_enabled(Link *link) {
static bool link_ipv6ll_enabled(Link *link) {
assert(link);
if (!socket_ipv6_is_supported())
return false;
if (link->flags & IFF_LOOPBACK)
return false;
@ -192,6 +198,9 @@ static bool link_proxy_arp_enabled(Link *link) {
static bool link_ipv6_accept_ra_enabled(Link *link) {
assert(link);
if (!socket_ipv6_is_supported())
return false;
if (link->flags & IFF_LOOPBACK)
return false;
@ -214,6 +223,7 @@ static bool link_ipv6_accept_ra_enabled(Link *link) {
}
static IPv6PrivacyExtensions link_ipv6_privacy_extensions(Link *link) {
assert(link);
if (!socket_ipv6_is_supported())
return _IPV6_PRIVACY_EXTENSIONS_INVALID;

View File

@ -20,6 +20,7 @@
#include "sd-bus.h"
#include "bus-error.h"
#include "bus-unit-util.h"
#include "bus-util.h"
#include "nspawn-register.h"
#include "stat-util.h"

View File

@ -25,6 +25,7 @@
#include "alloc-util.h"
#include "bus-error.h"
#include "bus-unit-util.h"
#include "bus-util.h"
#include "calendarspec.h"
#include "env-util.h"

1287
src/shared/bus-unit-util.c Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,57 @@
#pragma once
/***
This file is part of systemd.
Copyright 2016 Lennart Poettering
systemd is free software; you can redistribute it and/or modify it
under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 2.1 of the License, or
(at your option) any later version.
systemd is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
#include "sd-bus.h"
#include "output-mode.h"
#include "install.h"
typedef struct UnitInfo {
const char *machine;
const char *id;
const char *description;
const char *load_state;
const char *active_state;
const char *sub_state;
const char *following;
const char *unit_path;
uint32_t job_id;
const char *job_type;
const char *job_path;
} UnitInfo;
int bus_parse_unit_info(sd_bus_message *message, UnitInfo *u);
int bus_append_unit_property_assignment(sd_bus_message *m, const char *assignment);
typedef struct BusWaitForJobs BusWaitForJobs;
int bus_wait_for_jobs_new(sd_bus *bus, BusWaitForJobs **ret);
void bus_wait_for_jobs_free(BusWaitForJobs *d);
int bus_wait_for_jobs_add(BusWaitForJobs *d, const char *path);
int bus_wait_for_jobs(BusWaitForJobs *d, bool quiet, const char* const* extra_args);
int bus_wait_for_jobs_one(BusWaitForJobs *d, const char *path, bool quiet);
DEFINE_TRIVIAL_CLEANUP_FUNC(BusWaitForJobs*, bus_wait_for_jobs_free);
int bus_deserialize_and_dump_unit_file_changes(sd_bus_message *m, bool quiet, UnitFileChange **changes, unsigned *n_changes);
int unit_show_processes(sd_bus *bus, const char *unit, const char *cgroup_path, const char *prefix, unsigned n_columns, OutputFlags flags, sd_bus_error *error);

View File

@ -39,34 +39,16 @@
#include "bus-label.h"
#include "bus-message.h"
#include "bus-util.h"
#include "cgroup-util.h"
#include "def.h"
#include "env-util.h"
#include "escape.h"
#include "extract-word.h"
#include "fd-util.h"
#include "hashmap.h"
#include "install.h"
#include "kdbus.h"
#include "log.h"
#include "macro.h"
#include "missing.h"
#include "parse-util.h"
#include "path-util.h"
#include "proc-cmdline.h"
#include "process-util.h"
#include "rlimit-util.h"
#include "set.h"
#include "signal-util.h"
#include "stdio-util.h"
#include "string-util.h"
#include "strv.h"
#include "syslog-util.h"
#include "time-util.h"
#include "unit-name.h"
#include "user-util.h"
#include "utf8.h"
#include "util.h"
static int name_owner_change_callback(sd_bus_message *m, void *userdata, sd_bus_error *ret_error) {
sd_event *e = userdata;
@ -1383,847 +1365,6 @@ int bus_log_create_error(int r) {
return log_error_errno(r, "Failed to create bus message: %m");
}
int bus_parse_unit_info(sd_bus_message *message, UnitInfo *u) {
assert(message);
assert(u);
u->machine = NULL;
return sd_bus_message_read(
message,
"(ssssssouso)",
&u->id,
&u->description,
&u->load_state,
&u->active_state,
&u->sub_state,
&u->following,
&u->unit_path,
&u->job_id,
&u->job_type,
&u->job_path);
}
int bus_append_unit_property_assignment(sd_bus_message *m, const char *assignment) {
const char *eq, *field;
int r, rl;
assert(m);
assert(assignment);
eq = strchr(assignment, '=');
if (!eq) {
log_error("Not an assignment: %s", assignment);
return -EINVAL;
}
r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT, "sv");
if (r < 0)
return bus_log_create_error(r);
field = strndupa(assignment, eq - assignment);
eq++;
if (streq(field, "CPUQuota")) {
if (isempty(eq))
r = sd_bus_message_append(m, "sv", "CPUQuotaPerSecUSec", "t", USEC_INFINITY);
else if (endswith(eq, "%")) {
double percent;
if (sscanf(eq, "%lf%%", &percent) != 1 || percent <= 0) {
log_error("CPU quota '%s' invalid.", eq);
return -EINVAL;
}
r = sd_bus_message_append(m, "sv", "CPUQuotaPerSecUSec", "t", (usec_t) percent * USEC_PER_SEC / 100);
} else {
log_error("CPU quota needs to be in percent.");
return -EINVAL;
}
goto finish;
} else if (streq(field, "EnvironmentFile")) {
r = sd_bus_message_append(m, "sv", "EnvironmentFiles", "a(sb)", 1,
eq[0] == '-' ? eq + 1 : eq,
eq[0] == '-');
goto finish;
} else if (STR_IN_SET(field, "AccuracySec", "RandomizedDelaySec", "RuntimeMaxSec")) {
char *n;
usec_t t;
size_t l;
r = parse_sec(eq, &t);
if (r < 0)
return log_error_errno(r, "Failed to parse %s= parameter: %s", field, eq);
l = strlen(field);
n = newa(char, l + 2);
if (!n)
return log_oom();
/* Change suffix Sec → USec */
strcpy(mempcpy(n, field, l - 3), "USec");
r = sd_bus_message_append(m, "sv", n, "t", t);
goto finish;
}
r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, field);
if (r < 0)
return bus_log_create_error(r);
rl = rlimit_from_string(field);
if (rl >= 0) {
const char *sn;
struct rlimit l;
r = rlimit_parse(rl, eq, &l);
if (r < 0)
return log_error_errno(r, "Failed to parse resource limit: %s", eq);
r = sd_bus_message_append(m, "v", "t", l.rlim_max);
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_open_container(m, SD_BUS_TYPE_STRUCT, "sv");
if (r < 0)
return bus_log_create_error(r);
sn = strjoina(field, "Soft");
r = sd_bus_message_append(m, "sv", sn, "t", l.rlim_cur);
} else if (STR_IN_SET(field,
"CPUAccounting", "MemoryAccounting", "BlockIOAccounting", "TasksAccounting",
"SendSIGHUP", "SendSIGKILL", "WakeSystem", "DefaultDependencies",
"IgnoreSIGPIPE", "TTYVHangup", "TTYReset", "RemainAfterExit",
"PrivateTmp", "PrivateDevices", "PrivateNetwork", "NoNewPrivileges",
"SyslogLevelPrefix", "Delegate", "RemainAfterElapse")) {
r = parse_boolean(eq);
if (r < 0)
return log_error_errno(r, "Failed to parse boolean assignment %s.", assignment);
r = sd_bus_message_append(m, "v", "b", r);
} else if (streq(field, "MemoryLimit")) {
uint64_t bytes;
if (isempty(eq) || streq(eq, "infinity"))
bytes = (uint64_t) -1;
else {
r = parse_size(eq, 1024, &bytes);
if (r < 0) {
log_error("Failed to parse bytes specification %s", assignment);
return -EINVAL;
}
}
r = sd_bus_message_append(m, "v", "t", bytes);
} else if (streq(field, "TasksMax")) {
uint64_t n;
if (isempty(eq) || streq(eq, "infinity"))
n = (uint64_t) -1;
else {
r = safe_atou64(eq, &n);
if (r < 0) {
log_error("Failed to parse maximum tasks specification %s", assignment);
return -EINVAL;
}
}
r = sd_bus_message_append(m, "v", "t", n);
} else if (STR_IN_SET(field, "CPUShares", "StartupCPUShares")) {
uint64_t u;
r = cg_cpu_shares_parse(eq, &u);
if (r < 0) {
log_error("Failed to parse %s value %s.", field, eq);
return -EINVAL;
}
r = sd_bus_message_append(m, "v", "t", u);
} else if (STR_IN_SET(field, "BlockIOWeight", "StartupBlockIOWeight")) {
uint64_t u;
r = cg_cpu_shares_parse(eq, &u);
if (r < 0) {
log_error("Failed to parse %s value %s.", field, eq);
return -EINVAL;
}
r = sd_bus_message_append(m, "v", "t", u);
} else if (STR_IN_SET(field,
"User", "Group", "DevicePolicy", "KillMode",
"UtmpIdentifier", "UtmpMode", "PAMName", "TTYPath",
"StandardInput", "StandardOutput", "StandardError",
"Description", "Slice", "Type", "WorkingDirectory",
"RootDirectory", "SyslogIdentifier", "ProtectSystem",
"ProtectHome"))
r = sd_bus_message_append(m, "v", "s", eq);
else if (streq(field, "SyslogLevel")) {
int level;
level = log_level_from_string(eq);
if (level < 0) {
log_error("Failed to parse %s value %s.", field, eq);
return -EINVAL;
}
r = sd_bus_message_append(m, "v", "i", level);
} else if (streq(field, "SyslogFacility")) {
int facility;
facility = log_facility_unshifted_from_string(eq);
if (facility < 0) {
log_error("Failed to parse %s value %s.", field, eq);
return -EINVAL;
}
r = sd_bus_message_append(m, "v", "i", facility);
} else if (streq(field, "DeviceAllow")) {
if (isempty(eq))
r = sd_bus_message_append(m, "v", "a(ss)", 0);
else {
const char *path, *rwm, *e;
e = strchr(eq, ' ');
if (e) {
path = strndupa(eq, e - eq);
rwm = e+1;
} else {
path = eq;
rwm = "";
}
if (!path_startswith(path, "/dev")) {
log_error("%s is not a device file in /dev.", path);
return -EINVAL;
}
r = sd_bus_message_append(m, "v", "a(ss)", 1, path, rwm);
}
} else if (STR_IN_SET(field, "BlockIOReadBandwidth", "BlockIOWriteBandwidth")) {
if (isempty(eq))
r = sd_bus_message_append(m, "v", "a(st)", 0);
else {
const char *path, *bandwidth, *e;
uint64_t bytes;
e = strchr(eq, ' ');
if (e) {
path = strndupa(eq, e - eq);
bandwidth = e+1;
} else {
log_error("Failed to parse %s value %s.", field, eq);
return -EINVAL;
}
if (!path_startswith(path, "/dev")) {
log_error("%s is not a device file in /dev.", path);
return -EINVAL;
}
r = parse_size(bandwidth, 1000, &bytes);
if (r < 0) {
log_error("Failed to parse byte value %s.", bandwidth);
return -EINVAL;
}
r = sd_bus_message_append(m, "v", "a(st)", 1, path, bytes);
}
} else if (streq(field, "BlockIODeviceWeight")) {
if (isempty(eq))
r = sd_bus_message_append(m, "v", "a(st)", 0);
else {
const char *path, *weight, *e;
uint64_t u;
e = strchr(eq, ' ');
if (e) {
path = strndupa(eq, e - eq);
weight = e+1;
} else {
log_error("Failed to parse %s value %s.", field, eq);
return -EINVAL;
}
if (!path_startswith(path, "/dev")) {
log_error("%s is not a device file in /dev.", path);
return -EINVAL;
}
r = safe_atou64(weight, &u);
if (r < 0) {
log_error("Failed to parse %s value %s.", field, weight);
return -EINVAL;
}
r = sd_bus_message_append(m, "v", "a(st)", path, u);
}
} else if (streq(field, "Nice")) {
int32_t i;
r = safe_atoi32(eq, &i);
if (r < 0) {
log_error("Failed to parse %s value %s.", field, eq);
return -EINVAL;
}
r = sd_bus_message_append(m, "v", "i", i);
} else if (STR_IN_SET(field, "Environment", "PassEnvironment")) {
const char *p;
r = sd_bus_message_open_container(m, 'v', "as");
if (r < 0)
return bus_log_create_error(r);
r = sd_bus_message_open_container(m, 'a', "s");
if (r < 0)
return bus_log_create_error(r);
p = eq;
for (;;) {
_cleanup_free_ char *word = NULL;
r = extract_first_word(&p, &word, NULL, EXTRACT_QUOTES|EXTRACT_CUNESCAPE);
if (r < 0) {
log_error("Failed to parse Environment value %s", eq);
return -EINVAL;
}
if (r == 0)
break;
if (streq(field, "Environment")) {
if (!env_assignment_is_valid(word)) {
log_error("Invalid environment assignment: %s", word);
return -EINVAL;
}
} else { /* PassEnvironment */
if (!env_name_is_valid(word)) {
log_error("Invalid environment variable name: %s", word);
return -EINVAL;
}
}
r = sd_bus_message_append_basic(m, 's', word);
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);
} else if (streq(field, "KillSignal")) {
int sig;
sig = signal_from_string_try_harder(eq);
if (sig < 0) {
log_error("Failed to parse %s value %s.", field, eq);
return -EINVAL;
}
r = sd_bus_message_append(m, "v", "i", sig);
} else if (streq(field, "TimerSlackNSec")) {
nsec_t n;
r = parse_nsec(eq, &n);
if (r < 0) {
log_error("Failed to parse %s value %s", field, eq);
return -EINVAL;
}
r = sd_bus_message_append(m, "v", "t", n);
} else if (streq(field, "OOMScoreAdjust")) {
int oa;
r = safe_atoi(eq, &oa);
if (r < 0) {
log_error("Failed to parse %s value %s", field, eq);
return -EINVAL;
}
if (!oom_score_adjust_is_valid(oa)) {
log_error("OOM score adjust value out of range");
return -EINVAL;
}
r = sd_bus_message_append(m, "v", "i", oa);
} else if (STR_IN_SET(field, "ReadWriteDirectories", "ReadOnlyDirectories", "InaccessibleDirectories")) {
const char *p;
r = sd_bus_message_open_container(m, 'v', "as");
if (r < 0)
return bus_log_create_error(r);
r = sd_bus_message_open_container(m, 'a', "s");
if (r < 0)
return bus_log_create_error(r);
p = eq;
for (;;) {
_cleanup_free_ char *word = NULL;
int offset;
r = extract_first_word(&p, &word, NULL, EXTRACT_QUOTES);
if (r < 0) {
log_error("Failed to parse %s value %s", field, eq);
return -EINVAL;
}
if (r == 0)
break;
if (!utf8_is_valid(word)) {
log_error("Failed to parse %s value %s", field, eq);
return -EINVAL;
}
offset = word[0] == '-';
if (!path_is_absolute(word + offset)) {
log_error("Failed to parse %s value %s", field, eq);
return -EINVAL;
}
path_kill_slashes(word + offset);
r = sd_bus_message_append_basic(m, 's', word);
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);
} else if (streq(field, "RuntimeDirectory")) {
const char *p;
r = sd_bus_message_open_container(m, 'v', "as");
if (r < 0)
return bus_log_create_error(r);
r = sd_bus_message_open_container(m, 'a', "s");
if (r < 0)
return bus_log_create_error(r);
p = eq;
for (;;) {
_cleanup_free_ char *word = NULL;
r = extract_first_word(&p, &word, NULL, EXTRACT_QUOTES);
if (r < 0)
return log_error_errno(r, "Failed to parse %s value %s", field, eq);
if (r == 0)
break;
r = sd_bus_message_append_basic(m, 's', word);
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);
} else {
log_error("Unknown assignment %s.", assignment);
return -EINVAL;
}
finish:
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);
return 0;
}
typedef struct BusWaitForJobs {
sd_bus *bus;
Set *jobs;
char *name;
char *result;
sd_bus_slot *slot_job_removed;
sd_bus_slot *slot_disconnected;
} BusWaitForJobs;
static int match_disconnected(sd_bus_message *m, void *userdata, sd_bus_error *error) {
assert(m);
log_error("Warning! D-Bus connection terminated.");
sd_bus_close(sd_bus_message_get_bus(m));
return 0;
}
static int match_job_removed(sd_bus_message *m, void *userdata, sd_bus_error *error) {
const char *path, *unit, *result;
BusWaitForJobs *d = userdata;
uint32_t id;
char *found;
int r;
assert(m);
assert(d);
r = sd_bus_message_read(m, "uoss", &id, &path, &unit, &result);
if (r < 0) {
bus_log_parse_error(r);
return 0;
}
found = set_remove(d->jobs, (char*) path);
if (!found)
return 0;
free(found);
if (!isempty(result))
d->result = strdup(result);
if (!isempty(unit))
d->name = strdup(unit);
return 0;
}
void bus_wait_for_jobs_free(BusWaitForJobs *d) {
if (!d)
return;
set_free_free(d->jobs);
sd_bus_slot_unref(d->slot_disconnected);
sd_bus_slot_unref(d->slot_job_removed);
sd_bus_unref(d->bus);
free(d->name);
free(d->result);
free(d);
}
int bus_wait_for_jobs_new(sd_bus *bus, BusWaitForJobs **ret) {
_cleanup_(bus_wait_for_jobs_freep) BusWaitForJobs *d = NULL;
int r;
assert(bus);
assert(ret);
d = new0(BusWaitForJobs, 1);
if (!d)
return -ENOMEM;
d->bus = sd_bus_ref(bus);
/* When we are a bus client we match by sender. Direct
* connections OTOH have no initialized sender field, and
* hence we ignore the sender then */
r = sd_bus_add_match(
bus,
&d->slot_job_removed,
bus->bus_client ?
"type='signal',"
"sender='org.freedesktop.systemd1',"
"interface='org.freedesktop.systemd1.Manager',"
"member='JobRemoved',"
"path='/org/freedesktop/systemd1'" :
"type='signal',"
"interface='org.freedesktop.systemd1.Manager',"
"member='JobRemoved',"
"path='/org/freedesktop/systemd1'",
match_job_removed, d);
if (r < 0)
return r;
r = sd_bus_add_match(
bus,
&d->slot_disconnected,
"type='signal',"
"sender='org.freedesktop.DBus.Local',"
"interface='org.freedesktop.DBus.Local',"
"member='Disconnected'",
match_disconnected, d);
if (r < 0)
return r;
*ret = d;
d = NULL;
return 0;
}
static int bus_process_wait(sd_bus *bus) {
int r;
for (;;) {
r = sd_bus_process(bus, NULL);
if (r < 0)
return r;
if (r > 0)
return 0;
r = sd_bus_wait(bus, (uint64_t) -1);
if (r < 0)
return r;
}
}
static int bus_job_get_service_result(BusWaitForJobs *d, char **result) {
_cleanup_free_ char *dbus_path = NULL;
assert(d);
assert(d->name);
assert(result);
dbus_path = unit_dbus_path_from_name(d->name);
if (!dbus_path)
return -ENOMEM;
return sd_bus_get_property_string(d->bus,
"org.freedesktop.systemd1",
dbus_path,
"org.freedesktop.systemd1.Service",
"Result",
NULL,
result);
}
static const struct {
const char *result, *explanation;
} explanations [] = {
{ "resources", "a configured resource limit was exceeded" },
{ "timeout", "a timeout was exceeded" },
{ "exit-code", "the control process exited with error code" },
{ "signal", "a fatal signal was delivered to the control process" },
{ "core-dump", "a fatal signal was delivered causing the control process to dump core" },
{ "watchdog", "the service failed to send watchdog ping" },
{ "start-limit", "start of the service was attempted too often" }
};
static void log_job_error_with_service_result(const char* service, const char *result, const char* const* extra_args) {
_cleanup_free_ char *service_shell_quoted = NULL;
const char *systemctl = "systemctl", *journalctl = "journalctl";
assert(service);
service_shell_quoted = shell_maybe_quote(service);
if (extra_args && extra_args[1]) {
_cleanup_free_ char *t;
t = strv_join((char**) extra_args, " ");
systemctl = strjoina("systemctl ", t ? : "<args>");
journalctl = strjoina("journalctl ", t ? : "<args>");
}
if (!isempty(result)) {
unsigned i;
for (i = 0; i < ELEMENTSOF(explanations); ++i)
if (streq(result, explanations[i].result))
break;
if (i < ELEMENTSOF(explanations)) {
log_error("Job for %s failed because %s.\n"
"See \"%s status %s\" and \"%s -xe\" for details.\n",
service,
explanations[i].explanation,
systemctl,
service_shell_quoted ?: "<service>",
journalctl);
goto finish;
}
}
log_error("Job for %s failed.\n"
"See \"%s status %s\" and \"%s -xe\" for details.\n",
service,
systemctl,
service_shell_quoted ?: "<service>",
journalctl);
finish:
/* For some results maybe additional explanation is required */
if (streq_ptr(result, "start-limit"))
log_info("To force a start use \"%1$s reset-failed %2$s\"\n"
"followed by \"%1$s start %2$s\" again.",
systemctl,
service_shell_quoted ?: "<service>");
}
static int check_wait_response(BusWaitForJobs *d, bool quiet, const char* const* extra_args) {
int r = 0;
assert(d->result);
if (!quiet) {
if (streq(d->result, "canceled"))
log_error("Job for %s canceled.", strna(d->name));
else if (streq(d->result, "timeout"))
log_error("Job for %s timed out.", strna(d->name));
else if (streq(d->result, "dependency"))
log_error("A dependency job for %s failed. See 'journalctl -xe' for details.", strna(d->name));
else if (streq(d->result, "invalid"))
log_error("%s is not active, cannot reload.", strna(d->name));
else if (streq(d->result, "assert"))
log_error("Assertion failed on job for %s.", strna(d->name));
else if (streq(d->result, "unsupported"))
log_error("Operation on or unit type of %s not supported on this system.", strna(d->name));
else if (!streq(d->result, "done") && !streq(d->result, "skipped")) {
if (d->name) {
int q;
_cleanup_free_ char *result = NULL;
q = bus_job_get_service_result(d, &result);
if (q < 0)
log_debug_errno(q, "Failed to get Result property of service %s: %m", d->name);
log_job_error_with_service_result(d->name, result, extra_args);
} else
log_error("Job failed. See \"journalctl -xe\" for details.");
}
}
if (streq(d->result, "canceled"))
r = -ECANCELED;
else if (streq(d->result, "timeout"))
r = -ETIME;
else if (streq(d->result, "dependency"))
r = -EIO;
else if (streq(d->result, "invalid"))
r = -ENOEXEC;
else if (streq(d->result, "assert"))
r = -EPROTO;
else if (streq(d->result, "unsupported"))
r = -EOPNOTSUPP;
else if (!streq(d->result, "done") && !streq(d->result, "skipped"))
r = -EIO;
return r;
}
int bus_wait_for_jobs(BusWaitForJobs *d, bool quiet, const char* const* extra_args) {
int r = 0;
assert(d);
while (!set_isempty(d->jobs)) {
int q;
q = bus_process_wait(d->bus);
if (q < 0)
return log_error_errno(q, "Failed to wait for response: %m");
if (d->result) {
q = check_wait_response(d, quiet, extra_args);
/* Return the first error as it is most likely to be
* meaningful. */
if (q < 0 && r == 0)
r = q;
log_debug_errno(q, "Got result %s/%m for job %s", strna(d->result), strna(d->name));
}
d->name = mfree(d->name);
d->result = mfree(d->result);
}
return r;
}
int bus_wait_for_jobs_add(BusWaitForJobs *d, const char *path) {
int r;
assert(d);
r = set_ensure_allocated(&d->jobs, &string_hash_ops);
if (r < 0)
return r;
return set_put_strdup(d->jobs, path);
}
int bus_wait_for_jobs_one(BusWaitForJobs *d, const char *path, bool quiet) {
int r;
r = bus_wait_for_jobs_add(d, path);
if (r < 0)
return log_oom();
return bus_wait_for_jobs(d, quiet, NULL);
}
int bus_deserialize_and_dump_unit_file_changes(sd_bus_message *m, bool quiet, UnitFileChange **changes, unsigned *n_changes) {
const char *type, *path, *source;
int r;
r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "(sss)");
if (r < 0)
return bus_log_parse_error(r);
while ((r = sd_bus_message_read(m, "(sss)", &type, &path, &source)) > 0) {
/* We expect only "success" changes to be sent over the bus.
Hence, reject anything negative. */
UnitFileChangeType ch = unit_file_change_type_from_string(type);
if (ch < 0) {
log_notice("Manager reported unknown change type \"%s\" for path \"%s\", ignoring.", type, path);
continue;
}
r = unit_file_changes_add(changes, n_changes, ch, path, source);
if (r < 0)
return r;
}
if (r < 0)
return bus_log_parse_error(r);
r = sd_bus_message_exit_container(m);
if (r < 0)
return bus_log_parse_error(r);
unit_file_dump_changes(0, NULL, *changes, *n_changes, false);
return 0;
}
/**
* bus_path_encode_unique() - encode unique object path
* @b: bus connection or NULL

View File

@ -24,15 +24,12 @@
#include <stdint.h>
#include <sys/types.h>
#include "sd-bus-vtable.h"
#include "sd-bus.h"
#include "sd-event.h"
#include "hashmap.h"
#include "install.h"
#include "macro.h"
#include "string-util.h"
#include "time-util.h"
typedef enum BusTransport {
BUS_TRANSPORT_LOCAL,
@ -126,22 +123,6 @@ assert_cc(sizeof(mode_t) == sizeof(uint32_t));
int bus_log_parse_error(int r);
int bus_log_create_error(int r);
typedef struct UnitInfo {
const char *machine;
const char *id;
const char *description;
const char *load_state;
const char *active_state;
const char *sub_state;
const char *following;
const char *unit_path;
uint32_t job_id;
const char *job_type;
const char *job_path;
} UnitInfo;
int bus_parse_unit_info(sd_bus_message *message, UnitInfo *u);
#define BUS_DEFINE_PROPERTY_GET_ENUM(function, name, type) \
int function(sd_bus *bus, \
const char *path, \
@ -173,20 +154,6 @@ int bus_parse_unit_info(sd_bus_message *message, UnitInfo *u);
SD_BUS_PROPERTY(name, "t", bus_property_get_usec, (offset) + offsetof(struct dual_timestamp, realtime), (flags)), \
SD_BUS_PROPERTY(name "Monotonic", "t", bus_property_get_usec, (offset) + offsetof(struct dual_timestamp, monotonic), (flags))
int bus_append_unit_property_assignment(sd_bus_message *m, const char *assignment);
typedef struct BusWaitForJobs BusWaitForJobs;
int bus_wait_for_jobs_new(sd_bus *bus, BusWaitForJobs **ret);
void bus_wait_for_jobs_free(BusWaitForJobs *d);
int bus_wait_for_jobs_add(BusWaitForJobs *d, const char *path);
int bus_wait_for_jobs(BusWaitForJobs *d, bool quiet, const char* const* extra_args);
int bus_wait_for_jobs_one(BusWaitForJobs *d, const char *path, bool quiet);
DEFINE_TRIVIAL_CLEANUP_FUNC(BusWaitForJobs*, bus_wait_for_jobs_free);
int bus_deserialize_and_dump_unit_file_changes(sd_bus_message *m, bool quiet, UnitFileChange **changes, unsigned *n_changes);
int bus_path_encode_unique(sd_bus *b, const char *prefix, const char *sender_id, const char *external_id, char **ret_path);
int bus_path_decode_unique(const char *path, const char *prefix, char **ret_sender, char **ret_external);

View File

@ -37,23 +37,21 @@
#include "string-util.h"
#include "terminal-util.h"
static int compare(const void *a, const void *b) {
const pid_t *p = a, *q = b;
static void show_pid_array(
pid_t pids[],
unsigned n_pids,
const char *prefix,
unsigned n_columns,
bool extra,
bool more,
OutputFlags flags) {
if (*p < *q)
return -1;
if (*p > *q)
return 1;
return 0;
}
static void show_pid_array(pid_t pids[], unsigned n_pids, const char *prefix, unsigned n_columns, bool extra, bool more, bool kernel_threads, OutputFlags flags) {
unsigned i, j, pid_width;
if (n_pids == 0)
return;
qsort(pids, n_pids, sizeof(pid_t), compare);
qsort(pids, n_pids, sizeof(pid_t), pid_compare_func);
/* Filter duplicates */
for (j = 0, i = 1; i < n_pids; i++) {
@ -86,8 +84,13 @@ static void show_pid_array(pid_t pids[], unsigned n_pids, const char *prefix, un
}
}
static int show_cgroup_one_by_path(
const char *path,
const char *prefix,
unsigned n_columns,
bool more,
OutputFlags flags) {
static int show_cgroup_one_by_path(const char *path, const char *prefix, unsigned n_columns, bool more, bool kernel_threads, OutputFlags flags) {
char *fn;
_cleanup_fclose_ FILE *f = NULL;
size_t n = 0, n_allocated = 0;
@ -107,7 +110,7 @@ static int show_cgroup_one_by_path(const char *path, const char *prefix, unsigne
while ((r = cg_read_pid(f, &pid)) > 0) {
if (!kernel_threads && is_kernel_thread(pid) > 0)
if (!(flags & OUTPUT_KERNEL_THREADS) && is_kernel_thread(pid) > 0)
continue;
if (!GREEDY_REALLOC(pids, n_allocated, n + 1))
@ -120,12 +123,17 @@ static int show_cgroup_one_by_path(const char *path, const char *prefix, unsigne
if (r < 0)
return r;
show_pid_array(pids, n, prefix, n_columns, false, more, kernel_threads, flags);
show_pid_array(pids, n, prefix, n_columns, false, more, flags);
return 0;
}
int show_cgroup_by_path(const char *path, const char *prefix, unsigned n_columns, bool kernel_threads, OutputFlags flags) {
int show_cgroup_by_path(
const char *path,
const char *prefix,
unsigned n_columns,
OutputFlags flags) {
_cleanup_free_ char *fn = NULL, *p1 = NULL, *last = NULL, *p2 = NULL;
_cleanup_closedir_ DIR *d = NULL;
char *gn = NULL;
@ -137,8 +145,7 @@ int show_cgroup_by_path(const char *path, const char *prefix, unsigned n_columns
if (n_columns <= 0)
n_columns = columns();
if (!prefix)
prefix = "";
prefix = strempty(prefix);
r = cg_mangle_path(path, &fn);
if (r < 0)
@ -160,7 +167,7 @@ int show_cgroup_by_path(const char *path, const char *prefix, unsigned n_columns
continue;
if (!shown_pids) {
show_cgroup_one_by_path(path, prefix, n_columns, true, kernel_threads, flags);
show_cgroup_one_by_path(path, prefix, n_columns, true, flags);
shown_pids = true;
}
@ -173,7 +180,7 @@ int show_cgroup_by_path(const char *path, const char *prefix, unsigned n_columns
return -ENOMEM;
}
show_cgroup_by_path(last, p1, n_columns-2, kernel_threads, flags);
show_cgroup_by_path(last, p1, n_columns-2, flags);
free(last);
}
@ -185,7 +192,7 @@ int show_cgroup_by_path(const char *path, const char *prefix, unsigned n_columns
return r;
if (!shown_pids)
show_cgroup_one_by_path(path, prefix, n_columns, !!last, kernel_threads, flags);
show_cgroup_one_by_path(path, prefix, n_columns, !!last, flags);
if (last) {
printf("%s%s%s\n", prefix, draw_special_char(DRAW_TREE_RIGHT), cg_unescape(basename(last)));
@ -196,13 +203,17 @@ int show_cgroup_by_path(const char *path, const char *prefix, unsigned n_columns
return -ENOMEM;
}
show_cgroup_by_path(last, p2, n_columns-2, kernel_threads, flags);
show_cgroup_by_path(last, p2, n_columns-2, flags);
}
return 0;
}
int show_cgroup(const char *controller, const char *path, const char *prefix, unsigned n_columns, bool kernel_threads, OutputFlags flags) {
int show_cgroup(const char *controller,
const char *path,
const char *prefix,
unsigned n_columns,
OutputFlags flags) {
_cleanup_free_ char *p = NULL;
int r;
@ -212,10 +223,18 @@ int show_cgroup(const char *controller, const char *path, const char *prefix, un
if (r < 0)
return r;
return show_cgroup_by_path(p, prefix, n_columns, kernel_threads, flags);
return show_cgroup_by_path(p, prefix, n_columns, flags);
}
static int show_extra_pids(const char *controller, const char *path, const char *prefix, unsigned n_columns, const pid_t pids[], unsigned n_pids, OutputFlags flags) {
static int show_extra_pids(
const char *controller,
const char *path,
const char *prefix,
unsigned n_columns,
const pid_t pids[],
unsigned n_pids,
OutputFlags flags) {
_cleanup_free_ pid_t *copy = NULL;
unsigned i, j;
int r;
@ -247,24 +266,39 @@ static int show_extra_pids(const char *controller, const char *path, const char
copy[j++] = pids[i];
}
show_pid_array(copy, j, prefix, n_columns, true, false, false, flags);
show_pid_array(copy, j, prefix, n_columns, true, false, flags);
return 0;
}
int show_cgroup_and_extra(const char *controller, const char *path, const char *prefix, unsigned n_columns, bool kernel_threads, const pid_t extra_pids[], unsigned n_extra_pids, OutputFlags flags) {
int show_cgroup_and_extra(
const char *controller,
const char *path,
const char *prefix,
unsigned n_columns,
const pid_t extra_pids[],
unsigned n_extra_pids,
OutputFlags flags) {
int r;
assert(path);
r = show_cgroup(controller, path, prefix, n_columns, kernel_threads, flags);
r = show_cgroup(controller, path, prefix, n_columns, flags);
if (r < 0)
return r;
return show_extra_pids(controller, path, prefix, n_columns, extra_pids, n_extra_pids, flags);
}
int show_cgroup_and_extra_by_spec(const char *spec, const char *prefix, unsigned n_columns, bool kernel_threads, const pid_t extra_pids[], unsigned n_extra_pids, OutputFlags flags) {
int show_cgroup_and_extra_by_spec(
const char *spec,
const char *prefix,
unsigned n_columns,
const pid_t extra_pids[],
unsigned n_extra_pids,
OutputFlags flags) {
_cleanup_free_ char *controller = NULL, *path = NULL;
int r;
@ -274,5 +308,5 @@ int show_cgroup_and_extra_by_spec(const char *spec, const char *prefix, unsigned
if (r < 0)
return r;
return show_cgroup_and_extra(controller, path, prefix, n_columns, kernel_threads, extra_pids, n_extra_pids, flags);
return show_cgroup_and_extra(controller, path, prefix, n_columns, extra_pids, n_extra_pids, flags);
}

View File

@ -25,8 +25,8 @@
#include "logs-show.h"
#include "output-mode.h"
int show_cgroup_by_path(const char *path, const char *prefix, unsigned columns, bool kernel_threads, OutputFlags flags);
int show_cgroup(const char *controller, const char *path, const char *prefix, unsigned columns, bool kernel_threads, OutputFlags flags);
int show_cgroup_by_path(const char *path, const char *prefix, unsigned columns, OutputFlags flags);
int show_cgroup(const char *controller, const char *path, const char *prefix, unsigned columns, OutputFlags flags);
int show_cgroup_and_extra_by_spec(const char *spec, const char *prefix, unsigned n_columns, bool kernel_threads, const pid_t extra_pids[], unsigned n_extra_pids, OutputFlags flags);
int show_cgroup_and_extra(const char *controller, const char *path, const char *prefix, unsigned n_columns, bool kernel_threads, const pid_t extra_pids[], unsigned n_extra_pids, OutputFlags flags);
int show_cgroup_and_extra_by_spec(const char *spec, const char *prefix, unsigned n_columns, const pid_t extra_pids[], unsigned n_extra_pids, OutputFlags flags);
int show_cgroup_and_extra(const char *controller, const char *path, const char *prefix, unsigned n_columns, const pid_t extra_pids[], unsigned n_extra_pids, OutputFlags flags);

View File

@ -344,16 +344,22 @@ static int output_short(
t = (time_t) (x / USEC_PER_SEC);
switch(mode) {
switch (mode) {
case OUTPUT_SHORT_UNIX:
r = snprintf(buf, sizeof(buf), "%10llu.%06llu", (unsigned long long) t, (unsigned long long) (x % USEC_PER_SEC));
break;
case OUTPUT_SHORT_ISO:
r = strftime(buf, sizeof(buf), "%Y-%m-%dT%H:%M:%S%z", gettime_r(&t, &tm));
break;
case OUTPUT_SHORT_PRECISE:
r = strftime(buf, sizeof(buf), "%b %d %H:%M:%S", gettime_r(&t, &tm));
if (r > 0)
snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf),
".%06llu", (unsigned long long) (x % USEC_PER_SEC));
snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), ".%06llu", (unsigned long long) (x % USEC_PER_SEC));
break;
default:
r = strftime(buf, sizeof(buf), "%b %d %H:%M:%S", gettime_r(&t, &tm));
}
@ -367,6 +373,12 @@ static int output_short(
n += strlen(buf);
}
if (hostname && (flags & OUTPUT_NO_HOSTNAME)) {
/* Suppress display of the hostname if this is requested. */
hostname = NULL;
hostname_len = 0;
}
if (hostname && shall_print(hostname, hostname_len, flags)) {
fprintf(f, " %.*s", (int) hostname_len, hostname);
n += hostname_len + 1;
@ -894,6 +906,7 @@ static int (*output_funcs[_OUTPUT_MODE_MAX])(
[OUTPUT_SHORT_ISO] = output_short,
[OUTPUT_SHORT_PRECISE] = output_short,
[OUTPUT_SHORT_MONOTONIC] = output_short,
[OUTPUT_SHORT_UNIX] = output_short,
[OUTPUT_VERBOSE] = output_verbose,
[OUTPUT_EXPORT] = output_export,
[OUTPUT_JSON] = output_json,
@ -1040,8 +1053,8 @@ static int show_journal(FILE *f,
}
int add_matches_for_unit(sd_journal *j, const char *unit) {
const char *m1, *m2, *m3, *m4;
int r;
char *m1, *m2, *m3, *m4;
assert(j);
assert(unit);
@ -1073,7 +1086,9 @@ int add_matches_for_unit(sd_journal *j, const char *unit) {
);
if (r == 0 && endswith(unit, ".slice")) {
const char *m5 = strjoina("_SYSTEMD_SLICE=", unit);
const char *m5;
m5 = strjoina("_SYSTEMD_SLICE=", unit);
/* Show all messages belonging to a slice */
(void)(
@ -1123,7 +1138,9 @@ int add_matches_for_user_unit(sd_journal *j, const char *unit, uid_t uid) {
);
if (r == 0 && endswith(unit, ".slice")) {
char *m5 = strappend("_SYSTEMD_SLICE=", unit);
const char *m5;
m5 = strjoina("_SYSTEMD_SLICE=", unit);
/* Show all messages belonging to a slice */
(void)(
@ -1288,18 +1305,3 @@ int show_journal_by_unit(
return show_journal(f, j, mode, n_columns, not_before, how_many, flags, ellipsized);
}
static const char *const output_mode_table[_OUTPUT_MODE_MAX] = {
[OUTPUT_SHORT] = "short",
[OUTPUT_SHORT_ISO] = "short-iso",
[OUTPUT_SHORT_PRECISE] = "short-precise",
[OUTPUT_SHORT_MONOTONIC] = "short-monotonic",
[OUTPUT_VERBOSE] = "verbose",
[OUTPUT_EXPORT] = "export",
[OUTPUT_JSON] = "json",
[OUTPUT_JSON_PRETTY] = "json-pretty",
[OUTPUT_JSON_SSE] = "json-sse",
[OUTPUT_CAT] = "cat"
};
DEFINE_STRING_TABLE_LOOKUP(output_mode, OutputMode);

View File

@ -68,6 +68,3 @@ void json_escape(
const char* p,
size_t l,
OutputFlags flags);
const char* output_mode_to_string(OutputMode m) _const_;
OutputMode output_mode_from_string(const char *s) _pure_;

37
src/shared/output-mode.c Normal file
View File

@ -0,0 +1,37 @@
/***
This file is part of systemd.
Copyright 2012 Lennart Poettering
systemd is free software; you can redistribute it and/or modify it
under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 2.1 of the License, or
(at your option) any later version.
systemd is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
#include "output-mode.h"
#include "string-table.h"
static const char *const output_mode_table[_OUTPUT_MODE_MAX] = {
[OUTPUT_SHORT] = "short",
[OUTPUT_SHORT_ISO] = "short-iso",
[OUTPUT_SHORT_PRECISE] = "short-precise",
[OUTPUT_SHORT_MONOTONIC] = "short-monotonic",
[OUTPUT_SHORT_UNIX] = "short-unix",
[OUTPUT_VERBOSE] = "verbose",
[OUTPUT_EXPORT] = "export",
[OUTPUT_JSON] = "json",
[OUTPUT_JSON_PRETTY] = "json-pretty",
[OUTPUT_JSON_SSE] = "json-sse",
[OUTPUT_CAT] = "cat"
};
DEFINE_STRING_TABLE_LOOKUP(output_mode, OutputMode);

View File

@ -19,11 +19,14 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
#include "macro.h"
typedef enum OutputMode {
OUTPUT_SHORT,
OUTPUT_SHORT_ISO,
OUTPUT_SHORT_PRECISE,
OUTPUT_SHORT_MONOTONIC,
OUTPUT_SHORT_UNIX,
OUTPUT_VERBOSE,
OUTPUT_EXPORT,
OUTPUT_JSON,
@ -34,6 +37,9 @@ typedef enum OutputMode {
_OUTPUT_MODE_INVALID = -1
} OutputMode;
/* The output flags definitions are shared by the logs and process tree output. Some apply to both, some only to the
* logs output, others only to the process tree output. */
typedef enum OutputFlags {
OUTPUT_SHOW_ALL = 1 << 0,
OUTPUT_FOLLOW = 1 << 1,
@ -43,4 +49,9 @@ typedef enum OutputFlags {
OUTPUT_CATALOG = 1 << 5,
OUTPUT_BEGIN_NEWLINE = 1 << 6,
OUTPUT_UTC = 1 << 7,
OUTPUT_KERNEL_THREADS = 1 << 8,
OUTPUT_NO_HOSTNAME = 1 << 9,
} OutputFlags;
const char* output_mode_to_string(OutputMode m) _const_;
OutputMode output_mode_from_string(const char *s) _pure_;

View File

@ -586,9 +586,16 @@ int lookup_paths_init(
if (!add)
return -ENOMEM;
r = strv_extend_strv(&paths, add, true);
if (r < 0)
if (paths) {
r = strv_extend_strv(&paths, add, true);
if (r < 0)
return r;
} else {
/* Small optimization: if paths is NULL (and it usually is), we can simply assign 'add' to it,
* and don't have to copy anything */
paths = add;
add = NULL;
}
}
r = patch_root_prefix(&persistent_config, root);

View File

@ -39,6 +39,7 @@
#include "bus-common-errors.h"
#include "bus-error.h"
#include "bus-message.h"
#include "bus-unit-util.h"
#include "bus-util.h"
#include "cgroup-show.h"
#include "cgroup-util.h"
@ -324,6 +325,8 @@ static int compare_unit_info(const void *a, const void *b) {
}
static bool output_show_unit(const UnitInfo *u, char **patterns) {
assert(u);
if (!strv_fnmatch_or_empty(patterns, u->id, FNM_NOESCAPE))
return false;
@ -1280,6 +1283,8 @@ static int compare_unit_file_list(const void *a, const void *b) {
}
static bool output_show_unit_file(const UnitFileList *u, char **patterns) {
assert(u);
if (!strv_fnmatch_or_empty(patterns, basename(u->path), FNM_NOESCAPE))
return false;
@ -3434,6 +3439,7 @@ typedef struct UnitStatusInfo {
} UnitStatusInfo;
static void print_status_info(
sd_bus *bus,
UnitStatusInfo *i,
bool *ellipsized) {
@ -3444,6 +3450,7 @@ static void print_status_info(
char since2[FORMAT_TIMESTAMP_MAX], *s2;
const char *path;
char **t, **t2;
int r;
assert(i);
@ -3716,25 +3723,26 @@ static void print_status_info(
printf(" CPU: %s\n", format_timespan(buf, sizeof(buf), i->cpu_usage_nsec / NSEC_PER_USEC, USEC_PER_MSEC));
}
if (i->control_group &&
(i->main_pid > 0 || i->control_pid > 0 ||
(!IN_SET(arg_transport, BUS_TRANSPORT_LOCAL, BUS_TRANSPORT_MACHINE) || cg_is_empty_recursive(SYSTEMD_CGROUP_CONTROLLER, i->control_group) == 0))) {
unsigned c;
if (i->control_group)
printf(" CGroup: %s\n", i->control_group);
if (IN_SET(arg_transport,
BUS_TRANSPORT_LOCAL,
BUS_TRANSPORT_MACHINE)) {
{
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
static const char prefix[] = " ";
unsigned c;
c = columns();
if (c > sizeof(prefix) - 1)
c -= sizeof(prefix) - 1;
else
c = 0;
r = unit_show_processes(bus, i->id, i->control_group, prefix, c, get_output_flags(), &error);
if (r == -EBADR) {
unsigned k = 0;
pid_t extra[2];
static const char prefix[] = " ";
c = columns();
if (c > sizeof(prefix) - 1)
c -= sizeof(prefix) - 1;
else
c = 0;
/* Fallback for older systemd versions where the GetUnitProcesses() call is not yet available */
if (i->main_pid > 0)
extra[k++] = i->main_pid;
@ -3742,8 +3750,9 @@ static void print_status_info(
if (i->control_pid > 0)
extra[k++] = i->control_pid;
show_cgroup_and_extra(SYSTEMD_CGROUP_CONTROLLER, i->control_group, prefix, c, false, extra, k, get_output_flags());
}
show_cgroup_and_extra(SYSTEMD_CGROUP_CONTROLLER, i->control_group, prefix, c, extra, k, get_output_flags());
} else if (r < 0)
log_warning_errno(r, "Failed to dump process list, ignoring: %s", bus_error_message(&error, r));
}
if (i->id && arg_transport == BUS_TRANSPORT_LOCAL)
@ -4504,7 +4513,7 @@ static int show_one(
if (streq(verb, "help"))
show_unit_help(&info);
else
print_status_info(&info, ellipsized);
print_status_info(bus, &info, ellipsized);
}
strv_free(info.documentation);
@ -4658,7 +4667,7 @@ static int show_system_status(sd_bus *bus) {
else
c = 0;
show_cgroup(SYSTEMD_CGROUP_CONTROLLER, strempty(mi.control_group), prefix, c, false, get_output_flags());
show_cgroup(SYSTEMD_CGROUP_CONTROLLER, strempty(mi.control_group), prefix, c, get_output_flags());
}
return 0;

View File

@ -32,15 +32,17 @@
#include "util.h"
int main(int argc, char** argv) {
_cleanup_free_ char *cmd = NULL, *cmd2 = NULL, *ans = NULL, *ans2 = NULL, *d = NULL, *tmp = NULL, *line = NULL;
_cleanup_close_ int fd = -1, fd2 = -1, fd3 = -1;
const char *p = argv[1] ?: "/tmp";
char *pattern = strjoina(p, "/systemd-test-XXXXXX");
_cleanup_close_ int fd, fd2;
_cleanup_free_ char *cmd, *cmd2, *ans, *ans2;
char *pattern;
log_set_max_level(LOG_DEBUG);
log_parse_environment();
fd = open_tmpfile(p, O_RDWR|O_CLOEXEC);
pattern = strjoina(p, "/systemd-test-XXXXXX");
fd = open_tmpfile_unlinkable(p, O_RDWR|O_CLOEXEC);
assert_se(fd >= 0);
assert_se(asprintf(&cmd, "ls -l /proc/"PID_FMT"/fd/%d", getpid(), fd) > 0);
@ -59,5 +61,21 @@ int main(int argc, char** argv) {
log_debug("link2: %s", ans2);
assert_se(endswith(ans2, " (deleted)"));
pattern = strjoina(p, "/tmpfiles-test");
assert_se(tempfn_random(pattern, NULL, &d) >= 0);
fd = open_tmpfile_linkable(d, O_RDWR|O_CLOEXEC, &tmp);
assert_se(fd >= 0);
assert_se(write(fd, "foobar\n", 7) == 7);
assert_se(touch(d) >= 0);
assert_se(link_tmpfile(fd, tmp, d) == -EEXIST);
assert_se(unlink(d) >= 0);
assert_se(link_tmpfile(fd, tmp, d) >= 0);
assert_se(read_one_line_file(d, &line) >= 0);
assert_se(streq(line, "foobar"));
assert_se(unlink(d) >= 0);
return 0;
}

View File

@ -8,7 +8,7 @@
[Unit]
Description=Permit User Sessions
Documentation=man:systemd-user-sessions.service(8)
After=remote-fs.target nss-user-lookup.target
After=remote-fs.target nss-user-lookup.target network.target
[Service]
Type=oneshot