along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <assert.h>
+#include <errno.h>
#include <fcntl.h>
+#include <limits.h>
+#include <stdarg.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/inotify.h>
+#include <sys/socket.h>
+#include <sys/sysmacros.h>
+#include <sys/time.h>
#include <linux/kd.h>
#include <linux/tiocl.h>
#include <linux/vt.h>
#include <poll.h>
#include <signal.h>
#include <sys/ioctl.h>
-#include <sys/stat.h>
#include <sys/types.h>
#include <termios.h>
-#include <time.h>
#include <unistd.h>
#include "alloc-util.h"
#include "fileio.h"
#include "fs-util.h"
#include "io-util.h"
+#include "log.h"
+#include "macro.h"
#include "parse-util.h"
-#include "path-util.h"
#include "process-util.h"
#include "socket-util.h"
#include "stat-util.h"
#include "string-util.h"
+#include "strv.h"
#include "terminal-util.h"
#include "time-util.h"
#include "util.h"
errno = 0;
if (!fgets(line, sizeof(line), f))
- return errno ? -errno : -EIO;
+ return errno > 0 ? -errno : -EIO;
truncate_nl(line);
return 0;
}
-int ask_char(char *ret, const char *replies, const char *text, ...) {
+#define DEFAULT_ASK_REFRESH_USEC (2*USEC_PER_SEC)
+
+int ask_char(char *ret, const char *replies, const char *fmt, ...) {
int r;
assert(ret);
assert(replies);
- assert(text);
+ assert(fmt);
for (;;) {
va_list ap;
char c;
bool need_nl = true;
- if (on_tty())
+ if (colors_enabled())
fputs(ANSI_HIGHLIGHT, stdout);
- va_start(ap, text);
- vprintf(text, ap);
+ putchar('\r');
+
+ va_start(ap, fmt);
+ vprintf(fmt, ap);
va_end(ap);
- if (on_tty())
+ if (colors_enabled())
fputs(ANSI_NORMAL, stdout);
fflush(stdout);
- r = read_one_char(stdin, &c, USEC_INFINITY, &need_nl);
+ r = read_one_char(stdin, &c, DEFAULT_ASK_REFRESH_USEC, &need_nl);
if (r < 0) {
+ if (r == -ETIMEDOUT)
+ continue;
+
if (r == -EBADMSG) {
puts("Bad input, please try again.");
continue;
char line[LINE_MAX];
va_list ap;
- if (on_tty())
+ if (colors_enabled())
fputs(ANSI_HIGHLIGHT, stdout);
va_start(ap, text);
vprintf(text, ap);
va_end(ap);
- if (on_tty())
+ if (colors_enabled())
fputs(ANSI_NORMAL, stdout);
fflush(stdout);
errno = 0;
if (!fgets(line, sizeof(line), stdin))
- return errno ? -errno : -EIO;
+ return errno > 0 ? -errno : -EIO;
if (!endswith(line, "\n"))
putchar('\n');
}
r = isatty(fd);
- if (r < 0) {
- safe_close(fd);
- return -errno;
- }
-
- if (!r) {
+ if (r == 0) {
safe_close(fd);
return -ENOTTY;
}
goto fail;
}
- r = fd_wait_for_event(fd, POLLIN, ts + timeout - n);
+ r = fd_wait_for_event(notify, POLLIN, ts + timeout - n);
if (r < 0)
goto fail;
return tty;
}
+int get_kernel_consoles(char ***consoles) {
+ _cleanup_strv_free_ char **con = NULL;
+ _cleanup_free_ char *line = NULL;
+ const char *active;
+ int r;
+
+ assert(consoles);
+
+ r = read_one_line_file("/sys/class/tty/console/active", &line);
+ if (r < 0)
+ return r;
+
+ active = line;
+ for (;;) {
+ _cleanup_free_ char *tty = NULL;
+ char *path;
+
+ r = extract_first_word(&active, &tty, NULL, 0);
+ if (r < 0)
+ return r;
+ if (r == 0)
+ break;
+
+ if (streq(tty, "tty0")) {
+ tty = mfree(tty);
+ r = read_one_line_file("/sys/class/tty/tty0/active", &tty);
+ if (r < 0)
+ return r;
+ }
+
+ path = strappend("/dev/", tty);
+ if (!path)
+ return -ENOMEM;
+
+ if (access(path, F_OK) < 0) {
+ log_debug_errno(errno, "Console device %s is not accessible, skipping: %m", path);
+ free(path);
+ continue;
+ }
+
+ r = strv_consume(&con, path);
+ if (r < 0)
+ return r;
+ }
+
+ if (strv_isempty(con)) {
+ log_debug("No devices found for system console");
+
+ r = strv_extend(&con, "/dev/console");
+ if (r < 0)
+ return r;
+ }
+
+ *consoles = con;
+ con = NULL;
+ return 0;
+}
+
bool tty_is_vc_resolve(const char *tty) {
_cleanup_free_ char *active = NULL;
}
const char *default_term_for_tty(const char *tty) {
- assert(tty);
-
- return tty_is_vc_resolve(tty) ? "TERM=linux" : "TERM=vt220";
+ return tty && tty_is_vc_resolve(tty) ? "linux" : "vt220";
}
#endif // 0
/* Explicitly unset O_CLOEXEC, since if fd was < 3, then
* dup2() was a NOP and the bit hence possibly set. */
- fd_cloexec(STDIN_FILENO, false);
- fd_cloexec(STDOUT_FILENO, false);
- fd_cloexec(STDERR_FILENO, false);
+ stdio_unset_cloexec();
return 0;
}
return make_stdio(null_fd);
}
-#if 0 /// UNNEEDED by elogind
int getttyname_malloc(int fd, char **ret) {
size_t l = 100;
int r;
*r = s;
return 0;
}
-#endif // 0
int get_ctty_devnr(pid_t pid, dev_t *d) {
int r;
return receive_one_fd(pair[0], 0);
}
#endif // 0
+
+static bool getenv_terminal_is_dumb(void) {
+ const char *e;
+
+ e = getenv("TERM");
+ if (!e)
+ return true;
+
+ return streq(e, "dumb");
+}
+
+bool terminal_is_dumb(void) {
+ if (!on_tty())
+ return true;
+
+ return getenv_terminal_is_dumb();
+}
+
+bool colors_enabled(void) {
+ static int enabled = -1;
+
+ if (_unlikely_(enabled < 0)) {
+#if 0 /// elogind does not allow such forcing, and we are never init!
+ int val;
+
+ val = getenv_bool("SYSTEMD_COLORS");
+ if (val >= 0)
+ enabled = val;
+ else if (getpid() == 1)
+ /* PID1 outputs to the console without holding it open all the time */
+ enabled = !getenv_terminal_is_dumb();
+ else
+#endif // 0
+ enabled = !terminal_is_dumb();
+ }
+
+ return enabled;
+}