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