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