lspart

changeset 0:29d89c00e611

simple partition table reading test
author John Tsiombikas <nuclear@member.fsf.org>
date Fri, 14 Oct 2011 07:45:44 +0300
parents
children 3bd9cfd79fc0
files Makefile lspart.c ptype.h
diffstat 3 files changed, 324 insertions(+), 0 deletions(-) [+]
line diff
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/Makefile	Fri Oct 14 07:45:44 2011 +0300
     1.3 @@ -0,0 +1,13 @@
     1.4 +src = $(wildcard *.c)
     1.5 +obj = $(src:.c=.o)
     1.6 +bin = lspart
     1.7 +
     1.8 +CC = gcc
     1.9 +CFLAGS = -pedantic -Wall -g
    1.10 +
    1.11 +$(bin): $(obj)
    1.12 +	$(CC) -o $@ $(obj) $(LDFLAGS)
    1.13 +
    1.14 +.PHONY: clean
    1.15 +clean:
    1.16 +	rm -f $(obj) $(bin)
     2.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     2.2 +++ b/lspart.c	Fri Oct 14 07:45:44 2011 +0300
     2.3 @@ -0,0 +1,228 @@
     2.4 +#include <stdio.h>
     2.5 +#include <stdlib.h>
     2.6 +#include <string.h>
     2.7 +#include <inttypes.h>
     2.8 +#include <errno.h>
     2.9 +#include <unistd.h>
    2.10 +#include <fcntl.h>
    2.11 +#include "ptype.h"
    2.12 +
    2.13 +#define PATTR_ACT_BIT	(1 << 9)
    2.14 +#define PATTR_PRIM_BIT	(1 << 10)
    2.15 +
    2.16 +#define PTYPE(attr)		((attr) & 0xff)
    2.17 +#define IS_ACT(attr)	((attr) & PATTR_ACT_BIT)
    2.18 +#define IS_PRIM(attr)	((attr) & PATTR_PRIM_BIT)
    2.19 +
    2.20 +struct partition {
    2.21 +	uint32_t start_sect;
    2.22 +	size_t size_sect;
    2.23 +
    2.24 +	unsigned int attr;
    2.25 +
    2.26 +	struct partition *next;
    2.27 +};
    2.28 +
    2.29 +struct part_record {
    2.30 +	uint8_t stat;
    2.31 +	uint8_t first_head, first_cyl, first_sect;
    2.32 +	uint8_t type;
    2.33 +	uint8_t last_head, last_cyl, last_sect;
    2.34 +	uint32_t first_lba;
    2.35 +	uint32_t nsect_lba;
    2.36 +} __attribute__((packed));
    2.37 +
    2.38 +static void print_parlist(struct partition *plist);
    2.39 +
    2.40 +static struct partition *load_parlist(void);
    2.41 +static uint16_t bootsig(const char *sect);
    2.42 +static int read_sector(void *buf, uint32_t sector);
    2.43 +static const char *printsz(unsigned int sz);
    2.44 +static const char *ptype_name(int type);
    2.45 +
    2.46 +int bdev;
    2.47 +
    2.48 +int main(int argc, char **argv)
    2.49 +{
    2.50 +	struct partition *plist;
    2.51 +
    2.52 +	if(argc != 2) {
    2.53 +		fprintf(stderr, "usage: %s <block device>\n", argv[0]);
    2.54 +		return 1;
    2.55 +	}
    2.56 +
    2.57 +	if((bdev = open(argv[1], O_RDONLY)) == -1) {
    2.58 +		fprintf(stderr, "failed to open %s: %s\n", argv[1], strerror(errno));
    2.59 +		return 1;
    2.60 +	}
    2.61 +
    2.62 +	if((plist = load_parlist())) {
    2.63 +		printf("partitions:\n");
    2.64 +		print_parlist(plist);
    2.65 +	}
    2.66 +
    2.67 +	return 0;
    2.68 +}
    2.69 +
    2.70 +static void print_parlist(struct partition *plist)
    2.71 +{
    2.72 +	int idx = 0;
    2.73 +
    2.74 +	while(plist) {
    2.75 +		printf("%d%c ", idx++, IS_ACT(plist->attr) ? '*' : ' ');
    2.76 +		printf("(%s) %-20s ", IS_PRIM(plist->attr) ? "pri" : "log", ptype_name(PTYPE(plist->attr)));
    2.77 +		printf("start: %-10lu ", (unsigned long)plist->start_sect);
    2.78 +		printf("size: %-10lu [%s]\n", (unsigned long)plist->size_sect, printsz(plist->size_sect));
    2.79 +		plist = plist->next;
    2.80 +	}
    2.81 +}
    2.82 +
    2.83 +
    2.84 +#define BOOTSIG_OFFS	510
    2.85 +#define PTABLE_OFFS		0x1be
    2.86 +
    2.87 +#define BOOTSIG			0xaa55
    2.88 +
    2.89 +#define IS_MBR			(sidx == 0)
    2.90 +#define IS_FIRST_EBR	(!IS_MBR && (first_ebr_offs == 0))
    2.91 +static struct partition *load_parlist(void)
    2.92 +{
    2.93 +	char *sect;
    2.94 +	struct partition *phead = 0, *ptail = 0;
    2.95 +	uint32_t sidx = 0;
    2.96 +	uint32_t first_ebr_offs = 0;
    2.97 +	int i, num_bootrec = 0;
    2.98 +
    2.99 +	if(!(sect = malloc(512))) {
   2.100 +		perror("failed to allocate sector buffer");
   2.101 +		return 0;
   2.102 +	}
   2.103 +
   2.104 +
   2.105 +	do {
   2.106 +		int num_rec;
   2.107 +		struct part_record *prec;
   2.108 +
   2.109 +		if(IS_FIRST_EBR) {
   2.110 +			first_ebr_offs = sidx;
   2.111 +		}
   2.112 +
   2.113 +		if(read_sector(sect, sidx) == -1) {
   2.114 +			goto err;
   2.115 +		}
   2.116 +		if(bootsig(sect) != BOOTSIG) {
   2.117 +			fprintf(stderr, "invalid/corrupted partition table, sector %lu has no magic\n", (unsigned long)sidx);
   2.118 +			goto err;
   2.119 +		}
   2.120 +		prec = (struct part_record*)(sect + PTABLE_OFFS);
   2.121 +
   2.122 +		/* MBR has 4 records, EBRs have 2 */
   2.123 +		num_rec = IS_MBR ? 4 : 2;
   2.124 +
   2.125 +		for(i=0; i<num_rec; i++) {
   2.126 +			struct partition *pnode;
   2.127 +
   2.128 +			/* ignore empty partitions in the MBR, stop if encountered in an EBR */
   2.129 +			if(prec[i].type == 0) {
   2.130 +				if(num_bootrec > 0) {
   2.131 +					sidx = 0;
   2.132 +					break;
   2.133 +				}
   2.134 +				continue;
   2.135 +			}
   2.136 +
   2.137 +			/* ignore extended partitions and setup sector index to read
   2.138 +			 * the next logical partition afterwards.
   2.139 +			 */
   2.140 +			if(prec[i].type == PTYPE_EXT || prec[i].type == PTYPE_EXT_LBA) {
   2.141 +				/* all EBR start fields are relative to the first EBR offset */
   2.142 +				sidx = first_ebr_offs + prec[i].first_lba;
   2.143 +				continue;
   2.144 +			}
   2.145 +
   2.146 +			if(!(pnode = malloc(sizeof *pnode))) {
   2.147 +				perror("failed to allocate partition list node");
   2.148 +				goto err;
   2.149 +			}
   2.150 +
   2.151 +			pnode->attr = prec[i].type;
   2.152 +
   2.153 +			if(prec[i].stat & 0x80) {
   2.154 +				pnode->attr |= PATTR_ACT_BIT;
   2.155 +			}
   2.156 +			if(IS_MBR) {
   2.157 +				pnode->attr |= PATTR_PRIM_BIT;
   2.158 +			}
   2.159 +			pnode->start_sect = prec[i].first_lba + first_ebr_offs;
   2.160 +			pnode->size_sect = prec[i].nsect_lba;
   2.161 +			pnode->next = 0;
   2.162 +
   2.163 +			/* append to the list */
   2.164 +			if(!phead) {
   2.165 +				phead = ptail = pnode;
   2.166 +			} else {
   2.167 +				ptail->next = pnode;
   2.168 +				ptail = pnode;
   2.169 +			}
   2.170 +		}
   2.171 +
   2.172 +		num_bootrec++;
   2.173 +	} while(sidx > 0);
   2.174 +
   2.175 +	free(sect);
   2.176 +	return phead;
   2.177 +
   2.178 +err:
   2.179 +	free(sect);
   2.180 +	while(phead) {
   2.181 +		void *tmp = phead;
   2.182 +		phead = phead->next;
   2.183 +		free(tmp);
   2.184 +	}
   2.185 +	return 0;
   2.186 +}
   2.187 +
   2.188 +static uint16_t bootsig(const char *sect)
   2.189 +{
   2.190 +	return *(uint16_t*)(sect + BOOTSIG_OFFS);
   2.191 +}
   2.192 +
   2.193 +static int read_sector(void *buf, uint32_t sector)
   2.194 +{
   2.195 +	if(lseek(bdev, (off_t)sector * 512, SEEK_SET) == -1) {
   2.196 +		fprintf(stderr, "read_sector: failed to seek: %s\n", strerror(errno));
   2.197 +		return -1;
   2.198 +	}
   2.199 +	if(read(bdev, buf, 512) != 512) {
   2.200 +		fprintf(stderr, "failed to read sector %lu: %s\n", (unsigned long)sector, strerror(errno));
   2.201 +		return -1;
   2.202 +	}
   2.203 +	return 0;
   2.204 +}
   2.205 +
   2.206 +const char *printsz(unsigned int sz)
   2.207 +{
   2.208 +	int i = 0;
   2.209 +	const char *suffix[] = { "kb", "mb", "gb", "tb", "pb", 0 };
   2.210 +	static char buf[512];
   2.211 +
   2.212 +	while(sz > 1024 && suffix[i + 1]) {
   2.213 +		sz /= 1024;
   2.214 +		i++;
   2.215 +	}
   2.216 +
   2.217 +	sprintf(buf, "%u %s", sz, suffix[i]);
   2.218 +	return buf;
   2.219 +}
   2.220 +
   2.221 +static const char *ptype_name(int type)
   2.222 +{
   2.223 +	int i;
   2.224 +
   2.225 +	for(i=0; i<PTYPES_SIZE; i++) {
   2.226 +		if(partypes[i].type == type) {
   2.227 +			return partypes[i].name;
   2.228 +		}
   2.229 +	}
   2.230 +	return "unknown";
   2.231 +}
     3.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     3.2 +++ b/ptype.h	Fri Oct 14 07:45:44 2011 +0300
     3.3 @@ -0,0 +1,83 @@
     3.4 +#ifndef PTYPE_H_
     3.5 +#define PTYPE_H_
     3.6 +
     3.7 +
     3.8 +#define PTYPE_EXT		0x5
     3.9 +#define PTYPE_EXT_LBA	0xf
    3.10 +
    3.11 +
    3.12 +#define PTYPES_SIZE		(sizeof partypes / sizeof *partypes)
    3.13 +
    3.14 +struct {
    3.15 +	int type;
    3.16 +	const char *name;
    3.17 +} partypes[] = {
    3.18 +	{0, "empty"},
    3.19 +	{0x01, "fat12"},
    3.20 +	{0x02, "xenix root"},
    3.21 +	{0x03, "xenix usr"},
    3.22 +	{0x04, "fat16 (small)"},
    3.23 +	{0x05, "extended"},
    3.24 +	{0x06, "fat16"},
    3.25 +	{0x07, "hpfs/ntfs"},
    3.26 +	{0x08, "aix"},
    3.27 +	{0x09, "aix bootable"},
    3.28 +	{0x0a, "os/2 boot manager"},
    3.29 +	{0x0b, "fat32 (chs)"},
    3.30 +	{0x0c, "fat32 (lba)"},
    3.31 +	{0x0e, "fat16 (lba)"},
    3.32 +	{0x0f, "extended (lba)"},
    3.33 +	{0x11, "hidden fat12"},
    3.34 +	{0x12, "compaq diagnostics"},
    3.35 +	{0x14, "hidden fat16 (small)"},
    3.36 +	{0x16, "hidden fat16"},
    3.37 +	{0x17, "hidden hpfs/ntfs"},
    3.38 +	{0x1b, "hidden fat32"},
    3.39 +	{0x1c, "hidden fat32 (lba)"},
    3.40 +	{0x1d, "hidden fat16 (lba)"},
    3.41 +	{0x24, "nec dos"},
    3.42 +	{0x27, "windows recovery"},
    3.43 +	{0x39, "plan 9"},
    3.44 +	{0x3c, "partition magic"},
    3.45 +	{0x4d, "qnx"},
    3.46 +	{0x4e, "qnx 2nd"},
    3.47 +	{0x4f, "qnx 3rd"},
    3.48 +	{0x52, "cp/m"},
    3.49 +	{0x63, "hurd/sysv"},
    3.50 +	{0x64, "netware 286"},
    3.51 +	{0x65, "netware 386"},
    3.52 +	{0x80, "minix (old)"},
    3.53 +	{0x81, "minix"},
    3.54 +	{0x82, "linux swap/solaris"},
    3.55 +	{0x83, "linux"},
    3.56 +	{0x84, "windows suspend"},
    3.57 +	{0x85, "linux extended"},
    3.58 +	{0x86, "ntfs volume?"},
    3.59 +	{0x87, "ntfs volume?"},
    3.60 +	{0x88, "linux plaintext"},
    3.61 +	{0x8e, "linux lvm"},
    3.62 +	{0x9f, "bsd/os"},
    3.63 +	{0xa0, "laptop diagnostic"},
    3.64 +	{0xa5, "freebsd slice"},
    3.65 +	{0xa6, "openbsd slice"},
    3.66 +	{0xa7, "nextstep"},
    3.67 +	{0xa8, "darwin ufs"},
    3.68 +	{0xa9, "netbsd slice"},
    3.69 +	{0xab, "darwin boot"},
    3.70 +	{0xaf, "hfs/hfs+"},
    3.71 +	{0xb7, "bsdi"},
    3.72 +	{0xb8, "bsdi swap"},
    3.73 +	{0xbe, "solaris boot"},
    3.74 +	{0xbf, "solaris"},
    3.75 +	{0xde, "dell diagnostic"},
    3.76 +	{0xeb, "beos"},
    3.77 +	{0xee, "gpt"},
    3.78 +	{0xef, "efi (fat)"},
    3.79 +	{0xf0, "linux/pa-risc boot"},
    3.80 +	{0xf2, "dos secondary"},
    3.81 +	{0xfb, "vmware vmfs"},
    3.82 +	{0xfc, "vmware vmkcore"},
    3.83 +	{0xfd, "linux raid auto"}
    3.84 +};
    3.85 +
    3.86 +#endif	/* PTYPE_H_ */