⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 installboot.c

📁 操作系统磁盘分区的源程序
💻 C
📖 第 1 页 / 共 2 页
字号:
/*	installboot 1.23 - Make a device bootable	Author: Kees J. Bot
 *								21 Dec 1991
 *
 * Either make a device bootable or make an image from kernel, mm, fs, etc.
 */
#define nil 0
#define _POSIX_SOURCE	1
#define _MINIX		1
#include <stdio.h>
#include <stddef.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
#include <errno.h>
#include <a.out.h>
#include <minix/config.h>
#include <minix/const.h>
#include <minix/partition.h>
#include "rawfs.h"
#include "image.h"

#define BOOTBLOCK	0	/* Of course */
#define SECTOR_SIZE	512	/* Disk sector size. */
#define RATIO		(BLOCK_SIZE/SECTOR_SIZE)
#define SIGNATURE	0xAA55	/* Boot block signature. */
#define BOOT_MAX	64	/* Absolute maximum size of secondary boot */
#define JMP		0xEB	/* Opcode of a short jump */
#define JMPOFFM		0x01	/* Jump offset in normal master bootstrap */
#define JMPOFFE		0x02	/* Jump offset in extended bootstrap */
#define XOR		0x31	/* Jumping to an XOR instruction? */
#define SIGPOS		510	/* Where to put signature word. */
#define PARTPOS		446	/* Offset to the partition table in a master
				 * boot block.
				 */

#define between(a, c, z)	((unsigned) ((c) - (a)) <= ((z) - (a)))
#define control(c)		between('\0', (c), '\37')

#if !__minix_vmd
#define cv64ul(i)	(i)
#endif

void report(char *label)
/* installboot: label: No such file or directory */
{
	fprintf(stderr, "installboot: %s: %s\n", label, strerror(errno));
}

void fatal(char *label)
{
	report(label);
	exit(1);
}

char *basename(char *name)
/* Return the last component of name, stripping trailing slashes from name.
 * Precondition: name != "/".  If name is prefixed by a label, then the
 * label is copied to the basename too.
 */
{
	static char base[IM_NAME_MAX];
	char *p, *bp= base;

	if ((p= strchr(name, ':')) != nil) {
		while (name <= p && bp < base + IM_NAME_MAX - 1)
			*bp++ = *name++;
	}
	for (;;) {
		if ((p= strrchr(name, '/')) == nil) { p= name; break; }
		if (*++p != 0) break;
		*--p= 0;
	}
	while (*p != 0 && bp < base + IM_NAME_MAX - 1) *bp++ = *p++;
	*bp= 0;
	return base;
}

void bread(FILE *f, char *name, void *buf, size_t len)
/* Read len bytes.  Don't dare return without them. */
{
	if (len > 0 && fread(buf, len, 1, f) != 1) {
		if (ferror(f)) fatal(name);
		fprintf(stderr, "installboot: Unsuspected EOF on %s\n", name);
		exit(1);
	}
}

void bwrite(FILE *f, char *name, void *buf, size_t len)
{
	if (len > 0 && fwrite(buf, len, 1, f) != 1) fatal(name);
}

long total_text= 0, total_data= 0, total_bss= 0;
int making_image= 0;

void read_header(int talk, char *proc, FILE *procf, struct image_header *ihdr)
/* Read the a.out header of a program and check it.  If procf happens to be
 * nil then the header is already in *image_hdr and need only be checked.
 */
{
	int n, big= 0;
	static int banner= 0;
	struct exec *phdr= &ihdr->process;

	if (procf == nil) {
		/* Header already present. */
		n= phdr->a_hdrlen;
	} else {
		memset(ihdr, 0, sizeof(*ihdr));

		/* Put the basename of proc in the header. */
		strncpy(ihdr->name, basename(proc), IM_NAME_MAX);

		/* Read the header. */
		n= fread(phdr, sizeof(char), A_MINHDR, procf);
		if (ferror(procf)) fatal(proc);
	}

	if (n < A_MINHDR || BADMAG(*phdr)) {
		fprintf(stderr, "installboot: %s is not an executable\n", proc);
		exit(1);
	}

	/* Get the rest of the exec header. */
	if (procf != nil) {
		bread(procf, proc, ((char *) phdr) + A_MINHDR,
						phdr->a_hdrlen - A_MINHDR);
	}

	if (talk && !banner) {
		printf("    text    data     bss     size\n");
		banner= 1;
	}

	if (talk) {
		printf("%8ld%8ld%8ld%9ld  %s\n",
			phdr->a_text, phdr->a_data, phdr->a_bss,
			phdr->a_text + phdr->a_data + phdr->a_bss, proc);
	}
	total_text+= phdr->a_text;
	total_data+= phdr->a_data;
	total_bss+= phdr->a_bss;

	if (phdr->a_cpu == A_I8086) {
		long data= phdr->a_data + phdr->a_bss;

		if (!(phdr->a_flags & A_SEP)) data+= phdr->a_text;

		if (phdr->a_text >= 65536) big|= 1;
		if (data >= 65536) big|= 2;
	}
	if (big) {
		fprintf(stderr,
			"%s will crash, %s%s%s segment%s larger then 64K\n",
			proc,
			big & 1 ? "text" : "",
			big == 3 ? " and " : "",
			big & 2 ? "data" : "",
			big == 3 ? "s are" : " is");
	}
}

