📄 installboot.c
字号:
}
*len= sec - *start;
printf("%8ld%8ld %s\n", *start, *len, file);
*start= sec;
return 1;
}
enum howto { FS, BOOT };
void make_bootable(enum howto how, char *device, char *bootblock,
char *bootcode, char **imagev)
/* Install bootblock on the bootsector of device with the disk addresses to
* bootcode patched into the data segment of bootblock. "How" tells if there
* should or shoudn't be a file system on the disk. The images in the imagev
* vector are added to the end of the device.
*/
{
char buf[BLOCK_SIZE + 256], *adrp, *parmp;
struct fileaddr {
off_t address;
int count;
} bootaddr[BOOT_MAX + 1], *bap= bootaddr;
struct exec boothdr;
struct image_header dummy;
struct stat st;
ino_t ino;
off_t sector, max_sector;
FILE *bootf;
off_t addr, fssize, pos, len;
char *labels, *label, *image;
int nolabel;
/* Open device and set variables for readblock. */
if ((rawfd= open(rawdev= device, O_RDWR)) < 0) fatal(device);
/* Read and check the superblock. */
fssize= r_super();
switch (how) {
case FS:
if (fssize == 0) {
fprintf(stderr,
"installboot: %s is not a Minix file system\n",
device);
exit(1);
}
break;
case BOOT:
if (fssize != 0) {
int s;
printf("%s contains a file system!\n", device);
printf("Scribbling in 10 seconds");
for (s= 0; s < 10; s++) {
fputc('.', stdout);
fflush(stdout);
sleep(1);
}
fputc('\n', stdout);
}
fssize= 1; /* Just a boot block. */
}
if (how == FS) {
/* See if the boot code can be found on the file system. */
if ((ino= r_lookup(ROOT_INO, bootcode)) == 0) {
if (errno != ENOENT) fatal(bootcode);
}
} else {
/* Boot code must be attached at the end. */
ino= 0;
}
if (ino == 0) {
/* For a raw installation, we need to copy the boot code onto
* the device, so we need to look at the file to be copied.
*/
if (stat(bootcode, &st) < 0) fatal(bootcode);
if ((bootf= fopen(bootcode, "r")) == nil) fatal(bootcode);
} else {
/* Boot code is present in the file system. */
r_stat(ino, &st);
/* Get the header from the first block. */
if ((addr= r_vir2abs((off_t) 0)) == 0) {
boothdr.a_magic[0]= !A_MAGIC0;
} else {
readblock(addr, buf);
memcpy(&boothdr, buf, sizeof(struct exec));
}
bootf= nil;
dummy.process= boothdr;
}
/* See if it is an executable (read_header does the check). */
read_header(0, bootcode, bootf, &dummy);
boothdr= dummy.process;
if (bootf != nil) fclose(bootf);
/* Get all the sector addresses of the secondary boot code. */
max_sector= (boothdr.a_hdrlen + boothdr.a_text
+ boothdr.a_data + SECTOR_SIZE - 1) / SECTOR_SIZE;
if (max_sector > BOOT_MAX * RATIO) {
fprintf(stderr, "installboot: %s is way too big\n", bootcode);
exit(0);
}
/* Determine the addresses to the boot code to be patched into the
* boot block.
*/
bap->count= 0; /* Trick to get the address recording going. */
for (sector= 0; sector < max_sector; sector++) {
if (ino == 0) {
addr= fssize + (sector / RATIO);
} else
if ((addr= r_vir2abs(sector / RATIO)) == 0) {
fprintf(stderr, "installboot: %s has holes!\n",
bootcode);
exit(1);
}
addr= (addr * RATIO) + (sector % RATIO);
/* First address of the addresses array? */
if (bap->count == 0) bap->address= addr;
/* Paste sectors together in a multisector read. */
if (bap->address + bap->count == addr)
bap->count++;
else {
/* New address. */
bap++;
bap->address= addr;
bap->count= 1;
}
}
(++bap)->count= 0; /* No more. */
/* Get the boot block and patch the pieces in. */
readblock(BOOTBLOCK, buf);
if ((bootf= fopen(bootblock, "r")) == nil) fatal(bootblock);
read_header(0, bootblock, bootf, &dummy);
boothdr= dummy.process;
if (boothdr.a_text + boothdr.a_data +
4 * (bap - bootaddr) + 1 > SIGPOS) {
fprintf(stderr,
"installboot: %s + addresses to %s don't fit in the boot sector\n",
bootblock, bootcode);
fprintf(stderr,
"You can try copying/reinstalling %s to defragment it\n",
bootcode);
exit(1);
}
/* All checks out right. Read bootblock into the boot block! */
bread(bootf, bootblock, buf, boothdr.a_text + boothdr.a_data);
(void) fclose(bootf);
/* Patch the addresses in. */
adrp= buf + (int) (boothdr.a_text + boothdr.a_data);
for (bap= bootaddr; bap->count != 0; bap++) {
*adrp++= bap->count;
*adrp++= (bap->address >> 0) & 0xFF;
*adrp++= (bap->address >> 8) & 0xFF;
*adrp++= (bap->address >> 16) & 0xFF;
}
/* Zero count stops bootblock's reading loop. */
*adrp++= 0;
if (bap > bootaddr+1) {
printf("%s and %d addresses to %s patched into %s\n",
bootblock, (int)(bap - bootaddr), bootcode, device);
}
/* Boot block signature. */
adrp= buf + SIGPOS;
*adrp++= (SIGNATURE >> 0) & 0xFF;
*adrp++= (SIGNATURE >> 8) & 0xFF;
/* Sector 2 of the boot block is used for boot parameters, initially
* filled with null commands (newlines). Initialize it only if
* necessary.
*/
for (parmp= buf + SECTOR_SIZE; parmp < buf + 2*SECTOR_SIZE; parmp++) {
if (*imagev != nil || (control(*parmp) && *parmp != '\n')) {
/* Param sector must be initialized. */
memset(buf + SECTOR_SIZE, '\n', SECTOR_SIZE);
break;
}
}
/* Offset to the end of the file system to add boot code and images. */
pos= fssize * RATIO;
if (ino == 0) {
/* Place the boot code onto the boot device. */
len= max_sector;
if (!raw_install(bootcode, &pos, &len)) {
if (how == FS) {
fprintf(stderr,
"\t(Isn't there a copy of %s on %s that can be used?)\n",
bootcode, device);
}
exit(1);
}
}
parmp= buf + SECTOR_SIZE;
nolabel= 0;
if (how == BOOT) {
/* A boot only disk needs to have floppies swapped. */
strcpy(parmp, "delay=swap\n");
parmp+= strlen(parmp);
}
while ((labels= *imagev++) != nil) {
/* Place each kernel image on the boot device. */
if ((image= strchr(labels, ':')) != nil)
*image++= 0;
else {
if (nolabel) {
fprintf(stderr,
"installboot: Only one image can be the default\n");
exit(1);
}
nolabel= 1;
image= labels;
labels= nil;
}
len= 0;
if (!raw_install(image, &pos, &len)) exit(1);
if (labels == nil) {
/* Let this image be the default. */
sprintf(parmp, "image=%ld:%ld\n", pos-len, len);
parmp+= strlen(parmp);
}
while (labels != nil) {
/* Image is prefixed by a comma separated list of
* labels. Define functions to select label and image.
*/
label= labels;
if ((labels= strchr(labels, ',')) != nil) *labels++ = 0;
sprintf(parmp,
"%s(%c){label=%s;image=%ld:%ld;echo %s kernel selected;menu}\n",
label,
between('A', label[0], 'Z')
? label[0]-'A'+'a' : label[0],
label, pos-len, len, label);
parmp+= strlen(parmp);
}
if (parmp > buf + BLOCK_SIZE) {
fprintf(stderr,
"installboot: Out of parameter space, too many images\n");
exit(1);
}
}
/* Install boot block. */
writeblock((off_t) BOOTBLOCK, buf);
if (pos > fssize * RATIO) {
/* Tell the total size of the data on the device. */
printf("%16ld (%ld kb) total\n", pos,
(pos + RATIO - 1) / RATIO);
}
}
void install_master(char *device, char *masterboot, char *fix)
/* Booting a hard disk is a two stage process: The master bootstrap in sector
* 0 loads the bootstrap from sector 0 of the active partition which in turn
* starts the operating system. This code installs such a master bootstrap
* on a hard disk. If fix is non-null then the master bootstrap is locked
* into booting device /dev/hd'fix'.
*/
{
FILE *masf;
unsigned long size;
struct stat st;
char buf[BLOCK_SIZE];
/* Open device. */
if ((rawfd= open(rawdev= device, O_RDWR)) < 0) fatal(device);
/* Open the master boot code. */
if ((masf= fopen(masterboot, "r")) == nil) fatal(masterboot);
/* See if the user is cloning a device. */
if (fstat(fileno(masf), &st) >=0 && S_ISBLK(st.st_mode))
size= PARTPOS;
else {
/* Read and check header otherwise. */
struct image_header ihdr;
read_header(1, masterboot, masf, &ihdr);
size= ihdr.process.a_text + ihdr.process.a_data;
}
if (size > PARTPOS) {
fprintf(stderr, "installboot: %s is too big\n", masterboot);
exit(1);
}
/* Read the master boot block, patch it, write. */
readblock(BOOTBLOCK, buf);
(void) bread(masf, masterboot, buf, size);
if (fix != nil) {
/* Fixate partition to boot. */
int device= 0, logical= 0;
char *pf= fix;
while (between('0', *pf, '9')) {
device= 10 * device + (*pf - '0');
if (device >= 40) break;
pf++;
}
if (between('a', *pf, 'd')) {
logical= 1 + (*pf - 'a');
pf++;
}
if (*pf != 0) {
fprintf(stderr, "installboot: bad fix key '%s'\n", fix);
exit(1);
}
if (buf[0] == (char) JMP && buf[1] == (char) JMPOFFM
&& buf[3] == (char) XOR && logical == 0) {
/* Minix masterboot; patch device number. */
buf[2]= device;
} else
if (buf[0] == (char) JMP && buf[1] == (char) JMPOFFE
&& buf[4] == (char) XOR && logical != 0) {
/* Minix extboot; patch device and logical number. */
buf[2]= device;
buf[3]= logical;
} else {
fprintf(stderr,
"installboot: can't put fix flag '%s' on %s\n",
fix, masterboot);
exit(1);
}
}
/* Install signature. */
buf[SIGPOS+0]= (SIGNATURE >> 0) & 0xFF;
buf[SIGPOS+1]= (SIGNATURE >> 8) & 0xFF;
writeblock(BOOTBLOCK, buf);
}
void usage(void)
{
fprintf(stderr,
"Usage: installboot -i(mage) image kernel mm fs ... init\n");
fprintf(stderr,
" installboot -(e)x(tract) image\n");
fprintf(stderr,
" installboot -d(evice) device bootblock boot\n");
fprintf(stderr,
" installboot -b(oot) device bootblock boot image ...\n");
fprintf(stderr,
" installboot -m(aster) [fix] device masterboot\n");
exit(1);
}
int isoption(char *option, char *test)
/* Check if the option argument is equals "test". Also accept -i as short
* for -image, and the special case -x for -extract.
*/
{
if (strcmp(option, test) == 0) return 1;
if (option[0] != '-' && strlen(option) != 2) return 0;
if (option[1] == test[1]) return 1;
if (option[1] == 'x' && test[1] == 'e') return 1;
return 0;
}
int main(int argc, char **argv)
{
if (argc < 2) usage();
if (argc >= 4 && isoption(argv[1], "-image")) {
make_image(argv[2], argv + 3);
} else
if (argc == 3 && isoption(argv[1], "-extract")) {
extract_image(argv[2]);
} else
if (argc >= 5 && isoption(argv[1], "-device")) {
make_bootable(FS, argv[2], argv[3], argv[4], argv + 5);
} else
if (argc >= 6 && isoption(argv[1], "-boot")) {
make_bootable(BOOT, argv[2], argv[3], argv[4], argv + 5);
} else
if (argc == 4 && isoption(argv[1], "-master")) {
install_master(argv[2], argv[3], nil);
} else
if (argc == 5 && isoption(argv[1], "-master")
&& between('0', argv[2][0], '9')) {
install_master(argv[3], argv[4], argv[2]);
} else {
usage();
}
exit(0);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -