1
0
mirror of https://github.com/systemd/systemd synced 2026-04-24 16:04:51 +02:00

Compare commits

..

24 Commits

Author SHA1 Message Date
Lennart Poettering
de425dc72c
libblkid → turn into dlopen() dependency (#39084)
Split out of #38861
2025-09-24 21:15:01 +02:00
Lennart Poettering
4b2b2f3ab7 blkid-util: add blkid_probe_lookup_value_id128() helper
And similar, add a blkid_probe_lookup_value_u64() helper
2025-09-24 18:13:10 +02:00
Lennart Poettering
c349edfe49 libblkid: turn into dlopen() based dep 2025-09-24 18:13:10 +02:00
Lennart Poettering
d71f2899bd meson: drop libblkid dep from components not using it directly 2025-09-24 18:11:12 +02:00
Yu Watanabe
77adf896ca
firstboot: some love (#39070)
This is split out of #38764.

It mostly introduces the "chrome" stuff that puts a blue at the top of
bottom of the terminal screen when going through interactive tools such
as firstboot, homed-firstboot, and (in future) systemd-sysinstall).

it also introduces a generic "prompt_loop()" helper thatn queries the
user for some option in a loop until the rsponse matches certain
requirements. It's a generalization of a function of the same name that
so far only existed in firstboot.c. The more generic version will be
reused in a later PR by homed-firstboot and by sysinstall.
2025-09-25 00:38:23 +09:00
Daan De Meyer
938442ac27 man: Add missing parentheses 2025-09-24 16:32:44 +02:00
Yu Watanabe
faa3cc2974 machine: fix wrong field name in varlink IDL
Follow-up for d5feeb373cc13d96fa66967a6bdb7461df32c920 (v258).
2025-09-24 23:23:37 +09:00
Yu Watanabe
513d91a159
boot: two trivial cleanups (#39093) 2025-09-24 23:18:00 +09:00
Lennart Poettering
d7b966ad13 firstboot: don't call this thing a "wizard"
It isn't really, it's an initial setup tool, which is what GNOME calls
their equivalent too.
2025-09-24 15:46:30 +02:00
Lennart Poettering
875a618ed3 firstboot: modernize --help output 2025-09-24 15:46:30 +02:00
Lennart Poettering
73ee723aa7 firstboot: show blue "chrome" bar at top 2025-09-24 15:46:30 +02:00
Lennart Poettering
8191bbd23c prompt-util: add helpers that paint some "chrome" on top/bottom of screen
We'll soon have three different kind of interactive "wizard"-like console
UIs: systemd-firstboot, homectl firstboot and soon systemd-sysinstall.
Let's give them a limited, recognizable visual identity, to distinguish
them from the usual console output: let's add a bit of "chrome" to the
top and bottom of the screen, that we show during ther wizards, but hide
again afterwards.

This makes use of the DECSTBM sequence that reduces the scrolling area
by chopping off blocks from the top or bottom of the screen. The
sequence is quite standard, given it has been part of VT100 already.
xterm, vte, Linux console all support it just fine.
2025-09-24 15:46:30 +02:00
Lennart Poettering
71f3f1818f macro: add simple DEFER_VOID_CALL() helper 2025-09-24 15:46:30 +02:00
Lennart Poettering
32e0af0835 pretty-print: add WITH_BUFFERED_STDOUT() helper 2025-09-24 15:46:30 +02:00
Lennart Poettering
30aeab7883 terminal-util: add terminal_get_cursor_position() helper 2025-09-24 15:46:30 +02:00
Lennart Poettering
fa350969ab prompt-util: add generic prompt loop implementation
This is a generalization of the logic in systemd-firstboot. This also
ports over firstboot.c to make use of the new generalization.
2025-09-24 15:46:30 +02:00
Lennart Poettering
74b8ab014b glyph-util: add more emojis 2025-09-24 15:45:28 +02:00
Luca Boccassi
d80af3b97b machined: add PIDFD D-Bus variants for registering/creating machines
Current methods take a numeric PID, but we know that is unreliable for
the usual reasons. Add variants that take a PIDFD instead, or a
PID + PIDFDID combination for remote users.
2025-09-24 14:11:59 +01:00
Lennart Poettering
4284ef2f95
sd-boot: terminal handling tweaks (#39026)
Let's make sd-boot's terminal handling a bit cleaner, to the point that
uefi's weird handling allows this.
2025-09-24 14:40:38 +02:00
Lennart Poettering
e27a530919 boot: let's make the one space we output early on invisible
let's place the cursor at the beginning of the line before/after, so we
know it's the first char we overwrite, and we return to the front again
right after.
2025-09-24 12:33:59 +02:00
Lennart Poettering
f417a984c9 boot: return to beginning of line when enrolling 2025-09-24 12:33:59 +02:00
Lennart Poettering
8d36341cef boot: work around ansi color issues between sd-boot, uefi and terminals
So, UEFI's color texting is a bit weird. It translates everything to
ANSI sequences, but unlike ANSI sequences it has no understanding of a
distinct "default" bg/fg color, it assumes the ansi color "0" is always
equal to white on black, but that's of course not really true, most
terminal emulators at the very least support white background too.

tianocore then also tries to be smart and suppresses ANSI color changes
from a color to itself. But if the understanding of the color is wrong
in the first place, then any color change suppression like this hurts
more than it helps.

Then in addition there are certain terminal tools that will reset the bg
color on every line break ("less" for example) to the default.

Let's deal with that and improve the situation on all fronts:

1. force out color changes by doing two color changes whenever we really
   want it.

2. on every newline force out the color change again.

with this in place, using sd-boot on a terminal emulator is a lot nicer.
2025-09-24 12:33:59 +02:00
Yu Watanabe
63dd548fb4 boot: rename ENROLL_TIMEOUT_TYPE_MAX -> ENROLL_TIMEOUT_MAX
To make it consistent with ENROLL_TIMEOUT_MIN.

Follow-up for 64376936c70ac1cba18fcdcaec8eb337d80c48a7.
2025-09-24 18:22:12 +09:00
Yu Watanabe
2e3c792baf boot: use correct format specifier for timeout
This also drops space between number and 's', like we do in format_timespan(),
and fixes spurious type mismatch between timeout_sec and timeout_remain.
2025-09-24 18:20:10 +09:00
50 changed files with 1748 additions and 588 deletions

View File

@ -63,6 +63,10 @@ node /org/freedesktop/machine1 {
in ai ifindices, in ai ifindices,
in a(sv) scope_properties, in a(sv) scope_properties,
out o path); out o path);
CreateMachineEx(in s name,
in a(sv) properties,
in a(sv) scope_properties,
out o path);
RegisterMachine(in s name, RegisterMachine(in s name,
in ay id, in ay id,
in s service, in s service,
@ -78,6 +82,9 @@ node /org/freedesktop/machine1 {
in s root_directory, in s root_directory,
in ai ifindices, in ai ifindices,
out o path); out o path);
RegisterMachineEx(in s name,
in a(sv) properties,
out o path);
UnregisterMachine(in s name); UnregisterMachine(in s name);
TerminateMachine(in s id); TerminateMachine(in s id);
KillMachine(in s name, KillMachine(in s name,
@ -216,10 +223,14 @@ node /org/freedesktop/machine1 {
<variablelist class="dbus-method" generated="True" extra-ref="CreateMachineWithNetwork()"/> <variablelist class="dbus-method" generated="True" extra-ref="CreateMachineWithNetwork()"/>
<variablelist class="dbus-method" generated="True" extra-ref="CreateMachineEx()"/>
<variablelist class="dbus-method" generated="True" extra-ref="RegisterMachine()"/> <variablelist class="dbus-method" generated="True" extra-ref="RegisterMachine()"/>
<variablelist class="dbus-method" generated="True" extra-ref="RegisterMachineWithNetwork()"/> <variablelist class="dbus-method" generated="True" extra-ref="RegisterMachineWithNetwork()"/>
<variablelist class="dbus-method" generated="True" extra-ref="RegisterMachineEx()"/>
<variablelist class="dbus-method" generated="True" extra-ref="UnregisterMachine()"/> <variablelist class="dbus-method" generated="True" extra-ref="UnregisterMachine()"/>
<variablelist class="dbus-method" generated="True" extra-ref="TerminateMachine()"/> <variablelist class="dbus-method" generated="True" extra-ref="TerminateMachine()"/>
@ -353,6 +364,31 @@ node /org/freedesktop/machine1 {
multiple times, one instance for each container/VM they manage, and are invoked as system multiple times, one instance for each container/VM they manage, and are invoked as system
services.</para> services.</para>
<para><function>RegisterMachineEx()</function> and <function>CreateMachineEx()</function> are similar
to the counterparts, but take a series of key/value pairs instead of a fixed number of parameters, to
allow for future extensions, and take a PIDFD instead of a PID for the leader parameter. The currently
supported parameters are:
<itemizedlist>
<listitem><para><literal>Id</literal> (<literal>ay</literal>): the machine UUID.</para></listitem>
<listitem><para><literal>Service</literal> (<literal>s</literal>): the service string.</para></listitem>
<listitem><para><literal>Class</literal> (<literal>s</literal>): the class string.</para></listitem>
<listitem><para><literal>LeaderPIDFD</literal> (<literal>h</literal>): A PIDFD for the leader process of the machine.
This parameter is optional. If it is specified, it is preferred over the combination of
<literal>LeaderPID</literal>
and <literal>LeaderPIDFDID</literal>.</para></listitem>
<listitem><para><literal>LeaderPID</literal> (<literal>u</literal>): A PID for the leader process of the
machine. This parameter is optional. Must be specified together with
<literal>LeaderPIDFDID</literal>.</para></listitem>
<listitem><para><literal>LeaderPIDFDID</literal> (<literal>t</literal>): A PIDFDID for the leader
process of the machine. This parameter is optional. Must be specified together with
<literal>LeaderPID</literal>.</para></listitem>
<listitem><para><literal>RootDirectory</literal> (<literal>s</literal>): The root directory of the container. This
parameter is optional and for informational purposes only.</para></listitem>
<listitem><para><literal>NetworkInterfaces</literal> (<literal>ai</literal>): An array of network
interface indices, as in
<function>CreateMachineWithNetwork()</function>. This parameter is optional.</para></listitem>
</itemizedlist></para>
<para><function>CreateMachineWithNetwork()</function> and <para><function>CreateMachineWithNetwork()</function> and
<function>RegisterMachineWithNetwork()</function> are similar to <function>CreateMachine()</function> <function>RegisterMachineWithNetwork()</function> are similar to <function>CreateMachine()</function>
and <function>RegisterMachine()</function> but take an extra argument: an array of network interface and <function>RegisterMachine()</function> but take an extra argument: an array of network interface
@ -753,6 +789,8 @@ $ gdbus introspect --system \
<para><varname>LeaderPIDFDId</varname>, <varname>Supervisor</varname>, <para><varname>LeaderPIDFDId</varname>, <varname>Supervisor</varname>,
<varname>SupervisorPIDFDId</varname>, <varname>Subgroup</varname>, and <varname>UID</varname> were added <varname>SupervisorPIDFDId</varname>, <varname>Subgroup</varname>, and <varname>UID</varname> were added
in version 258.</para> in version 258.</para>
<para><function>CreateMachineEx()</function>, and <function>RegisterMachineEx()</function> were added
in version 259.</para>
</refsect2> </refsect2>
</refsect1> </refsect1>

View File

@ -439,15 +439,26 @@
<varlistentry> <varlistentry>
<term><varname>ANSI_COLOR=</varname></term> <term><varname>ANSI_COLOR=</varname></term>
<listitem><para>A suggested presentation color when showing the OS name on the console. This should <listitem><para>A suggested presentation (foreground) text color when showing the OS name on the
be specified as string suitable for inclusion in the ESC [ m ANSI/ECMA-48 escape code for setting console. This should be specified as string suitable for inclusion in the ESC [ m ANSI/ECMA-48
graphical rendition. This field is optional.</para> escape code for setting graphical rendition. This field is optional.</para>
<para>Examples: <literal>ANSI_COLOR="0;31"</literal> for red, <literal>ANSI_COLOR="1;34"</literal> <para>Examples: <literal>ANSI_COLOR="0;31"</literal> for red, <literal>ANSI_COLOR="1;34"</literal>
for light blue, or <literal>ANSI_COLOR="0;38;2;60;110;180"</literal> for Fedora blue. for light blue, or <literal>ANSI_COLOR="0;38;2;60;110;180"</literal> for Fedora blue.
</para></listitem> </para></listitem>
</varlistentry> </varlistentry>
<varlistentry>
<term><varname>ANSI_COLOR_REVERSE=</varname></term>
<listitem><para>Similar to <varname>ANSI_COLOR=</varname>, but should encode the desired
presentation color as background color, along with a suitable foreground color. This is may be used
by console applications to set off "chrome" UI elements from the main terminal contents. This field
is optional.</para>
<xi:include href="version-info.xml" xpointer="v259"/></listitem>
</varlistentry>
<varlistentry> <varlistentry>
<term><varname>VENDOR_NAME=</varname></term> <term><varname>VENDOR_NAME=</varname></term>

View File

@ -42,7 +42,7 @@
<para>Some of the functionality is also available via the <para>Some of the functionality is also available via the
<filename>/run/systemd/io.systemd.FactoryReset</filename> Varlink service (implemented via the <filename>/run/systemd/io.systemd.FactoryReset</filename> Varlink service (implemented via the
<filename>systemd-factory-reset.socket</filename>/<filename>systemd-factory-reset@.service</filename> <filename>systemd-factory-reset.socket</filename>/<filename>systemd-factory-reset@.service</filename>
units.</para> units).</para>
<para>See <ulink url="https://systemd.io/FACTORY_RESET">Factory Reset</ulink> for an overview of the <para>See <ulink url="https://systemd.io/FACTORY_RESET">Factory Reset</ulink> for an overview of the
factory reset logic.</para> factory reset logic.</para>

View File

@ -344,6 +344,16 @@
<xi:include href="version-info.xml" xpointer="v246"/></listitem> <xi:include href="version-info.xml" xpointer="v246"/></listitem>
</varlistentry> </varlistentry>
<varlistentry>
<term><option>--chrome=</option></term>
<listitem><para>Takes a boolean argument. By default the initial setup scren will show reverse color
"chrome" bars at the top and and the bottom of the terminal screen, which may be disabled by setting
this option to false.</para>
<xi:include href="version-info.xml" xpointer="v259"/></listitem>
</varlistentry>
<xi:include href="standard-options.xml" xpointer="help" /> <xi:include href="standard-options.xml" xpointer="help" />
<xi:include href="standard-options.xml" xpointer="version" /> <xi:include href="standard-options.xml" xpointer="version" />
</variablelist> </variablelist>

View File

@ -1195,6 +1195,7 @@ libblkid = dependency('blkid',
conf.set10('HAVE_BLKID', libblkid.found()) conf.set10('HAVE_BLKID', libblkid.found())
conf.set10('HAVE_BLKID_PROBE_SET_HINT', conf.set10('HAVE_BLKID_PROBE_SET_HINT',
libblkid.found() and cc.has_function('blkid_probe_set_hint', dependencies : libblkid)) libblkid.found() and cc.has_function('blkid_probe_set_hint', dependencies : libblkid))
libblkid_cflags = libblkid.partial_dependency(includes: true, compile_args: true)
libkmod = dependency('libkmod', libkmod = dependency('libkmod',
version : '>= 15', version : '>= 15',

View File

@ -88,6 +88,12 @@ const char* glyph_full(Glyph code, bool force_utf) {
[GLYPH_SUPERHERO] = "S", [GLYPH_SUPERHERO] = "S",
[GLYPH_IDCARD] = "@", [GLYPH_IDCARD] = "@",
[GLYPH_HOME] = "^", [GLYPH_HOME] = "^",
[GLYPH_ROCKET] = "^",
[GLYPH_BROOM] = "/",
[GLYPH_KEYBOARD] = "K",
[GLYPH_CLOCK] = "O",
[GLYPH_LABEL] = "L",
[GLYPH_SHELL] = "$",
}, },
/* UTF-8 */ /* UTF-8 */
@ -155,7 +161,6 @@ const char* glyph_full(Glyph code, bool force_utf) {
[GLYPH_WARNING_SIGN] = UTF8("⚠️"), [GLYPH_WARNING_SIGN] = UTF8("⚠️"),
[GLYPH_COMPUTER_DISK] = UTF8("💽"), [GLYPH_COMPUTER_DISK] = UTF8("💽"),
[GLYPH_WORLD] = UTF8("🌍"), [GLYPH_WORLD] = UTF8("🌍"),
[GLYPH_RED_CIRCLE] = UTF8("🔴"), [GLYPH_RED_CIRCLE] = UTF8("🔴"),
[GLYPH_YELLOW_CIRCLE] = UTF8("🟡"), [GLYPH_YELLOW_CIRCLE] = UTF8("🟡"),
[GLYPH_BLUE_CIRCLE] = UTF8("🔵"), [GLYPH_BLUE_CIRCLE] = UTF8("🔵"),
@ -163,6 +168,12 @@ const char* glyph_full(Glyph code, bool force_utf) {
[GLYPH_SUPERHERO] = UTF8("🦸"), [GLYPH_SUPERHERO] = UTF8("🦸"),
[GLYPH_IDCARD] = UTF8("🪪"), [GLYPH_IDCARD] = UTF8("🪪"),
[GLYPH_HOME] = UTF8("🏠"), [GLYPH_HOME] = UTF8("🏠"),
[GLYPH_ROCKET] = UTF8("🚀"),
[GLYPH_BROOM] = UTF8("🧹"),
[GLYPH_KEYBOARD] = UTF8("⌨️"),
[GLYPH_CLOCK] = UTF8("🕗"),
[GLYPH_LABEL] = UTF8("🏷️"),
[GLYPH_SHELL] = UTF8("🐚"),
}, },
}; };

View File

@ -56,6 +56,12 @@ typedef enum Glyph {
GLYPH_SUPERHERO, GLYPH_SUPERHERO,
GLYPH_IDCARD, GLYPH_IDCARD,
GLYPH_HOME, GLYPH_HOME,
GLYPH_ROCKET,
GLYPH_BROOM,
GLYPH_KEYBOARD,
GLYPH_CLOCK,
GLYPH_LABEL,
GLYPH_SHELL,
_GLYPH_MAX, _GLYPH_MAX,
_GLYPH_INVALID = -EINVAL, _GLYPH_INVALID = -EINVAL,
} Glyph; } Glyph;

View File

@ -206,3 +206,16 @@ static inline size_t size_add(size_t x, size_t y) {
for (typeof(entry) _va_sentinel_[1] = {}, _entries_[] = { __VA_ARGS__ __VA_OPT__(,) _va_sentinel_[0] }, *_current_ = _entries_; \ for (typeof(entry) _va_sentinel_[1] = {}, _entries_[] = { __VA_ARGS__ __VA_OPT__(,) _va_sentinel_[0] }, *_current_ = _entries_; \
((long)(_current_ - _entries_) < (long)(ELEMENTSOF(_entries_) - 1)) && ({ entry = *_current_; true; }); \ ((long)(_current_ - _entries_) < (long)(ELEMENTSOF(_entries_) - 1)) && ({ entry = *_current_; true; }); \
_current_++) _current_++)
typedef void (*void_func_t)(void);
static inline void dispatch_void_func(void_func_t *f) {
assert(f);
assert(*f);
(*f)();
}
/* Inspired by Go's "defer" construct, but much more basic. This basically just calls a void function when
* the current scope is left. Doesn't do function parameters (i.e. no closures). */
#define DEFER_VOID_CALL(x) _DEFER_VOID_CALL(UNIQ, x)
#define _DEFER_VOID_CALL(uniq, x) _unused_ _cleanup_(dispatch_void_func) void_func_t UNIQ_T(defer, uniq) = (x)

View File

@ -1855,6 +1855,226 @@ int terminal_set_cursor_position(int fd, unsigned row, unsigned column) {
return loop_write(fd, cursor_position, SIZE_MAX); return loop_write(fd, cursor_position, SIZE_MAX);
} }
static int terminal_verify_same(int input_fd, int output_fd) {
assert(input_fd >= 0);
assert(output_fd >= 0);
/* Validates that the specified fds reference the same TTY */
if (input_fd != output_fd) {
struct stat sti;
if (fstat(input_fd, &sti) < 0)
return -errno;
if (!S_ISCHR(sti.st_mode)) /* TTYs are character devices */
return -ENOTTY;
struct stat sto;
if (fstat(output_fd, &sto) < 0)
return -errno;
if (!S_ISCHR(sto.st_mode))
return -ENOTTY;
if (sti.st_rdev != sto.st_rdev)
return -ENOLINK;
}
if (!isatty_safe(input_fd)) /* The check above was just for char device, but now let's ensure it's actually a tty */
return -ENOTTY;
return 0;
}
typedef enum CursorPositionState {
CURSOR_TEXT,
CURSOR_ESCAPE,
CURSOR_ROW,
CURSOR_COLUMN,
} CursorPositionState;
typedef struct CursorPositionContext {
CursorPositionState state;
unsigned row, column;
} CursorPositionContext;
static int scan_cursor_position_response(
CursorPositionContext *context,
const char *buf,
size_t size,
size_t *ret_processed) {
assert(context);
assert(buf);
assert(ret_processed);
for (size_t i = 0; i < size; i++) {
char c = buf[i];
switch (context->state) {
case CURSOR_TEXT:
context->state = c == '\x1B' ? CURSOR_ESCAPE : CURSOR_TEXT;
break;
case CURSOR_ESCAPE:
context->state = c == '[' ? CURSOR_ROW : CURSOR_TEXT;
break;
case CURSOR_ROW:
if (c == ';')
context->state = context->row > 0 ? CURSOR_COLUMN : CURSOR_TEXT;
else {
int d = undecchar(c);
/* We read a decimal character, let's suffix it to the number we so far read,
* but let's do an overflow check first. */
if (d < 0 || context->row > (UINT_MAX-d)/10)
context->state = CURSOR_TEXT;
else
context->row = context->row * 10 + d;
}
break;
case CURSOR_COLUMN:
if (c == 'R') {
if (context->column > 0) {
*ret_processed = i + 1;
return 1; /* success! */
}
context->state = CURSOR_TEXT;
} else {
int d = undecchar(c);
/* As above, add the decimal character to our column number */
if (d < 0 || context->column > (UINT_MAX-d)/10)
context->state = CURSOR_TEXT;
else
context->column = context->column * 10 + d;
}
break;
}
/* Reset any positions we might have picked up */
if (IN_SET(context->state, CURSOR_TEXT, CURSOR_ESCAPE))
context->row = context->column = 0;
}
*ret_processed = size;
return 0; /* all good, but not enough data yet */
}
int terminal_get_cursor_position(
int input_fd,
int output_fd,
unsigned *ret_row,
unsigned *ret_column) {
_cleanup_close_ int nonblock_input_fd = -EBADF;
int r;
assert(input_fd >= 0);
assert(output_fd >= 0);
if (terminal_is_dumb())
return -EOPNOTSUPP;
r = terminal_verify_same(input_fd, output_fd);
if (r < 0)
return log_debug_errno(r, "Called with distinct input/output fds: %m");
struct termios old_termios;
if (tcgetattr(input_fd, &old_termios) < 0)
return log_debug_errno(errno, "Failed to get terminal settings: %m");
struct termios new_termios = old_termios;
termios_disable_echo(&new_termios);
if (tcsetattr(input_fd, TCSANOW, &new_termios) < 0)
return log_debug_errno(errno, "Failed to set new terminal settings: %m");
/* Request cursor position (DSR/CPR) */
r = loop_write(output_fd, "\x1B[6n", SIZE_MAX);
if (r < 0)
goto finish;
/* Open a 2nd input fd, in non-blocking mode, so that we won't ever hang in read() should someone
* else process the POLLIN. */
nonblock_input_fd = r = fd_reopen(input_fd, O_RDONLY|O_CLOEXEC|O_NONBLOCK|O_NOCTTY);
if (r < 0)
goto finish;
usec_t end = usec_add(now(CLOCK_MONOTONIC), CONSOLE_REPLY_WAIT_USEC);
char buf[STRLEN("\x1B[1;1R")]; /* The shortest valid reply possible */
size_t buf_full = 0;
CursorPositionContext context = {};
for (bool first = true;; first = false) {
if (buf_full == 0) {
usec_t n = now(CLOCK_MONOTONIC);
if (n >= end) {
r = -EOPNOTSUPP;
goto finish;
}
r = fd_wait_for_event(nonblock_input_fd, POLLIN, usec_sub_unsigned(end, n));
if (r < 0)
goto finish;
if (r == 0) {
r = -EOPNOTSUPP;
goto finish;
}
/* On the first try, read multiple characters, i.e. the shortest valid
* reply. Afterwards read byte-wise, since we don't want to read too much, and
* unnecessarily drop too many characters from the input queue. */
ssize_t l = read(nonblock_input_fd, buf, first ? sizeof(buf) : 1);
if (l < 0) {
if (errno == EAGAIN)
continue;
r = -errno;
goto finish;
}
assert((size_t) l <= sizeof(buf));
buf_full = l;
}
size_t processed;
r = scan_cursor_position_response(&context, buf, buf_full, &processed);
if (r < 0)
goto finish;
assert(processed <= buf_full);
buf_full -= processed;
memmove(buf, buf + processed, buf_full);
if (r > 0) {
/* Superficial validity check */
if (context.row >= 32766 || context.column >= 32766) {
r = -ENODATA;
goto finish;
}
if (ret_row)
*ret_row = context.row;
if (ret_column)
*ret_column = context.column;
r = 0;
goto finish;
}
}
finish:
RET_GATHER(r, RET_NERRNO(tcsetattr(input_fd, TCSANOW, &old_termios)));
return r;
}
int terminal_reset_defensive(int fd, TerminalResetFlags flags) { int terminal_reset_defensive(int fd, TerminalResetFlags flags) {
int r = 0; int r = 0;
@ -1894,37 +2114,6 @@ void termios_disable_echo(struct termios *termios) {
termios->c_cc[VTIME] = 0; termios->c_cc[VTIME] = 0;
} }
static int terminal_verify_same(int input_fd, int output_fd) {
assert(input_fd >= 0);
assert(output_fd >= 0);
/* Validates that the specified fds reference the same TTY */
if (input_fd != output_fd) {
struct stat sti;
if (fstat(input_fd, &sti) < 0)
return -errno;
if (!S_ISCHR(sti.st_mode)) /* TTYs are character devices */
return -ENOTTY;
struct stat sto;
if (fstat(output_fd, &sto) < 0)
return -errno;
if (!S_ISCHR(sto.st_mode))
return -ENOTTY;
if (sti.st_rdev != sto.st_rdev)
return -ENOLINK;
}
if (!isatty_safe(input_fd)) /* The check above was just for char device, but now let's ensure it's actually a tty */
return -ENOTTY;
return 0;
}
typedef enum BackgroundColorState { typedef enum BackgroundColorState {
BACKGROUND_TEXT, BACKGROUND_TEXT,
BACKGROUND_ESCAPE, BACKGROUND_ESCAPE,
@ -2174,86 +2363,6 @@ finish:
return r; return r;
} }
typedef enum CursorPositionState {
CURSOR_TEXT,
CURSOR_ESCAPE,
CURSOR_ROW,
CURSOR_COLUMN,
} CursorPositionState;
typedef struct CursorPositionContext {
CursorPositionState state;
unsigned row, column;
} CursorPositionContext;
static int scan_cursor_position_response(
CursorPositionContext *context,
const char *buf,
size_t size,
size_t *ret_processed) {
assert(context);
assert(buf);
assert(ret_processed);
for (size_t i = 0; i < size; i++) {
char c = buf[i];
switch (context->state) {
case CURSOR_TEXT:
context->state = c == '\x1B' ? CURSOR_ESCAPE : CURSOR_TEXT;
break;
case CURSOR_ESCAPE:
context->state = c == '[' ? CURSOR_ROW : CURSOR_TEXT;
break;
case CURSOR_ROW:
if (c == ';')
context->state = context->row > 0 ? CURSOR_COLUMN : CURSOR_TEXT;
else {
int d = undecchar(c);
/* We read a decimal character, let's suffix it to the number we so far read,
* but let's do an overflow check first. */
if (d < 0 || context->row > (UINT_MAX-d)/10)
context->state = CURSOR_TEXT;
else
context->row = context->row * 10 + d;
}
break;
case CURSOR_COLUMN:
if (c == 'R') {
if (context->column > 0) {
*ret_processed = i + 1;
return 1; /* success! */
}
context->state = CURSOR_TEXT;
} else {
int d = undecchar(c);
/* As above, add the decimal character to our column number */
if (d < 0 || context->column > (UINT_MAX-d)/10)
context->state = CURSOR_TEXT;
else
context->column = context->column * 10 + d;
}
break;
}
/* Reset any positions we might have picked up */
if (IN_SET(context->state, CURSOR_TEXT, CURSOR_ESCAPE))
context->row = context->column = 0;
}
*ret_processed = size;
return 0; /* all good, but not enough data yet */
}
int terminal_get_size_by_dsr( int terminal_get_size_by_dsr(
int input_fd, int input_fd,
int output_fd, int output_fd,

View File

@ -46,6 +46,7 @@ int terminal_reset_defensive(int fd, TerminalResetFlags flags);
int terminal_reset_defensive_locked(int fd, TerminalResetFlags flags); int terminal_reset_defensive_locked(int fd, TerminalResetFlags flags);
int terminal_set_cursor_position(int fd, unsigned row, unsigned column); int terminal_set_cursor_position(int fd, unsigned row, unsigned column);
int terminal_get_cursor_position(int input_fd, int output_fd, unsigned *ret_rows, unsigned *ret_column);
int open_terminal(const char *name, int mode); int open_terminal(const char *name, int mode);

View File

@ -19,7 +19,6 @@ executables += [
], ],
'sources' : files('bless-boot.c'), 'sources' : files('bless-boot.c'),
'link_with' : boot_link_with, 'link_with' : boot_link_with,
'dependencies' : libblkid,
}, },
generator_template + { generator_template + {
'name' : 'systemd-bless-boot-generator', 'name' : 'systemd-bless-boot-generator',

View File

@ -244,7 +244,7 @@ static char16_t* update_timeout_efivar(Config *config, bool inc) {
case TIMEOUT_MENU_HIDDEN: case TIMEOUT_MENU_HIDDEN:
return xstrdup16(u"Menu hidden. Hold down key at bootup to show menu."); return xstrdup16(u"Menu hidden. Hold down key at bootup to show menu.");
default: default:
return xasprintf("Menu timeout set to %u s.", (uint32_t)config->timeout_sec_efivar); return xasprintf("Menu timeout set to %"PRIu64"s.", config->timeout_sec_efivar);
} }
} }
@ -279,7 +279,7 @@ static void print_timeout_status(const char *label, uint64_t t) {
case TIMEOUT_MENU_HIDDEN: case TIMEOUT_MENU_HIDDEN:
return (void) printf("%s: menu-hidden\n", label); return (void) printf("%s: menu-hidden\n", label);
default: default:
return (void) printf("%s: %u s\n", label, (uint32_t)t); return (void) printf("%s: %"PRIu64"s\n", label, t);
} }
} }
@ -343,7 +343,7 @@ static void print_status(Config *config, char16_t *loaded_image_path) {
printf(" reboot-on-error: %s\n", reboot_on_error_to_string(config->reboot_on_error)); printf(" reboot-on-error: %s\n", reboot_on_error_to_string(config->reboot_on_error));
printf(" secure-boot-enroll: %s\n", secure_boot_enroll_to_string(config->secure_boot_enroll)); printf(" secure-boot-enroll: %s\n", secure_boot_enroll_to_string(config->secure_boot_enroll));
printf(" secure-boot-enroll-action: %s\n", secure_boot_enroll_action_to_string(config->secure_boot_enroll_action)); printf(" secure-boot-enroll-action: %s\n", secure_boot_enroll_action_to_string(config->secure_boot_enroll_action));
printf("secure-boot-enroll-timeout-sec: %" PRIu64 "\n", config->secure_boot_enroll_timeout_sec); printf("secure-boot-enroll-timeout-sec: %"PRIu64"s\n", config->secure_boot_enroll_timeout_sec);
switch (config->console_mode) { switch (config->console_mode) {
case CONSOLE_MODE_AUTO: case CONSOLE_MODE_AUTO:
@ -477,8 +477,8 @@ static bool menu_run(
size_t x_start = 0, y_start = 0, y_status = 0, x_max, y_max; size_t x_start = 0, y_start = 0, y_status = 0, x_max, y_max;
_cleanup_strv_free_ char16_t **lines = NULL; _cleanup_strv_free_ char16_t **lines = NULL;
_cleanup_free_ char16_t *clearline = NULL, *separator = NULL, *status = NULL; _cleanup_free_ char16_t *clearline = NULL, *separator = NULL, *status = NULL;
uint64_t timeout_efivar_saved = config->timeout_sec_efivar; uint64_t timeout_efivar_saved = config->timeout_sec_efivar,
uint32_t timeout_remain = config->timeout_sec == TIMEOUT_MENU_FORCE ? 0 : config->timeout_sec; timeout_remain = config->timeout_sec == TIMEOUT_MENU_FORCE ? 0 : config->timeout_sec;
int64_t console_mode_initial = ST->ConOut->Mode->Mode, console_mode_efivar_saved = config->console_mode_efivar; int64_t console_mode_initial = ST->ConOut->Mode->Mode, console_mode_efivar_saved = config->console_mode_efivar;
size_t default_efivar_saved = config->idx_default_efivar; size_t default_efivar_saved = config->idx_default_efivar;
@ -495,8 +495,9 @@ static bool menu_run(
ST->ConIn->Reset(ST->ConIn, false); ST->ConIn->Reset(ST->ConIn, false);
ST->ConOut->EnableCursor(ST->ConOut, false); ST->ConOut->EnableCursor(ST->ConOut, false);
/* draw a single character to make ClearScreen work on some firmware */ /* Draw a single character to the beginning of a line, in order to make ClearScreen() work on certain
ST->ConOut->OutputString(ST->ConOut, (char16_t *) u" "); * broken firmware. And let's immediately move back to the beginning of the line. */
printf("\r \r");
err = console_set_mode(config->console_mode_efivar != CONSOLE_MODE_KEEP ? err = console_set_mode(config->console_mode_efivar != CONSOLE_MODE_KEEP ?
config->console_mode_efivar : config->console_mode); config->console_mode_efivar : config->console_mode);
@ -622,7 +623,7 @@ static bool menu_run(
if (timeout_remain > 0) { if (timeout_remain > 0) {
free(status); free(status);
status = xasprintf("Boot in %u s.", timeout_remain); status = xasprintf("Boot in %"PRIu64"s.", timeout_remain);
} }
if (status) { if (status) {
@ -1104,7 +1105,7 @@ static void config_defaults_load_from_file(Config *config, char *content) {
config->secure_boot_enroll_timeout_sec = ENROLL_TIMEOUT_HIDDEN; config->secure_boot_enroll_timeout_sec = ENROLL_TIMEOUT_HIDDEN;
else { else {
uint64_t u; uint64_t u;
if (!parse_number8(value, &u, NULL) || u > ENROLL_TIMEOUT_TYPE_MAX) { if (!parse_number8(value, &u, NULL) || u > ENROLL_TIMEOUT_MAX) {
log_error("Error parsing 'secure-boot-enroll-timeout-sec' config option, ignoring: %s", log_error("Error parsing 'secure-boot-enroll-timeout-sec' config option, ignoring: %s",
value); value);
continue; continue;

View File

@ -917,6 +917,37 @@ static bool handle_format_specifier(FormatContext *ctx, SpecifierContext *sp) {
} }
} }
#if SD_BOOT
static void output_string_safe(EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *this, const char16_t *s) {
assert(this);
assert(s);
/* This is a color-conscious version of ST->ConOut->OutputString(). Whenever it encounters a newline
* character, it will reset the color to our default, because some UEFI implementations/terminals
* reset the color in that case, and we want our default color to remain in effect */
int32_t saved_attribute = ST->ConOut->Mode->Attribute;
for (;;) {
const char16_t *nl = strchr16(s, '\n');
if (!nl) /* No further newline */
return (void) ST->ConOut->OutputString(ST->ConOut, (char16_t*) s);
if (nl[1] == 0) { /* Newline is at the end of the string */
(void) ST->ConOut->OutputString(ST->ConOut, (char16_t*) s);
set_attribute_safe(saved_attribute);
return;
}
/* newline is in the middle of the string */
_cleanup_free_ char16_t *x = xstrndup16(s, nl - s + 1);
(void) ST->ConOut->OutputString(ST->ConOut, x);
set_attribute_safe(saved_attribute);
s = nl + 1;
}
}
#endif
/* printf_internal is largely compatible to userspace vasprintf. Any features omitted should trigger asserts. /* printf_internal is largely compatible to userspace vasprintf. Any features omitted should trigger asserts.
* *
* Supported: * Supported:
@ -983,7 +1014,7 @@ _printf_(2, 0) static char16_t *printf_internal(EFI_STATUS status, const char *f
} }
#if SD_BOOT #if SD_BOOT
ST->ConOut->OutputString(ST->ConOut, ctx.buf); output_string_safe(ST->ConOut, ctx.buf);
#endif #endif
return mfree(ctx.dyn_buf); return mfree(ctx.dyn_buf);

View File

@ -94,7 +94,7 @@ EFI_STATUS secure_boot_enroll_at(EFI_FILE *root_dir, const char16_t *path, bool
printf("Warning: Enrolling custom Secure Boot keys might soft-brick your machine!\n"); printf("Warning: Enrolling custom Secure Boot keys might soft-brick your machine!\n");
for (;;) { for (;;) {
printf("\rEnrolling in %" PRIu64 " s, press any key to abort.", timeout_sec); printf("\rEnrolling in %"PRIu64"s, press any key to abort.", timeout_sec);
err = console_key_read(/* ret_key= */ NULL, /* timeout_usec= */ 1000 * 1000); err = console_key_read(/* ret_key= */ NULL, /* timeout_usec= */ 1000 * 1000);
if (err == EFI_NOT_READY) if (err == EFI_NOT_READY)
@ -105,6 +105,9 @@ EFI_STATUS secure_boot_enroll_at(EFI_FILE *root_dir, const char16_t *path, bool
timeout_sec--; timeout_sec--;
continue; continue;
} }
printf("\n");
if (err != EFI_SUCCESS) if (err != EFI_SUCCESS)
return log_error_status( return log_error_status(
err, err,

View File

@ -19,10 +19,10 @@ typedef enum {
} secure_boot_enroll_action; } secure_boot_enroll_action;
enum { enum {
ENROLL_TIMEOUT_HIDDEN = 0, ENROLL_TIMEOUT_HIDDEN = 0,
ENROLL_TIMEOUT_MIN = 1, ENROLL_TIMEOUT_MIN = 1,
ENROLL_TIMEOUT_DEFAULT = 15, ENROLL_TIMEOUT_DEFAULT = 15,
ENROLL_TIMEOUT_TYPE_MAX = UINT32_MAX, ENROLL_TIMEOUT_MAX = UINT32_MAX,
}; };
bool secure_boot_enabled(void); bool secure_boot_enabled(void);

View File

@ -195,16 +195,27 @@ EFI_STATUS file_read(
return file_handle_read(handle, offset, size, ret, ret_size); return file_handle_read(handle, offset, size, ret, ret_size);
} }
void set_attribute_safe(size_t attr) {
/* Various UEFI implementations suppress color changes from a color to the same color. Often, we want
* to force out the color change though, hence change the color here once, and then back. We simply
* mark the color as bright for a moment, and then revert that. */
attr ^= 0x08;
ST->ConOut->SetAttribute(ST->ConOut, attr);
attr ^= 0x08;
ST->ConOut->SetAttribute(ST->ConOut, attr);
}
void print_at(size_t x, size_t y, size_t attr, const char16_t *str) { void print_at(size_t x, size_t y, size_t attr, const char16_t *str) {
assert(str); assert(str);
ST->ConOut->SetCursorPosition(ST->ConOut, x, y); ST->ConOut->SetCursorPosition(ST->ConOut, x, y);
ST->ConOut->SetAttribute(ST->ConOut, attr); set_attribute_safe(attr);
ST->ConOut->OutputString(ST->ConOut, (char16_t *) str); ST->ConOut->OutputString(ST->ConOut, (char16_t *) str);
} }
void clear_screen(size_t attr) { void clear_screen(size_t attr) {
log_wait(); log_wait();
ST->ConOut->SetAttribute(ST->ConOut, attr); set_attribute_safe(attr);
ST->ConOut->ClearScreen(ST->ConOut); ST->ConOut->ClearScreen(ST->ConOut);
} }

View File

@ -152,6 +152,7 @@ static inline void unload_imagep(EFI_HANDLE *image) {
#define GUID_FORMAT_VAL(g) (g).Data1, (g).Data2, (g).Data3, (g).Data4[0], (g).Data4[1], \ #define GUID_FORMAT_VAL(g) (g).Data1, (g).Data2, (g).Data3, (g).Data4[0], (g).Data4[1], \
(g).Data4[2], (g).Data4[3], (g).Data4[4], (g).Data4[5], (g).Data4[6], (g).Data4[7] (g).Data4[2], (g).Data4[3], (g).Data4[4], (g).Data4[5], (g).Data4[6], (g).Data4[7]
void set_attribute_safe(size_t attr);
void print_at(size_t x, size_t y, size_t attr, const char16_t *str); void print_at(size_t x, size_t y, size_t attr, const char16_t *str);
void clear_screen(size_t attr); void clear_screen(size_t attr);

View File

@ -20,6 +20,6 @@ executables += [
], ],
'sources' : bootctl_sources, 'sources' : bootctl_sources,
'link_with' : boot_link_with, 'link_with' : boot_link_with,
'dependencies' : [libblkid, libopenssl], 'dependencies' : [libopenssl],
}, },
] ]

View File

@ -132,7 +132,6 @@ libcore_static = static_library(
implicit_include_directories : false, implicit_include_directories : false,
c_args : ['-fvisibility=default'], c_args : ['-fvisibility=default'],
dependencies : [libaudit_cflags, dependencies : [libaudit_cflags,
libblkid,
libdl, libdl,
libm, libm,
libmount, libmount,

View File

@ -45,6 +45,7 @@
#include "path-util.h" #include "path-util.h"
#include "pretty-print.h" #include "pretty-print.h"
#include "proc-cmdline.h" #include "proc-cmdline.h"
#include "prompt-util.h"
#include "runtime-scope.h" #include "runtime-scope.h"
#include "smack-util.h" #include "smack-util.h"
#include "stat-util.h" #include "stat-util.h"
@ -84,6 +85,7 @@ static bool arg_root_password_is_hashed = false;
static bool arg_welcome = true; static bool arg_welcome = true;
static bool arg_reset = false; static bool arg_reset = false;
static ImagePolicy *arg_image_policy = NULL; static ImagePolicy *arg_image_policy = NULL;
static bool arg_chrome = true;
STATIC_DESTRUCTOR_REGISTER(arg_root, freep); STATIC_DESTRUCTOR_REGISTER(arg_root, freep);
STATIC_DESTRUCTOR_REGISTER(arg_image, freep); STATIC_DESTRUCTOR_REGISTER(arg_image, freep);
@ -113,6 +115,11 @@ static void print_welcome(int rfd) {
return; return;
} }
(void) terminal_reset_defensive_locked(STDOUT_FILENO, /* flags= */ 0);
if (arg_chrome)
chrome_show("Initial Setup", /* bottom= */ NULL);
r = parse_os_release_at(rfd, r = parse_os_release_at(rfd,
"PRETTY_NAME", &pretty_name, "PRETTY_NAME", &pretty_name,
"NAME", &os_name, "NAME", &os_name,
@ -124,13 +131,10 @@ static void print_welcome(int rfd) {
pn = os_release_pretty_name(pretty_name, os_name); pn = os_release_pretty_name(pretty_name, os_name);
ac = isempty(ansi_color) ? "0" : ansi_color; ac = isempty(ansi_color) ? "0" : ansi_color;
(void) terminal_reset_defensive_locked(STDOUT_FILENO, /* flags= */ 0);
if (colors_enabled()) if (colors_enabled())
printf("\n" printf(ANSI_HIGHLIGHT "Welcome to your new installation of " ANSI_NORMAL "\x1B[%sm%s" ANSI_HIGHLIGHT "!" ANSI_NORMAL "\n", ac, pn);
ANSI_HIGHLIGHT "Welcome to your new installation of " ANSI_NORMAL "\x1B[%sm%s" ANSI_HIGHLIGHT "!" ANSI_NORMAL "\n", ac, pn);
else else
printf("\nWelcome to your new installation of %s!\n", pn); printf("Welcome to your new installation of %s!\n", pn);
putchar('\n'); putchar('\n');
if (emoji_enabled()) { if (emoji_enabled()) {
@ -144,102 +148,6 @@ static void print_welcome(int rfd) {
done = true; done = true;
} }
static int get_completions(
const char *key,
char ***ret_list,
void *userdata) {
int r;
if (!userdata) {
*ret_list = NULL;
return 0;
}
_cleanup_strv_free_ char **copy = strv_copy(userdata);
if (!copy)
return -ENOMEM;
r = strv_extend(&copy, "list");
if (r < 0)
return r;
*ret_list = TAKE_PTR(copy);
return 0;
}
static int prompt_loop(
int rfd,
const char *text,
char **l,
unsigned ellipsize_percentage,
bool (*is_valid)(int rfd, const char *name),
char **ret) {
int r;
assert(text);
assert(is_valid);
assert(ret);
for (;;) {
_cleanup_free_ char *p = NULL;
r = ask_string_full(
&p,
get_completions,
l,
strv_isempty(l) ? "%s %s (empty to skip): "
: "%s %s (empty to skip, \"list\" to list options): ",
glyph(GLYPH_TRIANGULAR_BULLET), text);
if (r < 0)
return log_error_errno(r, "Failed to query user: %m");
if (isempty(p)) {
log_info("No data entered, skipping.");
return 0;
}
if (!strv_isempty(l)) {
if (streq(p, "list")) {
r = show_menu(l,
/* n_columns= */ 3,
/* column_width= */ 20,
ellipsize_percentage,
/* grey_prefix= */ NULL,
/* with_numbers= */ true);
if (r < 0)
return log_error_errno(r, "Failed to show menu: %m");
putchar('\n');
continue;
}
unsigned u;
r = safe_atou(p, &u);
if (r >= 0) {
if (u <= 0 || u > strv_length(l)) {
log_error("Specified entry number out of range.");
continue;
}
log_info("Selected '%s'.", l[u-1]);
return free_and_strdup_warn(ret, l[u-1]);
}
}
if (is_valid(rfd, p))
return free_and_replace(*ret, p);
/* Be more helpful to the user, and give a hint what the user might have wanted to type. */
const char *best_match = strv_find_closest(l, p);
if (best_match)
log_error("Invalid data '%s', did you mean '%s'?", p, best_match);
else
log_error("Invalid data '%s'.", p);
}
}
static int should_configure(int dir_fd, const char *filename) { static int should_configure(int dir_fd, const char *filename) {
_cleanup_fclose_ FILE *passwd = NULL, *shadow = NULL; _cleanup_fclose_ FILE *passwd = NULL, *shadow = NULL;
int r; int r;
@ -309,20 +217,14 @@ static int should_configure(int dir_fd, const char *filename) {
return true; return true;
} }
static bool locale_is_installed_bool(const char *name) { static int locale_is_ok(const char *name, void *userdata) {
return locale_is_installed(name) > 0; int rfd = ASSERT_FD(PTR_TO_FD(userdata)), r;
}
static bool locale_is_ok(int rfd, const char *name) {
int r;
assert(rfd >= 0);
r = dir_fd_is_root(rfd); r = dir_fd_is_root(rfd);
if (r < 0) if (r < 0)
log_debug_errno(r, "Unable to determine if operating on host root directory, assuming we are: %m"); log_debug_errno(r, "Unable to determine if operating on host root directory, assuming we are: %m");
return r != 0 ? locale_is_installed_bool(name) : locale_is_valid(name); return r != 0 ? locale_is_installed(name) > 0 : locale_is_valid(name);
} }
static int prompt_locale(int rfd) { static int prompt_locale(int rfd) {
@ -379,16 +281,35 @@ static int prompt_locale(int rfd) {
} else { } else {
print_welcome(rfd); print_welcome(rfd);
r = prompt_loop(rfd, "Please enter the new system locale name or number", r = prompt_loop("Please enter the new system locale name or number",
locales, 60, locale_is_ok, &arg_locale); GLYPH_WORLD,
locales,
/* accepted= */ NULL,
/* ellipsize_percentage= */ 60,
/* n_columns= */ 3,
/* column_width= */ 20,
locale_is_ok,
/* refresh= */ NULL,
FD_TO_PTR(rfd),
PROMPT_MAY_SKIP|PROMPT_SHOW_MENU,
&arg_locale);
if (r < 0) if (r < 0)
return r; return r;
if (isempty(arg_locale)) if (isempty(arg_locale))
return 0; return 0;
r = prompt_loop(rfd, "Please enter the new system message locale name or number", r = prompt_loop("Please enter the new system message locale name or number",
locales, 60, locale_is_ok, &arg_locale_messages); GLYPH_WORLD,
locales,
/* accepted= */ NULL,
/* ellipsize_percentage= */ 60,
/* n_columns= */ 3,
/* column_width= */ 20,
locale_is_ok,
/* refresh= */ NULL,
FD_TO_PTR(rfd),
PROMPT_MAY_SKIP|PROMPT_SHOW_MENU,
&arg_locale_messages);
if (r < 0) if (r < 0)
return r; return r;
@ -463,20 +384,14 @@ static int process_locale(int rfd) {
return 1; return 1;
} }
static bool keymap_exists_bool(const char *name) { static int keymap_is_ok(const char* name, void *userdata) {
return keymap_exists(name) > 0; int rfd = ASSERT_FD(PTR_TO_FD(userdata)), r;
}
static bool keymap_is_ok(int rfd, const char* name) {
int r;
assert(rfd >= 0);
r = dir_fd_is_root(rfd); r = dir_fd_is_root(rfd);
if (r < 0) if (r < 0)
log_debug_errno(r, "Unable to determine if operating on host root directory, assuming we are: %m"); log_debug_errno(r, "Unable to determine if operating on host root directory, assuming we are: %m");
return r != 0 ? keymap_exists_bool(name) : keymap_is_valid(name); return r != 0 ? keymap_exists(name) > 0 : keymap_is_valid(name);
} }
static int prompt_keymap(int rfd) { static int prompt_keymap(int rfd) {
@ -509,8 +424,19 @@ static int prompt_keymap(int rfd) {
print_welcome(rfd); print_welcome(rfd);
return prompt_loop(rfd, "Please enter the new keymap name or number", return prompt_loop(
kmaps, 60, keymap_is_ok, &arg_keymap); "Please enter the new keymap name or number",
GLYPH_KEYBOARD,
kmaps,
/* accepted= */ NULL,
/* ellipsize_percentage= */ 60,
/* n_columns= */ 3,
/* column_width= */ 20,
keymap_is_ok,
/* refresh= */ NULL,
FD_TO_PTR(rfd),
PROMPT_MAY_SKIP|PROMPT_SHOW_MENU,
&arg_keymap);
} }
static int process_keymap(int rfd) { static int process_keymap(int rfd) {
@ -578,9 +504,7 @@ static int process_keymap(int rfd) {
return 1; return 1;
} }
static bool timezone_is_ok(int rfd, const char *name) { static int timezone_is_ok(const char *name, void *userdata) {
assert(rfd >= 0);
return timezone_is_valid(name, LOG_DEBUG); return timezone_is_valid(name, LOG_DEBUG);
} }
@ -612,8 +536,19 @@ static int prompt_timezone(int rfd) {
print_welcome(rfd); print_welcome(rfd);
return prompt_loop(rfd, "Please enter the new timezone name or number", return prompt_loop(
zones, 30, timezone_is_ok, &arg_timezone); "Please enter the new timezone name or number",
GLYPH_CLOCK,
zones,
/* accepted= */ NULL,
/* ellipsize_percentage= */ 30,
/* n_columns= */ 3,
/* column_width= */ 20,
timezone_is_ok,
/* refresh= */ NULL,
FD_TO_PTR(rfd),
PROMPT_MAY_SKIP|PROMPT_SHOW_MENU,
&arg_timezone);
} }
static int process_timezone(int rfd) { static int process_timezone(int rfd) {
@ -677,9 +612,7 @@ static int process_timezone(int rfd) {
return 0; return 0;
} }
static bool hostname_is_ok(int rfd, const char *name) { static int hostname_is_ok(const char *name, void *userdata) {
assert(rfd >= 0);
return hostname_is_valid(name, VALID_HOSTNAME_TRAILING_DOT); return hostname_is_valid(name, VALID_HOSTNAME_TRAILING_DOT);
} }
@ -698,8 +631,18 @@ static int prompt_hostname(int rfd) {
print_welcome(rfd); print_welcome(rfd);
r = prompt_loop(rfd, "Please enter the new hostname", r = prompt_loop("Please enter the new hostname",
NULL, 0, hostname_is_ok, &arg_hostname); GLYPH_LABEL,
/* menu= */ NULL,
/* accepted= */ NULL,
/* ellipsize_percentage= */ 100,
/* n_columns= */ 3,
/* column_width= */ 20,
hostname_is_ok,
/* refresh= */ NULL,
FD_TO_PTR(rfd),
PROMPT_MAY_SKIP,
&arg_hostname);
if (r < 0) if (r < 0)
return r; return r;
@ -796,8 +739,8 @@ static int prompt_root_password(int rfd) {
print_welcome(rfd); print_welcome(rfd);
msg1 = strjoina(glyph(GLYPH_TRIANGULAR_BULLET), " Please enter the new root password (empty to skip):"); msg1 = strjoina("Please enter the new root password (empty to skip):");
msg2 = strjoina(glyph(GLYPH_TRIANGULAR_BULLET), " Please enter the new root password again:"); msg2 = strjoina("Please enter the new root password again:");
suggest_passwords(); suggest_passwords();
@ -868,8 +811,8 @@ static int find_shell(int rfd, const char *path) {
return 0; return 0;
} }
static bool shell_is_ok(int rfd, const char *path) { static int shell_is_ok(const char *path, void *userdata) {
assert(rfd >= 0); int rfd = ASSERT_FD(PTR_TO_FD(userdata));
return find_shell(rfd, path) >= 0; return find_shell(rfd, path) >= 0;
} }
@ -897,8 +840,19 @@ static int prompt_root_shell(int rfd) {
print_welcome(rfd); print_welcome(rfd);
return prompt_loop(rfd, "Please enter the new root shell", return prompt_loop(
NULL, 0, shell_is_ok, &arg_root_shell); "Please enter the new root shell",
GLYPH_SHELL,
/* menu= */ NULL,
/* accepted= */ NULL,
/* ellipsize_percentage= */ 0,
/* n_columns= */ 3,
/* column_width= */ 20,
shell_is_ok,
/* refresh= */ NULL,
FD_TO_PTR(rfd),
PROMPT_MAY_SKIP,
&arg_root_shell);
} }
static int write_root_passwd(int rfd, int etc_fd, const char *password, const char *shell) { static int write_root_passwd(int rfd, int etc_fd, const char *password, const char *shell) {
@ -1254,8 +1208,8 @@ static int help(void) {
if (r < 0) if (r < 0)
return log_oom(); return log_oom();
printf("%s [OPTIONS...]\n\n" printf("%1$s [OPTIONS...]\n"
"Configures basic settings of the system.\n\n" "\n%3$sConfigures basic settings of the system.%4$s\n\n"
" -h --help Show this help\n" " -h --help Show this help\n"
" --version Show package version\n" " --version Show package version\n"
" --root=PATH Operate on an alternate filesystem root\n" " --root=PATH Operate on an alternate filesystem root\n"
@ -1290,10 +1244,14 @@ static int help(void) {
" --force Overwrite existing files\n" " --force Overwrite existing files\n"
" --delete-root-password Delete root password\n" " --delete-root-password Delete root password\n"
" --welcome=no Disable the welcome text\n" " --welcome=no Disable the welcome text\n"
" --chrome=no Don't show color bar at top and bottom of\n"
" terminal\n"
" --reset Remove existing files\n" " --reset Remove existing files\n"
"\nSee the %s for details.\n", "\nSee the %2$s for details.\n",
program_invocation_short_name, program_invocation_short_name,
link); link,
ansi_highlight(),
ansi_normal());
return 0; return 0;
} }
@ -1333,6 +1291,7 @@ static int parse_argv(int argc, char *argv[]) {
ARG_FORCE, ARG_FORCE,
ARG_DELETE_ROOT_PASSWORD, ARG_DELETE_ROOT_PASSWORD,
ARG_WELCOME, ARG_WELCOME,
ARG_CHROME,
ARG_RESET, ARG_RESET,
}; };
@ -1370,6 +1329,7 @@ static int parse_argv(int argc, char *argv[]) {
{ "force", no_argument, NULL, ARG_FORCE }, { "force", no_argument, NULL, ARG_FORCE },
{ "delete-root-password", no_argument, NULL, ARG_DELETE_ROOT_PASSWORD }, { "delete-root-password", no_argument, NULL, ARG_DELETE_ROOT_PASSWORD },
{ "welcome", required_argument, NULL, ARG_WELCOME }, { "welcome", required_argument, NULL, ARG_WELCOME },
{ "chrome", required_argument, NULL, ARG_CHROME },
{ "reset", no_argument, NULL, ARG_RESET }, { "reset", no_argument, NULL, ARG_RESET },
{} {}
}; };
@ -1579,6 +1539,13 @@ static int parse_argv(int argc, char *argv[]) {
arg_welcome = r; arg_welcome = r;
break; break;
case ARG_CHROME:
r = parse_boolean_argument("--chrome=", optarg, &arg_chrome);
if (r < 0)
return r;
break;
case ARG_RESET: case ARG_RESET:
arg_reset = true; arg_reset = true;
break; break;
@ -1723,15 +1690,16 @@ static int run(int argc, char *argv[]) {
} }
LOG_SET_PREFIX(arg_image ?: arg_root); LOG_SET_PREFIX(arg_image ?: arg_root);
DEFER_VOID_CALL(chrome_hide);
/* We check these conditions here instead of in parse_argv() so that we can take the root directory /* We check these conditions here instead of in parse_argv() so that we can take the root directory
* into account. */ * into account. */
if (arg_keymap && !keymap_is_ok(rfd, arg_keymap)) if (arg_keymap && !keymap_is_ok(arg_keymap, FD_TO_PTR(rfd)))
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Keymap %s is not installed.", arg_keymap); return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Keymap %s is not installed.", arg_keymap);
if (arg_locale && !locale_is_ok(rfd, arg_locale)) if (arg_locale && !locale_is_ok(arg_locale, FD_TO_PTR(rfd)))
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Locale %s is not installed.", arg_locale); return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Locale %s is not installed.", arg_locale);
if (arg_locale_messages && !locale_is_ok(rfd, arg_locale_messages)) if (arg_locale_messages && !locale_is_ok(arg_locale_messages, FD_TO_PTR(rfd)))
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Locale %s is not installed.", arg_locale_messages); return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Locale %s is not installed.", arg_locale_messages);
if (arg_root_shell) { if (arg_root_shell) {

View File

@ -5,6 +5,5 @@ executables += [
'name' : 'systemd-gpt-auto-generator', 'name' : 'systemd-gpt-auto-generator',
'conditions' : ['HAVE_BLKID'], 'conditions' : ['HAVE_BLKID'],
'sources' : files('gpt-auto-generator.c'), 'sources' : files('gpt-auto-generator.c'),
'dependencies' : libblkid,
}, },
] ]

View File

@ -135,7 +135,7 @@ static int probe_file_system_by_fd(
sd_id128_t *ret_uuid) { sd_id128_t *ret_uuid) {
_cleanup_(blkid_free_probep) blkid_probe b = NULL; _cleanup_(blkid_free_probep) blkid_probe b = NULL;
const char *fstype = NULL, *uuid = NULL; const char *fstype = NULL;
sd_id128_t id; sd_id128_t id;
int r; int r;
@ -143,20 +143,24 @@ static int probe_file_system_by_fd(
assert(ret_fstype); assert(ret_fstype);
assert(ret_uuid); assert(ret_uuid);
b = blkid_new_probe(); r = dlopen_libblkid();
if (r < 0)
return r;
b = sym_blkid_new_probe();
if (!b) if (!b)
return -ENOMEM; return -ENOMEM;
errno = 0; errno = 0;
r = blkid_probe_set_device(b, fd, 0, 0); r = sym_blkid_probe_set_device(b, fd, 0, 0);
if (r != 0) if (r != 0)
return errno_or_else(ENOMEM); return errno_or_else(ENOMEM);
(void) blkid_probe_enable_superblocks(b, 1); (void) sym_blkid_probe_enable_superblocks(b, 1);
(void) blkid_probe_set_superblocks_flags(b, BLKID_SUBLKS_TYPE|BLKID_SUBLKS_UUID); (void) sym_blkid_probe_set_superblocks_flags(b, BLKID_SUBLKS_TYPE|BLKID_SUBLKS_UUID);
errno = 0; errno = 0;
r = blkid_do_safeprobe(b); r = sym_blkid_do_safeprobe(b);
if (r == _BLKID_SAFEPROBE_ERROR) if (r == _BLKID_SAFEPROBE_ERROR)
return errno_or_else(EIO); return errno_or_else(EIO);
if (IN_SET(r, _BLKID_SAFEPROBE_AMBIGUOUS, _BLKID_SAFEPROBE_NOT_FOUND)) if (IN_SET(r, _BLKID_SAFEPROBE_AMBIGUOUS, _BLKID_SAFEPROBE_NOT_FOUND))
@ -164,15 +168,13 @@ static int probe_file_system_by_fd(
assert(r == _BLKID_SAFEPROBE_FOUND); assert(r == _BLKID_SAFEPROBE_FOUND);
(void) blkid_probe_lookup_value(b, "TYPE", &fstype, NULL); (void) sym_blkid_probe_lookup_value(b, "TYPE", &fstype, NULL);
if (!fstype) if (!fstype)
return -ENOPKG; return -ENOPKG;
(void) blkid_probe_lookup_value(b, "UUID", &uuid, NULL); r = blkid_probe_lookup_value_id128(b, "UUID", &id);
if (!uuid) if (r == -ENXIO)
return -ENOPKG; return -ENOPKG;
r = sd_id128_from_string(uuid, &id);
if (r < 0) if (r < 0)
return r; return r;
@ -674,22 +676,26 @@ static int luks_validate(
assert(ret_offset); assert(ret_offset);
assert(ret_size); assert(ret_size);
b = blkid_new_probe(); r = dlopen_libblkid();
if (r < 0)
return r;
b = sym_blkid_new_probe();
if (!b) if (!b)
return -ENOMEM; return -ENOMEM;
errno = 0; errno = 0;
r = blkid_probe_set_device(b, fd, 0, 0); r = sym_blkid_probe_set_device(b, fd, 0, 0);
if (r != 0) if (r != 0)
return errno_or_else(ENOMEM); return errno_or_else(ENOMEM);
(void) blkid_probe_enable_superblocks(b, 1); (void) sym_blkid_probe_enable_superblocks(b, 1);
(void) blkid_probe_set_superblocks_flags(b, BLKID_SUBLKS_TYPE); (void) sym_blkid_probe_set_superblocks_flags(b, BLKID_SUBLKS_TYPE);
(void) blkid_probe_enable_partitions(b, 1); (void) sym_blkid_probe_enable_partitions(b, 1);
(void) blkid_probe_set_partitions_flags(b, BLKID_PARTS_ENTRY_DETAILS); (void) sym_blkid_probe_set_partitions_flags(b, BLKID_PARTS_ENTRY_DETAILS);
errno = 0; errno = 0;
r = blkid_do_safeprobe(b); r = sym_blkid_do_safeprobe(b);
if (r == _BLKID_SAFEPROBE_ERROR) if (r == _BLKID_SAFEPROBE_ERROR)
return errno_or_else(EIO); return errno_or_else(EIO);
if (IN_SET(r, _BLKID_SAFEPROBE_AMBIGUOUS, _BLKID_SAFEPROBE_NOT_FOUND)) if (IN_SET(r, _BLKID_SAFEPROBE_AMBIGUOUS, _BLKID_SAFEPROBE_NOT_FOUND))
@ -697,7 +703,7 @@ static int luks_validate(
assert(r == _BLKID_SAFEPROBE_FOUND); assert(r == _BLKID_SAFEPROBE_FOUND);
(void) blkid_probe_lookup_value(b, "TYPE", &fstype, NULL); (void) sym_blkid_probe_lookup_value(b, "TYPE", &fstype, NULL);
if (streq_ptr(fstype, "crypto_LUKS")) { if (streq_ptr(fstype, "crypto_LUKS")) {
/* Directly a LUKS image */ /* Directly a LUKS image */
*ret_offset = 0; *ret_offset = 0;
@ -707,17 +713,17 @@ static int luks_validate(
} else if (fstype) } else if (fstype)
return -ENOPKG; return -ENOPKG;
(void) blkid_probe_lookup_value(b, "PTTYPE", &pttype, NULL); (void) sym_blkid_probe_lookup_value(b, "PTTYPE", &pttype, NULL);
if (!streq_ptr(pttype, "gpt")) if (!streq_ptr(pttype, "gpt"))
return -ENOPKG; return -ENOPKG;
errno = 0; errno = 0;
pl = blkid_probe_get_partitions(b); pl = sym_blkid_probe_get_partitions(b);
if (!pl) if (!pl)
return errno_or_else(ENOMEM); return errno_or_else(ENOMEM);
errno = 0; errno = 0;
n = blkid_partlist_numof_partitions(pl); n = sym_blkid_partlist_numof_partitions(pl);
if (n < 0) if (n < 0)
return errno_or_else(EIO); return errno_or_else(EIO);
@ -726,14 +732,14 @@ static int luks_validate(
blkid_partition pp; blkid_partition pp;
errno = 0; errno = 0;
pp = blkid_partlist_get_partition(pl, i); pp = sym_blkid_partlist_get_partition(pl, i);
if (!pp) if (!pp)
return errno_or_else(EIO); return errno_or_else(EIO);
if (sd_id128_string_equal(blkid_partition_get_type_string(pp), SD_GPT_USER_HOME) <= 0) if (sd_id128_string_equal(sym_blkid_partition_get_type_string(pp), SD_GPT_USER_HOME) <= 0)
continue; continue;
if (!streq_ptr(blkid_partition_get_name(pp), label)) if (!streq_ptr(sym_blkid_partition_get_name(pp), label))
continue; continue;
r = blkid_partition_get_uuid_id128(pp, &id); r = blkid_partition_get_uuid_id128(pp, &id);
@ -745,8 +751,8 @@ static int luks_validate(
if (found) if (found)
return -ENOPKG; return -ENOPKG;
offset = blkid_partition_get_start(pp); offset = sym_blkid_partition_get_start(pp);
size = blkid_partition_get_size(pp); size = sym_blkid_partition_get_size(pp);
found_partition_uuid = id; found_partition_uuid = id;
found = true; found = true;

View File

@ -81,7 +81,7 @@ executables += [
libshared_fdisk libshared_fdisk
], ],
'dependencies' : [ 'dependencies' : [
libblkid, libblkid_cflags,
libcrypt, libcrypt,
libfdisk, libfdisk,
libopenssl, libopenssl,

View File

@ -33,6 +33,7 @@
#include "operation.h" #include "operation.h"
#include "os-util.h" #include "os-util.h"
#include "path-util.h" #include "path-util.h"
#include "socket-util.h"
#include "string-util.h" #include "string-util.h"
#include "strv.h" #include "strv.h"
#include "unit-def.h" #include "unit-def.h"
@ -226,11 +227,140 @@ static int method_list_machines(sd_bus_message *message, void *userdata, sd_bus_
return sd_bus_message_send(reply); return sd_bus_message_send(reply);
} }
static int machine_add_from_params(
Manager *manager,
sd_bus_message *message,
const char *polkit_action,
const char *name,
MachineClass c,
sd_id128_t id,
const char *service,
PidRef *leader_pidref,
PidRef *supervisor_pidref,
const char *root_directory,
const int32_t *netif,
size_t n_netif,
unsigned cid,
const char *ssh_address,
const char *ssh_private_key_path,
Machine **ret,
sd_bus_error *error) {
Machine *m;
int r;
assert(manager);
assert(message);
assert(name);
assert(ret);
if (leader_pidref->pid == 1)
return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid leader PID");
if (supervisor_pidref->pid == 1)
return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid supervisor PID");
_cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL;
r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_EUID, &creds);
if (r < 0)
return r;
uid_t uid;
r = sd_bus_creds_get_euid(creds, &uid);
if (r < 0)
return r;
/* Ensure an unprivileged user cannot claim any process they don't control as their own machine */
if (uid != 0) {
r = process_is_owned_by_uid(leader_pidref, uid);
if (r < 0)
return r;
if (r == 0)
return sd_bus_error_set(error, SD_BUS_ERROR_ACCESS_DENIED, "Only root may register machines for other users");
}
const char *details[] = {
"name", name,
"class", machine_class_to_string(c),
NULL
};
r = bus_verify_polkit_async(
message,
polkit_action,
details,
&manager->polkit_registry,
error);
if (r < 0)
return r;
if (r == 0)
return 0; /* Will call us back */
r = manager_add_machine(manager, name, &m);
if (r < 0)
return r;
m->leader = TAKE_PIDREF(*leader_pidref);
m->supervisor = TAKE_PIDREF(*supervisor_pidref);
m->class = c;
m->id = id;
m->uid = uid;
m->vsock_cid = cid;
if (!isempty(service)) {
m->service = strdup(service);
if (!m->service) {
r = -ENOMEM;
goto fail;
}
}
if (!isempty(root_directory)) {
m->root_directory = strdup(root_directory);
if (!m->root_directory) {
r = -ENOMEM;
goto fail;
}
}
if (n_netif > 0) {
assert_cc(sizeof(int32_t) == sizeof(int));
m->netif = memdup(netif, sizeof(int32_t) * n_netif);
if (!m->netif) {
r = -ENOMEM;
goto fail;
}
m->n_netif = n_netif;
}
if (!isempty(ssh_address)) {
m->ssh_address = strdup(ssh_address);
if (!m->ssh_address) {
r = -ENOMEM;
goto fail;
}
}
if (!isempty(ssh_private_key_path)) {
m->ssh_private_key_path = strdup(ssh_private_key_path);
if (!m->ssh_private_key_path) {
r = -ENOMEM;
goto fail;
}
}
*ret = m;
return 1;
fail:
machine_add_to_gc_queue(m);
return r;
}
static int method_create_or_register_machine( static int method_create_or_register_machine(
Manager *manager, Manager *manager,
sd_bus_message *message, sd_bus_message *message,
const char *polkit_action, const char *polkit_action,
bool read_network,
Machine **ret, Machine **ret,
sd_bus_error *error) { sd_bus_error *error) {
@ -240,7 +370,6 @@ static int method_create_or_register_machine(
MachineClass c; MachineClass c;
uint32_t leader; uint32_t leader;
sd_id128_t id; sd_id128_t id;
Machine *m;
size_t n_netif = 0; size_t n_netif = 0;
int r; int r;
@ -262,7 +391,7 @@ static int method_create_or_register_machine(
if (r < 0) if (r < 0)
return r; return r;
if (read_network) { if (endswith(sd_bus_message_get_member(message), "WithNetwork")) {
r = sd_bus_message_read_array(message, 'i', (const void**) &netif, &n_netif); r = sd_bus_message_read_array(message, 'i', (const void**) &netif, &n_netif);
if (r < 0) if (r < 0)
return r; return r;
@ -312,95 +441,224 @@ static int method_create_or_register_machine(
if (hashmap_get(manager->machines, name)) if (hashmap_get(manager->machines, name))
return sd_bus_error_setf(error, BUS_ERROR_MACHINE_EXISTS, "Machine '%s' already exists", name); return sd_bus_error_setf(error, BUS_ERROR_MACHINE_EXISTS, "Machine '%s' already exists", name);
_cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL; return machine_add_from_params(
r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_EUID, &creds); manager,
message,
polkit_action,
name,
c,
id,
service,
&leader_pidref,
&supervisor_pidref,
root_directory,
netif,
n_netif,
/* cid= */ 0,
/* ssh_address= */ NULL,
/* ssh_private_key_path= */ NULL,
ret,
error);
}
static int method_create_or_register_machine_ex(
Manager *manager,
sd_bus_message *message,
const char *polkit_action,
Machine **ret,
sd_bus_error *error) {
const char *name = NULL, *service = NULL, *class = NULL, *root_directory = NULL, *ssh_address = NULL, *ssh_private_key_path = NULL;
_cleanup_(pidref_done) PidRef leader_pidref = PIDREF_NULL, supervisor_pidref = PIDREF_NULL;
sd_id128_t id = SD_ID128_NULL;
const int32_t *netif = NULL;
size_t n_netif = 0;
unsigned cid = 0;
MachineClass c;
uint64_t leader_pidfdid = 0;
uint32_t leader_pid = 0;
int r, leader_pidfd = -EBADF;
assert(manager);
assert(message);
assert(ret);
r = sd_bus_message_read(message, "s", &name);
if (r < 0)
return r;
if (!hostname_is_valid(name, 0))
return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid machine name");
r = sd_bus_message_enter_container(message, 'a', "(sv)");
if (r < 0) if (r < 0)
return r; return r;
uid_t uid; for (;;) {
r = sd_bus_creds_get_euid(creds, &uid); const char *key;
if (r < 0)
return r;
/* Ensure an unprivileged user cannot claim any process they don't control as their own machine */ r = sd_bus_message_enter_container(message, 'r', "sv");
if (uid != 0) {
r = process_is_owned_by_uid(&leader_pidref, uid);
if (r < 0) if (r < 0)
return r; return r;
if (r == 0) if (r == 0)
return sd_bus_error_set(error, SD_BUS_ERROR_ACCESS_DENIED, "Only root may register machines for other users"); break;
r = sd_bus_message_read(message, "s", &key);
if (r < 0)
return r;
r = sd_bus_message_enter_container(message, 'v', NULL);
if (r < 0)
return r;
if (streq(key, "Id")) {
r = bus_message_read_id128(message, &id);
if (r < 0)
return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid machine ID parameter");
} else if (streq(key, "Service")) {
r = sd_bus_message_read(message, "s", &service);
if (r < 0)
return r;
} else if (streq(key, "Class")) {
r = sd_bus_message_read(message, "s", &class);
if (r < 0)
return r;
} else if (streq(key, "LeaderPID")) {
r = sd_bus_message_read(message, "u", &leader_pid);
if (r < 0)
return r;
} else if (streq(key, "LeaderPIDFD")) {
r = sd_bus_message_read(message, "h", &leader_pidfd);
if (r < 0)
return r;
} else if (streq(key, "LeaderPIDFDID")) {
r = sd_bus_message_read(message, "t", &leader_pidfdid);
if (r < 0)
return r;
} else if (streq(key, "RootDirectory")) {
r = sd_bus_message_read(message, "s", &root_directory);
if (r < 0)
return r;
} else if (streq(key, "NetworkInterfaces")) {
r = sd_bus_message_read_array(message, 'i', (const void**) &netif, &n_netif);
if (r < 0)
return r;
n_netif /= sizeof(int32_t);
for (size_t i = 0; i < n_netif; i++)
if (netif[i] <= 0)
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid network interface index %i", netif[i]);
} else if (streq(key, "VSockCID")) {
r = sd_bus_message_read(message, "u", &cid);
if (r < 0)
return r;
if (!VSOCK_CID_IS_REGULAR(cid))
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "JSON field 'vSockCid' is not a regular VSOCK CID.");
} else if (streq(key, "SSHAddress")) {
r = sd_bus_message_read(message, "s", &ssh_address);
if (r < 0)
return r;
} else if (streq(key, "SSHPrivateKeyPath")) {
r = sd_bus_message_read(message, "s", &ssh_private_key_path);
if (r < 0)
return r;
} else
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Unknown property '%s'", key);
r = sd_bus_message_exit_container(message);
if (r < 0)
return r;
r = sd_bus_message_exit_container(message);
if (r < 0)
return r;
} }
const char *details[] = { r = sd_bus_message_exit_container(message);
"name", name, if (r < 0)
"class", machine_class_to_string(c), return r;
NULL
};
r = bus_verify_polkit_async( if (isempty(class))
c = _MACHINE_CLASS_INVALID;
else {
c = machine_class_from_string(class);
if (c < 0)
return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid machine class parameter");
}
if (!isempty(root_directory) && (!path_is_absolute(root_directory) || !path_is_valid(root_directory)))
return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "Root directory must be empty or an absolute path");
if (hashmap_get(manager->machines, name))
return sd_bus_error_setf(error, BUS_ERROR_MACHINE_EXISTS, "Machine '%s' already exists", name);
/* If a PID is specified that's the leader, but if the client process is different from it, than that's the supervisor */
if (leader_pidfd >= 0) {
r = pidref_set_pidfd(&leader_pidref, leader_pidfd);
if (r < 0)
return sd_bus_error_set_errnof(error, r, "Failed to parse PIDFD %d: %m", leader_pidfd);
if (leader_pid > 0 && leader_pidref.pid != (pid_t) leader_pid)
return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "LeaderPID and LeaderPIDFD refer to different processes");
if (leader_pidfdid > 0) {
r = pidref_acquire_pidfd_id(&leader_pidref);
if (r >= 0 && leader_pidref.fd_id != leader_pidfdid)
return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "LeaderPIDFDID does not match the inode number of LeaderPIDFD");
}
} else if (leader_pid > 0 && leader_pidfdid > 0) {
r = pidref_set_pid_and_pidfd_id(&leader_pidref, leader_pid, leader_pidfdid);
if (r < 0)
return sd_bus_error_set_errnof(error, r, "Failed to pin process " PID_FMT " by PIDFDID %" PRIu64 ": %m", (pid_t) leader_pid, leader_pidfdid);
} else if (leader_pid > 0 || leader_pidfdid > 0)
return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "Both LeaderPID and LeaderPIDFDID must be specified to identify the leader process by PIDFDID");
if (pidref_is_set(&leader_pidref)) {
_cleanup_(pidref_done) PidRef client_pidref = PIDREF_NULL;
r = bus_query_sender_pidref(message, &client_pidref);
if (r < 0)
return sd_bus_error_set_errnof(error, r, "Failed to pin client process: %m");
if (!pidref_equal(&client_pidref, &leader_pidref))
supervisor_pidref = TAKE_PIDREF(client_pidref);
} else {
/* If no PID is specified, the client is the leader */
r = bus_query_sender_pidref(message, &leader_pidref);
if (r < 0)
return sd_bus_error_set_errnof(error, r, "Failed to pin client process: %m");
}
return machine_add_from_params(
manager,
message, message,
polkit_action, polkit_action,
details, name,
&manager->polkit_registry, c,
id,
service,
&leader_pidref,
&supervisor_pidref,
root_directory,
netif,
n_netif,
cid,
ssh_address,
ssh_private_key_path,
ret,
error); error);
if (r < 0)
return r;
if (r == 0)
return 0; /* Will call us back */
r = manager_add_machine(manager, name, &m);
if (r < 0)
return r;
m->leader = TAKE_PIDREF(leader_pidref);
m->supervisor = TAKE_PIDREF(supervisor_pidref);
m->class = c;
m->id = id;
m->uid = uid;
if (!isempty(service)) {
m->service = strdup(service);
if (!m->service) {
r = -ENOMEM;
goto fail;
}
}
if (!isempty(root_directory)) {
m->root_directory = strdup(root_directory);
if (!m->root_directory) {
r = -ENOMEM;
goto fail;
}
}
if (n_netif > 0) {
assert_cc(sizeof(int32_t) == sizeof(int));
m->netif = memdup(netif, sizeof(int32_t) * n_netif);
if (!m->netif) {
r = -ENOMEM;
goto fail;
}
m->n_netif = n_netif;
}
*ret = m;
return 1;
fail:
machine_add_to_gc_queue(m);
return r;
} }
static int method_create_machine_internal(sd_bus_message *message, bool read_network, void *userdata, sd_bus_error *error) { static int method_create_machine(sd_bus_message *message, void *userdata, sd_bus_error *error) {
Manager *manager = ASSERT_PTR(userdata); Manager *manager = ASSERT_PTR(userdata);
Machine *m = NULL; Machine *m = NULL;
int r; int r;
assert(message); assert(message);
r = method_create_or_register_machine(manager, message, "org.freedesktop.machine1.create-machine", read_network, &m, error); if (sd_bus_message_is_method_call(message, NULL, "CreateMachineEx"))
r = method_create_or_register_machine_ex(manager, message, "org.freedesktop.machine1.create-machines", &m, error);
else
r = method_create_or_register_machine(manager, message, "org.freedesktop.machine1.create-machine", &m, error);
if (r < 0) if (r < 0)
return r; return r;
if (r == 0) if (r == 0)
@ -422,15 +680,7 @@ fail:
return r; return r;
} }
static int method_create_machine_with_network(sd_bus_message *message, void *userdata, sd_bus_error *error) { static int method_register_machine(sd_bus_message *message, void *userdata, sd_bus_error *error) {
return method_create_machine_internal(message, true, userdata, error);
}
static int method_create_machine(sd_bus_message *message, void *userdata, sd_bus_error *error) {
return method_create_machine_internal(message, false, userdata, error);
}
static int method_register_machine_internal(sd_bus_message *message, bool read_network, void *userdata, sd_bus_error *error) {
Manager *manager = ASSERT_PTR(userdata); Manager *manager = ASSERT_PTR(userdata);
_cleanup_free_ char *p = NULL; _cleanup_free_ char *p = NULL;
Machine *m = NULL; Machine *m = NULL;
@ -438,7 +688,10 @@ static int method_register_machine_internal(sd_bus_message *message, bool read_n
assert(message); assert(message);
r = method_create_or_register_machine(manager, message, "org.freedesktop.machine1.register-machine", read_network, &m, error); if (sd_bus_message_is_method_call(message, NULL, "RegisterMachineEx"))
r = method_create_or_register_machine_ex(manager, message, "org.freedesktop.machine1.register-machine", &m, error);
else
r = method_create_or_register_machine(manager, message, "org.freedesktop.machine1.register-machine", &m, error);
if (r < 0) if (r < 0)
return r; return r;
if (r == 0) if (r == 0)
@ -482,14 +735,6 @@ fail:
return r; return r;
} }
static int method_register_machine_with_network(sd_bus_message *message, void *userdata, sd_bus_error *error) {
return method_register_machine_internal(message, true, userdata, error);
}
static int method_register_machine(sd_bus_message *message, void *userdata, sd_bus_error *error) {
return method_register_machine_internal(message, false, userdata, error);
}
static int redirect_method_to_machine(sd_bus_message *message, Manager *m, sd_bus_error *error, sd_bus_message_handler_t method) { static int redirect_method_to_machine(sd_bus_message *message, Manager *m, sd_bus_error *error, sd_bus_message_handler_t method) {
Machine *machine; Machine *machine;
const char *name; const char *name;
@ -969,7 +1214,12 @@ const sd_bus_vtable manager_vtable[] = {
SD_BUS_METHOD_WITH_ARGS("CreateMachineWithNetwork", SD_BUS_METHOD_WITH_ARGS("CreateMachineWithNetwork",
SD_BUS_ARGS("s", name, "ay", id, "s", service, "s", class, "u", leader, "s", root_directory, "ai", ifindices, "a(sv)", scope_properties), SD_BUS_ARGS("s", name, "ay", id, "s", service, "s", class, "u", leader, "s", root_directory, "ai", ifindices, "a(sv)", scope_properties),
SD_BUS_RESULT("o", path), SD_BUS_RESULT("o", path),
method_create_machine_with_network, method_create_machine,
SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD_WITH_ARGS("CreateMachineEx",
SD_BUS_ARGS("s", name, "a(sv)", properties, "a(sv)", scope_properties),
SD_BUS_RESULT("o", path),
method_create_machine,
SD_BUS_VTABLE_UNPRIVILEGED), SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD_WITH_ARGS("RegisterMachine", SD_BUS_METHOD_WITH_ARGS("RegisterMachine",
SD_BUS_ARGS("s", name, "ay", id, "s", service, "s", class, "u", leader, "s", root_directory), SD_BUS_ARGS("s", name, "ay", id, "s", service, "s", class, "u", leader, "s", root_directory),
@ -979,7 +1229,12 @@ const sd_bus_vtable manager_vtable[] = {
SD_BUS_METHOD_WITH_ARGS("RegisterMachineWithNetwork", SD_BUS_METHOD_WITH_ARGS("RegisterMachineWithNetwork",
SD_BUS_ARGS("s", name, "ay", id, "s", service, "s", class, "u", leader, "s", root_directory, "ai", ifindices), SD_BUS_ARGS("s", name, "ay", id, "s", service, "s", class, "u", leader, "s", root_directory, "ai", ifindices),
SD_BUS_RESULT("o", path), SD_BUS_RESULT("o", path),
method_register_machine_with_network, method_register_machine,
SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD_WITH_ARGS("RegisterMachineEx",
SD_BUS_ARGS("s", name, "a(sv)", properties),
SD_BUS_RESULT("o", path),
method_register_machine,
SD_BUS_VTABLE_UNPRIVILEGED), SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD_WITH_ARGS("UnregisterMachine", SD_BUS_METHOD_WITH_ARGS("UnregisterMachine",
SD_BUS_ARGS("s", name), SD_BUS_ARGS("s", name),

View File

@ -190,6 +190,10 @@
send_interface="org.freedesktop.machine1.Manager" send_interface="org.freedesktop.machine1.Manager"
send_member="CreateMachineWithNetwork"/> send_member="CreateMachineWithNetwork"/>
<allow send_destination="org.freedesktop.machine1"
send_interface="org.freedesktop.machine1.Manager"
send_member="CreateMachineEx"/>
<allow send_destination="org.freedesktop.machine1" <allow send_destination="org.freedesktop.machine1"
send_interface="org.freedesktop.machine1.Manager" send_interface="org.freedesktop.machine1.Manager"
send_member="RegisterMachine"/> send_member="RegisterMachine"/>
@ -198,6 +202,10 @@
send_interface="org.freedesktop.machine1.Manager" send_interface="org.freedesktop.machine1.Manager"
send_member="RegisterMachineWithNetwork"/> send_member="RegisterMachineWithNetwork"/>
<allow send_destination="org.freedesktop.machine1"
send_interface="org.freedesktop.machine1.Manager"
send_member="RegisterMachineEx"/>
<!-- org.freedesktop.machine1.Machine Method Calls --> <!-- org.freedesktop.machine1.Machine Method Calls -->
<allow send_destination="org.freedesktop.machine1" <allow send_destination="org.freedesktop.machine1"

View File

@ -47,7 +47,6 @@ executables += [
], ],
'extract' : nspawn_extract_sources, 'extract' : nspawn_extract_sources,
'dependencies' : [ 'dependencies' : [
libblkid,
libseccomp, libseccomp,
libselinux, libselinux,
], ],

View File

@ -131,6 +131,126 @@ static int can_set_coredump_receive(sd_bus *bus) {
return r >= 0; return r >= 0;
} }
static int create_or_register_machine_ex(
sd_bus *bus,
const char *machine_name,
const PidRef *pid,
const char *directory,
sd_id128_t uuid,
int local_ifindex,
const char *slice,
CustomMount *mounts,
unsigned n_mounts,
int kill_signal,
char **properties,
sd_bus_message *properties_message,
const char *service,
StartMode start_mode,
sd_bus_error *error,
bool keep_unit) {
_cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
int r;
assert(error);
r = bus_message_new_method_call(bus, &m, bus_machine_mgr, keep_unit ? "RegisterMachineEx" : "CreateMachineEx");
if (r < 0)
return bus_log_create_error(r);
r = sd_bus_message_append(m, "s", machine_name);
if (r < 0)
return bus_log_create_error(r);
r = sd_bus_message_open_container(m, 'a', "(sv)");
if (r < 0)
return bus_log_create_error(r);
r = sd_bus_message_append(
m,
"(sv)(sv)(sv)",
"Id", "ay", SD_BUS_MESSAGE_APPEND_ID128(uuid),
"Service", "s", service,
"Class", "s", "container");
if (r < 0)
return bus_log_create_error(r);
if (pidref_is_set(pid)) {
if (pid->fd >= 0) {
r = sd_bus_message_append(m, "(sv)", "LeaderPIDFD", "h", pid->fd);
if (r < 0)
return bus_log_create_error(r);
}
if (pid->fd_id > 0) {
r = sd_bus_message_append(m, "(sv)", "LeaderPIDFDID", "t", pid->fd_id);
if (r < 0)
return bus_log_create_error(r);
r = sd_bus_message_append(m, "(sv)", "LeaderPID", "u", pid->pid);
if (r < 0)
return bus_log_create_error(r);
}
}
if (!isempty(directory)) {
r = sd_bus_message_append(m, "(sv)", "RootDirectory", "s", directory);
if (r < 0)
return bus_log_create_error(r);
}
if (local_ifindex > 0) {
r = sd_bus_message_append(m, "(sv)", "NetworkInterfaces", "ai", 1, local_ifindex);
if (r < 0)
return bus_log_create_error(r);
}
r = sd_bus_message_close_container(m);
if (r < 0)
return bus_log_create_error(r);
if (!keep_unit) {
r = sd_bus_message_open_container(m, 'a', "(sv)");
if (r < 0)
return bus_log_create_error(r);
if (!isempty(slice)) {
r = sd_bus_message_append(m, "(sv)", "Slice", "s", slice);
if (r < 0)
return bus_log_create_error(r);
}
r = append_controller_property(bus, m);
if (r < 0)
return r;
r = append_machine_properties(
m,
mounts,
n_mounts,
kill_signal,
start_mode == START_BOOT && can_set_coredump_receive(bus) > 0);
if (r < 0)
return r;
if (properties_message) {
r = sd_bus_message_copy(m, properties_message, true);
if (r < 0)
return bus_log_create_error(r);
}
r = bus_append_unit_property_assignment_many(m, UNIT_SERVICE, properties);
if (r < 0)
return r;
r = sd_bus_message_close_container(m);
if (r < 0)
return bus_log_create_error(r);
}
return sd_bus_call(bus, m, 0, error, NULL);
}
int register_machine( int register_machine(
sd_bus *bus, sd_bus *bus,
const char *machine_name, const char *machine_name,
@ -153,6 +273,27 @@ int register_machine(
assert(bus); assert(bus);
r = create_or_register_machine_ex(
bus,
machine_name,
pid,
directory,
uuid,
local_ifindex,
slice,
mounts,
n_mounts,
kill_signal,
properties,
properties_message,
service,
start_mode,
&error,
FLAGS_SET(flags, REGISTER_MACHINE_KEEP_UNIT));
if (r >= 0)
return 0;
if (!sd_bus_error_has_name(&error, SD_BUS_ERROR_UNKNOWN_METHOD))
return log_error_errno(r, "Failed to register machine: %s", bus_error_message(&error, r));
if (FLAGS_SET(flags, REGISTER_MACHINE_KEEP_UNIT)) { if (FLAGS_SET(flags, REGISTER_MACHINE_KEEP_UNIT)) {
r = bus_call_method( r = bus_call_method(
bus, bus,

View File

@ -11,7 +11,6 @@ executables += [
], ],
'sources' : files('pcrextend.c'), 'sources' : files('pcrextend.c'),
'dependencies' : [ 'dependencies' : [
libblkid,
libopenssl, libopenssl,
tpm2, tpm2,
], ],

View File

@ -14,7 +14,7 @@ executables += [
libshared_fdisk, libshared_fdisk,
], ],
'dependencies' : [ 'dependencies' : [
libblkid, libblkid_cflags,
libfdisk, libfdisk,
libopenssl, libopenssl,
threads, threads,
@ -33,7 +33,7 @@ executables += [
libsystemd_static, libsystemd_static,
], ],
'dependencies' : [ 'dependencies' : [
libblkid, libblkid_cflags,
libfdisk, libfdisk,
libopenssl, libopenssl,
threads, threads,

View File

@ -4278,32 +4278,36 @@ static int context_wipe_range(Context *context, uint64_t offset, uint64_t size)
assert(offset != UINT64_MAX); assert(offset != UINT64_MAX);
assert(size != UINT64_MAX); assert(size != UINT64_MAX);
probe = blkid_new_probe(); r = dlopen_libblkid();
if (r < 0)
return log_error_errno(r, "Failed to load libblkid: %m");
probe = sym_blkid_new_probe();
if (!probe) if (!probe)
return log_oom(); return log_oom();
errno = 0; errno = 0;
r = blkid_probe_set_device(probe, fdisk_get_devfd(context->fdisk_context), offset, size); r = sym_blkid_probe_set_device(probe, fdisk_get_devfd(context->fdisk_context), offset, size);
if (r < 0) if (r < 0)
return log_error_errno(errno ?: SYNTHETIC_ERRNO(EIO), "Failed to allocate device probe for wiping."); return log_error_errno(errno ?: SYNTHETIC_ERRNO(EIO), "Failed to allocate device probe for wiping.");
errno = 0; errno = 0;
if (blkid_probe_enable_superblocks(probe, true) < 0 || if (sym_blkid_probe_enable_superblocks(probe, true) < 0 ||
blkid_probe_set_superblocks_flags(probe, BLKID_SUBLKS_MAGIC|BLKID_SUBLKS_BADCSUM) < 0 || sym_blkid_probe_set_superblocks_flags(probe, BLKID_SUBLKS_MAGIC|BLKID_SUBLKS_BADCSUM) < 0 ||
blkid_probe_enable_partitions(probe, true) < 0 || sym_blkid_probe_enable_partitions(probe, true) < 0 ||
blkid_probe_set_partitions_flags(probe, BLKID_PARTS_MAGIC) < 0) sym_blkid_probe_set_partitions_flags(probe, BLKID_PARTS_MAGIC) < 0)
return log_error_errno(errno ?: SYNTHETIC_ERRNO(EIO), "Failed to enable superblock and partition probing."); return log_error_errno(errno ?: SYNTHETIC_ERRNO(EIO), "Failed to enable superblock and partition probing.");
for (;;) { for (;;) {
errno = 0; errno = 0;
r = blkid_do_probe(probe); r = sym_blkid_do_probe(probe);
if (r < 0) if (r < 0)
return log_error_errno(errno_or_else(EIO), "Failed to probe for file systems."); return log_error_errno(errno_or_else(EIO), "Failed to probe for file systems.");
if (r > 0) if (r > 0)
break; break;
errno = 0; errno = 0;
if (blkid_do_wipe(probe, false) < 0) if (sym_blkid_do_wipe(probe, false) < 0)
return log_error_errno(errno_or_else(EIO), "Failed to wipe file system signature."); return log_error_errno(errno_or_else(EIO), "Failed to wipe file system signature.");
} }
@ -7392,20 +7396,24 @@ static int resolve_copy_blocks_auto_candidate(
return log_error_errno(r, "Failed to open block device " DEVNUM_FORMAT_STR ": %m", return log_error_errno(r, "Failed to open block device " DEVNUM_FORMAT_STR ": %m",
DEVNUM_FORMAT_VAL(whole_devno)); DEVNUM_FORMAT_VAL(whole_devno));
b = blkid_new_probe(); r = dlopen_libblkid();
if (r < 0)
return log_error_errno(r, "Failed to find libblkid: %m");
b = sym_blkid_new_probe();
if (!b) if (!b)
return log_oom(); return log_oom();
errno = 0; errno = 0;
r = blkid_probe_set_device(b, fd, 0, 0); r = sym_blkid_probe_set_device(b, fd, 0, 0);
if (r != 0) if (r != 0)
return log_error_errno(errno_or_else(ENOMEM), "Failed to open block device '%s': %m", p); return log_error_errno(errno_or_else(ENOMEM), "Failed to open block device '%s': %m", p);
(void) blkid_probe_enable_partitions(b, 1); (void) sym_blkid_probe_enable_partitions(b, 1);
(void) blkid_probe_set_partitions_flags(b, BLKID_PARTS_ENTRY_DETAILS); (void) sym_blkid_probe_set_partitions_flags(b, BLKID_PARTS_ENTRY_DETAILS);
errno = 0; errno = 0;
r = blkid_do_safeprobe(b); r = sym_blkid_do_safeprobe(b);
if (r == _BLKID_SAFEPROBE_ERROR) if (r == _BLKID_SAFEPROBE_ERROR)
return log_error_errno(errno_or_else(EIO), "Unable to probe for partition table of '%s': %m", p); return log_error_errno(errno_or_else(EIO), "Unable to probe for partition table of '%s': %m", p);
if (IN_SET(r, _BLKID_SAFEPROBE_AMBIGUOUS, _BLKID_SAFEPROBE_NOT_FOUND)) { if (IN_SET(r, _BLKID_SAFEPROBE_AMBIGUOUS, _BLKID_SAFEPROBE_NOT_FOUND)) {
@ -7415,18 +7423,18 @@ static int resolve_copy_blocks_auto_candidate(
assert(r == _BLKID_SAFEPROBE_FOUND); assert(r == _BLKID_SAFEPROBE_FOUND);
(void) blkid_probe_lookup_value(b, "PTTYPE", &pttype, NULL); (void) sym_blkid_probe_lookup_value(b, "PTTYPE", &pttype, NULL);
if (!streq_ptr(pttype, "gpt")) { if (!streq_ptr(pttype, "gpt")) {
log_debug("Didn't find a GPT partition table on '%s'.", p); log_debug("Didn't find a GPT partition table on '%s'.", p);
return false; return false;
} }
errno = 0; errno = 0;
pl = blkid_probe_get_partitions(b); pl = sym_blkid_probe_get_partitions(b);
if (!pl) if (!pl)
return log_error_errno(errno_or_else(EIO), "Unable read partition table of '%s': %m", p); return log_error_errno(errno_or_else(EIO), "Unable read partition table of '%s': %m", p);
pp = blkid_partlist_devno_to_partition(pl, partition_devno); pp = sym_blkid_partlist_devno_to_partition(pl, partition_devno);
if (!pp) { if (!pp) {
log_debug("Partition %u:%u has no matching partition table entry on '%s'.", log_debug("Partition %u:%u has no matching partition table entry on '%s'.",
major(partition_devno), minor(partition_devno), p); major(partition_devno), minor(partition_devno), p);

View File

@ -1,17 +1,106 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */ /* SPDX-License-Identifier: LGPL-2.1-or-later */
#if HAVE_BLKID
#include "sd-id128.h" #include "sd-id128.h"
#include "blkid-util.h" #include "blkid-util.h"
#include "log.h"
#include "parse-util.h"
#include "string-util.h" #include "string-util.h"
#if HAVE_BLKID
static void *libblkid_dl = NULL;
DLSYM_PROTOTYPE(blkid_do_fullprobe) = NULL;
DLSYM_PROTOTYPE(blkid_do_probe) = NULL;
DLSYM_PROTOTYPE(blkid_do_safeprobe) = NULL;
DLSYM_PROTOTYPE(blkid_do_wipe) = NULL;
DLSYM_PROTOTYPE(blkid_encode_string) = NULL;
DLSYM_PROTOTYPE(blkid_free_probe) = NULL;
DLSYM_PROTOTYPE(blkid_new_probe) = NULL;
DLSYM_PROTOTYPE(blkid_new_probe_from_filename) = NULL;
DLSYM_PROTOTYPE(blkid_partition_get_flags) = NULL;
DLSYM_PROTOTYPE(blkid_partition_get_name) = NULL;
DLSYM_PROTOTYPE(blkid_partition_get_partno) = NULL;
DLSYM_PROTOTYPE(blkid_partition_get_size) = NULL;
DLSYM_PROTOTYPE(blkid_partition_get_start) = NULL;
DLSYM_PROTOTYPE(blkid_partition_get_type) = NULL;
DLSYM_PROTOTYPE(blkid_partition_get_type_string) = NULL;
DLSYM_PROTOTYPE(blkid_partition_get_uuid) = NULL;
DLSYM_PROTOTYPE(blkid_partlist_devno_to_partition) = NULL;
DLSYM_PROTOTYPE(blkid_partlist_get_partition) = NULL;
DLSYM_PROTOTYPE(blkid_partlist_numof_partitions) = NULL;
DLSYM_PROTOTYPE(blkid_probe_enable_partitions) = NULL;
DLSYM_PROTOTYPE(blkid_probe_enable_superblocks) = NULL;
DLSYM_PROTOTYPE(blkid_probe_filter_superblocks_type) = NULL;
DLSYM_PROTOTYPE(blkid_probe_filter_superblocks_usage) = NULL;
DLSYM_PROTOTYPE(blkid_probe_get_fd) = NULL;
DLSYM_PROTOTYPE(blkid_probe_get_partitions) = NULL;
DLSYM_PROTOTYPE(blkid_probe_get_size) = NULL;
DLSYM_PROTOTYPE(blkid_probe_get_value) = NULL;
DLSYM_PROTOTYPE(blkid_probe_is_wholedisk) = NULL;
DLSYM_PROTOTYPE(blkid_probe_lookup_value) = NULL;
DLSYM_PROTOTYPE(blkid_probe_numof_values) = NULL;
DLSYM_PROTOTYPE(blkid_probe_set_device) = NULL;
DLSYM_PROTOTYPE(blkid_probe_set_hint) = NULL;
DLSYM_PROTOTYPE(blkid_probe_set_partitions_flags) = NULL;
DLSYM_PROTOTYPE(blkid_probe_set_sectorsize) = NULL;
DLSYM_PROTOTYPE(blkid_probe_set_superblocks_flags) = NULL;
DLSYM_PROTOTYPE(blkid_safe_string) = NULL;
int dlopen_libblkid(void) {
ELF_NOTE_DLOPEN("blkid",
"Support for block device identification",
ELF_NOTE_DLOPEN_PRIORITY_RECOMMENDED,
"libblkid.so.1");
return dlopen_many_sym_or_warn(
&libblkid_dl,
"libblkid.so.1",
LOG_DEBUG,
DLSYM_ARG(blkid_do_fullprobe),
DLSYM_ARG(blkid_do_probe),
DLSYM_ARG(blkid_do_safeprobe),
DLSYM_ARG(blkid_do_wipe),
DLSYM_ARG(blkid_encode_string),
DLSYM_ARG(blkid_free_probe),
DLSYM_ARG(blkid_new_probe),
DLSYM_ARG(blkid_new_probe_from_filename),
DLSYM_ARG(blkid_partition_get_flags),
DLSYM_ARG(blkid_partition_get_name),
DLSYM_ARG(blkid_partition_get_partno),
DLSYM_ARG(blkid_partition_get_size),
DLSYM_ARG(blkid_partition_get_start),
DLSYM_ARG(blkid_partition_get_type),
DLSYM_ARG(blkid_partition_get_type_string),
DLSYM_ARG(blkid_partition_get_uuid),
DLSYM_ARG(blkid_partlist_devno_to_partition),
DLSYM_ARG(blkid_partlist_get_partition),
DLSYM_ARG(blkid_partlist_numof_partitions),
DLSYM_ARG(blkid_probe_enable_partitions),
DLSYM_ARG(blkid_probe_enable_superblocks),
DLSYM_ARG(blkid_probe_filter_superblocks_type),
DLSYM_ARG(blkid_probe_filter_superblocks_usage),
DLSYM_ARG(blkid_probe_get_fd),
DLSYM_ARG(blkid_probe_get_partitions),
DLSYM_ARG(blkid_probe_get_size),
DLSYM_ARG(blkid_probe_get_value),
DLSYM_ARG(blkid_probe_is_wholedisk),
DLSYM_ARG(blkid_probe_lookup_value),
DLSYM_ARG(blkid_probe_numof_values),
DLSYM_ARG(blkid_probe_set_device),
DLSYM_ARG(blkid_probe_set_hint),
DLSYM_ARG(blkid_probe_set_partitions_flags),
DLSYM_ARG(blkid_probe_set_sectorsize),
DLSYM_ARG(blkid_probe_set_superblocks_flags),
DLSYM_ARG(blkid_safe_string));
}
int blkid_partition_get_uuid_id128(blkid_partition p, sd_id128_t *ret) { int blkid_partition_get_uuid_id128(blkid_partition p, sd_id128_t *ret) {
const char *s; const char *s;
assert(p); assert(p);
s = blkid_partition_get_uuid(p); s = sym_blkid_partition_get_uuid(p);
if (isempty(s)) if (isempty(s))
return -ENXIO; return -ENXIO;
@ -23,11 +112,34 @@ int blkid_partition_get_type_id128(blkid_partition p, sd_id128_t *ret) {
assert(p); assert(p);
s = blkid_partition_get_type_string(p); s = sym_blkid_partition_get_type_string(p);
if (isempty(s)) if (isempty(s))
return -ENXIO; return -ENXIO;
return sd_id128_from_string(s, ret); return sd_id128_from_string(s, ret);
} }
int blkid_probe_lookup_value_id128(blkid_probe b, const char *field, sd_id128_t *ret) {
assert(b);
assert(field);
const char *u = NULL;
(void) sym_blkid_probe_lookup_value(b, field, &u, /* ret_size= */ NULL);
if (!u)
return -ENXIO;
return sd_id128_from_string(u, ret);
}
int blkid_probe_lookup_value_u64(blkid_probe b, const char *field, uint64_t *ret) {
assert(b);
assert(field);
const char *u = NULL;
(void) sym_blkid_probe_lookup_value(b, field, &u, /* ret_size= */ NULL);
if (!u)
return -ENXIO;
return safe_atou64(u, ret);
}
#endif #endif

View File

@ -1,13 +1,54 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */ /* SPDX-License-Identifier: LGPL-2.1-or-later */
#pragma once #pragma once
#include "forward.h"
#if HAVE_BLKID #if HAVE_BLKID
#include <blkid.h> #include <blkid.h>
#include "forward.h" #include "dlfcn-util.h"
DEFINE_TRIVIAL_CLEANUP_FUNC_FULL(blkid_probe, blkid_free_probe, NULL); extern DLSYM_PROTOTYPE(blkid_do_fullprobe);
extern DLSYM_PROTOTYPE(blkid_do_probe);
extern DLSYM_PROTOTYPE(blkid_do_safeprobe);
extern DLSYM_PROTOTYPE(blkid_do_wipe);
extern DLSYM_PROTOTYPE(blkid_encode_string);
extern DLSYM_PROTOTYPE(blkid_free_probe);
extern DLSYM_PROTOTYPE(blkid_new_probe);
extern DLSYM_PROTOTYPE(blkid_new_probe_from_filename);
extern DLSYM_PROTOTYPE(blkid_partition_get_flags);
extern DLSYM_PROTOTYPE(blkid_partition_get_name);
extern DLSYM_PROTOTYPE(blkid_partition_get_partno);
extern DLSYM_PROTOTYPE(blkid_partition_get_size);
extern DLSYM_PROTOTYPE(blkid_partition_get_start);
extern DLSYM_PROTOTYPE(blkid_partition_get_type);
extern DLSYM_PROTOTYPE(blkid_partition_get_type_string);
extern DLSYM_PROTOTYPE(blkid_partition_get_uuid);
extern DLSYM_PROTOTYPE(blkid_partlist_devno_to_partition);
extern DLSYM_PROTOTYPE(blkid_partlist_get_partition);
extern DLSYM_PROTOTYPE(blkid_partlist_numof_partitions);
extern DLSYM_PROTOTYPE(blkid_probe_enable_partitions);
extern DLSYM_PROTOTYPE(blkid_probe_enable_superblocks);
extern DLSYM_PROTOTYPE(blkid_probe_filter_superblocks_type);
extern DLSYM_PROTOTYPE(blkid_probe_filter_superblocks_usage);
extern DLSYM_PROTOTYPE(blkid_probe_get_fd);
extern DLSYM_PROTOTYPE(blkid_probe_get_partitions);
extern DLSYM_PROTOTYPE(blkid_probe_get_size);
extern DLSYM_PROTOTYPE(blkid_probe_get_value);
extern DLSYM_PROTOTYPE(blkid_probe_is_wholedisk);
extern DLSYM_PROTOTYPE(blkid_probe_lookup_value);
extern DLSYM_PROTOTYPE(blkid_probe_numof_values);
extern DLSYM_PROTOTYPE(blkid_probe_set_device);
extern DLSYM_PROTOTYPE(blkid_probe_set_hint);
extern DLSYM_PROTOTYPE(blkid_probe_set_partitions_flags);
extern DLSYM_PROTOTYPE(blkid_probe_set_sectorsize);
extern DLSYM_PROTOTYPE(blkid_probe_set_superblocks_flags);
extern DLSYM_PROTOTYPE(blkid_safe_string);
int dlopen_libblkid(void);
DEFINE_TRIVIAL_CLEANUP_FUNC_FULL_RENAME(blkid_probe, sym_blkid_free_probe, blkid_free_probep, NULL);
int blkid_partition_get_uuid_id128(blkid_partition p, sd_id128_t *ret); int blkid_partition_get_uuid_id128(blkid_partition p, sd_id128_t *ret);
@ -22,4 +63,10 @@ enum {
_BLKID_SAFEPROBE_ERROR = -1, _BLKID_SAFEPROBE_ERROR = -1,
}; };
int blkid_probe_lookup_value_id128(blkid_probe b, const char *field, sd_id128_t *ret);
int blkid_probe_lookup_value_u64(blkid_probe b, const char *field, uint64_t *ret);
#else
static inline int dlopen_libblkid(void) {
return -EOPNOTSUPP;
}
#endif #endif

View File

@ -199,12 +199,12 @@ static int probe_blkid_filter(blkid_probe p) {
return r; return r;
errno = 0; errno = 0;
r = blkid_probe_filter_superblocks_type(p, BLKID_FLTR_ONLYIN, fstypes); r = sym_blkid_probe_filter_superblocks_type(p, BLKID_FLTR_ONLYIN, fstypes);
if (r != 0) if (r != 0)
return errno_or_else(EINVAL); return errno_or_else(EINVAL);
errno = 0; errno = 0;
r = blkid_probe_filter_superblocks_usage(p, BLKID_FLTR_NOTIN, BLKID_USAGE_RAID); r = sym_blkid_probe_filter_superblocks_usage(p, BLKID_FLTR_NOTIN, BLKID_USAGE_RAID);
if (r != 0) if (r != 0)
return errno_or_else(EINVAL); return errno_or_else(EINVAL);
@ -234,6 +234,10 @@ int probe_filesystem_full(
assert(fd >= 0 || path); assert(fd >= 0 || path);
assert(ret_fstype); assert(ret_fstype);
r = dlopen_libblkid();
if (r < 0)
return r;
if (fd < 0) { if (fd < 0) {
fd_close = open(path, O_RDONLY|O_NONBLOCK|O_CLOEXEC|O_NOCTTY); fd_close = open(path, O_RDONLY|O_NONBLOCK|O_CLOEXEC|O_NOCTTY);
if (fd_close < 0) if (fd_close < 0)
@ -253,7 +257,7 @@ int probe_filesystem_full(
if (size == 0) /* empty size? nothing found! */ if (size == 0) /* empty size? nothing found! */
goto not_found; goto not_found;
b = blkid_new_probe(); b = sym_blkid_new_probe();
if (!b) if (!b)
return -ENOMEM; return -ENOMEM;
@ -279,7 +283,7 @@ int probe_filesystem_full(
log_debug_errno(errno, "Failed to flush block device cache, ignoring: %m"); log_debug_errno(errno, "Failed to flush block device cache, ignoring: %m");
errno = 0; errno = 0;
r = blkid_probe_set_device( r = sym_blkid_probe_set_device(
b, b,
fd, fd,
offset, offset,
@ -287,11 +291,11 @@ int probe_filesystem_full(
if (r != 0) if (r != 0)
return errno_or_else(ENOMEM); return errno_or_else(ENOMEM);
blkid_probe_enable_superblocks(b, 1); sym_blkid_probe_enable_superblocks(b, 1);
blkid_probe_set_superblocks_flags(b, BLKID_SUBLKS_TYPE); sym_blkid_probe_set_superblocks_flags(b, BLKID_SUBLKS_TYPE);
errno = 0; errno = 0;
r = blkid_do_safeprobe(b); r = sym_blkid_do_safeprobe(b);
if (r == _BLKID_SAFEPROBE_NOT_FOUND) if (r == _BLKID_SAFEPROBE_NOT_FOUND)
goto not_found; goto not_found;
if (r == _BLKID_SAFEPROBE_AMBIGUOUS) if (r == _BLKID_SAFEPROBE_AMBIGUOUS)
@ -302,8 +306,7 @@ int probe_filesystem_full(
assert(r == _BLKID_SAFEPROBE_FOUND); assert(r == _BLKID_SAFEPROBE_FOUND);
(void) blkid_probe_lookup_value(b, "TYPE", &fstype, NULL); (void) sym_blkid_probe_lookup_value(b, "TYPE", &fstype, NULL);
if (fstype) { if (fstype) {
log_debug("Probed fstype '%s' on partition %s.", fstype, path); log_debug("Probed fstype '%s' on partition %s.", fstype, path);
return strdup_to_full(ret_fstype, fstype); return strdup_to_full(ret_fstype, fstype);
@ -731,7 +734,7 @@ static int dissect_image(
_cleanup_(blkid_free_probep) blkid_probe b = NULL; _cleanup_(blkid_free_probep) blkid_probe b = NULL;
_cleanup_free_ char *generic_node = NULL; _cleanup_free_ char *generic_node = NULL;
sd_id128_t generic_uuid = SD_ID128_NULL; sd_id128_t generic_uuid = SD_ID128_NULL;
const char *pttype = NULL, *sptuuid = NULL; const char *pttype = NULL;
blkid_partlist pl; blkid_partlist pl;
int r, generic_nr = -1, n_partitions; int r, generic_nr = -1, n_partitions;
@ -789,7 +792,11 @@ static int dissect_image(
} }
} }
b = blkid_new_probe(); r = dlopen_libblkid();
if (r < 0)
return r;
b = sym_blkid_new_probe();
if (!b) if (!b)
return -ENOMEM; return -ENOMEM;
@ -798,26 +805,26 @@ static int dissect_image(
return r; return r;
errno = 0; errno = 0;
r = blkid_probe_set_device(b, fd, 0, 0); r = sym_blkid_probe_set_device(b, fd, 0, 0);
if (r != 0) if (r != 0)
return errno_or_else(ENOMEM); return errno_or_else(ENOMEM);
errno = 0; errno = 0;
r = blkid_probe_set_sectorsize(b, m->sector_size); r = sym_blkid_probe_set_sectorsize(b, m->sector_size);
if (r != 0) if (r != 0)
return errno_or_else(EIO); return errno_or_else(EIO);
if ((flags & DISSECT_IMAGE_GPT_ONLY) == 0) { if ((flags & DISSECT_IMAGE_GPT_ONLY) == 0) {
/* Look for file system superblocks, unless we only shall look for GPT partition tables */ /* Look for file system superblocks, unless we only shall look for GPT partition tables */
blkid_probe_enable_superblocks(b, 1); sym_blkid_probe_enable_superblocks(b, 1);
blkid_probe_set_superblocks_flags(b, BLKID_SUBLKS_TYPE|BLKID_SUBLKS_USAGE|BLKID_SUBLKS_UUID); sym_blkid_probe_set_superblocks_flags(b, BLKID_SUBLKS_TYPE|BLKID_SUBLKS_USAGE|BLKID_SUBLKS_UUID);
} }
blkid_probe_enable_partitions(b, 1); sym_blkid_probe_enable_partitions(b, 1);
blkid_probe_set_partitions_flags(b, BLKID_PARTS_ENTRY_DETAILS); sym_blkid_probe_set_partitions_flags(b, BLKID_PARTS_ENTRY_DETAILS);
errno = 0; errno = 0;
r = blkid_do_safeprobe(b); r = sym_blkid_do_safeprobe(b);
if (r == _BLKID_SAFEPROBE_ERROR) if (r == _BLKID_SAFEPROBE_ERROR)
return errno_or_else(EIO); return errno_or_else(EIO);
if (IN_SET(r, _BLKID_SAFEPROBE_AMBIGUOUS, _BLKID_SAFEPROBE_NOT_FOUND)) if (IN_SET(r, _BLKID_SAFEPROBE_AMBIGUOUS, _BLKID_SAFEPROBE_NOT_FOUND))
@ -832,10 +839,10 @@ static int dissect_image(
/* If flags permit this, also allow using non-partitioned single-filesystem images */ /* If flags permit this, also allow using non-partitioned single-filesystem images */
(void) blkid_probe_lookup_value(b, "USAGE", &usage, NULL); (void) sym_blkid_probe_lookup_value(b, "USAGE", &usage, NULL);
if (STRPTR_IN_SET(usage, "filesystem", "crypto")) { if (STRPTR_IN_SET(usage, "filesystem", "crypto")) {
_cleanup_free_ char *t = NULL, *n = NULL, *o = NULL; _cleanup_free_ char *t = NULL, *n = NULL, *o = NULL;
const char *fstype = NULL, *options = NULL, *suuid = NULL; const char *fstype = NULL, *options = NULL;
_cleanup_close_ int mount_node_fd = -EBADF; _cleanup_close_ int mount_node_fd = -EBADF;
sd_id128_t uuid = SD_ID128_NULL; sd_id128_t uuid = SD_ID128_NULL;
PartitionPolicyFlags found_flags; PartitionPolicyFlags found_flags;
@ -852,8 +859,12 @@ static int dissect_image(
if (r == 0) /* policy says ignore this, so we ignore it */ if (r == 0) /* policy says ignore this, so we ignore it */
return -ENOPKG; return -ENOPKG;
(void) blkid_probe_lookup_value(b, "TYPE", &fstype, NULL); (void) sym_blkid_probe_lookup_value(b, "TYPE", &fstype, NULL);
(void) blkid_probe_lookup_value(b, "UUID", &suuid, NULL);
/* blkid will return FAT's serial number as UUID, hence it is quite possible that
* parsing this will fail. We'll ignore the ID, since it's just too short to be
* useful as true identifier. */
(void) blkid_probe_lookup_value_id128(b, "UUID", &uuid);
encrypted = streq_ptr(fstype, "crypto_LUKS"); encrypted = streq_ptr(fstype, "crypto_LUKS");
@ -882,15 +893,6 @@ static int dissect_image(
return -ENOMEM; return -ENOMEM;
} }
if (suuid) {
/* blkid will return FAT's serial number as UUID, hence it is quite possible
* that parsing this will fail. We'll ignore the ID, since it's just too
* short to be useful as true identifier. */
r = sd_id128_from_string(suuid, &uuid);
if (r < 0)
log_debug_errno(r, "Failed to parse file system UUID '%s', ignoring: %m", suuid);
}
r = make_partition_devname(devname, diskseq, -1, flags, &n); r = make_partition_devname(devname, diskseq, -1, flags, &n);
if (r < 0) if (r < 0)
return r; return r;
@ -931,7 +933,7 @@ static int dissect_image(
} }
} }
(void) blkid_probe_lookup_value(b, "PTTYPE", &pttype, NULL); (void) sym_blkid_probe_lookup_value(b, "PTTYPE", &pttype, NULL);
if (!pttype) if (!pttype)
return -ENOPKG; return -ENOPKG;
@ -955,20 +957,15 @@ static int dissect_image(
return -EPROTONOSUPPORT; return -EPROTONOSUPPORT;
} }
(void) blkid_probe_lookup_value(b, "PTUUID", &sptuuid, NULL); (void) blkid_probe_lookup_value_id128(b, "PTUUID", &m->image_uuid);
if (sptuuid) {
r = sd_id128_from_string(sptuuid, &m->image_uuid);
if (r < 0)
log_debug_errno(r, "Failed to parse partition table UUID '%s', ignoring: %m", sptuuid);
}
errno = 0; errno = 0;
pl = blkid_probe_get_partitions(b); pl = sym_blkid_probe_get_partitions(b);
if (!pl) if (!pl)
return errno_or_else(ENOMEM); return errno_or_else(ENOMEM);
errno = 0; errno = 0;
n_partitions = blkid_partlist_numof_partitions(pl); n_partitions = sym_blkid_partlist_numof_partitions(pl);
if (n_partitions < 0) if (n_partitions < 0)
return errno_or_else(EIO); return errno_or_else(EIO);
@ -980,26 +977,26 @@ static int dissect_image(
int nr; int nr;
errno = 0; errno = 0;
pp = blkid_partlist_get_partition(pl, i); pp = sym_blkid_partlist_get_partition(pl, i);
if (!pp) if (!pp)
return errno_or_else(EIO); return errno_or_else(EIO);
pflags = blkid_partition_get_flags(pp); pflags = sym_blkid_partition_get_flags(pp);
errno = 0; errno = 0;
nr = blkid_partition_get_partno(pp); nr = sym_blkid_partition_get_partno(pp);
if (nr < 0) if (nr < 0)
return errno_or_else(EIO); return errno_or_else(EIO);
errno = 0; errno = 0;
start = blkid_partition_get_start(pp); start = sym_blkid_partition_get_start(pp);
if (start < 0) if (start < 0)
return errno_or_else(EIO); return errno_or_else(EIO);
assert((uint64_t) start < UINT64_MAX/512); assert((uint64_t) start < UINT64_MAX/512);
errno = 0; errno = 0;
size = blkid_partition_get_size(pp); size = sym_blkid_partition_get_size(pp);
if (size < 0) if (size < 0)
return errno_or_else(EIO); return errno_or_else(EIO);
@ -1054,7 +1051,7 @@ static int dissect_image(
type = gpt_partition_type_from_uuid(type_id); type = gpt_partition_type_from_uuid(type_id);
label = blkid_partition_get_name(pp); /* libblkid returns NULL here if empty */ label = sym_blkid_partition_get_name(pp); /* libblkid returns NULL here if empty */
/* systemd-sysupdate expects empty partitions to be marked with an "_empty" label, hence ignore them here. */ /* systemd-sysupdate expects empty partitions to be marked with an "_empty" label, hence ignore them here. */
if (streq_ptr(label, "_empty")) if (streq_ptr(label, "_empty"))
@ -1360,7 +1357,7 @@ static int dissect_image(
} else if (is_mbr) { } else if (is_mbr) {
switch (blkid_partition_get_type(pp)) { switch (sym_blkid_partition_get_type(pp)) {
case 0x83: /* Linux partition */ case 0x83: /* Linux partition */

View File

@ -76,22 +76,26 @@ static int verify_esp_blkid(
const char *v; const char *v;
int r; int r;
r = dlopen_libblkid();
if (r < 0)
return log_debug_errno(r, "No libblkid support: %m");
r = devname_from_devnum(S_IFBLK, devid, &node); r = devname_from_devnum(S_IFBLK, devid, &node);
if (r < 0) if (r < 0)
return log_error_errno(r, "Failed to get device path for " DEVNUM_FORMAT_STR ": %m", DEVNUM_FORMAT_VAL(devid)); return log_error_errno(r, "Failed to get device path for " DEVNUM_FORMAT_STR ": %m", DEVNUM_FORMAT_VAL(devid));
errno = 0; errno = 0;
b = blkid_new_probe_from_filename(node); b = sym_blkid_new_probe_from_filename(node);
if (!b) if (!b)
return log_error_errno(errno ?: SYNTHETIC_ERRNO(ENOMEM), "Failed to open file system \"%s\": %m", node); return log_error_errno(errno ?: SYNTHETIC_ERRNO(ENOMEM), "Failed to open file system \"%s\": %m", node);
blkid_probe_enable_superblocks(b, 1); sym_blkid_probe_enable_superblocks(b, 1);
blkid_probe_set_superblocks_flags(b, BLKID_SUBLKS_TYPE); sym_blkid_probe_set_superblocks_flags(b, BLKID_SUBLKS_TYPE);
blkid_probe_enable_partitions(b, 1); sym_blkid_probe_enable_partitions(b, 1);
blkid_probe_set_partitions_flags(b, BLKID_PARTS_ENTRY_DETAILS); sym_blkid_probe_set_partitions_flags(b, BLKID_PARTS_ENTRY_DETAILS);
errno = 0; errno = 0;
r = blkid_do_safeprobe(b); r = sym_blkid_do_safeprobe(b);
if (r == -2) if (r == -2)
return log_error_errno(SYNTHETIC_ERRNO(ENODEV), "File system \"%s\" is ambiguous.", node); return log_error_errno(SYNTHETIC_ERRNO(ENODEV), "File system \"%s\" is ambiguous.", node);
if (r == 1) if (r == 1)
@ -99,7 +103,7 @@ static int verify_esp_blkid(
if (r != 0) if (r != 0)
return log_error_errno(errno ?: SYNTHETIC_ERRNO(EIO), "Failed to probe file system \"%s\": %m", node); return log_error_errno(errno ?: SYNTHETIC_ERRNO(EIO), "Failed to probe file system \"%s\": %m", node);
r = blkid_probe_lookup_value(b, "TYPE", &v, NULL); r = sym_blkid_probe_lookup_value(b, "TYPE", &v, NULL);
if (r != 0) if (r != 0)
return log_full_errno(searching ? LOG_DEBUG : LOG_ERR, return log_full_errno(searching ? LOG_DEBUG : LOG_ERR,
SYNTHETIC_ERRNO(searching ? EADDRNOTAVAIL : ENODEV), SYNTHETIC_ERRNO(searching ? EADDRNOTAVAIL : ENODEV),
@ -109,7 +113,7 @@ static int verify_esp_blkid(
SYNTHETIC_ERRNO(searching ? EADDRNOTAVAIL : ENODEV), SYNTHETIC_ERRNO(searching ? EADDRNOTAVAIL : ENODEV),
"File system \"%s\" is not FAT.", node); "File system \"%s\" is not FAT.", node);
r = blkid_probe_lookup_value(b, "PART_ENTRY_SCHEME", &v, NULL); r = sym_blkid_probe_lookup_value(b, "PART_ENTRY_SCHEME", &v, NULL);
if (r != 0) if (r != 0)
return log_full_errno(searching ? LOG_DEBUG : LOG_ERR, return log_full_errno(searching ? LOG_DEBUG : LOG_ERR,
SYNTHETIC_ERRNO(searching ? EADDRNOTAVAIL : ENODEV), SYNTHETIC_ERRNO(searching ? EADDRNOTAVAIL : ENODEV),
@ -120,7 +124,7 @@ static int verify_esp_blkid(
"File system \"%s\" is not on a GPT partition table.", node); "File system \"%s\" is not on a GPT partition table.", node);
errno = 0; errno = 0;
r = blkid_probe_lookup_value(b, "PART_ENTRY_TYPE", &v, NULL); r = sym_blkid_probe_lookup_value(b, "PART_ENTRY_TYPE", &v, NULL);
if (r != 0) if (r != 0)
return log_error_errno(errno ?: EIO, "Failed to probe partition type UUID of \"%s\": %m", node); return log_error_errno(errno ?: EIO, "Failed to probe partition type UUID of \"%s\": %m", node);
if (sd_id128_string_equal(v, SD_GPT_ESP) <= 0) if (sd_id128_string_equal(v, SD_GPT_ESP) <= 0)
@ -128,37 +132,25 @@ static int verify_esp_blkid(
SYNTHETIC_ERRNO(searching ? EADDRNOTAVAIL : ENODEV), SYNTHETIC_ERRNO(searching ? EADDRNOTAVAIL : ENODEV),
"File system \"%s\" has wrong type for an EFI System Partition (ESP).", node); "File system \"%s\" has wrong type for an EFI System Partition (ESP).", node);
errno = 0; r = blkid_probe_lookup_value_id128(b, "PART_ENTRY_UUID", &uuid);
r = blkid_probe_lookup_value(b, "PART_ENTRY_UUID", &v, NULL);
if (r != 0)
return log_error_errno(errno ?: SYNTHETIC_ERRNO(EIO), "Failed to probe partition entry UUID of \"%s\": %m", node);
r = sd_id128_from_string(v, &uuid);
if (r < 0) if (r < 0)
return log_error_errno(r, "Partition \"%s\" has invalid UUID \"%s\".", node, v); return log_error_errno(r, "Failed to probe partition entry UUID of \"%s\": %m", node);
errno = 0; errno = 0;
r = blkid_probe_lookup_value(b, "PART_ENTRY_NUMBER", &v, NULL); r = sym_blkid_probe_lookup_value(b, "PART_ENTRY_NUMBER", &v, NULL);
if (r != 0) if (r != 0)
return log_error_errno(errno ?: SYNTHETIC_ERRNO(EIO), "Failed to probe partition number of \"%s\": %m", node); return log_error_errno(errno ?: SYNTHETIC_ERRNO(EIO), "Failed to probe partition number of \"%s\": %m", node);
r = safe_atou32(v, &part); r = safe_atou32(v, &part);
if (r < 0) if (r < 0)
return log_error_errno(r, "Failed to parse PART_ENTRY_NUMBER field."); return log_error_errno(r, "Failed to parse PART_ENTRY_NUMBER field.");
errno = 0; r = blkid_probe_lookup_value_u64(b, "PART_ENTRY_OFFSET", &pstart);
r = blkid_probe_lookup_value(b, "PART_ENTRY_OFFSET", &v, NULL);
if (r != 0)
return log_error_errno(errno ?: SYNTHETIC_ERRNO(EIO), "Failed to probe partition offset of \"%s\": %m", node);
r = safe_atou64(v, &pstart);
if (r < 0) if (r < 0)
return log_error_errno(r, "Failed to parse PART_ENTRY_OFFSET field."); return log_error_errno(r, "Failed to probe partition offset of \"%s\": %m", node);
errno = 0; r = blkid_probe_lookup_value_u64(b, "PART_ENTRY_SIZE", &psize);
r = blkid_probe_lookup_value(b, "PART_ENTRY_SIZE", &v, NULL);
if (r != 0)
return log_error_errno(errno ?: SYNTHETIC_ERRNO(EIO), "Failed to probe partition size of \"%s\": %m", node);
r = safe_atou64(v, &psize);
if (r < 0) if (r < 0)
return log_error_errno(r, "Failed to parse PART_ENTRY_SIZE field."); return log_error_errno(r, "Failed to probe partition size of \"%s\": %m", node);
#endif #endif
if (ret_part) if (ret_part)
@ -603,21 +595,25 @@ static int verify_xbootldr_blkid(
const char *type, *v; const char *type, *v;
int r; int r;
r = dlopen_libblkid();
if (r < 0)
return log_debug_errno(r, "No libblkid support: %m");
r = devname_from_devnum(S_IFBLK, devid, &node); r = devname_from_devnum(S_IFBLK, devid, &node);
if (r < 0) if (r < 0)
return log_error_errno(r, "Failed to get block device path for " DEVNUM_FORMAT_STR ": %m", return log_error_errno(r, "Failed to get block device path for " DEVNUM_FORMAT_STR ": %m",
DEVNUM_FORMAT_VAL(devid)); DEVNUM_FORMAT_VAL(devid));
errno = 0; errno = 0;
b = blkid_new_probe_from_filename(node); b = sym_blkid_new_probe_from_filename(node);
if (!b) if (!b)
return log_error_errno(errno_or_else(ENOMEM), "%s: Failed to create blkid probe: %m", node); return log_error_errno(errno_or_else(ENOMEM), "%s: Failed to create blkid probe: %m", node);
blkid_probe_enable_partitions(b, 1); sym_blkid_probe_enable_partitions(b, 1);
blkid_probe_set_partitions_flags(b, BLKID_PARTS_ENTRY_DETAILS); sym_blkid_probe_set_partitions_flags(b, BLKID_PARTS_ENTRY_DETAILS);
errno = 0; errno = 0;
r = blkid_do_safeprobe(b); r = sym_blkid_do_safeprobe(b);
if (r == _BLKID_SAFEPROBE_AMBIGUOUS) if (r == _BLKID_SAFEPROBE_AMBIGUOUS)
return log_error_errno(SYNTHETIC_ERRNO(ENODEV), "%s: File system is ambiguous.", node); return log_error_errno(SYNTHETIC_ERRNO(ENODEV), "%s: File system is ambiguous.", node);
if (r == _BLKID_SAFEPROBE_NOT_FOUND) if (r == _BLKID_SAFEPROBE_NOT_FOUND)
@ -627,7 +623,7 @@ static int verify_xbootldr_blkid(
assert(r == _BLKID_SAFEPROBE_FOUND); assert(r == _BLKID_SAFEPROBE_FOUND);
r = blkid_probe_lookup_value(b, "PART_ENTRY_SCHEME", &type, NULL); r = sym_blkid_probe_lookup_value(b, "PART_ENTRY_SCHEME", &type, NULL);
if (r != 0) if (r != 0)
return log_full_errno(searching ? LOG_DEBUG : LOG_ERR, return log_full_errno(searching ? LOG_DEBUG : LOG_ERR,
searching ? SYNTHETIC_ERRNO(EADDRNOTAVAIL) : SYNTHETIC_ERRNO(EIO), searching ? SYNTHETIC_ERRNO(EADDRNOTAVAIL) : SYNTHETIC_ERRNO(EIO),
@ -635,7 +631,7 @@ static int verify_xbootldr_blkid(
if (streq(type, "gpt")) { if (streq(type, "gpt")) {
errno = 0; errno = 0;
r = blkid_probe_lookup_value(b, "PART_ENTRY_TYPE", &v, NULL); r = sym_blkid_probe_lookup_value(b, "PART_ENTRY_TYPE", &v, NULL);
if (r != 0) if (r != 0)
return log_error_errno(errno_or_else(EIO), "%s: Failed to probe PART_ENTRY_TYPE: %m", node); return log_error_errno(errno_or_else(EIO), "%s: Failed to probe PART_ENTRY_TYPE: %m", node);
if (sd_id128_string_equal(v, SD_GPT_XBOOTLDR) <= 0) if (sd_id128_string_equal(v, SD_GPT_XBOOTLDR) <= 0)
@ -643,18 +639,14 @@ static int verify_xbootldr_blkid(
searching ? SYNTHETIC_ERRNO(EADDRNOTAVAIL) : SYNTHETIC_ERRNO(ENODEV), searching ? SYNTHETIC_ERRNO(EADDRNOTAVAIL) : SYNTHETIC_ERRNO(ENODEV),
"%s: Partition has wrong PART_ENTRY_TYPE=%s for XBOOTLDR partition.", node, v); "%s: Partition has wrong PART_ENTRY_TYPE=%s for XBOOTLDR partition.", node, v);
errno = 0; r = blkid_probe_lookup_value_id128(b, "PART_ENTRY_UUID", &uuid);
r = blkid_probe_lookup_value(b, "PART_ENTRY_UUID", &v, NULL);
if (r != 0) if (r != 0)
return log_error_errno(errno_or_else(EIO), "%s: Failed to probe PART_ENTRY_UUID: %m", node); return log_error_errno(errno_or_else(EIO), "%s: Failed to probe PART_ENTRY_UUID: %m", node);
r = sd_id128_from_string(v, &uuid);
if (r < 0)
return log_error_errno(r, "%s: Partition has invalid UUID PART_ENTRY_TYPE=%s: %m", node, v);
} else if (streq(type, "dos")) { } else if (streq(type, "dos")) {
errno = 0; errno = 0;
r = blkid_probe_lookup_value(b, "PART_ENTRY_TYPE", &v, NULL); r = sym_blkid_probe_lookup_value(b, "PART_ENTRY_TYPE", &v, NULL);
if (r != 0) if (r != 0)
return log_error_errno(errno_or_else(EIO), "%s: Failed to probe PART_ENTRY_TYPE: %m", node); return log_error_errno(errno_or_else(EIO), "%s: Failed to probe PART_ENTRY_TYPE: %m", node);
if (!streq(v, "0xea")) if (!streq(v, "0xea"))

View File

@ -154,6 +154,7 @@ shared_sources = files(
'polkit-agent.c', 'polkit-agent.c',
'portable-util.c', 'portable-util.c',
'pretty-print.c', 'pretty-print.c',
'prompt-util.c',
'ptyfwd.c', 'ptyfwd.c',
'qrcode-util.c', 'qrcode-util.c',
'quota-util.c', 'quota-util.c',
@ -314,7 +315,7 @@ libshared_name = 'systemd-shared-@0@'.format(shared_lib_tag)
libshared_deps = [threads, libshared_deps = [threads,
libacl_cflags, libacl_cflags,
libaudit_cflags, libaudit_cflags,
libblkid, libblkid_cflags,
libcap, libcap,
libcrypt, libcrypt,
libdl, libdl,

View File

@ -30,26 +30,30 @@ static int device_get_file_system_word(
assert(ret); assert(ret);
#if HAVE_BLKID #if HAVE_BLKID
r = dlopen_libblkid();
if (r < 0)
return r;
_cleanup_close_ int block_fd = sd_device_open(d, O_RDONLY|O_CLOEXEC|O_NONBLOCK); _cleanup_close_ int block_fd = sd_device_open(d, O_RDONLY|O_CLOEXEC|O_NONBLOCK);
if (block_fd < 0) if (block_fd < 0)
return block_fd; return block_fd;
_cleanup_(blkid_free_probep) blkid_probe b = blkid_new_probe(); _cleanup_(blkid_free_probep) blkid_probe b = sym_blkid_new_probe();
if (!b) if (!b)
return -ENOMEM; return -ENOMEM;
errno = 0; errno = 0;
r = blkid_probe_set_device(b, block_fd, 0, 0); r = sym_blkid_probe_set_device(b, block_fd, 0, 0);
if (r != 0) if (r != 0)
return errno_or_else(ENOMEM); return errno_or_else(ENOMEM);
(void) blkid_probe_enable_superblocks(b, 1); (void) sym_blkid_probe_enable_superblocks(b, 1);
(void) blkid_probe_set_superblocks_flags(b, BLKID_SUBLKS_TYPE|BLKID_SUBLKS_UUID|BLKID_SUBLKS_LABEL); (void) sym_blkid_probe_set_superblocks_flags(b, BLKID_SUBLKS_TYPE|BLKID_SUBLKS_UUID|BLKID_SUBLKS_LABEL);
(void) blkid_probe_enable_partitions(b, 1); (void) sym_blkid_probe_enable_partitions(b, 1);
(void) blkid_probe_set_partitions_flags(b, BLKID_PARTS_ENTRY_DETAILS); (void) sym_blkid_probe_set_partitions_flags(b, BLKID_PARTS_ENTRY_DETAILS);
errno = 0; errno = 0;
r = blkid_do_safeprobe(b); r = sym_blkid_do_safeprobe(b);
if (r == _BLKID_SAFEPROBE_ERROR) if (r == _BLKID_SAFEPROBE_ERROR)
return errno_or_else(EIO); return errno_or_else(EIO);
if (IN_SET(r, _BLKID_SAFEPROBE_AMBIGUOUS, _BLKID_SAFEPROBE_NOT_FOUND)) if (IN_SET(r, _BLKID_SAFEPROBE_AMBIGUOUS, _BLKID_SAFEPROBE_NOT_FOUND))
@ -64,7 +68,7 @@ static int device_get_file_system_word(
FOREACH_STRING(field, "TYPE", "UUID", "LABEL", "PART_ENTRY_UUID", "PART_ENTRY_TYPE", "PART_ENTRY_NAME") { FOREACH_STRING(field, "TYPE", "UUID", "LABEL", "PART_ENTRY_UUID", "PART_ENTRY_TYPE", "PART_ENTRY_NAME") {
const char *v = NULL; const char *v = NULL;
(void) blkid_probe_lookup_value(b, field, &v, NULL); (void) sym_blkid_probe_lookup_value(b, field, &v, NULL);
_cleanup_free_ char *escaped = xescape(strempty(v), ":"); /* Avoid ambiguity around ":" */ _cleanup_free_ char *escaped = xescape(strempty(v), ":"); /* Avoid ambiguity around ":" */
if (!escaped) if (!escaped)

View File

@ -92,3 +92,6 @@ static inline void fflush_and_disable_bufferingp(FILE **p) {
#define WITH_BUFFERED_STDERR \ #define WITH_BUFFERED_STDERR \
_WITH_BUFFERED_STREAM(stderr, LONG_LINE_MAX, UNIQ_T(p, UNIQ)) _WITH_BUFFERED_STREAM(stderr, LONG_LINE_MAX, UNIQ_T(p, UNIQ))
#define WITH_BUFFERED_STDOUT \
_WITH_BUFFERED_STREAM(stdout, LONG_LINE_MAX, UNIQ_T(p, UNIQ))

332
src/shared/prompt-util.c Normal file
View File

@ -0,0 +1,332 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#include <unistd.h>
#include "alloc-util.h"
#include "glyph-util.h"
#include "log.h"
#include "macro.h"
#include "os-util.h"
#include "parse-util.h"
#include "pretty-print.h"
#include "prompt-util.h"
#include "string-util.h"
#include "strv.h"
#include "terminal-util.h"
static int get_completions(
const char *key,
char ***ret_list,
void *userdata) {
int r;
assert(ret_list);
if (!userdata) {
*ret_list = NULL;
return 0;
}
_cleanup_strv_free_ char **copy = strv_copy(userdata);
if (!copy)
return -ENOMEM;
r = strv_extend(&copy, "list");
if (r < 0)
return r;
*ret_list = TAKE_PTR(copy);
return 0;
}
int prompt_loop(
const char *text,
Glyph emoji,
char **menu, /* if non-NULL: choices to suggest */
char **accepted, /* if non-NULL: choices to accept (should be a superset of 'menu') */
unsigned ellipsize_percentage,
size_t n_columns,
size_t column_width,
int (*is_valid)(const char *name, void *userdata),
int (*refresh)(char ***ret_menu, char ***ret_accepted, void *userdata),
void *userdata,
PromptFlags flags,
char **ret) {
_cleanup_strv_free_ char **refreshed_menu = NULL, **refreshed_accepted = NULL;
int r;
assert(text);
assert(ret);
if (!emoji_enabled()) /* If emojis aren't available, simpler unicode chars might still be around,
* hence try to downgrade. (Consider the Linux Console!) */
emoji = GLYPH_TRIANGULAR_BULLET;
/* If requested show menu right-away */
if (FLAGS_SET(flags, PROMPT_SHOW_MENU_NOW) && !strv_isempty(menu)) {
r = show_menu(menu,
n_columns,
column_width,
ellipsize_percentage,
/* grey_prefix= */ NULL,
/* with_numbers= */ true);
if (r < 0)
return log_error_errno(r, "Failed to show menu: %m");
putchar('\n');
}
for (;;) {
_cleanup_free_ char *a = NULL;
if (!FLAGS_SET(flags, PROMPT_HIDE_MENU_HINT) && !strv_isempty(menu))
if (!strextend_with_separator(&a, ", ", "\"list\" to list options"))
return log_oom();
if (!FLAGS_SET(flags, PROMPT_HIDE_SKIP_HINT) && FLAGS_SET(flags, PROMPT_MAY_SKIP))
if (!strextend_with_separator(&a, ", ", "empty to skip"))
return log_oom();
if (a) {
char *b = strjoin(" (", a, ")");
if (!b)
return log_oom();
free_and_replace(a, b);
}
_cleanup_free_ char *p = NULL;
r = ask_string_full(
&p,
get_completions,
accepted ?: menu,
"%s%s%s%s: ",
emoji >= 0 ? glyph(emoji) : "",
emoji >= 0 ? " " : "",
text,
strempty(a));
if (r < 0)
return log_error_errno(r, "Failed to query user: %m");
if (isempty(p)) {
if (FLAGS_SET(flags, PROMPT_MAY_SKIP)) {
log_info("No data entered, skipping.");
*ret = NULL;
return 0;
}
log_info("No data entered, try again.");
continue;
}
/* NB: here we treat non-NULL but empty list different from NULL list. In the former case we
* support the "list" command, in the latter we don't. */
if (FLAGS_SET(flags, PROMPT_SHOW_MENU) && streq(p, "list")) {
putchar('\n');
if (refresh) {
_cleanup_strv_free_ char **rm = NULL, **ra = NULL;
/* If a refresh method is provided, then use it now to refresh the menu
* before redisplaying it. */
r = refresh(&rm, &ra, userdata);
if (r < 0)
return r;
strv_free_and_replace(refreshed_menu, rm);
strv_free_and_replace(refreshed_accepted, ra);
menu = refreshed_menu;
accepted = refreshed_accepted;
}
if (strv_isempty(menu)) {
log_warning("No entries known.");
continue;
}
r = show_menu(menu,
n_columns,
column_width,
ellipsize_percentage,
/* grey_prefix= */ NULL,
/* with_numbers= */ true);
if (r < 0)
return log_error_errno(r, "Failed to show menu: %m");
putchar('\n');
continue;
}
unsigned u;
if (safe_atou(p, &u) >= 0) {
if (u <= 0 || u > strv_length(menu)) {
log_error("Specified entry number out of range.");
continue;
}
log_info("Selected '%s'.", menu[u-1]);
return strdup_to_full(ret, menu[u-1]);
}
bool good = accepted ? strv_contains(accepted, p) : true;
if (good && is_valid) {
r = is_valid(p, userdata);
if (r < 0)
return r;
good = good && r;
}
if (good) {
*ret = TAKE_PTR(p);
return 1;
}
if (!FLAGS_SET(flags, PROMPT_SILENT_VALIDATE)) {
/* Be more helpful to the user, and give a hint what the user might have wanted to type. */
const char *best_match = strv_find_closest(accepted ?: menu, p);
if (best_match)
log_error("Invalid input '%s', did you mean '%s'?", p, best_match);
else
log_error("Invalid input '%s'.", p);
}
}
}
/* Default: bright white on blue background */
#define ANSI_COLOR_CHROME "\x1B[0;44;1;37m"
static unsigned chrome_visible = 0; /* if non-zero chrome is visible and value is saved number of lines */
int chrome_show(
const char *top,
const char *bottom) {
int r;
assert(top);
/* Shows our "chrome", i.e. a blue bar at top and bottom. Reduces the scrolling area to the area in
* between */
if (terminal_is_dumb())
return 0;
unsigned n = lines();
if (n < 12) /* Do not bother with the chrome on tiny screens */
return 0;
_cleanup_free_ char *b = NULL, *ansi_color_reverse = NULL;
if (!bottom) {
_cleanup_free_ char *pretty_name = NULL, *os_name = NULL, *ansi_color = NULL, *documentation_url = NULL;
r = parse_os_release(
/* root= */ NULL,
"PRETTY_NAME", &pretty_name,
"NAME", &os_name,
"ANSI_COLOR", &ansi_color,
"ANSI_COLOR_REVERSE", &ansi_color_reverse,
"DOCUMENTATION_URL", &documentation_url);
if (r < 0)
log_full_errno(r == -ENOENT ? LOG_DEBUG : LOG_WARNING, r,
"Failed to read os-release file, ignoring: %m");
const char *m = os_release_pretty_name(pretty_name, os_name);
const char *c = ansi_color ?: "0";
if (ansi_color_reverse) {
_cleanup_free_ char *j = strjoin("\x1B[0;", ansi_color_reverse, "m");
if (!j)
return log_oom_debug();
free_and_replace(ansi_color_reverse, j);
}
if (asprintf(&b, "\x1B[0;%sm %s %s", c, m, ansi_color_reverse ?: ANSI_COLOR_CHROME) < 0)
return log_oom_debug();
if (documentation_url) {
_cleanup_free_ char *u = NULL;
if (terminal_urlify(documentation_url, "documentation", &u) < 0)
return log_oom_debug();
if (!strextend(&b, " - See ", u, " for more information."))
return log_oom_debug();
}
bottom = b;
}
const char *chrome_color = ansi_color_reverse ?: ANSI_COLOR_CHROME;
WITH_BUFFERED_STDOUT;
fputs("\033[H" /* move home */
"\033[2J", /* clear screen */
stdout);
/* Blue bar on top (followed by one empty regular one) */
printf("\x1B[1;1H" /* jump to top left */
"%1$s" ANSI_ERASE_TO_END_OF_LINE "\n"
"%1$s %2$s" ANSI_ERASE_TO_END_OF_LINE "\n"
"%1$s" ANSI_ERASE_TO_END_OF_LINE "\n"
ANSI_NORMAL ANSI_ERASE_TO_END_OF_LINE,
chrome_color,
top);
/* Blue bar on bottom (with one empty regular one before) */
printf("\x1B[%1$u;1H" /* jump to bottom left, above the blue bar */
ANSI_NORMAL ANSI_ERASE_TO_END_OF_LINE "\n"
"%2$s" ANSI_ERASE_TO_END_OF_LINE "\n"
"%2$s %3$s" ANSI_ERASE_TO_END_OF_LINE "\n"
"%2$s" ANSI_ERASE_TO_END_OF_LINE ANSI_NORMAL,
n - 3,
chrome_color,
bottom);
/* Reduce scrolling area (DECSTBM), cutting off top and bottom bars */
printf("\x1B[5;%ur", n - 4);
/* Position cursor in fifth line */
fputs("\x1B[5;1H", stdout);
fflush(stdout);
chrome_visible = n;
return 1;
}
void chrome_hide(void) {
int r;
if (chrome_visible == 0)
return;
unsigned n = chrome_visible;
chrome_visible = 0;
unsigned saved_row = 0;
r = terminal_get_cursor_position(STDIN_FILENO, STDOUT_FILENO, &saved_row, /* ret_column= */ NULL);
if (r < 0)
return (void) log_debug_errno(r, "Failed to get terminal cursor position, skipping chrome hiding: %m");
WITH_BUFFERED_STDOUT;
/* Erase Blue bar on bottom */
assert(n >= 2);
printf("\x1B[%u;1H"
ANSI_NORMAL ANSI_ERASE_TO_END_OF_LINE "\n"
ANSI_NORMAL ANSI_ERASE_TO_END_OF_LINE "\n"
ANSI_NORMAL ANSI_ERASE_TO_END_OF_LINE,
n - 2);
/* Reset scrolling area (DECSTBM) */
fputs("\x1B[r\n", stdout);
/* Place the cursor where it was again, but not in the former blue bars */
assert(n >= 9);
unsigned k = CLAMP(saved_row, 5U, n - 4);
printf("\x1B[%u;1H", k);
fflush(stdout);
}

31
src/shared/prompt-util.h Normal file
View File

@ -0,0 +1,31 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#pragma once
#include <stdbool.h>
#include "forward.h"
typedef enum PromptFlags {
PROMPT_MAY_SKIP = 1 << 0, /* Question may be skipped */
PROMPT_SHOW_MENU = 1 << 1, /* Show menu list on "list" */
PROMPT_SHOW_MENU_NOW = 1 << 2, /* Show menu list right away, rather than only on request */
PROMPT_HIDE_MENU_HINT = 1 << 3, /* Don't show hint regarding "list" */
PROMPT_HIDE_SKIP_HINT = 1 << 4, /* Don't show hint regarding skipping */
PROMPT_SILENT_VALIDATE = 1 << 5, /* The validation log message logs on its own, don't log again */
} PromptFlags;
int prompt_loop(const char *text,
Glyph emoji,
char **menu,
char **accepted,
unsigned ellipsize_percentage,
size_t n_columns,
size_t column_width,
int (*is_valid)(const char *name, void *userdata),
int (*refresh)(char ***ret_menu, char ***ret_accepted, void *userdata),
void *userdata,
PromptFlags flags,
char **ret);
int chrome_show(const char *top, const char *bottom);
void chrome_hide(void);

View File

@ -104,7 +104,7 @@ static SD_VARLINK_DEFINE_METHOD_FULL(
SD_VARLINK_FIELD_COMMENT("Return the base UID/GID of the machine"), SD_VARLINK_FIELD_COMMENT("Return the base UID/GID of the machine"),
SD_VARLINK_DEFINE_OUTPUT(UIDShift, SD_VARLINK_INT, SD_VARLINK_NULLABLE), SD_VARLINK_DEFINE_OUTPUT(UIDShift, SD_VARLINK_INT, SD_VARLINK_NULLABLE),
SD_VARLINK_FIELD_COMMENT("Subcgroup path of the machine, relative to the unit's cgroup path"), SD_VARLINK_FIELD_COMMENT("Subcgroup path of the machine, relative to the unit's cgroup path"),
SD_VARLINK_DEFINE_OUTPUT(Subgroup, SD_VARLINK_STRING, SD_VARLINK_NULLABLE), SD_VARLINK_DEFINE_OUTPUT(subgroup, SD_VARLINK_STRING, SD_VARLINK_NULLABLE),
SD_VARLINK_FIELD_COMMENT("Numeric UNIX UID of the user who registered the machine"), SD_VARLINK_FIELD_COMMENT("Numeric UNIX UID of the user who registered the machine"),
SD_VARLINK_DEFINE_OUTPUT(UID, SD_VARLINK_INT, SD_VARLINK_NULLABLE)); SD_VARLINK_DEFINE_OUTPUT(UID, SD_VARLINK_INT, SD_VARLINK_NULLABLE));

View File

@ -32,7 +32,6 @@ executables += [
libshared_fdisk, libshared_fdisk,
], ],
'dependencies' : [ 'dependencies' : [
libblkid,
libfdisk, libfdisk,
libopenssl, libopenssl,
threads, threads,

View File

@ -215,7 +215,6 @@ simple_tests += files(
############################################################ ############################################################
common_test_dependencies = [ common_test_dependencies = [
libblkid,
libmount, libmount,
librt, librt,
libseccomp, libseccomp,
@ -288,8 +287,9 @@ executables += [
test_template + { test_template + {
'sources' : files('test-dlopen-so.c'), 'sources' : files('test-dlopen-so.c'),
'dependencies' : [ 'dependencies' : [
libp11kit_cflags, libblkid_cflags,
libkmod_cflags, libkmod_cflags,
libp11kit_cflags,
], ],
}, },
test_template + { test_template + {
@ -550,7 +550,7 @@ executables += [
}, },
core_test_template + { core_test_template + {
'sources' : files('test-loop-block.c'), 'sources' : files('test-loop-block.c'),
'dependencies' : [threads, libblkid], 'dependencies' : [threads],
'parallel' : false, 'parallel' : false,
}, },
core_test_template + { core_test_template + {
@ -559,7 +559,6 @@ executables += [
core_test_template + { core_test_template + {
'sources' : files('test-namespace.c'), 'sources' : files('test-namespace.c'),
'dependencies' : [ 'dependencies' : [
libblkid,
threads, threads,
], ],
}, },

View File

@ -2,6 +2,7 @@
#include "acl-util.h" #include "acl-util.h"
#include "apparmor-util.h" #include "apparmor-util.h"
#include "blkid-util.h"
#include "bpf-dlopen.h" #include "bpf-dlopen.h"
#include "compress.h" #include "compress.h"
#include "cryptsetup-util.h" #include "cryptsetup-util.h"
@ -54,6 +55,7 @@ static int run(int argc, char **argv) {
ASSERT_DLOPEN(dlopen_libaudit, HAVE_AUDIT); ASSERT_DLOPEN(dlopen_libaudit, HAVE_AUDIT);
ASSERT_DLOPEN(dlopen_libpam, HAVE_PAM); ASSERT_DLOPEN(dlopen_libpam, HAVE_PAM);
ASSERT_DLOPEN(dlopen_libacl, HAVE_ACL); ASSERT_DLOPEN(dlopen_libacl, HAVE_ACL);
ASSERT_DLOPEN(dlopen_libblkid, HAVE_BLKID);
return 0; return 0;
} }

View File

@ -81,7 +81,7 @@ TEST(keymaps) {
#define dump_glyph(x) log_info(STRINGIFY(x) ": %s", glyph(x)) #define dump_glyph(x) log_info(STRINGIFY(x) ": %s", glyph(x))
TEST(dump_glyphs) { TEST(dump_glyphs) {
assert_cc(GLYPH_HOME + 1 == _GLYPH_MAX); assert_cc(GLYPH_SHELL + 1 == _GLYPH_MAX);
log_info("is_locale_utf8: %s", yes_no(is_locale_utf8())); log_info("is_locale_utf8: %s", yes_no(is_locale_utf8()));
@ -135,6 +135,12 @@ TEST(dump_glyphs) {
dump_glyph(GLYPH_SUPERHERO); dump_glyph(GLYPH_SUPERHERO);
dump_glyph(GLYPH_IDCARD); dump_glyph(GLYPH_IDCARD);
dump_glyph(GLYPH_HOME); dump_glyph(GLYPH_HOME);
dump_glyph(GLYPH_ROCKET);
dump_glyph(GLYPH_BROOM);
dump_glyph(GLYPH_KEYBOARD);
dump_glyph(GLYPH_CLOCK);
dump_glyph(GLYPH_LABEL);
dump_glyph(GLYPH_SHELL);
} }
DEFINE_TEST_MAIN(LOG_INFO); DEFINE_TEST_MAIN(LOG_INFO);

View File

@ -115,7 +115,7 @@ endif
udev_dependencies = [ udev_dependencies = [
libacl_cflags, libacl_cflags,
libblkid, libblkid_cflags,
libkmod, libkmod,
threads, threads,
] ]
@ -132,7 +132,7 @@ udev_common_template = {
'objects' : ['udevadm'], 'objects' : ['udevadm'],
'dependencies' : [ 'dependencies' : [
libacl_cflags, libacl_cflags,
libblkid, libblkid_cflags,
threads, threads,
], ],
} }

View File

@ -49,21 +49,21 @@ static void print_property(UdevEvent *event, const char *name, const char *value
udev_builtin_add_property(event, "ID_FS_VERSION", value); udev_builtin_add_property(event, "ID_FS_VERSION", value);
} else if (streq(name, "UUID")) { } else if (streq(name, "UUID")) {
blkid_safe_string(value, s, sizeof(s)); sym_blkid_safe_string(value, s, sizeof(s));
udev_builtin_add_property(event, "ID_FS_UUID", s); udev_builtin_add_property(event, "ID_FS_UUID", s);
blkid_encode_string(value, s, sizeof(s)); sym_blkid_encode_string(value, s, sizeof(s));
udev_builtin_add_property(event, "ID_FS_UUID_ENC", s); udev_builtin_add_property(event, "ID_FS_UUID_ENC", s);
} else if (streq(name, "UUID_SUB")) { } else if (streq(name, "UUID_SUB")) {
blkid_safe_string(value, s, sizeof(s)); sym_blkid_safe_string(value, s, sizeof(s));
udev_builtin_add_property(event, "ID_FS_UUID_SUB", s); udev_builtin_add_property(event, "ID_FS_UUID_SUB", s);
blkid_encode_string(value, s, sizeof(s)); sym_blkid_encode_string(value, s, sizeof(s));
udev_builtin_add_property(event, "ID_FS_UUID_SUB_ENC", s); udev_builtin_add_property(event, "ID_FS_UUID_SUB_ENC", s);
} else if (streq(name, "LABEL")) { } else if (streq(name, "LABEL")) {
blkid_safe_string(value, s, sizeof(s)); sym_blkid_safe_string(value, s, sizeof(s));
udev_builtin_add_property(event, "ID_FS_LABEL", s); udev_builtin_add_property(event, "ID_FS_LABEL", s);
blkid_encode_string(value, s, sizeof(s)); sym_blkid_encode_string(value, s, sizeof(s));
udev_builtin_add_property(event, "ID_FS_LABEL_ENC", s); udev_builtin_add_property(event, "ID_FS_LABEL_ENC", s);
} else if (STR_IN_SET(name, "FSSIZE", "FSLASTBLOCK", "FSBLOCKSIZE")) { } else if (STR_IN_SET(name, "FSSIZE", "FSLASTBLOCK", "FSBLOCKSIZE")) {
@ -77,11 +77,11 @@ static void print_property(UdevEvent *event, const char *name, const char *value
udev_builtin_add_property(event, "ID_PART_TABLE_UUID", value); udev_builtin_add_property(event, "ID_PART_TABLE_UUID", value);
} else if (streq(name, "PART_ENTRY_NAME")) { } else if (streq(name, "PART_ENTRY_NAME")) {
blkid_encode_string(value, s, sizeof(s)); sym_blkid_encode_string(value, s, sizeof(s));
udev_builtin_add_property(event, "ID_PART_ENTRY_NAME", s); udev_builtin_add_property(event, "ID_PART_ENTRY_NAME", s);
} else if (streq(name, "PART_ENTRY_TYPE")) { } else if (streq(name, "PART_ENTRY_TYPE")) {
blkid_encode_string(value, s, sizeof(s)); sym_blkid_encode_string(value, s, sizeof(s));
udev_builtin_add_property(event, "ID_PART_ENTRY_TYPE", s); udev_builtin_add_property(event, "ID_PART_ENTRY_TYPE", s);
} else if (startswith(name, "PART_ENTRY_")) { } else if (startswith(name, "PART_ENTRY_")) {
@ -89,35 +89,35 @@ static void print_property(UdevEvent *event, const char *name, const char *value
udev_builtin_add_property(event, s, value); udev_builtin_add_property(event, s, value);
} else if (streq(name, "SYSTEM_ID")) { } else if (streq(name, "SYSTEM_ID")) {
blkid_encode_string(value, s, sizeof(s)); sym_blkid_encode_string(value, s, sizeof(s));
udev_builtin_add_property(event, "ID_FS_SYSTEM_ID", s); udev_builtin_add_property(event, "ID_FS_SYSTEM_ID", s);
} else if (streq(name, "PUBLISHER_ID")) { } else if (streq(name, "PUBLISHER_ID")) {
blkid_encode_string(value, s, sizeof(s)); sym_blkid_encode_string(value, s, sizeof(s));
udev_builtin_add_property(event, "ID_FS_PUBLISHER_ID", s); udev_builtin_add_property(event, "ID_FS_PUBLISHER_ID", s);
} else if (streq(name, "APPLICATION_ID")) { } else if (streq(name, "APPLICATION_ID")) {
blkid_encode_string(value, s, sizeof(s)); sym_blkid_encode_string(value, s, sizeof(s));
udev_builtin_add_property(event, "ID_FS_APPLICATION_ID", s); udev_builtin_add_property(event, "ID_FS_APPLICATION_ID", s);
} else if (streq(name, "BOOT_SYSTEM_ID")) { } else if (streq(name, "BOOT_SYSTEM_ID")) {
blkid_encode_string(value, s, sizeof(s)); sym_blkid_encode_string(value, s, sizeof(s));
udev_builtin_add_property(event, "ID_FS_BOOT_SYSTEM_ID", s); udev_builtin_add_property(event, "ID_FS_BOOT_SYSTEM_ID", s);
} else if (streq(name, "VOLUME_ID")) { } else if (streq(name, "VOLUME_ID")) {
blkid_encode_string(value, s, sizeof(s)); sym_blkid_encode_string(value, s, sizeof(s));
udev_builtin_add_property(event, "ID_FS_VOLUME_ID", s); udev_builtin_add_property(event, "ID_FS_VOLUME_ID", s);
} else if (streq(name, "LOGICAL_VOLUME_ID")) { } else if (streq(name, "LOGICAL_VOLUME_ID")) {
blkid_encode_string(value, s, sizeof(s)); sym_blkid_encode_string(value, s, sizeof(s));
udev_builtin_add_property(event, "ID_FS_LOGICAL_VOLUME_ID", s); udev_builtin_add_property(event, "ID_FS_LOGICAL_VOLUME_ID", s);
} else if (streq(name, "VOLUME_SET_ID")) { } else if (streq(name, "VOLUME_SET_ID")) {
blkid_encode_string(value, s, sizeof(s)); sym_blkid_encode_string(value, s, sizeof(s));
udev_builtin_add_property(event, "ID_FS_VOLUME_SET_ID", s); udev_builtin_add_property(event, "ID_FS_VOLUME_SET_ID", s);
} else if (streq(name, "DATA_PREPARER_ID")) { } else if (streq(name, "DATA_PREPARER_ID")) {
blkid_encode_string(value, s, sizeof(s)); sym_blkid_encode_string(value, s, sizeof(s));
udev_builtin_add_property(event, "ID_FS_DATA_PREPARER_ID", s); udev_builtin_add_property(event, "ID_FS_DATA_PREPARER_ID", s);
} }
} }
@ -222,7 +222,7 @@ static int find_gpt_root(UdevEvent *event, blkid_probe pr, const char *loop_back
} }
errno = 0; errno = 0;
blkid_partlist pl = blkid_probe_get_partitions(pr); blkid_partlist pl = sym_blkid_probe_get_partitions(pr);
if (!pl) if (!pl)
return log_device_debug_errno(dev, errno_or_else(ENOMEM), "Failed to probe partitions: %m"); return log_device_debug_errno(dev, errno_or_else(ENOMEM), "Failed to probe partitions: %m");
@ -233,7 +233,7 @@ static int find_gpt_root(UdevEvent *event, blkid_probe pr, const char *loop_back
/* If we already know the root partition, let's verify its type ID and then directly query /* If we already know the root partition, let's verify its type ID and then directly query
* its ID */ * its ID */
blkid_partition root_partition = blkid_partlist_devno_to_partition(pl, root_devno); blkid_partition root_partition = sym_blkid_partlist_devno_to_partition(pl, root_devno);
if (root_partition) { if (root_partition) {
sd_id128_t type; sd_id128_t type;
r = blkid_partition_get_type_id128(root_partition, &type); r = blkid_partition_get_type_id128(root_partition, &type);
@ -249,13 +249,13 @@ static int find_gpt_root(UdevEvent *event, blkid_probe pr, const char *loop_back
/* We do not know the root partition, let's search for it. */ /* We do not know the root partition, let's search for it. */
_cleanup_free_ char *root_label = NULL; _cleanup_free_ char *root_label = NULL;
int nvals = blkid_partlist_numof_partitions(pl); int nvals = sym_blkid_partlist_numof_partitions(pl);
for (int i = 0; i < nvals; i++) { for (int i = 0; i < nvals; i++) {
blkid_partition pp; blkid_partition pp;
const char *label; const char *label;
sd_id128_t type, id; sd_id128_t type, id;
pp = blkid_partlist_get_partition(pl, i); pp = sym_blkid_partlist_get_partition(pl, i);
if (!pp) if (!pp)
continue; continue;
@ -271,7 +271,7 @@ static int find_gpt_root(UdevEvent *event, blkid_probe pr, const char *loop_back
continue; continue;
} }
label = blkid_partition_get_name(pp); /* returns NULL if empty */ label = sym_blkid_partition_get_name(pp); /* returns NULL if empty */
if (need_esp_or_xbootldr && sd_id128_in_set(type, SD_GPT_ESP, SD_GPT_XBOOTLDR)) { if (need_esp_or_xbootldr && sd_id128_in_set(type, SD_GPT_ESP, SD_GPT_XBOOTLDR)) {
@ -282,7 +282,7 @@ static int find_gpt_root(UdevEvent *event, blkid_probe pr, const char *loop_back
} else if (sd_id128_equal(type, SD_GPT_ROOT_NATIVE)) { } else if (sd_id128_equal(type, SD_GPT_ROOT_NATIVE)) {
unsigned long long flags; unsigned long long flags;
flags = blkid_partition_get_flags(pp); flags = sym_blkid_partition_get_flags(pp);
if (flags & SD_GPT_FLAG_NO_AUTO) if (flags & SD_GPT_FLAG_NO_AUTO)
continue; continue;
@ -322,32 +322,32 @@ static int probe_superblocks(blkid_probe pr) {
/* TODO: Return negative errno. */ /* TODO: Return negative errno. */
if (fstat(blkid_probe_get_fd(pr), &st)) if (fstat(sym_blkid_probe_get_fd(pr), &st))
return -errno; return -errno;
blkid_probe_enable_partitions(pr, 1); sym_blkid_probe_enable_partitions(pr, 1);
if (!S_ISCHR(st.st_mode) && if (!S_ISCHR(st.st_mode) &&
blkid_probe_get_size(pr) <= 1024 * 1440 && sym_blkid_probe_get_size(pr) <= 1024 * 1440 &&
blkid_probe_is_wholedisk(pr)) { sym_blkid_probe_is_wholedisk(pr)) {
/* /*
* check if the small disk is partitioned, if yes then * check if the small disk is partitioned, if yes then
* don't probe for filesystems. * don't probe for filesystems.
*/ */
blkid_probe_enable_superblocks(pr, 0); sym_blkid_probe_enable_superblocks(pr, 0);
rc = blkid_do_fullprobe(pr); rc = sym_blkid_do_fullprobe(pr);
if (rc < 0) if (rc < 0)
return rc; /* -1 = error, 1 = nothing, 0 = success */ return rc; /* -1 = error, 1 = nothing, 0 = success */
if (blkid_probe_lookup_value(pr, "PTTYPE", NULL, NULL) == 0) if (sym_blkid_probe_lookup_value(pr, "PTTYPE", NULL, NULL) == 0)
return 0; /* partition table detected */ return 0; /* partition table detected */
} }
blkid_probe_set_partitions_flags(pr, BLKID_PARTS_ENTRY_DETAILS); sym_blkid_probe_set_partitions_flags(pr, BLKID_PARTS_ENTRY_DETAILS);
blkid_probe_enable_superblocks(pr, 1); sym_blkid_probe_enable_superblocks(pr, 1);
return blkid_do_safeprobe(pr); return sym_blkid_do_safeprobe(pr);
} }
static int read_loopback_backing_inode( static int read_loopback_backing_inode(
@ -440,8 +440,12 @@ static int builtin_blkid(UdevEvent *event, int argc, char *argv[]) {
{} {}
}; };
r = dlopen_libblkid();
if (r < 0)
return log_device_debug_errno(dev, r, "blkid not available: %m");
errno = 0; errno = 0;
pr = blkid_new_probe(); pr = sym_blkid_new_probe();
if (!pr) if (!pr)
return log_device_debug_errno(dev, errno_or_else(ENOMEM), "Failed to create blkid prober: %m"); return log_device_debug_errno(dev, errno_or_else(ENOMEM), "Failed to create blkid prober: %m");
@ -456,7 +460,7 @@ static int builtin_blkid(UdevEvent *event, int argc, char *argv[]) {
case 'H': case 'H':
#if HAVE_BLKID_PROBE_SET_HINT #if HAVE_BLKID_PROBE_SET_HINT
errno = 0; errno = 0;
r = blkid_probe_set_hint(pr, optarg, 0); r = sym_blkid_probe_set_hint(pr, optarg, 0);
if (r < 0) if (r < 0)
return log_device_error_errno(dev, errno_or_else(ENOMEM), "Failed to use '%s' probing hint: %m", optarg); return log_device_error_errno(dev, errno_or_else(ENOMEM), "Failed to use '%s' probing hint: %m", optarg);
break; break;
@ -482,7 +486,7 @@ static int builtin_blkid(UdevEvent *event, int argc, char *argv[]) {
} }
} }
blkid_probe_set_superblocks_flags(pr, sym_blkid_probe_set_superblocks_flags(pr,
BLKID_SUBLKS_LABEL | BLKID_SUBLKS_UUID | BLKID_SUBLKS_LABEL | BLKID_SUBLKS_UUID |
BLKID_SUBLKS_TYPE | BLKID_SUBLKS_SECTYPE | BLKID_SUBLKS_TYPE | BLKID_SUBLKS_SECTYPE |
#ifdef BLKID_SUBLKS_FSINFO #ifdef BLKID_SUBLKS_FSINFO
@ -491,7 +495,7 @@ static int builtin_blkid(UdevEvent *event, int argc, char *argv[]) {
BLKID_SUBLKS_USAGE | BLKID_SUBLKS_VERSION); BLKID_SUBLKS_USAGE | BLKID_SUBLKS_VERSION);
if (noraid) if (noraid)
blkid_probe_filter_superblocks_usage(pr, BLKID_FLTR_NOTIN, BLKID_USAGE_RAID); sym_blkid_probe_filter_superblocks_usage(pr, BLKID_FLTR_NOTIN, BLKID_USAGE_RAID);
r = sd_device_get_devname(dev, &devnode); r = sd_device_get_devname(dev, &devnode);
if (r < 0) if (r < 0)
@ -506,7 +510,7 @@ static int builtin_blkid(UdevEvent *event, int argc, char *argv[]) {
} }
errno = 0; errno = 0;
r = blkid_probe_set_device(pr, fd, offset, 0); r = sym_blkid_probe_set_device(pr, fd, offset, 0);
if (r < 0) if (r < 0)
return log_device_debug_errno(dev, errno_or_else(ENOMEM), "Failed to set device to blkid prober: %m"); return log_device_debug_errno(dev, errno_or_else(ENOMEM), "Failed to set device to blkid prober: %m");
@ -520,12 +524,12 @@ static int builtin_blkid(UdevEvent *event, int argc, char *argv[]) {
(void) sd_device_get_property_value(dev, "ID_PART_GPT_AUTO_ROOT_UUID", &root_partition); (void) sd_device_get_property_value(dev, "ID_PART_GPT_AUTO_ROOT_UUID", &root_partition);
errno = 0; errno = 0;
int nvals = blkid_probe_numof_values(pr); int nvals = sym_blkid_probe_numof_values(pr);
if (nvals < 0) if (nvals < 0)
return log_device_debug_errno(dev, errno_or_else(ENOMEM), "Failed to get number of probed values: %m"); return log_device_debug_errno(dev, errno_or_else(ENOMEM), "Failed to get number of probed values: %m");
for (int i = 0; i < nvals; i++) { for (int i = 0; i < nvals; i++) {
if (blkid_probe_get_value(pr, i, &name, &data, NULL) < 0) if (sym_blkid_probe_get_value(pr, i, &name, &data, NULL) < 0)
continue; continue;
print_property(event, name, data); print_property(event, name, data);
@ -559,7 +563,7 @@ static int builtin_blkid(UdevEvent *event, int argc, char *argv[]) {
char encoded[sizeof_field(struct loop_info64, lo_file_name) * 4 + 1]; char encoded[sizeof_field(struct loop_info64, lo_file_name) * 4 + 1];
assert(strlen(backing_fname) < ELEMENTSOF(encoded) / 4); assert(strlen(backing_fname) < ELEMENTSOF(encoded) / 4);
blkid_encode_string(backing_fname, encoded, ELEMENTSOF(encoded)); sym_blkid_encode_string(backing_fname, encoded, ELEMENTSOF(encoded));
udev_builtin_add_property(event, "ID_LOOP_BACKING_FILENAME", backing_fname); udev_builtin_add_property(event, "ID_LOOP_BACKING_FILENAME", backing_fname);
udev_builtin_add_property(event, "ID_LOOP_BACKING_FILENAME_ENC", encoded); udev_builtin_add_property(event, "ID_LOOP_BACKING_FILENAME_ENC", encoded);

View File

@ -8,7 +8,7 @@ executables += [
], ],
'sources' : files('validatefs.c'), 'sources' : files('validatefs.c'),
'dependencies' : [ 'dependencies' : [
libblkid, libblkid_cflags,
], ],
}, },
] ]

View File

@ -257,7 +257,7 @@ static int validate_gpt_label(blkid_probe b, const ValidateFields *f) {
return 0; return 0;
const char *v = NULL; const char *v = NULL;
(void) blkid_probe_lookup_value(b, "PART_ENTRY_NAME", &v, /* len= */ NULL); (void) sym_blkid_probe_lookup_value(b, "PART_ENTRY_NAME", &v, /* len= */ NULL);
if (strv_contains(f->gpt_label, strempty(v))) if (strv_contains(f->gpt_label, strempty(v)))
return 0; return 0;
@ -277,7 +277,7 @@ static int validate_gpt_type(blkid_probe b, const ValidateFields *f) {
return 0; return 0;
const char *v = NULL; const char *v = NULL;
(void) blkid_probe_lookup_value(b, "PART_ENTRY_TYPE", &v, /* len= */ NULL); (void) sym_blkid_probe_lookup_value(b, "PART_ENTRY_TYPE", &v, /* len= */ NULL);
sd_id128_t id; sd_id128_t id;
if (!v || sd_id128_from_string(v, &id) < 0) { if (!v || sd_id128_from_string(v, &id) < 0) {
@ -305,26 +305,30 @@ static int validate_gpt_metadata_one(sd_device *d, const char *path, const Valid
assert(d); assert(d);
assert(f); assert(f);
r = dlopen_libblkid();
if (r < 0)
return log_error_errno(r, "Cannot validate GPT constraints, refusing.");
_cleanup_close_ int block_fd = sd_device_open(d, O_RDONLY|O_CLOEXEC|O_NONBLOCK); _cleanup_close_ int block_fd = sd_device_open(d, O_RDONLY|O_CLOEXEC|O_NONBLOCK);
if (block_fd < 0) if (block_fd < 0)
return log_error_errno(block_fd, "Failed to open block device backing '%s': %m", path); return log_error_errno(block_fd, "Failed to open block device backing '%s': %m", path);
_cleanup_(blkid_free_probep) blkid_probe b = blkid_new_probe(); _cleanup_(blkid_free_probep) blkid_probe b = sym_blkid_new_probe();
if (!b) if (!b)
return log_oom(); return log_oom();
errno = 0; errno = 0;
r = blkid_probe_set_device(b, block_fd, 0, 0); r = sym_blkid_probe_set_device(b, block_fd, 0, 0);
if (r != 0) if (r != 0)
return log_error_errno(errno_or_else(ENOMEM), "Failed to set up block device prober for '%s': %m", path); return log_error_errno(errno_or_else(ENOMEM), "Failed to set up block device prober for '%s': %m", path);
(void) blkid_probe_enable_superblocks(b, 1); (void) sym_blkid_probe_enable_superblocks(b, 1);
(void) blkid_probe_set_superblocks_flags(b, BLKID_SUBLKS_TYPE|BLKID_SUBLKS_LABEL); (void) sym_blkid_probe_set_superblocks_flags(b, BLKID_SUBLKS_TYPE|BLKID_SUBLKS_LABEL);
(void) blkid_probe_enable_partitions(b, 1); (void) sym_blkid_probe_enable_partitions(b, 1);
(void) blkid_probe_set_partitions_flags(b, BLKID_PARTS_ENTRY_DETAILS); (void) sym_blkid_probe_set_partitions_flags(b, BLKID_PARTS_ENTRY_DETAILS);
errno = 0; errno = 0;
r = blkid_do_safeprobe(b); r = sym_blkid_do_safeprobe(b);
if (r == _BLKID_SAFEPROBE_ERROR) if (r == _BLKID_SAFEPROBE_ERROR)
return log_error_errno(errno_or_else(EIO), "Failed to probe block device of '%s': %m", path); return log_error_errno(errno_or_else(EIO), "Failed to probe block device of '%s': %m", path);
if (r == _BLKID_SAFEPROBE_AMBIGUOUS) if (r == _BLKID_SAFEPROBE_AMBIGUOUS)
@ -335,7 +339,7 @@ static int validate_gpt_metadata_one(sd_device *d, const char *path, const Valid
assert(r == _BLKID_SAFEPROBE_FOUND); assert(r == _BLKID_SAFEPROBE_FOUND);
const char *v = NULL; const char *v = NULL;
(void) blkid_probe_lookup_value(b, "PART_ENTRY_SCHEME", &v, /* len= */ NULL); (void) sym_blkid_probe_lookup_value(b, "PART_ENTRY_SCHEME", &v, /* len= */ NULL);
if (!streq_ptr(v, "gpt")) if (!streq_ptr(v, "gpt"))
return log_error_errno(SYNTHETIC_ERRNO(EPERM), "File system is supposed to be on a GPT partition table, but is not, refusing."); return log_error_errno(SYNTHETIC_ERRNO(EPERM), "File system is supposed to be on a GPT partition table, but is not, refusing.");

View File

@ -21,7 +21,6 @@ executables += [
'public' : true, 'public' : true,
'sources' : vmspawn_sources + vmspawn_extract_sources, 'sources' : vmspawn_sources + vmspawn_extract_sources,
'extract' : vmspawn_extract_sources, 'extract' : vmspawn_extract_sources,
'dependencies' : [libblkid]
}, },
test_template + { test_template + {
'sources' : files('test-vmspawn-util.c'), 'sources' : files('test-vmspawn-util.c'),

View File

@ -8,7 +8,7 @@
# (at your option) any later version. # (at your option) any later version.
[Unit] [Unit]
Description=First Boot Wizard Description=Initial Setup
Documentation=man:systemd-firstboot(1) Documentation=man:systemd-firstboot(1)
ConditionPathIsReadWrite=/etc ConditionPathIsReadWrite=/etc