f7e20b2
From bc6e654149018090b7954e6667d3c7e7654625f6 Mon Sep 17 00:00:00 2001
f7e20b2
From: =?UTF-8?q?Dan=20Hor=C3=A1k?= <dan@danny.cz>
f7e20b2
Date: Fri, 28 Jan 2011 14:18:39 +0100
f7e20b2
Subject: [PATCH 53/61] ttyrun: run a program if a terminal device is available
f7e20b2
f7e20b2
Summary:     ttyrun: run a program if a terminal device is available
f7e20b2
Description: Depending on your setup, Linux on System z might or might not
f7e20b2
             provide a particular terminal or console. ttyrun safely starts
f7e20b2
             getty programs and prevents respawns through the init program
f7e20b2
             if a terminal is not available.
f7e20b2
---
f7e20b2
 iucvterm/doc/Makefile |    2 +-
f7e20b2
 iucvterm/doc/ttyrun.8 |  146 +++++++++++++++++++++++++++++++++++++++
f7e20b2
 iucvterm/src/Makefile |   11 +++-
f7e20b2
 iucvterm/src/ttyrun.c |  183 +++++++++++++++++++++++++++++++++++++++++++++++++
f7e20b2
 4 files changed, 339 insertions(+), 3 deletions(-)
f7e20b2
 create mode 100644 iucvterm/doc/ttyrun.8
f7e20b2
 create mode 100644 iucvterm/src/ttyrun.c
f7e20b2
f7e20b2
diff --git a/iucvterm/doc/Makefile b/iucvterm/doc/Makefile
f7e20b2
index 5815f21..a646765 100644
f7e20b2
--- a/iucvterm/doc/Makefile
f7e20b2
+++ b/iucvterm/doc/Makefile
f7e20b2
@@ -2,7 +2,7 @@
f7e20b2
 
f7e20b2
 include ../../common.mak
f7e20b2
 
f7e20b2
-MANS = iucvconn.1 iucvtty.1 ts-shell.1 hvc_iucv.9 chiucvallow.8
f7e20b2
+MANS = iucvconn.1 iucvtty.1 ts-shell.1 hvc_iucv.9 chiucvallow.8 ttyrun.8
f7e20b2
 
f7e20b2
 all:
f7e20b2
 
