1*7c478bd9Sstevel@tonic-gate /*
2*7c478bd9Sstevel@tonic-gate * CDDL HEADER START
3*7c478bd9Sstevel@tonic-gate *
4*7c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the
5*7c478bd9Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only
6*7c478bd9Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance
7*7c478bd9Sstevel@tonic-gate * with the License.
8*7c478bd9Sstevel@tonic-gate *
9*7c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*7c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
11*7c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions
12*7c478bd9Sstevel@tonic-gate * and limitations under the License.
13*7c478bd9Sstevel@tonic-gate *
14*7c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
15*7c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*7c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
17*7c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
18*7c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
19*7c478bd9Sstevel@tonic-gate *
20*7c478bd9Sstevel@tonic-gate * CDDL HEADER END
21*7c478bd9Sstevel@tonic-gate */
22*7c478bd9Sstevel@tonic-gate /*
23*7c478bd9Sstevel@tonic-gate * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
24*7c478bd9Sstevel@tonic-gate * Use is subject to license terms.
25*7c478bd9Sstevel@tonic-gate */
26*7c478bd9Sstevel@tonic-gate
27*7c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI"
28*7c478bd9Sstevel@tonic-gate
29*7c478bd9Sstevel@tonic-gate /*
30*7c478bd9Sstevel@tonic-gate * bootlog() - error notification and progress reporting for
31*7c478bd9Sstevel@tonic-gate * WAN boot components
32*7c478bd9Sstevel@tonic-gate */
33*7c478bd9Sstevel@tonic-gate
34*7c478bd9Sstevel@tonic-gate #include <sys/varargs.h>
35*7c478bd9Sstevel@tonic-gate #include <sys/types.h>
36*7c478bd9Sstevel@tonic-gate #include <sys/strlog.h>
37*7c478bd9Sstevel@tonic-gate #include <sys/wanboot_impl.h>
38*7c478bd9Sstevel@tonic-gate #include <errno.h>
39*7c478bd9Sstevel@tonic-gate #include <time.h>
40*7c478bd9Sstevel@tonic-gate #include <boot_http.h>
41*7c478bd9Sstevel@tonic-gate #include <stdio.h>
42*7c478bd9Sstevel@tonic-gate #include <parseURL.h>
43*7c478bd9Sstevel@tonic-gate #include <bootlog.h>
44*7c478bd9Sstevel@tonic-gate #include <strings.h>
45*7c478bd9Sstevel@tonic-gate #include <stdlib.h>
46*7c478bd9Sstevel@tonic-gate #include <unistd.h>
47*7c478bd9Sstevel@tonic-gate #include <netdb.h>
48*7c478bd9Sstevel@tonic-gate #include <libintl.h>
49*7c478bd9Sstevel@tonic-gate #include <netboot_paths.h>
50*7c478bd9Sstevel@tonic-gate #include <wanboot_conf.h>
51*7c478bd9Sstevel@tonic-gate #include <bootinfo.h>
52*7c478bd9Sstevel@tonic-gate #ifdef _BOOT
53*7c478bd9Sstevel@tonic-gate #include <sys/bootdebug.h>
54*7c478bd9Sstevel@tonic-gate #endif
55*7c478bd9Sstevel@tonic-gate
56*7c478bd9Sstevel@tonic-gate static struct code pri_names[] = {
57*7c478bd9Sstevel@tonic-gate "panic", BOOTLOG_EMERG,
58*7c478bd9Sstevel@tonic-gate "alert", BOOTLOG_ALERT,
59*7c478bd9Sstevel@tonic-gate "crit", BOOTLOG_CRIT,
60*7c478bd9Sstevel@tonic-gate "warn", BOOTLOG_WARNING,
61*7c478bd9Sstevel@tonic-gate "info", BOOTLOG_INFO,
62*7c478bd9Sstevel@tonic-gate "debug", BOOTLOG_DEBUG,
63*7c478bd9Sstevel@tonic-gate "verbose", BOOTLOG_VERBOSE,
64*7c478bd9Sstevel@tonic-gate "progress", BOOTLOG_PROGRESS,
65*7c478bd9Sstevel@tonic-gate "none", NOPRI,
66*7c478bd9Sstevel@tonic-gate NULL, -1
67*7c478bd9Sstevel@tonic-gate };
68*7c478bd9Sstevel@tonic-gate
69*7c478bd9Sstevel@tonic-gate typedef enum {
70*7c478bd9Sstevel@tonic-gate BL_NO_TRANSPORT,
71*7c478bd9Sstevel@tonic-gate BL_LOCAL_FILE,
72*7c478bd9Sstevel@tonic-gate BL_CONSOLE,
73*7c478bd9Sstevel@tonic-gate BL_HTTP,
74*7c478bd9Sstevel@tonic-gate BL_HTTPS
75*7c478bd9Sstevel@tonic-gate } bl_transport_t;
76*7c478bd9Sstevel@tonic-gate
77*7c478bd9Sstevel@tonic-gate typedef struct list_entry {
78*7c478bd9Sstevel@tonic-gate char message[BOOTLOG_QS_MAX];
79*7c478bd9Sstevel@tonic-gate struct list_entry *flink;
80*7c478bd9Sstevel@tonic-gate } list;
81*7c478bd9Sstevel@tonic-gate
82*7c478bd9Sstevel@tonic-gate #define BOOTLOG_RING_NELEM 512
83*7c478bd9Sstevel@tonic-gate
84*7c478bd9Sstevel@tonic-gate static struct ringbuffer_t {
85*7c478bd9Sstevel@tonic-gate int w_ptr;
86*7c478bd9Sstevel@tonic-gate int r_ptr;
87*7c478bd9Sstevel@tonic-gate list entries[BOOTLOG_RING_NELEM];
88*7c478bd9Sstevel@tonic-gate } ringbuffer;
89*7c478bd9Sstevel@tonic-gate
90*7c478bd9Sstevel@tonic-gate static FILE *bl_filehandle = NULL;
91*7c478bd9Sstevel@tonic-gate static http_handle_t bl_httphandle = NULL;
92*7c478bd9Sstevel@tonic-gate static url_t bl_url;
93*7c478bd9Sstevel@tonic-gate static bl_transport_t bl_transport = BL_NO_TRANSPORT;
94*7c478bd9Sstevel@tonic-gate
95*7c478bd9Sstevel@tonic-gate static bl_transport_t openbootlog(void);
96*7c478bd9Sstevel@tonic-gate static boolean_t setup_con(http_handle_t, boolean_t, boolean_t);
97*7c478bd9Sstevel@tonic-gate static char *url_encode(const char *);
98*7c478bd9Sstevel@tonic-gate static boolean_t sendmessage(bl_transport_t, char *, const char *,
99*7c478bd9Sstevel@tonic-gate bootlog_severity_t, int);
100*7c478bd9Sstevel@tonic-gate static int ptr_incr(int ptr);
101*7c478bd9Sstevel@tonic-gate static int ptr_decr(int ptr);
102*7c478bd9Sstevel@tonic-gate static void rb_init(struct ringbuffer_t *);
103*7c478bd9Sstevel@tonic-gate static void rb_write(struct ringbuffer_t *, const char *);
104*7c478bd9Sstevel@tonic-gate static int rb_read(struct ringbuffer_t *, char *);
105*7c478bd9Sstevel@tonic-gate
106*7c478bd9Sstevel@tonic-gate /*
107*7c478bd9Sstevel@tonic-gate * Return a string representing the current time; not thread-safe.
108*7c478bd9Sstevel@tonic-gate */
109*7c478bd9Sstevel@tonic-gate static const char *
gettime(void)110*7c478bd9Sstevel@tonic-gate gettime(void)
111*7c478bd9Sstevel@tonic-gate {
112*7c478bd9Sstevel@tonic-gate static char timebuf[sizeof ("Tue Jan 19 03:14:07 2038\n")];
113*7c478bd9Sstevel@tonic-gate time_t curtime;
114*7c478bd9Sstevel@tonic-gate
115*7c478bd9Sstevel@tonic-gate if (time(&curtime) == 0)
116*7c478bd9Sstevel@tonic-gate return ("<time unavailable>");
117*7c478bd9Sstevel@tonic-gate
118*7c478bd9Sstevel@tonic-gate (void) strlcpy(timebuf, ctime(&curtime), sizeof (timebuf));
119*7c478bd9Sstevel@tonic-gate timebuf[19] = '\0'; /* truncate before "2038" above */
120*7c478bd9Sstevel@tonic-gate return (timebuf);
121*7c478bd9Sstevel@tonic-gate }
122*7c478bd9Sstevel@tonic-gate
123*7c478bd9Sstevel@tonic-gate /*
124*7c478bd9Sstevel@tonic-gate * bootlog_common() - Common routine used by bootlog() and
125*7c478bd9Sstevel@tonic-gate * bootlog_internal() to write a message comprising a message
126*7c478bd9Sstevel@tonic-gate * header and a message body to the appropriate transport.
127*7c478bd9Sstevel@tonic-gate * The message header comprises an ident string and a message
128*7c478bd9Sstevel@tonic-gate * severity.
129*7c478bd9Sstevel@tonic-gate */
130*7c478bd9Sstevel@tonic-gate static void
bootlog_common(const char * ident,bootlog_severity_t severity,char * message)131*7c478bd9Sstevel@tonic-gate bootlog_common(const char *ident, bootlog_severity_t severity, char *message)
132*7c478bd9Sstevel@tonic-gate {
133*7c478bd9Sstevel@tonic-gate bl_transport_t entry_transport;
134*7c478bd9Sstevel@tonic-gate static int blrecurs;
135*7c478bd9Sstevel@tonic-gate static int blretry;
136*7c478bd9Sstevel@tonic-gate
137*7c478bd9Sstevel@tonic-gate /*
138*7c478bd9Sstevel@tonic-gate * This function may be called recursively because the HTTP code
139*7c478bd9Sstevel@tonic-gate * is a bootlog consumer. The blrecurs variable is used to determine
140*7c478bd9Sstevel@tonic-gate * whether or not the invocation is recursive.
141*7c478bd9Sstevel@tonic-gate */
142*7c478bd9Sstevel@tonic-gate blrecurs++;
143*7c478bd9Sstevel@tonic-gate entry_transport = bl_transport;
144*7c478bd9Sstevel@tonic-gate
145*7c478bd9Sstevel@tonic-gate /*
146*7c478bd9Sstevel@tonic-gate * If this is the first bootlog call then setup the transport.
147*7c478bd9Sstevel@tonic-gate * We only do this in a non-recursive invocation as openbootlog()
148*7c478bd9Sstevel@tonic-gate * results in a recursive call for a HTTP or HTTPS transport.
149*7c478bd9Sstevel@tonic-gate */
150*7c478bd9Sstevel@tonic-gate if (bl_transport == BL_NO_TRANSPORT && blrecurs == 1) {
151*7c478bd9Sstevel@tonic-gate rb_init(&ringbuffer);
152*7c478bd9Sstevel@tonic-gate bl_transport = openbootlog();
153*7c478bd9Sstevel@tonic-gate }
154*7c478bd9Sstevel@tonic-gate
155*7c478bd9Sstevel@tonic-gate /*
156*7c478bd9Sstevel@tonic-gate * If we're not there already, try to move up a level.
157*7c478bd9Sstevel@tonic-gate * This is necessary because our consumer may have begun
158*7c478bd9Sstevel@tonic-gate * logging before it had enough information to initialize
159*7c478bd9Sstevel@tonic-gate * its HTTP or HTTPS transport. We've arbitrarily decided
160*7c478bd9Sstevel@tonic-gate * that we'll only check to see if we should move up, on
161*7c478bd9Sstevel@tonic-gate * every third (blretry) non-recursive invocation.
162*7c478bd9Sstevel@tonic-gate */
163*7c478bd9Sstevel@tonic-gate if (blrecurs == 1 &&
164*7c478bd9Sstevel@tonic-gate !(bl_transport == BL_HTTPS || bl_transport == BL_HTTP)) {
165*7c478bd9Sstevel@tonic-gate if (blretry > 3) {
166*7c478bd9Sstevel@tonic-gate bl_transport = openbootlog();
167*7c478bd9Sstevel@tonic-gate blretry = 0;
168*7c478bd9Sstevel@tonic-gate } else
169*7c478bd9Sstevel@tonic-gate blretry++;
170*7c478bd9Sstevel@tonic-gate }
171*7c478bd9Sstevel@tonic-gate
172*7c478bd9Sstevel@tonic-gate if (entry_transport != bl_transport) {
173*7c478bd9Sstevel@tonic-gate switch (bl_transport) {
174*7c478bd9Sstevel@tonic-gate
175*7c478bd9Sstevel@tonic-gate case BL_CONSOLE:
176*7c478bd9Sstevel@tonic-gate (void) printf(
177*7c478bd9Sstevel@tonic-gate "%s wanboot info: WAN boot messages->console\n",
178*7c478bd9Sstevel@tonic-gate gettime());
179*7c478bd9Sstevel@tonic-gate break;
180*7c478bd9Sstevel@tonic-gate
181*7c478bd9Sstevel@tonic-gate case BL_HTTP:
182*7c478bd9Sstevel@tonic-gate case BL_HTTPS:
183*7c478bd9Sstevel@tonic-gate (void) printf(
184*7c478bd9Sstevel@tonic-gate "%s wanboot info: WAN boot messages->%s:%u\n",
185*7c478bd9Sstevel@tonic-gate gettime(), bl_url.hport.hostname,
186*7c478bd9Sstevel@tonic-gate bl_url.hport.port);
187*7c478bd9Sstevel@tonic-gate break;
188*7c478bd9Sstevel@tonic-gate
189*7c478bd9Sstevel@tonic-gate default:
190*7c478bd9Sstevel@tonic-gate break;
191*7c478bd9Sstevel@tonic-gate }
192*7c478bd9Sstevel@tonic-gate }
193*7c478bd9Sstevel@tonic-gate
194*7c478bd9Sstevel@tonic-gate /*
195*7c478bd9Sstevel@tonic-gate * Failed attempts and recursively generated log messages are
196*7c478bd9Sstevel@tonic-gate * sent to the fallback transport.
197*7c478bd9Sstevel@tonic-gate */
198*7c478bd9Sstevel@tonic-gate if (blrecurs > 1 || !sendmessage(bl_transport, message, ident,
199*7c478bd9Sstevel@tonic-gate severity, 0)) {
200*7c478bd9Sstevel@tonic-gate /*
201*7c478bd9Sstevel@tonic-gate * Fallback to a log file if one exists, or the console
202*7c478bd9Sstevel@tonic-gate * as a last resort. Note that bl_filehandle will always
203*7c478bd9Sstevel@tonic-gate * be NULL in standalone.
204*7c478bd9Sstevel@tonic-gate */
205*7c478bd9Sstevel@tonic-gate (void) sendmessage(bl_filehandle != NULL ? BL_LOCAL_FILE :
206*7c478bd9Sstevel@tonic-gate BL_CONSOLE, message, ident, severity, 1);
207*7c478bd9Sstevel@tonic-gate }
208*7c478bd9Sstevel@tonic-gate blrecurs--;
209*7c478bd9Sstevel@tonic-gate }
210*7c478bd9Sstevel@tonic-gate
211*7c478bd9Sstevel@tonic-gate /*
212*7c478bd9Sstevel@tonic-gate * bootlog() - the exposed interface for logging boot messages.
213*7c478bd9Sstevel@tonic-gate */
214*7c478bd9Sstevel@tonic-gate /* PRINTFLIKE3 */
215*7c478bd9Sstevel@tonic-gate void
bootlog(const char * ident,bootlog_severity_t severity,char * fmt,...)216*7c478bd9Sstevel@tonic-gate bootlog(const char *ident, bootlog_severity_t severity, char *fmt, ...)
217*7c478bd9Sstevel@tonic-gate {
218*7c478bd9Sstevel@tonic-gate char message[BOOTLOG_MSG_MAX_LEN];
219*7c478bd9Sstevel@tonic-gate va_list adx;
220*7c478bd9Sstevel@tonic-gate
221*7c478bd9Sstevel@tonic-gate va_start(adx, fmt);
222*7c478bd9Sstevel@tonic-gate (void) vsnprintf(message, BOOTLOG_MSG_MAX_LEN, fmt, adx);
223*7c478bd9Sstevel@tonic-gate va_end(adx);
224*7c478bd9Sstevel@tonic-gate
225*7c478bd9Sstevel@tonic-gate bootlog_common(ident, severity, message);
226*7c478bd9Sstevel@tonic-gate }
227*7c478bd9Sstevel@tonic-gate
228*7c478bd9Sstevel@tonic-gate /*
229*7c478bd9Sstevel@tonic-gate * libbootlog() - an internal interface for logging boot
230*7c478bd9Sstevel@tonic-gate * messages.
231*7c478bd9Sstevel@tonic-gate */
232*7c478bd9Sstevel@tonic-gate /* PRINTFLIKE2 */
233*7c478bd9Sstevel@tonic-gate void
libbootlog(bootlog_severity_t severity,char * fmt,...)234*7c478bd9Sstevel@tonic-gate libbootlog(bootlog_severity_t severity, char *fmt, ...)
235*7c478bd9Sstevel@tonic-gate {
236*7c478bd9Sstevel@tonic-gate char message[BOOTLOG_MSG_MAX_LEN];
237*7c478bd9Sstevel@tonic-gate va_list adx;
238*7c478bd9Sstevel@tonic-gate
239*7c478bd9Sstevel@tonic-gate va_start(adx, fmt);
240*7c478bd9Sstevel@tonic-gate (void) vsnprintf(message, BOOTLOG_MSG_MAX_LEN,
241*7c478bd9Sstevel@tonic-gate dgettext(TEXT_DOMAIN, fmt), adx);
242*7c478bd9Sstevel@tonic-gate va_end(adx);
243*7c478bd9Sstevel@tonic-gate
244*7c478bd9Sstevel@tonic-gate bootlog_common("libwanboot", severity, message);
245*7c478bd9Sstevel@tonic-gate }
246*7c478bd9Sstevel@tonic-gate
247*7c478bd9Sstevel@tonic-gate static boolean_t
send_http(void)248*7c478bd9Sstevel@tonic-gate send_http(void)
249*7c478bd9Sstevel@tonic-gate {
250*7c478bd9Sstevel@tonic-gate http_respinfo_t *resp = NULL;
251*7c478bd9Sstevel@tonic-gate char buffer[BOOTLOG_MAX_URL + (BOOTLOG_QS_MAX * 3)];
252*7c478bd9Sstevel@tonic-gate char ringmessage[BOOTLOG_QS_MAX];
253*7c478bd9Sstevel@tonic-gate char *lenstr;
254*7c478bd9Sstevel@tonic-gate size_t length;
255*7c478bd9Sstevel@tonic-gate int retries;
256*7c478bd9Sstevel@tonic-gate
257*7c478bd9Sstevel@tonic-gate while ((rb_read(&ringbuffer, ringmessage) != -1)) {
258*7c478bd9Sstevel@tonic-gate (void) snprintf(buffer, sizeof (buffer), "%s?%s",
259*7c478bd9Sstevel@tonic-gate bl_url.abspath, url_encode(ringmessage));
260*7c478bd9Sstevel@tonic-gate
261*7c478bd9Sstevel@tonic-gate for (retries = 0; retries < BOOTLOG_CONN_RETRIES; retries++) {
262*7c478bd9Sstevel@tonic-gate if (retries > 0) {
263*7c478bd9Sstevel@tonic-gate (void) http_srv_disconnect(bl_httphandle);
264*7c478bd9Sstevel@tonic-gate if (http_srv_connect(bl_httphandle) != 0)
265*7c478bd9Sstevel@tonic-gate continue;
266*7c478bd9Sstevel@tonic-gate }
267*7c478bd9Sstevel@tonic-gate
268*7c478bd9Sstevel@tonic-gate if (http_get_request(bl_httphandle, buffer) != 0 ||
269*7c478bd9Sstevel@tonic-gate http_process_headers(bl_httphandle, &resp) != 0)
270*7c478bd9Sstevel@tonic-gate continue;
271*7c478bd9Sstevel@tonic-gate
272*7c478bd9Sstevel@tonic-gate if (resp->code != 200) {
273*7c478bd9Sstevel@tonic-gate http_free_respinfo(resp);
274*7c478bd9Sstevel@tonic-gate continue;
275*7c478bd9Sstevel@tonic-gate }
276*7c478bd9Sstevel@tonic-gate
277*7c478bd9Sstevel@tonic-gate http_free_respinfo(resp);
278*7c478bd9Sstevel@tonic-gate lenstr = http_get_header_value(bl_httphandle,
279*7c478bd9Sstevel@tonic-gate "Content-Length");
280*7c478bd9Sstevel@tonic-gate length = strtol(lenstr, NULL, 10);
281*7c478bd9Sstevel@tonic-gate if (http_read_body(bl_httphandle, buffer, length) > 0)
282*7c478bd9Sstevel@tonic-gate break;
283*7c478bd9Sstevel@tonic-gate }
284*7c478bd9Sstevel@tonic-gate
285*7c478bd9Sstevel@tonic-gate /*
286*7c478bd9Sstevel@tonic-gate * The attempt to log the message failed. Back the
287*7c478bd9Sstevel@tonic-gate * read pointer up so that we'll try to log it again
288*7c478bd9Sstevel@tonic-gate * later.
289*7c478bd9Sstevel@tonic-gate */
290*7c478bd9Sstevel@tonic-gate if (retries == BOOTLOG_CONN_RETRIES) {
291*7c478bd9Sstevel@tonic-gate ringbuffer.r_ptr = ptr_decr(ringbuffer.r_ptr);
292*7c478bd9Sstevel@tonic-gate return (B_FALSE);
293*7c478bd9Sstevel@tonic-gate }
294*7c478bd9Sstevel@tonic-gate }
295*7c478bd9Sstevel@tonic-gate
296*7c478bd9Sstevel@tonic-gate return (B_TRUE);
297*7c478bd9Sstevel@tonic-gate }
298*7c478bd9Sstevel@tonic-gate
299*7c478bd9Sstevel@tonic-gate static boolean_t
sendmessage(bl_transport_t transport,char * message,const char * ident,bootlog_severity_t severity,int failure)300*7c478bd9Sstevel@tonic-gate sendmessage(bl_transport_t transport, char *message, const char *ident,
301*7c478bd9Sstevel@tonic-gate bootlog_severity_t severity, int failure)
302*7c478bd9Sstevel@tonic-gate {
303*7c478bd9Sstevel@tonic-gate static char *progtype = NULL;
304*7c478bd9Sstevel@tonic-gate char ringmessage[BOOTLOG_QS_MAX];
305*7c478bd9Sstevel@tonic-gate char hostname[MAXHOSTNAMELEN];
306*7c478bd9Sstevel@tonic-gate uint32_t msgid;
307*7c478bd9Sstevel@tonic-gate boolean_t ret;
308*7c478bd9Sstevel@tonic-gate int i;
309*7c478bd9Sstevel@tonic-gate
310*7c478bd9Sstevel@tonic-gate /*
311*7c478bd9Sstevel@tonic-gate * In standalone, only log VERBOSE and DEBUG messages if the
312*7c478bd9Sstevel@tonic-gate * corresponding flag (-V or -d) has been passed to boot.
313*7c478bd9Sstevel@tonic-gate *
314*7c478bd9Sstevel@tonic-gate * Note that some bootlog() consumers impose additional constraints on
315*7c478bd9Sstevel@tonic-gate * printing these messages -- for instance, http_set_verbose() must be
316*7c478bd9Sstevel@tonic-gate * used before the HTTP code will call bootlog() with BOOTLOG_VERBOSE
317*7c478bd9Sstevel@tonic-gate * messages.
318*7c478bd9Sstevel@tonic-gate */
319*7c478bd9Sstevel@tonic-gate #ifdef _BOOT
320*7c478bd9Sstevel@tonic-gate if (severity == BOOTLOG_DEBUG && !(boothowto & RB_DEBUG))
321*7c478bd9Sstevel@tonic-gate return (B_TRUE);
322*7c478bd9Sstevel@tonic-gate if (severity == BOOTLOG_VERBOSE && !verbosemode)
323*7c478bd9Sstevel@tonic-gate return (B_TRUE);
324*7c478bd9Sstevel@tonic-gate #endif
325*7c478bd9Sstevel@tonic-gate
326*7c478bd9Sstevel@tonic-gate for (i = 0; pri_names[i].c_val != NOPRI; i++) {
327*7c478bd9Sstevel@tonic-gate if (severity == pri_names[i].c_val)
328*7c478bd9Sstevel@tonic-gate break;
329*7c478bd9Sstevel@tonic-gate }
330*7c478bd9Sstevel@tonic-gate
331*7c478bd9Sstevel@tonic-gate /*
332*7c478bd9Sstevel@tonic-gate * VERBOSE and DEBUG messages always go to the console
333*7c478bd9Sstevel@tonic-gate */
334*7c478bd9Sstevel@tonic-gate if (transport != BL_CONSOLE &&
335*7c478bd9Sstevel@tonic-gate (severity == BOOTLOG_DEBUG || severity == BOOTLOG_VERBOSE)) {
336*7c478bd9Sstevel@tonic-gate (void) printf("%s %s %s: %s\n", gettime(), ident,
337*7c478bd9Sstevel@tonic-gate pri_names[i].c_name, message);
338*7c478bd9Sstevel@tonic-gate }
339*7c478bd9Sstevel@tonic-gate
340*7c478bd9Sstevel@tonic-gate STRLOG_MAKE_MSGID(message, msgid);
341*7c478bd9Sstevel@tonic-gate (void) gethostname(hostname, sizeof (hostname));
342*7c478bd9Sstevel@tonic-gate
343*7c478bd9Sstevel@tonic-gate /*
344*7c478bd9Sstevel@tonic-gate * Note that in this case, "<time>" is a placeholder that will be used
345*7c478bd9Sstevel@tonic-gate * to fill in the actual time on the remote end.
346*7c478bd9Sstevel@tonic-gate */
347*7c478bd9Sstevel@tonic-gate (void) snprintf(ringmessage, sizeof (ringmessage),
348*7c478bd9Sstevel@tonic-gate "<time> %s %s: [ID %u user.%s] %s", hostname, ident, msgid,
349*7c478bd9Sstevel@tonic-gate pri_names[i].c_name, message);
350*7c478bd9Sstevel@tonic-gate
351*7c478bd9Sstevel@tonic-gate /*
352*7c478bd9Sstevel@tonic-gate * Prevent duplicate messages from being inserted into
353*7c478bd9Sstevel@tonic-gate * the ring buffer.
354*7c478bd9Sstevel@tonic-gate */
355*7c478bd9Sstevel@tonic-gate if (failure == 0) {
356*7c478bd9Sstevel@tonic-gate rb_write(&ringbuffer, ringmessage);
357*7c478bd9Sstevel@tonic-gate }
358*7c478bd9Sstevel@tonic-gate
359*7c478bd9Sstevel@tonic-gate switch (transport) {
360*7c478bd9Sstevel@tonic-gate case BL_CONSOLE:
361*7c478bd9Sstevel@tonic-gate /*
362*7c478bd9Sstevel@tonic-gate * PROGRESS messages update in-place on the console, as long
363*7c478bd9Sstevel@tonic-gate * as they are of the same 'progress type' (see below) --
364*7c478bd9Sstevel@tonic-gate * if not, reset the progress information.
365*7c478bd9Sstevel@tonic-gate */
366*7c478bd9Sstevel@tonic-gate if (progtype != NULL && (severity != BOOTLOG_PROGRESS ||
367*7c478bd9Sstevel@tonic-gate strncmp(progtype, message, strlen(progtype)) != 0)) {
368*7c478bd9Sstevel@tonic-gate (void) printf("\n");
369*7c478bd9Sstevel@tonic-gate free(progtype);
370*7c478bd9Sstevel@tonic-gate progtype = NULL;
371*7c478bd9Sstevel@tonic-gate }
372*7c478bd9Sstevel@tonic-gate
373*7c478bd9Sstevel@tonic-gate (void) printf("%s %s %s: %s\r", gettime(), ident,
374*7c478bd9Sstevel@tonic-gate pri_names[i].c_name, message);
375*7c478bd9Sstevel@tonic-gate
376*7c478bd9Sstevel@tonic-gate if (severity != BOOTLOG_PROGRESS) {
377*7c478bd9Sstevel@tonic-gate (void) printf("\n");
378*7c478bd9Sstevel@tonic-gate } else if (progtype == NULL) {
379*7c478bd9Sstevel@tonic-gate /*
380*7c478bd9Sstevel@tonic-gate * New progress message; save its "type" (the part
381*7c478bd9Sstevel@tonic-gate * of the message up to and including the first
382*7c478bd9Sstevel@tonic-gate * colon). This should be made less clumsy in the
383*7c478bd9Sstevel@tonic-gate * future.
384*7c478bd9Sstevel@tonic-gate */
385*7c478bd9Sstevel@tonic-gate progtype = strdup(message);
386*7c478bd9Sstevel@tonic-gate if (progtype != NULL) {
387*7c478bd9Sstevel@tonic-gate for (i = 0; progtype[i] != '\0'; i++) {
388*7c478bd9Sstevel@tonic-gate if (progtype[i] == ':') {
389*7c478bd9Sstevel@tonic-gate progtype[++i] = '\0';
390*7c478bd9Sstevel@tonic-gate break;
391*7c478bd9Sstevel@tonic-gate }
392*7c478bd9Sstevel@tonic-gate }
393*7c478bd9Sstevel@tonic-gate }
394*7c478bd9Sstevel@tonic-gate }
395*7c478bd9Sstevel@tonic-gate ret = B_TRUE;
396*7c478bd9Sstevel@tonic-gate break;
397*7c478bd9Sstevel@tonic-gate
398*7c478bd9Sstevel@tonic-gate case BL_LOCAL_FILE:
399*7c478bd9Sstevel@tonic-gate if (bl_filehandle == NULL)
400*7c478bd9Sstevel@tonic-gate return (B_FALSE);
401*7c478bd9Sstevel@tonic-gate
402*7c478bd9Sstevel@tonic-gate (void) fprintf(bl_filehandle, "%s %s %s: [ID %u user.%s] %s\n",
403*7c478bd9Sstevel@tonic-gate gettime(), hostname, ident, msgid, pri_names[i].c_name,
404*7c478bd9Sstevel@tonic-gate message);
405*7c478bd9Sstevel@tonic-gate ret = B_TRUE;
406*7c478bd9Sstevel@tonic-gate break;
407*7c478bd9Sstevel@tonic-gate
408*7c478bd9Sstevel@tonic-gate case BL_HTTP:
409*7c478bd9Sstevel@tonic-gate case BL_HTTPS:
410*7c478bd9Sstevel@tonic-gate if (bl_httphandle == NULL)
411*7c478bd9Sstevel@tonic-gate return (B_FALSE);
412*7c478bd9Sstevel@tonic-gate ret = send_http();
413*7c478bd9Sstevel@tonic-gate break;
414*7c478bd9Sstevel@tonic-gate
415*7c478bd9Sstevel@tonic-gate case BL_NO_TRANSPORT:
416*7c478bd9Sstevel@tonic-gate default:
417*7c478bd9Sstevel@tonic-gate ret = B_FALSE;
418*7c478bd9Sstevel@tonic-gate }
419*7c478bd9Sstevel@tonic-gate
420*7c478bd9Sstevel@tonic-gate return (ret);
421*7c478bd9Sstevel@tonic-gate }
422*7c478bd9Sstevel@tonic-gate
423*7c478bd9Sstevel@tonic-gate static bl_transport_t
openbootlog(void)424*7c478bd9Sstevel@tonic-gate openbootlog(void)
425*7c478bd9Sstevel@tonic-gate {
426*7c478bd9Sstevel@tonic-gate static boolean_t got_boot_logger = B_FALSE;
427*7c478bd9Sstevel@tonic-gate static boolean_t bl_url_valid = B_FALSE;
428*7c478bd9Sstevel@tonic-gate static boolean_t clientauth = B_FALSE;
429*7c478bd9Sstevel@tonic-gate static bc_handle_t bootconf_handle;
430*7c478bd9Sstevel@tonic-gate bl_transport_t transport;
431*7c478bd9Sstevel@tonic-gate
432*7c478bd9Sstevel@tonic-gate /*
433*7c478bd9Sstevel@tonic-gate * We try to use a logfile in userland since our consumer (install)
434*7c478bd9Sstevel@tonic-gate * needs complete control over the terminal.
435*7c478bd9Sstevel@tonic-gate */
436*7c478bd9Sstevel@tonic-gate #ifndef _BOOT
437*7c478bd9Sstevel@tonic-gate if (bl_filehandle == NULL)
438*7c478bd9Sstevel@tonic-gate bl_filehandle = fopen("/var/log/bootlog", "a");
439*7c478bd9Sstevel@tonic-gate #endif
440*7c478bd9Sstevel@tonic-gate transport = (bl_filehandle != NULL) ? BL_LOCAL_FILE : BL_CONSOLE;
441*7c478bd9Sstevel@tonic-gate
442*7c478bd9Sstevel@tonic-gate /*
443*7c478bd9Sstevel@tonic-gate * If we haven't already been able to access wanboot.conf for a
444*7c478bd9Sstevel@tonic-gate * boot_logger URL, see if we can now.
445*7c478bd9Sstevel@tonic-gate */
446*7c478bd9Sstevel@tonic-gate if (!got_boot_logger &&
447*7c478bd9Sstevel@tonic-gate bootconf_init(&bootconf_handle, NULL) == BC_SUCCESS) {
448*7c478bd9Sstevel@tonic-gate char *urlstr;
449*7c478bd9Sstevel@tonic-gate char *cas;
450*7c478bd9Sstevel@tonic-gate
451*7c478bd9Sstevel@tonic-gate /*
452*7c478bd9Sstevel@tonic-gate * If there is a boot_logger, ensure that it's is a legal URL.
453*7c478bd9Sstevel@tonic-gate */
454*7c478bd9Sstevel@tonic-gate if ((urlstr = bootconf_get(&bootconf_handle,
455*7c478bd9Sstevel@tonic-gate BC_BOOT_LOGGER)) != NULL &&
456*7c478bd9Sstevel@tonic-gate url_parse(urlstr, &bl_url) == URL_PARSE_SUCCESS) {
457*7c478bd9Sstevel@tonic-gate bl_url_valid = B_TRUE;
458*7c478bd9Sstevel@tonic-gate }
459*7c478bd9Sstevel@tonic-gate
460*7c478bd9Sstevel@tonic-gate /*
461*7c478bd9Sstevel@tonic-gate * If the boot_logger URL uses an HTTPS scheme, see if
462*7c478bd9Sstevel@tonic-gate * client authentication is specified.
463*7c478bd9Sstevel@tonic-gate */
464*7c478bd9Sstevel@tonic-gate if (bl_url.https) {
465*7c478bd9Sstevel@tonic-gate cas = bootconf_get(&bootconf_handle,
466*7c478bd9Sstevel@tonic-gate BC_CLIENT_AUTHENTICATION);
467*7c478bd9Sstevel@tonic-gate if (cas != NULL) {
468*7c478bd9Sstevel@tonic-gate clientauth = (strcmp(cas, BC_YES) == 0);
469*7c478bd9Sstevel@tonic-gate }
470*7c478bd9Sstevel@tonic-gate }
471*7c478bd9Sstevel@tonic-gate
472*7c478bd9Sstevel@tonic-gate bootconf_end(&bootconf_handle);
473*7c478bd9Sstevel@tonic-gate
474*7c478bd9Sstevel@tonic-gate /*
475*7c478bd9Sstevel@tonic-gate * Having now accessed wanboot.conf, remember not to come
476*7c478bd9Sstevel@tonic-gate * this way again; the value of boot_logger cannot change.
477*7c478bd9Sstevel@tonic-gate */
478*7c478bd9Sstevel@tonic-gate got_boot_logger = B_TRUE;
479*7c478bd9Sstevel@tonic-gate }
480*7c478bd9Sstevel@tonic-gate
481*7c478bd9Sstevel@tonic-gate /*
482*7c478bd9Sstevel@tonic-gate * If there is no legal boot_logger URL available, then we're done.
483*7c478bd9Sstevel@tonic-gate */
484*7c478bd9Sstevel@tonic-gate if (!bl_url_valid) {
485*7c478bd9Sstevel@tonic-gate return (transport);
486*7c478bd9Sstevel@tonic-gate }
487*7c478bd9Sstevel@tonic-gate
488*7c478bd9Sstevel@tonic-gate /*
489*7c478bd9Sstevel@tonic-gate * If we don't already have a bl_httphandle, try to get one.
490*7c478bd9Sstevel@tonic-gate * If we fail, then we're done.
491*7c478bd9Sstevel@tonic-gate */
492*7c478bd9Sstevel@tonic-gate if (bl_httphandle == NULL) {
493*7c478bd9Sstevel@tonic-gate bl_httphandle = http_srv_init(&bl_url);
494*7c478bd9Sstevel@tonic-gate if (bl_httphandle == NULL) {
495*7c478bd9Sstevel@tonic-gate return (transport);
496*7c478bd9Sstevel@tonic-gate }
497*7c478bd9Sstevel@tonic-gate }
498*7c478bd9Sstevel@tonic-gate
499*7c478bd9Sstevel@tonic-gate /*
500*7c478bd9Sstevel@tonic-gate * If we succeed in setting up the connection,
501*7c478bd9Sstevel@tonic-gate * then we use the connection as our transport.
502*7c478bd9Sstevel@tonic-gate * Otherwise, we use the transport we've already
503*7c478bd9Sstevel@tonic-gate * determined above.
504*7c478bd9Sstevel@tonic-gate */
505*7c478bd9Sstevel@tonic-gate if (setup_con(bl_httphandle, bl_url.https, clientauth)) {
506*7c478bd9Sstevel@tonic-gate transport = bl_url.https ? BL_HTTPS : BL_HTTP;
507*7c478bd9Sstevel@tonic-gate }
508*7c478bd9Sstevel@tonic-gate
509*7c478bd9Sstevel@tonic-gate return (transport);
510*7c478bd9Sstevel@tonic-gate }
511*7c478bd9Sstevel@tonic-gate
512*7c478bd9Sstevel@tonic-gate static boolean_t
setup_con(http_handle_t handle,boolean_t https,boolean_t client_auth)513*7c478bd9Sstevel@tonic-gate setup_con(http_handle_t handle, boolean_t https, boolean_t client_auth)
514*7c478bd9Sstevel@tonic-gate {
515*7c478bd9Sstevel@tonic-gate static boolean_t got_proxy = B_FALSE;
516*7c478bd9Sstevel@tonic-gate static boolean_t proxy_valid = B_FALSE;
517*7c478bd9Sstevel@tonic-gate static url_hport_t proxy;
518*7c478bd9Sstevel@tonic-gate int i;
519*7c478bd9Sstevel@tonic-gate
520*7c478bd9Sstevel@tonic-gate /*
521*7c478bd9Sstevel@tonic-gate * If an HTTPS scheme is specified, then check that time
522*7c478bd9Sstevel@tonic-gate * has been initialized.
523*7c478bd9Sstevel@tonic-gate * If time() returns a non-zero value, then we know
524*7c478bd9Sstevel@tonic-gate * that the boot file system has been mounted and that
525*7c478bd9Sstevel@tonic-gate * we have a trusted time.
526*7c478bd9Sstevel@tonic-gate */
527*7c478bd9Sstevel@tonic-gate if (https && time(0) == 0)
528*7c478bd9Sstevel@tonic-gate return (B_FALSE);
529*7c478bd9Sstevel@tonic-gate
530*7c478bd9Sstevel@tonic-gate if (!got_proxy && bootinfo_init()) {
531*7c478bd9Sstevel@tonic-gate char hpstr[URL_MAX_STRLEN];
532*7c478bd9Sstevel@tonic-gate size_t vallen = sizeof (hpstr);
533*7c478bd9Sstevel@tonic-gate
534*7c478bd9Sstevel@tonic-gate /*
535*7c478bd9Sstevel@tonic-gate * If there is a http-proxy, ensure that it's a legal host:port.
536*7c478bd9Sstevel@tonic-gate */
537*7c478bd9Sstevel@tonic-gate if (bootinfo_get(BI_HTTP_PROXY, hpstr, &vallen, NULL) ==
538*7c478bd9Sstevel@tonic-gate BI_E_SUCCESS && vallen > 0) {
539*7c478bd9Sstevel@tonic-gate hpstr[vallen] = '\0';
540*7c478bd9Sstevel@tonic-gate if (url_parse_hostport(hpstr, &proxy,
541*7c478bd9Sstevel@tonic-gate URL_DFLT_PROXY_PORT) == URL_PARSE_SUCCESS) {
542*7c478bd9Sstevel@tonic-gate proxy_valid = B_TRUE;
543*7c478bd9Sstevel@tonic-gate }
544*7c478bd9Sstevel@tonic-gate }
545*7c478bd9Sstevel@tonic-gate
546*7c478bd9Sstevel@tonic-gate got_proxy = B_TRUE;
547*7c478bd9Sstevel@tonic-gate }
548*7c478bd9Sstevel@tonic-gate if (proxy_valid && http_set_proxy(handle, &proxy) != 0)
549*7c478bd9Sstevel@tonic-gate return (B_FALSE);
550*7c478bd9Sstevel@tonic-gate
551*7c478bd9Sstevel@tonic-gate (void) http_set_keepalive(handle, 1);
552*7c478bd9Sstevel@tonic-gate (void) http_set_socket_read_timeout(handle, BOOTLOG_HTTP_TIMEOUT);
553*7c478bd9Sstevel@tonic-gate
554*7c478bd9Sstevel@tonic-gate /*
555*7c478bd9Sstevel@tonic-gate * If an HTTPS scheme is specified, then setup the necessary
556*7c478bd9Sstevel@tonic-gate * SSL context for the connection
557*7c478bd9Sstevel@tonic-gate */
558*7c478bd9Sstevel@tonic-gate if (https) {
559*7c478bd9Sstevel@tonic-gate if (http_set_random_file(handle, "/dev/urandom") == -1)
560*7c478bd9Sstevel@tonic-gate return (B_FALSE);
561*7c478bd9Sstevel@tonic-gate
562*7c478bd9Sstevel@tonic-gate if (http_set_certificate_authority_file(NB_CA_CERT_PATH) < 0)
563*7c478bd9Sstevel@tonic-gate return (B_FALSE);
564*7c478bd9Sstevel@tonic-gate
565*7c478bd9Sstevel@tonic-gate /*
566*7c478bd9Sstevel@tonic-gate * The client certificate and key will not exist unless
567*7c478bd9Sstevel@tonic-gate * client authentication has been configured. If it is
568*7c478bd9Sstevel@tonic-gate * configured then the webserver will have added these
569*7c478bd9Sstevel@tonic-gate * files to the wanboot file system and the HTTP library
570*7c478bd9Sstevel@tonic-gate * needs to be made aware of their existence.
571*7c478bd9Sstevel@tonic-gate */
572*7c478bd9Sstevel@tonic-gate if (client_auth) {
573*7c478bd9Sstevel@tonic-gate if (http_set_client_certificate_file(handle,
574*7c478bd9Sstevel@tonic-gate NB_CLIENT_CERT_PATH) < 0) {
575*7c478bd9Sstevel@tonic-gate return (B_FALSE);
576*7c478bd9Sstevel@tonic-gate }
577*7c478bd9Sstevel@tonic-gate
578*7c478bd9Sstevel@tonic-gate if (http_set_private_key_file(handle,
579*7c478bd9Sstevel@tonic-gate NB_CLIENT_KEY_PATH) < 0) {
580*7c478bd9Sstevel@tonic-gate return (B_FALSE);
581*7c478bd9Sstevel@tonic-gate }
582*7c478bd9Sstevel@tonic-gate }
583*7c478bd9Sstevel@tonic-gate
584*7c478bd9Sstevel@tonic-gate if (http_set_password(handle, WANBOOT_PASSPHRASE) < 0)
585*7c478bd9Sstevel@tonic-gate return (B_FALSE);
586*7c478bd9Sstevel@tonic-gate }
587*7c478bd9Sstevel@tonic-gate
588*7c478bd9Sstevel@tonic-gate for (i = 0; i < BOOTLOG_CONN_RETRIES; i++) {
589*7c478bd9Sstevel@tonic-gate if (http_srv_connect(handle) == 0)
590*7c478bd9Sstevel@tonic-gate return (B_TRUE);
591*7c478bd9Sstevel@tonic-gate
592*7c478bd9Sstevel@tonic-gate (void) http_srv_disconnect(handle);
593*7c478bd9Sstevel@tonic-gate }
594*7c478bd9Sstevel@tonic-gate
595*7c478bd9Sstevel@tonic-gate return (B_FALSE);
596*7c478bd9Sstevel@tonic-gate }
597*7c478bd9Sstevel@tonic-gate
598*7c478bd9Sstevel@tonic-gate static char *
url_encode(const char * ibufp)599*7c478bd9Sstevel@tonic-gate url_encode(const char *ibufp)
600*7c478bd9Sstevel@tonic-gate {
601*7c478bd9Sstevel@tonic-gate int i;
602*7c478bd9Sstevel@tonic-gate char c;
603*7c478bd9Sstevel@tonic-gate unsigned char nibble;
604*7c478bd9Sstevel@tonic-gate static char obuff[BOOTLOG_QS_MAX * 3];
605*7c478bd9Sstevel@tonic-gate char *obufp = obuff;
606*7c478bd9Sstevel@tonic-gate
607*7c478bd9Sstevel@tonic-gate /*
608*7c478bd9Sstevel@tonic-gate * Encode special characters as outlined in RFC2396.
609*7c478bd9Sstevel@tonic-gate *
610*7c478bd9Sstevel@tonic-gate * Special characters are encoded as a triplets beginning
611*7c478bd9Sstevel@tonic-gate * with '%' followed by the two hexidecimal digits representing
612*7c478bd9Sstevel@tonic-gate * the octet code. The space character is special. It can be encoded
613*7c478bd9Sstevel@tonic-gate * simply as a '+'.
614*7c478bd9Sstevel@tonic-gate */
615*7c478bd9Sstevel@tonic-gate while ((c = *ibufp++) != '\0') {
616*7c478bd9Sstevel@tonic-gate /*
617*7c478bd9Sstevel@tonic-gate * Is the character one of the special characters
618*7c478bd9Sstevel@tonic-gate * that require encoding? If so append '%' to the output
619*7c478bd9Sstevel@tonic-gate * buffer follow that by the hexascii value.
620*7c478bd9Sstevel@tonic-gate */
621*7c478bd9Sstevel@tonic-gate if (strchr("/?{}|^~[]`<>#%=\"\t", c) != NULL) {
622*7c478bd9Sstevel@tonic-gate *obufp++ = '%';
623*7c478bd9Sstevel@tonic-gate /*
624*7c478bd9Sstevel@tonic-gate * Compute the character's hex value and
625*7c478bd9Sstevel@tonic-gate * convert it to ASCII. That is two nibbles
626*7c478bd9Sstevel@tonic-gate * per character.
627*7c478bd9Sstevel@tonic-gate */
628*7c478bd9Sstevel@tonic-gate for (i = 1; i >= 0; i--) {
629*7c478bd9Sstevel@tonic-gate nibble = ((uchar_t)c >> (4 * i)) & 0x0f;
630*7c478bd9Sstevel@tonic-gate /*
631*7c478bd9Sstevel@tonic-gate * If the hex digit is 0xa - 0xf, then
632*7c478bd9Sstevel@tonic-gate * compute its ASCII value by adding 0x37
633*7c478bd9Sstevel@tonic-gate * else 0x0 - 0x9 just add 0x30.
634*7c478bd9Sstevel@tonic-gate */
635*7c478bd9Sstevel@tonic-gate if (nibble > 0x9)
636*7c478bd9Sstevel@tonic-gate nibble += 0x37;
637*7c478bd9Sstevel@tonic-gate else
638*7c478bd9Sstevel@tonic-gate nibble += 0x30;
639*7c478bd9Sstevel@tonic-gate *obufp++ = nibble;
640*7c478bd9Sstevel@tonic-gate }
641*7c478bd9Sstevel@tonic-gate /*
642*7c478bd9Sstevel@tonic-gate * The space character gets a special mapping.
643*7c478bd9Sstevel@tonic-gate */
644*7c478bd9Sstevel@tonic-gate } else if (c == ' ') {
645*7c478bd9Sstevel@tonic-gate *obufp++ = '+';
646*7c478bd9Sstevel@tonic-gate
647*7c478bd9Sstevel@tonic-gate /*
648*7c478bd9Sstevel@tonic-gate * Append the rest (sans any CR character)
649*7c478bd9Sstevel@tonic-gate */
650*7c478bd9Sstevel@tonic-gate } else if (c != '\n') {
651*7c478bd9Sstevel@tonic-gate *obufp++ = c;
652*7c478bd9Sstevel@tonic-gate }
653*7c478bd9Sstevel@tonic-gate }
654*7c478bd9Sstevel@tonic-gate *obufp = '\0';
655*7c478bd9Sstevel@tonic-gate return (obuff);
656*7c478bd9Sstevel@tonic-gate }
657*7c478bd9Sstevel@tonic-gate
658*7c478bd9Sstevel@tonic-gate static void
rb_init(struct ringbuffer_t * buffer)659*7c478bd9Sstevel@tonic-gate rb_init(struct ringbuffer_t *buffer)
660*7c478bd9Sstevel@tonic-gate {
661*7c478bd9Sstevel@tonic-gate int i;
662*7c478bd9Sstevel@tonic-gate
663*7c478bd9Sstevel@tonic-gate buffer->w_ptr = 0;
664*7c478bd9Sstevel@tonic-gate buffer->r_ptr = 0;
665*7c478bd9Sstevel@tonic-gate
666*7c478bd9Sstevel@tonic-gate for (i = 0; i < BOOTLOG_RING_NELEM; i++)
667*7c478bd9Sstevel@tonic-gate buffer->entries[i].message[0] = '\0';
668*7c478bd9Sstevel@tonic-gate }
669*7c478bd9Sstevel@tonic-gate
670*7c478bd9Sstevel@tonic-gate static int
ptr_incr(int ptr)671*7c478bd9Sstevel@tonic-gate ptr_incr(int ptr)
672*7c478bd9Sstevel@tonic-gate {
673*7c478bd9Sstevel@tonic-gate if (++ptr < BOOTLOG_RING_NELEM)
674*7c478bd9Sstevel@tonic-gate return (ptr);
675*7c478bd9Sstevel@tonic-gate else
676*7c478bd9Sstevel@tonic-gate return (0);
677*7c478bd9Sstevel@tonic-gate }
678*7c478bd9Sstevel@tonic-gate
679*7c478bd9Sstevel@tonic-gate static int
ptr_decr(int ptr)680*7c478bd9Sstevel@tonic-gate ptr_decr(int ptr)
681*7c478bd9Sstevel@tonic-gate {
682*7c478bd9Sstevel@tonic-gate if (ptr == 0)
683*7c478bd9Sstevel@tonic-gate return (BOOTLOG_RING_NELEM - 1);
684*7c478bd9Sstevel@tonic-gate else
685*7c478bd9Sstevel@tonic-gate return (--ptr);
686*7c478bd9Sstevel@tonic-gate }
687*7c478bd9Sstevel@tonic-gate
688*7c478bd9Sstevel@tonic-gate static void
rb_write(struct ringbuffer_t * buffer,const char * buff)689*7c478bd9Sstevel@tonic-gate rb_write(struct ringbuffer_t *buffer, const char *buff)
690*7c478bd9Sstevel@tonic-gate {
691*7c478bd9Sstevel@tonic-gate (void) strlcpy(buffer->entries[buffer->w_ptr].message, buff,
692*7c478bd9Sstevel@tonic-gate BOOTLOG_QS_MAX);
693*7c478bd9Sstevel@tonic-gate buffer->w_ptr = ptr_incr(buffer->w_ptr);
694*7c478bd9Sstevel@tonic-gate if (buffer->r_ptr == buffer->w_ptr)
695*7c478bd9Sstevel@tonic-gate buffer->r_ptr = ptr_incr(buffer->r_ptr);
696*7c478bd9Sstevel@tonic-gate }
697*7c478bd9Sstevel@tonic-gate
698*7c478bd9Sstevel@tonic-gate static int
rb_read(struct ringbuffer_t * buffer,char * buff)699*7c478bd9Sstevel@tonic-gate rb_read(struct ringbuffer_t *buffer, char *buff)
700*7c478bd9Sstevel@tonic-gate {
701*7c478bd9Sstevel@tonic-gate if (buffer->r_ptr != buffer->w_ptr) {
702*7c478bd9Sstevel@tonic-gate (void) strlcpy(buff, buffer->entries[buffer->r_ptr].message,
703*7c478bd9Sstevel@tonic-gate BOOTLOG_QS_MAX);
704*7c478bd9Sstevel@tonic-gate buffer->r_ptr = ptr_incr(buffer->r_ptr);
705*7c478bd9Sstevel@tonic-gate return (0);
706*7c478bd9Sstevel@tonic-gate }
707*7c478bd9Sstevel@tonic-gate return (-1);
708*7c478bd9Sstevel@tonic-gate }
709