|  | /* | 
|  | *  GRUB  --  GRand Unified Bootloader | 
|  | *  Copyright (C) 2000,2001,2002  Free Software Foundation, Inc. | 
|  | * | 
|  | *  This program is free software; you can redistribute it and/or modify | 
|  | *  it under the terms of the GNU General Public License as published by | 
|  | *  the Free Software Foundation; either version 2 of the License, or | 
|  | *  (at your option) any later version. | 
|  | * | 
|  | *  This program is distributed in the hope that it will be useful, | 
|  | *  but WITHOUT ANY WARRANTY; without even the implied warranty of | 
|  | *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | 
|  | *  GNU General Public License for more details. | 
|  | * | 
|  | *  You should have received a copy of the GNU General Public License | 
|  | *  along with this program; if not, write to the Free Software | 
|  | *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | 
|  | */ | 
|  |  | 
|  | /* Based on "src/misc.c" in etherboot-5.0.5.  */ | 
|  |  | 
|  | #define GRUB	1 | 
|  | #include <etherboot.h> | 
|  |  | 
|  | void | 
|  | sleep (int secs) | 
|  | { | 
|  | unsigned long tmo = currticks () + secs; | 
|  |  | 
|  | while (currticks () < tmo) | 
|  | ; | 
|  | } | 
|  |  | 
|  | void | 
|  | twiddle (void) | 
|  | { | 
|  | static unsigned long lastticks = 0; | 
|  | static int count = 0; | 
|  | static const char tiddles[]="-\\|/"; | 
|  | unsigned long ticks; | 
|  |  | 
|  | if (debug) | 
|  | { | 
|  | if ((ticks = currticks ()) == lastticks) | 
|  | return; | 
|  |  | 
|  | lastticks = ticks; | 
|  | grub_putchar (tiddles[(count++) & 3]); | 
|  | grub_putchar ('\b'); | 
|  | } | 
|  | } | 
|  |  | 
|  | /* Because Etherboot uses its own formats for the printf family, | 
|  | define separate definitions from GRUB.  */ | 
|  | /************************************************************************** | 
|  | PRINTF and friends | 
|  |  | 
|  | Formats: | 
|  | %[#]x	- 4 bytes long (8 hex digits, lower case) | 
|  | %[#]X	- 4 bytes long (8 hex digits, upper case) | 
|  | %[#]hx	- 2 bytes int (4 hex digits, lower case) | 
|  | %[#]hX	- 2 bytes int (4 hex digits, upper case) | 
|  | %[#]hhx	- 1 byte int (2 hex digits, lower case) | 
|  | %[#]hhX	- 1 byte int (2 hex digits, upper case) | 
|  | - optional # prefixes 0x or 0X | 
|  | %d	- decimal int | 
|  | %c	- char | 
|  | %s	- string | 
|  | %@	- Internet address in ddd.ddd.ddd.ddd notation | 
|  | %!	- Ethernet address in xx:xx:xx:xx:xx:xx notation | 
|  | Note: width specification not supported | 
|  | **************************************************************************/ | 
|  | static int | 
|  | etherboot_vsprintf (char *buf, const char *fmt, const int *dp) | 
|  | { | 
|  | char *p, *s; | 
|  |  | 
|  | s = buf; | 
|  | for ( ; *fmt != '\0'; ++fmt) | 
|  | { | 
|  | if (*fmt != '%') | 
|  | { | 
|  | buf ? *s++ = *fmt : grub_putchar (*fmt); | 
|  | continue; | 
|  | } | 
|  |  | 
|  | if (*++fmt == 's') | 
|  | { | 
|  | for (p = (char *) *dp++; *p != '\0'; p++) | 
|  | buf ? *s++ = *p : grub_putchar (*p); | 
|  | } | 
|  | else | 
|  | { | 
|  | /* Length of item is bounded */ | 
|  | char tmp[20], *q = tmp; | 
|  | int alt = 0; | 
|  | int shift = 28; | 
|  |  | 
|  | if (*fmt == '#') | 
|  | { | 
|  | alt = 1; | 
|  | fmt++; | 
|  | } | 
|  |  | 
|  | if (*fmt == 'h') | 
|  | { | 
|  | shift = 12; | 
|  | fmt++; | 
|  | } | 
|  |  | 
|  | if (*fmt == 'h') | 
|  | { | 
|  | shift = 4; | 
|  | fmt++; | 
|  | } | 
|  |  | 
|  | /* | 
|  | * Before each format q points to tmp buffer | 
|  | * After each format q points past end of item | 
|  | */ | 
|  | if ((*fmt | 0x20) == 'x') | 
|  | { | 
|  | /* With x86 gcc, sizeof(long) == sizeof(int) */ | 
|  | const long *lp = (const long *) dp; | 
|  | long h = *lp++; | 
|  | int ncase = (*fmt & 0x20); | 
|  |  | 
|  | dp = (const int *) lp; | 
|  | if (alt) | 
|  | { | 
|  | *q++ = '0'; | 
|  | *q++ = 'X' | ncase; | 
|  | } | 
|  | for (; shift >= 0; shift -= 4) | 
|  | *q++ = "0123456789ABCDEF"[(h >> shift) & 0xF] | ncase; | 
|  | } | 
|  | else if (*fmt == 'd') | 
|  | { | 
|  | int i = *dp++; | 
|  | char *r; | 
|  |  | 
|  | if (i < 0) | 
|  | { | 
|  | *q++ = '-'; | 
|  | i = -i; | 
|  | } | 
|  |  | 
|  | p = q;		/* save beginning of digits */ | 
|  | do | 
|  | { | 
|  | *q++ = '0' + (i % 10); | 
|  | i /= 10; | 
|  | } | 
|  | while (i); | 
|  |  | 
|  | /* reverse digits, stop in middle */ | 
|  | r = q;		/* don't alter q */ | 
|  | while (--r > p) | 
|  | { | 
|  | i = *r; | 
|  | *r = *p; | 
|  | *p++ = i; | 
|  | } | 
|  | } | 
|  | else if (*fmt == '@') | 
|  | { | 
|  | unsigned char *r; | 
|  | union | 
|  | { | 
|  | long		l; | 
|  | unsigned char	c[4]; | 
|  | } | 
|  | u; | 
|  | const long *lp = (const long *) dp; | 
|  |  | 
|  | u.l = *lp++; | 
|  | dp = (const int *) lp; | 
|  |  | 
|  | for (r = &u.c[0]; r < &u.c[4]; ++r) | 
|  | q += etherboot_sprintf (q, "%d.", *r); | 
|  |  | 
|  | --q; | 
|  | } | 
|  | else if (*fmt == '!') | 
|  | { | 
|  | char *r; | 
|  | p = (char *) *dp++; | 
|  |  | 
|  | for (r = p + ETH_ALEN; p < r; ++p) | 
|  | q += etherboot_sprintf (q, "%hhX:", *p); | 
|  |  | 
|  | --q; | 
|  | } | 
|  | else if (*fmt == 'c') | 
|  | *q++ = *dp++; | 
|  | else | 
|  | *q++ = *fmt; | 
|  |  | 
|  | /* now output the saved string */ | 
|  | for (p = tmp; p < q; ++p) | 
|  | buf ? *s++ = *p : grub_putchar (*p); | 
|  | } | 
|  | } | 
|  |  | 
|  | if (buf) | 
|  | *s = '\0'; | 
|  |  | 
|  | return (s - buf); | 
|  | } | 
|  |  | 
|  | int | 
|  | etherboot_sprintf (char *buf, const char *fmt, ...) | 
|  | { | 
|  | return etherboot_vsprintf (buf, fmt, ((const int *) &fmt) + 1); | 
|  | } | 
|  |  | 
|  | void | 
|  | etherboot_printf (const char *fmt, ...) | 
|  | { | 
|  | (void) etherboot_vsprintf (0, fmt, ((const int *) &fmt) + 1); | 
|  | } | 
|  |  | 
|  | int | 
|  | inet_aton (char *p, in_addr *addr) | 
|  | { | 
|  | unsigned long ip = 0; | 
|  | int val; | 
|  | int i; | 
|  |  | 
|  | for (i = 0; i < 4; i++) | 
|  | { | 
|  | val = getdec (&p); | 
|  |  | 
|  | if (val < 0 || val > 255) | 
|  | return 0; | 
|  |  | 
|  | if (i != 3 && *p++ != '.') | 
|  | return 0; | 
|  |  | 
|  | ip = (ip << 8) | val; | 
|  | } | 
|  |  | 
|  | addr->s_addr = htonl (ip); | 
|  |  | 
|  | return 1; | 
|  | } | 
|  |  | 
|  | int | 
|  | getdec (char **ptr) | 
|  | { | 
|  | char *p = *ptr; | 
|  | int ret = 0; | 
|  |  | 
|  | if (*p < '0' || *p > '9') | 
|  | return -1; | 
|  |  | 
|  | while (*p >= '0' && *p <= '9') | 
|  | { | 
|  | ret = ret * 10 + (*p - '0'); | 
|  | p++; | 
|  | } | 
|  |  | 
|  | *ptr = p; | 
|  |  | 
|  | return ret; | 
|  | } |