sch@oce.nl (Jakob Schripsema) (07/02/87)
I got a change to use diskpart on a DOS3.1 disk. It seems to work. The FDISK version for DOS 3.1 seems to use entry 4 for the DOS partition, the 2.1 version used entry 1. I also added 2 new commands : load boot sector from a file and save boot sector to a file. When using the DOS version of diskpart this gives you an easy way to create a backup of the original bootsector and restore it later on. WARNING : I did not test this version of diskpart under Minix !!!!! JaKob Schripsema (sch@oce.nl) ======================================================== This note does not necessarily represent the position of Oce-Nederland B.V. Therefore no liability or responsibility for whatever will be accepted. ======================================================== ------- Cut here ---------------------- /* * Diskpart. Display and modify partition table * Written by Jakob Schripsema * * First run the DOS utilities FDISK and FORMAT. FDISK * puts the boot code in sector 0. * Then run diskpart * * diskpart /dev/hdx (MINIX) * diskpart x: (DOS) * * Compiling * * cc -o diskpart -DUNIX diskpart.c (MINIX) * cl -DDOS diskpart.c (DOS with MS C compiler) */ #include <stdio.h> #ifdef DOS #include <dos.h> #endif /* * Constants */ #define NHEAD 4 /* # heads */ #define NSEC 17 /* sectors / track */ #define SECSIZE 512 /* sector size */ #define OK 0 #define ERR 1 #define TABLEOFFSET 0x1be /* offset in boot sector*/ /* * Description of entry in partition table */ struct part_entry { char bootind; /* boot indicator 0/0x80 */ char start_head; /* head value for first sector */ char start_sec; /* sector value for first sector*/ char start_cyl; /* track value for first sector */ char sysind; /* system indicator 00=?? 01=DOS*/ char last_head; /* head value for last sector */ char last_sec; /* sector value for last sector */ char last_cyl; /* track value for last sector */ long lowsec; /* logical first sector */ long size; /* size of partion in sectors */ }; /* * Globals */ char secbuf[SECSIZE]; char *devname; char *dosstr = " DOS "; char *ndosstr = "Non-DOS"; #ifdef DOS union REGS regs; struct SREGS sregs; int drivenum; #endif #ifdef UNIX int devfd; #endif main(argc,argv) int argc; char *argv[]; { char ch; /* init */ if (argc != 2) { printf("Usage: diskpart drive\n"); exit(1); } devname = argv[1]; getboot(secbuf); /* get boot sector */ do { dpl_partitions(); printf("\nchange write load save hexdump quit (c/w/l/s/x/q) ? "); ch = get_a_char(); putchar('\n'); switch (ch) { case 'c' : change_table(); break; case 'w' : if (chk_table() == OK) { putboot(secbuf); exit(0); } break; case 'l' : load_from_file(); break; case 's' : save_to_file(); break; case 'x' : dump_table(); break; case 'q' : exit(0); default : printf(" %c ????\n",ch); } } while (1); } /* * Read boot sector */ #ifdef DOS getboot(buffer) char *buffer; { segread(&sregs); /* get ds */ if (devname[1] != ':') { printf("Invalid drive %s\n",devname); exit(1); } if (*devname >= 'a') *devname += 'A' - 'a'; drivenum = (*devname - 'C') & 0xff; if (drivenum < 0 || drivenum > 7) { printf("Funny drive number %d\n",drivenum); exit(1); } regs.x.ax = 0x201; /* read 1 sectors */ regs.h.ch = 0; /* track */ regs.h.cl = 1; /* first sector = 1 */ regs.h.dh = 0; /* head = 0 */ regs.h.dl = 0x80+drivenum;/* drive = 0 */ sregs.es = sregs.ds; /* buffer address */ regs.x.bx = (int)secbuf; int86x(0x13,®s,®s,&sregs); if (regs.x.cflag) { printf("Cannot read boot sector\n"); exit(1); } } #endif #ifdef UNIX getboot(buffer) char *buffer; { devfd = open(devname,2); if (devfd < 0) { printf("Cannot open device %s\n",devname); exit(1); } if (read(devfd,buffer,SECSIZE) != SECSIZE) { printf("Cannot read boot sector\n"); exit(2); } } #endif /* * Write boot sector */ #ifdef DOS putboot(buffer) char *buffer; { regs.x.ax = 0x301; /* read 1 sectors */ regs.h.ch = 0; /* track */ regs.h.cl = 1; /* first sector = 1 */ regs.h.dh = 0; /* head = 0 */ regs.h.dl = 0x80+drivenum;/* drive = 0 */ sregs.es = sregs.ds; /* buffer address */ regs.x.bx = (int)secbuf; int86x(0x13,®s,®s,&sregs); if (regs.x.cflag) { printf("Cannot write boot sector\n"); exit(1); } } #endif #ifdef UNIX putboot(buffer) char *buffer; { int r; if (lseek(devfd,0L,0) < 0) { printf("Seek error during write\n"); exit(1); } if (write(devfd,buffer,SECSIZE) != SECSIZE) { printf("Write error\n"); exit(1); } sync(); } #endif /* * Load buffer from file */ load_from_file() { char file[80]; int fd; printf("Load from ? "); gets(file); #ifdef UNIX fd = open(file,0); #endif #ifdef DOS fd = open(file,0x8000); #endif if (fd < 0) { fprintf(stderr,"Cannot load from %s\n",file); exit(1); } if (read(fd,secbuf,SECSIZE) != SECSIZE) { fprintf(stderr,"Read error\n"); exit(1); } close(fd); } /* * Save to file */ save_to_file() { char file[80]; int fd; printf("Save to ? "); gets(file); #ifdef UNIX fd = creat(file,0644); #endif #ifdef DOS fd = creat(file,0644); if (fd < 0) { fprintf(stderr,"Cannot creat %s\n",file); exit(1); } close(fd); fd = open(file,0x8001); #endif if (fd < 0) { fprintf(stderr,"Cannot save to %s\n",file); exit(1); } if (write(fd,secbuf,SECSIZE) != SECSIZE) { fprintf(stderr,"Write error\n"); exit(1); } close(fd); } /* * Dump partition table */ dump_table() { struct part_entry *pe; int i; pe = (struct part_entry *)&secbuf[TABLEOFFSET]; printf("\n --first--- ---last---\n"); printf("Prt ac hd sec cyl sys hd sec cyl low size\n"); for (i = 1 ; i < 5 ; i++) { printf(" %x %2x %x %2x %2x %2x %x %2x %2x %6X%9X\n", i, pe->bootind & 0xff, pe->start_head & 0xff, pe->start_sec & 0xff, pe->start_cyl & 0xff, pe->sysind & 0xff, pe->last_head & 0xff, pe->last_sec & 0xff, pe->last_cyl & 0xff, pe->lowsec, pe->size); pe++; } } /* * Display partition table */ dpl_partitions() { struct part_entry *pe; int i; printf("\nPartition Type Begin End Active\n"); pe = (struct part_entry *)&secbuf[TABLEOFFSET]; for (i = 1 ; i <= 4 ; i++) { dpl_entry(i,pe); pe++; } } /* * Display an entry */ dpl_entry(number,entry) int number; struct part_entry *entry; { int low_cyl,high_cyl,temp; char *typestring; char active; if (entry->sysind == 0x01) typestring = dosstr; else typestring = ndosstr; printf("%5d %s ",number,typestring); temp = entry->start_sec & 0xc0; low_cyl = (entry->start_cyl & 0xff) + (temp << 2); temp = entry->last_sec & 0xc0; high_cyl = (entry->last_cyl & 0xff) + (temp << 2); printf("%4d %4d",low_cyl,high_cyl); if ((entry->bootind & 0xff) == 0x80) active = 'A'; else active = 'N'; printf(" %c\n",active); } /* * Check partition table */ chk_table() { struct part_entry *pe; int i; int active; long limit; pe = (struct part_entry *)&secbuf[TABLEOFFSET]; limit = 0L; active = 0; for (i = 1 ; i < 5 ; i++) { if (pe->size == 0L) return(OK); if (pe->lowsec <= limit) { printf("Overlap between part. %d and %d\n",i,i-1); return(ERR); } limit = pe->lowsec + pe->size - 1L; if (pe->bootind == 0x80) active++; pe++; } if (active > 1) { printf("%d active partitions\n",active); return(ERR); } return(OK); } /* * Check entry * head/sector/track info must match logical sector number * Used to check 'foreign' partition table during debugging */ chk_entry(entry) struct part_entry *entry; { char head; char sector; char track; sec_to_hst(entry->lowsec,&head,§or,&track); if ( (head != entry->start_head) || (sector != entry->start_sec) || (track != entry->start_cyl)) return(ERR); sec_to_hst(entry->lowsec + entry->size - 1L,&head,§or,&track); if ( (head != entry->last_head) || (sector != entry->last_sec) || (track != entry->last_cyl)) return(ERR); return(OK); } /* * Convert a logical sector number to * head / sector / track */ sec_to_hst(logsec,hd,sec,cyl) long logsec; char *hd,*sec,*cyl; { int bigcyl; bigcyl = logsec / (NHEAD * NSEC); *sec = (logsec % NSEC) + 1 + ((bigcyl >> 2) & 0xc0); *cyl = bigcyl & 0xff; *hd = (logsec % (NHEAD * NSEC)) / NSEC; } /* * change partition table */ change_table() { struct part_entry *pe; int i,temp,low_cyl,high_cyl; char ch; pe = (struct part_entry *)&secbuf[TABLEOFFSET]; for (i = 1 ; i <= 4 ; i++) { temp = pe->start_sec & 0xc0; low_cyl = (pe->start_cyl & 0xff) + (temp << 2); temp = pe->last_sec & 0xc0; high_cyl = (pe->last_cyl & 0xff) + (temp << 2); printf("Partition %d from %d to %d. Change ? ", i,low_cyl,high_cyl); ch = get_a_char(); if (ch == 'y' || ch == 'Y') get_partition(pe); pe++; } putchar('\n'); } /* * Get partition info : first & last cylinder */ get_partition(entry) struct part_entry *entry; { char buf[80]; int first,last; long low,high; char ch; printf(" First cylinder ? "); gets(buf); sscanf(buf,"%d",&first); printf(" Last cylinder ? "); gets(buf); sscanf(buf,"%d",&last);; if (first == 0 && last == 0) { entry->bootind = 0; entry->start_head = 0; entry->start_sec = 0; entry->start_cyl = 0; entry->sysind = 0; entry->last_head = 0; entry->last_sec = 0; entry->last_cyl = 0; entry->lowsec = 0L; entry->size = 0L ; return; } low = first & 0xffff; low = low * NSEC * NHEAD; if (low == 0) low = 1; /* sec0 is master boot record */ high = last & 0xffff; high = (high + 1)*NSEC*NHEAD - 1; entry->lowsec = low; entry->size = high - low + 1; sec_to_hst(low, &entry->start_head, &entry->start_sec, &entry->start_cyl); sec_to_hst(high, &entry->last_head, &entry->last_sec, &entry->last_cyl); printf(" DOS partition ? "); ch = get_a_char(); if (ch == 'y' || ch == 'Y') entry->sysind = 1; else entry->sysind = 0; printf(" Active partition ? "); ch = get_a_char(); if (ch == 'y' || ch == 'Y') entry->bootind = 0x80; else entry->bootind = 0; } /* * Read 1 character and discard rest of line */ get_a_char() { char ch; ch = getchar(); if (ch != '\n') while (getchar() != '\n'); return(ch); }