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_ */