Exemplo n.º 1
0
/* Convert a device name from IEEE1275 syntax to GRUB syntax.  */
char *
grub_ieee1275_encode_devname (const char *path)
{
  char *device = grub_ieee1275_get_devname (path);
  char *partition = grub_ieee1275_parse_args (path, GRUB_PARSE_PARTITION);
  char *encoding;

  if (partition)
    {
      unsigned int partno = grub_strtoul (partition, 0, 0);

      if (grub_ieee1275_test_flag (GRUB_IEEE1275_FLAG_0_BASED_PARTITIONS))
	/* GRUB partition 1 is OF partition 0.  */
	partno++;

      /* Assume partno will require less than five bytes to encode.  */
      encoding = grub_malloc (grub_strlen (device) + 3 + 5);
      grub_sprintf (encoding, "(%s,%d)", device, partno);
    }
  else
    {
      encoding = grub_malloc (grub_strlen (device) + 2);
      grub_sprintf (encoding, "(%s)", device);
    }

  grub_free (partition);
  grub_free (device);

  return encoding;
}
Exemplo n.º 2
0
static int
grub_efidisk_iterate (int (*hook) (const char *name))
{
  struct grub_efidisk_data *d;
  char buf[16];
  int count;
  
  for (d = fd_devices, count = 0; d; d = d->next, count++)
    {
      grub_sprintf (buf, "fd%d", count);
      grub_dprintf ("efidisk", "iterating %s\n", buf);
      if (hook (buf))
	return 1;
    }
  
  for (d = hd_devices, count = 0; d; d = d->next, count++)
    {
      grub_sprintf (buf, "hd%d", count);
      grub_dprintf ("efidisk", "iterating %s\n", buf);
      if (hook (buf))
	return 1;
    }
  
  for (d = cd_devices, count = 0; d; d = d->next, count++)
    {
      grub_sprintf (buf, "cd%d", count);
      grub_dprintf ("efidisk", "iterating %s\n", buf);
      if (hook (buf))
	return 1;
    }

  return 0;
}
Exemplo n.º 3
0
static int
grub_scsi_iterate (int (*hook) (const char *name))
{
    grub_scsi_dev_t p;

    auto int scsi_iterate (const char *name, int luns);

    int scsi_iterate (const char *name, int luns)
    {
        char sname[40];
        int i;

        /* In case of a single LUN, just return `usbX'.  */
        if (luns == 1)
            return hook (name);

        /* In case of multiple LUNs, every LUN will get a prefix to
        distinguish it.  */
        for (i = 0; i < luns; i++)
        {
            grub_sprintf (sname, "%s%c", name, 'a' + i);
            if (hook (sname))
                return 1;
        }
        return 0;
    }
Exemplo n.º 4
0
static char *
pc_partition_map_get_name (const grub_partition_t p)
{
  char *name;
  struct grub_pc_partition *pcdata = p->data;
  
  name = grub_malloc (13);
  if (! name)
    return 0;

  if (pcdata->bsd_part < 0)
    grub_sprintf (name, "%d", pcdata->dos_part + 1);
  else if (pcdata->dos_part < 0)
    grub_sprintf (name, "%c", pcdata->bsd_part + 'a');
  else
    grub_sprintf (name, "%d,%c", pcdata->dos_part + 1, pcdata->bsd_part + 'a');

  return name;
}
Exemplo n.º 5
0
static char *
sun_partition_map_get_name (const grub_partition_t p)
{
  char *name;
  
  name = grub_malloc (13);
  if (name)
    grub_sprintf (name, "%d", p->index + 1);
  
  return name;
}
Exemplo n.º 6
0
static inline void
save_number(const char *fmt, int number, int len)
{
    if (len < 30)
	len = 30;		/* actually log10(MAX_INT)+1 */

    get_space(len + 1);

    (void) grub_sprintf(out_buff + out_used, fmt, number);
    out_used += grub_strlen(out_buff + out_used);
}
Exemplo n.º 7
0
static inline void
save_text(const char *fmt, const char *s, int len)
{
    int s_len = grub_strlen(s);
    if (len > (int) s_len)
	s_len = len;

    get_space(s_len + 1);

    (void) grub_sprintf(out_buff + out_used, fmt, s);
    out_used += grub_strlen(out_buff + out_used);
}
Exemplo n.º 8
0
/* Walk children of 'devpath', calling hook for each.  */
grub_err_t
grub_children_iterate (char *devpath,
		  int (*hook) (struct grub_ieee1275_devalias *alias))
{
  grub_ieee1275_phandle_t dev;
  grub_ieee1275_phandle_t child;

  if (grub_ieee1275_finddevice (devpath, &dev))
    return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "Unknown device");

  if (grub_ieee1275_child (dev, &child))
    return grub_error (GRUB_ERR_BAD_DEVICE, "Device has no children");

  do
    {
      /* XXX: Don't use hardcoded path lengths.  */
      char childtype[64];
      char childpath[64];
      char childname[64];
      char fullname[64];
      struct grub_ieee1275_devalias alias;
      int actual;

      if (grub_ieee1275_get_property (child, "device_type", &childtype,
				      sizeof childtype, &actual))
	continue;

      if (grub_ieee1275_package_to_path (child, childpath, sizeof childpath,
					 &actual))
	continue;

      if (grub_ieee1275_get_property (child, "name", &childname,
				      sizeof childname, &actual))
	continue;

      grub_sprintf (fullname, "%s/%s", devpath, childname);

      alias.type = childtype;
      alias.path = childpath;
      alias.name = fullname;
      hook (&alias);
    }
  while (grub_ieee1275_peer (child, &child));

  return 0;
}
Exemplo n.º 9
0
static int
tftp (const char *name, int (*fnc) (unsigned char *, int, int, int))
{
  int retry = 0;
  static unsigned short iport = 2000;
  unsigned short oport = 0;
  unsigned short len, block = 0, prevblock = 0;
  int bcounter = 0;
  struct tftp_t *tr;
  struct tftpreq_t tp;
  int rc;
  int packetsize = TFTP_DEFAULTSIZE_PACKET;
  
  await_reply (AWAIT_QDRAIN, 0, NULL, 0);
  
  tp.opcode = htons (TFTP_RRQ);
  len = (grub_sprintf ((char *) tp.u.rrq, "%s%coctet%cblksize%c%d",
		       name, 0, 0, 0, TFTP_MAX_PACKET)
	 + sizeof (tp.ip) + sizeof (tp.udp) + sizeof (tp.opcode) + 1);
  if (! udp_transmit (arptable[ARP_SERVER].ipaddr.s_addr, ++iport,
		      TFTP_PORT, len, &tp))
    return 0;
  
  for (;;)
    {
      long timeout;
      
#ifdef CONGESTED
      timeout = rfc2131_sleep_interval (block ? TFTP_REXMT : TIMEOUT, retry);
#else
      timeout = rfc2131_sleep_interval (TIMEOUT, retry);
#endif

      if (! await_reply (AWAIT_TFTP, iport, NULL, timeout))
	{
	  if (! block && retry++ < MAX_TFTP_RETRIES)
	    {
	      
	      if (! udp_transmit (arptable[ARP_SERVER].ipaddr.s_addr,
				  ++iport, TFTP_PORT, len, &tp))
		return 0;
	      
	      continue;
	    }
	  
#ifdef CONGESTED
	  if (block && ((retry += TFTP_REXMT) < TFTP_TIMEOUT))
	    {
	      
#ifdef MDEBUG
	      grub_printf ("<REXMT>\n");
#endif
	      udp_transmit (arptable[ARP_SERVER].ipaddr.s_addr,
			    iport, oport,
			    TFTP_MIN_PACKET, &tp);
	      continue;
	    }
#endif
	  
	  break;
	}
      
      tr = (struct tftp_t *) &nic.packet[ETH_HLEN];
      if (tr->opcode == ntohs (TFTP_ERROR))
	{
	  grub_printf ("TFTP error %d (%s)\n",
		       ntohs (tr->u.err.errcode),
		       tr->u.err.errmsg);
	  break;
	}
      
      if (tr->opcode == ntohs (TFTP_OACK))
	{
	  char *p = tr->u.oack.data, *e;
	  
	  
	  if (prevblock)
	    
	    continue;
	  
	  len = ntohs (tr->udp.len) - sizeof (struct udphdr) - 2;
	  if (len > TFTP_MAX_PACKET)
	    goto noak;
	  
	  e = p + len;
	  while (*p != '\000' && p < e)
	    {
	      if (! grub_strcmp ("blksize", p))
		{
		  p += 8;
		  if ((packetsize = getdec (&p)) < TFTP_DEFAULTSIZE_PACKET)
		    goto noak;
		  
		  while (p < e && *p)
		    p++;
		  
		  if (p < e)
		    p++;
		}
	      else
		{
		noak:
		  tp.opcode = htons (TFTP_ERROR);
		  tp.u.err.errcode = 8;
		  len = (grub_sprintf ((char *) tp.u.err.errmsg,
				       "RFC1782 error")
			 + sizeof (tp.ip) + sizeof (tp.udp)
			 + sizeof (tp.opcode) + sizeof (tp.u.err.errcode)
			 + 1);
		  udp_transmit (arptable[ARP_SERVER].ipaddr.s_addr,
				iport, ntohs (tr->udp.src),
				len, &tp);
		  return 0;
		}
	    }
	  
	  if (p > e)
	    goto noak;
	  
	  
	  block = tp.u.ack.block = 0; 
	}
      else if (tr->opcode == ntohs (TFTP_DATA))
	{
	  len = ntohs (tr->udp.len) - sizeof (struct udphdr) - 4;
	  
	  if (len > packetsize)
	    
	    continue;
	  
	  block = ntohs (tp.u.ack.block = tr->u.data.block);
	}
      else
	
	break;
      
      if ((block || bcounter) && (block != prevblock + 1))
	
	tp.u.ack.block = htons (block = prevblock);
      
      
      tp.opcode = htons (TFTP_ACK);
      oport = ntohs (tr->udp.src);
      
      udp_transmit (arptable[ARP_SERVER].ipaddr.s_addr, iport,
		    oport, TFTP_MIN_PACKET, &tp);
      
      if ((unsigned short) (block - prevblock) != 1)
	continue;
      
      prevblock = block;
      
      retry = 0;
      
      if ((rc = fnc (tr->u.data.download,
		     ++bcounter, len, len < packetsize)) >= 0)
	return rc;

      
      if (len < packetsize)           
	return 1;
    }
  
  return 0;
}
/* Fill the buffer by receiving the data via the TFTP protocol.  */
static int
buf_fill (int abort)
{
#ifdef TFTP_DEBUG
  grub_printf ("buf_fill (%d)\n", abort);
#endif
  
  while (! buf_eof && (buf_read + packetsize <= FSYS_BUFLEN))
    {
      struct tftp_t *tr;
      long timeout;

#ifdef CONGESTED
      timeout = rfc2131_sleep_interval (block ? TFTP_REXMT : TIMEOUT, retry);
#else
      timeout = rfc2131_sleep_interval (TIMEOUT, retry);
#endif
  
      if (! await_reply (AWAIT_TFTP, iport, NULL, timeout))
	{
	  if (ip_abort)
	    return 0;

	  if (! block && retry++ < MAX_TFTP_RETRIES)
	    {
	      /* Maybe initial request was lost.  */
#ifdef TFTP_DEBUG
	      grub_printf ("Maybe initial request was lost.\n");
#endif
	      if (! udp_transmit (arptable[ARP_SERVER].ipaddr.s_addr,
				  ++iport, TFTP_PORT, len, &tp))
		return 0;
	      
	      continue;
	    }
	  
#ifdef CONGESTED
	  if (block && ((retry += TFTP_REXMT) < TFTP_TIMEOUT))
	    {
	      /* We resend our last ack.  */
# ifdef TFTP_DEBUG
	      grub_printf ("<REXMT>\n");
# endif
	      udp_transmit (arptable[ARP_SERVER].ipaddr.s_addr,
			    iport, oport,
			    TFTP_MIN_PACKET, &tp);
	      continue;
	    }
#endif
	  /* Timeout.  */
	  return 0;
	}

      tr = (struct tftp_t *) &nic.packet[ETH_HLEN];
      if (tr->opcode == ntohs (TFTP_ERROR))
	{
	  grub_printf ("TFTP error %d (%s)\n",
		       ntohs (tr->u.err.errcode),
		       tr->u.err.errmsg);
	  return 0;
	}
      
      if (tr->opcode == ntohs (TFTP_OACK))
	{
	  char *p = tr->u.oack.data, *e;

#ifdef TFTP_DEBUG
	  grub_printf ("OACK ");
#endif
	  /* Shouldn't happen.  */
	  if (prevblock)
	    {
	      /* Ignore it.  */
	      grub_printf ("%s:%d: warning: PREVBLOCK != 0 (0x%x)\n",
			   __FILE__, __LINE__, prevblock);
	      continue;
	    }
	  
	  len = ntohs (tr->udp.len) - sizeof (struct udphdr) - 2;
	  if (len > TFTP_MAX_PACKET)
	    goto noak;
	  
	  e = p + len;
	  while (*p != '\000' && p < e)
	    {
	      if (! grub_strcmp ("blksize", p))
		{
		  p += 8;
		  if ((packetsize = getdec (&p)) < TFTP_DEFAULTSIZE_PACKET)
		    goto noak;
#ifdef TFTP_DEBUG
		  grub_printf ("blksize = %d\n", packetsize);
#endif
		}
	      else if (! grub_strcmp ("tsize", p))
		{
		  p += 6;
		  if ((filemax = getdec (&p)) < 0)
		    {
		      filemax = -1;
		      goto noak;
		    }
#ifdef TFTP_DEBUG
		  grub_printf ("tsize = %d\n", filemax);
#endif
		}
	      else
		{
		noak:
#ifdef TFTP_DEBUG
		  grub_printf ("NOAK\n");
#endif
		  tp.opcode = htons (TFTP_ERROR);
		  tp.u.err.errcode = 8;
		  len = (grub_sprintf ((char *) tp.u.err.errmsg,
				       "RFC1782 error")
			 + sizeof (tp.ip) + sizeof (tp.udp)
			 + sizeof (tp.opcode) + sizeof (tp.u.err.errcode)
			 + 1);
		  udp_transmit (arptable[ARP_SERVER].ipaddr.s_addr,
				iport, ntohs (tr->udp.src),
				len, &tp);
		  return 0;
		}
	      
	      while (p < e && *p)
		p++;
	      
	      if (p < e)
		p++;
	    }
	  
	  if (p > e)
	    goto noak;
	  
	  /* This ensures that the packet does not get processed as
	     data!  */
	  block = tp.u.ack.block = 0;
	}
      else if (tr->opcode == ntohs (TFTP_DATA))
	{
#ifdef TFTP_DEBUG
	  grub_printf ("DATA ");
#endif
	  len = ntohs (tr->udp.len) - sizeof (struct udphdr) - 4;
	  
	  /* Shouldn't happen.  */
	  if (len > packetsize)
	    {
	      /* Ignore it.  */
	      grub_printf ("%s:%d: warning: LEN > PACKETSIZE (0x%x > 0x%x)\n",
			   __FILE__, __LINE__, len, packetsize);
	      continue;
	    }
	  
	  block = ntohs (tp.u.ack.block = tr->u.data.block);
	}
      else
	/* Neither TFTP_OACK nor TFTP_DATA.  */
	break;

      if ((block || bcounter) && (block != prevblock + (unsigned short) 1))
	/* Block order should be continuous */
	tp.u.ack.block = htons (block = prevblock);
      
      /* Should be continuous.  */
      tp.opcode = abort ? htons (TFTP_ERROR) : htons (TFTP_ACK);
      oport = ntohs (tr->udp.src);

#ifdef TFTP_DEBUG
      grub_printf ("ACK\n");
#endif
      /* Ack.  */
      udp_transmit (arptable[ARP_SERVER].ipaddr.s_addr, iport,
		    oport, TFTP_MIN_PACKET, &tp);
      
      if (abort)
	{
	  buf_eof = 1;
	  break;
	}

      /* Retransmission or OACK.  */
      if ((unsigned short) (block - prevblock) != 1)
	/* Don't process.  */
	continue;
      
      prevblock = block;
      /* Is it the right place to zero the timer?  */
      retry = 0;

      /* In GRUB, this variable doesn't play any important role at all,
	 but use it for consistency with Etherboot.  */
      bcounter++;
      
      /* Copy the downloaded data to the buffer.  */
      grub_memmove (buf + buf_read, tr->u.data.download, len);
      buf_read += len;

      /* End of data.  */
      if (len < packetsize)		
	buf_eof = 1;
    }
  
  return 1;
}
/* Check if the file DIRNAME really exists. Get the size and save it in
   FILEMAX.  */
