source: trunk/minix/commands/ibm/partition.c@ 15

Last change on this file since 15 was 9, checked in by Mattia Monga, 14 years ago

Minix 3.1.2a

File size: 9.3 KB
Line 
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 <ibm/partition.h>
15#include <sys/stat.h>
16#include <string.h>
17#include <errno.h>
18#include <sys/ioctl.h>
19#include <limits.h>
20
21#define SECTOR_SIZE 512
22
23#define arraysize(a) (sizeof(a)/sizeof((a)[0]))
24#define arraylimit(a) ((a) + arraysize(a))
25
26char *arg0;
27
28void report(const char *label)
29{
30 fprintf(stderr, "%s: %s: %s\n", arg0, label, strerror(errno));
31}
32
33void fatal(const char *label)
34{
35 report(label);
36 exit(1);
37}
38
39#ifndef makedev
40#define minor(dev) (((dev) >> MINOR) & BYTE)
41#define major(dev) (((dev) >> MAJOR) & BYTE)
42#define makedev(major, minor) \
43 ((dev_t) (((major) << MAJOR) | ((minor) << MINOR)))
44#endif
45
46int aflag; /* Add a new partition to the current table. */
47int mflag; /* Minix rules, no need for alignment. */
48int rflag; /* Report current partitions. */
49int fflag; /* Force making a table even if too small. */
50int nflag; /* Play-act, don't really do it. */
51
52int cylinders, heads, sectors; /* Device's geometry */
53int pad; /* Partitions must be padded. */
54
55/* Descriptions of the device to divide and the partitions to make, including
56 * gaps between partitions.
57 */
58char *device;
59struct part_entry primary, table[2 * NR_PARTITIONS + 1];
60int npart;
61
62/* Extra flags at construction time. */
63#define EXPAND_FLAG 0x01 /* Add the remaining sectors to this one */
64#define EXIST_FLAG 0x02 /* Use existing partition */
65
66void find_exist(struct part_entry *exist, int sysind, int nr)
67{
68 int f;
69 u16_t signature;
70 struct part_entry oldtable[NR_PARTITIONS];
71 int n, i;
72 u32_t minlow, curlow;
73 struct part_entry *cur;
74 char *nr_s[] = { "", "second ", "third ", "fourth" };
75
76 if ((f= open(device, O_RDONLY)) < 0
77
78 || lseek(f, (off_t) PART_TABLE_OFF, SEEK_SET) == -1
79
80 || read(f, oldtable, sizeof(oldtable)) < 0
81
82 || read(f, &signature, sizeof(signature)) < 0
83
84 || close(f) < 0
85 ) fatal(device);
86
87 minlow= 0;
88 n= 0;
89 for (;;) {
90 curlow= -1;
91 cur= nil;
92 for (i= 0; i < NR_PARTITIONS; i++) {
93 if (signature == 0xAA55
94 && oldtable[i].sysind != NO_PART
95 && oldtable[i].lowsec >= minlow
96 && oldtable[i].lowsec < curlow
97 ) {
98 cur= &oldtable[i];
99 curlow= oldtable[i].lowsec;
100 }
101 }
102 if (n == nr) break;
103 n++;
104 minlow= curlow+1;
105 }
106
107 if (cur == nil || cur->sysind != sysind) {
108 fprintf(stderr,
109 "%s: Can't find a %sexisting partition of type 0x%02X\n",
110 arg0, nr_s[nr], sysind);
111 exit(1);
112 }
113 *exist = *cur;
114}
115
116void write_table(void)
117{
118 int f;
119 u16_t signature= 0xAA55;
120 struct part_entry newtable[NR_PARTITIONS];
121 int i;
122
123 if (nflag) {
124 printf("(Table not written)\n");
125 return;
126 }
127
128 for (i= 0; i < NR_PARTITIONS; i++) newtable[i]= table[1 + 2*i];
129
130 if ((f= open(device, O_WRONLY)) < 0
131
132 || lseek(f, (off_t) PART_TABLE_OFF, SEEK_SET) == -1
133
134 || write(f, newtable, sizeof(newtable)) < 0
135
136 || write(f, &signature, sizeof(signature)) < 0
137
138 || close(f) < 0
139 ) fatal(device);
140}
141
142void sec2dos(unsigned long sec, unsigned char *dos)
143/* Translate a sector number into the three bytes DOS uses. */
144{
145 unsigned secspcyl= heads * sectors;
146 unsigned cyl;
147
148 cyl= sec / secspcyl;
149 dos[2]= cyl;
150 dos[1]= ((sec % sectors) + 1) | ((cyl >> 2) & 0xC0);
151 dos[0]= (sec % secspcyl) / sectors;
152}
153
154void show_chs(unsigned long pos)
155{
156 int cyl, head, sec;
157
158 if (pos == -1) {
159 cyl= head= 0;
160 sec= -1;
161 } else {
162 cyl= pos / (heads * sectors);
163 head= (pos / sectors) - (cyl * heads);
164 sec= pos % sectors;
165 }
166 printf(" %4d/%03d/%02d", cyl, head, sec);
167}
168
169void show_part(struct part_entry *p)
170{
171 static int banner= 0;
172 int n;
173
174 n= p - table;
175 if ((n % 2) == 0) return;
176
177 if (!banner) {
178 printf(
179 "Part First Last Base Size Kb\n");
180 banner= 1;
181 }
182
183 printf("%3d ", (n-1) / 2);
184 show_chs(p->lowsec);
185 show_chs(p->lowsec + p->size - 1);
186 printf(" %8lu %8lu %7lu\n", p->lowsec, p->size, p->size / 2);
187}
188
189void usage(void)
190{
191 fprintf(stderr,
192 "Usage: partition [-mfn] device [type:]length[+*] ...\n");
193 exit(1);
194}
195
196#define between(a, c, z) ((unsigned) ((c) - (a)) <= ((z) - (a)))
197
198void parse(char *descr)
199{
200 int seen= 0, sysind, flags, c;
201 unsigned long lowsec, size;
202
203 lowsec= 0;
204
205 if (strchr(descr, ':') == nil) {
206 /* A hole. */
207 if ((npart % 2) != 0) {
208 fprintf(stderr, "%s: Two holes can't be adjacent.\n",
209 arg0);
210 exit(1);
211 }
212 sysind= NO_PART;
213 seen|= 1;
214 } else {
215 /* A partition. */
216 if ((npart % 2) == 0) {
217 /* Need a hole before this partition. */
218 if (npart == 0) {
219 /* First hole contains the partition table. */
220 table[0].size= 1;
221 }
222 npart++;
223 }
224 sysind= 0;
225 for (;;) {
226 c= *descr++;
227 if (between('0', c, '9'))
228 c= (c - '0') + 0x0;
229 else
230 if (between('a', c, 'z'))
231 c= (c - 'a') + 0xa;
232 else
233 if (between('A', c, 'Z'))
234 c= (c - 'A') + 0xA;
235 else
236 break;
237 sysind= 0x10 * sysind + c;
238 seen|= 1;
239 }
240 if (c != ':') usage();
241 }
242
243 flags= 0;
244
245 if (strncmp(descr, "exist", 5) == 0 && (npart % 2) == 1) {
246 struct part_entry exist;
247
248 find_exist(&exist, sysind, (npart - 1) / 2);
249 sysind= exist.sysind;
250 lowsec= exist.lowsec;
251 size= exist.size;
252 flags |= EXIST_FLAG;
253 descr += 5;
254 c= *descr++;
255 seen|= 2;
256 } else {
257 size= 0;
258 while (between('0', (c= *descr++), '9')) {
259 size= 10 * size + (c - '0');
260 seen|= 2;
261 }
262 }
263
264 for (;;) {
265 if (c == '*')
266 flags|= ACTIVE_FLAG;
267 else
268 if (c == '+' && !(flags & EXIST_FLAG))
269 flags|= EXPAND_FLAG;
270 else
271 break;
272 c= *descr++;
273 }
274
275 if (seen != 3 || c != 0) usage();
276
277 if (npart == arraysize(table)) {
278 fprintf(stderr, "%s: too many partitions, only %d possible.\n",
279 arg0, NR_PARTITIONS);
280 exit(1);
281 }
282 table[npart].bootind= flags;
283 table[npart].sysind= sysind;
284 table[npart].lowsec= lowsec;
285 table[npart].size= size;
286 npart++;
287}
288
289void geometry(void)
290/* Get the geometry of the drive the device lives on, and the base and size
291 * of the device.
292 */
293{
294 int fd;
295 struct partition geometry;
296 struct stat sb;
297
298 if ((fd= open(device, O_RDONLY)) < 0) fatal(device);
299
300 /* Get the geometry of the drive, and the device's base and size. */
301 if (ioctl(fd, DIOCGETP, &geometry) < 0)
302 {
303 /* Use the same fake geometry as part. */
304 if (fstat(fd, &sb) < 0)
305 fatal(device);
306 geometry.base= cvul64(0);
307 geometry.size= cvul64(sb.st_size);
308 geometry.sectors= 32;
309 geometry.heads= 64;
310 geometry.cylinders= (sb.st_size-1)/SECTOR_SIZE/
311 (geometry.sectors*geometry.heads) + 1;
312 }
313 close(fd);
314 primary.lowsec= div64u(geometry.base, SECTOR_SIZE);
315 primary.size= div64u(geometry.size, SECTOR_SIZE);
316 cylinders= geometry.cylinders;
317 heads= geometry.heads;
318 sectors= geometry.sectors;
319
320 /* Is this a primary partition table? If so then pad partitions. */
321 pad= (!mflag && primary.lowsec == 0);
322}
323
324void boundary(struct part_entry *pe, int exp)
325/* Expand or reduce a primary partition to a track or cylinder boundary to
326 * avoid giving the fdisk's of simpler operating systems a fit.
327 */
328{
329 unsigned n;
330
331 n= !pad ? 1 : pe == &table[0] ? sectors : heads * sectors;
332 if (exp) pe->size+= n - 1;
333 pe->size= ((pe->lowsec + pe->size) / n * n) - pe->lowsec;
334}
335
336void distribute(void)
337/* Fit the partitions onto the device. Try to start and end them on a
338 * cylinder boundary if so required. The first partition is to start on
339 * track 1, not on cylinder 1.
340 */
341{
342 struct part_entry *pe, *exp;
343 long count;
344 unsigned long base, size, oldbase;
345
346 do {
347 exp= nil;
348 base= primary.lowsec;
349 count= primary.size;
350
351 for (pe= table; pe < arraylimit(table); pe++) {
352 oldbase= base;
353 if (pe->bootind & EXIST_FLAG) {
354 if (base > pe->lowsec) {
355 fprintf(stderr,
356 "%s: fixed partition %d is preceded by too big partitions/holes\n",
357 arg0, ((pe - table) - 1) / 2);
358 exit(1);
359 }
360 exp= nil; /* XXX - Extend before? */
361 } else {
362 pe->lowsec= base;
363 boundary(pe, 1);
364 if (pe->bootind & EXPAND_FLAG) exp= pe;
365 }
366 base= pe->lowsec + pe->size;
367 count-= base - oldbase;
368 }
369 if (count < 0) {
370 if (fflag) break;
371 fprintf(stderr, "%s: %s is %ld sectors too small\n",
372 arg0, device, -count);
373 exit(1);
374 }
375 if (exp != nil) {
376 /* Add leftover space to the partition marked for
377 * expanding.
378 */
379 exp->size+= count;
380 boundary(exp, 0);
381 exp->bootind&= ~EXPAND_FLAG;
382 }
383 } while (exp != nil);
384
385 for (pe= table; pe < arraylimit(table); pe++) {
386 if (pe->sysind == NO_PART) {
387 memset(pe, 0, sizeof(*pe));
388 } else {
389 sec2dos(pe->lowsec, &pe->start_head);
390 sec2dos(pe->lowsec + pe->size - 1, &pe->last_head);
391 pe->bootind&= ACTIVE_FLAG;
392 }
393 show_part(pe);
394 }
395}
396
397int main(int argc, char **argv)
398{
399 int i;
400
401 if ((arg0= strrchr(argv[0], '/')) == nil) arg0= argv[0]; else arg0++;
402
403 i= 1;
404 while (i < argc && argv[i][0] == '-') {
405 char *opt= argv[i++] + 1;
406
407 if (opt[0] == '-' && opt[1] == 0) break;
408
409 while (*opt != 0) switch (*opt++) {
410 case 'a': aflag= 1; break;
411 case 'm': mflag= 1; break;
412 case 'r': rflag= 1; break;
413 case 'f': fflag= 1; break;
414 case 'n': nflag= 1; break;
415 default: usage();
416 }
417 }
418
419 if (rflag) {
420 if (aflag) usage();
421 if ((argc - i) != 1) usage();
422 fprintf(stderr, "%s: -r is not yet implemented\n");
423 exit(1);
424 } else {
425 if ((argc - i) < 1) usage();
426 if (aflag) fprintf(stderr, "%s: -a is not yet implemented\n");
427
428 device= argv[i++];
429 geometry();
430
431 while (i < argc) parse(argv[i++]);
432
433 distribute();
434 write_table();
435 }
436 exit(0);
437}
Note: See TracBrowser for help on using the repository browser.