home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Chip 1998 February
/
CHIP_2_98.iso
/
misc
/
src
/
trees
/
syslinux
/
source
/
syslinux.c
< prev
next >
Wrap
C/C++ Source or Header
|
1996-11-02
|
7KB
|
281 lines
/*
* syslinux.c
*
* Creates a Linux bootable MS-DOS floppy
*
* Copyright (C) 1994-96 H. Peter Anvin
*
*/
#include <stdio.h>
#include <stdlib.h>
#include <dos.h>
#include <string.h>
extern char boot_sector[];
extern char ldlinux_sys[];
extern unsigned int ldlinux_len;
#define BOOTSECT_LEN 512 /* Length of the boot sector */
#define RETRIES 4 /* Make 4 read/write attempts */
typedef unsigned int word;
typedef unsigned char byte;
typedef unsigned long dword;
struct bootsector
{
byte jump[3];
byte oemname[8];
word bytespersec;
byte secperclust;
word ressectors;
byte fats;
word rootdirents;
word sectors;
byte media;
word fatsecs;
word secpertrack;
word heads;
dword hiddensecs;
dword hugesectors;
byte drivenumber;
byte reserved1;
byte bootsignature;
dword volumeid;
byte volumelabel[11];
byte filesystype[8];
byte bootstrap_code[448];
word boot_magic;
};
struct diskio
{
unsigned long sector;
unsigned count;
void far *buffer;
};
/*
* read_boot_sect: read the boot sector of the specified drive into the
* given buffer, using the DOS function INT 25h
*/
int read_boot_sect(int drive, void *buffer, int huge_disk)
{
int retry_ctr, err;
struct diskio huge_buf;
unsigned sectors;
if ( huge_disk )
{
huge_buf.buffer = buffer;
huge_buf.sector = 0;
huge_buf.count = 1;
buffer = &huge_buf;
sectors = 0xFFFF;
}
else
sectors = 1; /* Read one sector */
err = 0;
for ( retry_ctr = RETRIES ; retry_ctr ; retry_ctr-- )
{
_BX = (unsigned) buffer;
_CX = sectors;
_DX = 0; /* Sector zero = boot sector */
_AL = drive;
geninterrupt(0x25);
asm pop ax; /* Flags left on the stack */
asm sti; /* Make sure interrupts are on */
asm jnc read_ok;
}
err = 1; /* Operation failed */
read_ok:
return err;
}
/*
* write_boot_sect: read the boot sector of the specified drive into the
* given buffer, using the DOS function INT 26h
*/
int write_boot_sect(int drive, void *buffer, int huge_disk)
{
int retry_ctr, err, flg;
struct diskio huge_buf;
unsigned sectors;
if ( huge_disk )
{
huge_buf.buffer = buffer;
huge_buf.sector = 0;
huge_buf.count = 1;
buffer = &huge_buf;
sectors = 0xFFFF;
}
else
sectors = 1; /* Write one sector */
err = 0;
for ( retry_ctr = RETRIES ; retry_ctr ; retry_ctr-- )
{
_BX = (unsigned) buffer;
_CX = sectors;
_DX = 0; /* Sector zero = boot sector */
_AL = drive;
geninterrupt(0x26);
asm pop ax; /* Flags left on the stack */
asm sti; /* Make sure interrupts are on */
asm jnc write_ok;
}
err = 1; /* Operation failed */
write_ok:
return err;
}
/*
* disk_is_huge: Check if a disk is larger than 64K sectors (32 Mb)
*/
int disk_is_huge(int drive, int *sectsize)
{
unsigned secperclust, bytespersec, clusters;
unsigned long sectors;
_DL = drive+1;
_AH = 0x36;
geninterrupt(0x21);
*sectsize = _CX;
asm mul dx;
return _DX;
}
/*
* usage: Complain to the user, and exit
*/
void usage(void)
{
fprintf(stderr, "Usage:\n"
" SYSLINUX drive:\n");
exit(1);
}
/*
* Main program
*
*/
int main(int argc, char *argv[])
{
int drive, huge_disk, sectsize;
char *cmd_ptr;
int cmd_maxlen, cmd_len;
struct bootsector *orig_sect;
static char *ld_name = "?:\LDLINUX.SYS";
FILE *ld;
int i;
unsigned dosattr;
/* If no drive specified */
if ( argc < 2 || strlen(argv[1]) != 2 || argv[1][1] != ':' )
usage();
drive = argv[1][0] | 0x20;
if ( drive < 'a' || drive > 'z' )
usage();
if ( argc > 2 )
{
fprintf(stderr,
"Warning: specifying the default command on the SYSLINUX command\n"
" line is no longer supported. Create a SYSLINUX.CFG file\n"
" with a \"default\" line instead. The default kernel name\n"
" in the absence of a SYSLINUX.CFG file is now always\n"
" \"linux\".\n");
}
drive -= 'a';
huge_disk = disk_is_huge(drive, §size);
orig_sect = malloc(sectsize);
if ( !orig_sect )
{
fprintf(stderr, "Error: could not malloc %d bytes\n", sectsize);
exit(1);
}
/* Read in the original boot sector */
if ( read_boot_sect(drive, orig_sect, huge_disk) )
{
fprintf(stderr, "Error: could not read original boot sector\n");
exit(1);
}
/* Make sure we're dealing with something sane here */
if ( orig_sect->bytespersec != 512 )
{
fprintf(stderr, "Error: Bytes per sector is not 512\n");
exit(1);
}
if ( orig_sect->boot_magic != 0xAA55 )
{
fprintf(stderr, "Error: Boot sector signature not found on disk\n");
exit(1);
}
if ( orig_sect->bootsignature == 0x29 &&
memcmp(orig_sect->filesystype, "FAT12 ", 8) )
{
fprintf(stderr, "Error: Filesystem is not type FAT12 (or "
"ancient format program)\n");
exit(1);
}
/* Very well, copy the thing */
memcpy( &boot_sector[0x0B], &(orig_sect->bytespersec), 0x33 );
/* Write out the new boot sector */
if ( write_boot_sect(drive, boot_sector, huge_disk) )
{
fprintf(stderr, "Error: could not write new boot sector\n");
exit(1);
}
/* Get full name of LDLINUX.SYS */
*ld_name = drive+'A';
/* Clear readonly, hidden, system flags (but remember them) */
/* If these call fail, assume it is because the file doesn't exist */
if (_dos_getfileattr(ld_name, &dosattr))
dosattr = FA_ARCH; /* default attributes */
else
{
dosattr &= ~(FA_RDONLY|FA_HIDDEN|FA_SYSTEM);
_dos_setfileattr(ld_name, dosattr);
}
unlink(ld_name); /* If it exists, delete it */
ld = fopen(ld_name, "wb");
if ( !ld )
{
perror("Writing LDLINUX.SYS");
exit(1);
}
if ( fwrite(ldlinux_sys,1,ldlinux_len,ld) < ldlinux_len )
{
perror("Writing LDLINUX.SYS");
fclose(ld);
exit(1);
}
fclose(ld);
/* Set readonly flag - if you want to have the hidden flag set by
default, you can add FA_HIDDEN here. I suggest not setting FA_SYSTEM
since it implies a file that must not be moved, which is not the
case for LDLINUX.SYS. */
_dos_setfileattr(ld_name, dosattr|FA_ARCH|FA_RDONLY);
fprintf(stderr, "The Linux boot system was successfully installed.\n");
return 0;
}