* busyboxed by Quy Tonthat <quy@signal3.com>
* hacked by Tito <farmatito@tiscali.it>
*
- * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ * Licensed under GPLv2 or later, see file LICENSE in this source tree.
*/
+//config:config OPENVT
+//config: bool "openvt (7 kb)"
+//config: default y
+//config: select PLATFORM_LINUX
+//config: help
+//config: This program is used to start a command on an unused
+//config: virtual terminal.
+
+//applet:IF_OPENVT(APPLET(openvt, BB_DIR_USR_BIN, BB_SUID_DROP))
+
+//kbuild:lib-$(CONFIG_OPENVT) += openvt.o
+
+//usage:#define openvt_trivial_usage
+//usage: "[-c N] [-sw] [PROG ARGS]"
+//usage:#define openvt_full_usage "\n\n"
+//usage: "Start PROG on a new virtual terminal\n"
+//usage: "\n -c N Use specified VT"
+//usage: "\n -s Switch to the VT"
+/* //usage: "\n -l Run PROG as login shell (by prepending '-')" */
+//usage: "\n -w Wait for PROG to exit"
+//usage:
+//usage:#define openvt_example_usage
+//usage: "openvt 2 /bin/ash\n"
#include <linux/vt.h>
#include "libbb.h"
/* Do we, by chance, already have it? */
for (fd = 0; fd < 3; fd++)
if (!not_vt_fd(fd))
- return fd;
- /* _only_ O_NONBLOCK: ask for neither read not write perms */
- fd = open(DEV_CONSOLE, O_NONBLOCK);
+ return fd;
+ fd = open(DEV_CONSOLE, O_RDONLY | O_NONBLOCK);
if (fd >= 0 && !not_vt_fd(fd))
return fd;
bb_error_msg_and_die("can't find open VT");
int vtno;
int fd = get_vt_fd();
- errno = 0;
+ errno = 0;
/*xfunc_error_retval = 3; - do we need compat? */
if (ioctl(fd, VT_OPENQRY, &vtno) != 0 || vtno <= 0)
bb_perror_msg_and_die("can't find open VT");
-// Not really needed, grep for DAEMON_ONLY_SANITIZE
+// Not really needed, grep for DAEMON_CLOSE_EXTRA_FDS
// if (fd > 2)
// close(fd);
return vtno;
/* CHILD */
/* Try to make this VT our controlling tty */
setsid(); /* lose old ctty */
- ioctl(0, TIOCSCTTY, 0 /* 0: don't forcibly steal */);
+ ioctl(STDIN_FILENO, TIOCSCTTY, 0 /* 0: don't forcibly steal */);
//bb_error_msg("our sid %d", getsid(0));
//bb_error_msg("our pgrp %d", getpgrp());
//bb_error_msg("VT's sid %d", tcgetsid(0));
//bb_error_msg("VT's pgrp %d", tcgetpgrp(0));
- BB_EXECVP(argv[0], argv);
- bb_perror_msg_and_die("exec %s", argv[0]);
+ BB_EXECVP_or_die(argv);
}
}
int openvt_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
-int openvt_main(int argc ATTRIBUTE_UNUSED, char **argv)
+int openvt_main(int argc UNUSED_PARAM, char **argv)
{
char vtname[sizeof(VC_FORMAT) + sizeof(int)*3];
+ struct vt_stat vtstat;
char *str_c;
int vtno;
int flags;
/* Grab new VT */
sprintf(vtname, VC_FORMAT, vtno);
/* (Try to) clean up stray open fds above fd 2 */
- bb_daemonize_or_rexec(DAEMON_CLOSE_EXTRA_FDS | DAEMON_ONLY_SANITIZE, NULL);
- close(0);
+ bb_daemon_helper(DAEMON_CLOSE_EXTRA_FDS);
+ close(STDIN_FILENO);
/*setsid(); - BAD IDEA: after we exit, child is SIGHUPed... */
xopen(vtname, O_RDWR);
+ xioctl(STDIN_FILENO, VT_GETSTATE, &vtstat);
if (flags & OPT_s) {
- xioctl(0, VT_ACTIVATE, (void*)(ptrdiff_t)vtno);
- xioctl(0, VT_WAITACTIVE, (void*)(ptrdiff_t)vtno);
+ console_make_active(STDIN_FILENO, vtno);
}
if (!argv[0]) {
argv--;
- argv[0] = getenv("SHELL");
- if (!argv[0])
- argv[0] = (char *) DEFAULT_SHELL;
+ argv[0] = (char *) get_shell_name();
/*argv[1] = NULL; - already is */
}
- xdup2(0, STDOUT_FILENO);
- xdup2(0, STDERR_FILENO);
+ xdup2(STDIN_FILENO, STDOUT_FILENO);
+ xdup2(STDIN_FILENO, STDERR_FILENO);
#ifdef BLOAT
+ {
/* Handle -l (login shell) option */
const char *prog = argv[0];
if (flags & OPT_l)
argv[0] = xasprintf("-%s", argv[0]);
+ }
#endif
vfork_child(argv);
if (flags & OPT_w) {
- wait(NULL);
-// TODO: -ws handling should be here
+ /* We have only one child, wait for it */
+ safe_waitpid(-1, NULL, 0); /* loops on EINTR */
+ if (flags & OPT_s) {
+ console_make_active(STDIN_FILENO, vtstat.v_active);
+ // Compat: even with -c N (try to) disallocate:
+ // # /usr/app/kbd-1.12/bin/openvt -f -c 9 -ws sleep 5
+ // openvt: could not deallocate console 9
+ xioctl(STDIN_FILENO, VT_DISALLOCATE, (void*)(ptrdiff_t)vtno);
+ }
}
-
return EXIT_SUCCESS;
}