View Single Post
Old 17th July 2008
ephemera's Avatar
ephemera ephemera is offline
Knuth's homeboy
 
Join Date: Apr 2008
Posts: 537
Default

i don't think that there is a convinient OS interface to get partition info.
Here's a program to display info about DOS partitions:
Code:
/*
 *         Display DOS partitions.
 *         (reference: fdisk & wikipedia)
 *
 *         Copyright: ephemera @ daemonforums.org
 */

#include <sys/types.h>
#include <sys/stat.h>

#include <fcntl.h>
#include <err.h>
#include <errno.h>
#include <libgen.h>
#include <paths.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

#define	SEC_SIZE  512
#define	NDOSPART  4
#define DOSPARTSIZE 16
#define DOSPARTOFF 446
#define PRT_FLAG  0
#define PRT_TYPE  4
#define PRT_START  8
#define PRT_SIZE  12

#define u32dec(v) (*(uint32_t *)(v))

static struct part_type {
        uint8_t	type;
        const char *name;
} part_types[] = {
         {0x00, "unused"}
        ,{0x01, "Primary DOS with 12 bit FAT"}
        ,{0x02, "XENIX / file system"}
        ,{0x03, "XENIX /usr file system"}
        ,{0x04, "Primary DOS with 16 bit FAT (< 32MB)"}
        ,{0x05, "Extended DOS"}
        ,{0x06, "Primary 'big' DOS (>= 32MB)"}
        ,{0x07, "OS/2 HPFS, NTFS, QNX-2 (16 bit) or Advanced UNIX"}
        ,{0x08, "AIX file system or SplitDrive"}
        ,{0x09, "AIX boot partition or Coherent"}
        ,{0x0A, "OS/2 Boot Manager, OPUS or Coherent swap"}
        ,{0x0B, "DOS or Windows 95 with 32 bit FAT"}
        ,{0x0C, "DOS or Windows 95 with 32 bit FAT (LBA)"}
        ,{0x0E, "Primary 'big' DOS (>= 32MB, LBA)"}
        ,{0x0F, "Extended DOS (LBA)"}
        ,{0x10, "OPUS"}
        ,{0x11, "OS/2 BM: hidden DOS with 12-bit FAT"}
        ,{0x12, "Compaq diagnostics"}
        ,{0x14, "OS/2 BM: hidden DOS with 16-bit FAT (< 32MB)"}
        ,{0x16, "OS/2 BM: hidden DOS with 16-bit FAT (>= 32MB)"}
        ,{0x17, "OS/2 BM: hidden IFS (e.g. HPFS)"}
        ,{0x18, "AST Windows swapfile"}
        ,{0x24, "NEC DOS"}
        ,{0x3C, "PartitionMagic recovery"}
        ,{0x39, "plan9"}
        ,{0x40, "VENIX 286"}
        ,{0x41, "Linux/MINIX (sharing disk with DRDOS)"}
        ,{0x42, "SFS or Linux swap (sharing disk with DRDOS)"}
        ,{0x43, "Linux native (sharing disk with DRDOS)"}
        ,{0x4D, "QNX 4.2 Primary"}
        ,{0x4E, "QNX 4.2 Secondary"}
        ,{0x4F, "QNX 4.2 Tertiary"}
        ,{0x50, "DM (disk manager)"}
        ,{0x51, "DM6 Aux1 (or Novell)"}
        ,{0x52, "CP/M or Microport SysV/AT"}
        ,{0x53, "DM6 Aux3"}
        ,{0x54, "DM6"}
        ,{0x55, "EZ-Drive (disk manager)"}
        ,{0x56, "Golden Bow (disk manager)"}
        ,{0x5c, "Priam Edisk (disk manager)"} /* according to S. Widlake */
        ,{0x61, "SpeedStor"}
        ,{0x63, "System V/386 (such as ISC UNIX), GNU HURD or Mach"}
        ,{0x64, "Novell Netware/286 2.xx"}
        ,{0x65, "Novell Netware/386 3.xx"}
        ,{0x70, "DiskSecure Multi-Boot"}
        ,{0x75, "PCIX"}
        ,{0x77, "QNX4.x"}
        ,{0x78, "QNX4.x 2nd part"}
        ,{0x79, "QNX4.x 3rd part"}
        ,{0x80, "Minix until 1.4a"}
        ,{0x81, "Minix since 1.4b, early Linux partition or Mitac disk manager"}
        ,{0x82, "Linux swap or Solaris x86"}
        ,{0x83, "Linux native"}
        ,{0x84, "OS/2 hidden C: drive"}
        ,{0x85, "Linux extended"}
        ,{0x86, "NTFS volume set??"}
        ,{0x87, "NTFS volume set??"}
        ,{0x93, "Amoeba file system"}
        ,{0x94, "Amoeba bad block table"}
        ,{0x9F, "BSD/OS"}
        ,{0xA0, "Suspend to Disk"}
        ,{0xA5, "FreeBSD/NetBSD/386BSD"}
        ,{0xA6, "OpenBSD"}
        ,{0xA7, "NeXTSTEP"}
        ,{0xA9, "NetBSD"}
        ,{0xAC, "IBM JFS"}
        ,{0xAF, "HFS+"}
        ,{0xB7, "BSDI BSD/386 file system"}
        ,{0xB8, "BSDI BSD/386 swap"}
        ,{0xBE, "Solaris x86 boot"}
        ,{0xBF, "Solaris x86 (new)"}
        ,{0xC1, "DRDOS/sec with 12-bit FAT"}
        ,{0xC4, "DRDOS/sec with 16-bit FAT (< 32MB)"}
        ,{0xC6, "DRDOS/sec with 16-bit FAT (>= 32MB)"}
        ,{0xC7, "Syrinx"}
        ,{0xDB, "CP/M, Concurrent CP/M, Concurrent DOS or CTOS"}
        ,{0xE1, "DOS access or SpeedStor with 12-bit FAT extended partition"}
        ,{0xE3, "DOS R/O or SpeedStor"}
        ,{0xE4, "SpeedStor with 16-bit FAT extended partition < 1024 cyl."}
        ,{0xEB, "BeOS file system"}
        ,{0xEE, "EFI GPT"}
        ,{0xEF, "EFI System Partition"}
        ,{0xF1, "SpeedStor"}
        ,{0xF2, "DOS 3.3+ Secondary"}
        ,{0xF4, "SpeedStor large partition"}
        ,{0xFE, "SpeedStor >1024 cyl. or LANstep"}
        ,{0xFF, "Xenix bad blocks table"}
};

