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
62extern	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
90static int getbyte(uchar_t **);
91static int getlong(uchar_t **);
92
93#endif	/* defined(sparc) */
94
95static int get_solaris_part(int fd, struct ipart *ipart);
96
97#else	/* __STDC__ */
98
99#if	defined(sparc)
100
101static int getbyte();
102static int getlong();
103
104#endif	/* defined(sparc) */
105
106static int get_solaris_part();
107
108#endif	/* __STDC__ */
109
110#ifdef i386
111int extpart_init(ext_part_t **epp);
112#endif
113/*
114 * Handling the alignment problem of struct ipart.
115 */
116static void
117fill_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)
155static int
156getbyte(uchar_t **bp)
157{
158	int	b;
159
160	b = **bp;
161	*bp = *bp + 1;
162	return (b);
163}
164
165#ifdef DEADCODE
166static int
167getshort(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
177static int
178getlong(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 */
197static void
198get_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 */
217static void
218get_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 */
261static void
262get_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 */
311void
312open_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 */
353int
354c_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
423static void
424update_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
477static int
478get_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
674int
675copy_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)
820int
821auto_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
948int
949good_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
978int
979extpart_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