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

[Xen-devel] [RFC PATCH] sgetty: Smart serial console getty



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


_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxx
http://lists.xen.org/xen-devel


 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.