Merge pull request #27750 from keszybz/fix-root-resize-new

Allow firstboot.service to be started after sysusers.service
This commit is contained in:
Lennart Poettering
2023-05-23 09:53:13 -07:00
committed by GitHub
31 changed files with 367 additions and 182 deletions
+3
View File
@@ -35,6 +35,9 @@ All tools:
as `start` into no-ops. If that's what's explicitly desired, you might
consider setting `$SYSTEMD_OFFLINE=1`.
* `$SYSTEMD_FIRST_BOOT=0|1` — if set, assume "first boot" condition to be false
or true, instead of checking the flag file created by PID 1.
* `$SD_EVENT_PROFILE_DELAYS=1` — if set, the sd-event event loop implementation
will print latency information at runtime.
+34 -29
View File
@@ -34,18 +34,18 @@
<refsect1>
<title>Description</title>
<para><command>systemd-firstboot</command> initializes the most
basic system settings interactively on the first boot, or
optionally non-interactively when a system image is created.
The service is started if <varname>ConditionFirstBoot=yes</varname>
is satisfied. This essentially means that <filename>/etc/</filename>
<para><command>systemd-firstboot</command> initializes basic system settings interactively during the
first boot, or non-interactively on an offline system image. The service is started during boot if
<varname>ConditionFirstBoot=yes</varname> is met, which essentially means that <filename>/etc/</filename>
is empty, see
<citerefentry><refentrytitle>systemd.unit</refentrytitle><manvolnum>5</manvolnum></citerefentry>
for details.</para>
<citerefentry><refentrytitle>systemd.unit</refentrytitle><manvolnum>5</manvolnum></citerefentry> for
details.</para>
<para>The following settings may be set up:</para>
<para>The following settings may be configured:</para>
<itemizedlist>
<listitem><para>The machine ID of the system</para></listitem>
<listitem><para>The system locale, more specifically the two
locale variables <varname>LANG=</varname> and
<varname>LC_MESSAGES</varname></para></listitem>
@@ -56,9 +56,9 @@
<listitem><para>The system hostname</para></listitem>
<listitem><para>The machine ID of the system</para></listitem>
<listitem><para>The kernel command line used when installing kernel images</para></listitem>
<listitem><para>The root user's password</para></listitem>
<listitem><para>The root user's password and shell</para></listitem>
</itemizedlist>
<para>Each of the fields may either be queried interactively by
@@ -79,7 +79,7 @@
This allows <command>systemd-firstboot</command> to operate on
mounted but not booted disk images and in early boot. It is not
recommended to use <command>systemd-firstboot</command> on the
running system while it is up.</para>
running system after it has been set up.</para>
</refsect1>
<refsect1>
@@ -150,13 +150,25 @@
configuration file.</para></listitem>
</varlistentry>
<varlistentry>
<term><option>--setup-machine-id</option></term>
<listitem><para>Initialize the system's machine ID to a random ID. This controls the
<citerefentry><refentrytitle>machine-id</refentrytitle><manvolnum>5</manvolnum></citerefentry> file.
</para>
<para>This option only works in combination with <option>--root=</option> or
<option>--image=</option>. On a running system, <filename>machine-id</filename> is written by the
manager with help from
<citerefentry><refentrytitle>systemd-machine-id-commit.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>.
</para></listitem>
</varlistentry>
<varlistentry>
<term><option>--machine-id=<replaceable>ID</replaceable></option></term>
<listitem><para>Sets the system's machine ID. This controls
the
<citerefentry><refentrytitle>machine-id</refentrytitle><manvolnum>5</manvolnum></citerefentry>
file.</para></listitem>
<listitem><para>Set the system's machine ID to the specified value. The same restrictions apply
as to <option>--setup-machine-id</option>.</para></listitem>
</varlistentry>
<varlistentry>
@@ -230,8 +242,8 @@
<term><option>--copy-root-shell</option></term>
<listitem><para>Copy a specific basic setting from the host.
This only works in combination with <option>--root=</option>
(see above).</para></listitem>
This only works in combination with <option>--root=</option> or <option>--image=</option>.
</para></listitem>
</varlistentry>
<varlistentry>
@@ -247,21 +259,14 @@
</listitem>
</varlistentry>
<varlistentry>
<term><option>--setup-machine-id</option></term>
<listitem><para>Initialize the system's machine ID to a random
ID. This only works in combination with
<option>--root=</option>.</para></listitem>
</varlistentry>
<varlistentry>
<term><option>--force</option></term>
<listitem><para>systemd-firstboot doesn't modify existing files unless <option>--force</option>
is specified. For modifications to <filename>/etc/passwd</filename> and
<filename>/etc/shadow</filename>, systemd-firstboot only modifies the entry of the
<literal>root</literal> user instead of overwriting the entire file.</para></listitem>
<listitem><para>Write configuration even if the relevant files already exist. Without this option,
<filename>systemd-firstboot</filename> doesn't modify or replace existing files. Note that when
configuring the root account, even with this option, <filename>systemd-firstboot</filename> only
modifies the entry of the <literal>root</literal> user, leaving other entries in
<filename>/etc/passwd</filename> and <filename>/etc/shadow</filename> intact.</para></listitem>
</varlistentry>
<varlistentry>
+10 -2
View File
@@ -144,8 +144,16 @@
<varlistentry>
<term><option>--boot</option></term>
<listitem><para>Also execute lines with an exclamation mark.
</para></listitem>
<listitem><para>Also execute lines with an exclamation mark. Lines that are not safe to be executed
on a running system may be marked in this way. <command>systemd-tmpfiles</command> is executed in
early boot with <option>--boot</option> specified and will execute those lines. When invoked again
later, it should be called without <option>--boot</option>.</para></listitem>
</varlistentry>
<varlistentry>
<term><option>--graceful</option></term>
<listitem><para>Ignore configuration lines pertaining to unknown users or groups. This option is
intended to be used in early boot before all users or groups have been created.</para></listitem>
</varlistentry>
<varlistentry>
+6 -2
View File
@@ -287,7 +287,9 @@ int get_user_creds(
p = getpwnam(*username);
}
if (!p) {
r = errno_or_else(ESRCH);
/* getpwnam() may fail with ENOENT if /etc/passwd is missing.
* For us that is equivalent to the name not being defined. */
r = IN_SET(errno, 0, ENOENT) ? -ESRCH : -errno;
/* If the user requested that we only synthesize as fallback, do so now */
if (FLAGS_SET(flags, USER_CREDS_PREFER_NSS)) {
@@ -381,7 +383,9 @@ int get_group_creds(const char **groupname, gid_t *gid, UserCredsFlags flags) {
}
if (!g)
return errno_or_else(ESRCH);
/* getgrnam() may fail with ENOENT if /etc/group is missing.
* For us that is equivalent to the name not being defined. */
return IN_SET(errno, 0, ENOENT) ? -ESRCH : -errno;
if (gid) {
if (!gid_is_valid(g->gr_gid))
+5
View File
@@ -150,3 +150,8 @@ static inline bool hashed_password_is_locked_or_invalid(const char *password) {
/* A password indicating "hey, no password required for login" */
#define PASSWORD_NONE ""
/* Used by sysusers to indicate that the password should be filled in by firstboot.
* Also see https://github.com/systemd/systemd/pull/24680#pullrequestreview-1439464325.
*/
#define PASSWORD_UNPROVISIONED "!unprovisioned"
+77 -17
View File
@@ -234,17 +234,72 @@ static int prompt_loop(const char *text, char **l, unsigned percentage, bool (*i
}
static int should_configure(int dir_fd, const char *filename) {
_cleanup_fclose_ FILE *passwd = NULL, *shadow = NULL;
int r;
assert(dir_fd >= 0);
assert(filename);
if (faccessat(dir_fd, filename, F_OK, AT_SYMLINK_NOFOLLOW) < 0) {
if (errno != ENOENT)
return log_error_errno(errno, "Failed to access %s: %m", filename);
if (streq(filename, "passwd") && !arg_force)
/* We may need to do additional checks, so open the file. */
r = xfopenat(dir_fd, filename, "re", O_NOFOLLOW, &passwd);
else
r = RET_NERRNO(faccessat(dir_fd, filename, F_OK, AT_SYMLINK_NOFOLLOW));
if (r == -ENOENT)
return true; /* missing */
if (r < 0)
return log_error_errno(r, "Failed to access %s: %m", filename);
if (arg_force)
return true; /* exists, but if --force was given we should still configure the file. */
if (!passwd)
return false;
/* In case of /etc/passwd, do an additional check for the root password field.
* We first check that passwd redirects to shadow, and then we check shadow.
*/
struct passwd *i;
while ((r = fgetpwent_sane(passwd, &i)) > 0) {
if (!streq(i->pw_name, "root"))
continue;
if (streq_ptr(i->pw_passwd, PASSWORD_SEE_SHADOW))
break;
log_debug("passwd: root account with non-shadow password found, treating root as configured");
return false;
}
if (r < 0)
return log_error_errno(r, "Failed to read %s: %m", filename);
if (r == 0) {
log_debug("No root account found in %s, assuming root is not configured.", filename);
return true;
}
return arg_force; /* exists, but if --force was given we should still configure the file. */
r = xfopenat(dir_fd, "shadow", "re", O_NOFOLLOW, &shadow);
if (r == -ENOENT) {
log_debug("No shadow file found, assuming root is not configured.");
return true; /* missing */
}
if (r < 0)
return log_error_errno(r, "Failed to access shadow: %m");
struct spwd *j;
while ((r = fgetspent_sane(shadow, &j)) > 0) {
if (!streq(j->sp_namp, "root"))
continue;
bool unprovisioned = streq_ptr(j->sp_pwdp, PASSWORD_UNPROVISIONED);
log_debug("Root account found, %s.",
unprovisioned ? "with unprovisioned password, treating root as not configured" :
"treating root as configured");
return unprovisioned;
}
if (r < 0)
return log_error_errno(r, "Failed to read shadow: %m");
assert(r == 0);
log_debug("No root account found in shadow, assuming root is not configured.");
return true;
}
static bool locale_is_installed_bool(const char *name) {
@@ -1172,7 +1227,8 @@ static int help(void) {
" --keymap=KEYMAP Set keymap\n"
" --timezone=TIMEZONE Set timezone\n"
" --hostname=NAME Set hostname\n"
" --machine-ID=ID Set machine ID\n"
" --setup-machine-id Set a random machine ID\n"
" --machine-ID=ID Set specified machine ID\n"
" --root-password=PASSWORD Set root password from plaintext password\n"
" --root-password-file=FILE Set root password from file\n"
" --root-password-hashed=HASH Set root password from hashed password\n"
@@ -1190,7 +1246,6 @@ static int help(void) {
" --copy-root-password Copy root password from host\n"
" --copy-root-shell Copy root shell from host\n"
" --copy Copy locale, keymap, timezone, root password\n"
" --setup-machine-id Generate a new random machine ID\n"
" --force Overwrite existing files\n"
" --delete-root-password Delete root password\n"
" --welcome=no Disable the welcome text\n"
@@ -1214,6 +1269,7 @@ static int parse_argv(int argc, char *argv[]) {
ARG_KEYMAP,
ARG_TIMEZONE,
ARG_HOSTNAME,
ARG_SETUP_MACHINE_ID,
ARG_MACHINE_ID,
ARG_ROOT_PASSWORD,
ARG_ROOT_PASSWORD_FILE,
@@ -1233,7 +1289,6 @@ static int parse_argv(int argc, char *argv[]) {
ARG_COPY_TIMEZONE,
ARG_COPY_ROOT_PASSWORD,
ARG_COPY_ROOT_SHELL,
ARG_SETUP_MACHINE_ID,
ARG_FORCE,
ARG_DELETE_ROOT_PASSWORD,
ARG_WELCOME,
@@ -1251,6 +1306,7 @@ static int parse_argv(int argc, char *argv[]) {
{ "keymap", required_argument, NULL, ARG_KEYMAP },
{ "timezone", required_argument, NULL, ARG_TIMEZONE },
{ "hostname", required_argument, NULL, ARG_HOSTNAME },
{ "setup-machine-id", no_argument, NULL, ARG_SETUP_MACHINE_ID },
{ "machine-id", required_argument, NULL, ARG_MACHINE_ID },
{ "root-password", required_argument, NULL, ARG_ROOT_PASSWORD },
{ "root-password-file", required_argument, NULL, ARG_ROOT_PASSWORD_FILE },
@@ -1270,7 +1326,6 @@ static int parse_argv(int argc, char *argv[]) {
{ "copy-timezone", no_argument, NULL, ARG_COPY_TIMEZONE },
{ "copy-root-password", no_argument, NULL, ARG_COPY_ROOT_PASSWORD },
{ "copy-root-shell", no_argument, NULL, ARG_COPY_ROOT_SHELL },
{ "setup-machine-id", no_argument, NULL, ARG_SETUP_MACHINE_ID },
{ "force", no_argument, NULL, ARG_FORCE },
{ "delete-root-password", no_argument, NULL, ARG_DELETE_ROOT_PASSWORD },
{ "welcome", required_argument, NULL, ARG_WELCOME },
@@ -1392,6 +1447,13 @@ static int parse_argv(int argc, char *argv[]) {
hostname_cleanup(arg_hostname);
break;
case ARG_SETUP_MACHINE_ID:
r = sd_id128_randomize(&arg_machine_id);
if (r < 0)
return log_error_errno(r, "Failed to generate randomized machine ID: %m");
break;
case ARG_MACHINE_ID:
r = sd_id128_from_string(optarg, &arg_machine_id);
if (r < 0)
@@ -1460,13 +1522,6 @@ static int parse_argv(int argc, char *argv[]) {
arg_copy_root_shell = true;
break;
case ARG_SETUP_MACHINE_ID:
r = sd_id128_randomize(&arg_machine_id);
if (r < 0)
return log_error_errno(r, "Failed to generate randomized machine ID: %m");
break;
case ARG_FORCE:
arg_force = true;
break;
@@ -1496,10 +1551,15 @@ static int parse_argv(int argc, char *argv[]) {
if (arg_delete_root_password && (arg_copy_root_password || arg_root_password || arg_prompt_root_password))
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"--delete-root-password cannot be combined with other root password options");
"--delete-root-password cannot be combined with other root password options.");
if (arg_image && arg_root)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Please specify either --root= or --image=, the combination of both is not supported.");
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"--root= and --image= cannot be used together.");
if (!sd_id128_is_null(arg_machine_id) && !(arg_image || arg_root) && !arg_force)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"--machine-id=/--setup-machine-id only works with --root= or --image=.");
return 1;
}
+13 -5
View File
@@ -5515,15 +5515,11 @@ static int fd_apparent_size(int fd, uint64_t *ret) {
}
static int context_minimize(Context *context) {
const char *vt;
const char *vt = NULL;
int r;
assert(context);
r = var_tmp_dir(&vt);
if (r < 0)
return log_error_errno(r, "Could not determine temporary directory: %m");
LIST_FOREACH(partitions, p, context->partitions) {
_cleanup_(rm_rf_physical_and_freep) char *root = NULL;
_cleanup_(unlink_and_freep) char *temp = NULL;
@@ -5556,6 +5552,12 @@ static int context_minimize(Context *context) {
log_info("Pre-populating %s filesystem of partition %s twice to calculate minimal partition size",
p->format, strna(hint));
if (!vt) {
r = var_tmp_dir(&vt);
if (r < 0)
return log_error_errno(r, "Could not determine temporary directory: %m");
}
r = tempfn_random_child(vt, "repart", &temp);
if (r < 0)
return log_error_errno(r, "Failed to generate temporary file path: %m");
@@ -5713,6 +5715,12 @@ static int context_minimize(Context *context) {
log_info("Pre-populating verity hash data of partition %s to calculate minimal partition size",
strna(hint));
if (!vt) {
r = var_tmp_dir(&vt);
if (r < 0)
return log_error_errno(r, "Could not determine temporary directory: %m");
}
r = tempfn_random_child(vt, "repart", &temp);
if (r < 0)
return log_error_errno(r, "Failed to generate temporary file path: %m");
+27 -6
View File
@@ -821,22 +821,43 @@ static int condition_test_needs_update(Condition *c, char **env) {
return timespec_load_nsec(&usr.st_mtim) > timestamp;
}
static bool in_first_boot(void) {
static int first_boot = -1;
int r;
if (first_boot >= 0)
return first_boot;
const char *e = secure_getenv("SYSTEMD_FIRST_BOOT");
if (e) {
r = parse_boolean(e);
if (r < 0)
log_debug_errno(r, "Failed to parse $SYSTEMD_FIRST_BOOT, ignoring: %m");
else
return (first_boot = r);
}
r = RET_NERRNO(access("/run/systemd/first-boot", F_OK));
if (r < 0 && r != -ENOENT)
log_debug_errno(r, "Failed to check if /run/systemd/first-boot exists, assuming no: %m");
return r >= 0;
}
static int condition_test_first_boot(Condition *c, char **env) {
int r, q;
int r;
assert(c);
assert(c->parameter);
assert(c->type == CONDITION_FIRST_BOOT);
// TODO: Parse c->parameter immediately when reading the config.
// Apply negation when parsing too.
r = parse_boolean(c->parameter);
if (r < 0)
return r;
q = access("/run/systemd/first-boot", F_OK);
if (q < 0 && errno != ENOENT)
log_debug_errno(errno, "Failed to check if /run/systemd/first-boot exists, assuming no: %m");
return (q >= 0) == r;
return in_first_boot() == r;
}
static int condition_test_environment(Condition *c, char **env) {
+12 -6
View File
@@ -224,6 +224,7 @@ static int write_fsck_sysroot_service(
"[Unit]\n"
"Description=File System Check on %2$s\n"
"Documentation=man:%3$s(8)\n"
"\n"
"DefaultDependencies=no\n"
"BindsTo=%4$s\n"
"Conflicts=shutdown.target\n"
@@ -517,11 +518,13 @@ int generator_hook_up_mkswap(
"[Unit]\n"
"Description=Make Swap on %%f\n"
"Documentation=man:systemd-mkswap@.service(8)\n"
"\n"
"DefaultDependencies=no\n"
"BindsTo=%%i.device\n"
"Conflicts=shutdown.target\n"
"After=%%i.device\n"
"Before=shutdown.target %s\n"
"Before=%s\n"
"Conflicts=shutdown.target\n"
"Before=shutdown.target\n"
"\n"
"[Service]\n"
"Type=oneshot\n"
@@ -602,13 +605,15 @@ int generator_hook_up_mkfs(
"[Unit]\n"
"Description=Make File System on %%f\n"
"Documentation=man:systemd-makefs@.service(8)\n"
"\n"
"DefaultDependencies=no\n"
"BindsTo=%%i.device\n"
"Conflicts=shutdown.target\n"
"After=%%i.device\n"
/* fsck might or might not be used, so let's be safe and order
* ourselves before both systemd-fsck@.service and the mount unit. */
"Before=shutdown.target %s %s\n"
"Before=%s %s\n"
"Conflicts=shutdown.target\n"
"Before=shutdown.target\n"
"\n"
"[Service]\n"
"Type=oneshot\n"
@@ -748,11 +753,12 @@ int generator_write_cryptsetup_unit_section(
fprintf(f, "SourcePath=%s\n", source);
fprintf(f,
"\n"
"DefaultDependencies=no\n"
"IgnoreOnIsolate=true\n"
"After=cryptsetup-pre.target systemd-udevd-kernel.socket\n"
"Before=blockdev@dev-mapper-%%i.target\n"
"Wants=blockdev@dev-mapper-%%i.target\n");
"Wants=blockdev@dev-mapper-%%i.target\n"
"IgnoreOnIsolate=true\n");
return 0;
}
+23 -19
View File
@@ -415,7 +415,7 @@ static const char* pick_shell(const Item *i) {
return NOLOGIN;
}
static int write_temporary_passwd(const char *passwd_path, FILE **tmpfile, char **tmpfile_path) {
static int write_temporary_passwd(const char *passwd_path, FILE **ret_tmpfile, char **ret_tmpfile_path) {
_cleanup_fclose_ FILE *original = NULL, *passwd = NULL;
_cleanup_(unlink_and_freep) char *passwd_tmp = NULL;
struct passwd *pw = NULL;
@@ -511,7 +511,7 @@ static int write_temporary_passwd(const char *passwd_path, FILE **tmpfile, char
r = putpwent_sane(&n, passwd);
if (r < 0)
return log_debug_errno(r, "Failed to add new user \"%s\" to temporary passwd file: %m",
pw->pw_name);
i->name);
}
/* Append the remaining NIS entries if any */
@@ -532,8 +532,8 @@ static int write_temporary_passwd(const char *passwd_path, FILE **tmpfile, char
if (r < 0)
return log_debug_errno(r, "Failed to flush %s: %m", passwd_tmp);
*tmpfile = TAKE_PTR(passwd);
*tmpfile_path = TAKE_PTR(passwd_tmp);
*ret_tmpfile = TAKE_PTR(passwd);
*ret_tmpfile_path = TAKE_PTR(passwd_tmp);
return 0;
}
@@ -550,7 +550,7 @@ static usec_t epoch_or_now(void) {
return now(CLOCK_REALTIME);
}
static int write_temporary_shadow(const char *shadow_path, FILE **tmpfile, char **tmpfile_path) {
static int write_temporary_shadow(const char *shadow_path, FILE **ret_tmpfile, char **ret_tmpfile_path) {
_cleanup_fclose_ FILE *original = NULL, *shadow = NULL;
_cleanup_(unlink_and_freep) char *shadow_tmp = NULL;
struct spwd *sp = NULL;
@@ -618,7 +618,6 @@ static int write_temporary_shadow(const char *shadow_path, FILE **tmpfile, char
struct spwd n = {
.sp_namp = i->name,
.sp_pwdp = (char*) PASSWORD_LOCKED_AND_INVALID,
.sp_lstchg = lstchg,
.sp_min = -1,
.sp_max = -1,
@@ -641,11 +640,16 @@ static int write_temporary_shadow(const char *shadow_path, FILE **tmpfile, char
if (creds_password)
n.sp_pwdp = creds_password;
else if (streq(i->name, "root"))
/* Let firstboot set the password later */
n.sp_pwdp = (char*) PASSWORD_UNPROVISIONED;
else
n.sp_pwdp = (char*) PASSWORD_LOCKED_AND_INVALID;
r = putspent_sane(&n, shadow);
if (r < 0)
return log_debug_errno(r, "Failed to add new user \"%s\" to temporary shadow file: %m",
sp->sp_namp);
i->name);
}
/* Append the remaining NIS entries if any */
@@ -668,13 +672,13 @@ static int write_temporary_shadow(const char *shadow_path, FILE **tmpfile, char
if (r < 0)
return log_debug_errno(r, "Failed to flush %s: %m", shadow_tmp);
*tmpfile = TAKE_PTR(shadow);
*tmpfile_path = TAKE_PTR(shadow_tmp);
*ret_tmpfile = TAKE_PTR(shadow);
*ret_tmpfile_path = TAKE_PTR(shadow_tmp);
return 0;
}
static int write_temporary_group(const char *group_path, FILE **tmpfile, char **tmpfile_path) {
static int write_temporary_group(const char *group_path, FILE **ret_tmpfile, char **ret_tmpfile_path) {
_cleanup_fclose_ FILE *original = NULL, *group = NULL;
_cleanup_(unlink_and_freep) char *group_tmp = NULL;
bool group_changed = false;
@@ -774,13 +778,13 @@ static int write_temporary_group(const char *group_path, FILE **tmpfile, char **
return log_error_errno(r, "Failed to flush %s: %m", group_tmp);
if (group_changed) {
*tmpfile = TAKE_PTR(group);
*tmpfile_path = TAKE_PTR(group_tmp);
*ret_tmpfile = TAKE_PTR(group);
*ret_tmpfile_path = TAKE_PTR(group_tmp);
}
return 0;
}
static int write_temporary_gshadow(const char * gshadow_path, FILE **tmpfile, char **tmpfile_path) {
static int write_temporary_gshadow(const char * gshadow_path, FILE **ret_tmpfile, char **ret_tmpfile_path) {
#if ENABLE_GSHADOW
_cleanup_fclose_ FILE *original = NULL, *gshadow = NULL;
_cleanup_(unlink_and_freep) char *gshadow_tmp = NULL;
@@ -853,8 +857,8 @@ static int write_temporary_gshadow(const char * gshadow_path, FILE **tmpfile, ch
return log_error_errno(r, "Failed to flush %s: %m", gshadow_tmp);
if (group_changed) {
*tmpfile = TAKE_PTR(gshadow);
*tmpfile_path = TAKE_PTR(gshadow_tmp);
*ret_tmpfile = TAKE_PTR(gshadow);
*ret_tmpfile_path = TAKE_PTR(gshadow_tmp);
}
#endif
return 0;
@@ -891,23 +895,23 @@ static int write_files(void) {
if (group) {
r = make_backup("/etc/group", group_path);
if (r < 0)
return log_error_errno(r, "Failed to make backup %s: %m", group_path);
return log_error_errno(r, "Failed to backup %s: %m", group_path);
}
if (gshadow) {
r = make_backup("/etc/gshadow", gshadow_path);
if (r < 0)
return log_error_errno(r, "Failed to make backup %s: %m", gshadow_path);
return log_error_errno(r, "Failed to backup %s: %m", gshadow_path);
}
if (passwd) {
r = make_backup("/etc/passwd", passwd_path);
if (r < 0)
return log_error_errno(r, "Failed to make backup %s: %m", passwd_path);
return log_error_errno(r, "Failed to backup %s: %m", passwd_path);
}
if (shadow) {
r = make_backup("/etc/shadow", shadow_path);
if (r < 0)
return log_error_errno(r, "Failed to make backup %s: %m", shadow_path);
return log_error_errno(r, "Failed to backup %s: %m", shadow_path);
}
/* And make the new files count */
+68 -39
View File
@@ -86,35 +86,35 @@ typedef enum OperationMask {
typedef enum ItemType {
/* These ones take file names */
CREATE_FILE = 'f',
TRUNCATE_FILE = 'F', /* deprecated: use f+ */
CREATE_DIRECTORY = 'd',
TRUNCATE_DIRECTORY = 'D',
CREATE_SUBVOLUME = 'v',
CREATE_FILE = 'f',
TRUNCATE_FILE = 'F', /* deprecated: use f+ */
CREATE_DIRECTORY = 'd',
TRUNCATE_DIRECTORY = 'D',
CREATE_SUBVOLUME = 'v',
CREATE_SUBVOLUME_INHERIT_QUOTA = 'q',
CREATE_SUBVOLUME_NEW_QUOTA = 'Q',
CREATE_FIFO = 'p',
CREATE_SYMLINK = 'L',
CREATE_CHAR_DEVICE = 'c',
CREATE_BLOCK_DEVICE = 'b',
COPY_FILES = 'C',
CREATE_SUBVOLUME_NEW_QUOTA = 'Q',
CREATE_FIFO = 'p',
CREATE_SYMLINK = 'L',
CREATE_CHAR_DEVICE = 'c',
CREATE_BLOCK_DEVICE = 'b',
COPY_FILES = 'C',
/* These ones take globs */
WRITE_FILE = 'w',
EMPTY_DIRECTORY = 'e',
SET_XATTR = 't',
RECURSIVE_SET_XATTR = 'T',
SET_ACL = 'a',
RECURSIVE_SET_ACL = 'A',
SET_ATTRIBUTE = 'h',
RECURSIVE_SET_ATTRIBUTE = 'H',
IGNORE_PATH = 'x',
IGNORE_DIRECTORY_PATH = 'X',
REMOVE_PATH = 'r',
RECURSIVE_REMOVE_PATH = 'R',
RELABEL_PATH = 'z',
RECURSIVE_RELABEL_PATH = 'Z',
ADJUST_MODE = 'm', /* legacy, 'z' is identical to this */
WRITE_FILE = 'w',
EMPTY_DIRECTORY = 'e',
SET_XATTR = 't',
RECURSIVE_SET_XATTR = 'T',
SET_ACL = 'a',
RECURSIVE_SET_ACL = 'A',
SET_ATTRIBUTE = 'h',
RECURSIVE_SET_ATTRIBUTE = 'H',
IGNORE_PATH = 'x',
IGNORE_DIRECTORY_PATH = 'X',
REMOVE_PATH = 'r',
RECURSIVE_REMOVE_PATH = 'R',
RELABEL_PATH = 'z',
RECURSIVE_RELABEL_PATH = 'Z',
ADJUST_MODE = 'm', /* legacy, 'z' is identical to this */
} ItemType;
typedef enum AgeBy {
@@ -125,7 +125,7 @@ typedef enum AgeBy {
/* All file timestamp types are checked by default. */
AGE_BY_DEFAULT_FILE = AGE_BY_ATIME | AGE_BY_BTIME | AGE_BY_CTIME | AGE_BY_MTIME,
AGE_BY_DEFAULT_DIR = AGE_BY_ATIME | AGE_BY_BTIME | AGE_BY_MTIME
AGE_BY_DEFAULT_DIR = AGE_BY_ATIME | AGE_BY_BTIME | AGE_BY_MTIME,
} AgeBy;
typedef struct Item {
@@ -200,6 +200,7 @@ static bool arg_cat_config = false;
static RuntimeScope arg_runtime_scope = RUNTIME_SCOPE_SYSTEM;
static OperationMask arg_operation = 0;
static bool arg_boot = false;
static bool arg_graceful = false;
static PagerFlags arg_pager_flags = 0;
static char **arg_include_prefixes = NULL;
@@ -1131,7 +1132,8 @@ static int parse_acls_from_arg(Item *item) {
r = parse_acl(item->argument, &item->acl_access, &item->acl_access_exec,
&item->acl_default, !item->append_or_force);
if (r < 0)
log_warning_errno(r, "Failed to parse ACL \"%s\", ignoring: %m", item->argument);
log_full_errno(arg_graceful && IN_SET(r, -ENOENT, -ESRCH) ? LOG_DEBUG : LOG_WARNING,
r, "Failed to parse ACL \"%s\", ignoring: %m", item->argument);
#else
log_warning("ACLs are not supported, ignoring.");
#endif
@@ -3322,7 +3324,8 @@ static int parse_line(
ItemArray *existing;
OrderedHashmap *h;
int r, pos;
bool append_or_force = false, boot = false, allow_failure = false, try_replace = false, unbase64 = false, from_cred = false;
bool append_or_force = false, boot = false, allow_failure = false, try_replace = false,
unbase64 = false, from_cred = false, missing_user_or_group = false;
assert(fname);
assert(line >= 1);
@@ -3669,12 +3672,15 @@ static int parse_line(
u = user;
r = find_uid(u, &i.uid, uid_cache);
if (r < 0) {
if (r == -ESRCH && arg_graceful) {
log_syntax(NULL, LOG_DEBUG, fname, line, r,
"%s: user '%s' not found, not adjusting ownership.", i.path, u);
missing_user_or_group = true;
} else if (r < 0) {
*invalid_config = true;
return log_syntax(NULL, LOG_ERR, fname, line, r, "Failed to resolve user '%s': %m", u);
}
i.uid_set = true;
} else
i.uid_set = true;
}
if (!empty_or_dash(group)) {
@@ -3687,12 +3693,15 @@ static int parse_line(
g = group;
r = find_gid(g, &i.gid, gid_cache);
if (r < 0) {
if (r == -ESRCH && arg_graceful) {
log_syntax(NULL, LOG_DEBUG, fname, line, r,
"%s: group '%s' not found, not adjusting ownership.", i.path, g);
missing_user_or_group = true;
} else if (r < 0) {
*invalid_config = true;
return log_syntax(NULL, LOG_ERR, fname, line, r, "Failed to resolve group '%s'.", g);
}
i.gid_set = true;
return log_syntax(NULL, LOG_ERR, fname, line, r, "Failed to resolve group '%s': %m", g);
} else
i.gid_set = true;
}
if (!empty_or_dash(mode)) {
@@ -3717,7 +3726,20 @@ static int parse_line(
i.mode = m;
i.mode_set = true;
} else
i.mode = IN_SET(i.type, CREATE_DIRECTORY, TRUNCATE_DIRECTORY, CREATE_SUBVOLUME, CREATE_SUBVOLUME_INHERIT_QUOTA, CREATE_SUBVOLUME_NEW_QUOTA) ? 0755 : 0644;
i.mode = IN_SET(i.type,
CREATE_DIRECTORY,
TRUNCATE_DIRECTORY,
CREATE_SUBVOLUME,
CREATE_SUBVOLUME_INHERIT_QUOTA,
CREATE_SUBVOLUME_NEW_QUOTA) ? 0755 : 0644;
if (missing_user_or_group && (i.mode & ~0777) != 0) {
/* Refuse any special bits for nodes where we couldn't resolve the ownership properly. */
mode_t adjusted = i.mode & 0777;
log_syntax(NULL, LOG_INFO, fname, line, 0,
"Changing mode 0%o to 0%o because of changed ownership.", i.mode, adjusted);
i.mode = adjusted;
}
if (!empty_or_dash(age)) {
const char *a = age;
@@ -3839,6 +3861,7 @@ static int help(void) {
" --clean Clean up marked directories\n"
" --remove Remove marked files/directories\n"
" --boot Execute actions only safe at boot\n"
" --graceful Quitely ignore unknown users or groups\n"
" --prefix=PATH Only apply rules with the specified prefix\n"
" --exclude-prefix=PATH Ignore rules with the specified prefix\n"
" -E Ignore rules prefixed with /dev, /proc, /run, /sys\n"
@@ -3866,6 +3889,7 @@ static int parse_argv(int argc, char *argv[]) {
ARG_CLEAN,
ARG_REMOVE,
ARG_BOOT,
ARG_GRACEFUL,
ARG_PREFIX,
ARG_EXCLUDE_PREFIX,
ARG_ROOT,
@@ -3884,6 +3908,7 @@ static int parse_argv(int argc, char *argv[]) {
{ "clean", no_argument, NULL, ARG_CLEAN },
{ "remove", no_argument, NULL, ARG_REMOVE },
{ "boot", no_argument, NULL, ARG_BOOT },
{ "graceful", no_argument, NULL, ARG_GRACEFUL },
{ "prefix", required_argument, NULL, ARG_PREFIX },
{ "exclude-prefix", required_argument, NULL, ARG_EXCLUDE_PREFIX },
{ "root", required_argument, NULL, ARG_ROOT },
@@ -3933,6 +3958,10 @@ static int parse_argv(int argc, char *argv[]) {
arg_boot = true;
break;
case ARG_GRACEFUL:
arg_graceful = true;
break;
case ARG_PREFIX:
if (strv_push(&arg_include_prefixes, optarg) < 0)
return log_oom();
+2 -1
View File
@@ -10,8 +10,9 @@
[Unit]
Description=Local File Systems
Documentation=man:systemd.special(7)
DefaultDependencies=no
Conflicts=shutdown.target
After=local-fs-pre.target
Conflicts=shutdown.target
OnFailure=emergency.target
OnFailureJobMode=replace-irreversibly
+6 -3
View File
@@ -11,11 +11,14 @@
Description=Arbitrary Executable File Formats File System Automount Point
Documentation=https://docs.kernel.org/admin-guide/binfmt-misc.html
Documentation=https://www.freedesktop.org/wiki/Software/systemd/APIFileSystems
DefaultDependencies=no
Before=sysinit.target
Conflicts=shutdown.target
ConditionPathExists=/proc/sys/fs/binfmt_misc/
ConditionPathIsReadWrite=/proc/sys/
DefaultDependencies=no
Before=sysinit.target
Conflicts=shutdown.target
Before=shutdown.target
[Automount]
Where=/proc/sys/fs/binfmt_misc
+5 -2
View File
@@ -10,10 +10,13 @@
[Unit]
Description=Enable File System Quotas
Documentation=man:quotaon(8)
ConditionPathExists={{QUOTAON}}
DefaultDependencies=no
After=systemd-quotacheck.service
Before=remote-fs.target shutdown.target
ConditionPathExists={{QUOTAON}}
Before=remote-fs.target
Before=shutdown.target
[Service]
Type=oneshot
+2 -1
View File
@@ -13,8 +13,9 @@ Documentation=man:bootctl(1)
DefaultDependencies=no
After=local-fs.target
Before=sysinit.target systemd-update-done.service
Conflicts=shutdown.target
Before=sysinit.target shutdown.target systemd-update-done.service
Before=shutdown.target
[Service]
Type=oneshot
+8 -5
View File
@@ -10,14 +10,17 @@
[Unit]
Description=First Boot Wizard
Documentation=man:systemd-firstboot(1)
DefaultDependencies=no
Conflicts=shutdown.target
After=systemd-remount-fs.service
Before=systemd-sysusers.service systemd-vconsole-setup.service sysinit.target first-boot-complete.target shutdown.target
Wants=first-boot-complete.target
ConditionPathIsReadWrite=/etc
ConditionFirstBoot=yes
DefaultDependencies=no
After=systemd-remount-fs.service
Before=systemd-vconsole-setup.service sysinit.target first-boot-complete.target
Wants=first-boot-complete.target
Conflicts=shutdown.target
Before=shutdown.target
[Service]
Type=oneshot
RemainAfterExit=yes
+2 -1
View File
@@ -10,9 +10,10 @@
[Unit]
Description=Grow Root File System
Documentation=man:systemd-growfs-root.service(8)
DefaultDependencies=no
Conflicts=shutdown.target
After=systemd-repart.service systemd-remount-fs.service
Conflicts=shutdown.target
Before=shutdown.target
[Service]
+2 -1
View File
@@ -10,10 +10,11 @@
[Unit]
Description=Grow File System on %f
Documentation=man:systemd-growfs@.service(8)
DefaultDependencies=no
BindsTo=%i.mount
Conflicts=shutdown.target
After=systemd-repart.service %i.mount
Conflicts=shutdown.target
Before=shutdown.target
[Service]
+7 -4
View File
@@ -10,15 +10,18 @@
[Unit]
Description=Rebuild Hardware Database
Documentation=man:hwdb(7) man:systemd-hwdb(8)
DefaultDependencies=no
Conflicts=shutdown.target
After=systemd-remount-fs.service
Before=sysinit.target shutdown.target systemd-update-done.service
ConditionNeedsUpdate=/etc
ConditionPathExists=|!{{UDEVLIBEXECDIR}}/hwdb.bin
ConditionPathExists=|/etc/udev/hwdb.bin
ConditionDirectoryNotEmpty=|/etc/udev/hwdb.d/
DefaultDependencies=no
After=systemd-remount-fs.service
Before=sysinit.target systemd-update-done.service
Conflicts=shutdown.target
Before=shutdown.target
[Service]
Type=oneshot
RemainAfterExit=yes
+7 -4
View File
@@ -10,12 +10,15 @@
[Unit]
Description=Rebuild Journal Catalog
Documentation=man:systemd-journald.service(8) man:journald.conf(5)
DefaultDependencies=no
Conflicts=shutdown.target
After=local-fs.target systemd-tmpfiles-setup.service
Before=sysinit.target shutdown.target systemd-update-done.service
ConditionNeedsUpdate=/var
DefaultDependencies=no
After=local-fs.target systemd-tmpfiles-setup.service
Before=sysinit.target systemd-update-done.service
Conflicts=shutdown.target
Before=shutdown.target
[Service]
Type=oneshot
RemainAfterExit=yes
+8 -5
View File
@@ -10,13 +10,16 @@
[Unit]
Description=Flush Journal to Persistent Storage
Documentation=man:systemd-journald.service(8) man:journald.conf(5)
DefaultDependencies=no
Wants=systemd-journald.service
After=systemd-journald.service systemd-remount-fs.service
Before=systemd-tmpfiles-setup.service
RequiresMountsFor=/var/log/journal
ConditionPathExists=!/etc/initrd-release
DefaultDependencies=no
After=systemd-remount-fs.service
Before=systemd-tmpfiles-setup.service
Wants=systemd-journald.service
After=systemd-journald.service
RequiresMountsFor=/var/log/journal
[Service]
ExecStart=journalctl --flush
ExecStop=journalctl --smart-relinquish-var
+5 -2
View File
@@ -10,10 +10,13 @@
[Unit]
Description=File System Quota Check
Documentation=man:systemd-quotacheck.service(8)
ConditionPathExists={{QUOTACHECK}}
DefaultDependencies=no
After=systemd-remount-fs.service
Before=remote-fs.target shutdown.target
ConditionPathExists={{QUOTACHECK}}
Before=remote-fs.target
Before=shutdown.target
[Service]
Type=oneshot
+8 -7
View File
@@ -11,16 +11,17 @@
Description=Load/Save OS Random Seed
Documentation=man:systemd-random-seed.service(8) man:random(4)
DefaultDependencies=no
RequiresMountsFor={{RANDOM_SEED}}
Conflicts=shutdown.target
After=systemd-remount-fs.service
Before=first-boot-complete.target shutdown.target
Wants=first-boot-complete.target
ConditionVirtualization=!container
ConditionPathExists=!/etc/initrd-release
DefaultDependencies=no
After=systemd-remount-fs.service
Before=first-boot-complete.target
RequiresMountsFor={{RANDOM_SEED}}
Wants=first-boot-complete.target
Conflicts=shutdown.target
Before=shutdown.target
[Service]
Type=oneshot
RemainAfterExit=yes
+4 -2
View File
@@ -11,11 +11,13 @@
Description=Remount Root and Kernel File Systems
Documentation=man:systemd-remount-fs.service(8)
Documentation=https://www.freedesktop.org/wiki/Software/systemd/APIFileSystems
DefaultDependencies=no
Conflicts=shutdown.target
After=systemd-fsck-root.service
Before=local-fs-pre.target local-fs.target shutdown.target
Before=local-fs-pre.target local-fs.target
Wants=local-fs-pre.target
Conflicts=shutdown.target
Before=shutdown.target
[Service]
Type=oneshot
+8 -8
View File
@@ -10,22 +10,22 @@
[Unit]
Description=Repartition Root Disk
Documentation=man:systemd-repart.service(8)
DefaultDependencies=no
Conflicts=shutdown.target
Wants=modprobe@loop.service modprobe@dm_mod.service
After=initrd-usr-fs.target modprobe@loop.service modprobe@dm_mod.service
Before=initrd-root-fs.target shutdown.target
ConditionVirtualization=!container
ConditionDirectoryNotEmpty=|/usr/lib/repart.d
ConditionDirectoryNotEmpty=|/usr/local/lib/repart.d
ConditionDirectoryNotEmpty=|/etc/repart.d
ConditionDirectoryNotEmpty=|/run/repart.d
ConditionDirectoryNotEmpty=|/sysroot/usr/lib/repart.d
ConditionDirectoryNotEmpty=|/sysroot/usr/local/lib/repart.d
ConditionDirectoryNotEmpty=|/sysroot/etc/repart.d
ConditionDirectoryNotEmpty=|/sysusr/usr/lib/repart.d
ConditionDirectoryNotEmpty=|/sysusr/usr/local/lib/repart.d
DefaultDependencies=no
Wants=modprobe@loop.service modprobe@dm_mod.service
After=initrd-usr-fs.target modprobe@loop.service modprobe@dm_mod.service
Before=initrd-root-fs.target
Conflicts=shutdown.target initrd-switch-root.target
Before=shutdown.target initrd-switch-root.target
[Service]
Type=oneshot
RemainAfterExit=yes
+2 -1
View File
@@ -10,12 +10,13 @@
[Unit]
Description=Load/Save RF Kill Switch Status /dev/rfkill Watch
Documentation=man:systemd-rfkill.socket(8)
DefaultDependencies=no
BindsTo=sys-devices-virtual-misc-rfkill.device
After=sys-devices-virtual-misc-rfkill.device systemd-remount-fs.service
RequiresMountsFor=/var/lib/systemd/rfkill
Conflicts=shutdown.target
Before=shutdown.target
RequiresMountsFor=/var/lib/systemd/rfkill
[Socket]
ListenSpecial=/dev/rfkill
+3 -3
View File
@@ -11,15 +11,15 @@
Description=Create System Users
Documentation=man:sysusers.d(5) man:systemd-sysusers.service(8)
ConditionNeedsUpdate=|/etc
ConditionCredential=|sysusers.extra
DefaultDependencies=no
After=systemd-remount-fs.service
Before=sysinit.target systemd-update-done.service
Conflicts=shutdown.target initrd-switch-root.target
Before=shutdown.target initrd-switch-root.target
ConditionNeedsUpdate=|/etc
ConditionCredential=|sysusers.extra
[Service]
Type=oneshot
RemainAfterExit=yes
+1 -2
View File
@@ -12,7 +12,6 @@ Description=Create Static Device Nodes in /dev
Documentation=man:tmpfiles.d(5) man:systemd-tmpfiles(8)
DefaultDependencies=no
After=systemd-sysusers.service
Before=sysinit.target local-fs-pre.target systemd-udevd.service
Conflicts=shutdown.target initrd-switch-root.target
Before=shutdown.target initrd-switch-root.target
@@ -20,6 +19,6 @@ Before=shutdown.target initrd-switch-root.target
[Service]
Type=oneshot
RemainAfterExit=yes
ExecStart=systemd-tmpfiles --prefix=/dev --create --boot
ExecStart=systemd-tmpfiles --prefix=/dev --create --boot --graceful
SuccessExitStatus=DATAERR CANTCREAT
LoadCredential=tmpfiles.extra
+1 -1
View File
@@ -21,7 +21,7 @@ RefuseManualStop=yes
[Service]
Type=oneshot
RemainAfterExit=yes
ExecStart=systemd-tmpfiles --create --remove --boot --exclude-prefix=/dev
ExecStart=systemd-tmpfiles --create --remove --boot
SuccessExitStatus=DATAERR CANTCREAT
LoadCredential=tmpfiles.extra
LoadCredential=login.motd
+5 -3
View File
@@ -10,11 +10,13 @@
[Unit]
Description=Record System Boot/Shutdown in UTMP
Documentation=man:systemd-update-utmp.service(8) man:utmp(5)
DefaultDependencies=no
RequiresMountsFor=/var/log/wtmp
Conflicts=shutdown.target
After=systemd-remount-fs.service systemd-tmpfiles-setup.service auditd.service
Before=sysinit.target shutdown.target
Before=sysinit.target
Conflicts=shutdown.target
Before=shutdown.target
RequiresMountsFor=/var/log/wtmp
[Service]
Type=oneshot
+3 -1
View File
@@ -10,10 +10,12 @@
[Unit]
Description=Setup Virtual Console
Documentation=man:systemd-vconsole-setup.service(8) man:vconsole.conf(5)
ConditionPathExists=/dev/tty0
DefaultDependencies=no
Before=sysinit.target
Before=initrd-switch-root.target shutdown.target
ConditionPathExists=/dev/tty0
[Service]
Type=oneshot