kernel: scheduling fix for ARM
[minix.git] / commands / partition / partition.c
blobdac69cd71b2a1d2dedbe0ca44c9a7c80136dc229
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 <minix/config.h>
11 #include <minix/const.h>
12 #include <minix/partition.h>
13 #include <minix/u64.h>
14 #include <machine/partition.h>
15 #include <sys/stat.h>
16 #include <string.h>
17 #include <errno.h>
18 #include <sys/ioctl.h>
19 #include <limits.h>
21 #define SECTOR_SIZE 512
23 #define arraysize(a) (sizeof(a)/sizeof((a)[0]))
24 #define arraylimit(a) ((a) + arraysize(a))
26 char *arg0;
28 void report(const char *label)
30 fprintf(stderr, "%s: %s: %s\n", arg0, label, strerror(errno));
33 void fatal(const char *label)
35 report(label);
36 exit(1);
39 int aflag; /* Add a new partition to the current table. */
40 int mflag; /* Minix rules, no need for alignment. */
41 int rflag; /* Report current partitions. */
42 int fflag; /* Force making a table even if too small. */
43 int nflag; /* Play-act, don't really do it. */
45 int cylinders, heads, sectors; /* Device's geometry */
46 int pad; /* Partitions must be padded. */
48 /* Descriptions of the device to divide and the partitions to make, including
49 * gaps between partitions.
51 char *device;
52 struct part_entry primary, table[2 * NR_PARTITIONS + 1];
53 int npart;
55 /* Extra flags at construction time. */
56 #define EXPAND_FLAG 0x01 /* Add the remaining sectors to this one */
57 #define EXIST_FLAG 0x02 /* Use existing partition */
59 void find_exist(struct part_entry *exist, int sysind, int nr)
61 int f;
62 u16_t signature;
63 struct part_entry oldtable[NR_PARTITIONS];
64 int n, i;
65 u32_t minlow, curlow;
66 struct part_entry *cur;
67 char *nr_s[] = { "", "second ", "third ", "fourth" };
69 if ((f= open(device, O_RDONLY)) < 0
71 || lseek(f, (off_t) PART_TABLE_OFF, SEEK_SET) == -1
73 || read(f, oldtable, sizeof(oldtable)) < 0
75 || read(f, &signature, sizeof(signature)) < 0
77 || close(f) < 0
78 ) fatal(device);
80 minlow= 0;
81 n= 0;
82 for (;;) {
83 curlow= -1;
84 cur= nil;
85 for (i= 0; i < NR_PARTITIONS; i++) {
86 if (signature == 0xAA55
87 && oldtable[i].sysind != NO_PART
88 && oldtable[i].lowsec >= minlow
89 && oldtable[i].lowsec < curlow
90 ) {
91 cur= &oldtable[i];
92 curlow= oldtable[i].lowsec;
95 if (n == nr) break;
96 n++;
97 minlow= curlow+1;
100 if (cur == nil || cur->sysind != sysind) {
101 fprintf(stderr,
102 "%s: Can't find a %sexisting partition of type 0x%02X\n",
103 arg0, nr_s[nr], sysind);
104 exit(1);
106 *exist = *cur;
109 void write_table(void)
111 int f;
112 u16_t signature= 0xAA55;
113 struct part_entry newtable[NR_PARTITIONS];
114 int i;
116 if (nflag) {
117 printf("(Table not written)\n");
118 return;
121 for (i= 0; i < NR_PARTITIONS; i++) newtable[i]= table[1 + 2*i];
123 if ((f= open(device, O_WRONLY)) < 0
125 || lseek(f, (off_t) PART_TABLE_OFF, SEEK_SET) == -1
127 || write(f, newtable, sizeof(newtable)) < 0
129 || write(f, &signature, sizeof(signature)) < 0
131 || close(f) < 0
132 ) fatal(device);
135 void sec2dos(unsigned long sec, unsigned char *dos)
136 /* Translate a sector number into the three bytes DOS uses. */
138 unsigned secspcyl= heads * sectors;
139 unsigned cyl;
141 cyl= sec / secspcyl;
142 dos[2]= cyl;
143 dos[1]= ((sec % sectors) + 1) | ((cyl >> 2) & 0xC0);
144 dos[0]= (sec % secspcyl) / sectors;
147 void show_chs(unsigned long pos)
149 int cyl, head, sec;
151 if (pos == -1) {
152 cyl= head= 0;
153 sec= -1;
154 } else {
155 cyl= pos / (heads * sectors);
156 head= (pos / sectors) - (cyl * heads);
157 sec= pos % sectors;
159 printf(" %4d/%03d/%02d", cyl, head, sec);
162 void show_part(struct part_entry *p)
164 static int banner= 0;
165 int n;
167 n= p - table;
168 if ((n % 2) == 0) return;
170 if (!banner) {
171 printf(
172 "Part First Last Base Size Kb\n");
173 banner= 1;
176 printf("%3d ", (n-1) / 2);
177 show_chs(p->lowsec);
178 show_chs(p->lowsec + p->size - 1);
179 printf(" %8lu %8lu %7lu\n", p->lowsec, p->size, p->size / 2);
182 void usage(void)
184 fprintf(stderr,
185 "Usage: partition [-mfn] device [type:]length[+*] ...\n");
186 exit(1);
189 #define between(a, c, z) ((unsigned) ((c) - (a)) <= ((z) - (a)))
191 void parse(char *descr)
193 int seen= 0, sysind, flags, c;
194 unsigned long lowsec, size;
196 lowsec= 0;
198 if (strchr(descr, ':') == nil) {
199 /* A hole. */
200 if ((npart % 2) != 0) {
201 fprintf(stderr, "%s: Two holes can't be adjacent.\n",
202 arg0);
203 exit(1);
205 sysind= NO_PART;
206 seen|= 1;
207 } else {
208 /* A partition. */
209 if ((npart % 2) == 0) {
210 /* Need a hole before this partition. */
211 if (npart == 0) {
212 /* First hole contains the partition table. */
213 table[0].size= 1;
215 npart++;
217 sysind= 0;
218 for (;;) {
219 c= *descr++;
220 if (between('0', c, '9'))
221 c= (c - '0') + 0x0;
222 else
223 if (between('a', c, 'z'))
224 c= (c - 'a') + 0xa;
225 else
226 if (between('A', c, 'Z'))
227 c= (c - 'A') + 0xA;
228 else
229 break;
230 sysind= 0x10 * sysind + c;
231 seen|= 1;
233 if (c != ':') usage();
236 flags= 0;
238 if (strncmp(descr, "exist", 5) == 0 && (npart % 2) == 1) {
239 struct part_entry exist;
241 find_exist(&exist, sysind, (npart - 1) / 2);
242 sysind= exist.sysind;
243 lowsec= exist.lowsec;
244 size= exist.size;
245 flags |= EXIST_FLAG;
246 descr += 5;
247 c= *descr++;
248 seen|= 2;
249 } else {
250 size= 0;
251 while (between('0', (c= *descr++), '9')) {
252 size= 10 * size + (c - '0');
253 seen|= 2;
257 for (;;) {
258 if (c == '*')
259 flags|= ACTIVE_FLAG;
260 else
261 if (c == '+' && !(flags & EXIST_FLAG))
262 flags|= EXPAND_FLAG;
263 else
264 break;
265 c= *descr++;
268 if (seen != 3 || c != 0) usage();
270 if (npart == arraysize(table)) {
271 fprintf(stderr, "%s: too many partitions, only %d possible.\n",
272 arg0, NR_PARTITIONS);
273 exit(1);
275 table[npart].bootind= flags;
276 table[npart].sysind= sysind;
277 table[npart].lowsec= lowsec;
278 table[npart].size= size;
279 npart++;
282 void geometry(void)
283 /* Get the geometry of the drive the device lives on, and the base and size
284 * of the device.
287 int fd;
288 struct partition geometry;
289 struct stat sb;
291 if ((fd= open(device, O_RDONLY)) < 0) fatal(device);
293 /* Get the geometry of the drive, and the device's base and size. */
294 if (ioctl(fd, DIOCGETP, &geometry) < 0)
296 /* Use the same fake geometry as part. */
297 if (fstat(fd, &sb) < 0)
298 fatal(device);
299 geometry.base= cvul64(0);
300 geometry.size= cvul64(sb.st_size);
301 geometry.sectors= 32;
302 geometry.heads= 64;
303 geometry.cylinders= (sb.st_size-1)/SECTOR_SIZE/
304 (geometry.sectors*geometry.heads) + 1;
306 close(fd);
307 primary.lowsec= div64u(geometry.base, SECTOR_SIZE);
308 primary.size= div64u(geometry.size, SECTOR_SIZE);
309 cylinders= geometry.cylinders;
310 heads= geometry.heads;
311 sectors= geometry.sectors;
313 /* Is this a primary partition table? If so then pad partitions. */
314 pad= (!mflag && primary.lowsec == 0);
317 void boundary(struct part_entry *pe, int exp)
318 /* Expand or reduce a primary partition to a track or cylinder boundary to
319 * avoid giving the fdisk's of simpler operating systems a fit.
322 unsigned n;
324 n= !pad ? 1 : pe == &table[0] ? sectors : heads * sectors;
325 if (exp) pe->size+= n - 1;
326 pe->size= ((pe->lowsec + pe->size) / n * n) - pe->lowsec;
329 void distribute(void)
330 /* Fit the partitions onto the device. Try to start and end them on a
331 * cylinder boundary if so required. The first partition is to start on
332 * track 1, not on cylinder 1.
335 struct part_entry *pe, *exp;
336 long count;
337 unsigned long base, oldbase;
339 do {
340 exp= nil;
341 base= primary.lowsec;
342 count= primary.size;
344 for (pe= table; pe < arraylimit(table); pe++) {
345 oldbase= base;
346 if (pe->bootind & EXIST_FLAG) {
347 if (base > pe->lowsec) {
348 fprintf(stderr,
349 "%s: fixed partition %d is preceded by too big partitions/holes\n",
350 arg0, ((pe - table) - 1) / 2);
351 exit(1);
353 exp= nil; /* XXX - Extend before? */
354 } else {
355 pe->lowsec= base;
356 boundary(pe, 1);
357 if (pe->bootind & EXPAND_FLAG) exp= pe;
359 base= pe->lowsec + pe->size;
360 count-= base - oldbase;
362 if (count < 0) {
363 if (fflag) break;
364 fprintf(stderr, "%s: %s is %ld sectors too small\n",
365 arg0, device, -count);
366 exit(1);
368 if (exp != nil) {
369 /* Add leftover space to the partition marked for
370 * expanding.
372 exp->size+= count;
373 boundary(exp, 0);
374 exp->bootind&= ~EXPAND_FLAG;
376 } while (exp != nil);
378 for (pe= table; pe < arraylimit(table); pe++) {
379 if (pe->sysind == NO_PART) {
380 memset(pe, 0, sizeof(*pe));
381 } else {
382 sec2dos(pe->lowsec, &pe->start_head);
383 sec2dos(pe->lowsec + pe->size - 1, &pe->last_head);
384 pe->bootind&= ACTIVE_FLAG;
386 show_part(pe);
390 int main(int argc, char **argv)
392 int i;
394 if ((arg0= strrchr(argv[0], '/')) == nil) arg0= argv[0]; else arg0++;
396 i= 1;
397 while (i < argc && argv[i][0] == '-') {
398 char *opt= argv[i++] + 1;
400 if (opt[0] == '-' && opt[1] == 0) break;
402 while (*opt != 0) switch (*opt++) {
403 case 'a': aflag= 1; break;
404 case 'm': mflag= 1; break;
405 case 'r': rflag= 1; break;
406 case 'f': fflag= 1; break;
407 case 'n': nflag= 1; break;
408 default: usage();
412 if (rflag) {
413 if (aflag) usage();
414 if ((argc - i) != 1) usage();
415 fprintf(stderr, "%s: -r is not yet implemented\n", __func__);
416 exit(1);
417 } else {
418 if ((argc - i) < 1) usage();
419 if (aflag) fprintf(stderr, "%s: -a is not yet implemented\n", __func__);
421 device= argv[i++];
422 geometry();
424 while (i < argc) parse(argv[i++]);
426 distribute();
427 write_table();
429 exit(0);