📄 sfdisk.c
字号:
/* * sfdisk version 3.0 - aeb - 950813 * * Copyright (C) 1995 Andries E. Brouwer (aeb@cwi.nl) * * 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 1 * or (at your option) any later version. * * A.V. Le Blanc (LeBlanc@mcc.ac.uk) wrote Linux fdisk 1992-1994, * patched by various people (faith@cs.unc.edu, martin@cs.unc.edu, * leisner@sdsp.mc.xerox.com, esr@snark.thyrsus.com, aeb@cwi.nl) * 1993-1995, with version numbers (as far as I have seen) 0.93 - 2.0e. * This program had (head,sector,cylinder) as basic unit, and was * (therefore) broken in several ways for the use on larger disks - * for example, my last patch (from 2.0d to 2.0e) was required * to allow a partition to cross cylinder 8064, and to write an * extended partition past the 4GB mark. * * The current program is a rewrite from scratch, and I started a * version numbering at 3.0. * Andries Brouwer, aeb@cwi.nl, 950813 * * Well, a good user interface is still lacking. On the other hand, * many configurations cannot be handled by any other fdisk. * I changed the name to sfdisk to prevent confusion. - aeb, 970501 * * Changes: * 19990319 - Arnaldo Carvalho de Melo <acme@conectiva.com.br> - i18n * 20040428 - Jeroen Dobbelaere <jeroen.dobbelaere@acunia.com> - added PACKED * 20040824 - David A. Wheeler <dwheeler@dwheeler.com> - warnings to stderr */#define PROGNAME "sfdisk"#define VERSION "3.08"#define DATE "040824"#include <stdio.h>#include <stdlib.h> /* atoi, free */#include <stdarg.h> /* varargs */#include <unistd.h> /* read, write */#include <fcntl.h> /* O_RDWR */#include <errno.h> /* ERANGE */#include <string.h> /* index() */#include <ctype.h>#include <getopt.h>#include <sys/ioctl.h>#include <sys/stat.h>#include <sys/utsname.h>#include <linux/unistd.h> /* _syscall */#include "nls.h"#include "common.h"#define SIZE(a) (sizeof(a)/sizeof(a[0]))/* * Table of contents: * A. About seeking * B. About sectors * C. About heads, sectors and cylinders * D. About system Ids * E. About partitions * F. The standard input * G. The command line * H. Listing the current situation * I. Writing the new situation */int exit_status = 0;int force = 0; /* 1: do what I say, even if it is stupid ... */int quiet = 0; /* 1: suppress all warnings *//* IA-64 gcc spec file currently does -DLinux... */#undef Linuxint Linux = 0; /* 1: suppress warnings irrelevant for Linux */int DOS = 0; /* 1: shift extended partitions by #sectors, not 1 */int DOS_extended = 0; /* 1: use starting cylinder boundary of extd partn */int dump = 0; /* 1: list in a format suitable for later input */int verify = 0; /* 1: check that listed partition is reasonable */int no_write = 0; /* 1: do not actually write to disk */int no_reread = 0; /* 1: skip the BLKRRPART ioctl test at startup */int leave_last = 0; /* 1: don't allocate the last cylinder */int opt_list = 0;char *save_sector_file = NULL;char *restore_sector_file = NULL;static voiddo_warn(char *s, ...) { va_list p; va_start(p, s); fflush(stdout); vfprintf(stderr, s, p); fflush(stderr); va_end(p);}static voidwarn(char *s, ...) { va_list p; va_start(p, s); if (!quiet) { fflush(stdout); vfprintf(stderr, s, p); fflush(stderr); } va_end(p);}static voiderror(char *s, ...) { va_list p; va_start(p, s); fflush(stdout); fprintf(stderr, "\n" PROGNAME ": "); vfprintf(stderr, s, p); fflush(stderr); va_end(p);}static voidfatal(char *s, ...) { va_list p; va_start(p, s); fflush(stdout); fprintf(stderr, "\n" PROGNAME ": "); vfprintf(stderr, s, p); fflush(stderr); va_end(p); exit(1);}/* * GCC nonsense - needed for GCC 3.4.x with -O2 * * Maybe just test with #if (__GNUC__ >= 3) && (__GNUC_MINOR__ >= 4) ? */#ifndef __GNUC_PREREQ#define __GNUC_PREREQ(x,y) 0#endif#if __GNUC_PREREQ(3,4)#define __attribute__used __attribute__ ((used))#else#define __attribute__used#endif/* * arm needs PACKED - use it everywhere? */#if defined(__GNUC__) && defined(__arm__)# define PACKED __attribute__ ((packed))#else# define PACKED#endif/* * A. About seeking *//* * sseek: seek to specified sector - return 0 on failure * * For >4GB disks lseek needs a > 32bit arg, and we have to use llseek. * On the other hand, a 32 bit sector number is OK until 2TB. * The routines _llseek and sseek below are the only ones that * know about the loff_t type. * * Note: we use 512-byte sectors here, irrespective of the hardware ss. */#undef use_lseek#if defined (__alpha__) || defined (__ia64__) || defined (__x86_64__) || defined (__s390x__)#define use_lseek#endif#ifndef use_lseekstatic __attribute__used_syscall5(int, _llseek, unsigned int, fd, ulong, hi, ulong, lo, loff_t *, res, unsigned int, wh);#endifstatic intsseek(char *dev, unsigned int fd, unsigned long s) { loff_t in, out; in = ((loff_t) s << 9); out = 1;#ifndef use_lseek if (_llseek (fd, in>>32, in & 0xffffffff, &out, SEEK_SET) != 0) {#else if ((out = lseek(fd, in, SEEK_SET)) != in) {#endif perror("llseek"); error(_("seek error on %s - cannot seek to %lu\n"), dev, s); return 0; } if (in != out) { error(_("seek error: wanted 0x%08x%08x, got 0x%08x%08x\n"), (unsigned int)(in>>32), (unsigned int)(in & 0xffffffff), (unsigned int)(out>>32), (unsigned int)(out & 0xffffffff)); return 0; } return 1;}/* * B. About sectors *//* * We preserve all sectors read in a chain - some of these will * have to be modified and written back. */struct sector { struct sector *next; unsigned long sectornumber; int to_be_written; char data[512];} *sectorhead;static voidfree_sectors(void) { struct sector *s; while (sectorhead) { s = sectorhead; sectorhead = s->next; free(s); }}static struct sector *get_sector(char *dev, int fd, unsigned long sno) { struct sector *s; for(s = sectorhead; s; s = s->next) if (s->sectornumber == sno) return s; if (!sseek(dev, fd, sno)) return 0; if (!(s = (struct sector *) malloc(sizeof(struct sector)))) fatal(_("out of memory - giving up\n")); if (read(fd, s->data, sizeof(s->data)) != sizeof(s->data)) { if (errno) /* 0 in case we read past end-of-disk */ perror("read"); error(_("read error on %s - cannot read sector %lu\n"), dev, sno); free(s); return 0; } s->next = sectorhead; sectorhead = s; s->sectornumber = sno; s->to_be_written = 0; return s;}static intmsdos_signature (struct sector *s) { unsigned char *data = s->data; if (data[510] == 0x55 && data[511] == 0xaa) return 1; error(_("ERROR: sector %lu does not have an msdos signature\n"), s->sectornumber); return 0;}static intwrite_sectors(char *dev, int fd) { struct sector *s; for (s = sectorhead; s; s = s->next) if (s->to_be_written) { if (!sseek(dev, fd, s->sectornumber)) return 0; if (write(fd, s->data, sizeof(s->data)) != sizeof(s->data)) { perror("write"); error(_("write error on %s - cannot write sector %lu\n"), dev, s->sectornumber); return 0; } s->to_be_written = 0; } return 1;}static voidulong_to_chars(unsigned long u, char *uu) { int i; for(i=0; i<4; i++) { uu[i] = (u & 0xff); u >>= 8; }}static unsigned longchars_to_ulong(unsigned char *uu) { int i; unsigned long u = 0; for(i=3; i>=0; i--) u = (u << 8) | uu[i]; return u;}static intsave_sectors(char *dev, int fdin) { struct sector *s; char ss[516]; int fdout; fdout = open(save_sector_file, O_WRONLY | O_CREAT, 0444); if (fdout < 0) { perror(save_sector_file); error(_("cannot open partition sector save file (%s)\n"), save_sector_file); return 0; } for (s = sectorhead; s; s = s->next) if (s->to_be_written) { ulong_to_chars(s->sectornumber, ss); if (!sseek(dev, fdin, s->sectornumber)) return 0; if (read(fdin, ss+4, 512) != 512) { perror("read"); error(_("read error on %s - cannot read sector %lu\n"), dev, s->sectornumber); return 0; } if (write(fdout, ss, sizeof(ss)) != sizeof(ss)) { perror("write"); error(_("write error on %s\n"), save_sector_file); return 0; } } return 1;}static void reread_disk_partition(char *dev, int fd);static intrestore_sectors(char *dev) { int fdin, fdout, ct; struct stat statbuf; char *ss0, *ss; unsigned long sno; if (stat(restore_sector_file, &statbuf) < 0) { perror(restore_sector_file); error(_("cannot stat partition restore file (%s)\n"), restore_sector_file); return 0; } if (statbuf.st_size % 516) { error(_("partition restore file has wrong size - not restoring\n")); return 0; } if (!(ss = (char *) malloc(statbuf.st_size))) { error(_("out of memory?\n")); return 0; } fdin = open(restore_sector_file, O_RDONLY); if (fdin < 0) { perror(restore_sector_file); error(_("cannot open partition restore file (%s)\n"), restore_sector_file); return 0; } if (read(fdin, ss, statbuf.st_size) != statbuf.st_size) { perror("read"); error(_("error reading %s\n"), restore_sector_file); return 0; } fdout = open(dev, O_WRONLY); if (fdout < 0) { perror(dev); error(_("cannot open device %s for writing\n"), dev); return 0; } ss0 = ss; ct = statbuf.st_size/516; while(ct--) { sno = chars_to_ulong(ss); if (!sseek(dev, fdout, sno)) return 0; if (write(fdout, ss+4, 512) != 512) { perror(dev); error(_("error writing sector %lu on %s\n"), sno, dev); return 0; } ss += 516; } free(ss0); reread_disk_partition(dev, fdout); return 1;}/* * C. About heads, sectors and cylinders *//* * <linux/hdreg.h> defines HDIO_GETGEO and * struct hd_geometry { * unsigned char heads; * unsigned char sectors; * unsigned short cylinders; * unsigned long start; * }; * * For large disks g.cylinders is truncated, so we use BLKGETSIZE. *//* * We consider several geometries for a disk: * B - the BIOS geometry, gotten from the kernel via HDIO_GETGEO * F - the fdisk geometry * U - the user-specified geometry * * 0 means unspecified / unknown */struct geometry { unsigned long long total_size; /* in sectors */ unsigned long cylindersize; /* in sectors */ unsigned long heads, sectors, cylinders; unsigned long start;} B, F, U;static struct geometryget_geometry(char *dev, int fd, int silent) { struct hd_geometry g; unsigned long cyls; unsigned long long sectors; struct geometry R; if (ioctl(fd, HDIO_GETGEO, &g)) { g.heads = g.sectors = g.cylinders = g.start = 0; if (!silent) do_warn(_("Disk %s: cannot get geometry\n"), dev); } R.start = g.start; R.heads = g.heads; R.sectors = g.sectors; R.cylindersize = R.heads * R.sectors; R.cylinders = 0; R.total_size = 0; if (disksize(fd, §ors)) { /* maybe an ordinary file */ struct stat s; if (fstat(fd, &s) == 0 && S_ISREG(s.st_mode)) R.total_size = (s.st_size >> 9); else if (!silent) do_warn(_("Disk %s: cannot get size\n"), dev); } else R.total_size = sectors; if (R.cylindersize && R.total_size) { sectors /= R.cylindersize; cyls = sectors; if (cyls != sectors) cyls = ~0; R.cylinders = cyls;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -