terminal-util.c revision 1ba239315ff449779189bde77361f323851dc39f
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering/***
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering This file is part of systemd.
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering Copyright 2010 Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering systemd is free software; you can redistribute it and/or modify it
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering under the terms of the GNU Lesser General Public License as published by
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering the Free Software Foundation; either version 2.1 of the License, or
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering (at your option) any later version.
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering systemd is distributed in the hope that it will be useful, but
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering WITHOUT ANY WARRANTY; without even the implied warranty of
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering Lesser General Public License for more details.
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering You should have received a copy of the GNU Lesser General Public License
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering along with systemd; If not, see <http://www.gnu.org/licenses/>.
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering***/
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering#include <sys/ioctl.h>
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering#include <sys/types.h>
8bdbb8d9cbe1d35708385573d70984ab4533812dLennart Poettering#include <sys/stat.h>
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering#include <termios.h>
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering#include <unistd.h>
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering#include <fcntl.h>
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering#include <signal.h>
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering#include <time.h>
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering#include <assert.h>
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering#include <poll.h>
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering#include <linux/vt.h>
f48e75cb9a8112d35855c44a156934f2ee0edb2eLennart Poettering#include <linux/tiocl.h>
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering#include <linux/kd.h>
eef46c372f64f40dd75415b2c504c73138719c8dLennart Poettering
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen#include "terminal-util.h"
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering#include "time-util.h"
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering#include "process-util.h"
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering#include "util.h"
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering#include "fileio.h"
acf97e213e69a97e63ab8f7fad7ecd53608c757aLennart Poettering#include "path-util.h"
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersenstatic volatile unsigned cached_columns = 0;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poetteringstatic volatile unsigned cached_lines = 0;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poetteringint chvt(int vt) {
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering _cleanup_close_ int fd;
8b0cc9a36c8f92f010f2e8465942d2cd7c580d78Lennart Poettering
9d12709626bccc0cae677a7035f62efe6aabb4abLennart Poettering fd = open_terminal("/dev/tty0", O_RDWR|O_NOCTTY|O_CLOEXEC|O_NONBLOCK);
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering if (fd < 0)
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering return -errno;
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering if (vt <= 0) {
f2cbe59e113f08549949a76ac5b9b3972df4cc30Lennart Poettering int tiocl[2] = {
56159e0d918e9a9be07988133bb2847779325de0Lennart Poettering TIOCL_GETKMSGREDIRECT,
3d7415f43f0fe6a821d7bc4a341ba371e8a30ef3Lennart Poettering 0
0b452006de98294d1690f045f6ea2f7f6630ec3bRonny Chevalier };
288a74cce597f81d3ba01d8a5ca7d2ba5b654b7eRonny Chevalier
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering if (ioctl(fd, TIOCLINUX, tiocl) < 0)
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering return -errno;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering vt = tiocl[0] <= 0 ? 1 : tiocl[0];
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering }
e56056e93d33619a3acf13e483900b4f8938228fThomas Hindoe Paaboel Andersen
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering if (ioctl(fd, VT_ACTIVATE, vt) < 0)
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering return -errno;
d21ed1ead18d16d35c30299a69d3366847f8a039Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering return 0;
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering}
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering
d8f52ed25a9edce75fda5251c977b7898e33887eLennart Poetteringint read_one_char(FILE *f, char *ret, usec_t t, bool *need_nl) {
acf97e213e69a97e63ab8f7fad7ecd53608c757aLennart Poettering struct termios old_termios, new_termios;
8b0cc9a36c8f92f010f2e8465942d2cd7c580d78Lennart Poettering char c, line[LINE_MAX];
8b0cc9a36c8f92f010f2e8465942d2cd7c580d78Lennart Poettering
3d7415f43f0fe6a821d7bc4a341ba371e8a30ef3Lennart Poettering assert(f);
6e18cc9fa078d2a967251017ddb5baefb104b720Lennart Poettering assert(ret);
3d7415f43f0fe6a821d7bc4a341ba371e8a30ef3Lennart Poettering
587fec427c80b6c34dcf1d7570f891fcb652a7c5Lennart Poettering if (tcgetattr(fileno(f), &old_termios) >= 0) {
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering new_termios = old_termios;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering new_termios.c_lflag &= ~ICANON;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering new_termios.c_cc[VMIN] = 1;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering new_termios.c_cc[VTIME] = 0;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering if (tcsetattr(fileno(f), TCSADRAIN, &new_termios) >= 0) {
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering size_t k;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
acf97e213e69a97e63ab8f7fad7ecd53608c757aLennart Poettering if (t != USEC_INFINITY) {
acf97e213e69a97e63ab8f7fad7ecd53608c757aLennart Poettering if (fd_wait_for_event(fileno(f), POLLIN, t) <= 0) {
acf97e213e69a97e63ab8f7fad7ecd53608c757aLennart Poettering tcsetattr(fileno(f), TCSADRAIN, &old_termios);
acf97e213e69a97e63ab8f7fad7ecd53608c757aLennart Poettering return -ETIMEDOUT;
acf97e213e69a97e63ab8f7fad7ecd53608c757aLennart Poettering }
acf97e213e69a97e63ab8f7fad7ecd53608c757aLennart Poettering }
acf97e213e69a97e63ab8f7fad7ecd53608c757aLennart Poettering
acf97e213e69a97e63ab8f7fad7ecd53608c757aLennart Poettering k = fread(&c, 1, 1, f);
acf97e213e69a97e63ab8f7fad7ecd53608c757aLennart Poettering
acf97e213e69a97e63ab8f7fad7ecd53608c757aLennart Poettering tcsetattr(fileno(f), TCSADRAIN, &old_termios);
acf97e213e69a97e63ab8f7fad7ecd53608c757aLennart Poettering
acf97e213e69a97e63ab8f7fad7ecd53608c757aLennart Poettering if (k <= 0)
acf97e213e69a97e63ab8f7fad7ecd53608c757aLennart Poettering return -EIO;
8b0cc9a36c8f92f010f2e8465942d2cd7c580d78Lennart Poettering
8b0cc9a36c8f92f010f2e8465942d2cd7c580d78Lennart Poettering if (need_nl)
8b0cc9a36c8f92f010f2e8465942d2cd7c580d78Lennart Poettering *need_nl = c != '\n';
8b0cc9a36c8f92f010f2e8465942d2cd7c580d78Lennart Poettering
8b0cc9a36c8f92f010f2e8465942d2cd7c580d78Lennart Poettering *ret = c;
8b0cc9a36c8f92f010f2e8465942d2cd7c580d78Lennart Poettering return 0;
8b0cc9a36c8f92f010f2e8465942d2cd7c580d78Lennart Poettering }
8b0cc9a36c8f92f010f2e8465942d2cd7c580d78Lennart Poettering }
8b0cc9a36c8f92f010f2e8465942d2cd7c580d78Lennart Poettering
0b63e2789f984e84f40bf6e49f5da15c87298cedLennart Poettering if (t != USEC_INFINITY) {
0b63e2789f984e84f40bf6e49f5da15c87298cedLennart Poettering if (fd_wait_for_event(fileno(f), POLLIN, t) <= 0)
0b63e2789f984e84f40bf6e49f5da15c87298cedLennart Poettering return -ETIMEDOUT;
0b63e2789f984e84f40bf6e49f5da15c87298cedLennart Poettering }
0b63e2789f984e84f40bf6e49f5da15c87298cedLennart Poettering
0b63e2789f984e84f40bf6e49f5da15c87298cedLennart Poettering errno = 0;
0b63e2789f984e84f40bf6e49f5da15c87298cedLennart Poettering if (!fgets(line, sizeof(line), f))
0b63e2789f984e84f40bf6e49f5da15c87298cedLennart Poettering return errno ? -errno : -EIO;
0b63e2789f984e84f40bf6e49f5da15c87298cedLennart Poettering
0b63e2789f984e84f40bf6e49f5da15c87298cedLennart Poettering truncate_nl(line);
0b63e2789f984e84f40bf6e49f5da15c87298cedLennart Poettering
0b63e2789f984e84f40bf6e49f5da15c87298cedLennart Poettering if (strlen(line) != 1)
56159e0d918e9a9be07988133bb2847779325de0Lennart Poettering return -EBADMSG;
56159e0d918e9a9be07988133bb2847779325de0Lennart Poettering
0b63e2789f984e84f40bf6e49f5da15c87298cedLennart Poettering if (need_nl)
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen *need_nl = false;
0b63e2789f984e84f40bf6e49f5da15c87298cedLennart Poettering
0b63e2789f984e84f40bf6e49f5da15c87298cedLennart Poettering *ret = line[0];
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen return 0;
0b63e2789f984e84f40bf6e49f5da15c87298cedLennart Poettering}
56159e0d918e9a9be07988133bb2847779325de0Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poetteringint ask_char(char *ret, const char *replies, const char *text, ...) {
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering int r;
56159e0d918e9a9be07988133bb2847779325de0Lennart Poettering
56159e0d918e9a9be07988133bb2847779325de0Lennart Poettering assert(ret);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering assert(replies);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering assert(text);
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen for (;;) {
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen va_list ap;
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen char c;
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen bool need_nl = true;
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen if (on_tty())
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen fputs(ANSI_HIGHLIGHT, stdout);
3d7415f43f0fe6a821d7bc4a341ba371e8a30ef3Lennart Poettering
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen va_start(ap, text);
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen vprintf(text, ap);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering va_end(ap);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering if (on_tty())
3d7415f43f0fe6a821d7bc4a341ba371e8a30ef3Lennart Poettering fputs(ANSI_NORMAL, stdout);
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen
5b30bef856e89a571df57b7b953e9a1409d9acedLennart Poettering fflush(stdout);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen r = read_one_char(stdin, &c, USEC_INFINITY, &need_nl);
0b63e2789f984e84f40bf6e49f5da15c87298cedLennart Poettering if (r < 0) {
0b63e2789f984e84f40bf6e49f5da15c87298cedLennart Poettering
0b63e2789f984e84f40bf6e49f5da15c87298cedLennart Poettering if (r == -EBADMSG) {
0b63e2789f984e84f40bf6e49f5da15c87298cedLennart Poettering puts("Bad input, please try again.");
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering continue;
0b63e2789f984e84f40bf6e49f5da15c87298cedLennart Poettering }
0b63e2789f984e84f40bf6e49f5da15c87298cedLennart Poettering
0b63e2789f984e84f40bf6e49f5da15c87298cedLennart Poettering putchar('\n');
0b63e2789f984e84f40bf6e49f5da15c87298cedLennart Poettering return r;
0b63e2789f984e84f40bf6e49f5da15c87298cedLennart Poettering }
0b63e2789f984e84f40bf6e49f5da15c87298cedLennart Poettering
0b63e2789f984e84f40bf6e49f5da15c87298cedLennart Poettering if (need_nl)
0b63e2789f984e84f40bf6e49f5da15c87298cedLennart Poettering putchar('\n');
0b63e2789f984e84f40bf6e49f5da15c87298cedLennart Poettering
0b63e2789f984e84f40bf6e49f5da15c87298cedLennart Poettering if (strchr(replies, c)) {
0b63e2789f984e84f40bf6e49f5da15c87298cedLennart Poettering *ret = c;
0b63e2789f984e84f40bf6e49f5da15c87298cedLennart Poettering return 0;
0b63e2789f984e84f40bf6e49f5da15c87298cedLennart Poettering }
0b63e2789f984e84f40bf6e49f5da15c87298cedLennart Poettering
0b63e2789f984e84f40bf6e49f5da15c87298cedLennart Poettering puts("Read unexpected character, please try again.");
0b63e2789f984e84f40bf6e49f5da15c87298cedLennart Poettering }
0b63e2789f984e84f40bf6e49f5da15c87298cedLennart Poettering}
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersenint ask_string(char **ret, const char *text, ...) {
5b30bef856e89a571df57b7b953e9a1409d9acedLennart Poettering assert(ret);
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen assert(text);
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen for (;;) {
5b30bef856e89a571df57b7b953e9a1409d9acedLennart Poettering char line[LINE_MAX];
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering va_list ap;
0b63e2789f984e84f40bf6e49f5da15c87298cedLennart Poettering
0b63e2789f984e84f40bf6e49f5da15c87298cedLennart Poettering if (on_tty())
0b63e2789f984e84f40bf6e49f5da15c87298cedLennart Poettering fputs(ANSI_HIGHLIGHT, stdout);
0b63e2789f984e84f40bf6e49f5da15c87298cedLennart Poettering
0b63e2789f984e84f40bf6e49f5da15c87298cedLennart Poettering va_start(ap, text);
0b63e2789f984e84f40bf6e49f5da15c87298cedLennart Poettering vprintf(text, ap);
0b63e2789f984e84f40bf6e49f5da15c87298cedLennart Poettering va_end(ap);
0b63e2789f984e84f40bf6e49f5da15c87298cedLennart Poettering
0b63e2789f984e84f40bf6e49f5da15c87298cedLennart Poettering if (on_tty())
0b63e2789f984e84f40bf6e49f5da15c87298cedLennart Poettering fputs(ANSI_NORMAL, stdout);
0b63e2789f984e84f40bf6e49f5da15c87298cedLennart Poettering
0b63e2789f984e84f40bf6e49f5da15c87298cedLennart Poettering fflush(stdout);
0b63e2789f984e84f40bf6e49f5da15c87298cedLennart Poettering
0b63e2789f984e84f40bf6e49f5da15c87298cedLennart Poettering errno = 0;
e56056e93d33619a3acf13e483900b4f8938228fThomas Hindoe Paaboel Andersen if (!fgets(line, sizeof(line), stdin))
0b63e2789f984e84f40bf6e49f5da15c87298cedLennart Poettering return errno ? -errno : -EIO;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering if (!endswith(line, "\n"))
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering putchar('\n');
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering else {
cd61c3bfd718fb398cc53ced906266a9297782c9Lennart Poettering char *s;
cd61c3bfd718fb398cc53ced906266a9297782c9Lennart Poettering
cd61c3bfd718fb398cc53ced906266a9297782c9Lennart Poettering if (isempty(line))
cd61c3bfd718fb398cc53ced906266a9297782c9Lennart Poettering continue;
10f9c75519671e7c7ab8993b54fe22da7c2d0c38Lennart Poettering
10f9c75519671e7c7ab8993b54fe22da7c2d0c38Lennart Poettering truncate_nl(line);
b6b1849830f5e4a6065c3b0c993668e500c954d3Lennart Poettering s = strdup(line);
cd61c3bfd718fb398cc53ced906266a9297782c9Lennart Poettering if (!s)
cd61c3bfd718fb398cc53ced906266a9297782c9Lennart Poettering return -ENOMEM;
cd61c3bfd718fb398cc53ced906266a9297782c9Lennart Poettering
cd61c3bfd718fb398cc53ced906266a9297782c9Lennart Poettering *ret = s;
cd61c3bfd718fb398cc53ced906266a9297782c9Lennart Poettering return 0;
cd61c3bfd718fb398cc53ced906266a9297782c9Lennart Poettering }
cd61c3bfd718fb398cc53ced906266a9297782c9Lennart Poettering }
cd61c3bfd718fb398cc53ced906266a9297782c9Lennart Poettering}
56159e0d918e9a9be07988133bb2847779325de0Lennart Poettering
cd61c3bfd718fb398cc53ced906266a9297782c9Lennart Poetteringint reset_terminal_fd(int fd, bool switch_to_text) {
cd61c3bfd718fb398cc53ced906266a9297782c9Lennart Poettering struct termios termios;
c19de71113f956809995fc68817e055e9f61f607Lennart Poettering int r = 0;
cd61c3bfd718fb398cc53ced906266a9297782c9Lennart Poettering
cd61c3bfd718fb398cc53ced906266a9297782c9Lennart Poettering /* Set terminal to some sane defaults */
cd61c3bfd718fb398cc53ced906266a9297782c9Lennart Poettering
cd61c3bfd718fb398cc53ced906266a9297782c9Lennart Poettering assert(fd >= 0);
56159e0d918e9a9be07988133bb2847779325de0Lennart Poettering
b6b1849830f5e4a6065c3b0c993668e500c954d3Lennart Poettering /* We leave locked terminal attributes untouched, so that
10f9c75519671e7c7ab8993b54fe22da7c2d0c38Lennart Poettering * Plymouth may set whatever it wants to set, and we don't
cd61c3bfd718fb398cc53ced906266a9297782c9Lennart Poettering * interfere with that. */
56159e0d918e9a9be07988133bb2847779325de0Lennart Poettering
56159e0d918e9a9be07988133bb2847779325de0Lennart Poettering /* Disable exclusive mode, just in case */
cd61c3bfd718fb398cc53ced906266a9297782c9Lennart Poettering (void) ioctl(fd, TIOCNXCL);
cd61c3bfd718fb398cc53ced906266a9297782c9Lennart Poettering
cd61c3bfd718fb398cc53ced906266a9297782c9Lennart Poettering /* Switch to text mode */
cd61c3bfd718fb398cc53ced906266a9297782c9Lennart Poettering if (switch_to_text)
cd61c3bfd718fb398cc53ced906266a9297782c9Lennart Poettering (void) ioctl(fd, KDSETMODE, KD_TEXT);
cd61c3bfd718fb398cc53ced906266a9297782c9Lennart Poettering
cd61c3bfd718fb398cc53ced906266a9297782c9Lennart Poettering /* Enable console unicode mode */
cd61c3bfd718fb398cc53ced906266a9297782c9Lennart Poettering (void) ioctl(fd, KDSKBMODE, K_UNICODE);
cd61c3bfd718fb398cc53ced906266a9297782c9Lennart Poettering
cd61c3bfd718fb398cc53ced906266a9297782c9Lennart Poettering if (tcgetattr(fd, &termios) < 0) {
cd61c3bfd718fb398cc53ced906266a9297782c9Lennart Poettering r = -errno;
cd61c3bfd718fb398cc53ced906266a9297782c9Lennart Poettering goto finish;
cd61c3bfd718fb398cc53ced906266a9297782c9Lennart Poettering }
cd61c3bfd718fb398cc53ced906266a9297782c9Lennart Poettering
cd61c3bfd718fb398cc53ced906266a9297782c9Lennart Poettering /* We only reset the stuff that matters to the software. How
cd61c3bfd718fb398cc53ced906266a9297782c9Lennart Poettering * hardware is set up we don't touch assuming that somebody
b6b1849830f5e4a6065c3b0c993668e500c954d3Lennart Poettering * else will do that for us */
cd61c3bfd718fb398cc53ced906266a9297782c9Lennart Poettering
cd61c3bfd718fb398cc53ced906266a9297782c9Lennart Poettering termios.c_iflag &= ~(IGNBRK | BRKINT | ISTRIP | INLCR | IGNCR | IUCLC);
cd61c3bfd718fb398cc53ced906266a9297782c9Lennart Poettering termios.c_iflag |= ICRNL | IMAXBEL | IUTF8;
b6b1849830f5e4a6065c3b0c993668e500c954d3Lennart Poettering termios.c_oflag |= ONLCR;
b6b1849830f5e4a6065c3b0c993668e500c954d3Lennart Poettering termios.c_cflag |= CREAD;
10f9c75519671e7c7ab8993b54fe22da7c2d0c38Lennart Poettering termios.c_lflag = ISIG | ICANON | IEXTEN | ECHO | ECHOE | ECHOK | ECHOCTL | ECHOPRT | ECHOKE;
cd61c3bfd718fb398cc53ced906266a9297782c9Lennart Poettering
cd61c3bfd718fb398cc53ced906266a9297782c9Lennart Poettering termios.c_cc[VINTR] = 03; /* ^C */
cd61c3bfd718fb398cc53ced906266a9297782c9Lennart Poettering termios.c_cc[VQUIT] = 034; /* ^\ */
cd61c3bfd718fb398cc53ced906266a9297782c9Lennart Poettering termios.c_cc[VERASE] = 0177;
cd61c3bfd718fb398cc53ced906266a9297782c9Lennart Poettering termios.c_cc[VKILL] = 025; /* ^X */
cd61c3bfd718fb398cc53ced906266a9297782c9Lennart Poettering termios.c_cc[VEOF] = 04; /* ^D */
cd61c3bfd718fb398cc53ced906266a9297782c9Lennart Poettering termios.c_cc[VSTART] = 021; /* ^Q */
cd61c3bfd718fb398cc53ced906266a9297782c9Lennart Poettering termios.c_cc[VSTOP] = 023; /* ^S */
cd61c3bfd718fb398cc53ced906266a9297782c9Lennart Poettering termios.c_cc[VSUSP] = 032; /* ^Z */
cd61c3bfd718fb398cc53ced906266a9297782c9Lennart Poettering termios.c_cc[VLNEXT] = 026; /* ^V */
10f9c75519671e7c7ab8993b54fe22da7c2d0c38Lennart Poettering termios.c_cc[VWERASE] = 027; /* ^W */
10f9c75519671e7c7ab8993b54fe22da7c2d0c38Lennart Poettering termios.c_cc[VREPRINT] = 022; /* ^R */
b6b1849830f5e4a6065c3b0c993668e500c954d3Lennart Poettering termios.c_cc[VEOL] = 0;
10f9c75519671e7c7ab8993b54fe22da7c2d0c38Lennart Poettering termios.c_cc[VEOL2] = 0;
10f9c75519671e7c7ab8993b54fe22da7c2d0c38Lennart Poettering
10f9c75519671e7c7ab8993b54fe22da7c2d0c38Lennart Poettering termios.c_cc[VTIME] = 0;
10f9c75519671e7c7ab8993b54fe22da7c2d0c38Lennart Poettering termios.c_cc[VMIN] = 1;
cd61c3bfd718fb398cc53ced906266a9297782c9Lennart Poettering
10f9c75519671e7c7ab8993b54fe22da7c2d0c38Lennart Poettering if (tcsetattr(fd, TCSANOW, &termios) < 0)
10f9c75519671e7c7ab8993b54fe22da7c2d0c38Lennart Poettering r = -errno;
10f9c75519671e7c7ab8993b54fe22da7c2d0c38Lennart Poettering
cd61c3bfd718fb398cc53ced906266a9297782c9Lennart Poetteringfinish:
10f9c75519671e7c7ab8993b54fe22da7c2d0c38Lennart Poettering /* Just in case, flush all crap out */
b6b1849830f5e4a6065c3b0c993668e500c954d3Lennart Poettering (void) tcflush(fd, TCIOFLUSH);
10f9c75519671e7c7ab8993b54fe22da7c2d0c38Lennart Poettering
10f9c75519671e7c7ab8993b54fe22da7c2d0c38Lennart Poettering return r;
10f9c75519671e7c7ab8993b54fe22da7c2d0c38Lennart Poettering}
10f9c75519671e7c7ab8993b54fe22da7c2d0c38Lennart Poettering
10f9c75519671e7c7ab8993b54fe22da7c2d0c38Lennart Poetteringint reset_terminal(const char *name) {
b6b1849830f5e4a6065c3b0c993668e500c954d3Lennart Poettering _cleanup_close_ int fd = -1;
10f9c75519671e7c7ab8993b54fe22da7c2d0c38Lennart Poettering
10f9c75519671e7c7ab8993b54fe22da7c2d0c38Lennart Poettering /* We open the terminal with O_NONBLOCK here, to ensure we
10f9c75519671e7c7ab8993b54fe22da7c2d0c38Lennart Poettering * don't block on carrier if this is a terminal with carrier
cd61c3bfd718fb398cc53ced906266a9297782c9Lennart Poettering * configured. */
b6b1849830f5e4a6065c3b0c993668e500c954d3Lennart Poettering
b6b1849830f5e4a6065c3b0c993668e500c954d3Lennart Poettering fd = open_terminal(name, O_RDWR|O_NOCTTY|O_CLOEXEC|O_NONBLOCK);
b6b1849830f5e4a6065c3b0c993668e500c954d3Lennart Poettering if (fd < 0)
b6b1849830f5e4a6065c3b0c993668e500c954d3Lennart Poettering return fd;
b6b1849830f5e4a6065c3b0c993668e500c954d3Lennart Poettering
b6b1849830f5e4a6065c3b0c993668e500c954d3Lennart Poettering return reset_terminal_fd(fd, true);
cd61c3bfd718fb398cc53ced906266a9297782c9Lennart Poettering}
cd61c3bfd718fb398cc53ced906266a9297782c9Lennart Poettering
cd61c3bfd718fb398cc53ced906266a9297782c9Lennart Poetteringint open_terminal(const char *name, int mode) {
cd61c3bfd718fb398cc53ced906266a9297782c9Lennart Poettering int fd, r;
cd61c3bfd718fb398cc53ced906266a9297782c9Lennart Poettering unsigned c = 0;
cd61c3bfd718fb398cc53ced906266a9297782c9Lennart Poettering
cd61c3bfd718fb398cc53ced906266a9297782c9Lennart Poettering /*
cd61c3bfd718fb398cc53ced906266a9297782c9Lennart Poettering * If a TTY is in the process of being closed opening it might
cd61c3bfd718fb398cc53ced906266a9297782c9Lennart Poettering * cause EIO. This is horribly awful, but unlikely to be
cd61c3bfd718fb398cc53ced906266a9297782c9Lennart Poettering * changed in the kernel. Hence we work around this problem by
cd61c3bfd718fb398cc53ced906266a9297782c9Lennart Poettering * retrying a couple of times.
cd61c3bfd718fb398cc53ced906266a9297782c9Lennart Poettering *
b6b1849830f5e4a6065c3b0c993668e500c954d3Lennart Poettering * https://bugs.launchpad.net/ubuntu/+source/linux/+bug/554172/comments/245
10f9c75519671e7c7ab8993b54fe22da7c2d0c38Lennart Poettering */
10f9c75519671e7c7ab8993b54fe22da7c2d0c38Lennart Poettering
10f9c75519671e7c7ab8993b54fe22da7c2d0c38Lennart Poettering if (mode & O_CREAT)
c19de71113f956809995fc68817e055e9f61f607Lennart Poettering return -EINVAL;
10f9c75519671e7c7ab8993b54fe22da7c2d0c38Lennart Poettering
10f9c75519671e7c7ab8993b54fe22da7c2d0c38Lennart Poettering for (;;) {
cd61c3bfd718fb398cc53ced906266a9297782c9Lennart Poettering fd = open(name, mode, 0);
cd61c3bfd718fb398cc53ced906266a9297782c9Lennart Poettering if (fd >= 0)
b6b1849830f5e4a6065c3b0c993668e500c954d3Lennart Poettering break;
10f9c75519671e7c7ab8993b54fe22da7c2d0c38Lennart Poettering
b6b1849830f5e4a6065c3b0c993668e500c954d3Lennart Poettering if (errno != EIO)
cd61c3bfd718fb398cc53ced906266a9297782c9Lennart Poettering return -errno;
cd61c3bfd718fb398cc53ced906266a9297782c9Lennart Poettering
8937e7b68940d0fa0d0aab90eb7425fa7dccebc9Lennart Poettering /* Max 1s in total */
b6b1849830f5e4a6065c3b0c993668e500c954d3Lennart Poettering if (c >= 20)
b6b1849830f5e4a6065c3b0c993668e500c954d3Lennart Poettering return -errno;
b6b1849830f5e4a6065c3b0c993668e500c954d3Lennart Poettering
cd61c3bfd718fb398cc53ced906266a9297782c9Lennart Poettering usleep(50 * USEC_PER_MSEC);
cd61c3bfd718fb398cc53ced906266a9297782c9Lennart Poettering c++;
cd61c3bfd718fb398cc53ced906266a9297782c9Lennart Poettering }
cd61c3bfd718fb398cc53ced906266a9297782c9Lennart Poettering
cd61c3bfd718fb398cc53ced906266a9297782c9Lennart Poettering r = isatty(fd);
cd61c3bfd718fb398cc53ced906266a9297782c9Lennart Poettering if (r < 0) {
cd61c3bfd718fb398cc53ced906266a9297782c9Lennart Poettering safe_close(fd);
cd61c3bfd718fb398cc53ced906266a9297782c9Lennart Poettering return -errno;
89f7c8465cd1ab37347dd0c15920bce31e8225dfLennart Poettering }
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen if (!r) {
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering safe_close(fd);
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering return -ENOTTY;
8b0cc9a36c8f92f010f2e8465942d2cd7c580d78Lennart Poettering }
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering return fd;
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering}
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poetteringint acquire_terminal(
d21ed1ead18d16d35c30299a69d3366847f8a039Lennart Poettering const char *name,
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering bool fail,
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering bool force,
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering bool ignore_tiocstty_eperm,
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering usec_t timeout) {
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering int fd = -1, notify = -1, r = 0, wd = -1;
a7893c6b28772edbc7e1fea3c209caa54d465648Lennart Poettering usec_t ts = 0;
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering assert(name);
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering
89f7c8465cd1ab37347dd0c15920bce31e8225dfLennart Poettering /* We use inotify to be notified when the tty is closed. We
a7893c6b28772edbc7e1fea3c209caa54d465648Lennart Poettering * create the watch before checking if we can actually acquire
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering * it, so that we don't lose any event.
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen *
a7893c6b28772edbc7e1fea3c209caa54d465648Lennart Poettering * Note: strictly speaking this actually watches for the
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering * device being closed, it does *not* really watch whether a
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen * tty loses its controlling process. However, unless some
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering * rogue process uses TIOCNOTTY on /dev/tty *after* closing
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering * its tty otherwise this will not become a problem. As long
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering * as the administrator makes sure not configure any service
a7893c6b28772edbc7e1fea3c209caa54d465648Lennart Poettering * on the same tty as an untrusted user this should not be a
5b30bef856e89a571df57b7b953e9a1409d9acedLennart Poettering * problem. (Which he probably should not do anyway.) */
5b30bef856e89a571df57b7b953e9a1409d9acedLennart Poettering
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering if (timeout != USEC_INFINITY)
9d12709626bccc0cae677a7035f62efe6aabb4abLennart Poettering ts = now(CLOCK_MONOTONIC);
9d12709626bccc0cae677a7035f62efe6aabb4abLennart Poettering
9d12709626bccc0cae677a7035f62efe6aabb4abLennart Poettering if (!fail && !force) {
9d12709626bccc0cae677a7035f62efe6aabb4abLennart Poettering notify = inotify_init1(IN_CLOEXEC | (timeout != USEC_INFINITY ? IN_NONBLOCK : 0));
9d12709626bccc0cae677a7035f62efe6aabb4abLennart Poettering if (notify < 0) {
9d12709626bccc0cae677a7035f62efe6aabb4abLennart Poettering r = -errno;
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering goto fail;
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering }
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering wd = inotify_add_watch(notify, name, IN_CLOSE);
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering if (wd < 0) {
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering r = -errno;
8b0cc9a36c8f92f010f2e8465942d2cd7c580d78Lennart Poettering goto fail;
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering }
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering }
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering
f48e75cb9a8112d35855c44a156934f2ee0edb2eLennart Poettering for (;;) {
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering struct sigaction sa_old, sa_new = {
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering .sa_handler = SIG_IGN,
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering .sa_flags = SA_RESTART,
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering };
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering if (notify >= 0) {
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering r = flush_fd(notify);
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering if (r < 0)
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering goto fail;
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering }
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering /* We pass here O_NOCTTY only so that we can check the return
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering * value TIOCSCTTY and have a reliable way to figure out if we
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering * successfully became the controlling process of the tty */
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering fd = open_terminal(name, O_RDWR|O_NOCTTY|O_CLOEXEC);
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering if (fd < 0)
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering return fd;
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering /* Temporarily ignore SIGHUP, so that we don't get SIGHUP'ed
0dd25fb9f005d8ab7ac4bc10a609d00569f8c56aLennart Poettering * if we already own the tty. */
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering assert_se(sigaction(SIGHUP, &sa_new, &sa_old) == 0);
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering /* First, try to get the tty */
0dd25fb9f005d8ab7ac4bc10a609d00569f8c56aLennart Poettering if (ioctl(fd, TIOCSCTTY, force) < 0)
0dd25fb9f005d8ab7ac4bc10a609d00569f8c56aLennart Poettering r = -errno;
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering assert_se(sigaction(SIGHUP, &sa_old, NULL) == 0);
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering /* Sometimes it makes sense to ignore TIOCSCTTY
0dd25fb9f005d8ab7ac4bc10a609d00569f8c56aLennart Poettering * returning EPERM, i.e. when very likely we already
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering * are have this controlling terminal. */
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering if (r < 0 && r == -EPERM && ignore_tiocstty_eperm)
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering r = 0;
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering if (r < 0 && (force || fail || r != -EPERM))
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering goto fail;
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering
f48e75cb9a8112d35855c44a156934f2ee0edb2eLennart Poettering if (r >= 0)
f48e75cb9a8112d35855c44a156934f2ee0edb2eLennart Poettering break;
f48e75cb9a8112d35855c44a156934f2ee0edb2eLennart Poettering
f48e75cb9a8112d35855c44a156934f2ee0edb2eLennart Poettering assert(!fail);
f48e75cb9a8112d35855c44a156934f2ee0edb2eLennart Poettering assert(!force);
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering assert(notify >= 0);
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering for (;;) {
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering union inotify_event_buffer buffer;
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering struct inotify_event *e;
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering ssize_t l;
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering if (timeout != USEC_INFINITY) {
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering usec_t n;
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering n = now(CLOCK_MONOTONIC);
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering if (ts + timeout < n) {
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering r = -ETIMEDOUT;
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering goto fail;
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering }
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering r = fd_wait_for_event(fd, POLLIN, ts + timeout - n);
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering if (r < 0)
717603e391b52983ca1fd218e7333a1b9dfc5c05Lennart Poettering goto fail;
717603e391b52983ca1fd218e7333a1b9dfc5c05Lennart Poettering
717603e391b52983ca1fd218e7333a1b9dfc5c05Lennart Poettering if (r == 0) {
717603e391b52983ca1fd218e7333a1b9dfc5c05Lennart Poettering r = -ETIMEDOUT;
717603e391b52983ca1fd218e7333a1b9dfc5c05Lennart Poettering goto fail;
717603e391b52983ca1fd218e7333a1b9dfc5c05Lennart Poettering }
717603e391b52983ca1fd218e7333a1b9dfc5c05Lennart Poettering }
717603e391b52983ca1fd218e7333a1b9dfc5c05Lennart Poettering
717603e391b52983ca1fd218e7333a1b9dfc5c05Lennart Poettering l = read(notify, &buffer, sizeof(buffer));
717603e391b52983ca1fd218e7333a1b9dfc5c05Lennart Poettering if (l < 0) {
717603e391b52983ca1fd218e7333a1b9dfc5c05Lennart Poettering if (errno == EINTR || errno == EAGAIN)
717603e391b52983ca1fd218e7333a1b9dfc5c05Lennart Poettering continue;
717603e391b52983ca1fd218e7333a1b9dfc5c05Lennart Poettering
717603e391b52983ca1fd218e7333a1b9dfc5c05Lennart Poettering r = -errno;
717603e391b52983ca1fd218e7333a1b9dfc5c05Lennart Poettering goto fail;
717603e391b52983ca1fd218e7333a1b9dfc5c05Lennart Poettering }
717603e391b52983ca1fd218e7333a1b9dfc5c05Lennart Poettering
717603e391b52983ca1fd218e7333a1b9dfc5c05Lennart Poettering FOREACH_INOTIFY_EVENT(e, buffer, l) {
717603e391b52983ca1fd218e7333a1b9dfc5c05Lennart Poettering if (e->wd != wd || !(e->mask & IN_CLOSE)) {
717603e391b52983ca1fd218e7333a1b9dfc5c05Lennart Poettering r = -EIO;
717603e391b52983ca1fd218e7333a1b9dfc5c05Lennart Poettering goto fail;
717603e391b52983ca1fd218e7333a1b9dfc5c05Lennart Poettering }
717603e391b52983ca1fd218e7333a1b9dfc5c05Lennart Poettering }
717603e391b52983ca1fd218e7333a1b9dfc5c05Lennart Poettering
717603e391b52983ca1fd218e7333a1b9dfc5c05Lennart Poettering break;
717603e391b52983ca1fd218e7333a1b9dfc5c05Lennart Poettering }
717603e391b52983ca1fd218e7333a1b9dfc5c05Lennart Poettering
717603e391b52983ca1fd218e7333a1b9dfc5c05Lennart Poettering /* We close the tty fd here since if the old session
717603e391b52983ca1fd218e7333a1b9dfc5c05Lennart Poettering * ended our handle will be dead. It's important that
717603e391b52983ca1fd218e7333a1b9dfc5c05Lennart Poettering * we do this after sleeping, so that we don't enter
717603e391b52983ca1fd218e7333a1b9dfc5c05Lennart Poettering * an endless loop. */
717603e391b52983ca1fd218e7333a1b9dfc5c05Lennart Poettering fd = safe_close(fd);
717603e391b52983ca1fd218e7333a1b9dfc5c05Lennart Poettering }
717603e391b52983ca1fd218e7333a1b9dfc5c05Lennart Poettering
717603e391b52983ca1fd218e7333a1b9dfc5c05Lennart Poettering safe_close(notify);
717603e391b52983ca1fd218e7333a1b9dfc5c05Lennart Poettering
717603e391b52983ca1fd218e7333a1b9dfc5c05Lennart Poettering return fd;
717603e391b52983ca1fd218e7333a1b9dfc5c05Lennart Poettering
717603e391b52983ca1fd218e7333a1b9dfc5c05Lennart Poetteringfail:
717603e391b52983ca1fd218e7333a1b9dfc5c05Lennart Poettering safe_close(fd);
717603e391b52983ca1fd218e7333a1b9dfc5c05Lennart Poettering safe_close(notify);
717603e391b52983ca1fd218e7333a1b9dfc5c05Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering return r;
9f6eb1cd58f2ddf2eb6ba0e4de056e13d938af75Kay Sievers}
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
9f6eb1cd58f2ddf2eb6ba0e4de056e13d938af75Kay Sieversint release_terminal(void) {
9f6eb1cd58f2ddf2eb6ba0e4de056e13d938af75Kay Sievers static const struct sigaction sa_new = {
89f7c8465cd1ab37347dd0c15920bce31e8225dfLennart Poettering .sa_handler = SIG_IGN,
9f6eb1cd58f2ddf2eb6ba0e4de056e13d938af75Kay Sievers .sa_flags = SA_RESTART,
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering };
8b0cc9a36c8f92f010f2e8465942d2cd7c580d78Lennart Poettering
f48e75cb9a8112d35855c44a156934f2ee0edb2eLennart Poettering _cleanup_close_ int fd = -1;
f48e75cb9a8112d35855c44a156934f2ee0edb2eLennart Poettering struct sigaction sa_old;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering int r = 0;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen fd = open("/dev/tty", O_RDWR|O_NOCTTY|O_CLOEXEC|O_NONBLOCK);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering if (fd < 0)
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering return -errno;
f48e75cb9a8112d35855c44a156934f2ee0edb2eLennart Poettering
f48e75cb9a8112d35855c44a156934f2ee0edb2eLennart Poettering /* Temporarily ignore SIGHUP, so that we don't get SIGHUP'ed
56159e0d918e9a9be07988133bb2847779325de0Lennart Poettering * by our own TIOCNOTTY */
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering assert_se(sigaction(SIGHUP, &sa_new, &sa_old) == 0);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering if (ioctl(fd, TIOCNOTTY) < 0)
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering r = -errno;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering assert_se(sigaction(SIGHUP, &sa_old, NULL) == 0);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering return r;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering}
8b0cc9a36c8f92f010f2e8465942d2cd7c580d78Lennart Poettering
8b0cc9a36c8f92f010f2e8465942d2cd7c580d78Lennart Poetteringint terminal_vhangup_fd(int fd) {
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering assert(fd >= 0);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering if (ioctl(fd, TIOCVHANGUP) < 0)
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering return -errno;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering return 0;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering}
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poetteringint terminal_vhangup(const char *name) {
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering _cleanup_close_ int fd;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering fd = open_terminal(name, O_RDWR|O_NOCTTY|O_CLOEXEC|O_NONBLOCK);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering if (fd < 0)
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering return fd;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering return terminal_vhangup_fd(fd);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering}
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poetteringint vt_disallocate(const char *name) {
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering _cleanup_close_ int fd = -1;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering unsigned u;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering int r;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering /* Deallocate the VT if possible. If not possible
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering * (i.e. because it is the active one), at least clear it
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering * entirely (including the scrollback buffer) */
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering if (!startswith(name, "/dev/"))
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering return -EINVAL;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering if (!tty_is_vc(name)) {
f48e75cb9a8112d35855c44a156934f2ee0edb2eLennart Poettering /* So this is not a VT. I guess we cannot deallocate
f48e75cb9a8112d35855c44a156934f2ee0edb2eLennart Poettering * it then. But let's at least clear the screen */
f48e75cb9a8112d35855c44a156934f2ee0edb2eLennart Poettering
f48e75cb9a8112d35855c44a156934f2ee0edb2eLennart Poettering fd = open_terminal(name, O_RDWR|O_NOCTTY|O_CLOEXEC);
f48e75cb9a8112d35855c44a156934f2ee0edb2eLennart Poettering if (fd < 0)
f48e75cb9a8112d35855c44a156934f2ee0edb2eLennart Poettering return fd;
f48e75cb9a8112d35855c44a156934f2ee0edb2eLennart Poettering
f48e75cb9a8112d35855c44a156934f2ee0edb2eLennart Poettering loop_write(fd,
f48e75cb9a8112d35855c44a156934f2ee0edb2eLennart Poettering "\033[r" /* clear scrolling region */
f48e75cb9a8112d35855c44a156934f2ee0edb2eLennart Poettering "\033[H" /* move home */
f48e75cb9a8112d35855c44a156934f2ee0edb2eLennart Poettering "\033[2J", /* clear screen */
f48e75cb9a8112d35855c44a156934f2ee0edb2eLennart Poettering 10, false);
f48e75cb9a8112d35855c44a156934f2ee0edb2eLennart Poettering return 0;
f48e75cb9a8112d35855c44a156934f2ee0edb2eLennart Poettering }
f48e75cb9a8112d35855c44a156934f2ee0edb2eLennart Poettering
f48e75cb9a8112d35855c44a156934f2ee0edb2eLennart Poettering if (!startswith(name, "/dev/tty"))
f48e75cb9a8112d35855c44a156934f2ee0edb2eLennart Poettering return -EINVAL;
f48e75cb9a8112d35855c44a156934f2ee0edb2eLennart Poettering
f48e75cb9a8112d35855c44a156934f2ee0edb2eLennart Poettering r = safe_atou(name+8, &u);
f48e75cb9a8112d35855c44a156934f2ee0edb2eLennart Poettering if (r < 0)
f48e75cb9a8112d35855c44a156934f2ee0edb2eLennart Poettering return r;
f48e75cb9a8112d35855c44a156934f2ee0edb2eLennart Poettering
f48e75cb9a8112d35855c44a156934f2ee0edb2eLennart Poettering if (u <= 0)
f48e75cb9a8112d35855c44a156934f2ee0edb2eLennart Poettering return -EINVAL;
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering /* Try to deallocate */
878cd7e95ca303f9851d227a22d2022bd49944b0Lennart Poettering fd = open_terminal("/dev/tty0", O_RDWR|O_NOCTTY|O_CLOEXEC|O_NONBLOCK);
717603e391b52983ca1fd218e7333a1b9dfc5c05Lennart Poettering if (fd < 0)
717603e391b52983ca1fd218e7333a1b9dfc5c05Lennart Poettering return fd;
89f7c8465cd1ab37347dd0c15920bce31e8225dfLennart Poettering
89f7c8465cd1ab37347dd0c15920bce31e8225dfLennart Poettering r = ioctl(fd, VT_DISALLOCATE, u);
89f7c8465cd1ab37347dd0c15920bce31e8225dfLennart Poettering fd = safe_close(fd);
8b0cc9a36c8f92f010f2e8465942d2cd7c580d78Lennart Poettering
8b0cc9a36c8f92f010f2e8465942d2cd7c580d78Lennart Poettering if (r >= 0)
8b0cc9a36c8f92f010f2e8465942d2cd7c580d78Lennart Poettering return 0;
8b0cc9a36c8f92f010f2e8465942d2cd7c580d78Lennart Poettering
8b0cc9a36c8f92f010f2e8465942d2cd7c580d78Lennart Poettering if (errno != EBUSY)
8b0cc9a36c8f92f010f2e8465942d2cd7c580d78Lennart Poettering return -errno;
8b0cc9a36c8f92f010f2e8465942d2cd7c580d78Lennart Poettering
8b0cc9a36c8f92f010f2e8465942d2cd7c580d78Lennart Poettering /* Couldn't deallocate, so let's clear it fully with
8b0cc9a36c8f92f010f2e8465942d2cd7c580d78Lennart Poettering * scrollback */
8b0cc9a36c8f92f010f2e8465942d2cd7c580d78Lennart Poettering fd = open_terminal(name, O_RDWR|O_NOCTTY|O_CLOEXEC);
8b0cc9a36c8f92f010f2e8465942d2cd7c580d78Lennart Poettering if (fd < 0)
8b0cc9a36c8f92f010f2e8465942d2cd7c580d78Lennart Poettering return fd;
8b0cc9a36c8f92f010f2e8465942d2cd7c580d78Lennart Poettering
8b0cc9a36c8f92f010f2e8465942d2cd7c580d78Lennart Poettering loop_write(fd,
8b0cc9a36c8f92f010f2e8465942d2cd7c580d78Lennart Poettering "\033[r" /* clear scrolling region */
8b0cc9a36c8f92f010f2e8465942d2cd7c580d78Lennart Poettering "\033[H" /* move home */
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering "\033[3J", /* clear screen including scrollback, requires Linux 2.6.40 */
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering 10, false);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering return 0;
f48e75cb9a8112d35855c44a156934f2ee0edb2eLennart Poettering}
f48e75cb9a8112d35855c44a156934f2ee0edb2eLennart Poettering
f48e75cb9a8112d35855c44a156934f2ee0edb2eLennart Poetteringint make_console_stdio(void) {
f48e75cb9a8112d35855c44a156934f2ee0edb2eLennart Poettering int fd, r;
f48e75cb9a8112d35855c44a156934f2ee0edb2eLennart Poettering
f48e75cb9a8112d35855c44a156934f2ee0edb2eLennart Poettering /* Make /dev/console the controlling terminal and stdin/stdout/stderr */
f48e75cb9a8112d35855c44a156934f2ee0edb2eLennart Poettering
f48e75cb9a8112d35855c44a156934f2ee0edb2eLennart Poettering fd = acquire_terminal("/dev/console", false, true, true, USEC_INFINITY);
f48e75cb9a8112d35855c44a156934f2ee0edb2eLennart Poettering if (fd < 0)
f48e75cb9a8112d35855c44a156934f2ee0edb2eLennart Poettering return log_error_errno(fd, "Failed to acquire terminal: %m");
e7e9b6bb0b0bc5b1eb256a44f8afec6b634f26efZbigniew Jędrzejewski-Szmek
e7e9b6bb0b0bc5b1eb256a44f8afec6b634f26efZbigniew Jędrzejewski-Szmek r = reset_terminal_fd(fd, true);
f48e75cb9a8112d35855c44a156934f2ee0edb2eLennart Poettering if (r < 0)
f48e75cb9a8112d35855c44a156934f2ee0edb2eLennart Poettering log_warning_errno(r, "Failed to reset terminal, ignoring: %m");
f48e75cb9a8112d35855c44a156934f2ee0edb2eLennart Poettering
f48e75cb9a8112d35855c44a156934f2ee0edb2eLennart Poettering r = make_stdio(fd);
f48e75cb9a8112d35855c44a156934f2ee0edb2eLennart Poettering if (r < 0)
f48e75cb9a8112d35855c44a156934f2ee0edb2eLennart Poettering return log_error_errno(r, "Failed to duplicate terminal fd: %m");
f48e75cb9a8112d35855c44a156934f2ee0edb2eLennart Poettering
f48e75cb9a8112d35855c44a156934f2ee0edb2eLennart Poettering return 0;
f48e75cb9a8112d35855c44a156934f2ee0edb2eLennart Poettering}
fefdc04b38725457a91651218feb7000f6ccc1f4Lennart Poettering
a6c616024db23fef34152c1432892824a07799ccLennart Poetteringint status_vprintf(const char *status, bool ellipse, bool ephemeral, const char *format, va_list ap) {
9f6eb1cd58f2ddf2eb6ba0e4de056e13d938af75Kay Sievers static const char status_indent[] = " "; /* "[" STATUS "] " */
8b0cc9a36c8f92f010f2e8465942d2cd7c580d78Lennart Poettering _cleanup_free_ char *s = NULL;
8b0cc9a36c8f92f010f2e8465942d2cd7c580d78Lennart Poettering _cleanup_close_ int fd = -1;
8b0cc9a36c8f92f010f2e8465942d2cd7c580d78Lennart Poettering struct iovec iovec[6] = {};
8b0cc9a36c8f92f010f2e8465942d2cd7c580d78Lennart Poettering int n = 0;
8b0cc9a36c8f92f010f2e8465942d2cd7c580d78Lennart Poettering static bool prev_ephemeral;
8b0cc9a36c8f92f010f2e8465942d2cd7c580d78Lennart Poettering
8b0cc9a36c8f92f010f2e8465942d2cd7c580d78Lennart Poettering assert(format);
8b0cc9a36c8f92f010f2e8465942d2cd7c580d78Lennart Poettering
8b0cc9a36c8f92f010f2e8465942d2cd7c580d78Lennart Poettering /* This is independent of logging, as status messages are
8b0cc9a36c8f92f010f2e8465942d2cd7c580d78Lennart Poettering * optional and go exclusively to the console. */
9f6eb1cd58f2ddf2eb6ba0e4de056e13d938af75Kay Sievers
9f6eb1cd58f2ddf2eb6ba0e4de056e13d938af75Kay Sievers if (vasprintf(&s, format, ap) < 0)
a6c616024db23fef34152c1432892824a07799ccLennart Poettering return log_oom();
a6c616024db23fef34152c1432892824a07799ccLennart Poettering
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen fd = open_terminal("/dev/console", O_WRONLY|O_NOCTTY|O_CLOEXEC);
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen if (fd < 0)
56159e0d918e9a9be07988133bb2847779325de0Lennart Poettering return fd;
56159e0d918e9a9be07988133bb2847779325de0Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering if (ellipse) {
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering char *e;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering size_t emax, sl;
9f6eb1cd58f2ddf2eb6ba0e4de056e13d938af75Kay Sievers int c;
9f6eb1cd58f2ddf2eb6ba0e4de056e13d938af75Kay Sievers
9f6eb1cd58f2ddf2eb6ba0e4de056e13d938af75Kay Sievers c = fd_columns(fd);
9f6eb1cd58f2ddf2eb6ba0e4de056e13d938af75Kay Sievers if (c <= 0)
9f6eb1cd58f2ddf2eb6ba0e4de056e13d938af75Kay Sievers c = 80;
f647962d64e844689f3e2acfce6102fc47e76df2Michal Schmidt
f647962d64e844689f3e2acfce6102fc47e76df2Michal Schmidt sl = status ? sizeof(status_indent)-1 : 0;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering emax = c - sl - 1;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering if (emax < 3)
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering emax = 3;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
9f6eb1cd58f2ddf2eb6ba0e4de056e13d938af75Kay Sievers e = ellipsize(s, emax, 50);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering if (e) {
9f6eb1cd58f2ddf2eb6ba0e4de056e13d938af75Kay Sievers free(s);
9f6eb1cd58f2ddf2eb6ba0e4de056e13d938af75Kay Sievers s = e;
9f6eb1cd58f2ddf2eb6ba0e4de056e13d938af75Kay Sievers }
89f7c8465cd1ab37347dd0c15920bce31e8225dfLennart Poettering }
9f6eb1cd58f2ddf2eb6ba0e4de056e13d938af75Kay Sievers
f48e75cb9a8112d35855c44a156934f2ee0edb2eLennart Poettering if (prev_ephemeral)
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering IOVEC_SET_STRING(iovec[n++], "\r" ANSI_ERASE_TO_END_OF_LINE);
9f6eb1cd58f2ddf2eb6ba0e4de056e13d938af75Kay Sievers prev_ephemeral = ephemeral;
9f6eb1cd58f2ddf2eb6ba0e4de056e13d938af75Kay Sievers
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering if (status) {
fefdc04b38725457a91651218feb7000f6ccc1f4Lennart Poettering if (!isempty(status)) {
9f6eb1cd58f2ddf2eb6ba0e4de056e13d938af75Kay Sievers IOVEC_SET_STRING(iovec[n++], "[");
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering IOVEC_SET_STRING(iovec[n++], status);
56159e0d918e9a9be07988133bb2847779325de0Lennart Poettering IOVEC_SET_STRING(iovec[n++], "] ");
56159e0d918e9a9be07988133bb2847779325de0Lennart Poettering } else
56159e0d918e9a9be07988133bb2847779325de0Lennart Poettering IOVEC_SET_STRING(iovec[n++], status_indent);
56159e0d918e9a9be07988133bb2847779325de0Lennart Poettering }
9f6eb1cd58f2ddf2eb6ba0e4de056e13d938af75Kay Sievers
9f6eb1cd58f2ddf2eb6ba0e4de056e13d938af75Kay Sievers IOVEC_SET_STRING(iovec[n++], s);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering if (!ephemeral)
9f6eb1cd58f2ddf2eb6ba0e4de056e13d938af75Kay Sievers IOVEC_SET_STRING(iovec[n++], "\n");
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen
27e72d6b22890ba4a8cbc05c49667cd1cccf1461Simon Peeters if (writev(fd, iovec, n) < 0)
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen return -errno;
da927ba997d68401563b927f92e6e40e021a8e5cMichal Schmidt
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering return 0;
a7893c6b28772edbc7e1fea3c209caa54d465648Lennart Poettering}
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poetteringint status_printf(const char *status, bool ellipse, bool ephemeral, const char *format, ...) {
fefdc04b38725457a91651218feb7000f6ccc1f4Lennart Poettering va_list ap;
56159e0d918e9a9be07988133bb2847779325de0Lennart Poettering int r;
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen
56159e0d918e9a9be07988133bb2847779325de0Lennart Poettering assert(format);
9f6eb1cd58f2ddf2eb6ba0e4de056e13d938af75Kay Sievers
56159e0d918e9a9be07988133bb2847779325de0Lennart Poettering va_start(ap, format);
56159e0d918e9a9be07988133bb2847779325de0Lennart Poettering r = status_vprintf(status, ellipse, ephemeral, format, ap);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering va_end(ap);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering return r;
56159e0d918e9a9be07988133bb2847779325de0Lennart Poettering}
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poetteringbool tty_is_vc(const char *tty) {
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering assert(tty);
56159e0d918e9a9be07988133bb2847779325de0Lennart Poettering
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen return vtnr_from_tty(tty) >= 0;
9f6eb1cd58f2ddf2eb6ba0e4de056e13d938af75Kay Sievers}
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
fefdc04b38725457a91651218feb7000f6ccc1f4Lennart Poetteringbool tty_is_console(const char *tty) {
8c841f21f5042b11acc91cc1b039cb162cbbe8f4Djalal Harouni assert(tty);
9f6eb1cd58f2ddf2eb6ba0e4de056e13d938af75Kay Sievers
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering if (startswith(tty, "/dev/"))
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering tty += 5;
56159e0d918e9a9be07988133bb2847779325de0Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering return streq(tty, "console");
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering}
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersenint vtnr_from_tty(const char *tty) {
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen int i, r;
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen assert(tty);
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen if (startswith(tty, "/dev/"))
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen tty += 5;
56159e0d918e9a9be07988133bb2847779325de0Lennart Poettering
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen if (!startswith(tty, "tty") )
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen return -EINVAL;
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen if (tty[3] < '0' || tty[3] > '9')
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen return -EINVAL;
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen
5b30bef856e89a571df57b7b953e9a1409d9acedLennart Poettering r = safe_atoi(tty+3, &i);
5b30bef856e89a571df57b7b953e9a1409d9acedLennart Poettering if (r < 0)
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering return r;
9f6eb1cd58f2ddf2eb6ba0e4de056e13d938af75Kay Sievers
fefdc04b38725457a91651218feb7000f6ccc1f4Lennart Poettering if (i < 0 || i > 63)
9f6eb1cd58f2ddf2eb6ba0e4de056e13d938af75Kay Sievers return -EINVAL;
fefdc04b38725457a91651218feb7000f6ccc1f4Lennart Poettering
fefdc04b38725457a91651218feb7000f6ccc1f4Lennart Poettering return i;
fefdc04b38725457a91651218feb7000f6ccc1f4Lennart Poettering}
fefdc04b38725457a91651218feb7000f6ccc1f4Lennart Poettering
fefdc04b38725457a91651218feb7000f6ccc1f4Lennart Poetteringchar *resolve_dev_console(char **active) {
fefdc04b38725457a91651218feb7000f6ccc1f4Lennart Poettering char *tty;
fefdc04b38725457a91651218feb7000f6ccc1f4Lennart Poettering
fefdc04b38725457a91651218feb7000f6ccc1f4Lennart Poettering /* Resolve where /dev/console is pointing to, if /sys is actually ours
fefdc04b38725457a91651218feb7000f6ccc1f4Lennart Poettering * (i.e. not read-only-mounted which is a sign for container setups) */
fefdc04b38725457a91651218feb7000f6ccc1f4Lennart Poettering
fefdc04b38725457a91651218feb7000f6ccc1f4Lennart Poettering if (path_is_read_only_fs("/sys") > 0)
fefdc04b38725457a91651218feb7000f6ccc1f4Lennart Poettering return NULL;
fefdc04b38725457a91651218feb7000f6ccc1f4Lennart Poettering
c19de71113f956809995fc68817e055e9f61f607Lennart Poettering if (read_one_line_file("/sys/class/tty/console/active", active) < 0)
b6b1849830f5e4a6065c3b0c993668e500c954d3Lennart Poettering return NULL;
c19de71113f956809995fc68817e055e9f61f607Lennart Poettering
b6b1849830f5e4a6065c3b0c993668e500c954d3Lennart Poettering /* If multiple log outputs are configured the last one is what
fefdc04b38725457a91651218feb7000f6ccc1f4Lennart Poettering * /dev/console points to */
fefdc04b38725457a91651218feb7000f6ccc1f4Lennart Poettering tty = strrchr(*active, ' ');
fefdc04b38725457a91651218feb7000f6ccc1f4Lennart Poettering if (tty)
fefdc04b38725457a91651218feb7000f6ccc1f4Lennart Poettering tty++;
fefdc04b38725457a91651218feb7000f6ccc1f4Lennart Poettering else
b6b1849830f5e4a6065c3b0c993668e500c954d3Lennart Poettering tty = *active;
b6b1849830f5e4a6065c3b0c993668e500c954d3Lennart Poettering
fefdc04b38725457a91651218feb7000f6ccc1f4Lennart Poettering if (streq(tty, "tty0")) {
fefdc04b38725457a91651218feb7000f6ccc1f4Lennart Poettering char *tmp;
fefdc04b38725457a91651218feb7000f6ccc1f4Lennart Poettering
fefdc04b38725457a91651218feb7000f6ccc1f4Lennart Poettering /* Get the active VC (e.g. tty1) */
fefdc04b38725457a91651218feb7000f6ccc1f4Lennart Poettering if (read_one_line_file("/sys/class/tty/tty0/active", &tmp) >= 0) {
fefdc04b38725457a91651218feb7000f6ccc1f4Lennart Poettering free(*active);
fefdc04b38725457a91651218feb7000f6ccc1f4Lennart Poettering tty = *active = tmp;
fefdc04b38725457a91651218feb7000f6ccc1f4Lennart Poettering }
fefdc04b38725457a91651218feb7000f6ccc1f4Lennart Poettering }
9a14fb6285bdb089d4fc195410de3362cb4f586fThomas Hindoe Paaboel Andersen
fefdc04b38725457a91651218feb7000f6ccc1f4Lennart Poettering return tty;
fefdc04b38725457a91651218feb7000f6ccc1f4Lennart Poettering}
fefdc04b38725457a91651218feb7000f6ccc1f4Lennart Poettering
fefdc04b38725457a91651218feb7000f6ccc1f4Lennart Poetteringbool tty_is_vc_resolve(const char *tty) {
fefdc04b38725457a91651218feb7000f6ccc1f4Lennart Poettering _cleanup_free_ char *active = NULL;
fefdc04b38725457a91651218feb7000f6ccc1f4Lennart Poettering
fefdc04b38725457a91651218feb7000f6ccc1f4Lennart Poettering assert(tty);
fefdc04b38725457a91651218feb7000f6ccc1f4Lennart Poettering
fefdc04b38725457a91651218feb7000f6ccc1f4Lennart Poettering if (startswith(tty, "/dev/"))
fefdc04b38725457a91651218feb7000f6ccc1f4Lennart Poettering tty += 5;
fefdc04b38725457a91651218feb7000f6ccc1f4Lennart Poettering
fefdc04b38725457a91651218feb7000f6ccc1f4Lennart Poettering if (streq(tty, "console")) {
b6b1849830f5e4a6065c3b0c993668e500c954d3Lennart Poettering tty = resolve_dev_console(&active);
fefdc04b38725457a91651218feb7000f6ccc1f4Lennart Poettering if (!tty)
fefdc04b38725457a91651218feb7000f6ccc1f4Lennart Poettering return false;
fefdc04b38725457a91651218feb7000f6ccc1f4Lennart Poettering }
fefdc04b38725457a91651218feb7000f6ccc1f4Lennart Poettering
fefdc04b38725457a91651218feb7000f6ccc1f4Lennart Poettering return tty_is_vc(tty);
fefdc04b38725457a91651218feb7000f6ccc1f4Lennart Poettering}
b6b1849830f5e4a6065c3b0c993668e500c954d3Lennart Poettering
fefdc04b38725457a91651218feb7000f6ccc1f4Lennart Poetteringconst char *default_term_for_tty(const char *tty) {
fefdc04b38725457a91651218feb7000f6ccc1f4Lennart Poettering assert(tty);
fefdc04b38725457a91651218feb7000f6ccc1f4Lennart Poettering
b6b1849830f5e4a6065c3b0c993668e500c954d3Lennart Poettering return tty_is_vc_resolve(tty) ? "TERM=linux" : "TERM=vt220";
c19de71113f956809995fc68817e055e9f61f607Lennart Poettering}
c19de71113f956809995fc68817e055e9f61f607Lennart Poettering
b6b1849830f5e4a6065c3b0c993668e500c954d3Lennart Poetteringint fd_columns(int fd) {
c19de71113f956809995fc68817e055e9f61f607Lennart Poettering struct winsize ws = {};
b6b1849830f5e4a6065c3b0c993668e500c954d3Lennart Poettering
c19de71113f956809995fc68817e055e9f61f607Lennart Poettering if (ioctl(fd, TIOCGWINSZ, &ws) < 0)
b6b1849830f5e4a6065c3b0c993668e500c954d3Lennart Poettering return -errno;
b6b1849830f5e4a6065c3b0c993668e500c954d3Lennart Poettering
b6b1849830f5e4a6065c3b0c993668e500c954d3Lennart Poettering if (ws.ws_col <= 0)
b6b1849830f5e4a6065c3b0c993668e500c954d3Lennart Poettering return -EIO;
b6b1849830f5e4a6065c3b0c993668e500c954d3Lennart Poettering
b6b1849830f5e4a6065c3b0c993668e500c954d3Lennart Poettering return ws.ws_col;
b6b1849830f5e4a6065c3b0c993668e500c954d3Lennart Poettering}
fefdc04b38725457a91651218feb7000f6ccc1f4Lennart Poettering
fefdc04b38725457a91651218feb7000f6ccc1f4Lennart Poetteringunsigned columns(void) {
160e3793adf2da2bd9ae3fe6b8881bb937e6e71bLennart Poettering const char *e;
fefdc04b38725457a91651218feb7000f6ccc1f4Lennart Poettering int c;
fefdc04b38725457a91651218feb7000f6ccc1f4Lennart Poettering
b6b1849830f5e4a6065c3b0c993668e500c954d3Lennart Poettering if (_likely_(cached_columns > 0))
b6b1849830f5e4a6065c3b0c993668e500c954d3Lennart Poettering return cached_columns;
b6b1849830f5e4a6065c3b0c993668e500c954d3Lennart Poettering
b6b1849830f5e4a6065c3b0c993668e500c954d3Lennart Poettering c = 0;
b6b1849830f5e4a6065c3b0c993668e500c954d3Lennart Poettering e = getenv("COLUMNS");
b6b1849830f5e4a6065c3b0c993668e500c954d3Lennart Poettering if (e)
c19de71113f956809995fc68817e055e9f61f607Lennart Poettering (void) safe_atoi(e, &c);
b6b1849830f5e4a6065c3b0c993668e500c954d3Lennart Poettering
c19de71113f956809995fc68817e055e9f61f607Lennart Poettering if (c <= 0)
b6b1849830f5e4a6065c3b0c993668e500c954d3Lennart Poettering c = fd_columns(STDOUT_FILENO);
fefdc04b38725457a91651218feb7000f6ccc1f4Lennart Poettering
fefdc04b38725457a91651218feb7000f6ccc1f4Lennart Poettering if (c <= 0)
fefdc04b38725457a91651218feb7000f6ccc1f4Lennart Poettering c = 80;
fefdc04b38725457a91651218feb7000f6ccc1f4Lennart Poettering
fefdc04b38725457a91651218feb7000f6ccc1f4Lennart Poettering cached_columns = c;
fefdc04b38725457a91651218feb7000f6ccc1f4Lennart Poettering return cached_columns;
fefdc04b38725457a91651218feb7000f6ccc1f4Lennart Poettering}
fefdc04b38725457a91651218feb7000f6ccc1f4Lennart Poettering
fefdc04b38725457a91651218feb7000f6ccc1f4Lennart Poetteringint fd_lines(int fd) {
fefdc04b38725457a91651218feb7000f6ccc1f4Lennart Poettering struct winsize ws = {};
fefdc04b38725457a91651218feb7000f6ccc1f4Lennart Poettering
fefdc04b38725457a91651218feb7000f6ccc1f4Lennart Poettering if (ioctl(fd, TIOCGWINSZ, &ws) < 0)
fefdc04b38725457a91651218feb7000f6ccc1f4Lennart Poettering return -errno;
fefdc04b38725457a91651218feb7000f6ccc1f4Lennart Poettering
fefdc04b38725457a91651218feb7000f6ccc1f4Lennart Poettering if (ws.ws_row <= 0)
fefdc04b38725457a91651218feb7000f6ccc1f4Lennart Poettering return -EIO;
fefdc04b38725457a91651218feb7000f6ccc1f4Lennart Poettering
fefdc04b38725457a91651218feb7000f6ccc1f4Lennart Poettering return ws.ws_row;
fefdc04b38725457a91651218feb7000f6ccc1f4Lennart Poettering}
fefdc04b38725457a91651218feb7000f6ccc1f4Lennart Poettering
fefdc04b38725457a91651218feb7000f6ccc1f4Lennart Poetteringunsigned lines(void) {
fefdc04b38725457a91651218feb7000f6ccc1f4Lennart Poettering const char *e;
fefdc04b38725457a91651218feb7000f6ccc1f4Lennart Poettering int l;
fefdc04b38725457a91651218feb7000f6ccc1f4Lennart Poettering
fefdc04b38725457a91651218feb7000f6ccc1f4Lennart Poettering if (_likely_(cached_lines > 0))
fefdc04b38725457a91651218feb7000f6ccc1f4Lennart Poettering return cached_lines;
fefdc04b38725457a91651218feb7000f6ccc1f4Lennart Poettering
fefdc04b38725457a91651218feb7000f6ccc1f4Lennart Poettering l = 0;
fefdc04b38725457a91651218feb7000f6ccc1f4Lennart Poettering e = getenv("LINES");
fefdc04b38725457a91651218feb7000f6ccc1f4Lennart Poettering if (e)
fefdc04b38725457a91651218feb7000f6ccc1f4Lennart Poettering (void) safe_atoi(e, &l);
160e3793adf2da2bd9ae3fe6b8881bb937e6e71bLennart Poettering
160e3793adf2da2bd9ae3fe6b8881bb937e6e71bLennart Poettering if (l <= 0)
160e3793adf2da2bd9ae3fe6b8881bb937e6e71bLennart Poettering l = fd_lines(STDOUT_FILENO);
160e3793adf2da2bd9ae3fe6b8881bb937e6e71bLennart Poettering
160e3793adf2da2bd9ae3fe6b8881bb937e6e71bLennart Poettering if (l <= 0)
160e3793adf2da2bd9ae3fe6b8881bb937e6e71bLennart Poettering l = 24;
160e3793adf2da2bd9ae3fe6b8881bb937e6e71bLennart Poettering
160e3793adf2da2bd9ae3fe6b8881bb937e6e71bLennart Poettering cached_lines = l;
160e3793adf2da2bd9ae3fe6b8881bb937e6e71bLennart Poettering return cached_lines;
160e3793adf2da2bd9ae3fe6b8881bb937e6e71bLennart Poettering}
160e3793adf2da2bd9ae3fe6b8881bb937e6e71bLennart Poettering
160e3793adf2da2bd9ae3fe6b8881bb937e6e71bLennart Poettering/* intended to be used as a SIGWINCH sighandler */
160e3793adf2da2bd9ae3fe6b8881bb937e6e71bLennart Poetteringvoid columns_lines_cache_reset(int signum) {
160e3793adf2da2bd9ae3fe6b8881bb937e6e71bLennart Poettering cached_columns = 0;
160e3793adf2da2bd9ae3fe6b8881bb937e6e71bLennart Poettering cached_lines = 0;
160e3793adf2da2bd9ae3fe6b8881bb937e6e71bLennart Poettering}
160e3793adf2da2bd9ae3fe6b8881bb937e6e71bLennart Poettering
160e3793adf2da2bd9ae3fe6b8881bb937e6e71bLennart Poetteringbool on_tty(void) {
160e3793adf2da2bd9ae3fe6b8881bb937e6e71bLennart Poettering static int cached_on_tty = -1;
160e3793adf2da2bd9ae3fe6b8881bb937e6e71bLennart Poettering
160e3793adf2da2bd9ae3fe6b8881bb937e6e71bLennart Poettering if (_unlikely_(cached_on_tty < 0))
160e3793adf2da2bd9ae3fe6b8881bb937e6e71bLennart Poettering cached_on_tty = isatty(STDOUT_FILENO) > 0;
160e3793adf2da2bd9ae3fe6b8881bb937e6e71bLennart Poettering
160e3793adf2da2bd9ae3fe6b8881bb937e6e71bLennart Poettering return cached_on_tty;
160e3793adf2da2bd9ae3fe6b8881bb937e6e71bLennart Poettering}
160e3793adf2da2bd9ae3fe6b8881bb937e6e71bLennart Poettering
160e3793adf2da2bd9ae3fe6b8881bb937e6e71bLennart Poetteringint make_stdio(int fd) {
160e3793adf2da2bd9ae3fe6b8881bb937e6e71bLennart Poettering int r, s, t;
160e3793adf2da2bd9ae3fe6b8881bb937e6e71bLennart Poettering
160e3793adf2da2bd9ae3fe6b8881bb937e6e71bLennart Poettering assert(fd >= 0);
160e3793adf2da2bd9ae3fe6b8881bb937e6e71bLennart Poettering
160e3793adf2da2bd9ae3fe6b8881bb937e6e71bLennart Poettering r = dup2(fd, STDIN_FILENO);
160e3793adf2da2bd9ae3fe6b8881bb937e6e71bLennart Poettering s = dup2(fd, STDOUT_FILENO);
160e3793adf2da2bd9ae3fe6b8881bb937e6e71bLennart Poettering t = dup2(fd, STDERR_FILENO);
160e3793adf2da2bd9ae3fe6b8881bb937e6e71bLennart Poettering
160e3793adf2da2bd9ae3fe6b8881bb937e6e71bLennart Poettering if (fd >= 3)
160e3793adf2da2bd9ae3fe6b8881bb937e6e71bLennart Poettering safe_close(fd);
160e3793adf2da2bd9ae3fe6b8881bb937e6e71bLennart Poettering
160e3793adf2da2bd9ae3fe6b8881bb937e6e71bLennart Poettering if (r < 0 || s < 0 || t < 0)
160e3793adf2da2bd9ae3fe6b8881bb937e6e71bLennart Poettering return -errno;
160e3793adf2da2bd9ae3fe6b8881bb937e6e71bLennart Poettering
160e3793adf2da2bd9ae3fe6b8881bb937e6e71bLennart Poettering /* Explicitly unset O_CLOEXEC, since if fd was < 3, then
160e3793adf2da2bd9ae3fe6b8881bb937e6e71bLennart Poettering * dup2() was a NOP and the bit hence possibly set. */
160e3793adf2da2bd9ae3fe6b8881bb937e6e71bLennart Poettering fd_cloexec(STDIN_FILENO, false);
160e3793adf2da2bd9ae3fe6b8881bb937e6e71bLennart Poettering fd_cloexec(STDOUT_FILENO, false);
160e3793adf2da2bd9ae3fe6b8881bb937e6e71bLennart Poettering fd_cloexec(STDERR_FILENO, false);
160e3793adf2da2bd9ae3fe6b8881bb937e6e71bLennart Poettering
160e3793adf2da2bd9ae3fe6b8881bb937e6e71bLennart Poettering return 0;
160e3793adf2da2bd9ae3fe6b8881bb937e6e71bLennart Poettering}
160e3793adf2da2bd9ae3fe6b8881bb937e6e71bLennart Poettering
160e3793adf2da2bd9ae3fe6b8881bb937e6e71bLennart Poetteringint make_null_stdio(void) {
160e3793adf2da2bd9ae3fe6b8881bb937e6e71bLennart Poettering int null_fd;
160e3793adf2da2bd9ae3fe6b8881bb937e6e71bLennart Poettering
fefdc04b38725457a91651218feb7000f6ccc1f4Lennart Poettering null_fd = open("/dev/null", O_RDWR|O_NOCTTY);
fefdc04b38725457a91651218feb7000f6ccc1f4Lennart Poettering if (null_fd < 0)
fefdc04b38725457a91651218feb7000f6ccc1f4Lennart Poettering return -errno;
fefdc04b38725457a91651218feb7000f6ccc1f4Lennart Poettering
fefdc04b38725457a91651218feb7000f6ccc1f4Lennart Poettering return make_stdio(null_fd);
fefdc04b38725457a91651218feb7000f6ccc1f4Lennart Poettering}
fefdc04b38725457a91651218feb7000f6ccc1f4Lennart Poettering
fefdc04b38725457a91651218feb7000f6ccc1f4Lennart Poetteringint getttyname_malloc(int fd, char **ret) {
fefdc04b38725457a91651218feb7000f6ccc1f4Lennart Poettering size_t l = 100;
fefdc04b38725457a91651218feb7000f6ccc1f4Lennart Poettering int r;
fefdc04b38725457a91651218feb7000f6ccc1f4Lennart Poettering
fefdc04b38725457a91651218feb7000f6ccc1f4Lennart Poettering assert(fd >= 0);
fefdc04b38725457a91651218feb7000f6ccc1f4Lennart Poettering assert(ret);
fefdc04b38725457a91651218feb7000f6ccc1f4Lennart Poettering
fefdc04b38725457a91651218feb7000f6ccc1f4Lennart Poettering for (;;) {
fefdc04b38725457a91651218feb7000f6ccc1f4Lennart Poettering char path[l];
fefdc04b38725457a91651218feb7000f6ccc1f4Lennart Poettering
fefdc04b38725457a91651218feb7000f6ccc1f4Lennart Poettering r = ttyname_r(fd, path, sizeof(path));
fefdc04b38725457a91651218feb7000f6ccc1f4Lennart Poettering if (r == 0) {
fefdc04b38725457a91651218feb7000f6ccc1f4Lennart Poettering const char *p;
fefdc04b38725457a91651218feb7000f6ccc1f4Lennart Poettering char *c;
fefdc04b38725457a91651218feb7000f6ccc1f4Lennart Poettering
fefdc04b38725457a91651218feb7000f6ccc1f4Lennart Poettering p = startswith(path, "/dev/");
fefdc04b38725457a91651218feb7000f6ccc1f4Lennart Poettering c = strdup(p ?: path);
fefdc04b38725457a91651218feb7000f6ccc1f4Lennart Poettering if (!c)
fefdc04b38725457a91651218feb7000f6ccc1f4Lennart Poettering return -ENOMEM;
fefdc04b38725457a91651218feb7000f6ccc1f4Lennart Poettering
fefdc04b38725457a91651218feb7000f6ccc1f4Lennart Poettering *ret = c;
fefdc04b38725457a91651218feb7000f6ccc1f4Lennart Poettering return 0;
fefdc04b38725457a91651218feb7000f6ccc1f4Lennart Poettering }
fefdc04b38725457a91651218feb7000f6ccc1f4Lennart Poettering
fefdc04b38725457a91651218feb7000f6ccc1f4Lennart Poettering if (r != ERANGE)
fefdc04b38725457a91651218feb7000f6ccc1f4Lennart Poettering return -r;
160e3793adf2da2bd9ae3fe6b8881bb937e6e71bLennart Poettering
fefdc04b38725457a91651218feb7000f6ccc1f4Lennart Poettering l *= 2;
fefdc04b38725457a91651218feb7000f6ccc1f4Lennart Poettering }
fefdc04b38725457a91651218feb7000f6ccc1f4Lennart Poettering
160e3793adf2da2bd9ae3fe6b8881bb937e6e71bLennart Poettering return 0;
160e3793adf2da2bd9ae3fe6b8881bb937e6e71bLennart Poettering}
160e3793adf2da2bd9ae3fe6b8881bb937e6e71bLennart Poettering
160e3793adf2da2bd9ae3fe6b8881bb937e6e71bLennart Poetteringint getttyname_harder(int fd, char **r) {
160e3793adf2da2bd9ae3fe6b8881bb937e6e71bLennart Poettering int k;
fefdc04b38725457a91651218feb7000f6ccc1f4Lennart Poettering char *s = NULL;
fefdc04b38725457a91651218feb7000f6ccc1f4Lennart Poettering
fefdc04b38725457a91651218feb7000f6ccc1f4Lennart Poettering k = getttyname_malloc(fd, &s);
fefdc04b38725457a91651218feb7000f6ccc1f4Lennart Poettering if (k < 0)
fefdc04b38725457a91651218feb7000f6ccc1f4Lennart Poettering return k;
fefdc04b38725457a91651218feb7000f6ccc1f4Lennart Poettering
fefdc04b38725457a91651218feb7000f6ccc1f4Lennart Poettering if (streq(s, "tty")) {
fefdc04b38725457a91651218feb7000f6ccc1f4Lennart Poettering free(s);
90adaa25e894a580930ef2c3e65ab8db8295515aLennart Poettering return get_ctty(0, NULL, r);
90adaa25e894a580930ef2c3e65ab8db8295515aLennart Poettering }
90adaa25e894a580930ef2c3e65ab8db8295515aLennart Poettering
90adaa25e894a580930ef2c3e65ab8db8295515aLennart Poettering *r = s;
90adaa25e894a580930ef2c3e65ab8db8295515aLennart Poettering return 0;
90adaa25e894a580930ef2c3e65ab8db8295515aLennart Poettering}
90adaa25e894a580930ef2c3e65ab8db8295515aLennart Poettering
90adaa25e894a580930ef2c3e65ab8db8295515aLennart Poetteringint get_ctty_devnr(pid_t pid, dev_t *d) {
fefdc04b38725457a91651218feb7000f6ccc1f4Lennart Poettering int r;
fefdc04b38725457a91651218feb7000f6ccc1f4Lennart Poettering _cleanup_free_ char *line = NULL;
fefdc04b38725457a91651218feb7000f6ccc1f4Lennart Poettering const char *p;
fefdc04b38725457a91651218feb7000f6ccc1f4Lennart Poettering unsigned long ttynr;
fefdc04b38725457a91651218feb7000f6ccc1f4Lennart Poettering
fefdc04b38725457a91651218feb7000f6ccc1f4Lennart Poettering assert(pid >= 0);
fefdc04b38725457a91651218feb7000f6ccc1f4Lennart Poettering
fefdc04b38725457a91651218feb7000f6ccc1f4Lennart Poettering p = procfs_file_alloca(pid, "stat");
fefdc04b38725457a91651218feb7000f6ccc1f4Lennart Poettering r = read_one_line_file(p, &line);
fefdc04b38725457a91651218feb7000f6ccc1f4Lennart Poettering if (r < 0)
fefdc04b38725457a91651218feb7000f6ccc1f4Lennart Poettering return r;
fefdc04b38725457a91651218feb7000f6ccc1f4Lennart Poettering
160e3793adf2da2bd9ae3fe6b8881bb937e6e71bLennart Poettering p = strrchr(line, ')');
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering if (!p)
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering return -EIO;
9f6eb1cd58f2ddf2eb6ba0e4de056e13d938af75Kay Sievers
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering p++;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
56159e0d918e9a9be07988133bb2847779325de0Lennart Poettering if (sscanf(p, " "
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen "%*c " /* state */
56159e0d918e9a9be07988133bb2847779325de0Lennart Poettering "%*d " /* ppid */
90adaa25e894a580930ef2c3e65ab8db8295515aLennart Poettering "%*d " /* pgrp */
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering "%*d " /* session */
56159e0d918e9a9be07988133bb2847779325de0Lennart Poettering "%lu ", /* ttynr */
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering &ttynr) != 1)
acf97e213e69a97e63ab8f7fad7ecd53608c757aLennart Poettering return -EIO;
acf97e213e69a97e63ab8f7fad7ecd53608c757aLennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering if (major(ttynr) == 0 && minor(ttynr) == 0)
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering return -ENXIO;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
56159e0d918e9a9be07988133bb2847779325de0Lennart Poettering if (d)
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen *d = (dev_t) ttynr;
56159e0d918e9a9be07988133bb2847779325de0Lennart Poettering
56159e0d918e9a9be07988133bb2847779325de0Lennart Poettering return 0;
56159e0d918e9a9be07988133bb2847779325de0Lennart Poettering}
56159e0d918e9a9be07988133bb2847779325de0Lennart Poettering
56159e0d918e9a9be07988133bb2847779325de0Lennart Poetteringint get_ctty(pid_t pid, dev_t *_devnr, char **r) {
56159e0d918e9a9be07988133bb2847779325de0Lennart Poettering char fn[sizeof("/dev/char/")-1 + 2*DECIMAL_STR_MAX(unsigned) + 1 + 1], *b = NULL;
56159e0d918e9a9be07988133bb2847779325de0Lennart Poettering _cleanup_free_ char *s = NULL;
56159e0d918e9a9be07988133bb2847779325de0Lennart Poettering const char *p;
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen dev_t devnr;
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen int k;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen assert(r);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering k = get_ctty_devnr(pid, &devnr);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering if (k < 0)
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering return k;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering
56159e0d918e9a9be07988133bb2847779325de0Lennart Poettering sprintf(fn, "/dev/char/%u:%u", major(devnr), minor(devnr));
1dba654b27918c22e413ac5b3c19301f1ff86ad2Lennart Poettering
1dba654b27918c22e413ac5b3c19301f1ff86ad2Lennart Poettering k = readlink_malloc(fn, &s);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering if (k < 0) {
56159e0d918e9a9be07988133bb2847779325de0Lennart Poettering
1dba654b27918c22e413ac5b3c19301f1ff86ad2Lennart Poettering if (k != -ENOENT)
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering return k;
56159e0d918e9a9be07988133bb2847779325de0Lennart Poettering
1dba654b27918c22e413ac5b3c19301f1ff86ad2Lennart Poettering /* This is an ugly hack */
1dba654b27918c22e413ac5b3c19301f1ff86ad2Lennart Poettering if (major(devnr) == 136) {
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering if (asprintf(&b, "pts/%u", minor(devnr)) < 0)
56159e0d918e9a9be07988133bb2847779325de0Lennart Poettering return -ENOMEM;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering } else {
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering /* Probably something like the ptys which have no
56159e0d918e9a9be07988133bb2847779325de0Lennart Poettering * symlink in /dev/char. Let's return something
923d8fd381bced1c2d90ca53d18629d61a0f454aLennart Poettering * vaguely useful. */
56159e0d918e9a9be07988133bb2847779325de0Lennart Poettering
2723b3b51d409340558e46e37e90525d4f880fe1Lennart Poettering b = strdup(fn + 5);
923d8fd381bced1c2d90ca53d18629d61a0f454aLennart Poettering if (!b)
56159e0d918e9a9be07988133bb2847779325de0Lennart Poettering return -ENOMEM;
923d8fd381bced1c2d90ca53d18629d61a0f454aLennart Poettering }
acf97e213e69a97e63ab8f7fad7ecd53608c757aLennart Poettering } else {
acf97e213e69a97e63ab8f7fad7ecd53608c757aLennart Poettering if (startswith(s, "/dev/"))
56159e0d918e9a9be07988133bb2847779325de0Lennart Poettering p = s + 5;
923d8fd381bced1c2d90ca53d18629d61a0f454aLennart Poettering else if (startswith(s, "../"))
923d8fd381bced1c2d90ca53d18629d61a0f454aLennart Poettering p = s + 3;
923d8fd381bced1c2d90ca53d18629d61a0f454aLennart Poettering else
923d8fd381bced1c2d90ca53d18629d61a0f454aLennart Poettering p = s;
923d8fd381bced1c2d90ca53d18629d61a0f454aLennart Poettering
1dba654b27918c22e413ac5b3c19301f1ff86ad2Lennart Poettering b = strdup(p);
923d8fd381bced1c2d90ca53d18629d61a0f454aLennart Poettering if (!b)
1dba654b27918c22e413ac5b3c19301f1ff86ad2Lennart Poettering return -ENOMEM;
56159e0d918e9a9be07988133bb2847779325de0Lennart Poettering }
923d8fd381bced1c2d90ca53d18629d61a0f454aLennart Poettering
1dba654b27918c22e413ac5b3c19301f1ff86ad2Lennart Poettering *r = b;
923d8fd381bced1c2d90ca53d18629d61a0f454aLennart Poettering if (_devnr)
923d8fd381bced1c2d90ca53d18629d61a0f454aLennart Poettering *_devnr = devnr;
923d8fd381bced1c2d90ca53d18629d61a0f454aLennart Poettering
923d8fd381bced1c2d90ca53d18629d61a0f454aLennart Poettering return 0;
923d8fd381bced1c2d90ca53d18629d61a0f454aLennart Poettering}
923d8fd381bced1c2d90ca53d18629d61a0f454aLennart Poettering
923d8fd381bced1c2d90ca53d18629d61a0f454aLennart Poetteringint ptsname_malloc(int fd, char **ret) {
0370612e0522191f929e3feb7d4937fff3d421e2Lennart Poettering size_t l = 100;
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering
0370612e0522191f929e3feb7d4937fff3d421e2Lennart Poettering assert(fd >= 0);
0370612e0522191f929e3feb7d4937fff3d421e2Lennart Poettering assert(ret);
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering for (;;) {
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering char *c;
0370612e0522191f929e3feb7d4937fff3d421e2Lennart Poettering
2723b3b51d409340558e46e37e90525d4f880fe1Lennart Poettering c = new(char, l);
2723b3b51d409340558e46e37e90525d4f880fe1Lennart Poettering if (!c)
0370612e0522191f929e3feb7d4937fff3d421e2Lennart Poettering return -ENOMEM;
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering if (ptsname_r(fd, c, l) == 0) {
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering *ret = c;
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering return 0;
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering }
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering if (errno != ERANGE) {
0370612e0522191f929e3feb7d4937fff3d421e2Lennart Poettering free(c);
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering return -errno;
0370612e0522191f929e3feb7d4937fff3d421e2Lennart Poettering }
0370612e0522191f929e3feb7d4937fff3d421e2Lennart Poettering
0370612e0522191f929e3feb7d4937fff3d421e2Lennart Poettering free(c);
0370612e0522191f929e3feb7d4937fff3d421e2Lennart Poettering l *= 2;
0370612e0522191f929e3feb7d4937fff3d421e2Lennart Poettering }
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering}
0370612e0522191f929e3feb7d4937fff3d421e2Lennart Poettering
f2cbe59e113f08549949a76ac5b9b3972df4cc30Lennart Poetteringint ptsname_namespace(int pty, char **ret) {
f2cbe59e113f08549949a76ac5b9b3972df4cc30Lennart Poettering int no = -1, r;
f2cbe59e113f08549949a76ac5b9b3972df4cc30Lennart Poettering
f2cbe59e113f08549949a76ac5b9b3972df4cc30Lennart Poettering /* Like ptsname(), but doesn't assume that the path is
f2cbe59e113f08549949a76ac5b9b3972df4cc30Lennart Poettering * accessible in the local namespace. */
f2cbe59e113f08549949a76ac5b9b3972df4cc30Lennart Poettering
56159e0d918e9a9be07988133bb2847779325de0Lennart Poettering r = ioctl(pty, TIOCGPTN, &no);
90adaa25e894a580930ef2c3e65ab8db8295515aLennart Poettering if (r < 0)
56159e0d918e9a9be07988133bb2847779325de0Lennart Poettering return -errno;
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering if (no < 0)
56159e0d918e9a9be07988133bb2847779325de0Lennart Poettering return -EIO;
56159e0d918e9a9be07988133bb2847779325de0Lennart Poettering
2723b3b51d409340558e46e37e90525d4f880fe1Lennart Poettering if (asprintf(ret, "/dev/pts/%i", no) < 0)
2723b3b51d409340558e46e37e90525d4f880fe1Lennart Poettering return -ENOMEM;
90adaa25e894a580930ef2c3e65ab8db8295515aLennart Poettering
90adaa25e894a580930ef2c3e65ab8db8295515aLennart Poettering return 0;
90adaa25e894a580930ef2c3e65ab8db8295515aLennart Poettering}
90adaa25e894a580930ef2c3e65ab8db8295515aLennart Poettering
90adaa25e894a580930ef2c3e65ab8db8295515aLennart Poetteringint openpt_in_namespace(pid_t pid, int flags) {
90adaa25e894a580930ef2c3e65ab8db8295515aLennart Poettering _cleanup_close_ int pidnsfd = -1, mntnsfd = -1, usernsfd = -1, rootfd = -1;
90adaa25e894a580930ef2c3e65ab8db8295515aLennart Poettering _cleanup_close_pair_ int pair[2] = { -1, -1 };
90adaa25e894a580930ef2c3e65ab8db8295515aLennart Poettering siginfo_t si;
90adaa25e894a580930ef2c3e65ab8db8295515aLennart Poettering pid_t child;
90adaa25e894a580930ef2c3e65ab8db8295515aLennart Poettering int r;
90adaa25e894a580930ef2c3e65ab8db8295515aLennart Poettering
90adaa25e894a580930ef2c3e65ab8db8295515aLennart Poettering assert(pid > 0);
90adaa25e894a580930ef2c3e65ab8db8295515aLennart Poettering
90adaa25e894a580930ef2c3e65ab8db8295515aLennart Poettering r = namespace_open(pid, &pidnsfd, &mntnsfd, NULL, &usernsfd, &rootfd);
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering if (r < 0)
90adaa25e894a580930ef2c3e65ab8db8295515aLennart Poettering return r;
90adaa25e894a580930ef2c3e65ab8db8295515aLennart Poettering
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering if (socketpair(AF_UNIX, SOCK_DGRAM, 0, pair) < 0)
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering return -errno;
90adaa25e894a580930ef2c3e65ab8db8295515aLennart Poettering
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering child = fork();
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering if (child < 0)
190700621f95160d364f8ec1d3e360246c41ce75Lennart Poettering return -errno;
0ec5543c4c0318552a4dcdd83210793347b93081Lennart Poettering
0ec5543c4c0318552a4dcdd83210793347b93081Lennart Poettering if (child == 0) {
0ec5543c4c0318552a4dcdd83210793347b93081Lennart Poettering int master;
0ec5543c4c0318552a4dcdd83210793347b93081Lennart Poettering
0ec5543c4c0318552a4dcdd83210793347b93081Lennart Poettering pair[0] = safe_close(pair[0]);
0ec5543c4c0318552a4dcdd83210793347b93081Lennart Poettering
0ec5543c4c0318552a4dcdd83210793347b93081Lennart Poettering r = namespace_enter(pidnsfd, mntnsfd, -1, usernsfd, rootfd);
0ec5543c4c0318552a4dcdd83210793347b93081Lennart Poettering if (r < 0)
da054c3782f25b3b18243f6c76dcfcf90ba70274Lennart Poettering _exit(EXIT_FAILURE);
da054c3782f25b3b18243f6c76dcfcf90ba70274Lennart Poettering
0ec5543c4c0318552a4dcdd83210793347b93081Lennart Poettering master = posix_openpt(flags|O_NOCTTY|O_CLOEXEC);
da054c3782f25b3b18243f6c76dcfcf90ba70274Lennart Poettering if (master < 0)
0ec5543c4c0318552a4dcdd83210793347b93081Lennart Poettering _exit(EXIT_FAILURE);
0ec5543c4c0318552a4dcdd83210793347b93081Lennart Poettering
0ec5543c4c0318552a4dcdd83210793347b93081Lennart Poettering if (unlockpt(master) < 0)
da054c3782f25b3b18243f6c76dcfcf90ba70274Lennart Poettering _exit(EXIT_FAILURE);
0ec5543c4c0318552a4dcdd83210793347b93081Lennart Poettering
0ec5543c4c0318552a4dcdd83210793347b93081Lennart Poettering if (send_one_fd(pair[1], master, 0) < 0)
0ec5543c4c0318552a4dcdd83210793347b93081Lennart Poettering _exit(EXIT_FAILURE);
190700621f95160d364f8ec1d3e360246c41ce75Lennart Poettering
0ec5543c4c0318552a4dcdd83210793347b93081Lennart Poettering _exit(EXIT_SUCCESS);
0ec5543c4c0318552a4dcdd83210793347b93081Lennart Poettering }
0ec5543c4c0318552a4dcdd83210793347b93081Lennart Poettering
56159e0d918e9a9be07988133bb2847779325de0Lennart Poettering pair[1] = safe_close(pair[1]);
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering
2723b3b51d409340558e46e37e90525d4f880fe1Lennart Poettering r = wait_for_terminate(child, &si);
0ec5543c4c0318552a4dcdd83210793347b93081Lennart Poettering if (r < 0)
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering return r;
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering if (si.si_code != CLD_EXITED || si.si_status != EXIT_SUCCESS)
40205d706e1210763ff4c98a317556375bd04bcdLennart Poettering return -EIO;
56159e0d918e9a9be07988133bb2847779325de0Lennart Poettering
0ec5543c4c0318552a4dcdd83210793347b93081Lennart Poettering return receive_one_fd(pair[0], 0);
c7b7d4493aa03e9ef5fb1e670b8969a48aa494ddLennart Poettering}
0ec5543c4c0318552a4dcdd83210793347b93081Lennart Poettering
04d39279245834494baccfdb9349db8bf80abd13Lennart Poetteringint open_terminal_in_namespace(pid_t pid, const char *name, int mode) {
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering _cleanup_close_ int pidnsfd = -1, mntnsfd = -1, usernsfd = -1, rootfd = -1;
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering _cleanup_close_pair_ int pair[2] = { -1, -1 };
bf441e3d9371a7e5aa1def66cfc40f0118884644Lennart Poettering siginfo_t si;
de33fc625725d199629ed074d6278504deb23debLennart Poettering pid_t child;
923d8fd381bced1c2d90ca53d18629d61a0f454aLennart Poettering int r;
15411c0cb1192799b37ec8f25d6f30e8d7292fc6David Herrmann
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering r = namespace_open(pid, &pidnsfd, &mntnsfd, NULL, &usernsfd, &rootfd);
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering if (r < 0)
acf97e213e69a97e63ab8f7fad7ecd53608c757aLennart Poettering return r;
acf97e213e69a97e63ab8f7fad7ecd53608c757aLennart Poettering
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering if (socketpair(AF_UNIX, SOCK_DGRAM, 0, pair) < 0)
f647962d64e844689f3e2acfce6102fc47e76df2Michal Schmidt return -errno;
f647962d64e844689f3e2acfce6102fc47e76df2Michal Schmidt
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering child = fork();
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering if (child < 0)
f647962d64e844689f3e2acfce6102fc47e76df2Michal Schmidt return -errno;
f647962d64e844689f3e2acfce6102fc47e76df2Michal Schmidt
023fb90b83871a15ef7f57e8cd126e3426f99b9eLennart Poettering if (child == 0) {
63c372cb9df3bee01e3bf8cd7f96f336bddda846Lennart Poettering int master;
0ec5543c4c0318552a4dcdd83210793347b93081Lennart Poettering
0ec5543c4c0318552a4dcdd83210793347b93081Lennart Poettering pair[0] = safe_close(pair[0]);
0ec5543c4c0318552a4dcdd83210793347b93081Lennart Poettering
0ec5543c4c0318552a4dcdd83210793347b93081Lennart Poettering r = namespace_enter(pidnsfd, mntnsfd, -1, usernsfd, rootfd);
0ec5543c4c0318552a4dcdd83210793347b93081Lennart Poettering if (r < 0)
0ec5543c4c0318552a4dcdd83210793347b93081Lennart Poettering _exit(EXIT_FAILURE);
0ec5543c4c0318552a4dcdd83210793347b93081Lennart Poettering
0ec5543c4c0318552a4dcdd83210793347b93081Lennart Poettering master = open_terminal(name, mode|O_NOCTTY|O_CLOEXEC);
0ec5543c4c0318552a4dcdd83210793347b93081Lennart Poettering if (master < 0)
0ec5543c4c0318552a4dcdd83210793347b93081Lennart Poettering _exit(EXIT_FAILURE);
0ec5543c4c0318552a4dcdd83210793347b93081Lennart Poettering
0ec5543c4c0318552a4dcdd83210793347b93081Lennart Poettering if (send_one_fd(pair[1], master, 0) < 0)
2723b3b51d409340558e46e37e90525d4f880fe1Lennart Poettering _exit(EXIT_FAILURE);
2723b3b51d409340558e46e37e90525d4f880fe1Lennart Poettering
2723b3b51d409340558e46e37e90525d4f880fe1Lennart Poettering _exit(EXIT_SUCCESS);
2723b3b51d409340558e46e37e90525d4f880fe1Lennart Poettering }
2723b3b51d409340558e46e37e90525d4f880fe1Lennart Poettering
2723b3b51d409340558e46e37e90525d4f880fe1Lennart Poettering pair[1] = safe_close(pair[1]);
2723b3b51d409340558e46e37e90525d4f880fe1Lennart Poettering
2723b3b51d409340558e46e37e90525d4f880fe1Lennart Poettering r = wait_for_terminate(child, &si);
2723b3b51d409340558e46e37e90525d4f880fe1Lennart Poettering if (r < 0)
40205d706e1210763ff4c98a317556375bd04bcdLennart Poettering return r;
40205d706e1210763ff4c98a317556375bd04bcdLennart Poettering if (si.si_code != CLD_EXITED || si.si_status != EXIT_SUCCESS)
785890acf6d629ff881a1f065f431df1b7fc8c7aLennart Poettering return -EIO;
40205d706e1210763ff4c98a317556375bd04bcdLennart Poettering
04d39279245834494baccfdb9349db8bf80abd13Lennart Poettering return receive_one_fd(pair[0], 0);
40205d706e1210763ff4c98a317556375bd04bcdLennart Poettering}
40205d706e1210763ff4c98a317556375bd04bcdLennart Poettering