static int		is_valid_br(const uint8_t *br);
static int		is_ext_prt(const uint8_t *prt);
static int		is_zero_prt(const uint8_t *pr);
static const char *	get_type(int type);
static void		printprt(int partno, const uint8_t *part);

int 
main(int argc, char *argv[])
{
	char	*disk;
	uint8_t	*mbr_prt_ent, *ebr_prt_ent;
	uint8_t	mbr[SEC_SIZE], ebr[SEC_SIZE];
	int	i, fd, lpcnt;
	off_t	ebr_first, ebr_nxt;


	if (argc < 2) {
		fprintf(stderr, "Usage: %s disk\n", basename(argv[0]));
		exit(1);
	}

	disk = malloc(sizeof(_PATH_DEV) + strlen(argv[1]));
	sprintf(disk, "%s%s", argv[1][0] == '/' ? "" : _PATH_DEV, argv[1]); 
	if (disk == NULL)
		errx(1, "Out of memory.");

	fd = open(disk, O_RDONLY);
	if (fd < 0)
		err(1, "Can't open %s", disk);

	if (read(fd, mbr, SEC_SIZE) < 0) 
		err(1, "Can't read %s", disk);
	
	if (!is_valid_br(mbr))
		errx(1, "Invalid MBR on %s.", disk);

	printf("%-9s %10s %10s  %-4s  %s\n"
	       , "Disk:Part", "Start(sect)", "Size(KB)", "Flag", "Type");
	printf("%-9s %10s %10s  %-4s  %s\n"
	       , "---------", "-----------", "--------", "----", "----");
	printf("%s:\n", basename(disk));

	for (i = 0; i < NDOSPART; i++) {
		mbr_prt_ent = &mbr[DOSPARTOFF + i * DOSPARTSIZE];

		if (!is_zero_prt(mbr_prt_ent)) 
			printprt(i + 1, mbr_prt_ent);

		if (is_ext_prt(mbr_prt_ent)) {
			/* extended partition */
			ebr_first = ebr_nxt = u32dec(&mbr_prt_ent[PRT_START]);
			lpcnt = NDOSPART + 1;
			do {
				/* read in EBR for logical partition */
				if (pread(fd, ebr, SEC_SIZE
				          ,ebr_nxt * (off_t)SEC_SIZE)  < 0)
					err(1, "Can't read EBR");

				if (!is_valid_br(ebr)) {
					if (lpcnt == NDOSPART + 1)
						break;
					else
						errx(1, "Invalid EBR");
				}
						

				/* first partition entry in EBR */
				ebr_prt_ent = &ebr[DOSPARTOFF];

				u32dec(&ebr_prt_ent[PRT_START]) += ebr_nxt;
				printprt(lpcnt++, ebr_prt_ent);

				/* second partition entry in EBR */
				ebr_prt_ent += DOSPARTSIZE;
				ebr_nxt = ebr_first + u32dec(&ebr_prt_ent[PRT_START]);

			} while (!is_zero_prt(ebr_prt_ent));
		 } 
	}
        free(disk);
	return 0;
}

