home *** CD-ROM | disk | FTP | other *** search
/ Chip 1998 February / CHIP_2_98.iso / misc / src / trees / syslinux / source / syslinux.c < prev    next >
C/C++ Source or Header  |  1996-11-02  |  7KB  |  281 lines

  1. /*
  2.  * syslinux.c
  3.  *
  4.  * Creates a Linux bootable MS-DOS floppy
  5.  *
  6.  * Copyright (C) 1994-96 H. Peter Anvin
  7.  *
  8.  */
  9.  
  10. #include <stdio.h>
  11. #include <stdlib.h>
  12. #include <dos.h>
  13. #include <string.h>
  14.  
  15. extern char boot_sector[];
  16. extern char ldlinux_sys[];
  17. extern unsigned int ldlinux_len;
  18.  
  19. #define BOOTSECT_LEN    512         /* Length of the boot sector */
  20. #define RETRIES         4           /* Make 4 read/write attempts */
  21.  
  22. typedef unsigned int word;
  23. typedef unsigned char byte;
  24. typedef unsigned long dword;
  25.  
  26. struct bootsector
  27. {
  28.     byte jump[3];
  29.     byte oemname[8];
  30.     word bytespersec;
  31.     byte secperclust;
  32.     word ressectors;
  33.     byte fats;
  34.     word rootdirents;
  35.     word sectors;
  36.     byte media;
  37.     word fatsecs;
  38.     word secpertrack;
  39.     word heads;
  40.     dword hiddensecs;
  41.     dword hugesectors;
  42.     byte drivenumber;
  43.     byte reserved1;
  44.     byte bootsignature;
  45.     dword volumeid;
  46.     byte volumelabel[11];
  47.     byte filesystype[8];
  48.     byte bootstrap_code[448];
  49.     word boot_magic;
  50. };
  51.  
  52. struct diskio
  53. {
  54.     unsigned long sector;
  55.     unsigned count;
  56.     void far *buffer;
  57. };
  58.  
  59. /*
  60.  * read_boot_sect:  read the boot sector of the specified drive into the
  61.  *                  given buffer, using the DOS function INT 25h
  62.  */
  63. int read_boot_sect(int drive, void *buffer, int huge_disk)
  64. {
  65.     int retry_ctr, err;
  66.     struct diskio huge_buf;
  67.     unsigned sectors;
  68.  
  69.     if ( huge_disk )
  70.     {
  71.         huge_buf.buffer = buffer;
  72.         huge_buf.sector = 0;
  73.         huge_buf.count = 1;
  74.         buffer = &huge_buf;
  75.         sectors = 0xFFFF;
  76.     }
  77.     else
  78.         sectors = 1;            /* Read one sector */
  79.  
  80.     err = 0;
  81.     for ( retry_ctr = RETRIES ; retry_ctr ; retry_ctr-- )
  82.     {
  83.         _BX = (unsigned) buffer;
  84.         _CX = sectors;
  85.         _DX = 0;                    /* Sector zero = boot sector */
  86.         _AL = drive;
  87.         geninterrupt(0x25);
  88.         asm pop ax;                 /* Flags left on the stack */
  89.         asm sti;                    /* Make sure interrupts are on */
  90.         asm jnc read_ok;
  91.     }
  92.     err = 1;                        /* Operation failed */
  93. read_ok:
  94.     return err;
  95. }
  96.  
  97. /*
  98.  * write_boot_sect:  read the boot sector of the specified drive into the
  99.  *                   given buffer, using the DOS function INT 26h
  100.  */
  101. int write_boot_sect(int drive, void *buffer, int huge_disk)
  102. {
  103.     int retry_ctr, err, flg;
  104.     struct diskio huge_buf;
  105.     unsigned sectors;
  106.  
  107.     if ( huge_disk )
  108.     {
  109.         huge_buf.buffer = buffer;
  110.         huge_buf.sector = 0;
  111.         huge_buf.count = 1;
  112.         buffer = &huge_buf;
  113.         sectors = 0xFFFF;
  114.     }
  115.     else
  116.         sectors = 1;            /* Write one sector */
  117.  
  118.  
  119.     err = 0;
  120.     for ( retry_ctr = RETRIES ; retry_ctr ; retry_ctr-- )
  121.     {
  122.         _BX = (unsigned) buffer;
  123.         _CX = sectors;
  124.         _DX = 0;                    /* Sector zero = boot sector */
  125.         _AL = drive;
  126.         geninterrupt(0x26);
  127.         asm pop ax;                 /* Flags left on the stack */
  128.         asm sti;                    /* Make sure interrupts are on */
  129.         asm jnc write_ok;
  130.     }
  131.     err = 1;                        /* Operation failed */
  132. write_ok:
  133.     return err;
  134. }
  135.  
  136. /*
  137.  * disk_is_huge:    Check if a disk is larger than 64K sectors (32 Mb)
  138.  */
  139. int disk_is_huge(int drive, int *sectsize)
  140. {
  141.     unsigned secperclust, bytespersec, clusters;
  142.     unsigned long sectors;
  143.  
  144.     _DL = drive+1;
  145.     _AH = 0x36;
  146.     geninterrupt(0x21);
  147.     *sectsize = _CX;
  148.     asm mul dx;
  149.  
  150.     return _DX;
  151. }
  152.  
  153. /*
  154.  * usage:   Complain to the user, and exit
  155.  */
  156. void usage(void)
  157. {
  158.     fprintf(stderr, "Usage:\n"
  159.                     "         SYSLINUX drive:\n");
  160.     exit(1);
  161. }
  162.  
  163. /*
  164.  * Main program
  165.  *
  166.  */
  167. int main(int argc, char *argv[])
  168. {
  169.     int drive, huge_disk, sectsize;
  170.     char *cmd_ptr;
  171.     int cmd_maxlen, cmd_len;
  172.     struct bootsector *orig_sect;
  173.     static char *ld_name = "?:\LDLINUX.SYS";
  174.     FILE *ld;
  175.     int i;
  176.     unsigned dosattr;
  177.  
  178.  
  179.     /* If no drive specified */
  180.     if ( argc < 2 || strlen(argv[1]) != 2 || argv[1][1] != ':' )
  181.         usage();
  182.  
  183.     drive = argv[1][0] | 0x20;
  184.     if ( drive < 'a' || drive > 'z' )
  185.         usage();
  186.  
  187.     if ( argc > 2 )
  188.     {
  189.         fprintf(stderr,
  190.         "Warning: specifying the default command on the SYSLINUX command\n"
  191.         "         line is no longer supported.  Create a SYSLINUX.CFG file\n"
  192.         "         with a \"default\" line instead.  The default kernel name\n"
  193.         "         in the absence of a SYSLINUX.CFG file is now always\n"
  194.         "         \"linux\".\n");
  195.     }
  196.  
  197.     drive -= 'a';
  198.     huge_disk = disk_is_huge(drive, §size);
  199.  
  200.     orig_sect = malloc(sectsize);
  201.     if ( !orig_sect )
  202.     {
  203.         fprintf(stderr, "Error: could not malloc %d bytes\n", sectsize);
  204.         exit(1);
  205.     }
  206.  
  207.     /* Read in the original boot sector */
  208.     if ( read_boot_sect(drive, orig_sect, huge_disk) )
  209.     {
  210.         fprintf(stderr, "Error: could not read original boot sector\n");
  211.         exit(1);
  212.     }
  213.  
  214.     /* Make sure we're dealing with something sane here */
  215.     if ( orig_sect->bytespersec != 512 )
  216.     {
  217.         fprintf(stderr, "Error: Bytes per sector is not 512\n");
  218.         exit(1);
  219.     }
  220.     if ( orig_sect->boot_magic != 0xAA55 )
  221.     {
  222.         fprintf(stderr, "Error: Boot sector signature not found on disk\n");
  223.         exit(1);
  224.     }
  225.     if ( orig_sect->bootsignature == 0x29 &&
  226.          memcmp(orig_sect->filesystype, "FAT12   ", 8) )
  227.     {
  228.         fprintf(stderr, "Error: Filesystem is not type FAT12 (or "
  229.                         "ancient format program)\n");
  230.         exit(1);
  231.     }
  232.  
  233.     /* Very well, copy the thing */
  234.     memcpy( &boot_sector[0x0B], &(orig_sect->bytespersec), 0x33 );
  235.  
  236.     /* Write out the new boot sector */
  237.     if ( write_boot_sect(drive, boot_sector, huge_disk) )
  238.     {
  239.         fprintf(stderr, "Error: could not write new boot sector\n");
  240.         exit(1);
  241.     }
  242.  
  243.     /* Get full name of LDLINUX.SYS */
  244.     *ld_name = drive+'A';
  245.  
  246.     /* Clear readonly, hidden, system flags (but remember them) */
  247.     /* If these call fail, assume it is because the file doesn't exist */
  248.     if (_dos_getfileattr(ld_name, &dosattr))
  249.         dosattr = FA_ARCH;      /* default attributes */
  250.     else
  251.     {
  252.         dosattr &= ~(FA_RDONLY|FA_HIDDEN|FA_SYSTEM);
  253.         _dos_setfileattr(ld_name, dosattr);
  254.     }
  255.  
  256.     unlink(ld_name);            /* If it exists, delete it */
  257.     ld = fopen(ld_name, "wb");
  258.     if ( !ld )
  259.     {
  260.         perror("Writing LDLINUX.SYS");
  261.         exit(1);
  262.     }
  263.     if ( fwrite(ldlinux_sys,1,ldlinux_len,ld) < ldlinux_len )
  264.     {
  265.         perror("Writing LDLINUX.SYS");
  266.         fclose(ld);
  267.         exit(1);
  268.     }
  269.     fclose(ld);
  270.  
  271.     /* Set readonly flag - if you want to have the hidden flag set by
  272.        default, you can add FA_HIDDEN here.  I suggest not setting FA_SYSTEM
  273.        since it implies a file that must not be moved, which is not the
  274.        case for LDLINUX.SYS. */
  275.     _dos_setfileattr(ld_name, dosattr|FA_ARCH|FA_RDONLY);
  276.  
  277.     fprintf(stderr, "The Linux boot system was successfully installed.\n");
  278.     return 0;
  279. }
  280.  
  281.