mirror of
https://github.com/systemd/systemd.git
synced 2025-03-31 14:50:15 +03:00
commit
6448e16d21
@ -2944,6 +2944,8 @@ systemd_nspawn_SOURCES = \
|
||||
src/nspawn/nspawn-register.h \
|
||||
src/nspawn/nspawn-setuid.c \
|
||||
src/nspawn/nspawn-setuid.h \
|
||||
src/nspawn/nspawn-stub-pid1.c \
|
||||
src/nspawn/nspawn-stub-pid1.h \
|
||||
src/core/mount-setup.c \
|
||||
src/core/mount-setup.h \
|
||||
src/core/loopback-setup.c \
|
||||
|
@ -248,16 +248,76 @@
|
||||
<option>--ephemeral</option>.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><option>-a</option></term>
|
||||
<term><option>--as-pid2</option></term>
|
||||
|
||||
<listitem><para>Invoke the shell or specified program as process ID (PID) 2 instead of PID 1 (init). By
|
||||
default, if neither this option nor <option>--boot</option> is used, the selected binary is run as process with
|
||||
PID 1, a mode only suitable for programs that are aware of the special semantics that the process with PID 1
|
||||
has on UNIX. For example, it needs to reap all processes reparented to it, and should implement
|
||||
<command>sysvinit</command> compatible signal handling (specifically: it needs to reboot on SIGINT, reexecute
|
||||
on SIGTERM, reload configuration on SIGHUP, and so on). With <option>--as-pid2</option> a minimal stub init
|
||||
process is run as PID 1 and the selected binary is executed as PID 2 (and hence does not need to implement any
|
||||
special semantics). The stub init process will reap processes as necessary and react appropriately to
|
||||
signals. It is recommended to use this mode to invoke arbitrary commands in containers, unless they have been
|
||||
modified to run correctly as PID 1. Or in other words: this switch should be used for pretty much all commands,
|
||||
except when the command refers to an init or shell implementation, as these are generally capable of running
|
||||
correctly as PID 1). This option may not be combined with <option>--boot</option> or
|
||||
<option>--share-system</option>.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><option>-b</option></term>
|
||||
<term><option>--boot</option></term>
|
||||
|
||||
<listitem><para>Automatically search for an init binary and
|
||||
invoke it instead of a shell or a user supplied program. If
|
||||
this option is used, arguments specified on the command line
|
||||
are used as arguments for the init binary. This option may not
|
||||
be combined with <option>--share-system</option>.
|
||||
</para></listitem>
|
||||
<listitem><para>Automatically search for an init binary and invoke it as PID 1, instead of a shell or a user
|
||||
supplied program. If this option is used, arguments specified on the command line are used as arguments for the
|
||||
init binary. This option may not be combined with <option>--as-pid2</option> or
|
||||
<option>--share-system</option>.</para>
|
||||
|
||||
<para>The following table explains the different modes of invocation and relationship to
|
||||
<option>--as-pid2</option> (see above):</para>
|
||||
|
||||
<table>
|
||||
<title>Invocation Mode</title>
|
||||
<tgroup cols='2' align='left' colsep='1' rowsep='1'>
|
||||
<colspec colname="switch" />
|
||||
<colspec colname="explanation" />
|
||||
<thead>
|
||||
<row>
|
||||
<entry>Switch</entry>
|
||||
<entry>Explanation</entry>
|
||||
</row>
|
||||
</thead>
|
||||
<tbody>
|
||||
<row>
|
||||
<entry>Neither <option>--as-pid2</option> nor <option>--boot</option> specified</entry>
|
||||
<entry>The passed parameters are interpreted as command line, which is executed as PID 1 in the container.</entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry><option>--as-pid2</option> specified</entry>
|
||||
<entry>The passed parameters are interpreted as command line, which are executed as PID 2 in the container. A stub init process is run as PID 1.</entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry><option>--boot</option> specified</entry>
|
||||
<entry>An init binary as automatically searched and run as PID 1 in the container. The passed parameters are used as invocation parameters for this process.</entry>
|
||||
</row>
|
||||
|
||||
</tbody>
|
||||
</tgroup>
|
||||
</table>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><option>--chdir=</option></term>
|
||||
|
||||
<listitem><para>Change to the specified working directory before invoking the process in the container. Expects
|
||||
an absolute path in the container's file system namespace.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
|
@ -141,15 +141,21 @@
|
||||
<varlistentry>
|
||||
<term><varname>Boot=</varname></term>
|
||||
|
||||
<listitem><para>Takes a boolean argument, which defaults to off. If
|
||||
enabled, <command>systemd-nspawn</command> will automatically
|
||||
search for an <filename>init</filename> executable and invoke
|
||||
it. In this case, the specified parameters using
|
||||
<varname>Parameters=</varname> are passed as additional
|
||||
arguments to the <filename>init</filename> process. This
|
||||
setting corresponds to the <option>--boot</option> switch on
|
||||
the <command>systemd-nspawn</command> command
|
||||
line. </para></listitem>
|
||||
<listitem><para>Takes a boolean argument, which defaults to off. If enabled, <command>systemd-nspawn</command>
|
||||
will automatically search for an <filename>init</filename> executable and invoke it. In this case, the
|
||||
specified parameters using <varname>Parameters=</varname> are passed as additional arguments to the
|
||||
<filename>init</filename> process. This setting corresponds to the <option>--boot</option> switch on the
|
||||
<command>systemd-nspawn</command> command line. This option may not be combined with
|
||||
<varname>ProcessTwo=yes</varname>.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><varname>ProcessTwo=</varname></term>
|
||||
|
||||
<listitem><para>Takes a boolean argument, which defaults to off. If enabled, the specified program is run as
|
||||
PID 2. A stub init process is run as PID 1. This setting corresponds to the <option>--as-pid2</option> switch
|
||||
on the <command>systemd-nspawn</command> command line. This option may not be combined with
|
||||
<varname>Boot=yes</varname>.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
@ -186,6 +192,14 @@
|
||||
switch.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><varname>WorkingDirectory=</varname></term>
|
||||
|
||||
<listitem><para>Selects the working directory for the process invoked in the container. Expects an absolute
|
||||
path in the container's file system namespace. This corresponds to the <option>--chdir=</option> command line
|
||||
switch.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><varname>Capability=</varname></term>
|
||||
<term><varname>DropCapability=</varname></term>
|
||||
|
@ -383,6 +383,11 @@
|
||||
used to start long-running processes. All processes forked
|
||||
off by processes invoked via <varname>ExecStartPre=</varname> will
|
||||
be killed before the next service process is run.</para>
|
||||
|
||||
<para>Note that if any of the commands specified in <varname>ExecStartPre=</varname>,
|
||||
<varname>ExecStart=</varname>, or <varname>ExecStartPost=</varname> fail (and are not prefixed with
|
||||
<literal>-</literal>, see above) or time out before the service is fully up, execution continues with commands
|
||||
specified in <varname>ExecStopPost=</varname>, the commands in <varname>ExecStop=</varname> are skipped.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
@ -438,21 +443,36 @@
|
||||
<constant>SIGKILL</constant> immediately after the command
|
||||
exited, this would not result in a clean stop. The specified
|
||||
command should hence be a synchronous operation, not an
|
||||
asynchronous one.</para></listitem>
|
||||
asynchronous one.</para>
|
||||
|
||||
<para>Note that the commands specified in <varname>ExecStop=</varname> are only executed when the service
|
||||
started successfuly first. They are not invoked if the service was never started at all, or in case its
|
||||
start-up failed, for example because any of the commands specified in <varname>ExecStart=</varname>,
|
||||
<varname>ExecStartPre=</varname> or <varname>ExecStartPost=</varname> failed (and weren't prefixed with
|
||||
<literal>-</literal>, see above) or timed out. Use <varname>ExecStopPost=</varname> to invoke commands when a
|
||||
service failed to start up correctly and is shut down again.</para>
|
||||
|
||||
<para>It is recommended to use this setting for commands that communicate with the service requesting clean
|
||||
termination. When the commands specified with this option are executed it should be assumed that the service is
|
||||
still fully up and is able to react correctly to all commands. For post-mortem clean-up steps use
|
||||
<varname>ExecStopPost=</varname> instead.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><varname>ExecStopPost=</varname></term>
|
||||
<listitem><para>Additional commands that are executed after
|
||||
the service was stopped. This includes cases where the
|
||||
commands configured in <varname>ExecStop=</varname> were used,
|
||||
where the service does not have any
|
||||
<varname>ExecStop=</varname> defined, or where the service
|
||||
exited unexpectedly. This argument takes multiple command
|
||||
lines, following the same scheme as described for
|
||||
<varname>ExecStart=</varname>. Use of these settings is
|
||||
optional. Specifier and environment variable substitution is
|
||||
supported.</para></listitem>
|
||||
<listitem><para>Additional commands that are executed after the service is stopped. This includes cases where
|
||||
the commands configured in <varname>ExecStop=</varname> were used, where the service does not have any
|
||||
<varname>ExecStop=</varname> defined, or where the service exited unexpectedly. This argument takes multiple
|
||||
command lines, following the same scheme as described for <varname>ExecStart=</varname>. Use of these settings
|
||||
is optional. Specifier and environment variable substitution is supported. Note that – unlike
|
||||
<varname>ExecStop=</varname> – commands specified with this setting are invoked when a service failed to start
|
||||
up correctly and is shut down again.</para>
|
||||
|
||||
<para>It is recommended to use this setting for clean-up operations that shall be executed even when the
|
||||
service failed to start up correctly. Commands configured with this setting need to be able to operate even if
|
||||
the service failed starting up half-way and left incompletely initialized data around. As the service's
|
||||
processes have been terminated already when the commands specified with this setting are executed they should
|
||||
not attempt to communicate with them.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
|
@ -146,3 +146,17 @@ int clock_reset_timewarp(void) {
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define TIME_EPOCH_USEC ((usec_t) TIME_EPOCH * USEC_PER_SEC)
|
||||
|
||||
int clock_apply_epoch(void) {
|
||||
struct timespec ts;
|
||||
|
||||
if (now(CLOCK_REALTIME) >= TIME_EPOCH_USEC)
|
||||
return 0;
|
||||
|
||||
if (clock_settime(CLOCK_REALTIME, timespec_store(&ts, TIME_EPOCH_USEC)) < 0)
|
||||
return -errno;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
@ -28,3 +28,4 @@ int clock_set_timezone(int *min);
|
||||
int clock_reset_timewarp(void);
|
||||
int clock_get_hwclock(struct tm *tm);
|
||||
int clock_set_hwclock(const struct tm *tm);
|
||||
int clock_apply_epoch(void);
|
||||
|
@ -69,7 +69,7 @@ typedef struct dual_timestamp {
|
||||
#define FORMAT_TIMESTAMP_RELATIVE_MAX 256
|
||||
#define FORMAT_TIMESPAN_MAX 64
|
||||
|
||||
#define TIME_T_MAX (time_t)((1UL << ((sizeof(time_t) << 3) - 1)) - 1)
|
||||
#define TIME_T_MAX (time_t)((UINTMAX_C(1) << ((sizeof(time_t) << 3) - 1)) - 1)
|
||||
|
||||
#define DUAL_TIMESTAMP_NULL ((struct dual_timestamp) { 0ULL, 0ULL })
|
||||
|
||||
|
@ -972,17 +972,21 @@ static int busname_kill(Unit *u, KillWho who, int signo, sd_bus_error *error) {
|
||||
return unit_kill_common(u, who, signo, -1, BUSNAME(u)->control_pid, error);
|
||||
}
|
||||
|
||||
static int busname_get_timeout(Unit *u, uint64_t *timeout) {
|
||||
static int busname_get_timeout(Unit *u, usec_t *timeout) {
|
||||
BusName *n = BUSNAME(u);
|
||||
usec_t t;
|
||||
int r;
|
||||
|
||||
if (!n->timer_event_source)
|
||||
return 0;
|
||||
|
||||
r = sd_event_source_get_time(n->timer_event_source, timeout);
|
||||
r = sd_event_source_get_time(n->timer_event_source, &t);
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (t == USEC_INFINITY)
|
||||
return 0;
|
||||
|
||||
*timeout = t;
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
@ -1165,10 +1165,10 @@ void job_shutdown_magic(Job *j) {
|
||||
asynchronous_sync();
|
||||
}
|
||||
|
||||
int job_get_timeout(Job *j, uint64_t *timeout) {
|
||||
int job_get_timeout(Job *j, usec_t *timeout) {
|
||||
usec_t x = USEC_INFINITY, y = USEC_INFINITY;
|
||||
Unit *u = j->unit;
|
||||
uint64_t x = -1, y = -1;
|
||||
int r = 0, q = 0;
|
||||
int r;
|
||||
|
||||
assert(u);
|
||||
|
||||
@ -1176,20 +1176,18 @@ int job_get_timeout(Job *j, uint64_t *timeout) {
|
||||
r = sd_event_source_get_time(j->timer_event_source, &x);
|
||||
if (r < 0)
|
||||
return r;
|
||||
r = 1;
|
||||
}
|
||||
|
||||
if (UNIT_VTABLE(u)->get_timeout) {
|
||||
q = UNIT_VTABLE(u)->get_timeout(u, &y);
|
||||
if (q < 0)
|
||||
return q;
|
||||
r = UNIT_VTABLE(u)->get_timeout(u, &y);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
if (r == 0 && q == 0)
|
||||
if (x == USEC_INFINITY && y == USEC_INFINITY)
|
||||
return 0;
|
||||
|
||||
*timeout = MIN(x, y);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
@ -227,6 +227,8 @@ char *job_dbus_path(Job *j);
|
||||
|
||||
void job_shutdown_magic(Job *j);
|
||||
|
||||
int job_get_timeout(Job *j, usec_t *timeout) _pure_;
|
||||
|
||||
const char* job_type_to_string(JobType t) _const_;
|
||||
JobType job_type_from_string(const char *s) _pure_;
|
||||
|
||||
@ -239,6 +241,4 @@ JobMode job_mode_from_string(const char *s) _pure_;
|
||||
const char* job_result_to_string(JobResult t) _const_;
|
||||
JobResult job_result_from_string(const char *s) _pure_;
|
||||
|
||||
int job_get_timeout(Job *j, uint64_t *timeout) _pure_;
|
||||
|
||||
const char* job_type_to_access_method(JobType t);
|
||||
|
@ -1424,8 +1424,14 @@ int main(int argc, char *argv[]) {
|
||||
* saving time change. All kernel local time concepts will be treated
|
||||
* as UTC that way.
|
||||
*/
|
||||
clock_reset_timewarp();
|
||||
(void) clock_reset_timewarp();
|
||||
}
|
||||
|
||||
r = clock_apply_epoch();
|
||||
if (r < 0)
|
||||
log_error_errno(r, "Current system time is before build time, but cannot correct: %m");
|
||||
else if (r > 0)
|
||||
log_info("System time before build time, advancing clock.");
|
||||
}
|
||||
|
||||
/* Set the default for later on, but don't actually
|
||||
|
@ -158,11 +158,13 @@ static int mount_one(const MountPoint *p, bool relabel) {
|
||||
|
||||
/* Relabel first, just in case */
|
||||
if (relabel)
|
||||
label_fix(p->where, true, true);
|
||||
(void) label_fix(p->where, true, true);
|
||||
|
||||
r = path_is_mount_point(p->where, AT_SYMLINK_FOLLOW);
|
||||
if (r < 0 && r != -ENOENT)
|
||||
return r;
|
||||
if (r < 0 && r != -ENOENT) {
|
||||
log_full_errno((p->mode & MNT_FATAL) ? LOG_ERR : LOG_DEBUG, r, "Failed to determine whether %s is a mount point: %m", p->where);
|
||||
return (p->mode & MNT_FATAL) ? r : 0;
|
||||
}
|
||||
if (r > 0)
|
||||
return 0;
|
||||
|
||||
@ -173,9 +175,9 @@ static int mount_one(const MountPoint *p, bool relabel) {
|
||||
/* The access mode here doesn't really matter too much, since
|
||||
* the mounted file system will take precedence anyway. */
|
||||
if (relabel)
|
||||
mkdir_p_label(p->where, 0755);
|
||||
(void) mkdir_p_label(p->where, 0755);
|
||||
else
|
||||
mkdir_p(p->where, 0755);
|
||||
(void) mkdir_p(p->where, 0755);
|
||||
|
||||
log_debug("Mounting %s to %s of type %s with options %s.",
|
||||
p->what,
|
||||
@ -188,13 +190,13 @@ static int mount_one(const MountPoint *p, bool relabel) {
|
||||
p->type,
|
||||
p->flags,
|
||||
p->options) < 0) {
|
||||
log_full((p->mode & MNT_FATAL) ? LOG_ERR : LOG_DEBUG, "Failed to mount %s at %s: %m", p->type, p->where);
|
||||
log_full_errno((p->mode & MNT_FATAL) ? LOG_ERR : LOG_DEBUG, errno, "Failed to mount %s at %s: %m", p->type, p->where);
|
||||
return (p->mode & MNT_FATAL) ? -errno : 0;
|
||||
}
|
||||
|
||||
/* Relabel again, since we now mounted something fresh here */
|
||||
if (relabel)
|
||||
label_fix(p->where, false, false);
|
||||
(void) label_fix(p->where, false, false);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
@ -1556,17 +1556,21 @@ static void mount_shutdown(Manager *m) {
|
||||
m->mount_monitor = NULL;
|
||||
}
|
||||
|
||||
static int mount_get_timeout(Unit *u, uint64_t *timeout) {
|
||||
static int mount_get_timeout(Unit *u, usec_t *timeout) {
|
||||
Mount *m = MOUNT(u);
|
||||
usec_t t;
|
||||
int r;
|
||||
|
||||
if (!m->timer_event_source)
|
||||
return 0;
|
||||
|
||||
r = sd_event_source_get_time(m->timer_event_source, timeout);
|
||||
r = sd_event_source_get_time(m->timer_event_source, &t);
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (t == USEC_INFINITY)
|
||||
return 0;
|
||||
|
||||
*timeout = t;
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
@ -345,17 +345,21 @@ static int scope_kill(Unit *u, KillWho who, int signo, sd_bus_error *error) {
|
||||
return unit_kill_common(u, who, signo, -1, -1, error);
|
||||
}
|
||||
|
||||
static int scope_get_timeout(Unit *u, uint64_t *timeout) {
|
||||
static int scope_get_timeout(Unit *u, usec_t *timeout) {
|
||||
Scope *s = SCOPE(u);
|
||||
usec_t t;
|
||||
int r;
|
||||
|
||||
if (!s->timer_event_source)
|
||||
return 0;
|
||||
|
||||
r = sd_event_source_get_time(s->timer_event_source, timeout);
|
||||
r = sd_event_source_get_time(s->timer_event_source, &t);
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (t == USEC_INFINITY)
|
||||
return 0;
|
||||
|
||||
*timeout = t;
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
@ -1635,6 +1635,8 @@ static void service_enter_running(Service *s, ServiceResult f) {
|
||||
if (f != SERVICE_SUCCESS)
|
||||
s->result = f;
|
||||
|
||||
service_unwatch_control_pid(s);
|
||||
|
||||
if (service_good(s)) {
|
||||
|
||||
/* If there are any queued up sd_notify()
|
||||
@ -2788,7 +2790,7 @@ static void service_sigchld_event(Unit *u, pid_t pid, int code, int status) {
|
||||
|
||||
case SERVICE_START_POST:
|
||||
if (f != SERVICE_SUCCESS) {
|
||||
service_enter_stop(s, f);
|
||||
service_enter_signal(s, SERVICE_STOP_SIGTERM, f);
|
||||
break;
|
||||
}
|
||||
|
||||
@ -2878,7 +2880,7 @@ static int service_dispatch_timer(sd_event_source *source, usec_t usec, void *us
|
||||
|
||||
case SERVICE_START_POST:
|
||||
log_unit_warning(UNIT(s), "Start-post operation timed out. Stopping.");
|
||||
service_enter_stop(s, SERVICE_FAILURE_TIMEOUT);
|
||||
service_enter_signal(s, SERVICE_STOP_SIGTERM, SERVICE_FAILURE_TIMEOUT);
|
||||
break;
|
||||
|
||||
case SERVICE_RUNNING:
|
||||
@ -2887,8 +2889,7 @@ static int service_dispatch_timer(sd_event_source *source, usec_t usec, void *us
|
||||
break;
|
||||
|
||||
case SERVICE_RELOAD:
|
||||
log_unit_warning(UNIT(s), "Reload operation timed out. Stopping.");
|
||||
service_unwatch_control_pid(s);
|
||||
log_unit_warning(UNIT(s), "Reload operation timed out. Killing reload process.");
|
||||
service_kill_control_processes(s);
|
||||
s->reload_result = SERVICE_FAILURE_TIMEOUT;
|
||||
service_enter_running(s, SERVICE_SUCCESS);
|
||||
@ -3110,17 +3111,21 @@ static void service_notify_message(Unit *u, pid_t pid, char **tags, FDSet *fds)
|
||||
unit_add_to_dbus_queue(u);
|
||||
}
|
||||
|
||||
static int service_get_timeout(Unit *u, uint64_t *timeout) {
|
||||
static int service_get_timeout(Unit *u, usec_t *timeout) {
|
||||
Service *s = SERVICE(u);
|
||||
uint64_t t;
|
||||
int r;
|
||||
|
||||
if (!s->timer_event_source)
|
||||
return 0;
|
||||
|
||||
r = sd_event_source_get_time(s->timer_event_source, timeout);
|
||||
r = sd_event_source_get_time(s->timer_event_source, &t);
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (t == USEC_INFINITY)
|
||||
return 0;
|
||||
|
||||
*timeout = t;
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
@ -2770,17 +2770,21 @@ static int socket_kill(Unit *u, KillWho who, int signo, sd_bus_error *error) {
|
||||
return unit_kill_common(u, who, signo, -1, SOCKET(u)->control_pid, error);
|
||||
}
|
||||
|
||||
static int socket_get_timeout(Unit *u, uint64_t *timeout) {
|
||||
static int socket_get_timeout(Unit *u, usec_t *timeout) {
|
||||
Socket *s = SOCKET(u);
|
||||
usec_t t;
|
||||
int r;
|
||||
|
||||
if (!s->timer_event_source)
|
||||
return 0;
|
||||
|
||||
r = sd_event_source_get_time(s->timer_event_source, timeout);
|
||||
r = sd_event_source_get_time(s->timer_event_source, &t);
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (t == USEC_INFINITY)
|
||||
return 0;
|
||||
|
||||
*timeout = t;
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
@ -1396,17 +1396,21 @@ static int swap_kill(Unit *u, KillWho who, int signo, sd_bus_error *error) {
|
||||
return unit_kill_common(u, who, signo, -1, SWAP(u)->control_pid, error);
|
||||
}
|
||||
|
||||
static int swap_get_timeout(Unit *u, uint64_t *timeout) {
|
||||
static int swap_get_timeout(Unit *u, usec_t *timeout) {
|
||||
Swap *s = SWAP(u);
|
||||
usec_t t;
|
||||
int r;
|
||||
|
||||
if (!s->timer_event_source)
|
||||
return 0;
|
||||
|
||||
r = sd_event_source_get_time(s->timer_event_source, timeout);
|
||||
r = sd_event_source_get_time(s->timer_event_source, &t);
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (t == USEC_INFINITY)
|
||||
return 0;
|
||||
|
||||
*timeout = t;
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
@ -379,7 +379,8 @@ struct UnitVTable {
|
||||
/* Called whenever CLOCK_REALTIME made a jump */
|
||||
void (*time_change)(Unit *u);
|
||||
|
||||
int (*get_timeout)(Unit *u, uint64_t *timeout);
|
||||
/* Returns the next timeout of a unit */
|
||||
int (*get_timeout)(Unit *u, usec_t *timeout);
|
||||
|
||||
/* This is called for each unit type and should be used to
|
||||
* enumerate existing devices and load them. However,
|
||||
|
@ -515,14 +515,15 @@ static int add_boot(const char *what) {
|
||||
return log_error_errno(errno ?: EIO, "Failed to probe %s: %m", what);
|
||||
|
||||
(void) blkid_probe_lookup_value(b, "TYPE", &fstype, NULL);
|
||||
if (!streq(fstype, "vfat")) {
|
||||
if (!streq_ptr(fstype, "vfat")) {
|
||||
log_debug("Partition for /boot is not a FAT filesystem, ignoring.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
errno = 0;
|
||||
r = blkid_probe_lookup_value(b, "PART_ENTRY_UUID", &uuid, NULL);
|
||||
if (r != 0) {
|
||||
log_debug_errno(r, "Partition for /boot does not have a UUID, ignoring. %m");
|
||||
log_debug_errno(errno, "Partition for /boot does not have a UUID, ignoring.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -40,9 +40,9 @@ typedef struct FileDescriptor FileDescriptor;
|
||||
struct Window {
|
||||
MMapCache *cache;
|
||||
|
||||
bool invalidated;
|
||||
bool keep_always;
|
||||
bool in_unused;
|
||||
bool invalidated:1;
|
||||
bool keep_always:1;
|
||||
bool in_unused:1;
|
||||
|
||||
int prot;
|
||||
void *ptr;
|
||||
@ -78,7 +78,6 @@ struct MMapCache {
|
||||
|
||||
unsigned n_hit, n_missed;
|
||||
|
||||
|
||||
Hashmap *fds;
|
||||
Context *contexts[MMAP_CACHE_MAX_CONTEXTS];
|
||||
|
||||
@ -408,7 +407,7 @@ static int try_context(
|
||||
if (c->window->fd->sigbus)
|
||||
return -EIO;
|
||||
|
||||
c->window->keep_always |= keep_always;
|
||||
c->window->keep_always = c->window->keep_always || keep_always;
|
||||
|
||||
*ret = (uint8_t*) c->window->ptr + (offset - c->window->offset);
|
||||
return 1;
|
||||
@ -454,7 +453,7 @@ static int find_mmap(
|
||||
return -ENOMEM;
|
||||
|
||||
context_attach_window(c, w);
|
||||
w->keep_always += keep_always;
|
||||
w->keep_always = w->keep_always || keep_always;
|
||||
|
||||
*ret = (uint8_t*) w->ptr + (offset - w->offset);
|
||||
return 1;
|
||||
|
@ -15,7 +15,8 @@ struct ConfigPerfItem;
|
||||
%struct-type
|
||||
%includes
|
||||
%%
|
||||
Exec.Boot, config_parse_tristate, 0, offsetof(Settings, boot)
|
||||
Exec.Boot, config_parse_boot, 0, 0
|
||||
Exec.ProcessTwo, config_parse_pid2, 0, 0,
|
||||
Exec.Parameters, config_parse_strv, 0, offsetof(Settings, parameters)
|
||||
Exec.Environment, config_parse_strv, 0, offsetof(Settings, environment)
|
||||
Exec.User, config_parse_string, 0, offsetof(Settings, user)
|
||||
@ -24,6 +25,7 @@ Exec.DropCapability, config_parse_capability, 0, offsetof(Settings,
|
||||
Exec.KillSignal, config_parse_signal, 0, offsetof(Settings, kill_signal)
|
||||
Exec.Personality, config_parse_personality, 0, offsetof(Settings, personality)
|
||||
Exec.MachineID, config_parse_id128, 0, offsetof(Settings, machine_id)
|
||||
Exec.WorkingDirectory, config_parse_path, 0, offsetof(Settings, working_directory)
|
||||
Files.ReadOnly, config_parse_tristate, 0, offsetof(Settings, read_only)
|
||||
Files.Volatile, config_parse_volatile_mode, 0, offsetof(Settings, volatile_mode)
|
||||
Files.Bind, config_parse_bind, 0, 0
|
||||
|
@ -24,6 +24,7 @@
|
||||
#include "conf-parser.h"
|
||||
#include "nspawn-network.h"
|
||||
#include "nspawn-settings.h"
|
||||
#include "parse-util.h"
|
||||
#include "process-util.h"
|
||||
#include "strv.h"
|
||||
#include "util.h"
|
||||
@ -39,7 +40,7 @@ int settings_load(FILE *f, const char *path, Settings **ret) {
|
||||
if (!s)
|
||||
return -ENOMEM;
|
||||
|
||||
s->boot = -1;
|
||||
s->start_mode = _START_MODE_INVALID;
|
||||
s->personality = PERSONALITY_INVALID;
|
||||
|
||||
s->read_only = -1;
|
||||
@ -74,6 +75,7 @@ Settings* settings_free(Settings *s) {
|
||||
strv_free(s->parameters);
|
||||
strv_free(s->environment);
|
||||
free(s->user);
|
||||
free(s->working_directory);
|
||||
|
||||
strv_free(s->network_interfaces);
|
||||
strv_free(s->network_macvlan);
|
||||
@ -302,3 +304,93 @@ int config_parse_veth_extra(
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int config_parse_boot(
|
||||
const char *unit,
|
||||
const char *filename,
|
||||
unsigned line,
|
||||
const char *section,
|
||||
unsigned section_line,
|
||||
const char *lvalue,
|
||||
int ltype,
|
||||
const char *rvalue,
|
||||
void *data,
|
||||
void *userdata) {
|
||||
|
||||
Settings *settings = data;
|
||||
int r;
|
||||
|
||||
assert(filename);
|
||||
assert(lvalue);
|
||||
assert(rvalue);
|
||||
|
||||
r = parse_boolean(rvalue);
|
||||
if (r < 0) {
|
||||
log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse Boot= parameter %s, ignoring: %m", rvalue);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (r > 0) {
|
||||
if (settings->start_mode == START_PID2)
|
||||
goto conflict;
|
||||
|
||||
settings->start_mode = START_BOOT;
|
||||
} else {
|
||||
if (settings->start_mode == START_BOOT)
|
||||
goto conflict;
|
||||
|
||||
if (settings->start_mode < 0)
|
||||
settings->start_mode = START_PID1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
conflict:
|
||||
log_syntax(unit, LOG_ERR, filename, line, r, "Conflicting Boot= or ProcessTwo= setting found. Ignoring.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
int config_parse_pid2(
|
||||
const char *unit,
|
||||
const char *filename,
|
||||
unsigned line,
|
||||
const char *section,
|
||||
unsigned section_line,
|
||||
const char *lvalue,
|
||||
int ltype,
|
||||
const char *rvalue,
|
||||
void *data,
|
||||
void *userdata) {
|
||||
|
||||
Settings *settings = data;
|
||||
int r;
|
||||
|
||||
assert(filename);
|
||||
assert(lvalue);
|
||||
assert(rvalue);
|
||||
|
||||
r = parse_boolean(rvalue);
|
||||
if (r < 0) {
|
||||
log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse ProcessTwo= parameter %s, ignoring: %m", rvalue);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (r > 0) {
|
||||
if (settings->start_mode == START_BOOT)
|
||||
goto conflict;
|
||||
|
||||
settings->start_mode = START_PID2;
|
||||
} else {
|
||||
if (settings->start_mode == START_PID2)
|
||||
goto conflict;
|
||||
|
||||
if (settings->start_mode < 0)
|
||||
settings->start_mode = START_PID1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
conflict:
|
||||
log_syntax(unit, LOG_ERR, filename, line, r, "Conflicting Boot= or ProcessTwo= setting found. Ignoring.");
|
||||
return 0;
|
||||
}
|
||||
|
@ -27,25 +27,34 @@
|
||||
#include "nspawn-expose-ports.h"
|
||||
#include "nspawn-mount.h"
|
||||
|
||||
typedef enum StartMode {
|
||||
START_PID1, /* Run parameters as command line as process 1 */
|
||||
START_PID2, /* Use stub init process as PID 1, run parameters as command line as process 2 */
|
||||
START_BOOT, /* Search for init system, pass arguments as parameters */
|
||||
_START_MODE_MAX,
|
||||
_START_MODE_INVALID = -1
|
||||
} StartMode;
|
||||
|
||||
typedef enum SettingsMask {
|
||||
SETTING_BOOT = 1 << 0,
|
||||
SETTING_ENVIRONMENT = 1 << 1,
|
||||
SETTING_USER = 1 << 2,
|
||||
SETTING_CAPABILITY = 1 << 3,
|
||||
SETTING_KILL_SIGNAL = 1 << 4,
|
||||
SETTING_PERSONALITY = 1 << 5,
|
||||
SETTING_MACHINE_ID = 1 << 6,
|
||||
SETTING_NETWORK = 1 << 7,
|
||||
SETTING_EXPOSE_PORTS = 1 << 8,
|
||||
SETTING_READ_ONLY = 1 << 9,
|
||||
SETTING_VOLATILE_MODE = 1 << 10,
|
||||
SETTING_CUSTOM_MOUNTS = 1 << 11,
|
||||
_SETTINGS_MASK_ALL = (1 << 12) -1
|
||||
SETTING_START_MODE = 1 << 0,
|
||||
SETTING_ENVIRONMENT = 1 << 1,
|
||||
SETTING_USER = 1 << 2,
|
||||
SETTING_CAPABILITY = 1 << 3,
|
||||
SETTING_KILL_SIGNAL = 1 << 4,
|
||||
SETTING_PERSONALITY = 1 << 5,
|
||||
SETTING_MACHINE_ID = 1 << 6,
|
||||
SETTING_NETWORK = 1 << 7,
|
||||
SETTING_EXPOSE_PORTS = 1 << 8,
|
||||
SETTING_READ_ONLY = 1 << 9,
|
||||
SETTING_VOLATILE_MODE = 1 << 10,
|
||||
SETTING_CUSTOM_MOUNTS = 1 << 11,
|
||||
SETTING_WORKING_DIRECTORY = 1 << 12,
|
||||
_SETTINGS_MASK_ALL = (1 << 13) -1
|
||||
} SettingsMask;
|
||||
|
||||
typedef struct Settings {
|
||||
/* [Run] */
|
||||
int boot;
|
||||
StartMode start_mode;
|
||||
char **parameters;
|
||||
char **environment;
|
||||
char *user;
|
||||
@ -54,6 +63,7 @@ typedef struct Settings {
|
||||
int kill_signal;
|
||||
unsigned long personality;
|
||||
sd_id128_t machine_id;
|
||||
char *working_directory;
|
||||
|
||||
/* [Image] */
|
||||
int read_only;
|
||||
@ -89,3 +99,5 @@ int config_parse_volatile_mode(const char *unit, const char *filename, unsigned
|
||||
int config_parse_bind(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
|
||||
int config_parse_tmpfs(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
|
||||
int config_parse_veth_extra(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
|
||||
int config_parse_boot(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
|
||||
int config_parse_pid2(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
|
||||
|
170
src/nspawn/nspawn-stub-pid1.c
Normal file
170
src/nspawn/nspawn-stub-pid1.c
Normal file
@ -0,0 +1,170 @@
|
||||
/***
|
||||
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 <sys/reboot.h>
|
||||
#include <sys/unistd.h>
|
||||
#include <sys/wait.h>
|
||||
|
||||
#include "fd-util.h"
|
||||
#include "log.h"
|
||||
#include "nspawn-stub-pid1.h"
|
||||
#include "process-util.h"
|
||||
#include "signal-util.h"
|
||||
#include "time-util.h"
|
||||
#include "def.h"
|
||||
|
||||
int stub_pid1(void) {
|
||||
enum {
|
||||
STATE_RUNNING,
|
||||
STATE_REBOOT,
|
||||
STATE_POWEROFF,
|
||||
} state = STATE_RUNNING;
|
||||
|
||||
sigset_t fullmask, oldmask, waitmask;
|
||||
usec_t quit_usec = USEC_INFINITY;
|
||||
pid_t pid;
|
||||
int r;
|
||||
|
||||
/* Implements a stub PID 1, that reaps all processes and processes a couple of standard signals. This is useful
|
||||
* for allowing arbitrary processes run in a container, and still have all zombies reaped. */
|
||||
|
||||
assert_se(sigfillset(&fullmask) >= 0);
|
||||
assert_se(sigprocmask(SIG_BLOCK, &fullmask, &oldmask) >= 0);
|
||||
|
||||
pid = fork();
|
||||
if (pid < 0)
|
||||
return log_error_errno(errno, "Failed to fork child pid: %m");
|
||||
|
||||
if (pid == 0) {
|
||||
/* Return in the child */
|
||||
assert_se(sigprocmask(SIG_SETMASK, &oldmask, NULL) >= 0);
|
||||
setsid();
|
||||
return 0;
|
||||
}
|
||||
|
||||
reset_all_signal_handlers();
|
||||
|
||||
log_close();
|
||||
close_all_fds(NULL, 0);
|
||||
log_open();
|
||||
|
||||
rename_process("STUBINIT");
|
||||
|
||||
assert_se(sigemptyset(&waitmask) >= 0);
|
||||
assert_se(sigset_add_many(&waitmask,
|
||||
SIGCHLD, /* posix: process died */
|
||||
SIGINT, /* sysv: ctrl-alt-del */
|
||||
SIGRTMIN+3, /* systemd: halt */
|
||||
SIGRTMIN+4, /* systemd: poweroff */
|
||||
SIGRTMIN+5, /* systemd: reboot */
|
||||
SIGRTMIN+6, /* systemd: kexec */
|
||||
SIGRTMIN+13, /* systemd: halt */
|
||||
SIGRTMIN+14, /* systemd: poweroff */
|
||||
SIGRTMIN+15, /* systemd: reboot */
|
||||
SIGRTMIN+16, /* systemd: kexec */
|
||||
-1) >= 0);
|
||||
|
||||
/* Note that we ignore SIGTERM (sysv's reexec), SIGHUP (reload), and all other signals here, since we don't
|
||||
* support reexec/reloading in this stub process. */
|
||||
|
||||
for (;;) {
|
||||
siginfo_t si;
|
||||
usec_t current_usec;
|
||||
|
||||
si.si_pid = 0;
|
||||
r = waitid(P_ALL, 0, &si, WEXITED|WNOHANG);
|
||||
if (r < 0) {
|
||||
r = log_error_errno(errno, "Failed to reap children: %m");
|
||||
goto finish;
|
||||
}
|
||||
|
||||
current_usec = now(CLOCK_MONOTONIC);
|
||||
|
||||
if (si.si_pid == pid || current_usec >= quit_usec) {
|
||||
|
||||
/* The child we started ourselves died or we reached a timeout. */
|
||||
|
||||
if (state == STATE_REBOOT) { /* dispatch a queued reboot */
|
||||
(void) reboot(RB_AUTOBOOT);
|
||||
r = log_error_errno(errno, "Failed to reboot: %m");
|
||||
goto finish;
|
||||
|
||||
} else if (state == STATE_POWEROFF)
|
||||
(void) reboot(RB_POWER_OFF); /* if this fails, fall back to normal exit. */
|
||||
|
||||
if (si.si_pid == pid && si.si_code == CLD_EXITED)
|
||||
r = si.si_status; /* pass on exit code */
|
||||
else
|
||||
r = 255; /* signal, coredump, timeout, … */
|
||||
|
||||
goto finish;
|
||||
}
|
||||
if (si.si_pid != 0)
|
||||
/* We reaped something. Retry until there's nothing more to reap. */
|
||||
continue;
|
||||
|
||||
if (quit_usec == USEC_INFINITY)
|
||||
r = sigwaitinfo(&waitmask, &si);
|
||||
else {
|
||||
struct timespec ts;
|
||||
r = sigtimedwait(&waitmask, &si, timespec_store(&ts, quit_usec - current_usec));
|
||||
}
|
||||
if (r < 0) {
|
||||
if (errno == EINTR) /* strace -p attach can result in EINTR, let's handle this nicely. */
|
||||
continue;
|
||||
if (errno == EAGAIN) /* timeout reached */
|
||||
continue;
|
||||
|
||||
r = log_error_errno(errno, "Failed to wait for signal: %m");
|
||||
goto finish;
|
||||
}
|
||||
|
||||
if (si.si_signo == SIGCHLD)
|
||||
continue; /* Let's reap this */
|
||||
|
||||
if (state != STATE_RUNNING)
|
||||
continue;
|
||||
|
||||
/* Would love to use a switch() statement here, but SIGRTMIN is actually a function call, not a
|
||||
* constant… */
|
||||
|
||||
if (si.si_signo == SIGRTMIN+3 ||
|
||||
si.si_signo == SIGRTMIN+4 ||
|
||||
si.si_signo == SIGRTMIN+13 ||
|
||||
si.si_signo == SIGRTMIN+14)
|
||||
|
||||
state = STATE_POWEROFF;
|
||||
|
||||
else if (si.si_signo == SIGINT ||
|
||||
si.si_signo == SIGRTMIN+5 ||
|
||||
si.si_signo == SIGRTMIN+6 ||
|
||||
si.si_signo == SIGRTMIN+15 ||
|
||||
si.si_signo == SIGRTMIN+16)
|
||||
|
||||
state = STATE_REBOOT;
|
||||
else
|
||||
assert_not_reached("Got unexpected signal");
|
||||
|
||||
/* (void) kill_and_sigcont(pid, SIGTERM); */
|
||||
quit_usec = now(CLOCK_MONOTONIC) + DEFAULT_TIMEOUT_USEC;
|
||||
}
|
||||
|
||||
finish:
|
||||
_exit(r < 0 ? EXIT_FAILURE : r);
|
||||
}
|
22
src/nspawn/nspawn-stub-pid1.h
Normal file
22
src/nspawn/nspawn-stub-pid1.h
Normal file
@ -0,0 +1,22 @@
|
||||
#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/>.
|
||||
***/
|
||||
|
||||
int stub_pid1(void);
|
@ -79,6 +79,7 @@
|
||||
#include "nspawn-register.h"
|
||||
#include "nspawn-settings.h"
|
||||
#include "nspawn-setuid.h"
|
||||
#include "nspawn-stub-pid1.h"
|
||||
#include "parse-util.h"
|
||||
#include "path-util.h"
|
||||
#include "process-util.h"
|
||||
@ -114,6 +115,7 @@ typedef enum LinkJournal {
|
||||
|
||||
static char *arg_directory = NULL;
|
||||
static char *arg_template = NULL;
|
||||
static char *arg_chdir = NULL;
|
||||
static char *arg_user = NULL;
|
||||
static sd_id128_t arg_uuid = {};
|
||||
static char *arg_machine = NULL;
|
||||
@ -122,7 +124,7 @@ static const char *arg_selinux_apifs_context = NULL;
|
||||
static const char *arg_slice = NULL;
|
||||
static bool arg_private_network = false;
|
||||
static bool arg_read_only = false;
|
||||
static bool arg_boot = false;
|
||||
static StartMode arg_start_mode = START_PID1;
|
||||
static bool arg_ephemeral = false;
|
||||
static LinkJournal arg_link_journal = LINK_AUTO;
|
||||
static bool arg_link_journal_try = false;
|
||||
@ -192,7 +194,9 @@ static void help(void) {
|
||||
" -x --ephemeral Run container with snapshot of root directory, and\n"
|
||||
" remove it after exit\n"
|
||||
" -i --image=PATH File system device or disk image for the container\n"
|
||||
" -a --as-pid2 Maintain a stub init as PID1, invoke binary as PID2\n"
|
||||
" -b --boot Boot up full system (i.e. invoke init)\n"
|
||||
" --chdir=PATH Set working directory in the container\n"
|
||||
" -u --user=USER Run the command under specified user or uid\n"
|
||||
" -M --machine=NAME Set the machine name for the container\n"
|
||||
" --uuid=UUID Set a specific machine UUID for the container\n"
|
||||
@ -231,8 +235,8 @@ static void help(void) {
|
||||
" capability\n"
|
||||
" --drop-capability=CAP Drop the specified capability from the default set\n"
|
||||
" --kill-signal=SIGNAL Select signal to use for shutting down PID 1\n"
|
||||
" --link-journal=MODE Link up guest journal, one of no, auto, guest, host,\n"
|
||||
" try-guest, try-host\n"
|
||||
" --link-journal=MODE Link up guest journal, one of no, auto, guest, \n"
|
||||
" host, try-guest, try-host\n"
|
||||
" -j Equivalent to --link-journal=try-guest\n"
|
||||
" --read-only Mount the root directory read-only\n"
|
||||
" --bind=PATH[:PATH[:OPTIONS]]\n"
|
||||
@ -345,6 +349,7 @@ static int parse_argv(int argc, char *argv[]) {
|
||||
ARG_PRIVATE_USERS,
|
||||
ARG_KILL_SIGNAL,
|
||||
ARG_SETTINGS,
|
||||
ARG_CHDIR,
|
||||
};
|
||||
|
||||
static const struct option options[] = {
|
||||
@ -355,6 +360,7 @@ static int parse_argv(int argc, char *argv[]) {
|
||||
{ "ephemeral", no_argument, NULL, 'x' },
|
||||
{ "user", required_argument, NULL, 'u' },
|
||||
{ "private-network", no_argument, NULL, ARG_PRIVATE_NETWORK },
|
||||
{ "as-pid2", no_argument, NULL, 'a' },
|
||||
{ "boot", no_argument, NULL, 'b' },
|
||||
{ "uuid", required_argument, NULL, ARG_UUID },
|
||||
{ "read-only", no_argument, NULL, ARG_READ_ONLY },
|
||||
@ -389,6 +395,7 @@ static int parse_argv(int argc, char *argv[]) {
|
||||
{ "private-users", optional_argument, NULL, ARG_PRIVATE_USERS },
|
||||
{ "kill-signal", required_argument, NULL, ARG_KILL_SIGNAL },
|
||||
{ "settings", required_argument, NULL, ARG_SETTINGS },
|
||||
{ "chdir", required_argument, NULL, ARG_CHDIR },
|
||||
{}
|
||||
};
|
||||
|
||||
@ -400,7 +407,7 @@ static int parse_argv(int argc, char *argv[]) {
|
||||
assert(argc >= 0);
|
||||
assert(argv);
|
||||
|
||||
while ((c = getopt_long(argc, argv, "+hD:u:bL:M:jS:Z:qi:xp:n", options, NULL)) >= 0)
|
||||
while ((c = getopt_long(argc, argv, "+hD:u:abL:M:jS:Z:qi:xp:n", options, NULL)) >= 0)
|
||||
|
||||
switch (c) {
|
||||
|
||||
@ -491,8 +498,23 @@ static int parse_argv(int argc, char *argv[]) {
|
||||
break;
|
||||
|
||||
case 'b':
|
||||
arg_boot = true;
|
||||
arg_settings_mask |= SETTING_BOOT;
|
||||
if (arg_start_mode == START_PID2) {
|
||||
log_error("--boot and --as-pid2 may not be combined.");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
arg_start_mode = START_BOOT;
|
||||
arg_settings_mask |= SETTING_START_MODE;
|
||||
break;
|
||||
|
||||
case 'a':
|
||||
if (arg_start_mode == START_BOOT) {
|
||||
log_error("--boot and --as-pid2 may not be combined.");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
arg_start_mode = START_PID2;
|
||||
arg_settings_mask |= SETTING_START_MODE;
|
||||
break;
|
||||
|
||||
case ARG_UUID:
|
||||
@ -849,6 +871,19 @@ static int parse_argv(int argc, char *argv[]) {
|
||||
|
||||
break;
|
||||
|
||||
case ARG_CHDIR:
|
||||
if (!path_is_absolute(optarg)) {
|
||||
log_error("Working directory %s is not an absolute path.", optarg);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
r = free_and_strdup(&arg_chdir, optarg);
|
||||
if (r < 0)
|
||||
return log_oom();
|
||||
|
||||
arg_settings_mask |= SETTING_WORKING_DIRECTORY;
|
||||
break;
|
||||
|
||||
case '?':
|
||||
return -EINVAL;
|
||||
|
||||
@ -859,7 +894,7 @@ static int parse_argv(int argc, char *argv[]) {
|
||||
if (arg_share_system)
|
||||
arg_register = false;
|
||||
|
||||
if (arg_boot && arg_share_system) {
|
||||
if (arg_start_mode != START_PID1 && arg_share_system) {
|
||||
log_error("--boot and --share-system may not be combined.");
|
||||
return -EINVAL;
|
||||
}
|
||||
@ -907,7 +942,7 @@ static int parse_argv(int argc, char *argv[]) {
|
||||
if (!arg_parameters)
|
||||
return log_oom();
|
||||
|
||||
arg_settings_mask |= SETTING_BOOT;
|
||||
arg_settings_mask |= SETTING_START_MODE;
|
||||
}
|
||||
|
||||
/* Load all settings from .nspawn files */
|
||||
@ -943,7 +978,7 @@ static int verify_arguments(void) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (arg_boot && arg_kill_signal <= 0)
|
||||
if (arg_start_mode == START_BOOT && arg_kill_signal <= 0)
|
||||
arg_kill_signal = SIGRTMIN+3;
|
||||
|
||||
return 0;
|
||||
@ -2563,6 +2598,16 @@ static int inner_child(
|
||||
return -ESRCH;
|
||||
}
|
||||
|
||||
if (arg_chdir)
|
||||
if (chdir(arg_chdir) < 0)
|
||||
return log_error_errno(errno, "Failed to change to specified working directory %s: %m", arg_chdir);
|
||||
|
||||
if (arg_start_mode == START_PID2) {
|
||||
r = stub_pid1();
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
/* Now, explicitly close the log, so that we
|
||||
* then can close all remaining fds. Closing
|
||||
* the log explicitly first has the benefit
|
||||
@ -2574,7 +2619,7 @@ static int inner_child(
|
||||
log_close();
|
||||
(void) fdset_close_others(fds);
|
||||
|
||||
if (arg_boot) {
|
||||
if (arg_start_mode == START_BOOT) {
|
||||
char **a;
|
||||
size_t m;
|
||||
|
||||
@ -2598,7 +2643,9 @@ static int inner_child(
|
||||
} else if (!strv_isempty(arg_parameters))
|
||||
execvpe(arg_parameters[0], arg_parameters, env_use);
|
||||
else {
|
||||
chdir(home ?: "/root");
|
||||
if (!arg_chdir)
|
||||
chdir(home ?: "/root");
|
||||
|
||||
execle("/bin/bash", "-bash", NULL, env_use);
|
||||
execle("/bin/sh", "-sh", NULL, env_use);
|
||||
}
|
||||
@ -2894,15 +2941,22 @@ static int load_settings(void) {
|
||||
/* Copy over bits from the settings, unless they have been
|
||||
* explicitly masked by command line switches. */
|
||||
|
||||
if ((arg_settings_mask & SETTING_BOOT) == 0 &&
|
||||
settings->boot >= 0) {
|
||||
arg_boot = settings->boot;
|
||||
if ((arg_settings_mask & SETTING_START_MODE) == 0 &&
|
||||
settings->start_mode >= 0) {
|
||||
arg_start_mode = settings->start_mode;
|
||||
|
||||
strv_free(arg_parameters);
|
||||
arg_parameters = settings->parameters;
|
||||
settings->parameters = NULL;
|
||||
}
|
||||
|
||||
if ((arg_settings_mask & SETTING_WORKING_DIRECTORY) == 0 &&
|
||||
settings->working_directory) {
|
||||
free(arg_chdir);
|
||||
arg_chdir = settings->working_directory;
|
||||
settings->working_directory = NULL;
|
||||
}
|
||||
|
||||
if ((arg_settings_mask & SETTING_ENVIRONMENT) == 0 &&
|
||||
settings->environment) {
|
||||
strv_free(arg_setenv);
|
||||
@ -3044,6 +3098,10 @@ int main(int argc, char *argv[]) {
|
||||
log_parse_environment();
|
||||
log_open();
|
||||
|
||||
/* Make sure rename_process() in the stub init process can work */
|
||||
saved_argv = argv;
|
||||
saved_argc = argc;
|
||||
|
||||
r = parse_argv(argc, argv);
|
||||
if (r <= 0)
|
||||
goto finish;
|
||||
@ -3150,7 +3208,7 @@ int main(int argc, char *argv[]) {
|
||||
}
|
||||
}
|
||||
|
||||
if (arg_boot) {
|
||||
if (arg_start_mode == START_BOOT) {
|
||||
if (path_is_os_tree(arg_directory) <= 0) {
|
||||
log_error("Directory %s doesn't look like an OS root directory (os-release file is missing). Refusing.", arg_directory);
|
||||
r = -EINVAL;
|
||||
@ -3629,6 +3687,7 @@ finish:
|
||||
free(arg_image);
|
||||
free(arg_machine);
|
||||
free(arg_user);
|
||||
free(arg_chdir);
|
||||
strv_free(arg_setenv);
|
||||
free(arg_network_bridge);
|
||||
strv_free(arg_network_interfaces);
|
||||
|
@ -51,6 +51,7 @@ struct DnsCacheItem {
|
||||
bool authenticated:1;
|
||||
bool shared_owner:1;
|
||||
|
||||
int ifindex;
|
||||
int owner_family;
|
||||
union in_addr_union owner_address;
|
||||
|
||||
@ -329,6 +330,7 @@ static void dns_cache_item_update_positive(
|
||||
bool authenticated,
|
||||
bool shared_owner,
|
||||
usec_t timestamp,
|
||||
int ifindex,
|
||||
int owner_family,
|
||||
const union in_addr_union *owner_address) {
|
||||
|
||||
@ -356,6 +358,8 @@ static void dns_cache_item_update_positive(
|
||||
i->authenticated = authenticated;
|
||||
i->shared_owner = shared_owner;
|
||||
|
||||
i->ifindex = ifindex;
|
||||
|
||||
i->owner_family = owner_family;
|
||||
i->owner_address = *owner_address;
|
||||
|
||||
@ -368,6 +372,7 @@ static int dns_cache_put_positive(
|
||||
bool authenticated,
|
||||
bool shared_owner,
|
||||
usec_t timestamp,
|
||||
int ifindex,
|
||||
int owner_family,
|
||||
const union in_addr_union *owner_address) {
|
||||
|
||||
@ -414,6 +419,7 @@ static int dns_cache_put_positive(
|
||||
authenticated,
|
||||
shared_owner,
|
||||
timestamp,
|
||||
ifindex,
|
||||
owner_family,
|
||||
owner_address);
|
||||
return 0;
|
||||
@ -436,6 +442,7 @@ static int dns_cache_put_positive(
|
||||
i->until = calculate_until(rr, (uint32_t) -1, timestamp, false);
|
||||
i->authenticated = authenticated;
|
||||
i->shared_owner = shared_owner;
|
||||
i->ifindex = ifindex;
|
||||
i->owner_family = owner_family;
|
||||
i->owner_address = *owner_address;
|
||||
i->prioq_idx = PRIOQ_IDX_NULL;
|
||||
@ -615,7 +622,7 @@ int dns_cache_put(
|
||||
DnsResourceRecord *soa = NULL, *rr;
|
||||
DnsAnswerFlags flags;
|
||||
unsigned cache_keys;
|
||||
int r;
|
||||
int r, ifindex;
|
||||
|
||||
assert(c);
|
||||
assert(owner_address);
|
||||
@ -653,7 +660,7 @@ int dns_cache_put(
|
||||
timestamp = now(clock_boottime_or_monotonic());
|
||||
|
||||
/* Second, add in positive entries for all contained RRs */
|
||||
DNS_ANSWER_FOREACH_FLAGS(rr, flags, answer) {
|
||||
DNS_ANSWER_FOREACH_FULL(rr, ifindex, flags, answer) {
|
||||
if ((flags & DNS_ANSWER_CACHEABLE) == 0)
|
||||
continue;
|
||||
|
||||
@ -669,6 +676,7 @@ int dns_cache_put(
|
||||
flags & DNS_ANSWER_AUTHENTICATED,
|
||||
flags & DNS_ANSWER_SHARED_OWNER,
|
||||
timestamp,
|
||||
ifindex,
|
||||
owner_family, owner_address);
|
||||
if (r < 0)
|
||||
goto fail;
|
||||
@ -922,7 +930,7 @@ int dns_cache_lookup(DnsCache *c, DnsResourceKey *key, int *rcode, DnsAnswer **r
|
||||
if (!j->rr)
|
||||
continue;
|
||||
|
||||
r = dns_answer_add(answer, j->rr, 0, j->authenticated ? DNS_ANSWER_AUTHENTICATED : 0);
|
||||
r = dns_answer_add(answer, j->rr, j->ifindex, j->authenticated ? DNS_ANSWER_AUTHENTICATED : 0);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
@ -967,6 +967,17 @@ static int dns_query_cname_redirect(DnsQuery *q, const DnsResourceRecord *cname)
|
||||
if (r == 0 && k == 0) /* No actual cname happened? */
|
||||
return -ELOOP;
|
||||
|
||||
if (q->answer_protocol == DNS_PROTOCOL_DNS) {
|
||||
/* Don't permit CNAME redirects from unicast DNS to LLMNR or MulticastDNS, so that global resources
|
||||
* cannot invade the local namespace. The opposite way we permit: local names may redirect to global
|
||||
* ones. */
|
||||
|
||||
q->flags &= ~(SD_RESOLVED_LLMNR|SD_RESOLVED_MDNS); /* mask away the local protocols */
|
||||
}
|
||||
|
||||
/* Turn off searching for the new name */
|
||||
q->flags |= SD_RESOLVED_NO_SEARCH;
|
||||
|
||||
dns_question_unref(q->question_idna);
|
||||
q->question_idna = nq_idna;
|
||||
nq_idna = NULL;
|
||||
@ -977,10 +988,8 @@ static int dns_query_cname_redirect(DnsQuery *q, const DnsResourceRecord *cname)
|
||||
|
||||
dns_query_free_candidates(q);
|
||||
dns_query_reset_answer(q);
|
||||
q->state = DNS_TRANSACTION_NULL;
|
||||
|
||||
/* Turn off searching for the new name */
|
||||
q->flags |= SD_RESOLVED_NO_SEARCH;
|
||||
q->state = DNS_TRANSACTION_NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -57,8 +57,6 @@ int dns_scope_new(Manager *m, DnsScope **ret, Link *l, DnsProtocol protocol, int
|
||||
s->family = family;
|
||||
s->resend_timeout = MULTICAST_RESEND_TIMEOUT_MIN_USEC;
|
||||
|
||||
s->dnssec_mode = _DNSSEC_MODE_INVALID;
|
||||
|
||||
if (protocol == DNS_PROTOCOL_DNS) {
|
||||
/* Copy DNSSEC mode from the link if it is set there,
|
||||
* otherwise take the manager's DNSSEC mode. Note that
|
||||
@ -70,7 +68,8 @@ int dns_scope_new(Manager *m, DnsScope **ret, Link *l, DnsProtocol protocol, int
|
||||
s->dnssec_mode = link_get_dnssec_mode(l);
|
||||
else
|
||||
s->dnssec_mode = manager_get_dnssec_mode(m);
|
||||
}
|
||||
} else
|
||||
s->dnssec_mode = DNSSEC_NO;
|
||||
|
||||
LIST_PREPEND(scopes, m->dns_scopes, s);
|
||||
|
||||
|
@ -192,6 +192,8 @@ static void test_usec_add(void) {
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
uintmax_t x;
|
||||
|
||||
test_parse_sec();
|
||||
test_parse_time();
|
||||
test_parse_nsec();
|
||||
@ -202,5 +204,13 @@ int main(int argc, char *argv[]) {
|
||||
test_get_timezones();
|
||||
test_usec_add();
|
||||
|
||||
/* Ensure time_t is signed */
|
||||
assert_cc((time_t) -1 < (time_t) 1);
|
||||
|
||||
/* Ensure TIME_T_MAX works correctly */
|
||||
x = (uintmax_t) TIME_T_MAX;
|
||||
x ++;
|
||||
assert((time_t) x < 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user