1
0
mirror of https://github.com/systemd/systemd synced 2025-09-23 22:04:45 +02:00

Compare commits

..

20 Commits

Author SHA1 Message Date
Lennart Poettering
cb1277fa3b udev: get rid of "Could not set flow control of" message on "lo" interface
When setting flow control attributes of an interface we first acquire
the current settings and then add in the new settings before applying
them again. This only works on interfaces that implement the ethtool
ioctls. on others we'll see an ugly "Could not set flow control of"
message, simply because we issue the SIOCETHTOOL ioctl once, for getting
the data. In particular we'll get it for the "lo" interface all the
time, which sucks hard. Let's get rid of it.
2020-05-15 17:58:53 +02:00
Frantisek Sumsal
c07f18ffd4 shared: fix integer overflow in calendarspec
Fixes: oss-fuzz#22208

```
test/fuzz/fuzz-calendarspec/oss-fuzz-22208... ../src/shared/calendarspec.c:666:48: runtime error: signed integer overflow: 2147000000 + 1000000 cannot be represented in type 'int'
    #0 0x7f0b9f6cc56a in prepend_component ../src/shared/calendarspec.c:666
    #1 0x7f0b9f6cd03a in parse_chain ../src/shared/calendarspec.c:718
    #2 0x7f0b9f6cea1c in parse_calendar_time ../src/shared/calendarspec.c:845
    #3 0x7f0b9f6d1397 in calendar_spec_from_string ../src/shared/calendarspec.c:1084
    #4 0x401570 in LLVMFuzzerTestOneInput ../src/fuzz/fuzz-calendarspec.c:17
    #5 0x401ae0 in main ../src/fuzz/fuzz-main.c:39
    #6 0x7f0b9e31b1a2 in __libc_start_main (/lib64/libc.so.6+0x271a2)
    #7 0x40122d in _start (/home/fsumsal/repos/systemd/build/fuzz-calendarspec+0x40122d)

SUMMARY: UndefinedBehaviorSanitizer: undefined-behavior ../src/shared/calendarspec.c:666:48 in
```
2020-05-15 16:07:29 +02:00
Susant Sahani
89fe653544 network: Add support to group links.
Link groups are similar to port ranges found in managed switches.
You can add network interfaces to a numbered group and perform operations
on all the interfaces from that group at once.
2020-05-15 15:27:07 +02:00
Zbigniew Jędrzejewski-Szmek
bf896ca628
Merge pull request #15792 from poettering/repart-allocate
repart: add --size= and --empty=create options for growing/creating disk images from scratch
2020-05-15 11:40:24 +02:00
Lennart Poettering
e1e214c56b
Merge pull request #15265 from fbuihuu/mount-fixes
Mount fixes
2020-05-15 11:13:45 +02:00
Lennart Poettering
157644119b update TODO 2020-05-14 23:59:23 +02:00
Lennart Poettering
96deebbcda man: document new --empty=create and --size= switches to repart 2020-05-14 23:59:23 +02:00
Lennart Poettering
05ae606b79 test: update tests to use new repart features 2020-05-14 23:59:23 +02:00
Lennart Poettering
a26f4a49f4 repart: add support for create/growing loopback files
This adds --empty=create and --size= for creating loopback files from
scratch of a specified size, or growing loopback files to the specified
size when they already exist.

This is useful when operating on disk image files, as a manual
invocation of fallocate(1) becomes unnecessary.
2020-05-14 23:59:23 +02:00
Lennart Poettering
9a1deb8578 repart: suppress complaints about lack of BLKRRPART when operating on regular file 2020-05-14 23:01:09 +02:00
Lennart Poettering
e2d65cd299 repart: explain when we exit early and don't do a thing 2020-05-14 23:00:52 +02:00
Franck Bui
5a7c4f4f3b mount: introduce mount_is_nofail() helper 2020-04-09 15:26:21 +02:00
Franck Bui
2ec15c4f8a mount: default startup dependencies and default network ones are orthogonal
Regardless of whether a mount is setup in initrd or int the main system,
the network default dependencies _netdev should still be honored.

IOW if a mount unit use the following options "x-initrd.mount,_netdev", it
should be ordered against initrd-fs.target, network.target,
network-online.target.

/dev/vdb1 /mnt ext4 x-initrd.mount,_netdev defaults 0 0

Before this patch:

Before=umount.target initrd-fs.target
After=system.slice sysroot.mount dev-vdb1.device -.mount systemd-journald.socket blockdev@dev-vdb1.target

After this patch:

Before=initrd-fs.target umount.target
After=network-online.target -.mount blockdev@dev-vdb1.target dev-vdb1.device sysroot.mount system.slice network.target systemd-journald.socket
2020-04-09 15:26:14 +02:00
Franck Bui
61154cf953 mount: introduce mount_add_default_ordering_dependencies()
Move the handling of the usual startup/shutdown dependencies in a dedicated
funtion.

No functional change.
2020-04-09 15:25:14 +02:00
Franck Bui
b3d7aef525 automount: fix handling of default dependencies for automount units
First After=local-fs-pre.target wasn't described in the man page although it's
part of the default dependencies automatically set by pid1.

Secondly, Before=local-fs.target was only set if the automount unit was
generated from the fstab-generator because the dep was explicitly
generated. It was also not documented as a default dependency.

Fix it by managing the dep from pid1 instead.
2020-04-09 15:17:17 +02:00
Franck Bui
83cdc87094 mount: let pid1 alone handle the default dependencies for mount units
fstab-generator was also handling the default ordering dependencies for mount
units setup in initrd. To do that it was turning the defaults dependencies off
completely and ordered the mount unit against either local-fs.target or
initrd-fs.target or initrd-root-fs.target itself.

But it had the bad side effect to also remove all other default dependencies as
well. Thus if an initrd mount was using _netdev, the network dependencies were
missing.

In general fstab-generator shouldn't use DefaultDependecies=no because it can
handle only a small set of the default dependencies the rest are dealt by pid1.

