source: branches/3.2/mindi-busybox/console-tools/openvt.c @ 3232

Last change on this file since 3232 was 3232, checked in by bruno, 5 years ago
  • Update mindi-busybox to 1.21.1
File size: 4.9 KB
Line 
1/* vi: set sw=4 ts=4: */
2/*
3 *  openvt.c - open a vt to run a command.
4 *
5 *  busyboxed by Quy Tonthat <quy@signal3.com>
6 *  hacked by Tito <farmatito@tiscali.it>
7 *
8 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
9 */
10
11//usage:#define openvt_trivial_usage
12//usage:       "[-c N] [-sw] [PROG ARGS]"
13//usage:#define openvt_full_usage "\n\n"
14//usage:       "Start PROG on a new virtual terminal\n"
15//usage:     "\n    -c N    Use specified VT"
16//usage:     "\n    -s  Switch to the VT"
17/* //usage:     "\n -l  Run PROG as login shell (by prepending '-')" */
18//usage:     "\n    -w  Wait for PROG to exit"
19//usage:
20//usage:#define openvt_example_usage
21//usage:       "openvt 2 /bin/ash\n"
22
23#include <linux/vt.h>
24#include "libbb.h"
25
26/* "Standard" openvt's man page (we do not support all of this):
27
28openvt [-c NUM] [-fsulv] [--] [command [args]]
29
30Find the first available VT, and run command on it. Stdio is directed
31to that VT. If no command is specified then $SHELL is used.
32
33-c NUM
34    Use the given VT number, not the first free one.
35-f
36    Force opening a VT: don't try to check if VT is already in use.
37-s
38    Switch to the new VT when starting the command.
39    The VT of the new command will be made the new current VT.
40-u
41    Figure out the owner of the current VT, and run login as that user.
42    Suitable to be called by init. Shouldn't be used with -c or -l.
43-l
44    Make the command a login shell: a "-" is prepended to the argv[0]
45    when command is executed.
46-v
47    Verbose.
48-w
49    Wait for command to complete. If -w and -s are used together,
50    switch back to the controlling terminal when the command completes.
51
52bbox:
53-u: not implemented
54-f: always in effect
55-l: not implemented, ignored
56-v: ignored
57-ws: does NOT switch back
58*/
59
60/* Helper: does this fd understand VT_xxx? */
61static int not_vt_fd(int fd)
62{
63    struct vt_stat vtstat;
64    return ioctl(fd, VT_GETSTATE, &vtstat); /* !0: error, it's not VT fd */
65}
66
67/* Helper: get a fd suitable for VT_xxx */
68static int get_vt_fd(void)
69{
70    int fd;
71
72    /* Do we, by chance, already have it? */
73    for (fd = 0; fd < 3; fd++)
74        if (!not_vt_fd(fd))
75            return fd;
76    fd = open(DEV_CONSOLE, O_RDONLY | O_NONBLOCK);
77    if (fd >= 0 && !not_vt_fd(fd))
78        return fd;
79    bb_error_msg_and_die("can't find open VT");
80}
81
82static int find_free_vtno(void)
83{
84    int vtno;
85    int fd = get_vt_fd();
86
87    errno = 0;
88    /*xfunc_error_retval = 3; - do we need compat? */
89    if (ioctl(fd, VT_OPENQRY, &vtno) != 0 || vtno <= 0)
90        bb_perror_msg_and_die("can't find open VT");
91// Not really needed, grep for DAEMON_ONLY_SANITIZE
92//  if (fd > 2)
93//      close(fd);
94    return vtno;
95}
96
97/* vfork scares gcc, it generates bigger code.
98 * Keep it away from main program.
99 * TODO: move to libbb; or adapt existing libbb's spawn().
100 */
101static NOINLINE void vfork_child(char **argv)
102{
103    if (vfork() == 0) {
104        /* CHILD */
105        /* Try to make this VT our controlling tty */
106        setsid(); /* lose old ctty */
107        ioctl(STDIN_FILENO, TIOCSCTTY, 0 /* 0: don't forcibly steal */);
108        //bb_error_msg("our sid %d", getsid(0));
109        //bb_error_msg("our pgrp %d", getpgrp());
110        //bb_error_msg("VT's sid %d", tcgetsid(0));
111        //bb_error_msg("VT's pgrp %d", tcgetpgrp(0));
112        BB_EXECVP_or_die(argv);
113    }
114}
115
116int openvt_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
117int openvt_main(int argc UNUSED_PARAM, char **argv)
118{
119    char vtname[sizeof(VC_FORMAT) + sizeof(int)*3];
120    struct vt_stat vtstat;
121    char *str_c;
122    int vtno;
123    int flags;
124    enum {
125        OPT_c = (1 << 0),
126        OPT_w = (1 << 1),
127        OPT_s = (1 << 2),
128        OPT_l = (1 << 3),
129        OPT_f = (1 << 4),
130        OPT_v = (1 << 5),
131    };
132
133    /* "+" - stop on first non-option */
134    flags = getopt32(argv, "+c:wslfv", &str_c);
135    argv += optind;
136
137    if (flags & OPT_c) {
138        /* Check for illegal vt number: < 1 or > 63 */
139        vtno = xatou_range(str_c, 1, 63);
140    } else {
141        vtno = find_free_vtno();
142    }
143
144    /* Grab new VT */
145    sprintf(vtname, VC_FORMAT, vtno);
146    /* (Try to) clean up stray open fds above fd 2 */
147    bb_daemonize_or_rexec(DAEMON_CLOSE_EXTRA_FDS | DAEMON_ONLY_SANITIZE, NULL);
148    close(STDIN_FILENO);
149    /*setsid(); - BAD IDEA: after we exit, child is SIGHUPed... */
150    xopen(vtname, O_RDWR);
151    xioctl(STDIN_FILENO, VT_GETSTATE, &vtstat);
152
153    if (flags & OPT_s) {
154        console_make_active(STDIN_FILENO, vtno);
155    }
156
157    if (!argv[0]) {
158        argv--;
159        argv[0] = (char *) get_shell_name();
160        /*argv[1] = NULL; - already is */
161    }
162
163    xdup2(STDIN_FILENO, STDOUT_FILENO);
164    xdup2(STDIN_FILENO, STDERR_FILENO);
165
166#ifdef BLOAT
167    {
168    /* Handle -l (login shell) option */
169    const char *prog = argv[0];
170    if (flags & OPT_l)
171        argv[0] = xasprintf("-%s", argv[0]);
172    }
173#endif
174
175    vfork_child(argv);
176    if (flags & OPT_w) {
177        /* We have only one child, wait for it */
178        safe_waitpid(-1, NULL, 0); /* loops on EINTR */
179        if (flags & OPT_s) {
180            console_make_active(STDIN_FILENO, vtstat.v_active);
181            // Compat: even with -c N (try to) disallocate:
182            // # /usr/app/kbd-1.12/bin/openvt -f -c 9 -ws sleep 5
183            // openvt: could not deallocate console 9
184            xioctl(STDIN_FILENO, VT_DISALLOCATE, (void*)(ptrdiff_t)vtno);
185        }
186    }
187    return EXIT_SUCCESS;
188}
Note: See TracBrowser for help on using the repository browser.