/* eptedit PART SLOT TYPE BCYL BHEAD BSEC ECYL EHEAD ESEC RSEC TSEC */
static int
eptedit_func (char *arg, int flags)
{
  int ept_slot, new_type, rel_sec, tot_sec;
  int beg_cyl, beg_head, beg_sec, end_cyl, end_head, end_sec;
  int start_cl, start_ch, start_dh;
  int end_cl, end_ch, end_dh;
  unsigned long part = 0xFFFFFF;
  unsigned long start, len, offset, ext_offset;
  int entry, type;
  char mbr[512];

  /* Convert CHS address to the INT 13 format.  */
  auto void chs_to_int13 (int cylinder, int head, int sector, int *cl, int *ch, int *dh);
  void chs_to_int13 (int cylinder, int head, int sector, int *cl, int *ch, int *dh)
    {
      if (cylinder >= buf_geom.cylinders)
	cylinder = buf_geom.cylinders - 1;
      
      *cl = sector | ((cylinder & 0x300) >> 2);
      *ch = cylinder & 0xFF;
      *dh = head;
    }
      
  /* Get the drive and the partition.  */
  if (! set_device (arg))
    return 1;

  /* The drive must be a hard disk.  */
  if (! (current_drive & 0x80))
    {
      errnum = ERR_BAD_ARGUMENT;
      return 1;
    }

  /* The partition must be a PC slice.  */
  if ((current_partition >> 16) == 0xFF
      || (current_partition & 0xFFFF) != 0xFFFF)
    {
      errnum = ERR_BAD_ARGUMENT;
      return 1;
    }

  /* Get the EPT slot. */
  arg = skip_to (0, arg);
  if (! safe_parse_maxint (&arg, &ept_slot))
    return 1;

  /* The EPT slot must be "current" or "next".  */
  if ( !(ept_slot == 'c' || ept_slot == 'n') )
    {
      errnum = ERR_BAD_ARGUMENT;
      return 1;
    }

  /* Get the new partition type.  */
  arg = skip_to (0, arg);
  if (! safe_parse_maxint (&arg, &new_type))
    return 1;

  /* The partition type is unsigned char.  */
  if (new_type > 0xFF)
    {
      errnum = ERR_BAD_ARGUMENT;
      return 1;
    }

  /* Get the new begin cylinder.  */
  arg = skip_to (0, arg);
  if (! safe_parse_maxint (&arg, &beg_cyl))
    return 1;
  
  /* Check for start past end of disk.  */
  if (beg_cyl >= buf_geom.total_sectors / (buf_geom.heads * buf_geom.sectors) )
    {
      errnum = ERR_GEOM;
      return 1;
    }

  /* Get the new begin head.  */
  arg = skip_to (0, arg);
  if (! safe_parse_maxint (&arg, &beg_head))
    return 1;
  
  /* Check for invalid head value.  */
  if (beg_head >= buf_geom.heads)
    {
      errnum = ERR_GEOM;
      return 1;
    }

  /* Get the new begin sector.  */
  arg = skip_to (0, arg);
  if (! safe_parse_maxint (&arg, &begin_sec))
    return 1;
  
  /* Check for invalid sector value.  */
  if (beg_sec > buf_geom.sectors)
    {
      errnum = ERR_GEOM;
      return 1;
    }

  /* Get the new end cylinder.  */
  arg = skip_to (0, arg);
  if (! safe_parse_maxint (&arg, &end_cyl))
    return 1;
  
  /* Check for end past end of disk.  */
  if (end_cyl >= buf_geom.total_sectors / (buf_geom.heads * buf_geom.sectors) )
    {
      errnum = ERR_GEOM;
      return 1;
    }

  /* Get the new end head.  */
  arg = skip_to (0, arg);
  if (! safe_parse_maxint (&arg, &end_head))
    return 1;
  
  /* Check for invalid head value.  */
  if (end_head >= buf_geom.heads)
    {
      errnum = ERR_GEOM;
      return 1;
    }

  /* Get the new end sector.  */
  arg = skip_to (0, arg);
  if (! safe_parse_maxint (&arg, &end_sec))
    return 1;
  
  /* Check for invalid sector value.  */
  if (end_sec > buf_geom.sectors)
    {
      errnum = ERR_GEOM;
      return 1;
    }

  /* Get the new relative sectors.  */
  arg = skip_to (0, arg);
  if (! safe_parse_maxint (&arg, &rel_sec))
    return 1;
  
  /* Get the new total sectors.  */
  arg = skip_to (0, arg);
  if (! safe_parse_maxint (&arg, &tot_sec))
    return 1;

  /* Check for unreasonable relative sectors + total sectors.  */
  if (rel_sec + tot_sec > buf_geom.total_sectors)
    {
      errnum = ERR_GEOM;
      return 1;
    }

  /* Store the partition information in the MBR.  */
  chs_to_int13 (beg_cyl, beg_head, beg_sec, &start_cl, &start_ch, &start_dh);
  chs_to_int13 (end_cyl, end_head, end_sec, &end_cl, &end_ch, &end_dh);

  /* Look for the partition.  */
  while (next_partition (current_drive, 0xFFFFFF, &part, &type,
			 &start, &len, &offset, &entry,
			 &ext_offset, mbr))
    {
      if (part == current_partition)
	{
	  /* Found.  */

              /* Adjust for "current" or "next" slot.  */
              if (ept_slot == 'n') entry++;

	  /* Set the new values for SLOT in EPT.  */
              PC_SLICE_FLAG (mbr, entry) = 0;
              PC_SLICE_HEAD (mbr, entry) = start_dh;
              PC_SLICE_SEC (mbr, entry) = start_cl;
              PC_SLICE_CYL (mbr, entry) = start_ch;
              PC_SLICE_TYPE (mbr, entry) = new_type;
              PC_SLICE_EHEAD (mbr, entry) = end_dh;
              PC_SLICE_ESEC (mbr, entry) = end_cl;
              PC_SLICE_ECYL (mbr, entry) = end_ch;
              PC_SLICE_START (mbr, entry) = rel_sec;
              PC_SLICE_LENGTH (mbr, entry) = tot_sec;

	  /* Write back the MBR to the disk.  */
	  buf_track = -1;
	  if (! rawwrite (current_drive, offset, mbr))
	    return 1;

	  /* Succeed.  */
	  return 0;
	}
    }

  /* The partition was not found.  ERRNUM was set by next_partition.  */
  return 1;
}

