Print this page
7804 fdisk_read_master_part_table() causes 'format' to crash
Reviewed by: Jason King <jason.brian.king@gmail.com>
Reviewed by: Hans Rosenfeld <hans.rosenfeld@nexenta.com>
Reviewed by: Robert Mustacchi <rm@joyent.com>
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/lib/libfdisk/common/libfdisk.c
+++ new/usr/src/lib/libfdisk/common/libfdisk.c
1 1 /*
2 2 * CDDL HEADER START
3 3 *
4 4 * The contents of this file are subject to the terms of the
5 5 * Common Development and Distribution License (the "License").
6 6 * You may not use this file except in compliance with the License.
7 7 *
8 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 9 * or http://www.opensolaris.org/os/licensing.
10 10 * See the License for the specific language governing permissions
11 11 * and limitations under the License.
12 12 *
↓ open down ↓ |
12 lines elided |
↑ open up ↑ |
13 13 * When distributing Covered Code, include this CDDL HEADER in each
14 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 15 * If applicable, add the following below this CDDL HEADER, with the
16 16 * fields enclosed by brackets "[]" replaced with your own identifying
17 17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 18 *
19 19 * CDDL HEADER END
20 20 */
21 21 /*
22 22 * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
23 + * Copyright 2017 The MathWorks, Inc. All rights reserved.
23 24 */
24 25
25 26 #include <stdio.h>
26 27 #include <stdlib.h>
27 28 #include <string.h>
28 29 #include <strings.h>
29 30 #include <unistd.h>
30 31 #include <errno.h>
31 32 #include <fcntl.h>
32 33 #include <ctype.h>
33 34 #include <sys/stat.h>
34 35 #include <sys/types.h>
35 36 #include <sys/param.h>
36 37 #include <sys/systeminfo.h>
37 38 #include <sys/efi_partition.h>
38 39 #include <sys/byteorder.h>
39 40
40 41 #include <sys/vtoc.h>
41 42 #include <sys/tty.h>
42 43 #include <sys/dktp/fdisk.h>
43 44 #include <sys/dkio.h>
44 45 #include <sys/mnttab.h>
45 46 #include "libfdisk.h"
46 47
47 48 #define DEFAULT_PATH_PREFIX "/dev/rdsk/"
48 49
49 50 static void fdisk_free_ld_nodes(ext_part_t *epp);
50 51 static void fdisk_ext_place_in_sorted_list(ext_part_t *epp,
51 52 logical_drive_t *newld);
52 53 static void fdisk_ext_remove_from_sorted_list(ext_part_t *epp,
53 54 logical_drive_t *delld);
54 55 static int fdisk_ext_overlapping_parts(ext_part_t *epp, uint32_t begsec,
55 56 uint32_t endsec);
56 57 static int fdisk_read_extpart(ext_part_t *epp);
57 58 static void fdisk_set_CHS_values(ext_part_t *epp, struct ipart *part);
58 59 static int fdisk_init_master_part_table(ext_part_t *epp);
59 60 static struct ipart *fdisk_alloc_part_table();
60 61 static int fdisk_read_master_part_table(ext_part_t *epp);
61 62
62 63 static int
63 64 fdisk_init_disk_geom(ext_part_t *epp)
64 65 {
65 66 struct dk_geom disk_geom;
66 67 struct dk_minfo disk_info;
67 68 int no_virtgeom_ioctl = 0, no_physgeom_ioctl = 0;
68 69
69 70 /* Get disk's HBA (virtual) geometry */
70 71 errno = 0;
71 72 if (ioctl(epp->dev_fd, DKIOCG_VIRTGEOM, &disk_geom)) {
72 73 if (errno == ENOTTY) {
73 74 no_virtgeom_ioctl = 1;
74 75 } else if (errno == EINVAL) {
75 76 /*
76 77 * This means that the ioctl exists, but
77 78 * is invalid for this disk, meaning the
78 79 * disk doesn't have an HBA geometry
79 80 * (like, say, it's larger than 8GB).
80 81 */
81 82 epp->disk_geom.virt_cyl = epp->disk_geom.virt_heads =
82 83 epp->disk_geom.virt_sec = 0;
83 84 } else {
84 85 return (FDISK_ENOVGEOM);
85 86 }
86 87 } else {
87 88 /* save virtual geometry values obtained by ioctl */
88 89 epp->disk_geom.virt_cyl = disk_geom.dkg_ncyl;
89 90 epp->disk_geom.virt_heads = disk_geom.dkg_nhead;
90 91 epp->disk_geom.virt_sec = disk_geom.dkg_nsect;
91 92 }
92 93
93 94 errno = 0;
94 95 if (ioctl(epp->dev_fd, DKIOCG_PHYGEOM, &disk_geom)) {
95 96 if (errno == ENOTTY) {
96 97 no_physgeom_ioctl = 1;
97 98 } else {
98 99 return (FDISK_ENOPGEOM);
99 100 }
100 101 }
101 102 /*
102 103 * Call DKIOCGGEOM if the ioctls for physical and virtual
103 104 * geometry fail. Get both from this generic call.
104 105 */
105 106 if (no_virtgeom_ioctl && no_physgeom_ioctl) {
106 107 errno = 0;
107 108 if (ioctl(epp->dev_fd, DKIOCGGEOM, &disk_geom)) {
108 109 return (FDISK_ENOLGEOM);
109 110 }
110 111 }
111 112
112 113 epp->disk_geom.phys_cyl = disk_geom.dkg_ncyl;
113 114 epp->disk_geom.phys_heads = disk_geom.dkg_nhead;
114 115 epp->disk_geom.phys_sec = disk_geom.dkg_nsect;
115 116 epp->disk_geom.alt_cyl = disk_geom.dkg_acyl;
116 117
117 118 /*
118 119 * If DKIOCGMEDIAINFO ioctl succeeds, set the dki_lbsize as the
119 120 * size of the sector, else default to 512
120 121 */
121 122 if (ioctl(epp->dev_fd, DKIOCGMEDIAINFO, (caddr_t)&disk_info) < 0) {
122 123 /* ioctl failed, falling back to default value of 512 bytes */
123 124 epp->disk_geom.sectsize = 512;
124 125 } else {
125 126 epp->disk_geom.sectsize = ((disk_info.dki_lbsize) ?
126 127 disk_info.dki_lbsize : 512);
127 128 }
128 129
129 130 /*
130 131 * if hba geometry was not set by DKIOC_VIRTGEOM
131 132 * or we got an invalid hba geometry
132 133 * then set hba geometry based on max values
133 134 */
134 135 if (no_virtgeom_ioctl || disk_geom.dkg_ncyl == 0 ||
135 136 disk_geom.dkg_nhead == 0 || disk_geom.dkg_nsect == 0 ||
136 137 disk_geom.dkg_ncyl > MAX_CYL || disk_geom.dkg_nhead > MAX_HEAD ||
137 138 disk_geom.dkg_nsect > MAX_SECT) {
138 139 epp->disk_geom.virt_sec = MAX_SECT;
139 140 epp->disk_geom.virt_heads = MAX_HEAD + 1;
140 141 epp->disk_geom.virt_cyl = (epp->disk_geom.phys_cyl *
141 142 epp->disk_geom.phys_heads * epp->disk_geom.phys_sec) /
142 143 (epp->disk_geom.virt_sec * epp->disk_geom.virt_heads);
143 144 }
144 145 return (FDISK_SUCCESS);
145 146 }
146 147
147 148 /*
148 149 * Initialise important members of the ext_part_t structure and
149 150 * other data structures vital to functionality of libfdisk
150 151 */
151 152 int
152 153 libfdisk_init(ext_part_t **epp, char *devstr, struct ipart *parttab, int opflag)
153 154 {
154 155 ext_part_t *temp;
155 156 struct stat sbuf;
156 157 int rval = FDISK_SUCCESS;
157 158 int found_bad_magic = 0;
158 159
159 160 if ((temp = calloc(1, sizeof (ext_part_t))) == NULL) {
160 161 *epp = NULL;
161 162 return (ENOMEM);
162 163 }
163 164
164 165 (void) strncpy(temp->device_name, devstr,
165 166 sizeof (temp->device_name));
166 167
167 168 /* Try to stat the node as provided */
168 169 if (stat(temp->device_name, &sbuf) != 0) {
169 170
170 171 /* Prefix /dev/rdsk/ and stat again */
171 172 (void) snprintf(temp->device_name, sizeof (temp->device_name),
172 173 "%s%s", DEFAULT_PATH_PREFIX, devstr);
173 174
174 175 if (stat(temp->device_name, &sbuf) != 0) {
175 176
176 177 /*
177 178 * In case of an EFI labeled disk, the device name
178 179 * could be cN[tN]dN. There is no pN. So we add "p0"
179 180 * at the end if we do not find it and stat again.
180 181 */
181 182 if (strrchr(temp->device_name, 'p') == NULL) {
182 183 (void) strcat(temp->device_name, "p0");
183 184 }
184 185
185 186 if (stat(temp->device_name, &sbuf) != 0) {
186 187
187 188 /* Failed all options, give up */
188 189 rval = EINVAL;
189 190 goto fail;
190 191 }
191 192 }
192 193 }
193 194
194 195 /* Make sure the device is a raw device */
195 196 if ((sbuf.st_mode & S_IFMT) != S_IFCHR) {
196 197 rval = EINVAL;
197 198 goto fail;
198 199 }
199 200
200 201 temp->ld_head = NULL;
201 202 temp->sorted_ld_head = NULL;
202 203
203 204 if ((temp->dev_fd = open(temp->device_name, O_RDWR, 0666)) < 0) {
204 205 rval = EINVAL;
205 206 goto fail;
206 207 }
207 208
208 209 if ((temp->mtable = parttab) == NULL) {
209 210 if ((rval = fdisk_init_master_part_table(temp)) !=
210 211 FDISK_SUCCESS) {
211 212 /*
212 213 * When we have no fdisk magic 0xAA55 on the disk,
213 214 * we return FDISK_EBADMAGIC after successfully
214 215 * obtaining the disk geometry.
215 216 */
216 217 if (rval != FDISK_EBADMAGIC)
217 218 goto fail;
218 219 else
219 220 found_bad_magic = 1;
220 221 }
221 222 }
222 223
223 224 temp->op_flag = opflag;
224 225
225 226 if ((rval = fdisk_init_disk_geom(temp)) != FDISK_SUCCESS) {
226 227 goto fail;
227 228 }
228 229
229 230 *epp = temp;
230 231
231 232 if (found_bad_magic != 0) {
232 233 return (FDISK_EBADMAGIC);
233 234 }
234 235
235 236 if (opflag & FDISK_READ_DISK) {
236 237 rval = fdisk_read_extpart(*epp);
237 238 }
238 239 return (rval);
239 240
240 241 fail:
241 242 *epp = NULL;
242 243 free(temp);
243 244 return (rval);
244 245 }
245 246
246 247 int
247 248 libfdisk_reset(ext_part_t *epp)
248 249 {
249 250 int rval = FDISK_SUCCESS;
250 251
251 252 fdisk_free_ld_nodes(epp);
252 253 epp->first_ebr_is_null = 1;
253 254 epp->corrupt_logical_drives = 0;
254 255 epp->logical_drive_count = 0;
255 256 epp->invalid_bb_sig[0] = 0;
256 257 if (epp->op_flag & FDISK_READ_DISK) {
257 258 rval = fdisk_read_extpart(epp);
258 259 }
259 260 return (rval);
260 261 }
261 262
262 263 void
263 264 libfdisk_fini(ext_part_t **epp)
264 265 {
265 266 if (*epp == NULL)
266 267 return;
267 268
268 269 fdisk_free_ld_nodes(*epp);
269 270 (void) close((*epp)->dev_fd);
270 271 free(*epp);
271 272 *epp = NULL;
272 273 }
273 274
274 275 int
275 276 fdisk_is_linux_swap(ext_part_t *epp, uint32_t part_start, uint64_t *lsm_offset)
276 277 {
277 278 int i;
278 279 int rval = -1;
279 280 off_t seek_offset;
280 281 uint32_t linux_pg_size;
281 282 char *buf, *linux_swap_magic;
282 283 int sec_sz = fdisk_get_disk_geom(epp, PHYSGEOM, SSIZE);
283 284 off_t label_offset;
284 285
285 286 /*
286 287 * Known linux kernel page sizes
287 288 * The linux swap magic is found as the last 10 bytes of a disk chunk
288 289 * at the beginning of the linux swap partition whose size is that of
289 290 * kernel page size.
290 291 */
291 292 uint32_t linux_pg_size_arr[] = {4096, };
292 293
293 294 if ((buf = calloc(1, sec_sz)) == NULL) {
294 295 return (ENOMEM);
295 296 }
296 297
297 298 /*
298 299 * Check if there is a sane Solaris VTOC
299 300 * If there is a valid vtoc, no need to lookup
300 301 * for the linux swap signature.
301 302 */
302 303 label_offset = (part_start + DK_LABEL_LOC) * sec_sz;
303 304 if (lseek(epp->dev_fd, label_offset, SEEK_SET) < 0) {
304 305 rval = EIO;
305 306 goto done;
306 307 }
307 308
308 309 if ((rval = read(epp->dev_fd, buf, sec_sz)) < sec_sz) {
309 310 rval = EIO;
310 311 goto done;
311 312 }
312 313
313 314
314 315 if ((((struct dk_label *)buf)->dkl_magic == DKL_MAGIC) &&
315 316 (((struct dk_label *)buf)->dkl_vtoc.v_sanity == VTOC_SANE)) {
316 317 rval = -1;
317 318 goto done;
318 319 }
319 320
320 321 /* No valid vtoc, so check for linux swap signature */
321 322 linux_swap_magic = buf + sec_sz - LINUX_SWAP_MAGIC_LENGTH;
322 323
323 324 for (i = 0; i < sizeof (linux_pg_size_arr)/sizeof (uint32_t); i++) {
324 325 linux_pg_size = linux_pg_size_arr[i];
325 326 seek_offset = linux_pg_size/sec_sz - 1;
326 327 seek_offset += part_start;
327 328 seek_offset *= sec_sz;
328 329
329 330 if (lseek(epp->dev_fd, seek_offset, SEEK_SET) < 0) {
330 331 rval = EIO;
331 332 break;
332 333 }
333 334
334 335 if ((rval = read(epp->dev_fd, buf, sec_sz)) < sec_sz) {
335 336 rval = EIO;
336 337 break;
337 338 }
338 339
339 340 if ((strncmp(linux_swap_magic, "SWAP-SPACE",
340 341 LINUX_SWAP_MAGIC_LENGTH) == 0) ||
341 342 (strncmp(linux_swap_magic, "SWAPSPACE2",
342 343 LINUX_SWAP_MAGIC_LENGTH) == 0)) {
343 344 /* Found a linux swap */
344 345 rval = 0;
345 346 if (lsm_offset != NULL)
346 347 *lsm_offset = (uint64_t)seek_offset;
347 348 break;
348 349 }
349 350 }
350 351
351 352 done:
352 353 free(buf);
353 354 return (rval);
354 355 }
355 356
356 357 int
357 358 fdisk_get_solaris_part(ext_part_t *epp, int *pnum, uint32_t *begsec,
358 359 uint32_t *numsec)
359 360 {
360 361 logical_drive_t *temp = fdisk_get_ld_head(epp);
361 362 uint32_t part_start;
362 363 int pno;
363 364 int rval = -1;
364 365
365 366 for (pno = 5; temp != NULL; temp = temp->next, pno++) {
366 367 if (fdisk_is_solaris_part(LE_8(temp->parts[0].systid))) {
367 368 part_start = temp->abs_secnum + temp->logdrive_offset;
368 369 if ((temp->parts[0].systid == SUNIXOS) &&
369 370 (fdisk_is_linux_swap(epp, part_start,
370 371 NULL) == 0)) {
371 372 continue;
372 373 }
373 374 *pnum = pno;
374 375 *begsec = part_start;
375 376 *numsec = temp->numsect;
376 377 rval = FDISK_SUCCESS;
377 378 }
378 379 }
379 380 return (rval);
380 381 }
381 382
382 383 int
383 384 fdisk_get_part_info(ext_part_t *epp, int pnum, uchar_t *sysid, uint32_t *begsec,
384 385 uint32_t *numsec)
385 386 {
386 387 logical_drive_t *temp = fdisk_get_ld_head(epp);
387 388 int pno;
388 389
389 390 if ((pnum < 5) || (pnum >= MAX_EXT_PARTS + 5)) {
390 391 return (EINVAL);
391 392 }
392 393
393 394 for (pno = 5; (pno < pnum) && (temp != NULL); temp = temp->next, pno++)
394 395 ;
395 396
396 397 if (temp == NULL) {
397 398 return (EINVAL);
398 399 }
399 400
400 401 *sysid = LE_8(temp->parts[0].systid);
401 402 *begsec = temp->abs_secnum + temp->logdrive_offset;
402 403 *numsec = temp->numsect;
403 404 return (FDISK_SUCCESS);
404 405 }
405 406
406 407 /*
407 408 * Allocate a node of type logical_drive_t and return the pointer to it
408 409 */
409 410 static logical_drive_t *
410 411 fdisk_alloc_ld_node()
411 412 {
412 413 logical_drive_t *temp;
413 414
414 415 if ((temp = calloc(1, sizeof (logical_drive_t))) == NULL) {
415 416 return (NULL);
416 417 }
417 418 temp->next = NULL;
418 419 return (temp);
419 420 }
420 421
421 422 /*
422 423 * Free all the logical_drive_t's allocated during the run
423 424 */
424 425 static void
425 426 fdisk_free_ld_nodes(ext_part_t *epp)
426 427 {
427 428 logical_drive_t *temp;
428 429
429 430 for (temp = epp->ld_head; temp != NULL; ) {
430 431 temp = epp->ld_head -> next;
431 432 free(epp->ld_head);
432 433 epp->ld_head = temp;
433 434 }
434 435 epp->ld_head = NULL;
435 436 epp->sorted_ld_head = NULL;
436 437 }
437 438
438 439 /*
439 440 * Find the first free sector within the extended partition
440 441 */
441 442 int
442 443 fdisk_ext_find_first_free_sec(ext_part_t *epp, uint32_t *first_free_sec)
443 444 {
444 445 logical_drive_t *temp;
445 446 uint32_t last_free_sec;
446 447
447 448 *first_free_sec = epp->ext_beg_sec;
448 449
449 450 if (epp->ld_head == NULL) {
450 451 return (FDISK_SUCCESS);
451 452 }
452 453
453 454 /*
454 455 * When the first logical drive is out of order, we need to adjust
455 456 * first_free_sec accordingly. In this case, the first extended
456 457 * partition sector is not free even though the actual logical drive
457 458 * does not occupy space from the beginning of the extended partition.
458 459 * The next free sector would be the second sector of the extended
459 460 * partition.
460 461 */
461 462 if (epp->ld_head->abs_secnum > epp->ext_beg_sec +
462 463 MAX_LOGDRIVE_OFFSET) {
463 464 (*first_free_sec)++;
464 465 }
465 466
466 467 while (*first_free_sec <= epp->ext_end_sec) {
467 468 for (temp = epp->sorted_ld_head; temp != NULL; temp =
468 469 temp->sorted_next) {
469 470 if (temp->abs_secnum == *first_free_sec) {
470 471 *first_free_sec = temp->abs_secnum +
471 472 temp->logdrive_offset + temp->numsect;
472 473 }
473 474 }
474 475
475 476 last_free_sec = fdisk_ext_find_last_free_sec(epp,
476 477 *first_free_sec);
477 478
478 479 if ((last_free_sec - *first_free_sec) < MAX_LOGDRIVE_OFFSET) {
479 480 /*
480 481 * Minimum size of a partition assumed to be atleast one
481 482 * sector.
482 483 */
483 484 *first_free_sec = last_free_sec + 1;
484 485 continue;
485 486 }
486 487
487 488 break;
488 489 }
489 490
490 491 if (*first_free_sec > epp->ext_end_sec) {
491 492 return (FDISK_EOOBOUND);
492 493 }
493 494
494 495 return (FDISK_SUCCESS);
495 496 }
496 497
497 498 /*
498 499 * Find the last free sector within the extended partition given, a beginning
499 500 * sector (so that the range - "begsec to last_free_sec" is contiguous)
500 501 */
501 502 uint32_t
502 503 fdisk_ext_find_last_free_sec(ext_part_t *epp, uint32_t begsec)
503 504 {
504 505 logical_drive_t *temp;
505 506 uint32_t last_free_sec;
506 507
507 508 last_free_sec = epp->ext_end_sec;
508 509 for (temp = epp->sorted_ld_head; temp != NULL;
509 510 temp = temp->sorted_next) {
510 511 if (temp->abs_secnum > begsec) {
511 512 last_free_sec = temp->abs_secnum - 1;
512 513 break;
513 514 }
514 515 }
515 516 return (last_free_sec);
516 517 }
517 518
518 519 /*
519 520 * Place the given ext_part_t structure in a sorted list, sorted in the
520 521 * ascending order of their beginning sectors.
521 522 */
522 523 static void
523 524 fdisk_ext_place_in_sorted_list(ext_part_t *epp, logical_drive_t *newld)
524 525 {
525 526 logical_drive_t *pre, *cur;
526 527
527 528 if (newld->abs_secnum < epp->sorted_ld_head->abs_secnum) {
528 529 newld->sorted_next = epp->sorted_ld_head;
529 530 epp->sorted_ld_head = newld;
530 531 return;
531 532 }
532 533 pre = cur = epp->sorted_ld_head;
533 534
534 535 for (; cur != NULL; pre = cur, cur = cur->sorted_next) {
535 536 if (newld->abs_secnum < cur->abs_secnum) {
536 537 break;
537 538 }
538 539 }
539 540
540 541 newld->sorted_next = cur;
541 542 pre->sorted_next = newld;
542 543 }
543 544
544 545 static void
545 546 fdisk_ext_remove_from_sorted_list(ext_part_t *epp, logical_drive_t *delld)
546 547 {
547 548 logical_drive_t *pre, *cur;
548 549
549 550 if (delld == epp->sorted_ld_head) {
550 551 epp->sorted_ld_head = delld->sorted_next;
551 552 return;
552 553 }
553 554
554 555 pre = cur = epp->sorted_ld_head;
555 556
556 557 for (; cur != NULL; pre = cur, cur = cur->sorted_next) {
557 558 if (cur->abs_secnum == delld->abs_secnum) {
558 559 /* Found */
559 560 break;
560 561 }
561 562 }
562 563
563 564 pre->sorted_next = cur->sorted_next;
564 565 }
565 566
566 567 static int
567 568 fdisk_ext_overlapping_parts(ext_part_t *epp, uint32_t begsec, uint32_t endsec)
568 569 {
569 570 logical_drive_t *temp;
570 571 uint32_t firstsec, lastsec, last_free_sec;
571 572
572 573 for (temp = epp->ld_head; temp != NULL; temp = temp->next) {
573 574 firstsec = temp->abs_secnum;
574 575 lastsec = firstsec + temp->logdrive_offset + temp->numsect - 1;
575 576 if ((begsec >= firstsec) &&
576 577 (begsec <= lastsec)) {
577 578 return (1);
578 579 }
579 580 }
580 581
581 582 /*
582 583 * Find the maximum possible end sector value
583 584 * given a beginning sector value
584 585 */
585 586 last_free_sec = fdisk_ext_find_last_free_sec(epp, begsec);
586 587
587 588 if (endsec > last_free_sec) {
588 589 return (1);
589 590 }
590 591 return (0);
591 592 }
592 593
593 594 /*
594 595 * Check if the logical drive boundaries are sane
595 596 */
596 597 int
597 598 fdisk_validate_logical_drive(ext_part_t *epp, uint32_t begsec,
598 599 uint32_t offset, uint32_t numsec)
599 600 {
600 601 uint32_t endsec;
601 602
602 603 endsec = begsec + offset + numsec - 1;
603 604 if (begsec < epp->ext_beg_sec ||
604 605 begsec > epp->ext_end_sec ||
605 606 endsec < epp->ext_beg_sec ||
606 607 endsec > epp->ext_end_sec ||
607 608 endsec < begsec ||
608 609 fdisk_ext_overlapping_parts(epp, begsec, endsec)) {
609 610 return (1);
610 611 }
611 612
612 613 return (0);
613 614 }
614 615
615 616 /*
616 617 * Procedure to walk through the extended partitions and build a Singly
617 618 * Linked List out of the data.
618 619 */
619 620 static int
620 621 fdisk_read_extpart(ext_part_t *epp)
621 622 {
622 623 struct ipart *fdp, *ext_fdp;
623 624 int i = 0, j = 0, ext_part_found = 0, lpart = 5;
624 625 off_t secnum, offset;
625 626 logical_drive_t *temp, *ep_ptr;
626 627 unsigned char *ext_buf;
627 628 int sectsize = epp->disk_geom.sectsize;
628 629
629 630 if ((ext_buf = (uchar_t *)malloc(sectsize)) == NULL) {
630 631 return (ENOMEM);
631 632 }
632 633 fdp = epp->mtable;
633 634
634 635 for (i = 0; (i < FD_NUMPART) && (!ext_part_found); i++, fdp++) {
635 636 if (fdisk_is_dos_extended(LE_8(fdp->systid))) {
636 637 ext_part_found = 1;
637 638 secnum = LE_32(fdp->relsect);
638 639 offset = secnum * sectsize;
639 640 epp->ext_beg_sec = secnum;
640 641 epp->ext_end_sec = secnum + LE_32(fdp->numsect) - 1;
641 642 epp->ext_beg_cyl =
642 643 FDISK_SECT_TO_CYL(epp, epp->ext_beg_sec);
643 644 epp->ext_end_cyl =
644 645 FDISK_SECT_TO_CYL(epp, epp->ext_end_sec);
645 646
646 647 /*LINTED*/
647 648 while (B_TRUE) {
648 649 if (lseek(epp->dev_fd, offset, SEEK_SET) < 0) {
649 650 return (EIO);
650 651 }
651 652 if (read(epp->dev_fd, ext_buf, sectsize) <
652 653 sectsize) {
653 654 return (EIO);
654 655 }
655 656 /*LINTED*/
656 657 ext_fdp = (struct ipart *)
657 658 (&ext_buf[FDISK_PART_TABLE_START]);
658 659 if ((LE_32(ext_fdp->relsect) == 0) &&
659 660 (epp->logical_drive_count == 0)) {
660 661 /* No logical drives defined */
661 662 epp->first_ebr_is_null = 0;
662 663 return (FDISK_ENOLOGDRIVE);
663 664 }
664 665
665 666 temp = fdisk_alloc_ld_node();
666 667 temp->abs_secnum = secnum;
667 668 temp->logdrive_offset =
668 669 LE_32(ext_fdp->relsect);
669 670 temp ->numsect = LE_32(ext_fdp->numsect);
670 671 if (epp->ld_head == NULL) {
671 672 /* adding first logical drive */
672 673 if (temp->logdrive_offset >
673 674 MAX_LOGDRIVE_OFFSET) {
674 675 /* out of order */
675 676 temp->abs_secnum +=
676 677 temp->logdrive_offset;
677 678 temp->logdrive_offset = 0;
678 679 }
679 680 }
680 681 temp->begcyl =
681 682 FDISK_SECT_TO_CYL(epp, temp->abs_secnum);
682 683 temp->endcyl = FDISK_SECT_TO_CYL(epp,
683 684 temp->abs_secnum +
684 685 temp->logdrive_offset +
685 686 temp->numsect - 1);
686 687
687 688 /*
688 689 * Check for sanity of logical drives
689 690 */
690 691 if (fdisk_validate_logical_drive(epp,
691 692 temp->abs_secnum, temp->logdrive_offset,
692 693 temp->numsect)) {
693 694 epp->corrupt_logical_drives = 1;
694 695 free(temp);
695 696 return (FDISK_EBADLOGDRIVE);
696 697 }
697 698
698 699 temp->parts[0] = *ext_fdp;
699 700 ext_fdp++;
700 701 temp->parts[1] = *ext_fdp;
701 702
702 703 if (epp->ld_head == NULL) {
703 704 epp->ld_head = temp;
704 705 epp->sorted_ld_head = temp;
705 706 ep_ptr = temp;
706 707 epp->logical_drive_count = 1;
707 708 } else {
708 709 ep_ptr->next = temp;
709 710 ep_ptr = temp;
710 711 fdisk_ext_place_in_sorted_list(epp,
711 712 temp);
712 713 epp->logical_drive_count++;
713 714 }
714 715
715 716 /*LINTED*/
716 717 if (LE_16((*(uint16_t *)&ext_buf[510])) !=
717 718 MBB_MAGIC) {
718 719 epp->invalid_bb_sig[j++] = lpart;
719 720 temp->modified = FDISK_MINOR_WRITE;
720 721 }
721 722
722 723 if (LE_32(ext_fdp->relsect) == 0)
723 724 break;
724 725 else {
725 726 secnum = LE_32(fdp->relsect) +
726 727 LE_32(ext_fdp->relsect);
727 728 offset = secnum * sectsize;
728 729 }
729 730 lpart++;
730 731 }
731 732 }
732 733 }
733 734 return (FDISK_SUCCESS);
734 735 }
735 736
736 737 static int
737 738 fdisk_init_master_part_table(ext_part_t *epp)
738 739 {
739 740 int rval;
740 741 if ((epp->mtable = fdisk_alloc_part_table()) == NULL) {
741 742 return (ENOMEM);
742 743 }
743 744 rval = fdisk_read_master_part_table(epp);
744 745 if (rval) {
745 746 return (rval);
746 747 }
747 748 return (FDISK_SUCCESS);
748 749 }
749 750
750 751 static struct ipart *
751 752 fdisk_alloc_part_table()
752 753 {
753 754 int size = sizeof (struct ipart);
754 755 struct ipart *table;
755 756
756 757 if ((table = calloc(4, size)) == NULL) {
757 758 return (NULL);
758 759 }
759 760
760 761 return (table);
↓ open down ↓ |
728 lines elided |
↑ open up ↑ |
761 762 }
762 763
763 764 /*
764 765 * Reads the master fdisk partition table from the device assuming that it has
765 766 * a valid table.
766 767 * MBR is supposed to be of 512 bytes no matter what the device block size is.
767 768 */
768 769 static int
769 770 fdisk_read_master_part_table(ext_part_t *epp)
770 771 {
771 - uchar_t buf[512];
772 - int sectsize = 512;
772 + struct dk_minfo_ext dkmp_ext;
773 + uchar_t *buf;
774 + int sectsize;
773 775 int size = sizeof (struct ipart);
774 776 int cpcnt = FD_NUMPART * size;
775 777
776 778 if (lseek(epp->dev_fd, 0, SEEK_SET) < 0) {
777 779 return (EIO);
778 780 }
781 + if (ioctl(epp->dev_fd, DKIOCGMEDIAINFOEXT, &dkmp_ext) < 0) {
782 + return (EIO);
783 + }
784 + if (dkmp_ext.dki_lbsize < 512) {
785 + return (EIO);
786 + }
787 + sectsize = dkmp_ext.dki_lbsize;
788 + buf = calloc(sectsize, sizeof (uchar_t));
789 + if (buf == NULL) {
790 + return (ENOMEM);
791 + }
779 792 if (read(epp->dev_fd, buf, sectsize) < sectsize) {
793 + free(buf);
780 794 return (EIO);
781 795 }
782 796
783 797 /*LINTED*/
784 798 if (LE_16((*(uint16_t *)&buf[510])) != MBB_MAGIC) {
785 799 bzero(epp->mtable, cpcnt);
800 + free(buf);
786 801 return (FDISK_EBADMAGIC);
787 802 }
788 803
789 804 bcopy(&buf[FDISK_PART_TABLE_START], epp->mtable, cpcnt);
805 + free(buf);
790 806
791 807 return (FDISK_SUCCESS);
792 808 }
793 809
794 810 int
795 811 fdisk_ext_part_exists(ext_part_t *epp)
796 812 {
797 813 int i;
798 814 struct ipart *part_table = epp->mtable;
799 815
800 816 if (part_table == NULL) {
801 817 /* No extended partition found */
802 818 return (0);
803 819 }
804 820
805 821 for (i = 0; i < FD_NUMPART; i++) {
806 822 if (fdisk_is_dos_extended(LE_8(part_table[i].systid))) {
807 823 break;
808 824 }
809 825 }
810 826
811 827 if (i == FD_NUMPART) {
812 828 /* No extended partition found */
813 829 return (0);
814 830 }
815 831 return (1);
816 832 }
817 833
818 834 int
819 835 fdisk_ext_validate_part_start(ext_part_t *epp, uint32_t begcyl,
820 836 uint32_t *begsec)
821 837 {
822 838 logical_drive_t *temp;
823 839 uint32_t first_free_sec;
824 840 uint32_t first_free_cyl;
825 841 int rval;
826 842
827 843 rval = fdisk_ext_find_first_free_sec(epp, &first_free_sec);
828 844 if (rval != FDISK_SUCCESS) {
829 845 return (rval);
830 846 }
831 847
832 848 first_free_cyl = FDISK_SECT_TO_CYL(epp, first_free_sec);
833 849 if (begcyl == first_free_cyl) {
834 850 *begsec = first_free_sec;
835 851 return (FDISK_SUCCESS);
836 852 }
837 853
838 854 /* Check if the cylinder number is beyond the extended partition */
839 855 if ((begcyl < epp->ext_beg_cyl) || (begcyl > epp->ext_end_cyl)) {
840 856 return (FDISK_EOOBOUND);
841 857 }
842 858
843 859 for (temp = epp->ld_head; temp != NULL; temp = temp->next) {
844 860 if ((begcyl >= temp->begcyl) &&
845 861 (begcyl <= temp->endcyl)) {
846 862 return (FDISK_EOVERLAP);
847 863 }
848 864 }
849 865 *begsec = FDISK_CYL_TO_SECT(epp, begcyl);
850 866
851 867 return (FDISK_SUCCESS);
852 868 }
853 869
854 870 void
855 871 fdisk_change_logical_drive_id(ext_part_t *epp, int pno, uchar_t partid)
856 872 {
857 873 logical_drive_t *temp;
858 874 int i;
859 875
860 876 i = FD_NUMPART + 1;
861 877 for (temp = epp->ld_head; i < pno; temp = temp->next, i++)
862 878 ;
863 879
864 880 temp->parts[0].systid = LE_8(partid);
865 881 temp->modified = FDISK_MAJOR_WRITE;
866 882 }
867 883
868 884 /*
869 885 * A couple of special scenarios :
870 886 * 1. Since the first logical drive's EBR is always at the beginning of the
871 887 * extended partition, any specification that starts the first logical drive
872 888 * out of order will need to address the following issue :
873 889 * If the beginning of the drive is not coinciding with the beginning of the
874 890 * extended partition and :
875 891 * a) The start is within MAX_LOGDRIVE_OFFSET, the offset changes from the
876 892 * default of 63 to less than 63.
877 893 * logdrive_offset is updated to keep track of the space between
878 894 * the beginning of the logical drive and extended partition. abs_secnum
879 895 * points to the beginning of the extended partition.
880 896 * b) The start is greater than MAX_LOGDRIVE_OFFSET, the offset changes from
881 897 * the default of 63 to greater than 63.
882 898 * logdrive_offset is set to 0. abs_secnum points to the beginning of the
883 899 * logical drive, which is at an offset from the extended partition.
884 900 */
885 901 void
886 902 fdisk_add_logical_drive(ext_part_t *epp, uint32_t begsec, uint32_t endsec,
887 903 uchar_t partid)
888 904 {
889 905 logical_drive_t *temp, *pre, *cur;
890 906 struct ipart *part;
891 907
892 908 temp = fdisk_alloc_ld_node();
893 909 temp->abs_secnum = begsec;
894 910 temp->logdrive_offset = MAX_LOGDRIVE_OFFSET;
895 911 temp->numsect = endsec - begsec + 1 - MAX_LOGDRIVE_OFFSET;
896 912 temp->begcyl = FDISK_SECT_TO_CYL(epp, begsec);
897 913 temp->endcyl = FDISK_SECT_TO_CYL(epp, endsec);
898 914 temp->modified = FDISK_MAJOR_WRITE;
899 915
900 916 part = &temp->parts[0];
901 917 part->bootid = 0;
902 918 part->systid = LE_8(partid);
903 919 part->relsect = MAX_LOGDRIVE_OFFSET;
904 920 part->numsect = LE_32(temp->numsect);
905 921
906 922 fdisk_set_CHS_values(epp, part);
907 923
908 924 if (epp->ld_head == NULL) {
909 925 epp->corrupt_logical_drives = 0;
910 926 if (begsec != epp->ext_beg_sec) {
911 927 part->relsect = LE_32(begsec - epp->ext_beg_sec);
912 928 temp->numsect = endsec - begsec + 1;
913 929 part->numsect = LE_32(temp->numsect);
914 930 if (LE_32(part->relsect) > MAX_LOGDRIVE_OFFSET) {
915 931 temp->logdrive_offset = 0;
916 932 } else {
917 933 temp->abs_secnum = epp->ext_beg_sec;
918 934 temp->logdrive_offset = LE_32(part->relsect);
919 935 }
920 936 }
921 937 epp->first_ebr_is_null = 0;
922 938 epp->ld_head = temp;
923 939 epp->sorted_ld_head = temp;
924 940 epp->logical_drive_count = 1;
925 941 return;
926 942 }
927 943
928 944 if (temp->abs_secnum == epp->ext_beg_sec) {
929 945 part->relsect = LE_32(LE_32(part->relsect) - 1);
930 946 temp->logdrive_offset--;
931 947 temp->abs_secnum++;
932 948 }
933 949
934 950 for (pre = cur = epp->ld_head; cur != NULL; pre = cur, cur = cur->next)
935 951 ;
936 952
937 953 part = &pre->parts[1];
938 954 part->bootid = 0;
939 955 part->systid = LE_8(EXTDOS);
940 956 part->relsect = LE_32(temp->abs_secnum - epp->ext_beg_sec);
941 957 part->numsect = LE_32(temp->numsect + temp->logdrive_offset);
942 958
943 959 fdisk_set_CHS_values(epp, part);
944 960
945 961 pre->next = temp;
946 962 pre->modified = FDISK_MAJOR_WRITE;
947 963 epp->logical_drive_count++;
948 964 fdisk_ext_place_in_sorted_list(epp, temp);
949 965 }
950 966
951 967 /*
952 968 * There are 2 cases that need to be handled.
953 969 * 1. Deleting the first extended partition :
954 970 * The peculiarity of this case is that the offset of the first extended
955 971 * partition is always indicated by the entry in the master boot record.
956 972 * (MBR). This never changes, unless the extended partition itself is
957 973 * deleted. Hence, the location of the first EBR is fixed.
958 974 * It is only the logical drive which is deleted. This first EBR now gives
959 975 * information of the next logical drive and the info about the subsequent
960 976 * extended partition. Hence the "relsect" of the first EBR is modified to
961 977 * point to the next logical drive.
962 978 *
963 979 * 2. Deleting an intermediate extended partition.
964 980 * This is quite normal and follows the semantics of a normal linked list
965 981 * delete operation. The node being deleted has the information about the
966 982 * logical drive that it houses and the location and the size of the next
967 983 * extended partition. This informationis transferred to the node previous
968 984 * to the node being deleted.
969 985 *
970 986 */
971 987
972 988 void
973 989 fdisk_delete_logical_drive(ext_part_t *epp, int pno)
974 990 {
975 991 logical_drive_t *pre, *cur;
976 992 int i;
977 993
978 994 i = FD_NUMPART + 1;
979 995 pre = cur = epp->ld_head;
980 996 for (; i < pno; i++) {
981 997 pre = cur;
982 998 cur = cur->next;
983 999 }
984 1000
985 1001 if (cur == epp->ld_head) {
986 1002 /* Deleting the first logical drive */
987 1003 if (cur->next == NULL) {
988 1004 /* Deleting the only logical drive left */
989 1005 free(cur);
990 1006 epp->ld_head = NULL;
991 1007 epp->sorted_ld_head = NULL;
992 1008 epp->logical_drive_count = 0;
993 1009 epp->first_ebr_is_null = 1;
994 1010 } else {
995 1011 pre = epp->ld_head;
996 1012 cur = pre->next;
997 1013 cur->parts[0].relsect =
998 1014 LE_32(LE_32(cur->parts[0].relsect) +
999 1015 LE_32(pre->parts[1].relsect));
1000 1016 /* Corner case when partitions are out of order */
1001 1017 if ((pre->abs_secnum != epp->ext_beg_sec) &&
1002 1018 (cur->abs_secnum == epp->ext_beg_sec + 1)) {
1003 1019 cur->logdrive_offset++;
1004 1020 cur->abs_secnum = epp->ext_beg_sec;
1005 1021 } else {
1006 1022 cur->abs_secnum = LE_32(cur->parts[0].relsect) +
1007 1023 epp->ext_beg_sec;
1008 1024 cur->logdrive_offset = 0;
1009 1025 }
1010 1026 fdisk_ext_remove_from_sorted_list(epp, pre);
1011 1027 epp->ld_head = cur;
1012 1028 epp->ld_head->modified = FDISK_MAJOR_WRITE;
1013 1029 epp->logical_drive_count--;
1014 1030 free(pre);
1015 1031 }
1016 1032 } else {
1017 1033 pre->parts[1] = cur->parts[1];
1018 1034 pre->next = cur->next;
1019 1035 fdisk_ext_remove_from_sorted_list(epp, cur);
1020 1036 pre->modified = FDISK_MAJOR_WRITE;
1021 1037 free(cur);
1022 1038 epp->logical_drive_count--;
1023 1039 }
1024 1040 }
1025 1041
1026 1042 static void
1027 1043 fdisk_set_CHS_values(ext_part_t *epp, struct ipart *part)
1028 1044 {
1029 1045 uint32_t lba, cy, hd, sc;
1030 1046 uint32_t sectors = epp->disk_geom.virt_sec;
1031 1047 uint32_t heads = epp->disk_geom.virt_heads;
1032 1048
1033 1049 lba = LE_32(part->relsect) + epp->ext_beg_sec;
1034 1050 if (lba >= heads * sectors * MAX_CYL) {
1035 1051 /*
1036 1052 * the lba address cannot be expressed in CHS value
1037 1053 * so store the maximum CHS field values in the CHS fields.
1038 1054 */
1039 1055 cy = MAX_CYL + 1;
1040 1056 hd = MAX_HEAD;
1041 1057 sc = MAX_SECT;
1042 1058 } else {
1043 1059 cy = lba / sectors / heads;
1044 1060 hd = lba / sectors % heads;
1045 1061 sc = lba % sectors + 1;
1046 1062 }
1047 1063
1048 1064 part->begcyl = cy & 0xff;
1049 1065 part->beghead = (uchar_t)hd;
1050 1066 part->begsect = (uchar_t)(((cy >> 2) & 0xc0) | sc);
1051 1067
1052 1068 /*
1053 1069 * This code is identical to the code above
1054 1070 * except that it works on ending CHS values
1055 1071 */
1056 1072 lba += LE_32(part->numsect - 1);
1057 1073 if (lba >= heads * sectors * MAX_CYL) {
1058 1074 cy = MAX_CYL + 1;
1059 1075 hd = MAX_HEAD;
1060 1076 sc = MAX_SECT;
1061 1077 } else {
1062 1078 cy = lba / sectors / heads;
1063 1079 hd = lba / sectors % heads;
1064 1080 sc = lba % sectors + 1;
1065 1081 }
1066 1082 part->endcyl = cy & 0xff;
1067 1083 part->endhead = (uchar_t)hd;
1068 1084 part->endsect = (uchar_t)(((cy >> 2) & 0xc0) | sc);
1069 1085 }
1070 1086
1071 1087 static int
1072 1088 read_modify_write_ebr(ext_part_t *epp, unsigned char *ebr_buf,
1073 1089 struct ipart *ebr_tab, uint32_t sec_offset)
1074 1090 {
1075 1091 off_t seek_offset;
1076 1092 int sectsize = epp->disk_geom.sectsize;
1077 1093
1078 1094 seek_offset = (off_t)sec_offset * sectsize;
1079 1095
1080 1096 if (lseek(epp->dev_fd, seek_offset, SEEK_SET) < 0) {
1081 1097 return (EIO);
1082 1098 }
1083 1099 if (read(epp->dev_fd, ebr_buf, sectsize) < sectsize) {
1084 1100 return (EIO);
1085 1101 }
1086 1102
1087 1103 bzero(&ebr_buf[FDISK_PART_TABLE_START], 4 * sizeof (struct ipart));
1088 1104 if (ebr_tab != NULL) {
1089 1105 bcopy(ebr_tab, &ebr_buf[FDISK_PART_TABLE_START],
1090 1106 2 * sizeof (struct ipart));
1091 1107 }
1092 1108 ebr_buf[510] = 0x55;
1093 1109 ebr_buf[511] = 0xAA;
1094 1110 if (lseek(epp->dev_fd, seek_offset, SEEK_SET) < 0) {
1095 1111 return (EIO);
1096 1112 }
1097 1113 if (write(epp->dev_fd, ebr_buf, sectsize) < sectsize) {
1098 1114 return (EIO);
1099 1115 }
1100 1116 return (0);
1101 1117 }
1102 1118
1103 1119 /*
1104 1120 * XXX - ZFS mounts not detected. Needs to come in as a feature.
1105 1121 * Currently only /etc/mnttab entries are being checked
1106 1122 */
1107 1123 int
1108 1124 fdisk_mounted_logical_drives(ext_part_t *epp)
1109 1125 {
1110 1126 char *part_str, *canonp;
1111 1127 char compare_pdev_str[PATH_MAX];
1112 1128 char compare_sdev_str[PATH_MAX];
1113 1129 FILE *fp;
1114 1130 struct mnttab mt;
1115 1131 int part;
1116 1132 int look_for_mounted_slices = 0;
1117 1133 uint32_t begsec, numsec;
1118 1134
1119 1135 /*
1120 1136 * Do not check for mounted logical drives for
1121 1137 * devices other than /dev/rdsk/
1122 1138 */
1123 1139 if (strstr(epp->device_name, DEFAULT_PATH_PREFIX) == NULL) {
1124 1140 return (0);
1125 1141 }
1126 1142
1127 1143 if ((fp = fopen(MNTTAB, "r")) == NULL) {
1128 1144 return (ENOENT);
1129 1145 }
1130 1146
1131 1147 canonp = epp->device_name + strlen(DEFAULT_PATH_PREFIX);
1132 1148 (void) snprintf(compare_pdev_str, PATH_MAX, "%s%s", "/dev/dsk/",
1133 1149 canonp);
1134 1150 part_str = strrchr(compare_pdev_str, 'p');
1135 1151 *(part_str + 1) = '\0';
1136 1152 (void) strcpy(compare_sdev_str, compare_pdev_str);
1137 1153 part_str = strrchr(compare_sdev_str, 'p');
1138 1154 *part_str = 's';
1139 1155
1140 1156 if (fdisk_get_solaris_part(epp, &part, &begsec, &numsec) ==
1141 1157 FDISK_SUCCESS) {
1142 1158 if (part > FD_NUMPART) {
1143 1159 /*
1144 1160 * Solaris partition is on a logical drive. Look for
1145 1161 * mounted slices.
1146 1162 */
1147 1163 look_for_mounted_slices = 1;
1148 1164 }
1149 1165 }
1150 1166
1151 1167 while (getmntent(fp, &mt) == 0) {
1152 1168 if (strstr(mt.mnt_special, compare_pdev_str) == NULL) {
1153 1169 if (strstr(mt.mnt_special, compare_sdev_str) == NULL) {
1154 1170 continue;
1155 1171 } else {
1156 1172 if (look_for_mounted_slices) {
1157 1173 return (FDISK_EMOUNTED);
1158 1174 }
1159 1175 }
1160 1176 }
1161 1177
1162 1178 /*
1163 1179 * Get the partition number that is mounted, which would be
1164 1180 * found just beyond the last 'p' in the device string.
1165 1181 * For example, in /dev/dsk/c0t0d0p12, partition number 12
1166 1182 * is just beyond the last 'p'.
1167 1183 */
1168 1184 part_str = strrchr(mt.mnt_special, 'p');
1169 1185 if (part_str != NULL) {
1170 1186 part_str++;
1171 1187 part = atoi(part_str);
1172 1188 /* Extended partition numbers start from 5 */
1173 1189 if (part >= 5) {
1174 1190 return (FDISK_EMOUNTED);
1175 1191 }
1176 1192 }
1177 1193 }
1178 1194 return (0);
1179 1195 }
1180 1196
1181 1197 int
1182 1198 fdisk_commit_ext_part(ext_part_t *epp)
1183 1199 {
1184 1200 logical_drive_t *temp;
1185 1201 int wflag = 0; /* write flag */
1186 1202 int rval;
1187 1203 int sectsize = epp->disk_geom.sectsize;
1188 1204 unsigned char *ebr_buf;
1189 1205 int ld_count;
1190 1206 uint32_t abs_secnum;
1191 1207 int check_mounts = 0;
1192 1208
1193 1209 if ((ebr_buf = (unsigned char *)malloc(sectsize)) == NULL) {
1194 1210 return (ENOMEM);
1195 1211 }
1196 1212
1197 1213 if (epp->first_ebr_is_null) {
1198 1214 /*
1199 1215 * Indicator that the extended partition as a whole was
1200 1216 * modifies (either created or deleted. Must check for mounts
1201 1217 * and must commit
1202 1218 */
1203 1219 check_mounts = 1;
1204 1220 }
1205 1221
1206 1222 /*
1207 1223 * Pass1 through the logical drives to make sure that commit of minor
1208 1224 * written block dont get held up due to mounts.
1209 1225 */
1210 1226 for (temp = epp->ld_head; temp != NULL; temp = temp->next) {
1211 1227 if (temp == epp->ld_head) {
1212 1228 abs_secnum = epp->ext_beg_sec;
1213 1229 } else {
1214 1230 abs_secnum = temp->abs_secnum;
1215 1231 }
1216 1232 if (temp->modified == FDISK_MINOR_WRITE) {
1217 1233 rval = read_modify_write_ebr(epp, ebr_buf,
1218 1234 temp->parts, abs_secnum);
1219 1235 if (rval) {
1220 1236 goto error;
1221 1237 }
1222 1238 temp->modified = 0;
1223 1239 } else if (temp->modified == FDISK_MAJOR_WRITE) {
1224 1240 check_mounts = 1;
1225 1241 }
1226 1242 }
1227 1243
1228 1244 if (!check_mounts) {
1229 1245 goto skip_check_mounts;
1230 1246 }
1231 1247
1232 1248 if ((rval = fdisk_mounted_logical_drives(epp)) != 0) {
1233 1249 /* One/more extended partitions are mounted */
1234 1250 if (ebr_buf) {
1235 1251 free(ebr_buf);
1236 1252 }
1237 1253 return (rval);
1238 1254 }
1239 1255
1240 1256 skip_check_mounts:
1241 1257
1242 1258 if (epp->first_ebr_is_null) {
1243 1259 rval = read_modify_write_ebr(epp, ebr_buf, NULL,
1244 1260 epp->ext_beg_sec);
1245 1261 if (rval) {
1246 1262 goto error;
1247 1263 }
1248 1264 wflag = 1;
1249 1265 ld_count = 0;
1250 1266 } else {
1251 1267 if (epp->logical_drive_count == 0) {
1252 1268 /*
1253 1269 * Can hit this case when there is just an extended
1254 1270 * partition with no logical drives, and the user
1255 1271 * committed without making any changes
1256 1272 * We dont have anything to commit. Return success
1257 1273 */
1258 1274 if (ebr_buf) {
1259 1275 free(ebr_buf);
1260 1276 }
1261 1277 return (FDISK_SUCCESS);
1262 1278 }
1263 1279
1264 1280 /*
1265 1281 * Make sure that the first EBR is written with the first
1266 1282 * logical drive's data, which might not be the first in disk
1267 1283 * order.
1268 1284 */
1269 1285 for (temp = epp->ld_head, ld_count = 0; temp != NULL;
1270 1286 temp = temp->next, ld_count++) {
1271 1287 if (ld_count == 0) {
1272 1288 abs_secnum = epp->ext_beg_sec;
1273 1289 } else {
1274 1290 abs_secnum = temp->abs_secnum;
1275 1291 }
1276 1292 if (temp->modified) {
1277 1293 rval = read_modify_write_ebr(epp, ebr_buf,
1278 1294 temp->parts, abs_secnum);
1279 1295 if (rval) {
1280 1296 if (ld_count) {
1281 1297 /*
1282 1298 * There was atleast one
1283 1299 * write to the disk before
1284 1300 * this failure. Make sure that
1285 1301 * the kernel is notified.
1286 1302 * Issue the ioctl.
1287 1303 */
1288 1304 break;
1289 1305 }
1290 1306 goto error;
1291 1307 }
1292 1308 if ((!wflag) && (temp->modified ==
1293 1309 FDISK_MAJOR_WRITE)) {
1294 1310 wflag = 1;
1295 1311 }
1296 1312 }
1297 1313 }
1298 1314
1299 1315 if (wflag == 0) {
1300 1316 /* No changes made */
1301 1317 rval = FDISK_SUCCESS;
1302 1318 goto error;
1303 1319 }
1304 1320 }
1305 1321
1306 1322 /* Issue ioctl to the driver to update extended partition info */
1307 1323 rval = ioctl(epp->dev_fd, DKIOCSETEXTPART);
1308 1324
1309 1325 /*
1310 1326 * Certain devices ex:lofi do not support DKIOCSETEXTPART.
1311 1327 * Extended partitions are still created on these devices.
1312 1328 */
1313 1329 if (errno == ENOTTY)
1314 1330 rval = FDISK_SUCCESS;
1315 1331
1316 1332 error:
1317 1333 if (ebr_buf) {
1318 1334 free(ebr_buf);
1319 1335 }
1320 1336 return (rval);
1321 1337 }
1322 1338
1323 1339 int
1324 1340 fdisk_init_ext_part(ext_part_t *epp, uint32_t rsect, uint32_t nsect)
1325 1341 {
1326 1342 epp->first_ebr_is_null = 1;
1327 1343 epp->corrupt_logical_drives = 0;
1328 1344 epp->logical_drive_count = 0;
1329 1345 epp->ext_beg_sec = rsect;
1330 1346 epp->ext_end_sec = rsect + nsect - 1;
1331 1347 epp->ext_beg_cyl = FDISK_SECT_TO_CYL(epp, epp->ext_beg_sec);
1332 1348 epp->ext_end_cyl = FDISK_SECT_TO_CYL(epp, epp->ext_end_sec);
1333 1349 epp->invalid_bb_sig[0] = 0;
1334 1350 return (0);
1335 1351 }
1336 1352
1337 1353 int
1338 1354 fdisk_delete_ext_part(ext_part_t *epp)
1339 1355 {
1340 1356 epp->first_ebr_is_null = 1;
1341 1357 /* Clear the logical drive information */
1342 1358 fdisk_free_ld_nodes(epp);
1343 1359 epp->logical_drive_count = 0;
1344 1360 epp->corrupt_logical_drives = 0;
1345 1361 epp->invalid_bb_sig[0] = 0;
1346 1362 return (0);
1347 1363 }
1348 1364
1349 1365 int
1350 1366 fdisk_get_disk_geom(ext_part_t *epp, int type, int what)
1351 1367 {
1352 1368 switch (type) {
1353 1369 case PHYSGEOM:
1354 1370 switch (what) {
1355 1371 case NCYL:
1356 1372 return ((int)epp->disk_geom.phys_cyl);
1357 1373 case NHEADS:
1358 1374 return ((int)epp->disk_geom.phys_heads);
1359 1375 case NSECTPT:
1360 1376 return ((int)epp->disk_geom.phys_sec);
1361 1377 case SSIZE:
1362 1378 return ((int)epp->disk_geom.sectsize);
1363 1379 case ACYL:
1364 1380 return ((int)epp->disk_geom.alt_cyl);
1365 1381 default:
1366 1382 return (EINVAL);
1367 1383 }
1368 1384 case VIRTGEOM:
1369 1385 switch (what) {
1370 1386 case NCYL:
1371 1387 return ((int)epp->disk_geom.virt_cyl);
1372 1388 case NHEADS:
1373 1389 return ((int)epp->disk_geom.virt_heads);
1374 1390 case NSECTPT:
1375 1391 return ((int)epp->disk_geom.virt_sec);
1376 1392 case SSIZE:
1377 1393 return ((int)epp->disk_geom.sectsize);
1378 1394 case ACYL:
1379 1395 return ((int)epp->disk_geom.alt_cyl);
1380 1396 default:
1381 1397 return (EINVAL);
1382 1398 }
1383 1399 default:
1384 1400 return (EINVAL);
1385 1401 }
1386 1402 }
1387 1403
1388 1404 int
1389 1405 fdisk_invalid_bb_sig(ext_part_t *epp, uchar_t **bbsig_arr)
1390 1406 {
1391 1407 *bbsig_arr = &(epp->invalid_bb_sig[0]);
1392 1408 return (epp->invalid_bb_sig[0]);
1393 1409 }
↓ open down ↓ |
594 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX