summaryrefslogtreecommitdiffstats
path: root/rescuept/rescuept.c
diff options
context:
space:
mode:
Diffstat (limited to 'rescuept/rescuept.c')
-rw-r--r--rescuept/rescuept.c640
1 files changed, 640 insertions, 0 deletions
diff --git a/rescuept/rescuept.c b/rescuept/rescuept.c
new file mode 100644
index 000000000..b549568f1
--- /dev/null
+++ b/rescuept/rescuept.c
@@ -0,0 +1,640 @@
+/* call: rescuept /dev/hda */
+#include <stdio.h>
+#include <fcntl.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/ioctl.h>
+
+#include <linux/fs.h> /* for BLKGETSIZE */
+
+
+char *progname;
+char *device;
+
+#define MAXPARTITIONS 100
+
+#define MAXPAGESZ 65536
+
+#define BUFSZ 1024000
+#define BUFSECS (BUFSZ/512)
+char buf[BUFSZ];
+int bufstart = -1;
+
+typedef unsigned int uint32;
+typedef int sint32;
+typedef unsigned short uint16;
+typedef short sint16;
+typedef unsigned char uchar;
+
+void read_sectors(int fd, char *buf, int sectornr, int sectorct) {
+ extern long long llseek();
+ long long offset;
+ int n;
+
+ offset = sectornr;
+ offset *= 512;
+ if (llseek(fd, offset, SEEK_SET) != offset) {
+ fprintf(stderr, "%s: llseek error\n", progname);
+ exit(1);
+ }
+ n = read(fd, buf, sectorct*512);
+ if (n != sectorct*512) {
+ if (n == -1)
+ perror("read");
+ fprintf(stderr, "%s: error reading sectors %d-%d\n",
+ progname, sectornr, sectornr+sectorct-1);
+ exit(1);
+ }
+}
+
+
+/*
+ * Partition table stuff
+ */
+
+struct partition {
+ unsigned char bootable; /* 0 or 0x80 */
+ uchar begin_chs[3];
+ unsigned char sys_type;
+ uchar end_chs[3];
+ unsigned int start_sect; /* starting sector counting from 0 */
+ unsigned int nr_sects; /* nr of sectors in partition */
+};
+
+int
+is_extended(unsigned char sys_type) {
+ return (sys_type == 0x5 || sys_type == 0xf || sys_type == 0x85);
+}
+
+/*
+ * List of (extended) partition table sectors found
+ */
+struct epts {
+ int secno;
+ char pt4[64];
+} epts[MAXPARTITIONS];
+int eptsct;
+
+void addepts(int secno, char *data) {
+ if (eptsct >= MAXPARTITIONS)
+ return; /* ignore */
+ epts[eptsct].secno = secno;
+ memcpy(epts[eptsct].pt4, data+512-66, 64);
+ eptsct++;
+}
+
+/*
+ * List of guessed partitions
+ */
+struct pt {
+ int pno;
+ int start;
+ int size;
+ unsigned char type;
+} pts[MAXPARTITIONS];
+int partno;
+
+void addpart(int start, int size, unsigned char type) {
+ if (partno >= MAXPARTITIONS)
+ return; /* ignore */
+ pts[partno].start = start;
+ pts[partno].size = size;
+ pts[partno].type = type;
+ partno++;
+}
+
+void outparts() {
+ int i;
+
+ for(i=0; i<partno; i++)
+ printf("%s%d : start=%9d, size=%8d, Id=%2x\n",
+ device, pts[i].pno,
+ pts[i].start, pts[i].size, pts[i].type);
+}
+
+void outmsg(char *msg, int start, int nextstart, unsigned char type) {
+ printf("# %4d MB %16s (type %2x): sectors %9d-%9d\n",
+ ((nextstart-start)+1024)/2048, msg, type, start, nextstart-1);
+}
+
+int
+create_extended_partition(int fd, int secno, int size) {
+ int sec = secno;
+ int cursec = secno;
+ int pno = partno; /* number of extd partition */
+ int ei = eptsct-1;
+ unsigned char type = 0x5;
+ int lastseen = secno;
+ int ok = 0;
+
+ if (epts[ei].secno != secno) {
+ fprintf(stderr, "%s: program bug\n", progname);
+ exit(1);
+ }
+
+ outmsg("candidate ext pt", secno, secno+1, type);
+ addpart(secno, 1, type); /* size to be filled in later */
+
+ while(1) {
+ char buf[512];
+ struct partition *p1, *p2, *pr, *pe;
+ p1 = (struct partition *)(& epts[ei].pt4[0]);
+ p2 = (struct partition *)(& epts[ei].pt4[16]);
+ /* for the time being we just ignore the rest */
+
+ if (is_extended(p1->sys_type)) {
+ pr = p2;
+ pe = p1;
+ } else if (is_extended(p2->sys_type)) {
+ pr = p1;
+ pe = p2;
+ } else if (p1->sys_type == 0) {
+ pr = p2;
+ pe = 0;
+ } else if (p2->sys_type == 0) {
+ pr = p1;
+ pe = 0;
+ } else
+ break;
+
+ /* first handle the real partition, if any */
+ if (pr->sys_type != 0) {
+ int ss = cursec + pr->start_sect;
+ int es = ss + pr->nr_sects;
+ outmsg("found in ept", ss, es, pr->sys_type);
+ addpart(ss, pr->nr_sects, pr->sys_type);
+ if (lastseen < es - 1)
+ lastseen = es - 1;
+ if (lastseen >= size)
+ break;
+ }
+
+
+ /* then the extended link */
+
+ if (!pe) {
+ ok = 1;
+ break;
+ }
+ type = pe->sys_type;
+ cursec = sec + pe->start_sect;
+ if (cursec >= size)
+ break;
+ read_sectors(fd, buf, cursec, 1);
+ addepts(cursec, buf);
+ ei = eptsct-1;
+ }
+
+ if (!ok || lastseen == secno) {
+ printf("# retracted\n");
+ partno = pno;
+ return 0;
+ }
+
+ pts[pno].type = type;
+ pts[pno].size = lastseen+1-secno;
+ outmsg("extended part ok", secno, lastseen+1, type);
+ return lastseen;
+}
+
+
+
+/*
+ * Recognize an ext2 superblock
+ */
+#define EXT2_SUPER_MAGIC 0xEF53
+
+struct ext2_super_block {
+ uint32 s_inodes_count; /* 0: Inodes count */
+ uint32 s_blocks_count; /* 4: Blocks count */
+ uint32 s_r_blocks_count; /* 8: Reserved blocks count */
+ uint32 s_free_blocks_count; /* 12: Free blocks count */
+ uint32 s_free_inodes_count; /* 16: Free inodes count */
+ uint32 s_first_data_block; /* 20: First Data Block */
+ uint32 s_log_block_size; /* 24: Block size */
+ sint32 s_log_frag_size; /* 28: Fragment size */
+ uint32 s_blocks_per_group; /* 32: # Blocks per group */
+ uint32 s_frags_per_group; /* 36: # Fragments per group */
+ uint32 s_inodes_per_group; /* 40: # Inodes per group */
+ uint32 s_mtime; /* 44: Mount time */
+ uint32 s_wtime; /* 48: Write time */
+ uint16 s_mnt_count; /* 52: Mount count */
+ sint16 s_max_mnt_count; /* 54: Maximal mount count */
+ uint16 s_magic; /* 56: Magic signature */
+ uint16 s_state; /* 58: File system state */
+ uint16 s_errors; /* 60: Behaviour when detecting errors */
+ uint16 s_minor_rev_level; /* 62: minor revision level */
+ uint32 s_lastcheck; /* 64: time of last check */
+ uint32 s_checkinterval; /* 68: max. time between checks */
+ uint32 s_creator_os; /* 72: OS */
+ uint32 s_rev_level; /* 76: Revision level */
+ uint16 s_def_resuid; /* 80: Default uid for reserved blocks */
+ uint16 s_def_resgid; /* 82: Default gid for reserved blocks */
+
+ /* more stuff in later versions - especially s_block_group_nr is useful */
+ uint32 s_first_ino; /* 84: First non-reserved inode */
+ uint16 s_inode_size; /* 88: size of inode structure */
+ uint16 s_block_group_nr; /* 90: block group # of this superblock */
+ uint32 s_feature_compat; /* 92: compatible feature set */
+ uint32 s_feature_incompat; /* 96: incompatible feature set */
+ uint32 s_feature_ro_compat; /* 100: readonly-compatible feature set */
+ uchar s_uuid[16]; /* 104: 128-bit uuid for volume */
+ char s_volume_name[16]; /* 120: volume name */
+ char s_last_mounted[64]; /* 136: directory where last mounted */
+ uint32 s_algorithm_usage_bitmap;/* 200: For compression */
+ uchar s_prealloc_blocks; /* 204: Nr of blocks to try to preallocate*/
+ uchar s_prealloc_dir_blocks; /* 205: Nr to preallocate for dirs */
+ uchar s_reserved[818]; /* 206-1023 */
+};
+
+/*
+ * Heuristic to weed out false alarms for ext2 superblocks.
+ * Recompile this after 2005, of if you destroy things that
+ * have not been written the past ten years.
+ */
+#define YEAR (60*60*24*365)
+#define LOWERLIMIT (1992-1970)*YEAR
+#define UPPERLIMIT (2005-1970)*YEAR
+int
+is_time(uint32 t) {
+ return (t >= LOWERLIMIT && t <= UPPERLIMIT);
+}
+
+int
+is_ztime(uint32 t) {
+ return (t == 0 || (t >= LOWERLIMIT && t <= UPPERLIMIT));
+}
+
+/*
+ * Recognize a FAT filesystem
+ */
+
+struct fat_boot_sector_start {
+ uchar jump_code[3]; /* 0: Bootstrap short or near jump */
+ /* usually jump code (e.g. eb 3e or eb 58) + nop (0x90) */
+ uchar system_id[8]; /* 3: OEM Name */
+ /* fat16: MSDOS5.0 or MSWIN4.0 or ... */
+ /* fat32: MSWIN4.1 (=W95 OSR2) */
+ /* BIOS Parameter Block (BPB) */
+ uchar sector_size[2]; /* 11: bytes/sector (usually 512 or 2048) */
+ uchar cluster_size; /* 13: sectors/cluster (a power of two in 1..128) */
+ uint16 reserved; /* 14: reserved sectors (I see 1 for FAT16, 17 for FAT32) */
+ /* The # of sectors preceding the first FAT,
+ including the boot sector, so at least 1 */
+ uchar fats; /* 16: # of copies of FAT (usually 2) */
+ uchar dir_entries[2]; /* 17: max # of root directory entries (n/a for FAT32) */
+ /* (usually 512; 0 for FAT32) */
+ uchar sectors[2]; /* 19: total # of sectors (in <32MB partn) or 0 */
+ uchar media; /* 21: media code (0xf8 for hard disks) */
+ uint16 fat_length; /* 22: sectors/FAT (n/a: 0 for FAT32) */
+ uint16 secs_track; /* 24: S = # sectors/track (in 1..63) */
+ uint16 heads; /* 26: H = # of heads (in 1..255) */
+ uint32 hidden; /* 28: # of hidden sectors in partition, before boot sector */
+ /* (offset from cyl boundary - often equal to S) */
+ uint32 total_sect; /* 32: # of sectors (if sectors == 0) */
+};
+
+/* Media descriptor byte:
+ f8 hard disk
+ Floppy types:
+ f0 3.5" 36/2/80 2880k
+ f0 3.5" 18/2/80 1440k
+ f9 3.5" 9/2/80 720k
+ f9 5.25" 15/2/80 1200k
+ fa both 9/1/80 320k
+ fb both 9/2/80 640k
+ fc 5.25" 9/1/40 180k
+ fd 5.25" 9/2/40 360k
+ fe 5.25" 8/1/40 160k
+ ff 5.25" 8/2/40 320k
+ Conclusion: this bytes does not differentiate between 3.5" and 5.25",
+ it does not give the capacity or the number of sectors per track.
+ However, maybe C and H can be derived.
+*/
+
+struct fat_boot_sector_middle { /* offset 36-61 for FAT16, 64-89 for FAT32 */
+ /* Extended BIOS Parameter Block */
+ uchar drive_number; /* 0: logical drive number of partition */
+ /* (typically 0 for floppy, 0x80 for each disk) */
+ uchar current_head; /* Originally: track containing boot record. (Usually 0)
+ For WNT: bit 0: dirty: chkdsk must be run
+ bit 1: also run surface scan */
+ uchar extd_signature; /* 2: extended signature (0x29) */
+ /* WNT requires either 0x28 or 0x29 */
+ uchar serial_nr[4]; /* 3: serial number of partition */
+ uchar volume_name[11];/* 7: volume name of partition */
+ /* WNT stores the volume label as a special file
+ in the root directory */
+ uchar fs_name[8]; /* 18: filesystem name (FAT12, FAT16, FAT32) */
+};
+
+struct fat16_boot_sector {
+ struct fat_boot_sector_start s; /* 0-35 */
+ struct fat_boot_sector_middle m; /* 36-61 */
+ uchar boot_code[448]; /* 62-509 */
+ uchar signature[2]; /* 510-511: aa55 */
+};
+
+struct fat32_boot_sector {
+ struct fat_boot_sector_start s; /* 0-35 */
+
+ uint32 fat32_length; /* 36: sectors/FAT */
+ uint16 flags; /* 40: bit 7: fat mirroring, low 4: active fat */
+ /* If mirroring is disabled (bit8 set) the FAT
+ info is only written to the active FAT copy. */
+ uchar version[2]; /* 42: major, minor filesystem version */
+ uint32 root_cluster; /* 44: first cluster in root directory */
+ uint16 info_sector; /* 48: filesystem info sector # relative
+ to partition start (usually 1) */
+ uint16 backup_boot; /* 50: backup boot sector # relat. to part. start */
+ uint16 reserved2[6]; /* 52-63: Unused */
+
+ struct fat_boot_sector_middle m; /* 64-89 */
+ uchar boot_code[420]; /* 90-509 */
+ uchar signature[2]; /* 510-511: aa55 */
+};
+
+/*
+ * The boot code contains message strings ("Invalid system disk")
+ * but these are often localized ("Ongeldige diskette ").
+ * After these messages one finds two or three filenames.
+ * (MSDOS 6.2: "\r\nNon-System disk or disk error\r\n"
+ * "Replace and press any key when ready\r\n", "IO SYS", "MSDOS SYS")
+ * (W95: "IO SYS", "MSDOS SYS", "WINBOOT SYS")
+ * In all cases the sector seems to end with 0, 0, 55, aa.
+ *
+ * Random collection of messages (closed by \0377 or 0):
+ * "\r\nInvalid system disk"
+ * "\r\nOngeldige diskette "
+ * "\r\nDisk I/O error"
+ * "\r\nI/O-fout "
+ * "\r\nReplace the disk, and then press any key\r\n"
+ * "\r\nVervang de diskette en druk op een toets\r\n"
+ * This seems to suggest that the localized strings have the same length.
+ *
+ * "Non-System disk or disk error"
+ * "Replace and press any key when ready"
+ * "Disk Boot failure"
+ *
+ * "BOOT: Couldn't find NTLDR"
+ * "I/O error reading disk"
+ * "Please insert another disk"
+ */
+
+struct fat32_boot_fsinfo {
+ uint32 signature1; /* 41 61 52 52 */
+ uchar unknown1[480];
+ uint32 signature2; /* 61 41 72 72 0x61417272L */
+ uint32 free_clusters; /* Free cluster count. -1 if unknown */
+ uint32 next_cluster; /* Most recently allocated cluster.
+ * Unused under Linux. */
+ uchar unknown2[14];
+ uchar signature[2]; /* 510-511: aa55 */
+};
+
+struct msdos_dir_entry {
+ uchar name[8],ext[3]; /* name and extension */
+ uchar attr; /* attribute bits */
+ uchar lcase; /* Case for base and extension */
+ uchar ctime_ms; /* Creation time, milliseconds */
+ uint16 ctime; /* Creation time */
+ uint16 cdate; /* Creation date */
+ uint16 adate; /* Last access date */
+ uint16 starthi; /* High 16 bits of cluster in FAT32 */
+ uint16 time,date,start;/* time, date and first cluster */
+ uint32 size; /* file size (in bytes) */
+};
+
+/* New swap space */
+struct swap_header_v1 {
+ char bootbits[1024]; /* Space for disklabel etc. */
+ unsigned int version;
+ unsigned int last_page;
+ unsigned int nr_badpages;
+ unsigned int padding[125];
+ unsigned int badpages[1];
+};
+
+int
+main(int argc, char **argv){
+ int i,j,fd;
+ long size;
+ int pagesize, pagesecs;
+ unsigned char *bp;
+ struct ext2_super_block *e2bp;
+ struct fat16_boot_sector *fat16bs;
+ struct fat32_boot_sector *fat32bs;
+
+ progname = argv[0];
+
+ if (argc != 2) {
+ fprintf(stderr, "call: %s device\n", progname);
+ exit(1);
+ }
+
+ device = argv[1];
+
+ fd = open(device, O_RDONLY);
+ if (fd < 0) {
+ perror(device);
+ fprintf(stderr, "%s: could not open %s\n", progname, device);
+ exit(1);
+ }
+
+ if (ioctl(fd, BLKGETSIZE, &size)) {
+ perror("BLKGETSIZE");
+ fprintf(stderr, "%s: could not get device size\n", progname);
+ exit(1);
+ }
+
+ pagesize = getpagesize();
+ if (pagesize <= 0)
+ pagesize = 4096;
+ else if (pagesize > MAXPAGESZ) {
+ fprintf(stderr, "%s: ridiculous pagesize %d\n", progname, pagesize);
+ exit(1);
+ }
+ pagesecs = pagesize/512;
+
+ printf("# partition table of %s\n", device);
+ printf("# total size %d sectors\n", size);
+ printf("unit: sectors\n");
+
+ for(i=0; i<size; i++) {
+ if (i/BUFSECS != bufstart) {
+ int len, secno;
+ bufstart = i/BUFSECS;
+ secno = bufstart*BUFSECS;
+ len = BUFSECS;
+ if (size - secno < len)
+ len = size - secno;
+ len = (len / 2)*2; /* avoid reading the last (odd) sector */
+ read_sectors(fd, buf, secno, len);
+ }
+
+ j = i % BUFSECS;
+
+ bp = buf + 512 * j;
+
+ if (bp[510] == 0x55 && bp[511] == 0xAA) {
+ char *cp = bp+512-2-64;
+ int j;
+
+ if (i==0)
+ continue; /* the MBR is supposed to be broken */
+
+ /* Unfortunately one finds extended partition table sectors
+ that look just like a fat boot sector, except that the
+ partition table bytes have been overwritten */
+ /* typical FAT32 end: "nd then press ...", followed by
+ IO.SYS and MSDOS.SYS and WINBOOT.SYS directory entries.
+ typical extd part tab end: 2 entries, 32 nul bytes */
+
+ for(j=0; j<32; j++)
+ if (cp[32+j])
+ goto nonzero;
+ addepts(i, bp);
+ if (i > 0) {
+ j = create_extended_partition(fd, i, size);
+ if (j && j > i)
+ i = j; /* skip */
+ }
+ continue;
+ nonzero:
+ fat16bs = (struct fat16_boot_sector *) bp;
+ if (fat16bs->s.media == 0xf8 &&
+ fat16bs->m.extd_signature == 0x29 &&
+ !strncmp(fat16bs->m.fs_name, "FAT", 3)) {
+ int lth;
+ lth = fat16bs->s.sectors[0] +
+ fat16bs->s.sectors[1]*256;
+ if (lth) {
+ outmsg("small fat partition", i, i+lth, 0x1);
+ addpart(i, lth, 0x1);
+ } else {
+ lth = fat16bs->s.total_sect;
+ outmsg("fat partition", i, i+lth, 0x6);
+ addpart(i, lth, 0x6);
+ }
+ i = i+lth-1; /* skip */
+ continue;
+ }
+
+ fat32bs = (struct fat32_boot_sector *) bp;
+ if (fat32bs->s.media == 0xf8 &&
+ fat32bs->m.extd_signature == 0x29 &&
+ !strncmp(fat32bs->m.fs_name, "FAT32 ", 8)) {
+ int lth = fat32bs->s.total_sect;
+ outmsg("fat32 partition", i, i+lth, 0xb); /* or 0xc */
+ addpart(i, lth, 0xb);
+ i = i+lth-1; /* skip */
+ continue;
+ }
+ }
+
+ if (!strncmp(bp+502, "SWAP-SPACE", 10)) {
+ char *last;
+ int ct;
+ int ss = i-pagesecs+1;
+ int es;
+ char buf2[MAXPAGESZ];
+
+ read_sectors(fd, buf2, ss, pagesecs);
+ for (last = buf2+pagesize-10-1; last > buf2; last--)
+ if (*last)
+ break;
+ for (ct = 7; ct >= 0; ct--)
+ if (*last & (1<<ct))
+ break;
+ es = ((last - buf2)*8 + ct + 1)*pagesecs + ss;
+ if (es <= size) {
+ outmsg("old swap space", ss, es, 0x82);
+ addpart(ss, es-ss, 0x82);
+
+ i = es-1; /* skip */
+ continue;
+ }
+ }
+
+ if (!strncmp(bp+502, "SWAPSPACE2", 10)) {
+ int ss = i-pagesecs+1;
+ int es, lth;
+ char buf2[MAXPAGESZ];
+ struct swap_header_v1 *p;
+
+ read_sectors(fd, buf2, ss, pagesecs);
+ p = (struct swap_header_v1 *) buf2;
+ lth = (p->last_page + 1)* pagesecs;
+ es = ss + lth;
+ if (es <= size) {
+ outmsg("new swap space", ss, es, 0x82);
+ addpart(ss, lth, 0x82);
+
+ i = es-1; /* skip */
+ continue;
+ }
+ }
+
+ e2bp = (struct ext2_super_block *) bp;
+ if (e2bp->s_magic == EXT2_SUPER_MAGIC && is_time(e2bp->s_mtime)
+ && is_time(e2bp->s_wtime) && is_ztime(e2bp->s_lastcheck)
+ && e2bp->s_log_block_size <= 10 /* at most 1 MB blocks */) {
+ char buf[512];
+ struct ext2_super_block *bp2;
+ int ss, sz, es, gsz, j;
+
+ ss = i-2;
+ sz = (e2bp->s_blocks_count << (e2bp->s_log_block_size + 1));
+ gsz = (e2bp->s_blocks_per_group << (e2bp->s_log_block_size + 1));
+ if (e2bp->s_block_group_nr > 0)
+ ss -= gsz * e2bp->s_block_group_nr;
+ es = ss + sz;
+ if (ss > 0 && es > i && es <= size) {
+ if (e2bp->s_block_group_nr == 0) {
+ outmsg("ext2 partition", ss, es, 0x83);
+ addpart(ss, es-ss, 0x83);
+
+ i = es-1; /* skip */
+ continue;
+ }
+
+ /* maybe we jumped into the middle of a partially
+ obliterated ext2 partition? */
+
+ printf("# sector %d looks like an ext2 superblock copy #%d;\n"
+ "# in a partition covering sectors %d-%d\n",
+ i, e2bp->s_block_group_nr, ss, es-1);
+
+ for (j=1; j<=e2bp->s_block_group_nr; j++) {
+ read_sectors(fd, buf, i-j*gsz, 1);
+ bp2 = (struct ext2_super_block *) buf;
+ if (bp2->s_magic != EXT2_SUPER_MAGIC ||
+ bp2->s_block_group_nr !=
+ e2bp->s_block_group_nr - j)
+ break;
+ }
+ if (j == 1)
+ printf("# however, sector %d doesnt look like a sb.\n",
+ i-gsz);
+ else if (j <= e2bp->s_block_group_nr)
+ printf("# also the preceding %d block groups seem OK\n"
+ "# but before that things seem to be wrong.\n",
+ j-1);
+ else {
+ printf("# found all preceding superblocks OK\n"
+ "# Warning: overlapping partitions?\n");
+ outmsg("ext2 partition", ss, es, 0x83);
+ addpart(ss, es-ss, 0x83);
+ i = es-1; /* skip */
+ continue;
+ }
+ }
+
+ }
+ }
+
+ outparts();
+
+ exit(0);
+}
+