fdisk.c
来自「fdisk 实现源码,可以查询Linux下系统的分区信息」· C语言 代码 · 共 2,469 行 · 第 1/5 页
C
2,469 行
/* GNU fdisk - a clone of Linux fdisk. Copyright (C) 2006 Free Software Foundation, Inc. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA*/#include "../config.h"#include "common.h"#include "hacks.h"#include "command.h"#include "ui.h"#define N_(String) String#if ENABLE_NLS# include <libintl.h># include <locale.h># define _(String) dgettext (PACKAGE, String)#else# define _(String) (String)#endif /* ENABLE_NLS */#include <parted/parted.h>#include <parted/debug.h>#include <ctype.h>#include <stdarg.h>#include <stdlib.h>#include <string.h>#include <unistd.h>#include <fcntl.h>#include <limits.h>#ifdef ENABLE_MTRACE#include <mcheck.h>#endif#ifdef HAVE_GETOPT_H#include <getopt.h>/* minimum amount of free space to leave, or maximum amount to gobble up, * depending on your POV ;) */#define MIN_FREESPACE (1000 * 2) /* 1000k */#define MEGABYTE_SECTORS (PED_MEGABYTE_SIZE / PED_SECTOR_SIZE_DEFAULT)typedef struct { time_t last_update; time_t predicted_time_left;} TimerContext;/* NOTE: options and options_help MUST be in the same order and count */static struct option options[] = { /* name, has-arg, string-return-val, char-return-val */ {"help", 0, NULL, 'h'}, {"list", 0, NULL, 'l'}, {"raw-print", 0, NULL, 'r'}, {"size", 1, NULL, 's'},#ifdef GNU_EXT {"linux-fdisk", 0, NULL, 'L'}, {"gnu-fdisk", 0, NULL, 'G'},#endif {"interactive", 0, NULL, 'i'}, {"script", 0, NULL, 'p'}, {"sector-units",0, NULL, 'u'}, {"sector-size", 1, NULL, 'b'}, {"cylinders", 1, NULL, 'C'}, {"heads", 1, NULL, 'H'}, {"sectors", 1, NULL, 'S'}, {"list-partition-types", 0, NULL, 't'}, {"version", 0, NULL, 'v'}, {NULL, 0, NULL, 0}};#endif/* NOTE: options and options_help MUST be in the same order and count */static char* options_help [][2] = { {"help", N_("displays this help message")}, {"list", N_("list partition table(s)")}, {"raw-print", N_("show the raw data in the partition table(s)")}, {"size", N_("show partition size")},#ifdef GNU_EXT {"linux-fdisk", N_("enable Linux fdisk compatibility mode")}, {"gnu-fdisk", N_("disable Linux fdisk compatibility mode")},#endif {"interactive", N_("where necessary, prompts for user intervention")}, {"script", N_("never prompts for user intervention")}, {"sector-units",N_("use sectors instead of cylinder as a default unit")}, {"sector-size", N_("specify the sector size in bytes")}, {"cylinders", N_("specify the number of cylinders, actually does nothing")}, {"heads", N_("in lfdisk, specify the number of heads of the disk")}, {"sectors", N_("in lfdisk, specify the number of sectors per track")}, {"list-partition-types", N_("displays a list of supported partition types")}, {"version", N_("displays the version")}, {NULL, NULL}};#ifdef GNU_EXTint fdisk_compatibility_mode = 0;#else#define fdisk_compatibility_mode 1#endifint fdisk_opt_script_mode;int fdisk_list_table = 0;int fdisk_print_raw = 0;/* Used for -s option, NULL when there was no -s option */const char *fdisk_partsize_device = NULL;int fdisk_partsize_part = 0;int user_cyls = 0, user_sectors = 0, user_heads = 0, user_sectsize = 0;static char* number_msg = N_("NUMBER is the partition number used by Linux. On MS-DOS disk labels, the ""primary partitions number from 1 to 4, logical partitions from 5 onwards.\n");static char* label_type_msg_start = N_("LABEL-TYPE is one of: ");static char* flag_msg_start = N_("FLAG is one of: ");static char* unit_msg_start = N_("UNIT is one of: ");static char* part_type_msg = N_("PART-TYPE is one of: primary, logical, " "extended\n");static char* fs_type_msg_start = N_("FS-TYPE is one of: ");static char* start_end_msg = N_("START and END are disk locations, such as " "4GB or 10%. Negative values count from the end of the disk. " "For example, -1s specifies exactly the last sector.\n");static char* state_msg = N_("STATE is one of: on, off\n");static char* device_msg = N_("DEVICE is usually /dev/hda or /dev/sda\n");static char* name_msg = N_("NAME is any word you want\n");static char* resize_msg_start = N_("The partition must have one of the " "following FS-TYPEs: ");static char* label_type_msg;static char* flag_msg;static char* unit_msg;static char* mkfs_fs_type_msg;static char* mkpart_fs_type_msg;static char* resize_fs_type_msg;//static PedTimer* timer;static TimerContext timer_context;static FdiskCommand* fdisk_main_menu_commands[256] = {NULL};static FdiskCommand* fdisk_ex_menu_commands[256] = {NULL};static FdiskCommand* fdisk_bsd_menu_commands[256] = {NULL};static int in_menu = 0;/* 0 = Disk was not altered. 1 = Disk was altered. *///static int need_commit = 0;/* UI Calls structure */static UICalls uiquery;/* 0 = Sectors are the default unit. 1 = Cylinders are the default unit (Default).*/static int cylinder_unit = 1;/* When editing a BSD label, we remember the number of logical partitions on the original disk, so we display a more plausible device name */static int logical_offset = 0;static void _done (PedDevice* dev);/* Timer handler and other UI functions */ static void_timer_handler (PedTimer* timer, void* context){ TimerContext* tcontext = (TimerContext*) context; int draw_this_time; if (fdisk_opt_script_mode || !isatty(fileno(stdout))) return; if (tcontext->last_update != timer->now && timer->now > timer->start) { tcontext->predicted_time_left = timer->predicted_end - timer->now; tcontext->last_update = timer->now; draw_this_time = 1; } else { draw_this_time = 0; } if (draw_this_time) { fdisk_wipe_line (); if (timer->state_name) printf ("%s... ", timer->state_name); printf (_("%0.f%%\t(time left %.2d:%.2d)"), 100.0 * timer->frac, tcontext->predicted_time_left / 60, tcontext->predicted_time_left % 60); fflush (stdout); }}static intgetstring (const char* prompt, char** value, const StrList* words, const StrList* locwords, int multi_word){ char* def_str = NULL; char* input; StrList* valid = NULL; const StrList* walk; const StrList* locwalk; char* fix_result = NULL; /* TODO: Add a function that does just this to strlist.c */ valid = str_list_join (str_list_duplicate(words), str_list_duplicate(locwords)); if (*value) def_str = strdup(*value); input = fdisk_command_line_get_word (prompt, def_str, valid, multi_word); str_list_destroy(valid); if (def_str) free(def_str); /* If the user has choosen a localised string, we should return the non-localized one, corresponding to it */ for (walk = words, locwalk = locwords; walk && locwalk; walk = walk->next, locwalk = locwalk->next) { /* If it matches a non-localised string, we are happy */ if (str_list_match_node(walk, input)) { if (fix_result) free(fix_result); fix_result = NULL; break; } /* If it matches a localised string, we save the non-localised one, but we don't break */ if (!fix_result && str_list_match_node(locwalk, input)) { fix_result = str_list_convert_node(walk); } } if (fix_result) { free(input); *value = fix_result; } else *value = input; return 1;}/* We might as well get rid of this one */static intgetbool (const char* prompt, int* value){ *value = command_line_prompt_boolean_question (prompt); return 1;}/* We don't need this onestatic int(*getint) (const char* prompt, int* value) = fdisk_command_line_get_integer; */#if 0static int_partition_warn_busy (PedPartition* part){ char* path = ped_partition_get_path (part); if (ped_partition_is_busy (part)) { ped_exception_throw ( PED_EXCEPTION_ERROR, PED_EXCEPTION_CANCEL, _("Partition %s is being used. You must unmount it " "before you modify it with Parted."), path); ped_free (path); return 0; } ped_free (path); return 1;}static int_disk_warn_busy (PedDisk* disk){ if (ped_device_is_busy (disk->dev)) { if (ped_exception_throw ( PED_EXCEPTION_WARNING, PED_EXCEPTION_IGNORE_CANCEL, _("Partition(s) on %s are being used."), disk->dev->path) != PED_EXCEPTION_IGNORE) return 0; } return 1;}/* This function changes "sector" to "new_sector" if the new value lies * within the required range. */static intsnap (PedSector* sector, PedSector new_sector, PedGeometry* range){ PED_ASSERT (ped_geometry_test_sector_inside (range, *sector), return 0); if (!ped_geometry_test_sector_inside (range, new_sector)) return 0; *sector = new_sector; return 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};/* Find the prefered way to adjust the sector s inside range. * If a move isn't allowed or is out of range it can't be selected. * what contains SECT_START if the sector to adjust is a start sector * or SECT_END if it's an end one. * The prefered move is to the nearest allowed boundary of the part * partition (if at equal distance: to start if SECT_START or to end * if SECT_END). * The distance is returned in dist. */static EMovesprefer_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, return 0); 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, return 0); } *dist = ( move == MOVE_DOWN ? down_dist : ( move == MOVE_UP ? up_dist : 0 ) ); return move;}/* Snaps a partition to nearby partition boundaries. This is useful for * gobbling up small amounts of free space, and also for reinterpreting small * changes to a partition as non-changes (eg: perhaps the user only wanted to * resize the end of a partition). * Note that this isn't the end of the story... this function is * always called before the constraint solver kicks in. So you don't need to * worry too much about inadvertantly creating overlapping partitions, etc. */static voidsnap_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_want = end_want = MOVE_NO; 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 snaped 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, return); /* If start and end are on adjacent partitions, */ /* and if they would prefer crossing, then refrain */ /* the farest 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, return); } 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, return); } } /* 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), return); PED_ASSERT (ped_geometry_test_sector_inside (end_range, end), return); PED_ASSERT (start <= end, return); ped_geometry_set (new_geom, start, end - start + 1);}/* This functions constructs a constraint from the following information: * start, is_start_exact, end, is_end_exact. * * If is_start_exact == 1, then the constraint requires start be as given in * "start". Otherwise, the constraint does not set any requirements on the * start. */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);
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?