summaryrefslogtreecommitdiff
path: root/bootblocks/makeboot.c
diff options
context:
space:
mode:
Diffstat (limited to 'bootblocks/makeboot.c')
-rw-r--r--bootblocks/makeboot.c634
1 files changed, 530 insertions, 104 deletions
diff --git a/bootblocks/makeboot.c b/bootblocks/makeboot.c
index 5a6348d..28d7ded 100644
--- a/bootblocks/makeboot.c
+++ b/bootblocks/makeboot.c
@@ -1,103 +1,328 @@
#include <stdio.h>
+#include <ctype.h>
+#include <time.h>
-#include "tarboot.v"
#include "sysboot.v"
+#include "msdos.v"
+#include "skip.v"
+#include "tarboot.v"
-char tarblock[512];
+char buffer[1024];
+
+#define FS_NONE 0
+#define FS_ADOS 1
+#define FS_DOS 2
+#define FS_TAR 3
+#define FS_STAT 4
+
+struct bblist {
+ char * name;
+ char * data;
+ int fstype;
+ char * desc;
+} bblocks[] = {
+ { "tar", tarboot_data, FS_TAR, "Bootable GNU tar volume lable" },
+ { "dosfs", msdos_data, FS_ADOS, "Boots file BOOTFILE.SYS from dosfs" },
+ { "bare", sysboot_data, FS_DOS, "Bare bootblock, lockup if booted" },
+ { "skip", skip_data, FS_DOS, "Bypasses floppy boot with message" },
+ { "stat", 0, FS_STAT, "Display dosfs superblock" },
+ { "copy", 0, FS_STAT, "Copy boot block to makeboot.sav" },
+ { "Zap", 0, FS_NONE, "Clear boot block to NULs" },
+ 0
+};
+
+char * progname = "";
+
+int disktype = 0;
+FILE * diskfd;
+
+int disk_sect = 63; /* These are initilised to the maximums */
+int disk_head = 256; /* Set to the correct values when an MSDOS disk is */
+int disk_trck = 256; /* successfully identified */
-char *bootblock = tarboot_data;
+main(argc, argv)
+int argc;
+char ** argv;
+{
+ FILE * fd;
+ struct bblist *ptr;
+ int i;
-struct tar_head {
- char name[100];
- char mode[8];
- char uid[8];
- char gid[8];
- char size[12];
- char mtime[12];
- char chksum[8];
- char linkflag;
- char linkname[100];
- char magic[8];
- char uname[32];
- char gname[32];
- char devmajor[8];
- char devminor[8];
- char padding[167];
-} ;
+ progname = argv[0];
-#define head (*(struct tar_head*) tarblock)
-#define boothead (*(struct tar_head*) bootblock)
+ if( argc != 3 ) Usage();
-int force = 0;
-int relocatable = 0;
-int tableload = 0;
-long loadaddress = 0x8000;
-long execaddress = 0x8000;
+ if( (i=strlen(argv[1])) < 2 ) Usage();
+ for(ptr = bblocks; ptr->name; ptr++)
+ if( strncmp(argv[1], ptr->name, i) == 0 ) break;
+ if( ptr->name == 0 ) Usage();
-main(argc, argv)
-int argc;
-char ** argv;
+ open_disk(argv[2]);
+ if( read_sector(0, buffer) != 0 )
+ exit(1);
+ read_sector(1, buffer+512);
+
+ switch(ptr->fstype)
+ {
+ case FS_NONE: /* override */
+ break;
+ case FS_ADOS:
+ check_simpledos();
+ break;
+ case FS_DOS:
+ case FS_STAT:
+ check_msdos();
+ break;
+ case FS_TAR:
+ check_tar();
+ break;
+
+ default:
+ fprintf(stderr, "Program error, unknown filesystem requirement\n");
+ exit(2);
+ }
+
+ switch(ptr->fstype)
+ {
+ case FS_STAT:
+ print_super(buffer);
+ if( strcmp(ptr->name, "copy") == 0 )
+ save_super(buffer);
+ close_disk();
+ exit(0);
+ case FS_ADOS:
+ case FS_DOS:
+ for(i=0; i<sysboot_dosfs_stat; i++)
+ buffer[i] = ptr->data[i];
+ for(i=sysboot_codestart; i<512; i++)
+ buffer[i] = ptr->data[i];
+ break;
+
+ case FS_TAR:
+ copy_tarblock();
+ break;
+
+ case FS_NONE:
+ if( ptr->data )
+ memcpy(buffer, ptr->data, 512);
+ else
+ memset(buffer, '\0', 512);
+ break;
+ }
+
+ write_sector(0, buffer);
+ close_disk();
+ exit(0);
+}
+
+Usage()
{
- int ar;
- int done=0;
+ struct bblist *ptr = bblocks;
+
+ if( progname == 0 || *progname == 0 || progname[1] == 0 )
+ progname = "makeboot";
+
+#ifdef __MSDOS__
+ fprintf(stderr, "Usage: %s bootname a:\n", progname);
+#else
+ fprintf(stderr, "Usage: %s bootname /dev/fd0\n", progname);
+#endif
+ fprintf(stderr, "Blocks\n");
+ for(;ptr->name; ptr++)
+ fprintf(stderr, "\t%s\t%s\n", ptr->name, ptr->desc);
+ exit(1);
+}
- if( sizeof(head) != sizeof(tarblock) )
- { fprintf(stderr, "Program structure error\n"); exit(1); }
+/**************************************************************************/
- for(ar=1; ar<argc; ar++) if(argv[ar][0]=='-') switch(argv[ar][1])
+int
+open_disk(diskname)
+char * diskname;
+{
+#ifdef __MSDOS__
+ if( strcmp("a:", diskname) == 0 ) { disktype = 1; return 0; }
+ if( strcmp("b:", diskname) == 0 ) { disktype = 2; return 0; }
+ if( strcmp("A:", diskname) == 0 ) { disktype = 1; return 0; }
+ if( strcmp("B:", diskname) == 0 ) { disktype = 2; return 0; }
+#endif
+ disktype = 0;
+ diskfd = fopen(diskname, "r+");
+ if( diskfd == 0 )
{
- case 'f': force++; break;
- case 'r': relocatable++; break;
- case 't': tableload++; break;
- case 'l': sscanf(argv[ar]+2, "%li", &loadaddress); break;
- case 'x': sscanf(argv[ar]+2, "%li", &execaddress); break;
+ fprintf(stderr, "Cannot open %s\n", diskname);
+ exit(1);
+ }
+ return 0;
+}
- case '?': Usage(1); break;
- default: Usage(0); break;
+close_disk()
+{
+ if( diskfd && disktype == 0 ) fclose(diskfd);
+ diskfd = 0;
+ disktype = 0;
+}
+
+int
+write_sector(sectno, loadaddr)
+int sectno;
+char * loadaddr;
+{
+#ifdef __MSDOS__
+ if( disktype == 1 || disktype == 2 )
+ {
+ int tries, rv;
+ int s,h,c;
+ s = sectno%disk_sect + 1;
+ h = sectno/disk_sect%disk_head;
+ c = sectno/disk_sect/disk_head;
+
+ for(tries=0; tries<6; tries++)
+ if( (rv = dos_sect_write(disktype-1, c, h, s, loadaddr)) == 0 )
+ break;
+ if( rv )
+ {
+ fprintf(stderr, "Error writing sector %d, (%d)\n", sectno, rv/256);
+ return -1;
+ }
+ return 0;
}
- else
+#endif
+ if( disktype )
{
- mktarboot(argv[ar]);
- done++;
+ fprintf(stderr, "Cannot write sector %d\n", sectno);
+ return -1;
}
+ fseek(diskfd, (long)sectno*512, 0);
+ if( fwrite(loadaddr, 512, 1, diskfd) != 1 )
+ {
+ fprintf(stderr, "Cannot write sector %d\n", sectno);
+ return -1;
+ }
+ return 0;
}
-Usage(flg)
-int flg;
+int
+read_sector(sectno, loadaddr)
+int sectno;
+char * loadaddr;
{
- fprintf(stderr, "Usage: makeboot [-f] device\n");
- exit(9);
+ int cc;
+#ifdef __MSDOS__
+ if( disktype == 1 || disktype == 2 )
+ {
+ int tries, rv;
+ int s,h,c;
+ s = sectno%disk_sect + 1;
+ h = sectno/disk_sect%disk_head;
+ c = sectno/disk_sect/disk_head;
+
+ for(tries=0; tries<6; tries++)
+ if( (rv = dos_sect_read(disktype-1, c, h, s, loadaddr)) == 0 )
+ break;
+ if( rv )
+ {
+ fprintf(stderr, "Error reading sector %d, (%d)\n", sectno, rv/256);
+ memset(loadaddr, '\0', 512);
+ return -1;
+ }
+ return 0;
+ }
+#endif
+ if( disktype )
+ {
+ fprintf(stderr, "Cannot read sector %d\n", sectno);
+ return -1;
+ }
+ fseek(diskfd, (long)sectno*512, 0);
+ if( (cc=fread(loadaddr, 1, 512, diskfd)) != 512 )
+ {
+ fprintf(stderr, "Cannot read sector %d, clearing\n", sectno);
+ if(cc<0) cc=0;
+ memset(loadaddr+cc, '\0', 512-cc);
+ }
+ return 0;
}
+/**************************************************************************/
-mktarboot(fname)
-char * fname;
+#ifdef __MSDOS__
+dos_sect_read(drv, track, head, sector, loadaddr)
{
- FILE * fd;
+#asm
+ push bp
+ mov bp,sp
- fd = fopen(fname, "r+");
- if( !fd ) { perror(fname); exit(1); }
+ push ds
+ pop es
- if( fread(tarblock, sizeof(tarblock), 1, fd) != 1 )
- { fprintf(stderr, "Cannot read boot block\n"); exit(1); }
+ mov dh,[bp+2+_dos_sect_read.head]
+ mov dl,[bp+2+_dos_sect_read.drv]
+ mov cl,[bp+2+_dos_sect_read.sector]
+ mov ch,[bp+2+_dos_sect_read.track]
- check_tar(1);
- mangle_tarvol();
+ mov bx,[bp+2+_dos_sect_read.loadaddr]
- rewind(fd);
- if( fwrite(tarblock, sizeof(tarblock), 1, fd) != 1 )
- { fprintf(stderr, "Cannot write boot block\n"); exit(1); }
+ mov ax,#$0201
+ int $13
+ jc read_err
+ mov ax,#0
+read_err:
- rewind(fd);
- if( fread(tarblock, sizeof(tarblock), 1, fd) != 1 )
- { fprintf(stderr, "Cannot re-read boot block\n"); exit(1); }
+ pop bp
+#endasm
+}
+#endif
- if( fread(tarblock, sizeof(tarblock), 1, fd) == 1 && head.linkflag == '0' )
- printf("Boot block installed to boot file %s\n", head.name);
+#ifdef __MSDOS__
+dos_sect_write(drv, track, head, sector, loadaddr)
+{
+#asm
+ push bp
+ mov bp,sp
- fclose(fd);
- exit(0);
+ push ds
+ pop es
+
+ mov dh,[bp+2+_dos_sect_write.head]
+ mov dl,[bp+2+_dos_sect_write.drv]
+ mov cl,[bp+2+_dos_sect_write.sector]
+ mov ch,[bp+2+_dos_sect_write.track]
+
+ mov bx,[bp+2+_dos_sect_write.loadaddr]
+
+ mov ax,#$0301
+ int $13
+ jc write_err
+ mov ax,#0
+write_err:
+
+ pop bp
+#endasm
}
+#endif
+
+/**************************************************************************/
+
+struct tar_head {
+ char name[100];
+ char mode[8];
+ char uid[8];
+ char gid[8];
+ char size[12];
+ char mtime[12];
+ char chksum[8];
+ char linkflag;
+ char linkname[100];
+ char magic[8];
+ char uname[32];
+ char gname[32];
+ char devmajor[8];
+ char devminor[8];
+ char padding[167];
+} ;
+
+#define buff_tar (*(struct tar_head*) buffer)
+#define boot_tar (*(struct tar_head*) tarboot_data)
unsigned int oct(s)
char *s;
@@ -109,46 +334,46 @@ char *s;
return val;
}
-check_tar(fatal)
-int fatal;
+check_tar()
{
char vbuf[100], *p;
unsigned int csum = 0;
long osum = -1;
- osum = oct(head.chksum);
- memset(head.chksum, ' ', sizeof(head.chksum));
+ for(p=buffer; p<buffer+512; p++)
+ if( *p ) goto not_zapped;
+ /* Block zapped, ok */
+ return 0;
+not_zapped:
+
+ osum = oct(buff_tar.chksum);
+ memset(buff_tar.chksum, ' ', sizeof(buff_tar.chksum));
- for(p=tarblock; p<tarblock+sizeof(tarblock); p++)
+ for(p=buffer; p<buffer+512; p++)
csum += (*p & 0xFF);
if( csum != osum )
{
fprintf(stderr, "TAR file checksum failed, this isn't a tar file.\n");
- if(fatal) exit(9);
- return -1;
+ exit(9);
}
- if( head.linkflag != 'V' )
+ if( buff_tar.linkflag != 'V' )
{
fprintf(stderr, "Tar file doesn't start with a volume label\n");
- if(fatal) exit(8);
- return -1;
+ exit(8);
}
- strcpy(vbuf, boothead.name); strcat(vbuf, " Volume 1");
- if( !force && strcmp(boothead.name, head.name) != 0
- && strcmp(vbuf, head.name) != 0 )
+ strcpy(vbuf, boot_tar.name); strcat(vbuf, " Volume 1");
+ if( strcmp(boot_tar.name, buff_tar.name) != 0
+ && strcmp(vbuf, buff_tar.name) != 0 )
{
- fprintf(stderr, "Volume is labeled as '%s' not '%s'\n",
- head.name, boothead.name);
- fprintf(stderr, "Use -f flag to force write\n");
- if(fatal) exit(1);
- return -1;
+ fprintf(stderr, "WARNING: Volume is labeled as '%s' not '%s'\n",
+ buff_tar.name, boot_tar.name);
}
return 0;
}
-mangle_tarvol()
+copy_tarblock()
{
char lbuf[20];
char * p;
@@ -157,31 +382,232 @@ mangle_tarvol()
struct tar_head temp;
- temp = boothead;
+ temp = boot_tar;
/* Copy preserved fields
*/
- memcpy(temp.mtime, head.mtime, sizeof(temp.mtime));
-
- memset(temp.name, 0x90, 16);
- for(i=0; head.name[i] && head.name[i] != ' ' && i<14; i++)
+ if( buff_tar.name[0] )
{
- int ch = head.name[i];
- if( islower(ch) ) ch = toupper(ch);
- if( strchr("/?@ABCDEFGHIJKLMNO", ch) == 0 )
- ch = '?';
- temp.name[i] = ch;
+ memcpy(temp.mtime, buff_tar.mtime, sizeof(temp.mtime));
+
+ memset(temp.name, 0x90, 16);
+ for(i=0; buff_tar.name[i] && buff_tar.name[i] != ' ' && i<14; i++)
+ {
+ int ch = buff_tar.name[i];
+ if( islower(ch) ) ch = toupper(ch);
+ if( strchr("/?@ABCDEFGHIJKLMNO", ch) == 0 )
+ ch = '?';
+ temp.name[i] = ch;
+ }
+ temp.name[i++] = 0;
+ temp.name[i] = 0xC0;
}
- temp.name[i++] = 0;
- temp.name[i] = 0xC0;
+ else
+ sprintf(temp.mtime, "%11lo", time((void*)0));
+
+ buff_tar = temp;
- head = temp;
- /* Calculate the checksum */
- memset(head.chksum, ' ', sizeof(head.chksum));
+ /* Re-calculate the checksum */
+ memset(buff_tar.chksum, ' ', sizeof(buff_tar.chksum));
- for(p=tarblock; p<tarblock+sizeof(tarblock); p++)
+ for(p=buffer; p<buffer+512; p++)
csum += (*p & 0xFF);
- sprintf(head.chksum, "%7o", csum);
+ sprintf(buff_tar.chksum, "%7o", csum);
+
+ printf("Boot block installed");
+ if( ((struct tar_head*)buffer)[1].name[0] )
+ printf(" to boot file '%s'\n",
+ ((struct tar_head*)buffer)[1].name);
+ else
+ printf(", use 'tar -r' to add executable\n");
+}
+
+/**************************************************************************/
+
+#define DOS_SYSID 0
+#define DOS_SECT 1
+#define DOS_CLUST 2
+#define DOS_RESV 3
+#define DOS_NFAT 4
+#define DOS_NROOT 5
+#define DOS_MAXSECT 6
+#define DOS_MEDIA 7
+#define DOS_FATLEN 8
+#define DOS_SPT 9
+#define DOS_HEADS 10
+#define DOS_HIDDEN 11
+#define DOS4_MAXSECT 12
+#define DOS4_PHY_DRIVE 13
+#define DOS4_SERIAL 14
+#define DOS4_LABEL 15
+#define DOS4_FATTYPE 16
+
+struct bootfields {
+ int offset;
+ int length;
+ int value;
+}
+ dosflds[] =
+{
+ { 0x03, 8, 0},
+ { 0x0B, 2, 0},
+ { 0x0D, 1, 0},
+ { 0x0E, 2, 0},
+ { 0x10, 1, 0},
+ { 0x11, 2, 0},
+ { 0x13, 2, 0},
+ { 0x15, 1, 0},
+ { 0x16, 2, 0},
+ { 0x18, 2, 0},
+ { 0x1A, 2, 0},
+ { 0x1C, 4, 0},
+ { 0x20, 4, 0},
+ { 0x24, 1, 0},
+ { 0x27, 4, 0},
+ { 0x2B, 11, 0},
+ { 0x36, 8, 0},
+ { -1,0,0}
+};
+
+print_super(bootsect)
+char * bootsect;
+{
+static char * fieldnames[] = {
+ "System ID",
+ "Sector size",
+ "Cluster size",
+ "Reserved sectors",
+ "FAT count",
+ "Root dir entries",
+ "Sector count (=0 if large FS)",
+ "Media code",
+ "FAT length",
+ "Sect/Track",
+ "Heads",
+ "Hidden sectors (Partition offset)",
+ "Large FS sector count",
+ "Phys drive",
+ "Serial number",
+ "Disk Label (DOS 4+)",
+ "FAT type",
+ 0
+};
+ int i;
+
+ for(i=0; dosflds[i].offset >= 0; i++)
+ {
+ printf("%-35s", fieldnames[i]);
+ if( dosflds[i].length <= 4 )
+ {
+ long v = 0; int j;
+ for(j=dosflds[i].length-1; j>=0; j--)
+ {
+ v = v*256 + (0xFF&( bootsect[dosflds[i].offset+j] ));
+ }
+ printf("%ld\n", v);
+ }
+ else
+ {
+ int ch, j;
+ for(j=0; j<dosflds[i].length; j++)
+ {
+ ch = bootsect[dosflds[i].offset+j];
+ if( ch <= ' ' || ch > '~' ) putchar('.');
+ else putchar(ch);
+ }
+ putchar('\n');
+ }
+ }
+}
+
+decode_super(bootsect)
+char * bootsect;
+{
+ int i;
+
+ for(i=0; dosflds[i].offset >= 0; i++)
+ {
+ if( dosflds[i].length <= 4 )
+ {
+ long v = 0; int j;
+ for(j=dosflds[i].length-1; j>=0; j--)
+ {
+ v = v*256 + (0xFF&( bootsect[dosflds[i].offset+j] ));
+ }
+ dosflds[i].value = v;
+ }
+ else
+ dosflds[i].value = 0;
+ }
+}
+
+save_super(bootsect)
+char * bootsect;
+{
+ FILE * fd;
+ fd = fopen("makeboot.sav", "wb");
+ fwrite(bootsect, 1024, 1, fd);
+ fclose(fd);
+}
+
+/**************************************************************************/
+
+check_msdos()
+{
+ decode_super(buffer);
+ if( dosflds[DOS_CLUST].value == 0 ) /* MSDOS v1.0 */
+ dosflds[DOS_CLUST].value = 1;
+
+ if( dosflds[DOS_MEDIA].value < 0xF0 )
+ fprintf(stderr, "Dos media descriptor is invalid\n");
+ else if( dosflds[DOS_MEDIA].value != (0xFF&buffer[512])
+ && dosflds[DOS_RESV].value == 1 )
+ fprintf(stderr, "Dos media descriptor check failed\n");
+ else
+ {
+ disk_sect = dosflds[DOS_SPT].value;
+ disk_head = dosflds[DOS_HEADS].value;
+ disk_trck = dosflds[DOS_MAXSECT].value/disk_head/disk_sect;
+ return;
+ }
+ exit(2);
+}
+
+check_simpledos()
+{
+ int numclust;
+ char * err = 0;
+ check_msdos();
+
+ /* Work out how many real clusters there are */
+ numclust = ( dosflds[DOS_MAXSECT].value
+ - dosflds[DOS_RESV].value
+ - dosflds[DOS_NFAT].value * dosflds[DOS_FATLEN].value
+ - ((dosflds[DOS_NROOT].value+15)/16)
+ ) / dosflds[DOS_MAXSECT].value + 2;
+
+ if( dosflds[DOS_NFAT].value > 2 )
+ err = "Too many fat copies on disk";
+ else if( dosflds[DOS_HIDDEN].value != 0 )
+ err = "Dubious MSDOS floppy, it's got hidden sectors.";
+ else if( dosflds[DOS_NROOT].value < 15 )
+ err = "Root directory has unreasonable size.";
+ else if( dosflds[DOS_SECT].value != 512 )
+ err = "Drive sector size isn't 512 bytes sorry no-go.";
+ else if( dosflds[DOS_HEADS].value != 2 )
+ err = "Drive doesn't have two heads, this is required.";
+ else if( numclust > 0xFF0 )
+ err = "Filesystem has a 16 bit fat, only 12bits allowed.";
+ else if( dosflds[DOS_RESV].value + dosflds[DOS_FATLEN].value >
+ dosflds[DOS_SPT].value )
+ err = "The bootblock needs all of fat1 on the first track.";
+ else
+ return;
+
+ fprintf(stderr, "ERROR: %s\n\n", err);
+ print_super(buffer);
+ exit(2);
}
+/**************************************************************************/