#include <stdio.h>
#include <dos.h>
#include <conio.h>
#include <ctype.h>

typedef struct _EBPB_ 
{
  unsigned sectsize;
  char clustsize;
  unsigned ressecs;
  char fatcnt;
  unsigned rootsize;
  unsigned totsecs;
  char media;
  unsigned fatsize;
  unsigned seccnt;
  unsigned headcnt;
  unsigned hiddensec_low;
  unsigned hiddensec_hi;
  unsigned long drvsecs;
} EBPB;

typedef struct _BOOT_
{
  char jmp[3];
  char oem[8];
  EBPB bpb;
  char drive;
  char reserved;
  char signature;
  unsigned volser_lo;
  unsigned volser_hi;
  char label[11];
  char fat_format[8];
  char boot_code[450];
} BOOT;

int getboot(BOOT far *boot, int drive);

int main(void)
{
  char boot[512];
  BOOT far* boot_rec = (BOOT far*)boot;
  int i, status;
  char drive;

  printf("\nЧтение загрузочной записи логического диска"
    "\n   (C)Фролов А., 1995\n");

  // Запрашиваем диск, для которого необходимо
  // выполнить чтение загрузочной записи
  printf(
    "\nВведите обозначение диска, для просмотра"
    "\nзагрузочной записи (A, B, ...):");
  drive = getche();

  // Вычисляем номер дисковода
  drive = toupper(drive) - 'A';

  // Читаем загрузочную запись в буфер
    status = getboot((BOOT far*)boot_rec, drive);

  // Если произошла ошибка (например, неправильно
  // указано обозначение диска),
  // завершаем работу программы
  if(status)
  {
    printf("\nОшибка при чтении загрузочного сектора");
    return(-1);
  }

  printf("\nСодержимое загрузочного "
    "сектора для диска %c", drive + 'A');
  printf("\n"
    "\nOEM - название фирмы и версия DOS - ");

  for(i = 0; i < 8; i++)
    printf("%c", boot_rec->oem[i]);

  printf("\nНомер диска                       - %x"
    "\nПризнак расширенной BOOT-записи   - %c"
    "\nСерийный номер диска              - %04X-%04X"
    "\nМетка диска                       - ",
    (unsigned char)boot_rec->drive,
    boot_rec->signature,
    boot_rec->volser_hi,
    boot_rec->volser_lo);

  for(i = 0; i < 11; i++)
    printf("%c", boot_rec->label[i]);

  printf("\nФормат FAT                        - ");
  for(i = 0; i < 8; i++)
    printf("%c", boot_rec->fat_format[i]);

  printf("\n\nИнформация из BPB:");
  printf("\nКоличество байтов в секторе       - %d"
    "\nКоличество секторов в кластере    - %d"
    "\nЗарезервировано секторов          - %d"
    "\nКоличество копий FAT              - %d"
    "\nМакс. количество файлов в корневом каталоге - %d"
    "\nОбщее количество секторов на диске          - %d"
    "\nБайт-описатель среды              - %x"
    "\nКоличество секторов в FAT         - %d",
    boot_rec->bpb.sectsize, boot_rec->bpb.clustsize,
    boot_rec->bpb.ressecs,  boot_rec->bpb.fatcnt,
    boot_rec->bpb.rootsize, boot_rec->bpb.totsecs,
    (unsigned char)boot_rec->bpb.media,
    boot_rec->bpb.fatsize);

  printf("\n\nИнформация из расширения BPB:");
  printf("\nСекторов на дорожке               - %d"
    "\nКоличество головок                - %d"
    "\nСкрытых секторов для диска < 32 Mбайт  - %d"
    "\nСкрытых секторов для диска >= 32 Mбайт - %d"
    "\nВсего секторов на диске           - %u",
    boot_rec->bpb.seccnt, boot_rec->bpb.headcnt,
    boot_rec->bpb.hiddensec_low,
    boot_rec->bpb.hiddensec_hi,
    boot_rec->bpb.totsecs);

  return 0;
}

/**
* getboot
*
* Прочитать загрузочную запись
*
* int getmboot(BOOT far *boot, int drive);
*
*  boot   - указатель на буфер, в который
*           будет прочитана загрузочная запись
*
*  drive  - номер физического НМД
*           (0 - первый НМД, 1 - второй, ...)
**/

int getboot(BOOT far *boot, int drive)
{
  union REGS reg;
  struct SREGS segreg;

  reg.x.ax  = drive;
  reg.x.bx  = FP_OFF(boot);
  segreg.ds = FP_SEG(boot);
  reg.x.cx  = 1;
  reg.x.dx  = 0;
  int86x(0x25, &reg, &reg, &segreg);

  // Извлекаем из стека оставшееся там после
  // вызова прерывания слово
  asm pop ax
  return(reg.x.cflag);
}
