1 /*
2  * sfdisk version 3.0 - aeb - 950813
3  *
4  * Copyright (C) 1995  Andries E. Brouwer (aeb@cwi.nl)
5  *
6  * This program is free software. You can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation: either Version 1
9  * or (at your option) any later version.
10  *
11  * A.V. Le Blanc (LeBlanc@mcc.ac.uk) wrote Linux fdisk 1992-1994,
12  * patched by various people (faith@cs.unc.edu, martin@cs.unc.edu,
13  * leisner@sdsp.mc.xerox.com, esr@snark.thyrsus.com, aeb@cwi.nl)
14  * 1993-1995, with version numbers (as far as I have seen) 0.93 - 2.0e.
15  * This program had (head,sector,cylinder) as basic unit, and was
16  * (therefore) broken in several ways for the use on larger disks -
17  * for example, my last patch (from 2.0d to 2.0e) was required
18  * to allow a partition to cross cylinder 8064, and to write an
19  * extended partition past the 4GB mark.
20  *
21  * The current program is a rewrite from scratch, and I started a
22  * version numbering at 3.0.
23  *	Andries Brouwer, aeb@cwi.nl, 950813
24  *
25  * Well, a good user interface is still lacking. On the other hand,
26  * many configurations cannot be handled by any other fdisk.
27  * I changed the name to sfdisk to prevent confusion. - aeb, 970501
28  */
29 
30 #include <stdio.h>
31 #include <stdlib.h>		/* atoi, free */
32 #include <stdarg.h>		/* varargs */
33 #include <unistd.h>		/* read, write */
34 #include <fcntl.h>		/* O_RDWR */
35 #include <errno.h>		/* ERANGE */
36 #include <string.h>		/* strchr(), strrchr() */
37 #include <ctype.h>
38 #include <getopt.h>
39 #include <sys/ioctl.h>
40 #include <sys/stat.h>
41 #include <sys/utsname.h>
42 #include <limits.h>
43 
44 #include "c.h"
45 #include "nls.h"
46 #include "xalloc.h"
47 #include "blkdev.h"
48 #include "linux_version.h"
49 #include "pathnames.h"
50 #include "canonicalize.h"
51 #include "rpmatch.h"
52 #include "closestream.h"
53 #include "strutils.h"
54 #include "sysfs.h"
55 
56 struct systypes {
57 	unsigned char type;
58 	char *name;
59 };
60 
61 static struct systypes i386_sys_types[] = {
62 	#include "pt-mbr-partnames.h"
63 };
64 
65 static char *partname(char *dev, int pno, int lth);
66 
67 /*
68  * Table of contents:
69  *  A. About seeking
70  *  B. About sectors
71  *  C. About heads, sectors and cylinders
72  *  D. About system Ids
73  *  E. About partitions
74  *  F. The standard input
75  *  G. The command line
76  *  H. Listing the current situation
77  *  I. Writing the new situation
78  */
79 int exit_status = 0;
80 
81 int force = 0;			/* 1: do what I say, even if it is stupid ... */
82 int quiet = 0;			/* 1: suppress all warnings */
83 /* IA-64 gcc spec file currently does -DLinux... */
84 #undef Linux
85 int Linux = 0;			/* 1: suppress warnings irrelevant for Linux */
86 int DOS = 0;			/* 1: shift extended partitions by #sectors, not 1 */
87 int DOS_extended = 0;		/* 1: use starting cylinder boundary of extd partn */
88 int dump = 0;			/* 1: list in a format suitable for later input */
89 int verify = 0;			/* 1: check that listed partition is reasonable */
90 int no_write = 0;		/* 1: do not actually write to disk */
91 int no_reread = 0;		/* 1: skip the BLKRRPART ioctl test at startup */
92 int leave_last = 0;		/* 1: don't allocate the last cylinder */
93 int opt_list = 0;
94 char *save_sector_file = NULL;
95 char *restore_sector_file = NULL;
96 
97 /*
98  *  A. About seeking
99  */
100 
101 /*
102  * sseek: seek to specified sector - return 0 on failure
103  *
104  * Note: we use 512-byte sectors here, irrespective of the hardware ss.
105  */
106 
107 static int
sseek(char * dev,int fd,unsigned long s)108 sseek(char *dev, int fd, unsigned long s) {
109     off_t in, out;
110     in = ((off_t) s << 9);
111 
112     if ((out = lseek(fd, in, SEEK_SET)) != in) {
113 	warn(_("seek error on %s - cannot seek to %lu"), dev, s);
114 	return 0;
115     }
116 
117     if (in != out) {
118 	warnx(_("seek error: wanted 0x%08x%08x, got 0x%08x%08x"),
119 	      (unsigned int)(in >> 32), (unsigned int)(in & 0xffffffff),
120 	      (unsigned int)(out >> 32), (unsigned int)(out & 0xffffffff));
121 	return 0;
122     }
123     return 1;
124 }
125 
126 /*
127  *  B. About sectors
128  */
129 
130 /*
131  * We preserve all sectors read in a chain - some of these will
132  * have to be modified and written back.
133  */
134 struct sector {
135     struct sector *next;
136     unsigned long long sectornumber;
137     int to_be_written;
138     char data[512];
139 } *sectorhead;
140 
141 static void
free_sectors(void)142 free_sectors(void) {
143     struct sector *s;
144 
145     while (sectorhead) {
146 	s = sectorhead;
147 	sectorhead = s->next;
148 	free(s);
149     }
150 }
151 
152 static struct sector *
get_sector(char * dev,int fd,unsigned long long sno)153 get_sector(char *dev, int fd, unsigned long long sno) {
154     struct sector *s;
155 
156     for (s = sectorhead; s; s = s->next)
157 	if (s->sectornumber == sno)
158 	    return s;
159 
160     if (!sseek(dev, fd, sno))
161 	return 0;
162 
163     s = xmalloc(sizeof(struct sector));
164 
165     if (read(fd, s->data, sizeof(s->data)) != sizeof(s->data)) {
166 	warn(_("read error on %s - cannot read sector %llu"), dev, sno);
167 	free(s);
168 	return 0;
169     }
170 
171     s->next = sectorhead;
172     sectorhead = s;
173     s->sectornumber = sno;
174     s->to_be_written = 0;
175 
176     return s;
177 }
178 
179 static int
msdos_signature(struct sector * s)180 msdos_signature(struct sector *s) {
181     unsigned char *data = (unsigned char *)s->data;
182     if (data[510] == 0x55 && data[511] == 0xaa)
183 	return 1;
184     return 0;
185 }
186 
187 static int
write_sectors(char * dev,int fd)188 write_sectors(char *dev, int fd) {
189     struct sector *s;
190 
191     for (s = sectorhead; s; s = s->next)
192 	if (s->to_be_written) {
193 	    if (!sseek(dev, fd, s->sectornumber))
194 		return 0;
195 	    if (write(fd, s->data, sizeof(s->data)) != sizeof(s->data)) {
196 		warn(_("write error on %s - cannot write sector %llu"),
197 		     dev, s->sectornumber);
198 		return 0;
199 	    }
200 	    s->to_be_written = 0;
201 	}
202     return 1;
203 }
204 
205 static void
ulong_to_chars(unsigned long u,char * uu)206 ulong_to_chars(unsigned long u, char *uu) {
207     int i;
208 
209     for (i = 0; i < 4; i++) {
210 	uu[i] = (u & 0xff);
211 	u >>= 8;
212     }
213 }
214 
215 static unsigned long
chars_to_ulong(unsigned char * uu)216 chars_to_ulong(unsigned char *uu) {
217     int i;
218     unsigned long u = 0;
219 
220     for (i = 3; i >= 0; i--)
221 	u = (u << 8) | uu[i];
222     return u;
223 }
224 
225 static int
save_sectors(char * dev,int fdin)226 save_sectors(char *dev, int fdin) {
227     struct sector *s;
228     char ss[516];
229     int fdout = -1;
230 
231     fdout = open(save_sector_file, O_WRONLY | O_CREAT, 0444);
232     if (fdout < 0) {
233 	warn(_("cannot open partition sector save file (%s)"),
234 	     save_sector_file);
235 	goto err;
236     }
237 
238     for (s = sectorhead; s; s = s->next)
239 	if (s->to_be_written) {
240 	    ulong_to_chars(s->sectornumber, ss);
241 	    if (!sseek(dev, fdin, s->sectornumber))
242 		goto err;
243 	    if (read(fdin, ss + 4, 512) != 512) {
244 		warn(_("read error on %s - cannot read sector %llu"),
245 		     dev, s->sectornumber);
246 		goto err;
247 	    }
248 	    if (write(fdout, ss, sizeof(ss)) != sizeof(ss)) {
249 		warn(_("write error on %s"), save_sector_file);
250 		goto err;
251 	    }
252 	}
253 
254     if (close_fd(fdout) != 0) {
255 	warn(_("write failed: %s"), save_sector_file);
256 	return 0;
257     }
258     return 1;
259 
260  err:
261     if (fdout >= 0)
262 	if (close_fd(fdout) != 0)
263 	    warn(_("write failed: %s"), save_sector_file);
264     return 0;
265 }
266 
267 static int reread_disk_partition(char *dev, int fd);
268 
269 static int
restore_sectors(char * dev)270 restore_sectors(char *dev) {
271     int fdin = -1, fdout = -1;
272     int ct;
273     struct stat statbuf;
274     char *ss0 = NULL, *ss;
275     unsigned long sno;
276 
277     if (stat(restore_sector_file, &statbuf) < 0) {
278 	warn(_("cannot stat partition restore file (%s)"),
279 	     restore_sector_file);
280 	goto err;
281     }
282     if (statbuf.st_size % 516) {
283 	warnx(_("partition restore file has wrong size - not restoring"));
284 	goto err;
285     }
286 
287     ss0 = xmalloc(statbuf.st_size);
288     ss = ss0;
289 
290     fdin = open(restore_sector_file, O_RDONLY);
291     if (fdin < 0) {
292 	warn(_("cannot open partition restore file (%s)"),
293 	     restore_sector_file);
294 	goto err;
295     }
296     if (read(fdin, ss, statbuf.st_size) != statbuf.st_size) {
297 	warn(_("error reading %s"), restore_sector_file);
298 	goto err;
299     }
300 
301     fdout = open(dev, O_WRONLY);
302     if (fdout < 0) {
303 	warn(_("cannot open device %s for writing"), dev);
304 	goto err;
305     }
306 
307     ct = statbuf.st_size / 516;
308     while (ct--) {
309 	sno = chars_to_ulong((unsigned char *)ss);
310 	if (!sseek(dev, fdout, sno))
311 	    goto err;
312 	if (write(fdout, ss + 4, 512) != 512) {
313 	    warn(_("error writing sector %lu on %s"), sno, dev);
314 	    goto err;
315 	}
316 	ss += 516;
317     }
318     free(ss0);
319     ss0 = NULL;
320 
321     if (!reread_disk_partition(dev, fdout))	/* closes fdout */
322 	goto err;
323     close(fdin);
324     if (close_fd(fdout) != 0) {
325 	warnx(_("write failed: %s"), dev);
326 	return 0;
327     }
328     return 1;
329 
330  err:
331     free(ss0);
332     if (fdin >= 0)
333 	close(fdin);
334     if (fdout >= 0)
335 	close(fdout);
336 
337     return 0;
338 }
339 
340 /*
341  *  C. About heads, sectors and cylinders
342  */
343 
344 /*
345  * <linux/hdreg.h> defines HDIO_GETGEO and
346  * struct hd_geometry {
347  *      unsigned char heads;
348  *      unsigned char sectors;
349  *      unsigned short cylinders;
350  *      unsigned long start;
351  * };
352  *
353  * For large disks g.cylinders is truncated, so we use BLKGETSIZE.
354  */
355 
356 /*
357  * We consider several geometries for a disk:
358  * B - the BIOS geometry, gotten from the kernel via HDIO_GETGEO
359  * F - the fdisk geometry
360  * U - the user-specified geometry
361  *
362  * 0 means unspecified / unknown
363  */
364 struct geometry {
365     unsigned long long total_size;	/* in sectors */
366     unsigned long cylindersize;	/* in sectors */
367     unsigned long heads, sectors, cylinders;
368     unsigned long start;
369 } B, F, U;
370 
371 static struct geometry
get_geometry(char * dev,int fd,int silent)372 get_geometry(char *dev, int fd, int silent) {
373     struct hd_geometry g;
374     unsigned long cyls;
375     unsigned long long sectors;
376     struct geometry R;
377 
378 #ifdef HDIO_GETGEO
379     if (ioctl(fd, HDIO_GETGEO, &g))
380 #endif
381     {
382 	g.heads = g.sectors = g.cylinders = g.start = 0;
383 	if (!silent)
384 	    warnx(_("Disk %s: cannot get geometry"), dev);
385     }
386 
387     R.start = g.start;
388     R.heads = g.heads;
389     R.sectors = g.sectors;
390     R.cylindersize = R.heads * R.sectors;
391     R.cylinders = 0;
392     R.total_size = 0;
393 
394     if (blkdev_get_sectors(fd, &sectors) == -1) {
395 	/* maybe an ordinary file */
396 	struct stat s;
397 
398 	if (fstat(fd, &s) == 0 && S_ISREG(s.st_mode))
399 	    R.total_size = (s.st_size >> 9);
400 	else if (!silent)
401 	    warnx(_("Disk %s: cannot get size"), dev);
402     } else
403 	R.total_size = sectors;
404 
405     if (R.cylindersize && R.total_size) {
406 	sectors /= R.cylindersize;
407 	cyls = sectors;
408 	if (cyls != sectors)
409 	    cyls = ~0;
410 	R.cylinders = cyls;
411     }
412 
413     return R;
414 }
415 
416 static void
get_cylindersize(char * dev,int fd,int silent)417 get_cylindersize(char *dev, int fd, int silent) {
418     struct geometry R;
419 
420     R = get_geometry(dev, fd, silent);
421 
422     B.heads = (U.heads ? U.heads : R.heads ? R.heads : 255);
423     B.sectors = (U.sectors ? U.sectors : R.sectors ? R.sectors : 63);
424     B.cylinders = (U.cylinders ? U.cylinders : R.cylinders);
425 
426     B.cylindersize = B.heads * B.sectors;
427     B.total_size = R.total_size;
428 
429     if (B.cylinders == 0 && B.cylindersize != 0)
430 	B.cylinders = B.total_size / B.cylindersize;
431 
432     if (R.start && !force) {
433 	warnx(_("Warning: start=%lu - this looks like a partition rather than\n"
434 		  "the entire disk. Using fdisk on it is probably meaningless.\n"
435 		  "[Use the --force option if you really want this]"),
436 		R.start);
437 	exit(EXIT_FAILURE);
438     }
439 #if 0
440     if (R.heads && B.heads != R.heads)
441 	warnx(_("Warning: HDIO_GETGEO says that there are %lu heads"),
442 		R.heads);
443     if (R.sectors && B.sectors != R.sectors)
444 	warnx(_("Warning: HDIO_GETGEO says that there are %lu sectors"),
445 		R.sectors);
446     if (R.cylinders && B.cylinders != R.cylinders
447 	&& B.cylinders < 65536 && R.cylinders < 65536)
448 	warnx(_("Warning: BLKGETSIZE/HDIO_GETGEO says that there are %lu cylinders"),
449 		R.cylinders);
450 #endif
451 
452     if (B.sectors > 63)
453 	warnx(_("Warning: unlikely number of sectors (%lu) - usually at most 63\n"
454 		  "This will give problems with all software that uses C/H/S addressing."),
455 		B.sectors);
456     if (!silent)
457 	printf(_("\nDisk %s: %lu cylinders, %lu heads, %lu sectors/track\n"),
458 	       dev, B.cylinders, B.heads, B.sectors);
459 }
460 
461 typedef struct {
462     unsigned char h, s, c;
463 } __attribute__ ((packed)) chs;			/* has some c bits in s */
464 chs zero_chs = { 0, 0, 0 };
465 
466 typedef struct {
467     unsigned long h, s, c;
468 } longchs;
469 longchs zero_longchs;
470 
471 static chs
longchs_to_chs(longchs aa,struct geometry G)472 longchs_to_chs(longchs aa, struct geometry G) {
473     chs a;
474 
475     if (aa.h < 256 && aa.s < 64 && aa.c < 1024) {
476 	a.h = aa.h;
477 	a.s = aa.s | ((aa.c >> 2) & 0xc0);
478 	a.c = (aa.c & 0xff);
479     } else if (G.heads && G.sectors) {
480 	a.h = G.heads - 1;
481 	a.s = G.sectors | 0xc0;
482 	a.c = 0xff;
483     } else
484 	a = zero_chs;
485     return a;
486 }
487 
488 static longchs
chs_to_longchs(chs a)489 chs_to_longchs(chs a) {
490     longchs aa;
491 
492     aa.h = a.h;
493     aa.s = (a.s & 0x3f);
494     aa.c = (a.s & 0xc0);
495     aa.c = (aa.c << 2) + a.c;
496     return aa;
497 }
498 
499 static longchs
ulong_to_longchs(unsigned long sno,struct geometry G)500 ulong_to_longchs(unsigned long sno, struct geometry G) {
501     longchs aa;
502 
503     if (G.heads && G.sectors && G.cylindersize) {
504 	aa.s = 1 + sno % G.sectors;
505 	aa.h = (sno / G.sectors) % G.heads;
506 	aa.c = sno / G.cylindersize;
507 	return aa;
508     } else {
509 	return zero_longchs;
510     }
511 }
512 
513 static chs
ulong_to_chs(unsigned long sno,struct geometry G)514 ulong_to_chs(unsigned long sno, struct geometry G) {
515     return longchs_to_chs(ulong_to_longchs(sno, G), G);
516 }
517 
518 #if 0
519 static unsigned long
520 longchs_to_ulong(longchs aa, struct geometry G) {
521     return (aa.c * G.cylindersize + aa.h * G.sectors + aa.s - 1);
522 }
523 
524 static unsigned long
525 chs_to_ulong(chs a, struct geometry G) {
526     return longchs_to_ulong(chs_to_longchs(a), G);
527 }
528 #endif
529 
530 static int
is_equal_chs(chs a,chs b)531 is_equal_chs(chs a, chs b) {
532     return (a.h == b.h && a.s == b.s && a.c == b.c);
533 }
534 
535 static int
chs_ok(chs a,char * v,char * w)536 chs_ok(chs a, char *v, char *w) {
537     longchs aa = chs_to_longchs(a);
538     int ret = 1;
539 
540     if (is_equal_chs(a, zero_chs))
541 	return 1;
542     if (B.heads && aa.h >= B.heads) {
543 	warnx(_("%s of partition %s has impossible value for head: "
544 		  "%lu (should be in 0-%lu)"), w, v, aa.h, B.heads - 1);
545 	ret = 0;
546     }
547     if (B.sectors && (aa.s == 0 || aa.s > B.sectors)) {
548 	warnx(_("%s of partition %s has impossible value for sector: "
549 		  "%lu (should be in 1-%lu)"), w, v, aa.s, B.sectors);
550 	ret = 0;
551     }
552     if (B.cylinders && aa.c >= B.cylinders) {
553 	warnx(_("%s of partition %s has impossible value for cylinders: "
554 		  "%lu (should be in 0-%lu)"), w, v, aa.c, B.cylinders - 1);
555 	ret = 0;
556     }
557     return ret;
558 }
559 
560 /*
561  *  D. About system Ids
562  */
563 
564 #define EMPTY_PARTITION		0
565 #define EXTENDED_PARTITION	5
566 #define WIN98_EXTENDED		0x0f
567 #define DM6_AUX1PARTITION	0x51
568 #define DM6_AUX3PARTITION	0x53
569 #define DM6_PARTITION		0x54
570 #define EZD_PARTITION		0x55
571 #define LINUX_SWAP              0x82
572 #define LINUX_NATIVE	        0x83
573 #define LINUX_EXTENDED		0x85
574 #define BSD_PARTITION		0xa5
575 #define NETBSD_PARTITION	0xa9
576 
577 /* List of partition types */
578 
579 static const char *
sysname(unsigned char type)580 sysname(unsigned char type) {
581     struct systypes *s;
582 
583     for (s = i386_sys_types; s->name; s++)
584 	if (s->type == type)
585 	    return _(s->name);
586     return _("Unknown");
587 }
588 
589 static void
list_types(void)590 list_types(void) {
591     struct systypes *s;
592 
593     printf(_("Id  Name\n\n"));
594     for (s = i386_sys_types; s->name; s++)
595 	printf("%2x  %s\n", s->type, _(s->name));
596 }
597 
598 static int
is_extended(unsigned char type)599 is_extended(unsigned char type) {
600     return (type == EXTENDED_PARTITION
601 	    || type == LINUX_EXTENDED || type == WIN98_EXTENDED);
602 }
603 
604 static int
is_bsd(unsigned char type)605 is_bsd(unsigned char type) {
606     return (type == BSD_PARTITION || type == NETBSD_PARTITION);
607 }
608 
609 /*
610  *  E. About partitions
611  */
612 
613 /* MS/DOS partition */
614 
615 struct partition {
616     unsigned char bootable;	/* 0 or 0x80 */
617     chs begin_chs;
618     unsigned char sys_type;
619     chs end_chs;
620     unsigned int start_sect;	/* starting sector counting from 0 */
621     unsigned int nr_sects;	/* nr of sectors in partition */
622 } __attribute__ ((packed));
623 
624 /* Unfortunately, partitions are not aligned, and non-Intel machines
625    are unhappy with non-aligned integers. So, we need a copy by hand. */
626 static int
copy_to_int(unsigned char * cp)627 copy_to_int(unsigned char *cp) {
628     unsigned int m;
629 
630     m = *cp++;
631     m += (*cp++ << 8);
632     m += (*cp++ << 16);
633     m += (*cp++ << 24);
634     return m;
635 }
636 
637 static void
copy_from_int(int m,char * cp)638 copy_from_int(int m, char *cp) {
639     *cp++ = (m & 0xff);
640     m >>= 8;
641     *cp++ = (m & 0xff);
642     m >>= 8;
643     *cp++ = (m & 0xff);
644     m >>= 8;
645     *cp++ = (m & 0xff);
646 }
647 
648 static void
copy_to_part(char * cp,struct partition * p)649 copy_to_part(char *cp, struct partition *p) {
650     p->bootable = *cp++;
651     p->begin_chs.h = *cp++;
652     p->begin_chs.s = *cp++;
653     p->begin_chs.c = *cp++;
654     p->sys_type = *cp++;
655     p->end_chs.h = *cp++;
656     p->end_chs.s = *cp++;
657     p->end_chs.c = *cp++;
658     p->start_sect = copy_to_int((unsigned char *)cp);
659     p->nr_sects = copy_to_int((unsigned char *)cp + 4);
660 }
661 
662 static void
copy_from_part(struct partition * p,char * cp)663 copy_from_part(struct partition *p, char *cp) {
664     *cp++ = p->bootable;
665     *cp++ = p->begin_chs.h;
666     *cp++ = p->begin_chs.s;
667     *cp++ = p->begin_chs.c;
668     *cp++ = p->sys_type;
669     *cp++ = p->end_chs.h;
670     *cp++ = p->end_chs.s;
671     *cp++ = p->end_chs.c;
672     copy_from_int(p->start_sect, cp);
673     copy_from_int(p->nr_sects, cp + 4);
674 }
675 
676 /* Roughly speaking, Linux doesn't use any of the above fields except
677    for partition type, start sector and number of sectors. (However,
678    see also linux/drivers/scsi/fdomain.c.)
679    The only way partition type is used (in the kernel) is the comparison
680    for equality with EXTENDED_PARTITION (and these Disk Manager types). */
681 
682 struct part_desc {
683     unsigned long long start;
684     unsigned long long size;
685     unsigned long long sector, offset;	/* disk location of this info */
686     struct partition p;
687     struct part_desc *ep;	/* extended partition containing this one */
688     int ptype;
689 #define DOS_TYPE	0
690 #define BSD_TYPE	1
691 } zero_part_desc;
692 
693 static struct part_desc *
outer_extended_partition(struct part_desc * p)694 outer_extended_partition(struct part_desc *p) {
695     while (p->ep)
696 	p = p->ep;
697     return p;
698 }
699 
700 static int
is_parent(struct part_desc * pp,struct part_desc * p)701 is_parent(struct part_desc *pp, struct part_desc *p) {
702     while (p) {
703 	if (pp == p)
704 	    return 1;
705 	p = p->ep;
706     }
707     return 0;
708 }
709 
710 struct disk_desc {
711     struct part_desc partitions[512];
712     int partno;
713 } oldp, newp;
714 
715 /* determine where on the disk this information goes */
716 static void
add_sector_and_offset(struct disk_desc * z)717 add_sector_and_offset(struct disk_desc *z) {
718     int pno;
719     struct part_desc *p;
720 
721     for (pno = 0; pno < z->partno; pno++) {
722 	p = &(z->partitions[pno]);
723 	p->offset = 0x1be + (pno % 4) * sizeof(struct partition);
724 	p->sector = (p->ep ? p->ep->start : 0);
725     }
726 }
727 
728 /* tell the kernel to reread the partition tables */
729 static int
reread_ioctl(int fd)730 reread_ioctl(int fd) {
731 #ifdef BLKRRPART
732     if (ioctl(fd, BLKRRPART))
733 #else
734     errno = ENOSYS;
735 #endif
736     {
737 	/* perror might change errno */
738 	int err = errno;
739 
740 	warn("BLKRRPART");
741 
742 	/* 2.6.8 returns EIO for a zero table */
743 	if (err == EBUSY)
744 	    return -1;
745     }
746     return 0;
747 }
748 
749 /* reread after writing */
750 static int
reread_disk_partition(char * dev,int fd)751 reread_disk_partition(char *dev, int fd) {
752     fflush(stdout);
753     sync();
754 
755     if (is_blkdev(fd)) {
756 	printf(_("Re-reading the partition table ...\n"));
757 	if (reread_ioctl(fd) ) {
758 	   warnx(_("The command to re-read the partition table failed.\n"
759 		"Run partprobe(8), kpartx(8) or reboot your system now,\n"
760 		"before using mkfs"));
761 	   return 0;
762 	}
763     }
764 
765     if (close_fd(fd) != 0) {
766 	warn(_("Error closing %s"), dev);
767 	return 0;
768     }
769     printf("\n");
770 
771     return 1;
772 }
773 
774 /* find Linux name of this partition, assuming that it will have a name */
775 static int
index_to_linux(int pno,struct disk_desc * z)776 index_to_linux(int pno, struct disk_desc *z) {
777     int i, ct = 1;
778     struct part_desc *p = &(z->partitions[0]);
779     for (i = 0; i < pno; i++, p++)
780 	if (i < 4 || (p->size > 0 && !is_extended(p->p.sys_type)))
781 	    ct++;
782     return ct;
783 }
784 
785 static int
linux_to_index(int lpno,struct disk_desc * z)786 linux_to_index(int lpno, struct disk_desc *z) {
787     int i, ct = 0;
788     struct part_desc *p = &(z->partitions[0]);
789     for (i = 0; i < z->partno && ct < lpno; i++, p++)
790 	if ((i < 4 || (p->size > 0 && !is_extended(p->p.sys_type)))
791 	    && ++ct == lpno)
792 	    return i;
793     return -1;
794 }
795 
796 static int
asc_to_index(char * pnam,struct disk_desc * z)797 asc_to_index(char *pnam, struct disk_desc *z) {
798     int pnum, pno;
799 
800     if (*pnam == '#') {
801 	pno = atoi(pnam + 1);
802     } else {
803 	pnum = atoi(pnam);
804 	pno = linux_to_index(pnum, z);
805     }
806     if (!(pno >= 0 && pno < z->partno))
807 	errx(EXIT_FAILURE, _("%s: no such partition\n"), pnam);
808     return pno;
809 }
810 
811 /*
812  * List partitions - in terms of sectors, blocks or cylinders
813  */
814 #define F_SECTOR   1
815 #define F_BLOCK    2
816 #define F_CYLINDER 3
817 #define F_MEGABYTE 4
818 
819 int default_format = F_MEGABYTE;
820 int specified_format = 0;
821 int show_extended = 0;
822 int one_only = 0;
823 int one_only_pno;
824 int increment = 0;
825 
826 static void
set_format(char c)827 set_format(char c) {
828     switch (c) {
829     default:
830 	warnx(_("unrecognized format - using sectors"));
831 	/* fallthrough */
832     case 'S':
833 	specified_format = F_SECTOR;
834 	break;
835     case 'B':
836 	specified_format = F_BLOCK;
837 	break;
838     case 'C':
839 	specified_format = F_CYLINDER;
840 	break;
841     case 'M':
842 	specified_format = F_MEGABYTE;
843 	break;
844     }
845 }
846 
847 static unsigned long
unitsize(int format)848 unitsize(int format) {
849     default_format = (B.cylindersize ? F_CYLINDER : F_MEGABYTE);
850     if (!format && !(format = specified_format))
851 	format = default_format;
852 
853     switch (format) {
854     default:
855     case F_CYLINDER:
856 	if (B.cylindersize)
857 	    return B.cylindersize;
858 	/* fallthrough */
859     case F_SECTOR:
860 	return 1;
861     case F_BLOCK:
862 	return 2;
863     case F_MEGABYTE:
864 	return 2048;
865     }
866 }
867 
868 static unsigned long long
get_disksize(int format)869 get_disksize(int format) {
870     if (B.total_size && leave_last)
871 	/* don't use last cylinder (--leave-last option) */
872 	return (B.total_size - B.cylindersize) / unitsize(format);
873 
874     return B.total_size / unitsize(format);
875 }
876 
877 static void
out_partition_header(char * dev,int format,struct geometry G)878 out_partition_header(char *dev, int format, struct geometry G) {
879     if (dump) {
880 	printf("# partition table of %s\n", dev);
881 	printf("unit: sectors\n\n");
882 	return;
883     }
884 
885     default_format = (G.cylindersize ? F_CYLINDER : F_MEGABYTE);
886     if (!format && !(format = specified_format))
887 	format = default_format;
888 
889     switch (format) {
890     default:
891 	warnx(_("unimplemented format - using %s"),
892 		G.cylindersize ? _("cylinders") : _("sectors"));
893 	/* fallthrough */
894     case F_CYLINDER:
895 	if (G.cylindersize) {
896 	    printf(_("Units: cylinders of %lu bytes, blocks of 1024 bytes"
897 		     ", counting from %d\n\n"), G.cylindersize << 9, increment);
898 	    printf(_("   Device Boot Start     End   #cyls    #blocks   Id  System\n"));
899 	    break;
900 	}
901 	/* fall through */
902     case F_SECTOR:
903 	printf(_("Units: sectors of 512 bytes, counting from %d\n\n"),
904 	       increment);
905 	printf(_("   Device Boot    Start       End   #sectors  Id  System\n"));
906 	break;
907     case F_BLOCK:
908 	printf(_("Units: blocks of 1024 bytes, counting from %d\n\n"),
909 	       increment);
910 	printf(_("   Device Boot   Start       End    #blocks   Id  System\n"));
911 	break;
912     case F_MEGABYTE:
913 	printf(_("Units: 1MiB = 1024*1024 bytes, blocks of 1024 bytes"
914 		 ", counting from %d\n\n"), increment);
915 	printf(_("   Device Boot Start   End    MiB    #blocks   Id  System\n"));
916 	break;
917     }
918 }
919 
920 static void
out_rounddown(int width,unsigned long long n,unsigned long unit,int inc)921 out_rounddown(int width, unsigned long long n, unsigned long unit, int inc) {
922     printf("%*llu", width, inc + n / unit);
923     if (unit != 1)
924 	putchar((n % unit) ? '+' : ' ');
925     putchar(' ');
926 }
927 
928 static void
out_roundup(int width,unsigned long long n,unsigned long unit,int inc)929 out_roundup(int width, unsigned long long n, unsigned long unit, int inc) {
930     if (n == (unsigned long long)(-1))
931 	printf("%*s", width, "-");
932     else
933 	printf("%*llu", width, inc + n / unit);
934     if (unit != 1)
935 	putchar(((n + 1) % unit) ? '-' : ' ');
936     putchar(' ');
937 }
938 
939 static void
out_roundup_size(int width,unsigned long long n,unsigned long unit)940 out_roundup_size(int width, unsigned long long n, unsigned long unit) {
941     printf("%*llu", width, (n + unit - 1) / unit);
942     if (unit != 1)
943 	putchar((n % unit) ? '-' : ' ');
944     putchar(' ');
945 }
946 
947 static struct geometry
get_fdisk_geometry_one(struct part_desc * p)948 get_fdisk_geometry_one(struct part_desc *p) {
949     struct geometry G;
950     chs b = p->p.end_chs;
951     longchs bb = chs_to_longchs(b);
952 
953     memset(&G, 0, sizeof(struct geometry));
954     G.heads = bb.h + 1;
955     G.sectors = bb.s;
956     G.cylindersize = G.heads * G.sectors;
957     return G;
958 }
959 
960 static int
get_fdisk_geometry(struct disk_desc * z)961 get_fdisk_geometry(struct disk_desc *z) {
962     struct part_desc *p;
963     int pno, agree;
964     struct geometry G0, G;
965 
966     memset(&G0, 0, sizeof(struct geometry));
967     agree = 0;
968     for (pno = 0; pno < z->partno; pno++) {
969 	p = &(z->partitions[pno]);
970 	if (p->size != 0 && p->p.sys_type != 0) {
971 	    G = get_fdisk_geometry_one(p);
972 	    if (!G0.heads) {
973 		G0 = G;
974 		agree = 1;
975 	    } else if (G.heads != G0.heads || G.sectors != G0.sectors) {
976 		agree = 0;
977 		break;
978 	    }
979 	}
980     }
981     F = (agree ? G0 : B);
982     return (F.sectors != B.sectors || F.heads != B.heads);
983 }
984 
985 static void
out_partition(char * dev,int format,struct part_desc * p,struct disk_desc * z,struct geometry G)986 out_partition(char *dev, int format, struct part_desc *p,
987 	      struct disk_desc *z, struct geometry G) {
988     unsigned long long start, end, size;
989     int pno, lpno;
990 
991     if (!format && !(format = specified_format))
992 	format = default_format;
993 
994     pno = p - &(z->partitions[0]);	/* our index */
995     lpno = index_to_linux(pno, z);	/* name of next one that has a name */
996     if (pno == linux_to_index(lpno, z))	/* was that us? */
997 	printf("%s", partname(dev, lpno, 10));	/* yes */
998     else if (show_extended)
999 	printf("    -     ");
1000     else
1001 	return;
1002     putchar(dump ? ':' : ' ');
1003 
1004     start = p->start;
1005     end = p->start + p->size - 1;
1006     size = p->size;
1007 
1008     if (dump) {
1009 	printf(" start=%9llu", start);
1010 	printf(", size=%9llu", size);
1011 	if (p->ptype == DOS_TYPE) {
1012 	    printf(", Id=%2x", p->p.sys_type);
1013 	    if (p->p.bootable == 0x80)
1014 		printf(", bootable");
1015 	}
1016 	printf("\n");
1017 	return;
1018     }
1019 
1020     if (p->ptype != DOS_TYPE || p->p.bootable == 0)
1021 	printf("   ");
1022     else if (p->p.bootable == 0x80)
1023 	printf(" * ");
1024     else
1025 	printf(" ? ");		/* garbage */
1026 
1027     switch (format) {
1028     case F_CYLINDER:
1029 	if (G.cylindersize) {
1030 	    out_rounddown(6, start, G.cylindersize, increment);
1031 	    out_roundup(6, end, G.cylindersize, increment);
1032 	    out_roundup_size(6, size, G.cylindersize);
1033 	    out_rounddown(9, size, 2, 0);
1034 	    break;
1035 	}
1036 	/* fall through */
1037     default:
1038     case F_SECTOR:
1039 	out_rounddown(9, start, 1, increment);
1040 	out_roundup(9, end, 1, increment);
1041 	out_rounddown(10, size, 1, 0);
1042 	break;
1043     case F_BLOCK:
1044 #if 0
1045 	printf("%8lu,%3lu ",
1046 	       p->sector / 2, ((p->sector & 1) ? 512 : 0) + p->offset);
1047 #endif
1048 	out_rounddown(8, start, 2, increment);
1049 	out_roundup(8, end, 2, increment);
1050 	out_rounddown(9, size, 2, 0);
1051 	break;
1052     case F_MEGABYTE:
1053 	out_rounddown(5, start, 2048, increment);
1054 	out_roundup(5, end, 2048, increment);
1055 	out_roundup_size(5, size, 2048);
1056 	out_rounddown(9, size, 2, 0);
1057 	break;
1058     }
1059     if (p->ptype == DOS_TYPE) {
1060 	printf(" %2x  %s\n", p->p.sys_type, sysname(p->p.sys_type));
1061     } else {
1062 	printf("\n");
1063     }
1064 
1065     /* Is chs as we expect? */
1066     if (!quiet && p->ptype == DOS_TYPE) {
1067 	chs a, b;
1068 	longchs aa, bb;
1069 	a = (size ? ulong_to_chs(start, G) : zero_chs);
1070 	b = p->p.begin_chs;
1071 	aa = chs_to_longchs(a);
1072 	bb = chs_to_longchs(b);
1073 	if (a.s && !is_equal_chs(a, b))
1074 	    printf(_("\t\tstart: (c,h,s) expected (%ld,%ld,%ld) found (%ld,%ld,%ld)\n"),
1075 		    aa.c, aa.h, aa.s, bb.c, bb.h, bb.s);
1076 	a = (size ? ulong_to_chs(end, G) : zero_chs);
1077 	b = p->p.end_chs;
1078 	aa = chs_to_longchs(a);
1079 	bb = chs_to_longchs(b);
1080 	if (a.s && !is_equal_chs(a, b))
1081 	    printf(_("\t\tend: (c,h,s) expected (%ld,%ld,%ld) found (%ld,%ld,%ld)\n"),
1082 		    aa.c, aa.h, aa.s, bb.c, bb.h, bb.s);
1083 	if (G.cylinders && G.cylinders < 1024 && bb.c > G.cylinders)
1084 	    printf(_("partition ends on cylinder %ld, beyond the end of the disk\n"),
1085 		    bb.c);
1086     }
1087 }
1088 
1089 static void
out_partitions(char * dev,struct disk_desc * z)1090 out_partitions(char *dev, struct disk_desc *z) {
1091     int pno, format = 0;
1092 
1093     if (z->partno == 0) {
1094 	if (!opt_list)
1095 	    warnx(_("No partitions found"));
1096     } else {
1097 	if (get_fdisk_geometry(z) && !dump) {
1098 	    warnx(_("Warning: The partition table looks like it was made\n"
1099 		      "  for C/H/S=*/%ld/%ld (instead of %ld/%ld/%ld).\n"
1100 		      "For this listing I'll assume that geometry."),
1101 		    F.heads, F.sectors, B.cylinders, B.heads, B.sectors);
1102 	}
1103 
1104 	out_partition_header(dev, format, F);
1105 	for (pno = 0; pno < z->partno; pno++) {
1106 	    out_partition(dev, format, &(z->partitions[pno]), z, F);
1107 	    if (show_extended && pno % 4 == 3)
1108 		printf("\n");
1109 	}
1110     }
1111 }
1112 
1113 static int
disj(struct part_desc * p,struct part_desc * q)1114 disj(struct part_desc *p, struct part_desc *q) {
1115     return ((p->start + p->size <= q->start)
1116 	    || (is_extended(p->p.sys_type)
1117 		&& q->start + q->size <= p->start + p->size));
1118 }
1119 
1120 static char *
pnumber(struct part_desc * p,struct disk_desc * z)1121 pnumber(struct part_desc *p, struct disk_desc *z) {
1122     static char buf[20];
1123     int this, next;
1124     struct part_desc *p0 = &(z->partitions[0]);
1125 
1126     this = index_to_linux(p - p0, z);
1127     next = index_to_linux(p - p0 + 1, z);
1128 
1129     if (next > this)
1130 	sprintf(buf, "%d", this);
1131     else
1132 	sprintf(buf, "[%d]", this);
1133     return buf;
1134 }
1135 
1136 static int
partitions_ok(int fd,struct disk_desc * z)1137 partitions_ok(int fd, struct disk_desc *z) {
1138     struct part_desc *partitions = &(z->partitions[0]), *p, *q;
1139     int partno = z->partno;
1140     int sector_size;
1141 
1142 #define PNO(p) pnumber(p, z)
1143 
1144     /* Have at least 4 partitions been defined? */
1145     if (partno < 4) {
1146 	if (!partno)
1147 	    errx(EXIT_FAILURE, _("no partition table present"));
1148 	else
1149 	    errx(EXIT_FAILURE, P_("strange, only %d partition defined",
1150 		"strange, only %d partitions defined", partno), partno);
1151 	return 0;
1152     }
1153 
1154     /* Are the partitions of size 0 marked empty?
1155        And do they have start = 0? And bootable = 0? */
1156     for (p = partitions; p - partitions < partno; p++)
1157 	if (p->size == 0) {
1158 	    if (p->p.sys_type != EMPTY_PARTITION)
1159 		warnx(_("Warning: partition %s has size 0 but is not marked Empty"),
1160 			PNO(p));
1161 	    else if (p->p.bootable != 0)
1162 		warnx(_("Warning: partition %s has size 0 and is bootable"),
1163 			PNO(p));
1164 	    else if (p->p.start_sect != 0)
1165 		warnx(_("Warning: partition %s has size 0 and nonzero start"),
1166 			PNO(p));
1167 	    /* all this is probably harmless, no error return */
1168 	}
1169 
1170     /* Are the logical partitions contained in their extended partitions? */
1171     for (p = partitions + 4; p < partitions + partno; p++)
1172 	if (p->ptype == DOS_TYPE)
1173 	    if (p->size && !is_extended(p->p.sys_type)) {
1174 		q = p->ep;
1175 		if (p->start < q->start
1176 		    || p->start + p->size > q->start + q->size) {
1177 		    warnx(_("Warning: partition %s is not contained in "
1178 			      "partition %s"), PNO(p), PNO(q));
1179 		    return 0;
1180 		}
1181 	    }
1182 
1183     /* Are the data partitions mutually disjoint? */
1184     for (p = partitions; p < partitions + partno; p++)
1185 	if (p->size && !is_extended(p->p.sys_type))
1186 	    for (q = p + 1; q < partitions + partno; q++)
1187 		if (q->size && !is_extended(q->p.sys_type))
1188 		    if (!((p->start > q->start) ? disj(q, p) : disj(p, q))) {
1189 			warnx(_("Warning: partitions %s and %s overlap"),
1190 				PNO(p), PNO(q));
1191 			return 0;
1192 		    }
1193 
1194     /* Are the data partitions and the extended partition
1195        table sectors disjoint? */
1196     for (p = partitions; p < partitions + partno; p++)
1197 	if (p->size && !is_extended(p->p.sys_type))
1198 	    for (q = partitions; q < partitions + partno; q++)
1199 		if (is_extended(q->p.sys_type))
1200 		    if (p->start <= q->start && p->start + p->size > q->start) {
1201 			warnx(_("Warning: partition %s contains part of "
1202 				  "the partition table (sector %llu),\n"
1203 				  "and will destroy it when filled"),
1204 				PNO(p), q->start);
1205 			return 0;
1206 		    }
1207 
1208     /* Do they start past zero and end before end-of-disk? */
1209     {
1210 	unsigned long long ds = get_disksize(F_SECTOR);
1211 	for (p = partitions; p < partitions + partno; p++)
1212 	    if (p->size) {
1213 		if (p->start == 0) {
1214 		    warnx(_("Warning: partition %s starts at sector 0"),
1215 			    PNO(p));
1216 		    return 0;
1217 		}
1218 		if (p->size && p->start + p->size > ds) {
1219 		    warnx(_("Warning: partition %s extends past end of disk"),
1220 			    PNO(p));
1221 		    return 0;
1222 		}
1223 	    }
1224     }
1225 
1226     if (blkdev_get_sector_size(fd, &sector_size) == -1)
1227 	sector_size = DEFAULT_SECTOR_SIZE;
1228 
1229     /* Is the size of partitions less than 2^32 sectors limit? */
1230     for (p = partitions; p < partitions + partno; p++)
1231 	if (p->size > UINT_MAX) {
1232 	    unsigned long long bytes = p->size * sector_size;
1233 	    int giga = bytes / 1000000000;
1234 	    int hectogiga = (giga + 50) / 100;
1235 	    warnx(_("Warning: partition %s has size %d.%d TB (%llu bytes),\n"
1236 		      "which is larger than the %llu bytes limit imposed\n"
1237 		      "by the DOS partition table for %d-byte sectors"),
1238 		    PNO(p), hectogiga / 10, hectogiga % 10,
1239 		    bytes,
1240 		    (unsigned long long) UINT_MAX * sector_size,
1241 		    sector_size);
1242 	    return 0;
1243 	}
1244 
1245     /* Do the partitions start below the 2^32 sectors limit? */
1246     for (p = partitions; p < partitions + partno; p++)
1247 	if (p->start > UINT_MAX) {
1248 	    unsigned long long bytes = p->start * sector_size;
1249 	    int giga = bytes / 1000000000;
1250 	    int hectogiga = (giga + 50) / 100;
1251 	    warnx(_("Warning: partition %s starts at sector %llu (%d.%d TB for %d-byte sectors),\n"
1252 		      "which exceeds the DOS partition table limit of %llu sectors"),
1253 		    PNO(p),
1254 		    p->start,
1255 		    hectogiga / 10,
1256 		    hectogiga % 10,
1257 		    sector_size,
1258 		    (unsigned long long) UINT_MAX);
1259 	    return 0;
1260 	}
1261 
1262     /* At most one chain of DOS extended partitions ? */
1263     /* It seems that the OS/2 fdisk has the additional requirement
1264        that the extended partition must be the fourth one */
1265     {
1266 	int ect = 0;
1267 	for (p = partitions; p < partitions + 4; p++)
1268 	    if (p->p.sys_type == EXTENDED_PARTITION)
1269 		ect++;
1270 	if (ect > 1 && !Linux) {
1271 	    warnx(_("Among the primary partitions, at most one can be extended\n"
1272 		      " (although this is not a problem under Linux)"));
1273 	    return 0;
1274 	}
1275     }
1276 
1277     /*
1278      * Do all partitions start at a cylinder boundary ?
1279      * (this is not required for Linux)
1280      * The first partition starts after MBR.
1281      * Logical partitions start slightly after the containing extended partn.
1282      */
1283     if (B.cylindersize && !Linux) {
1284 	for (p = partitions; p < partitions + partno; p++)
1285 	    if (p->size) {
1286 		if (p->start % B.cylindersize != 0
1287 		    && (!p->ep
1288 			|| p->start / B.cylindersize !=
1289 			p->ep->start / B.cylindersize)
1290 		    && (p->p.start_sect >= B.cylindersize)) {
1291 		    warnx(_("Warning: partition %s does not start "
1292 			      "at a cylinder boundary"), PNO(p));
1293 		    if (specified_format == F_CYLINDER)
1294 			return 0;
1295 		}
1296 		if ((p->start + p->size) % B.cylindersize) {
1297 		    warnx(_("Warning: partition %s does not end "
1298 			      "at a cylinder boundary"), PNO(p));
1299 		    if (specified_format == F_CYLINDER)
1300 			return 0;
1301 		}
1302 	    }
1303     }
1304 
1305     /* Usually, one can boot only from primary partitions. */
1306     /* In fact, from a unique one only. */
1307     /* do not warn about bootable extended partitions -
1308        often LILO is there */
1309     {
1310 	int pno = -1;
1311 	for (p = partitions; p < partitions + partno; p++)
1312 	    if (p->p.bootable) {
1313 		if (pno == -1)
1314 		    pno = p - partitions;
1315 		else if (p - partitions < 4) {
1316 		    warnx(_("Warning: more than one primary partition is marked "
1317 			      "bootable (active)\n"
1318 			      "This does not matter for LILO, but the DOS MBR will "
1319 			      "not boot this disk."));
1320 		    break;
1321 		}
1322 		if (p - partitions >= 4) {
1323 		    warnx(_("Warning: usually one can boot from primary partitions "
1324 			      "only\nLILO disregards the `bootable' flag."));
1325 		    break;
1326 		}
1327 	    }
1328 	if (pno == -1 || pno >= 4)
1329 	    warnx(_("Warning: no primary partition is marked bootable (active)\n"
1330 		      "This does not matter for LILO, but the DOS MBR will "
1331 		      "not boot this disk."));
1332     }
1333 
1334     /* Is chs as we expect? */
1335     for (p = partitions; p < partitions + partno; p++)
1336 	if (p->ptype == DOS_TYPE) {
1337 	    chs a, b;
1338 	    longchs aa, bb;
1339 	    a = p->size ? ulong_to_chs(p->start, B) : zero_chs;
1340 	    b = p->p.begin_chs;
1341 	    aa = chs_to_longchs(a);
1342 	    bb = chs_to_longchs(b);
1343 	    if (!Linux && !chs_ok(b, PNO(p), _("start")))
1344 		return 0;
1345 	    if (a.s && !is_equal_chs(a, b))
1346 		warnx(_("partition %s: start: (c,h,s) expected (%ld,%ld,%ld) found (%ld,%ld,%ld)"),
1347 			PNO(p), aa.c, aa.h, aa.s, bb.c, bb.h, bb.s);
1348 	    a = p->size ? ulong_to_chs(p->start + p->size - 1, B) : zero_chs;
1349 	    b = p->p.end_chs;
1350 	    aa = chs_to_longchs(a);
1351 	    bb = chs_to_longchs(b);
1352 	    if (!Linux && !chs_ok(b, PNO(p), _("end")))
1353 		return 0;
1354 	    if (a.s && !is_equal_chs(a, b))
1355 		warnx(_("partition %s: end: (c,h,s) expected (%ld,%ld,%ld) found (%ld,%ld,%ld)"),
1356 			PNO(p), aa.c, aa.h, aa.s, bb.c, bb.h, bb.s);
1357 	    if (B.cylinders && B.cylinders < 1024 && bb.c > B.cylinders)
1358 		warnx(_("partition %s ends on cylinder %ld, beyond the end of the disk"),
1359 			PNO(p), bb.c);
1360 	}
1361 
1362     return 1;
1363 
1364 #undef PNO
1365 }
1366 
1367 static void
extended_partition(char * dev,int fd,struct part_desc * ep,struct disk_desc * z)1368 extended_partition(char *dev, int fd, struct part_desc *ep, struct disk_desc *z) {
1369     char *cp;
1370     struct sector *s;
1371     unsigned long long start, here, next;
1372     int i, moretodo = 1;
1373     struct partition p;
1374     struct part_desc *partitions = &(z->partitions[0]);
1375     size_t pno = z->partno;
1376 
1377     here = start = ep->start;
1378 
1379     if (B.cylindersize && start % B.cylindersize) {
1380 	/* This is BAD */
1381 	if (DOS_extended) {
1382 	    here = start -= (start % B.cylindersize);
1383 	    warnx(_("Warning: shifted start of the extd partition "
1384 		      "from %lld to %lld\n"
1385 		      "(For listing purposes only. "
1386 		      "Do not change its contents.)"), ep->start, start);
1387 	} else if (!Linux) {
1388 	    warnx(_("Warning: extended partition does not start at a "
1389 		      "cylinder boundary.\n"
1390 		      "DOS and Linux will interpret the contents differently."));
1391 	}
1392     }
1393 
1394     while (moretodo) {
1395 	moretodo = 0;
1396 
1397 	if (!(s = get_sector(dev, fd, here)))
1398 	    break;
1399 
1400 	if (!msdos_signature(s)) {
1401 	    warnx(_("ERROR: sector %llu does not have an msdos signature"),
1402 	          s->sectornumber);
1403 	    break;
1404 	}
1405 	cp = s->data + 0x1be;
1406 
1407 	if (pno + 4 >= ARRAY_SIZE(z->partitions)) {
1408 	    warnx(_("too many partitions - ignoring those past nr (%zu)"),
1409 		    pno - 1);
1410 	    break;
1411 	}
1412 
1413 	next = 0;
1414 
1415 	for (i = 0; i < 4; i++, cp += sizeof(struct partition)) {
1416 	    partitions[pno].sector = here;
1417 	    partitions[pno].offset = cp - s->data;
1418 	    partitions[pno].ep = ep;
1419 	    copy_to_part(cp, &p);
1420 	    if (is_extended(p.sys_type)) {
1421 		partitions[pno].start = start + p.start_sect;
1422 		if (next)
1423 		    warnx(_("tree of partitions?"));
1424 		else
1425 		    next = partitions[pno].start;	/* follow `upper' branch */
1426 		moretodo = 1;
1427 	    } else {
1428 		partitions[pno].start = here + p.start_sect;
1429 	    }
1430 	    partitions[pno].size = p.nr_sects;
1431 	    partitions[pno].ptype = DOS_TYPE;
1432 	    partitions[pno].p = p;
1433 	    pno++;
1434 	}
1435 	here = next;
1436     }
1437 
1438     z->partno = pno;
1439 }
1440 
1441 #define BSD_DISKMAGIC   (0x82564557UL)
1442 #define BSD_MAXPARTITIONS       16
1443 #define BSD_FS_UNUSED	   0
1444 typedef unsigned char u8;
1445 typedef unsigned short u16;
1446 typedef unsigned int u32;
1447 struct bsd_disklabel {
1448     u32 d_magic;
1449     char d_junk1[4];
1450     char d_typename[16];
1451     char d_packname[16];
1452     char d_junk2[92];
1453     u32 d_magic2;
1454     char d_junk3[2];
1455     u16 d_npartitions;		/* number of partitions in following */
1456     char d_junk4[8];
1457     struct bsd_partition {	/* the partition table */
1458 	u32 p_size;		/* number of sectors in partition */
1459 	u32 p_offset;		/* starting sector */
1460 	u32 p_fsize;		/* filesystem basic fragment size */
1461 	u8 p_fstype;		/* filesystem type, see below */
1462 	u8 p_frag;		/* filesystem fragments per block */
1463 	u16 p_cpg;		/* filesystem cylinders per group */
1464     } d_partitions[BSD_MAXPARTITIONS];	/* actually may be more */
1465 };
1466 
1467 static void
bsd_partition(char * dev,int fd,struct part_desc * ep,struct disk_desc * z)1468 bsd_partition(char *dev, int fd, struct part_desc *ep, struct disk_desc *z) {
1469     struct bsd_disklabel *l;
1470     struct bsd_partition *bp, *bp0;
1471     unsigned long long start = ep->start;
1472     struct sector *s;
1473     struct part_desc *partitions = &(z->partitions[0]);
1474     size_t pno = z->partno;
1475 
1476     if (!(s = get_sector(dev, fd, start + 1)))
1477 	return;
1478     l = (struct bsd_disklabel *)(s->data);
1479     if (l->d_magic != BSD_DISKMAGIC || l->d_magic2 != BSD_DISKMAGIC)
1480 	return;
1481 
1482     bp = bp0 = &l->d_partitions[0];
1483     while (bp - bp0 < BSD_MAXPARTITIONS && bp - bp0 < l->d_npartitions) {
1484 	if (pno + 1 >= ARRAY_SIZE(z->partitions)) {
1485 	    warnx(_("too many partitions - ignoring those "
1486 		      "past nr (%zu)"), pno - 1);
1487 	    break;
1488 	}
1489 	if (bp->p_fstype != BSD_FS_UNUSED) {
1490 	    partitions[pno].start = bp->p_offset;
1491 	    partitions[pno].size = bp->p_size;
1492 	    partitions[pno].sector = start + 1;
1493 	    partitions[pno].offset = (char *)bp - (char *)bp0;
1494 	    partitions[pno].ep = 0;
1495 	    partitions[pno].ptype = BSD_TYPE;
1496 	    pno++;
1497 	}
1498 	bp++;
1499     }
1500     z->partno = pno;
1501 }
1502 
1503 static int
msdos_partition(char * dev,int fd,unsigned long start,struct disk_desc * z)1504 msdos_partition(char *dev, int fd, unsigned long start, struct disk_desc *z) {
1505     int i;
1506     char *cp;
1507     struct partition pt;
1508     struct sector *s;
1509     struct part_desc *partitions = &(z->partitions[0]);
1510     int pno;
1511     int bsd_later = 1;
1512     unsigned short sig, magic;
1513 #ifdef __linux__
1514     bsd_later = (get_linux_version() >= KERNEL_VERSION(2, 3, 40));
1515 #endif
1516 
1517     if (!(s = get_sector(dev, fd, start)))
1518 	return 0;
1519 
1520     if (!msdos_signature(s))
1521 	return 0;
1522 
1523     cp = s->data + 0x1be;
1524     copy_to_part(cp, &pt);
1525 
1526     /* If I am not mistaken, recent kernels will hide this from us,
1527        so we will never actually see traces of a Disk Manager */
1528     if (pt.sys_type == DM6_PARTITION
1529 	|| pt.sys_type == EZD_PARTITION
1530 	|| pt.sys_type == DM6_AUX1PARTITION
1531 	|| pt.sys_type == DM6_AUX3PARTITION) {
1532 	warnx(_("detected Disk Manager - unable to handle that"));
1533 	return 0;
1534     }
1535 
1536     memcpy(&sig, s->data + 2, sizeof(sig));
1537     if (sig <= 0x1ae) {
1538 	memcpy(&magic, s->data + sig, sizeof(magic));
1539 	if (magic == 0x55aa && (1 & *(unsigned char *)(s->data + sig + 2))) {
1540 	    warnx(_("DM6 signature found - giving up"));
1541 	    return 0;
1542 	}
1543     }
1544 
1545     for (pno = 0; pno < 4; pno++, cp += sizeof(struct partition)) {
1546 	partitions[pno].sector = start;
1547 	partitions[pno].offset = cp - s->data;
1548 	copy_to_part(cp, &pt);
1549 	partitions[pno].start = start + pt.start_sect;
1550 	partitions[pno].size = pt.nr_sects;
1551 	partitions[pno].ep = 0;
1552 	partitions[pno].p = pt;
1553     }
1554 
1555     z->partno = pno;
1556 
1557     for (i = 0; i < 4; i++) {
1558 	if (is_extended(partitions[i].p.sys_type)) {
1559 	    if (!partitions[i].size) {
1560 		warnx(_("strange..., an extended partition of size 0?"));
1561 		continue;
1562 	    }
1563 	    extended_partition(dev, fd, &partitions[i], z);
1564 	}
1565 	if (!bsd_later && is_bsd(partitions[i].p.sys_type)) {
1566 	    if (!partitions[i].size) {
1567 		warnx(_("strange..., a BSD partition of size 0?"));
1568 		continue;
1569 	    }
1570 	    bsd_partition(dev, fd, &partitions[i], z);
1571 	}
1572     }
1573 
1574     if (bsd_later) {
1575 	for (i = 0; i < 4; i++) {
1576 	    if (is_bsd(partitions[i].p.sys_type)) {
1577 		if (!partitions[i].size) {
1578 		    warnx(_("strange..., a BSD partition of size 0?"));
1579 		    continue;
1580 		}
1581 		bsd_partition(dev, fd, &partitions[i], z);
1582 	    }
1583 	}
1584     }
1585 
1586     return 1;
1587 }
1588 
1589 static int
osf_partition(char * dev,int fd,unsigned long start,struct disk_desc * z)1590 osf_partition(char *dev __attribute__ ((__unused__)),
1591 	      int fd __attribute__ ((__unused__)),
1592 	      unsigned long start __attribute__ ((__unused__)),
1593 	      struct disk_desc *z __attribute__ ((__unused__))) {
1594     return 0;
1595 }
1596 
1597 static int
sun_partition(char * dev,int fd,unsigned long start,struct disk_desc * z)1598 sun_partition(char *dev __attribute__ ((__unused__)),
1599 	      int fd __attribute__ ((__unused__)),
1600 	      unsigned long start __attribute__ ((__unused__)),
1601 	      struct disk_desc *z __attribute__ ((__unused__))) {
1602     return 0;
1603 }
1604 
1605 static int
amiga_partition(char * dev,int fd,unsigned long start,struct disk_desc * z)1606 amiga_partition(char *dev __attribute__ ((__unused__)),
1607 		int fd __attribute__ ((__unused__)),
1608 		unsigned long start __attribute__ ((__unused__)),
1609 		struct disk_desc *z __attribute__ ((__unused__))) {
1610     return 0;
1611 }
1612 
1613 static void
get_partitions(char * dev,int fd,struct disk_desc * z)1614 get_partitions(char *dev, int fd, struct disk_desc *z) {
1615     z->partno = 0;
1616 
1617     if (!msdos_partition(dev, fd, 0, z)
1618 	&& !osf_partition(dev, fd, 0, z)
1619 	&& !sun_partition(dev, fd, 0, z)
1620 	&& !amiga_partition(dev, fd, 0, z)) {
1621 	if (!opt_list)
1622 	    warnx(_(" %s: unrecognized partition table type"), dev);
1623 	return;
1624     }
1625 }
1626 
1627 static int
write_partitions(char * dev,int fd,struct disk_desc * z)1628 write_partitions(char *dev, int fd, struct disk_desc *z) {
1629     struct sector *s;
1630     struct part_desc *partitions = &(z->partitions[0]), *p;
1631     int pno = z->partno;
1632 
1633     if (no_write) {
1634 	warnx(_("-n flag was given: Nothing changed"));
1635 	exit(EXIT_SUCCESS);
1636     }
1637 
1638     for (p = partitions; p < partitions + pno; p++) {
1639 	s = get_sector(dev, fd, p->sector);
1640 	if (!s)
1641 	    return 0;
1642 	s->to_be_written = 1;
1643 	if (p->ptype == DOS_TYPE) {
1644 	    copy_from_part(&(p->p), s->data + p->offset);
1645 	    s->data[510] = 0x55;
1646 	    s->data[511] = (unsigned char)0xaa;
1647 	}
1648     }
1649     if (save_sector_file) {
1650 	if (!save_sectors(dev, fd)) {
1651 	    errx(EXIT_FAILURE, _("Failed saving the old sectors - aborting\n"));
1652 	    return 0;
1653 	}
1654     }
1655     if (!write_sectors(dev, fd)) {
1656 	warnx(_("Failed writing the partition on %s"), dev);
1657 	return 0;
1658     }
1659     if (fsync(fd)) {
1660 	warn(_("Failed writing the partition on %s"), dev);
1661 	return 0;
1662     }
1663     return 1;
1664 }
1665 
1666 /*
1667  *  F. The standard input
1668  */
1669 
1670 /*
1671  * Input format:
1672  * <start> <size> <type> <bootable> <c,h,s> <c,h,s>
1673  * Fields are separated by whitespace or comma or semicolon possibly
1674  * followed by whitespace; initial and trailing whitespace is ignored.
1675  * Numbers can be octal, decimal or hexadecimal, decimal is default
1676  * The <c,h,s> parts can (and probably should) be omitted.
1677  * Bootable is specified as [*|-], with as default not-bootable.
1678  * Type is given in hex, without the 0x prefix, or is [E|S|L|X], where
1679  * L (LINUX_NATIVE (83)) is the default, S is LINUX_SWAP (82), and E
1680  * is EXTENDED_PARTITION (5), X is LINUX_EXTENDED (85).
1681  * The default value of start is the first nonassigned sector/cylinder/...
1682  * The default value of size is as much as possible (until next
1683  * partition or end-of-disk).
1684  * .: end of chain of extended partitions.
1685  *
1686  * On interactive input an empty line means: all defaults.
1687  * Otherwise empty lines are ignored.
1688  */
1689 
1690 int eof, eob;
1691 
1692 struct dumpfld {
1693     int fldno;
1694     char *fldname;
1695     int is_bool;
1696 } dumpflds[] = {
1697     {
1698     0, "start", 0}, {
1699     1, "size", 0}, {
1700     2, "Id", 0}, {
1701     3, "bootable", 1}, {
1702     4, "bh", 0}, {
1703     5, "bs", 0}, {
1704     6, "bc", 0}, {
1705     7, "eh", 0}, {
1706     8, "es", 0}, {
1707     9, "ec", 0}
1708 };
1709 
1710 /*
1711  * Read a line, split it into fields
1712  *
1713  * (some primitive handwork, but a more elaborate parser seems
1714  *  unnecessary)
1715  */
1716 #define RD_EOF (-1)
1717 #define RD_CMD (-2)
1718 
1719 static int
read_stdin(char ** fields,char * line,int fieldssize,int linesize)1720 read_stdin(char **fields, char *line, int fieldssize, int linesize) {
1721     char *lp, *ip;
1722     int c, fno;
1723 
1724     /* boolean true and empty string at start */
1725     line[0] = '*';
1726     line[1] = 0;
1727     for (fno = 0; fno < fieldssize; fno++)
1728 	fields[fno] = line + 1;
1729     fno = 0;
1730 
1731     /* read a line from stdin */
1732     lp = fgets(line + 2, linesize - 2, stdin);
1733     if (lp == NULL) {
1734 	eof = 1;
1735 	return RD_EOF;
1736     }
1737     if (!(lp = strchr(lp, '\n')))
1738 	errx(EXIT_FAILURE, _("long or incomplete input line - quitting"));
1739     *lp = 0;
1740 
1741     /* remove comments, if any */
1742     if ((lp = strchr(line + 2, '#')) != 0)
1743 	*lp = 0;
1744 
1745     /* recognize a few commands - to be expanded */
1746     if (!strcmp(line + 2, "unit: sectors")) {
1747 	specified_format = F_SECTOR;
1748 	return RD_CMD;
1749     }
1750 
1751     /* dump style? - then bad input is fatal */
1752     if ((ip = strchr(line + 2, ':')) != 0) {
1753 	struct dumpfld *d;
1754 
1755  nxtfld:
1756 	ip++;
1757 	while (isspace(*ip))
1758 	    ip++;
1759 	if (*ip == 0)
1760 	    return fno;
1761 	for (d = dumpflds; (size_t) (d - dumpflds) < ARRAY_SIZE(dumpflds); d++) {
1762 	    if (!strncmp(ip, d->fldname, strlen(d->fldname))) {
1763 		ip += strlen(d->fldname);
1764 		while (isspace(*ip))
1765 		    ip++;
1766 		if (d->is_bool)
1767 		    fields[d->fldno] = line;
1768 		else if (*ip == '=') {
1769 		    while (isspace(*++ip)) ;
1770 		    fields[d->fldno] = ip;
1771 		    while (isalnum(*ip))	/* 0x07FF */
1772 			ip++;
1773 		} else
1774 		    errx(EXIT_FAILURE, _("input error: `=' expected after %s field"),
1775 			  d->fldname);
1776 		if (fno <= d->fldno)
1777 		    fno = d->fldno + 1;
1778 		if (*ip == 0)
1779 		    return fno;
1780 		if (*ip != ',' && *ip != ';')
1781 		    errx(EXIT_FAILURE, _("input error: unexpected character %c after %s field"),
1782 			  *ip, d->fldname);
1783 		*ip = 0;
1784 		goto nxtfld;
1785 	    }
1786 	}
1787 	errx(EXIT_FAILURE, _("unrecognized input: %s"), ip);
1788     }
1789 
1790     /* split line into fields */
1791     lp = ip = line + 2;
1792     fields[fno++] = lp;
1793     while ((c = *ip++) != 0) {
1794 	if (!lp[-1] && (c == '\t' || c == ' ')) ;
1795 	else if (c == '\t' || c == ' ' || c == ',' || c == ';') {
1796 	    *lp++ = 0;
1797 	    if (fno < fieldssize)
1798 		fields[fno++] = lp;
1799 	    continue;
1800 	} else
1801 	    *lp++ = c;
1802     }
1803 
1804     if (lp == fields[fno - 1])
1805 	fno--;
1806     return fno;
1807 }
1808 
1809 /* read a number, use default if absent */
1810 /* a sign gives an offset from the default */
1811 static int
get_ul(char * u,unsigned long * up,unsigned long def,int base)1812 get_ul(char *u, unsigned long *up, unsigned long def, int base) {
1813     char *nu;
1814     int sign = 0;
1815     unsigned long val;
1816 
1817     if (*u == '+') {
1818 	sign = 1;
1819 	u++;
1820     } else if (*u == '-') {
1821 	sign = -1;
1822 	u++;
1823     }
1824     if (*u) {
1825 	errno = 0;
1826 	val = strtoul(u, &nu, base);
1827 	if (errno == ERANGE) {
1828 	    warnx(_("number too big"));
1829 	    return -1;
1830 	}
1831 	if (*nu) {
1832 	    warnx(_("trailing junk after number"));
1833 	    return -1;
1834 	}
1835 	if (sign == 1)
1836 	    val = def + val;
1837 	else if (sign == -1)
1838 	    val = def - val;
1839 	*up = val;
1840     } else
1841 	*up = def;
1842     return 0;
1843 }
1844 
1845 
1846 /* read a number, use default if absent */
1847 /* a sign gives an offset from the default */
1848 static int
get_ull(char * u,unsigned long long * up,unsigned long long def,int base)1849 get_ull(char *u, unsigned long long *up, unsigned long long def, int base) {
1850     char *nu;
1851     int sign = 0;
1852     unsigned long long val;
1853 
1854     if (*u == '+') {
1855 	sign = 1;
1856 	u++;
1857     } else if (*u == '-') {
1858 	sign = -1;
1859 	u++;
1860     }
1861     if (*u) {
1862 	errno = 0;
1863 	val = strtoull(u, &nu, base);
1864 	if (errno == ERANGE) {
1865 	    warnx(_("number too big"));
1866 	    return -1;
1867 	}
1868 	if (*nu) {
1869 	    warnx(_("trailing junk after number"));
1870 	    return -1;
1871 	}
1872 	if (sign == 1)
1873 	    val = def + val;
1874 	else if (sign == -1)
1875 	    val = def - val;
1876 	*up = val;
1877     } else
1878 	*up = def;
1879     return 0;
1880 }
1881 
1882 
1883 /* There are two common ways to structure extended partitions:
1884    as nested boxes, and as a chain. Sometimes the partitions
1885    must be given in order. Sometimes all logical partitions
1886    must lie inside the outermost extended partition.
1887 NESTED: every partition is contained in the surrounding partitions
1888    and is disjoint from all others.
1889 CHAINED: every data partition is contained in the surrounding partitions
1890    and disjoint from all others, but extended partitions may lie outside
1891    (insofar as allowed by all_logicals_inside_outermost_extended).
1892 ONESECTOR: all data partitions are mutually disjoint; extended partitions
1893    each use one sector only (except perhaps for the outermost one).
1894 */
1895 int partitions_in_order = 0;
1896 int all_logicals_inside_outermost_extended = 1;
1897 enum { NESTED, CHAINED, ONESECTOR } boxes = NESTED;
1898 
1899 /* find the default value for <start> - assuming entire units */
1900 static unsigned long long
first_free(int pno,int is_extended,struct part_desc * ep,int format,unsigned long long mid,struct disk_desc * z)1901 first_free(int pno, int is_extended, struct part_desc *ep, int format,
1902 	   unsigned long long mid, struct disk_desc *z) {
1903     unsigned long long ff, fff;
1904     unsigned long unit = unitsize(format);
1905     struct part_desc *partitions = &(z->partitions[0]), *pp = 0;
1906 
1907     /* if containing ep undefined, look at its container */
1908     if (ep && ep->p.sys_type == EMPTY_PARTITION)
1909 	ep = ep->ep;
1910 
1911     if (ep) {
1912 	if (boxes == NESTED || (boxes == CHAINED && !is_extended))
1913 	    pp = ep;
1914 	else if (all_logicals_inside_outermost_extended)
1915 	    pp = outer_extended_partition(ep);
1916     }
1917 #if 0
1918     ff = pp ? (pp->start + unit - 1) / unit : 0;
1919 #else
1920     /* rounding up wastes almost an entire cylinder - round down
1921        and leave it to compute_start_sect() to fix the difference */
1922     ff = pp ? pp->start / unit : 0;
1923 #endif
1924     /* MBR and 1st sector of an extended partition are never free */
1925     if (unit == 1)
1926 	ff++;
1927 
1928  again:
1929     for (pp = partitions; pp < partitions + pno; pp++) {
1930 	if (!is_parent(pp, ep) && pp->size > 0) {
1931 	    if ((partitions_in_order || pp->start / unit <= ff
1932 		 || (mid && pp->start / unit <= mid))
1933 		&& (fff = (pp->start + pp->size + unit - 1) / unit) > ff) {
1934 		ff = fff;
1935 		goto again;
1936 	    }
1937 	}
1938     }
1939 
1940     return ff;
1941 }
1942 
1943 /* find the default value for <size> - assuming entire units */
1944 static unsigned long long
max_length(int pno,int is_extended,struct part_desc * ep,int format,unsigned long long start,struct disk_desc * z)1945 max_length(int pno, int is_extended, struct part_desc *ep, int format,
1946 	   unsigned long long start, struct disk_desc *z) {
1947     unsigned long long fu;
1948     unsigned long unit = unitsize(format);
1949     struct part_desc *partitions = &(z->partitions[0]), *pp = 0;
1950 
1951     /* if containing ep undefined, look at its container */
1952     if (ep && ep->p.sys_type == EMPTY_PARTITION)
1953 	ep = ep->ep;
1954 
1955     if (ep) {
1956 	if (boxes == NESTED || (boxes == CHAINED && !is_extended))
1957 	    pp = ep;
1958 	else if (all_logicals_inside_outermost_extended)
1959 	    pp = outer_extended_partition(ep);
1960     }
1961     fu = pp ? (pp->start + pp->size) / unit : get_disksize(format);
1962 
1963     for (pp = partitions; pp < partitions + pno; pp++)
1964 	if (!is_parent(pp, ep) && pp->size > 0
1965 	    && pp->start / unit >= start && pp->start / unit < fu)
1966 	    fu = pp->start / unit;
1967 
1968     return (fu > start) ? fu - start : 0;
1969 }
1970 
1971 /* compute starting sector of a partition inside an extended one */
1972 /* return 0 on failure */
1973 /* ep is 0 or points to surrounding extended partition */
1974 static int
compute_start_sect(struct part_desc * p,struct part_desc * ep)1975 compute_start_sect(struct part_desc *p, struct part_desc *ep) {
1976     unsigned long long base;
1977     int inc = (DOS && B.sectors) ? B.sectors : 1;
1978     long long delta;
1979 
1980     if (ep && p->start + p->size >= ep->start + 1)
1981 	delta = p->start - ep->start - inc;
1982     else if (p->start == 0 && p->size > 0)
1983 	delta = -inc;
1984     else
1985 	delta = 0;
1986 
1987     if (delta < 0) {
1988 	unsigned long long old_size = p->size;
1989 	p->start -= delta;
1990 	p->size += delta;
1991 	if (is_extended(p->p.sys_type) && boxes == ONESECTOR)
1992 	    p->size = inc;
1993 	else if ((long long) old_size <= -delta) {
1994 	    warnx(_("no room for partition descriptor"));
1995 	    return 0;
1996 	}
1997     }
1998     base = (!ep ? 0
1999 	    : (is_extended(p->p.sys_type) ?
2000 	       outer_extended_partition(ep) : ep)->start);
2001     p->ep = ep;
2002     if (p->p.sys_type == EMPTY_PARTITION && p->size == 0) {
2003 	p->p.start_sect = 0;
2004 	p->p.begin_chs = zero_chs;
2005 	p->p.end_chs = zero_chs;
2006     } else {
2007 	p->p.start_sect = p->start - base;
2008 	p->p.begin_chs = ulong_to_chs(p->start, B);
2009 	p->p.end_chs = ulong_to_chs(p->start + p->size - 1, B);
2010     }
2011     p->p.nr_sects = p->size;
2012     return 1;
2013 }
2014 
2015 /* build the extended partition surrounding a given logical partition */
2016 static int
build_surrounding_extended(struct part_desc * p,struct part_desc * ep,struct disk_desc * z)2017 build_surrounding_extended(struct part_desc *p, struct part_desc *ep,
2018 			   struct disk_desc *z) {
2019     int inc = (DOS && B.sectors) ? B.sectors : 1;
2020     int format = F_SECTOR;
2021     struct part_desc *p0 = &(z->partitions[0]), *eep = ep->ep;
2022 
2023     if (boxes == NESTED) {
2024 	ep->start = first_free(ep - p0, 1, eep, format, p->start, z);
2025 	ep->size = max_length(ep - p0, 1, eep, format, ep->start, z);
2026 	if (ep->start > p->start || ep->start + ep->size < p->start + p->size) {
2027 	    warnx(_("cannot build surrounding extended partition"));
2028 	    return 0;
2029 	}
2030     } else {
2031 	ep->start = p->start;
2032 	if (boxes == CHAINED)
2033 	    ep->size = p->size;
2034 	else
2035 	    ep->size = inc;
2036     }
2037 
2038     ep->p.nr_sects = ep->size;
2039     ep->p.bootable = 0;
2040     ep->p.sys_type = EXTENDED_PARTITION;
2041     if (!compute_start_sect(ep, eep) || !compute_start_sect(p, ep)) {
2042 	ep->p.sys_type = EMPTY_PARTITION;
2043 	ep->size = 0;
2044 	return 0;
2045     }
2046 
2047     return 1;
2048 }
2049 
2050 static int
read_line(int pno,struct part_desc * ep,char * dev,int interactive,struct disk_desc * z)2051 read_line(int pno, struct part_desc *ep, char *dev, int interactive,
2052 	  struct disk_desc *z) {
2053     char line[1000];
2054     char *fields[11];
2055     int fno, pct = pno % 4;
2056     struct part_desc p, *orig;
2057     unsigned long long ff, ff1, ul, ml, ml1, def;
2058     int format, lpno, is_extd;
2059 
2060     if (eof || eob)
2061 	return -1;
2062 
2063     lpno = index_to_linux(pno, z);
2064 
2065     if (interactive) {
2066 	if (pct == 0 && (show_extended || pno == 0))
2067 	    putchar('\n');
2068 	warnx("%s:", partname(dev, lpno, 10));
2069     }
2070 
2071     /* read input line - skip blank lines when reading from a file */
2072     do {
2073 	fno = read_stdin(fields, line, ARRAY_SIZE(fields), ARRAY_SIZE(line));
2074     } while (fno == RD_CMD || (fno == 0 && !interactive));
2075     if (fno == RD_EOF) {
2076 	return -1;
2077     } else if (fno > 10 && *(fields[10]) != 0) {
2078 	warnx(_("too many input fields"));
2079 	return 0;
2080     }
2081 
2082     if (fno == 1 && !strcmp(fields[0], ".")) {
2083 	eob = 1;
2084 	return -1;
2085     }
2086 
2087     /* use specified format, but round to cylinders if F_MEGABYTE specified */
2088     format = 0;
2089     if (B.cylindersize && specified_format == F_MEGABYTE && !Linux)
2090 	format = F_CYLINDER;
2091 
2092     orig = (one_only ? &(oldp.partitions[pno]) : 0);
2093 
2094     p = zero_part_desc;
2095     p.ep = ep;
2096 
2097     /* first read the type - we need to know whether it is extended */
2098     /* stop reading when input blank (defaults) and all is full */
2099     is_extd = 0;
2100     if (fno == 0) {		/* empty line */
2101 	if (orig && is_extended(orig->p.sys_type))
2102 	    is_extd = 1;
2103 	ff = first_free(pno, is_extd, ep, format, 0, z);
2104 	ml = max_length(pno, is_extd, ep, format, ff, z);
2105 	if (ml == 0 && is_extd == 0) {
2106 	    is_extd = 1;
2107 	    ff = first_free(pno, is_extd, ep, format, 0, z);
2108 	    ml = max_length(pno, is_extd, ep, format, ff, z);
2109 	}
2110 	if (ml == 0 && pno >= 4) {
2111 	    /* no free blocks left - don't read any further */
2112 	    warnx(_("No room for more"));
2113 	    return -1;
2114 	}
2115     }
2116     if (fno < 3 || !*(fields[2]))
2117 	ul = orig ? orig->p.sys_type :
2118 	    (is_extd || (pno > 3 && pct == 1 && show_extended))
2119 	    ? EXTENDED_PARTITION : LINUX_NATIVE;
2120     else if (!strcmp(fields[2], "L"))
2121 	ul = LINUX_NATIVE;
2122     else if (!strcmp(fields[2], "S"))
2123 	ul = LINUX_SWAP;
2124     else if (!strcmp(fields[2], "E"))
2125 	ul = EXTENDED_PARTITION;
2126     else if (!strcmp(fields[2], "X"))
2127 	ul = LINUX_EXTENDED;
2128     else if (get_ull(fields[2], &ul, LINUX_NATIVE, 16))
2129 	return 0;
2130     if (ul > 255) {
2131 	warnx(_("Illegal type"));
2132 	return 0;
2133     }
2134     p.p.sys_type = ul;
2135     is_extd = is_extended(ul);
2136 
2137     /* find start */
2138     ff = first_free(pno, is_extd, ep, format, 0, z);
2139     ff1 = ff * unitsize(format);
2140     def = orig ? orig->start : (pno > 4 && pct > 1) ? 0 : ff1;
2141     if (fno < 1 || !*(fields[0]))
2142 	p.start = def;
2143     else {
2144 	if (get_ull(fields[0], &ul, def / unitsize(0), 0))
2145 	    return 0;
2146 	p.start = ul * unitsize(0);
2147 	p.start -= (p.start % unitsize(format));
2148     }
2149 
2150     /* find length */
2151     ml = max_length(pno, is_extd, ep, format, p.start / unitsize(format), z);
2152     ml1 = ml * unitsize(format);
2153     def = orig ? orig->size : (pno > 4 && pct > 1) ? 0 : ml1;
2154     if (fno < 2 || !*(fields[1]))
2155 	p.size = def;
2156     else if (!strcmp(fields[1], "+"))
2157 	p.size = ml1;
2158     else {
2159 	if (get_ull(fields[1], &ul, def / unitsize(0), 0))
2160 	    return 0;
2161 	p.size = ul * unitsize(0) + unitsize(format) - 1;
2162 	p.size -= (p.size % unitsize(format));
2163     }
2164     if (p.size > ml1) {
2165 	warnx(_("Warning: given size (%llu) exceeds max allowable size (%llu)"),
2166 		(p.size + unitsize(0) - 1) / unitsize(0), ml1 / unitsize(0));
2167 	if (!force)
2168 	    return 0;
2169     }
2170     if (p.size == 0 && pno >= 4 && (fno < 2 || !*(fields[1]))) {
2171 	warnx(_("Warning: empty partition"));
2172 	if (!force)
2173 	    return 0;
2174     }
2175     p.p.nr_sects = p.size;
2176 
2177     if (p.size == 0 && !orig) {
2178 	if (fno < 1 || !*(fields[0]))
2179 	    p.start = 0;
2180 	if (fno < 3 || !*(fields[2]))
2181 	    p.p.sys_type = EMPTY_PARTITION;
2182     }
2183 
2184     if (p.start < ff1 && p.size > 0) {
2185 	warnx(_("Warning: bad partition start (earliest %llu)"),
2186 		(ff1 + unitsize(0) - 1) / unitsize(0));
2187 	if (!force)
2188 	    return 0;
2189     }
2190 
2191     if (fno < 4 || !*(fields[3]))
2192 	ul = (orig ? orig->p.bootable : 0);
2193     else if (!strcmp(fields[3], "-"))
2194 	ul = 0;
2195     else if (!strcmp(fields[3], "*") || !strcmp(fields[3], "+"))
2196 	ul = 0x80;
2197     else {
2198 	warnx(_("unrecognized bootable flag - choose - or *"));
2199 	return 0;
2200     }
2201     p.p.bootable = ul;
2202 
2203     if (ep && ep->p.sys_type == EMPTY_PARTITION) {
2204 	if (!build_surrounding_extended(&p, ep, z))
2205 	    return 0;
2206     } else if (!compute_start_sect(&p, ep))
2207 	return 0;
2208 
2209     {
2210 	longchs aa = chs_to_longchs(p.p.begin_chs), bb;
2211 
2212 	if (fno < 5) {
2213 	    bb = aa;
2214 	} else if (fno < 7) {
2215 	    warnx(_("partial c,h,s specification?"));
2216 	    return 0;
2217 	} else if (get_ul(fields[4], &bb.c, aa.c, 0) ||
2218 		   get_ul(fields[5], &bb.h, aa.h, 0) ||
2219 		   get_ul(fields[6], &bb.s, aa.s, 0))
2220 	    return 0;
2221 	p.p.begin_chs = longchs_to_chs(bb, B);
2222     }
2223     {
2224 	longchs aa = chs_to_longchs(p.p.end_chs), bb;
2225 
2226 	if (fno < 8) {
2227 	    bb = aa;
2228 	} else if (fno < 10) {
2229 	    warnx(_("partial c,h,s specification?"));
2230 	    return 0;
2231 	} else if (get_ul(fields[7], &bb.c, aa.c, 0) ||
2232 		   get_ul(fields[8], &bb.h, aa.h, 0) ||
2233 		   get_ul(fields[9], &bb.s, aa.s, 0))
2234 	    return 0;
2235 	p.p.end_chs = longchs_to_chs(bb, B);
2236     }
2237 
2238     if (pno > 3 && p.size && show_extended && p.p.sys_type != EMPTY_PARTITION
2239 	&& (is_extended(p.p.sys_type) != (pct == 1))) {
2240 	warnx(_("Extended partition not where expected"));
2241 	if (!force)
2242 	    return 0;
2243     }
2244 
2245     z->partitions[pno] = p;
2246     if (pno >= z->partno)
2247 	z->partno += 4;		/* reqd for out_partition() */
2248 
2249     if (interactive)
2250 	out_partition(dev, 0, &(z->partitions[pno]), z, B);
2251 
2252     return 1;
2253 }
2254 
2255 /* ep either points to the extended partition to contain this one,
2256    or to the empty partition that may become extended or is 0 */
2257 static int
read_partition(char * dev,int interactive,int pno,struct part_desc * ep,struct disk_desc * z)2258 read_partition(char *dev, int interactive, int pno, struct part_desc *ep,
2259 	       struct disk_desc *z) {
2260     struct part_desc *p = &(z->partitions[pno]);
2261     int i;
2262 
2263     if (one_only) {
2264 	*p = oldp.partitions[pno];
2265 	if (one_only_pno != pno)
2266 	    goto ret;
2267     } else if (!show_extended && pno > 4 && pno % 4)
2268 	goto ret;
2269 
2270     while (!(i = read_line(pno, ep, dev, interactive, z)))
2271 	if (!interactive)
2272 	    errx(EXIT_FAILURE, _("bad input"));
2273     if (i < 0) {
2274 	p->ep = ep;
2275 	return 0;
2276     }
2277 
2278  ret:
2279     p->ep = ep;
2280     if (pno >= z->partno)
2281 	z->partno += 4;
2282     return 1;
2283 }
2284 
2285 static void
read_partition_chain(char * dev,int interactive,struct part_desc * ep,struct disk_desc * z)2286 read_partition_chain(char *dev, int interactive, struct part_desc *ep,
2287 		     struct disk_desc *z) {
2288     int i;
2289     size_t base;
2290 
2291     eob = 0;
2292     while (1) {
2293 	base = z->partno;
2294 	if (base + 4 > ARRAY_SIZE(z->partitions)) {
2295 	    warnx(_("too many partitions"));
2296 	    break;
2297 	}
2298 	for (i = 0; i < 4; i++)
2299 	    if (!read_partition(dev, interactive, base + i, ep, z))
2300 		return;
2301 	for (i = 0; i < 4; i++) {
2302 	    ep = &(z->partitions[base + i]);
2303 	    if (is_extended(ep->p.sys_type) && ep->size)
2304 		break;
2305 	}
2306 	if (i == 4) {
2307 	    /* nothing found - maybe an empty partition is going
2308 	       to be extended */
2309 	    if (one_only || show_extended)
2310 		break;
2311 	    ep = &(z->partitions[base + 1]);
2312 	    if (ep->size || ep->p.sys_type != EMPTY_PARTITION)
2313 		break;
2314 	}
2315     }
2316 }
2317 
2318 static void
read_input(char * dev,int interactive,struct disk_desc * z)2319 read_input(char *dev, int interactive, struct disk_desc *z) {
2320     size_t i;
2321     struct part_desc *partitions = &(z->partitions[0]), *ep;
2322 
2323     for (i = 0; i < ARRAY_SIZE(z->partitions); i++)
2324 	partitions[i] = zero_part_desc;
2325     z->partno = 0;
2326 
2327     if (interactive)
2328 	warnx(_("Input in the following format; absent fields get a default value.\n"
2329 		  "<start> <size> <type [E,S,L,X,hex]> <bootable [-,*]> <c,h,s> <c,h,s>\n"
2330 		  "Usually you only need to specify <start> and <size> (and perhaps <type>)."));
2331     eof = 0;
2332 
2333     for (i = 0; i < 4; i++)
2334 	read_partition(dev, interactive, i, 0, z);
2335     for (i = 0; i < 4; i++) {
2336 	ep = partitions + i;
2337 	if (is_extended(ep->p.sys_type) && ep->size)
2338 	    read_partition_chain(dev, interactive, ep, z);
2339     }
2340     add_sector_and_offset(z);
2341 }
2342 
2343 /*
2344  *  G. The command line
2345  */
usage(FILE * out)2346 static void usage(FILE * out)
2347 {
2348 	fputs(USAGE_HEADER, out);
2349 	fprintf(out,
2350 		_(" %s [options] <device>...\n"),  program_invocation_short_name);
2351 
2352 	fputs(USAGE_OPTIONS, out);
2353 	fputs(_(" -s, --show-size           list size of a partition\n"
2354 		" -c, --id                  change or print partition Id\n"
2355 		"     --change-id           change Id\n"
2356 		"     --print-id            print Id\n"), out);
2357 	fputs(_(" -l, --list                list partitions of each device\n"
2358 		" -d, --dump                idem, but in a format suitable for later input\n"
2359 		" -i, --increment           number cylinders etc. from 1 instead of from 0\n"
2360 		" -u, --unit <letter>       units to be used; <letter> can be one of\n"
2361 		"                             S (sectors), C (cylinders), B (blocks), or M (MB)\n"), out);
2362 	fputs(_(" -1, --one-only            reserved option that does nothing currently\n"
2363 		" -T, --list-types          list the known partition types\n"
2364 		" -D, --DOS                 for DOS-compatibility: waste a little space\n"
2365 		" -E, --DOS-extended        DOS extended partition compatibility\n"
2366 		" -R, --re-read             make the kernel reread the partition table\n"), out);
2367 	fputs(_(" -N <number>               change only the partition with this <number>\n"
2368 		" -n                        do not actually write to disk\n"
2369 		" -O <file>                 save the sectors that will be overwritten to <file>\n"
2370 		" -I <file>                 restore sectors from <file>\n"), out);
2371 	fputs(_(" -V, --verify              check that the listed partitions are reasonable\n"
2372 		" -v, --version             display version information and exit\n"
2373 		" -h, --help                display this help text and exit\n"), out);
2374 
2375 	fputs(_("\nDangerous options:\n"), out);
2376 	fputs(_(" -f, --force               disable all consistency checking\n"
2377 		"     --no-reread           do not check whether the partition is in use\n"
2378 		" -q, --quiet               suppress warning messages\n"
2379 		" -L, --Linux               do not complain about things irrelevant for Linux\n"), out);
2380 	fputs(_(" -g, --show-geometry       print the kernel's idea of the geometry\n"
2381 		" -G, --show-pt-geometry    print geometry guessed from the partition table\n"), out);
2382 	fputs(_(" -A, --activate[=<device>] activate the bootable flag\n"
2383 		" -U, --unhide[=<device>]   set partition as unhidden\n"
2384 		" -x, --show-extended       also list extended partitions in the output,\n"
2385 		"                             or expect descriptors for them in the input\n"), out);
2386 	fputs(_("     --leave-last          do not allocate the last cylinder\n"
2387 		"     --IBM                 same as --leave-last\n"), out);
2388 	fputs(_("     --in-order            partitions are in order\n"
2389 		"     --not-in-order        partitions are not in order\n"
2390 		"     --inside-outer        all logicals inside outermost extended\n"
2391 		"     --not-inside-outer    not all logicals inside outermost extended\n"), out);
2392 	fputs(_("     --nested              every partition is disjoint from all others\n"
2393 		"     --chained             like nested, but extended partitions may lie outside\n"
2394 		"     --onesector           partitions are mutually disjoint\n"), out);
2395 
2396 	fputs(_("\nOverride the detected geometry using:\n"
2397 		" -C, --cylinders <number>  set the number of cylinders to use\n"
2398 		" -H, --heads <number>      set the number of heads to use\n"
2399 		" -S, --sectors <number>    set the number of sectors to use\n"), out);
2400 
2401 	fprintf(out, USAGE_MAN_TAIL("sfdisk(8)"));
2402 	exit(out == stderr ? EXIT_FAILURE : EXIT_SUCCESS);
2403 }
2404 
2405 static void
activate_usage(void)2406 activate_usage(void) {
2407     char *p;
2408     if (!strcmp(program_invocation_short_name, "activate"))
2409 	p = " ";
2410     else
2411 	p = " --activate=";
2412     fputs(USAGE_HEADER, stderr);
2413     fputs(USAGE_SEPARATOR, stderr);
2414     fprintf(stderr, _(" %s%sdevice            list active partitions on device\n"),
2415 	   program_invocation_short_name, p);
2416     fprintf(stderr, _(" %s%sdevice n1 n2 ...  activate partitions n1 ..., inactivate the rest\n"),
2417 	   program_invocation_short_name, p);
2418     fprintf(stderr, USAGE_MAN_TAIL("sfdisk(8)"));
2419     exit(EXIT_FAILURE);
2420 }
2421 
2422 static const char short_opts[] = "cdfghilnqsu:vx1A::C:DGH:I:LN:O:RS:TU::V";
2423 
2424 #define PRINT_ID 0400
2425 #define CHANGE_ID 01000
2426 
2427 enum {
2428     OPT_NO_REREAD = CHAR_MAX + 1,
2429     OPT_LEAVE_LAST,
2430     OPT_IN_ORDER,
2431     OPT_NOT_IN_ORDER,
2432     OPT_INSIDE_OUTER,
2433     OPT_NOT_INSIDE_OUTER,
2434     OPT_NESTED,
2435     OPT_CHAINED,
2436     OPT_ONESECTOR
2437 };
2438 
2439 static const struct option long_opts[] = {
2440     { "change-id",        no_argument, NULL, 'c' + CHANGE_ID },
2441     { "print-id",         no_argument, NULL, 'c' + PRINT_ID },
2442     { "id",               no_argument, NULL, 'c' },
2443     { "dump",             no_argument, NULL, 'd' },
2444     { "force",            no_argument, NULL, 'f' },
2445     { "show-geometry",    no_argument, NULL, 'g' },
2446     { "help",             no_argument, NULL, 'h' },
2447     { "increment",        no_argument, NULL, 'i' },
2448     { "list",             no_argument, NULL, 'l' },
2449     { "quiet",            no_argument, NULL, 'q' },
2450     { "show-size",        no_argument, NULL, 's' },
2451     { "unit",             required_argument, NULL, 'u' },
2452     { "version",          no_argument, NULL, 'v' },
2453     { "show-extended",    no_argument, NULL, 'x' },
2454     { "one-only",         no_argument, NULL, '1' },
2455     { "cylinders",        required_argument, NULL, 'C' },
2456     { "heads",            required_argument, NULL, 'H' },
2457     { "sectors",          required_argument, NULL, 'S' },
2458     { "show-pt-geometry", no_argument, NULL, 'G' },
2459     { "activate",         optional_argument, NULL, 'A' },
2460     { "DOS",              no_argument, NULL, 'D' },
2461     { "DOS-extended",     no_argument, NULL, 'E' },
2462     { "Linux",            no_argument, NULL, 'L' },
2463     { "re-read",          no_argument, NULL, 'R' },
2464     { "list-types",       no_argument, NULL, 'T' },
2465     { "unhide",           optional_argument, NULL, 'U' },
2466     { "no-reread",        no_argument, NULL, OPT_NO_REREAD },
2467     { "IBM",              no_argument, NULL, OPT_LEAVE_LAST },
2468     { "leave-last",       no_argument, NULL, OPT_LEAVE_LAST },
2469 /* dangerous flags - not all completely implemented */
2470     { "in-order",         no_argument, NULL, OPT_IN_ORDER },
2471     { "not-in-order",     no_argument, NULL, OPT_NOT_IN_ORDER },
2472     { "inside-outer",     no_argument, NULL, OPT_INSIDE_OUTER },
2473     { "not-inside-outer", no_argument, NULL, OPT_NOT_INSIDE_OUTER },
2474     { "nested",           no_argument, NULL, OPT_NESTED },
2475     { "chained",          no_argument, NULL, OPT_CHAINED },
2476     { "onesector",        no_argument, NULL, OPT_ONESECTOR },
2477     { NULL, 0, NULL, 0 }
2478 };
2479 
is_ide_cdrom_or_tape(char * device)2480 static int is_ide_cdrom_or_tape(char *device)
2481 {
2482 	int fd, ret;
2483 
2484 	if ((fd = open(device, O_RDONLY)) < 0)
2485 		return 0;
2486 	ret = blkdev_is_cdrom(fd);
2487 
2488 	close(fd);
2489 	return ret;
2490 }
2491 
nextproc(FILE * f)2492 static char *nextproc(FILE *f)
2493 {
2494 	char line[128 + 1];
2495 
2496 	if (!f)
2497 		return NULL;
2498 
2499 	while (fgets(line, sizeof(line), f)) {
2500 		char buf[PATH_MAX], *cn;
2501 		dev_t devno;
2502 
2503 		if (sscanf(line, " %*d %*d %*d %128[^\n ]", buf) != 1)
2504 			continue;
2505 
2506 		devno = sysfs_devname_to_devno(buf, NULL);
2507 		if (devno <= 0)
2508 			continue;
2509 
2510 		if (sysfs_devno_is_lvm_private(devno) ||
2511 		    sysfs_devno_is_wholedisk(devno) <= 0)
2512 			continue;
2513 
2514 		if (!sysfs_devno_to_devpath(devno, buf, sizeof(buf)))
2515 			continue;
2516 
2517 		cn = canonicalize_path(buf);
2518 		if (cn)
2519 			return cn;
2520 	}
2521 
2522 	return NULL;
2523 }
2524 
2525 static void do_list(char *dev, int silent);
2526 static void do_size(char *dev, int silent);
2527 static void do_geom(char *dev, int silent);
2528 static void do_pt_geom(char *dev, int silent);
2529 static void do_fdisk(char *dev);
2530 static void do_reread(char *dev);
2531 static void do_change_id(char *dev, char *part, char *id);
2532 static void do_unhide(char **av, int ac, char *arg);
2533 static void do_activate(char **av, int ac, char *arg);
2534 
2535 unsigned long long total_size;
2536 
2537 int
main(int argc,char ** argv)2538 main(int argc, char **argv) {
2539     int c;
2540     char *dev;
2541     int opt_size = 0;
2542     int opt_out_geom = 0;
2543     int opt_out_pt_geom = 0;
2544     int opt_reread = 0;
2545     int activate = 0;
2546     int do_id = 0;
2547     int unhide = 0;
2548     char *activatearg = 0;
2549     char *unhidearg = 0;
2550 
2551     setlocale(LC_ALL, "");
2552     bindtextdomain(PACKAGE, LOCALEDIR);
2553     textdomain(PACKAGE);
2554     atexit(close_stdout);
2555 
2556     if (argc < 1)
2557 	errx(EXIT_FAILURE, _("no command?"));
2558     if (!strcmp(program_invocation_short_name, "activate"))
2559 	activate = 1;		/* equivalent to `sfdisk -A' */
2560 
2561     while ((c = getopt_long(argc, argv, short_opts, long_opts, NULL)) != -1) {
2562 	switch (c) {
2563 	case 'f':
2564 	    force = 1;
2565 	    break;		/* does not imply quiet */
2566 	case 'g':
2567 	    opt_out_geom = 1;
2568 	    break;
2569 	case 'G':
2570 	    opt_out_pt_geom = 1;
2571 	    break;
2572 	case 'i':
2573 	    increment = 1;
2574 	    break;
2575 	case 'c':
2576 	case 'c' + PRINT_ID:
2577 	case 'c' + CHANGE_ID:
2578 	    do_id = c;
2579 	    break;
2580 	case 'd':
2581 	    dump = 1;		/* fall through */
2582 	case 'l':
2583 	    opt_list = 1;
2584 	    break;
2585 	case 'n':
2586 	    no_write = 1;
2587 	    break;
2588 	case 'q':
2589 	    quiet = 1;
2590 	    break;
2591 	case 's':
2592 	    opt_size = 1;
2593 	    break;
2594 	case 'u':
2595 	    set_format(*optarg);
2596 	    break;
2597 	case 'v':
2598 	    printf(UTIL_LINUX_VERSION);
2599 	    return EXIT_SUCCESS;
2600 	case 'h':
2601 	    usage(stdout);
2602 	    return EXIT_SUCCESS;
2603 	case 'x':
2604 	    show_extended = 1;
2605 	    break;
2606 	case 'A':
2607 	    activatearg = optarg;
2608 	    activate = 1;
2609 	    break;
2610 	case 'C':
2611 	    U.cylinders = strtoul_or_err(optarg, _("invalid cylinders argument"));
2612 	    break;
2613 	case 'D':
2614 	    DOS = 1;
2615 	    break;
2616 	case 'E':
2617 	    DOS_extended = 1;
2618 	    break;
2619 	case 'H':
2620 	    U.heads = strtoul_or_err(optarg, _("invalid heads argument"));
2621 	    break;
2622 	case 'L':
2623 	    Linux = 1;
2624 	    break;
2625 	case 'N':
2626 	    one_only = strtol_or_err(optarg, _("invalid number of partitions argument"));
2627 	    break;
2628 	case 'I':
2629 	    restore_sector_file = optarg;
2630 	    break;
2631 	case 'O':
2632 	    save_sector_file = optarg;
2633 	    break;
2634 	case 'R':
2635 	    opt_reread = 1;
2636 	    break;
2637 	case 'S':
2638 	    U.sectors = strtoul_or_err(optarg, _("invalid sectors argument"));
2639 	    break;
2640 	case 'T':
2641 	    list_types();
2642 	    return EXIT_SUCCESS;
2643 	case 'U':
2644 	    unhidearg = optarg;
2645 	    unhide = 1;
2646 	    break;
2647 	case 'V':
2648 	    verify = 1;
2649 	    break;
2650 	default:
2651 	    usage(stderr);
2652 	    break;
2653 
2654 	    /* dangerous flags */
2655 	case OPT_IN_ORDER:
2656 	    partitions_in_order = 1;
2657 	    break;
2658 	case OPT_NOT_IN_ORDER:
2659 	    partitions_in_order = 0;
2660 	    break;
2661 	case OPT_INSIDE_OUTER:
2662 	    all_logicals_inside_outermost_extended = 1;
2663 	    break;
2664 	case OPT_NOT_INSIDE_OUTER:
2665 	    all_logicals_inside_outermost_extended = 0;
2666 	    break;
2667 	case OPT_NESTED:
2668 	    boxes = NESTED;
2669 	    break;
2670 	case OPT_CHAINED:
2671 	    boxes = CHAINED;
2672 	    break;
2673 	case OPT_ONESECTOR:
2674 	    boxes = ONESECTOR;
2675 	    break;
2676 
2677 	    /* more flags */
2678 	case OPT_NO_REREAD:
2679 	    no_reread = 1;
2680 	    break;
2681 	case OPT_LEAVE_LAST:
2682 	    leave_last = 1;
2683 	    break;
2684 	}
2685     }
2686 
2687     if (optind == argc &&
2688 	(opt_list || opt_out_geom || opt_out_pt_geom || opt_size || verify)) {
2689 	FILE *procf;
2690 
2691 	/* try all known devices */
2692 	total_size = 0;
2693 
2694 	procf = fopen(_PATH_PROC_PARTITIONS, "r");
2695 	if (!procf)
2696 	    fprintf(stderr, _("cannot open %s\n"), _PATH_PROC_PARTITIONS);
2697 	else {
2698 	    while ((dev = nextproc(procf)) != NULL) {
2699 		if (!is_ide_cdrom_or_tape(dev)) {
2700 		    if (opt_out_geom)
2701 			do_geom(dev, 1);
2702 		    if (opt_out_pt_geom)
2703 			do_pt_geom(dev, 1);
2704 		    if (opt_size)
2705 			do_size(dev, 1);
2706 		    if (opt_list || verify)
2707 			do_list(dev, 1);
2708 		}
2709 		free(dev);
2710 	    }
2711 	    fclose(procf);
2712 	}
2713 
2714 	if (opt_size)
2715 	    printf(_("total: %llu blocks\n"), total_size);
2716 
2717 	return exit_status;
2718     }
2719 
2720     if (optind == argc) {
2721 	if (activate)
2722 	    activate_usage();
2723 	else
2724 	    usage(stderr);
2725     }
2726 
2727     if (opt_list || opt_out_geom || opt_out_pt_geom || opt_size || verify) {
2728 	while (optind < argc) {
2729 	    if (opt_out_geom)
2730 		do_geom(argv[optind], 0);
2731 	    if (opt_out_pt_geom)
2732 		do_pt_geom(argv[optind], 0);
2733 	    if (opt_size)
2734 		do_size(argv[optind], 0);
2735 	    if (opt_list || verify)
2736 		do_list(argv[optind], 0);
2737 	    optind++;
2738 	}
2739 	return exit_status;
2740     }
2741 
2742     if (activate) {
2743 	do_activate(argv + optind, argc - optind, activatearg);
2744 	return exit_status;
2745     }
2746     if (unhide) {
2747 	do_unhide(argv + optind, argc - optind, unhidearg);
2748 	return exit_status;
2749     }
2750     if (do_id) {
2751 	if ((do_id & PRINT_ID) != 0 && optind != argc - 2)
2752 	    errx(EXIT_FAILURE, _("usage: sfdisk --print-id device partition-number"));
2753 	else if ((do_id & CHANGE_ID) != 0 && optind != argc - 3)
2754 	    errx(EXIT_FAILURE, _("usage: sfdisk --change-id device partition-number Id"));
2755 	else if (optind != argc - 3 && optind != argc - 2)
2756 	    errx(EXIT_FAILURE, _("usage: sfdisk --id device partition-number [Id]"));
2757 	do_change_id(argv[optind], argv[optind + 1],
2758 		     (optind == argc - 2) ? 0 : argv[optind + 2]);
2759 	return exit_status;
2760     }
2761 
2762     if (optind != argc - 1)
2763 	errx(EXIT_FAILURE, _("can specify only one device (except with -l or -s)"));
2764     dev = argv[optind];
2765 
2766     if (opt_reread)
2767 	do_reread(dev);
2768     else if (restore_sector_file)
2769 	restore_sectors(dev);
2770     else
2771 	do_fdisk(dev);
2772 
2773     return exit_status;
2774 }
2775 
2776 /*
2777  *  H. Listing the current situation
2778  */
2779 
2780 static int
my_open(char * dev,int rw,int silent)2781 my_open(char *dev, int rw, int silent) {
2782     int fd, mode;
2783 
2784     mode = (rw ? O_RDWR : O_RDONLY);
2785     fd = open(dev, mode);
2786     if (fd < 0 && !silent) {
2787 	if (rw)
2788 	    err(EXIT_FAILURE, _("cannot open %s read-write"), dev);
2789 	else
2790 	    err(EXIT_FAILURE, _("cannot open %s for reading"), dev);
2791     }
2792     return fd;
2793 }
2794 
2795 static void
do_list(char * dev,int silent)2796 do_list(char *dev, int silent) {
2797     int fd;
2798     struct disk_desc *z;
2799 
2800     fd = my_open(dev, 0, silent);
2801     if (fd < 0)
2802 	return;
2803 
2804     z = &oldp;
2805 
2806     free_sectors();
2807     get_cylindersize(dev, fd, dump ? 1 : opt_list ? 0 : 1);
2808     get_partitions(dev, fd, z);
2809 
2810     if (opt_list)
2811 	out_partitions(dev, z);
2812 
2813     if (verify) {
2814 	if (partitions_ok(fd, z))
2815 	    printf(_("%s: OK"), dev);
2816 	else
2817 	    exit_status = 1;
2818     }
2819 
2820     close(fd);
2821 }
2822 
2823 static void
do_geom(char * dev,int silent)2824 do_geom(char *dev, int silent) {
2825     int fd;
2826     struct geometry R;
2827 
2828     fd = my_open(dev, 0, silent);
2829     if (fd < 0)
2830 	return;
2831 
2832     R = get_geometry(dev, fd, silent);
2833     if (R.cylinders)
2834 	printf(_("%s: %ld cylinders, %ld heads, %ld sectors/track\n"),
2835 	       dev, R.cylinders, R.heads, R.sectors);
2836 
2837     close(fd);
2838 }
2839 
2840 static void
do_pt_geom(char * dev,int silent)2841 do_pt_geom(char *dev, int silent) {
2842     int fd;
2843     struct disk_desc *z;
2844     struct geometry R;
2845 
2846     fd = my_open(dev, 0, silent);
2847     if (fd < 0)
2848 	return;
2849 
2850     z = &oldp;
2851 
2852     free_sectors();
2853     get_cylindersize(dev, fd, 1);
2854     get_partitions(dev, fd, z);
2855 
2856     R = B;
2857 
2858     if (z->partno != 0 && get_fdisk_geometry(z)) {
2859 	R.heads = F.heads;
2860 	R.sectors = F.sectors;
2861 	R.cylindersize = R.heads * R.sectors;
2862 	R.cylinders = (R.cylindersize == 0) ? 0 : R.total_size / R.cylindersize;
2863     }
2864 
2865     if (R.cylinders)
2866 	printf(_("%s: %ld cylinders, %ld heads, %ld sectors/track\n"),
2867 	       dev, R.cylinders, R.heads, R.sectors);
2868 
2869     close(fd);
2870 }
2871 
2872 /* for compatibility with earlier fdisk: provide option -s */
2873 static void
do_size(char * dev,int silent)2874 do_size(char *dev, int silent) {
2875     int fd;
2876     unsigned long long size;
2877 
2878     fd = my_open(dev, 0, silent);
2879     if (fd < 0)
2880 	return;
2881 
2882     if (blkdev_get_sectors(fd, &size) == -1) {
2883 	if (!silent)
2884 	    err(EXIT_FAILURE, _("Cannot get size of %s"), dev);
2885 	goto done;
2886     }
2887 
2888     size /= 2;			/* convert sectors to blocks */
2889 
2890     /* a CDROM drive without mounted CD yields MAXINT */
2891     if (silent && size == ((1 << 30) - 1))
2892 	goto done;
2893 
2894     if (silent)
2895 	printf("%s: %9llu\n", dev, size);
2896     else
2897 	printf("%llu\n", size);
2898 
2899     total_size += size;
2900 
2901 done:
2902     close(fd);
2903 }
2904 
2905 /*
2906  * Activate: usually one wants to have a single primary partition
2907  * to be active. OS/2 fdisk makes non-bootable logical partitions
2908  * active - I don't know what that means to OS/2 Boot Manager.
2909  *
2910  * Call: activate /dev/hda 2 5 7	make these partitions active
2911  *					and the remaining ones inactive
2912  * Or:   sfdisk -A /dev/hda 2 5 7
2913  *
2914  * If only a single partition must be active, one may also use the form
2915  *       sfdisk -A2 /dev/hda
2916  *
2917  * With "activate /dev/hda" or "sfdisk -A /dev/hda" the active partitions
2918  * are listed but not changed. To get zero active partitions, use
2919  * "activate /dev/hda none" or "sfdisk -A /dev/hda none".
2920  * Use something like `echo ",,,*" | sfdisk -N2 /dev/hda' to only make
2921  * /dev/hda2 active, without changing other partitions.
2922  *
2923  * A warning will be given if after the change not precisely one primary
2924  * partition is active.
2925  *
2926  * The present syntax was chosen to be (somewhat) compatible with the
2927  * activate from the LILO package.
2928  */
2929 static void
set_active(struct disk_desc * z,char * pnam)2930 set_active(struct disk_desc *z, char *pnam) {
2931     int pno;
2932 
2933     pno = asc_to_index(pnam, z);
2934     if (z->partitions[pno].ptype == DOS_TYPE)
2935 	z->partitions[pno].p.bootable = 0x80;
2936 }
2937 
2938 static void
do_activate(char ** av,int ac,char * arg)2939 do_activate(char **av, int ac, char *arg) {
2940     char *dev = av[0];
2941     int fd;
2942     int rw, i, pno, lpno;
2943     struct disk_desc *z;
2944 
2945     z = &oldp;
2946 
2947     rw = (!no_write && (arg || ac > 1));
2948     fd = my_open(dev, rw, 0);
2949 
2950     free_sectors();
2951     get_cylindersize(dev, fd, 1);
2952     get_partitions(dev, fd, z);
2953 
2954     if (!arg && ac == 1) {
2955 	/* list active partitions */
2956 	for (pno = 0; pno < z->partno; pno++) {
2957 	    if (z->partitions[pno].p.bootable) {
2958 		lpno = index_to_linux(pno, z);
2959 		if (pno == linux_to_index(lpno, z))
2960 		    printf("%s\n", partname(dev, lpno, 0));
2961 		else
2962 		    printf("%s#%d\n", dev, pno);
2963 		if (z->partitions[pno].p.bootable != 0x80)
2964 		    warnx(_("bad active byte: 0x%x instead of 0x80"),
2965 			    z->partitions[pno].p.bootable);
2966 	    }
2967 	}
2968     } else {
2969 	/* clear `active byte' everywhere */
2970 	for (pno = 0; pno < z->partno; pno++)
2971 	    if (z->partitions[pno].ptype == DOS_TYPE)
2972 		z->partitions[pno].p.bootable = 0;
2973 
2974 	/* then set where desired */
2975 	if (ac == 1)
2976 	    set_active(z, arg);
2977 	else
2978 	    for (i = 1; i < ac; i++)
2979 		set_active(z, av[i]);
2980 
2981 	/* then write to disk */
2982 	if (write_partitions(dev, fd, z))
2983 	    warnx(_("Done"));
2984 	else
2985 	    exit_status = 1;
2986     }
2987     i = 0;
2988     for (pno = 0; pno < z->partno && pno < 4; pno++)
2989 	if (z->partitions[pno].p.bootable)
2990 	    i++;
2991     if (i != 1)
2992 	warnx(_("You have %d active primary partitions. This does not matter for LILO,\n"
2993 		 "but the DOS MBR will only boot a disk with 1 active partition."),
2994 		i);
2995 
2996     if (close_fd(fd) != 0) {
2997 	warnx(_("write failed"));
2998 	exit_status = 1;
2999     }
3000 }
3001 
3002 static void
set_unhidden(struct disk_desc * z,char * pnam)3003 set_unhidden(struct disk_desc *z, char *pnam) {
3004     int pno;
3005     unsigned char id;
3006 
3007     pno = asc_to_index(pnam, z);
3008     id = z->partitions[pno].p.sys_type;
3009     if (id == 0x11 || id == 0x14 || id == 0x16 || id == 0x17 ||
3010 	id == 0x17 || id == 0x1b || id == 0x1c || id == 0x1e)
3011 	id -= 0x10;
3012     else
3013 	errx(EXIT_FAILURE, _("partition %s has id %x and is not hidden"), pnam, id);
3014     z->partitions[pno].p.sys_type = id;
3015 }
3016 
3017 /*
3018  * maybe remove and make part of --change-id
3019  */
3020 static void
do_unhide(char ** av,int ac,char * arg)3021 do_unhide(char **av, int ac, char *arg) {
3022     char *dev = av[0];
3023     int fd, rw, i;
3024     struct disk_desc *z;
3025 
3026     z = &oldp;
3027 
3028     rw = !no_write;
3029     fd = my_open(dev, rw, 0);
3030 
3031     free_sectors();
3032     get_cylindersize(dev, fd, 1);
3033     get_partitions(dev, fd, z);
3034 
3035     /* unhide where desired */
3036     if (ac == 1)
3037 	set_unhidden(z, arg);
3038     else
3039 	for (i = 1; i < ac; i++)
3040 	    set_unhidden(z, av[i]);
3041 
3042     /* then write to disk */
3043     if (write_partitions(dev, fd, z))
3044 	warn(_("Done"));
3045     else
3046 	exit_status = 1;
3047 
3048     if (close_fd(fd) != 0) {
3049 	warn(_("write failed"));
3050 	exit_status = 1;
3051     }
3052 }
3053 
3054 static void
do_change_id(char * dev,char * pnam,char * id)3055 do_change_id(char *dev, char *pnam, char *id) {
3056     int fd, rw, pno;
3057     struct disk_desc *z;
3058     unsigned long i;
3059 
3060     z = &oldp;
3061 
3062     rw = !no_write;
3063     fd = my_open(dev, rw, 0);
3064 
3065     free_sectors();
3066     get_cylindersize(dev, fd, 1);
3067     get_partitions(dev, fd, z);
3068 
3069     pno = asc_to_index(pnam, z);
3070     if (id == 0) {
3071 	printf("%x\n", z->partitions[pno].p.sys_type);
3072 	goto done;
3073     }
3074     i = strtoul(id, NULL, 16);
3075     if (i > 255)
3076 	errx(EXIT_FAILURE, _("Bad Id %lx"), i);
3077     z->partitions[pno].p.sys_type = i;
3078 
3079     if (write_partitions(dev, fd, z))
3080 	warnx(_("Done"));
3081     else
3082 	exit_status = 1;
3083 
3084 done:
3085     if (close_fd(fd) != 0) {
3086 	warnx(_("write failed"));
3087 	exit_status = 1;
3088     }
3089 }
3090 
3091 static void
do_reread(char * dev)3092 do_reread(char *dev) {
3093     int fd;
3094 
3095     fd = my_open(dev, 0, 0);
3096     if (reread_ioctl(fd)) {
3097 	warnx(_("This disk is currently in use."));
3098 	exit(EXIT_FAILURE);
3099     }
3100 
3101     close(fd);
3102 }
3103 
3104 /*
3105  *  I. Writing the new situation
3106  */
3107 
3108 static void
do_fdisk(char * dev)3109 do_fdisk(char *dev) {
3110     int fd;
3111     char answer[32];
3112     struct stat statbuf;
3113     int interactive = isatty(0);
3114     struct disk_desc *z;
3115 
3116     if (stat(dev, &statbuf) < 0)
3117 	err(EXIT_FAILURE, _("Fatal error: cannot find %s"), dev);
3118     if (!S_ISBLK(statbuf.st_mode)) {
3119 	warnx(_("Warning: %s is not a block device"), dev);
3120 	no_reread = 1;
3121     }
3122     fd = my_open(dev, !no_write, 0);
3123 
3124     if (!no_write && !no_reread) {
3125 	warnx(_("Checking that no-one is using this disk right now ..."));
3126 	if (reread_ioctl(fd)) {
3127 	    warnx(_("\nThis disk is currently in use - repartitioning is probably a bad idea.\n"
3128 		      "Umount all file systems, and swapoff all swap partitions on this disk.\n"
3129 		      "Use the --no-reread flag to suppress this check."));
3130 	    if (!force)
3131 		errx(EXIT_FAILURE, _("Use the --force flag to overrule all checks."));
3132 	} else
3133 	    warnx(_("OK"));
3134     }
3135 
3136     z = &oldp;
3137 
3138     free_sectors();
3139     get_cylindersize(dev, fd, 0);
3140     get_partitions(dev, fd, z);
3141 
3142     printf(_("Old situation:\n"));
3143     out_partitions(dev, z);
3144 
3145     if (one_only && (one_only_pno = linux_to_index(one_only, z)) < 0)
3146         errx(EXIT_FAILURE, _("Partition %d does not exist, cannot change it"), one_only);
3147 
3148     z = &newp;
3149 
3150     while (1) {
3151 
3152 	read_input(dev, interactive, z);
3153 
3154 	printf(_("New situation:\n"));
3155 	out_partitions(dev, z);
3156 
3157 	if (!partitions_ok(fd, z) && !force) {
3158 	    if (!interactive)
3159 		errx(EXIT_FAILURE, _("I don't like these partitions - nothing changed.\n"
3160 					 "(If you really want this, use the --force option.)"));
3161 	    else
3162 		warnx(_("I don't like this - probably you should answer No"));
3163 	}
3164 	if (interactive) {
3165  ask:
3166 	    if (no_write)
3167 		/* TRANSLATORS: sfdisk uses rpmatch which means the answers y and n
3168 		 * should be translated, but that is not the case with q answer. */
3169 		printf(_("Are you satisfied with this? [ynq] "));
3170 	    else
3171 		printf(_("Do you want to write this to disk? [ynq] "));
3172 	    ignore_result( fgets(answer, sizeof(answer), stdin) );
3173 	    if (answer[0] == 'q' || answer[0] == 'Q') {
3174 		errx(EXIT_FAILURE, _("Quitting - nothing changed"));
3175 	    } else if (rpmatch(answer) == 0) {
3176 		continue;
3177 	    } else if (rpmatch(answer) == 1) {
3178 		break;
3179 	    } else {
3180 		printf(_("Please answer one of y,n,q\n"));
3181 		goto ask;
3182 	    }
3183 	} else
3184 	    break;
3185     }
3186 
3187     if (write_partitions(dev, fd, z))
3188 	printf(_("Successfully wrote the new partition table\n\n"));
3189     else
3190 	exit_status = 1;
3191 
3192     if (!reread_disk_partition(dev, fd)) {	/* close fd on success */
3193 	close(fd);
3194 	exit_status = 1;
3195     }
3196     warnx(_("If you created or changed a DOS partition, /dev/foo7, say, then use dd(1)\n"
3197 	      "to zero the first 512 bytes:  dd if=/dev/zero of=/dev/foo7 bs=512 count=1\n"
3198 	      "(See fdisk(8).)"));
3199 
3200     sync();			/* superstition */
3201 }
3202 
3203 
3204 /*
3205  * return partition name - uses static storage unless buf is supplied
3206  */
partname(char * dev,int pno,int lth)3207 static char *partname(char *dev, int pno, int lth)
3208 {
3209 	static char bufp[PATH_MAX];
3210 	char *p;
3211 	int w, wp;
3212 
3213 	w = strlen(dev);
3214 	p = "";
3215 
3216 	if (isdigit(dev[w-1]))
3217 		p = "p";
3218 
3219 	/* devfs kludge - note: fdisk partition names are not supposed
3220 	   to equal kernel names, so there is no reason to do this */
3221 	if (strcmp (dev + w - 4, "disc") == 0) {
3222 		w -= 4;
3223 		p = "part";
3224 	}
3225 
3226 	/* udev names partitions by appending -partN
3227 	   e.g. ata-SAMSUNG_SV8004H_0357J1FT712448-part1 */
3228 	if ((strncmp(dev, _PATH_DEV_BYID, strlen(_PATH_DEV_BYID)) == 0) ||
3229 	     strncmp(dev, _PATH_DEV_BYPATH, strlen(_PATH_DEV_BYPATH)) == 0) {
3230 	       p = "-part";
3231 	}
3232 
3233 	wp = strlen(p);
3234 
3235 	if (lth) {
3236 		snprintf(bufp, sizeof(bufp), "%*.*s%s%-2u",
3237 			 lth-wp-2, w, dev, p, pno);
3238 	} else {
3239 		snprintf(bufp, sizeof(bufp), "%.*s%s%-2u", w, dev, p, pno);
3240 	}
3241 	return bufp;
3242 }
3243 
3244