]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/boot/efi/efi-string.c
tree-wide: "<n>bit" → "<n>-bit"
[thirdparty/systemd.git] / src / boot / efi / efi-string.c
1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
2
3 #include "efi-string.h"
4
5 #if SD_BOOT
6 # include "proto/simple-text-io.h"
7 # include "util.h"
8 #else
9 # include <stdlib.h>
10 # include "alloc-util.h"
11 # define xnew(t, n) ASSERT_SE_PTR(new(t, n))
12 # define xmalloc(n) ASSERT_SE_PTR(malloc(n))
13 #endif
14
15 /* String functions for both char and char16_t that should behave the same way as their respective
16 * counterpart in userspace. Where it makes sense, these accept NULL and do something sensible whereas
17 * userspace does not allow for this (strlen8(NULL) returns 0 like strlen_ptr(NULL) for example). To make it
18 * easier to tell in code which kind of string they work on, we use 8/16 suffixes. This also makes is easier
19 * to unit test them. */
20
21 #define DEFINE_STRNLEN(type, name) \
22 size_t name(const type *s, size_t n) { \
23 if (!s) \
24 return 0; \
25 \
26 size_t len = 0; \
27 while (len < n && *s) { \
28 s++; \
29 len++; \
30 } \
31 \
32 return len; \
33 }
34
35 DEFINE_STRNLEN(char, strnlen8);
36 DEFINE_STRNLEN(char16_t, strnlen16);
37
38 #define TOLOWER(c) \
39 ({ \
40 typeof(c) _c = (c); \
41 (_c >= 'A' && _c <= 'Z') ? _c + ('a' - 'A') : _c; \
42 })
43
44 #define DEFINE_STRTOLOWER(type, name) \
45 void name(type *s) { \
46 if (!s) \
47 return; \
48 for (; *s; s++) \
49 *s = TOLOWER(*s); \
50 }
51
52 DEFINE_STRTOLOWER(char, strtolower8);
53 DEFINE_STRTOLOWER(char16_t, strtolower16);
54
55 #define DEFINE_STRNCASECMP(type, name, tolower) \
56 int name(const type *s1, const type *s2, size_t n) { \
57 if (!s1 || !s2) \
58 return CMP(s1, s2); \
59 \
60 while (n > 0) { \
61 type c1 = *s1, c2 = *s2; \
62 if (tolower) { \
63 c1 = TOLOWER(c1); \
64 c2 = TOLOWER(c2); \
65 } \
66 if (!c1 || c1 != c2) \
67 return CMP(c1, c2); \
68 \
69 s1++; \
70 s2++; \
71 n--; \
72 } \
73 \
74 return 0; \
75 }
76
77 DEFINE_STRNCASECMP(char, strncmp8, false);
78 DEFINE_STRNCASECMP(char16_t, strncmp16, false);
79 DEFINE_STRNCASECMP(char, strncasecmp8, true);
80 DEFINE_STRNCASECMP(char16_t, strncasecmp16, true);
81
82 #define DEFINE_STRCPY(type, name) \
83 type *name(type * restrict dest, const type * restrict src) { \
84 type *ret = ASSERT_PTR(dest); \
85 \
86 if (!src) { \
87 *dest = '\0'; \
88 return ret; \
89 } \
90 \
91 while (*src) { \
92 *dest = *src; \
93 dest++; \
94 src++; \
95 } \
96 \
97 *dest = '\0'; \
98 return ret; \
99 }
100
101 DEFINE_STRCPY(char, strcpy8);
102 DEFINE_STRCPY(char16_t, strcpy16);
103
104 #define DEFINE_STRCHR(type, name) \
105 type *name(const type *s, type c) { \
106 if (!s) \
107 return NULL; \
108 \
109 while (*s) { \
110 if (*s == c) \
111 return (type *) s; \
112 s++; \
113 } \
114 \
115 return c ? NULL : (type *) s; \
116 }
117
118 DEFINE_STRCHR(char, strchr8);
119 DEFINE_STRCHR(char16_t, strchr16);
120
121 #define DEFINE_STRNDUP(type, name, len_func) \
122 type *name(const type *s, size_t n) { \
123 if (!s) \
124 return NULL; \
125 \
126 size_t len = len_func(s, n); \
127 size_t size = len * sizeof(type); \
128 \
129 type *dup = xmalloc(size + sizeof(type)); \
130 if (size > 0) \
131 memcpy(dup, s, size); \
132 dup[len] = '\0'; \
133 \
134 return dup; \
135 }
136
137 DEFINE_STRNDUP(char, xstrndup8, strnlen8);
138 DEFINE_STRNDUP(char16_t, xstrndup16, strnlen16);
139
140 static unsigned utf8_to_unichar(const char *utf8, size_t n, char32_t *c) {
141 char32_t unichar;
142 unsigned len;
143
144 assert(utf8);
145 assert(c);
146
147 if (!(utf8[0] & 0x80)) {
148 *c = utf8[0];
149 return 1;
150 } else if ((utf8[0] & 0xe0) == 0xc0) {
151 len = 2;
152 unichar = utf8[0] & 0x1f;
153 } else if ((utf8[0] & 0xf0) == 0xe0) {
154 len = 3;
155 unichar = utf8[0] & 0x0f;
156 } else if ((utf8[0] & 0xf8) == 0xf0) {
157 len = 4;
158 unichar = utf8[0] & 0x07;
159 } else if ((utf8[0] & 0xfc) == 0xf8) {
160 len = 5;
161 unichar = utf8[0] & 0x03;
162 } else if ((utf8[0] & 0xfe) == 0xfc) {
163 len = 6;
164 unichar = utf8[0] & 0x01;
165 } else {
166 *c = UINT32_MAX;
167 return 1;
168 }
169
170 if (len > n) {
171 *c = UINT32_MAX;
172 return len;
173 }
174
175 for (unsigned i = 1; i < len; i++) {
176 if ((utf8[i] & 0xc0) != 0x80) {
177 *c = UINT32_MAX;
178 return len;
179 }
180 unichar <<= 6;
181 unichar |= utf8[i] & 0x3f;
182 }
183
184 *c = unichar;
185 return len;
186 }
187
188 /* Convert UTF-8 to UCS-2, skipping any invalid or short byte sequences. */
189 char16_t *xstrn8_to_16(const char *str8, size_t n) {
190 if (!str8 || n == 0)
191 return NULL;
192
193 size_t i = 0;
194 char16_t *str16 = xnew(char16_t, n + 1);
195
196 while (n > 0 && *str8 != '\0') {
197 char32_t unichar;
198
199 size_t utf8len = utf8_to_unichar(str8, n, &unichar);
200 str8 += utf8len;
201 n = LESS_BY(n, utf8len);
202
203 switch (unichar) {
204 case 0 ... 0xd7ffU:
205 case 0xe000U ... 0xffffU:
206 str16[i++] = unichar;
207 break;
208 }
209 }
210
211 str16[i] = '\0';
212 return str16;
213 }
214
215 char *startswith8(const char *s, const char *prefix) {
216 size_t l;
217
218 assert(prefix);
219
220 if (!s)
221 return NULL;
222
223 l = strlen8(prefix);
224 if (!strneq8(s, prefix, l))
225 return NULL;
226
227 return (char*) s + l;
228 }
229
230 static bool efi_fnmatch_prefix(const char16_t *p, const char16_t *h, const char16_t **ret_p, const char16_t **ret_h) {
231 assert(p);
232 assert(h);
233 assert(ret_p);
234 assert(ret_h);
235
236 for (;; p++, h++)
237 switch (*p) {
238 case '\0':
239 /* End of pattern. Check that haystack is now empty. */
240 return *h == '\0';
241
242 case '\\':
243 p++;
244 if (*p == '\0' || *p != *h)
245 /* Trailing escape or no match. */
246 return false;
247 break;
248
249 case '?':
250 if (*h == '\0')
251 /* Early end of haystack. */
252 return false;
253 break;
254
255 case '*':
256 /* Point ret_p at the remainder of the pattern. */
257 while (*p == '*')
258 p++;
259 *ret_p = p;
260 *ret_h = h;
261 return true;
262
263 case '[':
264 if (*h == '\0')
265 /* Early end of haystack. */
266 return false;
267
268 bool first = true, can_range = true, match = false;
269 for (;; first = false) {
270 p++;
271 if (*p == '\0')
272 return false;
273
274 if (*p == '\\') {
275 p++;
276 if (*p == '\0')
277 return false;
278 if (*p == *h)
279 match = true;
280 can_range = true;
281 continue;
282 }
283
284 /* End of set unless it's the first char. */
285 if (*p == ']' && !first)
286 break;
287
288 /* Range pattern if '-' is not first or last in set. */
289 if (*p == '-' && can_range && !first && *(p + 1) != ']') {
290 char16_t low = *(p - 1);
291 p++;
292 if (*p == '\\')
293 p++;
294 if (*p == '\0')
295 return false;
296
297 if (low <= *h && *h <= *p)
298 match = true;
299
300 /* Ranges cannot be chained: [a-c-f] == [-abcf] */
301 can_range = false;
302 continue;
303 }
304
305 if (*p == *h)
306 match = true;
307 can_range = true;
308 }
309
310 if (!match)
311 return false;
312 break;
313
314 default:
315 if (*p != *h)
316 /* Single char mismatch. */
317 return false;
318 }
319 }
320
321 /* Patterns are fnmatch-compatible (with reduced feature support). */
322 bool efi_fnmatch(const char16_t *pattern, const char16_t *haystack) {
323 /* Patterns can be considered as simple patterns (without '*') concatenated by '*'. By doing so we
324 * simply have to make sure the very first simple pattern matches the start of haystack. Then we just
325 * look for the remaining simple patterns *somewhere* within the haystack (in order) as any extra
326 * characters in between would be matches by the '*'. We then only have to ensure that the very last
327 * simple pattern matches at the actual end of the haystack.
328 *
329 * This means we do not need to use backtracking which could have catastrophic runtimes with the
330 * right input data. */
331
332 for (bool first = true;;) {
333 const char16_t *pattern_tail = NULL, *haystack_tail = NULL;
334 bool match = efi_fnmatch_prefix(pattern, haystack, &pattern_tail, &haystack_tail);
335 if (first) {
336 if (!match)
337 /* Initial simple pattern must match. */
338 return false;
339 if (!pattern_tail)
340 /* No '*' was in pattern, we can return early. */
341 return true;
342 first = false;
343 }
344
345 if (pattern_tail) {
346 assert(match);
347 pattern = pattern_tail;
348 haystack = haystack_tail;
349 } else {
350 /* If we have a match this must be at the end of the haystack. Note that
351 * efi_fnmatch_prefix compares the NUL-bytes at the end, so we cannot match the end
352 * of pattern in the middle of haystack). */
353 if (match || *haystack == '\0')
354 return match;
355
356 /* Match one character using '*'. */
357 haystack++;
358 }
359 }
360 }
361
362 #define DEFINE_PARSE_NUMBER(type, name) \
363 bool name(const type *s, uint64_t *ret_u, const type **ret_tail) { \
364 assert(ret_u); \
365 \
366 if (!s) \
367 return false; \
368 \
369 /* Need at least one digit. */ \
370 if (*s < '0' || *s > '9') \
371 return false; \
372 \
373 uint64_t u = 0; \
374 while (*s >= '0' && *s <= '9') { \
375 if (__builtin_mul_overflow(u, 10, &u)) \
376 return false; \
377 if (__builtin_add_overflow(u, *s - '0', &u)) \
378 return false; \
379 s++; \
380 } \
381 \
382 if (!ret_tail && *s != '\0') \
383 return false; \
384 \
385 *ret_u = u; \
386 if (ret_tail) \
387 *ret_tail = s; \
388 return true; \
389 }
390
391 DEFINE_PARSE_NUMBER(char, parse_number8);
392 DEFINE_PARSE_NUMBER(char16_t, parse_number16);
393
394 char16_t *hexdump(const void *data, size_t size) {
395 static const char hex[16] = "0123456789abcdef";
396 const uint8_t *d = data;
397
398 assert(data || size == 0);
399
400 char16_t *buf = xnew(char16_t, size * 2 + 1);
401
402 for (size_t i = 0; i < size; i++) {
403 buf[i * 2] = hex[d[i] >> 4];
404 buf[i * 2 + 1] = hex[d[i] & 0x0F];
405 }
406
407 buf[size * 2] = 0;
408 return buf;
409 }
410
411 static const char * const warn_table[] = {
412 [EFI_SUCCESS] = "Success",
413 [EFI_WARN_UNKNOWN_GLYPH] = "Unknown glyph",
414 [EFI_WARN_DELETE_FAILURE] = "Delete failure",
415 [EFI_WARN_WRITE_FAILURE] = "Write failure",
416 [EFI_WARN_BUFFER_TOO_SMALL] = "Buffer too small",
417 [EFI_WARN_STALE_DATA] = "Stale data",
418 [EFI_WARN_FILE_SYSTEM] = "File system",
419 [EFI_WARN_RESET_REQUIRED] = "Reset required",
420 };
421
422 /* Errors have MSB set, remove it to keep the table compact. */
423 #define NOERR(err) ((err) & ~EFI_ERROR_MASK)
424
425 static const char * const err_table[] = {
426 [NOERR(EFI_ERROR_MASK)] = "Error",
427 [NOERR(EFI_LOAD_ERROR)] = "Load error",
428 [NOERR(EFI_INVALID_PARAMETER)] = "Invalid parameter",
429 [NOERR(EFI_UNSUPPORTED)] = "Unsupported",
430 [NOERR(EFI_BAD_BUFFER_SIZE)] = "Bad buffer size",
431 [NOERR(EFI_BUFFER_TOO_SMALL)] = "Buffer too small",
432 [NOERR(EFI_NOT_READY)] = "Not ready",
433 [NOERR(EFI_DEVICE_ERROR)] = "Device error",
434 [NOERR(EFI_WRITE_PROTECTED)] = "Write protected",
435 [NOERR(EFI_OUT_OF_RESOURCES)] = "Out of resources",
436 [NOERR(EFI_VOLUME_CORRUPTED)] = "Volume corrupt",
437 [NOERR(EFI_VOLUME_FULL)] = "Volume full",
438 [NOERR(EFI_NO_MEDIA)] = "No media",
439 [NOERR(EFI_MEDIA_CHANGED)] = "Media changed",
440 [NOERR(EFI_NOT_FOUND)] = "Not found",
441 [NOERR(EFI_ACCESS_DENIED)] = "Access denied",
442 [NOERR(EFI_NO_RESPONSE)] = "No response",
443 [NOERR(EFI_NO_MAPPING)] = "No mapping",
444 [NOERR(EFI_TIMEOUT)] = "Time out",
445 [NOERR(EFI_NOT_STARTED)] = "Not started",
446 [NOERR(EFI_ALREADY_STARTED)] = "Already started",
447 [NOERR(EFI_ABORTED)] = "Aborted",
448 [NOERR(EFI_ICMP_ERROR)] = "ICMP error",
449 [NOERR(EFI_TFTP_ERROR)] = "TFTP error",
450 [NOERR(EFI_PROTOCOL_ERROR)] = "Protocol error",
451 [NOERR(EFI_INCOMPATIBLE_VERSION)] = "Incompatible version",
452 [NOERR(EFI_SECURITY_VIOLATION)] = "Security violation",
453 [NOERR(EFI_CRC_ERROR)] = "CRC error",
454 [NOERR(EFI_END_OF_MEDIA)] = "End of media",
455 [NOERR(EFI_ERROR_RESERVED_29)] = "Reserved (29)",
456 [NOERR(EFI_ERROR_RESERVED_30)] = "Reserved (30)",
457 [NOERR(EFI_END_OF_FILE)] = "End of file",
458 [NOERR(EFI_INVALID_LANGUAGE)] = "Invalid language",
459 [NOERR(EFI_COMPROMISED_DATA)] = "Compromised data",
460 [NOERR(EFI_IP_ADDRESS_CONFLICT)] = "IP address conflict",
461 [NOERR(EFI_HTTP_ERROR)] = "HTTP error",
462 };
463
464 static const char *status_to_string(EFI_STATUS status) {
465 if (status <= ELEMENTSOF(warn_table) - 1)
466 return warn_table[status];
467 if (status >= EFI_ERROR_MASK && status <= ((ELEMENTSOF(err_table) - 1) | EFI_ERROR_MASK))
468 return err_table[NOERR(status)];
469 return NULL;
470 }
471
472 typedef struct {
473 size_t padded_len; /* Field width in printf. */
474 size_t len; /* Precision in printf. */
475 bool pad_zero;
476 bool align_left;
477 bool alternative_form;
478 bool long_arg;
479 bool longlong_arg;
480 bool have_field_width;
481
482 const char *str;
483 const wchar_t *wstr;
484
485 /* For numbers. */
486 bool is_signed;
487 bool lowercase;
488 int8_t base;
489 char sign_pad; /* For + and (space) flags. */
490 } SpecifierContext;
491
492 typedef struct {
493 char16_t stack_buf[128]; /* We use stack_buf first to avoid allocations in most cases. */
494 char16_t *dyn_buf; /* Allocated buf or NULL if stack_buf is used. */
495 char16_t *buf; /* Points to the current active buf. */
496 size_t n_buf; /* Len of buf (in char16_t's, not bytes!). */
497 size_t n; /* Used len of buf (in char16_t's). This is always <n_buf. */
498
499 EFI_STATUS status;
500 const char *format;
501 va_list ap;
502 } FormatContext;
503
504 static void grow_buf(FormatContext *ctx, size_t need) {
505 assert(ctx);
506
507 assert_se(!__builtin_add_overflow(ctx->n, need, &need));
508
509 if (need < ctx->n_buf)
510 return;
511
512 /* Greedily allocate if we can. */
513 if (__builtin_mul_overflow(need, 2, &ctx->n_buf))
514 ctx->n_buf = need;
515
516 /* We cannot use realloc here as ctx->buf may be ctx->stack_buf, which we cannot free. */
517 char16_t *new_buf = xnew(char16_t, ctx->n_buf);
518 memcpy(new_buf, ctx->buf, ctx->n * sizeof(*ctx->buf));
519
520 free(ctx->dyn_buf);
521 ctx->buf = ctx->dyn_buf = new_buf;
522 }
523
524 static void push_padding(FormatContext *ctx, char pad, size_t len) {
525 assert(ctx);
526 while (len > 0) {
527 len--;
528 ctx->buf[ctx->n++] = pad;
529 }
530 }
531
532 static bool push_str(FormatContext *ctx, SpecifierContext *sp) {
533 assert(ctx);
534 assert(sp);
535
536 sp->padded_len = LESS_BY(sp->padded_len, sp->len);
537
538 grow_buf(ctx, sp->padded_len + sp->len);
539
540 if (!sp->align_left)
541 push_padding(ctx, ' ', sp->padded_len);
542
543 /* In userspace unit tests we cannot just memcpy() the wide string. */
544 if (sp->wstr && sizeof(wchar_t) == sizeof(char16_t)) {
545 memcpy(ctx->buf + ctx->n, sp->wstr, sp->len * sizeof(*sp->wstr));
546 ctx->n += sp->len;
547 } else
548 for (size_t i = 0; i < sp->len; i++)
549 ctx->buf[ctx->n++] = sp->str ? sp->str[i] : sp->wstr[i];
550
551 if (sp->align_left)
552 push_padding(ctx, ' ', sp->padded_len);
553
554 assert(ctx->n < ctx->n_buf);
555 return true;
556 }
557
558 static bool push_num(FormatContext *ctx, SpecifierContext *sp, uint64_t u) {
559 const char *digits = sp->lowercase ? "0123456789abcdef" : "0123456789ABCDEF";
560 char16_t tmp[32];
561 size_t n = 0;
562
563 assert(ctx);
564 assert(sp);
565 assert(IN_SET(sp->base, 10, 16));
566
567 /* "%.0u" prints nothing if value is 0. */
568 if (u == 0 && sp->len == 0)
569 return true;
570
571 if (sp->is_signed && (int64_t) u < 0) {
572 /* We cannot just do "u = -(int64_t)u" here because -INT64_MIN overflows. */
573
574 uint64_t rem = -((int64_t) u % sp->base);
575 u = (int64_t) u / -sp->base;
576 tmp[n++] = digits[rem];
577 sp->sign_pad = '-';
578 }
579
580 while (u > 0 || n == 0) {
581 uint64_t rem = u % sp->base;
582 u /= sp->base;
583 tmp[n++] = digits[rem];
584 }
585
586 /* Note that numbers never get truncated! */
587 size_t prefix = (sp->sign_pad != 0 ? 1 : 0) + (sp->alternative_form ? 2 : 0);
588 size_t number_len = prefix + MAX(n, sp->len);
589 grow_buf(ctx, MAX(sp->padded_len, number_len));
590
591 size_t padding = 0;
592 if (sp->pad_zero)
593 /* Leading zeroes go after the sign or 0x prefix. */
594 number_len = MAX(number_len, sp->padded_len);
595 else
596 padding = LESS_BY(sp->padded_len, number_len);
597
598 if (!sp->align_left)
599 push_padding(ctx, ' ', padding);
600
601 if (sp->sign_pad != 0)
602 ctx->buf[ctx->n++] = sp->sign_pad;
603 if (sp->alternative_form) {
604 ctx->buf[ctx->n++] = '0';
605 ctx->buf[ctx->n++] = sp->lowercase ? 'x' : 'X';
606 }
607
608 push_padding(ctx, '0', LESS_BY(number_len, n + prefix));
609
610 while (n > 0)
611 ctx->buf[ctx->n++] = tmp[--n];
612
613 if (sp->align_left)
614 push_padding(ctx, ' ', padding);
615
616 assert(ctx->n < ctx->n_buf);
617 return true;
618 }
619
620 /* This helps unit testing. */
621 #if SD_BOOT
622 # define NULLSTR "(null)"
623 # define wcsnlen strnlen16
624 #else
625 # define NULLSTR "(nil)"
626 #endif
627
628 static bool handle_format_specifier(FormatContext *ctx, SpecifierContext *sp) {
629 /* Parses one item from the format specifier in ctx and put the info into sp. If we are done with
630 * this specifier returns true, otherwise this function should be called again. */
631
632 /* This implementation assumes 32-bit ints. Also note that all types smaller than int are promoted to
633 * int in vararg functions, which is why we fetch only ints for any such types. The compiler would
634 * otherwise warn about fetching smaller types. */
635 assert_cc(sizeof(int) == 4);
636 assert_cc(sizeof(wchar_t) <= sizeof(int));
637 assert_cc(sizeof(intmax_t) <= sizeof(long long));
638
639 assert(ctx);
640 assert(sp);
641
642 switch (*ctx->format) {
643 case '#':
644 sp->alternative_form = true;
645 return false;
646 case '.':
647 sp->have_field_width = true;
648 return false;
649 case '-':
650 sp->align_left = true;
651 return false;
652 case '+':
653 case ' ':
654 sp->sign_pad = *ctx->format;
655 return false;
656
657 case '0':
658 if (!sp->have_field_width) {
659 sp->pad_zero = true;
660 return false;
661 }
662
663 /* If field width has already been provided then 0 is part of precision (%.0s). */
664 _fallthrough_;
665
666 case '*':
667 case '1' ... '9': {
668 int64_t i;
669
670 if (*ctx->format == '*')
671 i = va_arg(ctx->ap, int);
672 else {
673 uint64_t u;
674 if (!parse_number8(ctx->format, &u, &ctx->format) || u > INT_MAX)
675 assert_not_reached();
676 ctx->format--; /* Point it back to the last digit. */
677 i = u;
678 }
679
680 if (sp->have_field_width) {
681 /* Negative precision is ignored. */
682 if (i >= 0)
683 sp->len = (size_t) i;
684 } else {
685 /* Negative field width is treated as positive field width with '-' flag. */
686 if (i < 0) {
687 i *= -1;
688 sp->align_left = true;
689 }
690 sp->padded_len = i;
691 }
692
693 return false;
694 }
695
696 case 'h':
697 if (*(ctx->format + 1) == 'h')
698 ctx->format++;
699 /* char/short gets promoted to int, nothing to do here. */
700 return false;
701
702 case 'l':
703 if (*(ctx->format + 1) == 'l') {
704 ctx->format++;
705 sp->longlong_arg = true;
706 } else
707 sp->long_arg = true;
708 return false;
709
710 case 'z':
711 sp->long_arg = sizeof(size_t) == sizeof(long);
712 sp->longlong_arg = !sp->long_arg && sizeof(size_t) == sizeof(long long);
713 return false;
714
715 case 'j':
716 sp->long_arg = sizeof(intmax_t) == sizeof(long);
717 sp->longlong_arg = !sp->long_arg && sizeof(intmax_t) == sizeof(long long);
718 return false;
719
720 case 't':
721 sp->long_arg = sizeof(ptrdiff_t) == sizeof(long);
722 sp->longlong_arg = !sp->long_arg && sizeof(ptrdiff_t) == sizeof(long long);
723 return false;
724
725 case '%':
726 sp->str = "%";
727 sp->len = 1;
728 return push_str(ctx, sp);
729
730 case 'c':
731 sp->wstr = &(wchar_t){ va_arg(ctx->ap, int) };
732 sp->len = 1;
733 return push_str(ctx, sp);
734
735 case 's':
736 if (sp->long_arg) {
737 sp->wstr = va_arg(ctx->ap, const wchar_t *) ?: L"(null)";
738 sp->len = wcsnlen(sp->wstr, sp->len);
739 } else {
740 sp->str = va_arg(ctx->ap, const char *) ?: "(null)";
741 sp->len = strnlen8(sp->str, sp->len);
742 }
743 return push_str(ctx, sp);
744
745 case 'd':
746 case 'i':
747 case 'u':
748 case 'x':
749 case 'X':
750 sp->lowercase = *ctx->format == 'x';
751 sp->is_signed = IN_SET(*ctx->format, 'd', 'i');
752 sp->base = IN_SET(*ctx->format, 'x', 'X') ? 16 : 10;
753 if (sp->len == SIZE_MAX)
754 sp->len = 1;
755
756 uint64_t v;
757 if (sp->longlong_arg)
758 v = sp->is_signed ? (uint64_t) va_arg(ctx->ap, long long) :
759 va_arg(ctx->ap, unsigned long long);
760 else if (sp->long_arg)
761 v = sp->is_signed ? (uint64_t) va_arg(ctx->ap, long) : va_arg(ctx->ap, unsigned long);
762 else
763 v = sp->is_signed ? (uint64_t) va_arg(ctx->ap, int) : va_arg(ctx->ap, unsigned);
764
765 return push_num(ctx, sp, v);
766
767 case 'p': {
768 const void *ptr = va_arg(ctx->ap, const void *);
769 if (!ptr) {
770 sp->str = NULLSTR;
771 sp->len = STRLEN(NULLSTR);
772 return push_str(ctx, sp);
773 }
774
775 sp->base = 16;
776 sp->lowercase = true;
777 sp->alternative_form = true;
778 sp->len = 0; /* Precision is ignored for %p. */
779 return push_num(ctx, sp, (uintptr_t) ptr);
780 }
781
782 case 'm': {
783 sp->str = status_to_string(ctx->status);
784 if (sp->str) {
785 sp->len = strlen8(sp->str);
786 return push_str(ctx, sp);
787 }
788
789 sp->base = 16;
790 sp->lowercase = true;
791 sp->alternative_form = true;
792 sp->len = 0;
793 return push_num(ctx, sp, ctx->status);
794 }
795
796 default:
797 assert_not_reached();
798 }
799 }
800
801 /* printf_internal is largely compatible to userspace vasprintf. Any features omitted should trigger asserts.
802 *
803 * Supported:
804 * - Flags: #, 0, +, -, space
805 * - Lengths: h, hh, l, ll, z, j, t
806 * - Specifiers: %, c, s, u, i, d, x, X, p, m
807 * - Precision and width (inline or as int arg using *)
808 *
809 * Notable differences:
810 * - Passing NULL to %s is permitted and will print "(null)"
811 * - %p will also use "(null)"
812 * - The provided EFI_STATUS is used for %m instead of errno
813 * - "\n" is translated to "\r\n" */
814 _printf_(2, 0) static char16_t *printf_internal(EFI_STATUS status, const char *format, va_list ap, bool ret) {
815 assert(format);
816
817 FormatContext ctx = {
818 .buf = ctx.stack_buf,
819 .n_buf = ELEMENTSOF(ctx.stack_buf),
820 .format = format,
821 .status = status,
822 };
823
824 /* We cannot put this into the struct without making a copy. */
825 va_copy(ctx.ap, ap);
826
827 while (*ctx.format != '\0') {
828 SpecifierContext sp = { .len = SIZE_MAX };
829
830 switch (*ctx.format) {
831 case '%':
832 ctx.format++;
833 while (!handle_format_specifier(&ctx, &sp))
834 ctx.format++;
835 ctx.format++;
836 break;
837 case '\n':
838 ctx.format++;
839 sp.str = "\r\n";
840 sp.len = 2;
841 push_str(&ctx, &sp);
842 break;
843 default:
844 sp.str = ctx.format++;
845 while (!IN_SET(*ctx.format, '%', '\n', '\0'))
846 ctx.format++;
847 sp.len = ctx.format - sp.str;
848 push_str(&ctx, &sp);
849 }
850 }
851
852 va_end(ctx.ap);
853
854 assert(ctx.n < ctx.n_buf);
855 ctx.buf[ctx.n++] = '\0';
856
857 if (ret) {
858 if (ctx.dyn_buf)
859 return TAKE_PTR(ctx.dyn_buf);
860
861 char16_t *ret_buf = xnew(char16_t, ctx.n);
862 memcpy(ret_buf, ctx.buf, ctx.n * sizeof(*ctx.buf));
863 return ret_buf;
864 }
865
866 #if SD_BOOT
867 ST->ConOut->OutputString(ST->ConOut, ctx.buf);
868 #endif
869
870 return mfree(ctx.dyn_buf);
871 }
872
873 void printf_status(EFI_STATUS status, const char *format, ...) {
874 va_list ap;
875 va_start(ap, format);
876 printf_internal(status, format, ap, false);
877 va_end(ap);
878 }
879
880 void vprintf_status(EFI_STATUS status, const char *format, va_list ap) {
881 printf_internal(status, format, ap, false);
882 }
883
884 char16_t *xasprintf_status(EFI_STATUS status, const char *format, ...) {
885 va_list ap;
886 va_start(ap, format);
887 char16_t *ret = printf_internal(status, format, ap, true);
888 va_end(ap);
889 return ret;
890 }
891
892 char16_t *xvasprintf_status(EFI_STATUS status, const char *format, va_list ap) {
893 return printf_internal(status, format, ap, true);
894 }
895
896 #if SD_BOOT
897 /* To provide the actual implementation for these we need to remove the redirection to the builtins. */
898 # undef memchr
899 # undef memcmp
900 # undef memcpy
901 # undef memset
902 _used_ void *memchr(const void *p, int c, size_t n);
903 _used_ int memcmp(const void *p1, const void *p2, size_t n);
904 _used_ void *memcpy(void * restrict dest, const void * restrict src, size_t n);
905 _used_ void *memset(void *p, int c, size_t n);
906 #else
907 /* And for userspace unit testing we need to give them an efi_ prefix. */
908 # define memchr efi_memchr
909 # define memcmp efi_memcmp
910 # define memcpy efi_memcpy
911 # define memset efi_memset
912 #endif
913
914 void *memchr(const void *p, int c, size_t n) {
915 if (!p || n == 0)
916 return NULL;
917
918 const uint8_t *q = p;
919 for (size_t i = 0; i < n; i++)
920 if (q[i] == (unsigned char) c)
921 return (void *) (q + i);
922
923 return NULL;
924 }
925
926 int memcmp(const void *p1, const void *p2, size_t n) {
927 const uint8_t *up1 = p1, *up2 = p2;
928 int r;
929
930 if (!p1 || !p2)
931 return CMP(p1, p2);
932
933 while (n > 0) {
934 r = CMP(*up1, *up2);
935 if (r != 0)
936 return r;
937
938 up1++;
939 up2++;
940 n--;
941 }
942
943 return 0;
944 }
945
946 void *memcpy(void * restrict dest, const void * restrict src, size_t n) {
947 if (!dest || !src || n == 0)
948 return dest;
949
950 #if SD_BOOT
951 /* The firmware-provided memcpy is likely optimized, so use that. The function is guaranteed to be
952 * available by the UEFI spec. We still make it depend on the boot services pointer being set just in
953 * case the compiler emits a call before it is available. */
954 if (_likely_(BS)) {
955 BS->CopyMem(dest, (void *) src, n);
956 return dest;
957 }
958 #endif
959
960 uint8_t *d = dest;
961 const uint8_t *s = src;
962
963 while (n > 0) {
964 *d = *s;
965 d++;
966 s++;
967 n--;
968 }
969
970 return dest;
971 }
972
973 void *memset(void *p, int c, size_t n) {
974 if (!p || n == 0)
975 return p;
976
977 #if SD_BOOT
978 /* See comment in efi_memcpy. Note that the signature has c and n swapped! */
979 if (_likely_(BS)) {
980 BS->SetMem(p, n, c);
981 return p;
982 }
983 #endif
984
985 uint8_t *q = p;
986 while (n > 0) {
987 *q = c;
988 q++;
989 n--;
990 }
991
992 return p;
993 }