rev |
line source |
nuclear@0
|
1 #include <stdio.h>
|
nuclear@0
|
2 #include <stdlib.h>
|
nuclear@0
|
3 #include <string.h>
|
nuclear@0
|
4 #include <inttypes.h>
|
nuclear@0
|
5 #include <errno.h>
|
nuclear@0
|
6 #include <unistd.h>
|
nuclear@0
|
7 #include <fcntl.h>
|
nuclear@0
|
8 #include "ptype.h"
|
nuclear@0
|
9
|
nuclear@0
|
10 #define PATTR_ACT_BIT (1 << 9)
|
nuclear@0
|
11 #define PATTR_PRIM_BIT (1 << 10)
|
nuclear@0
|
12
|
nuclear@0
|
13 #define PTYPE(attr) ((attr) & 0xff)
|
nuclear@0
|
14 #define IS_ACT(attr) ((attr) & PATTR_ACT_BIT)
|
nuclear@0
|
15 #define IS_PRIM(attr) ((attr) & PATTR_PRIM_BIT)
|
nuclear@0
|
16
|
nuclear@0
|
17 struct partition {
|
nuclear@0
|
18 uint32_t start_sect;
|
nuclear@0
|
19 size_t size_sect;
|
nuclear@0
|
20
|
nuclear@0
|
21 unsigned int attr;
|
nuclear@0
|
22
|
nuclear@0
|
23 struct partition *next;
|
nuclear@0
|
24 };
|
nuclear@0
|
25
|
nuclear@0
|
26 struct part_record {
|
nuclear@0
|
27 uint8_t stat;
|
nuclear@0
|
28 uint8_t first_head, first_cyl, first_sect;
|
nuclear@0
|
29 uint8_t type;
|
nuclear@0
|
30 uint8_t last_head, last_cyl, last_sect;
|
nuclear@0
|
31 uint32_t first_lba;
|
nuclear@0
|
32 uint32_t nsect_lba;
|
nuclear@0
|
33 } __attribute__((packed));
|
nuclear@0
|
34
|
nuclear@0
|
35 static void print_parlist(struct partition *plist);
|
nuclear@0
|
36
|
nuclear@0
|
37 static struct partition *load_parlist(void);
|
nuclear@0
|
38 static uint16_t bootsig(const char *sect);
|
nuclear@0
|
39 static int read_sector(void *buf, uint32_t sector);
|
nuclear@0
|
40 static const char *printsz(unsigned int sz);
|
nuclear@0
|
41 static const char *ptype_name(int type);
|
nuclear@0
|
42
|
nuclear@0
|
43 int bdev;
|
nuclear@0
|
44
|
nuclear@0
|
45 int main(int argc, char **argv)
|
nuclear@0
|
46 {
|
nuclear@0
|
47 struct partition *plist;
|
nuclear@0
|
48
|
nuclear@0
|
49 if(argc != 2) {
|
nuclear@0
|
50 fprintf(stderr, "usage: %s <block device>\n", argv[0]);
|
nuclear@0
|
51 return 1;
|
nuclear@0
|
52 }
|
nuclear@0
|
53
|
nuclear@0
|
54 if((bdev = open(argv[1], O_RDONLY)) == -1) {
|
nuclear@0
|
55 fprintf(stderr, "failed to open %s: %s\n", argv[1], strerror(errno));
|
nuclear@0
|
56 return 1;
|
nuclear@0
|
57 }
|
nuclear@0
|
58
|
nuclear@0
|
59 if((plist = load_parlist())) {
|
nuclear@0
|
60 printf("partitions:\n");
|
nuclear@0
|
61 print_parlist(plist);
|
nuclear@0
|
62 }
|
nuclear@0
|
63
|
nuclear@0
|
64 return 0;
|
nuclear@0
|
65 }
|
nuclear@0
|
66
|
nuclear@0
|
67 static void print_parlist(struct partition *plist)
|
nuclear@0
|
68 {
|
nuclear@0
|
69 int idx = 0;
|
nuclear@0
|
70
|
nuclear@0
|
71 while(plist) {
|
nuclear@0
|
72 printf("%d%c ", idx++, IS_ACT(plist->attr) ? '*' : ' ');
|
nuclear@0
|
73 printf("(%s) %-20s ", IS_PRIM(plist->attr) ? "pri" : "log", ptype_name(PTYPE(plist->attr)));
|
nuclear@0
|
74 printf("start: %-10lu ", (unsigned long)plist->start_sect);
|
nuclear@0
|
75 printf("size: %-10lu [%s]\n", (unsigned long)plist->size_sect, printsz(plist->size_sect));
|
nuclear@0
|
76 plist = plist->next;
|
nuclear@0
|
77 }
|
nuclear@0
|
78 }
|
nuclear@0
|
79
|
nuclear@0
|
80
|
nuclear@0
|
81 #define BOOTSIG_OFFS 510
|
nuclear@0
|
82 #define PTABLE_OFFS 0x1be
|
nuclear@0
|
83
|
nuclear@0
|
84 #define BOOTSIG 0xaa55
|
nuclear@0
|
85
|
nuclear@0
|
86 #define IS_MBR (sidx == 0)
|
nuclear@0
|
87 #define IS_FIRST_EBR (!IS_MBR && (first_ebr_offs == 0))
|
nuclear@0
|
88 static struct partition *load_parlist(void)
|
nuclear@0
|
89 {
|
nuclear@0
|
90 char *sect;
|
nuclear@0
|
91 struct partition *phead = 0, *ptail = 0;
|
nuclear@0
|
92 uint32_t sidx = 0;
|
nuclear@0
|
93 uint32_t first_ebr_offs = 0;
|
nuclear@0
|
94 int i, num_bootrec = 0;
|
nuclear@0
|
95
|
nuclear@0
|
96 if(!(sect = malloc(512))) {
|
nuclear@0
|
97 perror("failed to allocate sector buffer");
|
nuclear@0
|
98 return 0;
|
nuclear@0
|
99 }
|
nuclear@0
|
100
|
nuclear@0
|
101
|
nuclear@0
|
102 do {
|
nuclear@0
|
103 int num_rec;
|
nuclear@0
|
104 struct part_record *prec;
|
nuclear@0
|
105
|
nuclear@0
|
106 if(IS_FIRST_EBR) {
|
nuclear@0
|
107 first_ebr_offs = sidx;
|
nuclear@0
|
108 }
|
nuclear@0
|
109
|
nuclear@0
|
110 if(read_sector(sect, sidx) == -1) {
|
nuclear@0
|
111 goto err;
|
nuclear@0
|
112 }
|
nuclear@0
|
113 if(bootsig(sect) != BOOTSIG) {
|
nuclear@0
|
114 fprintf(stderr, "invalid/corrupted partition table, sector %lu has no magic\n", (unsigned long)sidx);
|
nuclear@0
|
115 goto err;
|
nuclear@0
|
116 }
|
nuclear@0
|
117 prec = (struct part_record*)(sect + PTABLE_OFFS);
|
nuclear@0
|
118
|
nuclear@0
|
119 /* MBR has 4 records, EBRs have 2 */
|
nuclear@0
|
120 num_rec = IS_MBR ? 4 : 2;
|
nuclear@0
|
121
|
nuclear@0
|
122 for(i=0; i<num_rec; i++) {
|
nuclear@0
|
123 struct partition *pnode;
|
nuclear@0
|
124
|
nuclear@0
|
125 /* ignore empty partitions in the MBR, stop if encountered in an EBR */
|
nuclear@0
|
126 if(prec[i].type == 0) {
|
nuclear@0
|
127 if(num_bootrec > 0) {
|
nuclear@0
|
128 sidx = 0;
|
nuclear@0
|
129 break;
|
nuclear@0
|
130 }
|
nuclear@0
|
131 continue;
|
nuclear@0
|
132 }
|
nuclear@0
|
133
|
nuclear@0
|
134 /* ignore extended partitions and setup sector index to read
|
nuclear@0
|
135 * the next logical partition afterwards.
|
nuclear@0
|
136 */
|
nuclear@0
|
137 if(prec[i].type == PTYPE_EXT || prec[i].type == PTYPE_EXT_LBA) {
|
nuclear@0
|
138 /* all EBR start fields are relative to the first EBR offset */
|
nuclear@0
|
139 sidx = first_ebr_offs + prec[i].first_lba;
|
nuclear@0
|
140 continue;
|
nuclear@0
|
141 }
|
nuclear@0
|
142
|
nuclear@0
|
143 if(!(pnode = malloc(sizeof *pnode))) {
|
nuclear@0
|
144 perror("failed to allocate partition list node");
|
nuclear@0
|
145 goto err;
|
nuclear@0
|
146 }
|
nuclear@0
|
147
|
nuclear@0
|
148 pnode->attr = prec[i].type;
|
nuclear@0
|
149
|
nuclear@0
|
150 if(prec[i].stat & 0x80) {
|
nuclear@0
|
151 pnode->attr |= PATTR_ACT_BIT;
|
nuclear@0
|
152 }
|
nuclear@0
|
153 if(IS_MBR) {
|
nuclear@0
|
154 pnode->attr |= PATTR_PRIM_BIT;
|
nuclear@0
|
155 }
|
nuclear@0
|
156 pnode->start_sect = prec[i].first_lba + first_ebr_offs;
|
nuclear@0
|
157 pnode->size_sect = prec[i].nsect_lba;
|
nuclear@0
|
158 pnode->next = 0;
|
nuclear@0
|
159
|
nuclear@0
|
160 /* append to the list */
|
nuclear@0
|
161 if(!phead) {
|
nuclear@0
|
162 phead = ptail = pnode;
|
nuclear@0
|
163 } else {
|
nuclear@0
|
164 ptail->next = pnode;
|
nuclear@0
|
165 ptail = pnode;
|
nuclear@0
|
166 }
|
nuclear@0
|
167 }
|
nuclear@0
|
168
|
nuclear@0
|
169 num_bootrec++;
|
nuclear@0
|
170 } while(sidx > 0);
|
nuclear@0
|
171
|
nuclear@0
|
172 free(sect);
|
nuclear@0
|
173 return phead;
|
nuclear@0
|
174
|
nuclear@0
|
175 err:
|
nuclear@0
|
176 free(sect);
|
nuclear@0
|
177 while(phead) {
|
nuclear@0
|
178 void *tmp = phead;
|
nuclear@0
|
179 phead = phead->next;
|
nuclear@0
|
180 free(tmp);
|
nuclear@0
|
181 }
|
nuclear@0
|
182 return 0;
|
nuclear@0
|
183 }
|
nuclear@0
|
184
|
nuclear@0
|
185 static uint16_t bootsig(const char *sect)
|
nuclear@0
|
186 {
|
nuclear@0
|
187 return *(uint16_t*)(sect + BOOTSIG_OFFS);
|
nuclear@0
|
188 }
|
nuclear@0
|
189
|
nuclear@0
|
190 static int read_sector(void *buf, uint32_t sector)
|
nuclear@0
|
191 {
|
nuclear@0
|
192 if(lseek(bdev, (off_t)sector * 512, SEEK_SET) == -1) {
|
nuclear@0
|
193 fprintf(stderr, "read_sector: failed to seek: %s\n", strerror(errno));
|
nuclear@0
|
194 return -1;
|
nuclear@0
|
195 }
|
nuclear@0
|
196 if(read(bdev, buf, 512) != 512) {
|
nuclear@0
|
197 fprintf(stderr, "failed to read sector %lu: %s\n", (unsigned long)sector, strerror(errno));
|
nuclear@0
|
198 return -1;
|
nuclear@0
|
199 }
|
nuclear@0
|
200 return 0;
|
nuclear@0
|
201 }
|
nuclear@0
|
202
|
nuclear@1
|
203 const char *printsz(unsigned int sz_sect)
|
nuclear@0
|
204 {
|
nuclear@0
|
205 int i = 0;
|
nuclear@0
|
206 const char *suffix[] = { "kb", "mb", "gb", "tb", "pb", 0 };
|
nuclear@0
|
207 static char buf[512];
|
nuclear@0
|
208
|
nuclear@1
|
209 float sz = (float)sz_sect / 2.0;
|
nuclear@1
|
210
|
nuclear@1
|
211 while(sz > 1024.0 && suffix[i + 1]) {
|
nuclear@1
|
212 sz /= 1024.0;
|
nuclear@0
|
213 i++;
|
nuclear@0
|
214 }
|
nuclear@0
|
215
|
nuclear@1
|
216 sprintf(buf, "%.1f %s", sz, suffix[i]);
|
nuclear@0
|
217 return buf;
|
nuclear@0
|
218 }
|
nuclear@0
|
219
|
nuclear@0
|
220 static const char *ptype_name(int type)
|
nuclear@0
|
221 {
|
nuclear@0
|
222 int i;
|
nuclear@0
|
223
|
nuclear@0
|
224 for(i=0; i<PTYPES_SIZE; i++) {
|
nuclear@0
|
225 if(partypes[i].type == type) {
|
nuclear@0
|
226 return partypes[i].name;
|
nuclear@0
|
227 }
|
nuclear@0
|
228 }
|
nuclear@0
|
229 return "unknown";
|
nuclear@0
|
230 }
|