cab2aca3e7
Make sure we can properly process resource limit properties. Specifically, allow transient configuration of both the soft and hard limit, the same way from the unit files. Previously, only the the hard rlimits could be configured but they'd implicitly spill into the soft hard rlimits. This also updates the client-side code to be able to parse hard/soft resource limit specifications. Since we need to serialize two properties in bus_append_unit_property_assignment() now, the marshalling of the container around it is now moved into the function itself. This has the benefit of shortening the calling code. As a side effect this now beefs up the rlimit parser of "systemctl set-property" to understand time and disk sizes where that's appropriate.
238 lines
9.4 KiB
C
238 lines
9.4 KiB
C
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
|
|
|
|
/***
|
|
This file is part of systemd.
|
|
|
|
Copyright 2015 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 "bus-error.h"
|
|
#include "bus-util.h"
|
|
#include "nspawn-register.h"
|
|
#include "stat-util.h"
|
|
#include "strv.h"
|
|
#include "util.h"
|
|
|
|
int register_machine(
|
|
const char *machine_name,
|
|
pid_t pid,
|
|
const char *directory,
|
|
sd_id128_t uuid,
|
|
int local_ifindex,
|
|
const char *slice,
|
|
CustomMount *mounts,
|
|
unsigned n_mounts,
|
|
int kill_signal,
|
|
char **properties,
|
|
bool keep_unit,
|
|
const char *service) {
|
|
|
|
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
|
|
_cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
|
|
int r;
|
|
|
|
r = sd_bus_default_system(&bus);
|
|
if (r < 0)
|
|
return log_error_errno(r, "Failed to open system bus: %m");
|
|
|
|
if (keep_unit) {
|
|
r = sd_bus_call_method(
|
|
bus,
|
|
"org.freedesktop.machine1",
|
|
"/org/freedesktop/machine1",
|
|
"org.freedesktop.machine1.Manager",
|
|
"RegisterMachineWithNetwork",
|
|
&error,
|
|
NULL,
|
|
"sayssusai",
|
|
machine_name,
|
|
SD_BUS_MESSAGE_APPEND_ID128(uuid),
|
|
service,
|
|
"container",
|
|
(uint32_t) pid,
|
|
strempty(directory),
|
|
local_ifindex > 0 ? 1 : 0, local_ifindex);
|
|
} else {
|
|
_cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
|
|
char **i;
|
|
unsigned j;
|
|
|
|
r = sd_bus_message_new_method_call(
|
|
bus,
|
|
&m,
|
|
"org.freedesktop.machine1",
|
|
"/org/freedesktop/machine1",
|
|
"org.freedesktop.machine1.Manager",
|
|
"CreateMachineWithNetwork");
|
|
if (r < 0)
|
|
return bus_log_create_error(r);
|
|
|
|
r = sd_bus_message_append(
|
|
m,
|
|
"sayssusai",
|
|
machine_name,
|
|
SD_BUS_MESSAGE_APPEND_ID128(uuid),
|
|
service,
|
|
"container",
|
|
(uint32_t) pid,
|
|
strempty(directory),
|
|
local_ifindex > 0 ? 1 : 0, local_ifindex);
|
|
if (r < 0)
|
|
return bus_log_create_error(r);
|
|
|
|
r = sd_bus_message_open_container(m, 'a', "(sv)");
|
|
if (r < 0)
|
|
return bus_log_create_error(r);
|
|
|
|
if (!isempty(slice)) {
|
|
r = sd_bus_message_append(m, "(sv)", "Slice", "s", slice);
|
|
if (r < 0)
|
|
return bus_log_create_error(r);
|
|
}
|
|
|
|
r = sd_bus_message_append(m, "(sv)", "DevicePolicy", "s", "strict");
|
|
if (r < 0)
|
|
return bus_log_create_error(r);
|
|
|
|
/* If you make changes here, also make sure to update
|
|
* systemd-nspawn@.service, to keep the device
|
|
* policies in sync regardless if we are run with or
|
|
* without the --keep-unit switch. */
|
|
r = sd_bus_message_append(m, "(sv)", "DeviceAllow", "a(ss)", 9,
|
|
/* Allow the container to
|
|
* access and create the API
|
|
* device nodes, so that
|
|
* PrivateDevices= in the
|
|
* container can work
|
|
* fine */
|
|
"/dev/null", "rwm",
|
|
"/dev/zero", "rwm",
|
|
"/dev/full", "rwm",
|
|
"/dev/random", "rwm",
|
|
"/dev/urandom", "rwm",
|
|
"/dev/tty", "rwm",
|
|
"/dev/net/tun", "rwm",
|
|
/* Allow the container
|
|
* access to ptys. However,
|
|
* do not permit the
|
|
* container to ever create
|
|
* these device nodes. */
|
|
"/dev/pts/ptmx", "rw",
|
|
"char-pts", "rw");
|
|
if (r < 0)
|
|
return bus_log_create_error(r);
|
|
|
|
for (j = 0; j < n_mounts; j++) {
|
|
CustomMount *cm = mounts + j;
|
|
|
|
if (cm->type != CUSTOM_MOUNT_BIND)
|
|
continue;
|
|
|
|
r = is_device_node(cm->source);
|
|
if (r < 0)
|
|
return log_error_errno(r, "Failed to stat %s: %m", cm->source);
|
|
|
|
if (r) {
|
|
r = sd_bus_message_append(m, "(sv)", "DeviceAllow", "a(ss)", 1,
|
|
cm->source, cm->read_only ? "r" : "rw");
|
|
if (r < 0)
|
|
return log_error_errno(r, "Failed to append message arguments: %m");
|
|
}
|
|
}
|
|
|
|
if (kill_signal != 0) {
|
|
r = sd_bus_message_append(m, "(sv)", "KillSignal", "i", kill_signal);
|
|
if (r < 0)
|
|
return bus_log_create_error(r);
|
|
|
|
r = sd_bus_message_append(m, "(sv)", "KillMode", "s", "mixed");
|
|
if (r < 0)
|
|
return bus_log_create_error(r);
|
|
}
|
|
|
|
STRV_FOREACH(i, properties) {
|
|
r = bus_append_unit_property_assignment(m, *i);
|
|
if (r < 0)
|
|
return r;
|
|
}
|
|
|
|
r = sd_bus_message_close_container(m);
|
|
if (r < 0)
|
|
return bus_log_create_error(r);
|
|
|
|
r = sd_bus_call(bus, m, 0, &error, NULL);
|
|
}
|
|
|
|
if (r < 0) {
|
|
log_error("Failed to register machine: %s", bus_error_message(&error, r));
|
|
return r;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int terminate_machine(pid_t pid) {
|
|
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
|
|
_cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
|
|
_cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
|
|
const char *path;
|
|
int r;
|
|
|
|
r = sd_bus_default_system(&bus);
|
|
if (r < 0)
|
|
return log_error_errno(r, "Failed to open system bus: %m");
|
|
|
|
r = sd_bus_call_method(
|
|
bus,
|
|
"org.freedesktop.machine1",
|
|
"/org/freedesktop/machine1",
|
|
"org.freedesktop.machine1.Manager",
|
|
"GetMachineByPID",
|
|
&error,
|
|
&reply,
|
|
"u",
|
|
(uint32_t) pid);
|
|
if (r < 0) {
|
|
/* Note that the machine might already have been
|
|
* cleaned up automatically, hence don't consider it a
|
|
* failure if we cannot get the machine object. */
|
|
log_debug("Failed to get machine: %s", bus_error_message(&error, r));
|
|
return 0;
|
|
}
|
|
|
|
r = sd_bus_message_read(reply, "o", &path);
|
|
if (r < 0)
|
|
return bus_log_parse_error(r);
|
|
|
|
r = sd_bus_call_method(
|
|
bus,
|
|
"org.freedesktop.machine1",
|
|
path,
|
|
"org.freedesktop.machine1.Machine",
|
|
"Terminate",
|
|
&error,
|
|
NULL,
|
|
NULL);
|
|
if (r < 0) {
|
|
log_debug("Failed to terminate machine: %s", bus_error_message(&error, r));
|
|
return 0;
|
|
}
|
|
|
|
return 0;
|
|
}
|