So this patch makes pid1 handle all default dependencies.
2020-04-09 15:17:09 +02:00
Franck Bui
457d65932b mount: mount unit activated by automount unit should be only ordered against the automount unit
Both fstab-generator and pid1 are duplicating the handling of
"Before=local-fs.target" dependency for mount units.

fstab-generator is correctly skipping this dep if the mount unit is activated
by an automount unit.

However the condition used by pid1 was incorrect and missed the case when a mount
unit uses "x-systemd.automount" since in this case the mount unit should be
(only) ordered against its automount unit counterpart instead.
2020-04-02 10:56:30 +02:00
Franck Bui
ad8f1b0f36 generator: don't generate device dependencies for extrinsic mounts
Stop generating device dependencies for extrinsic mounts: we already exclude
extrinsic mounts from the usual start-up and shutdown dependencies but some
extra deps added by generator_write_device_deps() were remaining.
2020-04-01 17:30:34 +02:00
Franck Bui
bc9e5a4c67 fstab-util: introduce fstab_is_extrinsic() 2020-04-01 10:36:28 +02:00
Franck Bui
b862c25716 device: drop refuse_after
Scheduling devices after a given unit can be useful to start device *jobs* at a
specific time in the transaction, see commit 4195077ab4c823c.

This (hidden) change was introduced by commit eef85c4a3f8054d2.
2020-04-01 10:35:14 +02:00
22 changed files with 440 additions and 126 deletions

3
TODO
View File

@ -178,9 +178,6 @@ Features:
* systemd-repart: allow config of partition uuid
* systemd-repart: add --make= switch for fallocating a new file of the
specified size first.
* userdb: allow username prefix searches in varlink API, allow realname and
realname substr searches in varlink API

View File

@ -58,7 +58,7 @@
<itemizedlist>
<listitem><para>The root partition may be grown to cover the whole available disk space</para></listitem>
<listitem><para>A <filename>/home/</filename>, swap or <filename>/srv</filename> partition can be added in</para></listitem>
<listitem><para>A <filename>/home/</filename>, swap or <filename>/srv/</filename> partition can be added in</para></listitem>
<listitem><para>A second (or third, …) root partition may be added in, to cover A/B style setups
where a second version of the root file system is alternatingly used for implementing update
schemes. The deployed image would carry only a single partition ("A") but on first boot a second
@ -145,6 +145,12 @@
also be set explicitly, formatted as UUID via the <option>--seed=</option> option. By hashing these UUIDs
from a common seed images prepared with this tool become reproducible and the result of the algorithm
above deterministic.</para>
<para>The positional argument should specify the block device to operate on. Instead of a block device
node path a regular file may be specified too, in which case the command operates on it like it would if
a loopback block device node was specified with the file attached. If <option>--empty=create</option> is
specified the specified path is created as regular file, which is useful for generating disk images from
scratch.</para>
</refsect1>
<refsect1>
@ -165,9 +171,9 @@
<varlistentry>
<term><option>--empty=</option></term>
<listitem><para>Takes one of <literal>refuse</literal>, <literal>allow</literal>,
<literal>require</literal> or <literal>force</literal>. Controls how to operate on block devices that
are entirely empty, i.e. carry no partition table/disk label yet. If this switch is not specified the
implied default is <literal>refuse</literal>.</para>
<literal>require</literal>, <literal>force</literal> or <literal>create</literal>. Controls how to
operate on block devices that are entirely empty, i.e. carry no partition table/disk label yet. If
this switch is not specified the implied default is <literal>refuse</literal>.</para>
<para>If <literal>refuse</literal> <command>systemd-repart</command> requires that the block device
it shall operate on already carries a partition table and refuses operation if none is found. If
@ -176,7 +182,9 @@
exists so far, and refuse operation if one already exists. If <literal>force</literal> it will create
a fresh partition table unconditionally, erasing the disk fully in effect. If
<literal>force</literal> no existing partitions will be taken into account or survive the
operation. Hence: use with care, this is a great way to lose all your data.</para></listitem>
operation. Hence: use with care, this is a great way to lose all your data. If
<literal>create</literal> a new loopback file is create under the path passed via the device node
parameter, of the size indicated with <option>--size=</option>, see below.</para></listitem>
</varlistentry>
<varlistentry>
@ -186,7 +194,20 @@
the implied default. Controls whether to issue the <constant>BLKDISCARD</constant> I/O control
command on the space taken up by any added partitions or on the space in between them. Usually, it's
a good idea to issue this request since it tells the underlying hardware that the covered blocks
shall be considered empty, improving performance.</para></listitem>
shall be considered empty, improving performance. If operating on a regular file instead of a block
device node, a sparse file is generated.</para></listitem>
</varlistentry>
<varlistentry>
<term><option>--size=</option></term>
<listitem><para>Takes a size in bytes, using the usual K, M, G, T suffixes. If used the specified
device node path must refer to a regular file, which is then grown to the specified size if smaller,
before any change is made to the partition table. This is not supported if the specified node is a
block device. This switch has no effect if the file is already as large as the specified size or
larger. The specified size is implicitly rounded up to multiples of 4096. When used with
<option>--empty=create</option> this specifies the initial size of the loopback file to
create.</para></listitem>
</varlistentry>
<varlistentry>

View File

@ -86,6 +86,10 @@
<listitem><para>Automount units acquire automatic <varname>Before=</varname> and
<varname>Conflicts=</varname> on <filename>umount.target</filename> in order to be stopped during
shutdown.</para></listitem>
<listitem><para>Automount units automatically gain an <varname>After=</varname> dependency
on <filename>local-fs-pre.target</filename>, and a <varname>Before=</varname> dependency on
<filename>local-fs.target</filename>.</para></listitem>
</itemizedlist>
</refsect2>
</refsect1>

View File

