9000 /* installboot 2.0 -
Make a device bootable Author:
Kees J. Bot
9001 *
21 Dec 1991
9002 *
9003 * Either make a device bootable or make
an image from kernel, mm, fs, etc.
9004 */
9005 #define nil 0
9006 #define _POSIX_SOURCE 1
9007 #define _MINIX
1
9008 #include <stdio.h>
9009 #include <stddef.h>
9010 #include <sys/types.h>
9011 #include <sys/stat.h>
9012 #include <sys/ioctl.h>
9013 #include <stdlib.h>
9014 #include <unistd.h>
9015 #include <fcntl.h>
9016 #include <string.h>
9017 #include <errno.h>
9018 #include <a.out.h>
9019 #include <minix/config.h>
9020 #include <minix/const.h>
9021 #include <minix/partition.h>
9022 #include "rawfs.h"
9023 #include "image.h"
9024
9025 #define BOOTBLOCK
0 /* Of course */
9026 #define SECTOR_SIZE 512
/* Disk sector size. */
9027 #define RATIO
(BLOCK_SIZE/SECTOR_SIZE)
9028 #define SIGNATURE
0xAA55 /* Boot block signature. */
9029 #define BOOT_MAX
64 /* Absolute maximum size of secondary
boot */
9030 #define JMP
0xEB /* Opcode of a short jump */
9031 #define JMPOFFM
0x01 /* Jump offset in normal master bootstrap */
9032 #define JMPOFFE
0x02 /* Jump offset in extended bootstrap */
9033 #define XOR
0x31 /* Jumping to an XOR instruction? */
9034 #define SIGPOS
510 /* Where to put signature word. */
9035 #define PARTPOS
446 /* Offset to the partition table in a master
9036
* boot block.
9037
*/
9038
9039 #define between(a,
c, z) ((unsigned) ((c) - (a))
<= ((z) - (a)))
9040 #define control(c)
between('\0', (c), '\37')
9041
9042 #if !__minix_vmd
9043 #define cv64ul(i)
(i)
9044 #endif
9045
9046 void report(char *label)
9047 /* installboot: label: No such file or directory
*/
9048 {
9049
fprintf(stderr, "installboot: %s: %s\n", label, strerror(errno));
9050 }
9051
9052 void fatal(char *label)
9053 {
9054
report(label);
9055
exit(1);
9056 }
9057
9058 char *basename(char *name)
9059 /* Return the last component of name, stripping
trailing slashes from name.
9060 * Precondition: name != "/". If name
is prefixed by a label, then the
9061 * label is copied to the basename too.
9062 */
9063 {
9064
static char base[IM_NAME_MAX];
9065
char *p, *bp= base;
9066
9067
if ((p= strchr(name, ':')) != nil) {
9068
while (name <= p && bp < base + IM_NAME_MAX - 1)
9069
*bp++ = *name++;
9070 }
9071
for (;;) {
9072
if ((p= strrchr(name, '/')) == nil) { p= name;
break; }
9073
if (*++p != 0) break;
9074
*--p= 0;
9075 }
9076
while (*p != 0 && bp < base + IM_NAME_MAX - 1) *bp++ = *p++;
9077
*bp= 0;
9078
return base;
9079 }
9080
9081 void bread(FILE *f, char
*name, void *buf, size_t len)
9082 /* Read len bytes. Don't dare return without
them. */
9083 {
9084
if (len > 0 && fread(buf, len, 1, f) != 1) {
9085
if (ferror(f)) fatal(name);
9086
fprintf(stderr, "installboot: Unsuspected EOF on %s\n", name);
9087
exit(1);
9088 }
9089 }
9090
9091 void bwrite(FILE *f,
char *name, void *buf, size_t len)
9092 {
9093
if (len > 0 && fwrite(buf, len, 1, f) != 1) fatal(name);
9094 }
9095
9096 long total_text=
0, total_data= 0, total_bss= 0;
9097 int making_image= 0;
9098
9099 void read_header(int
talk, char *proc, FILE *procf, struct image_header *ihdr)
9100 /* Read the a.out header of a program and check
it. If procf happens to be
9101 * nil then the header is already in *image_hdr
and need only be checked.
9102 */
9103 {
9104
int n, big= 0;
9105
static int banner= 0;
9106
struct exec *phdr= &ihdr->process;
9107
9108
if (procf == nil) {
9109
/* Header already present. */
9110
n= phdr->a_hdrlen;
9111 }
else {
9112
memset(ihdr, 0, sizeof(*ihdr));
9113
9114
/* Put the basename of proc in the header. */
9115
strncpy(ihdr->name, basename(proc), IM_NAME_MAX);
9116
9117
/* Read the header. */
9118
n= fread(phdr, sizeof(char), A_MINHDR, procf);
9119
if (ferror(procf)) fatal(proc);
9120 }
9121
9122
if (n < A_MINHDR || BADMAG(*phdr)) {
9123
fprintf(stderr, "installboot: %s is not an executable\n", proc);
9124
exit(1);
9125 }
9126
9127
/* Get the rest of the exec header. */
9128
if (procf != nil) {
9129
bread(procf, proc, ((char *) phdr) + A_MINHDR,
9130
phdr->a_hdrlen - A_MINHDR);
9131 }
9132
9133
if (talk && !banner) {
9134
printf(" text data
bss size\n");
9135
banner= 1;
9136 }
9137
9138
if (talk) {
9139
printf("%8ld%8ld%8ld%9ld %s\n",
9140
phdr->a_text, phdr->a_data, phdr->a_bss,
9141
phdr->a_text + phdr->a_data + phdr->a_bss, proc);
9142 }
9143
total_text+= phdr->a_text;
9144
total_data+= phdr->a_data;
9145
total_bss+= phdr->a_bss;
9146
9147
if (phdr->a_cpu == A_I8086) {
9148
long data= phdr->a_data + phdr->a_bss;
9149
9150
if (!(phdr->a_flags & A_SEP)) data+= phdr->a_text;
9151
9152
if (phdr->a_text >= 65536) big|= 1;
9153
if (data >= 65536) big|= 2;
9154 }
9155
if (big) {
9156
fprintf(stderr,
9157
"%s will crash, %s%s%s segment%s larger then 64K\n",
9158
proc,
9159
big & 1 ? "text" : "",
9160
big == 3 ? " and " : "",
9161
big & 2 ? "data" : "",
9162
big == 3 ? "s are" : " is");
9163 }
9164 }
9165
9166 void padimage(char
*image, FILE *imagef, int n)
9167 /* Add n zeros to image to pad it to a sector
boundary. */
9168 {
9169
while (n > 0) {
9170
if (putc(0, imagef) == EOF) fatal(image);
9171
n--;
9172 }
9173 }
9174
9175 #define align(n)
(((n) + ((SECTOR_SIZE) - 1)) & ~((SECTOR_SIZE) - 1))
9176
9177 void copyexec(char
*proc, FILE *procf, char *image, FILE *imagef, long n)
9178 /* Copy n bytes from proc to image padded to fill
a sector. */
9179 {
9180
int pad, c;
9181
9182
/* Compute number of padding bytes. */
9183
pad= align(n) - n;
9184
9185
while (n > 0) {
9186
if ((c= getc(procf)) == EOF) {
9187
if (ferror(procf)) fatal(proc);
9188
fprintf(stderr, "installboot: premature EOF on %s\n",
9189
proc);
9190
exit(1);
9191
}
9192
if (putc(c, imagef) == EOF) fatal(image);
9193
n--;
9194 }
9195
padimage(image, imagef, pad);
9196 }
9197
9198 void make_image(char
*image, char **procv)
9199 /* Collect a set of files in an image, each "segment"
is nicely padded out
9200 * to SECTOR_SIZE, so it may be read from
disk into memory without trickery.
9201 */
9202 {
9203
FILE *imagef, *procf;
9204
char *proc, *file;
9205
int procn;
9206
struct image_header ihdr;
9207
struct exec phdr;
9208
struct stat st;
9209
9210
making_image= 1;
9211
9212
if ((imagef= fopen(image, "w")) == nil) fatal(image);
9213
9214
for (procn= 0; (proc= *procv++) != nil; procn++) {
9215
/* Remove the label from the file name. */
9216
if ((file= strchr(proc, ':')) != nil) file++; else file= proc;
9217
9218
/* Real files please, may need to seek. */
9219
if (stat(file, &st) < 0
9220
|| (errno= EISDIR, !S_ISREG(st.st_mode))
9221
|| (procf= fopen(file, "r")) == nil
9222
) fatal(proc);
9223
9224
/* Read a.out header. */
9225
read_header(1, proc, procf, &ihdr);
9226
9227
/* Scratch. */
9228
phdr= ihdr.process;
9229
9230
/* The symbol table is always stripped off. */
9231
ihdr.process.a_syms= 0;
9232
ihdr.process.a_flags &= ~A_NSYM;
9233
9234
/* Write header padded to fill a sector */
9235
bwrite(imagef, image, &ihdr, sizeof(ihdr));
9236
9237
padimage(image, imagef, SECTOR_SIZE - sizeof(ihdr));
9238
9239
/* A page aligned executable needs the header in text. */
9240
if (phdr.a_flags & A_PAL) {
9241
rewind(procf);
9242
phdr.a_text+= phdr.a_hdrlen;
9243
}
9244
9245
/* Copy text and data of proc to image. */
9246
if (phdr.a_flags & A_SEP) {
9247
/* Separate I&D: pad text & data separately. */
9248
9249
copyexec(proc, procf, image, imagef, phdr.a_text);
9250
copyexec(proc, procf, image, imagef, phdr.a_data);
9251
} else {
9252
/* Common I&D: keep text and data together. */
9253
9254
copyexec(proc, procf, image, imagef,
9255
phdr.a_text + phdr.a_data);
9256
}
9257
9258
/* Done with proc. */
9259
(void) fclose(procf);
9260 }
9261
/* Done with image. */
9262
9263
if (fclose(imagef) == EOF) fatal(image);
9264
9265
printf(" ------ ------ ------ -------\n");
9266
printf("%8ld%8ld%8ld%9ld total\n",
9267
total_text, total_data, total_bss,
9268
total_text + total_data + total_bss);
9269 }
9270
9271 void extractexec(FILE
*imagef, char *image, FILE *procf, char *proc,
9272
long count, off_t *alen)
9273 /* Copy a segment of an executable. It is
padded to a sector in image. */
9274 {
9275
char buf[SECTOR_SIZE];
9276
9277
while (count > 0) {
9278
bread(imagef, image, buf, sizeof(buf));
9279
*alen-= sizeof(buf);
9280
9281
bwrite(procf, proc, buf,
9282
count < sizeof(buf) ? (size_t) count : sizeof(buf));
9283
count-= sizeof(buf);
9284 }
9285 }
9286
9287 void extract_image(char
*image)
9288 /* Extract the executables from an image. */
9289 {
9290
FILE *imagef, *procf;
9291
off_t len;
9292
struct stat st;
9293
struct image_header ihdr;
9294
struct exec phdr;
9295
char buf[SECTOR_SIZE];
9296
9297
if (stat(image, &st) < 0) fatal(image);
9298
9299
/* Size of the image. */
9300
len= S_ISREG(st.st_mode) ? st.st_size : -1;
9301
9302
if ((imagef= fopen(image, "r")) == nil) fatal(image);
9303
9304
while (len != 0) {
9305
/* Extract a program, first sector is an extended header. */
9306
bread(imagef, image, buf, sizeof(buf));
9307
len-= sizeof(buf);
9308
9309
memcpy(&ihdr, buf, sizeof(ihdr));
9310
phdr= ihdr.process;
9311
9312
/* Check header. */
9313
read_header(1, ihdr.name, nil, &ihdr);
9314
9315
if ((procf= fopen(ihdr.name, "w")) == nil) fatal(ihdr.name);
9316
9317
if (phdr.a_flags & A_PAL) {
9318
/* A page aligned process contains a header in text. */
9319
phdr.a_text+= phdr.a_hdrlen;
9320
} else {
9321
bwrite(procf, ihdr.name, &ihdr.process, phdr.a_hdrlen);
9322
}
9323
9324
/* Extract text and data segments. */
9325
if (phdr.a_flags & A_SEP) {
9326
extractexec(imagef, image, procf, ihdr.name,
9327
phdr.a_text, &len);
9328
extractexec(imagef, image, procf, ihdr.name,
9329
phdr.a_data, &len);
9330
} else {
9331
extractexec(imagef, image, procf, ihdr.name,
9332
phdr.a_text + phdr.a_data, &len);
9333
}
9334
9335
if (fclose(procf) == EOF) fatal(ihdr.name);
9336 }
9337 }
9338
9339 int rawfd;
/* File descriptor to open device. */
9340 char *rawdev; /* Name of device. */
9341
9342 void readblock(off_t
blk, char *buf)
9343 /* For rawfs, so that it can read blocks. */
9344 {
9345
int n;
9346
9347
if (lseek(rawfd, blk * BLOCK_SIZE, SEEK_SET) < 0
9348
|| (n= read(rawfd, buf, BLOCK_SIZE)) < 0
9349
) fatal(rawdev);
9350
9351
if (n < BLOCK_SIZE) {
9352
fprintf(stderr, "installboot: unexpected EOF on %s\n", rawdev);
9353
exit(1);
9354 }
9355 }
9356
9357 void writeblock(off_t
blk, char *buf)
9358 /* Add a function to write blocks for local use.
*/
9359 {
9360
if (lseek(rawfd, blk * BLOCK_SIZE, SEEK_SET) < 0
9361
|| write(rawfd, buf, BLOCK_SIZE) < 0
9362
) fatal(rawdev);
9363 }
9364
9365 int raw_install(char
*file, off_t *start, off_t *len)
9366 /* Copy bootcode or an image to the boot device
at the given absolute disk
9367 * block number. This "raw" installation
is used to place bootcode and
9368 * image on a disk without a filesystem to
make a simple boot disk. Useful
9369 * in automated scripts for J. Random User.
9370 * Note: *len == 0 when an image is read.
It is set right afterwards.
9371 */
9372 {
9373
static char buf[BLOCK_SIZE]; /* Nonvolatile block buffer.
*/
9374
FILE *f;
9375
off_t sec;
9376
unsigned long devsize;
9377
static int banner= 0;
9378
struct partition entry;
9379
9380
/* See if the device has a maximum size. */
9381
devsize= -1;
9382
if (ioctl(rawfd, DIOCGETP, &entry) == 0) devsize= cv64ul(entry.size);
9383
9384
if ((f= fopen(file, "r")) == nil) fatal(file);
9385
9386
/* Copy sectors from file onto the boot device. */
9387
sec= *start;
9388
do {
9389
int off= sec % RATIO;
9390
9391
if (fread(buf + off * SECTOR_SIZE, 1, SECTOR_SIZE, f) == 0)
9392
break;
9393
9394
if (sec >= devsize) {
9395
fprintf(stderr,
9396
"installboot: %s can't be attached to %s\n",
9397
file, rawdev);
9398
return 0;
9399
}
9400
9401
if (off == RATIO - 1) writeblock(sec / RATIO, buf);
9402 }
while (++sec != *start + *len);
9403
9404
if (ferror(f)) fatal(file);
9405
(void) fclose(f);
9406
9407
/* Write a partial block, this may be the last image. */
9408
if (sec % RATIO != 0) writeblock(sec / RATIO, buf);
9409
9410
if (!banner) {
9411
printf(" sector length\n");
9412
banner= 1;
9413 }
9414
*len= sec - *start;
9415
printf("%8ld%8ld %s\n", *start, *len, file);
9416
*start= sec;
9417
return 1;
9418 }
9419
9420 enum howto {
FS, BOOT };
9421
9422 void make_bootable(enum
howto how, char *device, char *bootblock,
9423
char *bootcode, char **imagev)
9424 /* Install bootblock on the bootsector of device
with the disk addresses to
9425 * bootcode patched into the data segment
of bootblock. "How" tells if there
9426 * should or shoudn't be a file system on
the disk. The images in the imagev
9427 * vector are added to the end of the device.
9428 */
9429 {
9430
char buf[BLOCK_SIZE + 256], *adrp, *parmp;
9431
struct fileaddr {
9432
off_t address;
9433
int count;
9434 }
bootaddr[BOOT_MAX + 1], *bap= bootaddr;
9435
struct exec boothdr;
9436
struct image_header dummy;
9437
struct stat st;
9438
ino_t ino;
9439
off_t sector, max_sector;
9440
FILE *bootf;
9441
off_t addr, fssize, pos, len;
9442
char *labels, *label, *image;
9443
int nolabel;
9444
9445
/* Open device and set variables for readblock. */
9446
if ((rawfd= open(rawdev= device, O_RDWR)) < 0) fatal(device);
9447
9448
/* Read and check the superblock. */
9449
fssize= r_super();
9450
9451
switch (how) {
9452
case FS:
9453
if (fssize == 0) {
9454
fprintf(stderr,
9455
"installboot: %s is not a Minix file system\n",
9456
device);
9457
exit(1);
9458
}
9459
break;
9460
case BOOT:
9461
if (fssize != 0) {
9462
int s;
9463
printf("%s contains a file system!\n", device);
9464
printf("Scribbling in 10 seconds");
9465
for (s= 0; s < 10; s++) {
9466
fputc('.', stdout);
9467
fflush(stdout);
9468
sleep(1);
9469
}
9470
fputc('\n', stdout);
9471
}
9472
fssize= 1; /* Just a boot block. */
9473 }
9474
9475
if (how == FS) {
9476
/* See if the boot code can be found on the file system. */
9477
if ((ino= r_lookup(ROOT_INO, bootcode)) == 0) {
9478
if (errno != ENOENT) fatal(bootcode);
9479
}
9480 }
else {
9481
/* Boot code must be attached at the end. */
9482
ino= 0;
9483 }
9484
9485
if (ino == 0) {
9486
/* For a raw installation, we need to copy the boot code onto
9487
* the device, so we need to look at the file to be copied.
9488
*/
9489
if (stat(bootcode, &st) < 0) fatal(bootcode);
9490
9491
if ((bootf= fopen(bootcode, "r")) == nil) fatal(bootcode);
9492 }
else {
9493
/* Boot code is present in the file system. */
9494
r_stat(ino, &st);
9495
9496
/* Get the header from the first block. */
9497
if ((addr= r_vir2abs((off_t) 0)) == 0) {
9498
boothdr.a_magic[0]= !A_MAGIC0;
9499
} else {
9500
readblock(addr, buf);
9501
memcpy(&boothdr, buf, sizeof(struct exec));
9502
}
9503
bootf= nil;
9504
dummy.process= boothdr;
9505 }
9506
/* See if it is an executable (read_header does the check). */
9507
read_header(0, bootcode, bootf, &dummy);
9508
boothdr= dummy.process;
9509
9510
if (bootf != nil) fclose(bootf);
9511
9512
/* Get all the sector addresses of the secondary boot code. */
9513
max_sector= (boothdr.a_hdrlen + boothdr.a_text
9514
+ boothdr.a_data + SECTOR_SIZE - 1) / SECTOR_SIZE;
9515
9516
if (max_sector > BOOT_MAX * RATIO) {
9517
fprintf(stderr, "installboot: %s is way too big\n", bootcode);
9518
exit(0);
9519 }
9520
9521
/* Determine the addresses to the boot code to be patched into the
9522
* boot block.
9523
*/
9524
bap->count= 0; /* Trick to get the address recording going. */
9525
9526
for (sector= 0; sector < max_sector; sector++) {
9527
if (ino == 0) {
9528
addr= fssize + (sector / RATIO);
9529
} else
9530
if ((addr= r_vir2abs(sector / RATIO)) == 0) {
9531
fprintf(stderr, "installboot: %s has holes!\n",
9532
bootcode);
9533
exit(1);
9534
}
9535
addr= (addr * RATIO) + (sector % RATIO);
9536
9537
/* First address of the addresses array? */
9538
if (bap->count == 0) bap->address= addr;
9539
9540
/* Paste sectors together in a multisector read. */
9541
if (bap->address + bap->count == addr)
9542
bap->count++;
9543
else {
9544
/* New address. */
9545
bap++;
9546
bap->address= addr;
9547
bap->count= 1;
9548
}
9549 }
9550
(++bap)->count= 0; /* No more. */
9551
9552
/* Get the boot block and patch the pieces in. */
9553
readblock(BOOTBLOCK, buf);
9554
9555
if ((bootf= fopen(bootblock, "r")) == nil) fatal(bootblock);
9556
9557
read_header(0, bootblock, bootf, &dummy);
9558
boothdr= dummy.process;
9559
9560
if (boothdr.a_text + boothdr.a_data +
9561
4 * (bap - bootaddr) + 1 > SIGPOS) {
9562
fprintf(stderr,
9563
"installboot: %s + addresses to %s don't fit in the boot sector\n",
9564
bootblock, bootcode);
9565
fprintf(stderr,
9566
"You can try copying/reinstalling %s to defragment it\n",
9567
bootcode);
9568
exit(1);
9569 }
9570
9571
/* All checks out right. Read bootblock into the boot block! */
9572
bread(bootf, bootblock, buf, boothdr.a_text + boothdr.a_data);
9573
(void) fclose(bootf);
9574
9575
/* Patch the addresses in. */
9576
adrp= buf + (int) (boothdr.a_text + boothdr.a_data);
9577
for (bap= bootaddr; bap->count != 0; bap++) {
9578
*adrp++= bap->count;
9579
*adrp++= (bap->address >> 0) & 0xFF;
9580
*adrp++= (bap->address >> 8) & 0xFF;
9581
*adrp++= (bap->address >> 16) & 0xFF;
9582 }
9583
/* Zero count stops bootblock's reading loop. */
9584
*adrp++= 0;
9585
9586
if (bap > bootaddr+1) {
9587
printf("%s and %d addresses to %s patched into %s\n",
9588
bootblock, (int)(bap - bootaddr), bootcode, device);
9589 }
9590
9591
/* Boot block signature. */
9592
adrp= buf + SIGPOS;
9593
*adrp++= (SIGNATURE >> 0) & 0xFF;
9594
*adrp++= (SIGNATURE >> 8) & 0xFF;
9595
9596
/* Sector 2 of the boot block is used for boot parameters, initially
9597
* filled with null commands (newlines). Initialize it only if
9598
* necessary.
9599
*/
9600
for (parmp= buf + SECTOR_SIZE; parmp < buf + 2*SECTOR_SIZE; parmp++)
{
9601
if (*imagev != nil || (control(*parmp) && *parmp != '\n')) {
9602
/* Param sector must be initialized. */
9603
memset(buf + SECTOR_SIZE, '\n', SECTOR_SIZE);
9604
break;
9605
}
9606 }
9607
9608
/* Offset to the end of the file system to add boot code and images. */
9609
pos= fssize * RATIO;
9610
9611
if (ino == 0) {
9612
/* Place the boot code onto the boot device. */
9613
len= max_sector;
9614
if (!raw_install(bootcode, &pos, &len)) {
9615
if (how == FS) {
9616
fprintf(stderr,
9617
"\t(Isn't there a copy of %s on %s that can be used?)\n",
9618
bootcode, device);
9619
}
9620
exit(1);
9621
}
9622 }
9623
9624
parmp= buf + SECTOR_SIZE;
9625
nolabel= 0;
9626
9627
if (how == BOOT) {
9628
/* A boot only disk needs to have floppies swapped. */
9629
strcpy(parmp,
9630
"trailer()echo \\nInsert the root diskette then hit RETURN\\n\\w\\c\n");
9631
parmp+= strlen(parmp);
9632 }
9633
9634
while ((labels= *imagev++) != nil) {
9635
/* Place each kernel image on the boot device. */
9636
9637
if ((image= strchr(labels, ':')) != nil)
9638
*image++= 0;
9639
else {
9640
if (nolabel) {
9641
fprintf(stderr,
9642
"installboot: Only one image can be the default\n");
9643
exit(1);
9644
}
9645
nolabel= 1;
9646
image= labels;
9647
labels= nil;
9648
}
9649
len= 0;
9650
if (!raw_install(image, &pos, &len)) exit(1);
9651
9652
if (labels == nil) {
9653
/* Let this image be the default. */
9654
sprintf(parmp, "image=%ld:%ld\n", pos-len, len);
9655
parmp+= strlen(parmp);
9656
}
9657
9658
while (labels != nil) {
9659
/* Image is prefixed by a comma separated list of
9660
* labels. Define functions to select label and image.
9661
*/
9662
label= labels;
9663
if ((labels= strchr(labels, ',')) != nil) *labels++ = 0;
9664
9665
sprintf(parmp,
9666
"%s(%c){label=%s;image=%ld:%ld;echo %s kernel
selected;menu}\n",
9667
label,
9668
between('A', label[0], 'Z')
9669
? label[0]-'A'+'a' : label[0],
9670
label, pos-len, len, label);
9671
parmp+= strlen(parmp);
9672
}
9673
9674
if (parmp > buf + BLOCK_SIZE) {
9675
fprintf(stderr,
9676
"installboot: Out of parameter space, too many images\n");
9677
exit(1);
9678
}
9679 }
9680
/* Install boot block. */
9681
writeblock((off_t) BOOTBLOCK, buf);
9682
9683
if (pos > fssize * RATIO) {
9684
/* Tell the total size of the data on the device. */
9685
printf("%16ld (%ld kb) total\n", pos,
9686
(pos + RATIO - 1) / RATIO);
9687 }
9688 }
9689
9690 void install_master(char
*device, char *masterboot, char *fix)
9691 /* Booting a hard disk is a two stage process:
The master bootstrap in sector
9692 * 0 loads the bootstrap from sector 0 of
the active partition which in turn
9693 * starts the operating system. This
code installs such a master bootstrap
9694 * on a hard disk. If fix is non-null
then the master bootstrap is locked
9695 * into booting device /dev/hd'fix'.
9696 */
9697 {
9698
FILE *masf;
9699
unsigned long size;
9700
struct stat st;
9701
char buf[BLOCK_SIZE];
9702
9703
/* Open device. */
9704
if ((rawfd= open(rawdev= device, O_RDWR)) < 0) fatal(device);
9705
9706
/* Open the master boot code. */
9707
if ((masf= fopen(masterboot, "r")) == nil) fatal(masterboot);
9708
9709
/* See if the user is cloning a device. */
9710
if (fstat(fileno(masf), &st) >=0 && S_ISBLK(st.st_mode))
9711
size= PARTPOS;
9712
else {
9713
/* Read and check header otherwise. */
9714
struct image_header ihdr;
9715
9716
read_header(1, masterboot, masf, &ihdr);
9717
size= ihdr.process.a_text + ihdr.process.a_data;
9718 }
9719
if (size > PARTPOS) {
9720
fprintf(stderr, "installboot: %s is too big\n", masterboot);
9721
exit(1);
9722 }
9723
/* Read the master boot block, patch it, write. */
9724
readblock(BOOTBLOCK, buf);
9725
9726
(void) bread(masf, masterboot, buf, size);
9727
9728
if (fix != nil) {
9729
/* Fixate partition to boot. */
9730
int device= 0, logical= 0;
9731
char *pf= fix;
9732
9733
while (between('0', *pf, '9')) {
9734
device= 10 * device + (*pf - '0');
9735
if (device >= 40) break;
9736
pf++;
9737
}
9738
if (between('a', *pf, 'd')) {
9739
logical= 1 + (*pf - 'a');
9740
pf++;
9741
}
9742
if (*pf != 0) {
9743
fprintf(stderr, "installboot: bad fix key '%s'\n", fix);
9744
exit(1);
9745
}
9746
9747
if (buf[0] == (char) JMP && buf[1] == (char) JMPOFFM
9748
&& buf[3] == (char) XOR && logical == 0) {
9749
/* Minix masterboot; patch device number. */
9750
buf[2]= device;
9751
} else
9752
if (buf[0] == (char) JMP && buf[1] == (char) JMPOFFE
9753
&& buf[4] == (char) XOR && logical != 0) {
9754
/* Minix extboot; patch device and logical number. */
9755
buf[2]= device;
9756
buf[3]= logical;
9757
} else {
9758
fprintf(stderr,
9759
"installboot: can't put fix flag '%s' on %s\n",
9760
fix, masterboot);
9761
exit(1);
9762
}
9763 }
9764
9765
/* Install signature. */
9766
buf[SIGPOS+0]= (SIGNATURE >> 0) & 0xFF;
9767
buf[SIGPOS+1]= (SIGNATURE >> 8) & 0xFF;
9768
9769
writeblock(BOOTBLOCK, buf);
9770 }
9771
9772 void usage(void)
9773 {
9774
fprintf(stderr,
9775
"Usage: installboot -i(mage) image kernel mm fs ... init\n"
9776
" installboot -(e)x(tract) image\n"
9777
" installboot -d(evice) device bootblock
boot [image ...]\n"
9778
" installboot -b(oot) device bootblock
boot image ...\n"
9779
" installboot -m(aster) [fix] device
masterboot\n");
9780
exit(1);
9781 }
9782
9783 int isoption(char
*option, char *test)
9784 /* Check if the option argument is equals "test".
Also accept -i as short
9785 * for -image, and the special case -x for
-extract.
9786 */
9787 {
9788
if (strcmp(option, test) == 0) return 1;
9789
if (option[0] != '-' && strlen(option) != 2) return 0;
9790
if (option[1] == test[1]) return 1;
9791
if (option[1] == 'x' && test[1] == 'e') return 1;
9792
return 0;
9793 }
9794
9795 int main(int argc, char
**argv)
9796 {
9797
if (argc < 2) usage();
9798
9799
if (argc >= 4 && isoption(argv[1], "-image")) {
9800
make_image(argv[2], argv + 3);
9801 }
else
9802
if (argc == 3 && isoption(argv[1], "-extract")) {
9803
extract_image(argv[2]);
9804 }
else
9805
if (argc >= 5 && isoption(argv[1], "-device")) {
9806
make_bootable(FS, argv[2], argv[3], argv[4], argv + 5);
9807 }
else
9808
if (argc >= 6 && isoption(argv[1], "-boot")) {
9809
make_bootable(BOOT, argv[2], argv[3], argv[4], argv + 5);
9810 }
else
9811
if (argc == 4 && isoption(argv[1], "-master")) {
9812
install_master(argv[2], argv[3], nil);
9813 }
else
9814
if (argc == 5 && isoption(argv[1], "-master")
9815
&& between('0', argv[2][0], '9')) {
9816
install_master(argv[3], argv[4], argv[2]);
9817 }
else {
9818
usage();
9819 }
9820
exit(0);
9821 }