411 lines
11 KiB
Diff
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
|
|
|