/* Program to test resizing a partition using libparted
 *
 * Compile with:
 * gcc -lparted -luuid -ldl -o resize-using-libparted resize-using-libparted.c
 */
#include <stdio.h>
#include <parted/parted.h>

PedExceptionOption ped_exception_handler( PedException * e ) 
{
  printf("%s\n", e ->message);
  exit ( 1 );
  /* return PED_EXCEPTION_UNHANDLED; */
}

int commit_to_os( PedDisk *lp_disk )
{
  int return_val = ped_disk_commit_to_os( lp_disk );

  return return_val;
}

int commit( PedDisk *lp_disk )
{
  int return_val = ped_disk_commit_to_dev( lp_disk ) ;

  return_val = commit_to_os( lp_disk ) && return_val;

  return return_val;
}


int main (int argc, char *argv[])
{

  if ( argc != 5 ) {
    printf( "Usage:  %s device-path part-num start-sector size-in-sectors\n"
          , argv[0]
	  );
    printf( "E.g.: resize-using-libparted /dev/sdb 1 63 48132\n" );
    exit ( 1 );
  }

  /* WARNING - Ensure dev_name set to be a device with no important data */
  char * dev_name = argv[1];
  int part_num = atoi( argv[2] );
  long long sect_start = atoi( argv[3] );
  long long sect_new_size = atoi( argv[4] );

/*
   printf("%s %d %lld %lld\n", dev_name, part_num, sect_start, sect_new_size);
  exit( 1 );
*/

  ped_exception_set_handler( ped_exception_handler );

  PedDevice     *lp_device    = NULL;
  PedDisk       *lp_disk      = NULL;
  PedPartition  *lp_partition = NULL;
  PedConstraint *constraint   = NULL ;


  printf( "Using libparted %s\n", ped_get_version() );

  /* Retrieve device, disk, and partition */
  lp_device = ped_device_get( dev_name );
  if ( lp_device )
    lp_disk = ped_disk_new( lp_device );
  if ( lp_disk )
    lp_partition = ped_disk_get_partition (lp_disk, part_num );

  if ( lp_partition ) {
    PedGeometry *geom = NULL;
    geom = ped_geometry_new( lp_device
			   , sect_start
			   , sect_new_size
			   );
    constraint = ped_constraint_exact( geom ) ;

    if ( constraint ) {
	/* Actually resize the partition */
	if ( ped_disk_set_partition_geom( lp_disk
					, lp_partition
					, constraint
					, geom ->start
					, geom ->end
					)
	   ) {
	  printf( "Partition resizing succeeded.\n" );
	  printf( "  New Start: %lld sectors\n", geom ->start );
	  printf( "  New End  : %lld sectors\n", geom ->end );

	  /* Commit to device and os */
	  /*
	  if ( ! ped_disk_commit_to_dev( lp_disk ) )
	    printf( "ped_disk_commit_to_dev() failed.\n");
	  if ( ! ped_disk_commit_to_os( lp_disk ) )
	    printf( "ped_disk_commit_to_os() failed.\n");
	  */
	  if ( ! commit( lp_disk ) )
	    printf( "pd_disk_commit... failed.\n" );
	}

	//Clean up constraint
	ped_constraint_destroy( constraint );
    }
    else {
      printf( "Failed to find constraint for resizing partition.\n" );
    }
        
    //Close device and disk
    if ( lp_disk )
      ped_disk_destroy( lp_disk );
    if ( lp_device )
      ped_device_destroy( lp_device ) ;
  }
  else {
    printf( "Failed to locate partition and hence resize partition.\n" );
  }

  exit(0);
}
