Home | History | Annotate | Download | only in netboot
      1 /*
      2  *  GRUB  --  GRand Unified Bootloader
      3  *  Copyright (C) 2000,2001,2002  Free Software Foundation, Inc.
      4  *
      5  *  This program is free software; you can redistribute it and/or modify
      6  *  it under the terms of the GNU General Public License as published by
      7  *  the Free Software Foundation; either version 2 of the License, or
      8  *  (at your option) any later version.
      9  *
     10  *  This program is distributed in the hope that it will be useful,
     11  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
     12  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     13  *  GNU General Public License for more details.
     14  *
     15  *  You should have received a copy of the GNU General Public License
     16  *  along with this program; if not, write to the Free Software
     17  *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
     18  */
     19 
     20 /* Based on "src/misc.c" in etherboot-5.0.5.  */
     21 
     22 #define GRUB	1
     23 #include <etherboot.h>
     24 
     25 void
     26 sleep (int secs)
     27 {
     28   unsigned long tmo = currticks () + secs;
     29 
     30   while (currticks () < tmo)
     31     ;
     32 }
     33 
     34 void
     35 twiddle (void)
     36 {
     37   static unsigned long lastticks = 0;
     38   static int count = 0;
     39   static const char tiddles[]="-\\|/";
     40   unsigned long ticks;
     41 
     42   if (debug)
     43     {
     44       if ((ticks = currticks ()) == lastticks)
     45 	return;
     46 
     47       lastticks = ticks;
     48       grub_putchar (tiddles[(count++) & 3]);
     49       grub_putchar ('\b');
     50     }
     51 }
     52 
     53 /* Because Etherboot uses its own formats for the printf family,
     54    define separate definitions from GRUB.  */
     55 /**************************************************************************
     56 PRINTF and friends
     57 
     58 	Formats:
     59 		%[#]x	- 4 bytes long (8 hex digits, lower case)
     60 		%[#]X	- 4 bytes long (8 hex digits, upper case)
     61 		%[#]hx	- 2 bytes int (4 hex digits, lower case)
     62 		%[#]hX	- 2 bytes int (4 hex digits, upper case)
     63 		%[#]hhx	- 1 byte int (2 hex digits, lower case)
     64 		%[#]hhX	- 1 byte int (2 hex digits, upper case)
     65 			- optional # prefixes 0x or 0X
     66 		%d	- decimal int
     67 		%c	- char
     68 		%s	- string
     69 		%@	- Internet address in ddd.ddd.ddd.ddd notation
     70 		%!	- Ethernet address in xx:xx:xx:xx:xx:xx notation
     71 	Note: width specification not supported
     72 **************************************************************************/
     73 static int
     74 etherboot_vsprintf (char *buf, const char *fmt, const int *dp)
     75 {
     76   char *p, *s;
     77 
     78   s = buf;
     79   for ( ; *fmt != '\0'; ++fmt)
     80     {
     81       if (*fmt != '%')
     82 	{
     83 	  buf ? *s++ = *fmt : grub_putchar (*fmt);
     84 	  continue;
     85 	}
     86 
     87       if (*++fmt == 's')
     88 	{
     89 	  for (p = (char *) *dp++; *p != '\0'; p++)
     90 	    buf ? *s++ = *p : grub_putchar (*p);
     91 	}
     92       else
     93 	{
     94 	  /* Length of item is bounded */
     95 	  char tmp[20], *q = tmp;
     96 	  int alt = 0;
     97 	  int shift = 28;
     98 
     99 	  if (*fmt == '#')
    100 	    {
    101 	      alt = 1;
    102 	      fmt++;
    103 	    }
    104 
    105 	  if (*fmt == 'h')
    106 	    {
    107 	      shift = 12;
    108 	      fmt++;
    109 	    }
    110 
    111 	  if (*fmt == 'h')
    112 	    {
    113 	      shift = 4;
    114 	      fmt++;
    115 	    }
    116 
    117 	  /*
    118 	   * Before each format q points to tmp buffer
    119 	   * After each format q points past end of item
    120 	   */
    121 	  if ((*fmt | 0x20) == 'x')
    122 	    {
    123 	      /* With x86 gcc, sizeof(long) == sizeof(int) */
    124 	      const long *lp = (const long *) dp;
    125 	      long h = *lp++;
    126 	      int ncase = (*fmt & 0x20);
    127 
    128 	      dp = (const int *) lp;
    129 	      if (alt)
    130 		{
    131 		  *q++ = '0';
    132 		  *q++ = 'X' | ncase;
    133 		}
    134 	      for (; shift >= 0; shift -= 4)
    135 		*q++ = "0123456789ABCDEF"[(h >> shift) & 0xF] | ncase;
    136 	    }
    137 	  else if (*fmt == 'd')
    138 	    {
    139 	      int i = *dp++;
    140 	      char *r;
    141 
    142 	      if (i < 0)
    143 		{
    144 		  *q++ = '-';
    145 		  i = -i;
    146 		}
    147 
    148 	      p = q;		/* save beginning of digits */
    149 	      do
    150 		{
    151 		  *q++ = '0' + (i % 10);
    152 		  i /= 10;
    153 		}
    154 	      while (i);
    155 
    156 	      /* reverse digits, stop in middle */
    157 	      r = q;		/* don't alter q */
    158 	      while (--r > p)
    159 		{
    160 		  i = *r;
    161 		  *r = *p;
    162 		  *p++ = i;
    163 		}
    164 	    }
    165 	  else if (*fmt == '@')
    166 	    {
    167 	      unsigned char *r;
    168 	      union
    169 	      {
    170 		long		l;
    171 		unsigned char	c[4];
    172 	      }
    173 	      u;
    174 	      const long *lp = (const long *) dp;
    175 
    176 	      u.l = *lp++;
    177 	      dp = (const int *) lp;
    178 
    179 	      for (r = &u.c[0]; r < &u.c[4]; ++r)
    180 		q += etherboot_sprintf (q, "%d.", *r);
    181 
    182 	      --q;
    183 	    }
    184 	  else if (*fmt == '!')
    185 	    {
    186 	      char *r;
    187 	      p = (char *) *dp++;
    188 
    189 	      for (r = p + ETH_ALEN; p < r; ++p)
    190 		q += etherboot_sprintf (q, "%hhX:", *p);
    191 
    192 	      --q;
    193 	    }
    194 	  else if (*fmt == 'c')
    195 	    *q++ = *dp++;
    196 	  else
    197 	    *q++ = *fmt;
    198 
    199 	  /* now output the saved string */
    200 	  for (p = tmp; p < q; ++p)
    201 	    buf ? *s++ = *p : grub_putchar (*p);
    202 	}
    203     }
    204 
    205   if (buf)
    206     *s = '\0';
    207 
    208   return (s - buf);
    209 }
    210 
    211 int
    212 etherboot_sprintf (char *buf, const char *fmt, ...)
    213 {
    214   return etherboot_vsprintf (buf, fmt, ((const int *) &fmt) + 1);
    215 }
    216 
    217 void
    218 etherboot_printf (const char *fmt, ...)
    219 {
    220   (void) etherboot_vsprintf (0, fmt, ((const int *) &fmt) + 1);
    221 }
    222 
    223 int
    224 inet_aton (char *p, in_addr *addr)
    225 {
    226   unsigned long ip = 0;
    227   int val;
    228   int i;
    229 
    230   for (i = 0; i < 4; i++)
    231     {
    232       val = getdec (&p);
    233 
    234       if (val < 0 || val > 255)
    235 	return 0;
    236 
    237       if (i != 3 && *p++ != '.')
    238 	return 0;
    239 
    240       ip = (ip << 8) | val;
    241     }
    242 
    243   addr->s_addr = htonl (ip);
    244 
    245   return 1;
    246 }
    247 
    248 int
    249 getdec (char **ptr)
    250 {
    251   char *p = *ptr;
    252   int ret = 0;
    253 
    254   if (*p < '0' || *p > '9')
    255     return -1;
    256 
    257   while (*p >= '0' && *p <= '9')
    258     {
    259       ret = ret * 10 + (*p - '0');
    260       p++;
    261     }
    262 
    263   *ptr = p;
    264 
    265   return ret;
    266 }
    267