mirror of
https://github.com/systemd/systemd
synced 2026-04-24 07:55:12 +02:00
Compare commits
24 Commits
d88ecd2bca
...
de425dc72c
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
de425dc72c | ||
|
|
4b2b2f3ab7 | ||
|
|
c349edfe49 | ||
|
|
d71f2899bd | ||
|
|
77adf896ca | ||
|
|
938442ac27 | ||
|
|
faa3cc2974 | ||
|
|
513d91a159 | ||
|
|
d7b966ad13 | ||
|
|
875a618ed3 | ||
|
|
73ee723aa7 | ||
|
|
8191bbd23c | ||
|
|
71f3f1818f | ||
|
|
32e0af0835 | ||
|
|
30aeab7883 | ||
|
|
fa350969ab | ||
|
|
74b8ab014b | ||
|
|
d80af3b97b | ||
|
|
4284ef2f95 | ||
|
|
e27a530919 | ||
|
|
f417a984c9 | ||
|
|
8d36341cef | ||
|
|
63dd548fb4 | ||
|
|
2e3c792baf |
@ -63,6 +63,10 @@ node /org/freedesktop/machine1 {
|
||||
in ai ifindices,
|
||||
in a(sv) scope_properties,
|
||||
out o path);
|
||||
CreateMachineEx(in s name,
|
||||
in a(sv) properties,
|
||||
in a(sv) scope_properties,
|
||||
out o path);
|
||||
RegisterMachine(in s name,
|
||||
in ay id,
|
||||
in s service,
|
||||
@ -78,6 +82,9 @@ node /org/freedesktop/machine1 {
|
||||
in s root_directory,
|
||||
in ai ifindices,
|
||||
out o path);
|
||||
RegisterMachineEx(in s name,
|
||||
in a(sv) properties,
|
||||
out o path);
|
||||
UnregisterMachine(in s name);
|
||||
TerminateMachine(in s id);
|
||||
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="CreateMachineEx()"/>
|
||||
|
||||
<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="RegisterMachineEx()"/>
|
||||
|
||||
<variablelist class="dbus-method" generated="True" extra-ref="UnregisterMachine()"/>
|
||||
|
||||
<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
|
||||
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
|
||||
<function>RegisterMachineWithNetwork()</function> are similar to <function>CreateMachine()</function>
|
||||
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>,
|
||||
<varname>SupervisorPIDFDId</varname>, <varname>Subgroup</varname>, and <varname>UID</varname> were added
|
||||
in version 258.</para>
|
||||
<para><function>CreateMachineEx()</function>, and <function>RegisterMachineEx()</function> were added
|
||||
in version 259.</para>
|
||||
</refsect2>
|
||||
</refsect1>
|
||||
|
||||
|
||||
@ -439,15 +439,26 @@
|
||||
<varlistentry>
|
||||
<term><varname>ANSI_COLOR=</varname></term>
|
||||
|
||||
<listitem><para>A suggested presentation color when showing the OS name on the console. This should
|
||||
be specified as string suitable for inclusion in the ESC [ m ANSI/ECMA-48 escape code for setting
|
||||
graphical rendition. This field is optional.</para>
|
||||
<listitem><para>A suggested presentation (foreground) text color when showing the OS name on the
|
||||
console. This should be specified as string suitable for inclusion in the ESC [ m ANSI/ECMA-48
|
||||
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>
|
||||
for light blue, or <literal>ANSI_COLOR="0;38;2;60;110;180"</literal> for Fedora blue.
|
||||
</para></listitem>
|
||||
</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>
|
||||
<term><varname>VENDOR_NAME=</varname></term>
|
||||
|
||||
|
||||
@ -42,7 +42,7 @@
|
||||
<para>Some of the functionality is also available 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>
|
||||
units.</para>
|
||||
units).</para>
|
||||
|
||||
<para>See <ulink url="https://systemd.io/FACTORY_RESET">Factory Reset</ulink> for an overview of the
|
||||
factory reset logic.</para>
|
||||
|
||||
@ -344,6 +344,16 @@
|
||||
<xi:include href="version-info.xml" xpointer="v246"/></listitem>
|
||||
</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="version" />
|
||||
</variablelist>
|
||||
|
||||
@ -1195,6 +1195,7 @@ libblkid = dependency('blkid',
|
||||
conf.set10('HAVE_BLKID', libblkid.found())
|
||||
conf.set10('HAVE_BLKID_PROBE_SET_HINT',
|
||||
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',
|
||||
version : '>= 15',
|
||||
|
||||
@ -88,6 +88,12 @@ const char* glyph_full(Glyph code, bool force_utf) {
|
||||
[GLYPH_SUPERHERO] = "S",
|
||||
[GLYPH_IDCARD] = "@",
|
||||
[GLYPH_HOME] = "^",
|
||||
[GLYPH_ROCKET] = "^",
|
||||
[GLYPH_BROOM] = "/",
|
||||
[GLYPH_KEYBOARD] = "K",
|
||||
[GLYPH_CLOCK] = "O",
|
||||
[GLYPH_LABEL] = "L",
|
||||
[GLYPH_SHELL] = "$",
|
||||
},
|
||||
|
||||
/* UTF-8 */
|
||||
@ -155,7 +161,6 @@ const char* glyph_full(Glyph code, bool force_utf) {
|
||||
[GLYPH_WARNING_SIGN] = UTF8("⚠️"),
|
||||
[GLYPH_COMPUTER_DISK] = UTF8("💽"),
|
||||
[GLYPH_WORLD] = UTF8("🌍"),
|
||||
|
||||
[GLYPH_RED_CIRCLE] = UTF8("🔴"),
|
||||
[GLYPH_YELLOW_CIRCLE] = UTF8("🟡"),
|
||||
[GLYPH_BLUE_CIRCLE] = UTF8("🔵"),
|
||||
@ -163,6 +168,12 @@ const char* glyph_full(Glyph code, bool force_utf) {
|
||||
[GLYPH_SUPERHERO] = UTF8("🦸"),
|
||||
[GLYPH_IDCARD] = UTF8("🪪"),
|
||||
[GLYPH_HOME] = UTF8("🏠"),
|
||||
[GLYPH_ROCKET] = UTF8("🚀"),
|
||||
[GLYPH_BROOM] = UTF8("🧹"),
|
||||
[GLYPH_KEYBOARD] = UTF8("⌨️"),
|
||||
[GLYPH_CLOCK] = UTF8("🕗"),
|
||||
[GLYPH_LABEL] = UTF8("🏷️"),
|
||||
[GLYPH_SHELL] = UTF8("🐚"),
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
@ -56,6 +56,12 @@ typedef enum Glyph {
|
||||
GLYPH_SUPERHERO,
|
||||
GLYPH_IDCARD,
|
||||
GLYPH_HOME,
|
||||
GLYPH_ROCKET,
|
||||
GLYPH_BROOM,
|
||||
GLYPH_KEYBOARD,
|
||||
GLYPH_CLOCK,
|
||||
GLYPH_LABEL,
|
||||
GLYPH_SHELL,
|
||||
_GLYPH_MAX,
|
||||
_GLYPH_INVALID = -EINVAL,
|
||||
} Glyph;
|
||||
|
||||
@ -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_; \
|
||||
((long)(_current_ - _entries_) < (long)(ELEMENTSOF(_entries_) - 1)) && ({ entry = *_current_; true; }); \
|
||||
_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)
|
||||
|
||||
@ -1855,6 +1855,226 @@ int terminal_set_cursor_position(int fd, unsigned row, unsigned column) {
|
||||
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 r = 0;
|
||||
|
||||
@ -1894,37 +2114,6 @@ void termios_disable_echo(struct termios *termios) {
|
||||
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 {
|
||||
BACKGROUND_TEXT,
|
||||
BACKGROUND_ESCAPE,
|
||||
@ -2174,86 +2363,6 @@ finish:
|
||||
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 input_fd,
|
||||
int output_fd,
|
||||
|
||||
@ -46,6 +46,7 @@ int terminal_reset_defensive(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_get_cursor_position(int input_fd, int output_fd, unsigned *ret_rows, unsigned *ret_column);
|
||||
|
||||
int open_terminal(const char *name, int mode);
|
||||
|
||||
|
||||
@ -19,7 +19,6 @@ executables += [
|
||||
],
|
||||
'sources' : files('bless-boot.c'),
|
||||
'link_with' : boot_link_with,
|
||||
'dependencies' : libblkid,
|
||||
},
|
||||
generator_template + {
|
||||
'name' : 'systemd-bless-boot-generator',
|
||||
|
||||
@ -244,7 +244,7 @@ static char16_t* update_timeout_efivar(Config *config, bool inc) {
|
||||
case TIMEOUT_MENU_HIDDEN:
|
||||
return xstrdup16(u"Menu hidden. Hold down key at bootup to show menu.");
|
||||
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:
|
||||
return (void) printf("%s: menu-hidden\n", label);
|
||||
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(" 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-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) {
|
||||
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;
|
||||
_cleanup_strv_free_ char16_t **lines = NULL;
|
||||
_cleanup_free_ char16_t *clearline = NULL, *separator = NULL, *status = NULL;
|
||||
uint64_t timeout_efivar_saved = config->timeout_sec_efivar;
|
||||
uint32_t timeout_remain = config->timeout_sec == TIMEOUT_MENU_FORCE ? 0 : config->timeout_sec;
|
||||
uint64_t timeout_efivar_saved = config->timeout_sec_efivar,
|
||||
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;
|
||||
size_t default_efivar_saved = config->idx_default_efivar;
|
||||
|
||||
@ -495,8 +495,9 @@ static bool menu_run(
|
||||
ST->ConIn->Reset(ST->ConIn, false);
|
||||
ST->ConOut->EnableCursor(ST->ConOut, false);
|
||||
|
||||
/* draw a single character to make ClearScreen work on some firmware */
|
||||
ST->ConOut->OutputString(ST->ConOut, (char16_t *) u" ");
|
||||
/* Draw a single character to the beginning of a line, in order to make ClearScreen() work on certain
|
||||
* 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 ?
|
||||
config->console_mode_efivar : config->console_mode);
|
||||
@ -622,7 +623,7 @@ static bool menu_run(
|
||||
|
||||
if (timeout_remain > 0) {
|
||||
free(status);
|
||||
status = xasprintf("Boot in %u s.", timeout_remain);
|
||||
status = xasprintf("Boot in %"PRIu64"s.", timeout_remain);
|
||||
}
|
||||
|
||||
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;
|
||||
else {
|
||||
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",
|
||||
value);
|
||||
continue;
|
||||
|
||||
@ -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.
|
||||
*
|
||||
* Supported:
|
||||
@ -983,7 +1014,7 @@ _printf_(2, 0) static char16_t *printf_internal(EFI_STATUS status, const char *f
|
||||
}
|
||||
|
||||
#if SD_BOOT
|
||||
ST->ConOut->OutputString(ST->ConOut, ctx.buf);
|
||||
output_string_safe(ST->ConOut, ctx.buf);
|
||||
#endif
|
||||
|
||||
return mfree(ctx.dyn_buf);
|
||||
|
||||
@ -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");
|
||||
|
||||
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);
|
||||
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--;
|
||||
continue;
|
||||
}
|
||||
|
||||
printf("\n");
|
||||
|
||||
if (err != EFI_SUCCESS)
|
||||
return log_error_status(
|
||||
err,
|
||||
|
||||
@ -19,10 +19,10 @@ typedef enum {
|
||||
} secure_boot_enroll_action;
|
||||
|
||||
enum {
|
||||
ENROLL_TIMEOUT_HIDDEN = 0,
|
||||
ENROLL_TIMEOUT_MIN = 1,
|
||||
ENROLL_TIMEOUT_DEFAULT = 15,
|
||||
ENROLL_TIMEOUT_TYPE_MAX = UINT32_MAX,
|
||||
ENROLL_TIMEOUT_HIDDEN = 0,
|
||||
ENROLL_TIMEOUT_MIN = 1,
|
||||
ENROLL_TIMEOUT_DEFAULT = 15,
|
||||
ENROLL_TIMEOUT_MAX = UINT32_MAX,
|
||||
};
|
||||
|
||||
bool secure_boot_enabled(void);
|
||||
|
||||
@ -195,16 +195,27 @@ EFI_STATUS file_read(
|
||||
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) {
|
||||
assert(str);
|
||||
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);
|
||||
}
|
||||
|
||||
void clear_screen(size_t attr) {
|
||||
log_wait();
|
||||
ST->ConOut->SetAttribute(ST->ConOut, attr);
|
||||
set_attribute_safe(attr);
|
||||
ST->ConOut->ClearScreen(ST->ConOut);
|
||||
}
|
||||
|
||||
|
||||
@ -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], \
|
||||
(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 clear_screen(size_t attr);
|
||||
|
||||
|
||||
@ -20,6 +20,6 @@ executables += [
|
||||
],
|
||||
'sources' : bootctl_sources,
|
||||
'link_with' : boot_link_with,
|
||||
'dependencies' : [libblkid, libopenssl],
|
||||
'dependencies' : [libopenssl],
|
||||
},
|
||||
]
|
||||
|
||||
@ -132,7 +132,6 @@ libcore_static = static_library(
|
||||
implicit_include_directories : false,
|
||||
c_args : ['-fvisibility=default'],
|
||||
dependencies : [libaudit_cflags,
|
||||
libblkid,
|
||||
libdl,
|
||||
libm,
|
||||
libmount,
|
||||
|
||||
@ -45,6 +45,7 @@
|
||||
#include "path-util.h"
|
||||
#include "pretty-print.h"
|
||||
#include "proc-cmdline.h"
|
||||
#include "prompt-util.h"
|
||||
#include "runtime-scope.h"
|
||||
#include "smack-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_reset = false;
|
||||
static ImagePolicy *arg_image_policy = NULL;
|
||||
static bool arg_chrome = true;
|
||||
|
||||
STATIC_DESTRUCTOR_REGISTER(arg_root, freep);
|
||||
STATIC_DESTRUCTOR_REGISTER(arg_image, freep);
|
||||
@ -113,6 +115,11 @@ static void print_welcome(int rfd) {
|
||||
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,
|
||||
"PRETTY_NAME", &pretty_name,
|
||||
"NAME", &os_name,
|
||||
@ -124,13 +131,10 @@ static void print_welcome(int rfd) {
|
||||
pn = os_release_pretty_name(pretty_name, os_name);
|
||||
ac = isempty(ansi_color) ? "0" : ansi_color;
|
||||
|
||||
(void) terminal_reset_defensive_locked(STDOUT_FILENO, /* flags= */ 0);
|
||||
|
||||
if (colors_enabled())
|
||||
printf("\n"
|
||||
ANSI_HIGHLIGHT "Welcome to your new installation of " ANSI_NORMAL "\x1B[%sm%s" ANSI_HIGHLIGHT "!" ANSI_NORMAL "\n", ac, pn);
|
||||
printf(ANSI_HIGHLIGHT "Welcome to your new installation of " ANSI_NORMAL "\x1B[%sm%s" ANSI_HIGHLIGHT "!" ANSI_NORMAL "\n", ac, pn);
|
||||
else
|
||||
printf("\nWelcome to your new installation of %s!\n", pn);
|
||||
printf("Welcome to your new installation of %s!\n", pn);
|
||||
|
||||
putchar('\n');
|
||||
if (emoji_enabled()) {
|
||||
@ -144,102 +148,6 @@ static void print_welcome(int rfd) {
|
||||
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(©, "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) {
|
||||
_cleanup_fclose_ FILE *passwd = NULL, *shadow = NULL;
|
||||
int r;
|
||||
@ -309,20 +217,14 @@ static int should_configure(int dir_fd, const char *filename) {
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool locale_is_installed_bool(const char *name) {
|
||||
return locale_is_installed(name) > 0;
|
||||
}
|
||||
|
||||
static bool locale_is_ok(int rfd, const char *name) {
|
||||
int r;
|
||||
|
||||
assert(rfd >= 0);
|
||||
static int locale_is_ok(const char *name, void *userdata) {
|
||||
int rfd = ASSERT_FD(PTR_TO_FD(userdata)), r;
|
||||
|
||||
r = dir_fd_is_root(rfd);
|
||||
if (r < 0)
|
||||
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) {
|
||||
@ -379,16 +281,35 @@ static int prompt_locale(int rfd) {
|
||||
} else {
|
||||
print_welcome(rfd);
|
||||
|
||||
r = prompt_loop(rfd, "Please enter the new system locale name or number",
|
||||
locales, 60, locale_is_ok, &arg_locale);
|
||||
r = prompt_loop("Please enter the new system locale name or number",
|
||||
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)
|
||||
return r;
|
||||
|
||||
if (isempty(arg_locale))
|
||||
return 0;
|
||||
|
||||
r = prompt_loop(rfd, "Please enter the new system message locale name or number",
|
||||
locales, 60, locale_is_ok, &arg_locale_messages);
|
||||
r = prompt_loop("Please enter the new system message locale name or number",
|
||||
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)
|
||||
return r;
|
||||
|
||||
@ -463,20 +384,14 @@ static int process_locale(int rfd) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
static bool keymap_exists_bool(const char *name) {
|
||||
return keymap_exists(name) > 0;
|
||||
}
|
||||
|
||||
static bool keymap_is_ok(int rfd, const char* name) {
|
||||
int r;
|
||||
|
||||
assert(rfd >= 0);
|
||||
static int keymap_is_ok(const char* name, void *userdata) {
|
||||
int rfd = ASSERT_FD(PTR_TO_FD(userdata)), r;
|
||||
|
||||
r = dir_fd_is_root(rfd);
|
||||
if (r < 0)
|
||||
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) {
|
||||
@ -509,8 +424,19 @@ static int prompt_keymap(int rfd) {
|
||||
|
||||
print_welcome(rfd);
|
||||
|
||||
return prompt_loop(rfd, "Please enter the new keymap name or number",
|
||||
kmaps, 60, keymap_is_ok, &arg_keymap);
|
||||
return prompt_loop(
|
||||
"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) {
|
||||
@ -578,9 +504,7 @@ static int process_keymap(int rfd) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
static bool timezone_is_ok(int rfd, const char *name) {
|
||||
assert(rfd >= 0);
|
||||
|
||||
static int timezone_is_ok(const char *name, void *userdata) {
|
||||
return timezone_is_valid(name, LOG_DEBUG);
|
||||
}
|
||||
|
||||
@ -612,8 +536,19 @@ static int prompt_timezone(int rfd) {
|
||||
|
||||
print_welcome(rfd);
|
||||
|
||||
return prompt_loop(rfd, "Please enter the new timezone name or number",
|
||||
zones, 30, timezone_is_ok, &arg_timezone);
|
||||
return prompt_loop(
|
||||
"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) {
|
||||
@ -677,9 +612,7 @@ static int process_timezone(int rfd) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool hostname_is_ok(int rfd, const char *name) {
|
||||
assert(rfd >= 0);
|
||||
|
||||
static int hostname_is_ok(const char *name, void *userdata) {
|
||||
return hostname_is_valid(name, VALID_HOSTNAME_TRAILING_DOT);
|
||||
}
|
||||
|
||||
@ -698,8 +631,18 @@ static int prompt_hostname(int rfd) {
|
||||
|
||||
print_welcome(rfd);
|
||||
|
||||
r = prompt_loop(rfd, "Please enter the new hostname",
|
||||
NULL, 0, hostname_is_ok, &arg_hostname);
|
||||
r = prompt_loop("Please enter the new 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)
|
||||
return r;
|
||||
|
||||
@ -796,8 +739,8 @@ static int prompt_root_password(int rfd) {
|
||||
|
||||
print_welcome(rfd);
|
||||
|
||||
msg1 = strjoina(glyph(GLYPH_TRIANGULAR_BULLET), " Please enter the new root password (empty to skip):");
|
||||
msg2 = strjoina(glyph(GLYPH_TRIANGULAR_BULLET), " Please enter the new root password again:");
|
||||
msg1 = strjoina("Please enter the new root password (empty to skip):");
|
||||
msg2 = strjoina("Please enter the new root password again:");
|
||||
|
||||
suggest_passwords();
|
||||
|
||||
@ -868,8 +811,8 @@ static int find_shell(int rfd, const char *path) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool shell_is_ok(int rfd, const char *path) {
|
||||
assert(rfd >= 0);
|
||||
static int shell_is_ok(const char *path, void *userdata) {
|
||||
int rfd = ASSERT_FD(PTR_TO_FD(userdata));
|
||||
|
||||
return find_shell(rfd, path) >= 0;
|
||||
}
|
||||
@ -897,8 +840,19 @@ static int prompt_root_shell(int rfd) {
|
||||
|
||||
print_welcome(rfd);
|
||||
|
||||
return prompt_loop(rfd, "Please enter the new root shell",
|
||||
NULL, 0, shell_is_ok, &arg_root_shell);
|
||||
return prompt_loop(
|
||||
"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) {
|
||||
@ -1254,8 +1208,8 @@ static int help(void) {
|
||||
if (r < 0)
|
||||
return log_oom();
|
||||
|
||||
printf("%s [OPTIONS...]\n\n"
|
||||
"Configures basic settings of the system.\n\n"
|
||||
printf("%1$s [OPTIONS...]\n"
|
||||
"\n%3$sConfigures basic settings of the system.%4$s\n\n"
|
||||
" -h --help Show this help\n"
|
||||
" --version Show package version\n"
|
||||
" --root=PATH Operate on an alternate filesystem root\n"
|
||||
@ -1290,10 +1244,14 @@ static int help(void) {
|
||||
" --force Overwrite existing files\n"
|
||||
" --delete-root-password Delete root password\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"
|
||||
"\nSee the %s for details.\n",
|
||||
"\nSee the %2$s for details.\n",
|
||||
program_invocation_short_name,
|
||||
link);
|
||||
link,
|
||||
ansi_highlight(),
|
||||
ansi_normal());
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -1333,6 +1291,7 @@ static int parse_argv(int argc, char *argv[]) {
|
||||
ARG_FORCE,
|
||||
ARG_DELETE_ROOT_PASSWORD,
|
||||
ARG_WELCOME,
|
||||
ARG_CHROME,
|
||||
ARG_RESET,
|
||||
};
|
||||
|
||||
@ -1370,6 +1329,7 @@ static int parse_argv(int argc, char *argv[]) {
|
||||
{ "force", no_argument, NULL, ARG_FORCE },
|
||||
{ "delete-root-password", no_argument, NULL, ARG_DELETE_ROOT_PASSWORD },
|
||||
{ "welcome", required_argument, NULL, ARG_WELCOME },
|
||||
{ "chrome", required_argument, NULL, ARG_CHROME },
|
||||
{ "reset", no_argument, NULL, ARG_RESET },
|
||||
{}
|
||||
};
|
||||
@ -1579,6 +1539,13 @@ static int parse_argv(int argc, char *argv[]) {
|
||||
arg_welcome = r;
|
||||
break;
|
||||
|
||||
case ARG_CHROME:
|
||||
r = parse_boolean_argument("--chrome=", optarg, &arg_chrome);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
break;
|
||||
|
||||
case ARG_RESET:
|
||||
arg_reset = true;
|
||||
break;
|
||||
@ -1723,15 +1690,16 @@ static int run(int argc, char *argv[]) {
|
||||
}
|
||||
|
||||
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
|
||||
* 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);
|
||||
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);
|
||||
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);
|
||||
|
||||
if (arg_root_shell) {
|
||||
|
||||
@ -5,6 +5,5 @@ executables += [
|
||||
'name' : 'systemd-gpt-auto-generator',
|
||||
'conditions' : ['HAVE_BLKID'],
|
||||
'sources' : files('gpt-auto-generator.c'),
|
||||
'dependencies' : libblkid,
|
||||
},
|
||||
]
|
||||
|
||||
@ -135,7 +135,7 @@ static int probe_file_system_by_fd(
|
||||
sd_id128_t *ret_uuid) {
|
||||
|
||||
_cleanup_(blkid_free_probep) blkid_probe b = NULL;
|
||||
const char *fstype = NULL, *uuid = NULL;
|
||||
const char *fstype = NULL;
|
||||
sd_id128_t id;
|
||||
int r;
|
||||
|
||||
@ -143,20 +143,24 @@ static int probe_file_system_by_fd(
|
||||
assert(ret_fstype);
|
||||
assert(ret_uuid);
|
||||
|
||||
b = blkid_new_probe();
|
||||
r = dlopen_libblkid();
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
b = sym_blkid_new_probe();
|
||||
if (!b)
|
||||
return -ENOMEM;
|
||||
|
||||
errno = 0;
|
||||
r = blkid_probe_set_device(b, fd, 0, 0);
|
||||
r = sym_blkid_probe_set_device(b, fd, 0, 0);
|
||||
if (r != 0)
|
||||
return errno_or_else(ENOMEM);
|
||||
|
||||
(void) blkid_probe_enable_superblocks(b, 1);
|
||||
(void) blkid_probe_set_superblocks_flags(b, BLKID_SUBLKS_TYPE|BLKID_SUBLKS_UUID);
|
||||
(void) sym_blkid_probe_enable_superblocks(b, 1);
|
||||
(void) sym_blkid_probe_set_superblocks_flags(b, BLKID_SUBLKS_TYPE|BLKID_SUBLKS_UUID);
|
||||
|
||||
errno = 0;
|
||||
r = blkid_do_safeprobe(b);
|
||||
r = sym_blkid_do_safeprobe(b);
|
||||
if (r == _BLKID_SAFEPROBE_ERROR)
|
||||
return errno_or_else(EIO);
|
||||
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);
|
||||
|
||||
(void) blkid_probe_lookup_value(b, "TYPE", &fstype, NULL);
|
||||
(void) sym_blkid_probe_lookup_value(b, "TYPE", &fstype, NULL);
|
||||
if (!fstype)
|
||||
return -ENOPKG;
|
||||
|
||||
(void) blkid_probe_lookup_value(b, "UUID", &uuid, NULL);
|
||||
if (!uuid)
|
||||
r = blkid_probe_lookup_value_id128(b, "UUID", &id);
|
||||
if (r == -ENXIO)
|
||||
return -ENOPKG;
|
||||
|
||||
r = sd_id128_from_string(uuid, &id);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
@ -674,22 +676,26 @@ static int luks_validate(
|
||||
assert(ret_offset);
|
||||
assert(ret_size);
|
||||
|
||||
b = blkid_new_probe();
|
||||
r = dlopen_libblkid();
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
b = sym_blkid_new_probe();
|
||||
if (!b)
|
||||
return -ENOMEM;
|
||||
|
||||
errno = 0;
|
||||
r = blkid_probe_set_device(b, fd, 0, 0);
|
||||
r = sym_blkid_probe_set_device(b, fd, 0, 0);
|
||||
if (r != 0)
|
||||
return errno_or_else(ENOMEM);
|
||||
|
||||
(void) blkid_probe_enable_superblocks(b, 1);
|
||||
(void) blkid_probe_set_superblocks_flags(b, BLKID_SUBLKS_TYPE);
|
||||
(void) blkid_probe_enable_partitions(b, 1);
|
||||
(void) blkid_probe_set_partitions_flags(b, BLKID_PARTS_ENTRY_DETAILS);
|
||||
(void) sym_blkid_probe_enable_superblocks(b, 1);
|
||||
(void) sym_blkid_probe_set_superblocks_flags(b, BLKID_SUBLKS_TYPE);
|
||||
(void) sym_blkid_probe_enable_partitions(b, 1);
|
||||
(void) sym_blkid_probe_set_partitions_flags(b, BLKID_PARTS_ENTRY_DETAILS);
|
||||
|
||||
errno = 0;
|
||||
r = blkid_do_safeprobe(b);
|
||||
r = sym_blkid_do_safeprobe(b);
|
||||
if (r == _BLKID_SAFEPROBE_ERROR)
|
||||
return errno_or_else(EIO);
|
||||
if (IN_SET(r, _BLKID_SAFEPROBE_AMBIGUOUS, _BLKID_SAFEPROBE_NOT_FOUND))
|
||||
@ -697,7 +703,7 @@ static int luks_validate(
|
||||
|
||||
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")) {
|
||||
/* Directly a LUKS image */
|
||||
*ret_offset = 0;
|
||||
@ -707,17 +713,17 @@ static int luks_validate(
|
||||
} else if (fstype)
|
||||
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"))
|
||||
return -ENOPKG;
|
||||
|
||||
errno = 0;
|
||||
pl = blkid_probe_get_partitions(b);
|
||||
pl = sym_blkid_probe_get_partitions(b);
|
||||
if (!pl)
|
||||
return errno_or_else(ENOMEM);
|
||||
|
||||
errno = 0;
|
||||
n = blkid_partlist_numof_partitions(pl);
|
||||
n = sym_blkid_partlist_numof_partitions(pl);
|
||||
if (n < 0)
|
||||
return errno_or_else(EIO);
|
||||
|
||||
@ -726,14 +732,14 @@ static int luks_validate(
|
||||
blkid_partition pp;
|
||||
|
||||
errno = 0;
|
||||
pp = blkid_partlist_get_partition(pl, i);
|
||||
pp = sym_blkid_partlist_get_partition(pl, i);
|
||||
if (!pp)
|
||||
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;
|
||||
|
||||
if (!streq_ptr(blkid_partition_get_name(pp), label))
|
||||
if (!streq_ptr(sym_blkid_partition_get_name(pp), label))
|
||||
continue;
|
||||
|
||||
r = blkid_partition_get_uuid_id128(pp, &id);
|
||||
@ -745,8 +751,8 @@ static int luks_validate(
|
||||
if (found)
|
||||
return -ENOPKG;
|
||||
|
||||
offset = blkid_partition_get_start(pp);
|
||||
size = blkid_partition_get_size(pp);
|
||||
offset = sym_blkid_partition_get_start(pp);
|
||||
size = sym_blkid_partition_get_size(pp);
|
||||
found_partition_uuid = id;
|
||||
|
||||
found = true;
|
||||
|
||||
@ -81,7 +81,7 @@ executables += [
|
||||
libshared_fdisk
|
||||
],
|
||||
'dependencies' : [
|
||||
libblkid,
|
||||
libblkid_cflags,
|
||||
libcrypt,
|
||||
libfdisk,
|
||||
libopenssl,
|
||||
|
||||
@ -33,6 +33,7 @@
|
||||
#include "operation.h"
|
||||
#include "os-util.h"
|
||||
#include "path-util.h"
|
||||
#include "socket-util.h"
|
||||
#include "string-util.h"
|
||||
#include "strv.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);
|
||||
}
|
||||
|
||||
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(
|
||||
Manager *manager,
|
||||
sd_bus_message *message,
|
||||
const char *polkit_action,
|
||||
bool read_network,
|
||||
Machine **ret,
|
||||
sd_bus_error *error) {
|
||||
|
||||
@ -240,7 +370,6 @@ static int method_create_or_register_machine(
|
||||
MachineClass c;
|
||||
uint32_t leader;
|
||||
sd_id128_t id;
|
||||
Machine *m;
|
||||
size_t n_netif = 0;
|
||||
int r;
|
||||
|
||||
@ -262,7 +391,7 @@ static int method_create_or_register_machine(
|
||||
if (r < 0)
|
||||
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);
|
||||
if (r < 0)
|
||||
return r;
|
||||
@ -312,95 +441,224 @@ static int method_create_or_register_machine(
|
||||
if (hashmap_get(manager->machines, 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;
|
||||
r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_EUID, &creds);
|
||||
return machine_add_from_params(
|
||||
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)
|
||||
return r;
|
||||
|
||||
uid_t uid;
|
||||
r = sd_bus_creds_get_euid(creds, &uid);
|
||||
if (r < 0)
|
||||
return r;
|
||||
for (;;) {
|
||||
const char *key;
|
||||
|
||||
/* 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);
|
||||
r = sd_bus_message_enter_container(message, 'r', "sv");
|
||||
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");
|
||||
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[] = {
|
||||
"name", name,
|
||||
"class", machine_class_to_string(c),
|
||||
NULL
|
||||
};
|
||||
r = sd_bus_message_exit_container(message);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
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,
|
||||
polkit_action,
|
||||
details,
|
||||
&manager->polkit_registry,
|
||||
name,
|
||||
c,
|
||||
id,
|
||||
service,
|
||||
&leader_pidref,
|
||||
&supervisor_pidref,
|
||||
root_directory,
|
||||
netif,
|
||||
n_netif,
|
||||
cid,
|
||||
ssh_address,
|
||||
ssh_private_key_path,
|
||||
ret,
|
||||
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);
|
||||
Machine *m = NULL;
|
||||
int r;
|
||||
|
||||
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)
|
||||
return r;
|
||||
if (r == 0)
|
||||
@ -422,15 +680,7 @@ fail:
|
||||
return r;
|
||||
}
|
||||
|
||||
static int method_create_machine_with_network(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) {
|
||||
static int method_register_machine(sd_bus_message *message, void *userdata, sd_bus_error *error) {
|
||||
Manager *manager = ASSERT_PTR(userdata);
|
||||
_cleanup_free_ char *p = NULL;
|
||||
Machine *m = NULL;
|
||||
@ -438,7 +688,10 @@ static int method_register_machine_internal(sd_bus_message *message, bool read_n
|
||||
|
||||
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)
|
||||
return r;
|
||||
if (r == 0)
|
||||
@ -482,14 +735,6 @@ fail:
|
||||
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) {
|
||||
Machine *machine;
|
||||
const char *name;
|
||||
@ -969,7 +1214,12 @@ const sd_bus_vtable manager_vtable[] = {
|
||||
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_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_METHOD_WITH_ARGS("RegisterMachine",
|
||||
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_ARGS("s", name, "ay", id, "s", service, "s", class, "u", leader, "s", root_directory, "ai", ifindices),
|
||||
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_METHOD_WITH_ARGS("UnregisterMachine",
|
||||
SD_BUS_ARGS("s", name),
|
||||
|
||||
@ -190,6 +190,10 @@
|
||||
send_interface="org.freedesktop.machine1.Manager"
|
||||
send_member="CreateMachineWithNetwork"/>
|
||||
|
||||
<allow send_destination="org.freedesktop.machine1"
|
||||
send_interface="org.freedesktop.machine1.Manager"
|
||||
send_member="CreateMachineEx"/>
|
||||
|
||||
<allow send_destination="org.freedesktop.machine1"
|
||||
send_interface="org.freedesktop.machine1.Manager"
|
||||
send_member="RegisterMachine"/>
|
||||
@ -198,6 +202,10 @@
|
||||
send_interface="org.freedesktop.machine1.Manager"
|
||||
send_member="RegisterMachineWithNetwork"/>
|
||||
|
||||
<allow send_destination="org.freedesktop.machine1"
|
||||
send_interface="org.freedesktop.machine1.Manager"
|
||||
send_member="RegisterMachineEx"/>
|
||||
|
||||
<!-- org.freedesktop.machine1.Machine Method Calls -->
|
||||
|
||||
<allow send_destination="org.freedesktop.machine1"
|
||||
|
||||
@ -47,7 +47,6 @@ executables += [
|
||||
],
|
||||
'extract' : nspawn_extract_sources,
|
||||
'dependencies' : [
|
||||
libblkid,
|
||||
libseccomp,
|
||||
libselinux,
|
||||
],
|
||||
|
||||
@ -131,6 +131,126 @@ static int can_set_coredump_receive(sd_bus *bus) {
|
||||
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(
|
||||
sd_bus *bus,
|
||||
const char *machine_name,
|
||||
@ -153,6 +273,27 @@ int register_machine(
|
||||
|
||||
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)) {
|
||||
r = bus_call_method(
|
||||
bus,
|
||||
|
||||
@ -11,7 +11,6 @@ executables += [
|
||||
],
|
||||
'sources' : files('pcrextend.c'),
|
||||
'dependencies' : [
|
||||
libblkid,
|
||||
libopenssl,
|
||||
tpm2,
|
||||
],
|
||||
|
||||
@ -14,7 +14,7 @@ executables += [
|
||||
libshared_fdisk,
|
||||
],
|
||||
'dependencies' : [
|
||||
libblkid,
|
||||
libblkid_cflags,
|
||||
libfdisk,
|
||||
libopenssl,
|
||||
threads,
|
||||
@ -33,7 +33,7 @@ executables += [
|
||||
libsystemd_static,
|
||||
],
|
||||
'dependencies' : [
|
||||
libblkid,
|
||||
libblkid_cflags,
|
||||
libfdisk,
|
||||
libopenssl,
|
||||
threads,
|
||||
|
||||
@ -4278,32 +4278,36 @@ static int context_wipe_range(Context *context, uint64_t offset, uint64_t size)
|
||||
assert(offset != 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)
|
||||
return log_oom();
|
||||
|
||||
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)
|
||||
return log_error_errno(errno ?: SYNTHETIC_ERRNO(EIO), "Failed to allocate device probe for wiping.");
|
||||
|
||||
errno = 0;
|
||||
if (blkid_probe_enable_superblocks(probe, true) < 0 ||
|
||||
blkid_probe_set_superblocks_flags(probe, BLKID_SUBLKS_MAGIC|BLKID_SUBLKS_BADCSUM) < 0 ||
|
||||
blkid_probe_enable_partitions(probe, true) < 0 ||
|
||||
blkid_probe_set_partitions_flags(probe, BLKID_PARTS_MAGIC) < 0)
|
||||
if (sym_blkid_probe_enable_superblocks(probe, true) < 0 ||
|
||||
sym_blkid_probe_set_superblocks_flags(probe, BLKID_SUBLKS_MAGIC|BLKID_SUBLKS_BADCSUM) < 0 ||
|
||||
sym_blkid_probe_enable_partitions(probe, true) < 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.");
|
||||
|
||||
for (;;) {
|
||||
errno = 0;
|
||||
r = blkid_do_probe(probe);
|
||||
r = sym_blkid_do_probe(probe);
|
||||
if (r < 0)
|
||||
return log_error_errno(errno_or_else(EIO), "Failed to probe for file systems.");
|
||||
if (r > 0)
|
||||
break;
|
||||
|
||||
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.");
|
||||
}
|
||||
|
||||
@ -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",
|
||||
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)
|
||||
return log_oom();
|
||||
|
||||
errno = 0;
|
||||
r = blkid_probe_set_device(b, fd, 0, 0);
|
||||
r = sym_blkid_probe_set_device(b, fd, 0, 0);
|
||||
if (r != 0)
|
||||
return log_error_errno(errno_or_else(ENOMEM), "Failed to open block device '%s': %m", p);
|
||||
|
||||
(void) blkid_probe_enable_partitions(b, 1);
|
||||
(void) blkid_probe_set_partitions_flags(b, BLKID_PARTS_ENTRY_DETAILS);
|
||||
(void) sym_blkid_probe_enable_partitions(b, 1);
|
||||
(void) sym_blkid_probe_set_partitions_flags(b, BLKID_PARTS_ENTRY_DETAILS);
|
||||
|
||||
errno = 0;
|
||||
r = blkid_do_safeprobe(b);
|
||||
r = sym_blkid_do_safeprobe(b);
|
||||
if (r == _BLKID_SAFEPROBE_ERROR)
|
||||
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)) {
|
||||
@ -7415,18 +7423,18 @@ static int resolve_copy_blocks_auto_candidate(
|
||||
|
||||
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")) {
|
||||
log_debug("Didn't find a GPT partition table on '%s'.", p);
|
||||
return false;
|
||||
}
|
||||
|
||||
errno = 0;
|
||||
pl = blkid_probe_get_partitions(b);
|
||||
pl = sym_blkid_probe_get_partitions(b);
|
||||
if (!pl)
|
||||
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) {
|
||||
log_debug("Partition %u:%u has no matching partition table entry on '%s'.",
|
||||
major(partition_devno), minor(partition_devno), p);
|
||||
|
||||
@ -1,17 +1,106 @@
|
||||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
#if HAVE_BLKID
|
||||
|
||||
#include "sd-id128.h"
|
||||
|
||||
#include "blkid-util.h"
|
||||
#include "log.h"
|
||||
#include "parse-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) {
|
||||
const char *s;
|
||||
|
||||
assert(p);
|
||||
|
||||
s = blkid_partition_get_uuid(p);
|
||||
s = sym_blkid_partition_get_uuid(p);
|
||||
if (isempty(s))
|
||||
return -ENXIO;
|
||||
|
||||
@ -23,11 +112,34 @@ int blkid_partition_get_type_id128(blkid_partition p, sd_id128_t *ret) {
|
||||
|
||||
assert(p);
|
||||
|
||||
s = blkid_partition_get_type_string(p);
|
||||
s = sym_blkid_partition_get_type_string(p);
|
||||
if (isempty(s))
|
||||
return -ENXIO;
|
||||
|
||||
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
|
||||
|
||||
@ -1,13 +1,54 @@
|
||||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
#pragma once
|
||||
|
||||
#include "forward.h"
|
||||
|
||||
#if HAVE_BLKID
|
||||
|
||||
#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);
|
||||
|
||||
@ -22,4 +63,10 @@ enum {
|
||||
_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
|
||||
|
||||
@ -199,12 +199,12 @@ static int probe_blkid_filter(blkid_probe p) {
|
||||
return r;
|
||||
|
||||
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)
|
||||
return errno_or_else(EINVAL);
|
||||
|
||||
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)
|
||||
return errno_or_else(EINVAL);
|
||||
|
||||
@ -234,6 +234,10 @@ int probe_filesystem_full(
|
||||
assert(fd >= 0 || path);
|
||||
assert(ret_fstype);
|
||||
|
||||
r = dlopen_libblkid();
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (fd < 0) {
|
||||
fd_close = open(path, O_RDONLY|O_NONBLOCK|O_CLOEXEC|O_NOCTTY);
|
||||
if (fd_close < 0)
|
||||
@ -253,7 +257,7 @@ int probe_filesystem_full(
|
||||
if (size == 0) /* empty size? nothing found! */
|
||||
goto not_found;
|
||||
|
||||
b = blkid_new_probe();
|
||||
b = sym_blkid_new_probe();
|
||||
if (!b)
|
||||
return -ENOMEM;
|
||||
|
||||
@ -279,7 +283,7 @@ int probe_filesystem_full(
|
||||
log_debug_errno(errno, "Failed to flush block device cache, ignoring: %m");
|
||||
|
||||
errno = 0;
|
||||
r = blkid_probe_set_device(
|
||||
r = sym_blkid_probe_set_device(
|
||||
b,
|
||||
fd,
|
||||
offset,
|
||||
@ -287,11 +291,11 @@ int probe_filesystem_full(
|
||||
if (r != 0)
|
||||
return errno_or_else(ENOMEM);
|
||||
|
||||
blkid_probe_enable_superblocks(b, 1);
|
||||
blkid_probe_set_superblocks_flags(b, BLKID_SUBLKS_TYPE);
|
||||
sym_blkid_probe_enable_superblocks(b, 1);
|
||||
sym_blkid_probe_set_superblocks_flags(b, BLKID_SUBLKS_TYPE);
|
||||
|
||||
errno = 0;
|
||||
r = blkid_do_safeprobe(b);
|
||||
r = sym_blkid_do_safeprobe(b);
|
||||
if (r == _BLKID_SAFEPROBE_NOT_FOUND)
|
||||
goto not_found;
|
||||
if (r == _BLKID_SAFEPROBE_AMBIGUOUS)
|
||||
@ -302,8 +306,7 @@ int probe_filesystem_full(
|
||||
|
||||
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) {
|
||||
log_debug("Probed fstype '%s' on partition %s.", fstype, path);
|
||||
return strdup_to_full(ret_fstype, fstype);
|
||||
@ -731,7 +734,7 @@ static int dissect_image(
|
||||
_cleanup_(blkid_free_probep) blkid_probe b = NULL;
|
||||
_cleanup_free_ char *generic_node = NULL;
|
||||
sd_id128_t generic_uuid = SD_ID128_NULL;
|
||||
const char *pttype = NULL, *sptuuid = NULL;
|
||||
const char *pttype = NULL;
|
||||
blkid_partlist pl;
|
||||
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)
|
||||
return -ENOMEM;
|
||||
|
||||
@ -798,26 +805,26 @@ static int dissect_image(
|
||||
return r;
|
||||
|
||||
errno = 0;
|
||||
r = blkid_probe_set_device(b, fd, 0, 0);
|
||||
r = sym_blkid_probe_set_device(b, fd, 0, 0);
|
||||
if (r != 0)
|
||||
return errno_or_else(ENOMEM);
|
||||
|
||||
errno = 0;
|
||||
r = blkid_probe_set_sectorsize(b, m->sector_size);
|
||||
r = sym_blkid_probe_set_sectorsize(b, m->sector_size);
|
||||
if (r != 0)
|
||||
return errno_or_else(EIO);
|
||||
|
||||
if ((flags & DISSECT_IMAGE_GPT_ONLY) == 0) {
|
||||
/* Look for file system superblocks, unless we only shall look for GPT partition tables */
|
||||
blkid_probe_enable_superblocks(b, 1);
|
||||
blkid_probe_set_superblocks_flags(b, BLKID_SUBLKS_TYPE|BLKID_SUBLKS_USAGE|BLKID_SUBLKS_UUID);
|
||||
sym_blkid_probe_enable_superblocks(b, 1);
|
||||
sym_blkid_probe_set_superblocks_flags(b, BLKID_SUBLKS_TYPE|BLKID_SUBLKS_USAGE|BLKID_SUBLKS_UUID);
|
||||
}
|
||||
|
||||
blkid_probe_enable_partitions(b, 1);
|
||||
blkid_probe_set_partitions_flags(b, BLKID_PARTS_ENTRY_DETAILS);
|
||||
sym_blkid_probe_enable_partitions(b, 1);
|
||||
sym_blkid_probe_set_partitions_flags(b, BLKID_PARTS_ENTRY_DETAILS);
|
||||
|
||||
errno = 0;
|
||||
r = blkid_do_safeprobe(b);
|
||||
r = sym_blkid_do_safeprobe(b);
|
||||
if (r == _BLKID_SAFEPROBE_ERROR)
|
||||
return errno_or_else(EIO);
|
||||
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 */
|
||||
|
||||
(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")) {
|
||||
_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;
|
||||
sd_id128_t uuid = SD_ID128_NULL;
|
||||
PartitionPolicyFlags found_flags;
|
||||
@ -852,8 +859,12 @@ static int dissect_image(
|
||||
if (r == 0) /* policy says ignore this, so we ignore it */
|
||||
return -ENOPKG;
|
||||
|
||||
(void) blkid_probe_lookup_value(b, "TYPE", &fstype, NULL);
|
||||
(void) blkid_probe_lookup_value(b, "UUID", &suuid, NULL);
|
||||
(void) sym_blkid_probe_lookup_value(b, "TYPE", &fstype, 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");
|
||||
|
||||
@ -882,15 +893,6 @@ static int dissect_image(
|
||||
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);
|
||||
if (r < 0)
|
||||
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)
|
||||
return -ENOPKG;
|
||||
|
||||
@ -955,20 +957,15 @@ static int dissect_image(
|
||||
return -EPROTONOSUPPORT;
|
||||
}
|
||||
|
||||
(void) blkid_probe_lookup_value(b, "PTUUID", &sptuuid, NULL);
|
||||
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);
|
||||
}
|
||||
(void) blkid_probe_lookup_value_id128(b, "PTUUID", &m->image_uuid);
|
||||
|
||||
errno = 0;
|
||||
pl = blkid_probe_get_partitions(b);
|
||||
pl = sym_blkid_probe_get_partitions(b);
|
||||
if (!pl)
|
||||
return errno_or_else(ENOMEM);
|
||||
|
||||
errno = 0;
|
||||
n_partitions = blkid_partlist_numof_partitions(pl);
|
||||
n_partitions = sym_blkid_partlist_numof_partitions(pl);
|
||||
if (n_partitions < 0)
|
||||
return errno_or_else(EIO);
|
||||
|
||||
@ -980,26 +977,26 @@ static int dissect_image(
|
||||
int nr;
|
||||
|
||||
errno = 0;
|
||||
pp = blkid_partlist_get_partition(pl, i);
|
||||
pp = sym_blkid_partlist_get_partition(pl, i);
|
||||
if (!pp)
|
||||
return errno_or_else(EIO);
|
||||
|
||||
pflags = blkid_partition_get_flags(pp);
|
||||
pflags = sym_blkid_partition_get_flags(pp);
|
||||
|
||||
errno = 0;
|
||||
nr = blkid_partition_get_partno(pp);
|
||||
nr = sym_blkid_partition_get_partno(pp);
|
||||
if (nr < 0)
|
||||
return errno_or_else(EIO);
|
||||
|
||||
errno = 0;
|
||||
start = blkid_partition_get_start(pp);
|
||||
start = sym_blkid_partition_get_start(pp);
|
||||
if (start < 0)
|
||||
return errno_or_else(EIO);
|
||||
|
||||
assert((uint64_t) start < UINT64_MAX/512);
|
||||
|
||||
errno = 0;
|
||||
size = blkid_partition_get_size(pp);
|
||||
size = sym_blkid_partition_get_size(pp);
|
||||
if (size < 0)
|
||||
return errno_or_else(EIO);
|
||||
|
||||
@ -1054,7 +1051,7 @@ static int dissect_image(
|
||||
|
||||
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. */
|
||||
if (streq_ptr(label, "_empty"))
|
||||
@ -1360,7 +1357,7 @@ static int dissect_image(
|
||||
|
||||
} else if (is_mbr) {
|
||||
|
||||
switch (blkid_partition_get_type(pp)) {
|
||||
switch (sym_blkid_partition_get_type(pp)) {
|
||||
|
||||
case 0x83: /* Linux partition */
|
||||
|
||||
|
||||
@ -76,22 +76,26 @@ static int verify_esp_blkid(
|
||||
const char *v;
|
||||
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);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to get device path for " DEVNUM_FORMAT_STR ": %m", DEVNUM_FORMAT_VAL(devid));
|
||||
|
||||
errno = 0;
|
||||
b = blkid_new_probe_from_filename(node);
|
||||
b = sym_blkid_new_probe_from_filename(node);
|
||||
if (!b)
|
||||
return log_error_errno(errno ?: SYNTHETIC_ERRNO(ENOMEM), "Failed to open file system \"%s\": %m", node);
|
||||
|
||||
blkid_probe_enable_superblocks(b, 1);
|
||||
blkid_probe_set_superblocks_flags(b, BLKID_SUBLKS_TYPE);
|
||||
blkid_probe_enable_partitions(b, 1);
|
||||
blkid_probe_set_partitions_flags(b, BLKID_PARTS_ENTRY_DETAILS);
|
||||
sym_blkid_probe_enable_superblocks(b, 1);
|
||||
sym_blkid_probe_set_superblocks_flags(b, BLKID_SUBLKS_TYPE);
|
||||
sym_blkid_probe_enable_partitions(b, 1);
|
||||
sym_blkid_probe_set_partitions_flags(b, BLKID_PARTS_ENTRY_DETAILS);
|
||||
|
||||
errno = 0;
|
||||
r = blkid_do_safeprobe(b);
|
||||
r = sym_blkid_do_safeprobe(b);
|
||||
if (r == -2)
|
||||
return log_error_errno(SYNTHETIC_ERRNO(ENODEV), "File system \"%s\" is ambiguous.", node);
|
||||
if (r == 1)
|
||||
@ -99,7 +103,7 @@ static int verify_esp_blkid(
|
||||
if (r != 0)
|
||||
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)
|
||||
return log_full_errno(searching ? LOG_DEBUG : LOG_ERR,
|
||||
SYNTHETIC_ERRNO(searching ? EADDRNOTAVAIL : ENODEV),
|
||||
@ -109,7 +113,7 @@ static int verify_esp_blkid(
|
||||
SYNTHETIC_ERRNO(searching ? EADDRNOTAVAIL : ENODEV),
|
||||
"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)
|
||||
return log_full_errno(searching ? LOG_DEBUG : LOG_ERR,
|
||||
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);
|
||||
|
||||
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)
|
||||
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)
|
||||
@ -128,37 +132,25 @@ static int verify_esp_blkid(
|
||||
SYNTHETIC_ERRNO(searching ? EADDRNOTAVAIL : ENODEV),
|
||||
"File system \"%s\" has wrong type for an EFI System Partition (ESP).", node);
|
||||
|
||||
errno = 0;
|
||||
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);
|
||||
r = blkid_probe_lookup_value_id128(b, "PART_ENTRY_UUID", &uuid);
|
||||
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;
|
||||
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)
|
||||
return log_error_errno(errno ?: SYNTHETIC_ERRNO(EIO), "Failed to probe partition number of \"%s\": %m", node);
|
||||
r = safe_atou32(v, &part);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to parse PART_ENTRY_NUMBER field.");
|
||||
|
||||
errno = 0;
|
||||
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);
|
||||
r = blkid_probe_lookup_value_u64(b, "PART_ENTRY_OFFSET", &pstart);
|
||||
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(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);
|
||||
r = blkid_probe_lookup_value_u64(b, "PART_ENTRY_SIZE", &psize);
|
||||
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
|
||||
|
||||
if (ret_part)
|
||||
@ -603,21 +595,25 @@ static int verify_xbootldr_blkid(
|
||||
const char *type, *v;
|
||||
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);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to get block device path for " DEVNUM_FORMAT_STR ": %m",
|
||||
DEVNUM_FORMAT_VAL(devid));
|
||||
|
||||
errno = 0;
|
||||
b = blkid_new_probe_from_filename(node);
|
||||
b = sym_blkid_new_probe_from_filename(node);
|
||||
if (!b)
|
||||
return log_error_errno(errno_or_else(ENOMEM), "%s: Failed to create blkid probe: %m", node);
|
||||
|
||||
blkid_probe_enable_partitions(b, 1);
|
||||
blkid_probe_set_partitions_flags(b, BLKID_PARTS_ENTRY_DETAILS);
|
||||
sym_blkid_probe_enable_partitions(b, 1);
|
||||
sym_blkid_probe_set_partitions_flags(b, BLKID_PARTS_ENTRY_DETAILS);
|
||||
|
||||
errno = 0;
|
||||
r = blkid_do_safeprobe(b);
|
||||
r = sym_blkid_do_safeprobe(b);
|
||||
if (r == _BLKID_SAFEPROBE_AMBIGUOUS)
|
||||
return log_error_errno(SYNTHETIC_ERRNO(ENODEV), "%s: File system is ambiguous.", node);
|
||||
if (r == _BLKID_SAFEPROBE_NOT_FOUND)
|
||||
@ -627,7 +623,7 @@ static int verify_xbootldr_blkid(
|
||||
|
||||
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)
|
||||
return log_full_errno(searching ? LOG_DEBUG : LOG_ERR,
|
||||
searching ? SYNTHETIC_ERRNO(EADDRNOTAVAIL) : SYNTHETIC_ERRNO(EIO),
|
||||
@ -635,7 +631,7 @@ static int verify_xbootldr_blkid(
|
||||
if (streq(type, "gpt")) {
|
||||
|
||||
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)
|
||||
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)
|
||||
@ -643,18 +639,14 @@ static int verify_xbootldr_blkid(
|
||||
searching ? SYNTHETIC_ERRNO(EADDRNOTAVAIL) : SYNTHETIC_ERRNO(ENODEV),
|
||||
"%s: Partition has wrong PART_ENTRY_TYPE=%s for XBOOTLDR partition.", node, v);
|
||||
|
||||
errno = 0;
|
||||
r = blkid_probe_lookup_value(b, "PART_ENTRY_UUID", &v, NULL);
|
||||
r = blkid_probe_lookup_value_id128(b, "PART_ENTRY_UUID", &uuid);
|
||||
if (r != 0)
|
||||
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")) {
|
||||
|
||||
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)
|
||||
return log_error_errno(errno_or_else(EIO), "%s: Failed to probe PART_ENTRY_TYPE: %m", node);
|
||||
if (!streq(v, "0xea"))
|
||||
|
||||
@ -154,6 +154,7 @@ shared_sources = files(
|
||||
'polkit-agent.c',
|
||||
'portable-util.c',
|
||||
'pretty-print.c',
|
||||
'prompt-util.c',
|
||||
'ptyfwd.c',
|
||||
'qrcode-util.c',
|
||||
'quota-util.c',
|
||||
@ -314,7 +315,7 @@ libshared_name = 'systemd-shared-@0@'.format(shared_lib_tag)
|
||||
libshared_deps = [threads,
|
||||
libacl_cflags,
|
||||
libaudit_cflags,
|
||||
libblkid,
|
||||
libblkid_cflags,
|
||||
libcap,
|
||||
libcrypt,
|
||||
libdl,
|
||||
|
||||
@ -30,26 +30,30 @@ static int device_get_file_system_word(
|
||||
assert(ret);
|
||||
|
||||
#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);
|
||||
if (block_fd < 0)
|
||||
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)
|
||||
return -ENOMEM;
|
||||
|
||||
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)
|
||||
return errno_or_else(ENOMEM);
|
||||
|
||||
(void) blkid_probe_enable_superblocks(b, 1);
|
||||
(void) blkid_probe_set_superblocks_flags(b, BLKID_SUBLKS_TYPE|BLKID_SUBLKS_UUID|BLKID_SUBLKS_LABEL);
|
||||
(void) blkid_probe_enable_partitions(b, 1);
|
||||
(void) blkid_probe_set_partitions_flags(b, BLKID_PARTS_ENTRY_DETAILS);
|
||||
(void) sym_blkid_probe_enable_superblocks(b, 1);
|
||||
(void) sym_blkid_probe_set_superblocks_flags(b, BLKID_SUBLKS_TYPE|BLKID_SUBLKS_UUID|BLKID_SUBLKS_LABEL);
|
||||
(void) sym_blkid_probe_enable_partitions(b, 1);
|
||||
(void) sym_blkid_probe_set_partitions_flags(b, BLKID_PARTS_ENTRY_DETAILS);
|
||||
|
||||
errno = 0;
|
||||
r = blkid_do_safeprobe(b);
|
||||
r = sym_blkid_do_safeprobe(b);
|
||||
if (r == _BLKID_SAFEPROBE_ERROR)
|
||||
return errno_or_else(EIO);
|
||||
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") {
|
||||
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 ":" */
|
||||
if (!escaped)
|
||||
|
||||
@ -92,3 +92,6 @@ static inline void fflush_and_disable_bufferingp(FILE **p) {
|
||||
|
||||
#define WITH_BUFFERED_STDERR \
|
||||
_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
332
src/shared/prompt-util.c
Normal 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(©, "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
31
src/shared/prompt-util.h
Normal 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);
|
||||
@ -104,7 +104,7 @@ static SD_VARLINK_DEFINE_METHOD_FULL(
|
||||
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_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_DEFINE_OUTPUT(UID, SD_VARLINK_INT, SD_VARLINK_NULLABLE));
|
||||
|
||||
|
||||
@ -32,7 +32,6 @@ executables += [
|
||||
libshared_fdisk,
|
||||
],
|
||||
'dependencies' : [
|
||||
libblkid,
|
||||
libfdisk,
|
||||
libopenssl,
|
||||
threads,
|
||||
|
||||
@ -215,7 +215,6 @@ simple_tests += files(
|
||||
############################################################
|
||||
|
||||
common_test_dependencies = [
|
||||
libblkid,
|
||||
libmount,
|
||||
librt,
|
||||
libseccomp,
|
||||
@ -288,8 +287,9 @@ executables += [
|
||||
test_template + {
|
||||
'sources' : files('test-dlopen-so.c'),
|
||||
'dependencies' : [
|
||||
libp11kit_cflags,
|
||||
libblkid_cflags,
|
||||
libkmod_cflags,
|
||||
libp11kit_cflags,
|
||||
],
|
||||
},
|
||||
test_template + {
|
||||
@ -550,7 +550,7 @@ executables += [
|
||||
},
|
||||
core_test_template + {
|
||||
'sources' : files('test-loop-block.c'),
|
||||
'dependencies' : [threads, libblkid],
|
||||
'dependencies' : [threads],
|
||||
'parallel' : false,
|
||||
},
|
||||
core_test_template + {
|
||||
@ -559,7 +559,6 @@ executables += [
|
||||
core_test_template + {
|
||||
'sources' : files('test-namespace.c'),
|
||||
'dependencies' : [
|
||||
libblkid,
|
||||
threads,
|
||||
],
|
||||
},
|
||||
|
||||
@ -2,6 +2,7 @@
|
||||
|
||||
#include "acl-util.h"
|
||||
#include "apparmor-util.h"
|
||||
#include "blkid-util.h"
|
||||
#include "bpf-dlopen.h"
|
||||
#include "compress.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_libpam, HAVE_PAM);
|
||||
ASSERT_DLOPEN(dlopen_libacl, HAVE_ACL);
|
||||
ASSERT_DLOPEN(dlopen_libblkid, HAVE_BLKID);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -81,7 +81,7 @@ TEST(keymaps) {
|
||||
|
||||
#define dump_glyph(x) log_info(STRINGIFY(x) ": %s", glyph(x))
|
||||
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()));
|
||||
|
||||
@ -135,6 +135,12 @@ TEST(dump_glyphs) {
|
||||
dump_glyph(GLYPH_SUPERHERO);
|
||||
dump_glyph(GLYPH_IDCARD);
|
||||
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);
|
||||
|
||||
@ -115,7 +115,7 @@ endif
|
||||
|
||||
udev_dependencies = [
|
||||
libacl_cflags,
|
||||
libblkid,
|
||||
libblkid_cflags,
|
||||
libkmod,
|
||||
threads,
|
||||
]
|
||||
@ -132,7 +132,7 @@ udev_common_template = {
|
||||
'objects' : ['udevadm'],
|
||||
'dependencies' : [
|
||||
libacl_cflags,
|
||||
libblkid,
|
||||
libblkid_cflags,
|
||||
threads,
|
||||
],
|
||||
}
|
||||
|
||||
@ -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);
|
||||
|
||||
} 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);
|
||||
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);
|
||||
|
||||
} 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);
|
||||
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);
|
||||
|
||||
} 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);
|
||||
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);
|
||||
|
||||
} 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);
|
||||
|
||||
} 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);
|
||||
|
||||
} 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);
|
||||
|
||||
} 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);
|
||||
|
||||
} 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);
|
||||
|
||||
} 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);
|
||||
|
||||
} 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);
|
||||
|
||||
} 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);
|
||||
|
||||
} 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);
|
||||
|
||||
} 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);
|
||||
|
||||
} 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);
|
||||
|
||||
} 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);
|
||||
}
|
||||
}
|
||||
@ -222,7 +222,7 @@ static int find_gpt_root(UdevEvent *event, blkid_probe pr, const char *loop_back
|
||||
}
|
||||
|
||||
errno = 0;
|
||||
blkid_partlist pl = blkid_probe_get_partitions(pr);
|
||||
blkid_partlist pl = sym_blkid_probe_get_partitions(pr);
|
||||
if (!pl)
|
||||
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
|
||||
* 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) {
|
||||
sd_id128_t 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. */
|
||||
|
||||
_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++) {
|
||||
blkid_partition pp;
|
||||
const char *label;
|
||||
sd_id128_t type, id;
|
||||
|
||||
pp = blkid_partlist_get_partition(pl, i);
|
||||
pp = sym_blkid_partlist_get_partition(pl, i);
|
||||
if (!pp)
|
||||
continue;
|
||||
|
||||
@ -271,7 +271,7 @@ static int find_gpt_root(UdevEvent *event, blkid_probe pr, const char *loop_back
|
||||
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)) {
|
||||
|
||||
@ -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)) {
|
||||
unsigned long long flags;
|
||||
|
||||
flags = blkid_partition_get_flags(pp);
|
||||
flags = sym_blkid_partition_get_flags(pp);
|
||||
if (flags & SD_GPT_FLAG_NO_AUTO)
|
||||
continue;
|
||||
|
||||
@ -322,32 +322,32 @@ static int probe_superblocks(blkid_probe pr) {
|
||||
|
||||
/* TODO: Return negative errno. */
|
||||
|
||||
if (fstat(blkid_probe_get_fd(pr), &st))
|
||||
if (fstat(sym_blkid_probe_get_fd(pr), &st))
|
||||
return -errno;
|
||||
|
||||
blkid_probe_enable_partitions(pr, 1);
|
||||
sym_blkid_probe_enable_partitions(pr, 1);
|
||||
|
||||
if (!S_ISCHR(st.st_mode) &&
|
||||
blkid_probe_get_size(pr) <= 1024 * 1440 &&
|
||||
blkid_probe_is_wholedisk(pr)) {
|
||||
sym_blkid_probe_get_size(pr) <= 1024 * 1440 &&
|
||||
sym_blkid_probe_is_wholedisk(pr)) {
|
||||
/*
|
||||
* check if the small disk is partitioned, if yes then
|
||||
* 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)
|
||||
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 */
|
||||
}
|
||||
|
||||
blkid_probe_set_partitions_flags(pr, BLKID_PARTS_ENTRY_DETAILS);
|
||||
blkid_probe_enable_superblocks(pr, 1);
|
||||
sym_blkid_probe_set_partitions_flags(pr, BLKID_PARTS_ENTRY_DETAILS);
|
||||
sym_blkid_probe_enable_superblocks(pr, 1);
|
||||
|
||||
return blkid_do_safeprobe(pr);
|
||||
return sym_blkid_do_safeprobe(pr);
|
||||
}
|
||||
|
||||
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;
|
||||
pr = blkid_new_probe();
|
||||
pr = sym_blkid_new_probe();
|
||||
if (!pr)
|
||||
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':
|
||||
#if HAVE_BLKID_PROBE_SET_HINT
|
||||
errno = 0;
|
||||
r = blkid_probe_set_hint(pr, optarg, 0);
|
||||
r = sym_blkid_probe_set_hint(pr, optarg, 0);
|
||||
if (r < 0)
|
||||
return log_device_error_errno(dev, errno_or_else(ENOMEM), "Failed to use '%s' probing hint: %m", optarg);
|
||||
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_TYPE | BLKID_SUBLKS_SECTYPE |
|
||||
#ifdef BLKID_SUBLKS_FSINFO
|
||||
@ -491,7 +495,7 @@ static int builtin_blkid(UdevEvent *event, int argc, char *argv[]) {
|
||||
BLKID_SUBLKS_USAGE | BLKID_SUBLKS_VERSION);
|
||||
|
||||
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);
|
||||
if (r < 0)
|
||||
@ -506,7 +510,7 @@ static int builtin_blkid(UdevEvent *event, int argc, char *argv[]) {
|
||||
}
|
||||
|
||||
errno = 0;
|
||||
r = blkid_probe_set_device(pr, fd, offset, 0);
|
||||
r = sym_blkid_probe_set_device(pr, fd, offset, 0);
|
||||
if (r < 0)
|
||||
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);
|
||||
|
||||
errno = 0;
|
||||
int nvals = blkid_probe_numof_values(pr);
|
||||
int nvals = sym_blkid_probe_numof_values(pr);
|
||||
if (nvals < 0)
|
||||
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++) {
|
||||
if (blkid_probe_get_value(pr, i, &name, &data, NULL) < 0)
|
||||
if (sym_blkid_probe_get_value(pr, i, &name, &data, NULL) < 0)
|
||||
continue;
|
||||
|
||||
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];
|
||||
|
||||
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_ENC", encoded);
|
||||
|
||||
@ -8,7 +8,7 @@ executables += [
|
||||
],
|
||||
'sources' : files('validatefs.c'),
|
||||
'dependencies' : [
|
||||
libblkid,
|
||||
libblkid_cflags,
|
||||
],
|
||||
},
|
||||
]
|
||||
|
||||
@ -257,7 +257,7 @@ static int validate_gpt_label(blkid_probe b, const ValidateFields *f) {
|
||||
return 0;
|
||||
|
||||
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)))
|
||||
return 0;
|
||||
@ -277,7 +277,7 @@ static int validate_gpt_type(blkid_probe b, const ValidateFields *f) {
|
||||
return 0;
|
||||
|
||||
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;
|
||||
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(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);
|
||||
if (block_fd < 0)
|
||||
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)
|
||||
return log_oom();
|
||||
|
||||
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)
|
||||
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) blkid_probe_set_superblocks_flags(b, BLKID_SUBLKS_TYPE|BLKID_SUBLKS_LABEL);
|
||||
(void) blkid_probe_enable_partitions(b, 1);
|
||||
(void) blkid_probe_set_partitions_flags(b, BLKID_PARTS_ENTRY_DETAILS);
|
||||
(void) sym_blkid_probe_enable_superblocks(b, 1);
|
||||
(void) sym_blkid_probe_set_superblocks_flags(b, BLKID_SUBLKS_TYPE|BLKID_SUBLKS_LABEL);
|
||||
(void) sym_blkid_probe_enable_partitions(b, 1);
|
||||
(void) sym_blkid_probe_set_partitions_flags(b, BLKID_PARTS_ENTRY_DETAILS);
|
||||
|
||||
errno = 0;
|
||||
r = blkid_do_safeprobe(b);
|
||||
r = sym_blkid_do_safeprobe(b);
|
||||
if (r == _BLKID_SAFEPROBE_ERROR)
|
||||
return log_error_errno(errno_or_else(EIO), "Failed to probe block device of '%s': %m", path);
|
||||
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);
|
||||
|
||||
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"))
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EPERM), "File system is supposed to be on a GPT partition table, but is not, refusing.");
|
||||
|
||||
|
||||
@ -21,7 +21,6 @@ executables += [
|
||||
'public' : true,
|
||||
'sources' : vmspawn_sources + vmspawn_extract_sources,
|
||||
'extract' : vmspawn_extract_sources,
|
||||
'dependencies' : [libblkid]
|
||||
},
|
||||
test_template + {
|
||||
'sources' : files('test-vmspawn-util.c'),
|
||||
|
||||
@ -8,7 +8,7 @@
|
||||
# (at your option) any later version.
|
||||
|
||||
[Unit]
|
||||
Description=First Boot Wizard
|
||||
Description=Initial Setup
|
||||
Documentation=man:systemd-firstboot(1)
|
||||
|
||||
ConditionPathIsReadWrite=/etc
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user