2 * Copyright (c) 1998 Michael Smith <msmith@freebsd.org>
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
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.
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
27 #include <sys/cdefs.h>
32 #include "bootstrap.h"
34 * Core console support
37 static int cons_set(struct env_var
*ev
, int flags
, const void *value
);
38 static int cons_find(const char *name
);
39 static int cons_check(const char *string
);
40 static int cons_change(const char *string
);
41 static int twiddle_set(struct env_var
*ev
, int flags
, const void *value
);
44 * Detect possible console(s) to use. If preferred console(s) have been
45 * specified, mark them as active. Else, mark the first probed console
46 * as active. Also create the console variable.
55 /* We want a callback to install the new value when this var changes. */
56 env_setenv("twiddle_divisor", EV_VOLATILE
, "1", twiddle_set
, env_nounset
);
58 /* Do all console probes */
59 for (cons
= 0; consoles
[cons
] != NULL
; cons
++) {
60 consoles
[cons
]->c_flags
= 0;
61 consoles
[cons
]->c_probe(consoles
[cons
]);
63 /* Now find the first working one */
65 for (cons
= 0; consoles
[cons
] != NULL
&& active
== -1; cons
++) {
66 consoles
[cons
]->c_flags
= 0;
67 consoles
[cons
]->c_probe(consoles
[cons
]);
68 if (consoles
[cons
]->c_flags
== (C_PRESENTIN
| C_PRESENTOUT
))
71 /* Force a console even if all probes failed */
75 /* Check to see if a console preference has already been registered */
76 prefconsole
= getenv("console");
77 if (prefconsole
!= NULL
)
78 prefconsole
= strdup(prefconsole
);
79 if (prefconsole
!= NULL
) {
80 unsetenv("console"); /* we want to replace this */
81 cons_change(prefconsole
);
83 consoles
[active
]->c_flags
|= C_ACTIVEIN
| C_ACTIVEOUT
;
84 consoles
[active
]->c_init(consoles
[active
], 0);
85 prefconsole
= strdup(consoles
[active
]->c_name
);
89 for (cons
= 0; consoles
[cons
] != NULL
; cons
++)
90 if (consoles
[cons
]->c_flags
& (C_ACTIVEIN
| C_ACTIVEOUT
))
91 printf("%s ", consoles
[cons
]->c_desc
);
94 if (prefconsole
!= NULL
) {
95 env_setenv("console", EV_VOLATILE
, prefconsole
, cons_set
,
106 for (cons
= 0; consoles
[cons
] != NULL
; cons
++) {
108 consoles
[cons
]->c_flags
&= ~C_MODERAW
;
110 consoles
[cons
]->c_flags
|= C_MODERAW
;
118 int flags
= C_PRESENTIN
| C_ACTIVEIN
;
122 * Loop forever polling all active consoles. Somewhat strangely,
123 * this code expects all ->c_in() implementations to effectively do an
124 * ischar() check first, returning -1 if there's not a char ready.
127 for (cons
= 0; consoles
[cons
] != NULL
; cons
++) {
128 if ((consoles
[cons
]->c_flags
& flags
) == flags
&&
129 ((rv
= consoles
[cons
]->c_in(consoles
[cons
])) != -1))
132 delay(30 * 1000); /* delay 30ms */
141 for (cons
= 0; consoles
[cons
] != NULL
; cons
++)
142 if ((consoles
[cons
]->c_flags
& (C_PRESENTIN
| C_ACTIVEIN
)) ==
143 (C_PRESENTIN
| C_ACTIVEIN
) &&
144 (consoles
[cons
]->c_ready(consoles
[cons
]) != 0))
154 /* Expand newlines if not in raw mode */
155 for (cons
= 0; consoles
[cons
] != NULL
; cons
++)
156 if ((consoles
[cons
]->c_flags
& (C_PRESENTOUT
| C_ACTIVEOUT
)) ==
157 (C_PRESENTOUT
| C_ACTIVEOUT
)) {
158 if (c
== '\n' && (consoles
[cons
]->c_flags
& C_MODERAW
) == 0)
159 consoles
[cons
]->c_out(consoles
[cons
], '\r');
160 consoles
[cons
]->c_out(consoles
[cons
], c
);
165 * Find the console with the specified name.
168 cons_find(const char *name
)
172 for (cons
= 0; consoles
[cons
] != NULL
; cons
++)
173 if (!strcmp(consoles
[cons
]->c_name
, name
))
179 * Select one or more consoles.
182 cons_set(struct env_var
*ev
, int flags
, const void *value
)
186 if ((value
== NULL
) || (cons_check(value
) == 0)) {
188 * Return CMD_OK instead of CMD_ERROR to prevent forth syntax error,
189 * which would prevent it processing any further loader.conf entries.
194 ret
= cons_change(value
);
198 env_setenv(ev
->ev_name
, flags
| EV_NOHOOK
, value
, NULL
, NULL
);
203 * Check that at least one the consoles listed in *string is valid
206 cons_check(const char *string
)
208 int cons
, found
, failed
;
209 char *curpos
, *dup
, *next
;
211 dup
= next
= strdup(string
);
213 while (next
!= NULL
) {
214 curpos
= strsep(&next
, " ,");
215 if (*curpos
!= '\0') {
216 cons
= cons_find(curpos
);
218 printf("console %s is invalid!\n", curpos
);
229 printf("no valid consoles!\n");
231 if (found
== 0 || failed
!= 0) {
232 printf("Available consoles:\n");
233 for (cons
= 0; consoles
[cons
] != NULL
; cons
++)
234 printf(" %s\n", consoles
[cons
]->c_name
);
241 * Activate all the valid consoles listed in *string and disable all others.
244 cons_change(const char *string
)
247 char *curpos
, *dup
, *next
;
249 /* Disable all consoles */
250 for (cons
= 0; consoles
[cons
] != NULL
; cons
++) {
251 consoles
[cons
]->c_flags
&= ~(C_ACTIVEIN
| C_ACTIVEOUT
);
254 /* Enable selected consoles */
255 dup
= next
= strdup(string
);
257 while (next
!= NULL
) {
258 curpos
= strsep(&next
, " ,");
261 cons
= cons_find(curpos
);
263 consoles
[cons
]->c_flags
|= C_ACTIVEIN
| C_ACTIVEOUT
;
264 consoles
[cons
]->c_init(consoles
[cons
], 0);
265 if ((consoles
[cons
]->c_flags
& (C_PRESENTIN
| C_PRESENTOUT
)) ==
266 (C_PRESENTIN
| C_PRESENTOUT
)) {
272 /* If no consoles have initialised we wouldn't see this. */
273 printf("console %s failed to initialize\n",
274 consoles
[cons
]->c_name
);
282 /* All requested consoles failed to initialise, try to recover. */
283 for (cons
= 0; consoles
[cons
] != NULL
; cons
++) {
284 consoles
[cons
]->c_flags
|= C_ACTIVEIN
| C_ACTIVEOUT
;
285 consoles
[cons
]->c_init(consoles
[cons
], 0);
286 if ((consoles
[cons
]->c_flags
&
287 (C_PRESENTIN
| C_PRESENTOUT
)) ==
288 (C_PRESENTIN
| C_PRESENTOUT
))
293 return (CMD_ERROR
); /* Recovery failed. */
300 * Change the twiddle divisor.
302 * The user can set the twiddle_divisor variable to directly control how fast
303 * the progress twiddle spins, useful for folks with slow serial consoles. The
304 * code to monitor changes to the variable and propagate them to the twiddle
305 * routines has to live somewhere. Twiddling is console-related so it's here.
308 twiddle_set(struct env_var
*ev
, int flags
, const void *value
)
313 tdiv
= strtoul(value
, &eptr
, 0);
314 if (*(const char *)value
== 0 || *eptr
!= 0) {
315 printf("invalid twiddle_divisor '%s'\n", (const char *)value
);
318 twiddle_divisor((u_int
)tdiv
);
319 env_setenv(ev
->ev_name
, flags
| EV_NOHOOK
, value
, NULL
, NULL
);