s390utils/0053-ttyrun-run-a-program-i...

411 lines
11 KiB
Diff

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