xref: /illumos-gate/usr/src/common/bootbanner/bootbanner.c (revision 6112cec5d5374dff12a12bd285afeb5e660b7154)
1*6112cec5SJoshua M. Clulow /*
2*6112cec5SJoshua M. Clulow  * This file and its contents are supplied under the terms of the
3*6112cec5SJoshua M. Clulow  * Common Development and Distribution License ("CDDL"), version 1.0.
4*6112cec5SJoshua M. Clulow  * You may only use this file in accordance with the terms of version
5*6112cec5SJoshua M. Clulow  * 1.0 of the CDDL.
6*6112cec5SJoshua M. Clulow  *
7*6112cec5SJoshua M. Clulow  * A full copy of the text of the CDDL should have accompanied this
8*6112cec5SJoshua M. Clulow  * source.  A copy of the CDDL is also available via the Internet at
9*6112cec5SJoshua M. Clulow  * http://www.illumos.org/license/CDDL.
10*6112cec5SJoshua M. Clulow  */
11*6112cec5SJoshua M. Clulow 
12*6112cec5SJoshua M. Clulow /*
13*6112cec5SJoshua M. Clulow  * Copyright 2020 Oxide Computer Company
14*6112cec5SJoshua M. Clulow  */
15*6112cec5SJoshua M. Clulow 
16*6112cec5SJoshua M. Clulow #ifdef _KERNEL
17*6112cec5SJoshua M. Clulow #include <sys/types.h>
18*6112cec5SJoshua M. Clulow #include <sys/sunddi.h>
19*6112cec5SJoshua M. Clulow #else
20*6112cec5SJoshua M. Clulow #include <stdio.h>
21*6112cec5SJoshua M. Clulow #include <stdlib.h>
22*6112cec5SJoshua M. Clulow #include <strings.h>
23*6112cec5SJoshua M. Clulow #include <sys/utsname.h>
24*6112cec5SJoshua M. Clulow #include <sys/systeminfo.h>
25*6112cec5SJoshua M. Clulow #endif
26*6112cec5SJoshua M. Clulow #include <sys/debug.h>
27*6112cec5SJoshua M. Clulow 
28*6112cec5SJoshua M. Clulow /*
29*6112cec5SJoshua M. Clulow  * Rendering of the boot banner, used on the system and zone consoles.
30*6112cec5SJoshua M. Clulow  */
31*6112cec5SJoshua M. Clulow 
32*6112cec5SJoshua M. Clulow typedef enum ilstr_errno {
33*6112cec5SJoshua M. Clulow 	ILSTR_ERROR_OK = 0,
34*6112cec5SJoshua M. Clulow 	ILSTR_ERROR_NOMEM,
35*6112cec5SJoshua M. Clulow 	ILSTR_ERROR_OVERFLOW,
36*6112cec5SJoshua M. Clulow } ilstr_errno_t;
37*6112cec5SJoshua M. Clulow 
38*6112cec5SJoshua M. Clulow typedef struct ilstr {
39*6112cec5SJoshua M. Clulow 	char *ils_data;
40*6112cec5SJoshua M. Clulow 	size_t ils_datalen;
41*6112cec5SJoshua M. Clulow 	size_t ils_strlen;
42*6112cec5SJoshua M. Clulow 	uint_t ils_errno;
43*6112cec5SJoshua M. Clulow 	int ils_kmflag;
44*6112cec5SJoshua M. Clulow } ilstr_t;
45*6112cec5SJoshua M. Clulow 
46*6112cec5SJoshua M. Clulow static void
47*6112cec5SJoshua M. Clulow ilstr_init(ilstr_t *ils, int kmflag)
48*6112cec5SJoshua M. Clulow {
49*6112cec5SJoshua M. Clulow 	bzero(ils, sizeof (*ils));
50*6112cec5SJoshua M. Clulow 	ils->ils_kmflag = kmflag;
51*6112cec5SJoshua M. Clulow }
52*6112cec5SJoshua M. Clulow 
53*6112cec5SJoshua M. Clulow static void
54*6112cec5SJoshua M. Clulow ilstr_reset(ilstr_t *ils)
55*6112cec5SJoshua M. Clulow {
56*6112cec5SJoshua M. Clulow 	if (ils->ils_strlen > 0) {
57*6112cec5SJoshua M. Clulow 		/*
58*6112cec5SJoshua M. Clulow 		 * Truncate the string but do not free the buffer so that we
59*6112cec5SJoshua M. Clulow 		 * can use it again without further allocation.
60*6112cec5SJoshua M. Clulow 		 */
61*6112cec5SJoshua M. Clulow 		ils->ils_data[0] = '\0';
62*6112cec5SJoshua M. Clulow 		ils->ils_strlen = 0;
63*6112cec5SJoshua M. Clulow 	}
64*6112cec5SJoshua M. Clulow 	ils->ils_errno = ILSTR_ERROR_OK;
65*6112cec5SJoshua M. Clulow }
66*6112cec5SJoshua M. Clulow 
67*6112cec5SJoshua M. Clulow static void
68*6112cec5SJoshua M. Clulow ilstr_fini(ilstr_t *ils)
69*6112cec5SJoshua M. Clulow {
70*6112cec5SJoshua M. Clulow 	if (ils->ils_data != NULL) {
71*6112cec5SJoshua M. Clulow #ifdef _KERNEL
72*6112cec5SJoshua M. Clulow 		kmem_free(ils->ils_data, ils->ils_datalen);
73*6112cec5SJoshua M. Clulow #else
74*6112cec5SJoshua M. Clulow 		free(ils->ils_data);
75*6112cec5SJoshua M. Clulow #endif
76*6112cec5SJoshua M. Clulow 	}
77*6112cec5SJoshua M. Clulow }
78*6112cec5SJoshua M. Clulow 
79*6112cec5SJoshua M. Clulow static void
80*6112cec5SJoshua M. Clulow ilstr_append_str(ilstr_t *ils, const char *s)
81*6112cec5SJoshua M. Clulow {
82*6112cec5SJoshua M. Clulow 	size_t len;
83*6112cec5SJoshua M. Clulow 	size_t chunksz = 64;
84*6112cec5SJoshua M. Clulow 
85*6112cec5SJoshua M. Clulow 	if (ils->ils_errno != ILSTR_ERROR_OK) {
86*6112cec5SJoshua M. Clulow 		return;
87*6112cec5SJoshua M. Clulow 	}
88*6112cec5SJoshua M. Clulow 
89*6112cec5SJoshua M. Clulow 	if ((len = strlen(s)) < 1) {
90*6112cec5SJoshua M. Clulow 		return;
91*6112cec5SJoshua M. Clulow 	}
92*6112cec5SJoshua M. Clulow 
93*6112cec5SJoshua M. Clulow 	/*
94*6112cec5SJoshua M. Clulow 	 * Check to ensure that the new string length does not overflow,
95*6112cec5SJoshua M. Clulow 	 * leaving room for the termination byte:
96*6112cec5SJoshua M. Clulow 	 */
97*6112cec5SJoshua M. Clulow 	if (len >= SIZE_MAX - ils->ils_strlen - 1) {
98*6112cec5SJoshua M. Clulow 		ils->ils_errno = ILSTR_ERROR_OVERFLOW;
99*6112cec5SJoshua M. Clulow 		return;
100*6112cec5SJoshua M. Clulow 	}
101*6112cec5SJoshua M. Clulow 	size_t new_strlen = ils->ils_strlen + len;
102*6112cec5SJoshua M. Clulow 
103*6112cec5SJoshua M. Clulow 	if (new_strlen + 1 >= ils->ils_datalen) {
104*6112cec5SJoshua M. Clulow 		size_t new_datalen = ils->ils_datalen;
105*6112cec5SJoshua M. Clulow 		char *new_data;
106*6112cec5SJoshua M. Clulow 
107*6112cec5SJoshua M. Clulow 		/*
108*6112cec5SJoshua M. Clulow 		 * Grow the string buffer to make room for the new string.
109*6112cec5SJoshua M. Clulow 		 */
110*6112cec5SJoshua M. Clulow 		while (new_datalen < new_strlen + 1) {
111*6112cec5SJoshua M. Clulow 			if (chunksz >= SIZE_MAX - new_datalen) {
112*6112cec5SJoshua M. Clulow 				ils->ils_errno = ILSTR_ERROR_OVERFLOW;
113*6112cec5SJoshua M. Clulow 				return;
114*6112cec5SJoshua M. Clulow 			}
115*6112cec5SJoshua M. Clulow 			new_datalen += chunksz;
116*6112cec5SJoshua M. Clulow 		}
117*6112cec5SJoshua M. Clulow 
118*6112cec5SJoshua M. Clulow #ifdef _KERNEL
119*6112cec5SJoshua M. Clulow 		new_data = kmem_alloc(new_datalen, ils->ils_kmflag);
120*6112cec5SJoshua M. Clulow #else
121*6112cec5SJoshua M. Clulow 		new_data = malloc(new_datalen);
122*6112cec5SJoshua M. Clulow #endif
123*6112cec5SJoshua M. Clulow 		if (new_data == NULL) {
124*6112cec5SJoshua M. Clulow 			ils->ils_errno = ILSTR_ERROR_NOMEM;
125*6112cec5SJoshua M. Clulow 			return;
126*6112cec5SJoshua M. Clulow 		}
127*6112cec5SJoshua M. Clulow 
128*6112cec5SJoshua M. Clulow 		if (ils->ils_data != NULL) {
129*6112cec5SJoshua M. Clulow 			bcopy(ils->ils_data, new_data, ils->ils_strlen + 1);
130*6112cec5SJoshua M. Clulow #ifdef _KERNEL
131*6112cec5SJoshua M. Clulow 			kmem_free(ils->ils_data, ils->ils_datalen);
132*6112cec5SJoshua M. Clulow #else
133*6112cec5SJoshua M. Clulow 			free(ils->ils_data);
134*6112cec5SJoshua M. Clulow #endif
135*6112cec5SJoshua M. Clulow 		}
136*6112cec5SJoshua M. Clulow 
137*6112cec5SJoshua M. Clulow 		ils->ils_data = new_data;
138*6112cec5SJoshua M. Clulow 		ils->ils_datalen = new_datalen;
139*6112cec5SJoshua M. Clulow 	}
140*6112cec5SJoshua M. Clulow 
141*6112cec5SJoshua M. Clulow 	bcopy(s, ils->ils_data + ils->ils_strlen, len + 1);
142*6112cec5SJoshua M. Clulow 	ils->ils_strlen = new_strlen;
143*6112cec5SJoshua M. Clulow }
144*6112cec5SJoshua M. Clulow 
145*6112cec5SJoshua M. Clulow #ifdef _KERNEL
146*6112cec5SJoshua M. Clulow static void
147*6112cec5SJoshua M. Clulow ilstr_append_uint(ilstr_t *ils, uint_t n)
148*6112cec5SJoshua M. Clulow {
149*6112cec5SJoshua M. Clulow 	char buf[64];
150*6112cec5SJoshua M. Clulow 
151*6112cec5SJoshua M. Clulow 	if (ils->ils_errno != ILSTR_ERROR_OK) {
152*6112cec5SJoshua M. Clulow 		return;
153*6112cec5SJoshua M. Clulow 	}
154*6112cec5SJoshua M. Clulow 
155*6112cec5SJoshua M. Clulow 	VERIFY3U(snprintf(buf, sizeof (buf), "%u", n), <, sizeof (buf));
156*6112cec5SJoshua M. Clulow 
157*6112cec5SJoshua M. Clulow 	ilstr_append_str(ils, buf);
158*6112cec5SJoshua M. Clulow }
159*6112cec5SJoshua M. Clulow #endif
160*6112cec5SJoshua M. Clulow 
161*6112cec5SJoshua M. Clulow static void
162*6112cec5SJoshua M. Clulow ilstr_append_char(ilstr_t *ils, char c)
163*6112cec5SJoshua M. Clulow {
164*6112cec5SJoshua M. Clulow 	char buf[2];
165*6112cec5SJoshua M. Clulow 
166*6112cec5SJoshua M. Clulow 	if (ils->ils_errno != ILSTR_ERROR_OK) {
167*6112cec5SJoshua M. Clulow 		return;
168*6112cec5SJoshua M. Clulow 	}
169*6112cec5SJoshua M. Clulow 
170*6112cec5SJoshua M. Clulow 	buf[0] = c;
171*6112cec5SJoshua M. Clulow 	buf[1] = '\0';
172*6112cec5SJoshua M. Clulow 
173*6112cec5SJoshua M. Clulow 	ilstr_append_str(ils, buf);
174*6112cec5SJoshua M. Clulow }
175*6112cec5SJoshua M. Clulow 
176*6112cec5SJoshua M. Clulow static ilstr_errno_t
177*6112cec5SJoshua M. Clulow ilstr_errno(ilstr_t *ils)
178*6112cec5SJoshua M. Clulow {
179*6112cec5SJoshua M. Clulow 	return (ils->ils_errno);
180*6112cec5SJoshua M. Clulow }
181*6112cec5SJoshua M. Clulow 
182*6112cec5SJoshua M. Clulow static const char *
183*6112cec5SJoshua M. Clulow ilstr_cstr(ilstr_t *ils)
184*6112cec5SJoshua M. Clulow {
185*6112cec5SJoshua M. Clulow 	return (ils->ils_data);
186*6112cec5SJoshua M. Clulow }
187*6112cec5SJoshua M. Clulow 
188*6112cec5SJoshua M. Clulow static size_t
189*6112cec5SJoshua M. Clulow ilstr_len(ilstr_t *ils)
190*6112cec5SJoshua M. Clulow {
191*6112cec5SJoshua M. Clulow 	return (ils->ils_strlen);
192*6112cec5SJoshua M. Clulow }
193*6112cec5SJoshua M. Clulow 
194*6112cec5SJoshua M. Clulow static const char *
195*6112cec5SJoshua M. Clulow ilstr_errstr(ilstr_t *ils)
196*6112cec5SJoshua M. Clulow {
197*6112cec5SJoshua M. Clulow 	switch (ils->ils_errno) {
198*6112cec5SJoshua M. Clulow 	case ILSTR_ERROR_OK:
199*6112cec5SJoshua M. Clulow 		return ("ok");
200*6112cec5SJoshua M. Clulow 	case ILSTR_ERROR_NOMEM:
201*6112cec5SJoshua M. Clulow 		return ("could not allocate memory");
202*6112cec5SJoshua M. Clulow 	case ILSTR_ERROR_OVERFLOW:
203*6112cec5SJoshua M. Clulow 		return ("tried to construct too large a string");
204*6112cec5SJoshua M. Clulow 	default:
205*6112cec5SJoshua M. Clulow 		return ("unknown error");
206*6112cec5SJoshua M. Clulow 	}
207*6112cec5SJoshua M. Clulow }
208*6112cec5SJoshua M. Clulow 
209*6112cec5SJoshua M. Clulow /*
210*6112cec5SJoshua M. Clulow  * Expand a boot banner template string.  The following expansion tokens
211*6112cec5SJoshua M. Clulow  * are supported:
212*6112cec5SJoshua M. Clulow  *
213*6112cec5SJoshua M. Clulow  *	^^	a literal caret
214*6112cec5SJoshua M. Clulow  *	^s	the base kernel name (utsname.sysname)
215*6112cec5SJoshua M. Clulow  *	^o	the operating system name ("illumos")
216*6112cec5SJoshua M. Clulow  *	^v	the operating system version (utsname.version)
217*6112cec5SJoshua M. Clulow  *	^r	the operating system release (utsname.release)
218*6112cec5SJoshua M. Clulow  *	^w	the native address width in bits (e.g., "32" or "64")
219*6112cec5SJoshua M. Clulow  */
220*6112cec5SJoshua M. Clulow static void
221*6112cec5SJoshua M. Clulow bootbanner_expand_template(const char *input, ilstr_t *output)
222*6112cec5SJoshua M. Clulow {
223*6112cec5SJoshua M. Clulow 	size_t pos = 0;
224*6112cec5SJoshua M. Clulow 	enum {
225*6112cec5SJoshua M. Clulow 		ST_REST,
226*6112cec5SJoshua M. Clulow 		ST_CARET,
227*6112cec5SJoshua M. Clulow 	} state = ST_REST;
228*6112cec5SJoshua M. Clulow 
229*6112cec5SJoshua M. Clulow #ifndef _KERNEL
230*6112cec5SJoshua M. Clulow 	struct utsname utsname;
231*6112cec5SJoshua M. Clulow 	bzero(&utsname, sizeof (utsname));
232*6112cec5SJoshua M. Clulow 	(void) uname(&utsname);
233*6112cec5SJoshua M. Clulow #endif
234*6112cec5SJoshua M. Clulow 
235*6112cec5SJoshua M. Clulow 	for (;;) {
236*6112cec5SJoshua M. Clulow 		char c = input[pos];
237*6112cec5SJoshua M. Clulow 
238*6112cec5SJoshua M. Clulow 		if (c == '\0') {
239*6112cec5SJoshua M. Clulow 			/*
240*6112cec5SJoshua M. Clulow 			 * Even if the template came to an end mid way through
241*6112cec5SJoshua M. Clulow 			 * a caret expansion, it seems best to just print what
242*6112cec5SJoshua M. Clulow 			 * we have and drive on.  The onus will be on the
243*6112cec5SJoshua M. Clulow 			 * distributor to ensure their templates are
244*6112cec5SJoshua M. Clulow 			 * well-formed at build time.
245*6112cec5SJoshua M. Clulow 			 */
246*6112cec5SJoshua M. Clulow 			break;
247*6112cec5SJoshua M. Clulow 		}
248*6112cec5SJoshua M. Clulow 
249*6112cec5SJoshua M. Clulow 		switch (state) {
250*6112cec5SJoshua M. Clulow 		case ST_REST:
251*6112cec5SJoshua M. Clulow 			if (c == '^') {
252*6112cec5SJoshua M. Clulow 				state = ST_CARET;
253*6112cec5SJoshua M. Clulow 			} else {
254*6112cec5SJoshua M. Clulow 				ilstr_append_char(output, c);
255*6112cec5SJoshua M. Clulow 			}
256*6112cec5SJoshua M. Clulow 			pos++;
257*6112cec5SJoshua M. Clulow 			continue;
258*6112cec5SJoshua M. Clulow 
259*6112cec5SJoshua M. Clulow 		case ST_CARET:
260*6112cec5SJoshua M. Clulow 			if (c == '^') {
261*6112cec5SJoshua M. Clulow 				ilstr_append_char(output, c);
262*6112cec5SJoshua M. Clulow 			} else if (c == 's') {
263*6112cec5SJoshua M. Clulow 				ilstr_append_str(output, utsname.sysname);
264*6112cec5SJoshua M. Clulow 			} else if (c == 'o') {
265*6112cec5SJoshua M. Clulow 				ilstr_append_str(output, "illumos");
266*6112cec5SJoshua M. Clulow 			} else if (c == 'r') {
267*6112cec5SJoshua M. Clulow 				ilstr_append_str(output, utsname.release);
268*6112cec5SJoshua M. Clulow 			} else if (c == 'v') {
269*6112cec5SJoshua M. Clulow 				ilstr_append_str(output, utsname.version);
270*6112cec5SJoshua M. Clulow 			} else if (c == 'w') {
271*6112cec5SJoshua M. Clulow #ifdef _KERNEL
272*6112cec5SJoshua M. Clulow 				ilstr_append_uint(output,
273*6112cec5SJoshua M. Clulow 				    NBBY * (uint_t)sizeof (void *));
274*6112cec5SJoshua M. Clulow #else
275*6112cec5SJoshua M. Clulow 				char *bits;
276*6112cec5SJoshua M. Clulow 				char buf[32];
277*6112cec5SJoshua M. Clulow 				int r;
278*6112cec5SJoshua M. Clulow 
279*6112cec5SJoshua M. Clulow 				if ((r = sysinfo(SI_ADDRESS_WIDTH, buf,
280*6112cec5SJoshua M. Clulow 				    sizeof (buf))) > 0 &&
281*6112cec5SJoshua M. Clulow 				    r < (int)sizeof (buf)) {
282*6112cec5SJoshua M. Clulow 					bits = buf;
283*6112cec5SJoshua M. Clulow 				} else {
284*6112cec5SJoshua M. Clulow 					bits = "64";
285*6112cec5SJoshua M. Clulow 				}
286*6112cec5SJoshua M. Clulow 
287*6112cec5SJoshua M. Clulow 				ilstr_append_str(output, bits);
288*6112cec5SJoshua M. Clulow #endif
289*6112cec5SJoshua M. Clulow 			} else {
290*6112cec5SJoshua M. Clulow 				/*
291*6112cec5SJoshua M. Clulow 				 * Try to make it obvious what went wrong:
292*6112cec5SJoshua M. Clulow 				 */
293*6112cec5SJoshua M. Clulow 				ilstr_append_str(output, "!^");
294*6112cec5SJoshua M. Clulow 				ilstr_append_char(output, c);
295*6112cec5SJoshua M. Clulow 				ilstr_append_str(output, " UNKNOWN!");
296*6112cec5SJoshua M. Clulow 			}
297*6112cec5SJoshua M. Clulow 			state = ST_REST;
298*6112cec5SJoshua M. Clulow 			pos++;
299*6112cec5SJoshua M. Clulow 			continue;
300*6112cec5SJoshua M. Clulow 		}
301*6112cec5SJoshua M. Clulow 	}
302*6112cec5SJoshua M. Clulow }
303*6112cec5SJoshua M. Clulow 
304*6112cec5SJoshua M. Clulow static void
305*6112cec5SJoshua M. Clulow bootbanner_print_one(ilstr_t *s, void (*printfunc)(const char *, uint_t),
306*6112cec5SJoshua M. Clulow     const char *template, uint_t *nump)
307*6112cec5SJoshua M. Clulow {
308*6112cec5SJoshua M. Clulow 	ilstr_reset(s);
309*6112cec5SJoshua M. Clulow 
310*6112cec5SJoshua M. Clulow 	bootbanner_expand_template(template, s);
311*6112cec5SJoshua M. Clulow 
312*6112cec5SJoshua M. Clulow 	if (ilstr_errno(s) == ILSTR_ERROR_OK) {
313*6112cec5SJoshua M. Clulow 		if (ilstr_len(s) > 0) {
314*6112cec5SJoshua M. Clulow 			printfunc(ilstr_cstr(s), *nump);
315*6112cec5SJoshua M. Clulow 			*nump += 1;
316*6112cec5SJoshua M. Clulow 		}
317*6112cec5SJoshua M. Clulow 	} else {
318*6112cec5SJoshua M. Clulow 		char ebuf[128];
319*6112cec5SJoshua M. Clulow 
320*6112cec5SJoshua M. Clulow 		snprintf(ebuf, sizeof (ebuf), "boot banner error: %s",
321*6112cec5SJoshua M. Clulow 		    ilstr_errstr(s));
322*6112cec5SJoshua M. Clulow 
323*6112cec5SJoshua M. Clulow 		printfunc(ebuf, *nump);
324*6112cec5SJoshua M. Clulow 		*nump += 1;
325*6112cec5SJoshua M. Clulow 	}
326*6112cec5SJoshua M. Clulow }
327*6112cec5SJoshua M. Clulow 
328*6112cec5SJoshua M. Clulow /*
329*6112cec5SJoshua M. Clulow  * This routine should be called during early system boot to render the boot
330*6112cec5SJoshua M. Clulow  * banner on the system console, and during zone boot to do so on the zone
331*6112cec5SJoshua M. Clulow  * console.
332*6112cec5SJoshua M. Clulow  *
333*6112cec5SJoshua M. Clulow  * The "printfunc" argument is a callback function.  When passed a string, the
334*6112cec5SJoshua M. Clulow  * function must print it in a fashion appropriate for the context.  The
335*6112cec5SJoshua M. Clulow  * callback will only be called while within the call to bootbanner_print().
336*6112cec5SJoshua M. Clulow  * The "kmflag" value accepts the same values as kmem_alloc(9F) in the kernel,
337*6112cec5SJoshua M. Clulow  * and is ignored otherwise.
338*6112cec5SJoshua M. Clulow  */
339*6112cec5SJoshua M. Clulow void
340*6112cec5SJoshua M. Clulow bootbanner_print(void (*printfunc)(const char *, uint_t), int kmflag)
341*6112cec5SJoshua M. Clulow {
342*6112cec5SJoshua M. Clulow 	ilstr_t s;
343*6112cec5SJoshua M. Clulow 	uint_t num = 0;
344*6112cec5SJoshua M. Clulow 
345*6112cec5SJoshua M. Clulow 	ilstr_init(&s, kmflag);
346*6112cec5SJoshua M. Clulow 
347*6112cec5SJoshua M. Clulow 	bootbanner_print_one(&s, printfunc, BOOTBANNER1, &num);
348*6112cec5SJoshua M. Clulow 	bootbanner_print_one(&s, printfunc, BOOTBANNER2, &num);
349*6112cec5SJoshua M. Clulow 	bootbanner_print_one(&s, printfunc, BOOTBANNER3, &num);
350*6112cec5SJoshua M. Clulow 	bootbanner_print_one(&s, printfunc, BOOTBANNER4, &num);
351*6112cec5SJoshua M. Clulow 	bootbanner_print_one(&s, printfunc, BOOTBANNER5, &num);
352*6112cec5SJoshua M. Clulow 
353*6112cec5SJoshua M. Clulow 	ilstr_fini(&s);
354*6112cec5SJoshua M. Clulow }
355