1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21 /*
22 * Copyright (c) 1993, 2010, Oracle and/or its affiliates. All rights reserved.
23 */
24
25 /*
26 * This file contains functions that implement the fdisk menu commands.
27 */
28 #include "global.h"
29 #include <errno.h>
30 #include <sys/time.h>
31 #include <sys/resource.h>
32 #include <sys/wait.h>
33 #include <signal.h>
34 #include <string.h>
35 #include <fcntl.h>
36 #include <stdlib.h>
37 #include <sys/dktp/fdisk.h>
38 #include <sys/stat.h>
39 #include <sys/dklabel.h>
40 #ifdef i386
41 #include <libfdisk.h>
42 #endif
43
44 #include "main.h"
45 #include "analyze.h"
46 #include "menu.h"
47 #include "menu_command.h"
48 #include "menu_defect.h"
49 #include "menu_partition.h"
50 #include "menu_fdisk.h"
51 #include "param.h"
52 #include "misc.h"
53 #include "label.h"
54 #include "startup.h"
55 #include "partition.h"
56 #include "prompts.h"
57 #include "checkdev.h"
58 #include "io.h"
59 #include "ctlr_scsi.h"
60 #include "auto_sense.h"
61
62 extern struct menu_item menu_fdisk[];
63
64 /*
65 * Byte swapping macros for accessing struct ipart
66 * to resolve little endian on Sparc.
67 */
68 #if defined(sparc)
69 #define les(val) ((((val)&0xFF)<<8)|(((val)>>8)&0xFF))
70 #define lel(val) (((unsigned)(les((val)&0x0000FFFF))<<16) | \
71 (les((unsigned)((val)&0xffff0000)>>16)))
72
73 #elif defined(i386)
74
75 #define les(val) (val)
76 #define lel(val) (val)
77
78 #else /* defined(sparc) */
79
80 #error No Platform defined
81
82 #endif /* defined(sparc) */
83
84
85 /* Function prototypes */
86 #ifdef __STDC__
87
88 #if defined(sparc)
89
90 static int getbyte(uchar_t **);
91 static int getlong(uchar_t **);
92
93 #endif /* defined(sparc) */
94
95 static int get_solaris_part(int fd, struct ipart *ipart);
96
97 #else /* __STDC__ */
98
99 #if defined(sparc)
100
101 static int getbyte();
102 static int getlong();
103
104 #endif /* defined(sparc) */
105
106 static int get_solaris_part();
107
108 #endif /* __STDC__ */
109
110 #ifdef i386
111 int extpart_init(ext_part_t **epp);
112 #endif
113 /*
114 * Handling the alignment problem of struct ipart.
115 */
116 static void
fill_ipart(char * bootptr,struct ipart * partp)117 fill_ipart(char *bootptr, struct ipart *partp)
118 {
119 #if defined(sparc)
120 /*
121 * Sparc platform:
122 *
123 * Packing short/word for struct ipart to resolve
124 * little endian on Sparc since it is not
125 * properly aligned on Sparc.
126 */
127 partp->bootid = getbyte((uchar_t **)&bootptr);
128 partp->beghead = getbyte((uchar_t **)&bootptr);
129 partp->begsect = getbyte((uchar_t **)&bootptr);
130 partp->begcyl = getbyte((uchar_t **)&bootptr);
131 partp->systid = getbyte((uchar_t **)&bootptr);
132 partp->endhead = getbyte((uchar_t **)&bootptr);
133 partp->endsect = getbyte((uchar_t **)&bootptr);
134 partp->endcyl = getbyte((uchar_t **)&bootptr);
135 partp->relsect = getlong((uchar_t **)&bootptr);
136 partp->numsect = getlong((uchar_t **)&bootptr);
137 #elif defined(i386)
138 /*
139 * i386 platform:
140 *
141 * The fdisk table does not begin on a 4-byte boundary within
142 * the master boot record; so, we need to recopy its contents
143 * to another data structure to avoid an alignment exception.
144 */
145 (void) bcopy(bootptr, partp, sizeof (struct ipart));
146 #else
147 #error No Platform defined
148 #endif /* defined(sparc) */
149 }
150
151 /*
152 * Get a correct byte/short/word routines for Sparc platform.
153 */
154 #if defined(sparc)
155 static int
getbyte(uchar_t ** bp)156 getbyte(uchar_t **bp)
157 {
158 int b;
159
160 b = **bp;
161 *bp = *bp + 1;
162 return (b);
163 }
164
165 #ifdef DEADCODE
166 static int
getshort(uchar_t ** bp)167 getshort(uchar_t **bp)
168 {
169 int b;
170
171 b = ((**bp) << 8) | *(*bp + 1);
172 *bp += 2;
173 return (b);
174 }
175 #endif /* DEADCODE */
176
177 static int
getlong(uchar_t ** bp)178 getlong(uchar_t **bp)
179 {
180 int b, bh, bl;
181
182 bh = ((**bp) << 8) | *(*bp + 1);
183 *bp += 2;
184 bl = ((**bp) << 8) | *(*bp + 1);
185 *bp += 2;
186
187 b = (bh << 16) | bl;
188 return (b);
189 }
190 #endif /* defined(sparc) */
191
192 #ifdef i386
193 /*
194 * Convert emcpowerN[a-p,p0,p1,p2,p3,p4] to emcpowerNp0 path,
195 * this is specific for emc powerpath driver.
196 */
197 static void
get_emcpower_pname(char * name,char * devname)198 get_emcpower_pname(char *name, char *devname)
199 {
200 char *emcp = "emcpower";
201 char *npt = NULL;
202 char np[MAXNAMELEN];
203 int i = strlen(emcp);
204
205 (void) strcpy(np, devname);
206 npt = strstr(np, emcp);
207 while ((i < strlen(npt)) && (isdigit(npt[i])))
208 i++;
209 npt[i] = '\0';
210 (void) snprintf(name, MAXNAMELEN, "/dev/rdsk/%sp0", npt);
211 }
212 #endif
213
214 /*
215 * Convert cn[tn]dn to cn[tn]dns2 path
216 */
217 static void
get_sname(char * name)218 get_sname(char *name)
219 {
220 char buf[MAXPATHLEN];
221 char *devp = "/dev/dsk";
222 char *rdevp = "/dev/rdsk";
223 char np[MAXNAMELEN];
224 char *npt;
225
226 #ifdef i386
227 if (emcpower_name(cur_disk->disk_name)) {
228 get_emcpower_pname(name, cur_disk->disk_name);
229 return;
230 }
231 #endif
232
233 /*
234 * If it is a full path /dev/[r]dsk/cn[tn]dn, use this path
235 */
236 (void) strcpy(np, cur_disk->disk_name);
237 if (strncmp(rdevp, cur_disk->disk_name, strlen(rdevp)) == 0 ||
238 strncmp(devp, cur_disk->disk_name, strlen(devp)) == 0) {
239 /*
240 * Skip if the path is already included with sN
241 */
242 if (strchr(np, 's') == strrchr(np, 's')) {
243 npt = strrchr(np, 'p');
244 /* If pN is found, do not include it */
245 if (npt != NULL) {
246 *npt = '\0';
247 }
248 (void) snprintf(buf, sizeof (buf), "%ss2", np);
249 } else {
250 (void) snprintf(buf, sizeof (buf), "%s", np);
251 }
252 } else {
253 (void) snprintf(buf, sizeof (buf), "/dev/rdsk/%ss2", np);
254 }
255 (void) strcpy(name, buf);
256 }
257
258 /*
259 * Convert cn[tn]dnsn to cn[tn]dnp0 path
260 */
261 static void
get_pname(char * name)262 get_pname(char *name)
263 {
264 char buf[MAXPATHLEN];
265 char *devp = "/dev/dsk";
266 char *rdevp = "/dev/rdsk";
267 char np[MAXNAMELEN];
268 char *npt;
269
270 /*
271 * If it is a full path /dev/[r]dsk/cn[tn]dnsn, use this path
272 */
273 if (cur_disk == NULL) {
274 (void) strcpy(np, x86_devname);
275 } else {
276 (void) strcpy(np, cur_disk->disk_name);
277 }
278
279 #ifdef i386
280 if (emcpower_name(np)) {
281 get_emcpower_pname(name, np);
282 return;
283 }
284 #endif
285
286 if (strncmp(rdevp, np, strlen(rdevp)) == 0 ||
287 strncmp(devp, np, strlen(devp)) == 0) {
288 /*
289 * Skip if the path is already included with pN
290 */
291 if (strchr(np, 'p') == NULL) {
292 npt = strrchr(np, 's');
293 /* If sN is found, do not include it */
294 if (isdigit(*++npt)) {
295 *--npt = '\0';
296 }
297 (void) snprintf(buf, sizeof (buf), "%sp0", np);
298 } else {
299 (void) snprintf(buf, sizeof (buf), "%s", np);
300 }
301 } else {
302 (void) snprintf(buf, sizeof (buf), "/dev/rdsk/%sp0", np);
303 }
304 (void) strcpy(name, buf);
305 }
306
307 /*
308 * Open file descriptor for current disk (cur_file)
309 * with "p0" path or cur_disk->disk_path
310 */
311 void
open_cur_file(int mode)312 open_cur_file(int mode)
313 {
314 char *dkpath;
315 char pbuf[MAXPATHLEN];
316
317 switch (mode) {
318 case FD_USE_P0_PATH:
319 (void) get_pname(&pbuf[0]);
320 dkpath = pbuf;
321 break;
322 case FD_USE_CUR_DISK_PATH:
323 if (cur_disk->fdisk_part.systid == SUNIXOS ||
324 cur_disk->fdisk_part.systid == SUNIXOS2) {
325 (void) get_sname(&pbuf[0]);
326 dkpath = pbuf;
327 } else {
328 dkpath = cur_disk->disk_path;
329 }
330 break;
331 default:
332 err_print("Error: Invalid mode option for opening "
333 "cur_file\n");
334 fullabort();
335 }
336
337 /* Close previous cur_file */
338 (void) close(cur_file);
339 /* Open cur_file with the required path dkpath */
340 if ((cur_file = open_disk(dkpath, O_RDWR | O_NDELAY)) < 0) {
341 err_print(
342 "Error: can't open selected disk '%s'.\n", dkpath);
343 fullabort();
344 }
345 }
346
347
348 /*
349 * This routine implements the 'fdisk' command. It simply runs
350 * the fdisk command on the current disk.
351 * Use of this is restricted to interactive mode only.
352 */
353 int
c_fdisk()354 c_fdisk()
355 {
356
357 char buf[MAXPATHLEN];
358 char pbuf[MAXPATHLEN];
359 struct stat statbuf;
360
361 /*
362 * We must be in interactive mode to use the fdisk command
363 */
364 if (option_f != (char *)NULL || isatty(0) != 1 || isatty(1) != 1) {
365 err_print("Fdisk command is for interactive use only!\n");
366 return (-1);
367 }
368
369 /*
370 * There must be a current disk type and a current disk
371 */
372 if (cur_dtype == NULL) {
373 err_print("Current Disk Type is not set.\n");
374 return (-1);
375 }
376
377 /*
378 * Before running the fdisk command, get file status of
379 * /dev/rdsk/cn[tn]dnp0 path to see if this disk
380 * supports fixed disk partition table.
381 */
382 (void) get_pname(&pbuf[0]);
383 if (stat(pbuf, (struct stat *)&statbuf) == -1 ||
384 !S_ISCHR(statbuf.st_mode)) {
385 err_print(
386 "Disk does not support fixed disk partition table\n");
387 return (0);
388 }
389
390 /*
391 * Run the fdisk program.
392 */
393 (void) snprintf(buf, sizeof (buf), "fdisk %s\n", pbuf);
394 (void) system(buf);
395
396 /*
397 * Open cur_file with "p0" path for accessing the fdisk table
398 */
399 (void) open_cur_file(FD_USE_P0_PATH);
400
401 /*
402 * Get solaris partition information in the fdisk partition table
403 */
404 if (get_solaris_part(cur_file, &cur_disk->fdisk_part) == -1) {
405 err_print("No fdisk solaris partition found\n");
406 cur_disk->fdisk_part.numsect = 0; /* No Solaris */
407 }
408
409 /*
410 * Restore cur_file with cur_disk->disk_path
411 */
412 (void) open_cur_file(FD_USE_CUR_DISK_PATH);
413
414 return (0);
415 }
416
417 /*
418 * Read MBR on the disk
419 * if the Solaris partition has changed,
420 * reread the vtoc
421 */
422 #ifdef DEADCODE
423 static void
update_cur_parts()424 update_cur_parts()
425 {
426
427 int i;
428 register struct partition_info *parts;
429
430 for (i = 0; i < NDKMAP; i++) {
431 #if defined(_SUNOS_VTOC_16)
432 if (cur_parts->vtoc.v_part[i].p_tag &&
433 cur_parts->vtoc.v_part[i].p_tag != V_ALTSCTR) {
434 cur_parts->vtoc.v_part[i].p_start = 0;
435 cur_parts->vtoc.v_part[i].p_size = 0;
436
437 #endif
438 cur_parts->pinfo_map[i].dkl_nblk = 0;
439 cur_parts->pinfo_map[i].dkl_cylno = 0;
440 cur_parts->vtoc.v_part[i].p_tag =
441 default_vtoc_map[i].p_tag;
442 cur_parts->vtoc.v_part[i].p_flag =
443 default_vtoc_map[i].p_flag;
444 #if defined(_SUNOS_VTOC_16)
445 }
446 #endif
447 }
448 cur_parts->pinfo_map[C_PARTITION].dkl_nblk = ncyl * spc();
449
450 #if defined(_SUNOS_VTOC_16)
451 /*
452 * Adjust for the boot partitions
453 */
454 cur_parts->pinfo_map[I_PARTITION].dkl_nblk = spc();
455 cur_parts->pinfo_map[I_PARTITION].dkl_cylno = 0;
456 cur_parts->vtoc.v_part[C_PARTITION].p_start =
457 cur_parts->pinfo_map[C_PARTITION].dkl_cylno * nhead * nsect;
458 cur_parts->vtoc.v_part[C_PARTITION].p_size =
459 cur_parts->pinfo_map[C_PARTITION].dkl_nblk;
460
461 cur_parts->vtoc.v_part[I_PARTITION].p_start =
462 cur_parts->pinfo_map[I_PARTITION].dkl_cylno;
463 cur_parts->vtoc.v_part[I_PARTITION].p_size =
464 cur_parts->pinfo_map[I_PARTITION].dkl_nblk;
465
466 #endif /* defined(_SUNOS_VTOC_16) */
467 parts = cur_dtype->dtype_plist;
468 cur_dtype->dtype_ncyl = ncyl;
469 cur_dtype->dtype_plist = cur_parts;
470 parts->pinfo_name = cur_parts->pinfo_name;
471 cur_disk->disk_parts = cur_parts;
472 cur_ctype->ctype_dlist = cur_dtype;
473
474 }
475 #endif /* DEADCODE */
476
477 static int
get_solaris_part(int fd,struct ipart * ipart)478 get_solaris_part(int fd, struct ipart *ipart)
479 {
480 int i;
481 struct ipart ip;
482 int status;
483 char *mbr;
484 char *bootptr;
485 struct dk_label update_label;
486 ushort_t found = 0;
487 #ifdef i386
488 uint32_t relsec, numsec;
489 int pno, rval, ext_part_found = 0;
490 ext_part_t *epp;
491 #endif
492
493 (void) lseek(fd, 0, 0);
494
495 /*
496 * We may get mbr of different size, but the first 512 bytes
497 * are valid information.
498 */
499 mbr = malloc(cur_blksz);
500 if (mbr == NULL) {
501 err_print("No memory available.\n");
502 return (-1);
503 }
504 status = read(fd, mbr, cur_blksz);
505
506 if (status != cur_blksz) {
507 err_print("Bad read of fdisk partition. Status = %x\n", status);
508 err_print("Cannot read fdisk partition information.\n");
509 free(mbr);
510 return (-1);
511 }
512
513 (void) memcpy(&boot_sec, mbr, sizeof (struct mboot));
514 free(mbr);
515
516 #ifdef i386
517 (void) extpart_init(&epp);
518 #endif
519 for (i = 0; i < FD_NUMPART; i++) {
520 int ipc;
521
522 ipc = i * sizeof (struct ipart);
523
524 /* Handling the alignment problem of struct ipart */
525 bootptr = &boot_sec.parts[ipc];
526 (void) fill_ipart(bootptr, &ip);
527
528 #ifdef i386
529 if (fdisk_is_dos_extended(ip.systid) && (ext_part_found == 0)) {
530 /* We support only one extended partition per disk */
531 ext_part_found = 1;
532 rval = fdisk_get_solaris_part(epp, &pno, &relsec,
533 &numsec);
534 if (rval == FDISK_SUCCESS) {
535 /*
536 * Found a solaris partition inside the
537 * extended partition. Update the statistics.
538 */
539 if (nhead != 0 && nsect != 0) {
540 pcyl = numsec / (nhead * nsect);
541 xstart = relsec / (nhead * nsect);
542 ncyl = pcyl - acyl;
543 }
544 solaris_offset = relsec;
545 found = 2;
546 ip.bootid = 0;
547 ip.beghead = ip.begsect = ip.begcyl = 0xff;
548 ip.endhead = ip.endsect = ip.endcyl = 0xff;
549 ip.systid = SUNIXOS2;
550 ip.relsect = relsec;
551 ip.numsect = numsec;
552 ipart->bootid = ip.bootid;
553 status = bcmp(&ip, ipart,
554 sizeof (struct ipart));
555 bcopy(&ip, ipart, sizeof (struct ipart));
556 }
557 continue;
558 }
559 #endif
560
561 /*
562 * we are interested in Solaris and EFI partition types
563 */
564 #ifdef i386
565 if ((ip.systid == SUNIXOS &&
566 (fdisk_is_linux_swap(epp, lel(ip.relsect), NULL) != 0)) ||
567 ip.systid == SUNIXOS2 ||
568 ip.systid == EFI_PMBR) {
569 #else
570 if (ip.systid == SUNIXOS ||
571 ip.systid == SUNIXOS2 ||
572 ip.systid == EFI_PMBR) {
573 #endif
574 /*
575 * if the disk has an EFI label, nhead and nsect may
576 * be zero. This test protects us from FPE's, and
577 * format still seems to work fine
578 */
579 if (nhead != 0 && nsect != 0) {
580 pcyl = lel(ip.numsect) / (nhead * nsect);
581 xstart = lel(ip.relsect) / (nhead * nsect);
582 ncyl = pcyl - acyl;
583 }
584 #ifdef DEBUG
585 else {
586 err_print("Critical geometry values are zero:\n"
587 "\tnhead = %d; nsect = %d\n", nhead, nsect);
588 }
589 #endif /* DEBUG */
590
591 solaris_offset = (uint_t)lel(ip.relsect);
592 found = 1;
593 break;
594 }
595 }
596
597 #ifdef i386
598 libfdisk_fini(&epp);
599 #endif
600
601 if (!found) {
602 err_print("Solaris fdisk partition not found\n");
603 return (-1);
604 } else if (found == 1) {
605 /*
606 * Found a primary solaris partition.
607 * compare the previous and current Solaris partition
608 * but don't use bootid in determination of Solaris partition
609 * changes
610 */
611 ipart->bootid = ip.bootid;
612 status = bcmp(&ip, ipart, sizeof (struct ipart));
613
614 bcopy(&ip, ipart, sizeof (struct ipart));
615 }
616
617 /* if the disk partitioning has changed - get the VTOC */
618 if (status) {
619 struct extvtoc exvtoc;
620 struct vtoc vtoc;
621
622 status = ioctl(fd, DKIOCGEXTVTOC, &exvtoc);
623 if (status == -1) {
624 i = errno;
625 /* Try the old ioctl DKIOCGVTOC */
626 status = ioctl(fd, DKIOCGVTOC, &vtoc);
627 if (status == -1) {
628 err_print("Bad ioctl DKIOCGEXTVTOC.\n");
629 err_print("errno=%d %s\n", i, strerror(i));
630 err_print("Cannot read vtoc information.\n");
631 return (-1);
632 }
633 }
634
635 status = read_label(fd, &update_label);
636 if (status == -1) {
637 err_print("Cannot read label information.\n");
638 return (-1);
639 }
640
641 /* copy vtoc information */
642 cur_parts->vtoc = update_label.dkl_vtoc;
643
644 #if defined(_SUNOS_VTOC_16)
645 /*
646 * this is to update the slice table on x86
647 * we don't care about VTOC8 here
648 */
649 for (i = 0; i < NDKMAP; i ++) {
650 cur_parts->pinfo_map[i].dkl_cylno =
651 update_label.dkl_vtoc.v_part[i].p_start /
652 ((int)(update_label.dkl_nhead *
653 update_label.dkl_nsect));
654 cur_parts->pinfo_map[i].dkl_nblk =
655 update_label.dkl_vtoc.v_part[i].p_size;
656 }
657 #endif /* defined(_SUNOS_VTOC_16) */
658
659 cur_dtype->dtype_ncyl = update_label.dkl_ncyl;
660 cur_dtype->dtype_pcyl = update_label.dkl_pcyl;
661 cur_dtype->dtype_acyl = update_label.dkl_acyl;
662 cur_dtype->dtype_nhead = update_label.dkl_nhead;
663 cur_dtype->dtype_nsect = update_label.dkl_nsect;
664 ncyl = cur_dtype->dtype_ncyl;
665 acyl = cur_dtype->dtype_acyl;
666 pcyl = cur_dtype->dtype_pcyl;
667 nsect = cur_dtype->dtype_nsect;
668 nhead = cur_dtype->dtype_nhead;
669 }
670 return (0);
671 }
672
673
674 int
675 copy_solaris_part(struct ipart *ipart)
676 {
677
678 int status, i, fd;
679 struct mboot mboot;
680 char *mbr;
681 struct ipart ip;
682 char buf[MAXPATHLEN];
683 char *bootptr;
684 struct stat statbuf;
685 #ifdef i386
686 uint32_t relsec, numsec;
687 int pno, rval, ext_part_found = 0;
688 ext_part_t *epp;
689 #endif
690
691 (void) get_pname(&buf[0]);
692 if (stat(buf, &statbuf) == -1 ||
693 !S_ISCHR(statbuf.st_mode) ||
694 ((cur_label == L_TYPE_EFI) &&
695 (cur_disk->disk_flags & DSK_LABEL_DIRTY))) {
696 /*
697 * Make sure to reset solaris_offset to zero if it is
698 * previously set by a selected disk that
699 * supports the fdisk table.
700 */
701 solaris_offset = 0;
702 /*
703 * Return if this disk does not support fdisk table or
704 * if it uses an EFI label but has not yet been labelled.
705 * If the EFI label has not been written then the open
706 * on the partition will fail.
707 */
708 return (0);
709 }
710
711 if ((fd = open(buf, O_RDONLY)) < 0) {
712 err_print("Error: can't open disk '%s'.\n", buf);
713 return (-1);
714 }
715
716 /*
717 * We may get mbr of different size, but the first 512 bytes
718 * are valid information.
719 */
720 mbr = malloc(cur_blksz);
721 if (mbr == NULL) {
722 err_print("No memory available.\n");
723 return (-1);
724 }
725 status = read(fd, mbr, cur_blksz);
726
727 if (status != cur_blksz) {
728 err_print("Bad read of fdisk partition.\n");
729 (void) close(fd);
730 free(mbr);
731 return (-1);
732 }
733
734 (void) memcpy(&mboot, mbr, sizeof (struct mboot));
735
736 #ifdef i386
737 (void) extpart_init(&epp);
738 #endif
739 for (i = 0; i < FD_NUMPART; i++) {
740 int ipc;
741
742 ipc = i * sizeof (struct ipart);
743
744 /* Handling the alignment problem of struct ipart */
745 bootptr = &mboot.parts[ipc];
746 (void) fill_ipart(bootptr, &ip);
747
748 #ifdef i386
749 if (fdisk_is_dos_extended(ip.systid) && (ext_part_found == 0)) {
750 /* We support only one extended partition per disk */
751 ext_part_found = 1;
752 rval = fdisk_get_solaris_part(epp, &pno, &relsec,
753 &numsec);
754 if (rval == FDISK_SUCCESS) {
755 /*
756 * Found a solaris partition inside the
757 * extended partition. Update the statistics.
758 */
759 if (nhead != 0 && nsect != 0) {
760 pcyl = numsec / (nhead * nsect);
761 ncyl = pcyl - acyl;
762 }
763 solaris_offset = relsec;
764 ip.bootid = 0;
765 ip.beghead = ip.begsect = ip.begcyl = 0xff;
766 ip.endhead = ip.endsect = ip.endcyl = 0xff;
767 ip.systid = SUNIXOS2;
768 ip.relsect = relsec;
769 ip.numsect = numsec;
770 bcopy(&ip, ipart, sizeof (struct ipart));
771 }
772 continue;
773 }
774 #endif
775
776
777 #ifdef i386
778 if ((ip.systid == SUNIXOS &&
779 (fdisk_is_linux_swap(epp, lel(ip.relsect), NULL) != 0)) ||
780 ip.systid == SUNIXOS2 ||
781 ip.systid == EFI_PMBR) {
782 #else
783 if (ip.systid == SUNIXOS ||
784 ip.systid == SUNIXOS2 ||
785 ip.systid == EFI_PMBR) {
786 #endif
787 solaris_offset = lel(ip.relsect);
788 bcopy(&ip, ipart, sizeof (struct ipart));
789
790 /*
791 * if the disk has an EFI label, we typically won't
792 * have values for nhead and nsect. format seems to
793 * work without them, and we need to protect ourselves
794 * from FPE's
795 */
796 if (nhead != 0 && nsect != 0) {
797 pcyl = lel(ip.numsect) / (nhead * nsect);
798 ncyl = pcyl - acyl;
799 }
800 #ifdef DEBUG
801 else {
802 err_print("Critical geometry values are zero:\n"
803 "\tnhead = %d; nsect = %d\n", nhead, nsect);
804 }
805 #endif /* DEBUG */
806
807 break;
808 }
809 }
810 #ifdef i386
811 libfdisk_fini(&epp);
812 #endif
813
814 (void) close(fd);
815 free(mbr);
816 return (0);
817 }
818
819 #if defined(_FIRMWARE_NEEDS_FDISK)
820 int
821 auto_solaris_part(struct dk_label *label)
822 {
823
824 int status, i, fd;
825 struct mboot mboot;
826 char *mbr;
827 struct ipart ip;
828 char *bootptr;
829 char pbuf[MAXPATHLEN];
830 #ifdef i386
831 uint32_t relsec, numsec;
832 int pno, rval, ext_part_found = 0;
833 ext_part_t *epp;
834 #endif
835
836 (void) get_pname(&pbuf[0]);
837 if ((fd = open_disk(pbuf, O_RDONLY)) < 0) {
838 err_print("Error: can't open selected disk '%s'.\n", pbuf);
839 return (-1);
840 }
841
842 /*
843 * We may get mbr of different size, but the first 512 bytes
844 * are valid information.
845 */
846 mbr = malloc(cur_blksz);
847 if (mbr == NULL) {
848 err_print("No memory available.\n");
849 return (-1);
850 }
851 status = read(fd, mbr, cur_blksz);
852
853 if (status != cur_blksz) {
854 err_print("Bad read of fdisk partition.\n");
855 free(mbr);
856 return (-1);
857 }
858
859 (void) memcpy(&mboot, mbr, sizeof (struct mboot));
860
861 #ifdef i386
862 (void) extpart_init(&epp);
863 #endif
864 for (i = 0; i < FD_NUMPART; i++) {
865 int ipc;
866
867 ipc = i * sizeof (struct ipart);
868
869 /* Handling the alignment problem of struct ipart */
870 bootptr = &mboot.parts[ipc];
871 (void) fill_ipart(bootptr, &ip);
872
873 #ifdef i386
874 if (fdisk_is_dos_extended(ip.systid) && (ext_part_found == 0)) {
875 /* We support only one extended partition per disk */
876 ext_part_found = 1;
877 rval = fdisk_get_solaris_part(epp, &pno, &relsec,
878 &numsec);
879 if (rval == FDISK_SUCCESS) {
880 /*
881 * Found a solaris partition inside the
882 * extended partition. Update the statistics.
883 */
884 if ((label->dkl_nhead != 0) &&
885 (label->dkl_nsect != 0)) {
886 label->dkl_pcyl =
887 numsec / (label->dkl_nhead *
888 label->dkl_nsect);
889 label->dkl_ncyl = label->dkl_pcyl -
890 label->dkl_acyl;
891 }
892 solaris_offset = relsec;
893 }
894 continue;
895 }
896 #endif
897
898 /*
899 * if the disk has an EFI label, the nhead and nsect fields
900 * the label may be zero. This protects us from FPE's, and
901 * format still seems to work happily
902 */
903
904
905 #ifdef i386
906 if ((ip.systid == SUNIXOS &&
907 (fdisk_is_linux_swap(epp, lel(ip.relsect), NULL) != 0)) ||
908 ip.systid == SUNIXOS2 ||
909 ip.systid == EFI_PMBR) {
910 #else
911 if (ip.systid == SUNIXOS ||
912 ip.systid == SUNIXOS2 ||
913 ip.systid == EFI_PMBR) {
914 #endif
915 if ((label->dkl_nhead != 0) &&
916 (label->dkl_nsect != 0)) {
917 label->dkl_pcyl = lel(ip.numsect) /
918 (label->dkl_nhead * label->dkl_nsect);
919 label->dkl_ncyl = label->dkl_pcyl -
920 label->dkl_acyl;
921 }
922 #ifdef DEBUG
923 else {
924 err_print("Critical label fields aren't "
925 "non-zero:\n"
926 "\tlabel->dkl_nhead = %d; "
927 "label->dkl_nsect = "
928 "%d\n", label->dkl_nhead,
929 label->dkl_nsect);
930 }
931 #endif /* DEBUG */
932
933 solaris_offset = lel(ip.relsect);
934 break;
935 }
936 }
937
938 #ifdef i386
939 libfdisk_fini(&epp);
940 #endif
941 (void) close(fd);
942 free(mbr);
943 return (0);
944 }
945 #endif /* defined(_FIRMWARE_NEEDS_FDISK) */
946
947
948 int
949 good_fdisk()
950 {
951 char buf[MAXPATHLEN];
952 struct stat statbuf;
953
954 (void) get_pname(&buf[0]);
955 if (stat(buf, &statbuf) == -1 ||
956 !S_ISCHR(statbuf.st_mode) ||
957 cur_label == L_TYPE_EFI) {
958 /*
959 * Return if this disk does not support fdisk table or
960 * if the disk is labeled with EFI.
961 */
962 return (1);
963 }
964
965 if (lel(cur_disk->fdisk_part.numsect) > 0) {
966 return (1);
967 } else {
968 err_print("WARNING - ");
969 err_print("This disk may be in use by an application "
970 "that has\n\t modified the fdisk table. Ensure "
971 "that this disk is\n\t not currently in use "
972 "before proceeding to use fdisk.\n");
973 return (0);
974 }
975 }
976
977 #ifdef i386
978 int
979 extpart_init(ext_part_t **epp)
980 {
981 int rval, lf_op_flag = 0;
982 char p0_path[MAXPATHLEN];
983
984 get_pname(&p0_path[0]);
985 lf_op_flag |= FDISK_READ_DISK;
986 if ((rval = libfdisk_init(epp, p0_path, NULL, lf_op_flag)) !=
987 FDISK_SUCCESS) {
988 switch (rval) {
989 /*
990 * FDISK_EBADLOGDRIVE, FDISK_ENOLOGDRIVE
991 * and FDISK_EBADMAGIC can be considered
992 * as soft errors and hence we do not exit.
993 */
994 case FDISK_EBADLOGDRIVE:
995 break;
996 case FDISK_ENOLOGDRIVE:
997 break;
998 case FDISK_EBADMAGIC:
999 break;
1000 case FDISK_ENOVGEOM:
1001 err_print("Could not get virtual geometry for"
1002 " this device\n");
1003 fullabort();
1004 break;
1005 case FDISK_ENOPGEOM:
1006 err_print("Could not get physical geometry for"
1007 " this device\n");
1008 fullabort();
1009 break;
1010 case FDISK_ENOLGEOM:
1011 err_print("Could not get label geometry for "
1012 " this device\n");
1013 fullabort();
1014 break;
1015 default:
1016 err_print("Failed to initialise libfdisk.\n");
1017 fullabort();
1018 break;
1019 }
1020 }
1021 return (0);
1022 }
1023 #endif
1024