2011-12-08 16:10:18 +01:00
|
|
|
/********************************************************************
|
|
|
|
*
|
|
|
|
* L I N U X E J E C T C O M M A N D
|
|
|
|
*
|
|
|
|
* by Jeff Tranter (tranter@pobox.com)
|
|
|
|
*
|
|
|
|
********************************************************************
|
|
|
|
*
|
|
|
|
* Copyright (C) 1994-2005 Jeff Tranter (tranter@pobox.com)
|
|
|
|
*
|
|
|
|
* This program is free software; you can redistribute it and/or modify
|
|
|
|
* it under the terms of the GNU General Public License as published by
|
|
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
|
|
* (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with this program; if not, write to the Free Software
|
|
|
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
|
|
*
|
|
|
|
********************************************************************
|
|
|
|
*
|
|
|
|
* See the man page for a description of what this program does and what
|
|
|
|
* the requirements to run it are.
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
2012-01-17 18:23:40 +01:00
|
|
|
#include "linux_version.h"
|
|
|
|
#include "c.h"
|
|
|
|
#include "nls.h"
|
2011-12-08 16:10:18 +01:00
|
|
|
|
2012-01-18 14:19:42 +01:00
|
|
|
#define EJECT_DEFAULT_DEVICE "/dev/cdrom"
|
2011-12-08 16:10:18 +01:00
|
|
|
|
|
|
|
#include <unistd.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <fcntl.h>
|
|
|
|
#include <limits.h>
|
2012-01-18 14:19:42 +01:00
|
|
|
#include <err.h>
|
2012-02-02 16:34:20 +01:00
|
|
|
#include <stdarg.h>
|
2012-01-17 18:23:40 +01:00
|
|
|
|
2011-12-08 16:10:18 +01:00
|
|
|
#include <getopt.h>
|
|
|
|
#include <errno.h>
|
|
|
|
#include <regex.h>
|
|
|
|
#include <sys/types.h>
|
|
|
|
#include <sys/stat.h>
|
|
|
|
#include <sys/ioctl.h>
|
|
|
|
#include <sys/wait.h>
|
|
|
|
#include <sys/mtio.h>
|
|
|
|
#include <linux/cdrom.h>
|
|
|
|
#include <linux/fd.h>
|
|
|
|
#include <sys/mount.h>
|
|
|
|
#include <scsi/scsi.h>
|
|
|
|
#include <scsi/sg.h>
|
|
|
|
#include <scsi/scsi_ioctl.h>
|
|
|
|
#include <sys/time.h>
|
|
|
|
|
|
|
|
/* Used by the ToggleTray() function. If ejecting the tray takes this
|
|
|
|
* time or less, the tray was probably already ejected, so we close it
|
|
|
|
* again.
|
|
|
|
*/
|
|
|
|
#define TRAY_WAS_ALREADY_OPEN_USECS 200000 /* about 0.2 seconds */
|
|
|
|
|
|
|
|
|
|
|
|
/* Global Variables */
|
|
|
|
const char *version = VERSION; /* program version */
|
|
|
|
int a_option = 0; /* command flags and arguments */
|
|
|
|
int c_option = 0;
|
|
|
|
int d_option = 0;
|
|
|
|
int f_option = 0;
|
|
|
|
int h_option = 0;
|
|
|
|
int n_option = 0;
|
|
|
|
int q_option = 0;
|
|
|
|
int r_option = 0;
|
|
|
|
int s_option = 0;
|
|
|
|
int t_option = 0;
|
|
|
|
int T_option = 0;
|
|
|
|
int v_option = 0;
|
|
|
|
int x_option = 0;
|
|
|
|
int p_option = 0;
|
|
|
|
int m_option = 0;
|
|
|
|
int a_arg = 0;
|
|
|
|
int c_arg = 0;
|
|
|
|
int x_arg = 0;
|
2012-02-02 16:34:20 +01:00
|
|
|
|
2011-12-08 16:10:18 +01:00
|
|
|
|
|
|
|
/*
|
|
|
|
* These are the basenames of devices which can have multiple
|
|
|
|
* partitions per device.
|
|
|
|
*/
|
|
|
|
const char *partitionDevice[] = {
|
|
|
|
"hd",
|
|
|
|
"sd",
|
|
|
|
"xd",
|
|
|
|
"dos_hd",
|
|
|
|
"mfm",
|
|
|
|
"ad",
|
|
|
|
"ed",
|
|
|
|
"ftl",
|
|
|
|
"pd",
|
|
|
|
0};
|
|
|
|
|
|
|
|
|
|
|
|
/* Display command usage on standard error and exit. */
|
|
|
|
static void usage()
|
|
|
|
{
|
|
|
|
// perror(_("%s: device is `%s'\n"));
|
|
|
|
fprintf(stderr,_(
|
|
|
|
"Eject version %s by Jeff Tranter (tranter@pobox.com)\n"
|
|
|
|
"Usage:\n"
|
|
|
|
" eject -h -- display command usage and exit\n"
|
|
|
|
" eject -V -- display program version and exit\n"
|
|
|
|
" eject [-vnrsfq] [<name>] -- eject device\n"
|
|
|
|
" eject [-vn] -d -- display default device\n"
|
|
|
|
" eject [-vn] -a on|off|1|0 [<name>] -- turn auto-eject feature on or off\n"
|
|
|
|
" eject [-vn] -c <slot> [<name>] -- switch discs on a CD-ROM changer\n"
|
|
|
|
" eject [-vn] -t [<name>] -- close tray\n"
|
|
|
|
" eject [-vn] -T [<name>] -- toggle tray\n"
|
|
|
|
" eject [-vn] -x <speed> [<name>] -- set CD-ROM max speed\n"
|
|
|
|
"Options:\n"
|
|
|
|
" -v\t-- enable verbose output\n"
|
|
|
|
" -n\t-- don't eject, just show device found\n"
|
|
|
|
" -r\t-- eject CD-ROM\n"
|
|
|
|
" -s\t-- eject SCSI device\n"
|
|
|
|
" -f\t-- eject floppy\n"
|
|
|
|
" -q\t-- eject tape\n"
|
|
|
|
" -p\t-- use /proc/mounts instead of /etc/mtab\n"
|
|
|
|
" -m\t-- do not unmount device even if it is mounted\n"
|
|
|
|
)
|
|
|
|
, version);
|
2012-01-18 14:19:42 +01:00
|
|
|
|
|
|
|
|
2011-12-08 16:10:18 +01:00
|
|
|
fprintf(stderr,_(
|
|
|
|
"Long options:\n"
|
|
|
|
" -h --help -v --verbose -d --default\n"
|
|
|
|
" -a --auto -c --changerslot -t --trayclose -x --cdspeed\n"
|
|
|
|
" -r --cdrom -s --scsi -f --floppy\n"
|
|
|
|
" -q --tape -n --noop -V --version\n"
|
|
|
|
" -p --proc -m --no-unmount -T --traytoggle\n"));
|
2012-01-18 14:19:42 +01:00
|
|
|
|
|
|
|
|
2011-12-08 16:10:18 +01:00
|
|
|
fprintf(stderr,_(
|
|
|
|
"Parameter <name> can be a device file or a mount point.\n"
|
|
|
|
"If omitted, name defaults to `%s'.\n"
|
|
|
|
"By default tries -r, -s, -f, and -q in order until success.\n"),
|
2012-01-17 18:23:40 +01:00
|
|
|
EJECT_DEFAULT_DEVICE);
|
2011-12-08 16:10:18 +01:00
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* Handle command line options. */
|
|
|
|
static void parse_args(int argc, char **argv, char **device)
|
|
|
|
{
|
|
|
|
const char *flags = "a:c:x:dfhnqrstTvVpm";
|
2012-01-18 14:19:42 +01:00
|
|
|
|
2011-12-08 16:10:18 +01:00
|
|
|
static struct option long_options[] =
|
|
|
|
{
|
|
|
|
{"help", no_argument, NULL, 'h'},
|
|
|
|
{"verbose", no_argument, NULL, 'v'},
|
|
|
|
{"default", no_argument, NULL, 'd'},
|
|
|
|
{"auto", required_argument, NULL, 'a'},
|
|
|
|
{"changerslot", required_argument, NULL, 'c'},
|
|
|
|
{"trayclose", no_argument, NULL, 't'},
|
|
|
|
{"traytoggle", no_argument, NULL, 'T'},
|
|
|
|
{"cdspeed", required_argument, NULL, 'x'},
|
|
|
|
{"noop", no_argument, NULL, 'n'},
|
|
|
|
{"cdrom", no_argument, NULL, 'r'},
|
|
|
|
{"scsi", no_argument, NULL, 's'},
|
|
|
|
{"floppy", no_argument, NULL, 'f'},
|
|
|
|
{"tape", no_argument, NULL, 'q'},
|
|
|
|
{"version", no_argument, NULL, 'V'},
|
|
|
|
{"proc", no_argument, NULL, 'p'},
|
|
|
|
{"no-unmount", no_argument, NULL, 'm'},
|
|
|
|
{0, 0, 0, 0}
|
|
|
|
};
|
|
|
|
int option_index;
|
2012-01-18 14:19:42 +01:00
|
|
|
|
2011-12-08 16:10:18 +01:00
|
|
|
int c;
|
|
|
|
|
2012-01-18 14:19:42 +01:00
|
|
|
|
2011-12-08 16:10:18 +01:00
|
|
|
while ((c = getopt_long(argc, argv, flags, long_options, &option_index)) != EOF) {
|
|
|
|
switch (c) {
|
|
|
|
case 'a':
|
|
|
|
a_option = 1;
|
|
|
|
if (!strcmp(optarg, "0"))
|
|
|
|
a_arg = 0;
|
|
|
|
else if (!strcmp(optarg, "off"))
|
|
|
|
a_arg = 0;
|
|
|
|
else if (!strcmp(optarg, "1"))
|
|
|
|
a_arg = 1;
|
|
|
|
else if (!strcmp(optarg, "on"))
|
|
|
|
a_arg = 1;
|
|
|
|
else {
|
2012-02-02 16:34:20 +01:00
|
|
|
errx(1, _("invalid argument to --auto/-a option"));
|
2011-12-08 16:10:18 +01:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 'c':
|
|
|
|
c_option = 1;
|
|
|
|
/* atoi() returns 0 on error, so "0" must be parsed separately */
|
|
|
|
if (!strcmp(optarg, "0"))
|
|
|
|
c_arg = 0;
|
|
|
|
else {
|
|
|
|
c_arg = atoi(optarg);
|
|
|
|
if (c_arg <= 0) {
|
2012-02-02 16:34:20 +01:00
|
|
|
errx(1, _("invalid argument to --changerslot/-c option"));
|
2011-12-08 16:10:18 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 'x':
|
|
|
|
x_option = 1;
|
|
|
|
if (!strcmp(optarg, "0"))
|
|
|
|
x_arg = 0;
|
|
|
|
else {
|
|
|
|
x_arg = atoi(optarg);
|
|
|
|
if (x_arg <= 0) {
|
2012-02-02 16:34:20 +01:00
|
|
|
errx(1, _("%s: invalid argument to --cdspeed/-x option"));
|
2011-12-08 16:10:18 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 'd':
|
|
|
|
d_option = 1;
|
|
|
|
break;
|
|
|
|
case 'f':
|
|
|
|
f_option = 1;
|
|
|
|
break;
|
|
|
|
case 'h':
|
|
|
|
usage();
|
|
|
|
exit(0);
|
|
|
|
break;
|
|
|
|
case 'm':
|
|
|
|
m_option = 1;
|
|
|
|
break;
|
|
|
|
case 'n':
|
|
|
|
n_option = 1;
|
|
|
|
break;
|
|
|
|
case 'p':
|
|
|
|
p_option = 1;
|
|
|
|
break;
|
|
|
|
case 'q':
|
|
|
|
q_option = 1;
|
|
|
|
break;
|
|
|
|
case 'r':
|
|
|
|
r_option = 1;
|
|
|
|
break;
|
|
|
|
case 's':
|
|
|
|
s_option = 1;
|
|
|
|
break;
|
|
|
|
case 't':
|
|
|
|
t_option = 1;
|
|
|
|
break;
|
|
|
|
case 'T':
|
|
|
|
T_option = 1;
|
|
|
|
break;
|
|
|
|
case 'v':
|
|
|
|
v_option = 1;
|
|
|
|
break;
|
|
|
|
case 'V':
|
|
|
|
printf(_("eject version %s by Jeff Tranter (tranter@pobox.com)\n"), version);
|
|
|
|
exit(0);
|
|
|
|
break;
|
|
|
|
case '?':
|
|
|
|
exit(1);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/* check for a single additional argument */
|
|
|
|
if ((argc - optind) > 1) {
|
2012-02-02 16:34:20 +01:00
|
|
|
errx(1, _("%s: too many arguments"));
|
2011-12-08 16:10:18 +01:00
|
|
|
}
|
|
|
|
if ((argc - optind) == 1) { /* one argument */
|
|
|
|
*device = strdup(argv[optind]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-01-18 14:19:42 +01:00
|
|
|
void e_close(int fp) {
|
|
|
|
if (close(fp)==-1) {
|
|
|
|
err(1, NULL);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void e_fclose(FILE *fp) {
|
|
|
|
if (fclose(fp)==-1) {
|
|
|
|
err(1, NULL);
|
|
|
|
}
|
|
|
|
}
|
2011-12-08 16:10:18 +01:00
|
|
|
|
|
|
|
/* Return 1 if file/device exists, 0 otherwise. */
|
|
|
|
static int FileExists(const char *name)
|
|
|
|
{
|
|
|
|
|
|
|
|
/*
|
|
|
|
* access() uses the UID, not the EUID. This way a normal user
|
|
|
|
* cannot find out if a file (say, /root/fubar) exists or not, even
|
|
|
|
* if eject is SUID root
|
|
|
|
*/
|
|
|
|
if (access (name, F_OK) == 0) {
|
|
|
|
return 1;
|
|
|
|
} else {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Given name, such as foo, see if any of the following exist:
|
|
|
|
*
|
|
|
|
* foo (if foo starts with '.' or '/')
|
|
|
|
* /dev/foo
|
|
|
|
* /media/foo
|
|
|
|
* /mnt/foo
|
|
|
|
* /dev/cdroms/foo
|
|
|
|
* /dev/cdroms/foo0
|
|
|
|
* /dev/dsk/foo
|
|
|
|
* /dev/rdsk/foo
|
|
|
|
* ./foo
|
|
|
|
*
|
|
|
|
* If found, return the full path. If not found, return 0.
|
|
|
|
* Returns pointer to dynamically allocated string.
|
|
|
|
*/
|
|
|
|
static char *FindDevice(const char *name)
|
|
|
|
{
|
|
|
|
char *buf;
|
|
|
|
|
|
|
|
buf = (char *) malloc(strlen(name)+14); /* to allow for "/dev/cdroms/ + "0" + null */
|
|
|
|
if (buf==NULL) {
|
2012-02-02 16:34:20 +01:00
|
|
|
errx(1, _("could not allocate memory"));
|
2011-12-08 16:10:18 +01:00
|
|
|
}
|
|
|
|
if ((name[0] == '.') || (name[0] == '/')) {
|
|
|
|
strcpy(buf, name);
|
|
|
|
if (FileExists(buf))
|
|
|
|
return buf;
|
|
|
|
}
|
|
|
|
|
|
|
|
strcpy(buf, "/dev/");
|
|
|
|
strcat(buf, name);
|
|
|
|
if (FileExists(buf))
|
|
|
|
return buf;
|
|
|
|
|
|
|
|
strcpy(buf, "/media/");
|
|
|
|
strcat(buf, name);
|
|
|
|
if (FileExists(buf))
|
|
|
|
return buf;
|
|
|
|
|
|
|
|
strcpy(buf, "/mnt/");
|
|
|
|
strcat(buf, name);
|
|
|
|
if (FileExists(buf))
|
|
|
|
return buf;
|
|
|
|
|
|
|
|
/* for devfs under Linux */
|
|
|
|
strcpy(buf, "/dev/cdroms/");
|
|
|
|
strcat(buf, name);
|
|
|
|
if (FileExists(buf))
|
|
|
|
return buf;
|
|
|
|
|
|
|
|
strcpy(buf, "/dev/cdroms/");
|
|
|
|
strcat(buf, name);
|
|
|
|
strcat(buf, "0");
|
|
|
|
if (FileExists(buf))
|
|
|
|
return buf;
|
|
|
|
|
|
|
|
/* for devfs under Solaris */
|
|
|
|
strcpy(buf, "/dev/rdsk/");
|
|
|
|
strcat(buf, name);
|
|
|
|
if (FileExists(buf))
|
|
|
|
return buf;
|
|
|
|
|
|
|
|
strcpy(buf, "/dev/dsk/");
|
|
|
|
strcat(buf, name);
|
|
|
|
if (FileExists(buf))
|
|
|
|
return buf;
|
|
|
|
|
|
|
|
strcpy(buf, "./");
|
|
|
|
strcat(buf, name);
|
|
|
|
if (FileExists(buf))
|
|
|
|
return buf;
|
|
|
|
|
|
|
|
free(buf);
|
|
|
|
buf = 0;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* Set or clear auto-eject mode. */
|
|
|
|
static void AutoEject(int fd, int onOff)
|
|
|
|
{
|
|
|
|
int status;
|
|
|
|
|
|
|
|
status = ioctl(fd, CDROMEJECT_SW, onOff);
|
|
|
|
if (status != 0) {
|
2012-02-02 16:34:20 +01:00
|
|
|
err(1, _("CD-ROM auto-eject command failed"));
|
2011-12-08 16:10:18 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Changer select. CDROM_SELECT_DISC is preferred, older kernels used
|
|
|
|
* CDROMLOADFROMSLOT.
|
|
|
|
*/
|
|
|
|
static void ChangerSelect(int fd, int slot)
|
|
|
|
{
|
|
|
|
int status;
|
|
|
|
|
|
|
|
#ifdef CDROM_SELECT_DISC
|
|
|
|
status = ioctl(fd, CDROM_SELECT_DISC, slot);
|
|
|
|
if (status < 0) {
|
2012-02-02 16:34:20 +01:00
|
|
|
err(1, _("CD-ROM select disc command failed"));
|
2011-12-08 16:10:18 +01:00
|
|
|
}
|
|
|
|
#elif defined CDROMLOADFROMSLOT
|
|
|
|
status = ioctl(fd, CDROMLOADFROMSLOT, slot);
|
|
|
|
if (status != 0) {
|
2012-02-02 16:34:20 +01:00
|
|
|
err(1, _("CD-ROM load from slot command failed"));
|
2011-12-08 16:10:18 +01:00
|
|
|
}
|
|
|
|
#else
|
2012-02-02 16:34:20 +01:00
|
|
|
warnx( _("IDE/ATAPI CD-ROM changer not supported by this kernel\n") );
|
2011-12-08 16:10:18 +01:00
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Close tray. Not supported by older kernels.
|
|
|
|
*/
|
|
|
|
static void CloseTray(int fd)
|
|
|
|
{
|
|
|
|
int status;
|
|
|
|
|
|
|
|
#ifdef CDROMCLOSETRAY
|
|
|
|
status = ioctl(fd, CDROMCLOSETRAY);
|
|
|
|
if (status != 0) {
|
2012-02-02 16:34:20 +01:00
|
|
|
err(1, _("CD-ROM tray close command failed"));
|
2011-12-08 16:10:18 +01:00
|
|
|
}
|
|
|
|
#else
|
2012-02-02 16:34:20 +01:00
|
|
|
warnx( _("CD-ROM tray close command not supported by this kernel\n"));
|
2011-12-08 16:10:18 +01:00
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Toggle tray.
|
|
|
|
*
|
|
|
|
* Written by Benjamin Schwenk <benjaminschwenk@yahoo.de> and
|
|
|
|
* Sybren Stuvel <sybren@thirdtower.com>
|
|
|
|
*
|
|
|
|
* Not supported by older kernels because it might use
|
|
|
|
* CloseTray().
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
static void ToggleTray(int fd)
|
|
|
|
{
|
|
|
|
struct timeval time_start, time_stop;
|
|
|
|
int time_elapsed;
|
|
|
|
|
|
|
|
#ifdef CDROMCLOSETRAY
|
|
|
|
|
|
|
|
/* Try to open the CDROM tray and measure the time therefor
|
|
|
|
* needed. In my experience the function needs less than 0.05
|
|
|
|
* seconds if the tray was already open, and at least 1.5 seconds
|
|
|
|
* if it was closed. */
|
|
|
|
gettimeofday(&time_start, NULL);
|
|
|
|
|
|
|
|
/* Send the CDROMEJECT command to the device. */
|
|
|
|
if (ioctl(fd, CDROMEJECT, 0) < 0) {
|
|
|
|
perror("ioctl");
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Get the second timestamp, to measure the time needed to open
|
|
|
|
* the tray. */
|
|
|
|
gettimeofday(&time_stop, NULL);
|
|
|
|
|
|
|
|
time_elapsed = (time_stop.tv_sec * 1000000 + time_stop.tv_usec) -
|
|
|
|
(time_start.tv_sec * 1000000 + time_start.tv_usec);
|
|
|
|
|
|
|
|
/* If the tray "opened" too fast, we can be nearly sure, that it
|
|
|
|
* was already open. In this case, close it now. Else the tray was
|
|
|
|
* closed before. This would mean that we are done. */
|
|
|
|
if (time_elapsed < TRAY_WAS_ALREADY_OPEN_USECS)
|
|
|
|
CloseTray(fd);
|
|
|
|
|
|
|
|
#else
|
2012-02-02 16:34:20 +01:00
|
|
|
warnx( _("CD-ROM tray toggle command not supported by this kernel"));
|
2011-12-08 16:10:18 +01:00
|
|
|
#endif
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Select Speed of CD-ROM drive.
|
|
|
|
* Thanks to Roland Krivanek (krivanek@fmph.uniba.sk)
|
|
|
|
* http://dmpc.dbp.fmph.uniba.sk/~krivanek/cdrom_speed/
|
|
|
|
*/
|
|
|
|
static void SelectSpeedCdrom(int fd, int speed)
|
|
|
|
{
|
|
|
|
int status;
|
|
|
|
|
|
|
|
#ifdef CDROM_SELECT_SPEED
|
|
|
|
status = ioctl(fd, CDROM_SELECT_SPEED, speed);
|
|
|
|
if (status != 0) {
|
2012-02-02 16:34:20 +01:00
|
|
|
err(1, _("CD-ROM select speed command failed"));
|
2011-12-08 16:10:18 +01:00
|
|
|
}
|
|
|
|
#else
|
2012-02-02 16:34:20 +01:00
|
|
|
warnx( _("CD-ROM select speed command not supported by this kernel"));
|
2011-12-08 16:10:18 +01:00
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Eject using CDROMEJECT ioctl. Return 1 if successful, 0 otherwise.
|
|
|
|
*/
|
|
|
|
static int EjectCdrom(int fd)
|
|
|
|
{
|
|
|
|
int status;
|
|
|
|
|
|
|
|
status = ioctl(fd, CDROMEJECT);
|
|
|
|
return (status == 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Eject using SCSI commands. Return 1 if successful, 0 otherwise.
|
|
|
|
*/
|
|
|
|
static int EjectScsi(int fd)
|
|
|
|
{
|
|
|
|
int status;
|
|
|
|
struct sdata {
|
|
|
|
int inlen;
|
|
|
|
int outlen;
|
|
|
|
char cmd[256];
|
|
|
|
} scsi_cmd;
|
|
|
|
|
|
|
|
scsi_cmd.inlen = 0;
|
|
|
|
scsi_cmd.outlen = 0;
|
|
|
|
scsi_cmd.cmd[0] = ALLOW_MEDIUM_REMOVAL;
|
|
|
|
scsi_cmd.cmd[1] = 0;
|
|
|
|
scsi_cmd.cmd[2] = 0;
|
|
|
|
scsi_cmd.cmd[3] = 0;
|
|
|
|
scsi_cmd.cmd[4] = 0;
|
|
|
|
scsi_cmd.cmd[5] = 0;
|
|
|
|
status = ioctl(fd, SCSI_IOCTL_SEND_COMMAND, (void *)&scsi_cmd);
|
|
|
|
if (status != 0)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
scsi_cmd.inlen = 0;
|
|
|
|
scsi_cmd.outlen = 0;
|
|
|
|
scsi_cmd.cmd[0] = START_STOP;
|
|
|
|
scsi_cmd.cmd[1] = 0;
|
|
|
|
scsi_cmd.cmd[2] = 0;
|
|
|
|
scsi_cmd.cmd[3] = 0;
|
|
|
|
scsi_cmd.cmd[4] = 1;
|
|
|
|
scsi_cmd.cmd[5] = 0;
|
|
|
|
status = ioctl(fd, SCSI_IOCTL_SEND_COMMAND, (void *)&scsi_cmd);
|
|
|
|
if (status != 0)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
scsi_cmd.inlen = 0;
|
|
|
|
scsi_cmd.outlen = 0;
|
|
|
|
scsi_cmd.cmd[0] = START_STOP;
|
|
|
|
scsi_cmd.cmd[1] = 0;
|
|
|
|
scsi_cmd.cmd[2] = 0;
|
|
|
|
scsi_cmd.cmd[3] = 0;
|
|
|
|
scsi_cmd.cmd[4] = 2;
|
|
|
|
scsi_cmd.cmd[5] = 0;
|
|
|
|
status = ioctl(fd, SCSI_IOCTL_SEND_COMMAND, (void *)&scsi_cmd);
|
|
|
|
if (status != 0)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
/* force kernel to reread partition table when new disc inserted */
|
|
|
|
status = ioctl(fd, BLKRRPART);
|
|
|
|
return (status == 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Eject using FDEJECT ioctl. Return 1 if successful, 0 otherwise.
|
|
|
|
*/
|
|
|
|
static int EjectFloppy(int fd)
|
|
|
|
{
|
|
|
|
int status;
|
|
|
|
|
|
|
|
status = ioctl(fd, FDEJECT);
|
|
|
|
return (status == 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Eject using tape ioctl. Return 1 if successful, 0 otherwise.
|
|
|
|
*/
|
|
|
|
static int EjectTape(int fd)
|
|
|
|
{
|
|
|
|
int status;
|
|
|
|
struct mtop op;
|
|
|
|
|
|
|
|
op.mt_op = MTOFFL; /* rewind and eject */
|
|
|
|
op.mt_count = 0; /* not used */
|
|
|
|
status = ioctl(fd, MTIOCTOP, &op);
|
|
|
|
return (status == 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* Unmount a device. */
|
|
|
|
static void Unmount(const char *fullName)
|
|
|
|
{
|
|
|
|
int status;
|
|
|
|
|
|
|
|
switch (fork()) {
|
|
|
|
case 0: /* child */
|
|
|
|
seteuid(getuid()); /* reduce likelyhood of security holes when running setuid */
|
|
|
|
if(p_option)
|
|
|
|
execl("/bin/umount", "/bin/umount", fullName, "-n", NULL);
|
|
|
|
else
|
|
|
|
execl("/bin/umount", "/bin/umount", fullName, NULL);
|
2012-02-02 16:34:20 +01:00
|
|
|
errx(1, _("unable to exec /bin/umount of `%s'"), fullName);
|
2011-12-08 16:10:18 +01:00
|
|
|
break;
|
|
|
|
case -1:
|
2012-02-02 16:34:20 +01:00
|
|
|
warn( _("unable to fork"));
|
2011-12-08 16:10:18 +01:00
|
|
|
break;
|
|
|
|
default: /* parent */
|
|
|
|
wait(&status);
|
|
|
|
if (WIFEXITED(status) == 0) {
|
2012-02-02 16:34:20 +01:00
|
|
|
errx(1, _("unmount of `%s' did not exit normally\n"), fullName);
|
2011-12-08 16:10:18 +01:00
|
|
|
}
|
|
|
|
if (WEXITSTATUS(status) != 0) {
|
2012-02-02 16:34:20 +01:00
|
|
|
errx(1, _("unmount of `%s' failed\n"), fullName);
|
2011-12-08 16:10:18 +01:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* Open a device file. */
|
|
|
|
static int OpenDevice(const char *fullName)
|
|
|
|
{
|
|
|
|
int fd = open(fullName, O_RDONLY|O_NONBLOCK);
|
|
|
|
if (fd == -1) {
|
2012-02-02 16:34:20 +01:00
|
|
|
errx(1 , _("unable to open `%s'\n"), fullName);
|
2011-12-08 16:10:18 +01:00
|
|
|
}
|
|
|
|
return fd;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Get major and minor device numbers for a device file name, so we
|
|
|
|
* can check for duplicate devices.
|
|
|
|
*/
|
|
|
|
static int GetMajorMinor(const char *name, int *maj, int *min)
|
|
|
|
{
|
|
|
|
struct stat sstat;
|
|
|
|
*maj = *min = -1;
|
|
|
|
if (stat(name, &sstat) == -1)
|
|
|
|
return -1;
|
|
|
|
if (! S_ISBLK(sstat.st_mode))
|
|
|
|
return -1;
|
|
|
|
*maj = major(sstat.st_rdev);
|
|
|
|
*min = minor(sstat.st_rdev);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* See if device has been mounted by looking in mount table. If so, set
|
|
|
|
* device name and mount point name, and return 1, otherwise return 0.
|
|
|
|
*/
|
|
|
|
static int MountedDevice(const char *name, char **mountName, char **deviceName)
|
|
|
|
{
|
|
|
|
FILE *fp;
|
|
|
|
char line[1024];
|
|
|
|
char s1[1024];
|
|
|
|
char s2[1024];
|
|
|
|
int rc;
|
|
|
|
|
|
|
|
int maj;
|
|
|
|
int min;
|
|
|
|
|
|
|
|
GetMajorMinor(name, &maj, &min);
|
|
|
|
|
|
|
|
fp = fopen((p_option ? "/proc/mounts" : "/etc/mtab"), "r");
|
|
|
|
if (fp == NULL)
|
|
|
|
{
|
2012-02-02 16:34:20 +01:00
|
|
|
err(1, _("unable to open %s"), (p_option ? "/proc/mounts" : "/etc/mtab"));
|
2011-12-08 16:10:18 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
while (fgets(line, sizeof(line), fp) != 0) {
|
|
|
|
rc = sscanf(line, "%1023s %1023s", s1, s2);
|
|
|
|
if (rc >= 2) {
|
|
|
|
int mtabmaj, mtabmin;
|
|
|
|
GetMajorMinor(s1, &mtabmaj, &mtabmin);
|
|
|
|
if (((strcmp(s1, name) == 0) || (strcmp(s2, name) == 0)) ||
|
|
|
|
((maj != -1) && (maj == mtabmaj) && (min == mtabmin))) {
|
2012-01-18 14:19:42 +01:00
|
|
|
e_fclose(fp);
|
2011-12-08 16:10:18 +01:00
|
|
|
*deviceName = strdup(s1);
|
|
|
|
*mountName = strdup(s2);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
*deviceName = 0;
|
|
|
|
*mountName = 0;
|
2012-01-18 14:19:42 +01:00
|
|
|
e_fclose(fp);
|
2011-12-08 16:10:18 +01:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* See if device can be mounted by looking in /etc/fstab.
|
|
|
|
* If so, set device name and mount point name, and return 1,
|
|
|
|
* otherwise return 0.
|
|
|
|
*/
|
|
|
|
static int MountableDevice(const char *name, char **mountName, char **deviceName)
|
|
|
|
{
|
|
|
|
FILE *fp;
|
|
|
|
char line[1024];
|
|
|
|
char s1[1024];
|
|
|
|
char s2[1024];
|
|
|
|
int rc;
|
|
|
|
|
|
|
|
fp = fopen("/etc/fstab", "r");
|
|
|
|
if (fp == NULL) {
|
|
|
|
/*
|
|
|
|
* /etc/fstab may be unreadable in some situations due to passwords in the
|
|
|
|
* file.
|
|
|
|
*/
|
|
|
|
/* fprintf(stderr, _("%s: unable to open /etc/fstab: %s\n"), programName, strerror(errno));
|
|
|
|
exit(1);*/
|
|
|
|
if (v_option) {
|
2012-02-02 16:34:20 +01:00
|
|
|
warn( _("unable to open /etc/fstab") );
|
2011-12-08 16:10:18 +01:00
|
|
|
}
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
while (fgets(line, sizeof(line), fp) != 0) {
|
|
|
|
rc = sscanf(line, "%1023s %1023s", s1, s2);
|
|
|
|
if (rc >= 2 && s1[0] != '#' && strcmp(s2, name) == 0) {
|
2012-01-18 14:19:42 +01:00
|
|
|
e_fclose(fp);
|
2011-12-08 16:10:18 +01:00
|
|
|
*deviceName = strdup(s1);
|
|
|
|
*mountName = strdup(s2);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
}
|
2012-01-18 14:19:42 +01:00
|
|
|
e_fclose(fp);
|
2011-12-08 16:10:18 +01:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Step through mount table and unmount all devices that match a regular
|
|
|
|
* expression.
|
|
|
|
*/
|
|
|
|
static void UnmountDevices(const char *pattern)
|
|
|
|
{
|
|
|
|
regex_t preg;
|
|
|
|
FILE *fp;
|
|
|
|
char s1[1024];
|
|
|
|
char s2[1024];
|
|
|
|
char line[1024];
|
|
|
|
int status;
|
|
|
|
|
|
|
|
if (regcomp(&preg, pattern, REG_EXTENDED)!=0) {
|
2012-02-02 16:34:20 +01:00
|
|
|
err(0, _("regcomp"));
|
2011-12-08 16:10:18 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
fp = fopen((p_option ? "/proc/mounts" : "/etc/mtab"), "r");
|
|
|
|
if (fp == NULL)
|
|
|
|
{
|
2012-02-02 16:34:20 +01:00
|
|
|
err(1, _("unable to open %s"),(p_option ? "/proc/mounts" : "/etc/mtab"));
|
2011-12-08 16:10:18 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
while (fgets(line, sizeof(line), fp) != 0) {
|
|
|
|
status = sscanf(line, "%1023s %1023s", s1, s2);
|
|
|
|
if (status >= 2) {
|
|
|
|
status = regexec(&preg, s1, 0, 0, 0);
|
|
|
|
if (status == 0) {
|
|
|
|
if (v_option)
|
2012-02-02 16:34:20 +01:00
|
|
|
printf(_("%s: unmounting `%s'\n"), program_invocation_short_name, s1);
|
2011-12-08 16:10:18 +01:00
|
|
|
Unmount(s1);
|
|
|
|
regfree(&preg);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2012-01-18 14:19:42 +01:00
|
|
|
e_fclose(fp);
|
2011-12-08 16:10:18 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* Check if name is a symbolic link. If so, return what it points to. */
|
|
|
|
static char *SymLink(const char *name)
|
|
|
|
{
|
|
|
|
int status;
|
|
|
|
char s1[PATH_MAX];
|
|
|
|
char s2[PATH_MAX];
|
|
|
|
char s4[PATH_MAX];
|
|
|
|
char result[PATH_MAX];
|
|
|
|
char *s3;
|
|
|
|
|
|
|
|
memset(s1, 0, sizeof(s1));
|
|
|
|
memset(s2, 0, sizeof(s2));
|
|
|
|
memset(s4, 0, sizeof(s4));
|
|
|
|
memset(result, 0, sizeof(result));
|
|
|
|
|
|
|
|
status = readlink(name, s1, sizeof(s1) - 1);
|
|
|
|
|
|
|
|
if (status == -1)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
s1[status] = 0;
|
|
|
|
if (s1[0] == '/') { /* absolute link */
|
|
|
|
return strdup(s1);
|
|
|
|
} else { /* relative link, add base name */
|
|
|
|
strncpy(s2, name, sizeof(s2)-1);
|
|
|
|
s3 = strrchr(s2, '/');
|
|
|
|
if (s3 != 0) {
|
|
|
|
s3[1] = 0;
|
|
|
|
snprintf(result, sizeof(result)-1, "%s%s", s2, s1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
realpath(result, s4);
|
|
|
|
return strdup(s4);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Given a name, see if it matches a pattern for a device that can have
|
|
|
|
* multiple partitions. If so, return a regular expression that matches
|
|
|
|
* partitions for that device, otherwise return 0.
|
|
|
|
*/
|
|
|
|
static char *MultiplePartitions(const char *name)
|
|
|
|
{
|
|
|
|
int i = 0;
|
|
|
|
int status;
|
|
|
|
regex_t preg;
|
|
|
|
char pattern[256];
|
|
|
|
char *result = 0;
|
|
|
|
|
|
|
|
for (i = 0; partitionDevice[i] != 0; i++) {
|
|
|
|
/* look for ^/dev/foo[a-z]([0-9]?[0-9])?$, e.g. /dev/hda1 */
|
|
|
|
strcpy(pattern, "^/dev/");
|
|
|
|
strcat(pattern, partitionDevice[i]);
|
|
|
|
strcat(pattern, "[a-z]([0-9]?[0-9])?$");
|
|
|
|
regcomp(&preg, pattern, REG_EXTENDED|REG_NOSUB);
|
|
|
|
status = regexec(&preg, name, 1, 0, 0);
|
|
|
|
regfree(&preg);
|
|
|
|
if (status == 0) {
|
|
|
|
result = (char *) malloc(strlen(name) + 25);
|
|
|
|
strcpy(result, name);
|
|
|
|
result[strlen(partitionDevice[i]) + 6] = 0;
|
|
|
|
strcat(result, "([0-9]?[0-9])?$");
|
|
|
|
if (v_option)
|
2012-02-02 16:34:20 +01:00
|
|
|
printf(_("%s: `%s' is a multipartition device\n"), program_invocation_short_name, name);
|
2011-12-08 16:10:18 +01:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (v_option)
|
2012-02-02 16:34:20 +01:00
|
|
|
printf(_("%s: `%s' is not a multipartition device\n"), program_invocation_short_name, name);
|
2011-12-08 16:10:18 +01:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* handle -x option */
|
|
|
|
void HandleXOption(char *deviceName)
|
|
|
|
{
|
|
|
|
int fd; /* file descriptor for device */
|
|
|
|
if (x_option) {
|
|
|
|
if (v_option)
|
|
|
|
{
|
|
|
|
if (x_arg == 0)
|
2012-02-02 16:34:20 +01:00
|
|
|
printf(_("%s: setting CD-ROM speed to auto\n"), program_invocation_short_name);
|
2011-12-08 16:10:18 +01:00
|
|
|
else
|
2012-02-02 16:34:20 +01:00
|
|
|
printf(_("%s: setting CD-ROM speed to %dX\n"), program_invocation_short_name, x_arg);
|
2011-12-08 16:10:18 +01:00
|
|
|
}
|
|
|
|
fd = OpenDevice(deviceName);
|
|
|
|
SelectSpeedCdrom(fd, x_arg);
|
|
|
|
exit(0);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* main program */
|
|
|
|
int main(int argc, char **argv)
|
|
|
|
{
|
2012-02-02 16:34:20 +01:00
|
|
|
|
2012-01-17 18:23:40 +01:00
|
|
|
const char *defaultDevice = EJECT_DEFAULT_DEVICE; /* default if no name passed by user */
|
2011-12-08 16:10:18 +01:00
|
|
|
int worked = 0; /* set to 1 when successfully ejected */
|
|
|
|
char *device = 0; /* name passed from user */
|
|
|
|
char *fullName; /* expanded name */
|
|
|
|
char *deviceName; /* name of device */
|
|
|
|
char *linkName; /* name of device's symbolic link */
|
|
|
|
char *mountName; /* name of device's mount point */
|
2012-01-18 14:19:42 +01:00
|
|
|
int fd; /* file descriptor for device */
|
2011-12-08 16:10:18 +01:00
|
|
|
int mounted = 0; /* true if device is mounted */
|
|
|
|
int mountable = 0; /* true if device is in /etc/fstab */
|
2012-01-18 14:19:42 +01:00
|
|
|
char *pattern; /* regex for device if multiple partitions */
|
|
|
|
int ld = 6; /* symbolic link max depth */
|
2011-12-08 16:10:18 +01:00
|
|
|
|
2012-01-17 18:23:40 +01:00
|
|
|
setlocale(LC_ALL,"");
|
|
|
|
textdomain("eject");
|
|
|
|
bindtextdomain("eject",LOCALEDIR);
|
2011-12-08 16:10:18 +01:00
|
|
|
|
|
|
|
/* program name is global variable used by other procedures */
|
2012-02-02 16:34:20 +01:00
|
|
|
char *programName = program_invocation_short_name;
|
2011-12-08 16:10:18 +01:00
|
|
|
|
|
|
|
/* parse the command line arguments */
|
|
|
|
parse_args(argc, argv, &device);
|
|
|
|
|
|
|
|
|
|
|
|
/* handle -d option */
|
|
|
|
if (d_option) {
|
|
|
|
printf(_("%s: default device: `%s'\n"), programName, defaultDevice);
|
|
|
|
exit(0);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* if no device, use default */
|
|
|
|
if (device == 0) {
|
|
|
|
device = strdup(defaultDevice);
|
|
|
|
if (v_option)
|
|
|
|
printf(_("%s: using default device `%s'\n"), programName, device);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Strip any trailing slash from name in case user used bash/tcsh
|
|
|
|
style filename completion (e.g. /mnt/cdrom/) */
|
|
|
|
if (device[strlen(device)-1] == '/')
|
|
|
|
device[strlen(device)-1] = 0;
|
|
|
|
|
|
|
|
if (v_option)
|
|
|
|
printf(_("%s: device name is `%s'\n"), programName, device);
|
|
|
|
|
|
|
|
/* figure out full device or mount point name */
|
|
|
|
fullName = FindDevice(device);
|
|
|
|
if (fullName == 0) {
|
|
|
|
fprintf(stderr, _("%s: unable to find or open device for: `%s'\n"), programName, device);
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
if (v_option)
|
|
|
|
printf(_("%s: expanded name is `%s'\n"), programName, fullName);
|
|
|
|
|
|
|
|
/* check for a symbolic link */
|
|
|
|
while ((linkName = SymLink(fullName)) && (ld > 0)) {
|
|
|
|
if (v_option)
|
|
|
|
printf(_("%s: `%s' is a link to `%s'\n"), programName, fullName, linkName);
|
|
|
|
free(fullName);
|
|
|
|
fullName = strdup(linkName);
|
|
|
|
free(linkName);
|
|
|
|
linkName = 0;
|
|
|
|
ld--;
|
|
|
|
}
|
|
|
|
/* handle max depth exceeded option */
|
|
|
|
if (ld <= 0) {
|
|
|
|
printf(_("%s: maximum symbolic link depth exceeded: `%s'\n"), programName, fullName);
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* if mount point, get device name */
|
|
|
|
mounted = MountedDevice(fullName, &mountName, &deviceName);
|
|
|
|
if (v_option) {
|
|
|
|
if (mounted)
|
|
|
|
printf(_("%s: `%s' is mounted at `%s'\n"), programName, deviceName, mountName);
|
|
|
|
else
|
|
|
|
printf(_("%s: `%s' is not mounted\n"), programName, fullName);
|
|
|
|
}
|
|
|
|
if (!mounted) {
|
|
|
|
deviceName = strdup(fullName);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* if not currently mounted, see if it is a possible mount point */
|
|
|
|
if (!mounted) {
|
|
|
|
mountable = MountableDevice(fullName, &mountName, &deviceName);
|
|
|
|
/* if return value -1 then fstab could not be read */
|
|
|
|
if (v_option && mountable >= 0) {
|
|
|
|
if (mountable)
|
|
|
|
printf(_("%s: `%s' can be mounted at `%s'\n"), programName, deviceName, mountName);
|
|
|
|
else
|
|
|
|
printf(_("%s: `%s' is not a mount point\n"), programName, fullName);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* handle -n option */
|
|
|
|
if (n_option) {
|
|
|
|
printf(_("%s: device is `%s'\n"), programName, deviceName);
|
|
|
|
if (v_option)
|
|
|
|
printf(_("%s: exiting due to -n/--noop option\n"), programName);
|
|
|
|
exit(0);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* handle -a option */
|
|
|
|
if (a_option) {
|
|
|
|
if (v_option) {
|
|
|
|
if (a_arg)
|
|
|
|
printf(_("%s: enabling auto-eject mode for `%s'\n"), programName, deviceName);
|
|
|
|
else
|
|
|
|
printf(_("%s: disabling auto-eject mode for `%s'\n"), programName, deviceName);
|
|
|
|
}
|
|
|
|
fd = OpenDevice(deviceName);
|
|
|
|
AutoEject(fd, a_arg);
|
|
|
|
exit(0);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* handle -t option */
|
|
|
|
if (t_option) {
|
|
|
|
if (v_option)
|
|
|
|
printf(_("%s: closing tray\n"), programName);
|
|
|
|
fd = OpenDevice(deviceName);
|
|
|
|
CloseTray(fd);
|
|
|
|
HandleXOption(deviceName);
|
|
|
|
exit(0);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* handle -T option */
|
|
|
|
if (T_option) {
|
|
|
|
if (v_option)
|
|
|
|
printf(_("%s: toggling tray\n"), programName);
|
|
|
|
fd = OpenDevice(deviceName);
|
|
|
|
ToggleTray(fd);
|
|
|
|
HandleXOption(deviceName);
|
|
|
|
exit(0);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* handle -x option only */
|
|
|
|
if (!c_option) HandleXOption(deviceName);
|
|
|
|
|
|
|
|
/* unmount device if mounted */
|
|
|
|
if ((m_option != 1) && mounted) {
|
|
|
|
if (v_option)
|
|
|
|
printf(_("%s: unmounting `%s'\n"), programName, deviceName);
|
|
|
|
Unmount(deviceName);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* if it is a multipartition device, unmount any other partitions on
|
|
|
|
the device */
|
|
|
|
pattern = MultiplePartitions(deviceName);
|
|
|
|
if ((m_option != 1) && (pattern != 0))
|
|
|
|
UnmountDevices(pattern);
|
|
|
|
|
|
|
|
/* handle -c option */
|
|
|
|
if (c_option) {
|
|
|
|
if (v_option)
|
|
|
|
printf(_("%s: selecting CD-ROM disc #%d\n"), programName, c_arg);
|
|
|
|
fd = OpenDevice(deviceName);
|
|
|
|
ChangerSelect(fd, c_arg);
|
|
|
|
HandleXOption(deviceName);
|
|
|
|
exit(0);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* if user did not specify type of eject, try all four methods */
|
|
|
|
if ((r_option + s_option + f_option + q_option) == 0) {
|
|
|
|
r_option = s_option = f_option = q_option = 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* open device */
|
|
|
|
fd = OpenDevice(deviceName);
|
|
|
|
|
|
|
|
/* try various methods of ejecting until it works */
|
|
|
|
if (r_option) {
|
|
|
|
if (v_option)
|
|
|
|
printf(_("%s: trying to eject `%s' using CD-ROM eject command\n"), programName, deviceName);
|
|
|
|
worked = EjectCdrom(fd);
|
|
|
|
if (v_option) {
|
|
|
|
if (worked)
|
|
|
|
printf(_("%s: CD-ROM eject command succeeded\n"), programName);
|
|
|
|
else
|
|
|
|
printf(_("%s: CD-ROM eject command failed\n"), programName);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (s_option && !worked) {
|
|
|
|
if (v_option)
|
|
|
|
printf(_("%s: trying to eject `%s' using SCSI commands\n"), programName, deviceName);
|
|
|
|
worked = EjectScsi(fd);
|
|
|
|
if (v_option) {
|
|
|
|
if (worked)
|
|
|
|
printf(_("%s: SCSI eject succeeded\n"), programName);
|
|
|
|
else
|
|
|
|
printf(_("%s: SCSI eject failed\n"), programName);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (f_option && !worked) {
|
|
|
|
if (v_option)
|
|
|
|
printf(_("%s: trying to eject `%s' using floppy eject command\n"), programName, deviceName);
|
|
|
|
worked = EjectFloppy(fd);
|
|
|
|
if (v_option) {
|
|
|
|
if (worked)
|
|
|
|
printf(_("%s: floppy eject command succeeded\n"), programName);
|
|
|
|
else
|
|
|
|
printf(_("%s: floppy eject command failed\n"), programName);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (q_option && !worked) {
|
|
|
|
if (v_option)
|
|
|
|
printf(_("%s: trying to eject `%s' using tape offline command\n"), programName, deviceName);
|
|
|
|
worked = EjectTape(fd);
|
|
|
|
if (v_option) {
|
|
|
|
if (worked)
|
|
|
|
printf(_("%s: tape offline command succeeded\n"), programName);
|
|
|
|
else
|
|
|
|
printf(_("%s: tape offline command failed\n"), programName);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!worked) {
|
2012-02-02 16:34:20 +01:00
|
|
|
err(1, _("unable to eject, last error"), programName, strerror(errno));
|
2011-12-08 16:10:18 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/* cleanup */
|
2012-01-18 14:19:42 +01:00
|
|
|
e_close(fd);
|
2011-12-08 16:10:18 +01:00
|
|
|
free(device);
|
|
|
|
free(deviceName);
|
|
|
|
free(fullName);
|
|
|
|
free(linkName);
|
|
|
|
free(mountName);
|
|
|
|
free(pattern);
|
|
|
|
exit(0);
|
|
|
|
}
|