libfdisk.c revision 02032da2d8b8c39f8555e913f6239bba49238e55
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2010 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include <unistd.h>
#include <errno.h>
#include <fcntl.h>
#include <ctype.h>
#include <sys/systeminfo.h>
#include <sys/efi_partition.h>
#include <sys/byteorder.h>
#include "libfdisk.h"
#define DEFAULT_PATH_PREFIX "/dev/rdsk/"
static struct ipart *fdisk_alloc_part_table();
static int
{
int no_virtgeom_ioctl = 0, no_physgeom_ioctl = 0;
/* Get disk's HBA (virtual) geometry */
errno = 0;
no_virtgeom_ioctl = 1;
/*
* This means that the ioctl exists, but
* is invalid for this disk, meaning the
* disk doesn't have an HBA geometry
* (like, say, it's larger than 8GB).
*/
} else {
return (FDISK_ENOVGEOM);
}
} else {
/* save virtual geometry values obtained by ioctl */
}
errno = 0;
no_physgeom_ioctl = 1;
} else {
return (FDISK_ENOPGEOM);
}
}
/*
* Call DKIOCGGEOM if the ioctls for physical and virtual
* geometry fail. Get both from this generic call.
*/
if (no_virtgeom_ioctl && no_physgeom_ioctl) {
errno = 0;
return (FDISK_ENOLGEOM);
}
}
/*
* If DKIOCGMEDIAINFO ioctl succeeds, set the dki_lbsize as the
* size of the sector, else default to 512
*/
/* ioctl failed, falling back to default value of 512 bytes */
} else {
}
/*
* if hba geometry was not set by DKIOC_VIRTGEOM
* or we got an invalid hba geometry
* then set hba geometry based on max values
*/
}
return (FDISK_SUCCESS);
}
/*
* Initialise important members of the ext_part_t structure and
* other data structures vital to functionality of libfdisk
*/
int
{
int rval = FDISK_SUCCESS;
int found_bad_magic = 0;
return (ENOMEM);
}
sizeof (temp->device_name));
/* Try to stat the node as provided */
/*
* In case of an EFI labeled disk, the device name
* could be cN[tN]dN. There is no pN. So we add "p0"
* at the end if we do not find it and stat again.
*/
}
/* Failed all options, give up */
goto fail;
}
}
}
/* Make sure the device is a raw device */
goto fail;
}
goto fail;
}
/*
* When we have no fdisk magic 0xAA55 on the disk,
* we return FDISK_EBADMAGIC after successfully
* obtaining the disk geometry.
*/
if (rval != FDISK_EBADMAGIC)
goto fail;
else
found_bad_magic = 1;
}
}
goto fail;
}
if (found_bad_magic != 0) {
return (FDISK_EBADMAGIC);
}
if (opflag & FDISK_READ_DISK) {
}
return (rval);
fail:
return (rval);
}
int
{
int rval = FDISK_SUCCESS;
epp->corrupt_logical_drives = 0;
epp->logical_drive_count = 0;
epp->invalid_bb_sig[0] = 0;
}
return (rval);
}
void
{
return;
}
int
{
int i;
int rval = -1;
char *buf, *linux_swap_magic;
/*
* Known linux kernel page sizes
* The linux swap magic is found as the last 10 bytes of a disk chunk
* at the beginning of the linux swap partition whose size is that of
* kernel page size.
*/
return (ENOMEM);
}
/*
* Check if there is a sane Solaris VTOC
* If there is a valid vtoc, no need to lookup
* for the linux swap signature.
*/
goto done;
goto done;
}
rval = -1;
goto done;
}
/* No valid vtoc, so check for linux swap signature */
for (i = 0; i < sizeof (linux_pg_size_arr)/sizeof (uint32_t); i++) {
seek_offset *= sec_sz;
break;
}
break;
}
LINUX_SWAP_MAGIC_LENGTH) == 0) ||
LINUX_SWAP_MAGIC_LENGTH) == 0)) {
/* Found a linux swap */
rval = 0;
if (lsm_offset != NULL)
break;
}
}
done:
return (rval);
}
int
{
int pno;
int rval = -1;
NULL) == 0)) {
continue;
}
*begsec = part_start;
}
}
return (rval);
}
int
{
int pno;
return (EINVAL);
}
;
return (EINVAL);
}
return (FDISK_SUCCESS);
}
/*
* Allocate a node of type logical_drive_t and return the pointer to it
*/
static logical_drive_t *
{
return (NULL);
}
return (temp);
}
/*
* Free all the logical_drive_t's allocated during the run
*/
static void
{
}
}
/*
* Find the first free sector within the extended partition
*/
int
{
return (FDISK_SUCCESS);
}
/*
* When the first logical drive is out of order, we need to adjust
* first_free_sec accordingly. In this case, the first extended
* partition sector is not free even though the actual logical drive
* does not occupy space from the beginning of the extended partition.
* The next free sector would be the second sector of the extended
* partition.
*/
(*first_free_sec)++;
}
temp->sorted_next) {
}
}
/*
* Minimum size of a partition assumed to be atleast one
* sector.
*/
continue;
}
break;
}
return (FDISK_EOOBOUND);
}
return (FDISK_SUCCESS);
}
/*
* Find the last free sector within the extended partition given, a beginning
* sector (so that the range - "begsec to last_free_sec" is contiguous)
*/
{
break;
}
}
return (last_free_sec);
}
/*
* Place the given ext_part_t structure in a sorted list, sorted in the
* ascending order of their beginning sectors.
*/
static void
{
return;
}
break;
}
}
}
static void
{
return;
}
/* Found */
break;
}
}
}
static int
{
return (1);
}
}
/*
* Find the maximum possible end sector value
* given a beginning sector value
*/
if (endsec > last_free_sec) {
return (1);
}
return (0);
}
/*
* Check if the logical drive boundaries are sane
*/
int
{
return (1);
}
return (0);
}
/*
* Procedure to walk through the extended partitions and build a Singly
* Linked List out of the data.
*/
static int
{
unsigned char *ext_buf;
return (ENOMEM);
}
ext_part_found = 1;
epp->ext_beg_cyl =
epp->ext_end_cyl =
/*LINTED*/
while (B_TRUE) {
return (EIO);
}
sectsize) {
return (EIO);
}
/*LINTED*/
(epp->logical_drive_count == 0)) {
/* No logical drives defined */
epp->first_ebr_is_null = 0;
return (FDISK_ENOLOGDRIVE);
}
temp = fdisk_alloc_ld_node();
/* adding first logical drive */
if (temp->logdrive_offset >
/* out of order */
temp->abs_secnum +=
temp->logdrive_offset = 0;
}
}
temp->abs_secnum +
/*
* Check for sanity of logical drives
*/
return (FDISK_EBADLOGDRIVE);
}
ext_fdp++;
} else {
temp);
}
/*LINTED*/
MBB_MAGIC) {
}
break;
else {
}
lpart++;
}
}
}
return (FDISK_SUCCESS);
}
static int
{
int rval;
return (ENOMEM);
}
if (rval) {
return (rval);
}
return (FDISK_SUCCESS);
}
static struct ipart *
{
return (NULL);
}
return (table);
}
/*
* Reads the master fdisk partition table from the device assuming that it has
* a valid table.
* MBR is supposed to be of 512 bytes no matter what the device block size is.
*/
static int
{
int sectsize = 512;
return (EIO);
}
return (EIO);
}
/*LINTED*/
return (FDISK_EBADMAGIC);
}
return (FDISK_SUCCESS);
}
int
{
int i;
if (part_table == NULL) {
/* No extended partition found */
return (0);
}
for (i = 0; i < FD_NUMPART; i++) {
break;
}
}
if (i == FD_NUMPART) {
/* No extended partition found */
return (0);
}
return (1);
}
int
{
int rval;
if (rval != FDISK_SUCCESS) {
return (rval);
}
if (begcyl == first_free_cyl) {
*begsec = first_free_sec;
return (FDISK_SUCCESS);
}
/* Check if the cylinder number is beyond the extended partition */
return (FDISK_EOOBOUND);
}
return (FDISK_EOVERLAP);
}
}
return (FDISK_SUCCESS);
}
void
{
int i;
i = FD_NUMPART + 1;
;
}
/*
* A couple of special scenarios :
* 1. Since the first logical drive's EBR is always at the beginning of the
* extended partition, any specification that starts the first logical drive
* out of order will need to address the following issue :
* If the beginning of the drive is not coinciding with the beginning of the
* extended partition and :
* a) The start is within MAX_LOGDRIVE_OFFSET, the offset changes from the
* default of 63 to less than 63.
* logdrive_offset is updated to keep track of the space between
* the beginning of the logical drive and extended partition. abs_secnum
* points to the beginning of the extended partition.
* b) The start is greater than MAX_LOGDRIVE_OFFSET, the offset changes from
* the default of 63 to greater than 63.
* logdrive_offset is set to 0. abs_secnum points to the beginning of the
* logical drive, which is at an offset from the extended partition.
*/
void
{
temp = fdisk_alloc_ld_node();
epp->corrupt_logical_drives = 0;
temp->logdrive_offset = 0;
} else {
}
}
epp->first_ebr_is_null = 0;
return;
}
temp->logdrive_offset--;
temp->abs_secnum++;
}
;
}
/*
* There are 2 cases that need to be handled.
* 1. Deleting the first extended partition :
* The peculiarity of this case is that the offset of the first extended
* partition is always indicated by the entry in the master boot record.
* (MBR). This never changes, unless the extended partition itself is
* deleted. Hence, the location of the first EBR is fixed.
* It is only the logical drive which is deleted. This first EBR now gives
* information of the next logical drive and the info about the subsequent
* extended partition. Hence the "relsect" of the first EBR is modified to
* point to the next logical drive.
*
* 2. Deleting an intermediate extended partition.
* This is quite normal and follows the semantics of a normal linked list
* delete operation. The node being deleted has the information about the
* logical drive that it houses and the location and the size of the next
* extended partition. This informationis transferred to the node previous
* to the node being deleted.
*
*/
void
{
int i;
i = FD_NUMPART + 1;
for (; i < pno; i++) {
}
/* Deleting the first logical drive */
/* Deleting the only logical drive left */
epp->logical_drive_count = 0;
} else {
/* Corner case when partitions are out of order */
cur->logdrive_offset++;
} else {
cur->logdrive_offset = 0;
}
}
} else {
}
}
static void
{
/*
* the lba address cannot be expressed in CHS value
* so store the maximum CHS field values in the CHS fields.
*/
} else {
}
/*
* This code is identical to the code above
* except that it works on ending CHS values
*/
} else {
}
}
static int
{
return (EIO);
}
return (EIO);
}
2 * sizeof (struct ipart));
}
return (EIO);
}
return (EIO);
}
return (0);
}
/*
* XXX - ZFS mounts not detected. Needs to come in as a feature.
*/
int
{
char compare_pdev_str[PATH_MAX];
char compare_sdev_str[PATH_MAX];
int part;
int look_for_mounted_slices = 0;
/*
* Do not check for mounted logical drives for
*/
return (0);
}
return (ENOENT);
}
canonp);
*part_str = 's';
if (part > FD_NUMPART) {
/*
* Solaris partition is on a logical drive. Look for
* mounted slices.
*/
}
}
continue;
} else {
if (look_for_mounted_slices) {
return (FDISK_EMOUNTED);
}
}
}
/*
* Get the partition number that is mounted, which would be
* found just beyond the last 'p' in the device string.
* is just beyond the last 'p'.
*/
part_str++;
/* Extended partition numbers start from 5 */
if (part >= 5) {
return (FDISK_EMOUNTED);
}
}
}
return (0);
}
int
{
int wflag = 0; /* write flag */
int rval;
unsigned char *ebr_buf;
int ld_count;
int check_mounts = 0;
return (ENOMEM);
}
if (epp->first_ebr_is_null) {
/*
* Indicator that the extended partition as a whole was
* modifies (either created or deleted. Must check for mounts
* and must commit
*/
check_mounts = 1;
}
/*
* Pass1 through the logical drives to make sure that commit of minor
* written block dont get held up due to mounts.
*/
} else {
}
if (rval) {
goto error;
}
check_mounts = 1;
}
}
if (!check_mounts) {
goto skip_check_mounts;
}
if (ebr_buf) {
}
return (rval);
}
if (epp->first_ebr_is_null) {
epp->ext_beg_sec);
if (rval) {
goto error;
}
wflag = 1;
ld_count = 0;
} else {
if (epp->logical_drive_count == 0) {
/*
* Can hit this case when there is just an extended
* partition with no logical drives, and the user
* committed without making any changes
* We dont have anything to commit. Return success
*/
if (ebr_buf) {
}
return (FDISK_SUCCESS);
}
/*
* Make sure that the first EBR is written with the first
* logical drive's data, which might not be the first in disk
* order.
*/
if (ld_count == 0) {
} else {
}
if (rval) {
if (ld_count) {
/*
* There was atleast one
* write to the disk before
* this failure. Make sure that
* the kernel is notified.
* Issue the ioctl.
*/
break;
}
goto error;
}
wflag = 1;
}
}
}
if (wflag == 0) {
/* No changes made */
goto error;
}
}
/* Issue ioctl to the driver to update extended partition info */
/*
* Certain devices ex:lofi do not support DKIOCSETEXTPART.
* Extended partitions are still created on these devices.
*/
if (ebr_buf) {
}
return (rval);
}
int
{
epp->corrupt_logical_drives = 0;
epp->logical_drive_count = 0;
epp->invalid_bb_sig[0] = 0;
return (0);
}
int
{
/* Clear the logical drive information */
epp->logical_drive_count = 0;
epp->corrupt_logical_drives = 0;
epp->invalid_bb_sig[0] = 0;
return (0);
}
int
{
switch (type) {
case PHYSGEOM:
switch (what) {
case NCYL:
case NHEADS:
case NSECTPT:
case SSIZE:
case ACYL:
default:
return (EINVAL);
}
case VIRTGEOM:
switch (what) {
case NCYL:
case NHEADS:
case NSECTPT:
case SSIZE:
case ACYL:
default:
return (EINVAL);
}
default:
return (EINVAL);
}
}
int
{
return (epp->invalid_bb_sig[0]);
}