partition.c revision 18c2aff776a775d34a4c9893a4c72e0434d68e36
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License, Version 1.0 only
* (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 2004 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
/*
* Partition class implementation file.
*/
/*
* System include files
*/
#include <stdlib.h>
#include <string.h>
#include <thread.h>
#include <unistd.h>
/*
* Local include files
*/
#include "partition.h"
/*
* A medium can have a single partition, or a nested structure of
* partitions of varying types. The medium's top level partition
* can be a DOS partition containing a PCFS file system, an fdisk
* partition containing a table that gives the types and locations
* of other partitions on the medium, a Solaris partition containing
* a volume table of contents (VTOC), that gives the locations and
* sizes of the Solaris slices located on the medium, an HSFS
* partition, a UDF partition, or a DVD video partition. The
* headers of most partition types can contain descriptions of
* the types and locations of other partitions on the medium.
* A medium can therefore contain multiple partitions of differing
* types.
*
* The methods in this class implementation file read removable
* media and create models of their partition structures. The
* models have tree structures of the form shown below.
*
* -----------------------
* | |
* | Top Level Partition |
* | |
* -----------------------
* ^ ^
* | |
* | ---------------------------
* V |
* ------------------------ ---------------------------
* | | | |
* | Left Child Partition |<-->| Right Sibling Partition |<-->....
* | | | |
* ------------------------ ---------------------------
* ^ ^
* | |
* | |
* V V
* . .
* . .
*
* In the diagram above, the arrows indicate connections between
* parent partition objects and child partition objects and
* connections between sibling partition objects. Parent object
* private data structures contain handles for their leftmost
* children, sibling object private data structures contain
* handles for their left and right siblings, and child object
* private data structures contain handles for their parent objects.
*
* The public create_top_partition() method creates a single empty
* partition object that models the entire medium. It then
* calls the read_partition() method, which calls all the
* descendant class read_partition() methods in turn to try
* to read the description of the partition from the medium
* into the empty partition object. If the medium's top
* level partition contains subpartitions, its read_partition()
* method creates a nested structure of partition objects of
* the appropriate types and calls the appropriate
* read_partition() method for each partition to read the
* description of the partition into the partition object that
* corresponds to it.
*/
/*
* Private attribute and method declarations
*/
/*
* The partition_private.h include file defines the
* partition_private_t data type and declares private partition
* methods used by descendant partition classes of specialized
* types, such as the fdisk_partition class. The C source
* files for the specialized descendant partition types also
* include it so their private methods can write to private
* partition data structures and call the private partition
* methods when manipulating nested partition structures
* containing different partition types.
*
* Using private include files to hide type definitions and
* method declarations from clients but make them visible to
* private methods located in separate source files provides a
* mechanism for inheritance of abstract methods that are
* implemented differently in different descendant classes of a
* parent class. In this case the parent class is the partition
* class, and the descendant classes are the classes that define
* the various types of partition objects, such as fdisk partition
* objects, PCFS partition objects, Solaris partition objects,
* UFS partition objects, HSFS partition objects, UDF partition
* objects, HSFS audio partition objects, DVD video partition
* objects, and other types of partition objects that may be
* specified in later versions of the software.
*/
#include "partition_private.h"
#include "vtoc.h"
#define START_OF_MEDIUM (off_t)0L
#define PASSWORD_PROTECTED_NAME "password_protected"
/*
* The volfs_t types in the file_system_types[] array below MUST
* match the partition types in the typedef enum partition_type_t
* in partition_private.h
*/
static const volfs_t file_system_types [] = {
};
/*
* The strings in the permission_codes[] array below MUST match
* the permission types defined in typedef enum permissions_t
* in medium_private.h
*/
static const char *permission_codes[] = {
"pp", /* password protected */
"pw", /* password write protected */
"ro", /* read only */
"rw" /* read write */
};
/*
* Names of the slices in a Solaris or HSFS VTOC
*/
static const char *slice_names[] = {
"s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7",
"s8", "s9", "s10", "s11", "s12", "s13", "s14", "s15"
};
/*
* Declarations of private methods
*/
static void partition_destroy_volume(partition_private_t *);
/*
* Definitions of public methods
*/
{
} else {
}
if (partition_result == PARTITION_SUCCESS) {
}
}
if (partition_result == PARTITION_SUCCESS) {
if (partition_result == PARTITION_SUCCESS) {
NULL) {
}
}
} else {
}
}
return (partition_result);
}
void
{
/*
* NOTE: This method is recursive. It calls itself to
* destroy all the children of the partition it is
* destroying before destroying the partition itself.
* It does NOT destroy the volume object associated
* with the partition, since that volume object is
* also associated with other objects.
*/
if (partitionpp == NULL) {
} else {
if (partition_privatep == NULL) {
}
}
if (partition_result == PARTITION_SUCCESS) {
while (current_childp != NULL) {
}
}
}
}
/*
* If the medium has been reformatted,
* the volume object corresponding to the
* medium's top partition has been removed
* from the database and destroyed. If the
* medium has been ejected, the volume object
* corresponding to its top partition must be
* preserved so it can be found in the database
* if the medium is reinserted.
*/
(partition_privatep->partition_number != 0)) {
/*
* All PCFS partitions described in top level
* fdisk tables are top level partitions, but
* only the volume object corresponding to the
* first PCFS partition must be preserved when
* the medium is ejected, because that's the
* only volume object in the database.
*/
}
free(*partitionpp);
*partitionpp = NULL;
}
}
{
/*
* NOTE: This method is recursive. It calls itself to
* mount all the children of the partition it is
* mounting before mounting the partition itself.
*
* This method mounts the partition by adding an async_task
* structure with its act field set to INSERT to the
* volume manager daemon's event handling queue. It
* includes a vol_t object containing all the mount
* parameters in the async_task object.
*
* Later versions of this method will execute the mount
* command themselves. The volume manager daemon's
* current event handling mechanism doesn't allow that.
*/
struct async_task *mount_as;
if (partition_privatep == NULL) {
}
while ((partition_result == PARTITION_SUCCESS) &&
(next_childp != NULL)) {
}
if ((partition_result == PARTITION_SUCCESS) &&
} else {
}
}
return (partition_result);
}
int
{
return ((int)NUMBER_OF_PARTITION_TYPES);
}
{
return (partition_result);
}
{
/*
* NOTE: This method is recursive. It calls itself to
* remount all the children of the partition it is
* remounting before remounting the partition itself.
*
* This method remounts the partition by adding an async_task
* structure with its act field set to REMOUNT to the
* volume manager daemon's event handling queue. It
* includes a vol_t object containing all the remount
* parameters in the async_task object.
*
* Later versions of this method will execute the mount
* command themselves. The volume manager daemon's
* current event handling mechanism doesn't allow that.
*/
struct async_task *mount_as;
if (partition_privatep == NULL) {
}
while ((partition_result == PARTITION_SUCCESS) &&
(next_childp != NULL)) {
}
if ((partition_result == PARTITION_SUCCESS) &&
} else {
}
}
return (partition_result);
}
{
/*
* NOTE: This method is recursive. It calls itself to
* unmount all the children of the partition it is
* unmounting before unmounting the partition itself.
*
* Later versions of this method will execute the unmount
* command themselves. The volume manager daemon's
* current event handling mechanism doesn't allow that.
*/
if (partition_privatep == NULL) {
}
while ((partition_result == PARTITION_SUCCESS) &&
(next_childp != NULL)) {
}
if ((partition_result == PARTITION_SUCCESS) &&
/*
* The current version of the software can't
* unmount individual partitions, because the
* current volume manager event handling mechanism
* doesn't permit it. Later versions of this
* method will issue the unmount command directly.
*/
}
return (partition_result);
}
/*
* The following method definitions must be visible to classes
* descended from the partition class, such as the pcfs_partition
* and fdisk_partition classes. They are therefore visible outside
* this file. To keep their declarations invisible to clients of
* the partition class, they are declared in the partition_private.h
* include file.
*/
{
}
}
}
return (mode);
}
{
if (cloned_labelp == NULL) {
} else {
(void) memcpy(cloned_labelp,
original_labelp, sizeof (partition_label_t));
} else {
}
}
}
return (partition_result);
}
void
{
}
}
}
void
{
/*
* Convert a partition's vnodes to directory vnodes
* and make them the parent vnodes of the partition.
*/
}
void
{
/*
* Correct the block and raw pathnames.
* That may be necessary if there are duplicate vvnodes
* in the database and node_mkobj() has had to change
* the block and raw vvnode names to avoid duplication.
*
* Entry conditions:
*
* ((partition_privatep->raw_pathnamep != NULL) &&
* (partition_privatep->raw_vvnodep != NULL))
*
* Exit conditions:
*
* ((partition_privatep->raw_pathnamep != NULL) &&
* (partition_privatep->raw_vvnodep != NULL))
*
*/
}
}
}
{
if (rightmost_childp != NULL) {
&new_childp);
} else {
if (partition_result == PARTITION_SUCCESS) {
NULL;
NULL;
} else {
NULL;
}
}
}
return (partition_result);
}
{
if (new_partitionp == NULL) {
}
return (partition_result);
}
{
/*
* creates an empty label structure that the
* read_label() methods of the descendant
* partition classes fill in.
*/
} else {
}
return (partition_result);
}
{
char *name_bufferp;
char *parent_block_pathnamep;
char *parent_raw_pathnamep;
char *volume_namep;
if (name_bufferp == NULL) {
}
if (partition_result == PARTITION_SUCCESS) {
if (parent_privatep != NULL) {
} else {
}
if (parent_block_pathnamep != NULL) {
} else {
}
}
}
if (name_bufferp != NULL) {
}
return (partition_result);
}
{
/*
* NOTE:
*
* This method serves as part of the interface between
* the new partition class and the legacy database. When the
* legacy database is replaced or eliminated, this method
* wlll no longer be needed.
*/
char *vvnode_namep;
flags = NODE_TMPID;
if ((partition_result == PARTITION_SUCCESS) &&
&error);
}
if (partition_result == PARTITION_SUCCESS) {
}
if (partition_result == PARTITION_SUCCESS) {
&error);
}
if ((partition_result == PARTITION_SUCCESS) &&
&error);
}
if (partition_result == PARTITION_SUCCESS) {
}
if (partition_result == PARTITION_SUCCESS) {
&error);
}
return (partition_result);
}
{
/*
* This method handles two cases.
*
* 1. The medium contains only one file system.
* Create a symlink called "<device_name>" in
* vnode of the partition. Write a pointer
* to the symlink to the dp_symvn attribute
* of the device object that models the device
* in which the medium is inserted.
*
* 2. The medium contains more than one file system.
* Create a symlink called "<volume_name>" in the
* parent medium has created and make it point to
* the raw vnode of the partition.
*/
char *volume_namep;
/*
* There is either no file system on the medium
* or one file system on the medium. Create a
* a symbolic link to the top level raw vnode
* and give it the symbolic name of the device
* (e.g. floppy0, zip0, cdrom0, jaz0.)
*/
NULL);
} else {
/*
* In this case there are two or more volumes on the
* medium, and the current software architecture
* provides no way to connect them both to the device.
* The dp_mediump attribute of the device object
* connects the device to the medium, and that
* connection will have to be used on ejection to
* remove all volumes from the device. The mechanism
* for doing that has yet to be designed.
*/
NULL);
}
return (partition_result);
}
{
/*
* The current version of the software must find or create
* a global raw vvnode for the volume in the database to
* be able to find and mount a volume. Failure to find
* or create the global vvnode causes assertion failures
* and core dumps.
*/
/*
* At this point, nfs server has been suspended by acquiring
* node and changing devmaps.
*/
/*
* if previous volume was unlabelled, dp_mediump should have
* been cleared.
*/
if (omedium_privatep != NULL)
/*
* we will remove the node which has been made by the
* previous medium which was in the drive. If the volume
* object has been taken over by the other drive, ovolumep
* should be NULL.
*/
}
}
if ((partition_result == PARTITION_SUCCESS) &&
(global_raw_vvnodep != NULL)) {
/*
* The given vvnode can be created by the different
* device. So the volume hanging on vn_vol may have
* been pointed by other medium which has been
* inactivated. Thus, we detach volume from the
* medium, so that other device won't go to release
* the volume.
*/
if (vmedium_privatep != NULL)
/*
* The database contains a vvnode whose label
* key matches the label key of the volume
* that the partition object has just created.
* Remove the old vvnodes and volume from the
* database. The next guarded sequence replaces
* the vvnodes with new ones based on the new
* volume structure.
*/
}
if (partition_result == PARTITION_SUCCESS) {
(obj_t *)partition_privatep->
&error);
/*
* The "twinning" code in the node_mkobj() creates
* both partition_privatep->global_raw_vvnodep
* and partition_privatep->global_block_vvnodep
* when called once to create
* partition_privatep->global_raw_vvnodep, and writes
* a pointer to partition_privatep->global_block_vvnodep
* to partition_privatep->global_raw_vvnodep->vn_twin.
*
* NOTE:
*
* Remove the code that produces side effects like
* twin nodes and partition nodes from the node_mkobj()
* method as soon as time and resources permit.
*/
vn_num =
}
}
}
if (partition_result == PARTITION_SUCCESS) {
flags |= NODE_TMPID;
}
/*
* If we do not have a block device we do not want to
* create a vnode for it.
*/
&error);
}
&error);
¤t_time);
(void) db_update(
}
/*
* The next statement enables remove_medium_from_db()
* to find the volume representing the medium in the
* database.
*/
}
if (partition_result == PARTITION_SUCCESS) {
/*
* first create the new devmap by copying the old
* one as much as possible.
*/
/*
* volume is being destroyed. We will take care of
* missing events if exists.
*/
/*
* if this volume was taken over from the other
* medium, destroy here.
*/
}
} else {
}
}
}
if (partition_result == PARTITION_SUCCESS) {
/*
* devmap has been created.
* we need to notify vold of the new mapping, so that
* cancelled volume won't be failed with EIO.
*/
}
/*
*/
if (omedium_privatep != NULL) {
}
}
/*
* Only if we failed to create devmap, we destroy volume etc.
* Unlabelled volume will be released in dev_unhangvol(), so
* we need to know before calling dev_unhangvol().
*/
if (partition_result == PARTITION_CANT_CREATE_DEVMAP) {
/* volume hasn't gone(ie labelled volume) */
}
}
return (partition_result);
}
{
/*
* Each potentially mountable partition has a volume associated
* with it, because the current version of the volume management
* daemon passes a volume structure to the current version of
* the mount method in order to mount the partition. We plan to
* elminate the current version of the mount method in a future
* version of the software and enable individual partitions
* to mount themselves. That will eliminate the need for
* the volume structure.
*/
int type_index;
}
if (partition_result == PARTITION_SUCCESS) {
}
}
if (partition_result == PARTITION_SUCCESS) {
}
if (partition_result == PARTITION_SUCCESS) {
}
}
if (partition_result == PARTITION_SUCCESS) {
(partition_label_t **)
}
if (partition_result == PARTITION_SUCCESS) {
}
}
} else {
}
switch (partition_privatep->permissions) {
case PASSWORD_WRITE_PROTECTED:
case READ_ONLY:
break;
}
/*
* mount mode is always "ro" for medium in cdrom drive.
*/
} else {
}
}
if (partition_result != PARTITION_SUCCESS) {
}
return (partition_result);
}
{
/*
* NOTE:
*
* This method serves as part of the interface between
* the new partition class and the legacy database. When the
* legacy database is replaced or eliminated, this method
* wlll no longer be needed.
*/
/*
* The partition is a top level partition
*/
} else {
/*
* The partition is a slice or subpartition.
*/
}
return (partition_result);
}
void
{
}
}
}
char *
find_filenamep(char *directory_namep)
{
/*
* returns a pointer to the filename string
* doesn't duplicate the string
*/
char *last_slash_ptr;
char *filenamep;
char *next_slash_ptr;
while (next_slash_ptr != NULL) {
}
return (filenamep);
}
{
if (partition_result != PARTITION_SUCCESS) {
}
if (partition_result != PARTITION_SUCCESS) {
}
if (partition_result != PARTITION_SUCCESS) {
}
}
if (partition_result != PARTITION_SUCCESS) {
}
if (partition_result != PARTITION_SUCCESS) {
}
if (partition_result != PARTITION_SUCCESS) {
}
if (partition_result != PARTITION_SUCCESS) {
}
}
if (partition_result != PARTITION_SUCCESS) {
}
if (partition_result != PARTITION_SUCCESS) {
}
if (partition_result != PARTITION_SUCCESS) {
}
if (partition_result != PARTITION_SUCCESS) {
}
}
if (partition_result != PARTITION_SUCCESS) {
}
if (partition_result != PARTITION_SUCCESS) {
}
if (partition_result != PARTITION_SUCCESS) {
}
}
if (partition_result != PARTITION_SUCCESS) {
}
}
if (partition_result != PARTITION_SUCCESS) {
}
return (partition_result);
}
{
int ioctl_result;
int number_found;
int number_of_slices;
int partition_index;
number_found = 0;
}
if (partition_result == PARTITION_SUCCESS) {
vtocp);
}
}
continue;
if (partition_result != PARTITION_SUCCESS)
continue;
if (parent_privatep != NULL &&
} else {
}
}
if (partition_result == PARTITION_SUCCESS) {
}
}
}
return (partition_result);
}
/*
* Definitions of private methods
*/
static void
{
}
static partition_result_t
char *object_namep,
{
/*
* NOTE:
*
* This method serves as part of the interface between
* the new partition class and the legacy database. When the
* legacy database is replaced or eliminated, this method
* wlll no longer be needed.
*/
if (slice_objectp == NULL) {
} else {
}
}
if (partition_result == PARTITION_SUCCESS) {
}
return (partition_result);
}
static partition_result_t
{
if (partition_result == PARTITION_SUCCESS) {
} else {
}
}
return (partition_result);
}
static partition_result_t
{
char *name_bufferp;
struct vnwrap *next_vvnode_linkp;
struct vnwrap *vvnode_linkp;
name_bufferp = NULL;
vvnode_linkp = NULL;
if (name_bufferp == NULL) {
} else {
} else {
labelp);
}
}
if (found_volumep != NULL) {
if (vvnode_linkp == NULL) {
(void) node_lookup(name_bufferp);
if (vvnode_linkp == NULL) {
}
}
}
if (vvnode_linkp != NULL) {
/*
* Find the global vvnode for the volume.
*/
(next_vvnode_linkp != NULL)) {
}
}
/*
* Remove the vvnode link structure.
*/
}
if ((found_vvnodep != NULL) &&
noise("%s named %s already inserted in a drive\n",
}
if (name_bufferp != NULL) {
}
}
return (partition_result);
}
static partition_handle_t
{
while (next_childp != NULL) {
}
return (rightmost_childp);
}
static partition_result_t
{
if (partition_result != PARTITION_SUCCESS) {
}
if (partition_result != PARTITION_SUCCESS) {
}
return (partition_result);
}