/*
* 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"
/*
* Program to eject one or more pieces of media.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <dirent.h>
#include <fcntl.h>
#include <string.h>
#include <errno.h>
#include <locale.h>
#include <libintl.h>
#include <unistd.h>
#include <pwd.h>
#include <volmgt.h>
#include <signal.h>
static int work(char *, char *);
static void usage(void);
static int ejectit(char *);
static char *eject_getfullblkname(char *, boolean_t);
extern char *getfullrawname(char *);
/*
* ON-private libvolmgt routines
*/
int _dev_mounted(char *path);
int _dev_unmount(char *path);
char *_media_oldaliases(char *name);
void _media_printaliases(void);
/*
* Hold over from old eject.
* returns exit codes: (KEEP THESE - especially important for query)
* 0 = -n, -d or eject operation was ok, -q = media in drive
* 1 = -q only = media not in drive
* 2 = various parameter errors, etc.
* 3 = eject ioctl failed
* New Value (2/94)
* 4 = eject partially succeeded, but now manually remove media
*/
#define EJECT_OK 0
int
{
int c;
int excode;
int res;
#if !defined(TEXT_DOMAIN)
#endif
(void) textdomain(TEXT_DOMAIN);
/* process arguments */
switch (c) {
case 'd':
do_default = B_TRUE;
rmmount_opt = "-d";
break;
case 'q':
break;
case 'l':
rmmount_opt = "-l";
break;
case 'f':
break;
case 't':
break;
default:
usage();
}
}
/* no argument -- use the default */
} else {
/* multiple things to eject */
if (res == EJECT_MAN_EJ) {
}
}
if (err_seen) {
if (!is_direct) {
} else {
}
} else if (man_eject_seen) {
} else {
}
}
return (excode);
}
/*
* the the real work of ejecting (and notifying)
*/
static int
{
char *name;
if (!is_direct) {
/* exec rmmount */
if (do_closetray) {
(void) putenv("EJECT_CLOSETRAY=1");
}
if (do_query) {
(void) putenv("EJECT_QUERY=1");
}
if (pid < 0) {
exit(1);
} else if (pid == 0) {
/* child */
if (rmmount_opt != NULL) {
arg1 = rmmount_opt;
} else {
}
excode = 99;
} else {
exit(0);
}
} else {
/* parent */
excode = 1;
(WEXITSTATUS(status) != 0)) {
} else {
excode = 0;
}
}
}
/*
* rmmount returns 99 if HAL not running -
* fallback to direct in that case
*/
arg = "floppy";
}
}
if (do_default) {
goto out;
}
if (do_list) {
goto out;
}
if (do_query) {
return (EJECT_NO_MEDIA);
} else {
return (EJECT_PARM_ERR);
}
}
if (do_query) {
return (EJECT_NO_MEDIA);
}
}
} else {
}
}
out:
return (excode);
}
static void
usage(void)
{
gettext("usage: %s [-fldqt] [name | nickname]\n"),
gettext("options:\t-f force eject\n"));
gettext("\t\t-l list ejectable devices\n"));
gettext("\t\t-d show default device\n"));
gettext("\t\t-q query for media present\n"));
gettext("\t\t-t close tray\n"));
}
static int
{
int fd, r;
/*
* If volume management is either not running or not being managed by
* vold, and the device is mounted, we try to umount the device. If we
* fail, we give up, unless he used the -f flag.
*/
if (_dev_mounted(name)) {
r = _dev_unmount(name);
if (r == 0) {
if (!force_eject) {
gettext("WARNING: can not unmount %s, the file system is (probably) busy\n"),
name);
return (EJECT_PARM_ERR);
} else {
gettext("WARNING: %s has a mounted filesystem, ejecting anyway\n"),
name);
}
}
}
/*
* Require O_NDELAY for when floppy is not formatted
* will still id floppy in drive
*/
/*
* make sure we are dealing with a raw device
*
* XXX: NOTE: results from getfullrawname()
* really should be free()d when no longer
* in use
*/
gettext("%s is busy (try 'eject floppy' or 'eject cdrom'?)\n"),
name);
return (EJECT_PARM_ERR);
}
return (EJECT_PARM_ERR);
}
if (do_closetray) {
}
/* check on why eject failed */
/* check for no floppy in manually ejectable drive */
/* use code below to handle "not present" */
}
}
/*
* keep track of the fact that this is a manual
* ejection
*/
/*
* if our pathname is s slice (UFS is great) then
* check to see what really is busy
*/
}
gettext("%s not present in a drive\n"),
name);
} else {
}
}
return (result);
}
/*
* return B_TRUE if a floppy is in the drive, B_FALSE otherwise
*
* this routine assumes that the file descriptor passed in is for
* a floppy disk. this works because it's only called if the device
* is "manually ejectable", which only (currently) occurs for floppies.
*/
static boolean_t
{
int ival = 0;
if (!(ival & FDGC_CURRENT)) {
}
} else {
name);
}
return (rval);
}
/*
* display a "busy" message for the supplied pathname
*
* if the pathname is not a slice, then just display a busy message
* else if the pathname is some slice subdirectory then look for the
* *real* culprits
*
* if this is not done then the user can get a message like
* when they try to eject "cdrom0", but "s0" (e.g.) may be the only busy
* slice
*
* return B_TRUE iff we printed the appropriate error message, else
* return B_FALSE (and caller will print error message itself)
*/
static boolean_t
{
#ifdef DEBUG
#endif
/*
* get the block pathname.
* eject_getfullblkname returns NULL or pathname which
* has length < MAXPATHLEN.
*/
goto dun;
/* open mnttab for scanning */
/* can't open mnttab!? -- give up */
goto dun;
}
/* we found our entry -- we're done */
goto dun;
}
/* perhaps we have a sub-slice (which is what we exist to test for) */
/* create a base pathname */
/* no last slash in pathname!!?? -- give up */
goto dun;
}
*cp = '\0';
/* bblen = (uint)(cp - busy_base); */
/* scan for matches */
/*
* special device turns to NULL which isn't expected
*/
}
}
dun:
}
#ifdef DEBUG
#endif
errno = errno_save;
return (res);
}
/*
* In my experience with removable media drivers so far... the
* most reliable way to tell if a piece of media is in a drive
* is simply to open it. If the open works, there's something there,
* if it fails, there's not. We check for two errnos which we
* want to interpret for the user, ENOENT and EPERM. All other
* errors are considered to be "media isn't there".
*
* return B_TRUE if media found, else B_FALSE (XXX: was 0 and -1)
*/
static boolean_t
{
int fd;
if (doprint) {
}
} else {
if (doprint) {
name);
}
}
return (B_FALSE);
}
rval = 0;
/* hey, it worked, what a deal, it must be a floppy */
if (!(rval & FDGC_CURRENT)) {
if (doprint) {
name);
}
return (B_TRUE);
}
if (rval & FDGC_CURRENT) {
if (doprint) {
name);
}
return (B_FALSE);
}
}
/* great, the fancy ioctl is supported. */
if (state == DKIO_INSERTED) {
if (doprint) {
name);
}
return (B_TRUE);
}
if (state == DKIO_EJECTED) {
if (doprint) {
name);
}
return (B_FALSE);
}
/*
* Silly retry loop.
*/
(void) sleep(1);
goto again;
}
/*
* Ok, we've tried the non-blocking/ioctl route. The
* device doesn't support any of our nice ioctls, so
* we'll just say that if it opens it's there, if it
* doesn't, it's not.
*/
if (doprint) {
}
return (B_FALSE);
}
if (doprint) {
}
return (B_TRUE); /* success */
}
/*
* this routine will return the volmgt block name given the volmgt
* raw (char spcl) name
*
* if anything but a volmgt raw pathname is supplied that pathname will
* be returned
*
* NOTE: non-null return value will point to static data, overwritten with
* each call
*
* e.g. names starting with "/vol/r" will be changed to start with "/vol/",
*/
static char *
{
const char *vm_root;
#ifdef DEBUG
#endif
/*
* try different strategies based on whether or not vold is running
*/
if (vm_running) {
/* vold IS running -- look in /vol (or its alternate) */
/* get vm root dir */
vm_root = volmgt_root();
/* get first volmgt root dev directory (and its length) */
/* see if we have a raw volmgt pathname (e.g. "/vol/r*") */
return (NULL);
}
goto dun; /* found match in /vol */
}
/* get second volmgt root dev directory (and its length) */
return (NULL);
}
}
} else {
/* vold is NOT running -- look in /dev */
return (NULL);
}
goto dun; /* found match in /dev */
}
}
/* no match -- return what we got */
dun:
#ifdef DEBUG
#endif
return (res_buf);
}