part.c - vx32 - Local 9vx git repository for patches.
(HTM) git clone git://r-36.net/vx32
(DIR) Log
(DIR) Files
(DIR) Refs
---
part.c (7226B)
---
1 #include "u.h"
2 #include "lib.h"
3 #include "mem.h"
4 #include "dat.h"
5 #include "fns.h"
6
7 #include "sd.h"
8 #include "fs.h"
9
10 enum {
11 Npart = 32
12 };
13
14 uchar *mbrbuf, *partbuf;
15 int nbuf;
16 #define trace 0
17
18 int
19 tsdbio(SDunit *unit, SDpart *part, void *a, vlong off, int mbr)
20 {
21 uchar *b;
22
23 if(unit->dev->ifc->bio(unit, 0, 0, a, 1, (off/unit->secsize) + part->start) != unit->secsize){
24 if(trace)
25 print("%s: read %lud at %lld failed\n", unit->dev->name,
26 unit->secsize, (vlong)part->start*unit->secsize+off);
27 return -1;
28 }
29 b = a;
30 if(mbr && (b[0x1FE] != 0x55 || b[0x1FF] != 0xAA)){
31 if(trace)
32 print("%s: bad magic %.2ux %.2ux at %lld\n",
33 unit->dev->name, b[0x1FE], b[0x1FF],
34 (vlong)part->start*unit->secsize+off);
35 return -1;
36 }
37 return 0;
38 }
39
40 /*
41 * read partition table. The partition table is just ascii strings.
42 */
43 #define MAGIC "plan9 partitions"
44 static void
45 oldp9part(SDunit *unit)
46 {
47 SDpart *pp;
48 char *field[3], *line[Npart+1];
49 ulong n, start, end;
50 int i;
51
52 /*
53 * We have some partitions already.
54 */
55 pp = &unit->part[unit->npart];
56
57 /*
58 * We prefer partition tables on the second to last sector,
59 * but some old disks use the last sector instead.
60 */
61 pp->start = unit->sectors - 2;
62 pp->end = unit->sectors - 1;
63
64 if(tsdbio(unit, pp, partbuf, 0, 0) < 0)
65 return;
66
67 if(strncmp((char*)partbuf, MAGIC, sizeof(MAGIC)-1) != 0) {
68 /* not found on 2nd last sector; look on last sector */
69 pp->start++;
70 pp->end++;
71 if(tsdbio(unit, pp, partbuf, 0, 0) < 0)
72 return;
73 if(strncmp((char*)partbuf, MAGIC, sizeof(MAGIC)-1) != 0)
74 return;
75 print("%s: using old plan9 partition table on last sector\n", unit->dev->name);
76 }else
77 print("%s: using old plan9 partition table on 2nd-to-last sector\n", unit->dev->name);
78
79 /* we found a partition table, so add a partition partition */
80 unit->npart++;
81 partbuf[unit->secsize-1] = '\0';
82
83 /*
84 * parse partition table
85 */
86 n = getfields((char*)partbuf, line, Npart+1, 0, "\n");
87 if(n && strncmp(line[0], MAGIC, sizeof(MAGIC)-1) == 0){
88 for(i = 1; i < n && unit->npart < SDnpart; i++){
89 if(getfields(line[i], field, 3, 0, " ") != 3)
90 break;
91 start = strtoull(field[1], 0, 0);
92 end = strtoull(field[2], 0, 0);
93 if(start >= end || end > unit->sectors)
94 break;
95 sdaddpart(unit, field[0], start, end);
96 }
97 }
98 }
99
100 static void
101 p9part(SDunit *unit, char *name)
102 {
103 SDpart *p;
104 char *field[4], *line[Npart+1];
105 uvlong start, end;
106 int i, n;
107
108 p = sdfindpart(unit, name);
109 if(p == nil)
110 return;
111
112 if(tsdbio(unit, p, partbuf, unit->secsize, 0) < 0)
113 return;
114 partbuf[unit->secsize-1] = '\0';
115
116 if(strncmp((char*)partbuf, "part ", 5) != 0)
117 return;
118
119 n = getfields((char*)partbuf, line, Npart+1, 0, "\n");
120 if(n == 0)
121 return;
122 for(i = 0; i < n /* && unit->npart < SDnpart */; i++){
123 if(strncmp(line[i], "part ", 5) != 0)
124 break;
125 if(getfields(line[i], field, 4, 0, " ") != 4)
126 break;
127 start = strtoull(field[2], 0, 0);
128 end = strtoull(field[3], 0, 0);
129 if(start >= end || end > unit->sectors)
130 break;
131 sdaddpart(unit, field[1], p->start+start, p->start+end);
132 }
133 }
134
135 int
136 isdos(int t)
137 {
138 return t==FAT12 || t==FAT16 || t==FATHUGE || t==FAT32 || t==FAT32X;
139 }
140
141 int
142 isextend(int t)
143 {
144 return t==EXTEND || t==EXTHUGE || t==LEXTEND;
145 }
146
147 /*
148 * Fetch the first dos and all plan9 partitions out of the MBR partition table.
149 * We return -1 if we did not find a plan9 partition.
150 */
151 static int
152 mbrpart(SDunit *unit)
153 {
154 Dospart *dp;
155 ulong taboffset, start, end;
156 ulong firstxpart, nxtxpart;
157 int havedos, i, nplan9;
158 char name[10];
159
160 taboffset = 0;
161 dp = (Dospart*)&mbrbuf[0x1BE];
162 if(1) {
163 /* get the MBR (allowing for DMDDO) */
164 if(tsdbio(unit, &unit->part[0], mbrbuf, (vlong)taboffset*unit->secsize, 1) < 0)
165 return -1;
166 for(i=0; i<4; i++)
167 if(dp[i].type == DMDDO) {
168 if(trace)
169 print("DMDDO partition found\n");
170 taboffset = 63;
171 if(tsdbio(unit, &unit->part[0], mbrbuf, (vlong)taboffset*unit->secsize, 1) < 0)
172 return -1;
173 i = -1; /* start over */
174 }
175 }
176
177 /*
178 * Read the partitions, first from the MBR and then
179 * from successive extended partition tables.
180 */
181 nplan9 = 0;
182 havedos = 0;
183 firstxpart = 0;
184 for(;;) {
185 if(tsdbio(unit, &unit->part[0], mbrbuf, (vlong)taboffset*unit->secsize, 1) < 0)
186 return -1;
187 if(trace) {
188 if(firstxpart)
189 print("%s ext %lud ", unit->dev->name, taboffset);
190 else
191 print("%s mbr ", unit->dev->name);
192 }
193 nxtxpart = 0;
194 for(i=0; i<4; i++) {
195 if(trace)
196 print("dp %d...", dp[i].type);
197 start = taboffset+GLONG(dp[i].start);
198 end = start+GLONG(dp[i].len);
199
200 if(dp[i].type == PLAN9) {
201 if(nplan9 == 0)
202 strcpy(name, "plan9");
203 else
204 sprint(name, "plan9.%d", nplan9);
205 sdaddpart(unit, name, start, end);
206 p9part(unit, name);
207 nplan9++;
208 }
209
210 /*
211 * We used to take the active partition (and then the first
212 * when none are active). We have to take the first here,
213 * so that the partition we call ``dos'' agrees with the
214 * partition disk/fdisk calls ``dos''.
215 */
216 if(havedos==0 && isdos(dp[i].type)){
217 havedos = 1;
218 sdaddpart(unit, "dos", start, end);
219 }
220
221 /* nxtxpart is relative to firstxpart (or 0), not taboffset */
222 if(isextend(dp[i].type)){
223 nxtxpart = start-taboffset+firstxpart;
224 if(trace)
225 print("link %lud...", nxtxpart);
226 }
227 }
228 if(trace)
229 print("\n");
230
231 if(!nxtxpart)
232 break;
233 if(!firstxpart)
234 firstxpart = nxtxpart;
235 taboffset = nxtxpart;
236 }
237 return nplan9 ? 0 : -1;
238 }
239
240 /*
241 * To facilitate booting from CDs, we create a partition for
242 * the boot floppy image embedded in a bootable CD.
243 */
244 static int
245 part9660(SDunit *unit)
246 {
247 uchar buf[2048];
248 ulong a, n;
249 uchar *p;
250
251 if(unit->secsize != 2048)
252 return -1;
253
254 if(unit->dev->ifc->bio(unit, 0, 0, buf, 2048/unit->secsize, (17*2048)/unit->secsize) < 0)
255 return -1;
256
257 if(buf[0] || strcmp((char*)buf+1, "CD001\x01EL TORITO SPECIFICATION") != 0)
258 return -1;
259
260
261 p = buf+0x47;
262 a = p[0] | (p[1]<<8) | (p[2]<<16) | (p[3]<<24);
263
264 if(unit->dev->ifc->bio(unit, 0, 0, buf, 2048/unit->secsize, (a*2048)/unit->secsize) < 0)
265 return -1;
266
267 if(memcmp(buf, "\x01\x00\x00\x00", 4) != 0
268 || memcmp(buf+30, "\x55\xAA", 2) != 0
269 || buf[0x20] != 0x88)
270 return -1;
271
272 p = buf+0x28;
273 a = p[0] | (p[1]<<8) | (p[2]<<16) | (p[3]<<24);
274
275 switch(buf[0x21]){
276 case 0x01:
277 n = 1200*1024;
278 break;
279 case 0x02:
280 n = 1440*1024;
281 break;
282 case 0x03:
283 n = 2880*1024;
284 break;
285 default:
286 return -1;
287 }
288 n /= 2048;
289
290 print("found partition %s!cdboot; %lud+%lud\n", unit->dev->name, a, n);
291 sdaddpart(unit, "cdboot", a, a+n);
292 return 0;
293 }
294
295 enum {
296 NEW = 1<<0,
297 OLD = 1<<1
298 };
299
300 void
301 partition(SDunit *unit)
302 {
303 int type;
304 char *p;
305
306 if(unit->part == 0)
307 return;
308
309 if(part9660(unit) == 0)
310 return;
311
312 p = "new";
313
314 if(p != nil && strncmp(p, "new", 3) == 0)
315 type = NEW;
316 else if(p != nil && strncmp(p, "old", 3) == 0)
317 type = OLD;
318 else
319 type = NEW|OLD;
320
321 if(nbuf < unit->secsize) {
322 free(mbrbuf);
323 free(partbuf);
324 mbrbuf = malloc(unit->secsize);
325 partbuf = malloc(unit->secsize);
326 if(mbrbuf==nil || partbuf==nil) {
327 free(mbrbuf);
328 free(partbuf);
329 partbuf = mbrbuf = nil;
330 nbuf = 0;
331 return;
332 }
333 nbuf = unit->secsize;
334 }
335
336 if((type & NEW) && mbrpart(unit) >= 0){
337 /* nothing to do */;
338 }
339 else if(type & OLD)
340 oldp9part(unit);
341 }