partition.c

Go to the documentation of this file.
00001 /*      partition 1.13 - Make a partition table         Author: Kees J. Bot
00002  *                                                              27 Apr 1992
00003  */
00004 #define nil ((void*)0)
00005 #include <stdio.h>
00006 #include <sys/types.h>
00007 #include <stdlib.h>
00008 #include <unistd.h>
00009 #include <fcntl.h>
00010 #include <minix/config.h>
00011 #include <minix/const.h>
00012 #include <minix/partition.h>
00013 #include <minix/u64.h>
00014 #include <ibm/partition.h>
00015 #include <sys/stat.h>
00016 #include <string.h>
00017 #include <errno.h>
00018 #include <sys/ioctl.h>
00019 #include <limits.h>
00020 
00021 #define SECTOR_SIZE     512
00022 
00023 #define arraysize(a)    (sizeof(a)/sizeof((a)[0]))
00024 #define arraylimit(a)   ((a) + arraysize(a))
00025 
00026 char *arg0;
00027 
00028 void report(const char *label)
00029 {
00030         fprintf(stderr, "%s: %s: %s\n", arg0, label, strerror(errno));
00031 }
00032 
00033 void fatal(const char *label)
00034 {
00035         report(label);
00036         exit(1);
00037 }
00038 
00039 #ifndef makedev
00040 #define minor(dev)      (((dev) >> MINOR) & BYTE)
00041 #define major(dev)      (((dev) >> MAJOR) & BYTE)
00042 #define makedev(major, minor)   \
00043                         ((dev_t) (((major) << MAJOR) | ((minor) << MINOR)))
00044 #endif
00045 
00046 int aflag;                      /* Add a new partition to the current table. */
00047 int mflag;                      /* Minix rules, no need for alignment. */
00048 int rflag;                      /* Report current partitions. */
00049 int fflag;                      /* Force making a table even if too small. */
00050 int nflag;                      /* Play-act, don't really do it. */
00051 
00052 int cylinders, heads, sectors;  /* Device's geometry */
00053 int pad;                        /* Partitions must be padded. */
00054 
00055 /* Descriptions of the device to divide and the partitions to make, including
00056  * gaps between partitions.
00057  */
00058 char *device;
00059 struct part_entry primary, table[2 * NR_PARTITIONS + 1];
00060 int npart;
00061 
00062 /* Extra flags at construction time. */
00063 #define EXPAND_FLAG     0x01    /* Add the remaining sectors to this one */
00064 #define EXIST_FLAG      0x02    /* Use existing partition */
00065 
00066 void find_exist(struct part_entry *exist, int sysind, int nr)
00067 {
00068         int f;
00069         u16_t signature;
00070         struct part_entry oldtable[NR_PARTITIONS];
00071         int n, i;
00072         u32_t minlow, curlow;
00073         struct part_entry *cur;
00074         char *nr_s[] = { "", "second ", "third ", "fourth" };
00075 
00076         if ((f= open(device, O_RDONLY)) < 0
00077 
00078                 || lseek(f, (off_t) PART_TABLE_OFF, SEEK_SET) == -1
00079 
00080                 || read(f, oldtable, sizeof(oldtable)) < 0
00081 
00082                 || read(f, &signature, sizeof(signature)) < 0
00083 
00084                 || close(f) < 0
00085         ) fatal(device);
00086 
00087         minlow= 0;
00088         n= 0;
00089         for (;;) {
00090                 curlow= -1;
00091                 cur= nil;
00092                 for (i= 0; i < NR_PARTITIONS; i++) {
00093                         if (signature == 0xAA55
00094                                 && oldtable[i].sysind != NO_PART
00095                                 && oldtable[i].lowsec >= minlow
00096                                 && oldtable[i].lowsec < curlow
00097                         ) {
00098                                 cur= &oldtable[i];
00099                                 curlow= oldtable[i].lowsec;
00100                         }
00101                 }
00102                 if (n == nr) break;
00103                 n++;
00104                 minlow= curlow+1;
00105         }
00106 
00107         if (cur == nil || cur->sysind != sysind) {
00108                 fprintf(stderr,
00109                 "%s: Can't find a %sexisting partition of type 0x%02X\n",
00110                         arg0, nr_s[nr], sysind);
00111                 exit(1);
00112         }
00113         *exist = *cur;
00114 }
00115 
00116 void write_table(void)
00117 {
00118         int f;
00119         u16_t signature= 0xAA55;
00120         struct part_entry newtable[NR_PARTITIONS];
00121         int i;
00122 
00123         if (nflag) {
00124                 printf("(Table not written)\n");
00125                 return;
00126         }
00127 
00128         for (i= 0; i < NR_PARTITIONS; i++) newtable[i]= table[1 + 2*i];
00129 
00130         if ((f= open(device, O_WRONLY)) < 0
00131 
00132                 || lseek(f, (off_t) PART_TABLE_OFF, SEEK_SET) == -1
00133 
00134                 || write(f, newtable, sizeof(newtable)) < 0
00135 
00136                 || write(f, &signature, sizeof(signature)) < 0
00137 
00138                 || close(f) < 0
00139         ) fatal(device);
00140 }
00141 
00142 void sec2dos(unsigned long sec, unsigned char *dos)
00143 /* Translate a sector number into the three bytes DOS uses. */
00144 {
00145         unsigned secspcyl= heads * sectors;
00146         unsigned cyl;
00147 
00148         cyl= sec / secspcyl;
00149         dos[2]= cyl;
00150         dos[1]= ((sec % sectors) + 1) | ((cyl >> 2) & 0xC0);
00151         dos[0]= (sec % secspcyl) / sectors;
00152 }
00153 
00154 void show_chs(unsigned long pos)
00155 {
00156         int cyl, head, sec;
00157 
00158         if (pos == -1) {
00159                 cyl= head= 0;
00160                 sec= -1;
00161         } else {
00162                 cyl= pos / (heads * sectors);
00163                 head= (pos / sectors) - (cyl * heads);
00164                 sec= pos % sectors;
00165         }
00166         printf("  %4d/%03d/%02d", cyl, head, sec);
00167 }
00168 
00169 void show_part(struct part_entry *p)
00170 {
00171         static int banner= 0;
00172         int n;
00173 
00174         n= p - table;
00175         if ((n % 2) == 0) return;
00176 
00177         if (!banner) {
00178                 printf(
00179         "Part     First         Last         Base      Size       Kb\n");
00180                 banner= 1;
00181         }
00182 
00183         printf("%3d ", (n-1) / 2);
00184         show_chs(p->lowsec);
00185         show_chs(p->lowsec + p->size - 1);
00186         printf("  %8lu  %8lu  %7lu\n", p->lowsec, p->size, p->size / 2);
00187 }
00188 
00189 void usage(void)
00190 {
00191         fprintf(stderr,
00192                 "Usage: partition [-mfn] device [type:]length[+*] ...\n");
00193         exit(1);
00194 }
00195 
00196 #define between(a, c, z)        ((unsigned) ((c) - (a)) <= ((z) - (a)))
00197 
00198 void parse(char *descr)
00199 {
00200         int seen= 0, sysind, flags, c;
00201         unsigned long lowsec, size;
00202 
00203         lowsec= 0;
00204 
00205         if (strchr(descr, ':') == nil) {
00206                 /* A hole. */
00207                 if ((npart % 2) != 0) {
00208                         fprintf(stderr, "%s: Two holes can't be adjacent.\n",
00209                                 arg0);
00210                         exit(1);
00211                 }
00212                 sysind= NO_PART;
00213                 seen|= 1;
00214         } else {
00215                 /* A partition. */
00216                 if ((npart % 2) == 0) {
00217                         /* Need a hole before this partition. */
00218                         if (npart == 0) {
00219                                 /* First hole contains the partition table. */
00220                                 table[0].size= 1;
00221                         }
00222                         npart++;
00223                 }
00224                 sysind= 0;
00225                 for (;;) {
00226                         c= *descr++;
00227                         if (between('0', c, '9'))
00228                                 c= (c - '0') + 0x0;
00229                         else
00230                         if (between('a', c, 'z'))
00231                                 c= (c - 'a') + 0xa;
00232                         else
00233                         if (between('A', c, 'Z'))
00234                                 c= (c - 'A') + 0xA;
00235                         else
00236                                 break;
00237                         sysind= 0x10 * sysind + c;
00238                         seen|= 1;
00239                 }
00240                 if (c != ':') usage();
00241         }
00242 
00243         flags= 0;
00244 
00245         if (strncmp(descr, "exist", 5) == 0 && (npart % 2) == 1) {
00246                 struct part_entry exist;
00247 
00248                 find_exist(&exist, sysind, (npart - 1) / 2);
00249                 sysind= exist.sysind;
00250                 lowsec= exist.lowsec;
00251                 size= exist.size;
00252                 flags |= EXIST_FLAG;
00253                 descr += 5;
00254                 c= *descr++;
00255                 seen|= 2;
00256         } else {
00257                 size= 0;
00258                 while (between('0', (c= *descr++), '9')) {
00259                         size= 10 * size + (c - '0');
00260                         seen|= 2;
00261                 }
00262         }
00263 
00264         for (;;) {
00265                 if (c == '*')
00266                         flags|= ACTIVE_FLAG;
00267                 else
00268                 if (c == '+' && !(flags & EXIST_FLAG))
00269                         flags|= EXPAND_FLAG;
00270                 else
00271                         break;
00272                 c= *descr++;
00273         }
00274 
00275         if (seen != 3 || c != 0) usage();
00276 
00277         if (npart == arraysize(table)) {
00278                 fprintf(stderr, "%s: too many partitions, only %d possible.\n",
00279                         arg0, NR_PARTITIONS);
00280                 exit(1);
00281         }
00282         table[npart].bootind= flags;
00283         table[npart].sysind= sysind;
00284         table[npart].lowsec= lowsec;
00285         table[npart].size= size;
00286         npart++;
00287 }
00288 
00289 void geometry(void)
00290 /* Get the geometry of the drive the device lives on, and the base and size
00291  * of the device.
00292  */
00293 {
00294         int fd;
00295         struct partition geometry;
00296         struct stat sb;
00297 
00298         if ((fd= open(device, O_RDONLY)) < 0) fatal(device);
00299 
00300         /* Get the geometry of the drive, and the device's base and size. */
00301         if (ioctl(fd, DIOCGETP, &geometry) < 0)
00302         {
00303                 /* Use the same fake geometry as part. */
00304                 if (fstat(fd, &sb) < 0)
00305                         fatal(device);
00306                 geometry.base= cvul64(0);
00307                 geometry.size= cvul64(sb.st_size);
00308                 geometry.sectors= 32;
00309                 geometry.heads= 64;
00310                 geometry.cylinders= (sb.st_size-1)/SECTOR_SIZE/
00311                         (geometry.sectors*geometry.heads) + 1;
00312         }
00313         close(fd);
00314         primary.lowsec= div64u(geometry.base, SECTOR_SIZE);
00315         primary.size= div64u(geometry.size, SECTOR_SIZE);
00316         cylinders= geometry.cylinders;
00317         heads= geometry.heads;
00318         sectors= geometry.sectors;
00319 
00320         /* Is this a primary partition table?  If so then pad partitions. */
00321         pad= (!mflag && primary.lowsec == 0);
00322 }
00323 
00324 void boundary(struct part_entry *pe, int exp)
00325 /* Expand or reduce a primary partition to a track or cylinder boundary to
00326  * avoid giving the fdisk's of simpler operating systems a fit.
00327  */
00328 {
00329         unsigned n;
00330 
00331         n= !pad ? 1 : pe == &table[0] ? sectors : heads * sectors;
00332         if (exp) pe->size+= n - 1;
00333         pe->size= ((pe->lowsec + pe->size) / n * n) - pe->lowsec;
00334 }
00335 
00336 void distribute(void)
00337 /* Fit the partitions onto the device.  Try to start and end them on a
00338  * cylinder boundary if so required.  The first partition is to start on
00339  * track 1, not on cylinder 1.
00340  */
00341 {
00342         struct part_entry *pe, *exp;
00343         long count;
00344         unsigned long base, size, oldbase;
00345 
00346         do {
00347                 exp= nil;
00348                 base= primary.lowsec;
00349                 count= primary.size;
00350 
00351                 for (pe= table; pe < arraylimit(table); pe++) {
00352                         oldbase= base;
00353                         if (pe->bootind & EXIST_FLAG) {
00354                                 if (base > pe->lowsec) {
00355                                         fprintf(stderr,
00356         "%s: fixed partition %d is preceded by too big partitions/holes\n",
00357                                                 arg0, ((pe - table) - 1) / 2);
00358                                         exit(1);
00359                                 }
00360                                 exp= nil;       /* XXX - Extend before? */
00361                         } else {
00362                                 pe->lowsec= base;
00363                                 boundary(pe, 1);
00364                                 if (pe->bootind & EXPAND_FLAG) exp= pe;
00365                         }
00366                         base= pe->lowsec + pe->size;
00367                         count-= base - oldbase;
00368                 }
00369                 if (count < 0) {
00370                         if (fflag) break;
00371                         fprintf(stderr, "%s: %s is %ld sectors too small\n",
00372                                 arg0, device, -count);
00373                         exit(1);
00374                 }
00375                 if (exp != nil) {
00376                         /* Add leftover space to the partition marked for
00377                          * expanding.
00378                          */
00379                         exp->size+= count;
00380                         boundary(exp, 0);
00381                         exp->bootind&= ~EXPAND_FLAG;
00382                 }
00383         } while (exp != nil);
00384 
00385         for (pe= table; pe < arraylimit(table); pe++) {
00386                 if (pe->sysind == NO_PART) {
00387                         memset(pe, 0, sizeof(*pe));
00388                 } else {
00389                         sec2dos(pe->lowsec, &pe->start_head);
00390                         sec2dos(pe->lowsec + pe->size - 1, &pe->last_head);
00391                         pe->bootind&= ACTIVE_FLAG;
00392                 }
00393                 show_part(pe);
00394         }
00395 }
00396 
00397 int main(int argc, char **argv)
00398 {
00399         int i;
00400 
00401         if ((arg0= strrchr(argv[0], '/')) == nil) arg0= argv[0]; else arg0++;
00402 
00403         i= 1;
00404         while (i < argc && argv[i][0] == '-') {
00405                 char *opt= argv[i++] + 1;
00406 
00407                 if (opt[0] == '-' && opt[1] == 0) break;
00408 
00409                 while (*opt != 0) switch (*opt++) {
00410                 case 'a':       aflag= 1;       break;
00411                 case 'm':       mflag= 1;       break;
00412                 case 'r':       rflag= 1;       break;
00413                 case 'f':       fflag= 1;       break;
00414                 case 'n':       nflag= 1;       break;
00415                 default:        usage();
00416                 }
00417         }
00418 
00419         if (rflag) {
00420                 if (aflag) usage();
00421                 if ((argc - i) != 1) usage();
00422                 fprintf(stderr, "%s: -r is not yet implemented\n");
00423                 exit(1);
00424         } else {
00425                 if ((argc - i) < 1) usage();
00426                 if (aflag) fprintf(stderr, "%s: -a is not yet implemented\n");
00427 
00428                 device= argv[i++];
00429                 geometry();
00430 
00431                 while (i < argc) parse(argv[i++]);
00432 
00433                 distribute();
00434                 write_table();
00435         }
00436         exit(0);
00437 }

Generated on Fri Apr 14 22:56:57 2006 for minix by  doxygen 1.4.6