void padimage(char *image, FILE *imagef, int n)
/* Add n zeros to image to pad it to a sector boundary. */
{
	while (n > 0) {
		if (putc(0, imagef) == EOF) fatal(image);
		n--;
	}
}

#define align(n)	(((n) + ((SECTOR_SIZE) - 1)) & ~((SECTOR_SIZE) - 1))

void copyexec(char *proc, FILE *procf, char *image, FILE *imagef, long n)
/* Copy n bytes from proc to image padded to fill a sector. */
{
	int pad, c;

	/* Compute number of padding bytes. */
	pad= align(n) - n;

	while (n > 0) {
		if ((c= getc(procf)) == EOF) {
			if (ferror(procf)) fatal(proc);
			fprintf(stderr,	"installboot: premature EOF on %s\n",
									proc);
			exit(1);
		}
		if (putc(c, imagef) == EOF) fatal(image);
		n--;
	}
	padimage(image, imagef, pad);
}

void make_image(char *image, char **procv)
/* Collect a set of files in an image, each "segment" is nicely padded out
 * to SECTOR_SIZE, so it may be read from disk into memory without trickery.
 */
{
	FILE *imagef, *procf;
	char *proc, *file;
	int procn;
	struct image_header ihdr;
	struct exec phdr;
	struct stat st;

	making_image= 1;

	if ((imagef= fopen(image, "w")) == nil) fatal(image);

	for (procn= 0; (proc= *procv++) != nil; procn++) {
		/* Remove the label from the file name. */
		if ((file= strchr(proc, ':')) != nil) file++; else file= proc;

		/* Real files please, may need to seek. */
		if (stat(file, &st) < 0
			|| (errno= EISDIR, !S_ISREG(st.st_mode))
			|| (procf= fopen(file, "r")) == nil
		) fatal(proc);

		/* Read a.out header. */
		read_header(1, proc, procf, &ihdr);

		/* Scratch. */
		phdr= ihdr.process;

		/* The symbol table is always stripped off. */
		ihdr.process.a_syms= 0;
		ihdr.process.a_flags &= ~A_NSYM;

		/* Write header padded to fill a sector */
		bwrite(imagef, image, &ihdr, sizeof(ihdr));

		padimage(image, imagef, SECTOR_SIZE - sizeof(ihdr));

		/* A page aligned executable needs the header in text. */
		if (phdr.a_flags & A_PAL) {
			rewind(procf);
			phdr.a_text+= phdr.a_hdrlen;
		}

		/* Copy text and data of proc to image. */
		if (phdr.a_flags & A_SEP) {
			/* Separate I&D: pad text & data separately. */

			copyexec(proc, procf, image, imagef, phdr.a_text);
			copyexec(proc, procf, image, imagef, phdr.a_data);
		} else {
			/* Common I&D: keep text and data together. */

			copyexec(proc, procf, image, imagef,
						phdr.a_text + phdr.a_data);
		}

		/* Done with proc. */
		(void) fclose(procf);
	}
	/* Done with image. */

	if (fclose(imagef) == EOF) fatal(image);

	printf("  ------  ------  ------  -------\n");
	printf("%8ld%8ld%8ld%9ld  total\n",
		total_text, total_data, total_bss,
		total_text + total_data + total_bss);
}

void extractexec(FILE *imagef, char *image, FILE *procf, char *proc,
						long count, off_t *alen)
