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 + -
显示快捷键?