1 // Copyright 2016 The Fuchsia Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "util.h"
6 
7 #pragma GCC visibility push(hidden)
8 
9 #include <assert.h>
10 #include <zircon/syscalls.h>
11 #include <zircon/syscalls/log.h>
12 #include <stdarg.h>
13 #include <string.h>
14 
15 #pragma GCC visibility pop
16 
17 #define LOG_PREFIX "userboot: "
18 #define LOG_WRITE_FAIL \
19     (LOG_PREFIX "Error printing error message.  No error message printed.\n")
20 
hexstring(char * s,size_t len,uint64_t n)21 static char* hexstring(char* s, size_t len, uint64_t n) {
22     char tmp[16];
23     char* hex = tmp;
24     do {
25         *hex++ = "0123456789abcdef"[n & 15];
26         n >>= 4;
27     } while (n);
28 
29     if (len > 2) {
30         *s++ = '0';
31         *s++ = 'x';
32         len -= 2;
33     }
34 
35     while ((hex > tmp) && (len > 0)) {
36         *s++ = *--hex;
37         len--;
38     }
39     return s;
40 }
41 
u64string(char * s,size_t len,uint64_t n)42 static char* u64string(char* s, size_t len, uint64_t n) {
43     char tmp[21]; // strlen(maxint64) + 1
44     char* dec = tmp;
45     do {
46         *dec++ = "0123456789"[n % 10];
47         n /= 10;
48     } while (n > 0);
49 
50     while ((dec > tmp) && (len > 0)) {
51         *s++ = *--dec;
52         len--;
53     }
54     return s;
55 }
56 
i64string(char * s,size_t len,int64_t n)57 static char* i64string(char* s, size_t len, int64_t n) {
58     if (n < 0) {
59         // this will never be called with len < 1 so we
60         // don't need to check for len
61         n = -n;
62         *s++ = '-';
63         len--;
64     }
65     return u64string(s, len, n);
66 }
67 
vprintl(zx_handle_t log,const char * fmt,va_list ap)68 void vprintl(zx_handle_t log, const char* fmt, va_list ap) {
69     char buffer[ZX_LOG_RECORD_MAX - sizeof(zx_log_record_t)];
70     static_assert(sizeof(LOG_PREFIX) < sizeof(buffer), "buffer too small");
71 
72     memcpy(buffer, LOG_PREFIX, sizeof(LOG_PREFIX) - 1);
73     char* p = &buffer[sizeof(LOG_PREFIX) - 1];
74 
75     size_t avail;
76     const char* s;
77     uint64_t n;
78     int64_t i;
79 
80     while (*fmt && (avail = (size_t)(&buffer[sizeof(buffer)] - p))) {
81         if (*fmt != '%') {
82             *p++ = *fmt++;
83             continue;
84         }
85         switch (*++fmt) {
86         case 's':
87             s = va_arg(ap, const char*);
88             while (avail && *s) {
89                 *p++ = *s++;
90                 avail--;
91             }
92             break;
93         case '.':
94             fmt++;
95             if (*fmt != '*')
96                 goto bad_format;
97             fmt++;
98             if (*fmt != 's')
99                 goto bad_format;
100             i = va_arg(ap, int);
101             s = va_arg(ap, const char*);
102             while (avail && *s && i != 0) {
103                 *p++ = *s++;
104                 avail--;
105                 if (i > 0)
106                     --i;
107             }
108             break;
109         case 'z':
110             fmt++;
111             switch (*fmt) {
112             case 'u':
113                 n = va_arg(ap, uint64_t);
114                 goto u64print;
115             case 'd':
116                 i = va_arg(ap, int64_t);
117                 goto i64print;
118             case 'x':
119                 n = va_arg(ap, uint64_t);
120                 goto x64print;
121             default:
122                 goto bad_format;
123             }
124             break;
125         case 'p':
126             n = va_arg(ap, uint64_t);
127             goto x64print;
128         case 'u':
129             n = va_arg(ap, uint32_t);
130 u64print:
131             p = u64string(p, avail, n);
132             break;
133         case 'd':
134             i = va_arg(ap, int32_t);
135 i64print:
136             p = i64string(p, avail, i);
137             break;
138         case 'x':
139             n = va_arg(ap, uint32_t);
140 x64print:
141             p = hexstring(p, avail, n);
142             break;
143         default:
144 bad_format:
145             printl(log, "printl: invalid fmt char 0x%x", *fmt);
146             zx_process_exit(-1);
147         }
148         fmt++;
149     }
150 
151     if ((log == ZX_HANDLE_INVALID) ||
152         (zx_debuglog_write(log, 0, buffer, p - buffer) != ZX_OK)) {
153         zx_debug_write(buffer, p - buffer);
154         zx_debug_write("\n", 1);
155     }
156 }
157 
printl(zx_handle_t log,const char * fmt,...)158 void printl(zx_handle_t log, const char* fmt, ...) {
159     va_list ap;
160     va_start(ap, fmt);
161     vprintl(log, fmt, ap);
162     va_end(ap);
163 }
164 
fail(zx_handle_t log,const char * fmt,...)165 void fail(zx_handle_t log, const char* fmt, ...) {
166     va_list ap;
167     va_start(ap, fmt);
168     vprintl(log, fmt, ap);
169     va_end(ap);
170     zx_process_exit(-1);
171 }
172