dev_cdrom.c revision 18c2aff776a775d34a4c9893a4c72e0434d68e36
/*
* 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 2006 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
#if defined(_FIRMWARE_NEEDS_FDISK)
#endif /* defined(_FIRMWARE_NEEDS_FDISK) */
#include <errno.h>
#include <signal.h>
#include <string.h>
#include <dirent.h>
#include <stdlib.h>
#include <unistd.h>
#include <thread.h>
#include <synch.h>
#include "vold.h"
#include "vtoc.h"
#if !defined(P0_WA)
#endif
/*
* following defs are used to support the sparc solaris S partitions
* and are used to support the P partitions found on x86 Solaris
* and that may be used on sparc if it should support fdisk.
*/
#define S_TYPE 0 /* defn for S partitions */
#define CDROM_NAMEPROTO_DEFD "%sd0s%d"
#define CDROM_PBASEPART 0
#define CDROM_SBASEPART 2
#define CDROM_NAMEPROTO_P "%sp%d"
#define CDROM_NAMEPROTO_S "%ss%d"
#ifdef P0_WA
#define CDROM_NAMEPROTO_P_ALL 0
#endif
#define CDROM_READ_OFFSET 32768L
#define CDROM_READ_SIZE 2048
/*
* thread stack size
*/
/*
* determine which type of partition have the greatest
* number. Currently this is always S Partitions, but to
* be sure any changes in the future does not break this
* code.
*/
#if CDMAX_S_PART > CDMAX_P_PART
#define CDMAX_PARTS CDMAX_S_PART
#else
#define CDMAX_PARTS CDMAX_P_PART
#endif
struct cd_priv {
#ifdef CDROM_POLL
#endif
int cd_tid; /* thread id */
int cd_p_type; /* id's what partition type we are accessing */
int cd_defpart;
#ifdef P0_WA
char *cd_blk_p0_path; /* the p0 blk name */
int cd_p0_part;
#endif
#if defined(_FIRMWARE_NEEDS_FDISK)
#endif /* defined(_FIRMWARE_NEEDS_FDISK) */
};
#if defined(_FIRMWARE_NEEDS_FDISK)
#endif
/*
* Declarations of externally visible methods
* made visible through the devsw struct
*/
static void cdrom_devmap(vol_t *, int, int);
static int cdrom_getfd(dev_t);
#ifdef CDROM_POLL
static void cdrom_poll(dev_t);
#endif
static bool_t cdrom_testpath(char *);
extern bool_t support_nomedia;
static struct devsw cdromdevsw = {
cdrom_use, /* d_use */
cdrom_error, /* d_error */
cdrom_getfd, /* d_getfd */
#ifdef CDROM_POLL
cdrom_poll, /* d_poll */
#else
NULL, /* d_poll */
#endif
cdrom_devmap, /* d_devmap */
cdrom_close, /* d_close */
NULL, /* d_eject */
NULL, /* d_find */
cdrom_check, /* d_check */
CDROM_MTYPE, /* d_mtype */
DRIVE_CLASS, /* d_dtype */
(uid_t)0, /* d_uid */
(gid_t)0, /* d_gid */
(mode_t)0, /* d_mode */
cdrom_testpath, /* d_test */
cdrom_remount /* d_remount */
};
/*
* Declarations of private methods
*/
#if defined(_FIRMWARE_NEEDS_FDISK)
static void cdrom_open_exclusive(struct cd_priv *, char *, char *);
#endif
static void cdrom_thread_wait(struct devs *);
static int part_to_hack(struct vtoc *);
/*
* Definitions of externally visible methods
* made visible through the devsw struct
*/
dev_init()
{
return (TRUE);
}
/*
* cdrom_use -- this routine expects either a raw or block path that
* points to a cdrom. It further expects that the supplied
* the complimentary device by switching this segment, e.g.
* then this routine will expect the raw devices to be at
*
* 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.
*/
static bool_t
{
char mypath[MAXPATHLEN];
int i, n;
char namebuf[MAXPATHLEN];
char namebuf1[MAXPATHLEN];
char *p;
char *path_trunc = mypath;
char *s;
#if defined(_FIRMWARE_NEEDS_FDISK)
#else
#endif
/*
* we don't do an open for the cdrom because it returns ENODEV
* if there isn't a device there. Instead, we just stat the
* device and make sure it's there and is a reasonable type.
*/
/* just take a path if they hand it to us. */
/*
* we can accept a path of the form:
*
* /dev/{dsk,rdsk}/cNtN
*
* we fill in the rest by appending "d0sN"
*/
/* can't even find it with "d0sN" appended! */
return (FALSE);
}
} else {
/*
* the supplied path is complete -- truncate at the "slice"
* part of the name
*
* XXX: assume all CD-ROM pathnames end in "sN"
*/
/* XXX: should make sure a slice number follows */
*s = '\0'; /* truncate at the "sN" */
} else {
/* the full path didn't have an "s" in it! */
path);
return (FALSE);
}
}
/*
* Check to see if this guy is already configured.
*/
/*
* 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);
}
}
/*
* Check the modes to make sure that the path is either
* a block or a character device
*/
"cdrom: %s not block or char device (mode 0x%x)\n"),
return (FALSE);
}
/*
* create en empty cd_priv data structure
*/
/*
* n accounts for P and S partitions
*/
for (n = 0; n < S_AND_P; n++) {
/*
* i accounts for max partitions, different between
* S and P so with P we loose a little memory
*/
for (i = 0; i < CDMAX_PARTS; i++) {
}
}
/*
* we default to S types. That will change
* if we later find valid instances of c#t#d#p#
*/
#ifdef P0_WA
#endif
/* he gave us a raw path (i.e. "rdsk" in it) */
/* save a pointer to the raw vv-node */
/* create the names for rawpath for type p partitions */
for (i = 0; i < CDMAX_P_PART; i++) {
CDROM_NAMEPROTO_P, path_trunc, i);
}
/* create the names for rawpath for type s partitions */
for (i = 0; i < CDMAX_S_PART; i++) {
CDROM_NAMEPROTO_S, path_trunc, i);
}
/*
* get the block path now from the raw one
*/
if ((p = strchr(s, '/')) != 0) {
p++;
} else {
/* no slash after rdsk? */
/* what else can we do? */
}
/*
* get the block vv-node
*/
#ifdef P0_WA
/* set up the p0 block pathname */
#endif
/*
* called with the block pathname
*/
/*
* save a pointer to the block vvnode
*/
#ifdef P0_WA
#endif
/*
* skip past "dsk/"
*/
if ((p = strchr(s, '/')) != 0) {
p++;
} else {
/* no slash after "dsk"? */
/* what else can we do? */
}
/*
* save a pointer to the raw vv-node
*/
/* create the names for rawpath for type p partitions */
for (i = 0; i < CDMAX_P_PART; i++) {
CDROM_NAMEPROTO_P, namebuf, i);
}
/*
* create the names for rawpath for type s partitions
*/
for (i = 0; i < CDMAX_S_PART; i++) {
CDROM_NAMEPROTO_S, namebuf, i);
}
} else {
return (FALSE);
}
#endif
return (FALSE);
}
#if defined(_FIRMWARE_NEEDS_FDISK)
/*
* serious hackery
* open the p? interfaces (so others can't get in around us)
*/
#endif /* defined(_FIRMWARE_NEEDS_FDISK) */
#ifdef CDROM_POLL
#endif
if (thr_create(0, CDROM_STKSIZE,
return (FALSE);
}
#ifdef DEBUG
#endif
return (TRUE);
}
#ifdef CDROM_POLL
/*ARGSUSED*/
static void
{
}
#endif /* CDROM_POLL */
/*ARGSUSED*/
static void
{
/*
* Well for P partitions this is a hack!
* HSFS can be mounted only from p0, the name change is
* for historical reasons
*/
#ifdef DEBUG
#endif
/* hack! use p0 instead of the requested slice */
#ifdef DEBUG
#endif
} else {
/* return the actual 's' slice requested */
}
#ifdef DEBUG
#endif
}
static int
{
}
/*ARGSUSED*/
static bool_t
{
return (TRUE);
}
static int
/*
* Wake up the device thread for a CDROM device.
* 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 cdrom_check() method doesn't have to check for previously
* undetected insertions of media because the cdrom_thread_wait()
* method checks continuously for insertions of media, and
* the cdrom_check() method wakes up cdrom_thread_wait().
*/
{
int fd;
int result;
result = 1;
} else {
result = 0;
}
return (result);
}
/*
* 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 i, n;
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 {
}
/* This device has been mounted. cannot eject. */
return;
}
/* do the eject work */
DKIOCEJECT, 0);
}
/*
* Clean up the names in the name space.
*/
/*
* free the private data we've allocated.
*/
for (n = 0; n < S_AND_P; n++) {
for (i = 0; i < CDMAX_PARTS; i++) {
if (cdp->cd_rawpath[n][i]) {
}
}
}
}
#ifdef P0_WA
#endif
#if defined(_FIRMWARE_NEEDS_FDISK)
for (i = 0; i < (FD_NUMPART+1); i++) {
if (cdp->cd_raw_pfd[i]) {
}
}
#endif /* defined(_FIRMWARE_NEEDS_FDISK) */
/*
* Free the dp, so no one points at us anymore.
*/
dev_freedp(dp);
}
#ifdef DEBUG
static char *
{
static char state_buf[30];
switch (st) {
case DKIO_NONE:
break;
case DKIO_INSERTED:
break;
case DKIO_EJECTED:
break;
default:
break;
}
return (state_buf);
}
#endif /* DEBUG */
static bool_t
cdrom_testpath(char *path)
{
int fd;
char *rp;
return (FALSE);
}
/*
* Check to see if vold is already managing the device.
*/
return (TRUE);
} else {
return (FALSE);
}
}
/*
* Find the raw device path corresponding to path.
*/
return (FALSE);
}
/*
* The device can't be opened, 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.
*/
return (FALSE);
}
/*
* Check to make sure the device is a CD-ROM
*/
return (FALSE);
}
return (FALSE);
}
return (TRUE);
}
static bool_t
{
/*
* There's no need to find the new default file
* descriptor for a CDROM, at least not until
* read-write CDROMs become available. Since
* current CDROMs are read-only, their default
* file descriptors never change.
*/
/*
* We need to confound lint while creating a dummy
* function that does nothing with its argument.
*/
return (TRUE);
} else {
return (FALSE);
}
}
/*
* Definitions of private methods
*/
static void
{
/*
* close all the open fd's
*/
int partition_type;
int partition_number;
partition_type = 0;
while (partition_type < S_AND_P) {
partition_number = 0;
while (partition_number < CDMAX_PARTS) {
if (private_datap->
(void) close(private_datap->
}
}
}
}
#if defined(_FIRMWARE_NEEDS_FDISK)
static void
{
/*
* serious hackery
*
* -- attempt to open the p? interfaces of the specified
* device -- just to keep users from getting around volmgt
*
* If this fails, just ignore it.
*
* The supplied params path1 and path2 will be the block
* and char prototype paths (but not necessarily in that
* order).
*/
char namebuf[MAXPATHLEN];
int i;
char *raw_proto; /* for the "rdsk" path */
/* initialized all of the fds */
for (i = 0; i < (FD_NUMPART+1); i++) {
}
/* find out which one is the raw path prototype */
} else {
return;
}
/* (attempt to) open each p device */
for (i = 0; i < (FD_NUMPART+1); i++) {
/* do the raw device */
CDROM_NAMEPROTO_P, raw_proto, i);
#ifdef DEBUG
#endif
}
}
#endif /* defined(_FIRMWARE_NEEDS_FDISK) */
static void
{
extern int vold_running;
extern cond_t running_cv;
extern mutex_t running_mutex;
enum dkio_state cd_state;
int fd = -1;
int i;
struct vioc_event vie;
struct async_task *as;
#ifdef DEBUG
static char *state_to_str(enum dkio_state);
#endif
(void) mutex_lock(&running_mutex);
while (vold_running == 0) {
}
(void) mutex_unlock(&running_mutex);
/*
* need to check for p partitions first
* while these are only associated with x86 they may
* be on sparc in the future (sparc supporting fdisk)
*/
for (i = 0; i < CDMAX_P_PART; i++) {
break;
}
}
for (i = 0; i < CDMAX_S_PART; i++) {
return;
}
}
/*
* Check to make sure device is a CD-ROM, use s2 part
*/
noise("cdrom: %s DKIOCINFO; %m\n",
return;
}
noise("cdrom: %s is not a CD-ROM drive\n",
return;
}
/*
* the base partition number is dependent on if we have
* a p partition(0) or an s partition(2)
* ALWAYS check for P0 first to set defaults
*/
} else {
}
for (;;) { /* loop until the thread is killed */
/*
* this ioctl blocks until state changes.
*/
#ifdef DEBUG
debug(3,
"cdrom_thread_wait: ioctl(DKIOCSTATE, \"%s\") on \"%s\"\n",
#else
#endif
break;
}
(void) sleep(1);
continue;
}
#ifdef DEBUG
#endif
continue; /* steady state -- ignore */
}
if (cd_state == DKIO_DEV_GONE) {
/* device is gone */
continue;
}
/*
* We have media in the drive
*/
if (cd_state == DKIO_INSERTED) {
/*
* If we already know about the media in the
* device, just ignore the information.
*/
continue;
}
/*
* If this is defaulted to use Slices we need to
* find out the lowest partition that maps the
* beginning of the cdrom
*
* If it is P partitions we must determine the
* slice number (s#) to map the p0 to.
*/
cdp->cd_defpart =
}
"cd_defpart now %d\n",
cdp->cd_defpart);
} else {
cdp->cd_p0_part =
}
"hack part = %d\n",
cdp->cd_p0_part);
}
}
/* generate an "insert" event */
}
/*
* We have NO media in the drive (it's just been ejected)
*/
if (cd_state == DKIO_EJECTED) {
struct vol *v;
/*
* we need to grab the lock here, otherwise
* volume may be freed by async vol threads.
*/
(void) mutex_lock(&vold_main_mutex);
/*
* If we already know about the ejection,
* just continue in our happy loop.
*/
/*
* Create "nomedia" device node for empty
* removable media device.
*/
}
(void) mutex_unlock(&vold_main_mutex);
continue;
}
/*
* Generate an eject event (if we have a unit)
*/
/*
* One device maps to only one volume object
* so just select first volume object to close.
*/
if (v->v_ndev != 0) {
}
(void) mutex_unlock(&vold_main_mutex);
}
}
/*
* let vold_run close the device and reap this thread
*/
}
static int
part_to_hack(struct vtoc *v)
{
/*
* return the numnber of the slice that starts at zero and
* maps the largest portion of the medium. if none found
* return -1.
*/
int i;
int part_no = -1;
int part_start = -1;
int part_size = 0;
/* scan for lowest starting part that has biggest chunk */
for (i = 0; i < CDMAX_S_PART; i++) {
/* get size and start, ignoring this slice if no size */
continue;
}
/*
* 3 possible cases of choosing this partition over
* our previous best:
* -> we don't have a previous best
* -> this part starts earlier than previous best
* -> this part starts at same place but is larger
*/
if ((part_start < 0) ||
(st < part_start) ||
part_start = st;
part_no = i;
continue;
}
}
/* return part found (or -1 if none) */
return (part_no);
}