当前位置: 首页 > 工具软件 > libparted > 使用案例 >

使用libparted开发包代码实现分区:

秦才英
2023-12-01

使用libparted开发包代码实现分区:
官方文档:https://www.gnu.org/software/parted/api/modules.html
使用parted的方案在此不多讲,开始之前请安装好libparted开发包。没注释,没整理,全网第一篇使用libparted库实现分区的代码,且用且珍惜,自己搞了快两个星期的样子。大部分内容参考源码:https://github.com/bcl/parted
好多细节也没有深入,太累了!
代码如下:

#include <parted/parted.h>
#include <parted/unit.h>
// #include </parted/exception.h>
#include <parted/geom.h>
#include <stdio.h>
#include <ctype.h>

#ifndef PED_DEBUG_H_INCLUDED
#define PED_DEBUG_H_INCLUDED
#include <stdarg.h>

#ifdef DEBUG

typedef void (PedDebugHandler) ( const int level, const char* file, int line,
                                 const char* function, const char* msg );

extern void ped_debug_set_handler (PedDebugHandler* handler);
extern void ped_debug ( const int level, const char* file, int line,
                        const char* function, const char* msg, ... );

extern void __attribute__((__noreturn__))
ped_assert ( const char* cond_text,
                         const char* file, int line, const char* function );

#if defined __GNUC__ && !defined __JSFTRACE__

#define PED_DEBUG(level, ...) \
        ped_debug ( level, __FILE__, __LINE__, __PRETTY_FUNCTION__, \
                    __VA_ARGS__ )

#define PED_ASSERT(cond)					\
	do {							\
		if (!(cond)) {					\
			ped_assert (				\
			  #cond,				\
			  __FILE__,				\
			  __LINE__,				\
			  __PRETTY_FUNCTION__ );		\
		}						\
	} while (0)

#else /* !__GNUC__ */

/* function because variadic macros are C99 */
static void PED_DEBUG (int level, ...)
{
        va_list         va_args;

        va_start (va_args, level);
        ped_debug ( level, "unknown file", 0, "unknown function", va_args );
        va_end (va_args);
}

#define PED_ASSERT(cond)					\
	do {							\
		if (!(cond)) {					\
			ped_assert (				\
			  #cond,				\
			  "unknown",				\
			  0,					\
			  "unknown");				\
		}						\
	} while (0)

#endif /* __GNUC__ */

#else /* !DEBUG */

#define PED_ASSERT(cond)		do {} while (0)
#define PED_DEBUG(level, ...)           do {} while (0)


#endif /* DEBUG */

#endif /* PED_DEBUG_H_INCLUDED */



enum
{
        ALIGNMENT_NONE = 2,
        ALIGNMENT_CYLINDER,
        ALIGNMENT_MINIMAL,
        ALIGNMENT_OPTIMAL
};

enum AlignmentType
  {
    PA_MINIMUM = 1,
    PA_OPTIMUM
  };

// command_line_get_sector (const char* prompt, PedDevice* dev, PedSector* value,PedGeometry** range, char** raw_input)

int
command_line_get_sector (char* input, PedDevice* dev, PedSector* value,PedGeometry** range, char** raw_input)
{
        char*    def_str;
        int      valid;
        // char*    input = NULL;
        // *input = local;
        def_str = ped_unit_format (dev, *value);
        printf("input: %s\n",input);
        // input = command_line_get_word(local, *value ? def_str : NULL,NULL, 1);
        if (input && *value && !strcmp (input, def_str)) {
            // printf("true");
                if (range) {
                        *range = ped_geometry_new(dev, *value, 1);
                        free (def_str);
                        free (input);
                        return *range != NULL;
                }
                free (def_str);
                free (input);
                return 1;
        }

        free (def_str);
        if (!input) {
                *value = 0;
                if (range)
                        *range = NULL;
                return 0;
        }

        valid = ped_unit_parse(input, dev, value, range);

        if (raw_input)
            *raw_input = input;
        // else
        //    free(input);
        return valid;
}


static PedConstraint*
constraint_from_start_end (PedDevice* dev, PedGeometry* range_start,PedGeometry* range_end)
{
        return ped_constraint_new (ped_alignment_any, ped_alignment_any,
                range_start, range_end, 1, dev->length);
}

