Imported Upstream version 4.0.32
[platform/upstream/mtools.git] / mpartition.c
1 /*  Copyright 1997-2003,2005-2007,2009 Alain Knaff.
2  *  This file is part of mtools.
3  *
4  *  Mtools is free software: you can redistribute it and/or modify
5  *  it under the terms of the GNU General Public License as published by
6  *  the Free Software Foundation, either version 3 of the License, or
7  *  (at your option) any later version.
8  *
9  *  Mtools is distributed in the hope that it will be useful,
10  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
11  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  *  GNU General Public License for more details.
13  *
14  *  You should have received a copy of the GNU General Public License
15  *  along with Mtools.  If not, see <http://www.gnu.org/licenses/>.
16  *
17  * mformat.c
18  */
19 #define DONT_NEED_WAIT
20
21 #include "sysincludes.h"
22 #include "msdos.h"
23 #include "mtools.h"
24 #include "mainloop.h"
25 #include "fsP.h"
26 #include "file.h"
27 #include "plain_io.h"
28 #include "nameclash.h"
29 #include "buffer.h"
30 #include "partition.h"
31 #include "open_image.h"
32 #include "lba.h"
33
34 #ifdef OS_linux
35 #include "linux/hdreg.h"
36 #include "linux/fs.h"
37 #endif
38
39 static void set_offset(hsc *h, unsigned long offset,
40                        uint16_t heads, uint16_t sectors)
41 {
42         uint16_t head, sector;
43         unsigned int cyl;
44
45         if(! heads || !sectors)
46                 head = sector = cyl = 0; /* linear mode */
47         else {
48                 sector = offset % sectors;
49                 offset = offset / sectors;
50
51                 head = offset % heads;
52                 offset = offset / heads;
53                 if(offset > 1023)
54                         cyl = 1023;
55                 else
56                         cyl = (uint16_t) offset;
57         }
58         if(head > UINT8_MAX) {
59                 /* sector or head out of range => linear mode */
60                 head = sector = cyl = 0;
61         }
62         h->head = (uint8_t) head;
63         h->sector = ((sector+1) & 0x3f) | ((cyl & 0x300)>>2);
64         h->cyl = cyl & 0xff;
65 }
66
67 void setBeginEnd(struct partition *partTable,
68                  uint32_t begin, uint32_t end,
69                  uint16_t iheads, uint16_t isectors,
70                  int activate, uint8_t type, unsigned int fat_bits)
71 {
72         uint8_t heads, sectors;
73
74         if(iheads > UINT8_MAX) {
75                 fprintf(stderr,
76                         "Too many heads for partition: %d\n",
77                         iheads);
78                 exit(1);
79         }
80         heads=(uint8_t) iheads;
81         if(isectors > UINT8_MAX) {
82                 fprintf(stderr,
83                         "Too many sectors for partition: %d\n",
84                         isectors);
85                 exit(1);
86         }
87         sectors=(uint8_t) isectors;
88
89         set_offset(&partTable->start, begin, heads, sectors);
90         set_offset(&partTable->end, end-1, heads, sectors);
91         set_dword(partTable->start_sect, begin);
92         set_dword(partTable->nr_sects, end-begin);
93         if(activate)
94                 partTable->boot_ind = 0x80;
95         else
96                 partTable->boot_ind = 0;
97         if(!type) {
98                 if (fat_bits == 0) {
99                         /**
100                          * Fat bits unknown / not specified. We look
101                          * at size to get a rough estimate what FAT
102                          * bits are used.  Note: this is only an
103                          * estimate, the precise calculation would
104                          * involve the number of clusters, which is
105                          * not necessarily known here.
106                          */
107                         /* cc977219 would have a cutoff number of 32680,
108                          * corresponding to a FAT12 partition with 4K
109                          * clusters, however other information hints that
110                          * only partitions with less than 4096 sectors are
111                          * considered */
112                         if(end-begin < 4096)
113                                 fat_bits = 12;
114                         else
115                                 fat_bits = 16;
116                 }
117
118                 /* Description of various partition types in
119                  * https://en.wikipedia.org/wiki/Partition_type#List_of_partition_IDs
120                  * and
121                  * https://docs.microsoft.com/en-us/previous-versions/windows/it-pro/windows-2000-server/cc977219(v=technet.10)
122                  */
123                 if (fat_bits == 32)
124                         /* FAT 32 partition. For now, we disregard the
125                          * possibility of FAT 32 CHS partitions */
126                         type = 0x0C; /* Win95 FAT32, LBA */
127                 else if (end < 65536) {
128                         /* FAT 12 or FAT 16 partitions which fit entirely below
129                            the 32M mark */
130                         /* The 32M restriction doesn't apply to logical
131                            partitions within an extended partition, but for the
132                            moment mpartition only makes primary partitions */
133                         if(fat_bits == 12)
134                                 /* FAT 12 partition */
135                                 type = 0x01; /* DOS FAT12, CHS */
136                         else if (fat_bits == 16)
137                                 /* FAT 16 partition */
138                                 type = 0x04; /* DOS FAT16, CHS */
139                 } else if (end <  sectors * heads * 1024u)
140                         /* FAT 12 or FAT16 partition above the 32M
141                          * mark but below the 1024 cylinder mark.
142                          * Indeed, there can be no CHS partition
143                          * beyond 1024 cylinders */
144                         type = 0x06; /* DOS BIG FAT16 or FAT12, CHS */
145                 else
146                         type = 0x0E; /* Win95 BIG FAT16, LBA */
147         }
148         partTable->sys_ind = type;
149 }
150
151
152 /* setsize function.  Determines scsicam mapping if this cannot be inferred from
153  * any existing partitions. Shamelessly snarfed from the Linux kernel ;-) */
154
155 /*
156  * Function : static int setsize(unsigned long capacity,unsigned int *cyls,
157  *      unsigned int *hds, unsigned int *secs);
158  *
159  * Purpose : to determine a near-optimal int 0x13 mapping for a
160  *      SCSI disk in terms of lost space of size capacity, storing
161  *      the results in *cyls, *hds, and *secs.
162  *
163  * Returns : -1 on failure, 0 on success.
164  *
165  * Extracted from
166  *
167  * WORKING                                                    X3T9.2
168  * DRAFT                                                        792D
169  *
170  *
171  *                                                        Revision 6
172  *                                                         10-MAR-94
173  * Information technology -
174  * SCSI-2 Common access method
175  * transport and SCSI interface module
176  *
177  * ANNEX A :
178  *
179  * setsize() converts a read capacity value to int 13h
180  * head-cylinder-sector requirements. It minimizes the value for
181  * number of heads and maximizes the number of cylinders. This
182  * will support rather large disks before the number of heads
183  * will not fit in 4 bits (or 6 bits). This algorithm also
184  * minimizes the number of sectors that will be unused at the end
185  * of the disk while allowing for very large disks to be
186  * accommodated. This algorithm does not use physical geometry.
187  */
188
189 static int setsize(unsigned long capacity,unsigned int *cyls,
190                    uint16_t *hds,  uint16_t *secs) {
191     int rv = 0;
192     unsigned long heads, sectors, cylinders, temp;
193
194     cylinders = 1024L;                  /* Set number of cylinders to max */
195     sectors = 62L;                      /* Maximize sectors per track */
196
197     temp = cylinders * sectors;         /* Compute divisor for heads */
198     heads = capacity / temp;            /* Compute value for number of heads */
199     if (capacity % temp) {              /* If no remainder, done! */
200         heads++;                        /* Else, increment number of heads */
201         temp = cylinders * heads;       /* Compute divisor for sectors */
202         sectors = capacity / temp;      /* Compute value for sectors per
203                                                track */
204         if (capacity % temp) {          /* If no remainder, done! */
205             sectors++;                  /* Else, increment number of sectors */
206             temp = heads * sectors;     /* Compute divisor for cylinders */
207             cylinders = capacity / temp;/* Compute number of cylinders */
208         }
209     }
210     if (cylinders == 0) rv=-1;/* Give error if 0 cylinders */
211
212     *cyls = (unsigned int) cylinders;   /* Stuff return values */
213     *secs = (uint16_t) sectors;
214     *hds  = (uint16_t) heads;
215     return(rv);
216 }
217
218 static void setsize0(uint32_t capacity,unsigned int *cyls,
219                      uint16_t *hds, uint16_t *secs)
220 {
221         int r;
222
223         /* 1. First try "Megabyte" sizes */
224         if(capacity < 1024 * 2048 && !(capacity % 1024)) {
225                 *cyls = capacity >> 11;
226                 *hds  = 64;
227                 *secs = 32;
228                 return;
229         }
230
231         /* then try scsicam's size */
232         r = setsize(capacity,cyls,hds,secs);
233         if(r || *hds > 255 || *secs > 63) {
234                 /* scsicam failed. Do megabytes anyways */
235                 *cyls = capacity >> 11;
236                 *hds  = 64;
237                 *secs = 32;
238                 return;
239         }
240 }
241
242
243 static void usage(int ret) NORETURN;
244 static void usage(int ret)
245 {
246         fprintf(stderr,
247                 "Mtools version %s, dated %s\n", mversion, mdate);
248         fprintf(stderr,
249                 "Usage: %s [-pradcv] [-I] [-B bootsect-template] [-s sectors] "
250                         "[-t cylinders] "
251                 "[-h heads] [-T type] [-b begin] [-l length] "
252                 "drive\n", progname);
253         exit(ret);
254 }
255
256 static void checkTotalSectors(unsigned long tot_sectors) {
257         if(tot_sectors > UINT32_MAX) {
258                 fprintf(stderr, "Too many total sectors %ld\n",
259                         tot_sectors);
260                 exit(1);
261         }
262 }
263
264 void mpartition(int argc, char **argv, int dummy UNUSEDP) NORETURN;
265 void mpartition(int argc, char **argv, int dummy UNUSEDP)
266 {
267         Stream_t *Stream;
268         unsigned int dummy2;
269
270         unsigned int i;
271
272         uint16_t sec_per_cyl;
273         int doprint = 0;
274         int verbose = 0;
275         int create = 0;
276         int force = 0;
277         unsigned int length = 0;
278         int do_remove = 0;
279         int initialize = 0;
280
281         uint32_t tot_sectors=0;
282         /* Needs to be long due to BLKGETSIZE ioctl */
283
284         uint8_t type = 0;
285         int begin_set = 0;
286         int size_set = 0;
287         int end_set = 0;
288         int activate = 0;
289         int has_activated = 0;
290         int inconsistency=0;
291         unsigned int begin=0;
292         unsigned int end=0;
293         int dirty = 0;
294         int open2flags = 0;
295
296         int c;
297         struct device used_dev;
298         unsigned int argtracks;
299         uint16_t argheads, argsectors;
300
301         char drive, name[EXPAND_BUF];
302         unsigned char buf[512];
303         struct partition *partTable=(struct partition *)(buf+ 0x1ae);
304         struct device *dev;
305         char errmsg[2100];
306         char *bootSector=0;
307         struct partition *tpartition;
308
309         argtracks = 0;
310         argheads = 0;
311         argsectors = 0;
312
313         /* get command line options */
314         if(helpFlag(argc, argv))
315                 usage(0);
316         while ((c = getopt(argc, argv, "i:adprcIT:t:h:s:fvpb:l:S:B:")) != EOF) {
317                 char *endptr=NULL;
318                 errno=0;
319                 switch (c) {
320                         case 'i':
321                                 set_cmd_line_image(optarg);
322                                 break;
323                         case 'B':
324                                 bootSector = optarg;
325                                 break;
326                         case 'a':
327                                 /* no privs, as it could be abused to
328                                  * make other partitions unbootable, or
329                                  * to boot a rogue kernel from this one */
330                                 open2flags |= NO_PRIV;
331                                 activate = 1;
332                                 dirty = 1;
333                                 break;
334                         case 'd':
335                                 activate = -1;
336                                 dirty = 1;
337                                 break;
338                         case 'p':
339                                 doprint = 1;
340                                 break;
341                         case 'r':
342                                 do_remove = 1;
343                                 dirty = 1;
344                                 break;
345                         case 'I':
346                                 /* could be abused to nuke all other
347                                  * partitions */
348                                 open2flags |= NO_PRIV;
349                                 initialize = 1;
350                                 dirty = 1;
351                                 break;
352                         case 'c':
353                                 create = 1;
354                                 dirty = 1;
355                                 break;
356
357                         case 'T':
358                                 /* could be abused to "manually" create
359                                  * extended partitions */
360                                 open2flags |= NO_PRIV;
361                                 type = strtou8(optarg, &endptr, 0);
362                                 break;
363
364                         case 't':
365                                 argtracks = atoui(optarg);
366                                 break;
367                         case 'h':
368                                 argheads = atou16(optarg);
369                                 break;
370                         case 's':
371                                 argsectors = atou16(optarg);
372                                 break;
373
374                         case 'f':
375                                 /* could be abused by creating overlapping
376                                  * partitions and other such Snafu */
377                                 open2flags |= NO_PRIV;
378                                 force = 1;
379                                 break;
380
381                         case 'v':
382                                 verbose++;
383                                 break;
384                         case 'b':
385                                 begin_set = 1;
386                                 begin = strtoui(optarg, &endptr, 0);
387                                 break;
388                         case 'l':
389                                 size_set = 1;
390                                 length = strtoui(optarg, &endptr, 0);
391                                 break;
392
393                         default:
394                                 usage(1);
395                 }
396                 check_number_parse_errno((char)c, optarg, endptr);
397         }
398
399         if (argc - optind != 1 ||
400             !argv[optind][0] || argv[optind][1] != ':')
401                 usage(1);
402
403         drive = ch_toupper(argv[optind][0]);
404
405         /* check out a drive whose letter and parameters match */
406         sprintf(errmsg, "Drive '%c:' not supported", drive);
407         Stream = 0;
408         for(dev=devices;dev->drive;dev++) {
409                 int mode ;
410
411                 FREE(&(Stream));
412                 /* drive letter */
413                 if (dev->drive != drive)
414                         continue;
415                 if (dev->partition < 1 || dev->partition > 4) {
416                         sprintf(errmsg,
417                                 "Drive '%c:' is not a partition",
418                                 drive);
419                         continue;
420                 }
421                 used_dev = *dev;
422
423                 SET_INT(used_dev.tracks, argtracks);
424                 SET_INT(used_dev.heads, argheads);
425                 SET_INT(used_dev.sectors, argsectors);
426
427                 expand(dev->name, name);
428
429                 mode = dirty ? O_RDWR : O_RDONLY;
430                 if(initialize)
431                         mode |= O_CREAT;
432
433 #ifdef USING_NEW_VOLD
434                 strcpy(name, getVoldName(dev, name));
435 #endif
436                 Stream = OpenImage(&used_dev, dev, name, mode, errmsg,
437                                    open2flags | SKIP_PARTITION | ALWAYS_GET_GEOMETRY,
438                                    mode, NULL, NULL, NULL);
439
440                 if (!Stream) {
441 #ifdef HAVE_SNPRINTF
442                         snprintf(errmsg,sizeof(errmsg)-1,
443                                  "init: open: %s", strerror(errno));
444 #else
445                         sprintf(errmsg,"init: open: %s", strerror(errno));
446 #endif
447                         continue;
448                 }
449
450                 tot_sectors = used_dev.tot_sectors;
451
452                 /* read the partition table */
453                 if (READS(Stream, (char *) buf, 0, 512) != 512 && !initialize){
454 #ifdef HAVE_SNPRINTF
455                         snprintf(errmsg, sizeof(errmsg)-1,
456                                 "Error reading from '%s', wrong parameters?",
457                                 name);
458 #else
459                         sprintf(errmsg,
460                                 "Error reading from '%s', wrong parameters?",
461                                 name);
462 #endif
463                         continue;
464                 }
465                 if(verbose>=2)
466                         print_sector("Read sector", buf, 512);
467                 break;
468         }
469
470         /* print error msg if needed */
471         if ( dev->drive == 0 ){
472                 FREE(&Stream);
473                 fprintf(stderr,"%s: %s\n", argv[0],errmsg);
474                 exit(1);
475         }
476
477         if((used_dev.sectors || used_dev.heads) &&
478            (!used_dev.sectors || !used_dev.heads)) {
479                 fprintf(stderr,"You should either indicate both the number of sectors and the number of heads,\n");
480                 fprintf(stderr," or none of them\n");
481                 exit(1);
482         }
483
484         if(initialize) {
485                 if (bootSector) {
486                         int fd;
487                         fd = open(bootSector, O_RDONLY | O_BINARY | O_LARGEFILE);
488                         if (fd < 0) {
489                                 perror("open MBR");
490                                 exit(1);
491                         }
492                         if(read(fd, (char *) buf, 512) < 512) {
493                                 perror("read MBR");
494                                 exit(1);
495                         }
496                 }
497                 memset((char *)(partTable+1), 0, 4*sizeof(*partTable));
498                 set_word(((unsigned char*)buf)+510, 0xaa55);
499         }
500
501         /* check for boot signature, and place it if needed */
502         if((buf[510] != 0x55) || (buf[511] != 0xaa)) {
503                 fprintf(stderr,"Boot signature not set\n");
504                 fprintf(stderr,
505                         "Use the -I flag to initialize the partition table, and set the boot signature\n");
506                 inconsistency = 1;
507         }
508
509         tpartition=&partTable[dev->partition];
510         if(do_remove){
511                 if(!tpartition->sys_ind)
512                         fprintf(stderr,
513                                 "Partition for drive %c: does not exist\n",
514                                 drive);
515                 if((tpartition->sys_ind & 0x3f) == 5) {
516                         fprintf(stderr,
517                                 "Partition for drive %c: may be an extended partition\n",
518                                 drive);
519                         fprintf(stderr,
520                                 "Use the -f flag to remove it anyways\n");
521                         inconsistency = 1;
522                 }
523                 memset(tpartition, 0, sizeof(*tpartition));
524         }
525
526         if(create && tpartition->sys_ind) {
527                 fprintf(stderr,
528                         "Partition for drive %c: already exists\n", drive);
529                 fprintf(stderr,
530                         "Use the -r flag to remove it before attempting to recreate it\n");
531         }
532
533         /* if number of heads and sectors not known yet, set "reasonable"
534          * defaults */
535         compute_lba_geom_from_tot_sectors(&used_dev);
536
537         /* find out whether there is any activated partition. Moreover
538          * if no offset of a partition to be created have been
539          * specificed, find out whether it may be placed between the
540          * preceding and following partition already existing */
541         has_activated = 0;
542         for(i=1; i<5; i++){
543                 struct partition *partition=&partTable[i];
544                 if(!partition->sys_ind)
545                         continue;
546
547                 if(partition->boot_ind)
548                         has_activated++;
549
550                 if(i<dev->partition && !begin_set)
551                         begin = END(partition);
552                 if(i>dev->partition && !end_set && !size_set) {
553                         end = BEGIN(partition);
554                         end_set = 1;
555                 }
556         }
557
558         if(!used_dev.sectors && !used_dev.heads) {
559                 if(tot_sectors) {
560                         checkTotalSectors(tot_sectors);
561                         setsize0((uint32_t)tot_sectors,&dummy2,&used_dev.heads,
562                                  &used_dev.sectors);
563                 } else {
564                         used_dev.heads = 64;
565                         used_dev.sectors = 32;
566                 }
567         }
568
569         if(verbose)
570                 fprintf(stderr,"sectors: %d heads: %d %u\n",
571                         used_dev.sectors, used_dev.heads, tot_sectors);
572
573         sec_per_cyl = used_dev.sectors * used_dev.heads;
574         if(create) {
575                 unsigned int overlap;
576                 if(!end_set && !size_set && tot_sectors) {
577                         checkTotalSectors(tot_sectors);
578                         end = (uint32_t) tot_sectors -
579                                 (uint32_t) tot_sectors % sec_per_cyl;
580                         end_set = 1;
581                 }
582
583                 /* if the partition starts right at the beginning of
584                  * the disk, keep one track unused to allow place for
585                  * the master boot record */
586                 if(!begin && !begin_set)
587                         begin = used_dev.sectors ? used_dev.sectors : 2048;
588
589                 /* Do not try to align  partitions (other than first) on track
590                  * boundaries here: apparently this was a thing of the past */
591
592                 if(size_set) {
593                         end = begin + length;
594                 } else if(!end_set) {
595                         fprintf(stderr,"Unknown size\n");
596                         exit(1);
597                 }
598
599                 /* Make sure partition boundaries are correctly ordered
600                  * (end > begin) */
601                 if(begin >= end) {
602                         fprintf(stderr, "Begin larger than end\n");
603                         exit(1);
604                 }
605
606                 /* Check whether new partition doesn't overlap with
607                  * any of those already in place */
608                 if((overlap=findOverlap(partTable, 4, begin, end))) {
609                         fprintf(stderr,
610                                 "Partition would overlap with partition %d\n",
611                                 overlap);
612                         exit(1);
613                 }
614
615                 setBeginEnd(tpartition, begin, end,
616                             used_dev.heads, used_dev.sectors,
617                             !has_activated, type,
618                             abs(dev->fat_bits));
619         }
620
621         if(activate) {
622                 if(!tpartition->sys_ind) {
623                         fprintf(stderr,
624                                 "Partition for drive %c: does not exist\n",
625                                 drive);
626                 } else {
627                         switch(activate) {
628                                 case 1:
629                                         tpartition->boot_ind=0x80;
630                                         break;
631                                 case -1:
632                                         tpartition->boot_ind=0x00;
633                                         break;
634                         }
635                 }
636         }
637
638         inconsistency |= consistencyCheck(partTable, doprint, verbose,
639                                           &has_activated, tot_sectors,
640                                           &used_dev, dev->partition);
641
642         switch(has_activated) {
643                 case 0:
644                         fprintf(stderr,
645                                 "Warning: no active (bootable) partition present\n");
646                         break;
647                 case 1:
648                         break;
649                 default:
650                         fprintf(stderr,
651                                 "Warning: %d active (bootable) partitions present\n",
652                                 has_activated);
653                         fprintf(stderr,
654                                 "Usually, a disk should have exactly one active partition\n");
655                         break;
656         }
657
658         if(inconsistency && !force) {
659                 fprintf(stderr,
660                         "inconsistency detected!\n" );
661                 if(dirty) {
662                         fprintf(stderr,
663                                 "Retry with the -f switch to go ahead anyways\n");
664                         exit(1);
665                 }
666         }
667
668         if(doprint && tpartition->sys_ind) {
669                 printf("The following command will recreate the partition for drive %c:\n",
670                        drive);
671                 used_dev.tracks =
672                         (_DWORD(tpartition->nr_sects) +
673                          (BEGIN(tpartition) % sec_per_cyl)) /
674                         sec_per_cyl;
675                 printf("mpartition -c -b %d -l %d -t %d -h %d -s %d -b %u %c:\n",
676                        BEGIN(tpartition), PART_SIZE(tpartition),
677                        used_dev.tracks, used_dev.heads, used_dev.sectors,
678                        BEGIN(tpartition), drive);
679         }
680
681         if(dirty) {
682                 /* write data back to the disk */
683                 if(verbose>=2)
684                         print_sector("Writing sector", buf, 512);
685                 if (WRITES(Stream, (char *) buf, 0, 512) != 512) {
686                         fprintf(stderr,"Error writing partition table");
687                         exit(1);
688                 }
689                 if(verbose>=3)
690                         print_sector("Sector written", buf, 512);
691         }
692         FREE(&Stream);
693         exit(0);
694 }