[RFC PATCH] sgetty: Smart serial console getty

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Very often when I was switching from Xen to Linux I was forced
to change /etc/inittab to make serial console working. It was
boring so I thought how to solve that problem. I was not able
to find sensible solution. So I decided to write something.
Here it is.

I posted this patch earlier to Xen-devel list but Ian Campbell
stated that it is more generic and maybe I should try to include
this in util-linux. I am posting sgetty here with minor changes.
Maybe this solution should be merged with agetty but I am not
sure right now. If you think that it is good idea then
I will do that.

Anyway, I am looking for your comments.

I am not subscribed to util-linux list so please
include my email address in your reply.

Signed-off-by: Daniel Kiper <daniel.kiper@xxxxxxxxxx>
---
 term-utils/Makemodule.am |    2 +
 term-utils/sgetty.c      |  243 ++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 245 insertions(+)
 create mode 100644 term-utils/sgetty.c

diff --git a/term-utils/Makemodule.am b/term-utils/Makemodule.am
index e53471f..e9055fc 100644
--- a/term-utils/Makemodule.am
+++ b/term-utils/Makemodule.am
@@ -21,6 +21,8 @@ sbin_PROGRAMS += agetty
 dist_man_MANS += term-utils/agetty.8
 agetty_SOURCES = term-utils/agetty.c
 agetty_LDADD = $(LDADD) libcommon.la
+sbin_PROGRAMS += sgetty
+sgetty_SOURCES = term-utils/sgetty.c
 endif # BUILD_AGETTY
 
 
