SECURITY: Add SECURITY file
[grub.git] / grub-core / kern / misc.c
blob3af336ee22753e620531f34c668f1c07ea9ba1ee
1 /* misc.c - definitions of misc functions */
2 /*
3 * GRUB -- GRand Unified Bootloader
4 * Copyright (C) 1999,2000,2001,2002,2003,2004,2005,2006,2007,2008,2009,2010 Free Software Foundation, Inc.
6 * GRUB is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
11 * GRUB is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
20 #include <grub/misc.h>
21 #include <grub/err.h>
22 #include <grub/mm.h>
23 #include <stdarg.h>
24 #include <grub/term.h>
25 #include <grub/env.h>
26 #include <grub/i18n.h>
28 union printf_arg
30 /* Yes, type is also part of union as the moment we fill the value
31 we don't need to store its type anymore (when we'll need it, we'll
32 have format spec again. So save some space. */
33 enum
35 INT, LONG, LONGLONG,
36 UNSIGNED_INT = 3, UNSIGNED_LONG, UNSIGNED_LONGLONG,
37 STRING
38 } type;
39 long long ll;
42 struct printf_args
44 union printf_arg prealloc[32];
45 union printf_arg *ptr;
46 grub_size_t count;
49 static void
50 parse_printf_args (const char *fmt0, struct printf_args *args,
51 va_list args_in);
52 static int
53 grub_vsnprintf_real (char *str, grub_size_t max_len, const char *fmt0,
54 struct printf_args *args);
56 static void
57 free_printf_args (struct printf_args *args)
59 if (args->ptr != args->prealloc)
60 grub_free (args->ptr);
63 static int
64 grub_iswordseparator (int c)
66 return (grub_isspace (c) || c == ',' || c == ';' || c == '|' || c == '&');
69 /* grub_gettext_dummy is not translating anything. */
70 static const char *
71 grub_gettext_dummy (const char *s)
73 return s;
76 const char* (*grub_gettext) (const char *s) = grub_gettext_dummy;
78 void *
79 grub_memmove (void *dest, const void *src, grub_size_t n)
81 char *d = (char *) dest;
82 const char *s = (const char *) src;
84 if (d < s)
85 while (n--)
86 *d++ = *s++;
87 else
89 d += n;
90 s += n;
92 while (n--)
93 *--d = *--s;
96 return dest;
99 char *
100 grub_strcpy (char *dest, const char *src)
102 char *p = dest;
104 while ((*p++ = *src++) != '\0')
107 return dest;
111 grub_printf (const char *fmt, ...)
113 va_list ap;
114 int ret;
116 va_start (ap, fmt);
117 ret = grub_vprintf (fmt, ap);
118 va_end (ap);
120 return ret;
124 grub_printf_ (const char *fmt, ...)
126 va_list ap;
127 int ret;
129 va_start (ap, fmt);
130 ret = grub_vprintf (_(fmt), ap);
131 va_end (ap);
133 return ret;
137 grub_puts_ (const char *s)
139 return grub_puts (_(s));
142 #if defined (__APPLE__) && ! defined (GRUB_UTIL)
144 grub_err_printf (const char *fmt, ...)
146 va_list ap;
147 int ret;
149 va_start (ap, fmt);
150 ret = grub_vprintf (fmt, ap);
151 va_end (ap);
153 return ret;
155 #endif
157 #if ! defined (__APPLE__) && ! defined (GRUB_UTIL)
158 int grub_err_printf (const char *fmt, ...)
159 __attribute__ ((alias("grub_printf")));
160 #endif
163 grub_debug_enabled (const char * condition)
165 const char *debug;
167 debug = grub_env_get ("debug");
168 if (!debug)
169 return 0;
171 if (grub_strword (debug, "all") || grub_strword (debug, condition))
172 return 1;
174 return 0;
177 void
178 grub_real_dprintf (const char *file, const int line, const char *condition,
179 const char *fmt, ...)
181 va_list args;
183 if (grub_debug_enabled (condition))
185 grub_printf ("%s:%d: ", file, line);
186 va_start (args, fmt);
187 grub_vprintf (fmt, args);
188 va_end (args);
189 grub_refresh ();
193 #define PREALLOC_SIZE 255
196 grub_vprintf (const char *fmt, va_list ap)
198 grub_size_t s;
199 static char buf[PREALLOC_SIZE + 1];
200 char *curbuf = buf;
201 struct printf_args args;
203 parse_printf_args (fmt, &args, ap);
205 s = grub_vsnprintf_real (buf, PREALLOC_SIZE, fmt, &args);
206 if (s > PREALLOC_SIZE)
208 curbuf = grub_malloc (s + 1);
209 if (!curbuf)
211 grub_errno = GRUB_ERR_NONE;
212 buf[PREALLOC_SIZE - 3] = '.';
213 buf[PREALLOC_SIZE - 2] = '.';
214 buf[PREALLOC_SIZE - 1] = '.';
215 buf[PREALLOC_SIZE] = 0;
216 curbuf = buf;
218 else
219 s = grub_vsnprintf_real (curbuf, s, fmt, &args);
222 free_printf_args (&args);
224 grub_xputs (curbuf);
226 if (curbuf != buf)
227 grub_free (curbuf);
229 return s;
233 grub_memcmp (const void *s1, const void *s2, grub_size_t n)
235 const grub_uint8_t *t1 = s1;
236 const grub_uint8_t *t2 = s2;
238 while (n--)
240 if (*t1 != *t2)
241 return (int) *t1 - (int) *t2;
243 t1++;
244 t2++;
247 return 0;
251 grub_strcmp (const char *s1, const char *s2)
253 while (*s1 && *s2)
255 if (*s1 != *s2)
256 break;
258 s1++;
259 s2++;
262 return (int) (grub_uint8_t) *s1 - (int) (grub_uint8_t) *s2;
266 grub_strncmp (const char *s1, const char *s2, grub_size_t n)
268 if (n == 0)
269 return 0;
271 while (*s1 && *s2 && --n)
273 if (*s1 != *s2)
274 break;
276 s1++;
277 s2++;
280 return (int) (grub_uint8_t) *s1 - (int) (grub_uint8_t) *s2;
283 char *
284 grub_strchr (const char *s, int c)
288 if (*s == c)
289 return (char *) s;
291 while (*s++);
293 return 0;
296 char *
297 grub_strrchr (const char *s, int c)
299 char *p = NULL;
303 if (*s == c)
304 p = (char *) s;
306 while (*s++);
308 return p;
312 grub_strword (const char *haystack, const char *needle)
314 const char *n_pos = needle;
316 while (grub_iswordseparator (*haystack))
317 haystack++;
319 while (*haystack)
321 /* Crawl both the needle and the haystack word we're on. */
322 while(*haystack && !grub_iswordseparator (*haystack)
323 && *haystack == *n_pos)
325 haystack++;
326 n_pos++;
329 /* If we reached the end of both words at the same time, the word
330 is found. If not, eat everything in the haystack that isn't the
331 next word (or the end of string) and "reset" the needle. */
332 if ( (!*haystack || grub_iswordseparator (*haystack))
333 && (!*n_pos || grub_iswordseparator (*n_pos)))
334 return 1;
335 else
337 n_pos = needle;
338 while (*haystack && !grub_iswordseparator (*haystack))
339 haystack++;
340 while (grub_iswordseparator (*haystack))
341 haystack++;
345 return 0;
349 grub_isspace (int c)
351 return (c == '\n' || c == '\r' || c == ' ' || c == '\t');
354 unsigned long
355 grub_strtoul (const char * restrict str, const char ** const restrict end,
356 int base)
358 unsigned long long num;
360 num = grub_strtoull (str, end, base);
361 #if GRUB_CPU_SIZEOF_LONG != 8
362 if (num > ~0UL)
364 grub_error (GRUB_ERR_OUT_OF_RANGE, N_("overflow is detected"));
365 return ~0UL;
367 #endif
369 return (unsigned long) num;
372 unsigned long long
373 grub_strtoull (const char * restrict str, const char ** const restrict end,
374 int base)
376 unsigned long long num = 0;
377 int found = 0;
379 /* Skip white spaces. */
380 /* grub_isspace checks that *str != '\0'. */
381 while (grub_isspace (*str))
382 str++;
384 /* Guess the base, if not specified. The prefix `0x' means 16, and
385 the prefix `0' means 8. */
386 if (str[0] == '0')
388 if (str[1] == 'x')
390 if (base == 0 || base == 16)
392 base = 16;
393 str += 2;
396 else if (base == 0 && str[1] >= '0' && str[1] <= '7')
397 base = 8;
400 if (base == 0)
401 base = 10;
403 while (*str)
405 unsigned long digit;
407 digit = grub_tolower (*str) - '0';
408 if (digit >= 'a' - '0')
409 digit += '0' - 'a' + 10;
410 else if (digit > 9)
411 break;
413 if (digit >= (unsigned long) base)
414 break;
416 found = 1;
418 /* NUM * BASE + DIGIT > ~0ULL */
419 if (num > grub_divmod64 (~0ULL - digit, base, 0))
421 grub_error (GRUB_ERR_OUT_OF_RANGE,
422 N_("overflow is detected"));
424 if (end)
425 *end = (char *) str;
427 return ~0ULL;
430 num = num * base + digit;
431 str++;
434 if (! found)
436 grub_error (GRUB_ERR_BAD_NUMBER,
437 N_("unrecognized number"));
439 if (end)
440 *end = (char *) str;
442 return 0;
445 if (end)
446 *end = (char *) str;
448 return num;
451 char *
452 grub_strdup (const char *s)
454 grub_size_t len;
455 char *p;
457 len = grub_strlen (s) + 1;
458 p = (char *) grub_malloc (len);
459 if (! p)
460 return 0;
462 return grub_memcpy (p, s, len);
465 char *
466 grub_strndup (const char *s, grub_size_t n)
468 grub_size_t len;
469 char *p;
471 len = grub_strlen (s);
472 if (len > n)
473 len = n;
474 p = (char *) grub_malloc (len + 1);
475 if (! p)
476 return 0;
478 grub_memcpy (p, s, len);
479 p[len] = '\0';
480 return p;
483 /* clang detects that we're implementing here a memset so it decides to
484 optimise and calls memset resulting in infinite recursion. With volatile
485 we make it not optimise in this way. */
486 #ifdef __clang__
487 #define VOLATILE_CLANG volatile
488 #else
489 #define VOLATILE_CLANG
490 #endif
492 void *
493 grub_memset (void *s, int c, grub_size_t len)
495 void *p = s;
496 grub_uint8_t pattern8 = c;
498 if (len >= 3 * sizeof (unsigned long))
500 unsigned long patternl = 0;
501 grub_size_t i;
503 for (i = 0; i < sizeof (unsigned long); i++)
504 patternl |= ((unsigned long) pattern8) << (8 * i);
506 while (len > 0 && (((grub_addr_t) p) & (sizeof (unsigned long) - 1)))
508 *(VOLATILE_CLANG grub_uint8_t *) p = pattern8;
509 p = (grub_uint8_t *) p + 1;
510 len--;
512 while (len >= sizeof (unsigned long))
514 *(VOLATILE_CLANG unsigned long *) p = patternl;
515 p = (unsigned long *) p + 1;
516 len -= sizeof (unsigned long);
520 while (len > 0)
522 *(VOLATILE_CLANG grub_uint8_t *) p = pattern8;
523 p = (grub_uint8_t *) p + 1;
524 len--;
527 return s;
530 grub_size_t
531 grub_strlen (const char *s)
533 const char *p = s;
535 while (*p)
536 p++;
538 return p - s;
541 static inline void
542 grub_reverse (char *str)
544 char *p = str + grub_strlen (str) - 1;
546 while (str < p)
548 char tmp;
550 tmp = *str;
551 *str = *p;
552 *p = tmp;
553 str++;
554 p--;
558 /* Divide N by D, return the quotient, and store the remainder in *R. */
559 grub_uint64_t
560 grub_divmod64 (grub_uint64_t n, grub_uint64_t d, grub_uint64_t *r)
562 /* This algorithm is typically implemented by hardware. The idea
563 is to get the highest bit in N, 64 times, by keeping
564 upper(N * 2^i) = (Q * D + M), where upper
565 represents the high 64 bits in 128-bits space. */
566 unsigned bits = 64;
567 grub_uint64_t q = 0;
568 grub_uint64_t m = 0;
570 /* ARM and IA64 don't have a fast 32-bit division.
571 Using that code would just make us use software division routines, calling
572 ourselves indirectly and hence getting infinite recursion.
574 #if !GRUB_DIVISION_IN_SOFTWARE
575 /* Skip the slow computation if 32-bit arithmetic is possible. */
576 if (n < 0xffffffff && d < 0xffffffff)
578 if (r)
579 *r = ((grub_uint32_t) n) % (grub_uint32_t) d;
581 return ((grub_uint32_t) n) / (grub_uint32_t) d;
583 #endif
585 while (bits--)
587 m <<= 1;
589 if (n & (1ULL << 63))
590 m |= 1;
592 q <<= 1;
593 n <<= 1;
595 if (m >= d)
597 q |= 1;
598 m -= d;
602 if (r)
603 *r = m;
605 return q;
608 /* Convert a long long value to a string. This function avoids 64-bit
609 modular arithmetic or divisions. */
610 static inline char *
611 grub_lltoa (char *str, int c, unsigned long long n)
613 unsigned base = ((c == 'x') || (c == 'X')) ? 16 : 10;
614 char *p;
616 if ((long long) n < 0 && c == 'd')
618 n = (unsigned long long) (-((long long) n));
619 *str++ = '-';
622 p = str;
624 if (base == 16)
627 unsigned d = (unsigned) (n & 0xf);
628 *p++ = (d > 9) ? d + ((c == 'x') ? 'a' : 'A') - 10 : d + '0';
630 while (n >>= 4);
631 else
632 /* BASE == 10 */
635 grub_uint64_t m;
637 n = grub_divmod64 (n, 10, &m);
638 *p++ = m + '0';
640 while (n);
642 *p = 0;
644 grub_reverse (str);
645 return p;
649 * Parse printf() fmt0 string into args arguments.
651 * The parsed arguments are either used by a printf() function to format the fmt0
652 * string or they are used to compare a format string from an untrusted source
653 * against a format string with expected arguments.
655 * When the fmt_check is set to !0, e.g. 1, then this function is executed in
656 * printf() format check mode. This enforces stricter rules for parsing the
657 * fmt0 to limit exposure to possible errors in printf() handling. It also
658 * disables positional parameters, "$", because some formats, e.g "%s%1$d",
659 * cannot be validated with the current implementation.
661 * The max_args allows to set a maximum number of accepted arguments. If the fmt0
662 * string defines more arguments than the max_args then the parse_printf_arg_fmt()
663 * function returns an error. This is currently used for format check only.
665 static grub_err_t
666 parse_printf_arg_fmt (const char *fmt0, struct printf_args *args,
667 int fmt_check, grub_size_t max_args)
669 const char *fmt;
670 char c;
671 grub_size_t n = 0;
673 args->count = 0;
675 COMPILE_TIME_ASSERT (sizeof (int) == sizeof (grub_uint32_t));
676 COMPILE_TIME_ASSERT (sizeof (int) <= sizeof (long long));
677 COMPILE_TIME_ASSERT (sizeof (long) <= sizeof (long long));
678 COMPILE_TIME_ASSERT (sizeof (long long) == sizeof (void *)
679 || sizeof (int) == sizeof (void *));
681 fmt = fmt0;
682 while ((c = *fmt++) != 0)
684 if (c != '%')
685 continue;
687 if (*fmt =='-')
688 fmt++;
690 while (grub_isdigit (*fmt))
691 fmt++;
693 if (*fmt == '$')
695 if (fmt_check)
696 return grub_error (GRUB_ERR_BAD_ARGUMENT,
697 "positional arguments are not supported");
698 fmt++;
701 if (*fmt =='-')
702 fmt++;
704 while (grub_isdigit (*fmt))
705 fmt++;
707 if (*fmt =='.')
708 fmt++;
710 while (grub_isdigit (*fmt))
711 fmt++;
713 c = *fmt++;
714 if (c == 'l')
715 c = *fmt++;
716 if (c == 'l')
717 c = *fmt++;
719 switch (c)
721 case 'p':
722 case 'x':
723 case 'X':
724 case 'u':
725 case 'd':
726 case 'c':
727 case 'C':
728 case 's':
729 args->count++;
730 break;
731 case '%':
732 /* "%%" is the escape sequence to output "%". */
733 break;
734 default:
735 if (fmt_check)
736 return grub_error (GRUB_ERR_BAD_ARGUMENT, "unexpected format");
737 break;
741 if (fmt_check && args->count > max_args)
742 return grub_error (GRUB_ERR_BAD_ARGUMENT, "too many arguments");
744 if (args->count <= ARRAY_SIZE (args->prealloc))
745 args->ptr = args->prealloc;
746 else
748 args->ptr = grub_calloc (args->count, sizeof (args->ptr[0]));
749 if (!args->ptr)
751 if (fmt_check)
752 return grub_errno;
754 grub_errno = GRUB_ERR_NONE;
755 args->ptr = args->prealloc;
756 args->count = ARRAY_SIZE (args->prealloc);
760 grub_memset (args->ptr, 0, args->count * sizeof (args->ptr[0]));
762 fmt = fmt0;
763 n = 0;
764 while ((c = *fmt++) != 0)
766 int longfmt = 0;
767 grub_size_t curn;
768 const char *p;
770 if (c != '%')
771 continue;
773 curn = n++;
775 if (*fmt =='-')
776 fmt++;
778 p = fmt;
780 while (grub_isdigit (*fmt))
781 fmt++;
783 if (*fmt == '$')
785 curn = grub_strtoull (p, 0, 10) - 1;
786 fmt++;
789 if (*fmt =='-')
790 fmt++;
792 while (grub_isdigit (*fmt))
793 fmt++;
795 if (*fmt =='.')
796 fmt++;
798 while (grub_isdigit (*fmt))
799 fmt++;
801 c = *fmt++;
802 if (c == '%')
804 n--;
805 continue;
808 if (c == 'l')
810 c = *fmt++;
811 longfmt = 1;
813 if (c == 'l')
815 c = *fmt++;
816 longfmt = 2;
818 if (curn >= args->count)
819 continue;
820 switch (c)
822 case 'x':
823 case 'X':
824 case 'u':
825 args->ptr[curn].type = UNSIGNED_INT + longfmt;
826 break;
827 case 'd':
828 args->ptr[curn].type = INT + longfmt;
829 break;
830 case 'p':
831 if (sizeof (void *) == sizeof (long long))
832 args->ptr[curn].type = UNSIGNED_LONGLONG;
833 else
834 args->ptr[curn].type = UNSIGNED_INT;
835 break;
836 case 's':
837 args->ptr[curn].type = STRING;
838 break;
839 case 'C':
840 case 'c':
841 args->ptr[curn].type = INT;
842 break;
846 return GRUB_ERR_NONE;
849 static void
850 parse_printf_args (const char *fmt0, struct printf_args *args, va_list args_in)
852 grub_size_t n;
854 parse_printf_arg_fmt (fmt0, args, 0, 0);
856 for (n = 0; n < args->count; n++)
857 switch (args->ptr[n].type)
859 case INT:
860 args->ptr[n].ll = va_arg (args_in, int);
861 break;
862 case LONG:
863 args->ptr[n].ll = va_arg (args_in, long);
864 break;
865 case UNSIGNED_INT:
866 args->ptr[n].ll = va_arg (args_in, unsigned int);
867 break;
868 case UNSIGNED_LONG:
869 args->ptr[n].ll = va_arg (args_in, unsigned long);
870 break;
871 case LONGLONG:
872 case UNSIGNED_LONGLONG:
873 args->ptr[n].ll = va_arg (args_in, long long);
874 break;
875 case STRING:
876 if (sizeof (void *) == sizeof (long long))
877 args->ptr[n].ll = va_arg (args_in, long long);
878 else
879 args->ptr[n].ll = va_arg (args_in, unsigned int);
880 break;
884 static inline void __attribute__ ((always_inline))
885 write_char (char *str, grub_size_t *count, grub_size_t max_len, unsigned char ch)
887 if (*count < max_len)
888 str[*count] = ch;
890 (*count)++;
893 static int
894 grub_vsnprintf_real (char *str, grub_size_t max_len, const char *fmt0,
895 struct printf_args *args)
897 char c;
898 grub_size_t n = 0;
899 grub_size_t count = 0;
900 const char *fmt;
902 fmt = fmt0;
904 while ((c = *fmt++) != 0)
906 unsigned int format1 = 0;
907 unsigned int format2 = ~ 0U;
908 char zerofill = ' ';
909 char rightfill = 0;
910 grub_size_t curn;
912 if (c != '%')
914 write_char (str, &count, max_len,c);
915 continue;
918 curn = n++;
920 rescan:;
922 if (*fmt =='-')
924 rightfill = 1;
925 fmt++;
928 /* Read formatting parameters. */
929 if (grub_isdigit (*fmt))
931 if (fmt[0] == '0')
932 zerofill = '0';
933 format1 = grub_strtoul (fmt, &fmt, 10);
936 if (*fmt == '.')
937 fmt++;
939 if (grub_isdigit (*fmt))
940 format2 = grub_strtoul (fmt, &fmt, 10);
942 if (*fmt == '$')
944 curn = format1 - 1;
945 fmt++;
946 format1 = 0;
947 format2 = ~ 0U;
948 zerofill = ' ';
949 rightfill = 0;
951 goto rescan;
954 c = *fmt++;
955 if (c == 'l')
956 c = *fmt++;
957 if (c == 'l')
958 c = *fmt++;
960 if (c == '%')
962 write_char (str, &count, max_len,c);
963 n--;
964 continue;
967 if (curn >= args->count)
968 continue;
970 long long curarg = args->ptr[curn].ll;
972 switch (c)
974 case 'p':
975 write_char (str, &count, max_len, '0');
976 write_char (str, &count, max_len, 'x');
977 c = 'x';
978 /* Fall through. */
979 case 'x':
980 case 'X':
981 case 'u':
982 case 'd':
984 char tmp[32];
985 const char *p = tmp;
986 grub_size_t len;
987 grub_size_t fill;
989 len = grub_lltoa (tmp, c, curarg) - tmp;
990 fill = len < format1 ? format1 - len : 0;
991 if (! rightfill)
992 while (fill--)
993 write_char (str, &count, max_len, zerofill);
994 while (*p)
995 write_char (str, &count, max_len, *p++);
996 if (rightfill)
997 while (fill--)
998 write_char (str, &count, max_len, zerofill);
1000 break;
1002 case 'c':
1003 write_char (str, &count, max_len,curarg & 0xff);
1004 break;
1006 case 'C':
1008 grub_uint32_t code = curarg;
1009 int shift;
1010 unsigned mask;
1012 if (code <= 0x7f)
1014 shift = 0;
1015 mask = 0;
1017 else if (code <= 0x7ff)
1019 shift = 6;
1020 mask = 0xc0;
1022 else if (code <= 0xffff)
1024 shift = 12;
1025 mask = 0xe0;
1027 else if (code <= 0x10ffff)
1029 shift = 18;
1030 mask = 0xf0;
1032 else
1034 code = '?';
1035 shift = 0;
1036 mask = 0;
1039 write_char (str, &count, max_len,mask | (code >> shift));
1041 for (shift -= 6; shift >= 0; shift -= 6)
1042 write_char (str, &count, max_len,0x80 | (0x3f & (code >> shift)));
1044 break;
1046 case 's':
1048 grub_size_t len = 0;
1049 grub_size_t fill;
1050 const char *p = ((char *) (grub_addr_t) curarg) ? : "(null)";
1051 grub_size_t i;
1053 while (len < format2 && p[len])
1054 len++;
1056 fill = len < format1 ? format1 - len : 0;
1058 if (!rightfill)
1059 while (fill--)
1060 write_char (str, &count, max_len, zerofill);
1062 for (i = 0; i < len; i++)
1063 write_char (str, &count, max_len,*p++);
1065 if (rightfill)
1066 while (fill--)
1067 write_char (str, &count, max_len, zerofill);
1070 break;
1072 default:
1073 write_char (str, &count, max_len,c);
1074 break;
1078 if (count < max_len)
1079 str[count] = '\0';
1080 else
1081 str[max_len] = '\0';
1082 return count;
1086 grub_vsnprintf (char *str, grub_size_t n, const char *fmt, va_list ap)
1088 grub_size_t ret;
1089 struct printf_args args;
1091 if (!n)
1092 return 0;
1094 n--;
1096 parse_printf_args (fmt, &args, ap);
1098 ret = grub_vsnprintf_real (str, n, fmt, &args);
1100 free_printf_args (&args);
1102 return ret < n ? ret : n;
1106 grub_snprintf (char *str, grub_size_t n, const char *fmt, ...)
1108 va_list ap;
1109 int ret;
1111 va_start (ap, fmt);
1112 ret = grub_vsnprintf (str, n, fmt, ap);
1113 va_end (ap);
1115 return ret;
1118 char *
1119 grub_xvasprintf (const char *fmt, va_list ap)
1121 grub_size_t s, as = PREALLOC_SIZE;
1122 char *ret;
1123 struct printf_args args;
1125 parse_printf_args (fmt, &args, ap);
1127 while (1)
1129 ret = grub_malloc (as + 1);
1130 if (!ret)
1132 free_printf_args (&args);
1133 return NULL;
1136 s = grub_vsnprintf_real (ret, as, fmt, &args);
1138 if (s <= as)
1140 free_printf_args (&args);
1141 return ret;
1144 grub_free (ret);
1145 as = s;
1149 char *
1150 grub_xasprintf (const char *fmt, ...)
1152 va_list ap;
1153 char *ret;
1155 va_start (ap, fmt);
1156 ret = grub_xvasprintf (fmt, ap);
1157 va_end (ap);
1159 return ret;
1162 grub_err_t
1163 grub_printf_fmt_check (const char *fmt, const char *fmt_expected)
1165 struct printf_args args_expected, args_fmt;
1166 grub_err_t ret;
1167 grub_size_t n;
1169 if (fmt == NULL || fmt_expected == NULL)
1170 return grub_error (GRUB_ERR_BAD_ARGUMENT, "invalid format");
1172 ret = parse_printf_arg_fmt (fmt_expected, &args_expected, 1, GRUB_SIZE_MAX);
1173 if (ret != GRUB_ERR_NONE)
1174 return ret;
1176 /* Limit parsing to the number of expected arguments. */
1177 ret = parse_printf_arg_fmt (fmt, &args_fmt, 1, args_expected.count);
1178 if (ret != GRUB_ERR_NONE)
1180 free_printf_args (&args_expected);
1181 return ret;
1184 for (n = 0; n < args_fmt.count; n++)
1185 if (args_fmt.ptr[n].type != args_expected.ptr[n].type)
1187 ret = grub_error (GRUB_ERR_BAD_ARGUMENT, "arguments types do not match");
1188 break;
1191 free_printf_args (&args_expected);
1192 free_printf_args (&args_fmt);
1194 return ret;
1198 /* Abort GRUB. This function does not return. */
1199 static void __attribute__ ((noreturn))
1200 grub_abort (void)
1202 grub_printf ("\nAborted.");
1204 #ifndef GRUB_UTIL
1205 if (grub_term_inputs)
1206 #endif
1208 grub_printf (" Press any key to exit.");
1209 grub_getkey ();
1212 grub_exit ();
1215 void
1216 grub_fatal (const char *fmt, ...)
1218 va_list ap;
1220 va_start (ap, fmt);
1221 grub_vprintf (_(fmt), ap);
1222 va_end (ap);
1224 grub_refresh ();
1226 grub_abort ();
1229 #if BOOT_TIME_STATS
1231 #include <grub/time.h>
1233 struct grub_boot_time *grub_boot_time_head;
1234 static struct grub_boot_time **boot_time_last = &grub_boot_time_head;
1236 void
1237 grub_real_boot_time (const char *file,
1238 const int line,
1239 const char *fmt, ...)
1241 struct grub_boot_time *n;
1242 va_list args;
1244 grub_error_push ();
1245 n = grub_malloc (sizeof (*n));
1246 if (!n)
1248 grub_errno = 0;
1249 grub_error_pop ();
1250 return;
1252 n->file = file;
1253 n->line = line;
1254 n->tp = grub_get_time_ms ();
1255 n->next = 0;
1257 va_start (args, fmt);
1258 n->msg = grub_xvasprintf (fmt, args);
1259 va_end (args);
1261 *boot_time_last = n;
1262 boot_time_last = &n->next;
1264 grub_errno = 0;
1265 grub_error_pop ();
1267 #endif