/*
* 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 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#include <stdio.h>
#include <stdio_ext.h>
#include <errno.h>
#include <ctype.h>
#include <syslog.h>
#include <signal.h>
#include <limits.h>
#include <unistd.h>
#include <stdlib.h>
#include <fcntl.h>
#include <string.h>
#include <door.h>
#include <pwd.h>
#include <thread.h>
#include <synch.h>
#include <pthread.h>
#include <locale.h>
#include <sys/resource.h>
#include <netconfig.h>
#include "smserver.h"
#include "smed.h"
#include "myaudit.h"
#include <bsm/audit_uevents.h>
#include <utmpx.h>
/*
* The comments below would help in understanding what is being attempted
* in the server.
*
* The server can be started either by inetd or by the client directly.
* Normally the server is started by inetd when the client invokes the
* appropriate libsmedia library call(smedia_get_handle).
* However since the inetd runs only at init level 2 and above a mechanism
* is provided for the server to be started if an attempt is made to use
* the libsmedia calls in maintenence mode(init level 1).
* The main() routine determines how the server was invoked and takes
* the necessary action.
* When started by inetd it registers itself as an RPC program.
* The server also implements a mechanism by which it removes itself
* after a period of inactivity. The period of inactivity is specified
* by SVC_CLOSEDOWN which is set at 180 secs.
* The logic of detecting inactivity is as follows:
*
* Two variables svcstate and svccount are used to determine if the server
* is IDLE.
* The svcstate is set to 1(_SERVED) when ever the server does any operation
* on behalf of the client.
* The svccount indicates the number of active clients who have established
* a connection with the server. A connection is established when the
* libsmedia call smedia_get_handle() succeeds.
* The connection is broken when the client calls smedia_free_handle() OR
* exits.
* A thread called closedown is started up when server is started.
* This thread runs periodically and monitors both svcstate and svccount.
* If svcstate is IDLE and svccount is 0 then server exits.
* The svcstate is set to IDLE by the closedown thread. It is set to _SERVED
* by server. It is possible for the state to be _SERVED and the svccount
* to be 0. The server could be kept busy by client calls of smedia_get_handle
* that do not succeed. This is the reason for using both svcstate and svccount
* to determine the true server state.
*
* The communication between client and server is thru door calls.
* Below are the door descriptors available to communicate to the server.
*
* main_door_descriptor:
* ---------------------
* This is a predefined descriptor used by client to establish a
* connection with the server. This descriptor is available to the client
* as /var/adm/smedia_svc
* The client uses the main_door_descriptor to obtain a dedicated
* client_door_descriptor for itself. The smedia_get_handle call communicates
* to the server using the main_door_descriptor and obtains the
* client_door_descriptor which is stored in the handle structure.
* All other libsmedia calls use the client_door_descriptor to communicate
* with the server.
*
* client_door_descriptor:
* -----------------------
* This is the door descriptor that is used by the clients to
* request server to perform the necessary tasks. This door descriptor is
* available only to the client for whom it was created.
*
* death_door_descriptor:
* ----------------------
* The sole function of this descriptor HAD been to inform the server of
* the untimely death of the client. This descriptor is no longer used, though
* it is still created, as libsmedia expects to use it. This descriptor's
* service procedure had used pthread cancellation(5) to terminate the thread of
* the associated client_door_descriptor. The client_door_descriptor now
* handles the scenarios where a door_call/client are aborted/terminated.
*
* main_servproc()
* -------------
* This is the routine associated with the main_door_descriptor.
* This is the routine that handles the smedia_get_handle() call
* of the client. If the door call to this routine succeeds it creates a
* client_door_descriptor that is used by the client in subsequent library
* calls.
* This client_door_descriptor is passed to the client thru the door_return
* call. This client_door_descriptor cannot be used by any other process other
* than the client process that obtained it.
* In addition to the client_door_descriptor a death_door_descriptor is also
* created by the main server and passed on to the client. The client does not
* use the death_door_descriptor.
*
* client_servproc()
* ---------------
* This is the routine that handles the libsmedia calls of the
* client. In the current implementation the server takes control of the
* number of threads that handle the door calls. This is done by creating the
* door descriptor as DOOR_PRIVATE.
* The server runs only one thread per handle. This makes the implementation
* simple as we do not have to use mutex to make the code MT safe.
* The server thread has a data structure door_data_t associated with it.
*
* door_data_t
* -----------
* This is the data structure that is created by the main_servproc when it
* creates the client_door_descriptor. The door mechanism has a way to associate
* a cookie with the door descriptor. door_data_t is the cookie for the
* client_door_descriptor. This cookie is passed to the server function that
* handles the client_door_descriptor calls. In our case it is the
* client_servproc routine.
* The key elements of the door_data_t are the following:
*
* dd_fd file descriptor for the device.
* dd_buf The shared memory buffer between client-server.
* dd_thread The thread that handles the door_calls.
*
* signal handling:
* ----------------
* The main purpose of trapping the signals is to exit gracefully
* from the server after recording the appropriate message in the syslog.
* This will help the administrator to determine the cause of failure of the
* server by examining the log file.
*
* cleanup()
* ---------
* This routine frees up all the resources allocated for the client.
* Resources include the file descriptor, shared memory, threads.
*
* shared memory
* -------------
* In order to reduce the overheads of moving large amounts of data
* client. The smedia_raw_read, smedia_raw_write library calls mmap the
* memory and pass on the file descriptor that maps the memory to the server.
* The server subsequently uses this mmapped memory during the IO.
* If the mmapped memory changes in size, the server is informed and it
* remaps the memory to the changed size.
*/
#ifdef DEBUG
#else
#define DEFAULT_VERBOSE 0
#define DEFAULT_DEBUG 0
#endif
/*
* We will NOT be permitting the following USCI cmd options.
*
* RESET of target
* RESET of Bus.
* Tagged commands to device
* POLLED MODE of operation.
* Explicitly setting NO DISCONNECT features.
* use of RESERVED flags.
*/
/* States a server can be in wrt request */
#define _IDLE 0
static char *prog_name;
/*
* Log messages
*/
/* global variables */
static void cleanup(door_data_t *);
static void *init_server(void *);
static void *sm_server_thread(void *arg);
static char *xlate_state(int32_t);
static int32_t
{
debug(5,
"Invalid device type(0x%x) found for uscsi cmd.\n",
return (EINVAL);
}
debug(5,
"Invalid flags(0x%x) set in uscsi cmd. cdb[0]=0x%x\n",
return (EINVAL);
}
debug(5,
"Invalid command(0x%x) found in cdb.\n",
return (EINVAL);
}
return (0);
}
static uint32_t
{
sector_size = 512;
} else {
}
return (sector_size);
}
static char *
{
switch (state) {
case SM_WRITE_PROTECT_DISABLE:
return ("PROTECTION_DISABLED");
case SM_WRITE_PROTECT_PASSWD:
return ("WRITE_PROTECT_PASSWD");
return ("WRITE_PROTECT_NOPASSWD");
case SM_READ_WRITE_PROTECT:
return ("READ_WRITE_PROTECT");
case SM_TEMP_UNLOCK_MODE:
return ("PROTECTION DISABLED");
default:
return ("UNKNOWN_STATE");
}
}
static char *
{
switch (cnum) {
case SMEDIA_CNUM_OPEN_FD:
return ("SMEDIA_CNUM_OPEN_FD");
return ("SMEDIA_CNUM_GET_DEVICE_INFO");
return ("SMEDIA_CNUM_GET_MEDIUM_PROPERTY");
return ("SMEDIA_CNUM_GET_PROTECTION_STATUS");
return ("SMEDIA_CNUM_SET_PROTECTION_STATUS");
case SMEDIA_CNUM_RAW_READ:
return ("SMEDIA_CNUM_RAW_READ");
case SMEDIA_CNUM_RAW_WRITE:
return (" SMEDIA_CNUM_RAW_WRITE");
case SMEDIA_CNUM_FORMAT:
return ("SMEDIA_CNUM_FORMAT");
return ("SMEDIA_CNUM_CHECK_FORMAT_STATUS");
case SMEDIA_CNUM_EJECT:
return ("SMEDIA_CNUM_EJECT");
return ("SMEDIA_CNUM_REASSIGN_BLOCK");
case SMEDIA_CNUM_SET_SHFD:
return ("SMEDIA_CNUM_SET_SHFD");
case SMEDIA_CNUM_PING:
return ("SMEDIA_CNUM_PING");
case SMEDIA_CNUM_USCSI_CMD:
return ("SMEDIA_CNUM_USCSI_CMD");
default:
return ("UNKNOWN_CNUM");
}
}
/*ARGSUSED*/
{
(void) mutex_lock(&svcstate_lock);
(void) mutex_unlock(&svcstate_lock);
server_info.status = 0;
(void) init_server(NULL);
}
return (&server_info);
}
return (&server_info);
}
/*ARGSUSED*/
static void
{
}
static int32_t
{
/*
* Set function flags for driver.
*/
#ifdef DEBUG
#else
#endif /* DEBUG */
errno = 0;
return (ret_val);
}
if (!errno)
return (-1);
}
static int32_t
{
int32_t i;
for (i = 0; i < 8; i++) {
}
return (SCSI_IOMEGA);
}
return (SCSI_FLOPPY);
}
return (SCSI_GENERIC);
}
static int32_t
{
return (-1);
}
return (dev_type);
}
static int32_t
{
/* retrieve size discriptor of inserted media */
cdb[0] = SCMD_READ_FORMAT_CAP;
/* Fill in the USCSI fields */
(rq_data[13] == 0)) {
}
return (-1);
}
/* No media, bail out */
return (-1);
}
/*
* Generate capacity and blocksize information
*/
return (0);
}
static int32_t
{
if ((mode != SM_FORMAT_IMMEDIATE) &&
(mode != SM_FORMAT_BLOCKED)) {
return (ENOTSUP);
}
/*
* Do an inquiry and try to figure out if it an
* IOMEGA JAZ 2GB device.
*/
cdb[0] = SCMD_INQUIRY;
return (ucmd.uscsi_status);
}
cdb[0] = SCMD_READ_CAPACITY;
return (ucmd.uscsi_status);
}
cdb[0] = SCMD_FORMAT;
/*
* Defect list sent by initiator is a complete list of defects.
*/
/*
* Target should examine the setting of the DPRY, DCRT, STPF, IP
* and DSP bits.
*/
switch (flavor) {
case SM_FORMAT_QUICK :
/*
* Target should not perform any vendor specific
* medium certification process or format verification
*/
/*
* Defect list sent is an addition to the existing
* list of defects.
*/
break;
case SM_FORMAT_FORCE :
debug(1,
"LONG Format of JAZ media not supported\n");
return (ENOTSUP);
}
/*
* protected cartridge is allowed.
* This is a vendor specific Format Option.
*/
break;
case SM_FORMAT_LONG :
debug(1,
"LONG Format of JAZ media not supported\n");
return (ENOTSUP);
}
/*
* Defect list sent is an addition to the existing
* list of defects.
*/
break;
default :
flavor);
return (ENOTSUP);
}
if (mode == SM_FORMAT_IMMEDIATE) {
}
return (errno);
}
return (0);
}
static int32_t
{
cdb[0] = SCMD_FORMAT;
switch (flavor) {
case SM_FORMAT_QUICK :
return (-1);
case SM_FORMAT_FORCE :
break;
case SM_FORMAT_LONG :
break;
default :
return (-1);
}
}
}
return (-1);
}
return (0);
}
static int32_t
{
if ((mode != SM_FORMAT_IMMEDIATE) &&
(mode != SM_FORMAT_BLOCKED)) {
return (-1);
}
/*
* Do an inquiry and try to figure out if it an
* IOMEGA JAZ 2GB device.
*/
cdb[0] = SCMD_INQUIRY;
return (ucmd.uscsi_status);
}
cdb[0] = SCMD_READ_CAPACITY;
return (ucmd.uscsi_status);
}
cdb[0] = SCMD_FORMAT;
/*
* Defect list sent is an addition to the existing
* list of defects.
*/
/*
* Target should examine the setting of the DPRY, DCRT, STPF, IP
* and DSP bits.
*/
if (mode == SM_FORMAT_IMMEDIATE) {
debug(5,
"SM_FORMAT_IMMEDIATE specified ignored. Performing a long format!\n");
}
switch (flavor) {
case SM_FORMAT_LONG :
debug(1,
"LONG Format of JAZ media not supported\n");
return (ENOTSUP);
}
/*
* Defect list sent is an addition to the existing
* list of defects.
*/
break;
default :
flavor);
return (ENOTSUP);
}
return (ucmd.uscsi_status);
}
return (0);
}
static int32_t
{
return (-1);
}
}
} else {
}
return (cur_status);
}
static int32_t
{
cdb[0] = IOMEGA_NONSENSE_CMD;
"rv = %d uscsi_status = %d errno = %d\n",
return (-1);
}
return (-1);
}
switch (mode) {
case UNLOCK_MODE:
break;
case WRITE_PROTECT_MODE:
break;
break;
case READ_WRITE_PROTECT_MODE:
break;
default :
if (mode & TEMP_UNLOCK_MODE)
else
break;
}
return (status);
}
static int32_t
{
cdb[0] = SCMD_REASSIGN_BLOCK;
return (-1);
}
return (0);
}
static int32_t
{
cdb[0] = SCMD_MODE_SENSE;
return (-2);
}
return (0);
}
static int32_t
{
/*
* Do an inquiry and try to figure out if it an
* ATAPI or SCSI device.
*/
cdb[0] = SCMD_INQUIRY;
return (-1);
}
wa_bit = 0;
} else {
wa_bit = 1;
}
switch (wp->sm_new_state) {
case SM_WRITE_PROTECT_DISABLE :
new_mode = 0x0;
break;
case SM_WRITE_PROTECT_NOPASSWD :
new_mode = 0x2;
break;
case SM_WRITE_PROTECT_PASSWD :
new_mode = 0x3;
break;
case SM_READ_WRITE_PROTECT :
new_mode = 0x5;
break;
case SM_TEMP_UNLOCK_MODE :
new_mode = 0x8;
break;
default :
wp->sm_new_state);
return (-1);
}
cdb[0] = IOMEGA_CATRIDGE_PROTECT;
if (wa_bit)
/*
* Oops, ATAPI device with an odd length passwd!
* Allocate a buffer to hold one extra byte.
*/
errno = 0;
if (tmp_passwd == NULL) {
if (errno == 0)
return (-1);
}
} else {
}
if (tmp_passwd != NULL) {
}
"= %d uscsi_status = %d errno = %d\n", status,
/* Wrong passwd */
"passwd. errno is being set to EACCES.\n");
}
}
return (-1);
}
return (0);
}
/*ARGSUSED*/
static int32_t
{
return (-1);
}
/*
* This thread becomes the server-side thread used in
* the implementation of a door_call between a client
* and the Client Door.
*
* This thread is customized both by the door_server_create(3c)
* function sm_door_server_create, as well as by itself.
*
* This thread needs to synchronize with the
* main_servproc[SMEDIA_CNUM_OPEN_FD] door_call in terms of
* both successful and failure scenarios. main_servproc
* locks dd_lock before calling door_create. This thread
* then attempts to lock, but will block until main_servproc
* has either created all doors it requires, or until a
* door_create has failed (door_create's return and the
* creation of an associated thread are asynchronous).
*
* If door_create failed, this thread will be able to obtain
* dd_lock and call pthread_exit. If all door_create's succeed,
* this thread will obtain dd_lock and commence with
* customizing the thread's attributes. door_bind is called to
* bind this thread to the per-door private thread pool, and
* main_servproc is cond_signal'd to avail it of this fact.
*
* Finally, this thread calls door_return, which causes it to
* commence its lifetime as a server-side thread in implementation
* of a Client Door door_call.
*/
static void *
{
int i;
int err;
fatal("sm_server_thread[%d]: argument is NULL!!\n",
pthread_self());
exit(-1);
}
/* Wait for Client Door to be created */
if (door_dp->dd_cdoor_descriptor < 0) {
pthread_self());
pthread_exit((void *)-2);
}
for (i = 0; i < N_BADSIGS; i++) {
}
errno);
/* Bind thread with pool associated with Client Door */
fatal("door_bind");
exit(-1);
}
/*
* Set these two cancellation(5) attributes. Ensure that the
* pthread we create has cancellation(5) DISABLED and DEFERRED,
* as our implementation is based on this. DEFERRED is the
* default, but set it anyways, in case the defaults change in
* the future.
*/
" failed = %d\n"), err);
NULL)) != 0)
"failed = %d\n"), err);
/* Inform main_servproc that door_bind() is complete. */
/*
* Per doors protocol, transfer control to the doors-runtime in
* order to make this thread available to answer future door_call()'s.
*/
return (NULL);
}
/*
* This function cleans up all per-connection resources.
*
* This function is called when the Client Door's service procedure
* (client_servproc) is called w/ DOOR_UNREF_DATA, which is the
* doors protocol convention stating that the number of file
* descriptors referring to this door has dropped to one.
* client_servproc is passed DOOR_UNREF_DATA because the Client Door
* was door_create'd with the DOOR_UNREF bitflag.
*/
static void
{
/* do door_revoke() of Death Door */
if (door_dp->dd_ddoor_descriptor >= 0) {
"Door(%d) failed = %d"), pthread_self(),
} else {
}
}
/* release memory that is shared between client and (our) server */
door_dp->dd_buf_len = 0;
}
/* close the (target) device that the Client is operating on */
}
}
/*
* Unbind the current thread from the Client Door's private
* thread pool.
*/
if (door_unbind() < 0)
warning("door_unbind() of Client Door[%d] failed = "
/* Disallow any future requests to the Client Door */
if (door_dp->dd_cdoor_descriptor >= 0) {
"Client Door[%d] failed = %d"), pthread_self(),
}
}
}
/*
* This is the door_server_create(3c) function used to customize
* creation of the threads used in the handling of our daemon's
* door_call(3c)'s.
*
* This function is called synchronously as part of door_create(3c).
* Note that door_create(), however, is not synchronous; it can return
* with the created door file descriptor before any associated
* thread has been created. As a result, synchronization is needed
* between door_create() caller and the created pthread. This is
* needed both when each activity succeeds or when either activity
* fails.
*
* Specifically, this function ensures that each "connection"
* with the client creates only one thread in the per-door,
* private thread pool. This function locks dd_threadlock and
* then calls pthread_create(). If that succeeds, dd_thread
* is assigned the thread id, and dd_threadlock is unlocked.
* Any per-connection door_create that causes control to flow
* to this function will eventually find that dd_thread is
* non-zero, and control will exit this function.
*
* In the current implementation, the door_create for the Client Door
* is called first, and the Death Door is door_create'd second.
* As a result, the following function can safely make the static
* assumption that the first door (within a connection) is the
* Client Door. A connection's Client Door and Death Door share
* the same thread as well as the same door_data_t instance.
*/
static void
{
int ret_val;
int err;
return;
}
/* create one thread for this door */
"thread.\n", pthread_self());
return;
}
(void) pthread_attr_init(&attr);
PTHREAD_CREATE_DETACHED)) != 0)
err);
if (ret_val != 0) {
(void) pthread_attr_destroy(&attr);
return;
}
(void) pthread_attr_destroy(&attr);
pthread_self(), tid);
}
static void
{
}
static void
{
}
static int32_t
{
if (door_dp->dd_sector_size == 0) {
return (-1);
}
return (-1);
}
return (-1);
}
return (ret_val);
}
static int32_t
{
if (door_dp->dd_sector_size == 0) {
return (-1);
}
return (-1);
}
return (-1);
}
return (ret_val);
}
static int32_t
{
/*
* Read the current protection state before modifiying.
* Needed for audit purposes.
*/
case SCSI_IOMEGA:
break;
case SCSI_FLOPPY:
info("Formatting floppy");
break;
case SCSI_GENERIC:
break;
}
saved_errno = errno;
if (can_audit()) {
(void) audit_save_me(door_dp);
door_dp->audit_text[0] = 0;
door_dp->audit_text1[0] = 0;
}
if (ret_val < 0) {
} else uname[0] = 0;
if (can_audit()) {
sizeof (door_dp->audit_text),
sizeof (door_dp->audit_text1),
warning("Error in writing audit info\n");
}
} /* errno == EACCES */
errno = saved_errno;
return (-1);
}
if (can_audit()) {
sizeof (door_dp->audit_text),
sizeof (door_dp->audit_text1),
door_dp->audit_sorf = 0;
warning("Error in writing audit info\n");
}
errno = saved_errno;
return (0);
}
static int32_t
{
void *fbuf;
if (ret_val == -1)
errno);
door_dp->dd_buf_len = 0;
}
if (fbuf == MAP_FAILED) {
return (ret_val);
}
return (0);
}
static int32_t
{
char *read_buf;
if (ret_val != 0)
return (-1);
return (0);
}
/*
* No need to check if enough data is returned for
* AWRE bit or not.
* It will be 0 otherwise which needs to reassign the block.
*/
if (ret_val != 0)
return (-1);
return (0);
}
/* Alloc failed. Atleast reassign the block */
if (ret_val != 0)
return (-1);
return (0);
}
/* Read the sector */
/* Write the data back */
if (ret_val != 0)
return (-1);
return (0);
}
return (0);
}
static void
{
while (ndesc > 0) {
dp++;
ndesc--;
}
}
/*
* This is a Death Door's service procedure.
*
* This procedure is a NOP because the Death Door functionality
* is no longer used and will be removed in the future.
*/
/*ARGSUSED*/
static void
{
}
/*
* This is a Client Door's service procedure.
*
* This procedure is specified in the door_create() of a Client Door,
* and its functionality represents the bulk of services that the
* rpc.smserverd daemon offers.
*/
static void
{
if (argp == DOOR_UNREF_DATA) {
pthread_self());
(void) mutex_lock(&svcstate_lock);
svccount--;
(void) mutex_unlock(&svcstate_lock);
return;
}
(void) mutex_lock(&svcstate_lock);
(void) mutex_unlock(&svcstate_lock);
/*
* Our caller may have passed more descriptors than we expected.
* If so, we silently close (and ignore) them.
*/
if (ndesc > nexpected_desc) {
}
default:
break;
case SMEDIA_CNUM_SET_SHFD:
if (ndesc == 0)
/*
* Allocate shared memory for this connection.
* If this connection already has shared memory,
* deallocate before doing the allocation.
*/
req);
if (ret_val == 0) {
my_door_return((char *)&reterror,
sizeof (smedia_reterror_t), 0, 0);
} else {
}
break;
case SMEDIA_CNUM_RAW_READ:
(int)arg_size,
retbuf_size = sizeof (smedia_retraw_read_t);
/* Nothing to write */
my_door_return((char *)&rmsvc,
sizeof (smedia_retraw_write_t), 0, 0);
}
if (ret_val == -1) {
}
break;
case SMEDIA_CNUM_USCSI_CMD:
retbuf_size = sizeof (smedia_retuscsi_cmd_t);
/*
* Check the device type and invalid flags specified.
* We permit operations only on CDROM devices types.
*/
if (errno) {
}
"dd_buf_len=0x%x dd_buf=0x%p\n",
}
}
break;
case SMEDIA_CNUM_RAW_WRITE:
/* Nothing to write */
my_door_return((char *)&rmsvc,
sizeof (smedia_retraw_write_t), 0, 0);
}
if (ret_val == -1)
0, 0);
break;
}
(void) strlcpy(
sizeof (smedia_retget_device_info_t), 0, 0);
break;
0, sizeof (smmedium_prop_t));
if (ret_val < 0) {
/*
* Devices may fail DKIOCGMEDIAINFO if an unformed
* media is inserted. We can get the capacity
* information from the SCMD_READ_FORMAT_CAP command.
*/
"SCMD_READ_FORMAT_CAP");
if (ret_val >= 0) {
} else {
}
}
/*
* These devices show as SCSI devices but we need to treat it
* differently. so we need a seperate class.
*/
}
/* Check for EFI type because DKIOCGGEOM does not support EFI */
if (ret_val < 0) {
/*
* DKIOCGGEOM may fail for unformed floppies.
* We need to generate the appropriate geometry
* information.
*/
sm_media_type == SM_SCSI_FLOPPY) {
if (ret_val < 0) {
"media size");
}
} else {
#ifdef sparc
#else /* !sparc */
/*
* Try getting Physical geometry on x86.
*/
DKIOCG_PHYGEOM, &dkgeom);
if (ret_val < 0) {
"ioctl failed");
}
#endif /* sparc */
}
}
/*
* Some faked geometry may not have pcyl filled in so
* later calculations using this field will be
* incorrect. We will substitute it with the number of
* available cylinders.
*/
else
}
sizeof (smedia_retget_medium_property_t), 0, 0);
break;
case SCSI_FLOPPY:
break;
case SCSI_IOMEGA:
break;
case SCSI_GENERIC:
break;
default:
}
if (status < 0)
sizeof (smedia_retget_protection_status_t), 0, 0);
break;
if (ret_val == -1)
else
sizeof (smedia_retset_protection_status_t),
0, 0);
break;
case SMEDIA_CNUM_FORMAT:
case SCSI_FLOPPY:
info("formatting floppy");
break;
case SCSI_IOMEGA:
break;
case SCSI_GENERIC:
break;
default:
}
if (err)
sizeof (smedia_retformat_t), 0, 0);
break;
}
/* Deffered error. The format must have failed */
}
} else {
completed = (100);
}
sizeof (smedia_retcheck_format_status_t), 0, 0);
break;
if (ret_val == -1)
sizeof (smedia_retreassign_block_t), 0, 0);
break;
} /* end of switch */
}
/*
* This is the service procedure for the door that is associated with
* the (doorfs) filesystem Door that is created at 'smedia_service'.
*/
/*ARGSUSED*/
static void
{
int ret_val;
(void) mutex_lock(&svcstate_lock);
(void) mutex_unlock(&svcstate_lock);
if (ndesc > 0)
my_door_return((char *)&reterror,
sizeof (smedia_reterror_t), 0, 0);
}
/*
* Our caller may have passed more descriptors than we expected.
* If so, we silently close (and ignore) them.
*/
if (ndesc > nexpected_desc) {
}
default:
break;
case SMEDIA_CNUM_PING:
/*
* This service is to indicate that server is up and
* running. It is usually called from another instance of
* server that is started.
*/
my_door_return((char *)&reterror,
sizeof (smedia_reterror_t), 0, 0);
break;
case SMEDIA_CNUM_OPEN_FD:
if (ndesc == 0) {
my_door_return((char *)&reterror,
sizeof (smedia_reterror_t), 0, 0);
}
"errno = %d\n"), errno);
my_door_return((char *)&reterror,
sizeof (smedia_reterror_t), 0, 0);
}
/* Obtain the credentials of the user */
if (ret_val < 0) {
"failed. errno = %d\n"), errno);
my_door_return((char *)&reterror,
sizeof (smedia_reterror_t), 0, 0);
}
&dkinfo) == -1) {
"errno = %d\n"), errno);
my_door_return((char *)&reterror,
sizeof (smedia_reterror_t), 0, 0);
}
"errno = %d\n"), errno);
my_door_return((char *)&reterror,
sizeof (smedia_reterror_t), 0, 0);
}
ddata->dd_buf_len = 0;
ddata->dd_sector_size = 0;
/* specify a function that'll customize our door threads */
(void) door_server_create(sm_door_server_create);
/* create Client Door */
if (ddata->dd_cdoor_descriptor < 0) {
/* then door_create() failed */
"Door failed = %d\n"), err);
/* close target device */
my_door_return((char *)&reterror,
sizeof (smedia_reterror_t), 0, 0);
}
/* create Death Door */
if (ddata->dd_ddoor_descriptor < 0) {
"Door failed = %d\n"), errno);
} else {
DOOR_PARAM_DATA_MAX, 0);
}
"Death Door = %d", pthread_self(),
/* wait until sm_server_thread does door_bind() */
(void) mutex_lock(&svcstate_lock);
svccount++;
(void) mutex_unlock(&svcstate_lock);
if (ddata->dd_ddoor_descriptor < 0) {
/* Return only the Client Door to the client. */
my_door_return((char *)&reterror,
} else {
/*
* Return the Client Door and Death Door
* to the client.
*/
my_door_return((char *)&retok,
}
break;
}
}
/* ARGSUSED */
static void
{
pthread_self(),
sig);
}
/* ARGSUSED */
static void
{
pthread_self(),
sig);
}
/*ARGSUSED*/
static void
{
pthread_self(),
sig);
}
/*ARGSUSED*/
static void
{
}
/*ARGSUSED*/
static void *
{
int i, fd;
#if !defined(TEXT_DOMAIN)
#endif
(void) textdomain(TEXT_DOMAIN);
/*
* setup signal handlers.
*/
for (i = 0; i < N_BADSIGS; i++) {
}
/*
* Ignore SIGHUP until all the initialization is done.
*/
/*
* Increase file descriptor limit to the most it can possibly
* be.
*/
}
}
if (server_door == -1) {
exit(1);
}
(void) unlink(smedia_service);
if (fd < 0) {
exit(1);
}
if (server_fd == -1) {
exit(1);
}
/*
* setup signal handlers for post-init
*/
return (NULL);
}
static int
{
int doorh;
if (doorh < 0)
return (0);
return (0);
}
return (0);
}
return (0);
}
return (0);
}
return (1);
}
static int
{
int run_level;
setutxent();
}
}
return (run_level);
}
/*ARGSUSED*/
static void *
{
int current_run_level;
/*CONSTCOND*/
#ifndef lint
while (1) {
#endif
/*
* If the server was started at init level 1
* and the current init level is 1 then
* do not exit from server. This server will run
* until it is explicitly stopped by the user.
*/
if (svcstart_level == 1) {
if (current_run_level == 1)
#ifndef lint
continue;
#else
return (NULL);
#endif
/*
* who ever started the server at level 1 has
* forgotten to stop the server. we will kill ourself.
*/
debug(5,
"Terminating the server started at init level 1\n");
exit(0);
}
if (mutex_trylock(&svcstate_lock) != 0)
#ifndef lint
continue;
#else
return (NULL);
#endif
int size;
int i, openfd = 0;
if (svc_pollfd[i].fd >= 0)
openfd++;
if (openfd <= 1) {
debug(5,
"Exiting the server from closedown routine.\n");
exit(0);
}
} else
(void) mutex_unlock(&svcstate_lock);
#ifndef lint
}
#else
return (NULL);
#endif
}
static void
usage()
{
}
/*ARGSUSED*/
int
{
int c;
#if !defined(TEXT_DOMAIN)
#endif
(void) textdomain(TEXT_DOMAIN);
switch (c) {
case 'L':
break;
default:
usage();
break;
}
}
/*
* If stdin looks like a TLI endpoint, we assume
* that we were started by a port monitor. If
* t_getstate fails with TBADF, this is not a
* TLI endpoint.
*/
char *netid;
int pmclose;
/* started from inetd */
pmclose = 1;
} else {
"cannot get transport info"));
}
exit(1);
}
if (nconf)
smserverprog_1, 0)) {
"unable to register (SMSERVERPROG, SMSERVERVERS)."));
exit(1);
}
if (pmclose) {
(void) pthread_attr_init(&attr);
(void) pthread_attr_setscope(&attr,
(void) pthread_attr_setdetachstate(&attr,
"cannot create closedown thread"));
exit(1);
}
(void) pthread_attr_destroy(&attr);
}
svc_run();
exit(1);
/* NOTREACHED */
} else {
/*
* Started by library or manually.
*/
/*
* Check to see if the server is already running.
* There is no need to log messages in the syslog file
* because server will get launched each time libsmedia
* library calls are made at init 1 level.
* We ensure that only one copy will run.
*/
if (server_exists()) {
exit(0);
}
(void) pthread_attr_init(&attr);
(void) pthread_attr_setscope(&attr,
(void) pthread_attr_setdetachstate(&attr,
"cannot create closedown thread"));
exit(1);
}
(void) pthread_attr_destroy(&attr);
(void) init_server(NULL);
for (;;) (void) pause();
}
return (0);
}
/*ARGSUSED*/
static int32_t
{
return (-1);
}
/*
* Generate standard geometry information for SCSI floppy devices. And
* register the geometry with the SCSI driver. This will expand as more
* formats are added.
*/
/*ARGSUSED*/
static int32_t
{
switch (capacity) {
case 0x5A0:
/* Double Density 720K */
break;
case 0x4D0:
/* High Density 1.25MB */
break;
case 0xB40:
/* High Density 1.44MB */
break;
case 0x3C300:
/* Ultra High density ls-120 120MB */
break;
default:
return (-1);
}
return (0);
}
/* ARGSUSED */
static int32_t
{
int i;
return (-1);
}
switch (flavor) {
case SM_FORMAT_QUICK :
return (-1);
case SM_FORMAT_FORCE :
break;
case SM_FORMAT_LONG :
break;
default :
return (-1);
}
if (capacity >= 0x3C300) {
/*
* It's an LS-120 media, it does not support track
* formatting.
*/
}
if (ret_val) {
return (-1);
}
/* retrieve size discriptor of inserted media */
/*
* Defect list sent by initiator is a complete list of defects.
*/
cdb[2] = i;
}
}
return (-1);
}
(void) info("Invalid command for media\n");
}
}
return (-1);
}
}
return (0);
}
/* ARGSUSED */
static int32_t
{
/*
* issue 10 byte mode sense (0x5A)
*/
cdb[0] = SCMD_MODE_SENSE_G1;
/*
* UFI devices may not respond to the 0 mode page.
* retry with the error recovery page(0x01)
*/
}
return (-1);
}
}
} else {
}
return (cur_status);
}