int
tftp_dir (char *dirname)
{
  int ch;

#ifdef TFTP_DEBUG
  grub_printf ("tftp_dir (%s)\n", dirname);
#endif
  
  /* In TFTP, there is no way to know what files exist.  */
  if (print_possibilities)
    return 1;

  /* Don't know the size yet.  */
  filemax = -1;
  
 reopen:
  /* Construct the TFTP request packet.  */
  tp.opcode = htons (TFTP_RRQ);
  /* Terminate the filename.  */
  ch = nul_terminate (dirname);
  /* Make the request string (octet, blksize and tsize).  */
  len = (grub_sprintf ((char *) tp.u.rrq,
		       "%s%coctet%cblksize%c%d%ctsize%c0",
		       dirname, 0, 0, 0, TFTP_MAX_PACKET, 0, 0)
	 + sizeof (tp.ip) + sizeof (tp.udp) + sizeof (tp.opcode) + 1);
  /* Restore the original DIRNAME.  */
  dirname[grub_strlen (dirname)] = ch;
  /* Save the TFTP packet so that we can reopen the file later.  */
  grub_memmove ((char *) &saved_tp, (char *) &tp, len);
  saved_len = len;
  if (! send_rrq ())
    {
      errnum = ERR_WRITE;
      return 0;
    }
  
  /* Read the data.  */
  if (! buf_fill (0))
    {
      errnum = ERR_FILE_NOT_FOUND;
      return 0;
    }

  if (filemax == -1)
    {
      /* The server doesn't support the "tsize" option, so we must read
	 the file twice...  */

      /* Zero the size of the file.  */
      filemax = 0;
      do
	{
	  /* Add the length of the downloaded data.  */
	  filemax += buf_read;
	  /* Reset the offset. Just discard the contents of the buffer.  */
	  buf_read = 0;
	  /* Read the data.  */
	  if (! buf_fill (0))
	    {
	      errnum = ERR_READ;
	      return 0;
	    }
	}
      while (! buf_eof);

      /* Maybe a few amounts of data remains.  */
      filemax += buf_read;
      
      /* Retry the open instruction.  */
      goto reopen;
    }

  return 1;
}
Exemplo n.º 12
0
static char *
grub_ieee1275_parse_args (const char *path, enum grub_ieee1275_parse_type ptype)
{
  char type[64]; /* XXX check size.  */
  char *device = grub_ieee1275_get_devname (path);
  char *args = grub_ieee1275_get_devargs (path);
  char *ret = 0;
  grub_ieee1275_phandle_t dev;

  if (!args)
    /* Shouldn't happen.  */
    return 0;

  /* We need to know what type of device it is in order to parse the full
     file path properly.  */
  if (grub_ieee1275_finddevice (device, &dev))
    {
      grub_error (GRUB_ERR_UNKNOWN_DEVICE, "Device %s not found\n", device);
      goto fail;
    }
  if (grub_ieee1275_get_property (dev, "device_type", &type, sizeof type, 0))
    {
      grub_error (GRUB_ERR_UNKNOWN_DEVICE,
		  "Device %s lacks a device_type property\n", device);
      goto fail;
    }

  if (!grub_strcmp ("block", type))
    {
      /* The syntax of the device arguments is defined in the CHRP and PReP
         IEEE1275 bindings: "[partition][,[filename]]".  */
      char *comma = grub_strchr (args, ',');

      if (ptype == GRUB_PARSE_FILENAME)
	{
	  if (comma)
	    {
	      char *filepath = comma + 1;

	      ret = grub_malloc (grub_strlen (filepath) + 1);
	      /* Make sure filepath has leading backslash.  */
	      if (filepath[0] != '\\')
		grub_sprintf (ret, "\\%s", filepath);
	      else
		grub_strcpy (ret, filepath);
	    }
	}
      else if (ptype == GRUB_PARSE_PARTITION)
        {
	  if (!comma)
	    ret = grub_strdup (args);
	  else
	    ret = grub_strndup (args, (grub_size_t)(comma - args));
	}
    }
  else
    {
      /* XXX Handle net devices by configuring & registering a grub_net_dev
	 here, then return its name?
	 Example path: "net:<server ip>,<file name>,<client ip>,<gateway
	 ip>,<bootp retries>,<tftp retries>".  */
      grub_printf ("Unsupported type %s for device %s\n", type, device);
    }

fail:
  grub_free (device);
  grub_free (args);
  return ret;
}
Exemplo n.º 13
0
static int
tftp (const char *name, int (*fnc) (unsigned char *, int, int, int))
{
  int retry = 0;
  static unsigned short iport = 2000;
  unsigned short oport = 0;
  unsigned short len, block = 0, prevblock = 0;
  int bcounter = 0;
  struct tftp_t *tr;
  struct tftpreq_t tp;
  int rc;
  int packetsize = TFTP_DEFAULTSIZE_PACKET;
  
  /* Clear out the Rx queue first.  It contains nothing of interest,
   * except possibly ARP requests from the DHCP/TFTP server.  We use
   * polling throughout Etherboot, so some time may have passed since we
   * last polled the receive queue, which may now be filled with
   * broadcast packets.  This will cause the reply to the packets we are
   * about to send to be lost immediately.  Not very clever.  */
  await_reply (AWAIT_QDRAIN, 0, NULL, 0);
  
  tp.opcode = htons (TFTP_RRQ);
  len = (grub_sprintf ((char *) tp.u.rrq, "%s%coctet%cblksize%c%d",
		       name, 0, 0, 0, TFTP_MAX_PACKET)
	 + sizeof (tp.ip) + sizeof (tp.udp) + sizeof (tp.opcode) + 1);
  if (! udp_transmit (arptable[ARP_SERVER].ipaddr.s_addr, ++iport,
		      TFTP_PORT, len, &tp))
    return 0;
  
  for (;;)
    {
      long timeout;
      
#ifdef CONGESTED
      timeout = rfc2131_sleep_interval (block ? TFTP_REXMT : TIMEOUT, retry);
#else
      timeout = rfc2131_sleep_interval (TIMEOUT, retry);
#endif

      if (! await_reply (AWAIT_TFTP, iport, NULL, timeout))
	{
	  if (! block && retry++ < MAX_TFTP_RETRIES)
	    {
	      /* Maybe initial request was lost.  */
	      if (! udp_transmit (arptable[ARP_SERVER].ipaddr.s_addr,
				  ++iport, TFTP_PORT, len, &tp))
		return 0;
	      
	      continue;
	    }
	  
#ifdef CONGESTED
	  if (block && ((retry += TFTP_REXMT) < TFTP_TIMEOUT))
	    {
	      /* We resend our last ack.  */
#ifdef MDEBUG
	      grub_printf ("<REXMT>\n");
#endif
	      udp_transmit (arptable[ARP_SERVER].ipaddr.s_addr,
			    iport, oport,
			    TFTP_MIN_PACKET, &tp);
	      continue;
	    }
#endif
	  /* Timeout.  */
	  break;
	}
      
      tr = (struct tftp_t *) &nic.packet[ETH_HLEN];
      if (tr->opcode == ntohs (TFTP_ERROR))
	{
	  grub_printf ("TFTP error %d (%s)\n",
		       ntohs (tr->u.err.errcode),
		       tr->u.err.errmsg);
	  break;
	}
      
      if (tr->opcode == ntohs (TFTP_OACK))
	{
	  char *p = tr->u.oack.data, *e;
	  
	  /* Shouldn't happen.  */
	  if (prevblock)
	    /* Ignore it.  */
	    continue;
	  
	  len = ntohs (tr->udp.len) - sizeof (struct udphdr) - 2;
	  if (len > TFTP_MAX_PACKET)
	    goto noak;
	  
	  e = p + len;
	  while (*p != '\000' && p < e)
	    {
	      if (! grub_strcmp ("blksize", p))
		{
		  p += 8;
		  if ((packetsize = getdec (&p)) < TFTP_DEFAULTSIZE_PACKET)
		    goto noak;
		  
		  while (p < e && *p)
		    p++;
		  
		  if (p < e)
		    p++;
		}
	      else
		{
		noak:
		  tp.opcode = htons (TFTP_ERROR);
		  tp.u.err.errcode = 8;
		  len = (grub_sprintf ((char *) tp.u.err.errmsg,
				       "RFC1782 error")
			 + sizeof (tp.ip) + sizeof (tp.udp)
			 + sizeof (tp.opcode) + sizeof (tp.u.err.errcode)
			 + 1);
		  udp_transmit (arptable[ARP_SERVER].ipaddr.s_addr,
				iport, ntohs (tr->udp.src),
				len, &tp);
		  return 0;
		}
	    }
	  
	  if (p > e)
	    goto noak;
	  
	  /* This ensures that the packet does not get processed as data!  */
	  block = tp.u.ack.block = 0; 
	}
      else if (tr->opcode == ntohs (TFTP_DATA))
	{
	  len = ntohs (tr->udp.len) - sizeof (struct udphdr) - 4;
	  /* Shouldn't happen.  */
	  if (len > packetsize)
	    /* Ignore it.  */
	    continue;
	  
	  block = ntohs (tp.u.ack.block = tr->u.data.block);
	}
      else
	/* Neither TFTP_OACK nor TFTP_DATA.  */
	break;
      
      if ((block || bcounter) && (block != prevblock + 1))
	/* Block order should be continuous */
	tp.u.ack.block = htons (block = prevblock);
      
      /* Should be continuous.  */
      tp.opcode = htons (TFTP_ACK);
      oport = ntohs (tr->udp.src);
      /* Ack.  */
      udp_transmit (arptable[ARP_SERVER].ipaddr.s_addr, iport,
		    oport, TFTP_MIN_PACKET, &tp);
      
      if ((unsigned short) (block - prevblock) != 1)
	/* Retransmission or OACK, don't process via callback
	 * and don't change the value of prevblock.  */
	continue;
      
      prevblock = block;
      /* Is it the right place to zero the timer?  */
      retry = 0;
      
      if ((rc = fnc (tr->u.data.download,
		     ++bcounter, len, len < packetsize)) >= 0)
	return rc;

      /* End of data.  */
      if (len < packetsize)           
	return 1;
    }
  
  return 0;
}
Exemplo n.º 14
0
/*
 * Given the nul-terminated input string s, expand all variable references
 * within that string into the buffer pointed to by d, which must be of length
 * not less than len bytes.
 *
 * We also expand the special case tokens "$ISADIR" and "$ZFS-BOOTFS" here.
 *
 * If the string will not fit, returns ERR_WONT_FIT.
 * If a nonexistent variable is referenced, returns ERR_NOVAR.
 * Otherwise, returns 0.  The resulting string is nul-terminated.  On error,
 * the contents of the destination buffer are undefined.
 */
