home *** CD-ROM | disk | FTP | other *** search
- /*
- * 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;
- }
-
-