The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/boot/installboot.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*      installboot 3.0 - Make a device bootable        Author: Kees J. Bot
    2  *                                                              21 Dec 1991
    3  *
    4  * Either make a device bootable or make an image from kernel, mm, fs, etc.
    5  */
    6 #define nil 0
    7 #define _POSIX_SOURCE   1
    8 #define _MINIX          1
    9 #include <stdio.h>
   10 #include <stddef.h>
   11 #include <sys/types.h>
   12 #include <sys/stat.h>
   13 #include <sys/ioctl.h>
   14 #include <stdlib.h>
   15 #include <unistd.h>
   16 #include <fcntl.h>
   17 #include <string.h>
   18 #include <errno.h>
   19 #include <dirent.h>
   20 #include <a.out.h>
   21 #include <minix/config.h>
   22 #include <minix/const.h>
   23 #include <minix/partition.h>
   24 #include <minix/u64.h>
   25 #include "rawfs.h"
   26 #include "image.h"
   27 
   28 #define BOOTBLOCK       0       /* Of course */
   29 #define SECTOR_SIZE     512     /* Disk sector size. */
   30 #define RATIO(b)        ((b)/SECTOR_SIZE)
   31 #define SIGNATURE       0xAA55  /* Boot block signature. */
   32 #define BOOT_MAX        64      /* Absolute maximum size of secondary boot */
   33 #define SIGPOS          510     /* Where to put signature word. */
   34 #define PARTPOS         446     /* Offset to the partition table in a master
   35                                  * boot block.
   36                                  */
   37 
   38 #define between(a, c, z)        ((unsigned) ((c) - (a)) <= ((z) - (a)))
   39 #define control(c)              between('\0', (c), '\37')
   40 
   41 #define BOOT_BLOCK_SIZE 1024
   42 
   43 void report(char *label)
   44 /* installboot: label: No such file or directory */
   45 {
   46         fprintf(stderr, "installboot: %s: %s\n", label, strerror(errno));
   47 }
   48 
   49 void fatal(char *label)
   50 {
   51         report(label);
   52         exit(1);
   53 }
   54 
   55 char *basename(char *name)
   56 /* Return the last component of name, stripping trailing slashes from name.
   57  * Precondition: name != "/".  If name is prefixed by a label, then the
   58  * label is copied to the basename too.
   59  */
   60 {
   61         static char base[IM_NAME_MAX];
   62         char *p, *bp= base;
   63 
   64         if ((p= strchr(name, ':')) != nil) {
   65                 while (name <= p && bp < base + IM_NAME_MAX - 1)
   66                         *bp++ = *name++;
   67         }
   68         for (;;) {
   69                 if ((p= strrchr(name, '/')) == nil) { p= name; break; }
   70                 if (*++p != 0) break;
   71                 *--p= 0;
   72         }
   73         while (*p != 0 && bp < base + IM_NAME_MAX - 1) *bp++ = *p++;
   74         *bp= 0;
   75         return base;
   76 }
   77 
   78 void bread(FILE *f, char *name, void *buf, size_t len)
   79 /* Read len bytes.  Don't dare return without them. */
   80 {
   81         if (len > 0 && fread(buf, len, 1, f) != 1) {
   82                 if (ferror(f)) fatal(name);
   83                 fprintf(stderr, "installboot: Unexpected EOF on %s\n", name);
   84                 exit(1);
   85         }
   86 }
   87 
   88 void bwrite(FILE *f, char *name, void *buf, size_t len)
   89 {
   90         if (len > 0 && fwrite(buf, len, 1, f) != 1) fatal(name);
   91 }
   92 
   93 long total_text= 0, total_data= 0, total_bss= 0;
   94 int making_image= 0;
   95 
   96 void read_header(int talk, char *proc, FILE *procf, struct image_header *ihdr)
   97 /* Read the a.out header of a program and check it.  If procf happens to be
   98  * nil then the header is already in *image_hdr and need only be checked.
   99  */
  100 {
  101         int n, big= 0;
  102         static int banner= 0;
  103         struct exec *phdr= &ihdr->process;
  104 
  105         if (procf == nil) {
  106                 /* Header already present. */
  107                 n= phdr->a_hdrlen;
  108         } else {
  109                 memset(ihdr, 0, sizeof(*ihdr));
  110 
  111                 /* Put the basename of proc in the header. */
  112                 strncpy(ihdr->name, basename(proc), IM_NAME_MAX);
  113 
  114                 /* Read the header. */
  115                 n= fread(phdr, sizeof(char), A_MINHDR, procf);
  116                 if (ferror(procf)) fatal(proc);
  117         }
  118 
  119         if (n < A_MINHDR || BADMAG(*phdr)) {
  120                 fprintf(stderr, "installboot: %s is not an executable\n", proc);
  121                 exit(1);
  122         }
  123 
  124         /* Get the rest of the exec header. */
  125         if (procf != nil) {
  126                 bread(procf, proc, ((char *) phdr) + A_MINHDR,
  127                                                 phdr->a_hdrlen - A_MINHDR);
  128         }
  129 
  130         if (talk && !banner) {
  131                 printf("     text     data      bss      size\n");
  132                 banner= 1;
  133         }
  134 
  135         if (talk) {
  136                 printf(" %8ld %8ld %8ld %9ld  %s\n",
  137                         phdr->a_text, phdr->a_data, phdr->a_bss,
  138                         phdr->a_text + phdr->a_data + phdr->a_bss, proc);
  139         }
  140         total_text+= phdr->a_text;
  141         total_data+= phdr->a_data;
  142         total_bss+= phdr->a_bss;
  143 
  144         if (phdr->a_cpu == A_I8086) {
  145                 long data= phdr->a_data + phdr->a_bss;
  146 
  147                 if (!(phdr->a_flags & A_SEP)) data+= phdr->a_text;
  148 
  149                 if (phdr->a_text >= 65536) big|= 1;
  150                 if (data >= 65536) big|= 2;
  151         }
  152         if (big) {
  153                 fprintf(stderr,
  154                         "%s will crash, %s%s%s segment%s larger then 64K\n",
  155                         proc,
  156                         big & 1 ? "text" : "",
  157                         big == 3 ? " and " : "",
  158                         big & 2 ? "data" : "",
  159                         big == 3 ? "s are" : " is");
  160         }
  161 }
  162 
  163 void padimage(char *image, FILE *imagef, int n)
  164 /* Add n zeros to image to pad it to a sector boundary. */
  165 {
  166         while (n > 0) {
  167                 if (putc(0, imagef) == EOF) fatal(image);
  168                 n--;
  169         }
  170 }
  171 
  172 #define align(n)        (((n) + ((SECTOR_SIZE) - 1)) & ~((SECTOR_SIZE) - 1))
  173 
  174 void copyexec(char *proc, FILE *procf, char *image, FILE *imagef, long n)
  175 /* Copy n bytes from proc to image padded to fill a sector. */
  176 {
  177         int pad, c;
  178 
  179         /* Compute number of padding bytes. */
  180         pad= align(n) - n;
  181 
  182         while (n > 0) {
  183                 if ((c= getc(procf)) == EOF) {
  184                         if (ferror(procf)) fatal(proc);
  185                         fprintf(stderr, "installboot: premature EOF on %s\n",
  186                                                                         proc);
  187                         exit(1);
  188                 }
  189                 if (putc(c, imagef) == EOF) fatal(image);
  190                 n--;
  191         }
  192         padimage(image, imagef, pad);
  193 }
  194 
  195 void make_image(char *image, char **procv)
  196 /* Collect a set of files in an image, each "segment" is nicely padded out
  197  * to SECTOR_SIZE, so it may be read from disk into memory without trickery.
  198  */
  199 {
  200         FILE *imagef, *procf;
  201         char *proc, *file;
  202         int procn;
  203         struct image_header ihdr;
  204         struct exec phdr;
  205         struct stat st;
  206 
  207         making_image= 1;
  208 
  209         if ((imagef= fopen(image, "w")) == nil) fatal(image);
  210 
  211         for (procn= 0; (proc= *procv++) != nil; procn++) {
  212                 /* Remove the label from the file name. */
  213                 if ((file= strchr(proc, ':')) != nil) file++; else file= proc;
  214 
  215                 /* Real files please, may need to seek. */
  216                 if (stat(file, &st) < 0
  217                         || (errno= EISDIR, !S_ISREG(st.st_mode))
  218                         || (procf= fopen(file, "r")) == nil
  219                 ) fatal(proc);
  220 
  221                 /* Read a.out header. */
  222                 read_header(1, proc, procf, &ihdr);
  223 
  224                 /* Scratch. */
  225                 phdr= ihdr.process;
  226 
  227                 /* The symbol table is always stripped off. */
  228                 ihdr.process.a_syms= 0;
  229                 ihdr.process.a_flags &= ~A_NSYM;
  230 
  231                 /* Write header padded to fill a sector */
  232                 bwrite(imagef, image, &ihdr, sizeof(ihdr));
  233 
  234                 padimage(image, imagef, SECTOR_SIZE - sizeof(ihdr));
  235 
  236                 /* A page aligned executable needs the header in text. */
  237                 if (phdr.a_flags & A_PAL) {
  238                         rewind(procf);
  239                         phdr.a_text+= phdr.a_hdrlen;
  240                 }
  241 
  242                 /* Copy text and data of proc to image. */
  243                 if (phdr.a_flags & A_SEP) {
  244                         /* Separate I&D: pad text & data separately. */
  245 
  246                         copyexec(proc, procf, image, imagef, phdr.a_text);
  247                         copyexec(proc, procf, image, imagef, phdr.a_data);
  248                 } else {
  249                         /* Common I&D: keep text and data together. */
  250 
  251                         copyexec(proc, procf, image, imagef,
  252                                                 phdr.a_text + phdr.a_data);
  253                 }
  254 
  255                 /* Done with proc. */
  256                 (void) fclose(procf);
  257         }
  258         /* Done with image. */
  259 
  260         if (fclose(imagef) == EOF) fatal(image);
  261 
  262         printf("   ------   ------   ------   -------\n");
  263         printf(" %8ld %8ld %8ld %9ld  total\n",
  264                 total_text, total_data, total_bss,
  265                 total_text + total_data + total_bss);
  266 }
  267 
  268 void extractexec(FILE *imagef, char *image, FILE *procf, char *proc,
  269                                                 long count, off_t *alen)
  270 /* Copy a segment of an executable.  It is padded to a sector in image. */
  271 {
  272         char buf[SECTOR_SIZE];
  273 
  274         while (count > 0) {
  275                 bread(imagef, image, buf, sizeof(buf));
  276                 *alen-= sizeof(buf);
  277 
  278                 bwrite(procf, proc, buf,
  279                         count < sizeof(buf) ? (size_t) count : sizeof(buf));
  280                 count-= sizeof(buf);
  281         }
  282 }
  283 
  284 void extract_image(char *image)
  285 /* Extract the executables from an image. */
  286 {
  287         FILE *imagef, *procf;
  288         off_t len;
  289         struct stat st;
  290         struct image_header ihdr;
  291         struct exec phdr;
  292         char buf[SECTOR_SIZE];
  293 
  294         if (stat(image, &st) < 0) fatal(image);
  295 
  296         /* Size of the image. */
  297         len= S_ISREG(st.st_mode) ? st.st_size : -1;
  298 
  299         if ((imagef= fopen(image, "r")) == nil) fatal(image);
  300 
  301         while (len != 0) {
  302                 /* Extract a program, first sector is an extended header. */
  303                 bread(imagef, image, buf, sizeof(buf));
  304                 len-= sizeof(buf);
  305 
  306                 memcpy(&ihdr, buf, sizeof(ihdr));
  307                 phdr= ihdr.process;
  308 
  309                 /* Check header. */
  310                 read_header(1, ihdr.name, nil, &ihdr);
  311 
  312                 if ((procf= fopen(ihdr.name, "w")) == nil) fatal(ihdr.name);
  313 
  314                 if (phdr.a_flags & A_PAL) {
  315                         /* A page aligned process contains a header in text. */
  316                         phdr.a_text+= phdr.a_hdrlen;
  317                 } else {
  318                         bwrite(procf, ihdr.name, &ihdr.process, phdr.a_hdrlen);
  319                 }
  320 
  321                 /* Extract text and data segments. */
  322                 if (phdr.a_flags & A_SEP) {
  323                         extractexec(imagef, image, procf, ihdr.name,
  324                                                 phdr.a_text, &len);
  325                         extractexec(imagef, image, procf, ihdr.name,
  326                                                 phdr.a_data, &len);
  327                 } else {
  328                         extractexec(imagef, image, procf, ihdr.name,
  329                                 phdr.a_text + phdr.a_data, &len);
  330                 }
  331 
  332                 if (fclose(procf) == EOF) fatal(ihdr.name);
  333         }
  334 }
  335 
  336 int rawfd;      /* File descriptor to open device. */
  337 char *rawdev;   /* Name of device. */
  338 
  339 void readblock(off_t blk, char *buf, int block_size)
  340 /* For rawfs, so that it can read blocks. */
  341 {
  342         int n;
  343 
  344         if (lseek(rawfd, blk * block_size, SEEK_SET) < 0
  345                 || (n= read(rawfd, buf, block_size)) < 0
  346         ) fatal(rawdev);
  347 
  348         if (n < block_size) {
  349                 fprintf(stderr, "installboot: Unexpected EOF on %s\n", rawdev);
  350                 exit(1);
  351         }
  352 }
  353 
  354 void writeblock(off_t blk, char *buf, int block_size)
  355 /* Add a function to write blocks for local use. */
  356 {
  357         if (lseek(rawfd, blk * block_size, SEEK_SET) < 0
  358                 || write(rawfd, buf, block_size) < 0
  359         ) fatal(rawdev);
  360 }
  361 
  362 int raw_install(char *file, off_t *start, off_t *len, int block_size)
  363 /* Copy bootcode or an image to the boot device at the given absolute disk
  364  * block number.  This "raw" installation is used to place bootcode and
  365  * image on a disk without a filesystem to make a simple boot disk.  Useful
  366  * in automated scripts for J. Random User.
  367  * Note: *len == 0 when an image is read.  It is set right afterwards.
  368  */
  369 {
  370         static char buf[MAX_BLOCK_SIZE];        /* Nonvolatile block buffer. */
  371         FILE *f;
  372         off_t sec;
  373         unsigned long devsize;
  374         static int banner= 0;
  375         struct partition entry;
  376 
  377         /* See if the device has a maximum size. */
  378         devsize= -1;
  379         if (ioctl(rawfd, DIOCGETP, &entry) == 0) devsize= cv64ul(entry.size);
  380 
  381         if ((f= fopen(file, "r")) == nil) fatal(file);
  382 
  383         /* Copy sectors from file onto the boot device. */
  384         sec= *start;
  385         do {
  386                 int off= sec % RATIO(BOOT_BLOCK_SIZE);
  387 
  388                 if (fread(buf + off * SECTOR_SIZE, 1, SECTOR_SIZE, f) == 0)
  389                         break;
  390 
  391                 if (sec >= devsize) {
  392                         fprintf(stderr,
  393                         "installboot: %s can't be attached to %s\n",
  394                                 file, rawdev);
  395                         return 0;
  396                 }
  397 
  398                 if (off == RATIO(BOOT_BLOCK_SIZE) - 1) writeblock(sec / RATIO(BOOT_BLOCK_SIZE), buf, BOOT_BLOCK_SIZE);
  399         } while (++sec != *start + *len);
  400 
  401         if (ferror(f)) fatal(file);
  402         (void) fclose(f);
  403 
  404         /* Write a partial block, this may be the last image. */
  405         if (sec % RATIO(BOOT_BLOCK_SIZE) != 0) writeblock(sec / RATIO(BOOT_BLOCK_SIZE), buf, BOOT_BLOCK_SIZE);
  406 
  407         if (!banner) {
  408                 printf("  sector  length\n");
  409                 banner= 1;
  410         }
  411         *len= sec - *start;
  412         printf("%8ld%8ld  %s\n", *start, *len, file);
  413         *start= sec;
  414         return 1;
  415 }
  416 
  417 enum howto { FS, BOOT };
  418 
  419 void make_bootable(enum howto how, char *device, char *bootblock,
  420                                         char *bootcode, char **imagev)
  421 /* Install bootblock on the bootsector of device with the disk addresses to
  422  * bootcode patched into the data segment of bootblock.  "How" tells if there
  423  * should or shoudn't be a file system on the disk.  The images in the imagev
  424  * vector are added to the end of the device.
  425  */
  426 {
  427         char buf[MAX_BLOCK_SIZE + 256], *adrp, *parmp;
  428         struct fileaddr {
  429                 off_t   address;
  430                 int     count;
  431         } bootaddr[BOOT_MAX + 1], *bap= bootaddr;
  432         struct exec boothdr;
  433         struct image_header dummy;
  434         struct stat st;
  435         ino_t ino;
  436         off_t sector, max_sector;
  437         FILE *bootf;
  438         off_t addr, fssize, pos, len;
  439         char *labels, *label, *image;
  440         int nolabel;
  441         int block_size = 0;
  442 
  443         /* Open device and set variables for readblock. */
  444         if ((rawfd= open(rawdev= device, O_RDWR)) < 0) fatal(device);
  445 
  446         /* Read and check the superblock. */
  447         fssize= r_super(&block_size);
  448 
  449         switch (how) {
  450         case FS:
  451                 if (fssize == 0) {
  452                         fprintf(stderr,
  453                                 "installboot: %s is not a Minix file system\n",
  454                                 device);
  455                         exit(1);
  456                 }
  457                 break;
  458         case BOOT:
  459                 if (fssize != 0) {
  460                         int s;
  461                         printf("%s contains a file system!\n", device);
  462                         printf("Scribbling in 10 seconds");
  463                         for (s= 0; s < 10; s++) {
  464                                 fputc('.', stdout);
  465                                 fflush(stdout);
  466                                 sleep(1);
  467                         }
  468                         fputc('\n', stdout);
  469                 }
  470                 fssize= 1;      /* Just a boot block. */
  471         }
  472 
  473         if (how == FS) {
  474                 /* See if the boot code can be found on the file system. */
  475                 if ((ino= r_lookup(ROOT_INO, bootcode)) == 0) {
  476                         if (errno != ENOENT) fatal(bootcode);
  477                 }
  478         } else {
  479                 /* Boot code must be attached at the end. */
  480                 ino= 0;
  481         }
  482 
  483         if (ino == 0) {
  484                 /* For a raw installation, we need to copy the boot code onto
  485                  * the device, so we need to look at the file to be copied.
  486                  */
  487                 if (stat(bootcode, &st) < 0) fatal(bootcode);
  488 
  489                 if ((bootf= fopen(bootcode, "r")) == nil) fatal(bootcode);
  490         } else {
  491                 /* Boot code is present in the file system. */
  492                 r_stat(ino, &st);
  493 
  494                 /* Get the header from the first block. */
  495                 if ((addr= r_vir2abs((off_t) 0)) == 0) {
  496                         boothdr.a_magic[0]= !A_MAGIC0;
  497                 } else {
  498                         readblock(addr, buf, block_size);
  499                         memcpy(&boothdr, buf, sizeof(struct exec));
  500                 }
  501                 bootf= nil;
  502                 dummy.process= boothdr;
  503         }
  504         /* See if it is an executable (read_header does the check). */
  505         read_header(0, bootcode, bootf, &dummy);
  506         boothdr= dummy.process;
  507 
  508         if (bootf != nil) fclose(bootf);
  509 
  510         /* Get all the sector addresses of the secondary boot code. */
  511         max_sector= (boothdr.a_hdrlen + boothdr.a_text
  512                         + boothdr.a_data + SECTOR_SIZE - 1) / SECTOR_SIZE;
  513 
  514         if (max_sector > BOOT_MAX * RATIO(block_size)) {
  515                 fprintf(stderr, "installboot: %s is way too big\n", bootcode);
  516                 exit(0);
  517         }
  518 
  519         /* Determine the addresses to the boot code to be patched into the
  520          * boot block.
  521          */
  522         bap->count= 0;  /* Trick to get the address recording going. */
  523 
  524         for (sector= 0; sector < max_sector; sector++) {
  525                 if (ino == 0) {
  526                         addr= fssize + (sector / RATIO(block_size));
  527                 } else
  528                 if ((addr= r_vir2abs(sector / RATIO(block_size))) == 0) {
  529                         fprintf(stderr, "installboot: %s has holes!\n",
  530                                                                 bootcode);
  531                         exit(1);
  532                 }
  533                 addr= (addr * RATIO(block_size)) + (sector % RATIO(block_size));
  534 
  535                 /* First address of the addresses array? */
  536                 if (bap->count == 0) bap->address= addr;
  537 
  538                 /* Paste sectors together in a multisector read. */
  539                 if (bap->address + bap->count == addr)
  540                         bap->count++;
  541                 else {
  542                         /* New address. */
  543                         bap++;
  544                         bap->address= addr;
  545                         bap->count= 1;
  546                 }
  547         }
  548         (++bap)->count= 0;      /* No more. */
  549 
  550         /* Get the boot block and patch the pieces in. */
  551         readblock(BOOTBLOCK, buf, BOOT_BLOCK_SIZE);
  552 
  553         if ((bootf= fopen(bootblock, "r")) == nil) fatal(bootblock);
  554 
  555         read_header(0, bootblock, bootf, &dummy);
  556         boothdr= dummy.process;
  557 
  558         if (boothdr.a_text + boothdr.a_data +
  559                                          4 * (bap - bootaddr) + 1 > PARTPOS) {
  560                 fprintf(stderr,
  561         "installboot: %s + addresses to %s don't fit in the boot sector\n",
  562                         bootblock, bootcode);
  563                 fprintf(stderr,
  564                     "You can try copying/reinstalling %s to defragment it\n",
  565                         bootcode);
  566                 exit(1);
  567         }
  568 
  569         /* All checks out right.  Read bootblock into the boot block! */
  570         bread(bootf, bootblock, buf, boothdr.a_text + boothdr.a_data);
  571         (void) fclose(bootf);
  572 
  573         /* Patch the addresses in. */
  574         adrp= buf + (int) (boothdr.a_text + boothdr.a_data);
  575         for (bap= bootaddr; bap->count != 0; bap++) {
  576                 *adrp++= bap->count;
  577                 *adrp++= (bap->address >>  0) & 0xFF;
  578                 *adrp++= (bap->address >>  8) & 0xFF;
  579                 *adrp++= (bap->address >> 16) & 0xFF;
  580         }
  581         /* Zero count stops bootblock's reading loop. */
  582         *adrp++= 0;
  583 
  584         if (bap > bootaddr+1) {
  585                 printf("%s and %d addresses to %s patched into %s\n",
  586                         bootblock, (int)(bap - bootaddr), bootcode, device);
  587         }
  588 
  589         /* Boot block signature. */
  590         buf[SIGPOS+0]= (SIGNATURE >> 0) & 0xFF;
  591         buf[SIGPOS+1]= (SIGNATURE >> 8) & 0xFF;
  592 
  593         /* Sector 2 of the boot block is used for boot parameters, initially
  594          * filled with null commands (newlines).  Initialize it only if
  595          * necessary.
  596          */
  597         for (parmp= buf + SECTOR_SIZE; parmp < buf + 2*SECTOR_SIZE; parmp++) {
  598                 if (*imagev != nil || (control(*parmp) && *parmp != '\n')) {
  599                         /* Param sector must be initialized. */
  600                         memset(buf + SECTOR_SIZE, '\n', SECTOR_SIZE);
  601                         break;
  602                 }
  603         }
  604 
  605         /* Offset to the end of the file system to add boot code and images. */
  606         pos= fssize * RATIO(block_size);
  607 
  608         if (ino == 0) {
  609                 /* Place the boot code onto the boot device. */
  610                 len= max_sector;
  611                 if (!raw_install(bootcode, &pos, &len, block_size)) {
  612                         if (how == FS) {
  613                                 fprintf(stderr,
  614         "\t(Isn't there a copy of %s on %s that can be used?)\n",
  615                                         bootcode, device);
  616                         }
  617                         exit(1);
  618                 }
  619         }
  620 
  621         parmp= buf + SECTOR_SIZE;
  622         nolabel= 0;
  623 
  624         if (how == BOOT) {
  625                 /* A boot only disk needs to have floppies swapped. */
  626                 strcpy(parmp,
  627         "trailer()echo \\nInsert the root diskette then hit RETURN\\n\\w\\c\n");
  628                 parmp+= strlen(parmp);
  629         }
  630 
  631         while ((labels= *imagev++) != nil) {
  632                 /* Place each kernel image on the boot device. */
  633 
  634                 if ((image= strchr(labels, ':')) != nil)
  635                         *image++= 0;
  636                 else {
  637                         if (nolabel) {
  638                                 fprintf(stderr,
  639                             "installboot: Only one image can be the default\n");
  640                                 exit(1);
  641                         }
  642                         nolabel= 1;
  643                         image= labels;
  644                         labels= nil;
  645                 }
  646                 len= 0;
  647                 if (!raw_install(image, &pos, &len, block_size)) exit(1);
  648 
  649                 if (labels == nil) {
  650                         /* Let this image be the default. */
  651                         sprintf(parmp, "image=%ld:%ld\n", pos-len, len);
  652                         parmp+= strlen(parmp);
  653                 }
  654 
  655                 while (labels != nil) {
  656                         /* Image is prefixed by a comma separated list of
  657                          * labels.  Define functions to select label and image.
  658                          */
  659                         label= labels;
  660                         if ((labels= strchr(labels, ',')) != nil) *labels++ = 0;
  661 
  662                         sprintf(parmp,
  663                 "%s(%c){label=%s;image=%ld:%ld;echo %s kernel selected;menu}\n",
  664                                 label,
  665                                 between('A', label[0], 'Z')
  666                                         ? label[0]-'A'+'a' : label[0],
  667                                 label, pos-len, len, label);
  668                         parmp+= strlen(parmp);
  669                 }
  670 
  671                 if (parmp > buf + block_size) {
  672                         fprintf(stderr,
  673                 "installboot: Out of parameter space, too many images\n");
  674                         exit(1);
  675                 }
  676         }
  677         /* Install boot block. */
  678         writeblock((off_t) BOOTBLOCK, buf, 1024);
  679 
  680         if (pos > fssize * RATIO(block_size)) {
  681                 /* Tell the total size of the data on the device. */
  682                 printf("%16ld  (%ld kb) total\n", pos,
  683                                                 (pos + RATIO(block_size) - 1) / RATIO(block_size));
  684         }
  685 }
  686 
  687 void install_master(char *device, char *masterboot, char **guide)
  688 /* Booting a hard disk is a two stage process:  The master bootstrap in sector
  689  * 0 loads the bootstrap from sector 0 of the active partition which in turn
  690  * starts the operating system.  This code installs such a master bootstrap
  691  * on a hard disk.  If guide[0] is non-null then the master bootstrap is
  692  * guided into booting a certain device.
  693  */
  694 {
  695         FILE *masf;
  696         unsigned long size;
  697         struct stat st;
  698         static char buf[MAX_BLOCK_SIZE];
  699 
  700         /* Open device. */
  701         if ((rawfd= open(rawdev= device, O_RDWR)) < 0) fatal(device);
  702 
  703         /* Open the master boot code. */
  704         if ((masf= fopen(masterboot, "r")) == nil) fatal(masterboot);
  705 
  706         /* See if the user is cloning a device. */
  707         if (fstat(fileno(masf), &st) >=0 && S_ISBLK(st.st_mode))
  708                 size= PARTPOS;
  709         else {
  710                 /* Read and check header otherwise. */
  711                 struct image_header ihdr;
  712 
  713                 read_header(1, masterboot, masf, &ihdr);
  714                 size= ihdr.process.a_text + ihdr.process.a_data;
  715         }
  716         if (size > PARTPOS) {
  717                 fprintf(stderr, "installboot: %s is too big\n", masterboot);
  718                 exit(1);
  719         }
  720 
  721         /* Read the master boot block, patch it, write. */
  722         readblock(BOOTBLOCK, buf, BOOT_BLOCK_SIZE);
  723 
  724         memset(buf, 0, PARTPOS);
  725         (void) bread(masf, masterboot, buf, size);
  726 
  727         if (guide[0] != nil) {
  728                 /* Fixate partition to boot. */
  729                 char *keys= guide[0];
  730                 char *logical= guide[1];
  731                 size_t i;
  732                 int logfd;
  733                 u32_t offset;
  734                 struct partition geometry;
  735 
  736                 /* A string of digits to be seen as keystrokes. */
  737                 i= 0;
  738                 do {
  739                         if (!between('', keys[i], '9')) {
  740                                 fprintf(stderr,
  741                                         "installboot: bad guide keys '%s'\n",
  742                                         keys);
  743                                 exit(1);
  744                         }
  745                 } while (keys[++i] != 0);
  746 
  747                 if (size + i + 1 > PARTPOS) {
  748                         fprintf(stderr,
  749                         "installboot: not enough space after '%s' for '%s'\n",
  750                                 masterboot, keys);
  751                         exit(1);
  752                 }
  753                 memcpy(buf + size, keys, i);
  754                 size += i;
  755                 buf[size]= '\r';
  756 
  757                 if (logical != nil) {
  758                         if ((logfd= open(logical, O_RDONLY)) < 0
  759                                 || ioctl(logfd, DIOCGETP, &geometry) < 0
  760                         ) {
  761                                 fatal(logical);
  762                         }
  763                         offset= div64u(geometry.base, SECTOR_SIZE);
  764                         if (size + 5 > PARTPOS) {
  765                                 fprintf(stderr,
  766                                         "installboot: not enough space "
  767                                         "after '%s' for '%s' and an offset "
  768                                         "to '%s'\n",
  769                                         masterboot, keys, logical);
  770                                 exit(1);
  771                         }
  772                         buf[size]= '#';
  773                         memcpy(buf+size+1, &offset, 4);
  774                 }
  775         }
  776 
  777         /* Install signature. */
  778         buf[SIGPOS+0]= (SIGNATURE >> 0) & 0xFF;
  779         buf[SIGPOS+1]= (SIGNATURE >> 8) & 0xFF;
  780 
  781         writeblock(BOOTBLOCK, buf, BOOT_BLOCK_SIZE);
  782 }
  783 
  784 void usage(void)
  785 {
  786         fprintf(stderr,
  787           "Usage: installboot -i(mage) image kernel mm fs ... init\n"
  788           "       installboot -(e)x(tract) image\n"
  789           "       installboot -d(evice) device bootblock boot [image ...]\n"
  790           "       installboot -b(oot) device bootblock boot image ...\n"
  791           "       installboot -m(aster) device masterboot [keys [logical]]\n");
  792         exit(1);
  793 }
  794 
  795 int isoption(char *option, char *test)
  796 /* Check if the option argument is equals "test".  Also accept -i as short
  797  * for -image, and the special case -x for -extract.
  798  */
  799 {
  800         if (strcmp(option, test) == 0) return 1;
  801         if (option[0] != '-' && strlen(option) != 2) return 0;
  802         if (option[1] == test[1]) return 1;
  803         if (option[1] == 'x' && test[1] == 'e') return 1;
  804         return 0;
  805 }
  806 
  807 int main(int argc, char **argv)
  808 {
  809         if (argc < 2) usage();
  810 
  811         if (argc >= 4 && isoption(argv[1], "-image")) {
  812                 make_image(argv[2], argv + 3);
  813         } else
  814         if (argc == 3 && isoption(argv[1], "-extract")) {
  815                 extract_image(argv[2]);
  816         } else
  817         if (argc >= 5 && isoption(argv[1], "-device")) {
  818                 make_bootable(FS, argv[2], argv[3], argv[4], argv + 5);
  819         } else
  820         if (argc >= 6 && isoption(argv[1], "-boot")) {
  821                 make_bootable(BOOT, argv[2], argv[3], argv[4], argv + 5);
  822         } else
  823         if ((4 <= argc && argc <= 6) && isoption(argv[1], "-master")) {
  824                 install_master(argv[2], argv[3], argv + 4);
  825         } else {
  826                 usage();
  827         }
  828         exit(0);
  829 }
  830 
  831 /*
  832  * $PchId: installboot.c,v 1.10 2000/08/13 22:07:50 philip Exp $
  833  */

Cache object: 035c78a03adb7659b9974907220b1c0b


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.