source: trunk/minix/boot/installboot.c@ 10

Last change on this file since 10 was 9, checked in by Mattia Monga, 14 years ago

Minix 3.1.2a

File size: 21.2 KB
RevLine 
[9]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
43void report(char *label)
44/* installboot: label: No such file or directory */
45{
46 fprintf(stderr, "installboot: %s: %s\n", label, strerror(errno));
47}
48
49void fatal(char *label)
50{
51 report(label);
52 exit(1);
53}
54
55char *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
78void 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
88void 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
93long total_text= 0, total_data= 0, total_bss= 0;
94int making_image= 0;
95
96void 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
163void 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
174void 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
195void 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
268void 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
284void 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
336int rawfd; /* File descriptor to open device. */
337char *rawdev; /* Name of device. */
338
339void 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
354void 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
362int 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
417enum howto { FS, BOOT };
418
419void 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
687void 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('0', 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
784void 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
795int 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
807int 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 */
Note: See TracBrowser for help on using the repository browser.