From 8c3a5a440f71ccdbf69ec7ed4f2bb087e858c83f Mon Sep 17 00:00:00 2001 From: Karel Zak Date: Thu, 9 Jan 2014 14:49:45 +0100 Subject: cfdisk: basic UI stuff --- fdisks/cfdisk.c | 3221 +++++++++---------------------------------------------- 1 file changed, 524 insertions(+), 2697 deletions(-) (limited to 'fdisks/cfdisk.c') diff --git a/fdisks/cfdisk.c b/fdisks/cfdisk.c index 1a95c1e0b..50c38a41d 100644 --- a/fdisks/cfdisk.c +++ b/fdisks/cfdisk.c @@ -1,69 +1,7 @@ -/**************************************************************************** - * - * CFDISK - * - * cfdisk is a curses based disk drive partitioning program that can - * create partitions for a wide variety of operating systems including - * Linux, MS-DOS and OS/2. - * - * cfdisk was inspired by the fdisk program, by A. V. Le Blanc - * (LeBlanc@mcc.ac.uk). - * - * Copyright (C) 1994 Kevin E. Martin (martin@cs.unc.edu) - * - * cfdisk 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 2 of the License, or - * (at your option) any later version. - * - * cfdisk 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 Street, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Created: Fri Jan 28 22:46:58 1994, martin@cs.unc.edu - * >2GB patches: Sat Feb 11 09:08:10 1995, faith@cs.unc.edu - * Prettier menus: Sat Feb 11 09:08:25 1995, Janne Kukonlehto - * - * Versions 0.8e-p: aeb@cwi.nl - * Rebaptised 2.9p, following util-linux versioning. - * - * Recognition of NTFS / HPFS difference inspired by patches - * from Marty Leisner - * Exit codes by Enrique Zanardi : - * 0: all went well - * 1: command line error, out of memory - * 2: hardware problems [Cannot open/seek/read/write disk drive]. - * 3: ioctl(fd, HDIO_GETGEO,...) failed. (Probably it is not a disk.) - * 4: bad partition table on disk. [Bad primary/logical partition]. - * - * Sat, 23 Jan 1999 19:34:45 +0100 - * Internationalized + provided initial French translation. - * Sat Mar 20 09:26:34 EST 1999 - * Some more i18n. - * Sun Jul 18 03:19:42 MEST 1999 - * Terabyte-sized disks. - * Sat Jun 30 05:23:19 EST 2001 - * XFS label recognition. - * Thu Nov 22 15:42:56 CET 2001 - * ext3 and ReiserFS recognition. - * Sun Oct 12 17:43:43 CEST 2003 - * JFS recognition; ReiserFS label recognition. - * - ****************************************************************************/ - #include #include -#include -#include -#include #include -#include -#include +#include #ifdef HAVE_SLANG_H #include @@ -83,2807 +21,696 @@ #include #endif -#include -#include -#include -#include -#include - -#ifdef HAVE_LIBBLKID -#include -#endif - #ifdef HAVE_WIDECHAR #include #endif +#include "c.h" #include "closestream.h" #include "nls.h" -#include "rpmatch.h" -#include "blkdev.h" #include "strutils.h" +#include "xalloc.h" #include "mbsalign.h" -#include "widechar.h" -struct systypes { - unsigned char type; - char *name; +#include "fdiskP.h" + +#define ARROW_CURSOR_STRING ">>> " +#define ARROW_CURSOR_DUMMY " " +#define ARROW_CURSOR_WIDTH (sizeof(ARROW_CURSOR_STRING) - 1) + +#define MENU_PADDING 2 +#define TABLE_START_LINE 4 +#define MENU_START_LINE (LINES - 5) + + +struct cfdisk_menudesc { + int key; /* keyboard shortcut */ + const char *name; /* item name */ + const char *desc; /* item description */ }; -static struct systypes i386_sys_types[] = { - #include "pt-mbr-partnames.h" +struct cfdisk_menu { + struct cfdisk_menudesc *desc; + char *ignore; + size_t id; + size_t width; + size_t nitems; + struct cfdisk_menu *prev; }; -#ifdef __GNU__ -#define DEFAULT_DEVICE "/dev/hd0" -#define ALTERNATE_DEVICE "/dev/sd0" -#elif defined(__FreeBSD__) -#define DEFAULT_DEVICE "/dev/ad0" -#define ALTERNATE_DEVICE "/dev/da0" -#else -#define DEFAULT_DEVICE "/dev/hda" -#define ALTERNATE_DEVICE "/dev/sda" -#endif +static struct cfdisk_menudesc menu_main[] = { + { 'b', N_("Bootable"), N_("Toggle bootable flag of the current partition") }, + { 'd', N_("Delete"), N_("Delete the current partition") }, +// { 'g', N_("Geometry"), N_("Change disk geometry (experts only)") }, +// { 'h', N_("Help"), N_("Print help screen") }, +// { 'm', N_("Maximize"), N_("Maximize disk usage of the current partition (experts only)") }, + { 'n', N_("New"), N_("Create new partition from free space") }, +// { 'p', N_("Print"), N_("Print partition table to the screen or to a file") }, + { 'q', N_("Quit"), N_("Quit program without writing partition table") }, + { 't', N_("Type"), N_("Change the partition type") }, +// { 'u', N_("Units"), N_("Change units of the partition size display (MB, sect, cyl)") }, + { 'W', N_("Write"), N_("Write partition table to disk (this might destroy data)") }, + { 0, NULL, NULL } +}; -/* With K=1024 we have `binary' megabytes, gigabytes, etc. - Some misguided hackers like that. - With K=1000 we have MB and GB that follow the standards - [SI, ATA, IEEE etc] and the disk manufacturers and the law. */ -#define K 1000 - -#define LINE_LENGTH 80 -#define MAXIMUM_PARTS 60 - -#define SECTOR_SIZE 512 - -#define MAX_HEADS 256 -#define MAX_SECTORS 63 - -#define ACTIVE_FLAG 0x80 -#define PART_TABLE_FLAG0 0x55 -#define PART_TABLE_FLAG1 0xAA - -#define UNUSABLE -1 -#define FREE_SPACE 0x00 -#define DOS_EXTENDED 0x05 -#define OS2_OR_NTFS 0x07 -#define WIN98_EXTENDED 0x0f -#define LINUX_EXTENDED 0x85 -#define LINUX_MINIX 0x81 -#define LINUX_SWAP 0x82 -#define LINUX 0x83 - -#define PRI_OR_LOG -1 -#define PRIMARY -2 -#define LOGICAL -3 - -#define COL_ID_WIDTH 25 - -#define ESC '\033' -#define DEL '\177' -#define BELL '\007' -#define REDRAWKEY '\014' /* ^L */ - -/* Display units */ -#define GIGABYTES 1 -#define MEGABYTES 2 -#define SECTORS 3 -#define CYLINDERS 4 - -#define GS_DEFAULT -1 -#define GS_ESCAPE -2 - -#define PRINT_RAW_TABLE 1 -#define PRINT_SECTOR_TABLE 2 -#define PRINT_PARTITION_TABLE 4 - -#define IS_PRIMARY(p) ((p) >= 0 && (p) < 4) -#define IS_LOGICAL(p) ((p) > 3) - -#define round_int(d) ((double)((int)(d+0.5))) -#define ceiling(d) ((double)(((d) != (int)(d)) ? (int)(d+1.0) : (int)(d))) - -struct partition { - unsigned char boot_ind; /* 0x80 - active */ - unsigned char head; /* starting head */ - unsigned char sector; /* starting sector */ - unsigned char cyl; /* starting cylinder */ - unsigned char sys_ind; /* What partition type */ - unsigned char end_head; /* end head */ - unsigned char end_sector; /* end sector */ - unsigned char end_cyl; /* end cylinder */ - unsigned char start4[4]; /* starting sector counting from 0 */ - unsigned char size4[4]; /* nr of sectors in partition */ +enum { + CFDISK_MENU_MAIN = 0, }; -int heads = 0; -int sectors = 0; -long long cylinders = 0; -int cylinder_size = 0; /* heads * sectors */ -long long actual_size = 0; /* (in 512-byte sectors) - set using ioctl */ - /* explicitly given user values */ -int user_heads = 0, user_sectors = 0; -long long user_cylinders = 0; - /* kernel values; ignore the cylinders */ -int kern_heads = 0, kern_sectors = 0; - /* partition-table derived values */ -int pt_heads = 0, pt_sectors = 0; - - -static void -set_hsc0(unsigned char *h, unsigned char *s, int *c, long long sector) { - *s = sector % sectors + 1; - sector /= sectors; - *h = sector % heads; - sector /= heads; - *c = sector; -} +static struct cfdisk_menudesc *menus[] = { + [CFDISK_MENU_MAIN] = menu_main +}; -static void -set_hsc(unsigned char *h, unsigned char *s, unsigned char *c, - long long sector) { - int cc; +struct cfdisk { + struct fdisk_context *cxt; /* libfdisk context */ + struct fdisk_table *table; /* partition table */ - if (sector >= 1024*cylinder_size) - sector = 1024*cylinder_size - 1; - set_hsc0(h, s, &cc, sector); - *c = cc & 0xFF; - *s |= (cc >> 2) & 0xC0; -} + struct cfdisk_menu *menu; /* the current menu */ + size_t menu_idx; -static void -set_hsc_begin(struct partition *p, long long sector) { - set_hsc(& p->head, & p->sector, & p->cyl, sector); -} + int *cols; /* output columns */ + size_t ncols; /* number of columns */ -static void -set_hsc_end(struct partition *p, long long sector) { - set_hsc(& p->end_head, & p->end_sector, & p->end_cyl, sector); -} + char *linesbuf; /* table as string */ + size_t linesbufsz; /* size of the tb_buf */ -#define is_extended(x) ((x) == DOS_EXTENDED || (x) == WIN98_EXTENDED || \ - (x) == LINUX_EXTENDED) - -/* start_sect and nr_sects are stored little endian on all machines */ -/* moreover, they are not aligned correctly */ -static void -store4_little_endian(unsigned char *cp, unsigned int val) { - cp[0] = (val & 0xff); - cp[1] = ((val >> 8) & 0xff); - cp[2] = ((val >> 16) & 0xff); - cp[3] = ((val >> 24) & 0xff); -} + char **lines; /* array with lines */ + size_t nlines; /* number of lines */ + size_t lines_idx; /* current line <0..N>, exclude header */ -static unsigned int -read4_little_endian(unsigned char *cp) { - return (unsigned int)(cp[0]) + ((unsigned int)(cp[1]) << 8) - + ((unsigned int)(cp[2]) << 16) - + ((unsigned int)(cp[3]) << 24); -} + unsigned int ui_enabled : 1; +}; -static void -set_start_sect(struct partition *p, unsigned int start_sect) { - store4_little_endian(p->start4, start_sect); -} +static int cols_init(struct cfdisk *cf) +{ + assert(cf); -static unsigned int -get_start_sect(struct partition *p) { - return read4_little_endian(p->start4); -} + free(cf->cols); + cf->cols = NULL; + cf->ncols = 0; -static void -set_nr_sects(struct partition *p, unsigned int nr_sects) { - store4_little_endian(p->size4, nr_sects); + return fdisk_get_columns(cf->cxt, 0, &cf->cols, &cf->ncols); } -static unsigned int -get_nr_sects(struct partition *p) { - return read4_little_endian(p->size4); -} +/* It would be possible to use fdisk_table_to_string(), but we want some + * extension to the output format, so let's do it without libfdisk + */ +static char *table_to_string(struct cfdisk *cf, struct fdisk_table *tb) +{ + struct fdisk_partition *pa; + const struct fdisk_column *col; + struct fdisk_label *lb; + struct fdisk_iter *itr = NULL; + struct tt *tt = NULL; + char *res = NULL; + size_t i; + + DBG(FRONTEND, dbgprint("table: convert to string")); + + assert(cf); + assert(cf->cxt); + assert(cf->cols); + assert(tb); + + lb = fdisk_context_get_label(cf->cxt, NULL); + assert(lb); + + tt = tt_new_table(TT_FL_FREEDATA | TT_FL_MAX); + if (!tt) + goto done; + itr = fdisk_new_iter(FDISK_ITER_FORWARD); + if (!itr) + goto done; -#define ALIGNMENT 2 -typedef union { - struct { - unsigned char align[ALIGNMENT]; - unsigned char b[SECTOR_SIZE]; - } c; - struct { - unsigned char align[ALIGNMENT]; - unsigned char buffer[0x1BE]; - struct partition part[4]; - unsigned char magicflag[2]; - } p; -} partition_table; - -typedef struct { - long long first_sector; /* first sector in partition */ - long long last_sector; /* last sector in partition */ - long offset; /* offset from first sector to start of data */ - int flags; /* active == 0x80 */ - int id; /* filesystem type */ - int num; /* number of partition -- primary vs. logical */ -#define LABELSZ 16 - char volume_label[LABELSZ+1]; -#define OSTYPESZ 8 - char ostype[OSTYPESZ+1]; -#define FSTYPESZ 12 - char fstype[FSTYPESZ+1]; -} partition_info; - -char *disk_device = DEFAULT_DEVICE; -int fd; -int changed = FALSE; -int opened = FALSE; -int opentype; -int curses_started = 0; - -partition_info p_info[MAXIMUM_PARTS]; -partition_info ext_info; -int num_parts = 0; - -int logical = 0; -long long logical_sectors[MAXIMUM_PARTS]; - -#ifdef HAVE_SIGHANDLER_T -sighandler_t old_SIGINT, old_SIGTERM; -#else -void (* old_SIGINT)(int), (* old_SIGTERM)(int); -#endif + /* headers */ + for (i = 0; i < cf->ncols; i++) { + col = fdisk_label_get_column(lb, cf->cols[i]); + if (col) + tt_define_column(tt, col->name, + col->width, + col->tt_flags); + } + + /* data */ + while (fdisk_table_next_partition(tb, itr, &pa) == 0) { + struct tt_line *ln = tt_add_line(tt, NULL); + if (!ln) + goto done; + for (i = 0; i < cf->ncols; i++) { + char *cdata = NULL; + + col = fdisk_label_get_column(lb, cf->cols[i]); + if (!col) + continue; + if (fdisk_partition_to_string(pa, cf->cxt, col->id, &cdata)) + continue; + tt_line_set_data(ln, i, cdata); + } + } -int arrow_cursor = FALSE; -int display_units = MEGABYTES; -int zero_table = FALSE; -int use_partition_table_geometry = FALSE; -int print_only = 0; - -/* Curses screen information */ -int cur_part = 0; -int warning_last_time = FALSE; -int defined = FALSE; -int COLUMNS = 80; -int NUM_ON_SCREEN = 1; - -/* Y coordinates */ -int HEADER_START = 0; -int DISK_TABLE_START = 6; -int WARNING_START = 23; -int COMMAND_LINE_Y = 21; - -/* X coordinates */ -int NAME_START = 4; -int FLAGS_START = 16; -int PTYPE_START = 28; -int FSTYPE_START = 38; -int LABEL_START = 54; -int SIZE_START = 68; -int COMMAND_LINE_X = 5; - -static void die_x(int ret); -static void draw_screen(void); - -/* Guaranteed alloc */ -static void * -xmalloc (size_t size) { - void *t; - - if (size == 0) - return NULL; - - t = malloc (size); - if (t == NULL) { - fprintf (stderr, _("%s: Out of memory!\n"), "cfdisk"); - die_x(1); - } - return t; -} + if (!tt_is_empty(tt)) { + tt_set_termreduce(tt, ARROW_CURSOR_WIDTH); + tt_print_table_to_string(tt, &res); + } +done: + tt_free_table(tt); + fdisk_free_iter(itr); -/* Some libc's have their own basename() */ -static char * -my_basename(char *devname) { - char *s = strrchr(devname, '/'); - return s ? s+1 : devname; + return res; } -static char * -partition_type_name(unsigned char type) { - struct systypes *s = i386_sys_types; - while(s->name && s->type != type) - s++; - return s->name; -} +static int lines_refresh_buffer(struct cfdisk *cf) +{ + int rc; + char *p; + size_t i; -static char * -partition_type_text(int i) { - if (p_info[i].id == UNUSABLE) - return _("Unusable"); - else if (p_info[i].id == FREE_SPACE) - return _("Free Space"); - else if (*p_info[i].fstype) - return p_info[i].fstype; - else - return _(partition_type_name(p_info[i].id)); -} + assert(cf); -static void -fdexit(int ret) { - if (opened) { - if (changed) { - if (close_fd(fd) != 0) { - fprintf(stderr, _("write failed\n")); - exit(2); - } - } else - close(fd); - } - if (changed) { - fprintf(stderr, _("Disk has been changed.\n")); -#if 0 - fprintf(stderr, _("Reboot the system to ensure the partition " - "table is correctly updated.\n")); -#endif + DBG(FRONTEND, dbgprint("refresing buffer")); - fprintf( stderr, _("\nWARNING: If you have created or modified any\n" - "DOS 6.x partitions, please see the cfdisk manual\n" - "page for additional information.\n") ); - } + free(cf->linesbuf); + free(cf->lines); + cf->linesbuf = NULL; + cf->linesbufsz = 0; + cf->lines = NULL; + cf->nlines = 0; - exit(ret); -} + fdisk_unref_table(cf->table); + fdisk_context_enable_freespace(cf->cxt, 1); -/* - * Note that @len is size of @str buffer. - * - * Returns number of read bytes (without \0). - */ -static int -get_string(char *str, int len, char *def) { - size_t cells = 0; - ssize_t i = 0; - int x, y; - int use_def = FALSE; - wint_t c; - - getyx(stdscr, y, x); - clrtoeol(); - - str[i] = 0; - - if (def != NULL) { - mvaddstr(y, x, def); - move(y, x); - use_def = TRUE; - } - - refresh(); - - while (1) { -#if !defined(HAVE_SLCURSES_H) && !defined(HAVE_SLANG_SLCURSES_H) && \ - defined(HAVE_LIBNCURSESW) && defined(HAVE_WIDECHAR) - if (get_wch(&c) == ERR) { -#else - if ((c = getch()) == ERR) { -#endif - if (!isatty(STDIN_FILENO)) - exit(2); - else - break; - } - if (c == '\r' || c == '\n' || c == KEY_ENTER) - break; + rc = fdisk_get_table(cf->cxt, &cf->table); + if (rc) + return rc; - switch (c) { - case ESC: - move(y, x); - clrtoeol(); - refresh(); - return GS_ESCAPE; - case DEL: - case '\b': - case KEY_BACKSPACE: - if (i > 0) { - cells--; - i = mbs_truncate(str, &cells); - if (i < 0) - return GS_ESCAPE; - mvaddch(y, x + cells, ' '); - move(y, x + cells); - } else if (use_def) { - clrtoeol(); - use_def = FALSE; - } else - putchar(BELL); - break; - default: -#if defined(HAVE_LIBNCURSESW) && defined(HAVE_WIDECHAR) - if (i + 1 < len && iswprint(c)) { - wchar_t wc = (wchar_t) c; - char s[MB_CUR_MAX + 1]; - int sz = wctomb(s, wc); - - if (sz > 0 && sz + i < len) { - s[sz] = '\0'; - mvaddnstr(y, x + cells, s, sz); - if (use_def) { - clrtoeol(); - use_def = FALSE; - } - memcpy(str + i, s, sz); - i += sz; - str[i] = '\0'; - cells += wcwidth(wc); - } else - putchar(BELL); - } -#else - if (i + 1 < len && isprint(c)) { - mvaddch(y, x + cells, c); - if (use_def) { - clrtoeol(); - use_def = FALSE; - } - str[i++] = c; - str[i] = 0; - cells++; - } -#endif - else - putchar(BELL); - } - refresh(); - } + cf->linesbuf = table_to_string(cf, cf->table); + if (!cf->linesbuf) + return -ENOMEM; - if (use_def) - return GS_DEFAULT; - else - return i; -} - -static void -clear_warning(void) { - int i; + cf->linesbufsz = strlen(cf->linesbuf); + cf->nlines = fdisk_table_get_nents(cf->table) + 1; /* 1 for header line */ - if (!curses_started || !warning_last_time) - return; + cf->lines = calloc(cf->nlines, sizeof(char *)); + if (!cf->lines) + return -ENOMEM; - move(WARNING_START,0); - for (i = 0; i < COLS; i++) - addch(' '); + for (p = cf->linesbuf, i = 0; p && i < cf->nlines; i++) { + cf->lines[i] = p; + p = strchr(p, '\n'); + if (p) { + *p = '\0'; + p++; + } + } - warning_last_time = FALSE; + return 0; } -static void -print_warning(char *s) { - if (!curses_started) { - fprintf(stderr, "%s\n", s); - } else { - mvaddstr(WARNING_START, (COLS-strlen(s))/2, s); - putchar(BELL); /* CTRL-G */ +static int ask_callback(struct fdisk_context *cxt, struct fdisk_ask *ask, + void *data __attribute__((__unused__))) +{ + int rc = 0; - warning_last_time = TRUE; - } -} + assert(cxt); + assert(ask); -static void -fatal(char *s, int ret) { - char *err1 = _("FATAL ERROR"); - char *err2 = _("Press any key to exit cfdisk"); - - if (curses_started) { - char *str = xmalloc(strlen(s) + strlen(err1) + strlen(err2) + 10); - - sprintf(str, "%s: %s", err1, s); - if (strlen(str) > (size_t) COLS) - str[COLS] = 0; - mvaddstr(WARNING_START, (COLS-strlen(str))/2, str); - sprintf(str, "%s", err2); - if (strlen(str) > (size_t) COLS) - str[COLS] = 0; - mvaddstr(WARNING_START+1, (COLS-strlen(str))/2, str); - putchar(BELL); /* CTRL-G */ - refresh(); - (void)getch(); - die_x(ret); - } else { - fprintf(stderr, "%s: %s\n", err1, s); - exit(ret); - } + switch(fdisk_ask_get_type(ask)) { + case FDISK_ASKTYPE_INFO: + fputs(fdisk_ask_print_get_mesg(ask), stdout); + fputc('\n', stdout); + break; + case FDISK_ASKTYPE_WARNX: + fputs(fdisk_ask_print_get_mesg(ask), stderr); + fputc('\n', stderr); + break; + case FDISK_ASKTYPE_WARN: + fputs(fdisk_ask_print_get_mesg(ask), stderr); + errno = fdisk_ask_print_get_errno(ask); + fprintf(stderr, ": %m\n"); + break; + default: + warnx(_("internal error: unsupported dialog type %d"), fdisk_ask_get_type(ask)); + return -EINVAL; + } + return rc; } -static void -die(int dummy __attribute__((__unused__))) { - die_x(0); -} -static void -die_x(int ret) { - signal(SIGINT, old_SIGINT); - signal(SIGTERM, old_SIGTERM); +static int ui_end(struct cfdisk *cf) +{ + if (cf && !cf->ui_enabled) + return -EINVAL; + #if defined(HAVE_SLCURSES_H) || defined(HAVE_SLANG_SLCURSES_H) - SLsmg_gotorc(LINES-1, 0); - SLsmg_refresh(); + SLsmg_gotorc(LINES - 1, 0); + SLsmg_refresh(); #else - mvcur(0, COLS-1, LINES-1, 0); + mvcur(0, COLS - 1, LINES-1, 0); #endif - nl(); - endwin(); - printf("\n"); - fdexit(ret); + nl(); + endwin(); + printf("\n"); + return 0; } -static void -read_sector(unsigned char *buffer, long long sect_num) { - if (lseek(fd, sect_num*SECTOR_SIZE, SEEK_SET) < 0) - fatal(_("Cannot seek on disk drive"), 2); - if (read(fd, buffer, SECTOR_SIZE) != SECTOR_SIZE) - fatal(_("Cannot read disk drive"), 2); -} - -static void -write_sector(unsigned char *buffer, long long sect_num) { - if (lseek(fd, sect_num*SECTOR_SIZE, SEEK_SET) < 0) - fatal(_("Cannot seek on disk drive"), 2); - if (write(fd, buffer, SECTOR_SIZE) != SECTOR_SIZE) - fatal(_("Cannot write disk drive"), 2); -} - -#ifdef HAVE_LIBBLKID -static void -get_fsinfo(int i) +static void ui_print_center(int line, const char *fmt, ...) { - blkid_probe pr; - blkid_loff_t offset, size; - const char *data; - - offset = (p_info[i].first_sector + p_info[i].offset) * SECTOR_SIZE; - size = (p_info[i].last_sector - p_info[i].first_sector + 1) * SECTOR_SIZE; - pr = blkid_new_probe(); - if (!pr) - return; - blkid_probe_enable_superblocks(pr, 1); - blkid_probe_set_superblocks_flags(pr, BLKID_SUBLKS_LABEL | - BLKID_SUBLKS_TYPE); - if (blkid_probe_set_device(pr, fd, offset, size)) - goto done; - if (blkid_do_safeprobe(pr)) - goto done; + size_t width; + va_list ap; + char *buf = NULL; - if (!blkid_probe_lookup_value(pr, "TYPE", &data, 0)) - strncpy(p_info[i].fstype, data, FSTYPESZ); + move(line, 0); + clrtoeol(); - if (!blkid_probe_lookup_value(pr, "LABEL", &data, 0)) - strncpy(p_info[i].volume_label, data, LABELSZ); -done: - blkid_free_probe(pr); -} -#endif + va_start(ap, fmt); + xvasprintf(&buf, fmt, ap); + va_end(ap); -static void -check_part_info(void) { - int i, pri = 0, log = 0; - - for (i = 0; i < num_parts; i++) - if (p_info[i].id > 0 && IS_PRIMARY(p_info[i].num)) - pri++; - else if (p_info[i].id > 0 && IS_LOGICAL(p_info[i].num)) - log++; - if (is_extended(ext_info.id)) { - if (log > 0) - pri++; - else { - ext_info.first_sector = 0; - ext_info.last_sector = 0; - ext_info.offset = 0; - ext_info.flags = 0; - ext_info.id = FREE_SPACE; - ext_info.num = PRIMARY; - } - } - - if (pri >= 4) { - for (i = 0; i < num_parts; i++) - if (p_info[i].id == FREE_SPACE || p_info[i].id == UNUSABLE) { - if (is_extended(ext_info.id)) { - if (p_info[i].first_sector >= ext_info.first_sector && - p_info[i].last_sector <= ext_info.last_sector) { - p_info[i].id = FREE_SPACE; - p_info[i].num = LOGICAL; - } else if (i > 0 && - p_info[i-1].first_sector >= - ext_info.first_sector && - p_info[i-1].last_sector <= - ext_info.last_sector) { - p_info[i].id = FREE_SPACE; - p_info[i].num = LOGICAL; - } else if (i < num_parts-1 && - p_info[i+1].first_sector >= - ext_info.first_sector && - p_info[i+1].last_sector <= - ext_info.last_sector) { - p_info[i].id = FREE_SPACE; - p_info[i].num = LOGICAL; - } else - p_info[i].id = UNUSABLE; - } else /* if (!is_extended(ext_info.id)) */ - p_info[i].id = UNUSABLE; - } else /* if (p_info[i].id > 0) */ - while (0); /* Leave these alone */ - } else { /* if (pri < 4) */ - for (i = 0; i < num_parts; i++) { - if (p_info[i].id == UNUSABLE) - p_info[i].id = FREE_SPACE; - if (p_info[i].id == FREE_SPACE) { - if (is_extended(ext_info.id)) { - if (p_info[i].first_sector >= ext_info.first_sector && - p_info[i].last_sector <= ext_info.last_sector) - p_info[i].num = LOGICAL; - else if (i > 0 && - p_info[i-1].first_sector >= - ext_info.first_sector && - p_info[i-1].last_sector <= - ext_info.last_sector) - p_info[i].num = PRI_OR_LOG; - else if (i < num_parts-1 && - p_info[i+1].first_sector >= - ext_info.first_sector && - p_info[i+1].last_sector <= - ext_info.last_sector) - p_info[i].num = PRI_OR_LOG; - else - p_info[i].num = PRIMARY; - } else /* if (!is_extended(ext_info.id)) */ - p_info[i].num = PRI_OR_LOG; - } else /* if (p_info[i].id > 0) */ - while (0); /* Leave these alone */ - } - } + width = strlen(buf); /* TODO: count cells! */ + mvaddstr(line, (COLS - width) / 2, buf); + free(buf); } -static void -remove_part(int i) { - int p; - for (p = i; p < num_parts; p++) - p_info[p] = p_info[p+1]; - - num_parts--; - if (cur_part == num_parts) - cur_part--; +static void die_on_signal(int dummy __attribute__((__unused__))) +{ + ui_end(NULL); + exit(EXIT_FAILURE); } -static void -insert_empty_part(int i, long long first, long long last) { - int p; - - for (p = num_parts; p > i; p--) - p_info[p] = p_info[p-1]; +static void menu_update_ignore(struct cfdisk *cf) +{ + char *ignore = NULL; + struct cfdisk_menu *m; + struct cfdisk_menudesc *d; - p_info[i].first_sector = first; - p_info[i].last_sector = last; - p_info[i].offset = 0; - p_info[i].flags = 0; - p_info[i].id = FREE_SPACE; - p_info[i].num = PRI_OR_LOG; - p_info[i].volume_label[0] = 0; - p_info[i].fstype[0] = 0; - p_info[i].ostype[0] = 0; + assert(cf); - num_parts++; -} + m = cf->menu; + DBG(FRONTEND, dbgprint("menu: update menu ignored keys")); -static void -del_part(int i) { - int num = p_info[i].num; - - if (i > 0 && (p_info[i-1].id == FREE_SPACE || - p_info[i-1].id == UNUSABLE)) { - /* Merge with previous partition */ - p_info[i-1].last_sector = p_info[i].last_sector; - remove_part(i--); - } - - if (i < num_parts - 1 && (p_info[i+1].id == FREE_SPACE || - p_info[i+1].id == UNUSABLE)) { - /* Merge with next partition */ - p_info[i+1].first_sector = p_info[i].first_sector; - remove_part(i); - } - - if (i > 0) - p_info[i].first_sector = p_info[i-1].last_sector + 1; - else - p_info[i].first_sector = 0; - - if (i < num_parts - 1) - p_info[i].last_sector = p_info[i+1].first_sector - 1; - else - p_info[i].last_sector = actual_size - 1; - - p_info[i].offset = 0; - p_info[i].flags = 0; - p_info[i].id = FREE_SPACE; - p_info[i].num = PRI_OR_LOG; - - if (IS_LOGICAL(num)) { - /* We have a logical partition --> shrink the extended partition - * if (1) this is the first logical drive, or (2) this is the - * last logical drive; and if there are any other logical drives - * then renumber the ones after "num". - */ - if (i == 0 || (i > 0 && IS_PRIMARY(p_info[i-1].num))) { - ext_info.first_sector = p_info[i].last_sector + 1; - ext_info.offset = 0; + switch (m->id) { + case CFDISK_MENU_MAIN: + break; } - if (i == num_parts-1 || - (i < num_parts-1 && IS_PRIMARY(p_info[i+1].num))) - ext_info.last_sector = p_info[i].first_sector - 1; - for (i = 0; i < num_parts; i++) - if (p_info[i].num > num) - p_info[i].num--; - } - - /* Clean up the rest of the partitions */ - check_part_info(); -} -static int -add_part(int num, int id, int flags, long long first, long long last, - long long offset, int want_label, char **errmsg) { - int i, pri = 0, log = 0; - - if (num_parts == MAXIMUM_PARTS) { - *errmsg = _("Too many partitions"); - return -1; - } - - if (first < 0) { - *errmsg = _("Partition begins before sector 0"); - return -1; - } - - if (last < 0) { - *errmsg = _("Partition ends before sector 0"); - return -1; - } - - if (first >= actual_size) { - *errmsg = _("Partition begins after end-of-disk"); - return -1; - } - - if (last >= actual_size) { - *errmsg = _("Partition ends after end-of-disk"); - return -1; - } - - for (i = 0; i < num_parts; i++) { - if (p_info[i].id > 0 && IS_PRIMARY(p_info[i].num)) - pri++; - else if (p_info[i].id > 0 && IS_LOGICAL(p_info[i].num)) - log++; - } - if (is_extended(ext_info.id) && log > 0) - pri++; - - if (IS_PRIMARY(num)) { - if (pri >= 4) { - return -1; /* no room for more */ - } else - pri++; - } - - for (i = 0; i < num_parts && p_info[i].last_sector < first; i++); - - if (i < num_parts && p_info[i].id != FREE_SPACE) { - if (last < p_info[i].first_sector) - *errmsg = _("logical partitions not in disk order"); - else if (first + offset <= p_info[i].last_sector && - p_info[i].first_sector + p_info[i].offset <= last) - *errmsg = _("logical partitions overlap"); - else - /* the enlarged logical partition starts at the - partition table sector that defines it */ - *errmsg = _("enlarged logical partitions overlap"); - return -1; - } - - if (i == num_parts || last > p_info[i].last_sector) { - return -1; - } - - if (is_extended(id)) { - if (ext_info.id != FREE_SPACE) { - return -1; /* second extended */ - } - else if (IS_PRIMARY(num)) { - ext_info.first_sector = first; - ext_info.last_sector = last; - ext_info.offset = offset; - ext_info.flags = flags; - ext_info.id = id; - ext_info.num = num; - ext_info.volume_label[0] = 0; - ext_info.fstype[0] = 0; - ext_info.ostype[0] = 0; - return 0; - } else { - return -1; /* explicit extended logical */ + /* return if no change */ + if ( (!m->ignore && (!ignore || !*ignore)) + || (m->ignore && ignore && strcmp(m->ignore, ignore) == 0)) { + free(ignore); + return; } - } - if (IS_LOGICAL(num)) { - if (!is_extended(ext_info.id)) { - print_warning(_("!!!! Internal error creating logical " - "drive with no extended partition !!!!")); - } else { - /* We might have a logical partition outside of the extended - * partition's range --> we have to extend the extended - * partition's range to encompass this new partition, but we - * must make sure that there are no primary partitions between - * it and the closest logical drive in extended partition. - */ - if (first < ext_info.first_sector) { - if (i < num_parts-1 && IS_PRIMARY(p_info[i+1].num)) { - print_warning(_("Cannot create logical drive here -- would create two extended partitions")); - return -1; - } else { - if (first == 0) { - ext_info.first_sector = 0; - ext_info.offset = first = offset; - } else { - ext_info.first_sector = first; - } - } - } else if (last > ext_info.last_sector) { - if (i > 0 && IS_PRIMARY(p_info[i-1].num)) { - print_warning(_("Cannot create logical drive here -- would create two extended partitions")); - return -1; - } else { - ext_info.last_sector = last; - } - } - } - } - - if (first != p_info[i].first_sector && - !(IS_LOGICAL(num) && first == offset)) { - insert_empty_part(i, p_info[i].first_sector, first-1); - i++; - } - - if (last != p_info[i].last_sector) - insert_empty_part(i+1, last+1, p_info[i].last_sector); - - p_info[i].first_sector = first; - p_info[i].last_sector = last; - p_info[i].offset = offset; - p_info[i].flags = flags; - p_info[i].id = id; - p_info[i].num = num; - p_info[i].volume_label[0] = 0; - p_info[i].fstype[0] = 0; - p_info[i].ostype[0] = 0; - -#ifdef HAVE_LIBBLKID - if (want_label) - get_fsinfo(i); -#endif - check_part_info(); + free(m->ignore); + m->ignore = ignore; + m->nitems = 0; - return 0; + for (d = m->desc; d->name; d++) { + if (m->ignore && strchr(m->ignore, d->key)) + m->nitems++; + } } -static int -find_primary(void) { - int num = 0, cur = 0; - - while (cur < num_parts && IS_PRIMARY(num)) - if ((p_info[cur].id > 0 && p_info[cur].num == num) || - (is_extended(ext_info.id) && ext_info.num == num)) { - num++; - cur = 0; - } else - cur++; +static struct cfdisk_menu *menu_push(struct cfdisk *cf, size_t id) +{ + struct cfdisk_menu *m = xcalloc(1, sizeof(*m)); + struct cfdisk_menudesc *d; - if (!IS_PRIMARY(num)) - return -1; - else - return num; -} + assert(cf); + assert(id < ARRAY_SIZE(menus)); -static int -find_logical(int i) { - int num = -1; - int j; + DBG(FRONTEND, dbgprint("menu: new menu")); - for (j = i; j < num_parts && num == -1; j++) - if (p_info[j].id > 0 && IS_LOGICAL(p_info[j].num)) - num = p_info[j].num; + m->prev = cf->menu; + m->id = id; + m->desc = menus[id]; - if (num == -1) { - num = 4; - for (j = 0; j < num_parts; j++) - if (p_info[j].id > 0 && p_info[j].num == num) - num++; - } + for (d = m->desc; d->name; d++) { + const char *name = _(d->name); + size_t len = strlen(name); /* TODO: we care about cells! */ + if (len > m->width) + m->width = len; + m->nitems++; + } - return num; + cf->menu = m; + return m; } -/* - * Command menu support by Janne Kukonlehto - * September 1994 - */ - -/* Constants for menuType parameter of menuSelect function */ -#define MENU_ACCEPT_OTHERS 4 -#define MENU_BUTTON 8 -/* Miscellenous constants */ -#define MENU_SPACING 2 -#define MENU_MAX_ITEMS 256 /* for simpleMenu function */ - -struct MenuItem +static struct cfdisk_menu *menu_pop(struct cfdisk *cf) { - int key; /* Keyboard shortcut; if zero, then there is no more items in the menu item table */ - char *name; /* Item name, should be eight characters with current implementation */ - char *desc; /* Item description to be printed when item is selected */ -}; - -/* - * Actual function which prints the button bar and highlights the active button - * Should not be called directly. Call function menuSelect instead. - */ + struct cfdisk_menu *m = NULL; -static int -menuUpdate( int y, int x, struct MenuItem *menuItems, int itemLength, - char *available, int menuType, int current ) { - int i, lmargin = x; - char *mcd; + assert(cf); - /* Print available buttons */ - move( y, x ); clrtoeol(); + DBG(FRONTEND, dbgprint("menu: rem menu")); - for( i = 0; menuItems[i].key; i++ ) { - char buff[20]; - int lenName; - const char *mi; - - /* Search next available button */ - while( menuItems[i].key && !strchr(available, menuItems[i].key) ) - i++; - - if( !menuItems[i].key ) break; /* No more menu items */ - - /* If selected item is not available and we have bypassed it, - make current item selected */ - if( current < i && menuItems[current].key < 0 ) current = i; - - /* If current item is selected, highlight it */ - if( current == i ) /*attron( A_REVERSE )*/ standout (); - - /* Print item */ - /* Because of a bug in gettext() we must not translate empty strings */ - if (menuItems[i].name[0]) - mi = _(menuItems[i].name); - else - mi = ""; - lenName = strlen( mi ); -#if 0 - if(lenName > itemLength || lenName >= sizeof(buff)) - print_warning(_("Menu item too long. Menu may look odd.")); -#endif - if ((size_t) lenName >= sizeof(buff)) { /* truncate ridiculously long string */ - xstrncpy(buff, mi, sizeof(buff)); - } else if (lenName >= itemLength) { - snprintf(buff, sizeof(buff), - (menuType & MENU_BUTTON) ? "[%s]" : "%s", mi); - } else { - snprintf(buff, sizeof(buff), - (menuType & MENU_BUTTON) ? "[%*s%-*s]" : "%*s%-*s", - (itemLength - lenName) / 2, "", - (itemLength - lenName + 1) / 2 + lenName, mi); + if (cf->menu) { + m = cf->menu->prev; + free(cf->menu->ignore); + free(cf->menu); } - mvaddstr( y, x, buff ); - - /* Lowlight after selected item */ - if( current == i ) /*attroff( A_REVERSE )*/ standend (); - - /* Calculate position for the next item */ - x += itemLength + MENU_SPACING; - if( menuType & MENU_BUTTON ) x += 2; - if( x > COLUMNS - lmargin - 12 ) - { - x = lmargin; - y ++ ; - } - } - - /* Print the description of selected item */ - mcd = _(menuItems[current].desc); - mvaddstr( WARNING_START + 1, (COLUMNS - strlen( mcd )) / 2, mcd ); - return y; + cf->menu = m; + return cf->menu; } -/* This function takes a list of menu items, lets the user choose one * - * and returns the keyboard shortcut value of the selected menu item */ - -static int -menuSelect( int y, int x, struct MenuItem *menuItems, int itemLength, - char *available, int menuType, int menuDefault ) { - int i, ylast = y, key = 0, current = menuDefault; - - /* Make sure that the current is one of the available items */ - while( !strchr(available, menuItems[current].key) ) { - current ++ ; - if( !menuItems[current].key ) current = 0; - } - - keypad(stdscr, TRUE); - - /* Repeat until allowable choice has been made */ - while( !key ) { - /* Display the menu and read a command */ - ylast = menuUpdate( y, x, menuItems, itemLength, available, - menuType, current ); - refresh(); - key = getch(); - - if (key == ERR) - if (!isatty(STDIN_FILENO)) - exit(2); - - /* Clear out all prompts and such */ - clear_warning(); - for (i = y; i < ylast; i++) { - move(i, x); - clrtoeol(); - } - move( WARNING_START + 1, 0 ); - clrtoeol(); - - switch (key) { - case KEY_RIGHT: - case '\t': - /* Select next menu item */ - do { - current++; - if (!menuItems[current].key) - current = 0; - } while (!strchr(available, menuItems[current].key)); - key = 0; - break; - case KEY_LEFT: -#ifdef KEY_BTAB - case KEY_BTAB: /* Back tab */ -#endif - /* Select previous menu item */ - do { - current--; - if (current < 0) { - while (menuItems[current + 1].key) - current++; - } - } while (!strchr(available, menuItems[current].key)); - key = 0; - break; - case KEY_ENTER: - case '\n': - case '\r': - /* Enter equals the keyboard shortcut of current menu item */ - key = menuItems[current].key; - break; - } - /* Should all keys to be accepted? */ - if( key && (menuType & MENU_ACCEPT_OTHERS) ) break; - - /* Is pressed key among acceptable ones? */ - if( key && (strchr(available, tolower(key)) || strchr(available, key))) - break; - - /* The key has not been accepted so far -> let's reject it */ - if (key) { - key = 0; - putchar( BELL ); - print_warning(_("Illegal key")); - } - } - - keypad(stdscr, FALSE); - - /* Clear out prompts and such */ - clear_warning(); - for( i = y; i <= ylast; i ++ ) { - move( i, x ); - clrtoeol(); - } - move( WARNING_START + 1, 0 ); - clrtoeol(); - return key; -} +static int ui_init(struct cfdisk *cf) +{ + struct sigaction sa; -/* A function which displays "Press a key to continue" * - * and waits for a keypress. * - * Perhaps calling function menuSelect is a bit overkill but who cares? */ + DBG(FRONTEND, dbgprint("ui: init")); -static void -menuContinue(void) { - static struct MenuItem menuContinueBtn[]= - { - { 'c', "", N_("Press a key to continue") }, - { 0, NULL, NULL } - }; + /* setup SIGCHLD handler */ + sigemptyset(&sa.sa_mask); + sa.sa_flags = 0; + sa.sa_handler = die_on_signal; + sigaction(SIGINT, &sa, NULL); + sigaction(SIGTERM, &sa, NULL); - menuSelect(COMMAND_LINE_Y, COMMAND_LINE_X, - menuContinueBtn, 0, "c", MENU_ACCEPT_OTHERS, 0 ); -} + cf->ui_enabled = 1; + initscr(); -/* Function menuSelect takes way too many parameters * - * Luckily, most of time we can do with this function */ - -static int -menuSimple(struct MenuItem *menuItems, int menuDefault) { - int i, j, itemLength = 0; - char available[MENU_MAX_ITEMS]; - - for(i = 0; menuItems[i].key; i++) - { - j = strlen( _(menuItems[i].name) ); - if( j > itemLength ) itemLength = j; - available[i] = menuItems[i].key; - } - available[i] = 0; - return menuSelect(COMMAND_LINE_Y, COMMAND_LINE_X, menuItems, itemLength, - available, MENU_BUTTON, menuDefault); -} + cbreak(); + noecho(); + nonl(); + curs_set(0); + keypad(stdscr, TRUE); -/* End of command menu support code */ - -static void -new_part(int i) { - char response[LINE_LENGTH], def[LINE_LENGTH]; - char c; - long long first = p_info[i].first_sector; - long long last = p_info[i].last_sector; - long long offset = 0; - int flags = 0; - int id = LINUX; - int num = -1; - long long num_sects = last - first + 1; - int len, ext, j; - char *errmsg; - double sectors_per_MB = K*K / 512.0; - - if (p_info[i].num == PRI_OR_LOG) { - static struct MenuItem menuPartType[]= - { - { 'p', N_("Primary"), N_("Create a new primary partition") }, - { 'l', N_("Logical"), N_("Create a new logical partition") }, - { ESC, N_("Cancel"), N_("Don't create a partition") }, - { 0, NULL, NULL } - }; - - c = menuSimple( menuPartType, 0 ); - if (toupper(c) == 'P') - num = find_primary(); - else if (toupper(c) == 'L') - num = find_logical(i); - else - return; - } else if (p_info[i].num == PRIMARY) - num = find_primary(); - else if (p_info[i].num == LOGICAL) - num = find_logical(i); - else - print_warning(_("!!! Internal error !!!")); - - snprintf(def, sizeof(def), "%.2f", num_sects/sectors_per_MB); - mvaddstr(COMMAND_LINE_Y, COMMAND_LINE_X, _("Size (in MB): ")); - if ((len = get_string(response, LINE_LENGTH, def)) <= 0 && - len != GS_DEFAULT) - return; - else if (len > 0) { -#define num_cyls(bytes) (round_int(bytes/SECTOR_SIZE/cylinder_size)) - for (j = 0; - j < len-1 && (isdigit(response[j]) || response[j] == '.'); - j++); - if (toupper(response[j]) == 'K') { - num_sects = num_cyls(atof(response)*K)*cylinder_size; - } else if (toupper(response[j]) == 'M') { - num_sects = num_cyls(atof(response)*K*K)*cylinder_size; - } else if (toupper(response[j]) == 'G') { - num_sects = num_cyls(atof(response)*K*K*K)*cylinder_size; - } else if (toupper(response[j]) == 'C') { - num_sects = round_int(atof(response))*cylinder_size; - } else if (toupper(response[j]) == 'S') { - num_sects = round_int(atof(response)); - } else { - num_sects = num_cyls(atof(response)*K*K)*cylinder_size; - } - } - - if (num_sects <= 0 || - num_sects > p_info[i].last_sector - p_info[i].first_sector + 1) - return; - - move( COMMAND_LINE_Y, COMMAND_LINE_X ); clrtoeol(); - if (num_sects < p_info[i].last_sector - p_info[i].first_sector + 1) { - /* Determine where inside free space to put partition. - */ - static struct MenuItem menuPlace[]= - { - { 'b', N_("Beginning"), N_("Add partition at beginning of free space") }, - { 'e', N_("End"), N_("Add partition at end of free space") }, - { ESC, N_("Cancel"), N_("Don't create a partition") }, - { 0, NULL, NULL } - }; - c = menuSimple( menuPlace, 0 ); - if (toupper(c) == 'B') - last = first + num_sects - 1; - else if (toupper(c) == 'E') - first = last - num_sects + 1; - else - return; - } - - if (IS_LOGICAL(num) && !is_extended(ext_info.id)) { - /* We want to add a logical partition, but need to create an - * extended partition first. - */ - if ((ext = find_primary()) < 0) { - print_warning(_("No room to create the extended partition")); - return; - } - errmsg = 0; - if (add_part(ext, DOS_EXTENDED, 0, first, last, - (first == 0 ? sectors : 0), 0, &errmsg) && errmsg) - print_warning(errmsg); - first = ext_info.first_sector + ext_info.offset; - } - - /* increment number of all partitions past this one */ - if (IS_LOGICAL(num)) { -#if 0 - /* original text - ok, but fails when partitions not in disk order */ - for (j = i; j < num_parts; j++) - if (p_info[j].id > 0 && IS_LOGICAL(p_info[j].num)) - p_info[j].num++; -#else - /* always ok */ - for (j = 0; j < num_parts; j++) - if (p_info[j].id > 0 && p_info[j].num >= num) - p_info[j].num++; -#endif - } - - /* Now we have a complete partition to ourselves */ - if (first == 0 || IS_LOGICAL(num)) - offset = sectors; - - errmsg = 0; - if (add_part(num, id, flags, first, last, offset, 0, &errmsg) && errmsg) - print_warning(errmsg); + return 0; } -static void -get_kernel_geometry(void) { -#ifdef HDIO_GETGEO - struct hd_geometry geometry; +static size_t menuitem_get_line(struct cfdisk *cf, size_t idx) +{ + size_t len = cf->menu->width + 4 + MENU_PADDING; /* item width */ + size_t items = COLS / len; /* items per line */ - if (!ioctl(fd, HDIO_GETGEO, &geometry)) { - kern_heads = geometry.heads; - kern_sectors = geometry.sectors; - } -#endif + return MENU_START_LINE + ((idx / items)); } -static int -said_yes(char answer) { - char reply[2]; +static int menuitem_get_column(struct cfdisk *cf, size_t idx) +{ + size_t len = cf->menu->width + 4 + MENU_PADDING; /* item width */ + size_t items = COLS / len; /* items per line */ + size_t extra = items < cf->menu->nitems ? /* extra space on line */ + COLS % len : /* - multi-line menu */ + COLS - (cf->menu->nitems * len); /* - one line menu */ - reply[0] = answer; - reply[1] = 0; + extra += MENU_PADDING; /* add padding after last item to extra */ - return (rpmatch(reply) == 1) ? 1 : 0; + if (idx < items) + return (idx * len) + (extra / 2); + return ((idx % items) * len) + (extra / 2); } -static void -get_partition_table_geometry(partition_table *bufp) { - struct partition *p; - int i,h,s,hh,ss; - int first = TRUE; - int bad = FALSE; - - for (i=0; i<66; i++) - if (bufp->c.b[446+i]) - goto nonz; - - /* zero table */ - if (!curses_started) { - fatal(_("No partition table.\n"), 3); - return; - } else { - mvaddstr(WARNING_START, 0, - _("No partition table. Starting with zero table.")); - putchar(BELL); - refresh(); - zero_table = TRUE; - return; - } - nonz: - if (bufp->p.magicflag[0] != PART_TABLE_FLAG0 || - bufp->p.magicflag[1] != PART_TABLE_FLAG1) { - if (!curses_started) - fatal(_("Bad signature on partition table"), 3); - - /* Matthew Wilcox */ - mvaddstr(WARNING_START, 0, - _("Unknown partition table type")); - mvaddstr(WARNING_START+1, 0, - _("Do you wish to start with a zero table [y/N] ?")); - putchar(BELL); - refresh(); - { - int cont = getch(); - if (cont == EOF || !said_yes(cont)) - die_x(3); - } - zero_table = TRUE; - return; - } - - hh = ss = 0; - for (i=0; i<4; i++) { - p = &(bufp->p.part[i]); - if (p->sys_ind != 0) { - h = p->end_head + 1; - s = (p->end_sector & 077); - if (first) { - hh = h; - ss = s; - first = FALSE; - } else if (hh != h || ss != s) - bad = TRUE; - } - } +static struct cfdisk_menudesc *menu_get_menuitem(struct cfdisk *cf, size_t idx) +{ + struct cfdisk_menudesc *d; + size_t i; - if (!first && !bad) { - pt_heads = hh; - pt_sectors = ss; + for (i = 0, d = cf->menu->desc; d->name; d++) { + if (cf->menu->ignore && strchr(cf->menu->ignore, d->key)) + continue; + if (i++ == idx) + return d; } -} -static void -decide_on_geometry(void) { - heads = (user_heads ? user_heads : - pt_heads ? pt_heads : - kern_heads ? kern_heads : 255); - sectors = (user_sectors ? user_sectors : - pt_sectors ? pt_sectors : - kern_sectors ? kern_sectors : 63); - cylinder_size = heads*sectors; - cylinders = actual_size/cylinder_size; - if (user_cylinders > 0) - cylinders = user_cylinders; - - if (cylinder_size * cylinders > actual_size) - print_warning(_("You specified more cylinders than fit on disk")); + return NULL; } -static void -clear_p_info(void) { - num_parts = 1; - p_info[0].first_sector = 0; - p_info[0].last_sector = actual_size - 1; - p_info[0].offset = 0; - p_info[0].flags = 0; - p_info[0].id = FREE_SPACE; - p_info[0].num = PRI_OR_LOG; - - ext_info.first_sector = 0; - ext_info.last_sector = 0; - ext_info.offset = 0; - ext_info.flags = 0; - ext_info.id = FREE_SPACE; - ext_info.num = PRIMARY; +static void ui_draw_menuitem(struct cfdisk *cf, + struct cfdisk_menudesc *d, + size_t idx) +{ + char buf[80 * MB_CUR_MAX]; + const char *name; + size_t width = cf->menu->width + 2; /* 2 = blank around string */ + int ln, cl; + + name = _(d->name); + mbsalign(name, buf, sizeof(buf), &width, MBS_ALIGN_CENTER, 0); + + ln = menuitem_get_line(cf, idx); + cl = menuitem_get_column(cf, idx); + + DBG(FRONTEND, dbgprint("ui: menuitem: cl=%d, ln=%d, item='%s'", + cl, ln, buf)); + + if (cf->menu_idx == idx) { + standout(); + mvprintw(ln, cl, "[%s]", buf); + standend(); + if (d->desc) + ui_print_center(LINES - 1, d->desc); + } else + mvprintw(ln, cl, "[%s]", buf); } -static void -fill_p_info(void) { - int pn, i; - long long bs, bsz; - unsigned long long llsectors; - struct partition *p; - partition_table buffer; - partition_info tmp_ext; - - memset(&tmp_ext, 0, sizeof tmp_ext); - tmp_ext.id = FREE_SPACE; - tmp_ext.num = PRIMARY; - - if ((fd = open(disk_device, O_RDWR)) < 0) { - if ((fd = open(disk_device, O_RDONLY)) < 0) - fatal(_("Cannot open disk drive"), 2); - opentype = O_RDONLY; - print_warning(_("Opened disk read-only - you have no permission to write")); - if (curses_started) { - refresh(); - getch(); - clear_warning(); - } - } else - opentype = O_RDWR; - opened = TRUE; - -#ifdef BLKFLSBUF - /* Blocks are visible in more than one way: - e.g. as block on /dev/hda and as block on /dev/hda3 - By a bug in the Linux buffer cache, we will see the old - contents of /dev/hda when the change was made to /dev/hda3. - In order to avoid this, discard all blocks on /dev/hda. - Note that partition table blocks do not live in /dev/hdaN, - so this only plays a role if we want to show volume labels. */ - ioctl(fd, BLKFLSBUF); /* ignore errors */ - /* e.g. Permission Denied */ -#endif - - if (blkdev_get_sectors(fd, &llsectors) == -1) - fatal(_("Cannot get disk size"), 3); - actual_size = llsectors; - - read_sector(buffer.c.b, 0); - - get_kernel_geometry(); - - if (!zero_table || use_partition_table_geometry) - get_partition_table_geometry(& buffer); - - decide_on_geometry(); - - clear_p_info(); - - if (!zero_table) { - char *errmsg = ""; +static void ui_draw_menu(struct cfdisk *cf) +{ + struct cfdisk_menudesc *d; + size_t i = 0; - for (i = 0; i < 4; i++) { - p = & buffer.p.part[i]; - bs = get_start_sect(p); - bsz = get_nr_sects(p); + assert(cf); + assert(cf->menu); - if (p->sys_ind > 0 && - add_part(i, p->sys_ind, p->boot_ind, - ((bs <= sectors) ? 0 : bs), bs + bsz - 1, - ((bs <= sectors) ? bs : 0), 1, &errmsg)) { - char *bad = _("Bad primary partition"); - char *msg = (char *) xmalloc(strlen(bad) + strlen(errmsg) + 30); - sprintf(msg, "%s %d: %s", bad, i + 1, errmsg); - fatal(msg, 4); - } - if (is_extended(buffer.p.part[i].sys_ind)) - tmp_ext = ext_info; - } + DBG(FRONTEND, dbgprint("ui: menu: draw start")); - if (is_extended(tmp_ext.id)) { - ext_info = tmp_ext; - logical_sectors[logical] = - ext_info.first_sector + ext_info.offset; - read_sector(buffer.c.b, logical_sectors[logical++]); - i = 4; - do { - for (pn = 0; - pn < 4 && (!buffer.p.part[pn].sys_ind || - is_extended(buffer.p.part[pn].sys_ind)); - pn++); - - if (pn < 4) { - p = & buffer.p.part[pn]; - bs = get_start_sect(p); - bsz = get_nr_sects(p); - - if (add_part(i++, p->sys_ind, p->boot_ind, - logical_sectors[logical-1], - logical_sectors[logical-1] + bs + bsz - 1, - bs, 1, &errmsg)) { - char *bad = _("Bad logical partition"); - char *msg = (char *) xmalloc(strlen(bad) + strlen(errmsg) + 30); - sprintf(msg, "%s %d: %s", bad, i, errmsg); - fatal(msg, 4); - } - } + menu_update_ignore(cf); - for (pn = 0; - pn < 4 && !is_extended(buffer.p.part[pn].sys_ind); - pn++); - if (pn < 4) { - p = & buffer.p.part[pn]; - bs = get_start_sect(p); - logical_sectors[logical] = ext_info.first_sector - + ext_info.offset + bs; - read_sector(buffer.c.b, logical_sectors[logical++]); - } - } while (pn < 4 && logical < MAXIMUM_PARTS-4); - } - } -} + while ((d = menu_get_menuitem(cf, i))) + ui_draw_menuitem(cf, d, i++); -static void -fill_part_table(struct partition *p, partition_info *pi) { - long long begin; - - p->boot_ind = pi->flags; - p->sys_ind = pi->id; - begin = pi->first_sector + pi->offset; - if (IS_LOGICAL(pi->num)) - set_start_sect(p,pi->offset); - else - set_start_sect(p,begin); - set_nr_sects(p, pi->last_sector - begin + 1); - set_hsc_begin(p, begin); - set_hsc_end(p, pi->last_sector); + DBG(FRONTEND, dbgprint("ui: menu: draw end.")); } -static void -fill_primary_table(partition_table *buffer) { - int i; - - /* Zero out existing table */ - for (i = 0x1BE; i < SECTOR_SIZE; i++) - buffer->c.b[i] = 0; - - for (i = 0; i < num_parts; i++) - if (IS_PRIMARY(p_info[i].num)) - fill_part_table(&(buffer->p.part[p_info[i].num]), &(p_info[i])); +static void ui_menu_goto(struct cfdisk *cf, int where) +{ + struct cfdisk_menudesc *d; + size_t old; + + if (where < 0) + where = cf->menu->nitems - 1; + else if ((size_t) where > cf->menu->nitems - 1) + where = 0; + if ((size_t) where == cf->menu_idx) + return; - if (is_extended(ext_info.id)) - fill_part_table(&(buffer->p.part[ext_info.num]), &ext_info); + old = cf->menu_idx; + cf->menu_idx = where; - buffer->p.magicflag[0] = PART_TABLE_FLAG0; - buffer->p.magicflag[1] = PART_TABLE_FLAG1; -} + d = menu_get_menuitem(cf, old); + ui_draw_menuitem(cf, d, old); -static void -fill_logical_table(partition_table *buffer, partition_info *pi) { - struct partition *p; - int i; - - for (i = 0; i < logical && pi->first_sector != logical_sectors[i]; i++); - if (i == logical || buffer->p.magicflag[0] != PART_TABLE_FLAG0 - || buffer->p.magicflag[1] != PART_TABLE_FLAG1) - for (i = 0; i < SECTOR_SIZE; i++) - buffer->c.b[i] = 0; - - /* Zero out existing table */ - for (i = 0x1BE; i < SECTOR_SIZE; i++) - buffer->c.b[i] = 0; - - fill_part_table(&(buffer->p.part[0]), pi); - - for (i = 0; - i < num_parts && pi->num != p_info[i].num - 1; - i++); - - if (i < num_parts) { - p = &(buffer->p.part[1]); - pi = &(p_info[i]); - - p->boot_ind = 0; - p->sys_ind = DOS_EXTENDED; - set_start_sect(p, pi->first_sector - ext_info.first_sector - ext_info.offset); - set_nr_sects(p, pi->last_sector - pi->first_sector + 1); - set_hsc_begin(p, pi->first_sector); - set_hsc_end(p, pi->last_sector); - } - - buffer->p.magicflag[0] = PART_TABLE_FLAG0; - buffer->p.magicflag[1] = PART_TABLE_FLAG1; + d = menu_get_menuitem(cf, where); + ui_draw_menuitem(cf, d, where); } -static void -write_part_table(void) { - int i, ct, done = FALSE, len; - partition_table buffer; - struct stat s; - int is_bdev; - char response[LINE_LENGTH]; - - if (opentype == O_RDONLY) { - print_warning(_("Opened disk read-only - you have no permission to write")); - refresh(); - getch(); - clear_warning(); - return; - } - - is_bdev = 0; - if(fstat(fd, &s) == 0 && S_ISBLK(s.st_mode)) - is_bdev = 1; - - if (is_bdev) { - print_warning(_("Warning!! This may destroy data on your disk!")); - - while (!done) { - mvaddstr(COMMAND_LINE_Y, COMMAND_LINE_X, - _("Are you sure you want to write the partition table " - "to disk? (yes or no): ")); - len = get_string(response, LINE_LENGTH, NULL); - clear_warning(); - if (len == GS_ESCAPE) - return; - else if (strcasecmp(response, _("no")) == 0 || - strcasecmp(response, "no") == 0) { - print_warning(_("Did not write partition table to disk")); - return; - } else if (strcasecmp(response, _("yes")) == 0 || - strcasecmp(response, "yes") == 0) - done = TRUE; - else - print_warning(_("Please enter `yes' or `no'")); - } - - clear_warning(); - print_warning(_("Writing partition table to disk...")); - refresh(); - } - - read_sector(buffer.c.b, 0); - fill_primary_table(&buffer); - write_sector(buffer.c.b, 0); - - for (i = 0; i < num_parts; i++) - if (IS_LOGICAL(p_info[i].num)) { - read_sector(buffer.c.b, p_info[i].first_sector); - fill_logical_table(&buffer, &(p_info[i])); - write_sector(buffer.c.b, p_info[i].first_sector); - } - - if (is_bdev) { -#ifdef BLKRRPART - sync(); - if (!ioctl(fd,BLKRRPART)) - changed = TRUE; -#endif - sync(); - - clear_warning(); - if (changed) - print_warning(_("Wrote partition table to disk")); - else - print_warning(_("Wrote partition table, but re-read table failed. Run partprobe(8), kpartx(8) or reboot to update table.")); - } else - print_warning(_("Wrote partition table to disk")); - - /* Check: unique bootable primary partition? */ - ct = 0; - for (i = 0; i < num_parts; i++) - if (IS_PRIMARY(i) && p_info[i].flags == ACTIVE_FLAG) - ct++; - if (ct == 0) - print_warning(_("No primary partitions are marked bootable. DOS MBR cannot boot this.")); - if (ct > 1) - print_warning(_("More than one primary partition is marked bootable. DOS MBR cannot boot this.")); +static int ui_menu_action(struct cfdisk *cf, int key) +{ + return 0; } -static void -fp_printf(FILE *fp, char *format, ...) { - va_list args; - char buf[1024]; - int y, x __attribute__((unused)); - - va_start(args, format); - vsnprintf(buf, sizeof(buf), format, args); - va_end(args); - - if (fp == NULL) { - /* The following works best if the string to be printed has at - most only one newline. */ - printw("%s", buf); - getyx(stdscr, y, x); - if (y >= COMMAND_LINE_Y-2) { - menuContinue(); - erase(); - move(0, 0); - } - } else - fprintf(fp, "%s", buf); -} +static void ui_draw_partition(struct cfdisk *cf, size_t i) +{ + int ln = TABLE_START_LINE + 1 + i; /* skip table header */ + int cl = ARROW_CURSOR_WIDTH; /* we need extra space for cursor */ -#define MAX_PER_LINE 16 -static void -print_file_buffer(FILE *fp, unsigned char *buffer) { - int i,l; - - for (i = 0, l = 0; i < SECTOR_SIZE; i++, l++) { - if (l == 0) - fp_printf(fp, "0x%03X:", i); - fp_printf(fp, " %02X", buffer[i]); - if (l == MAX_PER_LINE - 1) { - fp_printf(fp, "\n"); - l = -1; - } - } - if (l > 0) - fp_printf(fp, "\n"); - fp_printf(fp, "\n"); -} + DBG(FRONTEND, dbgprint("ui: draw partition %zu", i)); -static void -print_raw_table(void) { - int i, to_file; - partition_table buffer; - char fname[LINE_LENGTH]; - FILE *fp; - - if (print_only) { - fp = stdout; - to_file = TRUE; - } else { - mvaddstr(COMMAND_LINE_Y, COMMAND_LINE_X, - _("Enter filename or press RETURN to display on screen: ")); - - if ((to_file = get_string(fname, LINE_LENGTH, NULL)) < 0) - return; - - if (to_file) { - if ((fp = fopen(fname, "w")) == NULL) { - char errstr[LINE_LENGTH]; - snprintf(errstr, sizeof(errstr), - _("cannot open %s"), fname); - print_warning(errstr); - return; - } + if (cf->lines_idx == i) { + standout(); + mvaddstr(ln, 0, ARROW_CURSOR_STRING); + mvaddstr(ln, cl, cf->lines[i + 1]); + standend(); } else { - fp = NULL; - erase(); - move(0, 0); - } - } - - fp_printf(fp, _("Disk Drive: %s\n"), disk_device); - - fp_printf(fp, _("Sector 0:\n")); - read_sector(buffer.c.b, 0); - fill_primary_table(&buffer); - print_file_buffer(fp, buffer.c.b); - - for (i = 0; i < num_parts; i++) - if (IS_LOGICAL(p_info[i].num)) { - fp_printf(fp, _("Sector %d:\n"), p_info[i].first_sector); - read_sector(buffer.c.b, p_info[i].first_sector); - fill_logical_table(&buffer, &(p_info[i])); - print_file_buffer(fp, buffer.c.b); + mvaddstr(ln, 0, ARROW_CURSOR_DUMMY); + mvaddstr(ln, cl, cf->lines[i + 1]); } - if (to_file) { - if (!print_only) - if (close_stream(fp) != 0) { - char errstr[LINE_LENGTH]; - snprintf(errstr, sizeof(errstr), _("write failed: %s"), fname); - print_warning(errstr); - } - } else { - menuContinue(); - } -} - -static void -print_p_info_entry(FILE *fp, partition_info *p) { - long long size; - char part_str[40]; - - if (p->id == UNUSABLE) - fp_printf(fp, _(" None ")); - else if (p->id == FREE_SPACE && p->num == PRI_OR_LOG) - fp_printf(fp, _(" Pri/Log")); - else if (p->id == FREE_SPACE && p->num == PRIMARY) - fp_printf(fp, _(" Primary")); - else if (p->id == FREE_SPACE && p->num == LOGICAL) - fp_printf(fp, _(" Logical")); - else - fp_printf(fp, "%2d %-7.7s", p->num+1, - IS_LOGICAL(p->num) ? _("Logical") : _("Primary")); - - fp_printf(fp, " "); - - fp_printf(fp, "%11lld%c", p->first_sector, - ((p->first_sector/cylinder_size) != - ((float)p->first_sector/cylinder_size) ? - '*' : ' ')); - - fp_printf(fp, "%11lld%c", p->last_sector, - (((p->last_sector+1)/cylinder_size) != - ((float)(p->last_sector+1)/cylinder_size) ? - '*' : ' ')); - - fp_printf(fp, "%6ld%c", p->offset, - ((((p->first_sector == 0 || IS_LOGICAL(p->num)) && - (p->offset != sectors)) || - (p->first_sector != 0 && IS_PRIMARY(p->num) && - p->offset != 0)) ? - '#' : ' ')); - - size = p->last_sector - p->first_sector + 1; - fp_printf(fp, "%11lld%c", size, - ((size/cylinder_size) != ((float)size/cylinder_size) ? - '*' : ' ')); - - /* fp_printf(fp, " "); */ - - if (p->id == UNUSABLE) - sprintf(part_str, "%.15s", _("Unusable")); - else if (p->id == FREE_SPACE) - sprintf(part_str, "%.15s", _("Free Space")); - else if (partition_type_name(p->id)) - sprintf(part_str, "%.15s (%02X)", _(partition_type_name(p->id)), p->id); - else - sprintf(part_str, "%.15s (%02X)", _("Unknown"), p->id); - fp_printf(fp, "%-20.20s", part_str); - - fp_printf(fp, " "); - - if (p->flags == ACTIVE_FLAG) - fp_printf(fp, _("Boot"), p->flags); - else if (p->flags != 0) - fp_printf(fp, _("(%02X)"), p->flags); - else - fp_printf(fp, _("None"), p->flags); - - fp_printf(fp, "\n"); -} - -static void -print_p_info(void) { - char fname[LINE_LENGTH]; - FILE *fp; - int i, to_file, pext = is_extended(ext_info.id); - - if (print_only) { - fp = stdout; - to_file = TRUE; - } else { - mvaddstr(COMMAND_LINE_Y, COMMAND_LINE_X, - _("Enter filename or press RETURN to display on screen: ")); - - if ((to_file = get_string(fname, LINE_LENGTH, NULL)) < 0) - return; - - if (to_file) { - if ((fp = fopen(fname, "w")) == NULL) { - char errstr[LINE_LENGTH]; - snprintf(errstr, LINE_LENGTH, _("cannot open %s"), fname); - print_warning(errstr); - return; - } - } else { - fp = NULL; - erase(); - move(0, 0); - } - } - - fp_printf(fp, _("Partition Table for %s\n"), disk_device); - fp_printf(fp, "\n"); - fp_printf(fp, _(" First Last\n")); - fp_printf(fp, _(" # Type Sector Sector Offset Length Filesystem Type (ID) Flag\n")); - fp_printf(fp, _("-- ------- ----------- ----------- ------ ----------- -------------------- ----\n")); - - for (i = 0; i < num_parts; i++) { - if (pext && (p_info[i].first_sector >= ext_info.first_sector)) { - print_p_info_entry(fp,&ext_info); - pext = FALSE; - } - print_p_info_entry(fp, &(p_info[i])); - } - - if (to_file) { - if (!print_only) - if (close_stream(fp) != 0) { - char errstr[LINE_LENGTH]; - snprintf(errstr, sizeof(errstr), _("write failed: %s"), fname); - print_warning(errstr); - } - } else { - menuContinue(); - } } -static void -print_part_entry(FILE *fp, int num, partition_info *pi) { - long long first = 0, start = 0, end = 0, size = 0; - unsigned char ss, es, sh, eh; - int sc, ec; - int flags = 0, id = 0; - - ss = sh = es = eh = 0; - sc = ec = 0; +static int ui_draw_table(struct cfdisk *cf) +{ + int cl = ARROW_CURSOR_WIDTH; + size_t i, nparts = fdisk_table_get_nents(cf->table); - if (pi != NULL) { - flags = pi->flags; - id = pi->id; + DBG(FRONTEND, dbgprint("ui: draw table")); - if (IS_LOGICAL(num)) - first = pi->offset; - else - first = pi->first_sector + pi->offset; + if (cf->nlines - 2 < cf->lines_idx) + cf->lines_idx = cf->nlines - 2; /* don't count header */ - start = pi->first_sector + pi->offset; - end = pi->last_sector; - size = end - start + 1; + /* print header */ + attron(A_BOLD); + mvaddstr(TABLE_START_LINE, cl, cf->lines[0]); + attroff(A_BOLD); - set_hsc0(&sh, &ss, &sc, start); - set_hsc0(&eh, &es, &ec, end); - } + /* print partitions */ + for (i = 0; i < nparts; i++) + ui_draw_partition(cf, i); - fp_printf(fp, "%2d 0x%02X %4d %4d %5d 0x%02X %4d %4d %5d %11lld %11lld\n", - num+1, flags, sh, ss, sc, id, eh, es, ec, first, size); + return 0; } +static int ui_table_goto(struct cfdisk *cf, int where) +{ + size_t old; + size_t nparts = fdisk_table_get_nents(cf->table); -static void -print_part_table(void) { - int i, j, to_file; - char fname[LINE_LENGTH]; - FILE *fp; + DBG(FRONTEND, dbgprint("ui: goto table %d", where)); - if (print_only) { - fp = stdout; - to_file = TRUE; - } else { - mvaddstr(COMMAND_LINE_Y, COMMAND_LINE_X, - _("Enter filename or press RETURN to display on screen: ")); + if (where < 0) + where = 0; + else if ((size_t) where > nparts - 1) + where = nparts - 1; - if ((to_file = get_string(fname, LINE_LENGTH, NULL)) < 0) - return; + if ((size_t) where == cf->lines_idx) + return 0; - if (to_file) { - if ((fp = fopen(fname, "w")) == NULL) { - char errstr[LINE_LENGTH]; - snprintf(errstr, LINE_LENGTH, _("cannot open %s"), fname); - print_warning(errstr); - return; - } - } else { - fp = NULL; - erase(); - move(0, 0); - } - } - - fp_printf(fp, _("Partition Table for %s\n"), disk_device); - fp_printf(fp, "\n"); - /* Three-line heading. Read "Start Sector" etc vertically. */ - fp_printf(fp, _(" ---Starting---- ----Ending----- Start Number of\n")); - fp_printf(fp, _(" # Flags Head Sect Cyl ID Head Sect Cyl Sector Sectors\n")); - fp_printf(fp, _("-- ----- ---- ---- ----- ---- ---- ---- ----- ----------- -----------\n")); - - for (i = 0; i < 4; i++) { - for (j = 0; - j < num_parts && (p_info[j].id <= 0 || p_info[j].num != i); - j++); - if (j < num_parts) { - print_part_entry(fp, i, &(p_info[j])); - } else if (is_extended(ext_info.id) && ext_info.num == i) { - print_part_entry(fp, i, &ext_info); - } else { - print_part_entry(fp, i, NULL); - } - } - - for (i = 0; i < num_parts; i++) - if (IS_LOGICAL(p_info[i].num)) - print_part_entry(fp, p_info[i].num, &(p_info[i])); - - if (to_file) { - if (!print_only) - if (close_stream(fp) != 0) { - char errstr[LINE_LENGTH]; - snprintf(errstr, sizeof(errstr), _("write failed: %s"), fname); - print_warning(errstr); - } - } else { - menuContinue(); - } -} + old = cf->lines_idx; + cf->lines_idx = where; -static void -print_tables(void) { - int done = FALSE; - - static struct MenuItem menuFormat[]= - { - { 'r', N_("Raw"), N_("Print the table using raw data format") }, - { 's', N_("Sectors"), N_("Print the table ordered by sectors") }, - { 't', N_("Table"), N_("Just print the partition table") }, - { ESC, N_("Cancel"), N_("Don't print the table") }, - { 0, NULL, NULL } - }; - - while (!done) - switch ( toupper(menuSimple( menuFormat, 2)) ) { - case 'R': - print_raw_table(); - done = TRUE; - break; - case 'S': - print_p_info(); - done = TRUE; - break; - case 'T': - print_part_table(); - done = TRUE; - break; - case ESC: - done = TRUE; - break; - } + ui_draw_partition(cf, old); /* cleanup old */ + ui_draw_partition(cf, where); /* draw new */ + ui_draw_menu(cf); + refresh(); + return 0; } -#define END_OF_HELP "EOHS!" -static void -display_help(void) { - char *help_text[] = { - N_("Help Screen for cfdisk"), - "", - N_("This is cfdisk, a curses based disk partitioning program, which"), - N_("allows you to create, delete and modify partitions on your hard"), - N_("disk drive."), - "", - N_("Copyright (C) 1994-1999 Kevin E. Martin & aeb"), - "", - N_("Command Meaning"), - N_("------- -------"), - N_(" b Toggle bootable flag of the current partition"), - N_(" d Delete the current partition"), - N_(" g Change cylinders, heads, sectors-per-track parameters"), - N_(" WARNING: This option should only be used by people who"), - N_(" know what they are doing."), - N_(" h Print this screen"), - N_(" m Maximize disk usage of the current partition"), - N_(" Note: This may make the partition incompatible with"), - N_(" DOS, OS/2, ..."), - N_(" n Create new partition from free space"), - N_(" p Print partition table to the screen or to a file"), - N_(" There are several different formats for the partition"), - N_(" that you can choose from:"), - N_(" r - Raw data (exactly what would be written to disk)"), - N_(" s - Table ordered by sectors"), - N_(" t - Table in raw format"), - N_(" q Quit program without writing partition table"), - N_(" t Change the filesystem type"), - N_(" u Change units of the partition size display"), - N_(" Rotates through MB, sectors and cylinders"), - N_(" W Write partition table to disk (must enter upper case W)"), - N_(" Since this might destroy data on the disk, you must"), - N_(" either confirm or deny the write by entering `yes' or"), - N_(" `no'"), - N_("Up Arrow Move cursor to the previous partition"), - N_("Down Arrow Move cursor to the next partition"), - N_("CTRL-L Redraws the screen"), - N_(" ? Print this screen"), - "", - N_("Note: All of the commands can be entered with either upper or lower"), - N_("case letters (except for Writes)."), - END_OF_HELP - }; - - int cur_line = 0; - FILE *fp = NULL; - - erase(); - move(0, 0); - while (strcmp(help_text[cur_line], END_OF_HELP)) { - if (help_text[cur_line][0]) - fp_printf(fp, "%s\n", _(help_text[cur_line])); +static int ui_refresh(struct cfdisk *cf) +{ + char *id = NULL; + uint64_t bytes = cf->cxt->total_sectors * cf->cxt->sector_size; + char *strsz = size_to_human_string(SIZE_SUFFIX_SPACE + | SIZE_SUFFIX_3LETTER, bytes); + erase(); + + if (!cf->ui_enabled) + return -EINVAL; + + /* header */ + attron(A_BOLD); + ui_print_center(0, _("Disk: %s"), cf->cxt->dev_path); + attroff(A_BOLD); + ui_print_center(1, _("Size: %s, %ju bytes, %ju sectors"), + strsz, bytes, (uintmax_t) cf->cxt->total_sectors); + if (fdisk_get_disklabel_id(cf->cxt, &id) == 0 && id) + ui_print_center(2, _("Label: %s, identifier: %s"), + cf->cxt->label->name, id); else - fp_printf(fp, "\n"); - cur_line++; - } - menuContinue(); -} + ui_print_center(2, _("Label: %s")); + free(strsz); -static int -change_geometry(void) { - int ret_val = FALSE; - int done = FALSE; - char def[LINE_LENGTH]; - char response[LINE_LENGTH]; - long long tmp_val; - int i; - - while (!done) { - static struct MenuItem menuGeometry[]= - { - { 'c', N_("Cylinders"), N_("Change cylinder geometry") }, - { 'h', N_("Heads"), N_("Change head geometry") }, - { 's', N_("Sectors"), N_("Change sector geometry") }, - { 'd', N_("Done"), N_("Done with changing geometry") }, - { 0, NULL, NULL } - }; - move(COMMAND_LINE_Y, COMMAND_LINE_X); - clrtoeol(); + ui_draw_table(cf); + ui_draw_menu(cf); refresh(); - - clear_warning(); - - switch (toupper( menuSimple(menuGeometry, 3) )) { - case 'C': - sprintf(def, "%llu", actual_size/cylinder_size); - mvaddstr(COMMAND_LINE_Y, COMMAND_LINE_X, - _("Enter the number of cylinders: ")); - i = get_string(response, LINE_LENGTH, def); - if (i == GS_DEFAULT) { - user_cylinders = actual_size/cylinder_size; - ret_val = TRUE; - } else if (i > 0) { - tmp_val = atoll(response); - if (tmp_val > 0) { - user_cylinders = tmp_val; - ret_val = TRUE; - } else - print_warning(_("Illegal cylinders value")); - } - break; - case 'H': - sprintf(def, "%d", heads); - mvaddstr(COMMAND_LINE_Y, COMMAND_LINE_X, - _("Enter the number of heads: ")); - if (get_string(response, LINE_LENGTH, def) > 0) { - tmp_val = atoll(response); - if (tmp_val > 0 && tmp_val <= MAX_HEADS) { - user_heads = tmp_val; - ret_val = TRUE; - } else - print_warning(_("Illegal heads value")); - } - break; - case 'S': - sprintf(def, "%d", sectors); - mvaddstr(COMMAND_LINE_Y, COMMAND_LINE_X, - _("Enter the number of sectors per track: ")); - if (get_string(response, LINE_LENGTH, def) > 0) { - tmp_val = atoll(response); - if (tmp_val > 0 && tmp_val <= MAX_SECTORS) { - user_sectors = tmp_val; - ret_val = TRUE; - } else - print_warning(_("Illegal sectors value")); - } - break; - case ESC: - case 'D': - done = TRUE; - break; - default: - putchar(BELL); - break; - } - - if (ret_val) { - decide_on_geometry(); - draw_screen(); - } - } - - if (ret_val) { - long long disk_end; - - disk_end = actual_size-1; - - if (p_info[num_parts-1].last_sector > disk_end) { - while (p_info[num_parts-1].first_sector > disk_end) { - if (p_info[num_parts-1].id == FREE_SPACE || - p_info[num_parts-1].id == UNUSABLE) - remove_part(num_parts-1); - else - del_part(num_parts-1); - } - - p_info[num_parts-1].last_sector = disk_end; - - if (ext_info.last_sector > disk_end) - ext_info.last_sector = disk_end; - } else if (p_info[num_parts-1].last_sector < disk_end) { - if (p_info[num_parts-1].id == FREE_SPACE || - p_info[num_parts-1].id == UNUSABLE) { - p_info[num_parts-1].last_sector = disk_end; - } else { - insert_empty_part(num_parts, - p_info[num_parts-1].last_sector+1, - disk_end); - } - } - - /* Make sure the partitions are correct */ - check_part_info(); - } - - return ret_val; -} - -static void -change_id(int i) { - char id[LINE_LENGTH], def[LINE_LENGTH]; - int num_types = 0; - int num_across, num_down; - int len, new_id = ((p_info[i].id == LINUX) ? LINUX_SWAP : LINUX); - int y_start, y_end, row, row_min, row_max, row_offset, j, needmore; - - for (j = 1; i386_sys_types[j].name; j++) ; - num_types = j-1; /* do not count the Empty type */ - - num_across = COLS/COL_ID_WIDTH; - num_down = (((float)num_types)/num_across + 1); - y_start = COMMAND_LINE_Y - 1 - num_down; - if (y_start < 1) { - y_start = 1; - y_end = COMMAND_LINE_Y - 2; - } else { - if (y_start > DISK_TABLE_START+cur_part+4) - y_start = DISK_TABLE_START+cur_part+4; - y_end = y_start + num_down - 1; - } - - row_min = 1; - row_max = COMMAND_LINE_Y - 2; - row_offset = 0; - do { - for (j = y_start - 1; j <= y_end + 1; j++) { - move(j, 0); - clrtoeol(); - } - needmore = 0; - for (j = 1; i386_sys_types[j].name; j++) { - row = y_start + (j-1) % num_down - row_offset; - if (row >= row_min && row <= row_max) { - move(row, ((j-1)/num_down)*COL_ID_WIDTH + 1); - printw("%02X %-20.20s", - i386_sys_types[j].type, - _(i386_sys_types[j].name)); - } - if (row > row_max) - needmore = 1; - } - if (needmore) - menuContinue(); - row_offset += (row_max - row_min + 1); - } while(needmore); - - sprintf(def, "%02X", new_id); - mvaddstr(COMMAND_LINE_Y, COMMAND_LINE_X, _("Enter filesystem type: ")); - if ((len = get_string(id, 3, def)) <= 0 && len != GS_DEFAULT) - return; - - if (len != GS_DEFAULT) { - if (!isxdigit(id[0])) - return; - new_id = (isdigit(id[0]) ? id[0] - '0' : tolower(id[0]) - 'a' + 10); - if (len == 2) { - if (isxdigit(id[1])) - new_id = new_id*16 + - (isdigit(id[1]) ? id[1] - '0' : tolower(id[1]) - 'a' + 10); - else - return; - } - } - - if (new_id == 0) - print_warning(_("Cannot change FS Type to empty")); - else if (is_extended(new_id)) - print_warning(_("Cannot change FS Type to extended")); - else - p_info[i].id = new_id; + return 0; } -static void -draw_partition(int i) { - int j; - int y = i + DISK_TABLE_START + 2 - (cur_part/NUM_ON_SCREEN)*NUM_ON_SCREEN; - char *t; - long long size; - double fsize; - - if (!arrow_cursor) { - move(y, 0); - for (j = 0; j < COLS; j++) - addch(' '); - } - - if (p_info[i].id > 0) { - char *dbn = my_basename(disk_device); - int l = strlen(dbn); - int digit_last = isdigit(dbn[l-1]); - - mvprintw(y, NAME_START, - "%s%s%d", dbn, (digit_last ? "p" : ""), - p_info[i].num+1); - if (p_info[i].flags) { - if (p_info[i].flags == ACTIVE_FLAG) - mvaddstr(y, FLAGS_START, _("Boot")); - else - mvprintw(y, FLAGS_START, _("Unk(%02X)"), p_info[i].flags); - if (p_info[i].first_sector == 0 || IS_LOGICAL(p_info[i].num)) { - if (p_info[i].offset != sectors) - addstr(_(", NC")); - } else { - if (p_info[i].offset != 0) - addstr(_(", NC")); - } - } else { - if (p_info[i].first_sector == 0 || IS_LOGICAL(p_info[i].num)) { - if (p_info[i].offset != sectors) - mvaddstr(y, FLAGS_START, _("NC")); - } else { - if (p_info[i].offset != 0) - mvaddstr(y, FLAGS_START, _("NC")); - } - } - } - mvaddstr(y, PTYPE_START, - (p_info[i].id == UNUSABLE ? "" : - (IS_LOGICAL(p_info[i].num) ? _("Logical") : - (p_info[i].num >= 0 ? _("Primary") : - (p_info[i].num == PRI_OR_LOG ? _("Pri/Log") : - (p_info[i].num == PRIMARY ? _("Primary") : _("Logical"))))))); - - t = partition_type_text(i); - if (t) - mvaddstr(y, FSTYPE_START, t); - else - mvprintw(y, FSTYPE_START, _("Unknown (%02X)"), p_info[i].id); - - if (p_info[i].volume_label[0]) { - int l = strlen(p_info[i].volume_label); - int s = SIZE_START-5-l; - mvprintw(y, (s > LABEL_START) ? LABEL_START : s, - " [%s] ", p_info[i].volume_label); - } - - size = p_info[i].last_sector - p_info[i].first_sector + 1; - fsize = (double) size * SECTOR_SIZE; - if (display_units == SECTORS) - mvprintw(y, SIZE_START, "%11lld", size); - else if (display_units == CYLINDERS) - mvprintw(y, SIZE_START, "%11lld", size/cylinder_size); - else if (display_units == MEGABYTES) - mvprintw(y, SIZE_START, "%11.2f", ceiling((100*fsize)/(K*K))/100); - else if (display_units == GIGABYTES) - mvprintw(y, SIZE_START, "%11.2f", ceiling((100*fsize)/(K*K*K))/100); - if (size % cylinder_size != 0 || - p_info[i].first_sector % cylinder_size != 0) - mvprintw(y, COLUMNS-1, "*"); -} +static int ui_run(struct cfdisk *cf) +{ + int rc; -static void -init_const(void) { - if (!defined) { - NAME_START = (((float)NAME_START)/COLUMNS)*COLS; - FLAGS_START = (((float)FLAGS_START)/COLUMNS)*COLS; - PTYPE_START = (((float)PTYPE_START)/COLUMNS)*COLS; - FSTYPE_START = (((float)FSTYPE_START)/COLUMNS)*COLS; - LABEL_START = (((float)LABEL_START)/COLUMNS)*COLS; - SIZE_START = (((float)SIZE_START)/COLUMNS)*COLS; - COMMAND_LINE_X = (((float)COMMAND_LINE_X)/COLUMNS)*COLS; - - COMMAND_LINE_Y = LINES - 4; - WARNING_START = LINES - 2; - - if ((NUM_ON_SCREEN = COMMAND_LINE_Y - DISK_TABLE_START - 3) <= 0) - NUM_ON_SCREEN = 1; - - COLUMNS = COLS; - defined = TRUE; - } -} + DBG(FRONTEND, dbgprint("ui: start COLS=%d, LINES=%d", COLS, LINES)); -static void -draw_screen(void) { - int i; - char *line; + menu_push(cf, CFDISK_MENU_MAIN); - line = (char *) xmalloc((COLS+1)*sizeof(char)); + rc = ui_refresh(cf); + if (rc) + return rc; - if (warning_last_time) { - for (i = 0; i < COLS; i++) { - move(WARNING_START, i); - line[i] = inch(); - } - line[COLS] = 0; - } - - erase(); - - if (warning_last_time) - mvaddstr(WARNING_START, 0, line); - - - snprintf(line, COLS+1, "cfdisk (%s)", PACKAGE_STRING); - mvaddstr(HEADER_START, (COLS-strlen(line))/2, line); - snprintf(line, COLS+1, _("Disk Drive: %s"), disk_device); - mvaddstr(HEADER_START+2, (COLS-strlen(line))/2, line); - { - long long bytes = actual_size*(long long) SECTOR_SIZE; - long long megabytes = bytes/(K*K); - - if (megabytes < 10000) - sprintf(line, _("Size: %lld bytes, %lld MB"), - bytes, megabytes); - else - sprintf(line, _("Size: %lld bytes, %lld.%lld GB"), - bytes, megabytes/K, (10*megabytes/K)%10); - } - mvaddstr(HEADER_START+3, (COLS-strlen(line))/2, line); - snprintf(line, COLS+1, _("Heads: %d Sectors per Track: %d Cylinders: %lld"), - heads, sectors, cylinders); - mvaddstr(HEADER_START+4, (COLS-strlen(line))/2, line); - - mvaddstr(DISK_TABLE_START, NAME_START, _("Name")); - mvaddstr(DISK_TABLE_START, FLAGS_START, _("Flags")); - mvaddstr(DISK_TABLE_START, PTYPE_START-1, _("Part Type")); - mvaddstr(DISK_TABLE_START, FSTYPE_START, _("FS Type")); - mvaddstr(DISK_TABLE_START, LABEL_START+1, _("[Label]")); - if (display_units == SECTORS) - mvaddstr(DISK_TABLE_START, SIZE_START, _(" Sectors")); - else if (display_units == CYLINDERS) - mvaddstr(DISK_TABLE_START, SIZE_START, _(" Cylinders")); - else if (display_units == MEGABYTES) - mvaddstr(DISK_TABLE_START, SIZE_START, _(" Size (MB)")); - else if (display_units == GIGABYTES) - mvaddstr(DISK_TABLE_START, SIZE_START, _(" Size (GB)")); - - move(DISK_TABLE_START+1, 1); - for (i = 1; i < COLS-1; i++) - addch('-'); - - if (NUM_ON_SCREEN >= num_parts) - for (i = 0; i < num_parts; i++) - draw_partition(i); - else - for (i = (cur_part/NUM_ON_SCREEN)*NUM_ON_SCREEN; - i < NUM_ON_SCREEN + (cur_part/NUM_ON_SCREEN)*NUM_ON_SCREEN && - i < num_parts; - i++) - draw_partition(i); - - free(line); -} + do { + int key = getch(); -static void -draw_cursor(int move) { - if (move != 0 && (cur_part + move < 0 || cur_part + move >= num_parts)) { - print_warning(_("No more partitions")); - return; - } - - if (arrow_cursor) - mvaddstr(DISK_TABLE_START + cur_part + 2 - - (cur_part/NUM_ON_SCREEN)*NUM_ON_SCREEN, 0, " "); - else - draw_partition(cur_part); - - cur_part += move; - - if (((cur_part - move)/NUM_ON_SCREEN)*NUM_ON_SCREEN != - (cur_part/NUM_ON_SCREEN)*NUM_ON_SCREEN) - draw_screen(); - - if (arrow_cursor) - mvaddstr(DISK_TABLE_START + cur_part + 2 - - (cur_part/NUM_ON_SCREEN)*NUM_ON_SCREEN, 0, "-->"); - else { - standout(); - draw_partition(cur_part); - standend(); - } -} + if (key == 'q') + break; -static void -do_curses_fdisk(void) { - int done = FALSE; - int command; - int is_first_run = TRUE; - - static struct MenuItem menuMain[] = { - { 'b', N_("Bootable"), N_("Toggle bootable flag of the current partition") }, - { 'd', N_("Delete"), N_("Delete the current partition") }, - { 'g', N_("Geometry"), N_("Change disk geometry (experts only)") }, - { 'h', N_("Help"), N_("Print help screen") }, - { 'm', N_("Maximize"), N_("Maximize disk usage of the current partition (experts only)") }, - { 'n', N_("New"), N_("Create new partition from free space") }, - { 'p', N_("Print"), N_("Print partition table to the screen or to a file") }, - { 'q', N_("Quit"), N_("Quit program without writing partition table") }, - { 't', N_("Type"), N_("Change the filesystem type (DOS, Linux, OS/2 and so on)") }, - { 'u', N_("Units"), N_("Change units of the partition size display (MB, sect, cyl)") }, - { 'W', N_("Write"), N_("Write partition table to disk (this might destroy data)") }, - { 0, NULL, NULL } - }; - curses_started = 1; - initscr(); - init_const(); - - old_SIGINT = signal(SIGINT, die); - old_SIGTERM = signal(SIGTERM, die); -#ifdef DEBUG - signal(SIGINT, old_SIGINT); - signal(SIGTERM, old_SIGTERM); + switch (key) { + case KEY_DOWN: + case '\016': /* ^N */ + case 'j': /* Vi-like alternative */ + ui_table_goto(cf, cf->lines_idx + 1); + break; + case KEY_UP: + case '\020': /* ^P */ + case 'k': /* Vi-like alternative */ + ui_table_goto(cf, cf->lines_idx - 1); + break; + case KEY_HOME: + ui_table_goto(cf, 0); + break; + case KEY_END: + ui_table_goto(cf, cf->nlines - 1); + break; + ui_menu_action(cf, 0); + break; + case KEY_LEFT: +#ifdef KEY_BTAB + case KEY_BTAB: #endif + ui_menu_goto(cf, cf->menu_idx - 1); + break; + case KEY_RIGHT: + case '\t': + ui_menu_goto(cf, cf->menu_idx + 1); + break; + case KEY_ENTER: + case '\n': + case '\r': + ui_menu_action(cf, 0); + break; + default: + if (ui_menu_action(cf, key) != 0) + beep(); + break; + } + } while (1); - cbreak(); - noecho(); - nonl(); + menu_pop(cf); - fill_p_info(); + DBG(FRONTEND, dbgprint("ui: end")); + + return 0; +} - draw_screen(); +int main(int argc, char *argv[]) +{ + struct cfdisk _cf = { .lines_idx = 0 }, + *cf = &_cf; - while (!done) { - char *s; + setlocale(LC_ALL, ""); + bindtextdomain(PACKAGE, LOCALEDIR); + textdomain(PACKAGE); + atexit(close_stdout); - draw_cursor(0); + fdisk_init_debug(0); + cf->cxt = fdisk_new_context(); + if (!cf->cxt) + err(EXIT_FAILURE, _("failed to allocate libfdisk context")); - if (p_info[cur_part].id == FREE_SPACE) { - s = ((opentype == O_RDWR) ? "hnpquW" : "hnpqu"); - command = menuSelect(COMMAND_LINE_Y, COMMAND_LINE_X, menuMain, 10, - s, MENU_BUTTON | MENU_ACCEPT_OTHERS, 5); - } else if (p_info[cur_part].id > 0) { - s = ((opentype == O_RDWR) ? "bdhmpqtuW" : "bdhmpqtu"); - command = menuSelect(COMMAND_LINE_Y, COMMAND_LINE_X, menuMain, 10, - s, MENU_BUTTON | MENU_ACCEPT_OTHERS, is_first_run ? 7 : 0); - } else { - s = ((opentype == O_RDWR) ? "hpquW" : "hpqu"); - command = menuSelect(COMMAND_LINE_Y, COMMAND_LINE_X, menuMain, 10, - s, MENU_BUTTON | MENU_ACCEPT_OTHERS, 0); - } - is_first_run = FALSE; - switch ( command ) { - case 'B': - case 'b': - if (p_info[cur_part].id > 0) - p_info[cur_part].flags ^= 0x80; - else - print_warning(_("Cannot make this partition bootable")); - break; - case 'D': - case 'd': - if (p_info[cur_part].id > 0) { - del_part(cur_part); - if (cur_part >= num_parts) - cur_part = num_parts - 1; - draw_screen(); - } else - print_warning(_("Cannot delete an empty partition")); - break; - case 'G': - case 'g': - if (change_geometry()) - draw_screen(); - break; - case 'M': - case 'm': - if (p_info[cur_part].id > 0) { - if (p_info[cur_part].first_sector == 0 || - IS_LOGICAL(p_info[cur_part].num)) { - if (p_info[cur_part].offset == sectors) - p_info[cur_part].offset = 1; - else - p_info[cur_part].offset = sectors; - draw_screen(); - } else if (p_info[cur_part].offset != 0) - p_info[cur_part].offset = 0; - else - print_warning(_("Cannot maximize this partition")); - } else - print_warning(_("Cannot maximize this partition")); - break; - case 'N': - case 'n': - if (p_info[cur_part].id == FREE_SPACE) { - new_part(cur_part); - draw_screen(); - } else if (p_info[cur_part].id == UNUSABLE) - print_warning(_("This partition is unusable")); - else - print_warning(_("This partition is already in use")); - break; - case 'P': - case 'p': - print_tables(); - draw_screen(); - break; - case 'Q': - case 'q': - done = TRUE; - break; - case 'T': - case 't': - if (p_info[cur_part].id > 0) { - change_id(cur_part); - draw_screen(); - } else - print_warning(_("Cannot change the type of an empty partition")); - break; - case 'U': - case 'u': - if (display_units == GIGABYTES) - display_units = MEGABYTES; - else if (display_units == MEGABYTES) - display_units = SECTORS; - else if (display_units == SECTORS) - display_units = CYLINDERS; - else if (display_units == CYLINDERS) - display_units = MEGABYTES; /* not yet GIGA */ - draw_screen(); - break; - case 'W': - write_part_table(); - break; - case 'H': - case 'h': - case '?': - display_help(); - draw_screen(); - break; - case KEY_UP: /* Up arrow key */ - case '\020': /* ^P */ - case 'k': /* Vi-like alternative */ - draw_cursor(-1); - break; - case KEY_DOWN: /* Down arrow key */ - case '\016': /* ^N */ - case 'j': /* Vi-like alternative */ - draw_cursor(1); - break; - case REDRAWKEY: - clear(); - draw_screen(); - break; - case KEY_HOME: - draw_cursor(-cur_part); - break; - case KEY_END: - draw_cursor(num_parts - cur_part - 1); - break; - default: - print_warning(_("Illegal command")); - putchar(BELL); /* CTRL-G */ - } - } + fdisk_context_set_ask(cf->cxt, ask_callback, (void *) cf); + fdisk_context_enable_freespace(cf->cxt, 1); - die_x(0); -} + if (argc != 2) + err(EXIT_FAILURE, "usage: %s ", argv[0]); -static void -copyright(void) { - fprintf(stderr, _("Copyright (C) 1994-2002 Kevin E. Martin & aeb\n")); -} + if (fdisk_context_assign_device(cf->cxt, argv[optind], 0) != 0) + err(EXIT_FAILURE, _("cannot open %s"), argv[optind]); + cols_init(cf); -static void __attribute__ ((__noreturn__)) usage(FILE *out) -{ - fputs(USAGE_HEADER, out); - fprintf(out, _(" %s [options] \n"), program_invocation_short_name); - fputs(USAGE_OPTIONS, out); - fputs(_(" -c, --cylinders set the number of cylinders to use\n"), out); - fputs(_(" -h, --heads set the number of heads to use\n"), out); - fputs(_(" -s, --sectors set the number of sectors to use\n"), out); - fputs(_(" -g, --guess guess a geometry from partition table\n"), out); - fputs(_(" -P, --print print partition table in specified format\n"), out); - fputs(_(" -z, --zero start with zeroed partition table\n"), out); - fputs(_(" -a, --arrow use arrow for highlighting the current partition\n"), out); - fputs(USAGE_SEPARATOR, out); - fputs(_(" --help display this help and exit\n"), out); - fputs(USAGE_VERSION, out); - fprintf(out, USAGE_MAN_TAIL("cfdisk(8)")); - copyright(); - exit(out == stderr ? EXIT_FAILURE : EXIT_SUCCESS); -} + if (lines_refresh_buffer(cf)) + errx(EXIT_FAILURE, _("failed to read partitions")); -int -main(int argc, char **argv) -{ - int c; - int i, len; - - enum { - OPT_HELP = CHAR_MAX + 1, - }; - - static const struct option longopts[] = { - {"cylinders", required_argument, 0, 'c'}, - {"heads", required_argument, 0, 'h'}, - {"sectors", required_argument, 0, 's'}, - {"guess", no_argument, 0, 'g'}, - {"print", required_argument, 0, 'P'}, - {"zero", no_argument, 0, 'z'}, - {"arrow", no_argument, 0, 'a'}, - {"help", no_argument, 0, OPT_HELP}, - {"version", no_argument, 0, 'V'}, - {NULL, no_argument, 0, '0'}, - }; - - setlocale(LC_ALL, ""); - bindtextdomain(PACKAGE, LOCALEDIR); - textdomain(PACKAGE); - atexit(close_stdout); - - while ((c = getopt_long(argc, argv, "ac:gh:s:vVzP:", longopts, NULL)) != -1) - switch (c) { - case 'a': - arrow_cursor = TRUE; - break; - case 'c': - user_cylinders = cylinders = strtos64_or_err(optarg, _("cannot parse number of cylinders")); - if (cylinders <= 0) { - fprintf(stderr, "%s: %s\n", argv[0], _("Illegal cylinders value")); - exit(1); - } - break; - case 'g': - use_partition_table_geometry = TRUE; - break; - case 'h': - user_heads = heads = strtol_or_err(optarg, _("cannot parse number of heads")); - if (heads <= 0 || heads > MAX_HEADS) { - fprintf(stderr, "%s: %s\n", argv[0], _("Illegal heads value")); - exit(1); - } - break; - case 's': - user_sectors = sectors = strtol_or_err(optarg, _("cannot parse number of sectors")); - if (sectors <= 0 || sectors > MAX_SECTORS) { - fprintf(stderr, "%s: %s\n", argv[0], _("Illegal sectors value")); - exit(1); - } - break; - case 'v': - case 'V': - printf(UTIL_LINUX_VERSION); - copyright(); - return EXIT_SUCCESS; - case 'z': - zero_table = TRUE; - break; - case 'P': - len = strlen(optarg); - for (i = 0; i < len; i++) { - switch (optarg[i]) { - case 'r': - print_only |= PRINT_RAW_TABLE; - break; - case 's': - print_only |= PRINT_SECTOR_TABLE; - break; - case 't': - print_only |= PRINT_PARTITION_TABLE; - break; - default: - usage(stderr); - } - } - break; - case OPT_HELP: - usage(stdout); - default: - usage(stderr); - } + /* Don't use err(), warn() from this point */ + ui_init(cf); + ui_run(cf); + ui_end(cf); - if (argc-optind == 1) - disk_device = argv[optind]; - else if (argc-optind != 0) { - usage(stderr); - } else if ((fd = open(DEFAULT_DEVICE, O_RDONLY)) < 0) - disk_device = ALTERNATE_DEVICE; - else close(fd); - - if (print_only) { - fill_p_info(); - if (print_only & PRINT_RAW_TABLE) - print_raw_table(); - if (print_only & PRINT_SECTOR_TABLE) - print_p_info(); - if (print_only & PRINT_PARTITION_TABLE) - print_part_table(); - } else - do_curses_fdisk(); - - return 0; + free(cf->lines); + free(cf->linesbuf); + fdisk_unref_table(cf->table); + fdisk_free_context(cf->cxt); + return EXIT_SUCCESS; } -- cgit v1.2.3-55-g7522