static int
is_valid_br(const uint8_t *br)
{

	return br[SEC_SIZE - 1] == 0xaa && br[SEC_SIZE - 2] == 0x55;
}

static int
is_ext_prt(const uint8_t *prt)
{

	return prt[PRT_TYPE] == 0x0f || prt[PRT_TYPE] == 0x05;
}

/* check for empty partition */
static int
is_zero_prt(const uint8_t *pr)
{
	uint32_t	*tst = (uint32_t *)pr;
	
	return !(tst[0] | tst[1] | tst[2] | tst[3]);
}

static const char *
get_type(int type)
{
        int			i, npart_types;
        struct part_type	*ptr = part_types;

	npart_types = sizeof(part_types) / sizeof(struct part_type);
        for (i = 0; i < npart_types; i++, ptr++) 
                if (ptr->type == type)
                        return ptr->name;

        return "?";
}

static void 
printprt(int partno, const uint8_t *part)
{

	printf("%sp%-*d %10u %10u  %-4s  (0x%02x) %s\n"
	       ,partno > NDOSPART ? "      " : "    "
	       ,partno > NDOSPART ? 3 : 5
	       ,partno
	       ,u32dec(&part[PRT_START])
	       ,u32dec(&part[PRT_SIZE]) >> 1	/* assuming SEC_SIZE=512 */
	       ,part[PRT_FLAG] == 0x80 ? "boot" : "-"
	       ,part[PRT_TYPE]
	       ,get_type(part[PRT_TYPE]));
	return;
}
Output:
Code:
Disk:Slice Start(sect)  Size(KB)  Flag  Type
---------- ----------  ---------  ----  ----
ad0:
    s1             63   10240240  -     (0x83) Linux native
    s2       20480544    8192016  boot  (0x83) Linux native
    s3       36864576    8192016  -     (0xa5) FreeBSD/NetBSD/386BSD
    s4       53248670   12456833  -     (0x0f) Extended DOS (LBA)
      s5     53248671    1126408  -     (0x82) Linux swap or Solaris x86
      s6     55501551   11330392  -     (0x0b) DOS or Windows 95 with 32 bit FAT
(for some reason? fbsd fdisk doesn't have support for logical partitions.)
AFAIK getting fbsd partition info from an fbsd slice will also require getting down and dirty.

Last edited by ephemera; 1st August 2008 at 12:37 PM.
Reply With Quote