void _strip_trailing_spaces(char *str)
{
        if (!str)
                return;
        size_t i = strlen(str);
        while (i && isblank(str[--i]))
                str[i]='\0';
}


static bool
_string_ends_with_iec_unit(const char *str)
{
        /* 3 characters for the IEC unit and at least 1 digit */
        if (!str || strlen(str) < 4)
                return false;

        char const *p = str + strlen(str) - 3;
        return strchr ("kMGTPEZY", *p) && strcasecmp (p+1, "iB") == 0;
}



static bool
_string_has_unit_suffix(const char *str)
{
        /* At least 1 digit and 1 character to meet the condition */
        if (!str || strlen(str) < 2)
                return false;

        if (!isdigit(str[strlen(str) - 1]))
                return true;

        return false;
}



static void
_adjust_end_if_iec (PedSector* start, PedSector* end,
                    PedGeometry* range_end, char* end_input)
{
        PED_ASSERT(start);
        PED_ASSERT(end);
        PED_ASSERT(range_end);

        /* 1s partition - do not move the end */
        if (*start == *end)
                return;

        _strip_trailing_spaces(end_input);
        PedUnit unit = ped_unit_get_default();
        if (_string_ends_with_iec_unit(end_input) ||
            (!_string_has_unit_suffix(end_input) &&
             ((unit == PED_UNIT_KIBIBYTE) || (unit == PED_UNIT_MEBIBYTE) ||
              (unit == PED_UNIT_GIBIBYTE) || (unit == PED_UNIT_TEBIBYTE)))) {
                *end -= 1;
                range_end->start -= 1;
                range_end->end -= 1;
        }
}

typedef enum {
        MOVE_NO         = 0,
        MOVE_STILL      = 1,
        MOVE_UP         = 2,
        MOVE_DOWN       = 4
} EMoves;



enum { /* Don't change these values */
        SECT_START      =  0,
        SECT_END        = -1
};


static EMoves
prefer_snap (PedSector s, int what, PedGeometry* range, EMoves* allow,
             PedPartition* part, PedSector* dist)
{
        PedSector up_dist = -1, down_dist = -1;
        PedSector new_sect;
        EMoves move;

        PED_ASSERT (what == SECT_START || what == SECT_END);

        if (!(*allow & (MOVE_UP | MOVE_DOWN))) {
                *dist = 0;
                return MOVE_STILL;
        }

        if (*allow & MOVE_UP) {
                new_sect = part->geom.end + 1 + what;
                if (ped_geometry_test_sector_inside (range, new_sect))
                        up_dist = new_sect - s;
                else
                        *allow &= ~MOVE_UP;
        }

        if (*allow & MOVE_DOWN) {
                new_sect = part->geom.start + what;
                if (ped_geometry_test_sector_inside (range, new_sect))
                        down_dist = s - new_sect;
                else
                        *allow &= ~MOVE_DOWN;
        }

        move = MOVE_STILL;
        if ((*allow & MOVE_UP) && (*allow & MOVE_DOWN)) {
                if (down_dist < up_dist || (down_dist == up_dist
                                            && what == SECT_START) )
                        move = MOVE_DOWN;
                else if (up_dist < down_dist || (down_dist == up_dist
                                                 && what == SECT_END) )
                        move = MOVE_UP;
                else
                        PED_ASSERT (0);
        } else if (*allow & MOVE_UP)
                move = MOVE_UP;
        else if (*allow & MOVE_DOWN)
                move = MOVE_DOWN;

        *dist = ( move == MOVE_DOWN ? down_dist :
                ( move == MOVE_UP   ? up_dist   :
                  0 ) );
        return move;
}

static int
snap (PedSector* sector, PedSector new_sector, PedGeometry* range)
{
        PED_ASSERT (ped_geometry_test_sector_inside (range, *sector));
        if (!ped_geometry_test_sector_inside (range, new_sector))
                return 0;
        *sector = new_sector;
        return 1;
}

