Systemd/src/getty-generator/getty-generator.c

233 lines
7.1 KiB
C
Raw Normal View History

/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
/***
This file is part of systemd.
Copyright 2010 Lennart Poettering
systemd is free software; you can redistribute it and/or modify it
under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 2.1 of the License, or
(at your option) any later version.
systemd is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <fcntl.h>
#include "log.h"
#include "util.h"
#include "mkdir.h"
#include "unit-name.h"
2011-09-23 17:20:45 +02:00
#include "virt.h"
#include "fileio.h"
#include "path-util.h"
2015-04-10 19:10:00 +02:00
#include "process-util.h"
2015-04-10 23:15:59 +02:00
#include "terminal-util.h"
2012-02-29 14:42:49 +01:00
static const char *arg_dest = "/tmp";
static int add_symlink(const char *fservice, const char *tservice) {
char *from, *to;
int r;
assert(fservice);
assert(tservice);
from = strjoina(SYSTEM_DATA_UNIT_PATH "/", fservice);
to = strjoina(arg_dest, "/getty.target.wants/", tservice);
mkdir_parents_label(to, 0755);
r = symlink(from, to);
if (r < 0) {
/* In case console=hvc0 is passed this will very likely result in EEXIST */
if (errno == EEXIST)
2013-10-30 20:19:22 +01:00
return 0;
return log_error_errno(errno, "Failed to create symlink %s: %m", to);
}
2013-10-30 20:19:22 +01:00
return 0;
}
static int add_serial_getty(const char *tty) {
2013-10-30 20:19:22 +01:00
_cleanup_free_ char *n = NULL;
int r;
assert(tty);
log_debug("Automatically adding serial getty for /dev/%s.", tty);
r = unit_name_from_path_instance("serial-getty", tty, ".service", &n);
if (r < 0)
return log_error_errno(r, "Failed to generate service name: %m");
2013-10-30 20:19:22 +01:00
return add_symlink("serial-getty@.service", n);
}
static int add_container_getty(const char *tty) {
_cleanup_free_ char *n = NULL;
int r;
assert(tty);
log_debug("Automatically adding container getty for /dev/pts/%s.", tty);
r = unit_name_from_path_instance("container-getty", tty, ".service", &n);
if (r < 0)
return log_error_errno(r, "Failed to generate service name: %m");
return add_symlink("container-getty@.service", n);
}
static int verify_tty(const char *name) {
_cleanup_close_ int fd = -1;
const char *p;
/* Some TTYs are weird and have been enumerated but don't work
* when you try to use them, such as classic ttyS0 and
* friends. Let's check that and open the device and run
* isatty() on it. */
p = strjoina("/dev/", name);
/* O_NONBLOCK is essential here, to make sure we don't wait
* for DCD */
fd = open(p, O_RDWR|O_NONBLOCK|O_NOCTTY|O_CLOEXEC|O_NOFOLLOW);
if (fd < 0)
return -errno;
errno = 0;
if (isatty(fd) <= 0)
return errno ? -errno : -EIO;
return 0;
}
int main(int argc, char *argv[]) {
static const char virtualization_consoles[] =
"hvc0\0"
"xvc0\0"
"hvsi0\0"
"sclp_line0\0"
getty: Start getty on 3270 terminals available on Linux on System z Add the first 3270 terminal device that is associated with the Linux preferred console to the list of virtualization consoles. This is required to automatically start a getty if the conmode=3270 kernel parameter is specified for Linux on z/VM instances. Note that a queued upstream patch also enable the 3270 terminal device if it is associated with the Linux preferred console. How To successfully start agetty on a 3270 terminal, a change in the agetty parameter order is required. Previously, agetty would started like this: /sbin/agetty --keep-baud 3270/tty1 115200,38400,9600 TERM The agetty program interprets the "3270/tty1" as baud rate and fails to start with the "bad speed: 3270/tty1" error message. Fixing this in agetty is more complex rather than reordering the command line parameters like this: /sbin/agetty --keep-baud 115200,38400,9600 3270/tty1 TERM According to agetty sources and "agetty --help", agetty accepts the "tty", "baudrate tty", and "tty baudrate" specifications. P.S. The "tty: Set correct tty name in 'active' sysfs attribute" introduces a change to display the terminal device which is associated with the Linux preferred console. This change helps to let systemd handle this particular case only. Without the changes of this commit, no additional 3270 terminal device can be managed by systemd. https://git.kernel.org/cgit/linux/kernel/git/gregkh/tty.git/commit/?id=723abd87f6e536f1353c8f64f621520bc29523a3
2014-03-11 18:41:09 +01:00
"ttysclp0\0"
"3270!tty1\0";
2013-10-30 20:19:22 +01:00
_cleanup_free_ char *active = NULL;
const char *j;
int r;
if (argc > 1 && argc != 4) {
log_error("This program takes three or no arguments.");
return EXIT_FAILURE;
}
if (argc > 1)
arg_dest = argv[1];
log_set_target(LOG_TARGET_SAFE);
log_parse_environment();
log_open();
umask(0022);
if (detect_container(NULL) > 0) {
_cleanup_free_ char *container_ttys = NULL;
2011-08-24 23:29:28 +02:00
log_debug("Automatically adding console shell.");
if (add_symlink("console-getty.service", "console-getty.service") < 0)
2013-10-30 20:19:22 +01:00
return EXIT_FAILURE;
/* When $container_ttys is set for PID 1, spawn
* gettys on all ptys named therein. Note that despite
* the variable name we only support ptys here. */
r = getenv_for_pid(1, "container_ttys", &container_ttys);
if (r > 0) {
const char *word, *state;
size_t l;
FOREACH_WORD(word, l, container_ttys, state) {
const char *t;
char tty[l + 1];
memcpy(tty, word, l);
tty[l] = 0;
/* First strip off /dev/ if it is specified */
t = path_startswith(tty, "/dev/");
if (!t)
t = tty;
/* Then, make sure it's actually a pty */
2013-12-13 23:21:35 +01:00
t = path_startswith(t, "pts/");
if (!t)
continue;
if (add_container_getty(t) < 0)
return EXIT_FAILURE;
}
}
/* Don't add any further magic if we are in a container */
2013-10-30 20:19:22 +01:00
return EXIT_SUCCESS;
}
if (read_one_line_file("/sys/class/tty/console/active", &active) >= 0) {
const char *word, *state;
size_t l;
/* Automatically add in a serial getty on all active
* kernel consoles */
FOREACH_WORD(word, l, active, state) {
2013-10-30 20:19:22 +01:00
_cleanup_free_ char *tty = NULL;
tty = strndup(word, l);
if (!tty) {
2013-10-30 20:19:22 +01:00
log_oom();
return EXIT_FAILURE;
}
2013-10-30 20:19:22 +01:00
if (isempty(tty) || tty_is_vc(tty))
continue;
if (verify_tty(tty) < 0)
continue;
/* We assume that gettys on virtual terminals are
* started via manual configuration and do this magic
* only for non-VC terminals. */
2013-10-30 20:19:22 +01:00
if (add_serial_getty(tty) < 0)
return EXIT_FAILURE;
}
}
/* Automatically add in a serial getty on the first
* virtualizer console */
NULSTR_FOREACH(j, virtualization_consoles) {
char *p;
p = strjoina("/sys/class/tty/", j);
2013-10-30 20:19:22 +01:00
if (access(p, F_OK) < 0)
continue;
2013-10-30 20:19:22 +01:00
if (add_serial_getty(j) < 0)
return EXIT_FAILURE;
}
2013-10-30 20:19:22 +01:00
return EXIT_SUCCESS;
}