]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - stand/common/console.c
bhyvectl(8): Normalize the man page date
[FreeBSD/FreeBSD.git] / stand / common / console.c
1 /*-
2  * Copyright (c) 1998 Michael Smith <msmith@freebsd.org>
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24  * SUCH DAMAGE.
25  */
26
27 #include <sys/cdefs.h>
28 __FBSDID("$FreeBSD$");
29
30 #include <stand.h>
31 #include <string.h>
32
33 #include "bootstrap.h"
34 /*
35  * Core console support
36  */
37
38 static int      cons_set(struct env_var *ev, int flags, const void *value);
39 static int      cons_find(const char *name);
40 static int      cons_check(const char *string);
41 static int      cons_change(const char *string);
42 static int      twiddle_set(struct env_var *ev, int flags, const void *value);
43
44 /*
45  * Detect possible console(s) to use.  If preferred console(s) have been
46  * specified, mark them as active. Else, mark the first probed console
47  * as active.  Also create the console variable.
48  */
49 void
50 cons_probe(void)
51 {
52         int     cons;
53         int     active;
54         char    *prefconsole;
55
56         /* We want a callback to install the new value when this var changes. */
57         env_setenv("twiddle_divisor", EV_VOLATILE, "1", twiddle_set,
58             env_nounset);
59
60         /* Do all console probes */
61         for (cons = 0; consoles[cons] != NULL; cons++) {
62                 consoles[cons]->c_flags = 0;
63                 consoles[cons]->c_probe(consoles[cons]);
64         }
65         /* Now find the first working one */
66         active = -1;
67         for (cons = 0; consoles[cons] != NULL && active == -1; cons++) {
68                 consoles[cons]->c_flags = 0;
69                 consoles[cons]->c_probe(consoles[cons]);
70                 if (consoles[cons]->c_flags == (C_PRESENTIN | C_PRESENTOUT))
71                         active = cons;
72         }
73         /* Force a console even if all probes failed */
74         if (active == -1)
75                 active = 0;
76
77         /* Check to see if a console preference has already been registered */
78         prefconsole = getenv("console");
79         if (prefconsole != NULL)
80                 prefconsole = strdup(prefconsole);
81         if (prefconsole != NULL) {
82                 unsetenv("console");            /* we want to replace this */
83                 cons_change(prefconsole);
84         } else {
85                 consoles[active]->c_flags |= C_ACTIVEIN | C_ACTIVEOUT;
86                 consoles[active]->c_init(0);
87                 prefconsole = strdup(consoles[active]->c_name);
88         }
89
90         printf("Consoles: ");
91         for (cons = 0; consoles[cons] != NULL; cons++)
92                 if (consoles[cons]->c_flags & (C_ACTIVEIN | C_ACTIVEOUT))
93                         printf("%s  ", consoles[cons]->c_desc);
94         printf("\n");
95
96         if (prefconsole != NULL) {
97                 env_setenv("console", EV_VOLATILE, prefconsole, cons_set,
98                     env_nounset);
99                 free(prefconsole);
100         }
101 }
102
103 int
104 getchar(void)
105 {
106         int     cons;
107         int     rv;
108
109         /* Loop forever polling all active consoles */
110         for (;;) {
111                 for (cons = 0; consoles[cons] != NULL; cons++) {
112                         if ((consoles[cons]->c_flags &
113                             (C_PRESENTIN | C_ACTIVEIN)) ==
114                             (C_PRESENTIN | C_ACTIVEIN) &&
115                             ((rv = consoles[cons]->c_in()) != -1))
116                                 return (rv);
117                 }
118         }
119 }
120
121 int
122 ischar(void)
123 {
124         int     cons;
125
126         for (cons = 0; consoles[cons] != NULL; cons++)
127                 if ((consoles[cons]->c_flags & (C_PRESENTIN | C_ACTIVEIN)) ==
128                     (C_PRESENTIN | C_ACTIVEIN) &&
129                     (consoles[cons]->c_ready() != 0))
130                         return (1);
131         return (0);
132 }
133
134 void
135 putchar(int c)
136 {
137         int     cons;
138
139         /* Expand newlines */
140         if (c == '\n')
141                 putchar('\r');
142
143         for (cons = 0; consoles[cons] != NULL; cons++) {
144                 if ((consoles[cons]->c_flags & (C_PRESENTOUT | C_ACTIVEOUT)) ==
145                     (C_PRESENTOUT | C_ACTIVEOUT))
146                         consoles[cons]->c_out(c);
147         }
148 }
149
150 /*
151  * Find the console with the specified name.
152  */
153 static int
154 cons_find(const char *name)
155 {
156         int     cons;
157
158         for (cons = 0; consoles[cons] != NULL; cons++)
159                 if (strcmp(consoles[cons]->c_name, name) == 0)
160                         return (cons);
161         return (-1);
162 }
163
164 /*
165  * Select one or more consoles.
166  */
167 static int
168 cons_set(struct env_var *ev, int flags, const void *value)
169 {
170         int     ret;
171
172         if ((value == NULL) || (cons_check(value) == 0)) {
173                 /*
174                  * Return CMD_OK instead of CMD_ERROR to prevent forth syntax
175                  * error, which would prevent it processing any further
176                  * loader.conf entries.
177                  */
178                 return (CMD_OK);
179         }
180
181         ret = cons_change(value);
182         if (ret != CMD_OK)
183                 return (ret);
184
185         env_setenv(ev->ev_name, flags | EV_NOHOOK, value, NULL, NULL);
186         return (CMD_OK);
187 }
188
189 /*
190  * Check that at least one the consoles listed in *string is valid
191  */
192 static int
193 cons_check(const char *string)
194 {
195         int     cons, found, failed;
196         char    *curpos, *dup, *next;
197
198         dup = next = strdup(string);
199         found = failed = 0;
200         while (next != NULL) {
201                 curpos = strsep(&next, " ,");
202                 if (*curpos != '\0') {
203                         cons = cons_find(curpos);
204                         if (cons == -1) {
205                                 printf("console %s is invalid!\n", curpos);
206                                 failed++;
207                         } else {
208                                 found++;
209                         }
210                 }
211         }
212
213         free(dup);
214
215         if (found == 0)
216                 printf("no valid consoles!\n");
217
218         if (found == 0 || failed != 0) {
219                 printf("Available consoles:\n");
220                 for (cons = 0; consoles[cons] != NULL; cons++)
221                         printf("    %s\n", consoles[cons]->c_name);
222         }
223
224         return (found);
225 }
226
227 /*
228  * Activate all the valid consoles listed in *string and disable all others.
229  */
230 static int
231 cons_change(const char *string)
232 {
233         int     cons, active;
234         char    *curpos, *dup, *next;
235
236         /* Disable all consoles */
237         for (cons = 0; consoles[cons] != NULL; cons++) {
238                 consoles[cons]->c_flags &= ~(C_ACTIVEIN | C_ACTIVEOUT);
239         }
240
241         /* Enable selected consoles */
242         dup = next = strdup(string);
243         active = 0;
244         while (next != NULL) {
245                 curpos = strsep(&next, " ,");
246                 if (*curpos == '\0')
247                         continue;
248                 cons = cons_find(curpos);
249                 if (cons >= 0) {
250                         consoles[cons]->c_flags |= C_ACTIVEIN | C_ACTIVEOUT;
251                         consoles[cons]->c_init(0);
252                         if ((consoles[cons]->c_flags &
253                             (C_PRESENTIN | C_PRESENTOUT)) ==
254                             (C_PRESENTIN | C_PRESENTOUT)) {
255                                 active++;
256                                 continue;
257                         }
258
259                         if (active != 0) {
260                                 /*
261                                  * If no consoles have initialised we
262                                  * wouldn't see this.
263                                  */
264                                 printf("console %s failed to initialize\n",
265                                     consoles[cons]->c_name);
266                         }
267                 }
268         }
269
270         free(dup);
271
272         if (active == 0) {
273                 /*
274                  * All requested consoles failed to initialise,
275                  * try to recover.
276                  */
277                 for (cons = 0; consoles[cons] != NULL; cons++) {
278                         consoles[cons]->c_flags |= C_ACTIVEIN | C_ACTIVEOUT;
279                         consoles[cons]->c_init(0);
280                         if ((consoles[cons]->c_flags &
281                             (C_PRESENTIN | C_PRESENTOUT)) ==
282                             (C_PRESENTIN | C_PRESENTOUT))
283                                 active++;
284                 }
285
286                 if (active == 0)
287                         return (CMD_ERROR); /* Recovery failed. */
288         }
289
290         return (CMD_OK);
291 }
292
293 /*
294  * Change the twiddle divisor.
295  *
296  * The user can set the twiddle_divisor variable to directly control how fast
297  * the progress twiddle spins, useful for folks with slow serial consoles.  The
298  * code to monitor changes to the variable and propagate them to the twiddle
299  * routines has to live somewhere.  Twiddling is console-related so it's here.
300  */
301 static int
302 twiddle_set(struct env_var *ev, int flags, const void *value)
303 {
304         u_long tdiv;
305         char *eptr;
306
307         tdiv = strtoul(value, &eptr, 0);
308         if (*(const char *)value == 0 || *eptr != 0) {
309                 printf("invalid twiddle_divisor '%s'\n", (const char *)value);
310                 return (CMD_ERROR);
311         }
312         twiddle_divisor((u_int)tdiv);
313         env_setenv(ev->ev_name, flags | EV_NOHOOK, value, NULL, NULL);
314
315         return (CMD_OK);
316 }