Drop main() prototype. Syncs with NetBSD-8
[minix.git] / minix / commands / partition / partition.c
blob103e1f906a8cefec0b22921b1c7ef28399518d7c
1 /* partition 1.13 - Make a partition table Author: Kees J. Bot
2 * 27 Apr 1992
3 */
4 #define nil ((void*)0)
5 #include <stdio.h>
6 #include <sys/types.h>
7 #include <stdlib.h>
8 #include <unistd.h>
9 #include <fcntl.h>
10 #include <sys/stat.h>
11 #include <string.h>
12 #include <errno.h>
13 #include <sys/ioctl.h>
14 #include <limits.h>
15 #include <stdint.h>
16 #include <inttypes.h>
17 #include <assert.h>
19 #ifdef __minix
20 #include <machine/partition.h>
21 #include <minix/config.h>
22 #include <minix/const.h>
23 #include <minix/partition.h>
24 #else
25 #include "partition.h"
26 #define NR_PARTITIONS 4
27 #endif
29 #define SECTOR_SIZE 512
31 #define arraysize(a) (sizeof(a)/sizeof((a)[0]))
32 #define arraylimit(a) ((a) + arraysize(a))
34 char *arg0;
36 void report(const char *label)
38 fprintf(stderr, "%s: %s: %s\n", arg0, label, strerror(errno));
41 void fatal(const char *label)
43 report(label);
44 exit(1);
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.
59 char *device;
60 struct part_entry primary, table[2 * NR_PARTITIONS + 1];
61 int npart;
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)
69 int f;
70 uint16_t signature;
71 struct part_entry oldtable[NR_PARTITIONS];
72 int n, i;
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
85 || close(f) < 0
86 ) fatal(device);
88 minlow= 0;
89 n= 0;
90 for (;;) {
91 curlow= -1;
92 cur= nil;
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
98 ) {
99 cur= &oldtable[i];
100 curlow= oldtable[i].lowsec;
103 if (n == nr) break;
104 n++;
105 minlow= curlow+1;
108 if (cur == nil || cur->sysind != sysind) {
109 fprintf(stderr,
110 "%s: Can't find a %sexisting partition of type 0x%02X\n",
111 arg0, nr_s[nr], sysind);
112 exit(1);
114 *exist = *cur;
117 void write_table(void)
119 int f;
120 uint16_t signature= 0xAA55;
121 struct part_entry newtable[NR_PARTITIONS];
122 int i;
124 if (nflag) {
125 printf("(Table not written)\n");
126 return;
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
147 || close(f) < 0
148 ) fatal(device);
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;
155 unsigned cyl;
157 cyl= sec / secspcyl;
158 dos[2]= cyl;
159 dos[1]= ((sec % sectors) + 1) | ((cyl >> 2) & 0xC0);
160 dos[0]= (sec % secspcyl) / sectors;
163 void show_chs(unsigned long pos)
165 int cyl, head, sec;
167 if (pos == -1) {
168 cyl= head= 0;
169 sec= -1;
170 } else {
171 cyl= pos / (heads * sectors);
172 head= (pos / sectors) - (cyl * heads);
173 sec= pos % sectors;
175 printf(" %4d/%03d/%02d", cyl, head, sec);
178 void show_part(struct part_entry *p)
180 static int banner= 0;
181 int n;
183 n= p - table;
184 if ((n % 2) == 0) return;
186 if (!banner) {
187 printf(
188 "Part First Last Base Size Kb\n");
189 banner= 1;
192 printf("%3d ", (n-1) / 2);
193 show_chs(p->lowsec);
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);
199 void usage(void)
201 fprintf(stderr,
202 "Usage: partition [-mfn] device [type:]length[+*] ...\n");
203 exit(1);
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;
213 lowsec= 0;
215 if (strchr(descr, ':') == nil) {
216 /* A hole. */
217 if ((npart % 2) != 0) {
218 fprintf(stderr, "%s: Two holes can't be adjacent.\n",
219 arg0);
220 exit(1);
222 sysind= NO_PART;
223 seen|= 1;
224 } else {
225 /* A partition. */
226 if ((npart % 2) == 0) {
227 /* Need a hole before this partition. */
228 if (npart == 0) {
229 /* First hole contains the partition table. */
230 table[0].size= 1;
232 npart++;
234 sysind= 0;
235 for (;;) {
236 c= *descr++;
237 if (between('0', c, '9'))
238 c= (c - '0') + 0x0;
239 else
240 if (between('a', c, 'z'))
241 c= (c - 'a') + 0xa;
242 else
243 if (between('A', c, 'Z'))
244 c= (c - 'A') + 0xA;
245 else
246 break;
247 sysind= 0x10 * sysind + c;
248 seen|= 1;
250 if (c != ':') usage();
253 flags= 0;
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;
261 size= exist.size;
262 flags |= EXIST_FLAG;
263 descr += 5;
264 c= *descr++;
265 seen|= 2;
266 } else {
267 size= 0;
268 while (between('0', (c= *descr++), '9')) {
269 size= 10 * size + (c - '0');
270 seen|= 2;
274 for (;;) {
275 if (c == '*')
276 flags|= ACTIVE_FLAG;
277 else
278 if (c == '+' && !(flags & EXIST_FLAG))
279 flags|= EXPAND_FLAG;
280 else
281 break;
282 c= *descr++;
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);
290 exit(1);
292 table[npart].bootind= flags;
293 table[npart].sysind= sysind;
294 table[npart].lowsec= lowsec;
295 table[npart].size= size;
296 npart++;
299 void geometry(void)
300 /* Get the geometry of the drive the device lives on, and the base and size
301 * of the device.
304 int fd;
305 struct stat sb;
307 if ((fd= open(device, O_RDONLY)) < 0) fatal(device);
309 #ifdef __minix
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)
318 fatal(device);
319 geometry.base= ((u64_t)(0));
320 geometry.size= ((u64_t)(sb.st_size));
321 geometry.sectors= 32;
322 geometry.heads= 64;
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;
331 #else
332 if (fstat(fd, &sb) < 0) fatal(device);
333 primary.lowsec= 0;
334 primary.size= sb.st_size / SECTOR_SIZE;
335 heads= 64;
336 sectors= 32;
337 cylinders= (sb.st_size-1) / SECTOR_SIZE / (sectors*heads) + 1;
338 #endif
340 close(fd);
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.
351 unsigned n;
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;
365 long count;
366 unsigned long base, oldbase;
368 do {
369 exp= nil;
370 base= primary.lowsec;
371 count= primary.size;
373 for (pe= table; pe < arraylimit(table); pe++) {
374 oldbase= base;
375 if (pe->bootind & EXIST_FLAG) {
376 if (base > pe->lowsec) {
377 fprintf(stderr,
378 "%s: fixed partition %u is preceded by too big partitions/holes\n",
379 arg0, ((unsigned int)(pe - table) - 1) / 2);
380 exit(1);
382 exp= nil; /* XXX - Extend before? */
383 } else {
384 pe->lowsec= base;
385 boundary(pe, 1);
386 if (pe->bootind & EXPAND_FLAG) exp= pe;
388 base= pe->lowsec + pe->size;
389 count-= base - oldbase;
391 if (count < 0) {
392 if (fflag) break;
393 fprintf(stderr, "%s: %s is %ld sectors too small\n",
394 arg0, device, -count);
395 exit(1);
397 if (exp != nil) {
398 /* Add leftover space to the partition marked for
399 * expanding.
401 exp->size+= count;
402 boundary(exp, 0);
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));
410 } else {
411 sec2dos(pe->lowsec, &pe->start_head);
412 sec2dos(pe->lowsec + pe->size - 1, &pe->last_head);
413 pe->bootind&= ACTIVE_FLAG;
415 show_part(pe);
419 int main(int argc, char **argv)
421 int i;
423 if ((arg0= strrchr(argv[0], '/')) == nil) arg0= argv[0]; else arg0++;
425 i= 1;
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;
437 default: usage();
441 if (rflag) {
442 if (aflag) usage();
443 if ((argc - i) != 1) usage();
444 fprintf(stderr, "%s: -r is not yet implemented\n", __func__);
445 exit(1);
446 } else {
447 if ((argc - i) < 1) usage();
448 if (aflag) fprintf(stderr, "%s: -a is not yet implemented\n", __func__);
450 device= argv[i++];
451 geometry();
453 while (i < argc) parse(argv[i++]);
455 distribute();
456 write_table();
458 exit(0);