1 /* partition 1.13 - Make a partition table Author: Kees J. Bot
13 #include <sys/ioctl.h>
20 #include <machine/partition.h>
21 #include <minix/config.h>
22 #include <minix/const.h>
23 #include <minix/partition.h>
25 #include "partition.h"
26 #define NR_PARTITIONS 4
29 #define SECTOR_SIZE 512
31 #define arraysize(a) (sizeof(a)/sizeof((a)[0]))
32 #define arraylimit(a) ((a) + arraysize(a))
36 void report(const char *label
)
38 fprintf(stderr
, "%s: %s: %s\n", arg0
, label
, strerror(errno
));
41 void fatal(const char *label
)
47 int aflag
; /* Add a new partition to the current table. */
48 int mflag
; /* Minix rules, no need for alignment. */
49 int rflag
; /* Report current partitions. */
50 int fflag
; /* Force making a table even if too small. */
51 int nflag
; /* Play-act, don't really do it. */
53 int cylinders
, heads
, sectors
; /* Device's geometry */
54 int pad
; /* Partitions must be padded. */
56 /* Descriptions of the device to divide and the partitions to make, including
57 * gaps between partitions.
60 struct part_entry primary
, table
[2 * NR_PARTITIONS
+ 1];
63 /* Extra flags at construction time. */
64 #define EXPAND_FLAG 0x01 /* Add the remaining sectors to this one */
65 #define EXIST_FLAG 0x02 /* Use existing partition */
67 void find_exist(struct part_entry
*exist
, int sysind
, int nr
)
71 struct part_entry oldtable
[NR_PARTITIONS
];
73 uint32_t minlow
, curlow
;
74 struct part_entry
*cur
;
75 char *nr_s
[] = { "", "second ", "third ", "fourth" };
77 if ((f
= open(device
, O_RDONLY
)) < 0
79 || lseek(f
, (off_t
) PART_TABLE_OFF
, SEEK_SET
) == -1
81 || read(f
, oldtable
, sizeof(oldtable
)) < 0
83 || read(f
, &signature
, sizeof(signature
)) < 0
93 for (i
= 0; i
< NR_PARTITIONS
; i
++) {
94 if (signature
== 0xAA55
95 && oldtable
[i
].sysind
!= NO_PART
96 && oldtable
[i
].lowsec
>= minlow
97 && oldtable
[i
].lowsec
< curlow
100 curlow
= oldtable
[i
].lowsec
;
108 if (cur
== nil
|| cur
->sysind
!= sysind
) {
110 "%s: Can't find a %sexisting partition of type 0x%02X\n",
111 arg0
, nr_s
[nr
], sysind
);
117 void write_table(void)
120 uint16_t signature
= 0xAA55;
121 struct part_entry newtable
[NR_PARTITIONS
];
125 printf("(Table not written)\n");
129 for (i
= 0; i
< NR_PARTITIONS
; i
++) newtable
[i
]= table
[1 + 2*i
];
131 /* we have a abstract struct but it must conform to a certain
132 * reality that will never change (in-MBR sizes and offsets).
133 * each partition entry is 16 bytes and there are 4 of them.
134 * this also determines the signature offset.
136 assert(sizeof(struct part_entry
) == 16);
137 assert(sizeof(newtable
) == 64);
139 if ((f
= open(device
, O_WRONLY
)) < 0
141 || lseek(f
, (off_t
) PART_TABLE_OFF
, SEEK_SET
) == -1
143 || write(f
, newtable
, sizeof(newtable
)) < 0
145 || write(f
, &signature
, sizeof(signature
)) < 0
151 void sec2dos(unsigned long sec
, unsigned char *dos
)
152 /* Translate a sector number into the three bytes DOS uses. */
154 unsigned secspcyl
= heads
* sectors
;
159 dos
[1]= ((sec
% sectors
) + 1) | ((cyl
>> 2) & 0xC0);
160 dos
[0]= (sec
% secspcyl
) / sectors
;
163 void show_chs(unsigned long pos
)
171 cyl
= pos
/ (heads
* sectors
);
172 head
= (pos
/ sectors
) - (cyl
* heads
);
175 printf(" %4d/%03d/%02d", cyl
, head
, sec
);
178 void show_part(struct part_entry
*p
)
180 static int banner
= 0;
184 if ((n
% 2) == 0) return;
188 "Part First Last Base Size Kb\n");
192 printf("%3d ", (n
-1) / 2);
194 show_chs(p
->lowsec
+ p
->size
- 1);
195 printf(" %8"PRIu32
" %8"PRIu32
" %7"PRIu32
"\n",
196 p
->lowsec
, p
->size
, p
->size
/ 2);
202 "Usage: partition [-mfn] device [type:]length[+*] ...\n");
206 #define between(a, c, z) ((unsigned) ((c) - (a)) <= ((z) - (a)))
208 void parse(char *descr
)
210 int seen
= 0, sysind
, flags
, c
;
211 unsigned long lowsec
, size
;
215 if (strchr(descr
, ':') == nil
) {
217 if ((npart
% 2) != 0) {
218 fprintf(stderr
, "%s: Two holes can't be adjacent.\n",
226 if ((npart
% 2) == 0) {
227 /* Need a hole before this partition. */
229 /* First hole contains the partition table. */
237 if (between('0', c
, '9'))
240 if (between('a', c
, 'z'))
243 if (between('A', c
, 'Z'))
247 sysind
= 0x10 * sysind
+ c
;
250 if (c
!= ':') usage();
255 if (strncmp(descr
, "exist", 5) == 0 && (npart
% 2) == 1) {
256 struct part_entry exist
;
258 find_exist(&exist
, sysind
, (npart
- 1) / 2);
259 sysind
= exist
.sysind
;
260 lowsec
= exist
.lowsec
;
268 while (between('0', (c
= *descr
++), '9')) {
269 size
= 10 * size
+ (c
- '0');
278 if (c
== '+' && !(flags
& EXIST_FLAG
))
285 if (seen
!= 3 || c
!= 0) usage();
287 if (npart
== arraysize(table
)) {
288 fprintf(stderr
, "%s: too many partitions, only %d possible.\n",
289 arg0
, NR_PARTITIONS
);
292 table
[npart
].bootind
= flags
;
293 table
[npart
].sysind
= sysind
;
294 table
[npart
].lowsec
= lowsec
;
295 table
[npart
].size
= size
;
300 /* Get the geometry of the drive the device lives on, and the base and size
307 if ((fd
= open(device
, O_RDONLY
)) < 0) fatal(device
);
310 struct part_geom geometry
;
313 /* Get the geometry of the drive, and the device's base and size. */
314 if (ioctl(fd
, DIOCGETP
, &geometry
) < 0)
316 /* Use the same fake geometry as part. */
317 if (fstat(fd
, &sb
) < 0)
319 geometry
.base
= ((u64_t
)(0));
320 geometry
.size
= ((u64_t
)(sb
.st_size
));
321 geometry
.sectors
= 32;
323 geometry
.cylinders
= (sb
.st_size
-1)/SECTOR_SIZE
/
324 (geometry
.sectors
*geometry
.heads
) + 1;
326 primary
.lowsec
= (unsigned long)(geometry
.base
/ SECTOR_SIZE
);
327 primary
.size
= (unsigned long)(geometry
.size
/ SECTOR_SIZE
);
328 cylinders
= geometry
.cylinders
;
329 heads
= geometry
.heads
;
330 sectors
= geometry
.sectors
;
332 if (fstat(fd
, &sb
) < 0) fatal(device
);
334 primary
.size
= sb
.st_size
/ SECTOR_SIZE
;
337 cylinders
= (sb
.st_size
-1) / SECTOR_SIZE
/ (sectors
*heads
) + 1;
342 /* Is this a primary partition table? If so then pad partitions. */
343 pad
= (!mflag
&& primary
.lowsec
== 0);
346 void boundary(struct part_entry
*pe
, int exp
)
347 /* Expand or reduce a primary partition to a track or cylinder boundary to
348 * avoid giving the fdisk's of simpler operating systems a fit.
353 n
= !pad
? 1 : pe
== &table
[0] ? sectors
: heads
* sectors
;
354 if (exp
) pe
->size
+= n
- 1;
355 pe
->size
= ((pe
->lowsec
+ pe
->size
) / n
* n
) - pe
->lowsec
;
358 void distribute(void)
359 /* Fit the partitions onto the device. Try to start and end them on a
360 * cylinder boundary if so required. The first partition is to start on
361 * track 1, not on cylinder 1.
364 struct part_entry
*pe
, *exp
;
366 unsigned long base
, oldbase
;
370 base
= primary
.lowsec
;
373 for (pe
= table
; pe
< arraylimit(table
); pe
++) {
375 if (pe
->bootind
& EXIST_FLAG
) {
376 if (base
> pe
->lowsec
) {
378 "%s: fixed partition %u is preceded by too big partitions/holes\n",
379 arg0
, ((unsigned int)(pe
- table
) - 1) / 2);
382 exp
= nil
; /* XXX - Extend before? */
386 if (pe
->bootind
& EXPAND_FLAG
) exp
= pe
;
388 base
= pe
->lowsec
+ pe
->size
;
389 count
-= base
- oldbase
;
393 fprintf(stderr
, "%s: %s is %ld sectors too small\n",
394 arg0
, device
, -count
);
398 /* Add leftover space to the partition marked for
403 exp
->bootind
&= ~EXPAND_FLAG
;
405 } while (exp
!= nil
);
407 for (pe
= table
; pe
< arraylimit(table
); pe
++) {
408 if (pe
->sysind
== NO_PART
) {
409 memset(pe
, 0, sizeof(*pe
));
411 sec2dos(pe
->lowsec
, &pe
->start_head
);
412 sec2dos(pe
->lowsec
+ pe
->size
- 1, &pe
->last_head
);
413 pe
->bootind
&= ACTIVE_FLAG
;
419 int main(int argc
, char **argv
)
423 if ((arg0
= strrchr(argv
[0], '/')) == nil
) arg0
= argv
[0]; else arg0
++;
426 while (i
< argc
&& argv
[i
][0] == '-') {
427 char *opt
= argv
[i
++] + 1;
429 if (opt
[0] == '-' && opt
[1] == 0) break;
431 while (*opt
!= 0) switch (*opt
++) {
432 case 'a': aflag
= 1; break;
433 case 'm': mflag
= 1; break;
434 case 'r': rflag
= 1; break;
435 case 'f': fflag
= 1; break;
436 case 'n': nflag
= 1; break;
443 if ((argc
- i
) != 1) usage();
444 fprintf(stderr
, "%s: -r is not yet implemented\n", __func__
);
447 if ((argc
- i
) < 1) usage();
448 if (aflag
) fprintf(stderr
, "%s: -a is not yet implemented\n", __func__
);
453 while (i
< argc
) parse(argv
[i
++]);