void detect_linux_lvm(SECTION *section, int level) { unsigned char *buf; char s[256]; int minor_version, pv_number; u8 pe_size, pe_count, pe_start; if (get_buffer(section, 0, 1024, (void **)&buf) < 1024) return; /* signature */ if (buf[0] != 'H' || buf[1] != 'M') return; /* helpful sanity check... */ if (get_le_long(buf + 36) == 0 || get_le_long(buf + 40) == 0) return; minor_version = get_le_short(buf + 2); print_line(level, "Linux LVM1 volume, version %d%s", minor_version, (minor_version < 1 || minor_version > 2) ? " (unknown)" : ""); /* volume group name */ get_string(buf + 172, 128, s); print_line(level + 1, "Volume group name \"%s\"", s); /* "UUID" of this physical volume */ format_uuid_lvm(buf + 0x2c, s); print_line(level + 1, "PV UUID %s", s); /* number of this physical volume */ pv_number = get_le_long(buf + 432); print_line(level + 1, "PV number %d", pv_number); /* volume size */ pe_size = get_le_long(buf + 452); pe_count = get_le_long(buf + 456); format_blocky_size(s, pe_count, pe_size * 512, "PEs", NULL); print_line(level + 1, "Useable size %s", s); /* get start of first PE */ if (minor_version == 1) { /* minor format 1: first PE starts after the declared length of the PE tables */ pe_start = get_le_long(buf + 36) + get_le_long(buf + 40); } else if (minor_version == 2) { /* minor format 2: a field in the header indicates this */ pe_start = get_le_long(buf + 464) << 9; } else { /* unknown minor format */ pe_start = 0; } /* try to detect from first PE */ if (pe_start > 0) { analyze_recursive(section, level + 1, pe_start, 0, 0); /* TODO: elaborate on this by reading the PE allocation map */ } }
void detect_reiser(SECTION *section, int level) { unsigned char *buf; int i, at, newformat; int offsets[3] = { 8, 64, -1 }; char s[256]; u8 blockcount; u4 blocksize; for (i = 0; offsets[i] >= 0; i++) { at = offsets[i]; if (get_buffer(section, at * 1024, 1024, (void **)&buf) < 1024) continue; /* check signature */ if (memcmp(buf + 52, "ReIsErFs", 8) == 0) { print_line(level, "ReiserFS file system (old 3.5 format, standard journal, starts at %d KiB)", at); newformat = 0; } else if (memcmp(buf + 52, "ReIsEr2Fs", 9) == 0) { print_line(level, "ReiserFS file system (new 3.6 format, standard journal, starts at %d KiB)", at); newformat = 1; } else if (memcmp(buf + 52, "ReIsEr3Fs", 9) == 0) { newformat = get_le_short(buf + 72); if (newformat == 0) { print_line(level, "ReiserFS file system (old 3.5 format, non-standard journal, starts at %d KiB)", at); } else if (newformat == 2) { print_line(level, "ReiserFS file system (new 3.6 format, non-standard journal, starts at %d KiB)", at); newformat = 1; } else { print_line(level, "ReiserFS file system (v3 magic, but unknown version %d, starts at %d KiB)", newformat, at); continue; } } else continue; /* get data */ blockcount = get_le_long(buf); blocksize = get_le_short(buf + 44); /* for new format only: hashtype = get_le_long(buf + 64); */ /* get label */ get_string(buf + 100, 16, s); if (s[0]) print_line(level + 1, "Volume name \"%s\"", s); format_uuid(buf + 84, s); print_line(level + 1, "UUID %s", s); /* print size */ format_blocky_size(s, blockcount, blocksize, "blocks", NULL); print_line(level + 1, "Volume size %s", s); /* TODO: print hash code */ } }
void detect_linux_raid(SECTION *section, int level) { unsigned char *buf; u8 pos; int rlevel, nr_disks, raid_disks, spare; u1 uuid[16]; char s[256]; /* don't do this if: * - the size is unknown (0) * - the size is too small for the calculation * - it is inefficient to read from the end of the source */ if (section->size < 65536 || section->source->sequential) return; /* get RAID superblock from the end of the device */ pos = (section->size & ~65535) - 65536; if (get_buffer(section, pos, 4096, (void **)&buf) < 4096) return; /* signature */ if (get_le_long(buf) != 0xa92b4efc) return; print_line(level, "Linux RAID disk, version %lu.%lu.%lu", get_le_long(buf + 4), get_le_long(buf + 8), get_le_long(buf + 12)); /* get some data */ rlevel = (int)(long)get_le_long(buf + 28); /* is signed, actually */ nr_disks = get_le_long(buf + 36); raid_disks = get_le_long(buf + 40); spare = nr_disks - raid_disks; /* find the name for the personality in the table */ if (rlevel < -4 || rlevel > 5 || levels[rlevel+4] == NULL) { print_line(level + 1, "Unknown RAID level %d using %d regular %d spare disks", rlevel, raid_disks, spare); } else { print_line(level + 1, "%s set using %d regular %d spare disks", levels[rlevel+4], raid_disks, spare); } /* get the UUID */ memcpy(uuid, buf + 5*4, 4); memcpy(uuid + 4, buf + 13*4, 3*4); format_uuid(uuid, s); print_line(level + 1, "RAID set UUID %s", s); }
static int validate_tag(unsigned char *buf, u4 sector) { int cksum, i; /* tag checksum */ cksum = 0; for (i = 0; i < 16; i++) if (i != 4) cksum += buf[i]; if ((cksum & 0xFF) != buf[4]) return 0; /* reserverd */ if (buf[5] != 0) return 0; /* tag location */ if (get_le_long(buf + 12) != sector) return 0; return 1; }
void detect_linux_lvm2(SECTION *section, int level) { unsigned char *buf; int at, i; char s[256]; u8 labelsector; u4 labeloffset; u8 pvsize, mdoffset, mdsize; int mda_version; for (at = 0; at < 4; at++) { if (get_buffer(section, at * 512, 512, (void **)&buf) < 512) continue; /* check signature */ if (memcmp(buf, "LABELONE", 8) != 0) continue; labelsector = get_le_quad(buf + 8); labeloffset = get_le_long(buf + 20); if (memcmp(buf + 24, "LVM2 001", 8) != 0) { get_string(buf + 24, 8, s); print_line(level, "LABELONE label at sector %d, unknown type \"%s\"", at, s); return; } print_line(level, "Linux LVM2 volume, version 001"); print_line(level + 1, "LABELONE label at sector %d", at); if (labeloffset >= 512 || labelsector > 256 || labelsector != at) { print_line(level + 1, "LABELONE data inconsistent, aborting analysis"); return; } /* "UUID" of this physical volume */ format_uuid_lvm(buf + labeloffset, s); print_line(level + 1, "PV UUID %s", s); /* raw volume size */ pvsize = get_le_quad(buf + labeloffset + 32); format_size_verbose(s, pvsize); print_line(level + 1, "Volume size %s", s); /* find first metadata area in list */ mdoffset = 0; for (i = 0; i < 16; i++) if (get_le_quad(buf + labeloffset + 40 + i * 16) == 0) { i++; mdoffset = get_le_quad(buf + labeloffset + 40 + i * 16); mdsize = get_le_quad(buf + labeloffset + 40 + i * 16 + 8); break; } if (mdoffset == 0) return; if (get_buffer(section, mdoffset, mdsize, (void **)&buf) < mdsize) return; if (memcmp(buf + 4, " LVM2 x[5A%r0N*>", 16) != 0) return; mda_version = get_le_long(buf + 20); print_line(level + 1, "Meta-data version %d", mda_version); /* TODO: parse the metadata area (big task...) */ return; } }
void detect_ext234(SECTION *section, int level) { unsigned char *buf; char s[256]; int fslevel, is_journal, is_dev; u4 blocksize; u8 blockcount; if (get_buffer(section, 1024, 1024, (void **)&buf) < 1024) return; if (get_le_short(buf + 56) == 0xEF53) { fslevel = 2; is_journal = 0; is_dev = 0; /* Ext3/4 external journal: INCOMPAT feature JOURNAL_DEV */ if (get_le_long(buf + 96) & 0x0008) { is_journal = 1; fslevel = 3; /* at least ext3, ext2 has no journalling */ } /* Ext3/4 COMPAT feature: HAS_JOURNAL */ if (get_le_long(buf + 92) & 0x0004) fslevel = 3; /* Ext4 INCOMPAT features: EXTENTS, 64BIT, FLEX_BG */ //if (get_le_long(buf + 96) & 0x02C0) // fslevel = 4; /* Ext4 RO_COMPAT features: HUGE_FILE, GDT_CSUM, DIR_NLINK, EXTRA_ISIZE */ if (get_le_long(buf + 100) & 0x0078) fslevel = 4; /* Ext4 sets min_extra_isize even on external journals */ //if (get_le_short(buf + 348) >= 0x1c) // fslevel = 4; /* Ext4dev TEST_FILESYS flag */ //if (get_le_long(buf + 352) & 0x0004) // is_dev = 1; print_line(level, "Ext%d%s %s", fslevel, is_dev ? "dev" : "", is_journal ? "external journal" : "file system"); get_string(buf + 120, 16, s); if (s[0]) print_line(level + 1, "Volume name \"%s\"", s); format_uuid(buf + 104, s); print_line(level + 1, "UUID %s", s); get_string(buf + 136, 64, s); if (s[0]) print_line(level + 1, "Last mounted at \"%s\"", s); blocksize = 1024 << get_le_long(buf + 24); blockcount = get_le_long(buf + 4); format_blocky_size(s, blockcount, blocksize, "blocks", NULL); print_line(level + 1, "Volume size %s", s); /* 76 4 s_rev_level */ /* 62 2 s_minor_rev_level */ /* 72 4 s_creator_os */ /* 92 3x4 s_feature_compat, s_feature_incompat, s_feature_ro_compat */ } }
static int probe_udf(SECTION *section, int level, int sector_size) { unsigned char *buffer; u4 count, addr, sect; int seen_primary = 0; int seen_logical = 0; int i; char s[256]; /* first read the Anchor Volume Descriptor Pointer @ sector 256 */ if (get_buffer(section, 256 * sector_size, 512, (void **)&buffer) < 512) return 0; if (!validate_tag(buffer, 256)) return 0; /* tag identifier */ if (get_le_short(buffer) != 2) return 0; print_line(level, "UDF file system"); print_line(level + 1, "Sector size %d bytes", sector_size); /* get the Volume Descriptor Area */ count = get_le_long(buffer + 16) / sector_size; addr = get_le_long(buffer + 20); /* look for a Logical Volume Descriptor */ for (i = 0; i < count; i++) { sect = addr + i; if (get_buffer(section, (u8)sect * sector_size, 512, (void **)&buffer) < 512) break; if (!validate_tag(buffer, sect)) continue; /* switch by tag identifier */ switch (get_le_short(buffer)) { case 1: /* Primary Volume Descriptor */ if (!seen_primary) { seen_primary = 1; if (buffer[24] == 8) { get_string(buffer + 25, 30, s); print_line(level+1, "Volume name \"%s\"", s); } else if (buffer[24] == 16) { format_utf16_le(buffer + 25, 30, s); print_line(level+1, "Volume name \"%s\"", s); } else { print_line(level+1, "Volume name encoding not supported"); } } break; case 6: /* Logical Volume Descriptor */ if (!seen_logical) { seen_logical = 1; if (memcmp(buffer + 216+1, "*OSTA UDF Compliant", 19) == 0) { print_line(level+1, "UDF version %x.%02x", (int)buffer[216+25], (int)buffer[216+24]); } } break; } } if (!seen_primary) { print_line(level + 1, "Primary Volume Descriptor missing"); } return 1; /* some problems */ }