@ -205,6 +205,15 @@
controlled by other applications.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><varname>Group=</varname></term>
<listitem>
<para>Link groups are similar to port ranges found in managed switches.
When network interfaces are added to a numbered group, operations on
all the interfaces from that group can be performed at once. An unsigned
integer ranges 0 to 4294967294. Default to unset.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><varname>RequiredForOnline=</varname></term>
<listitem>

View File

@ -152,6 +152,10 @@ static int automount_add_default_dependencies(Automount *a) {
if (!MANAGER_IS_SYSTEM(UNIT(a)->manager))
return 0;
r = unit_add_dependency_by_name(UNIT(a), UNIT_BEFORE, SPECIAL_LOCAL_FS_TARGET, true, UNIT_DEPENDENCY_DEFAULT);
if (r < 0)
return r;
r = unit_add_dependency_by_name(UNIT(a), UNIT_AFTER, SPECIAL_LOCAL_FS_PRE_TARGET, true, UNIT_DEPENDENCY_DEFAULT);
if (r < 0)
return r;

View File

@ -1063,7 +1063,6 @@ const UnitVTable device_vtable = {
"Device\0"
"Install\0",
.refuse_after = true,
.gc_jobs = true,
.init = device_init,

View File

@ -66,6 +66,14 @@ static bool MOUNT_STATE_WITH_PROCESS(MountState state) {
MOUNT_CLEANING);
}
static bool mount_is_automount(const MountParameters *p) {
assert(p);
return fstab_test_option(p->options,
"comment=systemd.automount\0"
"x-systemd.automount\0");
}
static bool mount_is_network(const MountParameters *p) {
assert(p);
@ -78,6 +86,15 @@ static bool mount_is_network(const MountParameters *p) {
return false;
}
static bool mount_is_nofail(const Mount *m) {
assert(m);
if (!m->from_fragment)
return false;
return fstab_test_yes_no_option(m->parameters_fragment.options, "nofail\0" "fail\0");
}
static bool mount_is_loop(const MountParameters *p) {
assert(p);
@ -400,42 +417,72 @@ static bool mount_is_extrinsic(Mount *m) {
MountParameters *p;
assert(m);
/* Returns true for all units that are "magic" and should be excluded from the usual start-up and shutdown
* dependencies. We call them "extrinsic" here, as they are generally mounted outside of the systemd dependency
* logic. We shouldn't attempt to manage them ourselves but it's fine if the user operates on them with us. */
/* Returns true for all units that are "magic" and should be excluded from the usual
* start-up and shutdown dependencies. We call them "extrinsic" here, as they are generally
* mounted outside of the systemd dependency logic. We shouldn't attempt to manage them
* ourselves but it's fine if the user operates on them with us. */
if (!MANAGER_IS_SYSTEM(UNIT(m)->manager)) /* We only automatically manage mounts if we are in system mode */
/* We only automatically manage mounts if we are in system mode */
if (!MANAGER_IS_SYSTEM(UNIT(m)->manager))
return true;
if (UNIT(m)->perpetual) /* All perpetual units never change state */
return true;
if (PATH_IN_SET(m->where, /* Don't bother with the OS data itself */
"/", /* (strictly speaking redundant: should already be covered by the perpetual flag check above) */
"/usr",
"/etc"))
return true;
if (PATH_STARTSWITH_SET(m->where,
"/run/initramfs", /* This should stay around from before we boot until after we shutdown */
"/proc", /* All of this is API VFS */
"/sys", /* … dito … */
"/dev")) /* … dito … */
return true;
/* If this is an initrd mount, and we are not in the initrd, then leave this around forever, too. */
p = get_mount_parameters(m);
if (p && fstab_test_option(p->options, "x-initrd.mount\0") && !in_initrd())
if (p && fstab_is_extrinsic(m->where, p->options))
return true;
return false;
}
static int mount_add_default_ordering_dependencies(
Mount *m,
MountParameters *p,
UnitDependencyMask mask) {
const char *after, *before, *e;
int r;
assert(m);
e = path_startswith(m->where, "/sysroot");
if (e && in_initrd()) {
/* All mounts under /sysroot need to happen later, at initrd-fs.target time. IOW,
* it's not technically part of the basic initrd filesystem itself, and so
* shouldn't inherit the default Before=local-fs.target dependency. */
after = NULL;
before = isempty(e) ? SPECIAL_INITRD_ROOT_FS_TARGET : SPECIAL_INITRD_FS_TARGET;
} else if (mount_is_network(p)) {
after = SPECIAL_REMOTE_FS_PRE_TARGET;
before = SPECIAL_REMOTE_FS_TARGET;
} else {
after = SPECIAL_LOCAL_FS_PRE_TARGET;
before = SPECIAL_LOCAL_FS_TARGET;
}
if (!mount_is_nofail(m) && !mount_is_automount(p)) {
r = unit_add_dependency_by_name(UNIT(m), UNIT_BEFORE, before, true, mask);
if (r < 0)
return r;
}
if (after) {
r = unit_add_dependency_by_name(UNIT(m), UNIT_AFTER, after, true, mask);
if (r < 0)
return r;
}
return unit_add_two_dependencies_by_name(UNIT(m), UNIT_BEFORE, UNIT_CONFLICTS,
SPECIAL_UMOUNT_TARGET, true, mask);
}
static int mount_add_default_dependencies(Mount *m) {
const char *after, *before;
UnitDependencyMask mask;
MountParameters *p;
bool nofail;
int r;
assert(m);
@ -443,9 +490,10 @@ static int mount_add_default_dependencies(Mount *m) {
if (!UNIT(m)->default_dependencies)
return 0;
/* We do not add any default dependencies to /, /usr or /run/initramfs/, since they are guaranteed to stay
* mounted the whole time, since our system is on it. Also, don't bother with anything mounted below virtual
* file systems, it's also going to be virtual, and hence not worth the effort. */
/* We do not add any default dependencies to /, /usr or /run/initramfs/, since they are
* guaranteed to stay mounted the whole time, since our system is on it. Also, don't
* bother with anything mounted below virtual file systems, it's also going to be virtual,
* and hence not worth the effort. */
if (mount_is_extrinsic(m))
return 0;
@ -454,51 +502,31 @@ static int mount_add_default_dependencies(Mount *m) {
return 0;
mask = m->from_fragment ? UNIT_DEPENDENCY_FILE : UNIT_DEPENDENCY_MOUNTINFO_DEFAULT;
nofail = m->from_fragment ? fstab_test_yes_no_option(m->parameters_fragment.options, "nofail\0" "fail\0") : false;
r = mount_add_default_ordering_dependencies(m, p, mask);
if (r < 0)
return r;
if (mount_is_network(p)) {
/* We order ourselves after network.target. This is
* primarily useful at shutdown: services that take
* down the network should order themselves before
* network.target, so that they are shut down only
* after this mount unit is stopped. */
/* We order ourselves after network.target. This is primarily useful at shutdown:
* services that take down the network should order themselves before
* network.target, so that they are shut down only after this mount unit is
* stopped. */
r = unit_add_dependency_by_name(UNIT(m), UNIT_AFTER, SPECIAL_NETWORK_TARGET, true, mask);
if (r < 0)
return r;
/* We pull in network-online.target, and order
* ourselves after it. This is useful at start-up to
* actively pull in tools that want to be started
* before we start mounting network file systems, and
* whose purpose it is to delay this until the network
* is "up". */
/* We pull in network-online.target, and order ourselves after it. This is useful
* at start-up to actively pull in tools that want to be started before we start
* mounting network file systems, and whose purpose it is to delay this until the
* network is "up". */
r = unit_add_two_dependencies_by_name(UNIT(m), UNIT_WANTS, UNIT_AFTER, SPECIAL_NETWORK_ONLINE_TARGET, true, mask);
if (r < 0)
return r;
after = SPECIAL_REMOTE_FS_PRE_TARGET;
before = SPECIAL_REMOTE_FS_TARGET;
} else {
after = SPECIAL_LOCAL_FS_PRE_TARGET;
before = SPECIAL_LOCAL_FS_TARGET;
}
if (!nofail) {
r = unit_add_dependency_by_name(UNIT(m), UNIT_BEFORE, before, true, mask);
if (r < 0)
return r;
}
r = unit_add_dependency_by_name(UNIT(m), UNIT_AFTER, after, true, mask);
if (r < 0)
return r;
r = unit_add_two_dependencies_by_name(UNIT(m), UNIT_BEFORE, UNIT_CONFLICTS, SPECIAL_UMOUNT_TARGET, true, mask);
if (r < 0)
return r;
/* If this is a tmpfs mount then we have to unmount it before we try to deactivate swaps */
if (streq_ptr(p->fstype, "tmpfs")) {
r = unit_add_dependency_by_name(UNIT(m), UNIT_AFTER, SPECIAL_SWAP_TARGET, true, mask);

View File

@ -3028,13 +3028,10 @@ int unit_add_dependency(
return 0;
}
if (d == UNIT_AFTER && UNIT_VTABLE(u)->refuse_after) {
log_unit_warning(u, "Requested dependency After=%s ignored (%s units cannot be delayed).", other->id, unit_type_to_string(u->type));
return 0;
}
if (d == UNIT_BEFORE && UNIT_VTABLE(other)->refuse_after) {
log_unit_warning(u, "Requested dependency Before=%s ignored (%s units cannot be delayed).", other->id, unit_type_to_string(other->type));
/* Note that ordering a device unit after a unit is permitted since it
* allows to start its job running timeout at a specific time. */
if (d == UNIT_BEFORE && other->type == UNIT_DEVICE) {
log_unit_warning(u, "Dependency Before=%s ignored (.device units cannot be delayed)", other->id);
return 0;
}

View File

@ -615,9 +615,6 @@ typedef struct UnitVTable {
/* True if the unit type knows a failure state, and thus can be source of an OnFailure= dependency */
bool can_fail:1;
/* True if After= dependencies should be refused */
bool refuse_after:1;
/* True if units of this type shall be startable only once and then never again */
bool once_only:1;

View File

@ -391,12 +391,6 @@ static int add_mount(
"SourcePath=%s\n",
source);
/* All mounts under /sysroot need to happen later, at initrd-fs.target time. IOW, it's not
* technically part of the basic initrd filesystem itself, and so shouldn't inherit the default
* Before=local-fs.target dependency. */
if (in_initrd() && path_startswith(where, "/sysroot"))
fprintf(f, "DefaultDependencies=no\n");
if (STRPTR_IN_SET(fstype, "nfs", "nfs4") && !(flags & AUTOMOUNT) &&
fstab_test_yes_no_option(opts, "bg\0" "fg\0")) {
/* The default retry timeout that mount.nfs uses for 'bg' mounts
@ -411,9 +405,6 @@ static int add_mount(
SET_FLAG(flags, NOFAIL, true);
}
if (!(flags & NOFAIL) && !(flags & AUTOMOUNT))
fprintf(f, "Before=%s\n", post);
if (!(flags & AUTOMOUNT) && opts) {
r = write_after(f, opts);
if (r < 0)
@ -535,8 +526,6 @@ static int add_mount(
"Documentation=man:fstab(5) man:systemd-fstab-generator(8)\n",
source);
fprintf(f, "Before=%s\n", post);
if (opts) {
r = write_after(f, opts);
if (r < 0)

View File

@ -1825,6 +1825,53 @@ int link_down(Link *link, link_netlink_message_handler_t callback) {
return 0;
}
static int link_group_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
int r;
assert(link);
if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
return 1;
r = sd_netlink_message_get_errno(m);
if (r < 0)
log_link_message_warning_errno(link, m, r, "Could not set group for the interface");
return 1;
}
static int link_set_group(Link *link) {
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL;
int r;
assert(link);
assert(link->network);
assert(link->manager);
assert(link->manager->rtnl);
if (link->network->group <= 0)
return 0;
log_link_debug(link, "Setting group");
r = sd_rtnl_message_new_link(link->manager->rtnl, &req, RTM_SETLINK, link->ifindex);
if (r < 0)
return log_link_error_errno(link, r, "Could not allocate RTM_SETLINK message: %m");
r = sd_netlink_message_append_u32(req, IFLA_GROUP, link->network->group);
if (r < 0)
return log_link_error_errno(link, r, "Could not set link group: %m");
r = netlink_call_async(link->manager->rtnl, NULL, req, link_group_handler,
link_netlink_destroy_callback, link);
if (r < 0)
return log_link_error_errno(link, r, "Could not send rtnetlink message: %m");
link_ref(link);
return 0;
}
static int link_handle_bound_to_list(Link *link) {
Link *l;
Iterator i;
@ -2819,6 +2866,10 @@ static int link_configure(Link *link) {
if (r < 0)
return r;
r = link_set_group(link);
if (r < 0)
return r;
if (link_ipv4ll_enabled(link, ADDRESS_FAMILY_IPV4 | ADDRESS_FAMILY_FALLBACK_IPV4)) {
r = ipv4ll_configure(link);
if (r < 0)

View File

@ -46,6 +46,7 @@ Match.KernelVersion, config_parse_net_condition,
Match.Architecture, config_parse_net_condition, CONDITION_ARCHITECTURE, offsetof(Network, conditions)
Link.MACAddress, config_parse_hwaddr, 0, offsetof(Network, mac)
Link.MTUBytes, config_parse_mtu, AF_UNSPEC, offsetof(Network, mtu)
Link.Group, config_parse_uint32, 0, offsetof(Network, group)
Link.ARP, config_parse_tristate, 0, offsetof(Network, arp)
Link.Multicast, config_parse_tristate, 0, offsetof(Network, multicast)
Link.AllMulticast, config_parse_tristate, 0, offsetof(Network, allmulticast)

View File

@ -247,6 +247,7 @@ struct Network {
struct ether_addr *mac;
uint32_t mtu;
uint32_t group;
int arp;
int multicast;
int allmulticast;

View File

@ -58,6 +58,7 @@ static enum {
EMPTY_ALLOW, /* allow empty disks, create partition table if necessary */
EMPTY_REQUIRE, /* require an empty disk, create a partition table */
EMPTY_FORCE, /* make disk empty, erase everything, create a partition table always */
EMPTY_CREATE, /* create disk as loopback file, create a partition table always */
} arg_empty = EMPTY_REFUSE;
static bool arg_dry_run = true;
@ -70,6 +71,7 @@ static int arg_factory_reset = -1;
static sd_id128_t arg_seed = SD_ID128_NULL;
static bool arg_randomize = false;
static int arg_pretty = -1;
static uint64_t arg_size = UINT64_MAX;
STATIC_DESTRUCTOR_REGISTER(arg_root, freep);
STATIC_DESTRUCTOR_REGISTER(arg_definitions, freep);
@ -1166,7 +1168,11 @@ static int disk_acquire_uuid(Context *context, sd_id128_t *ret) {
return 0;
}
static int context_load_partition_table(Context *context, const char *node) {
static int context_load_partition_table(
Context *context,
const char *node,
int *backing_fd) {
_cleanup_(fdisk_unref_contextp) struct fdisk_context *c = NULL;
_cleanup_(fdisk_unref_tablep) struct fdisk_table *t = NULL;
uint64_t left_boundary = UINT64_MAX, first_lba, last_lba, nsectors;
@ -1178,14 +1184,31 @@ static int context_load_partition_table(Context *context, const char *node) {
assert(context);
assert(node);
assert(backing_fd);
c = fdisk_new_context();
if (!c)
return log_oom();
r = fdisk_assign_device(c, node, arg_dry_run);
/* libfdisk doesn't have an API to operate on arbitrary fds, hence reopen the fd going via the
* /proc/self/fd/ magic path if we have an existing fd. Open the original file otherwise. */
if (*backing_fd < 0)
r = fdisk_assign_device(c, node, arg_dry_run);
else {
char procfs_path[STRLEN("/proc/self/fd/") + DECIMAL_STR_MAX(int)];
xsprintf(procfs_path, "/proc/self/fd/%i", *backing_fd);
r = fdisk_assign_device(c, procfs_path, arg_dry_run);
}
if (r < 0)
return log_error_errno(r, "Failed to open device: %m");
return log_error_errno(r, "Failed to open device '%s': %m", node);
if (*backing_fd < 0) {
/* If we have no fd referencing the device yet, make a copy of the fd now, so that we have one */
*backing_fd = fcntl(fdisk_get_devfd(c), F_DUPFD_CLOEXEC, 3);
if (*backing_fd < 0)
return log_error_errno(errno, "Failed to duplicate fdisk fd: %m");
}
/* Tell udev not to interfere while we are processing the device */
if (flock(fdisk_get_devfd(c), arg_dry_run ? LOCK_SH : LOCK_EX) < 0)
@ -1225,6 +1248,7 @@ static int context_load_partition_table(Context *context, const char *node) {
break;
case EMPTY_FORCE:
case EMPTY_CREATE:
/* Always reinitiaize the disk, don't consider what there was on the disk before */
from_scratch = true;
break;
@ -1900,8 +1924,7 @@ static int context_discard_range(Context *context, uint64_t offset, uint64_t siz
if (size <= 0)
return 0;
fd = fdisk_get_devfd(context->fdisk_context);
assert(fd >= 0);
assert_se((fd = fdisk_get_devfd(context->fdisk_context)) >= 0);
if (fstat(fd, &st) < 0)
return -errno;
@ -2256,7 +2279,7 @@ static int device_kernel_partitions_supported(int fd) {
if (fstat(fd, &st) < 0)
return log_error_errno(fd, "Failed to fstat() image file: %m");
if (!S_ISBLK(st.st_mode))
return false;
return -ENOTBLK; /* we do not log in this one special case about errors */
if (ioctl(fd, LOOP_GET_STATUS64, &info) < 0) {
@ -2461,9 +2484,11 @@ static int context_write_partition_table(
return log_error_errno(r, "Failed to write partition table: %m");
capable = device_kernel_partitions_supported(fdisk_get_devfd(context->fdisk_context));
if (capable < 0)
if (capable == -ENOTBLK)
log_debug("Not telling kernel to reread partition table, since we are not operating on a block device.");
else if (capable < 0)
return capable;
if (capable > 0) {
else if (capable > 0) {
log_info("Telling kernel to reread partition table.");
if (from_scratch)
@ -2588,8 +2613,8 @@ static int help(void) {
" -h --help Show this help\n"
" --version Show package version\n"
" --dry-run=BOOL Whether to run dry-run operation\n"
" --empty=MODE One of refuse, allow, require, force; controls how to\n"
" handle empty disks lacking partition table\n"
" --empty=MODE One of refuse, allow, require, force, create; controls\n"
" how to handle empty disks lacking partition tables\n"
" --discard=BOOL Whether to discard backing blocks for new partitions\n"
" --pretty=BOOL Whether to show pretty summary before executing operation\n"
" --factory-reset=BOOL Whether to remove data partitions before recreating\n"
@ -2598,6 +2623,7 @@ static int help(void) {
" --root=PATH Operate relative to root path\n"
" --definitions=DIR Find partitions in specified directory\n"
" --seed=UUID 128bit seed UUID to derive all UUIDs from\n"
" --size=BYTES Grow loopback file to specified size\n"
"\nSee the %s for details.\n"
, program_invocation_short_name
, ansi_highlight(), ansi_normal()
@ -2620,6 +2646,7 @@ static int parse_argv(int argc, char *argv[]) {
ARG_SEED,
ARG_PRETTY,
ARG_DEFINITIONS,
ARG_SIZE,
};
static const struct option options[] = {
@ -2634,10 +2661,11 @@ static int parse_argv(int argc, char *argv[]) {
{ "seed", required_argument, NULL, ARG_SEED },
{ "pretty", required_argument, NULL, ARG_PRETTY },
{ "definitions", required_argument, NULL, ARG_DEFINITIONS },
{ "size", required_argument, NULL, ARG_SIZE },
{}
};
int c, r;
int c, r, dry_run = -1;
assert(argc >= 0);
assert(argv);
@ -2657,7 +2685,7 @@ static int parse_argv(int argc, char *argv[]) {
if (r < 0)
return log_error_errno(r, "Failed to parse --dry-run= parameter: %s", optarg);
arg_dry_run = r;
dry_run = r;
break;
case ARG_EMPTY:
@ -2669,7 +2697,14 @@ static int parse_argv(int argc, char *argv[]) {
arg_empty = EMPTY_REQUIRE;
else if (streq(optarg, "force"))
arg_empty = EMPTY_FORCE;
else
else if (streq(optarg, "create")) {
arg_empty = EMPTY_CREATE;
if (dry_run < 0)
dry_run = false; /* Imply --dry-run=no if we create the loopback file
* anew. After all we cannot really break anyone's
* partition tables that way. */
} else
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"Failed to parse --empty= parameter: %s", optarg);
break;
@ -2730,6 +2765,27 @@ static int parse_argv(int argc, char *argv[]) {
return r;
break;
case ARG_SIZE: {
uint64_t parsed, rounded;
r = parse_size(optarg, 1024, &parsed);
if (r < 0)
return log_error_errno(r, "Failed to parse --size= parameter: %s", optarg);
rounded = round_up_size(parsed, 4096);
if (rounded == 0)
return log_error_errno(SYNTHETIC_ERRNO(ERANGE), "Specified image size too small, refusing.");
if (rounded == UINT64_MAX)
return log_error_errno(SYNTHETIC_ERRNO(ERANGE), "Specified image size too large, refusing.");
if (rounded != parsed)
log_warning("Specified size is not a multiple of 4096, rounding up automatically. (%" PRIu64 " → %" PRIu64 ")",
parsed, rounded);
arg_size = rounded;
break;
}
case '?':
return -EINVAL;
@ -2741,14 +2797,27 @@ static int parse_argv(int argc, char *argv[]) {
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"Expected at most one argument, the path to the block device.");
if (arg_factory_reset > 0 && IN_SET(arg_empty, EMPTY_FORCE, EMPTY_REQUIRE))
if (arg_factory_reset > 0 && IN_SET(arg_empty, EMPTY_FORCE, EMPTY_REQUIRE, EMPTY_CREATE))
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"Combination of --factory-reset=yes and --empty=force/--empty=require is invalid.");
"Combination of --factory-reset=yes and --empty=force/--empty=require/--empty=create is invalid.");
if (arg_can_factory_reset)
arg_dry_run = true;
arg_dry_run = true; /* When --can-factory-reset is specified we don't make changes, hence
* non-dry-run mode makes no sense. Thus, imply dry run mode so that we
* open things strictly read-only. */
else if (dry_run >= 0)
arg_dry_run = dry_run;
if (arg_empty == EMPTY_CREATE && arg_size == UINT64_MAX)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"If --empty=create is specified, --size= must be specified, too.");
arg_node = argc > optind ? argv[optind] : NULL;
if (IN_SET(arg_empty, EMPTY_FORCE, EMPTY_REQUIRE, EMPTY_CREATE) && !arg_node)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"A path to a device node or loopback file must be specified when --empty=force, --empty=require or --empty=create are used.");
return 1;
}
@ -2815,12 +2884,16 @@ static int remove_efi_variable_factory_reset(void) {
return 0;
}
static int acquire_root_devno(const char *p, int mode, char **ret) {
static int acquire_root_devno(const char *p, int mode, char **ret, int *ret_fd) {
_cleanup_close_ int fd = -1;
struct stat st;
dev_t devno;
dev_t devno, fd_devno = (mode_t) -1;
int r;
assert(p);
assert(ret);
assert(ret_fd);
fd = open(p, mode);
if (fd < 0)
return -errno;
@ -2836,23 +2909,23 @@ static int acquire_root_devno(const char *p, int mode, char **ret) {
return log_oom();
*ret = s;
*ret_fd = TAKE_FD(fd);
return 0;
}
if (S_ISBLK(st.st_mode))
devno = st.st_rdev;
fd_devno = devno = st.st_rdev;
else if (S_ISDIR(st.st_mode)) {
devno = st.st_dev;
if (major(st.st_dev) == 0) {
if (major(devno) == 0) {
r = btrfs_get_block_device_fd(fd, &devno);
if (r == -ENOTTY) /* not btrfs */
return -ENODEV;
if (r < 0)
return r;
}
} else
return -ENOTBLK;
@ -2866,21 +2939,50 @@ static int acquire_root_devno(const char *p, int mode, char **ret) {
if (r < 0)
log_debug_errno(r, "Failed to find whole disk block device for '%s', ignoring: %m", p);
return device_path_make_canonical(S_IFBLK, devno, ret);
r = device_path_make_canonical(S_IFBLK, devno, ret);
if (r < 0)
return log_debug_errno(r, "Failed to determine canonical path for '%s': %m", p);
/* Only if we still lock at the same block device we can reuse the fd. Otherwise return an
* invalidated fd. */
*ret_fd = fd_devno != (mode_t) -1 && fd_devno == devno ? TAKE_FD(fd) : -1;
return 0;
}
static int find_root(char **ret) {
static int find_root(char **ret, int *ret_fd) {
const char *t;
int r;
assert(ret);
assert(ret_fd);
if (arg_node) {
r = acquire_root_devno(arg_node, O_RDONLY|O_CLOEXEC, ret);
if (arg_empty == EMPTY_CREATE) {
_cleanup_close_ int fd = -1;
_cleanup_free_ char *s = NULL;
s = strdup(arg_node);
if (!s)
return log_oom();
fd = open(arg_node, O_RDONLY|O_CREAT|O_EXCL|O_CLOEXEC|O_NOFOLLOW, 0777);
if (fd < 0)
return log_error_errno(errno, "Failed to create '%s': %m", arg_node);
*ret = TAKE_PTR(s);
*ret_fd = TAKE_FD(fd);
return 0;
}
r = acquire_root_devno(arg_node, O_RDONLY|O_CLOEXEC, ret, ret_fd);
if (r < 0)
return log_error_errno(r, "Failed to determine backing device of %s: %m", arg_node);
return 0;
}
assert(IN_SET(arg_empty, EMPTY_REFUSE, EMPTY_ALLOW));
/* Let's search for the root device. We look for two cases here: first in /, and then in /usr. The
* latter we check for cases where / is a tmpfs and only /usr is an actual persistent block device
* (think: volatile setups) */
@ -2898,7 +3000,7 @@ static int find_root(char **ret) {
} else
p = t;
r = acquire_root_devno(p, O_RDONLY|O_DIRECTORY|O_CLOEXEC, ret);
r = acquire_root_devno(p, O_RDONLY|O_DIRECTORY|O_CLOEXEC, ret, ret_fd);
if (r < 0) {
if (r != -ENODEV)
return log_error_errno(r, "Failed to determine backing device of %s: %m", p);
@ -2909,9 +3011,83 @@ static int find_root(char **ret) {
return log_error_errno(SYNTHETIC_ERRNO(ENODEV), "Failed to discover root block device.");
}
static int resize_backing_fd(const char *node, int *fd) {
char buf1[FORMAT_BYTES_MAX], buf2[FORMAT_BYTES_MAX];
_cleanup_close_ int writable_fd = -1;
struct stat st;
int r;
assert(node);
assert(fd);
if (arg_size == UINT64_MAX) /* Nothing to do */
return 0;
if (*fd < 0) {
/* Open the file if we haven't opened it yet. Note that we open it read-only here, just to
* keep a reference to the file we can pass around. */
*fd = open(node, O_RDONLY|O_CLOEXEC);
if (*fd < 0)
return log_error_errno(errno, "Failed to open '%s' in order to adjust size: %m", node);
}
if (fstat(*fd, &st) < 0)
return log_error_errno(errno, "Failed to stat '%s': %m", node);
r = stat_verify_regular(&st);
if (r < 0)
return log_error_errno(r, "Specified path '%s' is not a regular file, cannot resize: %m", node);
assert_se(format_bytes(buf1, sizeof(buf1), st.st_size));
assert_se(format_bytes(buf2, sizeof(buf2), arg_size));
if ((uint64_t) st.st_size >= arg_size) {
log_info("File '%s' already is of requested size or larger, not growing. (%s >= %s)", node, buf1, buf2);
return 0;
}
/* The file descriptor is read-only. In order to grow the file we need to have a writable fd. We
* reopen the file for that temporarily. We keep the writable fd only open for this operation though,
* as fdisk can't accept it anyway. */
writable_fd = fd_reopen(*fd, O_WRONLY|O_CLOEXEC);
if (writable_fd < 0)
return log_error_errno(writable_fd, "Failed to reopen backing file '%s' writable: %m", node);
if (!arg_discard) {
if (fallocate(writable_fd, 0, 0, arg_size) < 0) {
if (!ERRNO_IS_NOT_SUPPORTED(errno))
return log_error_errno(errno, "Failed to grow '%s' from %s to %s by allocation: %m",
node, buf1, buf2);
/* Fallback to truncation, if fallocate() is not supported. */
log_debug("Backing file system does not support fallocate(), falling back to ftruncate().");
} else {
if (st.st_size == 0) /* Likely regular file just created by us */
log_info("Allocated %s for '%s'.", buf2, node);
else
log_info("File '%s' grown from %s to %s by allocation.", node, buf1, buf2);
return 1;
}
}
if (ftruncate(writable_fd, arg_size) < 0)
return log_error_errno(errno, "Failed to grow '%s' from %s to %s by truncation: %m",
node, buf1, buf2);
if (st.st_size == 0) /* Likely regular file just created by us */
log_info("Sized '%s' to %s.", node, buf2);
else
log_info("File '%s' grown from %s to %s by truncation.", node, buf1, buf2);
return 1;
}
static int run(int argc, char *argv[]) {
_cleanup_(context_freep) Context* context = NULL;
_cleanup_free_ char *node = NULL;
_cleanup_close_ int backing_fd = -1;
bool from_scratch;
int r;
@ -2946,14 +3122,22 @@ static int run(int argc, char *argv[]) {
if (r < 0)
return r;
if (context->n_partitions <= 0 && arg_empty != EMPTY_FORCE)
if (context->n_partitions <= 0 && arg_empty == EMPTY_REFUSE) {
log_info("Didn't find any partition definition files, nothing to do.");
return 0;
}
r = find_root(&node);
r = find_root(&node, &backing_fd);
if (r < 0)
return r;
r = context_load_partition_table(context, node);
if (arg_size != UINT64_MAX) {
r = resize_backing_fd(node, &backing_fd);
if (r < 0)
return r;
}
r = context_load_partition_table(context, node, &backing_fd);
if (r == -EHWPOISON)
return 77; /* Special return value which means "Not GPT, so not doing anything". This isn't
* really an error when called at boot. */
@ -2982,7 +3166,7 @@ static int run(int argc, char *argv[]) {
/* Reload the reduced partition table */
context_unload_partition_table(context);
r = context_load_partition_table(context, node);
r = context_load_partition_table(context, node, &backing_fd);
if (r < 0)
return r;
}

View File

@ -8,11 +8,9 @@ D=$(mktemp --directory)
trap "rm -rf '$D'" EXIT INT QUIT PIPE
mkdir -p $D/definitions
truncate -s 1G $D/zzz
SEED=e2a40bf9-73f1-4278-9160-49c031e7aef8
$repart $D/zzz --empty=force --dry-run=no --seed=$SEED
$repart $D/zzz --empty=create --size=1G --seed=$SEED
sfdisk -d $D/zzz | grep -v -e 'sector-size' -e '^$' > $D/empty
@ -90,9 +88,7 @@ $D/zzz4 : start= 1777624, size= 131072, type=0657FD6D-A4AB-43C4-84E5-09
$D/zzz5 : start= 1908696, size= 188416, type=0FC63DAF-8483-4772-8E79-3D69D8477DE4, uuid=03477476-06AD-44E8-9EF4-BC2BD7771289, name="linux-generic"
EOF
truncate -s 2G $D/zzz
$repart $D/zzz --dry-run=no --seed=$SEED --definitions=$D/definitions
$repart $D/zzz --size=2G --dry-run=no --seed=$SEED --definitions=$D/definitions
sfdisk -d $D/zzz | grep -v -e 'sector-size' -e '^$' >$D/populated3

View File

@ -659,6 +659,10 @@ static int prepend_component(const char **p, bool usec, unsigned nesting, Calend
/* If no repeat value is specified for the µs component, then let's explicitly refuse ranges
* below 1s because our default repeat granularity is beyond that. */
/* Overflow check */
if (start > INT_MAX - repeat)
return -ERANGE;
if (usec && stop >= 0 && start + repeat > stop)
return -EINVAL;
}

View File

@ -35,6 +35,30 @@ int fstab_has_fstype(const char *fstype) {
return false;
}
bool fstab_is_extrinsic(const char *mount, const char *opts) {
/* Don't bother with the OS data itself */
if (PATH_IN_SET(mount,
"/",
"/usr",
"/etc"))
return true;
if (PATH_STARTSWITH_SET(mount,
"/run/initramfs", /* This should stay around from before we boot until after we shutdown */
"/proc", /* All of this is API VFS */
"/sys", /* … dito … */
"/dev")) /* … dito … */
return true;
/* If this is an initrd mount, and we are not in the initrd, then leave
* this around forever, too. */
if (opts && fstab_test_option(opts, "x-initrd.mount\0") && !in_initrd())
return true;
return false;
}
int fstab_is_mount_point(const char *mount) {
_cleanup_endmntent_ FILE *f = NULL;
struct mntent *m;

View File

@ -6,6 +6,7 @@
#include "macro.h"
bool fstab_is_extrinsic(const char *mount, const char *opts);
int fstab_is_mount_point(const char *mount);
int fstab_has_fstype(const char *fstype);

View File

@ -260,6 +260,9 @@ int generator_write_device_deps(
_cleanup_free_ char *node = NULL, *unit = NULL;
int r;
if (fstab_is_extrinsic(where, opts))
return 0;
if (!fstab_test_option(opts, "_netdev\0"))
return 0;

View File

@ -413,9 +413,11 @@ int link_config_apply(link_config_ctx *ctx, link_config *config,
log_warning_errno(r, "Could not set ring buffer of %s: %m", old_name);
}
r = ethtool_set_flow_control(&ctx->ethtool_fd, old_name, config->rx_flow_control, config->tx_flow_control, config->autoneg_flow_control);
if (r < 0)
log_warning_errno(r, "Could not set flow control of %s: %m", old_name);
if (config->rx_flow_control >= 0 || config->tx_flow_control >= 0 || config->autoneg_flow_control >= 0) {
r = ethtool_set_flow_control(&ctx->ethtool_fd, old_name, config->rx_flow_control, config->tx_flow_control, config->autoneg_flow_control);
if (r < 0)
log_warning_errno(r, "Could not set flow control of %s: %m", old_name);
}
r = sd_device_get_ifindex(device, &ifindex);
if (r < 0)

View File

@ -0,0 +1 @@
4:3:2147..2

View File

@ -37,6 +37,7 @@ Unmanaged=
MTUBytes=
Multicast=
MACAddress=
Group=
[BridgeFDB]
VLANId=
MACAddress=