static void
snap_to_boundaries (PedGeometry* new_geom, PedGeometry* old_geom,
                    PedDisk* disk,
                    PedGeometry* start_range, PedGeometry* end_range)
{
        PedPartition*   start_part;
        PedPartition*   end_part;
        PedSector       start = new_geom->start;
        PedSector       end = new_geom->end;
        PedSector       start_dist = -1, end_dist = -1;
        EMoves          start_allow, end_allow, start_want, end_want;
        int             adjacent;

        start_allow = end_allow = MOVE_STILL | MOVE_UP | MOVE_DOWN;

        start_part = ped_disk_get_partition_by_sector (disk, start);
        end_part = ped_disk_get_partition_by_sector (disk, end);
        adjacent = (start_part->geom.end + 1 == end_part->geom.start);

        /* If we can snap to old_geom, then we will... */
        /* and this will enforce the snapped positions  */
        if (old_geom) {
                if (snap (&start, old_geom->start, start_range))
                        start_allow = MOVE_STILL;
                if (snap (&end, old_geom->end, end_range))
                        end_allow = MOVE_STILL;
        }

        /* If start and end are on the same partition, we */
        /* don't allow them to cross. */
        if (start_part == end_part) {
                start_allow &= ~MOVE_UP;
                end_allow &= ~MOVE_DOWN;
        }

        /* Let's find our way */
        start_want = prefer_snap (start, SECT_START, start_range, &start_allow,
                                  start_part, &start_dist );
        end_want = prefer_snap (end, SECT_END, end_range, &end_allow,
                                end_part, &end_dist );

        PED_ASSERT (start_dist >= 0 && end_dist >= 0);

        /* If start and end are on adjacent partitions,    */
        /* and if they would prefer crossing, then refrain */
        /* the farthest to do so. */
        if (adjacent && start_want == MOVE_UP && end_want == MOVE_DOWN) {
                if (end_dist < start_dist) {
                        start_allow &= ~MOVE_UP;
                        start_want = prefer_snap (start, SECT_START,
                                                  start_range, &start_allow,
                                                  start_part, &start_dist );
                        PED_ASSERT (start_dist >= 0);
                } else {
                        end_allow &= ~MOVE_DOWN;
                        end_want = prefer_snap (end, SECT_END,
                                                end_range, &end_allow,
                                                end_part, &end_dist );
                        PED_ASSERT (end_dist >= 0);
                }
        }

        /* New positions */
        start = ( start_want == MOVE_DOWN ? start_part->geom.start :
                ( start_want == MOVE_UP ? start_part->geom.end + 1 :
                  start ) );
        end = ( end_want == MOVE_DOWN ? end_part->geom.start - 1 :
              ( end_want == MOVE_UP ? end_part->geom.end :
                end ) );
        PED_ASSERT (ped_geometry_test_sector_inside(start_range,start));
        PED_ASSERT (ped_geometry_test_sector_inside (end_range, end));
        PED_ASSERT (start <= end);
        ped_geometry_set (new_geom, start, end - start + 1);
}

static bool
partition_align_check (PedDisk const *disk, PedPartition const *part,
		       enum AlignmentType a_type, char **align_err)
{
  PED_ASSERT (part->disk == disk);
  PedDevice const *dev = disk->dev;

  PedAlignment *pa = (a_type == PA_MINIMUM
		      ? ped_device_get_minimum_alignment (dev)
		      : ped_device_get_optimum_alignment (dev));
  if (pa == NULL)
      return true;

  PED_ASSERT (pa->grain_size != 0);
  bool ok = (part->geom.start % pa->grain_size == pa->offset);

  /* If it isn't aligned and the caller wants an explanation,
     show them the math.  */
  if (!ok && align_err) {
      if (asprintf(align_err,
                   "%llds %% %llds != %llds",
                   part->geom.start, pa->grain_size, pa->offset) < 0) {
          *align_err = NULL;
      }
  }
  free (pa);
  return ok;
}

