使用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;
}