f7e20b2
diff --git a/iucvterm/doc/ttyrun.8 b/iucvterm/doc/ttyrun.8
f7e20b2
new file mode 100644
f7e20b2
index 0000000..fc7a16f
f7e20b2
--- /dev/null
f7e20b2
+++ b/iucvterm/doc/ttyrun.8
f7e20b2
@@ -0,0 +1,146 @@
f7e20b2
+.\" ttyrun.8
f7e20b2
+.\"
f7e20b2
+.\"
f7e20b2
+.\" Copyright IBM Corp. 2010
f7e20b2
+.\" Author(s): Hendrik Brueckner <brueckner@linux.vnet.ibm.com>
f7e20b2
+.\" -------------------------------------------------------------------------
f7e20b2
+.TH "ttyrun" "8" "April 2010" "s390-tools" "System Management Commands"
f7e20b2
+.LO 8
f7e20b2
+.
f7e20b2
+.ds s ttyrun
f7e20b2
+.
f7e20b2
+.
f7e20b2
+.SH NAME
f7e20b2
+ttyrun \- Start a program if a specified terminal device is available
f7e20b2
+.
f7e20b2
+.
f7e20b2
+.
f7e20b2
+.SH SYNOPSIS
f7e20b2
+.B \*s
f7e20b2
+.RB [ \-e | \-\-exitstatus
f7e20b2
+.IR status ]
f7e20b2
+.I term
f7e20b2
+.I program
f7e20b2
+.RI [ "program_options" ]
f7e20b2
+.br
f7e20b2
+.B \*s
f7e20b2
+.RB [ \-h | \-\-help ]
f7e20b2
+.br
f7e20b2
+.B \*s
f7e20b2
+.RB [ \-v | \-\-version ]
f7e20b2
+.
f7e20b2
+.
f7e20b2
+.
f7e20b2
+.SH DESCRIPTION
f7e20b2
+\fB\*s\fP is typically started during system initialization and is used
f7e20b2
+to prevent a respawn through the
f7e20b2
+.BR init (8)
f7e20b2
+program when a terminal is not available.
f7e20b2
+
f7e20b2
+\fIterm\fP is the name of the terminal device and is a path relative to
f7e20b2
+the \f(CW/dev\fP directory, for example, specify \f(CWhvc0\fP for
f7e20b2
+\f(CW/dev/hvc0\fP.
f7e20b2
+.br
f7e20b2
+If the specified terminal device can be opened, \fB\*s\fP starts the
f7e20b2
+specified program.
f7e20b2
+
f7e20b2
+If the terminal device cannot be opened, the behavior of \fB\*s\fP
f7e20b2
+depends on the \fB\-e\fP option:
f7e20b2
+.
f7e20b2
+.RS 2
f7e20b2
+.IP "\(bu" 2
f7e20b2
+If the \fB\-e\fP option has been specified, \fB\*s\fP exits with the
f7e20b2
+specified return value, or
f7e20b2
+.IP "\(bu" 2
f7e20b2
+If the \fB\-e\fP option has not been specified,  \fB\*s\fP sleeps until
f7e20b2
+it receives a signal that causes an exit.
f7e20b2
+.RE
f7e20b2
+.PP
f7e20b2
+\fIprogram\fP is an absolute path to the program to be started by
f7e20b2
+\fB\*s\fP and \fIprogram_options\fP specify additional arguments.
f7e20b2
+Depending on the program, arguments might be required.  The variable
f7e20b2
+\f(CW%t\fP in the \fIprogram_options\fP is resolved to the terminal
f7e20b2
+device specified with \fIterm\fP.
f7e20b2
+.
f7e20b2
+.
f7e20b2
+.
f7e20b2
+.SH OPTIONS
f7e20b2
+.TP
f7e20b2
+.BR \-e ", " \-\-exitstatus\~\fIstatus\fP
f7e20b2
+Specifies an exit status that is returned when the terminal device
f7e20b2
+is not available.  \fIstatus\fP must be an integer in the range 1 to 255.
f7e20b2
+
f7e20b2
+You can use this status value in an upstart job file to prevent
f7e20b2
+respawning.
f7e20b2
+.
f7e20b2
+.TP
f7e20b2
+.BR \-h ", " \-\-help
f7e20b2
+Displays a short help text, then exits.
f7e20b2
+.
f7e20b2
+.TP
f7e20b2
+.BR \-v ", " \-\-version
f7e20b2
+Displays the version number of \fB\*s\fP, then exits.
f7e20b2
+.
f7e20b2
+.
f7e20b2
+.
f7e20b2
+.SH "RETURN VALUES"
f7e20b2
+\fB\*s\fP exits with one of the following return values to report an
f7e20b2
+error condition:
f7e20b2
+.TP
f7e20b2
+.B 1
f7e20b2
+\fB\*s\fP has been started with an argument that is not valid or
f7e20b2
+required but missing.
f7e20b2
+.TP
f7e20b2
+.B 2
f7e20b2
+\fB\*s\fP could open the file specified for \fIterm\fP but the
f7e20b2
+file is not a terminal device.
f7e20b2
+.TP
f7e20b2
+.B 3
f7e20b2
+\fB\*s\fP could not start the specified program.
f7e20b2
+.PP
f7e20b2
+The return values 1 to 3 might also be returned when the \fB\-e\fP
f7e20b2
+option is used and the terminal device is not available.
f7e20b2
+.TP
f7e20b2
+.B 4 \- 255
f7e20b2
+The terminal device is not available and the \fB\-e\fP option
f7e20b2
+specifies an exit status in this range.
f7e20b2
+.
f7e20b2
+.
f7e20b2
+.
f7e20b2
+.SH "EXAMPLES"
f7e20b2
+.SS inittab
f7e20b2
+To start \fB/sbin/agetty\fP on terminal device "hvc1", specify:
f7e20b2
+.PP
f7e20b2
+.ft CW
f7e20b2
+.in +0.25in
f7e20b2
+.nf
f7e20b2
+h1:2345:respawn:/sbin/\*s hvc1 /sbin/agetty -L 9600 %t linux
f7e20b2
+.fi
f7e20b2
+.in -0.25in
f7e20b2
+.ft
f7e20b2
+.
f7e20b2
+.SS upstart job/event files
f7e20b2
+To start \fB/sbin/agetty\fP on terminal device "hvc1", add the following
f7e20b2
+settings to the job file:
f7e20b2
+.PP
f7e20b2
+.ft CW
f7e20b2
+.in +0.25in
f7e20b2
+.nf
f7e20b2
+respawn
f7e20b2
+normal exit 42
f7e20b2
+exec /sbin/\*s -e 42 hvc1 /sbin/agetty -L 9600 %t linux
f7e20b2
+.fi
f7e20b2
+.in -0.25in
f7e20b2
+.ft
f7e20b2
+.PP
f7e20b2
+With the normal exit statement, you specify an exit status that will
f7e20b2
+prevent upstart from respawning the program.  To prevent respawning with
f7e20b2
+\fB\*s\fP, you must specify the same value for the \fB\-e\fP option.
f7e20b2
+.
f7e20b2
+.
f7e20b2
+.
f7e20b2
+.SH "SEE ALSO"
f7e20b2
+.BR agetty (8),
f7e20b2
+.BR mingetty (8),
f7e20b2
+.BR inittab (5),
f7e20b2
+.BR events (5)
f7e20b2
diff --git a/iucvterm/src/Makefile b/iucvterm/src/Makefile
f7e20b2
index f1f8f7c..369c887 100644
f7e20b2
--- a/iucvterm/src/Makefile
f7e20b2
+++ b/iucvterm/src/Makefile
f7e20b2
@@ -11,20 +11,27 @@ CPPFLAGS += -DUSE_NLS -DGETTEXT_TEXTDOMAIN=\"$(GETTEXT_TEXTDOMAIN)\"
f7e20b2
 #CPPFLAGS += -D__DEBUG__
f7e20b2
 
f7e20b2
 PROGRAMS = iucvconn iucvtty
f7e20b2
+SYSTOOLS = ttyrun
f7e20b2
 
f7e20b2
-all: $(PROGRAMS)
f7e20b2
+all: $(PROGRAMS) $(SYSTOOLS)
f7e20b2
 check:
f7e20b2
 install:
f7e20b2
 	for prg in $(PROGRAMS); do \
f7e20b2
 	  $(INSTALL) -g $(GROUP) -o $(OWNER) -m 755 $$prg $(USRBINDIR) ; \
f7e20b2
 	done
f7e20b2
+	for prg in $(SYSTOOLS); do \
f7e20b2
+	  $(INSTALL) -g $(GROUP) -o $(OWNER) -m 755 $$prg $(BINDIR) ; \
f7e20b2
+	done
f7e20b2
 
f7e20b2
 clean:
f7e20b2
-	-rm -f *.o $(PROGRAMS)
f7e20b2
+	-rm -f *.o $(PROGRAMS) $(SYSTOOLS)
f7e20b2
 
f7e20b2
 iucvconn: iucvconn.o getopt.o auditlog.o functions.o
f7e20b2
 
f7e20b2
 iucvtty: LDLIBS = -lutil
f7e20b2
 iucvtty: iucvtty.o getopt.o auditlog.o functions.o
f7e20b2
 
f7e20b2
+ttyrun: GETTEXT_TEXTDOMAIN = ttyrun
f7e20b2
+ttyrun: ttyrun.o
f7e20b2
+
f7e20b2
 .PHONY: install clean
f7e20b2
diff --git a/iucvterm/src/ttyrun.c b/iucvterm/src/ttyrun.c
f7e20b2
new file mode 100644
f7e20b2
index 0000000..55c2bc2
f7e20b2
--- /dev/null
f7e20b2
+++ b/iucvterm/src/ttyrun.c
f7e20b2
@@ -0,0 +1,183 @@
f7e20b2
+/*
f7e20b2
+ * ttyrun - Start a program if a specified terminal device is available
f7e20b2
+ *
f7e20b2
+ *
f7e20b2
+ * ttyrun is typically used to prevent a respawn through the init(8)
f7e20b2
+ * program when a terminal is not available.
f7e20b2
+ * ttyrun runs the specific program if the specified terminal device
f7e20b2
+ * can be opened successfully.  Otherwise the program enters a sleep or
f7e20b2
+ * exits with a specified return value.
f7e20b2
+ *
f7e20b2
+ * Example: To start /sbin/agetty on terminal device hvc1, use:
f7e20b2
+ *
f7e20b2
+ *	 h1:2345:respawn:/sbin/ttyrun hvc1 /sbin/agetty -L 9600 %t linux
f7e20b2
+ *
f7e20b2
+ * Note: %t is resolved to the terminal device "hvc1" before /sbin/agetty
f7e20b2
+ *	 is started.
f7e20b2
+ *
f7e20b2
+ * Return values:
f7e20b2
+ *	   1 - invalid argument or parameter is missing
f7e20b2
+ *	   2 - terminal does not resolve to a terminal device
f7e20b2
+ *	   3 - starting the specified program failed
f7e20b2
+ *    1..255 - terminal is not available and the return code is
f7e20b2
+ *	       specified with the -e option
f7e20b2
+ *
f7e20b2
+ * Copyright IBM Corp. 2010
f7e20b2
+ * Author(s): Hendrik Brueckner <brueckner@linux.vnet.ibm.com>
f7e20b2
+ */
f7e20b2
+#include <errno.h>
f7e20b2
+#include <getopt.h>
f7e20b2
+#include <limits.h>
f7e20b2
+#include <signal.h>
f7e20b2
+#include <stdlib.h>
f7e20b2
+#include <stdio.h>
f7e20b2
+#include <string.h>
f7e20b2
+#include <sys/types.h>
f7e20b2
+#include <syslog.h>
f7e20b2
+#include <fcntl.h>
f7e20b2
+#include <unistd.h>
f7e20b2
+
f7e20b2
+#include "zt_common.h"
f7e20b2
+
f7e20b2
+
f7e20b2
+#define TTY_ESCAPE_STR		"%t"
f7e20b2
+
f7e20b2
+#define EXIT_INVALID_ARG	1
f7e20b2
+#define EXIT_NO_TERMINAL	2
f7e20b2
+#define EXIT_EXEC_FAILED	3
f7e20b2
+
f7e20b2
+
f7e20b2
+static const char usage[] =
f7e20b2
+"Usage: %s [-e status] <term> <program> [<program_options>]\n"
f7e20b2
+"       %s [-h|--help] [-v|--version]\n"
f7e20b2
+"\n"
f7e20b2
+"Start the program if the specified terminal device is available.\n"
f7e20b2
+"If the terminal device cannot be opened, sleep until a signal is received\n"
f7e20b2
+"that causes an exit or exit with the return value specified with status.\n"
f7e20b2
+"\n"
f7e20b2
+"-e, --exitstatus     Specifies an exit status in the range 1 to 255.\n"
f7e20b2
+"-h, --help           Displays this help, then exits.\n"
f7e20b2
+"-v, --version        Displays version information, then exits.\n";
f7e20b2
+
f7e20b2
+static void help_exit(const char *prg)
f7e20b2
+{
f7e20b2
+	printf(usage, prg, prg);
f7e20b2
+	exit(EXIT_SUCCESS);
f7e20b2
+}
f7e20b2
+
f7e20b2
+static void version_exit(const char *prg)
f7e20b2
+{
f7e20b2
+	printf("%s: Start a program if a terminal device is available, "
f7e20b2
+	       "version %s\n", prg, RELEASE_STRING);
f7e20b2
+	printf("Copyright IBM Corp. 2010\n");
f7e20b2
+	exit(EXIT_SUCCESS);
f7e20b2
+}
f7e20b2
+
f7e20b2
+static void err_exit(const char *prg, const char *msg)
f7e20b2
+{
f7e20b2
+	fprintf(stderr, "%s: %s\n", prg, msg);
f7e20b2
+	exit(EXIT_INVALID_ARG);
f7e20b2
+}
f7e20b2
+
f7e20b2
+static void wait_and_exit(void)
f7e20b2
+{
f7e20b2
+	/* sleep until a signal is received, then exit */
f7e20b2
+	pause();
f7e20b2
+	exit(EXIT_SUCCESS);
f7e20b2
+}
f7e20b2
+
f7e20b2
+static const struct option prog_opts[] = {
f7e20b2
+	{ "help",	no_argument, NULL, 'h'},
f7e20b2
+	{ "version",	no_argument, NULL, 'v'},
f7e20b2
+	{ "exitstatus",	required_argument, NULL, 'e'},
f7e20b2
+	{ NULL,		no_argument, NULL,  0 },
f7e20b2
+};
f7e20b2
+
f7e20b2
+int main(int argc, char *argv[])
f7e20b2
+{
f7e20b2
+	int rc, tty, i, c, index, done, term_index;
f7e20b2
+	char terminal[PATH_MAX] = "";
f7e20b2
+	unsigned long exitstatus;
f7e20b2
+
f7e20b2
+
f7e20b2
+	/* parse command options */
f7e20b2
+	if (argc == 1)
f7e20b2
+		err_exit(argv[0], "One or more options are required but missing");
f7e20b2
+
f7e20b2
+	exitstatus = done = term_index = 0;
f7e20b2
+	while (!done) {
f7e20b2
+		c = getopt_long(argc, argv, "-hve:", prog_opts, NULL);
f7e20b2
+		switch (c) {
f7e20b2
+		case -1:
f7e20b2
+			done = 1;
f7e20b2
+			break;
f7e20b2
+		case 1:
f7e20b2
+			/* the first non-optional argument must be the
f7e20b2
+			 * terminal device */
f7e20b2
+			if (!strncmp(optarg, "/", 1))
f7e20b2
+				strncpy(terminal, optarg, PATH_MAX - 1);
f7e20b2
+			else
f7e20b2
+				snprintf(terminal, PATH_MAX, "/dev/%s", optarg);
f7e20b2
+			terminal[PATH_MAX - 1] = 0;
f7e20b2
+			term_index = optind - 1;
f7e20b2
+			done = 1;
f7e20b2
+			break;
f7e20b2
+		case 'e':
f7e20b2
+			errno = 0;
f7e20b2
+			exitstatus = strtoul(optarg, (char **) NULL, 10);
f7e20b2
+			if (errno == ERANGE)
f7e20b2
+				err_exit(argv[0], "The exit status must be "
f7e20b2
+					"an integer in the range 1 to 255");
f7e20b2
+
f7e20b2
+			if (!exitstatus || exitstatus > 255)
f7e20b2
+				err_exit(argv[0], "The exit status must be "
f7e20b2
+					 "in the range 1 to 255");
f7e20b2
+			break;
f7e20b2
+		case 'h':
f7e20b2
+			help_exit(argv[0]);
f7e20b2
+		case 'v':
f7e20b2
+			version_exit(argv[0]);
f7e20b2
+		case '?':
f7e20b2
+			fprintf(stderr, "Try %s --help for more information\n",
f7e20b2
+				argv[0]);
f7e20b2
+			exit(EXIT_INVALID_ARG);
f7e20b2
+		}
f7e20b2
+	}
f7e20b2
+	index = optind;
f7e20b2
+
f7e20b2
+	/* check terminal */
f7e20b2
+	if (!strlen(terminal))
f7e20b2
+		err_exit(argv[0], "You must specify the name of "
f7e20b2
+				  "a terminal device");
f7e20b2
+
f7e20b2
+	/* any program to start? */
f7e20b2
+	if (index == argc)
f7e20b2
+		err_exit(argv[0], "You must specify a program to start");
f7e20b2
+
f7e20b2
+	/* open and check terminal device */
f7e20b2
+	tty = open(terminal, O_NOCTTY | O_RDONLY | O_NONBLOCK);
f7e20b2
+	if (tty == -1) {
f7e20b2
+		openlog(argv[0], LOG_PID, LOG_DAEMON);
f7e20b2
+		syslog(LOG_INFO, "Could not open tty %s (%s)", terminal,
f7e20b2
+		       strerror(errno));
f7e20b2
+		closelog();
f7e20b2
+
f7e20b2
+		/* enter wait or exit */
f7e20b2
+		if (exitstatus)
f7e20b2
+			exit(exitstatus);
f7e20b2
+		wait_and_exit();
f7e20b2
+	}
f7e20b2
+	rc = !isatty(tty);
f7e20b2
+	close(tty);
f7e20b2
+	if (rc)
f7e20b2
+		exit(EXIT_NO_TERMINAL);
f7e20b2
+
f7e20b2
+	/* start getty program */
f7e20b2
+	for (i = index; i < argc; i++)
f7e20b2
+		if (!strcmp(argv[i], TTY_ESCAPE_STR) && term_index)
f7e20b2
+			argv[i] = argv[term_index];
f7e20b2
+	if (execv(argv[index], argv + index))
f7e20b2
+		exit(EXIT_EXEC_FAILED);
f7e20b2
+
f7e20b2
+	exit(EXIT_SUCCESS);
f7e20b2
+}
f7e20b2
-- 
f7e20b2
1.7.3.5
f7e20b2