static struct builtin builtin_eptedit =
{
  "eptedit",
  eptedit_func,
  BUILTIN_CMDLINE | BUILTIN_MENU | BUILTIN_HELP_LIST,
  "eptedit PART SLOT TYPE BCYL BHEAD BSEC ECYL EHEAD ESEC RSEC TSEC",
  "Change data in SLOT (""c"" [current] or ""n"" [next]) in extended partition table"
  "of logical partition PART to type TYPE, begin cylinder BCYL, begin head" 
  "BHEAD, begin sector BSEC, end cylinder ECYL, end head EHEAD, end"
  "sector ESEC, relative sectors RSEC, and total sectors TSEC"
};

NOTE: Need to add following pointer to (builtin_table) in builtins.c:
  &builtin_eptedit,

NOTE: In ChangeLog add:
.
.
.

2006-11-##  ?name?  <nnnnn@nnn.nnn>

	Added new command "eptedit" based on code
             derived from functions “partnew” and "parttype",
             based on the patch by ?name? <nnnnn@nnn.nnn>:
	* stage2/builtins.c
             (eptedit_func): New function.
	(builtin_eptedit): New variable.
	(builtin_table): Added pointer to BUILTIN_EPTEDIT.
.
.
.

NOTE: In grub.texi add:
.
.
.

@menu
* bootp::                       Initialize a network device via BOOTP
.
.
.
* eptedit::                     Change data in an extended partition table
.
.
.

@node eptedit
@subsection eptedit

@deffn Command eptedit part slot type bcyl bhead bsec ecyl ehead esec rsec tsec
Change data in an extended partition table. @var{part} is a partition
specification in GRUB syntax (@pxref{Naming convention}); @var{slot}
is the position in the extended partition table and must be "c" [current]
or "n" [next]; @var{type} is the partition type and must be a number in the
range @code{0-0xff}; @var{bcyl} is the beginning cylinder; @var{bhead}
is the beginning head; @var{bsec} is the beginning sector; @var{ecyl}
is the ending cylinder; @var{ehead} is the ending head; @var{esec}
is the ending sector; @var{rsec} is the relative sectors and @var{tsec}
is the total sectors, both in sector units.
@end deffn
.
.
.

NOTE: In grub.info add:
.
.
.
13.2 The list of general commands
=================================

Commands usable anywhere in the menu and in the command-line.

* Menu:

* bootp::                       Initialize a network device via BOOTP
.
.
.
* eptedit::                     Change data in an extended partition table
.
.
.

File: grub.info,  Node: eptedit,  Next: hide,  Prev: dhcp,  Up: General commands

13.2.5 eptedit
--------------

 -- Command: eptedit part slot type bcyl bhead bsec ecyl ehead esec rsec tsec
     Change data in an extended partition table.  PART is a partition
     specification in GRUB syntax (*note Naming convention::); SLOT is
     the position in the extended partition table ("c" [current] or "n" [next]);
     TYPE is the partition type and must be a number in the range `0-0xff';
     BCYL is the beginning cylinder; BHEAD is the beginning head; BSEC
     is the beginning sector; ECYL is the ending cylinder; EHEAD is the
     ending head; ESEC is the ending sector; RSEC is the relative sectors
     and TSEC is the total sectors, both in sector units.  This is useful when
     using extended partitions of different ranges to accommodate a mix of
     “LBA aware” and ”LBA ignorant” operating systems, and to avoid the
     “DOS/Win9x last logical partition bug” if you want to have a non-FAT
     last logical partition.
.
.
.

File: grub.info,  Node: Index,  Prev: Internals,  Up: Top

Index
*****

 [index ]
* Menu:

* blocklist:                             blocklist.            (line  7)
.
.
.
* eptedit:                               eptedit.              (line  7)
.
.
.

Tag Table:
.
.
.
Node: eptedit##### - ?
.
.
.