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/bootimage.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 /*      bootimage.c - Load an image and start it.       Author: Kees J. Bot
    2  *                                                              19 Jan 1992
    3  */
    4 #define BIOS            1       /* Can only be used under the BIOS. */
    5 #define nil 0
    6 #define _POSIX_SOURCE   1
    7 #define _MINIX          1
    8 #include <stddef.h>
    9 #include <sys/types.h>
   10 #include <sys/stat.h>
   11 #include <stdlib.h>
   12 #include <stdio.h>
   13 #include <limits.h>
   14 #include <string.h>
   15 #include <errno.h>
   16 #include <a.out.h>
   17 #include <minix/config.h>
   18 #include <minix/const.h>
   19 #include <minix/type.h>
   20 #include <minix/syslib.h>
   21 #include <kernel/const.h>
   22 #include <kernel/type.h>
   23 #include <ibm/partition.h>
   24 #include "rawfs.h"
   25 #include "image.h"
   26 #include "boot.h"
   27 
   28 static int block_size = 0;
   29 
   30 #define click_shift     clck_shft       /* 7 char clash with click_size. */
   31 
   32 /* Some kernels have extra features: */
   33 #define K_I386   0x0001 /* Make the 386 transition before you call me. */
   34 #define K_CLAIM  0x0002 /* I will acquire my own bss pages, thank you. */
   35 #define K_CHMEM  0x0004 /* This kernel listens to chmem for its stack size. */
   36 #define K_HIGH   0x0008 /* Load mm, fs, etc. in extended memory. */
   37 #define K_HDR    0x0010 /* No need to patch sizes, kernel uses the headers. */
   38 #define K_RET    0x0020 /* Returns to the monitor on reboot. */
   39 #define K_INT86  0x0040 /* Requires generic INT support. */
   40 #define K_MEML   0x0080 /* Pass a list of free memory. */
   41 #define K_BRET   0x0100 /* New monitor code on shutdown in boot parameters. */
   42 #define K_ALL    0x01FF /* All feature bits this monitor supports. */
   43 
   44 
   45 /* Data about the different processes. */
   46 
   47 #define PROCESS_MAX     16      /* Must match the space in kernel/mpx.x */
   48 #define KERNEL          0       /* The first process is the kernel. */
   49 #define FS              2       /* The third must be fs. */
   50 
   51 struct process {        /* Per-process memory adresses. */
   52         u32_t   entry;          /* Entry point. */
   53         u32_t   cs;             /* Code segment. */
   54         u32_t   ds;             /* Data segment. */
   55         u32_t   data;           /* To access the data segment. */
   56         u32_t   end;            /* End of this process, size = (end - cs). */
   57 } process[PROCESS_MAX];
   58 int n_procs;                    /* Number of processes. */
   59 
   60 /* Magic numbers in process' data space. */
   61 #define MAGIC_OFF       0       /* Offset of magic # in data seg. */
   62 #define CLICK_OFF       2       /* Offset in kernel text to click_shift. */
   63 #define FLAGS_OFF       4       /* Offset in kernel text to flags. */
   64 #define KERNEL_D_MAGIC  0x526F  /* Kernel magic number. */
   65 
   66 /* Offsets of sizes to be patched into kernel and fs. */
   67 #define P_SIZ_OFF       0       /* Process' sizes into kernel data. */
   68 #define P_INIT_OFF      4       /* Init cs & sizes into fs data. */
   69 
   70 
   71 #define between(a, c, z)        ((unsigned) ((c) - (a)) <= ((z) - (a)))
   72 
   73 void pretty_image(char *image)
   74 /* Pretty print the name of the image to load.  Translate '/' and '_' to
   75  * space, first letter goes uppercase.  An 'r' before a digit prints as
   76  * 'revision'.  E.g. 'minix/1.6.16r10' -> 'Minix 1.6.16 revision 10'.
   77  * The idea is that the part before the 'r' is the official Minix release
   78  * and after the 'r' you can put version numbers for your own changes.
   79  */
   80 {
   81         int up= 0, c;
   82 
   83         while ((c= *image++) != 0) {
   84                 if (c == '/' || c == '_') c= ' ';
   85 
   86                 if (c == 'r' && between('', *image, '9')) {
   87                         printf(" revision ");
   88                         continue;
   89                 }
   90                 if (!up && between('a', c, 'z')) c= c - 'a' + 'A';
   91 
   92                 if (between('A', c, 'Z')) up= 1;
   93 
   94                 putch(c);
   95         }
   96 }
   97 
   98 void raw_clear(u32_t addr, u32_t count)
   99 /* Clear "count" bytes at absolute address "addr". */
  100 {
  101         static char zeros[128];
  102         u32_t dst;
  103         u32_t zct;
  104 
  105         zct= sizeof(zeros);
  106         if (zct > count) zct= count;
  107         raw_copy(addr, mon2abs(&zeros), zct);
  108         count-= zct;
  109 
  110         while (count > 0) {
  111                 dst= addr + zct;
  112                 if (zct > count) zct= count;
  113                 raw_copy(dst, addr, zct);
  114                 count-= zct;
  115                 zct*= 2;
  116         }
  117 }
  118 
  119 /* Align a to a multiple of n (a power of 2): */
  120 #define align(a, n)     (((u32_t)(a) + ((u32_t)(n) - 1)) & ~((u32_t)(n) - 1))
  121 unsigned click_shift;
  122 unsigned click_size;    /* click_size = Smallest kernel memory object. */
  123 unsigned k_flags;       /* Not all kernels are created equal. */
  124 u32_t reboot_code;      /* Obsolete reboot code return pointer. */
  125 
  126 int params2params(char *params, size_t psize)
  127 /* Repackage the environment settings for the kernel. */
  128 {
  129         size_t i, n;
  130         environment *e;
  131         char *name, *value;
  132         dev_t dev;
  133 
  134         i= 0;
  135         for (e= env; e != nil; e= e->next) {
  136                 name= e->name;
  137                 value= e->value;
  138 
  139                 if (!(e->flags & E_VAR)) continue;
  140 
  141                 if (e->flags & E_DEV) {
  142                         if ((dev= name2dev(value)) == -1) return 0;
  143                         value= ul2a10((u16_t) dev);
  144                 }
  145 
  146                 n= i + strlen(name) + 1 + strlen(value) + 1;
  147                 if (n < psize) {
  148                         strcpy(params + i, name);
  149                         strcat(params + i, "=");
  150                         strcat(params + i, value);
  151                 }
  152                 i= n;
  153         }
  154 
  155         if (!(k_flags & K_MEML)) {
  156                 /* Require old memory size variables. */
  157 
  158                 value= ul2a10((mem[0].base + mem[0].size) / 1024);
  159                 n= i + 7 + 1 + strlen(value) + 1;
  160                 if (n < psize) {
  161                         strcpy(params + i, "memsize=");
  162                         strcat(params + i, value);
  163                 }
  164                 i= n;
  165                 value= ul2a10(mem[1].size / 1024);
  166                 n= i + 7 + 1 + strlen(value) + 1;
  167                 if (n < psize) {
  168                         strcpy(params + i, "emssize=");
  169                         strcat(params + i, value);
  170                 }
  171                 i= n;
  172         }
  173 
  174         if (i >= psize) {
  175                 printf("Too many boot parameters\n");
  176                 return 0;
  177         }
  178         params[i]= 0;   /* End marked with empty string. */
  179         return 1;
  180 }
  181 
  182 void patch_sizes(void)
  183 /* Patch sizes of each process into kernel data space, kernel ds into kernel
  184  * text space, and sizes of init into data space of fs.  All the patched
  185  * numbers are based on the kernel click size, not hardware segments.
  186  */
  187 {
  188         u16_t text_size, data_size;
  189         int i;
  190         struct process *procp, *initp;
  191         u32_t doff;
  192 
  193         if (k_flags & K_HDR) return;    /* Uses the headers. */
  194 
  195         /* Patch text and data sizes of the processes into kernel data space.
  196          */
  197         doff= process[KERNEL].data + P_SIZ_OFF;
  198 
  199         for (i= 0; i < n_procs; i++) {
  200                 procp= &process[i];
  201                 text_size= (procp->ds - procp->cs) >> click_shift;
  202                 data_size= (procp->end - procp->ds) >> click_shift;
  203 
  204                 /* Two words per process, the text and data size: */
  205                 put_word(doff, text_size); doff+= 2;
  206                 put_word(doff, data_size); doff+= 2;
  207 
  208                 initp= procp;   /* The last process must be init. */
  209         }
  210 
  211         if (k_flags & (K_HIGH|K_MEML)) return;  /* Doesn't need FS patching. */
  212 
  213         /* Patch cs and sizes of init into fs data. */
  214         put_word(process[FS].data + P_INIT_OFF+0, initp->cs >> click_shift);
  215         put_word(process[FS].data + P_INIT_OFF+2, text_size);
  216         put_word(process[FS].data + P_INIT_OFF+4, data_size);
  217 }
  218 
  219 int selected(char *name)
  220 /* True iff name has no label or the proper label. */
  221 {
  222         char *colon, *label;
  223         int cmp;
  224 
  225         if ((colon= strchr(name, ':')) == nil) return 1;
  226         if ((label= b_value("label")) == nil) return 1;
  227 
  228         *colon= 0;
  229         cmp= strcmp(label, name);
  230         *colon= ':';
  231         return cmp == 0;
  232 }
  233 
  234 u32_t proc_size(struct image_header *hdr)
  235 /* Return the size of a process in sectors as found in an image. */
  236 {
  237         u32_t len= hdr->process.a_text;
  238 
  239         if (hdr->process.a_flags & A_PAL) len+= hdr->process.a_hdrlen;
  240         if (hdr->process.a_flags & A_SEP) len= align(len, SECTOR_SIZE);
  241         len= align(len + hdr->process.a_data, SECTOR_SIZE);
  242 
  243         return len >> SECTOR_SHIFT;
  244 }
  245 
  246 off_t image_off, image_size;
  247 u32_t (*vir2sec)(u32_t vsec);   /* Where is a sector on disk? */
  248 
  249 u32_t file_vir2sec(u32_t vsec)
  250 /* Translate a virtual sector number to an absolute disk sector. */
  251 {
  252         off_t blk;
  253 
  254         if(!block_size) { errno = 0;  return -1; }
  255 
  256         if ((blk= r_vir2abs(vsec / RATIO(block_size))) == -1) {
  257                 errno= EIO;
  258                 return -1;
  259         }
  260         return blk == 0 ? 0 : lowsec + blk * RATIO(block_size) + vsec % RATIO(block_size);
  261 }
  262 
  263 u32_t flat_vir2sec(u32_t vsec)
  264 /* Simply add an absolute sector offset to vsec. */
  265 {
  266         return lowsec + image_off + vsec;
  267 }
  268 
  269 char *get_sector(u32_t vsec)
  270 /* Read a sector "vsec" from the image into memory and return its address.
  271  * Return nil on error.  (This routine tries to read an entire track, so
  272  * the next request is usually satisfied from the track buffer.)
  273  */
  274 {
  275         u32_t sec;
  276         int r;
  277 #define SECBUFS 16
  278         static char buf[SECBUFS * SECTOR_SIZE];
  279         static size_t count;            /* Number of sectors in the buffer. */
  280         static u32_t bufsec;            /* First Sector now in the buffer. */
  281 
  282         if (vsec == 0) count= 0;        /* First sector; initialize. */
  283 
  284         if ((sec= (*vir2sec)(vsec)) == -1) return nil;
  285 
  286         if (sec == 0) {
  287                 /* A hole. */
  288                 count= 0;
  289                 memset(buf, 0, SECTOR_SIZE);
  290                 return buf;
  291         }
  292 
  293         /* Can we return a sector from the buffer? */
  294         if ((sec - bufsec) < count) {
  295                 return buf + ((size_t) (sec - bufsec) << SECTOR_SHIFT);
  296         }
  297 
  298         /* Not in the buffer. */
  299         count= 0;
  300         bufsec= sec;
  301 
  302         /* Read a whole track if possible. */
  303         while (++count < SECBUFS && !dev_boundary(bufsec + count)) {
  304                 vsec++;
  305                 if ((sec= (*vir2sec)(vsec)) == -1) break;
  306 
  307                 /* Consecutive? */
  308                 if (sec != bufsec + count) break;
  309         }
  310 
  311         /* Actually read the sectors. */
  312         if ((r= readsectors(mon2abs(buf), bufsec, count)) != 0) {
  313                 readerr(bufsec, r);
  314                 count= 0;
  315                 errno= 0;
  316                 return nil;
  317         }
  318         return buf;
  319 }
  320 
  321 int get_clickshift(u32_t ksec, struct image_header *hdr)
  322 /* Get the click shift and special flags from kernel text. */
  323 {
  324         char *textp;
  325 
  326         if ((textp= get_sector(ksec)) == nil) return 0;
  327 
  328         if (hdr->process.a_flags & A_PAL) textp+= hdr->process.a_hdrlen;
  329         click_shift= * (u16_t *) (textp + CLICK_OFF);
  330         k_flags= * (u16_t *) (textp + FLAGS_OFF);
  331 
  332         if ((k_flags & ~K_ALL) != 0) {
  333                 printf("%s requires features this monitor doesn't offer\n",
  334                         hdr->name);
  335                 return 0;
  336         }
  337 
  338         if (click_shift < HCLICK_SHIFT || click_shift > 16) {
  339                 printf("%s click size is bad\n", hdr->name);
  340                 errno= 0;
  341                 return 0;
  342         }
  343 
  344         click_size= 1 << click_shift;
  345 
  346         return 1;
  347 }
  348 
  349 int get_segment(u32_t *vsec, long *size, u32_t *addr, u32_t limit)
  350 /* Read *size bytes starting at virtual sector *vsec to memory at *addr. */
  351 {
  352         char *buf;
  353         size_t cnt, n;
  354 
  355         cnt= 0;
  356         while (*size > 0) {
  357                 if (cnt == 0) {
  358                         if ((buf= get_sector((*vsec)++)) == nil) return 0;
  359                         cnt= SECTOR_SIZE;
  360                 }
  361                 if (*addr + click_size > limit) { errno= ENOMEM; return 0; }
  362                 n= click_size;
  363                 if (n > cnt) n= cnt;
  364                 raw_copy(*addr, mon2abs(buf), n);
  365                 *addr+= n;
  366                 *size-= n;
  367                 buf+= n;
  368                 cnt-= n;
  369         }
  370 
  371         /* Zero extend to a click. */
  372         n= align(*addr, click_size) - *addr;
  373         raw_clear(*addr, n);
  374         *addr+= n;
  375         *size-= n;
  376         return 1;
  377 }
  378 
  379 void exec_image(char *image)
  380 /* Get a Minix image into core, patch it up and execute. */
  381 {
  382         char *delayvalue;
  383         int i;
  384         struct image_header hdr;
  385         char *buf;
  386         u32_t vsec, addr, limit, aout, n;
  387         struct process *procp;          /* Process under construction. */
  388         long a_text, a_data, a_bss, a_stack;
  389         int banner= 0;
  390         long processor= a2l(b_value("processor"));
  391         u16_t mode;
  392         char *console;
  393         char params[SECTOR_SIZE];
  394         extern char *sbrk(int);
  395 
  396         /* The stack is pretty deep here, so check if heap and stack collide. */
  397         (void) sbrk(0);
  398 
  399         printf("\nLoading ");
  400         pretty_image(image);
  401         printf(".\n\n");
  402 
  403         vsec= 0;                        /* Load this sector from image next. */
  404         addr= mem[0].base;              /* Into this memory block. */
  405         limit= mem[0].base + mem[0].size;
  406         if (limit > caddr) limit= caddr;
  407 
  408         /* Allocate and clear the area where the headers will be placed. */
  409         aout = (limit -= PROCESS_MAX * A_MINHDR);
  410 
  411         /* Clear the area where the headers will be placed. */
  412         raw_clear(aout, PROCESS_MAX * A_MINHDR);
  413 
  414         /* Read the many different processes: */
  415         for (i= 0; vsec < image_size; i++) {
  416                 if (i == PROCESS_MAX) {
  417                         printf("There are more then %d programs in %s\n",
  418                                 PROCESS_MAX, image);
  419                         errno= 0;
  420                         return;
  421                 }
  422                 procp= &process[i];
  423 
  424                 /* Read header. */
  425                 for (;;) {
  426                         if ((buf= get_sector(vsec++)) == nil) return;
  427 
  428                         memcpy(&hdr, buf, sizeof(hdr));
  429 
  430                         if (BADMAG(hdr.process)) { errno= ENOEXEC; return; }
  431 
  432                         /* Check the optional label on the process. */
  433                         if (selected(hdr.name)) break;
  434 
  435                         /* Bad label, skip this process. */
  436                         vsec+= proc_size(&hdr);
  437                 }
  438 
  439                 /* Sanity check: an 8086 can't run a 386 kernel. */
  440                 if (hdr.process.a_cpu == A_I80386 && processor < 386) {
  441                         printf("You can't run a 386 kernel on this 80%ld\n",
  442                                 processor);
  443                         errno= 0;
  444                         return;
  445                 }
  446 
  447                 /* Get the click shift from the kernel text segment. */
  448                 if (i == KERNEL) {
  449                         if (!get_clickshift(vsec, &hdr)) return;
  450                         addr= align(addr, click_size);
  451                 }
  452 
  453                 /* Save a copy of the header for the kernel, with a_syms
  454                  * misused as the address where the process is loaded at.
  455                  */
  456                 hdr.process.a_syms= addr;
  457                 raw_copy(aout + i * A_MINHDR, mon2abs(&hdr.process), A_MINHDR);
  458 
  459                 if (!banner) {
  460                         printf("     cs       ds     text     data      bss");
  461                         if (k_flags & K_CHMEM) printf("    stack");
  462                         putch('\n');
  463                         banner= 1;
  464                 }
  465 
  466                 /* Segment sizes. */
  467                 a_text= hdr.process.a_text;
  468                 a_data= hdr.process.a_data;
  469                 a_bss= hdr.process.a_bss;
  470                 if (k_flags & K_CHMEM) {
  471                         a_stack= hdr.process.a_total - a_data - a_bss;
  472                         if (!(hdr.process.a_flags & A_SEP)) a_stack-= a_text;
  473                 } else {
  474                         a_stack= 0;
  475                 }
  476 
  477                 /* Collect info about the process to be. */
  478                 procp->cs= addr;
  479 
  480                 /* Process may be page aligned so that the text segment contains
  481                  * the header, or have an unmapped zero page against vaxisms.
  482                  */
  483                 procp->entry= hdr.process.a_entry;
  484                 if (hdr.process.a_flags & A_PAL) a_text+= hdr.process.a_hdrlen;
  485                 if (hdr.process.a_flags & A_UZP) procp->cs-= click_size;
  486 
  487                 /* Separate I&D: two segments.  Common I&D: only one. */
  488                 if (hdr.process.a_flags & A_SEP) {
  489                         /* Read the text segment. */
  490                         if (!get_segment(&vsec, &a_text, &addr, limit)) return;
  491 
  492                         /* The data segment follows. */
  493                         procp->ds= addr;
  494                         if (hdr.process.a_flags & A_UZP) procp->ds-= click_size;
  495                         procp->data= addr;
  496                 } else {
  497                         /* Add text to data to form one segment. */
  498                         procp->data= addr + a_text;
  499                         procp->ds= procp->cs;
  500                         a_data+= a_text;
  501                 }
  502 
  503                 printf("%07lx  %07lx %8ld %8ld %8ld",
  504                         procp->cs, procp->ds,
  505                         hdr.process.a_text, hdr.process.a_data,
  506                         hdr.process.a_bss
  507                 );
  508                 if (k_flags & K_CHMEM) printf(" %8ld", a_stack);
  509 
  510                 printf("  %s\n", hdr.name);
  511 
  512                 /* Read the data segment. */
  513                 if (!get_segment(&vsec, &a_data, &addr, limit)) return;
  514 
  515                 /* Make space for bss and stack unless... */
  516                 if (i != KERNEL && (k_flags & K_CLAIM)) a_bss= a_stack= 0;
  517 
  518                 /* Note that a_data may be negative now, but we can look at it
  519                  * as -a_data bss bytes.
  520                  */
  521 
  522                 /* Compute the number of bss clicks left. */
  523                 a_bss+= a_data;
  524                 n= align(a_bss, click_size);
  525                 a_bss-= n;
  526 
  527                 /* Zero out bss. */
  528                 if (addr + n > limit) { errno= ENOMEM; return; }
  529                 raw_clear(addr, n);
  530                 addr+= n;
  531 
  532                 /* And the number of stack clicks. */
  533                 a_stack+= a_bss;
  534                 n= align(a_stack, click_size);
  535                 a_stack-= n;
  536 
  537                 /* Add space for the stack. */
  538                 addr+= n;
  539 
  540                 /* Process endpoint. */
  541                 procp->end= addr;
  542 
  543                 if (i == 0 && (k_flags & K_HIGH)) {
  544                         /* Load the rest in extended memory. */
  545                         addr= mem[1].base;
  546                         limit= mem[1].base + mem[1].size;
  547                 }
  548         }
  549 
  550         if ((n_procs= i) == 0) {
  551                 printf("There are no programs in %s\n", image);
  552                 errno= 0;
  553                 return;
  554         }
  555 
  556         /* Check the kernel magic number. */
  557         if (get_word(process[KERNEL].data + MAGIC_OFF) != KERNEL_D_MAGIC) {
  558                 printf("Kernel magic number is incorrect\n");
  559                 errno= 0;
  560                 return;
  561         }
  562 
  563         /* Patch sizes, etc. into kernel data. */
  564         patch_sizes();
  565 
  566 #if !DOS
  567         if (!(k_flags & K_MEML)) {
  568                 /* Copy the a.out headers to the old place. */
  569                 raw_copy(HEADERPOS, aout, PROCESS_MAX * A_MINHDR);
  570         }
  571 #endif
  572 
  573         /* Do delay if wanted. */
  574         if((delayvalue = b_value("bootdelay")) != nil > 0) {
  575                 delay(delayvalue);
  576         }
  577 
  578         /* Run the trailer function just before starting Minix. */
  579         if (!run_trailer()) { errno= 0; return; }
  580 
  581         /* Translate the boot parameters to what Minix likes best. */
  582         if (!params2params(params, sizeof(params))) { errno= 0; return; }
  583 
  584         /* Set the video to the required mode. */
  585         if ((console= b_value("console")) == nil || (mode= a2x(console)) == 0) {
  586                 mode= strcmp(b_value("chrome"), "color") == 0 ? COLOR_MODE :
  587                                                                 MONO_MODE;
  588         }
  589         set_mode(mode);
  590 
  591         /* Close the disk. */
  592         (void) dev_close();
  593 
  594         /* Minix. */
  595         minix(process[KERNEL].entry, process[KERNEL].cs,
  596                         process[KERNEL].ds, params, sizeof(params), aout);
  597 
  598         if (!(k_flags & K_BRET)) {
  599                 extern u32_t reboot_code;
  600                 raw_copy(mon2abs(params), reboot_code, sizeof(params));
  601         }
  602         parse_code(params);
  603 
  604         /* Return from Minix.  Things may have changed, so assume nothing. */
  605         fsok= -1;
  606         errno= 0;
  607 
  608         /* Read leftover character, if any. */
  609         scan_keyboard();
  610 }
  611 
  612 ino_t latest_version(char *version, struct stat *stp)
  613 /* Recursively read the current directory, selecting the newest image on
  614  * the way up.  (One can't use r_stat while reading a directory.)
  615  */
  616 {
  617         char name[NAME_MAX + 1];
  618         ino_t ino, newest;
  619         time_t mtime;
  620 
  621         if ((ino= r_readdir(name)) == 0) { stp->st_mtime= 0; return 0; }
  622 
  623         newest= latest_version(version, stp);
  624         mtime= stp->st_mtime;
  625         r_stat(ino, stp);
  626 
  627         if (S_ISREG(stp->st_mode) && stp->st_mtime > mtime) {
  628                 newest= ino;
  629                 strcpy(version, name);
  630         } else {
  631                 stp->st_mtime= mtime;
  632         }
  633         return newest;
  634 }
  635 
  636 char *select_image(char *image)
  637 /* Look image up on the filesystem, if it is a file then we're done, but
  638  * if its a directory then we want the newest file in that directory.  If
  639  * it doesn't exist at all, then see if it is 'number:number' and get the
  640  * image from that absolute offset off the disk.
  641  */
  642 {
  643         ino_t image_ino;
  644         struct stat st;
  645 
  646         image= strcpy(malloc((strlen(image) + 1 + NAME_MAX + 1)
  647                                                  * sizeof(char)), image);
  648 
  649         fsok= r_super(&block_size) != 0;
  650         if (!fsok || (image_ino= r_lookup(ROOT_INO, image)) == 0) {
  651                 char *size;
  652 
  653                 if (numprefix(image, &size) && *size++ == ':'
  654                                                 && numeric(size)) {
  655                         vir2sec= flat_vir2sec;
  656                         image_off= a2l(image);
  657                         image_size= a2l(size);
  658                         strcpy(image, "Minix");
  659                         return image;
  660                 }
  661                 if (!fsok)
  662                         printf("No image selected\n");
  663                 else
  664                         printf("Can't load %s: %s\n", image, unix_err(errno));
  665                 goto bail_out;
  666         }
  667 
  668         r_stat(image_ino, &st);
  669         if (!S_ISREG(st.st_mode)) {
  670                 char *version= image + strlen(image);
  671                 char dots[NAME_MAX + 1];
  672 
  673                 if (!S_ISDIR(st.st_mode)) {
  674                         printf("%s: %s\n", image, unix_err(ENOTDIR));
  675                         goto bail_out;
  676                 }
  677                 (void) r_readdir(dots);
  678                 (void) r_readdir(dots); /* "." & ".." */
  679                 *version++= '/';
  680                 *version= 0;
  681                 if ((image_ino= latest_version(version, &st)) == 0) {
  682                         printf("There are no images in %s\n", image);
  683                         goto bail_out;
  684                 }
  685                 r_stat(image_ino, &st);
  686         }
  687         vir2sec= file_vir2sec;
  688         image_size= (st.st_size + SECTOR_SIZE - 1) >> SECTOR_SHIFT;
  689         return image;
  690 bail_out:
  691         free(image);
  692         return nil;
  693 }
  694 
  695 void bootminix(void)
  696 /* Load Minix and run it.  (Given the size of this program it is surprising
  697  * that it ever gets to that.)
  698  */
  699 {
  700         char *image;
  701 
  702         if ((image= select_image(b_value("image"))) == nil) return;
  703 
  704         exec_image(image);
  705 
  706         switch (errno) {
  707         case ENOEXEC:
  708                 printf("%s contains a bad program header\n", image);
  709                 break;
  710         case ENOMEM:
  711                 printf("Not enough memory to load %s\n", image);
  712                 break;
  713         case EIO:
  714                 printf("Unsuspected EOF on %s\n", image);
  715         case 0:
  716                 /* No error or error already reported. */;
  717         }
  718         free(image);
  719 }
  720 
  721 /*
  722  * $PchId: bootimage.c,v 1.10 2002/02/27 19:39:09 philip Exp $
  723  */

Cache object: 318dc0c02e4c192670ad582855f1632d


[ 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.