installboot.c

Go to the documentation of this file.
00001 /*      installboot 3.0 - Make a device bootable        Author: Kees J. Bot
00002  *                                                              21 Dec 1991
00003  *
00004  * Either make a device bootable or make an image from kernel, mm, fs, etc.
00005  */
00006 #define nil 0
00007 #define _POSIX_SOURCE   1
00008 #define _MINIX          1
00009 #include <stdio.h>
00010 #include <stddef.h>
00011 #include <sys/types.h>
00012 #include <sys/stat.h>
00013 #include <sys/ioctl.h>
00014 #include <stdlib.h>
00015 #include <unistd.h>
00016 #include <fcntl.h>
00017 #include <string.h>
00018 #include <errno.h>
00019 #include <dirent.h>
00020 #include <a.out.h>
00021 #include <minix/config.h>
00022 #include <minix/const.h>
00023 #include <minix/partition.h>
00024 #include <minix/u64.h>
00025 #include "rawfs.h"
00026 #include "image.h"
00027 
00028 #define BOOTBLOCK       0       /* Of course */
00029 #define SECTOR_SIZE     512     /* Disk sector size. */
00030 #define RATIO(b)        ((b)/SECTOR_SIZE)
00031 #define SIGNATURE       0xAA55  /* Boot block signature. */
00032 #define BOOT_MAX        64      /* Absolute maximum size of secondary boot */
00033 #define SIGPOS          510     /* Where to put signature word. */
00034 #define PARTPOS         446     /* Offset to the partition table in a master
00035                                  * boot block.
00036                                  */
00037 
00038 #define between(a, c, z)        ((unsigned) ((c) - (a)) <= ((z) - (a)))
00039 #define control(c)              between('\0', (c), '\37')
00040 
00041 #define BOOT_BLOCK_SIZE 1024
00042 
00043 void report(char *label)
00044 /* installboot: label: No such file or directory */
00045 {
00046         fprintf(stderr, "installboot: %s: %s\n", label, strerror(errno));
00047 }
00048 
00049 void fatal(char *label)
00050 {
00051         report(label);
00052         exit(1);
00053 }
00054 
00055 char *basename(char *name)
00056 /* Return the last component of name, stripping trailing slashes from name.
00057  * Precondition: name != "/".  If name is prefixed by a label, then the
00058  * label is copied to the basename too.
00059  */
00060 {
00061         static char base[IM_NAME_MAX];
00062         char *p, *bp= base;
00063 
00064         if ((p= strchr(name, ':')) != nil) {
00065                 while (name <= p && bp < base + IM_NAME_MAX - 1)
00066                         *bp++ = *name++;
00067         }
00068         for (;;) {
00069                 if ((p= strrchr(name, '/')) == nil) { p= name; break; }
00070                 if (*++p != 0) break;
00071                 *--p= 0;
00072         }
00073         while (*p != 0 && bp < base + IM_NAME_MAX - 1) *bp++ = *p++;
00074         *bp= 0;
00075         return base;
00076 }
00077 
00078 void bread(FILE *f, char *name, void *buf, size_t len)
00079 /* Read len bytes.  Don't dare return without them. */
00080 {
00081         if (len > 0 && fread(buf, len, 1, f) != 1) {
00082                 if (ferror(f)) fatal(name);
00083                 fprintf(stderr, "installboot: Unexpected EOF on %s\n", name);
00084                 exit(1);
00085         }
00086 }
00087 
00088 void bwrite(FILE *f, char *name, void *buf, size_t len)
00089 {
00090         if (len > 0 && fwrite(buf, len, 1, f) != 1) fatal(name);
00091 }
00092 
00093 long total_text= 0, total_data= 0, total_bss= 0;
00094 int making_image= 0;
00095 
00096 void read_header(int talk, char *proc, FILE *procf, struct image_header *ihdr)
00097 /* Read the a.out header of a program and check it.  If procf happens to be
00098  * nil then the header is already in *image_hdr and need only be checked.
00099  */
00100 {
00101         int n, big= 0;
00102         static int banner= 0;
00103         struct exec *phdr= &ihdr->process;
00104 
00105         if (procf == nil) {
00106                 /* Header already present. */
00107                 n= phdr->a_hdrlen;
00108         } else {
00109                 memset(ihdr, 0, sizeof(*ihdr));
00110 
00111                 /* Put the basename of proc in the header. */
00112                 strncpy(ihdr->name, basename(proc), IM_NAME_MAX);
00113 
00114                 /* Read the header. */
00115                 n= fread(phdr, sizeof(char), A_MINHDR, procf);
00116                 if (ferror(procf)) fatal(proc);
00117         }
00118 
00119         if (n < A_MINHDR || BADMAG(*phdr)) {
00120                 fprintf(stderr, "installboot: %s is not an executable\n", proc);
00121                 exit(1);
00122         }
00123 
00124         /* Get the rest of the exec header. */
00125         if (procf != nil) {
00126                 bread(procf, proc, ((char *) phdr) + A_MINHDR,
00127                                                 phdr->a_hdrlen - A_MINHDR);
00128         }
00129 
00130         if (talk && !banner) {
00131                 printf("     text     data      bss      size\n");
00132                 banner= 1;
00133         }
00134 
00135         if (talk) {
00136                 printf(" %8ld %8ld %8ld %9ld  %s\n",
00137                         phdr->a_text, phdr->a_data, phdr->a_bss,
00138                         phdr->a_text + phdr->a_data + phdr->a_bss, proc);
00139         }
00140         total_text+= phdr->a_text;
00141         total_data+= phdr->a_data;
00142         total_bss+= phdr->a_bss;
00143 
00144         if (phdr->a_cpu == A_I8086) {
00145                 long data= phdr->a_data + phdr->a_bss;
00146 
00147                 if (!(phdr->a_flags & A_SEP)) data+= phdr->a_text;
00148 
00149                 if (phdr->a_text >= 65536) big|= 1;
00150                 if (data >= 65536) big|= 2;
00151         }
00152         if (big) {
00153                 fprintf(stderr,
00154                         "%s will crash, %s%s%s segment%s larger then 64K\n",
00155                         proc,
00156                         big & 1 ? "text" : "",
00157                         big == 3 ? " and " : "",
00158                         big & 2 ? "data" : "",
00159                         big == 3 ? "s are" : " is");
00160         }
00161 }
00162 
00163 void padimage(char *image, FILE *imagef, int n)
00164 /* Add n zeros to image to pad it to a sector boundary. */
00165 {
00166         while (n > 0) {
00167                 if (putc(0, imagef) == EOF) fatal(image);
00168                 n--;
00169         }
00170 }
00171 
00172 #define align(n)        (((n) + ((SECTOR_SIZE) - 1)) & ~((SECTOR_SIZE) - 1))
00173 
00174 void copyexec(char *proc, FILE *procf, char *image, FILE *imagef, long n)
00175 /* Copy n bytes from proc to image padded to fill a sector. */
00176 {
00177         int pad, c;
00178 
00179         /* Compute number of padding bytes. */
00180         pad= align(n) - n;
00181 
00182         while (n > 0) {
00183                 if ((c= getc(procf)) == EOF) {
00184                         if (ferror(procf)) fatal(proc);
00185                         fprintf(stderr, "installboot: premature EOF on %s\n",
00186                                                                         proc);
00187                         exit(1);
00188                 }
00189                 if (putc(c, imagef) == EOF) fatal(image);
00190                 n--;
00191         }
00192         padimage(image, imagef, pad);
00193 }
00194 
00195 void make_image(char *image, char **procv)
00196 /* Collect a set of files in an image, each "segment" is nicely padded out
00197  * to SECTOR_SIZE, so it may be read from disk into memory without trickery.
00198  */
00199 {
00200         FILE *imagef, *procf;
00201         char *proc, *file;
00202         int procn;
00203         struct image_header ihdr;
00204         struct exec phdr;
00205         struct stat st;
00206 
00207         making_image= 1;
00208 
00209         if ((imagef= fopen(image, "w")) == nil) fatal(image);
00210 
00211         for (procn= 0; (proc= *procv++) != nil; procn++) {
00212                 /* Remove the label from the file name. */
00213                 if ((file= strchr(proc, ':')) != nil) file++; else file= proc;
00214 
00215                 /* Real files please, may need to seek. */
00216                 if (stat(file, &st) < 0
00217                         || (errno= EISDIR, !S_ISREG(st.st_mode))
00218                         || (procf= fopen(file, "r")) == nil
00219                 ) fatal(proc);
00220 
00221                 /* Read a.out header. */
00222                 read_header(1, proc, procf, &ihdr);
00223 
00224                 /* Scratch. */
00225                 phdr= ihdr.process;
00226 
00227                 /* The symbol table is always stripped off. */
00228                 ihdr.process.a_syms= 0;
00229                 ihdr.process.a_flags &= ~A_NSYM;
00230 
00231                 /* Write header padded to fill a sector */
00232                 bwrite(imagef, image, &ihdr, sizeof(ihdr));
00233 
00234                 padimage(image, imagef, SECTOR_SIZE - sizeof(ihdr));
00235 
00236                 /* A page aligned executable needs the header in text. */
00237                 if (phdr.a_flags & A_PAL) {
00238                         rewind(procf);
00239                         phdr.a_text+= phdr.a_hdrlen;
00240                 }
00241 
00242                 /* Copy text and data of proc to image. */
00243                 if (phdr.a_flags & A_SEP) {
00244                         /* Separate I&D: pad text & data separately. */
00245 
00246                         copyexec(proc, procf, image, imagef, phdr.a_text);
00247                         copyexec(proc, procf, image, imagef, phdr.a_data);
00248                 } else {
00249                         /* Common I&D: keep text and data together. */
00250 
00251                         copyexec(proc, procf, image, imagef,
00252                                                 phdr.a_text + phdr.a_data);
00253                 }
00254 
00255                 /* Done with proc. */
00256                 (void) fclose(procf);
00257         }
00258         /* Done with image. */
00259 
00260         if (fclose(imagef) == EOF) fatal(image);
00261 
00262         printf("   ------   ------   ------   -------\n");
00263         printf(" %8ld %8ld %8ld %9ld  total\n",
00264                 total_text, total_data, total_bss,
00265                 total_text + total_data + total_bss);
00266 }
00267 
00268 void extractexec(FILE *imagef, char *image, FILE *procf, char *proc,
00269                                                 long count, off_t *alen)
00270 /* Copy a segment of an executable.  It is padded to a sector in image. */
00271 {
00272         char buf[SECTOR_SIZE];
00273 
00274         while (count > 0) {
00275                 bread(imagef, image, buf, sizeof(buf));
00276                 *alen-= sizeof(buf);
00277 
00278                 bwrite(procf, proc, buf,
00279                         count < sizeof(buf) ? (size_t) count : sizeof(buf));
00280                 count-= sizeof(buf);
00281         }
00282 }
00283 
00284 void extract_image(char *image)
00285 /* Extract the executables from an image. */
00286 {
00287         FILE *imagef, *procf;
00288         off_t len;
00289         struct stat st;
00290         struct image_header ihdr;
00291         struct exec phdr;
00292         char buf[SECTOR_SIZE];
00293 
00294         if (stat(image, &st) < 0) fatal(image);
00295 
00296         /* Size of the image. */
00297         len= S_ISREG(st.st_mode) ? st.st_size : -1;
00298 
00299         if ((imagef= fopen(image, "r")) == nil) fatal(image);
00300 
00301         while (len != 0) {
00302                 /* Extract a program, first sector is an extended header. */
00303                 bread(imagef, image, buf, sizeof(buf));
00304                 len-= sizeof(buf);
00305 
00306                 memcpy(&ihdr, buf, sizeof(ihdr));
00307                 phdr= ihdr.process;
00308 
00309                 /* Check header. */
00310                 read_header(1, ihdr.name, nil, &ihdr);
00311 
00312                 if ((procf= fopen(ihdr.name, "w")) == nil) fatal(ihdr.name);
00313 
00314                 if (phdr.a_flags & A_PAL) {
00315                         /* A page aligned process contains a header in text. */
00316                         phdr.a_text+= phdr.a_hdrlen;
00317                 } else {
00318                         bwrite(procf, ihdr.name, &ihdr.process, phdr.a_hdrlen);
00319                 }
00320 
00321                 /* Extract text and data segments. */
00322                 if (phdr.a_flags & A_SEP) {
00323                         extractexec(imagef, image, procf, ihdr.name,
00324                                                 phdr.a_text, &len);
00325                         extractexec(imagef, image, procf, ihdr.name,
00326                                                 phdr.a_data, &len);
00327                 } else {
00328                         extractexec(imagef, image, procf, ihdr.name,
00329                                 phdr.a_text + phdr.a_data, &len);
00330                 }
00331 
00332                 if (fclose(procf) == EOF) fatal(ihdr.name);
00333         }
00334 }
00335 
00336 int rawfd;      /* File descriptor to open device. */
00337 char *rawdev;   /* Name of device. */
00338 
00339 void readblock(off_t blk, char *buf, int block_size)
00340 /* For rawfs, so that it can read blocks. */
00341 {
00342         int n;
00343 
00344         if (lseek(rawfd, blk * block_size, SEEK_SET) < 0
00345                 || (n= read(rawfd, buf, block_size)) < 0
00346         ) fatal(rawdev);
00347 
00348         if (n < block_size) {
00349                 fprintf(stderr, "installboot: Unexpected EOF on %s\n", rawdev);
00350                 exit(1);
00351         }
00352 }
00353 
00354 void writeblock(off_t blk, char *buf, int block_size)
00355 /* Add a function to write blocks for local use. */
00356 {
00357         if (lseek(rawfd, blk * block_size, SEEK_SET) < 0
00358                 || write(rawfd, buf, block_size) < 0
00359         ) fatal(rawdev);
00360 }
00361 
00362 int raw_install(char *file, off_t *start, off_t *len, int block_size)
00363 /* Copy bootcode or an image to the boot device at the given absolute disk
00364  * block number.  This "raw" installation is used to place bootcode and
00365  * image on a disk without a filesystem to make a simple boot disk.  Useful
00366  * in automated scripts for J. Random User.
00367  * Note: *len == 0 when an image is read.  It is set right afterwards.
00368  */
00369 {
00370         static char buf[_MAX_BLOCK_SIZE];       /* Nonvolatile block buffer. */
00371         FILE *f;
00372         off_t sec;
00373         unsigned long devsize;
00374         static int banner= 0;
00375         struct partition entry;
00376 
00377         /* See if the device has a maximum size. */
00378         devsize= -1;
00379         if (ioctl(rawfd, DIOCGETP, &entry) == 0) devsize= cv64ul(entry.size);
00380 
00381         if ((f= fopen(file, "r")) == nil) fatal(file);
00382 
00383         /* Copy sectors from file onto the boot device. */
00384         sec= *start;
00385         do {
00386                 int off= sec % RATIO(BOOT_BLOCK_SIZE);
00387 
00388                 if (fread(buf + off * SECTOR_SIZE, 1, SECTOR_SIZE, f) == 0)
00389                         break;
00390 
00391                 if (sec >= devsize) {
00392                         fprintf(stderr,
00393                         "installboot: %s can't be attached to %s\n",
00394                                 file, rawdev);
00395                         return 0;
00396                 }
00397 
00398                 if (off == RATIO(BOOT_BLOCK_SIZE) - 1) writeblock(sec / RATIO(BOOT_BLOCK_SIZE), buf, BOOT_BLOCK_SIZE);
00399         } while (++sec != *start + *len);
00400 
00401         if (ferror(f)) fatal(file);
00402         (void) fclose(f);
00403 
00404         /* Write a partial block, this may be the last image. */
00405         if (sec % RATIO(BOOT_BLOCK_SIZE) != 0) writeblock(sec / RATIO(BOOT_BLOCK_SIZE), buf, BOOT_BLOCK_SIZE);
00406 
00407         if (!banner) {
00408                 printf("  sector  length\n");
00409                 banner= 1;
00410         }
00411         *len= sec - *start;
00412         printf("%8ld%8ld  %s\n", *start, *len, file);
00413         *start= sec;
00414         return 1;
00415 }
00416 
00417 enum howto { FS, BOOT };
00418 
00419 void make_bootable(enum howto how, char *device, char *bootblock,
00420                                         char *bootcode, char **imagev)
00421 /* Install bootblock on the bootsector of device with the disk addresses to
00422  * bootcode patched into the data segment of bootblock.  "How" tells if there
00423  * should or shoudn't be a file system on the disk.  The images in the imagev
00424  * vector are added to the end of the device.
00425  */
00426 {
00427         char buf[_MAX_BLOCK_SIZE + 256], *adrp, *parmp;
00428         struct fileaddr {
00429                 off_t   address;
00430                 int     count;
00431         } bootaddr[BOOT_MAX + 1], *bap= bootaddr;
00432         struct exec boothdr;
00433         struct image_header dummy;
00434         struct stat st;
00435         ino_t ino;
00436         off_t sector, max_sector;
00437         FILE *bootf;
00438         off_t addr, fssize, pos, len;
00439         char *labels, *label, *image;
00440         int nolabel;
00441         int block_size = 0;
00442 
00443         /* Open device and set variables for readblock. */
00444         if ((rawfd= open(rawdev= device, O_RDWR)) < 0) fatal(device);
00445 
00446         /* Read and check the superblock. */
00447         fssize= r_super(&block_size);
00448 
00449         switch (how) {
00450         case FS:
00451                 if (fssize == 0) {
00452                         fprintf(stderr,
00453                                 "installboot: %s is not a Minix file system\n",
00454                                 device);
00455                         exit(1);
00456                 }
00457                 break;
00458         case BOOT:
00459                 if (fssize != 0) {
00460                         int s;
00461                         printf("%s contains a file system!\n", device);
00462                         printf("Scribbling in 10 seconds");
00463                         for (s= 0; s < 10; s++) {
00464                                 fputc('.', stdout);
00465                                 fflush(stdout);
00466                                 sleep(1);
00467                         }
00468                         fputc('\n', stdout);
00469                 }
00470                 fssize= 1;      /* Just a boot block. */
00471         }
00472 
00473         if (how == FS) {
00474                 /* See if the boot code can be found on the file system. */
00475                 if ((ino= r_lookup(ROOT_INO, bootcode)) == 0) {
00476                         if (errno != ENOENT) fatal(bootcode);
00477                 }
00478         } else {
00479                 /* Boot code must be attached at the end. */
00480                 ino= 0;
00481         }
00482 
00483         if (ino == 0) {
00484                 /* For a raw installation, we need to copy the boot code onto
00485                  * the device, so we need to look at the file to be copied.
00486                  */
00487                 if (stat(bootcode, &st) < 0) fatal(bootcode);
00488 
00489                 if ((bootf= fopen(bootcode, "r")) == nil) fatal(bootcode);
00490         } else {
00491                 /* Boot code is present in the file system. */
00492                 r_stat(ino, &st);
00493 
00494                 /* Get the header from the first block. */
00495                 if ((addr= r_vir2abs((off_t) 0)) == 0) {
00496                         boothdr.a_magic[0]= !A_MAGIC0;
00497                 } else {
00498                         readblock(addr, buf, block_size);
00499                         memcpy(&boothdr, buf, sizeof(struct exec));
00500                 }
00501                 bootf= nil;
00502                 dummy.process= boothdr;
00503         }
00504         /* See if it is an executable (read_header does the check). */
00505         read_header(0, bootcode, bootf, &dummy);
00506         boothdr= dummy.process;
00507 
00508         if (bootf != nil) fclose(bootf);
00509 
00510         /* Get all the sector addresses of the secondary boot code. */
00511         max_sector= (boothdr.a_hdrlen + boothdr.a_text
00512                         + boothdr.a_data + SECTOR_SIZE - 1) / SECTOR_SIZE;
00513 
00514         if (max_sector > BOOT_MAX * RATIO(block_size)) {
00515                 fprintf(stderr, "installboot: %s is way too big\n", bootcode);
00516                 exit(0);
00517         }
00518 
00519         /* Determine the addresses to the boot code to be patched into the
00520          * boot block.
00521          */
00522         bap->count= 0;  /* Trick to get the address recording going. */
00523 
00524         for (sector= 0; sector < max_sector; sector++) {
00525                 if (ino == 0) {
00526                         addr= fssize + (sector / RATIO(block_size));
00527                 } else
00528                 if ((addr= r_vir2abs(sector / RATIO(block_size))) == 0) {
00529                         fprintf(stderr, "installboot: %s has holes!\n",
00530                                                                 bootcode);
00531                         exit(1);
00532                 }
00533                 addr= (addr * RATIO(block_size)) + (sector % RATIO(block_size));
00534 
00535                 /* First address of the addresses array? */
00536                 if (bap->count == 0) bap->address= addr;
00537 
00538                 /* Paste sectors together in a multisector read. */
00539                 if (bap->address + bap->count == addr)
00540                         bap->count++;
00541                 else {
00542                         /* New address. */
00543                         bap++;
00544                         bap->address= addr;
00545                         bap->count= 1;
00546                 }
00547         }
00548         (++bap)->count= 0;      /* No more. */
00549 
00550         /* Get the boot block and patch the pieces in. */
00551         readblock(BOOTBLOCK, buf, BOOT_BLOCK_SIZE);
00552 
00553         if ((bootf= fopen(bootblock, "r")) == nil) fatal(bootblock);
00554 
00555         read_header(0, bootblock, bootf, &dummy);
00556         boothdr= dummy.process;
00557 
00558         if (boothdr.a_text + boothdr.a_data +
00559                                          4 * (bap - bootaddr) + 1 > PARTPOS) {
00560                 fprintf(stderr,
00561         "installboot: %s + addresses to %s don't fit in the boot sector\n",
00562                         bootblock, bootcode);
00563                 fprintf(stderr,
00564                     "You can try copying/reinstalling %s to defragment it\n",
00565                         bootcode);
00566                 exit(1);
00567         }
00568 
00569         /* All checks out right.  Read bootblock into the boot block! */
00570         bread(bootf, bootblock, buf, boothdr.a_text + boothdr.a_data);
00571         (void) fclose(bootf);
00572 
00573         /* Patch the addresses in. */
00574         adrp= buf + (int) (boothdr.a_text + boothdr.a_data);
00575         for (bap= bootaddr; bap->count != 0; bap++) {
00576                 *adrp++= bap->count;
00577                 *adrp++= (bap->address >>  0) & 0xFF;
00578                 *adrp++= (bap->address >>  8) & 0xFF;
00579                 *adrp++= (bap->address >> 16) & 0xFF;
00580         }
00581         /* Zero count stops bootblock's reading loop. */
00582         *adrp++= 0;
00583 
00584         if (bap > bootaddr+1) {
00585                 printf("%s and %d addresses to %s patched into %s\n",
00586                         bootblock, (int)(bap - bootaddr), bootcode, device);
00587         }
00588 
00589         /* Boot block signature. */
00590         buf[SIGPOS+0]= (SIGNATURE >> 0) & 0xFF;
00591         buf[SIGPOS+1]= (SIGNATURE >> 8) & 0xFF;
00592 
00593         /* Sector 2 of the boot block is used for boot parameters, initially
00594          * filled with null commands (newlines).  Initialize it only if
00595          * necessary.
00596          */
00597         for (parmp= buf + SECTOR_SIZE; parmp < buf + 2*SECTOR_SIZE; parmp++) {
00598                 if (*imagev != nil || (control(*parmp) && *parmp != '\n')) {
00599                         /* Param sector must be initialized. */
00600                         memset(buf + SECTOR_SIZE, '\n', SECTOR_SIZE);
00601                         break;
00602                 }
00603         }
00604 
00605         /* Offset to the end of the file system to add boot code and images. */
00606         pos= fssize * RATIO(block_size);
00607 
00608         if (ino == 0) {
00609                 /* Place the boot code onto the boot device. */
00610                 len= max_sector;
00611                 if (!raw_install(bootcode, &pos, &len, block_size)) {
00612                         if (how == FS) {
00613                                 fprintf(stderr,
00614         "\t(Isn't there a copy of %s on %s that can be used?)\n",
00615                                         bootcode, device);
00616                         }
00617                         exit(1);
00618                 }
00619         }
00620 
00621         parmp= buf + SECTOR_SIZE;
00622         nolabel= 0;
00623 
00624         if (how == BOOT) {
00625                 /* A boot only disk needs to have floppies swapped. */
00626                 strcpy(parmp,
00627         "trailer()echo \\nInsert the root diskette then hit RETURN\\n\\w\\c\n");
00628                 parmp+= strlen(parmp);
00629         }
00630 
00631         while ((labels= *imagev++) != nil) {
00632                 /* Place each kernel image on the boot device. */
00633 
00634                 if ((image= strchr(labels, ':')) != nil)
00635                         *image++= 0;
00636                 else {
00637                         if (nolabel) {
00638                                 fprintf(stderr,
00639                             "installboot: Only one image can be the default\n");
00640                                 exit(1);
00641                         }
00642                         nolabel= 1;
00643                         image= labels;
00644                         labels= nil;
00645                 }
00646                 len= 0;
00647                 if (!raw_install(image, &pos, &len, block_size)) exit(1);
00648 
00649                 if (labels == nil) {
00650                         /* Let this image be the default. */
00651                         sprintf(parmp, "image=%ld:%ld\n", pos-len, len);
00652                         parmp+= strlen(parmp);
00653                 }
00654 
00655                 while (labels != nil) {
00656                         /* Image is prefixed by a comma separated list of
00657                          * labels.  Define functions to select label and image.
00658                          */
00659                         label= labels;
00660                         if ((labels= strchr(labels, ',')) != nil) *labels++ = 0;
00661 
00662                         sprintf(parmp,
00663                 "%s(%c){label=%s;image=%ld:%ld;echo %s kernel selected;menu}\n",
00664                                 label,
00665                                 between('A', label[0], 'Z')
00666                                         ? label[0]-'A'+'a' : label[0],
00667                                 label, pos-len, len, label);
00668                         parmp+= strlen(parmp);
00669                 }
00670 
00671                 if (parmp > buf + block_size) {
00672                         fprintf(stderr,
00673                 "installboot: Out of parameter space, too many images\n");
00674                         exit(1);
00675                 }
00676         }
00677         /* Install boot block. */
00678         writeblock((off_t) BOOTBLOCK, buf, 1024);
00679 
00680         if (pos > fssize * RATIO(block_size)) {
00681                 /* Tell the total size of the data on the device. */
00682                 printf("%16ld  (%ld kb) total\n", pos,
00683                                                 (pos + RATIO(block_size) - 1) / RATIO(block_size));
00684         }
00685 }
00686 
00687 void install_master(char *device, char *masterboot, char **guide)
00688 /* Booting a hard disk is a two stage process:  The master bootstrap in sector
00689  * 0 loads the bootstrap from sector 0 of the active partition which in turn
00690  * starts the operating system.  This code installs such a master bootstrap
00691  * on a hard disk.  If guide[0] is non-null then the master bootstrap is
00692  * guided into booting a certain device.
00693  */
00694 {
00695         FILE *masf;
00696         unsigned long size;
00697         struct stat st;
00698         static char buf[_MAX_BLOCK_SIZE];
00699 
00700         /* Open device. */
00701         if ((rawfd= open(rawdev= device, O_RDWR)) < 0) fatal(device);
00702 
00703         /* Open the master boot code. */
00704         if ((masf= fopen(masterboot, "r")) == nil) fatal(masterboot);
00705 
00706         /* See if the user is cloning a device. */
00707         if (fstat(fileno(masf), &st) >=0 && S_ISBLK(st.st_mode))
00708                 size= PARTPOS;
00709         else {
00710                 /* Read and check header otherwise. */
00711                 struct image_header ihdr;
00712 
00713                 read_header(1, masterboot, masf, &ihdr);
00714                 size= ihdr.process.a_text + ihdr.process.a_data;
00715         }
00716         if (size > PARTPOS) {
00717                 fprintf(stderr, "installboot: %s is too big\n", masterboot);
00718                 exit(1);
00719         }
00720 
00721         /* Read the master boot block, patch it, write. */
00722         readblock(BOOTBLOCK, buf, BOOT_BLOCK_SIZE);
00723 
00724         memset(buf, 0, PARTPOS);
00725         (void) bread(masf, masterboot, buf, size);
00726 
00727         if (guide[0] != nil) {
00728                 /* Fixate partition to boot. */
00729                 char *keys= guide[0];
00730                 char *logical= guide[1];
00731                 size_t i;
00732                 int logfd;
00733                 u32_t offset;
00734                 struct partition geometry;
00735 
00736                 /* A string of digits to be seen as keystrokes. */
00737                 i= 0;
00738                 do {
00739                         if (!between('0', keys[i], '9')) {
00740                                 fprintf(stderr,
00741                                         "installboot: bad guide keys '%s'\n",
00742                                         keys);
00743                                 exit(1);
00744                         }
00745                 } while (keys[++i] != 0);
00746 
00747                 if (size + i + 1 > PARTPOS) {
00748                         fprintf(stderr,
00749                         "installboot: not enough space after '%s' for '%s'\n",
00750                                 masterboot, keys);
00751                         exit(1);
00752                 }
00753                 memcpy(buf + size, keys, i);
00754                 size += i;
00755                 buf[size]= '\r';
00756 
00757                 if (logical != nil) {
00758                         if ((logfd= open(logical, O_RDONLY)) < 0
00759                                 || ioctl(logfd, DIOCGETP, &geometry) < 0
00760                         ) {
00761                                 fatal(logical);
00762                         }
00763                         offset= div64u(geometry.base, SECTOR_SIZE);
00764                         if (size + 5 > PARTPOS) {
00765                                 fprintf(stderr,
00766                                         "installboot: not enough space "
00767                                         "after '%s' for '%s' and an offset "
00768                                         "to '%s'\n",
00769                                         masterboot, keys, logical);
00770                                 exit(1);
00771                         }
00772                         buf[size]= '#';
00773                         memcpy(buf+size+1, &offset, 4);
00774                 }
00775         }
00776 
00777         /* Install signature. */
00778         buf[SIGPOS+0]= (SIGNATURE >> 0) & 0xFF;
00779         buf[SIGPOS+1]= (SIGNATURE >> 8) & 0xFF;
00780 
00781         writeblock(BOOTBLOCK, buf, BOOT_BLOCK_SIZE);
00782 }
00783 
00784 void usage(void)
00785 {
00786         fprintf(stderr,
00787           "Usage: installboot -i(mage) image kernel mm fs ... init\n"
00788           "       installboot -(e)x(tract) image\n"
00789           "       installboot -d(evice) device bootblock boot [image ...]\n"
00790           "       installboot -b(oot) device bootblock boot image ...\n"
00791           "       installboot -m(aster) device masterboot [keys [logical]]\n");
00792         exit(1);
00793 }
00794 
00795 int isoption(char *option, char *test)
00796 /* Check if the option argument is equals "test".  Also accept -i as short
00797  * for -image, and the special case -x for -extract.
00798  */
00799 {
00800         if (strcmp(option, test) == 0) return 1;
00801         if (option[0] != '-' && strlen(option) != 2) return 0;
00802         if (option[1] == test[1]) return 1;
00803         if (option[1] == 'x' && test[1] == 'e') return 1;
00804         return 0;
00805 }
00806 
00807 int main(int argc, char **argv)
00808 {
00809         if (argc < 2) usage();
00810 
00811         if (argc >= 4 && isoption(argv[1], "-image")) {
00812                 make_image(argv[2], argv + 3);
00813         } else
00814         if (argc == 3 && isoption(argv[1], "-extract")) {
00815                 extract_image(argv[2]);
00816         } else
00817         if (argc >= 5 && isoption(argv[1], "-device")) {
00818                 make_bootable(FS, argv[2], argv[3], argv[4], argv + 5);
00819         } else
00820         if (argc >= 6 && isoption(argv[1], "-boot")) {
00821                 make_bootable(BOOT, argv[2], argv[3], argv[4], argv + 5);
00822         } else
00823         if ((4 <= argc && argc <= 6) && isoption(argv[1], "-master")) {
00824                 install_master(argv[2], argv[3], argv + 4);
00825         } else {
00826                 usage();
00827         }
00828         exit(0);
00829 }
00830 
00831 /*
00832  * $PchId: installboot.c,v 1.10 2000/08/13 22:07:50 philip Exp $
00833  */

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