/* * 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. */ #include "grub.h" #include "timer.h" #include "nic.h" /************************************************************************** RANDOM - compute a random number between 0 and 2147483647L or 2147483562? **************************************************************************/ int32_t random(void) { static int32_t seed = 0; int32_t q; if (!seed) /* Initialize linear congruential generator */ seed = currticks() + *(int32_t *)&arptable[ARP_CLIENT].node + ((int16_t *)arptable[ARP_CLIENT].node)[2]; /* simplified version of the LCG given in Bruce Schneier's "Applied Cryptography" */ q = seed/53668; if ((seed = 40014*(seed-53668*q) - 12211*q) < 0) seed += 2147483563L; return seed; } /************************************************************************** POLL INTERRUPTIONS **************************************************************************/ void poll_interruptions(void) { if (checkkey() != -1 && ASCII_CHAR(getkey()) == K_INTR) { user_abort++; } } /************************************************************************** SLEEP **************************************************************************/ void sleep(int secs) { unsigned long tmo; for (tmo = currticks()+secs*TICKS_PER_SEC; currticks() < tmo; ) { poll_interruptions(); } } /************************************************************************** INTERRUPTIBLE SLEEP **************************************************************************/ void interruptible_sleep(int secs) { printf("\n"); return sleep(secs); } /************************************************************************** TWIDDLE **************************************************************************/ void twiddle(void) { #ifdef BAR_PROGRESS static int count=0; static const char tiddles[]="-\\|/"; static unsigned long lastticks = 0; unsigned long ticks; #endif #ifdef FREEBSD_PXEEMU extern char pxeemu_nbp_active; if(pxeemu_nbp_active != 0) return; #endif #ifdef BAR_PROGRESS /* Limit the maximum rate at which characters are printed */ ticks = currticks(); if ((lastticks + (TICKS_PER_SEC/18)) > ticks) return; lastticks = ticks; putchar(tiddles[(count++)&3]); putchar('\b'); #else //putchar('.'); #endif /* BAR_PROGRESS */ } /* 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; }