Merge pull request #8184 from poettering/color-ask-pw
Trivial merge conflict resolved locally.
This commit is contained in:
commit
730f40eb57
|
@ -67,6 +67,7 @@ BuildPackages=
|
||||||
m4
|
m4
|
||||||
meson
|
meson
|
||||||
pam-devel
|
pam-devel
|
||||||
|
pcre2-devel
|
||||||
pkgconfig
|
pkgconfig
|
||||||
python3-devel
|
python3-devel
|
||||||
python3-lxml
|
python3-lxml
|
||||||
|
|
12
TODO
12
TODO
|
@ -32,6 +32,18 @@ Features:
|
||||||
* teach tmpfiles.d q/Q logic something sensible in the context of XFS/ext4
|
* teach tmpfiles.d q/Q logic something sensible in the context of XFS/ext4
|
||||||
project quota
|
project quota
|
||||||
|
|
||||||
|
* introduce DefaultSlice= or so in system.conf that allows changing where we
|
||||||
|
place our units by default, i.e. change system.slice to something
|
||||||
|
else. Similar, ManagerSlice= should exist so that PID1's own scope unit could
|
||||||
|
be moved somewhere else too. Finally machined and logind should get similar
|
||||||
|
options so that it is possible to move user session scopes and machines to a
|
||||||
|
different slice too by default. Usecase: people who want to put resources on
|
||||||
|
the entire system, with the exception of one specific service. See:
|
||||||
|
https://lists.freedesktop.org/archives/systemd-devel/2018-February/040369.html
|
||||||
|
|
||||||
|
* check what setting the login shell to /bin/false vs. /sbin/nologin means and
|
||||||
|
do the right thing in get_user_creds_clean() with it.
|
||||||
|
|
||||||
* maybe rework get_user_creds() to query the user database if $SHELL is used
|
* maybe rework get_user_creds() to query the user database if $SHELL is used
|
||||||
for root, but only then.
|
for root, but only then.
|
||||||
|
|
||||||
|
|
|
@ -850,17 +850,33 @@ int kill_and_sigcont(pid_t pid, int sig) {
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
int getenv_for_pid(pid_t pid, const char *field, char **_value) {
|
int getenv_for_pid(pid_t pid, const char *field, char **ret) {
|
||||||
_cleanup_fclose_ FILE *f = NULL;
|
_cleanup_fclose_ FILE *f = NULL;
|
||||||
char *value = NULL;
|
char *value = NULL;
|
||||||
int r;
|
|
||||||
bool done = false;
|
bool done = false;
|
||||||
size_t l;
|
|
||||||
const char *path;
|
const char *path;
|
||||||
|
size_t l;
|
||||||
|
|
||||||
assert(pid >= 0);
|
assert(pid >= 0);
|
||||||
assert(field);
|
assert(field);
|
||||||
assert(_value);
|
assert(ret);
|
||||||
|
|
||||||
|
if (pid == 0 || pid == getpid_cached()) {
|
||||||
|
const char *e;
|
||||||
|
|
||||||
|
e = getenv(field);
|
||||||
|
if (!e) {
|
||||||
|
*ret = NULL;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
value = strdup(e);
|
||||||
|
if (!value)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
*ret = value;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
path = procfs_file_alloca(pid, "environ");
|
path = procfs_file_alloca(pid, "environ");
|
||||||
|
|
||||||
|
@ -868,13 +884,13 @@ int getenv_for_pid(pid_t pid, const char *field, char **_value) {
|
||||||
if (!f) {
|
if (!f) {
|
||||||
if (errno == ENOENT)
|
if (errno == ENOENT)
|
||||||
return -ESRCH;
|
return -ESRCH;
|
||||||
|
|
||||||
return -errno;
|
return -errno;
|
||||||
}
|
}
|
||||||
|
|
||||||
(void) __fsetlocking(f, FSETLOCKING_BYCALLER);
|
(void) __fsetlocking(f, FSETLOCKING_BYCALLER);
|
||||||
|
|
||||||
l = strlen(field);
|
l = strlen(field);
|
||||||
r = 0;
|
|
||||||
|
|
||||||
do {
|
do {
|
||||||
char line[LINE_MAX];
|
char line[LINE_MAX];
|
||||||
|
@ -899,14 +915,14 @@ int getenv_for_pid(pid_t pid, const char *field, char **_value) {
|
||||||
if (!value)
|
if (!value)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
r = 1;
|
*ret = value;
|
||||||
break;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
} while (!done);
|
} while (!done);
|
||||||
|
|
||||||
*_value = value;
|
*ret = NULL;
|
||||||
return r;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool pid_is_unwaited(pid_t pid) {
|
bool pid_is_unwaited(pid_t pid) {
|
||||||
|
|
|
@ -48,6 +48,8 @@
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
#include "macro.h"
|
#include "macro.h"
|
||||||
#include "parse-util.h"
|
#include "parse-util.h"
|
||||||
|
#include "path-util.h"
|
||||||
|
#include "proc-cmdline.h"
|
||||||
#include "process-util.h"
|
#include "process-util.h"
|
||||||
#include "socket-util.h"
|
#include "socket-util.h"
|
||||||
#include "stat-util.h"
|
#include "stat-util.h"
|
||||||
|
@ -56,14 +58,20 @@
|
||||||
#include "terminal-util.h"
|
#include "terminal-util.h"
|
||||||
#include "time-util.h"
|
#include "time-util.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
#include "path-util.h"
|
|
||||||
|
|
||||||
static volatile unsigned cached_columns = 0;
|
static volatile unsigned cached_columns = 0;
|
||||||
static volatile unsigned cached_lines = 0;
|
static volatile unsigned cached_lines = 0;
|
||||||
|
|
||||||
|
static volatile int cached_on_tty = -1;
|
||||||
|
static volatile int cached_colors_enabled = -1;
|
||||||
|
static volatile int cached_underline_enabled = -1;
|
||||||
|
|
||||||
int chvt(int vt) {
|
int chvt(int vt) {
|
||||||
_cleanup_close_ int fd;
|
_cleanup_close_ int fd;
|
||||||
|
|
||||||
|
/* Switch to the specified vt number. If the VT is specified <= 0 switch to the VT the kernel log messages go,
|
||||||
|
* if that's configured. */
|
||||||
|
|
||||||
fd = open_terminal("/dev/tty0", O_RDWR|O_NOCTTY|O_CLOEXEC|O_NONBLOCK);
|
fd = open_terminal("/dev/tty0", O_RDWR|O_NOCTTY|O_CLOEXEC|O_NONBLOCK);
|
||||||
if (fd < 0)
|
if (fd < 0)
|
||||||
return -errno;
|
return -errno;
|
||||||
|
@ -323,8 +331,8 @@ int reset_terminal(const char *name) {
|
||||||
}
|
}
|
||||||
|
|
||||||
int open_terminal(const char *name, int mode) {
|
int open_terminal(const char *name, int mode) {
|
||||||
int fd, r;
|
|
||||||
unsigned c = 0;
|
unsigned c = 0;
|
||||||
|
int fd;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If a TTY is in the process of being closed opening it might
|
* If a TTY is in the process of being closed opening it might
|
||||||
|
@ -354,8 +362,7 @@ int open_terminal(const char *name, int mode) {
|
||||||
c++;
|
c++;
|
||||||
}
|
}
|
||||||
|
|
||||||
r = isatty(fd);
|
if (isatty(fd) <= 0) {
|
||||||
if (r == 0) {
|
|
||||||
safe_close(fd);
|
safe_close(fd);
|
||||||
return -ENOTTY;
|
return -ENOTTY;
|
||||||
}
|
}
|
||||||
|
@ -365,44 +372,36 @@ int open_terminal(const char *name, int mode) {
|
||||||
|
|
||||||
int acquire_terminal(
|
int acquire_terminal(
|
||||||
const char *name,
|
const char *name,
|
||||||
bool fail,
|
AcquireTerminalFlags flags,
|
||||||
bool force,
|
|
||||||
bool ignore_tiocstty_eperm,
|
|
||||||
usec_t timeout) {
|
usec_t timeout) {
|
||||||
|
|
||||||
int fd = -1, notify = -1, r = 0, wd = -1;
|
_cleanup_close_ int notify = -1, fd = -1;
|
||||||
usec_t ts = 0;
|
usec_t ts = USEC_INFINITY;
|
||||||
|
int r, wd = -1;
|
||||||
|
|
||||||
assert(name);
|
assert(name);
|
||||||
|
assert(IN_SET(flags & ~ACQUIRE_TERMINAL_PERMISSIVE, ACQUIRE_TERMINAL_TRY, ACQUIRE_TERMINAL_FORCE, ACQUIRE_TERMINAL_WAIT));
|
||||||
|
|
||||||
/* We use inotify to be notified when the tty is closed. We
|
/* We use inotify to be notified when the tty is closed. We create the watch before checking if we can actually
|
||||||
* create the watch before checking if we can actually acquire
|
* acquire it, so that we don't lose any event.
|
||||||
* it, so that we don't lose any event.
|
|
||||||
*
|
*
|
||||||
* Note: strictly speaking this actually watches for the
|
* Note: strictly speaking this actually watches for the device being closed, it does *not* really watch
|
||||||
* device being closed, it does *not* really watch whether a
|
* whether a tty loses its controlling process. However, unless some rogue process uses TIOCNOTTY on /dev/tty
|
||||||
* tty loses its controlling process. However, unless some
|
* *after* closing its tty otherwise this will not become a problem. As long as the administrator makes sure
|
||||||
* rogue process uses TIOCNOTTY on /dev/tty *after* closing
|
* not configure any service on the same tty as an untrusted user this should not be a problem. (Which he
|
||||||
* its tty otherwise this will not become a problem. As long
|
* probably should not do anyway.) */
|
||||||
* as the administrator makes sure not configure any service
|
|
||||||
* on the same tty as an untrusted user this should not be a
|
|
||||||
* problem. (Which he probably should not do anyway.) */
|
|
||||||
|
|
||||||
if (timeout != USEC_INFINITY)
|
if ((flags & ~ACQUIRE_TERMINAL_PERMISSIVE) == ACQUIRE_TERMINAL_WAIT) {
|
||||||
ts = now(CLOCK_MONOTONIC);
|
|
||||||
|
|
||||||
if (!fail && !force) {
|
|
||||||
notify = inotify_init1(IN_CLOEXEC | (timeout != USEC_INFINITY ? IN_NONBLOCK : 0));
|
notify = inotify_init1(IN_CLOEXEC | (timeout != USEC_INFINITY ? IN_NONBLOCK : 0));
|
||||||
if (notify < 0) {
|
if (notify < 0)
|
||||||
r = -errno;
|
return -errno;
|
||||||
goto fail;
|
|
||||||
}
|
|
||||||
|
|
||||||
wd = inotify_add_watch(notify, name, IN_CLOSE);
|
wd = inotify_add_watch(notify, name, IN_CLOSE);
|
||||||
if (wd < 0) {
|
if (wd < 0)
|
||||||
r = -errno;
|
return -errno;
|
||||||
goto fail;
|
|
||||||
}
|
if (timeout != USEC_INFINITY)
|
||||||
|
ts = now(CLOCK_MONOTONIC);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
|
@ -414,41 +413,43 @@ int acquire_terminal(
|
||||||
if (notify >= 0) {
|
if (notify >= 0) {
|
||||||
r = flush_fd(notify);
|
r = flush_fd(notify);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
goto fail;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* We pass here O_NOCTTY only so that we can check the return
|
/* We pass here O_NOCTTY only so that we can check the return value TIOCSCTTY and have a reliable way
|
||||||
* value TIOCSCTTY and have a reliable way to figure out if we
|
* to figure out if we successfully became the controlling process of the tty */
|
||||||
* successfully became the controlling process of the tty */
|
|
||||||
fd = open_terminal(name, O_RDWR|O_NOCTTY|O_CLOEXEC);
|
fd = open_terminal(name, O_RDWR|O_NOCTTY|O_CLOEXEC);
|
||||||
if (fd < 0)
|
if (fd < 0)
|
||||||
return fd;
|
return fd;
|
||||||
|
|
||||||
/* Temporarily ignore SIGHUP, so that we don't get SIGHUP'ed
|
/* Temporarily ignore SIGHUP, so that we don't get SIGHUP'ed if we already own the tty. */
|
||||||
* if we already own the tty. */
|
|
||||||
assert_se(sigaction(SIGHUP, &sa_new, &sa_old) == 0);
|
assert_se(sigaction(SIGHUP, &sa_new, &sa_old) == 0);
|
||||||
|
|
||||||
/* First, try to get the tty */
|
/* First, try to get the tty */
|
||||||
if (ioctl(fd, TIOCSCTTY, force) < 0)
|
r = ioctl(fd, TIOCSCTTY,
|
||||||
r = -errno;
|
(flags & ~ACQUIRE_TERMINAL_PERMISSIVE) == ACQUIRE_TERMINAL_FORCE) < 0 ? -errno : 0;
|
||||||
|
|
||||||
|
/* Reset signal handler to old value */
|
||||||
assert_se(sigaction(SIGHUP, &sa_old, NULL) == 0);
|
assert_se(sigaction(SIGHUP, &sa_old, NULL) == 0);
|
||||||
|
|
||||||
/* Sometimes, it makes sense to ignore TIOCSCTTY
|
/* Success? Exit the loop now! */
|
||||||
* returning EPERM, i.e. when very likely we already
|
|
||||||
* are have this controlling terminal. */
|
|
||||||
if (r < 0 && r == -EPERM && ignore_tiocstty_eperm)
|
|
||||||
r = 0;
|
|
||||||
|
|
||||||
if (r < 0 && (force || fail || r != -EPERM))
|
|
||||||
goto fail;
|
|
||||||
|
|
||||||
if (r >= 0)
|
if (r >= 0)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
assert(!fail);
|
/* Any failure besides -EPERM? Fail, regardless of the mode. */
|
||||||
assert(!force);
|
if (r != -EPERM)
|
||||||
|
return r;
|
||||||
|
|
||||||
|
if (flags & ACQUIRE_TERMINAL_PERMISSIVE) /* If we are in permissive mode, then EPERM is fine, turn this
|
||||||
|
* into a success. Note that EPERM is also returned if we
|
||||||
|
* already are the owner of the TTY. */
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (flags != ACQUIRE_TERMINAL_WAIT) /* If we are in TRY or FORCE mode, then propagate EPERM as EPERM */
|
||||||
|
return r;
|
||||||
|
|
||||||
assert(notify >= 0);
|
assert(notify >= 0);
|
||||||
|
assert(wd >= 0);
|
||||||
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
union inotify_event_buffer buffer;
|
union inotify_event_buffer buffer;
|
||||||
|
@ -458,20 +459,17 @@ int acquire_terminal(
|
||||||
if (timeout != USEC_INFINITY) {
|
if (timeout != USEC_INFINITY) {
|
||||||
usec_t n;
|
usec_t n;
|
||||||
|
|
||||||
|
assert(ts != USEC_INFINITY);
|
||||||
|
|
||||||
n = now(CLOCK_MONOTONIC);
|
n = now(CLOCK_MONOTONIC);
|
||||||
if (ts + timeout < n) {
|
if (ts + timeout < n)
|
||||||
r = -ETIMEDOUT;
|
return -ETIMEDOUT;
|
||||||
goto fail;
|
|
||||||
}
|
|
||||||
|
|
||||||
r = fd_wait_for_event(notify, POLLIN, ts + timeout - n);
|
r = fd_wait_for_event(notify, POLLIN, ts + timeout - n);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
goto fail;
|
return r;
|
||||||
|
if (r == 0)
|
||||||
if (r == 0) {
|
return -ETIMEDOUT;
|
||||||
r = -ETIMEDOUT;
|
|
||||||
goto fail;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
l = read(notify, &buffer, sizeof(buffer));
|
l = read(notify, &buffer, sizeof(buffer));
|
||||||
|
@ -479,34 +477,27 @@ int acquire_terminal(
|
||||||
if (IN_SET(errno, EINTR, EAGAIN))
|
if (IN_SET(errno, EINTR, EAGAIN))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
r = -errno;
|
return -errno;
|
||||||
goto fail;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
FOREACH_INOTIFY_EVENT(e, buffer, l) {
|
FOREACH_INOTIFY_EVENT(e, buffer, l) {
|
||||||
if (e->wd != wd || !(e->mask & IN_CLOSE)) {
|
if (e->mask & IN_Q_OVERFLOW) /* If we hit an inotify queue overflow, simply check if the terminal is up for grabs now. */
|
||||||
r = -EIO;
|
break;
|
||||||
goto fail;
|
|
||||||
}
|
if (e->wd != wd || !(e->mask & IN_CLOSE)) /* Safety checks */
|
||||||
|
return -EIO;
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* We close the tty fd here since if the old session
|
/* We close the tty fd here since if the old session ended our handle will be dead. It's important that
|
||||||
* ended our handle will be dead. It's important that
|
* we do this after sleeping, so that we don't enter an endless loop. */
|
||||||
* we do this after sleeping, so that we don't enter
|
|
||||||
* an endless loop. */
|
|
||||||
fd = safe_close(fd);
|
fd = safe_close(fd);
|
||||||
}
|
}
|
||||||
|
|
||||||
safe_close(notify);
|
r = fd;
|
||||||
|
fd = -1;
|
||||||
return fd;
|
|
||||||
|
|
||||||
fail:
|
|
||||||
safe_close(fd);
|
|
||||||
safe_close(notify);
|
|
||||||
|
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
@ -519,7 +510,7 @@ int release_terminal(void) {
|
||||||
|
|
||||||
_cleanup_close_ int fd = -1;
|
_cleanup_close_ int fd = -1;
|
||||||
struct sigaction sa_old;
|
struct sigaction sa_old;
|
||||||
int r = 0;
|
int r;
|
||||||
|
|
||||||
fd = open("/dev/tty", O_RDWR|O_NOCTTY|O_CLOEXEC|O_NONBLOCK);
|
fd = open("/dev/tty", O_RDWR|O_NOCTTY|O_CLOEXEC|O_NONBLOCK);
|
||||||
if (fd < 0)
|
if (fd < 0)
|
||||||
|
@ -529,8 +520,7 @@ int release_terminal(void) {
|
||||||
* by our own TIOCNOTTY */
|
* by our own TIOCNOTTY */
|
||||||
assert_se(sigaction(SIGHUP, &sa_new, &sa_old) == 0);
|
assert_se(sigaction(SIGHUP, &sa_new, &sa_old) == 0);
|
||||||
|
|
||||||
if (ioctl(fd, TIOCNOTTY) < 0)
|
r = ioctl(fd, TIOCNOTTY) < 0 ? -errno : 0;
|
||||||
r = -errno;
|
|
||||||
|
|
||||||
assert_se(sigaction(SIGHUP, &sa_old, NULL) == 0);
|
assert_se(sigaction(SIGHUP, &sa_old, NULL) == 0);
|
||||||
|
|
||||||
|
@ -630,7 +620,7 @@ int make_console_stdio(void) {
|
||||||
|
|
||||||
/* Make /dev/console the controlling terminal and stdin/stdout/stderr */
|
/* Make /dev/console the controlling terminal and stdin/stdout/stderr */
|
||||||
|
|
||||||
fd = acquire_terminal("/dev/console", false, true, true, USEC_INFINITY);
|
fd = acquire_terminal("/dev/console", ACQUIRE_TERMINAL_FORCE|ACQUIRE_TERMINAL_PERMISSIVE, USEC_INFINITY);
|
||||||
if (fd < 0)
|
if (fd < 0)
|
||||||
return log_error_errno(fd, "Failed to acquire terminal: %m");
|
return log_error_errno(fd, "Failed to acquire terminal: %m");
|
||||||
|
|
||||||
|
@ -642,6 +632,8 @@ int make_console_stdio(void) {
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_error_errno(r, "Failed to duplicate terminal fd: %m");
|
return log_error_errno(r, "Failed to duplicate terminal fd: %m");
|
||||||
|
|
||||||
|
reset_terminal_feature_caches();
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -680,57 +672,80 @@ int vtnr_from_tty(const char *tty) {
|
||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
|
|
||||||
char *resolve_dev_console(char **active) {
|
int resolve_dev_console(char **ret) {
|
||||||
|
_cleanup_free_ char *active = NULL;
|
||||||
char *tty;
|
char *tty;
|
||||||
|
int r;
|
||||||
|
|
||||||
/* Resolve where /dev/console is pointing to, if /sys is actually ours
|
assert(ret);
|
||||||
* (i.e. not read-only-mounted which is a sign for container setups) */
|
|
||||||
|
/* Resolve where /dev/console is pointing to, if /sys is actually ours (i.e. not read-only-mounted which is a
|
||||||
|
* sign for container setups) */
|
||||||
|
|
||||||
if (path_is_read_only_fs("/sys") > 0)
|
if (path_is_read_only_fs("/sys") > 0)
|
||||||
return NULL;
|
return -ENOMEDIUM;
|
||||||
|
|
||||||
if (read_one_line_file("/sys/class/tty/console/active", active) < 0)
|
r = read_one_line_file("/sys/class/tty/console/active", &active);
|
||||||
return NULL;
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
/* If multiple log outputs are configured the last one is what
|
/* If multiple log outputs are configured the last one is what /dev/console points to */
|
||||||
* /dev/console points to */
|
tty = strrchr(active, ' ');
|
||||||
tty = strrchr(*active, ' ');
|
|
||||||
if (tty)
|
if (tty)
|
||||||
tty++;
|
tty++;
|
||||||
else
|
else
|
||||||
tty = *active;
|
tty = active;
|
||||||
|
|
||||||
if (streq(tty, "tty0")) {
|
if (streq(tty, "tty0")) {
|
||||||
char *tmp;
|
active = mfree(active);
|
||||||
|
|
||||||
/* Get the active VC (e.g. tty1) */
|
/* Get the active VC (e.g. tty1) */
|
||||||
if (read_one_line_file("/sys/class/tty/tty0/active", &tmp) >= 0) {
|
r = read_one_line_file("/sys/class/tty/tty0/active", &active);
|
||||||
free(*active);
|
if (r < 0)
|
||||||
tty = *active = tmp;
|
return r;
|
||||||
}
|
|
||||||
|
tty = active;
|
||||||
}
|
}
|
||||||
|
|
||||||
return tty;
|
if (tty == active) {
|
||||||
|
*ret = active;
|
||||||
|
active = NULL;
|
||||||
|
} else {
|
||||||
|
char *tmp;
|
||||||
|
|
||||||
|
tmp = strdup(tty);
|
||||||
|
if (!tmp)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
*ret = tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int get_kernel_consoles(char ***consoles) {
|
int get_kernel_consoles(char ***ret) {
|
||||||
_cleanup_strv_free_ char **con = NULL;
|
_cleanup_strv_free_ char **l = NULL;
|
||||||
_cleanup_free_ char *line = NULL;
|
_cleanup_free_ char *line = NULL;
|
||||||
const char *active;
|
const char *p;
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
assert(consoles);
|
assert(ret);
|
||||||
|
|
||||||
|
/* If we /sys is mounted read-only this means we are running in some kind of container environment. In that
|
||||||
|
* case /sys would reflect the host system, not us, hence ignore the data we can read from it. */
|
||||||
|
if (path_is_read_only_fs("/sys") > 0)
|
||||||
|
goto fallback;
|
||||||
|
|
||||||
r = read_one_line_file("/sys/class/tty/console/active", &line);
|
r = read_one_line_file("/sys/class/tty/console/active", &line);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
active = line;
|
p = line;
|
||||||
for (;;) {
|
for (;;) {
|
||||||
_cleanup_free_ char *tty = NULL;
|
_cleanup_free_ char *tty = NULL;
|
||||||
char *path;
|
char *path;
|
||||||
|
|
||||||
r = extract_first_word(&active, &tty, NULL, 0);
|
r = extract_first_word(&p, &tty, NULL, 0);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
if (r == 0)
|
if (r == 0)
|
||||||
|
@ -753,35 +768,44 @@ int get_kernel_consoles(char ***consoles) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
r = strv_consume(&con, path);
|
r = strv_consume(&l, path);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (strv_isempty(con)) {
|
if (strv_isempty(l)) {
|
||||||
log_debug("No devices found for system console");
|
log_debug("No devices found for system console");
|
||||||
|
goto fallback;
|
||||||
r = strv_extend(&con, "/dev/console");
|
|
||||||
if (r < 0)
|
|
||||||
return r;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
*consoles = con;
|
*ret = l;
|
||||||
con = NULL;
|
l = NULL;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
fallback:
|
||||||
|
r = strv_extend(&l, "/dev/console");
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
|
*ret = l;
|
||||||
|
l = NULL;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool tty_is_vc_resolve(const char *tty) {
|
bool tty_is_vc_resolve(const char *tty) {
|
||||||
_cleanup_free_ char *active = NULL;
|
_cleanup_free_ char *resolved = NULL;
|
||||||
|
|
||||||
assert(tty);
|
assert(tty);
|
||||||
|
|
||||||
tty = skip_dev_prefix(tty);
|
tty = skip_dev_prefix(tty);
|
||||||
|
|
||||||
if (streq(tty, "console")) {
|
if (streq(tty, "console")) {
|
||||||
tty = resolve_dev_console(&active);
|
if (resolve_dev_console(&resolved) < 0)
|
||||||
if (!tty)
|
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
tty = resolved;
|
||||||
}
|
}
|
||||||
|
|
||||||
return tty_is_vc(tty);
|
return tty_is_vc(tty);
|
||||||
|
@ -807,7 +831,7 @@ unsigned columns(void) {
|
||||||
const char *e;
|
const char *e;
|
||||||
int c;
|
int c;
|
||||||
|
|
||||||
if (_likely_(cached_columns > 0))
|
if (cached_columns > 0)
|
||||||
return cached_columns;
|
return cached_columns;
|
||||||
|
|
||||||
c = 0;
|
c = 0;
|
||||||
|
@ -841,7 +865,7 @@ unsigned lines(void) {
|
||||||
const char *e;
|
const char *e;
|
||||||
int l;
|
int l;
|
||||||
|
|
||||||
if (_likely_(cached_lines > 0))
|
if (cached_lines > 0)
|
||||||
return cached_lines;
|
return cached_lines;
|
||||||
|
|
||||||
l = 0;
|
l = 0;
|
||||||
|
@ -865,10 +889,17 @@ void columns_lines_cache_reset(int signum) {
|
||||||
cached_lines = 0;
|
cached_lines = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool on_tty(void) {
|
void reset_terminal_feature_caches(void) {
|
||||||
static int cached_on_tty = -1;
|
cached_columns = 0;
|
||||||
|
cached_lines = 0;
|
||||||
|
|
||||||
if (_unlikely_(cached_on_tty < 0))
|
cached_colors_enabled = -1;
|
||||||
|
cached_underline_enabled = -1;
|
||||||
|
cached_on_tty = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool on_tty(void) {
|
||||||
|
if (cached_on_tty < 0)
|
||||||
cached_on_tty = isatty(STDOUT_FILENO) > 0;
|
cached_on_tty = isatty(STDOUT_FILENO) > 0;
|
||||||
|
|
||||||
return cached_on_tty;
|
return cached_on_tty;
|
||||||
|
@ -879,7 +910,7 @@ int make_stdio(int fd) {
|
||||||
|
|
||||||
assert(fd >= 0);
|
assert(fd >= 0);
|
||||||
|
|
||||||
if (dup2(fd, STDIN_FILENO) < 0 && r >= 0)
|
if (dup2(fd, STDIN_FILENO) < 0)
|
||||||
r = -errno;
|
r = -errno;
|
||||||
if (dup2(fd, STDOUT_FILENO) < 0 && r >= 0)
|
if (dup2(fd, STDOUT_FILENO) < 0 && r >= 0)
|
||||||
r = -errno;
|
r = -errno;
|
||||||
|
@ -896,13 +927,17 @@ int make_stdio(int fd) {
|
||||||
}
|
}
|
||||||
|
|
||||||
int make_null_stdio(void) {
|
int make_null_stdio(void) {
|
||||||
int null_fd;
|
int null_fd, r;
|
||||||
|
|
||||||
null_fd = open("/dev/null", O_RDWR|O_NOCTTY|O_CLOEXEC);
|
null_fd = open("/dev/null", O_RDWR|O_NOCTTY|O_CLOEXEC);
|
||||||
if (null_fd < 0)
|
if (null_fd < 0)
|
||||||
return -errno;
|
return -errno;
|
||||||
|
|
||||||
return make_stdio(null_fd);
|
r = make_stdio(null_fd);
|
||||||
|
|
||||||
|
reset_terminal_feature_caches();
|
||||||
|
|
||||||
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
int getttyname_malloc(int fd, char **ret) {
|
int getttyname_malloc(int fd, char **ret) {
|
||||||
|
@ -1205,38 +1240,63 @@ bool terminal_is_dumb(void) {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool colors_enabled(void) {
|
bool colors_enabled(void) {
|
||||||
static int enabled = -1;
|
|
||||||
|
|
||||||
if (_unlikely_(enabled < 0)) {
|
/* Returns true if colors are considered supported on our stdout. For that we check $SYSTEMD_COLORS first
|
||||||
|
* (which is the explicit way to turn off/on colors). If that didn't work we turn off colors unless we are on a
|
||||||
|
* TTY. And if we are on a TTY we turn it off if $TERM is set to "dumb". There's one special tweak though: if
|
||||||
|
* we are PID 1 then we do not check whether we are connected to a TTY, because we don't keep /dev/console open
|
||||||
|
* continously due to fear of SAK, and hence things are a bit weird. */
|
||||||
|
|
||||||
|
if (cached_colors_enabled < 0) {
|
||||||
int val;
|
int val;
|
||||||
|
|
||||||
val = getenv_bool("SYSTEMD_COLORS");
|
val = getenv_bool("SYSTEMD_COLORS");
|
||||||
if (val >= 0)
|
if (val >= 0)
|
||||||
enabled = val;
|
cached_colors_enabled = val;
|
||||||
else if (getpid_cached() == 1)
|
else if (getpid_cached() == 1)
|
||||||
/* PID1 outputs to the console without holding it open all the time */
|
/* PID1 outputs to the console without holding it open all the time */
|
||||||
enabled = !getenv_terminal_is_dumb();
|
cached_colors_enabled = !getenv_terminal_is_dumb();
|
||||||
else
|
else
|
||||||
enabled = !terminal_is_dumb();
|
cached_colors_enabled = !terminal_is_dumb();
|
||||||
}
|
}
|
||||||
|
|
||||||
return enabled;
|
return cached_colors_enabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool dev_console_colors_enabled(void) {
|
||||||
|
_cleanup_free_ char *s = NULL;
|
||||||
|
int b;
|
||||||
|
|
||||||
|
/* Returns true if we assume that color is supported on /dev/console.
|
||||||
|
*
|
||||||
|
* For that we first check if we explicitly got told to use colors or not, by checking $SYSTEMD_COLORS. If that
|
||||||
|
* didn't tell us anything we check whether PID 1 has $TERM set, and if not whether $TERM is set on the kernel
|
||||||
|
* command line. If we find $TERM set we assume color if it's not set to "dumb", similar to regular
|
||||||
|
* colors_enabled() operates. */
|
||||||
|
|
||||||
|
b = getenv_bool("SYSTEMD_COLORS");
|
||||||
|
if (b >= 0)
|
||||||
|
return b;
|
||||||
|
|
||||||
|
if (getenv_for_pid(1, "TERM", &s) <= 0)
|
||||||
|
(void) proc_cmdline_get_key("TERM", 0, &s);
|
||||||
|
|
||||||
|
return !streq_ptr(s, "dumb");
|
||||||
}
|
}
|
||||||
|
|
||||||
bool underline_enabled(void) {
|
bool underline_enabled(void) {
|
||||||
static int enabled = -1;
|
|
||||||
|
|
||||||
if (enabled < 0) {
|
if (cached_underline_enabled < 0) {
|
||||||
|
|
||||||
/* The Linux console doesn't support underlining, turn it off, but only there. */
|
/* The Linux console doesn't support underlining, turn it off, but only there. */
|
||||||
|
|
||||||
if (!colors_enabled())
|
if (colors_enabled())
|
||||||
enabled = false;
|
cached_underline_enabled = !streq_ptr(getenv("TERM"), "linux");
|
||||||
else
|
else
|
||||||
enabled = !streq_ptr(getenv("TERM"), "linux");
|
cached_underline_enabled = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return enabled;
|
return cached_underline_enabled;
|
||||||
}
|
}
|
||||||
|
|
||||||
int vt_default_utf8(void) {
|
int vt_default_utf8(void) {
|
||||||
|
|
|
@ -52,7 +52,23 @@ int reset_terminal_fd(int fd, bool switch_to_text);
|
||||||
int reset_terminal(const char *name);
|
int reset_terminal(const char *name);
|
||||||
|
|
||||||
int open_terminal(const char *name, int mode);
|
int open_terminal(const char *name, int mode);
|
||||||
int acquire_terminal(const char *name, bool fail, bool force, bool ignore_tiocstty_eperm, usec_t timeout);
|
|
||||||
|
/* Flags for tweaking the way we become the controlling process of a terminal. */
|
||||||
|
typedef enum AcquireTerminalFlags {
|
||||||
|
/* Try to become the controlling process of the TTY. If we can't return -EPERM. */
|
||||||
|
ACQUIRE_TERMINAL_TRY = 0,
|
||||||
|
|
||||||
|
/* Tell the kernel to forcibly make us the controlling process of the TTY. Returns -EPERM if the kernel doesn't allow that. */
|
||||||
|
ACQUIRE_TERMINAL_FORCE = 1,
|
||||||
|
|
||||||
|
/* If we can't become the controlling process of the TTY right-away, then wait until we can. */
|
||||||
|
ACQUIRE_TERMINAL_WAIT = 2,
|
||||||
|
|
||||||
|
/* Pick one of the above, and then OR this flag in, in order to request permissive behaviour, if we can't become controlling process then don't mind */
|
||||||
|
ACQUIRE_TERMINAL_PERMISSIVE = 4,
|
||||||
|
} AcquireTerminalFlags;
|
||||||
|
|
||||||
|
int acquire_terminal(const char *name, AcquireTerminalFlags flags, usec_t timeout);
|
||||||
int release_terminal(void);
|
int release_terminal(void);
|
||||||
|
|
||||||
int terminal_vhangup_fd(int fd);
|
int terminal_vhangup_fd(int fd);
|
||||||
|
@ -66,8 +82,8 @@ int ask_string(char **ret, const char *text, ...) _printf_(2, 3);
|
||||||
|
|
||||||
int vt_disallocate(const char *name);
|
int vt_disallocate(const char *name);
|
||||||
|
|
||||||
char *resolve_dev_console(char **active);
|
int resolve_dev_console(char **ret);
|
||||||
int get_kernel_consoles(char ***consoles);
|
int get_kernel_consoles(char ***ret);
|
||||||
bool tty_is_vc(const char *tty);
|
bool tty_is_vc(const char *tty);
|
||||||
bool tty_is_vc_resolve(const char *tty);
|
bool tty_is_vc_resolve(const char *tty);
|
||||||
bool tty_is_console(const char *tty) _pure_;
|
bool tty_is_console(const char *tty) _pure_;
|
||||||
|
@ -82,12 +98,15 @@ int fd_columns(int fd);
|
||||||
unsigned columns(void);
|
unsigned columns(void);
|
||||||
int fd_lines(int fd);
|
int fd_lines(int fd);
|
||||||
unsigned lines(void);
|
unsigned lines(void);
|
||||||
|
|
||||||
void columns_lines_cache_reset(int _unused_ signum);
|
void columns_lines_cache_reset(int _unused_ signum);
|
||||||
|
void reset_terminal_feature_caches(void);
|
||||||
|
|
||||||
bool on_tty(void);
|
bool on_tty(void);
|
||||||
bool terminal_is_dumb(void);
|
bool terminal_is_dumb(void);
|
||||||
bool colors_enabled(void);
|
bool colors_enabled(void);
|
||||||
bool underline_enabled(void);
|
bool underline_enabled(void);
|
||||||
|
bool dev_console_colors_enabled(void);
|
||||||
|
|
||||||
#define DEFINE_ANSI_FUNC(name, NAME) \
|
#define DEFINE_ANSI_FUNC(name, NAME) \
|
||||||
static inline const char *ansi_##name(void) { \
|
static inline const char *ansi_##name(void) { \
|
||||||
|
|
|
@ -408,3 +408,22 @@ int utf8_encoded_valid_unichar(const char *str) {
|
||||||
|
|
||||||
return len;
|
return len;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
size_t utf8_n_codepoints(const char *str) {
|
||||||
|
size_t n = 0;
|
||||||
|
|
||||||
|
/* Returns the number of UTF-8 codepoints in this string, or (size_t) -1 if the string is not valid UTF-8. */
|
||||||
|
|
||||||
|
while (*str != 0) {
|
||||||
|
int k;
|
||||||
|
|
||||||
|
k = utf8_encoded_valid_unichar(str);
|
||||||
|
if (k < 0)
|
||||||
|
return (size_t) -1;
|
||||||
|
|
||||||
|
str += k;
|
||||||
|
n++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
|
|
@ -59,3 +59,5 @@ static inline bool utf16_is_trailing_surrogate(char16_t c) {
|
||||||
static inline char32_t utf16_surrogate_pair_to_unichar(char16_t lead, char16_t trail) {
|
static inline char32_t utf16_surrogate_pair_to_unichar(char16_t lead, char16_t trail) {
|
||||||
return ((lead - 0xd800) << 10) + (trail - 0xdc00) + 0x10000;
|
return ((lead - 0xd800) << 10) + (trail - 0xdc00) + 0x10000;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
size_t utf8_n_codepoints(const char *str);
|
||||||
|
|
|
@ -509,9 +509,9 @@ static int setup_input(
|
||||||
int fd;
|
int fd;
|
||||||
|
|
||||||
fd = acquire_terminal(exec_context_tty_path(context),
|
fd = acquire_terminal(exec_context_tty_path(context),
|
||||||
i == EXEC_INPUT_TTY_FAIL,
|
i == EXEC_INPUT_TTY_FAIL ? ACQUIRE_TERMINAL_TRY :
|
||||||
i == EXEC_INPUT_TTY_FORCE,
|
i == EXEC_INPUT_TTY_FORCE ? ACQUIRE_TERMINAL_FORCE :
|
||||||
false,
|
ACQUIRE_TERMINAL_WAIT,
|
||||||
USEC_INFINITY);
|
USEC_INFINITY);
|
||||||
if (fd < 0)
|
if (fd < 0)
|
||||||
return fd;
|
return fd;
|
||||||
|
@ -753,7 +753,7 @@ static int setup_confirm_stdio(const char *vc, int *_saved_stdin, int *_saved_st
|
||||||
if (saved_stdout < 0)
|
if (saved_stdout < 0)
|
||||||
return -errno;
|
return -errno;
|
||||||
|
|
||||||
fd = acquire_terminal(vc, false, false, false, DEFAULT_CONFIRM_USEC);
|
fd = acquire_terminal(vc, ACQUIRE_TERMINAL_WAIT, DEFAULT_CONFIRM_USEC);
|
||||||
if (fd < 0)
|
if (fd < 0)
|
||||||
return fd;
|
return fd;
|
||||||
|
|
||||||
|
@ -3871,8 +3871,7 @@ static int exec_context_load_environment(const Unit *unit, const ExecContext *c,
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool tty_may_match_dev_console(const char *tty) {
|
static bool tty_may_match_dev_console(const char *tty) {
|
||||||
_cleanup_free_ char *active = NULL;
|
_cleanup_free_ char *resolved = NULL;
|
||||||
char *console;
|
|
||||||
|
|
||||||
if (!tty)
|
if (!tty)
|
||||||
return true;
|
return true;
|
||||||
|
@ -3883,13 +3882,11 @@ static bool tty_may_match_dev_console(const char *tty) {
|
||||||
if (streq(tty, "console"))
|
if (streq(tty, "console"))
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
console = resolve_dev_console(&active);
|
if (resolve_dev_console(&resolved) < 0)
|
||||||
/* if we could not resolve, assume it may */
|
return true; /* if we could not resolve, assume it may */
|
||||||
if (!console)
|
|
||||||
return true;
|
|
||||||
|
|
||||||
/* "tty0" means the active VC, so it may be the same sometimes */
|
/* "tty0" means the active VC, so it may be the same sometimes */
|
||||||
return streq(console, tty) || (streq(console, "tty0") && tty_is_vc(tty));
|
return streq(resolved, tty) || (streq(resolved, "tty0") && tty_is_vc(tty));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool exec_context_may_touch_console(const ExecContext *ec) {
|
bool exec_context_may_touch_console(const ExecContext *ec) {
|
||||||
|
|
|
@ -558,7 +558,7 @@ static int prompt_root_password(void) {
|
||||||
for (;;) {
|
for (;;) {
|
||||||
_cleanup_string_free_erase_ char *a = NULL, *b = NULL;
|
_cleanup_string_free_erase_ char *a = NULL, *b = NULL;
|
||||||
|
|
||||||
r = ask_password_tty(msg1, NULL, 0, 0, NULL, &a);
|
r = ask_password_tty(-1, msg1, NULL, 0, 0, NULL, &a);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_error_errno(r, "Failed to query root password: %m");
|
return log_error_errno(r, "Failed to query root password: %m");
|
||||||
|
|
||||||
|
@ -567,7 +567,7 @@ static int prompt_root_password(void) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
r = ask_password_tty(msg2, NULL, 0, 0, NULL, &b);
|
r = ask_password_tty(-1, msg2, NULL, 0, 0, NULL, &b);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_error_errno(r, "Failed to query root password: %m");
|
return log_error_errno(r, "Failed to query root password: %m");
|
||||||
|
|
||||||
|
|
|
@ -201,7 +201,29 @@ static void backspace_chars(int ttyfd, size_t p) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void backspace_string(int ttyfd, const char *str) {
|
||||||
|
size_t m;
|
||||||
|
|
||||||
|
assert(str);
|
||||||
|
|
||||||
|
if (ttyfd < 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
/* Backspaces back for enough characters to entirely undo printing of the specified string. */
|
||||||
|
|
||||||
|
m = utf8_n_codepoints(str);
|
||||||
|
if (m == (size_t) -1)
|
||||||
|
m = strlen(str); /* Not a valid UTF-8 string? If so, let's backspace the number of bytes output. Most
|
||||||
|
* likely this happened because we are not in an UTF-8 locale, and in that case that
|
||||||
|
* is the correct thing to do. And even if it's not, terminals tend to stop
|
||||||
|
* backspacing at the leftmost column, hence backspacing too much should be mostly
|
||||||
|
* OK. */
|
||||||
|
|
||||||
|
backspace_chars(ttyfd, m);
|
||||||
|
}
|
||||||
|
|
||||||
int ask_password_tty(
|
int ask_password_tty(
|
||||||
|
int ttyfd,
|
||||||
const char *message,
|
const char *message,
|
||||||
const char *keyname,
|
const char *keyname,
|
||||||
usec_t until,
|
usec_t until,
|
||||||
|
@ -209,19 +231,20 @@ int ask_password_tty(
|
||||||
const char *flag_file,
|
const char *flag_file,
|
||||||
char **ret) {
|
char **ret) {
|
||||||
|
|
||||||
struct termios old_termios, new_termios;
|
|
||||||
char passphrase[LINE_MAX + 1] = {}, *x;
|
|
||||||
size_t p = 0, codepoint = 0;
|
|
||||||
int r;
|
|
||||||
_cleanup_close_ int ttyfd = -1, notify = -1;
|
|
||||||
struct pollfd pollfd[2];
|
|
||||||
bool reset_tty = false;
|
|
||||||
bool dirty = false;
|
|
||||||
enum {
|
enum {
|
||||||
POLL_TTY,
|
POLL_TTY,
|
||||||
POLL_INOTIFY
|
POLL_INOTIFY,
|
||||||
|
_POLL_MAX,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
bool reset_tty = false, dirty = false, use_color = false;
|
||||||
|
_cleanup_close_ int cttyfd = -1, notify = -1;
|
||||||
|
struct termios old_termios, new_termios;
|
||||||
|
char passphrase[LINE_MAX + 1] = {}, *x;
|
||||||
|
struct pollfd pollfd[_POLL_MAX];
|
||||||
|
size_t p = 0, codepoint = 0;
|
||||||
|
int r;
|
||||||
|
|
||||||
assert(ret);
|
assert(ret);
|
||||||
|
|
||||||
if (flags & ASK_PASSWORD_NO_TTY)
|
if (flags & ASK_PASSWORD_NO_TTY)
|
||||||
|
@ -232,33 +255,34 @@ int ask_password_tty(
|
||||||
|
|
||||||
if (flag_file) {
|
if (flag_file) {
|
||||||
notify = inotify_init1(IN_CLOEXEC|IN_NONBLOCK);
|
notify = inotify_init1(IN_CLOEXEC|IN_NONBLOCK);
|
||||||
if (notify < 0) {
|
if (notify < 0)
|
||||||
r = -errno;
|
return -errno;
|
||||||
goto finish;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (inotify_add_watch(notify, flag_file, IN_ATTRIB /* for the link count */) < 0) {
|
if (inotify_add_watch(notify, flag_file, IN_ATTRIB /* for the link count */) < 0)
|
||||||
r = -errno;
|
return -errno;
|
||||||
goto finish;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ttyfd = open("/dev/tty", O_RDWR|O_NOCTTY|O_CLOEXEC);
|
/* If the caller didn't specify a TTY, then use the controlling tty, if we can. */
|
||||||
|
if (ttyfd < 0)
|
||||||
|
ttyfd = cttyfd = open("/dev/tty", O_RDWR|O_NOCTTY|O_CLOEXEC);
|
||||||
|
|
||||||
if (ttyfd >= 0) {
|
if (ttyfd >= 0) {
|
||||||
|
if (tcgetattr(ttyfd, &old_termios) < 0)
|
||||||
|
return -errno;
|
||||||
|
|
||||||
if (tcgetattr(ttyfd, &old_termios) < 0) {
|
if (flags & ASK_PASSWORD_CONSOLE_COLOR)
|
||||||
r = -errno;
|
use_color = dev_console_colors_enabled();
|
||||||
goto finish;
|
else
|
||||||
}
|
use_color = colors_enabled();
|
||||||
|
|
||||||
if (colors_enabled())
|
if (use_color)
|
||||||
loop_write(ttyfd, ANSI_HIGHLIGHT,
|
(void) loop_write(ttyfd, ANSI_HIGHLIGHT, STRLEN(ANSI_HIGHLIGHT), false);
|
||||||
STRLEN(ANSI_HIGHLIGHT), false);
|
|
||||||
loop_write(ttyfd, message, strlen(message), false);
|
(void) loop_write(ttyfd, message, strlen(message), false);
|
||||||
loop_write(ttyfd, " ", 1, false);
|
(void) loop_write(ttyfd, " ", 1, false);
|
||||||
if (colors_enabled())
|
|
||||||
loop_write(ttyfd, ANSI_NORMAL, STRLEN(ANSI_NORMAL),
|
if (use_color)
|
||||||
false);
|
(void) loop_write(ttyfd, ANSI_NORMAL, STRLEN(ANSI_NORMAL), false);
|
||||||
|
|
||||||
new_termios = old_termios;
|
new_termios = old_termios;
|
||||||
new_termios.c_lflag &= ~(ICANON|ECHO);
|
new_termios.c_lflag &= ~(ICANON|ECHO);
|
||||||
|
@ -273,16 +297,19 @@ int ask_password_tty(
|
||||||
reset_tty = true;
|
reset_tty = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
zero(pollfd);
|
pollfd[POLL_TTY] = (struct pollfd) {
|
||||||
pollfd[POLL_TTY].fd = ttyfd >= 0 ? ttyfd : STDIN_FILENO;
|
.fd = ttyfd >= 0 ? ttyfd : STDIN_FILENO,
|
||||||
pollfd[POLL_TTY].events = POLLIN;
|
.events = POLLIN,
|
||||||
pollfd[POLL_INOTIFY].fd = notify;
|
};
|
||||||
pollfd[POLL_INOTIFY].events = POLLIN;
|
pollfd[POLL_INOTIFY] = (struct pollfd) {
|
||||||
|
.fd = notify,
|
||||||
|
.events = POLLIN,
|
||||||
|
};
|
||||||
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
char c;
|
|
||||||
int sleep_for = -1, k;
|
int sleep_for = -1, k;
|
||||||
ssize_t n;
|
ssize_t n;
|
||||||
|
char c;
|
||||||
|
|
||||||
if (until > 0) {
|
if (until > 0) {
|
||||||
usec_t y;
|
usec_t y;
|
||||||
|
@ -294,7 +321,7 @@ int ask_password_tty(
|
||||||
goto finish;
|
goto finish;
|
||||||
}
|
}
|
||||||
|
|
||||||
sleep_for = (int) ((until - y) / USEC_PER_MSEC);
|
sleep_for = (int) DIV_ROUND_UP(until - y, USEC_PER_MSEC);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (flag_file)
|
if (flag_file)
|
||||||
|
@ -329,72 +356,99 @@ int ask_password_tty(
|
||||||
r = -errno;
|
r = -errno;
|
||||||
goto finish;
|
goto finish;
|
||||||
|
|
||||||
} else if (n == 0)
|
}
|
||||||
|
|
||||||
|
/* We treat EOF, newline and NUL byte all as valid end markers */
|
||||||
|
if (n == 0 || c == '\n' || c == 0)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
if (c == '\n')
|
if (c == 21) { /* C-u */
|
||||||
break;
|
|
||||||
else if (c == 21) { /* C-u */
|
|
||||||
|
|
||||||
if (!(flags & ASK_PASSWORD_SILENT))
|
if (!(flags & ASK_PASSWORD_SILENT))
|
||||||
backspace_chars(ttyfd, p);
|
backspace_string(ttyfd, passphrase);
|
||||||
p = 0;
|
|
||||||
|
explicit_bzero(passphrase, sizeof(passphrase));
|
||||||
|
p = codepoint = 0;
|
||||||
|
|
||||||
} else if (IN_SET(c, '\b', 127)) {
|
} else if (IN_SET(c, '\b', 127)) {
|
||||||
|
|
||||||
if (p > 0) {
|
if (p > 0) {
|
||||||
|
size_t q;
|
||||||
|
|
||||||
if (!(flags & ASK_PASSWORD_SILENT))
|
if (!(flags & ASK_PASSWORD_SILENT))
|
||||||
backspace_chars(ttyfd, 1);
|
backspace_chars(ttyfd, 1);
|
||||||
|
|
||||||
p--;
|
/* Remove a full UTF-8 codepoint from the end. For that, figure out where the last one
|
||||||
|
* begins */
|
||||||
|
q = 0;
|
||||||
|
for (;;) {
|
||||||
|
size_t z;
|
||||||
|
|
||||||
|
z = utf8_encoded_valid_unichar(passphrase + q);
|
||||||
|
if (z == 0) {
|
||||||
|
q = (size_t) -1; /* Invalid UTF8! */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (q + z >= p) /* This one brings us over the edge */
|
||||||
|
break;
|
||||||
|
|
||||||
|
q += z;
|
||||||
|
}
|
||||||
|
|
||||||
|
p = codepoint = q == (size_t) -1 ? p - 1 : q;
|
||||||
|
explicit_bzero(passphrase + p, sizeof(passphrase) - p);
|
||||||
|
|
||||||
} else if (!dirty && !(flags & ASK_PASSWORD_SILENT)) {
|
} else if (!dirty && !(flags & ASK_PASSWORD_SILENT)) {
|
||||||
|
|
||||||
flags |= ASK_PASSWORD_SILENT;
|
flags |= ASK_PASSWORD_SILENT;
|
||||||
|
|
||||||
/* There are two ways to enter silent
|
/* There are two ways to enter silent mode. Either by pressing backspace as first key
|
||||||
* mode. Either by pressing backspace
|
* (and only as first key), or ... */
|
||||||
* as first key (and only as first
|
|
||||||
* key), or ... */
|
|
||||||
if (ttyfd >= 0)
|
if (ttyfd >= 0)
|
||||||
loop_write(ttyfd, "(no echo) ", 10, false);
|
(void) loop_write(ttyfd, "(no echo) ", 10, false);
|
||||||
|
|
||||||
} else if (ttyfd >= 0)
|
} else if (ttyfd >= 0)
|
||||||
loop_write(ttyfd, "\a", 1, false);
|
(void) loop_write(ttyfd, "\a", 1, false);
|
||||||
|
|
||||||
} else if (c == '\t' && !(flags & ASK_PASSWORD_SILENT)) {
|
} else if (c == '\t' && !(flags & ASK_PASSWORD_SILENT)) {
|
||||||
|
|
||||||
backspace_chars(ttyfd, p);
|
backspace_string(ttyfd, passphrase);
|
||||||
flags |= ASK_PASSWORD_SILENT;
|
flags |= ASK_PASSWORD_SILENT;
|
||||||
|
|
||||||
/* ... or by pressing TAB at any time. */
|
/* ... or by pressing TAB at any time. */
|
||||||
|
|
||||||
if (ttyfd >= 0)
|
if (ttyfd >= 0)
|
||||||
loop_write(ttyfd, "(no echo) ", 10, false);
|
(void) loop_write(ttyfd, "(no echo) ", 10, false);
|
||||||
} else {
|
|
||||||
if (p >= sizeof(passphrase)-1) {
|
|
||||||
loop_write(ttyfd, "\a", 1, false);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
} else if (p >= sizeof(passphrase)-1) {
|
||||||
|
|
||||||
|
/* Reached the size limit */
|
||||||
|
if (ttyfd >= 0)
|
||||||
|
(void) loop_write(ttyfd, "\a", 1, false);
|
||||||
|
|
||||||
|
} else {
|
||||||
passphrase[p++] = c;
|
passphrase[p++] = c;
|
||||||
|
|
||||||
if (!(flags & ASK_PASSWORD_SILENT) && ttyfd >= 0) {
|
if (!(flags & ASK_PASSWORD_SILENT) && ttyfd >= 0) {
|
||||||
|
/* Check if we got a complete UTF-8 character now. If so, let's output one '*'. */
|
||||||
n = utf8_encoded_valid_unichar(passphrase + codepoint);
|
n = utf8_encoded_valid_unichar(passphrase + codepoint);
|
||||||
if (n >= 0) {
|
if (n >= 0) {
|
||||||
codepoint = p;
|
codepoint = p;
|
||||||
loop_write(ttyfd, (flags & ASK_PASSWORD_ECHO) ? &c : "*", 1, false);
|
(void) loop_write(ttyfd, (flags & ASK_PASSWORD_ECHO) ? &c : "*", 1, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
dirty = true;
|
dirty = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Let's forget this char, just to not keep needlessly copies of key material around */
|
||||||
c = 'x';
|
c = 'x';
|
||||||
}
|
}
|
||||||
|
|
||||||
x = strndup(passphrase, p);
|
x = strndup(passphrase, p);
|
||||||
explicit_bzero(passphrase, p);
|
explicit_bzero(passphrase, sizeof(passphrase));
|
||||||
if (!x) {
|
if (!x) {
|
||||||
r = -ENOMEM;
|
r = -ENOMEM;
|
||||||
goto finish;
|
goto finish;
|
||||||
|
@ -408,8 +462,8 @@ int ask_password_tty(
|
||||||
|
|
||||||
finish:
|
finish:
|
||||||
if (ttyfd >= 0 && reset_tty) {
|
if (ttyfd >= 0 && reset_tty) {
|
||||||
loop_write(ttyfd, "\n", 1, false);
|
(void) loop_write(ttyfd, "\n", 1, false);
|
||||||
tcsetattr(ttyfd, TCSADRAIN, &old_termios);
|
(void) tcsetattr(ttyfd, TCSADRAIN, &old_termios);
|
||||||
}
|
}
|
||||||
|
|
||||||
return r;
|
return r;
|
||||||
|
@ -715,7 +769,7 @@ int ask_password_auto(
|
||||||
if (!(flags & ASK_PASSWORD_NO_TTY) && isatty(STDIN_FILENO)) {
|
if (!(flags & ASK_PASSWORD_NO_TTY) && isatty(STDIN_FILENO)) {
|
||||||
char *s = NULL, **l = NULL;
|
char *s = NULL, **l = NULL;
|
||||||
|
|
||||||
r = ask_password_tty(message, keyname, until, flags, NULL, &s);
|
r = ask_password_tty(-1, message, keyname, until, flags, NULL, &s);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
|
|
|
@ -25,15 +25,16 @@
|
||||||
#include "time-util.h"
|
#include "time-util.h"
|
||||||
|
|
||||||
typedef enum AskPasswordFlags {
|
typedef enum AskPasswordFlags {
|
||||||
ASK_PASSWORD_ACCEPT_CACHED = 1,
|
ASK_PASSWORD_ACCEPT_CACHED = 1U << 0,
|
||||||
ASK_PASSWORD_PUSH_CACHE = 2,
|
ASK_PASSWORD_PUSH_CACHE = 1U << 1,
|
||||||
ASK_PASSWORD_ECHO = 4, /* show the password literally while reading, instead of "*" */
|
ASK_PASSWORD_ECHO = 1U << 2, /* show the password literally while reading, instead of "*" */
|
||||||
ASK_PASSWORD_SILENT = 8, /* do no show any password at all while reading */
|
ASK_PASSWORD_SILENT = 1U << 3, /* do no show any password at all while reading */
|
||||||
ASK_PASSWORD_NO_TTY = 16,
|
ASK_PASSWORD_NO_TTY = 1U << 4,
|
||||||
ASK_PASSWORD_NO_AGENT = 32,
|
ASK_PASSWORD_NO_AGENT = 1U << 5,
|
||||||
|
ASK_PASSWORD_CONSOLE_COLOR = 1U << 6, /* Use color if /dev/console points to a console that supports color */
|
||||||
} AskPasswordFlags;
|
} AskPasswordFlags;
|
||||||
|
|
||||||
int ask_password_tty(const char *message, const char *keyname, usec_t until, AskPasswordFlags flags, const char *flag_file, char **ret);
|
int ask_password_tty(int tty_fd, const char *message, const char *keyname, usec_t until, AskPasswordFlags flags, const char *flag_file, char **ret);
|
||||||
int ask_password_agent(const char *message, const char *icon, const char *id, const char *keyname, usec_t until, AskPasswordFlags flag, char ***ret);
|
int ask_password_agent(const char *message, const char *icon, const char *id, const char *keyname, usec_t until, AskPasswordFlags flag, char ***ret);
|
||||||
int ask_password_keyring(const char *keyname, AskPasswordFlags flags, char ***ret);
|
int ask_password_keyring(const char *keyname, AskPasswordFlags flags, char ***ret);
|
||||||
int ask_password_auto(const char *message, const char *icon, const char *id, const char *keyname, usec_t until, AskPasswordFlags flag, char ***ret);
|
int ask_password_auto(const char *message, const char *icon, const char *id, const char *keyname, usec_t until, AskPasswordFlags flag, char ***ret);
|
||||||
|
|
|
@ -26,7 +26,7 @@ static void ask_password(void) {
|
||||||
int r;
|
int r;
|
||||||
_cleanup_free_ char *ret;
|
_cleanup_free_ char *ret;
|
||||||
|
|
||||||
r = ask_password_tty("hello?", "da key", 0, 0, NULL, &ret);
|
r = ask_password_tty(-1, "hello?", "da key", 0, 0, NULL, &ret);
|
||||||
assert(r >= 0);
|
assert(r >= 0);
|
||||||
|
|
||||||
log_info("Got %s", ret);
|
log_info("Got %s", ret);
|
||||||
|
|
|
@ -254,6 +254,7 @@ static int send_passwords(const char *socket_name, char **passwords) {
|
||||||
union sockaddr_union sa = { .un.sun_family = AF_UNIX };
|
union sockaddr_union sa = { .un.sun_family = AF_UNIX };
|
||||||
size_t packet_length = 1;
|
size_t packet_length = 1;
|
||||||
char **p, *d;
|
char **p, *d;
|
||||||
|
ssize_t n;
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
assert(socket_name);
|
assert(socket_name);
|
||||||
|
@ -279,9 +280,13 @@ static int send_passwords(const char *socket_name, char **passwords) {
|
||||||
|
|
||||||
strncpy(sa.un.sun_path, socket_name, sizeof(sa.un.sun_path));
|
strncpy(sa.un.sun_path, socket_name, sizeof(sa.un.sun_path));
|
||||||
|
|
||||||
r = sendto(socket_fd, packet, packet_length, MSG_NOSIGNAL, &sa.sa, SOCKADDR_UN_LEN(sa.un));
|
n = sendto(socket_fd, packet, packet_length, MSG_NOSIGNAL, &sa.sa, SOCKADDR_UN_LEN(sa.un));
|
||||||
if (r < 0)
|
if (n < 0) {
|
||||||
r = log_debug_errno(errno, "sendto(): %m");
|
r = log_debug_errno(errno, "sendto(): %m");
|
||||||
|
goto finish;
|
||||||
|
}
|
||||||
|
|
||||||
|
r = (int) n;
|
||||||
|
|
||||||
finish:
|
finish:
|
||||||
explicit_bzero(packet, packet_length);
|
explicit_bzero(packet, packet_length);
|
||||||
|
@ -363,18 +368,21 @@ static int parse_password(const char *filename, char **wall) {
|
||||||
int tty_fd = -1;
|
int tty_fd = -1;
|
||||||
|
|
||||||
if (arg_console) {
|
if (arg_console) {
|
||||||
const char *con = arg_device ? arg_device : "/dev/console";
|
const char *con = arg_device ?: "/dev/console";
|
||||||
|
|
||||||
tty_fd = acquire_terminal(con, false, false, false, USEC_INFINITY);
|
tty_fd = acquire_terminal(con, ACQUIRE_TERMINAL_WAIT, USEC_INFINITY);
|
||||||
if (tty_fd < 0)
|
if (tty_fd < 0)
|
||||||
return log_error_errno(tty_fd, "Failed to acquire /dev/console: %m");
|
return log_error_errno(tty_fd, "Failed to acquire %s: %m", con);
|
||||||
|
|
||||||
r = reset_terminal_fd(tty_fd, true);
|
r = reset_terminal_fd(tty_fd, true);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
log_warning_errno(r, "Failed to reset terminal, ignoring: %m");
|
log_warning_errno(r, "Failed to reset terminal, ignoring: %m");
|
||||||
}
|
}
|
||||||
|
|
||||||
r = ask_password_tty(message, NULL, not_after, echo ? ASK_PASSWORD_ECHO : 0, filename, &password);
|
r = ask_password_tty(tty_fd, message, NULL, not_after,
|
||||||
|
(echo ? ASK_PASSWORD_ECHO : 0) |
|
||||||
|
(arg_console ? ASK_PASSWORD_CONSOLE_COLOR : 0),
|
||||||
|
filename, &password);
|
||||||
|
|
||||||
if (arg_console) {
|
if (arg_console) {
|
||||||
tty_fd = safe_close(tty_fd);
|
tty_fd = safe_close(tty_fd);
|
||||||
|
|
Loading…
Reference in a new issue