bootimage.c

Go to the documentation of this file.
00001 /*      bootimage.c - Load an image and start it.       Author: Kees J. Bot
00002  *                                                              19 Jan 1992
00003  */
00004 #define BIOS            1       /* Can only be used under the BIOS. */
00005 #define nil 0
00006 #define _POSIX_SOURCE   1
00007 #define _MINIX          1
00008 #include <stddef.h>
00009 #include <sys/types.h>
00010 #include <sys/stat.h>
00011 #include <stdlib.h>
00012 #include <stdio.h>
00013 #include <limits.h>
00014 #include <string.h>
00015 #include <errno.h>
00016 #include <a.out.h>
00017 #include <minix/config.h>
00018 #include <minix/const.h>
00019 #include <minix/type.h>
00020 #include <minix/syslib.h>
00021 #include <kernel/const.h>
00022 #include <kernel/type.h>
00023 #include <ibm/partition.h>
00024 #include "rawfs.h"
00025 #include "image.h"
00026 #include "boot.h"
00027 
00028 static int block_size = 0;
00029 
00030 #define click_shift     clck_shft       /* 7 char clash with click_size. */
00031 
00032 /* Some kernels have extra features: */
00033 #define K_I386   0x0001 /* Make the 386 transition before you call me. */
00034 #define K_CLAIM  0x0002 /* I will acquire my own bss pages, thank you. */
00035 #define K_CHMEM  0x0004 /* This kernel listens to chmem for its stack size. */
00036 #define K_HIGH   0x0008 /* Load mm, fs, etc. in extended memory. */
00037 #define K_HDR    0x0010 /* No need to patch sizes, kernel uses the headers. */
00038 #define K_RET    0x0020 /* Returns to the monitor on reboot. */
00039 #define K_INT86  0x0040 /* Requires generic INT support. */
00040 #define K_MEML   0x0080 /* Pass a list of free memory. */
00041 #define K_BRET   0x0100 /* New monitor code on shutdown in boot parameters. */
00042 #define K_ALL    0x01FF /* All feature bits this monitor supports. */
00043 
00044 
00045 /* Data about the different processes. */
00046 
00047 #define PROCESS_MAX     16      /* Must match the space in kernel/mpx.x */
00048 #define KERNEL          0       /* The first process is the kernel. */
00049 #define FS              2       /* The third must be fs. */
00050 
00051 struct process {        /* Per-process memory adresses. */
00052         u32_t   entry;          /* Entry point. */
00053         u32_t   cs;             /* Code segment. */
00054         u32_t   ds;             /* Data segment. */
00055         u32_t   data;           /* To access the data segment. */
00056         u32_t   end;            /* End of this process, size = (end - cs). */
00057 } process[PROCESS_MAX];
00058 int n_procs;                    /* Number of processes. */
00059 
00060 /* Magic numbers in process' data space. */
00061 #define MAGIC_OFF       0       /* Offset of magic # in data seg. */
00062 #define CLICK_OFF       2       /* Offset in kernel text to click_shift. */
00063 #define FLAGS_OFF       4       /* Offset in kernel text to flags. */
00064 #define KERNEL_D_MAGIC  0x526F  /* Kernel magic number. */
00065 
00066 /* Offsets of sizes to be patched into kernel and fs. */
00067 #define P_SIZ_OFF       0       /* Process' sizes into kernel data. */
00068 #define P_INIT_OFF      4       /* Init cs & sizes into fs data. */
00069 
00070 
00071 #define between(a, c, z)        ((unsigned) ((c) - (a)) <= ((z) - (a)))
00072 
00073 void pretty_image(char *image)
00074 /* Pretty print the name of the image to load.  Translate '/' and '_' to
00075  * space, first letter goes uppercase.  An 'r' before a digit prints as
00076  * 'revision'.  E.g. 'minix/1.6.16r10' -> 'Minix 1.6.16 revision 10'.
00077  * The idea is that the part before the 'r' is the official Minix release
00078  * and after the 'r' you can put version numbers for your own changes.
00079  */
00080 {
00081         int up= 0, c;
00082 
00083         while ((c= *image++) != 0) {
00084                 if (c == '/' || c == '_') c= ' ';
00085 
00086                 if (c == 'r' && between('0', *image, '9')) {
00087                         printf(" revision ");
00088                         continue;
00089                 }
00090                 if (!up && between('a', c, 'z')) c= c - 'a' + 'A';
00091 
00092                 if (between('A', c, 'Z')) up= 1;
00093 
00094                 putch(c);
00095         }
00096 }
00097 
00098 void raw_clear(u32_t addr, u32_t count)
00099 /* Clear "count" bytes at absolute address "addr". */
00100 {
00101         static char zeros[128];
00102         u32_t dst;
00103         u32_t zct;
00104 
00105         zct= sizeof(zeros);
00106         if (zct > count) zct= count;
00107         raw_copy(addr, mon2abs(&zeros), zct);
00108         count-= zct;
00109 
00110         while (count > 0) {
00111                 dst= addr + zct;
00112                 if (zct > count) zct= count;
00113                 raw_copy(dst, addr, zct);
00114                 count-= zct;
00115                 zct*= 2;
00116         }
00117 }
00118 
00119 /* Align a to a multiple of n (a power of 2): */
00120 #define align(a, n)     (((u32_t)(a) + ((u32_t)(n) - 1)) & ~((u32_t)(n) - 1))
00121 unsigned click_shift;
00122 unsigned click_size;    /* click_size = Smallest kernel memory object. */
00123 unsigned k_flags;       /* Not all kernels are created equal. */
00124 u32_t reboot_code;      /* Obsolete reboot code return pointer. */
00125 
00126 int params2params(char *params, size_t psize)
00127 /* Repackage the environment settings for the kernel. */
00128 {
00129         size_t i, n;
00130         environment *e;
00131         char *name, *value;
00132         dev_t dev;
00133 
00134         i= 0;
00135         for (e= env; e != nil; e= e->next) {
00136                 name= e->name;
00137                 value= e->value;
00138 
00139                 if (!(e->flags & E_VAR)) continue;
00140 
00141                 if (e->flags & E_DEV) {
00142                         if ((dev= name2dev(value)) == -1) return 0;
00143                         value= ul2a10((u16_t) dev);
00144                 }
00145 
00146                 n= i + strlen(name) + 1 + strlen(value) + 1;
00147                 if (n < psize) {
00148                         strcpy(params + i, name);
00149                         strcat(params + i, "=");
00150                         strcat(params + i, value);
00151                 }
00152                 i= n;
00153         }
00154 
00155         if (!(k_flags & K_MEML)) {
00156                 /* Require old memory size variables. */
00157 
00158                 value= ul2a10((mem[0].base + mem[0].size) / 1024);
00159                 n= i + 7 + 1 + strlen(value) + 1;
00160                 if (n < psize) {
00161                         strcpy(params + i, "memsize=");
00162                         strcat(params + i, value);
00163                 }
00164                 i= n;
00165                 value= ul2a10(mem[1].size / 1024);
00166                 n= i + 7 + 1 + strlen(value) + 1;
00167                 if (n < psize) {
00168                         strcpy(params + i, "emssize=");
00169                         strcat(params + i, value);
00170                 }
00171                 i= n;
00172         }
00173 
00174         if (i >= psize) {
00175                 printf("Too many boot parameters\n");
00176                 return 0;
00177         }
00178         params[i]= 0;   /* End marked with empty string. */
00179         return 1;
00180 }
00181 
00182 void patch_sizes(void)
00183 /* Patch sizes of each process into kernel data space, kernel ds into kernel
00184  * text space, and sizes of init into data space of fs.  All the patched
00185  * numbers are based on the kernel click size, not hardware segments.
00186  */
00187 {
00188         u16_t text_size, data_size;
00189         int i;
00190         struct process *procp, *initp;
00191         u32_t doff;
00192 
00193         if (k_flags & K_HDR) return;    /* Uses the headers. */
00194 
00195         /* Patch text and data sizes of the processes into kernel data space.
00196          */
00197         doff= process[KERNEL].data + P_SIZ_OFF;
00198 
00199         for (i= 0; i < n_procs; i++) {
00200                 procp= &process[i];
00201                 text_size= (procp->ds - procp->cs) >> click_shift;
00202                 data_size= (procp->end - procp->ds) >> click_shift;
00203 
00204                 /* Two words per process, the text and data size: */
00205                 put_word(doff, text_size); doff+= 2;
00206                 put_word(doff, data_size); doff+= 2;
00207 
00208                 initp= procp;   /* The last process must be init. */
00209         }
00210 
00211         if (k_flags & (K_HIGH|K_MEML)) return;  /* Doesn't need FS patching. */
00212 
00213         /* Patch cs and sizes of init into fs data. */
00214         put_word(process[FS].data + P_INIT_OFF+0, initp->cs >> click_shift);
00215         put_word(process[FS].data + P_INIT_OFF+2, text_size);
00216         put_word(process[FS].data + P_INIT_OFF+4, data_size);
00217 }
00218 
00219 int selected(char *name)
00220 /* True iff name has no label or the proper label. */
00221 {
00222         char *colon, *label;
00223         int cmp;
00224 
00225         if ((colon= strchr(name, ':')) == nil) return 1;
00226         if ((label= b_value("label")) == nil) return 1;
00227 
00228         *colon= 0;
00229         cmp= strcmp(label, name);
00230         *colon= ':';
00231         return cmp == 0;
00232 }
00233 
00234 u32_t proc_size(struct image_header *hdr)
00235 /* Return the size of a process in sectors as found in an image. */
00236 {
00237         u32_t len= hdr->process.a_text;
00238 
00239         if (hdr->process.a_flags & A_PAL) len+= hdr->process.a_hdrlen;
00240         if (hdr->process.a_flags & A_SEP) len= align(len, SECTOR_SIZE);
00241         len= align(len + hdr->process.a_data, SECTOR_SIZE);
00242 
00243         return len >> SECTOR_SHIFT;
00244 }
00245 
00246 off_t image_off, image_size;
00247 u32_t (*vir2sec)(u32_t vsec);   /* Where is a sector on disk? */
00248 
00249 u32_t file_vir2sec(u32_t vsec)
00250 /* Translate a virtual sector number to an absolute disk sector. */
00251 {
00252         off_t blk;
00253 
00254         if(!block_size) { errno = 0;  return -1; }
00255 
00256         if ((blk= r_vir2abs(vsec / RATIO(block_size))) == -1) {
00257                 errno= EIO;
00258                 return -1;
00259         }
00260         return blk == 0 ? 0 : lowsec + blk * RATIO(block_size) + vsec % RATIO(block_size);
00261 }
00262 
00263 u32_t flat_vir2sec(u32_t vsec)
00264 /* Simply add an absolute sector offset to vsec. */
00265 {
00266         return lowsec + image_off + vsec;
00267 }
00268 
00269 char *get_sector(u32_t vsec)
00270 /* Read a sector "vsec" from the image into memory and return its address.
00271  * Return nil on error.  (This routine tries to read an entire track, so
00272  * the next request is usually satisfied from the track buffer.)
00273  */
00274 {
00275         u32_t sec;
00276         int r;
00277 #define SECBUFS 16
00278         static char buf[SECBUFS * SECTOR_SIZE];
00279         static size_t count;            /* Number of sectors in the buffer. */
00280         static u32_t bufsec;            /* First Sector now in the buffer. */
00281 
00282         if (vsec == 0) count= 0;        /* First sector; initialize. */
00283 
00284         if ((sec= (*vir2sec)(vsec)) == -1) return nil;
00285 
00286         if (sec == 0) {
00287                 /* A hole. */
00288                 count= 0;
00289                 memset(buf, 0, SECTOR_SIZE);
00290                 return buf;
00291         }
00292 
00293         /* Can we return a sector from the buffer? */
00294         if ((sec - bufsec) < count) {
00295                 return buf + ((size_t) (sec - bufsec) << SECTOR_SHIFT);
00296         }
00297 
00298         /* Not in the buffer. */
00299         count= 0;
00300         bufsec= sec;
00301 
00302         /* Read a whole track if possible. */
00303         while (++count < SECBUFS && !dev_boundary(bufsec + count)) {
00304                 vsec++;
00305                 if ((sec= (*vir2sec)(vsec)) == -1) break;
00306 
00307                 /* Consecutive? */
00308                 if (sec != bufsec + count) break;
00309         }
00310 
00311         /* Actually read the sectors. */
00312         if ((r= readsectors(mon2abs(buf), bufsec, count)) != 0) {
00313                 readerr(bufsec, r);
00314                 count= 0;
00315                 errno= 0;
00316                 return nil;
00317         }
00318         return buf;
00319 }
00320 
00321 int get_clickshift(u32_t ksec, struct image_header *hdr)
00322 /* Get the click shift and special flags from kernel text. */
00323 {
00324         char *textp;
00325 
00326         if ((textp= get_sector(ksec)) == nil) return 0;
00327 
00328         if (hdr->process.a_flags & A_PAL) textp+= hdr->process.a_hdrlen;
00329         click_shift= * (u16_t *) (textp + CLICK_OFF);
00330         k_flags= * (u16_t *) (textp + FLAGS_OFF);
00331 
00332         if ((k_flags & ~K_ALL) != 0) {
00333                 printf("%s requires features this monitor doesn't offer\n",
00334                         hdr->name);
00335                 return 0;
00336         }
00337 
00338         if (click_shift < HCLICK_SHIFT || click_shift > 16) {
00339                 printf("%s click size is bad\n", hdr->name);
00340                 errno= 0;
00341                 return 0;
00342         }
00343 
00344         click_size= 1 << click_shift;
00345 
00346         return 1;
00347 }
00348 
00349 int get_segment(u32_t *vsec, long *size, u32_t *addr, u32_t limit)
00350 /* Read *size bytes starting at virtual sector *vsec to memory at *addr. */
00351 {
00352         char *buf;
00353         size_t cnt, n;
00354 
00355         cnt= 0;
00356         while (*size > 0) {
00357                 if (cnt == 0) {
00358                         if ((buf= get_sector((*vsec)++)) == nil) return 0;
00359                         cnt= SECTOR_SIZE;
00360                 }
00361                 if (*addr + click_size > limit) { errno= ENOMEM; return 0; }
00362                 n= click_size;
00363                 if (n > cnt) n= cnt;
00364                 raw_copy(*addr, mon2abs(buf), n);
00365                 *addr+= n;
00366                 *size-= n;
00367                 buf+= n;
00368                 cnt-= n;
00369         }
00370 
00371         /* Zero extend to a click. */
00372         n= align(*addr, click_size) - *addr;
00373         raw_clear(*addr, n);
00374         *addr+= n;
00375         *size-= n;
00376         return 1;
00377 }
00378 
00379 void exec_image(char *image)
00380 /* Get a Minix image into core, patch it up and execute. */
00381 {
00382         char *delayvalue;
00383         int i;
00384         struct image_header hdr;
00385         char *buf;
00386         u32_t vsec, addr, limit, aout, n;
00387         struct process *procp;          /* Process under construction. */
00388         long a_text, a_data, a_bss, a_stack;
00389         int banner= 0;
00390         long processor= a2l(b_value("processor"));
00391         u16_t mode;
00392         char *console;
00393         char params[SECTOR_SIZE];
00394         extern char *sbrk(int);
00395 
00396         /* The stack is pretty deep here, so check if heap and stack collide. */
00397         (void) sbrk(0);
00398 
00399         printf("\nLoading ");
00400         pretty_image(image);
00401         printf(".\n\n");
00402 
00403         vsec= 0;                        /* Load this sector from image next. */
00404         addr= mem[0].base;              /* Into this memory block. */
00405         limit= mem[0].base + mem[0].size;
00406         if (limit > caddr) limit= caddr;
00407 
00408         /* Allocate and clear the area where the headers will be placed. */
00409         aout = (limit -= PROCESS_MAX * A_MINHDR);
00410 
00411         /* Clear the area where the headers will be placed. */
00412         raw_clear(aout, PROCESS_MAX * A_MINHDR);
00413 
00414         /* Read the many different processes: */
00415         for (i= 0; vsec < image_size; i++) {
00416                 if (i == PROCESS_MAX) {
00417                         printf("There are more then %d programs in %s\n",
00418                                 PROCESS_MAX, image);
00419                         errno= 0;
00420                         return;
00421                 }
00422                 procp= &process[i];
00423 
00424                 /* Read header. */
00425                 for (;;) {
00426                         if ((buf= get_sector(vsec++)) == nil) return;
00427 
00428                         memcpy(&hdr, buf, sizeof(hdr));
00429 
00430                         if (BADMAG(hdr.process)) { errno= ENOEXEC; return; }
00431 
00432                         /* Check the optional label on the process. */
00433                         if (selected(hdr.name)) break;
00434 
00435                         /* Bad label, skip this process. */
00436                         vsec+= proc_size(&hdr);
00437                 }
00438 
00439                 /* Sanity check: an 8086 can't run a 386 kernel. */
00440                 if (hdr.process.a_cpu == A_I80386 && processor < 386) {
00441                         printf("You can't run a 386 kernel on this 80%ld\n",
00442                                 processor);
00443                         errno= 0;
00444                         return;
00445                 }
00446 
00447                 /* Get the click shift from the kernel text segment. */
00448                 if (i == KERNEL) {
00449                         if (!get_clickshift(vsec, &hdr)) return;
00450                         addr= align(addr, click_size);
00451                 }
00452 
00453                 /* Save a copy of the header for the kernel, with a_syms
00454                  * misused as the address where the process is loaded at.
00455                  */
00456                 hdr.process.a_syms= addr;
00457                 raw_copy(aout + i * A_MINHDR, mon2abs(&hdr.process), A_MINHDR);
00458 
00459                 if (!banner) {
00460                         printf("     cs       ds     text     data      bss");
00461                         if (k_flags & K_CHMEM) printf("    stack");
00462                         putch('\n');
00463                         banner= 1;
00464                 }
00465 
00466                 /* Segment sizes. */
00467                 a_text= hdr.process.a_text;
00468                 a_data= hdr.process.a_data;
00469                 a_bss= hdr.process.a_bss;
00470                 if (k_flags & K_CHMEM) {
00471                         a_stack= hdr.process.a_total - a_data - a_bss;
00472                         if (!(hdr.process.a_flags & A_SEP)) a_stack-= a_text;
00473                 } else {
00474                         a_stack= 0;
00475                 }
00476 
00477                 /* Collect info about the process to be. */
00478                 procp->cs= addr;
00479 
00480                 /* Process may be page aligned so that the text segment contains
00481                  * the header, or have an unmapped zero page against vaxisms.
00482                  */
00483                 procp->entry= hdr.process.a_entry;
00484                 if (hdr.process.a_flags & A_PAL) a_text+= hdr.process.a_hdrlen;
00485                 if (hdr.process.a_flags & A_UZP) procp->cs-= click_size;
00486 
00487                 /* Separate I&D: two segments.  Common I&D: only one. */
00488                 if (hdr.process.a_flags & A_SEP) {
00489                         /* Read the text segment. */
00490                         if (!get_segment(&vsec, &a_text, &addr, limit)) return;
00491 
00492                         /* The data segment follows. */
00493                         procp->ds= addr;
00494                         if (hdr.process.a_flags & A_UZP) procp->ds-= click_size;
00495                         procp->data= addr;
00496                 } else {
00497                         /* Add text to data to form one segment. */
00498                         procp->data= addr + a_text;
00499                         procp->ds= procp->cs;
00500                         a_data+= a_text;
00501                 }
00502 
00503                 /* Read the data segment. */
00504                 if (!get_segment(&vsec, &a_data, &addr, limit)) return;
00505 
00506                 /* Make space for bss and stack unless... */
00507                 if (i != KERNEL && (k_flags & K_CLAIM)) a_bss= a_stack= 0;
00508 
00509                 printf("%07lx  %07lx %8ld %8ld %8ld",
00510                         procp->cs, procp->ds,
00511                         hdr.process.a_text, hdr.process.a_data,
00512                         hdr.process.a_bss
00513                 );
00514                 if (k_flags & K_CHMEM) printf(" %8ld", a_stack);
00515 
00516                 printf("  %s\n", hdr.name);
00517 
00518                 /* Note that a_data may be negative now, but we can look at it
00519                  * as -a_data bss bytes.
00520                  */
00521 
00522                 /* Compute the number of bss clicks left. */
00523                 a_bss+= a_data;
00524                 n= align(a_bss, click_size);
00525                 a_bss-= n;
00526 
00527                 /* Zero out bss. */
00528                 if (addr + n > limit) { errno= ENOMEM; return; }
00529                 raw_clear(addr, n);
00530                 addr+= n;
00531 
00532                 /* And the number of stack clicks. */
00533                 a_stack+= a_bss;
00534                 n= align(a_stack, click_size);
00535                 a_stack-= n;
00536 
00537                 /* Add space for the stack. */
00538                 addr+= n;
00539 
00540                 /* Process endpoint. */
00541                 procp->end= addr;
00542 
00543                 if (i == 0 && (k_flags & K_HIGH)) {
00544                         /* Load the rest in extended memory. */
00545                         addr= mem[1].base;
00546                         limit= mem[1].base + mem[1].size;
00547                 }
00548         }
00549 
00550         if ((n_procs= i) == 0) {
00551                 printf("There are no programs in %s\n", image);
00552                 errno= 0;
00553                 return;
00554         }
00555 
00556         /* Check the kernel magic number. */
00557         if (get_word(process[KERNEL].data + MAGIC_OFF) != KERNEL_D_MAGIC) {
00558                 printf("Kernel magic number is incorrect\n");
00559                 errno= 0;
00560                 return;
00561         }
00562 
00563         /* Patch sizes, etc. into kernel data. */
00564         patch_sizes();
00565 
00566 #if !DOS
00567         if (!(k_flags & K_MEML)) {
00568                 /* Copy the a.out headers to the old place. */
00569                 raw_copy(HEADERPOS, aout, PROCESS_MAX * A_MINHDR);
00570         }
00571 #endif
00572 
00573         /* Do delay if wanted. */
00574         if((delayvalue = b_value("bootdelay")) != nil > 0) {
00575                 delay(delayvalue);
00576         }
00577 
00578         /* Run the trailer function just before starting Minix. */
00579         if (!run_trailer()) { errno= 0; return; }
00580 
00581         /* Translate the boot parameters to what Minix likes best. */
00582         if (!params2params(params, sizeof(params))) { errno= 0; return; }
00583 
00584         /* Set the video to the required mode. */
00585         if ((console= b_value("console")) == nil || (mode= a2x(console)) == 0) {
00586                 mode= strcmp(b_value("chrome"), "color") == 0 ? COLOR_MODE :
00587                                                                 MONO_MODE;
00588         }
00589         set_mode(mode);
00590 
00591         /* Close the disk. */
00592         (void) dev_close();
00593 
00594         /* Minix. */
00595         minix(process[KERNEL].entry, process[KERNEL].cs,
00596                         process[KERNEL].ds, params, sizeof(params), aout);
00597 
00598         if (!(k_flags & K_BRET)) {
00599                 extern u32_t reboot_code;
00600                 raw_copy(mon2abs(params), reboot_code, sizeof(params));
00601         }
00602         parse_code(params);
00603 
00604         /* Return from Minix.  Things may have changed, so assume nothing. */
00605         fsok= -1;
00606         errno= 0;
00607 
00608         /* Read leftover character, if any. */
00609         scan_keyboard();
00610 }
00611 
00612 ino_t latest_version(char *version, struct stat *stp)
00613 /* Recursively read the current directory, selecting the newest image on
00614  * the way up.  (One can't use r_stat while reading a directory.)
00615  */
00616 {
00617         char name[NAME_MAX + 1];
00618         ino_t ino, newest;
00619         time_t mtime;
00620 
00621         if ((ino= r_readdir(name)) == 0) { stp->st_mtime= 0; return 0; }
00622 
00623         newest= latest_version(version, stp);
00624         mtime= stp->st_mtime;
00625         r_stat(ino, stp);
00626 
00627         if (S_ISREG(stp->st_mode) && stp->st_mtime > mtime) {
00628                 newest= ino;
00629                 strcpy(version, name);
00630         } else {
00631                 stp->st_mtime= mtime;
00632         }
00633         return newest;
00634 }
00635 
00636 char *select_image(char *image)
00637 /* Look image up on the filesystem, if it is a file then we're done, but
00638  * if its a directory then we want the newest file in that directory.  If
00639  * it doesn't exist at all, then see if it is 'number:number' and get the
00640  * image from that absolute offset off the disk.
00641  */
00642 {
00643         ino_t image_ino;
00644         struct stat st;
00645 
00646         image= strcpy(malloc((strlen(image) + 1 + NAME_MAX + 1)
00647                                                  * sizeof(char)), image);
00648 
00649         fsok= r_super(&block_size) != 0;
00650         if (!fsok || (image_ino= r_lookup(ROOT_INO, image)) == 0) {
00651                 char *size;
00652 
00653                 if (numprefix(image, &size) && *size++ == ':'
00654                                                 && numeric(size)) {
00655                         vir2sec= flat_vir2sec;
00656                         image_off= a2l(image);
00657                         image_size= a2l(size);
00658                         strcpy(image, "Minix");
00659                         return image;
00660                 }
00661                 if (!fsok)
00662                         printf("No image selected\n");
00663                 else
00664                         printf("Can't load %s: %s\n", image, unix_err(errno));
00665                 goto bail_out;
00666         }
00667 
00668         r_stat(image_ino, &st);
00669         if (!S_ISREG(st.st_mode)) {
00670                 char *version= image + strlen(image);
00671                 char dots[NAME_MAX + 1];
00672 
00673                 if (!S_ISDIR(st.st_mode)) {
00674                         printf("%s: %s\n", image, unix_err(ENOTDIR));
00675                         goto bail_out;
00676                 }
00677                 (void) r_readdir(dots);
00678                 (void) r_readdir(dots); /* "." & ".." */
00679                 *version++= '/';
00680                 *version= 0;
00681                 if ((image_ino= latest_version(version, &st)) == 0) {
00682                         printf("There are no images in %s\n", image);
00683                         goto bail_out;
00684                 }
00685                 r_stat(image_ino, &st);
00686         }
00687         vir2sec= file_vir2sec;
00688         image_size= (st.st_size + SECTOR_SIZE - 1) >> SECTOR_SHIFT;
00689         return image;
00690 bail_out:
00691         free(image);
00692         return nil;
00693 }
00694 
00695 void bootminix(void)
00696 /* Load Minix and run it.  (Given the size of this program it is surprising
00697  * that it ever gets to that.)
00698  */
00699 {
00700         char *image;
00701 
00702         if ((image= select_image(b_value("image"))) == nil) return;
00703 
00704         exec_image(image);
00705 
00706         switch (errno) {
00707         case ENOEXEC:
00708                 printf("%s contains a bad program header\n", image);
00709                 break;
00710         case ENOMEM:
00711                 printf("Not enough memory to load %s\n", image);
00712                 break;
00713         case EIO:
00714                 printf("Unsuspected EOF on %s\n", image);
00715         case 0:
00716                 /* No error or error already reported. */;
00717         }
00718         free(image);
00719 }
00720 
00721 /*
00722  * $PchId: bootimage.c,v 1.10 2002/02/27 19:39:09 philip Exp $
00723  */

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