static int
do_mkpart ()
{
        PedDisk*                 disk;
        PedPartition*            part;
        PedPartitionType         part_type;
        // const PedFileSystemType* fs_type = ped_file_system_type_get ("ext2");
        PedSector                start = 0, end = 0;
		char *startLocal = "0"; 
		char *endLocal = "2048";
        PedGeometry              *range_start = NULL, *range_end = NULL;
        PedConstraint*           user_constraint;
        PedConstraint*           dev_constraint;
        PedConstraint*           final_constraint;
        char*                    peek_word;
        char*                    part_name = NULL;
        char                     *start_usr = NULL, *end_usr = NULL;
        char                     *start_sol = NULL, *end_sol = NULL;
		int alignment = ALIGNMENT_CYLINDER;
		int opt_script_mode = 0;
		int disk_is_modified = 0;
		
		const char *path = "/dev/sdb";
		PedDevice *dev = ped_device_get(path);	// 读取设备
        // PedDevice **dev = devOne;
		// *dev = devOne;
		printf("磁盘号:%d\n",*dev);
		// PedDisk** diskp = ped_disk_new(devOne);
		disk = ped_disk_new(dev);	//读取分区表
        // *diskp = disk;
		ped_disk_print(disk);
        if (!disk)
            goto error;

        if (ped_disk_is_flag_available(disk, PED_DISK_CYLINDER_ALIGNMENT))
            if (!ped_disk_set_flag(disk, PED_DISK_CYLINDER_ALIGNMENT,alignment == ALIGNMENT_CYLINDER))
                goto error;

        if (!ped_disk_type_check_feature (disk->type, PED_DISK_TYPE_EXTENDED)) {
                part_type = PED_PARTITION_NORMAL;
        } else {
			part_type = PED_PARTITION_NORMAL;
            // if (!command_line_get_part_type (_("Partition type?"),disk, &part_type))
            //            goto error;
        }

        /* The undocumented feature that mkpart sometimes takes a
           partition name is next to useless, at least with a dvh
           partition table, since it makes the "mkpart" command
           fail unconditionally for a primary partition.  E.g.,
           mkpart primary any-name xfs 4096s 5000s
           requires the name, yet always fails, saying that only
           logical partitions may have names.
           If you want a name, use parted's separate "name" command.  */

        if (ped_disk_type_check_feature (disk->type,PED_DISK_TYPE_PARTITION_NAME) && ! (strcmp (disk->type->name, "dvh") == 0 && part_type != PED_PARTITION_LOGICAL))
                part_name = "one";
		printf("磁盘名:%s\n",part_name);
        // peek_word = command_line_peek_word ();		
		/*peek_word = "ext4";
        if (part_type == PED_PARTITION_EXTENDED || (peek_word && (isdigit (peek_word[0]) || peek_word[0] == '-'))) {
                fs_type = NULL;
                free (peek_word);
        } else {
                free (peek_word);
                if (!command_line_get_fs_type (_("File system type?"), &fs_type))
                        goto error;
        }*/
		const PedFileSystemType* fs_type = ped_file_system_type_get("ext4");
		printf("文件系统:    %s\n",fs_type->name);
        if (!command_line_get_sector (startLocal, dev, &start, &range_start, NULL)){
                printf("debug\n");
                goto error;
        }
        printf("debug    %s\n",fs_type->name);
        char *end_input;
        if (!command_line_get_sector (endLocal, dev, &end, &range_end, &end_input))
                goto error;
		// printf("设备路径: %s\n",dev->path);
        _adjust_end_if_iec(&start, &end, range_end, end_input);
        
		// free(end_input);
        
		// printf("磁盘号:%d\n",dev);
        /* processing starts here */
        part = ped_partition_new (disk, part_type, fs_type, start, end);
        if (!part)
                goto error;
        
        snap_to_boundaries (&part->geom, NULL, disk, range_start, range_end);
        
        /* create constraints */
        user_constraint = constraint_from_start_end(dev, range_start, range_end);
        PED_ASSERT (user_constraint != NULL);

        if (alignment == ALIGNMENT_OPTIMAL)
                dev_constraint =
                        ped_device_get_optimal_aligned_constraint(dev);
        else if (alignment == ALIGNMENT_MINIMAL)
                dev_constraint =
                        ped_device_get_minimal_aligned_constraint(dev);
        else
                dev_constraint = ped_device_get_constraint(dev);
        PED_ASSERT (dev_constraint != NULL);

        final_constraint = ped_constraint_intersect (user_constraint,
                        dev_constraint);
        ped_constraint_destroy (user_constraint);
        ped_constraint_destroy (dev_constraint);
        if (!final_constraint)
                goto error_destroy_simple_constraints;
        
        /* subject to partition constraint */
        ped_exception_fetch_all(); 
        bool added_ok = ped_disk_add_partition (disk, part, final_constraint);
        ped_constraint_destroy (final_constraint);
        if (!added_ok) {
                ped_exception_leave_all();

                PedConstraint *constraint_any = ped_constraint_any (dev);
                added_ok = ped_disk_add_partition (disk, part,
                                                        constraint_any);
                ped_constraint_destroy (constraint_any);

                if (!added_ok)
                        goto error_destroy_simple_constraints;

                if (!ped_geometry_test_sector_inside(range_start, part->geom.start) ||
                    !ped_geometry_test_sector_inside(range_end, part->geom.end)) {
                        start_usr = ped_unit_format (dev, start);
                        end_usr   = ped_unit_format (dev, end);
                        start_sol = ped_unit_format (dev, part->geom.start);
                        end_sol   = ped_unit_format (dev, part->geom.end);

                        /* In script mode failure to use specified values is fatal.
                         * However, in interactive mode, it merely elicits a warning
                         * and a prompt for whether to proceed.
                         */
                        switch (ped_exception_throw (
                                (opt_script_mode
                                 ? PED_EXCEPTION_ERROR
                                 : PED_EXCEPTION_WARNING),
                                (opt_script_mode
                                 ? PED_EXCEPTION_CANCEL
                                 : PED_EXCEPTION_YES_NO),
                                ("You requested a partition from %s to %s (sectors %llu..%llu).\n The closest location we can manage is %s to %s (sectors %llu..%llu).%s"),
                                start_usr, end_usr,
                                start, end,
                                start_sol, end_sol,
                                part->geom.start, part->geom.end,(opt_script_mode ? "" : ("\nIs this still acceptable to you?"))))
                        {
                                case PED_EXCEPTION_YES:
                                        /* all is well in this state */
                                        break;
                                case PED_EXCEPTION_NO:
                                case PED_EXCEPTION_UNHANDLED:
                                default:
                                        /* undo partition addition */
                                        goto error_remove_part;
                        }
                }

                char *align_err = NULL;
                if ((alignment == ALIGNMENT_OPTIMAL &&
                     !partition_align_check(disk, part, PA_OPTIMUM, &align_err)) ||
                    (alignment == ALIGNMENT_MINIMAL &&
                     !partition_align_check(disk, part, PA_MINIMUM, &align_err))) {
                        if (ped_exception_throw(
                                PED_EXCEPTION_WARNING,
                                (opt_script_mode
                                 ? PED_EXCEPTION_OK
                                 : PED_EXCEPTION_IGNORE_CANCEL),
                                ("The resulting partition is not properly aligned for best performance: %s"),
                                align_err ? align_err : ("unknown (malloc failed)")) ==
                            PED_EXCEPTION_CANCEL) {
                                free(align_err);
                                /* undo partition addition */
                                goto error_remove_part;
                        }
                        free(align_err);
                }
        } else {
                ped_exception_leave_all();
        }
        ped_exception_catch();
        
        /* set minor attributes */
        if (part_name)
            if (!ped_partition_set_name (part, part_name))
                goto error_remove_part;
        //  free (part_name);  /* avoid double-free upon failure */
        part_name = NULL;

        if (!ped_partition_set_system (part, fs_type))
                goto error_remove_part;
        if (ped_partition_is_flag_available (part, PED_PARTITION_LBA))
                ped_partition_set_flag (part, PED_PARTITION_LBA, 1);

        if (!ped_disk_commit (disk))
                goto error_remove_part;

        /* clean up */
        if (range_start != NULL)
                ped_geometry_destroy (range_start);
        if (range_end != NULL)
                ped_geometry_destroy (range_end);
        printf("设备路径: %s\n",dev->path);
        free (start_usr);
        free (end_usr);
        free (start_sol);
        free (end_sol);
		
        if ((dev)->type != PED_DEVICE_FILE)
                disk_is_modified = 1;

        return 1;

error_remove_part:
        ped_disk_remove_partition (disk, part);
error_destroy_simple_constraints:
        ped_partition_destroy (part);
error:
        free (part_name);
        if (range_start != NULL)
                ped_geometry_destroy (range_start);
        if (range_end != NULL)
                ped_geometry_destroy (range_end);

        free (start_usr);
        free (end_usr);
        free (start_sol);
        free (end_sol);

        return 0;
}
int main(int argc, char* argv[])
{
	do_mkpart();
	return 0;
}
 类似资料: