1/* fdisk.c -- Partition table manipulator for Linux.
2 *
3 * Copyright (C) 1992  A. V. Le Blanc (LeBlanc@mcc.ac.uk)
4 *
5 * This program is free software.  You can redistribute it and/or
6 * modify it under the terms of the GNU General Public License as
7 * published by the Free Software Foundation: either version 1 or
8 * (at your option) any later version.
9 */
10
11#include <unistd.h>
12#include <stdio.h>
13#include <stdlib.h>
14#include <string.h>
15#include <fcntl.h>
16#include <ctype.h>
17#include <setjmp.h>
18#include <errno.h>
19#include <getopt.h>
20#include <sys/stat.h>
21
22#include "nls.h"
23#include "common.h"
24#include "fdisk.h"
25
26#include "fdisksunlabel.h"
27#include "fdisksgilabel.h"
28#include "fdiskaixlabel.h"
29
30#ifdef HAVE_LINUX_COMPILER_H
31#include <linux/compiler.h>
32#endif
33#ifdef HAVE_LINUX_BLKPG_H
34#include <linux/blkpg.h>
35#endif
36
37static void delete_partition(int i);
38
39#define hex_val(c)	({ \
40				char _c = (c); \
41				isdigit(_c) ? _c - '0' : \
42				tolower(_c) + 10 - 'a'; \
43			})
44
45
46#define LINE_LENGTH	800
47#define pt_offset(b, n)	((struct partition *)((b) + 0x1be + \
48				(n) * sizeof(struct partition)))
49#define sector(s)	((s) & 0x3f)
50#define cylinder(s, c)	((c) | (((s) & 0xc0) << 2))
51
52#define hsc2sector(h,s,c) (sector(s) - 1 + sectors * \
53				((h) + heads * cylinder(s,c)))
54#define set_hsc(h,s,c,sector) { \
55				s = sector % sectors + 1;	\
56				sector /= sectors;	\
57				h = sector % heads;	\
58				sector /= heads;	\
59				c = sector & 0xff;	\
60				s |= (sector >> 2) & 0xc0;	\
61			}
62
63/* A valid partition table sector ends in 0x55 0xaa */
64static unsigned int
65part_table_flag(char *b) {
66	return ((unsigned int) b[510]) + (((unsigned int) b[511]) << 8);
67}
68
69int
70valid_part_table_flag(unsigned char *b) {
71	return (b[510] == 0x55 && b[511] == 0xaa);
72}
73
74static void
75write_part_table_flag(char *b) {
76	b[510] = 0x55;
77	b[511] = 0xaa;
78}
79
80/* start_sect and nr_sects are stored little endian on all machines */
81/* moreover, they are not aligned correctly */
82static void
83store4_little_endian(unsigned char *cp, unsigned int val) {
84	cp[0] = (val & 0xff);
85	cp[1] = ((val >> 8) & 0xff);
86	cp[2] = ((val >> 16) & 0xff);
87	cp[3] = ((val >> 24) & 0xff);
88}
89
90static unsigned int
91read4_little_endian(unsigned char *cp) {
92	return (unsigned int)(cp[0]) + ((unsigned int)(cp[1]) << 8)
93		+ ((unsigned int)(cp[2]) << 16)
94		+ ((unsigned int)(cp[3]) << 24);
95}
96
97static void
98set_start_sect(struct partition *p, unsigned int start_sect) {
99	store4_little_endian(p->start4, start_sect);
100}
101
102unsigned int
103get_start_sect(struct partition *p) {
104	return read4_little_endian(p->start4);
105}
106
107static void
108set_nr_sects(struct partition *p, unsigned int nr_sects) {
109	store4_little_endian(p->size4, nr_sects);
110}
111
112unsigned int
113get_nr_sects(struct partition *p) {
114	return read4_little_endian(p->size4);
115}
116
117/* normally O_RDWR, -l option gives O_RDONLY */
118static int type_open = O_RDWR;
119
120/*
121 * Raw disk label. For DOS-type partition tables the MBR,
122 * with descriptions of the primary partitions.
123 */
124char MBRbuffer[MAX_SECTOR_SIZE];
125
126/*
127 * per partition table entry data
128 *
129 * The four primary partitions have the same sectorbuffer (MBRbuffer)
130 * and have NULL ext_pointer.
131 * Each logical partition table entry has two pointers, one for the
132 * partition and one link to the next one.
133 */
134struct pte {
135	struct partition *part_table;	/* points into sectorbuffer */
136	struct partition *ext_pointer;	/* points into sectorbuffer */
137	char changed;			/* boolean */
138	unsigned int offset;		/* disk sector number */
139	char *sectorbuffer;		/* disk sector contents */
140} ptes[MAXIMUM_PARTS];
141
142char	*disk_device,			/* must be specified */
143	*line_ptr,			/* interactive input */
144	line_buffer[LINE_LENGTH];
145
146int	fd,				/* the disk */
147	ext_index,			/* the prime extended partition */
148	listing = 0,			/* no aborts for fdisk -l */
149	nowarn = 0,			/* no warnings for fdisk -l/-s */
150	dos_compatible_flag = ~0,
151	dos_changed = 0,
152	partitions = 4;			/* maximum partition + 1 */
153
154unsigned int	user_cylinders, user_heads, user_sectors;
155unsigned int	pt_heads, pt_sectors;
156unsigned int	kern_heads, kern_sectors;
157
158unsigned int	heads,
159	sectors,
160	cylinders,
161	sector_size = DEFAULT_SECTOR_SIZE,
162	user_set_sector_size = 0,
163	sector_offset = 1,
164	units_per_sector = 1,
165	display_in_cyl_units = 1,
166	extended_offset = 0;		/* offset of link pointers */
167
168unsigned long long total_number_of_sectors;
169
170#define dos_label (!sun_label && !sgi_label && !aix_label && !osf_label)
171int     sun_label = 0;                  /* looking at sun disklabel */
172int	sgi_label = 0;			/* looking at sgi disklabel */
173int	aix_label = 0;			/* looking at aix disklabel */
174int	osf_label = 0;			/* looking at OSF/1 disklabel */
175int	possibly_osf_label = 0;
176
177jmp_buf listingbuf;
178
179void fatal(enum failure why) {
180	char	error[LINE_LENGTH],
181		*message = error;
182
183	if (listing) {
184		close(fd);
185		longjmp(listingbuf, 1);
186	}
187
188	switch (why) {
189		case usage: message = _(
190"Usage: fdisk [-b SSZ] [-u] DISK     Change partition table\n"
191"       fdisk -l [-b SSZ] [-u] DISK  List partition table(s)\n"
192"       fdisk -s PARTITION           Give partition size(s) in blocks\n"
193"       fdisk -v                     Give fdisk version\n"
194"Here DISK is something like /dev/hdb or /dev/sda\n"
195"and PARTITION is something like /dev/hda7\n"
196"-u: give Start and End in sector (instead of cylinder) units\n"
197"-b 2048: (for certain MO disks) use 2048-byte sectors\n");
198			break;
199		case usage2:
200		  /* msg in cases where fdisk used to probe */
201			message = _(
202"Usage: fdisk [-l] [-b SSZ] [-u] device\n"
203"E.g.: fdisk /dev/hda  (for the first IDE disk)\n"
204"  or: fdisk /dev/sdc  (for the third SCSI disk)\n"
205"  or: fdisk /dev/eda  (for the first PS/2 ESDI drive)\n"
206"  or: fdisk /dev/rd/c0d0  or: fdisk /dev/ida/c0d0  (for RAID devices)\n"
207"  ...\n");
208			break;
209		case unable_to_open:
210			snprintf(error, sizeof(error),
211				 _("Unable to open %s\n"), disk_device);
212			break;
213		case unable_to_read:
214			snprintf(error, sizeof(error),
215				 _("Unable to read %s\n"), disk_device);
216			break;
217		case unable_to_seek:
218			snprintf(error, sizeof(error),
219				_("Unable to seek on %s\n"),disk_device);
220			break;
221		case unable_to_write:
222			snprintf(error, sizeof(error),
223				_("Unable to write %s\n"), disk_device);
224			break;
225		case ioctl_error:
226			snprintf(error, sizeof(error),
227				 _("BLKGETSIZE ioctl failed on %s\n"),
228				disk_device);
229			break;
230		case out_of_memory:
231			message = _("Unable to allocate any more memory\n");
232			break;
233		default:
234			message = _("Fatal error\n");
235	}
236
237	fputc('\n', stderr);
238	fputs(message, stderr);
239	exit(1);
240}
241
242static void
243seek_sector(int fd, unsigned int secno) {
244	off_t offset = (off_t) secno * sector_size;
245	if (lseek(fd, offset, SEEK_SET) == (off_t) -1)
246		fatal(unable_to_seek);
247}
248
249static void
250read_sector(int fd, unsigned int secno, char *buf) {
251	seek_sector(fd, secno);
252	if (read(fd, buf, sector_size) != sector_size)
253		fatal(unable_to_read);
254}
255
256static void
257write_sector(int fd, unsigned int secno, char *buf) {
258	seek_sector(fd, secno);
259	if (write(fd, buf, sector_size) != sector_size)
260		fatal(unable_to_write);
261}
262
263/* Allocate a buffer and read a partition table sector */
264static void
265read_pte(int fd, int pno, unsigned int offset) {
266	struct pte *pe = &ptes[pno];
267
268	pe->offset = offset;
269	pe->sectorbuffer = (char *) malloc(sector_size);
270	if (!pe->sectorbuffer)
271		fatal(out_of_memory);
272	read_sector(fd, offset, pe->sectorbuffer);
273	pe->changed = 0;
274	pe->part_table = pe->ext_pointer = NULL;
275}
276
277static unsigned int
278get_partition_start(struct pte *pe) {
279	return pe->offset + get_start_sect(pe->part_table);
280}
281
282struct partition *
283get_part_table(int i) {
284	return ptes[i].part_table;
285}
286
287void
288set_all_unchanged(void) {
289	int i;
290
291	for (i = 0; i < MAXIMUM_PARTS; i++)
292		ptes[i].changed = 0;
293}
294
295void
296set_changed(int i) {
297	ptes[i].changed = 1;
298}
299
300static int
301is_garbage_table(void) {
302	int i;
303
304	for (i = 0; i < 4; i++) {
305		struct pte *pe = &ptes[i];
306		struct partition *p = pe->part_table;
307
308		if (p->boot_ind != 0 && p->boot_ind != 0x80)
309			return 1;
310	}
311	return 0;
312}
313
314/*
315 * Avoid warning about DOS partitions when no DOS partition was changed.
316 * Here a heuristic "is probably dos partition".
317 * We might also do the opposite and warn in all cases except
318 * for "is probably nondos partition".
319 */
320static int
321is_dos_partition(int t) {
322	return (t == 1 || t == 4 || t == 6 ||
323		t == 0x0b || t == 0x0c || t == 0x0e ||
324		t == 0x11 || t == 0x12 || t == 0x14 || t == 0x16 ||
325		t == 0x1b || t == 0x1c || t == 0x1e || t == 0x24 ||
326		t == 0xc1 || t == 0xc4 || t == 0xc6);
327}
328
329static void
330menu(void) {
331	if (sun_label) {
332	   puts(_("Command action"));
333	   puts(_("   a   toggle a read only flag")); 		/* sun */
334	   puts(_("   b   edit bsd disklabel"));
335	   puts(_("   c   toggle the mountable flag"));		/* sun */
336	   puts(_("   d   delete a partition"));
337	   puts(_("   l   list known partition types"));
338	   puts(_("   m   print this menu"));
339	   puts(_("   n   add a new partition"));
340	   puts(_("   o   create a new empty DOS partition table"));
341	   puts(_("   p   print the partition table"));
342	   puts(_("   q   quit without saving changes"));
343	   puts(_("   s   create a new empty Sun disklabel"));	/* sun */
344	   puts(_("   t   change a partition's system id"));
345	   puts(_("   u   change display/entry units"));
346	   puts(_("   v   verify the partition table"));
347	   puts(_("   w   write table to disk and exit"));
348	   puts(_("   x   extra functionality (experts only)"));
349	}
350	else if (sgi_label) {
351	   puts(_("Command action"));
352	   puts(_("   a   select bootable partition"));    /* sgi flavour */
353	   puts(_("   b   edit bootfile entry"));          /* sgi */
354	   puts(_("   c   select sgi swap partition"));    /* sgi flavour */
355	   puts(_("   d   delete a partition"));
356	   puts(_("   l   list known partition types"));
357	   puts(_("   m   print this menu"));
358	   puts(_("   n   add a new partition"));
359	   puts(_("   o   create a new empty DOS partition table"));
360	   puts(_("   p   print the partition table"));
361	   puts(_("   q   quit without saving changes"));
362	   puts(_("   s   create a new empty Sun disklabel"));	/* sun */
363	   puts(_("   t   change a partition's system id"));
364	   puts(_("   u   change display/entry units"));
365	   puts(_("   v   verify the partition table"));
366	   puts(_("   w   write table to disk and exit"));
367	}
368	else if (aix_label) {
369	   puts(_("Command action"));
370	   puts(_("   m   print this menu"));
371	   puts(_("   o   create a new empty DOS partition table"));
372	   puts(_("   q   quit without saving changes"));
373	   puts(_("   s   create a new empty Sun disklabel"));	/* sun */
374	}
375	else {
376	   puts(_("Command action"));
377	   puts(_("   a   toggle a bootable flag"));
378	   puts(_("   b   edit bsd disklabel"));
379	   puts(_("   c   toggle the dos compatibility flag"));
380	   puts(_("   d   delete a partition"));
381	   puts(_("   l   list known partition types"));
382	   puts(_("   m   print this menu"));
383	   puts(_("   n   add a new partition"));
384	   puts(_("   o   create a new empty DOS partition table"));
385	   puts(_("   p   print the partition table"));
386	   puts(_("   q   quit without saving changes"));
387	   puts(_("   s   create a new empty Sun disklabel"));	/* sun */
388	   puts(_("   t   change a partition's system id"));
389	   puts(_("   u   change display/entry units"));
390	   puts(_("   v   verify the partition table"));
391	   puts(_("   w   write table to disk and exit"));
392	   puts(_("   x   extra functionality (experts only)"));
393	}
394}
395
396static void
397xmenu(void) {
398	if (sun_label) {
399	   puts(_("Command action"));
400	   puts(_("   a   change number of alternate cylinders"));      /*sun*/
401	   puts(_("   c   change number of cylinders"));
402	   puts(_("   d   print the raw data in the partition table"));
403	   puts(_("   e   change number of extra sectors per cylinder"));/*sun*/
404	   puts(_("   h   change number of heads"));
405	   puts(_("   i   change interleave factor"));			/*sun*/
406	   puts(_("   o   change rotation speed (rpm)"));		/*sun*/
407	   puts(_("   m   print this menu"));
408	   puts(_("   p   print the partition table"));
409	   puts(_("   q   quit without saving changes"));
410	   puts(_("   r   return to main menu"));
411	   puts(_("   s   change number of sectors/track"));
412	   puts(_("   v   verify the partition table"));
413	   puts(_("   w   write table to disk and exit"));
414	   puts(_("   y   change number of physical cylinders"));	/*sun*/
415	}
416	else if (sgi_label) {
417	   puts(_("Command action"));
418	   puts(_("   b   move beginning of data in a partition")); /* !sun */
419	   puts(_("   c   change number of cylinders"));
420	   puts(_("   d   print the raw data in the partition table"));
421	   puts(_("   e   list extended partitions"));		/* !sun */
422	   puts(_("   g   create an IRIX (SGI) partition table"));/* sgi */
423	   puts(_("   h   change number of heads"));
424	   puts(_("   m   print this menu"));
425	   puts(_("   p   print the partition table"));
426	   puts(_("   q   quit without saving changes"));
427	   puts(_("   r   return to main menu"));
428	   puts(_("   s   change number of sectors/track"));
429	   puts(_("   v   verify the partition table"));
430	   puts(_("   w   write table to disk and exit"));
431	}
432	else if (aix_label) {
433	   puts(_("Command action"));
434	   puts(_("   b   move beginning of data in a partition")); /* !sun */
435	   puts(_("   c   change number of cylinders"));
436	   puts(_("   d   print the raw data in the partition table"));
437	   puts(_("   e   list extended partitions"));		/* !sun */
438	   puts(_("   g   create an IRIX (SGI) partition table"));/* sgi */
439	   puts(_("   h   change number of heads"));
440	   puts(_("   m   print this menu"));
441	   puts(_("   p   print the partition table"));
442	   puts(_("   q   quit without saving changes"));
443	   puts(_("   r   return to main menu"));
444	   puts(_("   s   change number of sectors/track"));
445	   puts(_("   v   verify the partition table"));
446	   puts(_("   w   write table to disk and exit"));
447	}
448	else {
449	   puts(_("Command action"));
450	   puts(_("   b   move beginning of data in a partition")); /* !sun */
451	   puts(_("   c   change number of cylinders"));
452	   puts(_("   d   print the raw data in the partition table"));
453	   puts(_("   e   list extended partitions"));		/* !sun */
454	   puts(_("   f   fix partition order"));		/* !sun, !aix, !sgi */
455	   puts(_("   g   create an IRIX (SGI) partition table"));/* sgi */
456	   puts(_("   h   change number of heads"));
457	   puts(_("   m   print this menu"));
458	   puts(_("   p   print the partition table"));
459	   puts(_("   q   quit without saving changes"));
460	   puts(_("   r   return to main menu"));
461	   puts(_("   s   change number of sectors/track"));
462	   puts(_("   v   verify the partition table"));
463	   puts(_("   w   write table to disk and exit"));
464	}
465}
466
467static int
468get_sysid(int i) {
469	return (
470		sun_label ? sunlabel->infos[i].id :
471		sgi_label ? sgi_get_sysid(i) :
472		ptes[i].part_table->sys_ind);
473}
474
475static struct systypes *
476get_sys_types(void) {
477	return (
478		sun_label ? sun_sys_types :
479		sgi_label ? sgi_sys_types :
480		i386_sys_types);
481}
482
483char *partition_type(unsigned char type)
484{
485	int i;
486	struct systypes *types = get_sys_types();
487
488	for (i=0; types[i].name; i++)
489		if (types[i].type == type)
490			return _(types[i].name);
491
492	return NULL;
493}
494
495void list_types(struct systypes *sys)
496{
497	unsigned int last[4], done = 0, next = 0, size;
498	int i;
499
500	for (i = 0; sys[i].name; i++);
501	size = i;
502
503	for (i = 3; i >= 0; i--)
504		last[3 - i] = done += (size + i - done) / (i + 1);
505	i = done = 0;
506
507	do {
508		printf("%c%2x  %-15.15s", i ? ' ' : '\n',
509		        sys[next].type, _(sys[next].name));
510 		next = last[i++] + done;
511		if (i > 3 || next >= last[i]) {
512			i = 0;
513			next = ++done;
514		}
515	} while (done < last[0]);
516	putchar('\n');
517}
518
519static int
520is_cleared_partition(struct partition *p) {
521	return !(!p || p->boot_ind || p->head || p->sector || p->cyl ||
522		 p->sys_ind || p->end_head || p->end_sector || p->end_cyl ||
523		 get_start_sect(p) || get_nr_sects(p));
524}
525
526static void
527clear_partition(struct partition *p) {
528	if (!p)
529		return;
530	p->boot_ind = 0;
531	p->head = 0;
532	p->sector = 0;
533	p->cyl = 0;
534	p->sys_ind = 0;
535	p->end_head = 0;
536	p->end_sector = 0;
537	p->end_cyl = 0;
538	set_start_sect(p,0);
539	set_nr_sects(p,0);
540}
541
542static void
543set_partition(int i, int doext, unsigned int start, unsigned int stop,
544	      int sysid) {
545	struct partition *p;
546	unsigned int offset;
547
548	if (doext) {
549		p = ptes[i].ext_pointer;
550		offset = extended_offset;
551	} else {
552		p = ptes[i].part_table;
553		offset = ptes[i].offset;
554	}
555	p->boot_ind = 0;
556	p->sys_ind = sysid;
557	set_start_sect(p, start - offset);
558	set_nr_sects(p, stop - start + 1);
559	if (dos_compatible_flag && (start/(sectors*heads) > 1023))
560		start = heads*sectors*1024 - 1;
561	set_hsc(p->head, p->sector, p->cyl, start);
562	if (dos_compatible_flag && (stop/(sectors*heads) > 1023))
563		stop = heads*sectors*1024 - 1;
564	set_hsc(p->end_head, p->end_sector, p->end_cyl, stop);
565	ptes[i].changed = 1;
566}
567
568static int
569test_c(char **m, char *mesg) {
570	int val = 0;
571	if (!*m)
572		fprintf(stderr, _("You must set"));
573	else {
574		fprintf(stderr, " %s", *m);
575		val = 1;
576	}
577	*m = mesg;
578	return val;
579}
580
581static int
582warn_geometry(void) {
583	char *m = NULL;
584	int prev = 0;
585
586	if (sgi_label)	/* cannot set cylinders etc anyway */
587		return 0;
588	if (!heads)
589		prev = test_c(&m, _("heads"));
590	if (!sectors)
591		prev = test_c(&m, _("sectors"));
592	if (!cylinders)
593		prev = test_c(&m, _("cylinders"));
594	if (!m)
595		return 0;
596	fprintf(stderr,
597		_("%s%s.\nYou can do this from the extra functions menu.\n"),
598		prev ? _(" and ") : " ", m);
599	return 1;
600}
601
602void update_units(void)
603{
604	int cyl_units = heads * sectors;
605
606	if (display_in_cyl_units && cyl_units)
607		units_per_sector = cyl_units;
608	else
609		units_per_sector = 1; 	/* in sectors */
610}
611
612static void
613warn_cylinders(void) {
614	if (dos_label && cylinders > 1024 && !nowarn)
615		fprintf(stderr, _("\n"
616"The number of cylinders for this disk is set to %d.\n"
617"There is nothing wrong with that, but this is larger than 1024,\n"
618"and could in certain setups cause problems with:\n"
619"1) software that runs at boot time (e.g., old versions of LILO)\n"
620"2) booting and partitioning software from other OSs\n"
621"   (e.g., DOS FDISK, OS/2 FDISK)\n"),
622			cylinders);
623}
624
625static void
626read_extended(int ext) {
627	int i;
628	struct pte *pex;
629	struct partition *p, *q;
630
631	ext_index = ext;
632	pex = &ptes[ext];
633	pex->ext_pointer = pex->part_table;
634
635	p = pex->part_table;
636	if (!get_start_sect(p)) {
637		fprintf(stderr,
638			_("Bad offset in primary extended partition\n"));
639		return;
640	}
641
642	while (IS_EXTENDED (p->sys_ind)) {
643		struct pte *pe = &ptes[partitions];
644
645		if (partitions >= MAXIMUM_PARTS) {
646			/* This is not a Linux restriction, but
647			   this program uses arrays of size MAXIMUM_PARTS.
648			   Do not try to `improve' this test. */
649			struct pte *pre = &ptes[partitions-1];
650
651			fprintf(stderr,
652				_("Warning: omitting partitions after #%d.\n"
653				  "They will be deleted "
654				  "if you save this partition table.\n"),
655				partitions);
656			clear_partition(pre->ext_pointer);
657			pre->changed = 1;
658			return;
659		}
660
661		read_pte(fd, partitions, extended_offset + get_start_sect(p));
662
663		if (!extended_offset)
664			extended_offset = get_start_sect(p);
665
666		q = p = pt_offset(pe->sectorbuffer, 0);
667		for (i = 0; i < 4; i++, p++) if (get_nr_sects(p)) {
668			if (IS_EXTENDED (p->sys_ind)) {
669				if (pe->ext_pointer)
670					fprintf(stderr,
671						_("Warning: extra link "
672						  "pointer in partition table"
673						  " %d\n"), partitions + 1);
674				else
675					pe->ext_pointer = p;
676			} else if (p->sys_ind) {
677				if (pe->part_table)
678					fprintf(stderr,
679						_("Warning: ignoring extra "
680						  "data in partition table"
681						  " %d\n"), partitions + 1);
682				else
683					pe->part_table = p;
684			}
685		}
686
687		/* very strange code here... */
688		if (!pe->part_table) {
689			if (q != pe->ext_pointer)
690				pe->part_table = q;
691			else
692				pe->part_table = q + 1;
693		}
694		if (!pe->ext_pointer) {
695			if (q != pe->part_table)
696				pe->ext_pointer = q;
697			else
698				pe->ext_pointer = q + 1;
699		}
700
701		p = pe->ext_pointer;
702		partitions++;
703	}
704
705	/* remove empty links */
706 remove:
707	for (i = 4; i < partitions; i++) {
708		struct pte *pe = &ptes[i];
709
710		if (!get_nr_sects(pe->part_table) &&
711		    (partitions > 5 || ptes[4].part_table->sys_ind)) {
712			printf("omitting empty partition (%d)\n", i+1);
713			delete_partition(i);
714			goto remove; 	/* numbering changed */
715		}
716	}
717}
718
719static void
720create_doslabel(void) {
721	int i;
722
723	fprintf(stderr,
724	_("Building a new DOS disklabel. Changes will remain in memory only,\n"
725	  "until you decide to write them. After that, of course, the previous\n"
726	  "content won't be recoverable.\n\n"));
727	sun_nolabel();  /* otherwise always recognised as sun */
728	sgi_nolabel();  /* otherwise always recognised as sgi */
729	aix_label = osf_label = possibly_osf_label = 0;
730	partitions = 4;
731
732	for (i = 510-64; i < 510; i++)
733		MBRbuffer[i] = 0;
734	write_part_table_flag(MBRbuffer);
735	extended_offset = 0;
736	set_all_unchanged();
737	set_changed(0);
738	get_boot(create_empty_dos);
739}
740
741#include <sys/utsname.h>
742#define MAKE_VERSION(p,q,r)     (65536*(p) + 256*(q) + (r))
743
744static int
745linux_version_code(void) {
746	static int kernel_version = 0;
747        struct utsname my_utsname;
748        int p, q, r;
749
750        if (!kernel_version && uname(&my_utsname) == 0) {
751                p = atoi(strtok(my_utsname.release, "."));
752                q = atoi(strtok(NULL, "."));
753                r = atoi(strtok(NULL, "."));
754                kernel_version = MAKE_VERSION(p,q,r);
755        }
756        return kernel_version;
757}
758
759static void
760get_sectorsize(int fd) {
761#if defined(BLKSSZGET)
762	if (!user_set_sector_size &&
763	    linux_version_code() >= MAKE_VERSION(2,3,3)) {
764		int arg;
765		if (ioctl(fd, BLKSSZGET, &arg) == 0)
766			sector_size = arg;
767		if (sector_size != DEFAULT_SECTOR_SIZE)
768			printf(_("Note: sector size is %d (not %d)\n"),
769			       sector_size, DEFAULT_SECTOR_SIZE);
770	}
771#else
772	/* maybe the user specified it; and otherwise we still
773	   have the DEFAULT_SECTOR_SIZE default */
774#endif
775}
776
777static void
778get_kernel_geometry(int fd) {
779#ifdef HDIO_GETGEO
780	struct hd_geometry geometry;
781
782	if (!ioctl(fd, HDIO_GETGEO, &geometry)) {
783		kern_heads = geometry.heads;
784		kern_sectors = geometry.sectors;
785		/* never use geometry.cylinders - it is truncated */
786	}
787#endif
788}
789
790static int
791is_probably_full_disk(char *name) {
792#ifdef HDIO_GETGEO
793	struct hd_geometry geometry;
794	int fd, i = 0;
795
796	fd = open(name, O_RDONLY);
797	if (fd >= 0) {
798		i = ioctl(fd, HDIO_GETGEO, &geometry);
799		close(fd);
800	}
801	return (fd >= 0 && i == 0 && geometry.start == 0);
802#else
803	/* silly heuristic */
804	while (*name)
805		name++;
806	return !isdigit(name[-1]);
807#endif
808}
809
810static void
811get_partition_table_geometry(void) {
812	unsigned char *bufp = MBRbuffer;
813	struct partition *p;
814	int i, h, s, hh, ss;
815	int first = 1;
816	int bad = 0;
817
818	if (!(valid_part_table_flag(bufp)))
819		return;
820
821	hh = ss = 0;
822	for (i=0; i<4; i++) {
823		p = pt_offset(bufp, i);
824		if (p->sys_ind != 0) {
825			h = p->end_head + 1;
826			s = (p->end_sector & 077);
827			if (first) {
828				hh = h;
829				ss = s;
830				first = 0;
831			} else if (hh != h || ss != s)
832				bad = 1;
833		}
834	}
835
836	if (!first && !bad) {
837		pt_heads = hh;
838		pt_sectors = ss;
839	}
840}
841
842void
843get_geometry(int fd, struct geom *g) {
844	int sec_fac;
845	unsigned long long llsectors, llcyls;
846
847	get_sectorsize(fd);
848	sec_fac = sector_size / 512;
849	guess_device_type(fd);
850	heads = cylinders = sectors = 0;
851	kern_heads = kern_sectors = 0;
852	pt_heads = pt_sectors = 0;
853
854	get_kernel_geometry(fd);
855	get_partition_table_geometry();
856
857	heads = user_heads ? user_heads :
858		pt_heads ? pt_heads :
859		kern_heads ? kern_heads : 255;
860	sectors = user_sectors ? user_sectors :
861		pt_sectors ? pt_sectors :
862		kern_sectors ? kern_sectors : 63;
863
864	if (disksize(fd, &llsectors))
865		llsectors = 0;
866
867	total_number_of_sectors = llsectors;
868
869	sector_offset = 1;
870	if (dos_compatible_flag)
871		sector_offset = sectors;
872
873	llcyls = total_number_of_sectors / (heads * sectors * sec_fac);
874	cylinders = llcyls;
875	if (cylinders != llcyls)	/* truncated? */
876		cylinders = ~0;
877	if (!cylinders)
878		cylinders = user_cylinders;
879
880	if (g) {
881		g->heads = heads;
882		g->sectors = sectors;
883		g->cylinders = cylinders;
884	}
885}
886
887/*
888 * Read MBR.  Returns:
889 *   -1: no 0xaa55 flag present (possibly entire disk BSD)
890 *    0: found or created label
891 *    1: I/O error
892 */
893int
894get_boot(enum action what) {
895	int i;
896
897	partitions = 4;
898	ext_index = 0;
899	extended_offset = 0;
900
901	for (i = 0; i < 4; i++) {
902		struct pte *pe = &ptes[i];
903
904		pe->part_table = pt_offset(MBRbuffer, i);
905		pe->ext_pointer = NULL;
906		pe->offset = 0;
907		pe->sectorbuffer = MBRbuffer;
908		pe->changed = (what == create_empty_dos);
909	}
910
911	if (what == create_empty_sun && check_sun_label())
912		return 0;
913
914	memset(MBRbuffer, 0, 512);
915
916	if (what == create_empty_dos)
917		goto got_dos_table;		/* skip reading disk */
918
919	if ((fd = open(disk_device, type_open)) < 0) {
920	    if ((fd = open(disk_device, O_RDONLY)) < 0) {
921		if (what == try_only)
922		    return 1;
923		fatal(unable_to_open);
924	    } else
925		printf(_("You will not be able to write "
926			 "the partition table.\n"));
927	}
928
929	if (512 != read(fd, MBRbuffer, 512)) {
930		if (what == try_only)
931			return 1;
932		fatal(unable_to_read);
933	}
934
935	get_geometry(fd, NULL);
936
937	update_units();
938
939	if (check_sun_label())
940		return 0;
941
942	if (check_sgi_label())
943		return 0;
944
945	if (check_aix_label())
946		return 0;
947
948	if (check_osf_label()) {
949		possibly_osf_label = 1;
950		if (!valid_part_table_flag(MBRbuffer)) {
951			osf_label = 1;
952			return 0;
953		}
954		printf(_("This disk has both DOS and BSD magic.\n"
955			 "Give the 'b' command to go to BSD mode.\n"));
956	}
957
958got_dos_table:
959
960	if (!valid_part_table_flag(MBRbuffer)) {
961		switch(what) {
962		case fdisk:
963			fprintf(stderr,
964				_("Device contains neither a valid DOS "
965				  "partition table, nor Sun, SGI or OSF "
966				  "disklabel\n"));
967#ifdef __sparc__
968			create_sunlabel();
969#else
970			create_doslabel();
971#endif
972			return 0;
973		case require:
974			return -1;
975		case try_only:
976		        return -1;
977		case create_empty_dos:
978		case create_empty_sun:
979			break;
980		default:
981			fprintf(stderr, _("Internal error\n"));
982			exit(1);
983		}
984	}
985
986	warn_cylinders();
987	warn_geometry();
988
989	for (i = 0; i < 4; i++) {
990		struct pte *pe = &ptes[i];
991
992		if (IS_EXTENDED (pe->part_table->sys_ind)) {
993			if (partitions != 4)
994				fprintf(stderr, _("Ignoring extra extended "
995					"partition %d\n"), i + 1);
996			else
997				read_extended(i);
998		}
999	}
1000
1001	for (i = 3; i < partitions; i++) {
1002		struct pte *pe = &ptes[i];
1003
1004		if (!valid_part_table_flag(pe->sectorbuffer)) {
1005			fprintf(stderr,
1006				_("Warning: invalid flag 0x%04x of partition "
1007				"table %d will be corrected by w(rite)\n"),
1008				part_table_flag(pe->sectorbuffer), i + 1);
1009			pe->changed = 1;
1010		}
1011	}
1012
1013	return 0;
1014}
1015
1016/* read line; return 0 or first char */
1017int
1018read_line(void)
1019{
1020	static int got_eof = 0;
1021
1022	line_ptr = line_buffer;
1023	if (!fgets(line_buffer, LINE_LENGTH, stdin)) {
1024		if (feof(stdin))
1025			got_eof++; 	/* user typed ^D ? */
1026		if (got_eof >= 3) {
1027			fflush(stdout);
1028			fprintf(stderr, _("\ngot EOF thrice - exiting..\n"));
1029			exit(1);
1030		}
1031		return 0;
1032	}
1033	while (*line_ptr && !isgraph(*line_ptr))
1034		line_ptr++;
1035	return *line_ptr;
1036}
1037
1038char
1039read_char(char *mesg)
1040{
1041	do {
1042		fputs(mesg, stdout);
1043		fflush (stdout);	 /* requested by niles@scyld.com */
1044	} while (!read_line());
1045	return *line_ptr;
1046}
1047
1048char
1049read_chars(char *mesg)
1050{
1051        fputs(mesg, stdout);
1052	fflush (stdout);	/* niles@scyld.com */
1053        if (!read_line()) {
1054		*line_ptr = '\n';
1055		line_ptr[1] = 0;
1056	}
1057	return *line_ptr;
1058}
1059
1060int
1061read_hex(struct systypes *sys)
1062{
1063        int hex;
1064
1065        while (1)
1066        {
1067           read_char(_("Hex code (type L to list codes): "));
1068           if (tolower(*line_ptr) == 'l')
1069               list_types(sys);
1070	   else if (isxdigit (*line_ptr))
1071	   {
1072	      hex = 0;
1073	      do
1074		 hex = hex << 4 | hex_val(*line_ptr++);
1075	      while (isxdigit(*line_ptr));
1076	      return hex;
1077	   }
1078        }
1079}
1080
1081/*
1082 * Print the message MESG, then read an integer in LOW..HIGH.
1083 * If the user hits Enter, DFLT is returned, provided that is in LOW..HIGH.
1084 * Answers like +10 are interpreted as offsets from BASE.
1085 *
1086 * There is no default if DFLT is not between LOW and HIGH.
1087 */
1088unsigned int
1089read_int(unsigned int low, unsigned int dflt, unsigned int high,
1090	 unsigned int base, char *mesg)
1091{
1092	unsigned int i;
1093	int default_ok = 1;
1094	static char *ms = NULL;
1095	static int mslen = 0;
1096
1097	if (!ms || strlen(mesg)+100 > mslen) {
1098		mslen = strlen(mesg)+200;
1099		if (!(ms = realloc(ms,mslen)))
1100			fatal(out_of_memory);
1101	}
1102
1103	if (dflt < low || dflt > high)
1104		default_ok = 0;
1105
1106	if (default_ok)
1107		snprintf(ms, mslen, _("%s (%u-%u, default %u): "),
1108			 mesg, low, high, dflt);
1109	else
1110		snprintf(ms, mslen, "%s (%u-%u): ",
1111			 mesg, low, high);
1112
1113	while (1) {
1114		int use_default = default_ok;
1115
1116		/* ask question and read answer */
1117		while (read_chars(ms) != '\n' && !isdigit(*line_ptr)
1118		       && *line_ptr != '-' && *line_ptr != '+')
1119			continue;
1120
1121		if (*line_ptr == '+' || *line_ptr == '-') {
1122			int minus = (*line_ptr == '-');
1123			int absolute = 0;
1124
1125			i = atoi(line_ptr+1);
1126
1127 			while (isdigit(*++line_ptr))
1128				use_default = 0;
1129
1130			switch (*line_ptr) {
1131				case 'c':
1132				case 'C':
1133					if (!display_in_cyl_units)
1134						i *= heads * sectors;
1135					break;
1136				case 'K':
1137					absolute = 1024;
1138					break;
1139				case 'k':
1140					absolute = 1000;
1141					break;
1142				case 'm':
1143				case 'M':
1144					absolute = 1000000;
1145					break;
1146				case 'g':
1147				case 'G':
1148					absolute = 1000000000;
1149					break;
1150				default:
1151					break;
1152			}
1153			if (absolute) {
1154				unsigned long long bytes;
1155				unsigned long unit;
1156
1157				bytes = (unsigned long long) i * absolute;
1158				unit = sector_size * units_per_sector;
1159				bytes += unit/2;	/* round */
1160				bytes /= unit;
1161				i = bytes;
1162			}
1163			if (minus)
1164				i = -i;
1165			i += base;
1166		} else {
1167			i = atoi(line_ptr);
1168			while (isdigit(*line_ptr)) {
1169				line_ptr++;
1170				use_default = 0;
1171			}
1172		}
1173		if (use_default)
1174			printf(_("Using default value %u\n"), i = dflt);
1175		if (i >= low && i <= high)
1176			break;
1177		else
1178			printf(_("Value out of range.\n"));
1179	}
1180	return i;
1181}
1182
1183int
1184get_partition(int warn, int max) {
1185	struct pte *pe;
1186	int i;
1187
1188	i = read_int(1, 0, max, 0, _("Partition number")) - 1;
1189	pe = &ptes[i];
1190
1191	if (warn) {
1192		if ((!sun_label && !sgi_label && !pe->part_table->sys_ind)
1193		    || (sun_label &&
1194			(!sunlabel->partitions[i].num_sectors ||
1195			 !sunlabel->infos[i].id))
1196		    || (sgi_label && (!sgi_get_num_sectors(i)))
1197		   )
1198			fprintf(stderr,
1199				_("Warning: partition %d has empty type\n"),
1200				i+1);
1201	}
1202	return i;
1203}
1204
1205static int
1206get_existing_partition(int warn, int max) {
1207	int pno = -1;
1208	int i;
1209
1210	for (i = 0; i < max; i++) {
1211		struct pte *pe = &ptes[i];
1212		struct partition *p = pe->part_table;
1213
1214		if (p && !is_cleared_partition(p)) {
1215			if (pno >= 0)
1216				goto not_unique;
1217			pno = i;
1218		}
1219	}
1220	if (pno >= 0) {
1221		printf(_("Selected partition %d\n"), pno+1);
1222		return pno;
1223	}
1224	printf(_("No partition is defined yet!\n"));
1225	return -1;
1226
1227 not_unique:
1228	return get_partition(warn, max);
1229}
1230
1231static int
1232get_nonexisting_partition(int warn, int max) {
1233	int pno = -1;
1234	int i;
1235
1236	for (i = 0; i < max; i++) {
1237		struct pte *pe = &ptes[i];
1238		struct partition *p = pe->part_table;
1239
1240		if (p && is_cleared_partition(p)) {
1241			if (pno >= 0)
1242				goto not_unique;
1243			pno = i;
1244		}
1245	}
1246	if (pno >= 0) {
1247		printf(_("Selected partition %d\n"), pno+1);
1248		return pno;
1249	}
1250	printf(_("All primary partitions have been defined already!\n"));
1251	return -1;
1252
1253 not_unique:
1254	return get_partition(warn, max);
1255}
1256
1257char * const
1258str_units(int n) {	/* n==1: use singular */
1259	if (n == 1)
1260		return display_in_cyl_units ? _("cylinder") : _("sector");
1261	else
1262		return display_in_cyl_units ? _("cylinders") : _("sectors");
1263}
1264
1265void change_units(void)
1266{
1267	display_in_cyl_units = !display_in_cyl_units;
1268	update_units();
1269	printf(_("Changing display/entry units to %s\n"),
1270		str_units(PLURAL));
1271}
1272
1273static void
1274toggle_active(int i) {
1275	struct pte *pe = &ptes[i];
1276	struct partition *p = pe->part_table;
1277
1278	if (IS_EXTENDED (p->sys_ind) && !p->boot_ind)
1279		fprintf(stderr,
1280			_("WARNING: Partition %d is an extended partition\n"),
1281			i + 1);
1282	p->boot_ind = (p->boot_ind ? 0 : ACTIVE_FLAG);
1283	pe->changed = 1;
1284}
1285
1286static void
1287toggle_dos_compatibility_flag(void) {
1288	dos_compatible_flag = ~dos_compatible_flag;
1289	if (dos_compatible_flag) {
1290		sector_offset = sectors;
1291		printf(_("DOS Compatibility flag is set\n"));
1292	}
1293	else {
1294		sector_offset = 1;
1295		printf(_("DOS Compatibility flag is not set\n"));
1296	}
1297}
1298
1299static void
1300delete_partition(int i) {
1301	struct pte *pe = &ptes[i];
1302	struct partition *p = pe->part_table;
1303	struct partition *q = pe->ext_pointer;
1304
1305/* Note that for the fifth partition (i == 4) we don't actually
1306 * decrement partitions.
1307 */
1308
1309	if (warn_geometry())
1310		return;		/* C/H/S not set */
1311	pe->changed = 1;
1312
1313	if (sun_label) {
1314		sun_delete_partition(i);
1315		return;
1316	}
1317
1318	if (sgi_label) {
1319		sgi_delete_partition(i);
1320		return;
1321	}
1322
1323	if (i < 4) {
1324		if (IS_EXTENDED (p->sys_ind) && i == ext_index) {
1325			partitions = 4;
1326			ptes[ext_index].ext_pointer = NULL;
1327			extended_offset = 0;
1328		}
1329		clear_partition(p);
1330		return;
1331	}
1332
1333	if (!q->sys_ind && i > 4) {
1334		/* the last one in the chain - just delete */
1335		--partitions;
1336		--i;
1337		clear_partition(ptes[i].ext_pointer);
1338		ptes[i].changed = 1;
1339	} else {
1340		/* not the last one - further ones will be moved down */
1341		if (i > 4) {
1342			/* delete this link in the chain */
1343			p = ptes[i-1].ext_pointer;
1344			*p = *q;
1345			set_start_sect(p, get_start_sect(q));
1346			set_nr_sects(p, get_nr_sects(q));
1347			ptes[i-1].changed = 1;
1348		} else if (partitions > 5) {    /* 5 will be moved to 4 */
1349			/* the first logical in a longer chain */
1350			struct pte *pe = &ptes[5];
1351
1352			if (pe->part_table) /* prevent SEGFAULT */
1353				set_start_sect(pe->part_table,
1354					       get_partition_start(pe) -
1355					       extended_offset);
1356			pe->offset = extended_offset;
1357			pe->changed = 1;
1358		}
1359
1360		if (partitions > 5) {
1361			partitions--;
1362			while (i < partitions) {
1363				ptes[i] = ptes[i+1];
1364				i++;
1365			}
1366		} else
1367			/* the only logical: clear only */
1368			clear_partition(ptes[i].part_table);
1369	}
1370}
1371
1372static void
1373change_sysid(void) {
1374	char *temp;
1375	int i, sys, origsys;
1376	struct partition *p;
1377
1378	/* If sgi_label then don't use get_existing_partition,
1379	   let the user select a partition, since get_existing_partition()
1380	   only works for Linux like partition tables. */
1381	if (!sgi_label) {
1382		i = get_existing_partition(0, partitions);
1383	} else {
1384		i = get_partition(0, partitions);
1385	}
1386
1387	if (i == -1)
1388		return;
1389	p = ptes[i].part_table;
1390	origsys = sys = get_sysid(i);
1391
1392	/* if changing types T to 0 is allowed, then
1393	   the reverse change must be allowed, too */
1394	if (!sys && !sgi_label && !sun_label && !get_nr_sects(p))
1395                printf(_("Partition %d does not exist yet!\n"), i + 1);
1396        else while (1) {
1397		sys = read_hex (get_sys_types());
1398
1399		if (!sys && !sgi_label && !sun_label) {
1400			printf(_("Type 0 means free space to many systems\n"
1401			       "(but not to Linux). Having partitions of\n"
1402			       "type 0 is probably unwise. You can delete\n"
1403			       "a partition using the `d' command.\n"));
1404			/* break; */
1405		}
1406
1407		if (!sun_label && !sgi_label) {
1408			if (IS_EXTENDED (sys) != IS_EXTENDED (p->sys_ind)) {
1409				printf(_("You cannot change a partition into"
1410				       " an extended one or vice versa\n"
1411				       "Delete it first.\n"));
1412				break;
1413			}
1414		}
1415
1416                if (sys < 256) {
1417			if (sun_label && i == 2 && sys != WHOLE_DISK)
1418				printf(_("Consider leaving partition 3 "
1419				       "as Whole disk (5),\n"
1420				       "as SunOS/Solaris expects it and "
1421				       "even Linux likes it.\n\n"));
1422			if (sgi_label && ((i == 10 && sys != ENTIRE_DISK)
1423					  || (i == 8 && sys != 0)))
1424				printf(_("Consider leaving partition 9 "
1425				       "as volume header (0),\nand "
1426				       "partition 11 as entire volume (6)"
1427				       "as IRIX expects it.\n\n"));
1428                        if (sys == origsys)
1429				break;
1430			if (sun_label) {
1431				sun_change_sysid(i, sys);
1432			} else
1433			if (sgi_label) {
1434				sgi_change_sysid(i, sys);
1435			} else
1436				p->sys_ind = sys;
1437                        printf (_("Changed system type of partition %d "
1438                                "to %x (%s)\n"), i + 1, sys,
1439                                (temp = partition_type(sys)) ? temp :
1440                                _("Unknown"));
1441                        ptes[i].changed = 1;
1442			if (is_dos_partition(origsys) ||
1443			    is_dos_partition(sys))
1444				dos_changed = 1;
1445                        break;
1446                }
1447        }
1448}
1449
1450/* check_consistency() and long2chs() added Sat Mar 6 12:28:16 1993,
1451 * faith@cs.unc.edu, based on code fragments from pfdisk by Gordon W. Ross,
1452 * Jan.  1990 (version 1.2.1 by Gordon W. Ross Aug. 1990; Modified by S.
1453 * Lubkin Oct.  1991). */
1454
1455static void
1456long2chs(ulong ls, unsigned int *c, unsigned int *h, unsigned int *s) {
1457	int spc = heads * sectors;
1458
1459	*c = ls / spc;
1460	ls = ls % spc;
1461	*h = ls / sectors;
1462	*s = ls % sectors + 1;	/* sectors count from 1 */
1463}
1464
1465static void check_consistency(struct partition *p, int partition) {
1466	unsigned int pbc, pbh, pbs;	/* physical beginning c, h, s */
1467	unsigned int pec, peh, pes;	/* physical ending c, h, s */
1468	unsigned int lbc, lbh, lbs;	/* logical beginning c, h, s */
1469	unsigned int lec, leh, les;	/* logical ending c, h, s */
1470
1471	if (!heads || !sectors || (partition >= 4))
1472		return;		/* do not check extended partitions */
1473
1474/* physical beginning c, h, s */
1475	pbc = (p->cyl & 0xff) | ((p->sector << 2) & 0x300);
1476	pbh = p->head;
1477	pbs = p->sector & 0x3f;
1478
1479/* physical ending c, h, s */
1480	pec = (p->end_cyl & 0xff) | ((p->end_sector << 2) & 0x300);
1481	peh = p->end_head;
1482	pes = p->end_sector & 0x3f;
1483
1484/* compute logical beginning (c, h, s) */
1485	long2chs(get_start_sect(p), &lbc, &lbh, &lbs);
1486
1487/* compute logical ending (c, h, s) */
1488	long2chs(get_start_sect(p) + get_nr_sects(p) - 1, &lec, &leh, &les);
1489
1490/* Same physical / logical beginning? */
1491	if (cylinders <= 1024 && (pbc != lbc || pbh != lbh || pbs != lbs)) {
1492		printf(_("Partition %d has different physical/logical "
1493			"beginnings (non-Linux?):\n"), partition + 1);
1494		printf(_("     phys=(%d, %d, %d) "), pbc, pbh, pbs);
1495		printf(_("logical=(%d, %d, %d)\n"),lbc, lbh, lbs);
1496	}
1497
1498/* Same physical / logical ending? */
1499	if (cylinders <= 1024 && (pec != lec || peh != leh || pes != les)) {
1500		printf(_("Partition %d has different physical/logical "
1501			"endings:\n"), partition + 1);
1502		printf(_("     phys=(%d, %d, %d) "), pec, peh, pes);
1503		printf(_("logical=(%d, %d, %d)\n"),lec, leh, les);
1504	}
1505
1506#if 0
1507/* Beginning on cylinder boundary? */
1508	if (pbh != !pbc || pbs != 1) {
1509		printf(_("Partition %i does not start on cylinder "
1510			"boundary:\n"), partition + 1);
1511		printf(_("     phys=(%d, %d, %d) "), pbc, pbh, pbs);
1512		printf(_("should be (%d, %d, 1)\n"), pbc, !pbc);
1513	}
1514#endif
1515
1516/* Ending on cylinder boundary? */
1517	if (peh != (heads - 1) || pes != sectors) {
1518		printf(_("Partition %i does not end on cylinder boundary.\n"),
1519			partition + 1);
1520#if 0
1521		printf(_("     phys=(%d, %d, %d) "), pec, peh, pes);
1522		printf(_("should be (%d, %d, %d)\n"),
1523		pec, heads - 1, sectors);
1524#endif
1525	}
1526}
1527
1528static void
1529list_disk_geometry(void) {
1530	long long bytes = (total_number_of_sectors << 9);
1531	long megabytes = bytes/1000000;
1532
1533	if (megabytes < 10000)
1534		printf(_("\nDisk %s: %ld MB, %lld bytes\n"),
1535		       disk_device, megabytes, bytes);
1536	else
1537		printf(_("\nDisk %s: %ld.%ld GB, %lld bytes\n"),
1538		       disk_device, megabytes/1000, (megabytes/100)%10, bytes);
1539	printf(_("%d heads, %d sectors/track, %d cylinders"),
1540	       heads, sectors, cylinders);
1541	if (units_per_sector == 1)
1542		printf(_(", total %llu sectors"),
1543		       total_number_of_sectors / (sector_size/512));
1544	printf("\n");
1545	printf(_("Units = %s of %d * %d = %d bytes\n\n"),
1546	       str_units(PLURAL),
1547	       units_per_sector, sector_size, units_per_sector * sector_size);
1548}
1549
1550/*
1551 * Check whether partition entries are ordered by their starting positions.
1552 * Return 0 if OK. Return i if partition i should have been earlier.
1553 * Two separate checks: primary and logical partitions.
1554 */
1555static int
1556wrong_p_order(int *prev) {
1557	struct pte *pe;
1558	struct partition *p;
1559	unsigned int last_p_start_pos = 0, p_start_pos;
1560	int i, last_i = 0;
1561
1562	for (i = 0 ; i < partitions; i++) {
1563		if (i == 4) {
1564			last_i = 4;
1565			last_p_start_pos = 0;
1566		}
1567		pe = &ptes[i];
1568		if ((p = pe->part_table)->sys_ind) {
1569			p_start_pos = get_partition_start(pe);
1570
1571			if (last_p_start_pos > p_start_pos) {
1572				if (prev)
1573					*prev = last_i;
1574				return i;
1575			}
1576
1577			last_p_start_pos = p_start_pos;
1578			last_i = i;
1579		}
1580	}
1581	return 0;
1582}
1583
1584/*
1585 * Fix the chain of logicals.
1586 * extended_offset is unchanged, the set of sectors used is unchanged
1587 * The chain is sorted so that sectors increase, and so that
1588 * starting sectors increase.
1589 *
1590 * After this it may still be that cfdisk doesnt like the table.
1591 * (This is because cfdisk considers expanded parts, from link to
1592 * end of partition, and these may still overlap.)
1593 * Now
1594 *   sfdisk /dev/hda > ohda; sfdisk /dev/hda < ohda
1595 * may help.
1596 */
1597static void
1598fix_chain_of_logicals(void) {
1599	int j, oj, ojj, sj, sjj;
1600	struct partition *pj,*pjj,tmp;
1601
1602	/* Stage 1: sort sectors but leave sector of part 4 */
1603	/* (Its sector is the global extended_offset.) */
1604 stage1:
1605	for (j = 5; j < partitions-1; j++) {
1606		oj = ptes[j].offset;
1607		ojj = ptes[j+1].offset;
1608		if (oj > ojj) {
1609			ptes[j].offset = ojj;
1610			ptes[j+1].offset = oj;
1611			pj = ptes[j].part_table;
1612			set_start_sect(pj, get_start_sect(pj)+oj-ojj);
1613			pjj = ptes[j+1].part_table;
1614			set_start_sect(pjj, get_start_sect(pjj)+ojj-oj);
1615			set_start_sect(ptes[j-1].ext_pointer,
1616				       ojj-extended_offset);
1617			set_start_sect(ptes[j].ext_pointer,
1618				       oj-extended_offset);
1619			goto stage1;
1620		}
1621	}
1622
1623	/* Stage 2: sort starting sectors */
1624 stage2:
1625	for (j = 4; j < partitions-1; j++) {
1626		pj = ptes[j].part_table;
1627		pjj = ptes[j+1].part_table;
1628		sj = get_start_sect(pj);
1629		sjj = get_start_sect(pjj);
1630		oj = ptes[j].offset;
1631		ojj = ptes[j+1].offset;
1632		if (oj+sj > ojj+sjj) {
1633			tmp = *pj;
1634			*pj = *pjj;
1635			*pjj = tmp;
1636			set_start_sect(pj, ojj+sjj-oj);
1637			set_start_sect(pjj, oj+sj-ojj);
1638			goto stage2;
1639		}
1640	}
1641
1642	/* Probably something was changed */
1643	for (j = 4; j < partitions; j++)
1644		ptes[j].changed = 1;
1645}
1646
1647static void
1648fix_partition_table_order(void) {
1649	struct pte *pei, *pek;
1650	int i,k;
1651
1652	if (!wrong_p_order(NULL)) {
1653		printf(_("Nothing to do. Ordering is correct already.\n\n"));
1654		return;
1655	}
1656
1657	while ((i = wrong_p_order(&k)) != 0 && i < 4) {
1658		/* partition i should have come earlier, move it */
1659		/* We have to move data in the MBR */
1660		struct partition *pi, *pk, *pe, pbuf;
1661		pei = &ptes[i];
1662		pek = &ptes[k];
1663
1664		pe = pei->ext_pointer;
1665		pei->ext_pointer = pek->ext_pointer;
1666		pek->ext_pointer = pe;
1667
1668		pi = pei->part_table;
1669		pk = pek->part_table;
1670
1671		memmove(&pbuf, pi, sizeof(struct partition));
1672		memmove(pi, pk, sizeof(struct partition));
1673		memmove(pk, &pbuf, sizeof(struct partition));
1674
1675		pei->changed = pek->changed = 1;
1676	}
1677
1678	if (i)
1679		fix_chain_of_logicals();
1680
1681	printf("Done.\n");
1682
1683}
1684
1685static void
1686list_table(int xtra) {
1687	struct partition *p;
1688	char *type;
1689	int i, w;
1690
1691	if (sun_label) {
1692		sun_list_table(xtra);
1693		return;
1694	}
1695
1696	if (sgi_label) {
1697		sgi_list_table(xtra);
1698		return;
1699	}
1700
1701	list_disk_geometry();
1702
1703	if (osf_label) {
1704		xbsd_print_disklabel(xtra);
1705		return;
1706	}
1707
1708	if (is_garbage_table()) {
1709		printf(_("This doesn't look like a partition table\n"
1710			 "Probably you selected the wrong device.\n\n"));
1711	}
1712
1713
1714	/* Heuristic: we list partition 3 of /dev/foo as /dev/foo3,
1715	   but if the device name ends in a digit, say /dev/foo1,
1716	   then the partition is called /dev/foo1p3. */
1717	w = strlen(disk_device);
1718	if (w && isdigit(disk_device[w-1]))
1719		w++;
1720	if (w < 5)
1721		w = 5;
1722
1723	printf(_("%*s Boot      Start        End     Blocks  Id System\n"),
1724	       w+1, _("Device"));
1725
1726	for (i = 0; i < partitions; i++) {
1727		struct pte *pe = &ptes[i];
1728
1729		p = pe->part_table;
1730		if (p && !is_cleared_partition(p)) {
1731			unsigned int psects = get_nr_sects(p);
1732			unsigned int pblocks = psects;
1733			unsigned int podd = 0;
1734
1735			if (sector_size < 1024) {
1736				pblocks /= (1024 / sector_size);
1737				podd = psects % (1024 / sector_size);
1738			}
1739			if (sector_size > 1024)
1740				pblocks *= (sector_size / 1024);
1741                        printf("%s   %c%11lu%11lu%11lu%c %2x %s\n",
1742			partname(disk_device, i+1, w+2),
1743/* boot flag */		!p->boot_ind ? ' ' : p->boot_ind == ACTIVE_FLAG
1744			? '*' : '?',
1745/* start */		(unsigned long) cround(get_partition_start(pe)),
1746/* end */		(unsigned long) cround(get_partition_start(pe) + psects
1747				- (psects ? 1 : 0)),
1748/* odd flag on end */	(unsigned long) pblocks, podd ? '+' : ' ',
1749/* type id */		p->sys_ind,
1750/* type name */		(type = partition_type(p->sys_ind)) ?
1751			type : _("Unknown"));
1752			check_consistency(p, i);
1753		}
1754	}
1755
1756	/* Is partition table in disk order? It need not be, but... */
1757	/* partition table entries are not checked for correct order if this
1758	   is a sgi, sun or aix labeled disk... */
1759	if (dos_label && wrong_p_order(NULL)) {
1760		printf(_("\nPartition table entries are not in disk order\n"));
1761	}
1762}
1763
1764static void
1765x_list_table(int extend) {
1766	struct pte *pe;
1767	struct partition *p;
1768	int i;
1769
1770	printf(_("\nDisk %s: %d heads, %d sectors, %d cylinders\n\n"),
1771		disk_device, heads, sectors, cylinders);
1772        printf(_("Nr AF  Hd Sec  Cyl  Hd Sec  Cyl     Start      Size ID\n"));
1773	for (i = 0 ; i < partitions; i++) {
1774		pe = &ptes[i];
1775		p = (extend ? pe->ext_pointer : pe->part_table);
1776		if (p != NULL) {
1777                        printf("%2d %02x%4d%4d%5d%4d%4d%5d%11u%11u %02x\n",
1778				i + 1, p->boot_ind, p->head,
1779				sector(p->sector),
1780				cylinder(p->sector, p->cyl), p->end_head,
1781				sector(p->end_sector),
1782				cylinder(p->end_sector, p->end_cyl),
1783				get_start_sect(p), get_nr_sects(p), p->sys_ind);
1784			if (p->sys_ind)
1785				check_consistency(p, i);
1786		}
1787	}
1788}
1789
1790static void
1791fill_bounds(unsigned int *first, unsigned int *last) {
1792	int i;
1793	struct pte *pe = &ptes[0];
1794	struct partition *p;
1795
1796	for (i = 0; i < partitions; pe++,i++) {
1797		p = pe->part_table;
1798		if (!p->sys_ind || IS_EXTENDED (p->sys_ind)) {
1799			first[i] = 0xffffffff;
1800			last[i] = 0;
1801		} else {
1802			first[i] = get_partition_start(pe);
1803			last[i] = first[i] + get_nr_sects(p) - 1;
1804		}
1805	}
1806}
1807
1808static void
1809check(int n, unsigned int h, unsigned int s, unsigned int c,
1810      unsigned int start) {
1811	unsigned int total, real_s, real_c;
1812
1813	real_s = sector(s) - 1;
1814	real_c = cylinder(s, c);
1815	total = (real_c * sectors + real_s) * heads + h;
1816	if (!total)
1817		fprintf(stderr, _("Warning: partition %d contains sector 0\n"), n);
1818	if (h >= heads)
1819		fprintf(stderr,
1820			_("Partition %d: head %d greater than maximum %d\n"),
1821			n, h + 1, heads);
1822	if (real_s >= sectors)
1823		fprintf(stderr, _("Partition %d: sector %d greater than "
1824			"maximum %d\n"), n, s, sectors);
1825	if (real_c >= cylinders)
1826		fprintf(stderr, _("Partitions %d: cylinder %d greater than "
1827			"maximum %d\n"), n, real_c + 1, cylinders);
1828	if (cylinders <= 1024 && start != total)
1829		fprintf(stderr,
1830			_("Partition %d: previous sectors %d disagrees with "
1831			"total %d\n"), n, start, total);
1832}
1833
1834static void
1835verify(void) {
1836	int i, j;
1837	unsigned int total = 1;
1838	unsigned int first[partitions], last[partitions];
1839	struct partition *p;
1840
1841	if (warn_geometry())
1842		return;
1843
1844	if (sun_label) {
1845		verify_sun();
1846		return;
1847	}
1848
1849	if (sgi_label) {
1850		verify_sgi(1);
1851		return;
1852	}
1853
1854	fill_bounds(first, last);
1855	for (i = 0; i < partitions; i++) {
1856		struct pte *pe = &ptes[i];
1857
1858		p = pe->part_table;
1859		if (p->sys_ind && !IS_EXTENDED (p->sys_ind)) {
1860			check_consistency(p, i);
1861			if (get_partition_start(pe) < first[i])
1862				printf(_("Warning: bad start-of-data in "
1863					"partition %d\n"), i + 1);
1864			check(i + 1, p->end_head, p->end_sector, p->end_cyl,
1865				last[i]);
1866			total += last[i] + 1 - first[i];
1867			for (j = 0; j < i; j++)
1868			if ((first[i] >= first[j] && first[i] <= last[j])
1869			 || ((last[i] <= last[j] && last[i] >= first[j]))) {
1870				printf(_("Warning: partition %d overlaps "
1871					"partition %d.\n"), j + 1, i + 1);
1872				total += first[i] >= first[j] ?
1873					first[i] : first[j];
1874				total -= last[i] <= last[j] ?
1875					last[i] : last[j];
1876			}
1877		}
1878	}
1879
1880	if (extended_offset) {
1881		struct pte *pex = &ptes[ext_index];
1882		unsigned int e_last = get_start_sect(pex->part_table) +
1883			get_nr_sects(pex->part_table) - 1;
1884
1885		for (i = 4; i < partitions; i++) {
1886			total++;
1887			p = ptes[i].part_table;
1888			if (!p->sys_ind) {
1889				if (i != 4 || i + 1 < partitions)
1890					printf(_("Warning: partition %d "
1891						"is empty\n"), i + 1);
1892			}
1893			else if (first[i] < extended_offset ||
1894					last[i] > e_last)
1895				printf(_("Logical partition %d not entirely in "
1896					"partition %d\n"), i + 1, ext_index + 1);
1897		}
1898	}
1899
1900	if (total > total_number_of_sectors)
1901		printf(_("Total allocated sectors %d greater than the maximum "
1902			"%lld\n"), total, total_number_of_sectors);
1903	else if (total < total_number_of_sectors)
1904		printf(_("%lld unallocated sectors\n"),
1905		       total_number_of_sectors - total);
1906}
1907
1908static void
1909add_partition(int n, int sys) {
1910	char mesg[256];		/* 48 does not suffice in Japanese */
1911	int i, read = 0;
1912	struct partition *p = ptes[n].part_table;
1913	struct partition *q = ptes[ext_index].part_table;
1914	long long llimit;
1915	unsigned int start, stop = 0, limit, temp,
1916		first[partitions], last[partitions];
1917
1918	if (p && p->sys_ind) {
1919		printf(_("Partition %d is already defined.  Delete "
1920			 "it before re-adding it.\n"), n + 1);
1921		return;
1922	}
1923	fill_bounds(first, last);
1924	if (n < 4) {
1925		start = sector_offset;
1926		if (display_in_cyl_units || !total_number_of_sectors)
1927			llimit = heads * sectors * cylinders - 1;
1928		else
1929			llimit = total_number_of_sectors - 1;
1930		limit = llimit;
1931		if (limit != llimit)
1932			limit = 0x7fffffff;
1933		if (extended_offset) {
1934			first[ext_index] = extended_offset;
1935			last[ext_index] = get_start_sect(q) +
1936				get_nr_sects(q) - 1;
1937		}
1938	} else {
1939		start = extended_offset + sector_offset;
1940		limit = get_start_sect(q) + get_nr_sects(q) - 1;
1941	}
1942	if (display_in_cyl_units)
1943		for (i = 0; i < partitions; i++)
1944			first[i] = (cround(first[i]) - 1) * units_per_sector;
1945
1946	snprintf(mesg, sizeof(mesg), _("First %s"), str_units(SINGULAR));
1947	do {
1948		temp = start;
1949		for (i = 0; i < partitions; i++) {
1950			int lastplusoff;
1951
1952			if (start == ptes[i].offset)
1953				start += sector_offset;
1954			lastplusoff = last[i] + ((n<4) ? 0 : sector_offset);
1955			if (start >= first[i] && start <= lastplusoff)
1956				start = lastplusoff + 1;
1957		}
1958		if (start > limit)
1959			break;
1960		if (start >= temp+units_per_sector && read) {
1961			printf(_("Sector %d is already allocated\n"), temp);
1962			temp = start;
1963			read = 0;
1964		}
1965		if (!read && start == temp) {
1966			unsigned int i = start;
1967
1968			start = read_int(cround(i), cround(i), cround(limit),
1969					 0, mesg);
1970			if (display_in_cyl_units) {
1971				start = (start - 1) * units_per_sector;
1972				if (start < i) start = i;
1973			}
1974			read = 1;
1975		}
1976	} while (start != temp || !read);
1977	if (n > 4) {			/* NOT for fifth partition */
1978		struct pte *pe = &ptes[n];
1979
1980		pe->offset = start - sector_offset;
1981		if (pe->offset == extended_offset) { /* must be corrected */
1982			pe->offset++;
1983			if (sector_offset == 1)
1984				start++;
1985		}
1986	}
1987
1988	for (i = 0; i < partitions; i++) {
1989		struct pte *pe = &ptes[i];
1990
1991		if (start < pe->offset && limit >= pe->offset)
1992			limit = pe->offset - 1;
1993		if (start < first[i] && limit >= first[i])
1994			limit = first[i] - 1;
1995	}
1996	if (start > limit) {
1997		printf(_("No free sectors available\n"));
1998		if (n > 4)
1999			partitions--;
2000		return;
2001	}
2002	if (cround(start) == cround(limit)) {
2003		stop = limit;
2004	} else {
2005		snprintf(mesg, sizeof(mesg),
2006			 _("Last %s or +size or +sizeM or +sizeK"),
2007			 str_units(SINGULAR));
2008		stop = read_int(cround(start), cround(limit), cround(limit),
2009				cround(start), mesg);
2010		if (display_in_cyl_units) {
2011			stop = stop * units_per_sector - 1;
2012			if (stop >limit)
2013				stop = limit;
2014		}
2015	}
2016
2017	set_partition(n, 0, start, stop, sys);
2018	if (n > 4)
2019		set_partition(n - 1, 1, ptes[n].offset, stop, EXTENDED);
2020
2021	if (IS_EXTENDED (sys)) {
2022		struct pte *pe4 = &ptes[4];
2023		struct pte *pen = &ptes[n];
2024
2025		ext_index = n;
2026		pen->ext_pointer = p;
2027		pe4->offset = extended_offset = start;
2028		if (!(pe4->sectorbuffer = calloc(1, sector_size)))
2029			fatal(out_of_memory);
2030		pe4->part_table = pt_offset(pe4->sectorbuffer, 0);
2031		pe4->ext_pointer = pe4->part_table + 1;
2032		pe4->changed = 1;
2033		partitions = 5;
2034	}
2035}
2036
2037static void
2038add_logical(void) {
2039	if (partitions > 5 || ptes[4].part_table->sys_ind) {
2040		struct pte *pe = &ptes[partitions];
2041
2042		if (!(pe->sectorbuffer = calloc(1, sector_size)))
2043			fatal(out_of_memory);
2044		pe->part_table = pt_offset(pe->sectorbuffer, 0);
2045		pe->ext_pointer = pe->part_table + 1;
2046		pe->offset = 0;
2047		pe->changed = 1;
2048		partitions++;
2049	}
2050	add_partition(partitions - 1, LINUX_NATIVE);
2051}
2052
2053static void
2054new_partition(void) {
2055	int i, free_primary = 0;
2056
2057	if (warn_geometry())
2058		return;
2059
2060	if (sun_label) {
2061		add_sun_partition(get_partition(0, partitions), LINUX_NATIVE);
2062		return;
2063	}
2064
2065	if (sgi_label) {
2066		sgi_add_partition(get_partition(0, partitions), LINUX_NATIVE);
2067		return;
2068	}
2069
2070	if (aix_label) {
2071		printf(_("\tSorry - this fdisk cannot handle AIX disk labels."
2072			 "\n\tIf you want to add DOS-type partitions, create"
2073			 "\n\ta new empty DOS partition table first. (Use o.)"
2074			 "\n\tWARNING: "
2075			 "This will destroy the present disk contents.\n"));
2076		return;
2077	}
2078
2079	for (i = 0; i < 4; i++)
2080		free_primary += !ptes[i].part_table->sys_ind;
2081
2082	if (!free_primary && partitions >= MAXIMUM_PARTS) {
2083		printf(_("The maximum number of partitions has been created\n"));
2084		return;
2085	}
2086
2087	if (!free_primary) {
2088		if (extended_offset)
2089			add_logical();
2090		else
2091			printf(_("You must delete some partition and add "
2092				 "an extended partition first\n"));
2093	} else if (partitions >= MAXIMUM_PARTS) {
2094		printf(_("All logical partitions are in use\n"));
2095		printf(_("Adding a primary partition\n"));
2096		add_partition(get_partition(0, 4), LINUX_NATIVE);
2097	} else {
2098		char c, line[LINE_LENGTH];
2099		snprintf(line, sizeof(line),
2100			 _("Command action\n   %s\n   p   primary "
2101			   "partition (1-4)\n"), extended_offset ?
2102			 _("l   logical (5 or over)") : _("e   extended"));
2103		while (1) {
2104			if ((c = tolower(read_char(line))) == 'p') {
2105				int i = get_nonexisting_partition(0, 4);
2106				if (i >= 0)
2107					add_partition(i, LINUX_NATIVE);
2108				return;
2109			}
2110			else if (c == 'l' && extended_offset) {
2111				add_logical();
2112				return;
2113			}
2114			else if (c == 'e' && !extended_offset) {
2115				int i = get_nonexisting_partition(0, 4);
2116				if (i >= 0)
2117					add_partition(i, EXTENDED);
2118				return;
2119			}
2120			else
2121				printf(_("Invalid partition number "
2122					 "for type `%c'\n"), c);
2123		}
2124	}
2125}
2126
2127static void
2128write_table(void) {
2129	int i;
2130	if (dos_label) {
2131		for (i=0; i<3; i++)
2132			if (ptes[i].changed)
2133				ptes[3].changed = 1;
2134		for (i = 3; i < partitions; i++) {
2135			struct pte *pe = &ptes[i];
2136
2137			if (pe->changed) {
2138				write_part_table_flag(pe->sectorbuffer);
2139				write_sector(fd, pe->offset, pe->sectorbuffer);
2140			}
2141		}
2142	}
2143	else if (sgi_label) {
2144		/* no test on change? the printf below might be mistaken */
2145		sgi_write_table();
2146	} else if (sun_label) {
2147		int needw = 0;
2148
2149		for (i=0; i<8; i++)
2150			if (ptes[i].changed)
2151				needw = 1;
2152		if (needw)
2153			sun_write_table();
2154	}
2155
2156	printf(_("The partition table has been altered!\n\n"));
2157	reread_partition_table(1);
2158}
2159
2160void
2161reread_partition_table(int leave) {
2162	int error = 0;
2163	int i;
2164
2165	printf(_("Calling ioctl() to re-read partition table.\n"));
2166	sync();
2167	sleep(2);
2168	if ((i = ioctl(fd, BLKRRPART)) != 0) {
2169                error = errno;
2170        } else {
2171                /* some kernel versions (1.2.x) seem to have trouble
2172                   rereading the partition table, but if asked to do it
2173		   twice, the second time works. - biro@yggdrasil.com */
2174                sync();
2175                sleep(2);
2176                if ((i = ioctl(fd, BLKRRPART)) != 0)
2177                        error = errno;
2178        }
2179
2180	if (i) {
2181		printf(_("\nWARNING: Re-reading the partition table "
2182			 "failed with error %d: %s.\n"
2183			 "The kernel still uses the old table.\n"
2184			 "The new table will be used "
2185			 "at the next reboot.\n"),
2186			error, strerror(error));
2187	}
2188
2189	if (dos_changed)
2190	    printf(
2191		_("\nWARNING: If you have created or modified any DOS 6.x\n"
2192		"partitions, please see the fdisk manual page for additional\n"
2193		"information.\n"));
2194
2195	if (leave) {
2196		if (fsync(fd) || close(fd)) {
2197			fprintf(stderr, _("\nError closing file\n"));
2198			exit(1);
2199		}
2200
2201		printf(_("Syncing disks.\n"));
2202		sync();
2203		sleep(4);		/* for sync() */
2204
2205		exit(!!i);
2206	}
2207}
2208
2209#define MAX_PER_LINE	16
2210static void
2211print_buffer(char pbuffer[]) {
2212	int	i,
2213		l;
2214
2215	for (i = 0, l = 0; i < sector_size; i++, l++) {
2216		if (l == 0)
2217			printf("0x%03X:", i);
2218		printf(" %02X", (unsigned char) pbuffer[i]);
2219		if (l == MAX_PER_LINE - 1) {
2220			printf("\n");
2221			l = -1;
2222		}
2223	}
2224	if (l > 0)
2225		printf("\n");
2226	printf("\n");
2227}
2228
2229static void
2230print_raw(void) {
2231	int i;
2232
2233	printf(_("Device: %s\n"), disk_device);
2234	if (sun_label || sgi_label)
2235		print_buffer(MBRbuffer);
2236	else for (i = 3; i < partitions; i++)
2237		print_buffer(ptes[i].sectorbuffer);
2238}
2239
2240static void
2241move_begin(int i) {
2242	struct pte *pe = &ptes[i];
2243	struct partition *p = pe->part_table;
2244	unsigned int new, first;
2245
2246	if (warn_geometry())
2247		return;
2248	if (!p->sys_ind || !get_nr_sects(p) || IS_EXTENDED (p->sys_ind)) {
2249		printf(_("Partition %d has no data area\n"), i + 1);
2250		return;
2251	}
2252	first = get_partition_start(pe);
2253	new = read_int(first, first, first + get_nr_sects(p) - 1, first,
2254		       _("New beginning of data")) - pe->offset;
2255
2256	if (new != get_nr_sects(p)) {
2257		first = get_nr_sects(p) + get_start_sect(p) - new;
2258		set_nr_sects(p, first);
2259		set_start_sect(p, new);
2260		pe->changed = 1;
2261	}
2262}
2263
2264static void
2265xselect(void) {
2266	char c;
2267
2268	while(1) {
2269		putchar('\n');
2270		c = tolower(read_char(_("Expert command (m for help): ")));
2271		switch (c) {
2272		case 'a':
2273			if (sun_label)
2274				sun_set_alt_cyl();
2275			break;
2276		case 'b':
2277			if (dos_label)
2278				move_begin(get_partition(0, partitions));
2279			break;
2280		case 'c':
2281			user_cylinders = cylinders =
2282				read_int(1, cylinders, 1048576, 0,
2283					 _("Number of cylinders"));
2284			if (sun_label)
2285				sun_set_ncyl(cylinders);
2286			if (dos_label)
2287				warn_cylinders();
2288			break;
2289		case 'd':
2290			print_raw();
2291			break;
2292		case 'e':
2293			if (sgi_label)
2294				sgi_set_xcyl();
2295			else if (sun_label)
2296				sun_set_xcyl();
2297			else
2298			if (dos_label)
2299				x_list_table(1);
2300			break;
2301		case 'f':
2302			if (dos_label)
2303				fix_partition_table_order();
2304			break;
2305		case 'g':
2306			create_sgilabel();
2307			break;
2308		case 'h':
2309			user_heads = heads = read_int(1, heads, 256, 0,
2310					 _("Number of heads"));
2311			update_units();
2312			break;
2313		case 'i':
2314			if (sun_label)
2315				sun_set_ilfact();
2316			break;
2317		case 'o':
2318			if (sun_label)
2319				sun_set_rspeed();
2320			break;
2321		case 'p':
2322			if (sun_label)
2323				list_table(1);
2324			else
2325				x_list_table(0);
2326			break;
2327		case 'q':
2328			close(fd);
2329			printf("\n");
2330			exit(0);
2331		case 'r':
2332			return;
2333		case 's':
2334			user_sectors = sectors = read_int(1, sectors, 63, 0,
2335					   _("Number of sectors"));
2336			if (dos_compatible_flag) {
2337				sector_offset = sectors;
2338				fprintf(stderr, _("Warning: setting "
2339					"sector offset for DOS "
2340					"compatiblity\n"));
2341			}
2342			update_units();
2343			break;
2344		case 'v':
2345			verify();
2346			break;
2347		case 'w':
2348			write_table();	/* does not return */
2349			break;
2350		case 'y':
2351			if (sun_label)
2352				sun_set_pcylcount();
2353			break;
2354		default:
2355			xmenu();
2356		}
2357	}
2358}
2359
2360static int
2361is_ide_cdrom_or_tape(char *device) {
2362	FILE *procf;
2363	char buf[100];
2364	struct stat statbuf;
2365	int is_ide = 0;
2366
2367	/* No device was given explicitly, and we are trying some
2368	   likely things.  But opening /dev/hdc may produce errors like
2369           "hdc: tray open or drive not ready"
2370	   if it happens to be a CD-ROM drive. It even happens that
2371	   the process hangs on the attempt to read a music CD.
2372	   So try to be careful. This only works since 2.1.73. */
2373
2374	if (strncmp("/dev/hd", device, 7))
2375		return 0;
2376
2377	snprintf(buf, sizeof(buf), "/proc/ide/%s/media", device+5);
2378	procf = fopen(buf, "r");
2379	if (procf != NULL && fgets(buf, sizeof(buf), procf))
2380		is_ide = (!strncmp(buf, "cdrom", 5) ||
2381			  !strncmp(buf, "tape", 4));
2382	else
2383		/* Now when this proc file does not exist, skip the
2384		   device when it is read-only. */
2385		if (stat(device, &statbuf) == 0)
2386			is_ide = ((statbuf.st_mode & 0222) == 0);
2387
2388	if (procf)
2389		fclose(procf);
2390	return is_ide;
2391}
2392
2393static void
2394try(char *device, int user_specified) {
2395	int gb;
2396
2397	disk_device = device;
2398	if (setjmp(listingbuf))
2399		return;
2400	if (!user_specified)
2401		if (is_ide_cdrom_or_tape(device))
2402			return;
2403	if ((fd = open(disk_device, type_open)) >= 0) {
2404		gb = get_boot(try_only);
2405		if (gb > 0) { /* I/O error */
2406		} else if (gb < 0) { /* no DOS signature */
2407			list_disk_geometry();
2408			if (!aix_label && btrydev(device) < 0)
2409				fprintf(stderr,
2410					_("Disk %s doesn't contain a valid "
2411					  "partition table\n"), device);
2412		} else {
2413			list_table(0);
2414		}
2415		close(fd);
2416	} else {
2417		/* Ignore other errors, since we try IDE
2418		   and SCSI hard disks which may not be
2419		   installed on the system. */
2420		if (errno == EACCES) {
2421			fprintf(stderr, _("Cannot open %s\n"), device);
2422			return;
2423		}
2424	}
2425}
2426
2427/*
2428 * for fdisk -l:
2429 * try all things in /proc/partitions that look like a full disk
2430 */
2431static void
2432tryprocpt(void) {
2433	FILE *procpt;
2434	char line[100], ptname[100], devname[120];
2435	int ma, mi, sz;
2436
2437	procpt = fopen(PROC_PARTITIONS, "r");
2438	if (procpt == NULL) {
2439		fprintf(stderr, _("cannot open %s\n"), PROC_PARTITIONS);
2440		return;
2441	}
2442
2443	while (fgets(line, sizeof(line), procpt)) {
2444		if (sscanf (line, " %d %d %d %[^\n ]",
2445			    &ma, &mi, &sz, ptname) != 4)
2446			continue;
2447		snprintf(devname, sizeof(devname), "/dev/%s", ptname);
2448		if (is_probably_full_disk(devname))
2449			try(devname, 0);
2450	}
2451	fclose(procpt);
2452}
2453
2454static void
2455dummy(int *kk) {}
2456
2457static void
2458unknown_command(int c) {
2459	printf(_("%c: unknown command\n"), c);
2460}
2461
2462int
2463main(int argc, char **argv) {
2464	int j, c;
2465	int optl = 0, opts = 0;
2466
2467//	setlocale(LC_ALL, "");
2468//	bindtextdomain(PACKAGE, LOCALEDIR);
2469//	textdomain(PACKAGE);
2470
2471	/*
2472	 * Calls:
2473	 *  fdisk -v
2474	 *  fdisk -l [-b sectorsize] [-u] device ...
2475	 *  fdisk -s [partition] ...
2476	 *  fdisk [-b sectorsize] [-u] device
2477	 *
2478	 * Options -C, -H, -S set the geometry.
2479	 *
2480	 */
2481	while ((c = getopt(argc, argv, "b:C:H:lsS:uvV")) != -1) {
2482		switch (c) {
2483		case 'b':
2484			/* Ugly: this sector size is really per device,
2485			   so cannot be combined with multiple disks,
2486			   and te same goes for the C/H/S options.
2487			*/
2488			sector_size = atoi(optarg);
2489			if (sector_size != 512 && sector_size != 1024 &&
2490			    sector_size != 2048)
2491				fatal(usage);
2492			sector_offset = 2;
2493			user_set_sector_size = 1;
2494			break;
2495		case 'C':
2496			user_cylinders = atoi(optarg);
2497			break;
2498		case 'H':
2499			user_heads = atoi(optarg);
2500			if (user_heads <= 0 || user_heads >= 256)
2501				user_heads = 0;
2502			break;
2503		case 'S':
2504			user_sectors = atoi(optarg);
2505			if (user_sectors <= 0 || user_sectors >= 64)
2506				user_sectors = 0;
2507			break;
2508		case 'l':
2509			optl = 1;
2510			break;
2511		case 's':
2512			opts = 1;
2513			break;
2514		case 'u':
2515			display_in_cyl_units = 0;
2516			break;
2517		case 'V':
2518		case 'v':
2519			printf("fdisk (%s)\n", PACKAGE_STRING);
2520			exit(0);
2521		default:
2522			fatal(usage);
2523		}
2524	}
2525
2526#if 0
2527	printf(_("This kernel finds the sector size itself - "
2528		 "-b option ignored\n"));
2529#else
2530	if (user_set_sector_size && argc-optind != 1)
2531		printf(_("Warning: the -b (set sector size) option should"
2532			 " be used with one specified device\n"));
2533#endif
2534
2535	if (optl) {
2536		nowarn = 1;
2537		type_open = O_RDONLY;
2538		if (argc > optind) {
2539			int k;
2540			/* avoid gcc warning:
2541			   variable `k' might be clobbered by `longjmp' */
2542			dummy(&k);
2543			listing = 1;
2544			for (k = optind; k < argc; k++)
2545				try(argv[k], 1);
2546		} else {
2547			/* we no longer have default device names */
2548			/* but we can use /proc/partitions instead */
2549			tryprocpt();
2550		}
2551		exit(0);
2552	}
2553
2554	if (opts) {
2555		unsigned long long size;
2556
2557		nowarn = 1;
2558		type_open = O_RDONLY;
2559
2560		opts = argc - optind;
2561		if (opts <= 0)
2562			fatal(usage);
2563
2564		for (j = optind; j < argc; j++) {
2565			disk_device = argv[j];
2566			if ((fd = open(disk_device, type_open)) < 0)
2567				fatal(unable_to_open);
2568			if (disksize(fd, &size))
2569				fatal(ioctl_error);
2570			close(fd);
2571			if (opts == 1)
2572				printf("%llu\n", size/2);
2573			else
2574				printf("%s: %llu\n", argv[j], size/2);
2575		}
2576		exit(0);
2577	}
2578
2579	if (argc-optind == 1)
2580		disk_device = argv[optind];
2581	else if (argc-optind != 0)
2582		fatal(usage);
2583	else
2584		fatal(usage2);
2585
2586	get_boot(fdisk);
2587
2588	if (osf_label) {
2589		/* OSF label, and no DOS label */
2590		printf(_("Detected an OSF/1 disklabel on %s, entering "
2591			 "disklabel mode.\n"),
2592		       disk_device);
2593		bselect();
2594		osf_label = 0;
2595		/* If we return we may want to make an empty DOS label? */
2596	}
2597
2598	while (1) {
2599		putchar('\n');
2600		c = tolower(read_char(_("Command (m for help): ")));
2601		switch (c) {
2602		case 'a':
2603			if (dos_label)
2604				toggle_active(get_partition(1, partitions));
2605			else if (sun_label)
2606				toggle_sunflags(get_partition(1, partitions),
2607						0x01);
2608			else if (sgi_label)
2609				sgi_set_bootpartition(
2610					get_partition(1, partitions));
2611			else
2612				unknown_command(c);
2613			break;
2614		case 'b':
2615			if (sgi_label) {
2616				printf(_("\nThe current boot file is: %s\n"),
2617				       sgi_get_bootfile());
2618				if (read_chars(_("Please enter the name of the "
2619					       "new boot file: ")) == '\n')
2620					printf(_("Boot file unchanged\n"));
2621				else
2622					sgi_set_bootfile(line_ptr);
2623			} else
2624				bselect();
2625			break;
2626		case 'c':
2627			if (dos_label)
2628				toggle_dos_compatibility_flag();
2629			else if (sun_label)
2630				toggle_sunflags(get_partition(1, partitions),
2631						0x10);
2632			else if (sgi_label)
2633				sgi_set_swappartition(
2634						get_partition(1, partitions));
2635			else
2636				unknown_command(c);
2637			break;
2638		case 'd':
2639        		/* If sgi_label then don't use get_existing_partition,
2640			   let the user select a partition, since
2641			   get_existing_partition() only works for Linux-like
2642			   partition tables */
2643        		if (!sgi_label) {
2644                		j = get_existing_partition(1, partitions);
2645        		} else {
2646                		j = get_partition(1, partitions);
2647        		}
2648			if (j >= 0)
2649				delete_partition(j);
2650			break;
2651		case 'i':
2652			if (sgi_label)
2653				create_sgiinfo();
2654			else
2655				unknown_command(c);
2656		case 'l':
2657			list_types(get_sys_types());
2658			break;
2659		case 'm':
2660			menu();
2661			break;
2662		case 'n':
2663			new_partition();
2664			break;
2665		case 'o':
2666			create_doslabel();
2667			break;
2668		case 'p':
2669			list_table(0);
2670			break;
2671		case 'q':
2672			close(fd);
2673			printf("\n");
2674			exit(0);
2675		case 's':
2676			create_sunlabel();
2677			break;
2678		case 't':
2679			change_sysid();
2680			break;
2681		case 'u':
2682			change_units();
2683			break;
2684		case 'v':
2685			verify();
2686			break;
2687		case 'w':
2688			write_table();	/* does not return */
2689			break;
2690		case 'x':
2691			if (sgi_label) {
2692				fprintf(stderr,
2693					_("\n\tSorry, no experts menu for SGI "
2694					"partition tables available.\n\n"));
2695			} else
2696				xselect();
2697			break;
2698		default:
2699			unknown_command(c);
2700			menu();
2701		}
2702	}
2703	return 0;
2704}
2705