diff --git a/term-utils/sgetty.c b/term-utils/sgetty.c
new file mode 100644
index 0000000..2bd3500
--- /dev/null
+++ b/term-utils/sgetty.c
@@ -0,0 +1,243 @@
+/*
+ * Copyright (c) 2013 Daniel Kiper, Oracle Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <errno.h>
+#include <libgen.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <syslog.h>
+#include <unistd.h>
+
+#define BOOT_CMDLINE	"/proc/cmdline"
+
+#define GETTY		"/sbin/getty"
+
+static char *sgetty_file = "sgetty";
+
+static char *opt_b = NULL;
+static int opt_c = 1;
+static char *opt_g = GETTY;
+static char *opt_t = NULL;
+
+static void usage(int status)
+{
+	FILE *stream;
+
+	stream = (status == EXIT_SUCCESS) ? stdout : stderr;
+
+	fprintf(stream, "\nsgetty Ver. 1.0.0\n\n"
+			"sgetty establishes serial console name from system boot command\n"
+			"line (%s) and then runs getty. This is very useful if e.g.\n"
+			"someone switches very often between Linux and Xen and uses serial\n"
+			"console. sgetty does boring things and runs getty on relevant line.\n"
+			"This way nobody needs to worry about /etc/inittab changes anymore.\n\n"
+			"Usage: sgetty [<options>] [-- [<getty_options>]]\n\n"
+			"Options:\n"
+			"  -b <baud_rate> - baud rate (required),\n"
+			"  -c <console> - serial console number in system boot\n"
+			"                 command line (default: 1),\n"
+			"  -g <getty> - path to getty (default: %s),\n"
+			"  -h - display this help,\n"
+			"  -t <term> - terminal type.\n\n"
+			"<getty_options> are passed without any changes to getty.\n\n"
+			"Warning: do not pass a line name, baud rate and terminal type\n"
+			"in <getty_options>. The line name is established by sgetty.\n"
+			"Baud rate and terminal type (if needed) must be\n"
+			"passed via relevant sgetty options.\n\n"
+			"sgetty takes into account and counts console arguments with ttyS*,\n"
+			"hvc* and xvc* only in system boot command line.\n\n"
+			"Example: sgetty -g /sbin/agetty -b 115200 -c 2 -- -i\n\n",
+			BOOT_CMDLINE, GETTY);
+	exit(status);
+}
+
+static void do_log(int priority, const char *format, ...)
+{
+	va_list ap;
+
+	va_start(ap, format);
+
+	openlog(sgetty_file, LOG_PID, LOG_AUTHPRIV);
+	vsyslog(priority, format, ap);
+	closelog();
+
+	va_end(ap);
+}
+
+static void init(int argc, char *const argv[])
+{
+	char *endptr, *s;
+	int c;
+
+	s = basename(argv[0]);
+
+	if (strcmp(s, ".") && strcmp(s, "/"))
+		sgetty_file = s;
+
+	opterr = 0;
+
+	while ((c = getopt(argc, argv, "+b:c:g:ht:")) != -1)
+		switch (c) {
+			case 'b':
+				opt_b = optarg;
+				break;
+
+			case 'c':
+				errno = 0;
+				opt_c = strtol(optarg, &endptr, 10);
+
+				if (errno || *endptr || opt_c < 1) {
+					fprintf(stderr, "Wrong serial console number\n");
+					do_log(LOG_WARNING, "Wrong serial console number");
+					usage(EXIT_FAILURE);
+				}
+
+				break;
+
+			case 'g':
+				opt_g = optarg;
+				break;
+
+			case 'h':
+				usage(EXIT_SUCCESS);
+
+			case 't':
+				opt_t = optarg;
+				break;
+
+			default:
+				fprintf(stderr, "Wrong arguments\n");
+				do_log(LOG_WARNING, "Wrong arguments");
+				usage(EXIT_FAILURE);
+		}
+
+	if (!opt_b) {
+		fprintf(stderr, "Baud rate is not specified\n");
+		do_log(LOG_ERR, "Baud rate is not specified");
+		usage(EXIT_FAILURE);
+	}
+}
+
+static char *get_console_name(void)
+{
+	FILE *stream;
+	char *boot_cmdline = NULL, *tok;
+	int i = 1;
+	size_t n;
+	ssize_t rc;
+
+	stream = fopen(BOOT_CMDLINE, "r");
+
+	if (!stream) {
+		do_log(LOG_ERR, "Cannot open file: %s: %m", BOOT_CMDLINE);
+		exit(EXIT_FAILURE);
+	}
+
+	rc = getline(&boot_cmdline, &n, stream);
+
+	if (rc == -1) {
+		do_log(LOG_ERR, "Cannot read file: %s: %m", BOOT_CMDLINE);
+		exit(EXIT_FAILURE);
+	}
+
+	fclose(stream);
+
+	tok = strtok(boot_cmdline, " \n\r\t");
+
+	while (tok) {
+		if (strstr(tok, "console=ttyS") == tok ||
+		    strstr(tok, "console=hvc") == tok ||
+		    strstr(tok, "console=xvc") == tok) {
+			if (i == opt_c) {
+				tok += strlen("console=");
+				return strtok(tok, ", \n\r\t");
+			}
+
+			if (++i > opt_c)
+				return NULL;
+		}
+
+		tok = strtok(NULL, " \n\r\t");
+	}
+
+	return NULL;
+}
+
+static void exec_getty(int argc, char *const argv[], char *console)
+{
+	char **g_argv;
+	/* Path to getty, console name, baud rate and final NULL. */
+	int g_argc = 4;
+	int i = 0, j = optind;
+
+	if (!console) {
+		do_log(LOG_INFO, "Serial console not found. Nothing to do. "
+				 "I am going sleep... Yawn...");
+		sleep(86400); /* Sleep one day... */
+		exit(EXIT_SUCCESS);
+	}
+
+	/* How many plain getty options do we have? */
+	g_argc += argc - optind;
+
+	/* Add space for terminal type if needed. */
+	if (opt_t)
+		++g_argc;
+
+	g_argv = calloc(g_argc, sizeof(char *));
+
+	if (!g_argv) {
+		do_log(LOG_ERR, "Cannot allocate memory for getty args: %m");
+		exit(EXIT_FAILURE);
+	}
+
+	/* Path to getty. */
+	g_argv[i++] = opt_g;
+
+	/* Plain options to getty. */
+	while (j < argc)
+		g_argv[i++] = argv[j++];
+
+	/* Console name. */
+	g_argv[i++] = console;
+
+	/* Baud rate. */
+	g_argv[i++] = opt_b;
+
+	/* Terminal type if available. */
+	if (opt_t)
+		g_argv[i] = opt_t;
+
+	/* Run getty. */
+	execv(opt_g, g_argv);
+
+	/* Ugh... Something went wrong... Dying... */
+	do_log(LOG_ERR, "Cannot execute %s: %m", opt_g);
+}
+
+int main(int argc, char *const argv[])
+{
+	char *console;
+
+	init(argc, argv);
+	console = get_console_name();
+	exec_getty(argc, argv, console);
+
+	return EXIT_FAILURE;
+}
-- 
1.7.10.4

--
To unsubscribe from this list: send the line "unsubscribe util-linux" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html




[Index of Archives]     [Netdev]     [Ethernet Bridging]     [Linux Wireless]     [Kernel Newbies]     [Security]     [Linux for Hams]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux RAID]     [Linux Admin]     [Samba]

  Powered by Linux