/* Copy a segment of an executable.  It is padded to a sector in image. */
{
	char buf[SECTOR_SIZE];

	while (count > 0) {
		bread(imagef, image, buf, sizeof(buf));
		*alen-= sizeof(buf);

		bwrite(procf, proc, buf,
			count < sizeof(buf) ? (size_t) count : sizeof(buf));
		count-= sizeof(buf);
	}
}

void extract_image(char *image)
/* Extract the executables from an image. */
{
	FILE *imagef, *procf;
	off_t len;
	struct stat st;
	struct image_header ihdr;
	struct exec phdr;
	char buf[SECTOR_SIZE];

	if (stat(image, &st) < 0) fatal(image);

	/* Size of the image. */
	len= S_ISREG(st.st_mode) ? st.st_size : -1;

	if ((imagef= fopen(image, "r")) == nil) fatal(image);

	while (len != 0) {
		/* Extract a program, first sector is an extended header. */
		bread(imagef, image, buf, sizeof(buf));
		len-= sizeof(buf);

		memcpy(&ihdr, buf, sizeof(ihdr));
		phdr= ihdr.process;

		/* Check header. */
		read_header(1, ihdr.name, nil, &ihdr);

		if ((procf= fopen(ihdr.name, "w")) == nil) fatal(ihdr.name);

		if (phdr.a_flags & A_PAL) {
			/* A page aligned process contains a header in text. */
			phdr.a_text+= phdr.a_hdrlen;
		} else {
			bwrite(procf, ihdr.name, &ihdr.process, phdr.a_hdrlen);
		}

		/* Extract text and data segments. */
		if (phdr.a_flags & A_SEP) {
			extractexec(imagef, image, procf, ihdr.name,
						phdr.a_text, &len);
			extractexec(imagef, image, procf, ihdr.name,
						phdr.a_data, &len);
		} else {
			extractexec(imagef, image, procf, ihdr.name,
				phdr.a_text + phdr.a_data, &len);
		}

		if (fclose(procf) == EOF) fatal(ihdr.name);
	}
}

int rawfd;	/* File descriptor to open device. */
char *rawdev;	/* Name of device. */

void readblock(off_t blk, char *buf)
/* For rawfs, so that it can read blocks. */
{
	int n;

	if (lseek(rawfd, blk * BLOCK_SIZE, SEEK_SET) < 0
		|| (n= read(rawfd, buf, BLOCK_SIZE)) < 0
	) fatal(rawdev);

	if (n < BLOCK_SIZE) {
		fprintf(stderr, "installboot: unexpected EOF on %s\n", rawdev);
		exit(1);
	}
}

void writeblock(off_t blk, char *buf)
/* Add a function to write blocks for local use. */
{
	if (lseek(rawfd, blk * BLOCK_SIZE, SEEK_SET) < 0
		|| write(rawfd, buf, BLOCK_SIZE) < 0
	) fatal(rawdev);
}

int raw_install(char *file, off_t *start, off_t *len)
/* Copy bootcode or an image to the boot device at the given absolute disk
 * block number.  This "raw" installation is used to place bootcode and
 * image on a disk without a filesystem to make a simple boot disk.  Useful
 * in automated scripts for J. Random User.
 * Note: *len == 0 when an image is read.  It is set right afterwards.
 */
{
	static char buf[BLOCK_SIZE];	/* Nonvolatile block buffer. */
	FILE *f;
	off_t sec;
	unsigned long devsize;
	static int banner= 0;
	struct partition entry;

	/* See if the device has a maximum size. */
	devsize= -1;
	if (ioctl(rawfd, DIOCGETP, &entry) == 0) devsize= cv64ul(entry.size);

	if ((f= fopen(file, "r")) == nil) fatal(file);

	/* Copy sectors from file onto the boot device. */
	sec= *start;
	do {
		int off= sec % RATIO;

		if (fread(buf + off * SECTOR_SIZE, 1, SECTOR_SIZE, f) == 0)
			break;

		if (sec >= devsize) {
			fprintf(stderr,
			"installboot: %s can't be attached to %s\n",
				file, rawdev);
			return 0;
		}

		if (off == RATIO - 1) writeblock(sec / RATIO, buf);
	} while (++sec != *start + *len);

	if (ferror(f)) fatal(file);
	(void) fclose(f);

	/* Write a partial block, this may be the last image. */
	if (sec % RATIO != 0) writeblock(sec / RATIO, buf);

	if (!banner) {
		printf("  sector  length\n");
		banner= 1;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -