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