dev_rmdisk.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 2005 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
#include <errno.h>
#include <signal.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <thread.h>
#include <synch.h>
#include "vold.h"
#include "vtoc.h"
#if defined(_FIRMWARE_NEEDS_FDISK)
static int fdisk_supported = 1;
#else
static int fdisk_supported = 0;
#endif
#define NUM_FS_TYPES 2
#define RMDISK_READ_SIZE 512
#define RMDMAX_FDISK_PARTITIONS 5
static const int P_TYPE = 1;
static const int P_DEFAULT_PARTITION = 0;
static const char *P_PATH_FORMAT = "%sp%d";
static const int S_TYPE = 0;
static const int S_DEFAULT_PARTITION = 2;
static const char *S_PATH_FORMAT = "%ss%d";
extern bool_t support_nomedia;
struct rmdisk_priv {
int rmd_tid;
int rmd_defpart[NUM_FS_TYPES];
int rmd_fs_type;
};
/*
* Declarations of methods that are externally
* visible throught the devsw structure
*/
static bool_t rmdisk_use(char *, char *);
static int rmdisk_getfd(dev_t);
static void rmdisk_devmap(vol_t *, int, int);
static bool_t rmdisk_testpath(char *);
static struct devsw rmdiskdevsw = {
rmdisk_use, /* d_use */
rmdisk_error, /* d_error */
rmdisk_getfd, /* d_getfd */
NULL, /* d_poll */
rmdisk_devmap, /* d_devmap */
rmdisk_close, /* d_close */
NULL, /* d_eject */
NULL, /* d_find */
rmdisk_check, /* d_check */
"drive", /* d_dtype */
(uid_t)0, /* d_uid */
(gid_t)0, /* d_gid */
(mode_t)0, /* d_mode */
rmdisk_testpath, /* d_test */
rmdisk_remount /* d_remount */
};
/*
* Declarations of private methods
*/
#define CANT_REOPEN -1
#define CANT_CLOSE -1
#define REOPEN_RO 1
#define REOPEN_RW 0
/*
* Definitions of externally visible methods
*/
dev_init()
{
return (TRUE);
}
/*
* rmdisk_use -- this routine expects either a raw or block path
* to a removable disk and detects that the disk is removable
* by issuing a DKIOCREMOVABLE ioctl().
*
* it further expects that the supplied
*
* it finds the complimentary device by switching this
* group of block devices, then this routine will
*
* a thread is created which will handle this new group of
* interfaces to a device
*
* a devs struct is filled in and passed on to the thread
*
* return TRUE implies that the device is one which isn't
* currently managed, and needs to be
*/
static bool_t
{
int default_partition;
char *device_namep;
char *dsk_startp;
int fs_type;
int partition_number;
int pathname_length;
struct rmdisk_priv *private_datap;
char *rdsk_startp;
return (FALSE);
}
/*
* Remove "nomedia" node if support has changed.
* By sending a HUP signal to vold, dev_use()
* will call here.
*/
}
/*
* Create "nomedia" node if support has changed.
*/
}
return (TRUE);
} else {
return (FALSE);
}
}
(void) strncpy(block_slice_pathname,
(void) strncpy(raw_slice_pathname,
} else {
"rmdisk: %s not block or char device (mode 0x%x)\n"),
return (FALSE);
}
(void) strncpy(block_device_pathname,
(void) strncpy(raw_device_pathname,
partition_number = 0;
while (partition_number < V_NUMPAR) {
}
if (fdisk_supported) {
partition_number = 0;
while (partition_number < V_NUMPAR) {
}
} else {
partition_number = 0;
while (partition_number < V_NUMPAR) {
NULL;
}
}
return (FALSE);
}
if (thr_create(0, THREAD_STACK_SIZE,
return (FALSE);
}
return (TRUE);
}
/*ARGSUSED*/
static void
{
struct rmdisk_priv *rmdp;
/*
* This handles the case in which there's a Solaris VTOC
* described by an fdisk table on an Intel system.
*/
} else {
/*
* return the path of the partition corresponding
* to the default file system type of the system
* (P_TYPE for Intel systems, S_TYPE for SPARC systems.)
*/
}
}
static int
{
struct rmdisk_priv *rmdp;
int fd;
if (fdisk_supported) {
} else {
}
return (fd);
}
/*ARGSUSED*/
static bool_t
{
return (TRUE);
}
/*
* State that must be cleaned up:
* name in the name space
* the "dp"
* any pointers to the media
* eject any existing media
* the priv structure
*/
/*
* XXX: a bug still exists here. we have a thread polling on this
* XXX: device in the kernel, we need to get rid of this also.
* XXX: since we're going to move the waiter thread up to the
* XXX: user level, it'll be easier to kill off as part of the
* XXX: cleanup of the device private data.
*/
static void
{
int default_partition;
int fd;
int fs_type;
int partition;
struct rmdisk_priv *rmdp;
return;
}
} else {
}
return;
}
/*
* get our private data
*/
/*
* take care of the listner thread
*/
/*
* if there is a volume inserted in this device ...
*/
/*
* clean up the name space and the device maps
* to remove references to any volume that might
* be in the device right now
*
* this crap with the flags is to keep the
* "poll" from being relaunched by this function
*
* yes, its a hack and there should be a better way
*/
} else {
}
return;
}
}
/*
* clean up the names in the name space
*/
/*
* free the private data we've allocated
*/
}
}
}
}
/*
* free the dp, so no one points at us anymore
*/
dev_freedp(dp);
}
static int
/*
* Wake up the device thread for a removable media disk drive.
* See the floppy_check() method in dev_floppy.c to find the
* general interface rules for <device>_check() methods and
* an example of a <device>_check() method that checks for
* previously undetected insertions of media into devices.
* The rmdisk_check() method doesn't have to check for previously
* undetected insertions of media because the rmdisk_thread_wait()
* method continuously checks for insertions of media, and the
* rmdisk_check() method wakes up the rmdisk_thread_wait() method.
*/
{
int fd;
int fs_type;
struct rmdisk_priv *rmdp;
int result;
result = 1;
} else {
result = 0;
}
return (result);
}
static bool_t
rmdisk_testpath(char *path)
{
int fd = -1;
int removable;
/* check to see if we're already using it */
/* something's seriously wrong */
goto dun;
}
return (TRUE);
} else {
return (FALSE);
}
}
path);
goto dun;
}
/*
* if we can't open it, assume that it's because it's busy or
* something else is wrong
*
* in any event, dev_use couldn't open it either, so it's
* not worth trying to use the device
*/
goto dun;
}
/*
* check to make sure device is a SCSI or PCMCIA-ATA device
*/
rp);
goto dun;
}
debug(5,
"rmdisk(probing): \"%s\" not a SCSI or PCMCIA-ATA drive\n",
rp);
debug(5,
"rmdisk(probing): (disk type %d or %d expected, %d found)\n",
goto dun;
}
/*
* if we stop here, we'll end up trying to manage hard disks that
* are found, since they also return DKC_SCSI_CCS,
* so do a DKIOCREMOVABLE ioctl (more general than trying
* to do a SCSI inquiry here, since this latter method won't
* work on non-SCSI devices, such as IDE disks)
*/
/* do the inquiry */
debug(5,
"rmdisk(probing): \"%s\" DKIOCREMOVABLE ioctl failed; %m\n",
rp);
goto dun;
}
/*
* for now setting removable for know t# and c#
*/
if (removable == 0) {
rp);
goto dun;
}
rp);
dun:
/* all done */
if (fd >= 0) {
}
}
return (res);
}
static bool_t
{
/*
* Find the new default file descriptor for
* a device after the medium inserted in it
* has been repartitioned.
*/
int device_fd;
struct rmdisk_priv *device_privatep;
int reopen_result, basepart;
/*
* The default file descriptor for fdisk-based file systems
* is always the P0 file descriptor, so there's no need to
* change it when the medium has been repartitioned.
*/
} else {
}
}
/*
* Close and reopen the new default partition, and reset the
* medium's access permissions to the correct values.
*/
if (reopen_result == REOPEN_RO) {
} else if (reopen_result == REOPEN_RW) {
} else {
}
return (result);
}
/*
* Definitions of private methods
*/
static void
{
/*
* close all the open fd's
*/
int partition_type;
int partition_number;
partition_type = 0;
while (partition_type < NUM_FS_TYPES) {
partition_number = 0;
while (partition_number < V_NUMPAR) {
if (private_datap->
(void) close(private_datap->
}
}
}
}
static char *
{
static char state_buf[30];
switch (st) {
case DKIO_NONE:
break;
case DKIO_INSERTED:
break;
case DKIO_EJECTED:
break;
case DKIO_DEV_GONE:
break;
default:
break;
}
return (state_buf);
}
static int
{
/*
* Close and reopen the default partition on a removable
* medium.
*/
int count;
int defpart;
int fd;
int fs_type;
char *raw_path;
int result;
} else {
if (fd >= 0) {
if (fd >= 0) {
}
} else {
raw_path);
}
/*
* The following sequence is a temporary workaround
* for a race condition in which a copy of rmmount
* has the default partition open while reopen_rmdisk()
* is trying to open it O_EXCL. Remove the workaround
* when the root cause of the race condition is found
* and removed.
*/
count = 0;
if (fd >= 0) {
break;
}
} else {
if (fd >= 0) {
break;
}
}
sleep(1);
count++;
}
/*
* we could not open the device without O_NONBLOCK set.
* That may be caused because the medium is half corrupted,
* or completely unformatted. Try open with NONBLOCK as
* a final option.
*/
if (fd < 0) {
if (fd >= 0)
}
/*
* End of the temporary workaround for the race condition.
*/
if (fd < 0) {
raw_path);
} else {
/*
* set close-on-exec
*/
}
}
return (result);
}
static void
{
extern cond_t running_cv;
extern mutex_t running_mutex;
extern int vold_running;
int defpart;
int fd;
int fs_type;
int partition_number;
int reopen_result;
struct rmdisk_priv *rmdp;
enum dkio_state rmdisk_state;
struct vioc_event vie;
struct async_task *as;
/*
* Ensure vold_main() is running before continuing.
*/
(void) mutex_lock(&running_mutex);
while (vold_running == 0) {
}
(void) mutex_unlock(&running_mutex);
if (fdisk_supported) {
/*
* Check for P partitions first.
*/
partition_number = 0;
while (partition_number < RMDMAX_FDISK_PARTITIONS) {
/*
* Always open rdonly here, since the
* DKIOC_INSERTED state will cause a
*/
if (fd < 0) {
noise("rmdisk: open of \"%s\"; %m\n",
rmdp->
return;
}
}
}
partition_number = 0;
while (partition_number < V_NUMPAR) {
/*
* Always open rdonly here, since the DKIOC_INSERTED
*/
noise("rmdisk: open of \"%s\"; %m\n",
return;
}
}
/*
* Get the vendor's device name (e.g. jaz, zip),
* and reset the device symbolic name to reflect it.
*/
return;
}
/*
* DP_MEJECTABLE should be set for each drvices.
*/
dp->dp_symname);
for (;;) { /* loop until the thread is killed */
if (fd < 0) {
"rmdisk_thread_wait: bad file descriptor for %s\n"),
return;
}
debug(3,
"rmdisk_thread_wait: ioctl(DKIOCSTATE) on \"%s\"\n",
/*
* The following ioctl blocks until the device state changes.
*/
debug(1,
"rmdisk_thread_wait: DKIOCSTATE of \"%s\"; %m\n",
return;
}
(void) sleep(1);
continue;
}
if (rmdisk_state == DKIO_NONE) {
/*
* No event has occurred. Do nothing.
*/
continue;
}
if (rmdisk_state == DKIO_DEV_GONE) {
/* device is gone */
/*
* we don't bail out from the loop, because we
* will need to keep watching the device if device
* was busy, and we couldn't close the device.
*/
continue;
}
if (rmdisk_state == DKIO_INSERTED) {
/*
* If vold already knows there's a medium
* in the device, do nothing.
*/
continue;
}
/*
* Find the partition that starts at byte 0 on the
* medium and that maps the largest portion of the
* medium.
*/
if (basepart < 0)
debug(1,
"rmdisk_thread_wait: rmd_defpart now %d\n",
}
/*
* Reopen the base file descriptor just found
* and generate an insert event. Note:
* the reopen is required to set the access
* permissions on the new file descriptor
* to those on the medium just inserted into
* the device.
*/
if (reopen_result >= 0) {
switch (reopen_result) {
case 0:
break;
case 1:
break;
}
}
}
if (rmdisk_state == DKIO_EJECTED) {
(void) mutex_lock(&vold_main_mutex);
/*
* Create "nomedia" device node for empty
* removable media device.
*/
}
(void) mutex_unlock(&vold_main_mutex);
continue;
}
partition_number = 0;
}
}
(void) mutex_unlock(&vold_main_mutex);
}
}
/*
* got error. let vold_run close the device and reap this thread
*/
}