1 /* misc.c - definitions of misc functions */
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>
24 #include <grub/term.h>
26 #include <grub/i18n.h>
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. */
36 UNSIGNED_INT
= 3, UNSIGNED_LONG
, UNSIGNED_LONGLONG
,
44 union printf_arg prealloc
[32];
45 union printf_arg
*ptr
;
50 parse_printf_args (const char *fmt0
, struct printf_args
*args
,
53 grub_vsnprintf_real (char *str
, grub_size_t max_len
, const char *fmt0
,
54 struct printf_args
*args
);
57 free_printf_args (struct printf_args
*args
)
59 if (args
->ptr
!= args
->prealloc
)
60 grub_free (args
->ptr
);
64 grub_iswordseparator (int c
)
66 return (grub_isspace (c
) || c
== ',' || c
== ';' || c
== '|' || c
== '&');
69 /* grub_gettext_dummy is not translating anything. */
71 grub_gettext_dummy (const char *s
)
76 const char* (*grub_gettext
) (const char *s
) = grub_gettext_dummy
;
79 grub_memmove (void *dest
, const void *src
, grub_size_t n
)
81 char *d
= (char *) dest
;
82 const char *s
= (const char *) src
;
100 grub_strcpy (char *dest
, const char *src
)
104 while ((*p
++ = *src
++) != '\0')
111 grub_printf (const char *fmt
, ...)
117 ret
= grub_vprintf (fmt
, ap
);
124 grub_printf_ (const char *fmt
, ...)
130 ret
= grub_vprintf (_(fmt
), ap
);
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
, ...)
150 ret
= grub_vprintf (fmt
, ap
);
157 #if ! defined (__APPLE__) && ! defined (GRUB_UTIL)
158 int grub_err_printf (const char *fmt
, ...)
159 __attribute__ ((alias("grub_printf")));
163 grub_debug_enabled (const char * condition
)
167 debug
= grub_env_get ("debug");
171 if (grub_strword (debug
, "all") || grub_strword (debug
, condition
))
178 grub_real_dprintf (const char *file
, const int line
, const char *condition
,
179 const char *fmt
, ...)
183 if (grub_debug_enabled (condition
))
185 grub_printf ("%s:%d: ", file
, line
);
186 va_start (args
, fmt
);
187 grub_vprintf (fmt
, args
);
193 #define PREALLOC_SIZE 255
196 grub_vprintf (const char *fmt
, va_list ap
)
199 static char buf
[PREALLOC_SIZE
+ 1];
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);
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;
219 s
= grub_vsnprintf_real (curbuf
, s
, fmt
, &args
);
222 free_printf_args (&args
);
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
;
241 return (int) *t1
- (int) *t2
;
251 grub_strcmp (const char *s1
, const char *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
)
271 while (*s1
&& *s2
&& --n
)
280 return (int) (grub_uint8_t
) *s1
- (int) (grub_uint8_t
) *s2
;
284 grub_strchr (const char *s
, int c
)
297 grub_strrchr (const char *s
, int c
)
312 grub_strword (const char *haystack
, const char *needle
)
314 const char *n_pos
= needle
;
316 while (grub_iswordseparator (*haystack
))
321 /* Crawl both the needle and the haystack word we're on. */
322 while(*haystack
&& !grub_iswordseparator (*haystack
)
323 && *haystack
== *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
)))
338 while (*haystack
&& !grub_iswordseparator (*haystack
))
340 while (grub_iswordseparator (*haystack
))
351 return (c
== '\n' || c
== '\r' || c
== ' ' || c
== '\t');
355 grub_strtoul (const char * restrict str
, const char ** const restrict end
,
358 unsigned long long num
;
360 num
= grub_strtoull (str
, end
, base
);
361 #if GRUB_CPU_SIZEOF_LONG != 8
364 grub_error (GRUB_ERR_OUT_OF_RANGE
, N_("overflow is detected"));
369 return (unsigned long) num
;
373 grub_strtoull (const char * restrict str
, const char ** const restrict end
,
376 unsigned long long num
= 0;
379 /* Skip white spaces. */
380 /* grub_isspace checks that *str != '\0'. */
381 while (grub_isspace (*str
))
384 /* Guess the base, if not specified. The prefix `0x' means 16, and
385 the prefix `0' means 8. */
390 if (base
== 0 || base
== 16)
396 else if (base
== 0 && str
[1] >= '0' && str
[1] <= '7')
407 digit
= grub_tolower (*str
) - '0';
408 if (digit
>= 'a' - '0')
409 digit
+= '0' - 'a' + 10;
413 if (digit
>= (unsigned long) base
)
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"));
430 num
= num
* base
+ digit
;
436 grub_error (GRUB_ERR_BAD_NUMBER
,
437 N_("unrecognized number"));
452 grub_strdup (const char *s
)
457 len
= grub_strlen (s
) + 1;
458 p
= (char *) grub_malloc (len
);
462 return grub_memcpy (p
, s
, len
);
466 grub_strndup (const char *s
, grub_size_t n
)
471 len
= grub_strlen (s
);
474 p
= (char *) grub_malloc (len
+ 1);
478 grub_memcpy (p
, s
, len
);
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. */
487 #define VOLATILE_CLANG volatile
489 #define VOLATILE_CLANG
493 grub_memset (void *s
, int c
, grub_size_t len
)
496 grub_uint8_t pattern8
= c
;
498 if (len
>= 3 * sizeof (unsigned long))
500 unsigned long patternl
= 0;
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;
512 while (len
>= sizeof (unsigned long))
514 *(VOLATILE_CLANG
unsigned long *) p
= patternl
;
515 p
= (unsigned long *) p
+ 1;
516 len
-= sizeof (unsigned long);
522 *(VOLATILE_CLANG grub_uint8_t
*) p
= pattern8
;
523 p
= (grub_uint8_t
*) p
+ 1;
531 grub_strlen (const char *s
)
542 grub_reverse (char *str
)
544 char *p
= str
+ grub_strlen (str
) - 1;
558 /* Divide N by D, return the quotient, and store the remainder in *R. */
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. */
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)
579 *r
= ((grub_uint32_t
) n
) % (grub_uint32_t
) d
;
581 return ((grub_uint32_t
) n
) / (grub_uint32_t
) d
;
589 if (n
& (1ULL << 63))
608 /* Convert a long long value to a string. This function avoids 64-bit
609 modular arithmetic or divisions. */
611 grub_lltoa (char *str
, int c
, unsigned long long n
)
613 unsigned base
= ((c
== 'x') || (c
== 'X')) ? 16 : 10;
616 if ((long long) n
< 0 && c
== 'd')
618 n
= (unsigned long long) (-((long long) n
));
627 unsigned d
= (unsigned) (n
& 0xf);
628 *p
++ = (d
> 9) ? d
+ ((c
== 'x') ? 'a' : 'A') - 10 : d
+ '0';
637 n
= grub_divmod64 (n
, 10, &m
);
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.
666 parse_printf_arg_fmt (const char *fmt0
, struct printf_args
*args
,
667 int fmt_check
, grub_size_t max_args
)
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 *));
682 while ((c
= *fmt
++) != 0)
690 while (grub_isdigit (*fmt
))
696 return grub_error (GRUB_ERR_BAD_ARGUMENT
,
697 "positional arguments are not supported");
704 while (grub_isdigit (*fmt
))
710 while (grub_isdigit (*fmt
))
732 /* "%%" is the escape sequence to output "%". */
736 return grub_error (GRUB_ERR_BAD_ARGUMENT
, "unexpected format");
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
;
748 args
->ptr
= grub_calloc (args
->count
, sizeof (args
->ptr
[0]));
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]));
764 while ((c
= *fmt
++) != 0)
780 while (grub_isdigit (*fmt
))
785 curn
= grub_strtoull (p
, 0, 10) - 1;
792 while (grub_isdigit (*fmt
))
798 while (grub_isdigit (*fmt
))
818 if (curn
>= args
->count
)
825 args
->ptr
[curn
].type
= UNSIGNED_INT
+ longfmt
;
828 args
->ptr
[curn
].type
= INT
+ longfmt
;
831 if (sizeof (void *) == sizeof (long long))
832 args
->ptr
[curn
].type
= UNSIGNED_LONGLONG
;
834 args
->ptr
[curn
].type
= UNSIGNED_INT
;
837 args
->ptr
[curn
].type
= STRING
;
841 args
->ptr
[curn
].type
= INT
;
846 return GRUB_ERR_NONE
;
850 parse_printf_args (const char *fmt0
, struct printf_args
*args
, va_list args_in
)
854 parse_printf_arg_fmt (fmt0
, args
, 0, 0);
856 for (n
= 0; n
< args
->count
; n
++)
857 switch (args
->ptr
[n
].type
)
860 args
->ptr
[n
].ll
= va_arg (args_in
, int);
863 args
->ptr
[n
].ll
= va_arg (args_in
, long);
866 args
->ptr
[n
].ll
= va_arg (args_in
, unsigned int);
869 args
->ptr
[n
].ll
= va_arg (args_in
, unsigned long);
872 case UNSIGNED_LONGLONG
:
873 args
->ptr
[n
].ll
= va_arg (args_in
, long long);
876 if (sizeof (void *) == sizeof (long long))
877 args
->ptr
[n
].ll
= va_arg (args_in
, long long);
879 args
->ptr
[n
].ll
= va_arg (args_in
, unsigned int);
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
)
894 grub_vsnprintf_real (char *str
, grub_size_t max_len
, const char *fmt0
,
895 struct printf_args
*args
)
899 grub_size_t count
= 0;
904 while ((c
= *fmt
++) != 0)
906 unsigned int format1
= 0;
907 unsigned int format2
= ~ 0U;
914 write_char (str
, &count
, max_len
,c
);
928 /* Read formatting parameters. */
929 if (grub_isdigit (*fmt
))
933 format1
= grub_strtoul (fmt
, &fmt
, 10);
939 if (grub_isdigit (*fmt
))
940 format2
= grub_strtoul (fmt
, &fmt
, 10);
962 write_char (str
, &count
, max_len
,c
);
967 if (curn
>= args
->count
)
970 long long curarg
= args
->ptr
[curn
].ll
;
975 write_char (str
, &count
, max_len
, '0');
976 write_char (str
, &count
, max_len
, 'x');
989 len
= grub_lltoa (tmp
, c
, curarg
) - tmp
;
990 fill
= len
< format1
? format1
- len
: 0;
993 write_char (str
, &count
, max_len
, zerofill
);
995 write_char (str
, &count
, max_len
, *p
++);
998 write_char (str
, &count
, max_len
, zerofill
);
1003 write_char (str
, &count
, max_len
,curarg
& 0xff);
1008 grub_uint32_t code
= curarg
;
1017 else if (code
<= 0x7ff)
1022 else if (code
<= 0xffff)
1027 else if (code
<= 0x10ffff)
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
)));
1048 grub_size_t len
= 0;
1050 const char *p
= ((char *) (grub_addr_t
) curarg
) ? : "(null)";
1053 while (len
< format2
&& p
[len
])
1056 fill
= len
< format1
? format1
- len
: 0;
1060 write_char (str
, &count
, max_len
, zerofill
);
1062 for (i
= 0; i
< len
; i
++)
1063 write_char (str
, &count
, max_len
,*p
++);
1067 write_char (str
, &count
, max_len
, zerofill
);
1073 write_char (str
, &count
, max_len
,c
);
1078 if (count
< max_len
)
1081 str
[max_len
] = '\0';
1086 grub_vsnprintf (char *str
, grub_size_t n
, const char *fmt
, va_list ap
)
1089 struct printf_args args
;
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
, ...)
1112 ret
= grub_vsnprintf (str
, n
, fmt
, ap
);
1119 grub_xvasprintf (const char *fmt
, va_list ap
)
1121 grub_size_t s
, as
= PREALLOC_SIZE
;
1123 struct printf_args args
;
1125 parse_printf_args (fmt
, &args
, ap
);
1129 ret
= grub_malloc (as
+ 1);
1132 free_printf_args (&args
);
1136 s
= grub_vsnprintf_real (ret
, as
, fmt
, &args
);
1140 free_printf_args (&args
);
1150 grub_xasprintf (const char *fmt
, ...)
1156 ret
= grub_xvasprintf (fmt
, ap
);
1163 grub_printf_fmt_check (const char *fmt
, const char *fmt_expected
)
1165 struct printf_args args_expected
, args_fmt
;
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
)
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
);
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");
1191 free_printf_args (&args_expected
);
1192 free_printf_args (&args_fmt
);
1198 /* Abort GRUB. This function does not return. */
1199 static void __attribute__ ((noreturn
))
1202 grub_printf ("\nAborted.");
1205 if (grub_term_inputs
)
1208 grub_printf (" Press any key to exit.");
1216 grub_fatal (const char *fmt
, ...)
1221 grub_vprintf (_(fmt
), ap
);
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
;
1237 grub_real_boot_time (const char *file
,
1239 const char *fmt
, ...)
1241 struct grub_boot_time
*n
;
1245 n
= grub_malloc (sizeof (*n
));
1254 n
->tp
= grub_get_time_ms ();
1257 va_start (args
, fmt
);
1258 n
->msg
= grub_xvasprintf (fmt
, args
);
1261 *boot_time_last
= n
;
1262 boot_time_last
= &n
->next
;