int
expand_string(const char *s, char *d, unsigned int len)
{
	unsigned int i;
	int vlen;
	const char *p;
	char *q;
	const char *start;
	char name[EV_NAMELEN];
	const char *val;

	for (p = s, q = d; *p != '\0' && q < d + len; ) {
		/* Special case: $ISADIR */
		if (grub_strncmp(p, "$ISADIR", 7) == 0) {
			if (isamd64() && check_min_mem64()) {
				if (q + 5 >= d + len)
					return (ERR_WONT_FIT);
				(void) grub_memcpy(q, "amd64", 5);
				q += 5;	/* amd64 */
			}
			p += 7;	/* $ISADIR */
			continue;
		}
		/* Special case: $ZFS-BOOTFS */
		if (grub_strncmp(p, "$ZFS-BOOTFS", 11) == 0 &&
		    is_zfs_mount != 0) {
			if (current_bootpath[0] == '\0' &&
			    current_devid[0] == '\0') {
				return (ERR_NO_BOOTPATH);
			}

			/* zfs-bootfs=%s/%u */
			vlen = (current_bootfs_obj > 0) ? 10 : 0;
			vlen += 11;
			vlen += strlen(current_rootpool);

			/* ,bootpath=\"%s\" */
			if (current_bootpath[0] != '\0')
				vlen += 12 + strlen(current_bootpath);

			/* ,diskdevid=\"%s\" */
			if (current_devid[0] != '\0')
				vlen += 13 + strlen(current_devid);

			if (q + vlen >= d + len)
				return (ERR_WONT_FIT);

			if (current_bootfs_obj > 0) {
				q += grub_sprintf(q, "zfs-bootfs=%s/%u",
				    current_rootpool, current_bootfs_obj);
			} else {
				q += grub_sprintf(q, "zfs-bootfs=%s",
				    current_rootpool);
			}
			if (current_bootpath[0] != '\0') {
				q += grub_sprintf(q, ",bootpath=\"%s\"",
				    current_bootpath);
			}
			if (current_devid[0] != '\0') {
				q += grub_sprintf(q, ",diskdevid=\"%s\"",
				    current_devid);
			}

			p += 11;	/* $ZFS-BOOTFS */
			continue;
		}
		if (*p == '$' && *(p + 1) == '{') {
			start = p + 2;
			for (p = start; *p != '\0' && *p != '}' &&
			    p - start < sizeof (name) - 1; p++) {
				name[p - start] = *p;
			}
			/*
			 * Unterminated reference.  Copy verbatim.
			 */
			if (p - start >= sizeof (name) - 1 || *p != '}') {
				p = start;
				*q++ = '$';
				*q++ = '{';
				continue;
			}

			name[p - start] = '\0';
			val = get_variable(name);
			if (val == NULL)
				return (ERR_NOVAR);

			if ((vlen = grub_strlen(val)) >= q + len - d)
				return (ERR_WONT_FIT);

			(void) grub_memcpy(q, val, vlen);
			q += vlen;
			p++;
		} else {
			*q++ = *p++;
		}
	}

	if (q >= d + len)
		return (ERR_WONT_FIT);

	*q = '\0';

	return (0);
}