kadischi/eject_live_cd Makefile.am, NONE, 1.1 eject_live_cd.c, NONE, 1.1 i18n.h, NONE, 1.1
Jasper O'neal Hartline (autopsy)
fedora-extras-commits at redhat.com
Mon Jul 10 11:49:58 UTC 2006
Author: autopsy
Update of /cvs/devel/kadischi/eject_live_cd
In directory cvs-int.fedora.redhat.com:/tmp/cvs-serv9780/kadischi/eject_live_cd
Added Files:
Makefile.am eject_live_cd.c i18n.h
Log Message:
Use modified eject.c to handle our LiveCD ejections on shutdown.
--- NEW FILE Makefile.am ---
initrddir = $(libexecdir)/kadischi
initrd_PROGRAMS = eject-live-cd
eject_live_cd_SOURCES = eject_live_cd.c
eject_live_cd_LDADD = -lkudzu -lpci
--- NEW FILE eject_live_cd.c ---
/********************************************************************
*
* L I N U X E J E C T C O M M A N D
*
* by Jeff Tranter (tranter at pobox.com)
*
********************************************************************
*
* Copyright (C) 1994-2005 Jeff Tranter (tranter at 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.
*
*/
#include "i18n.h"
#define DEFAULTDEVICE "/tmp/cdrom"
#include <linux/version.h>
/* handy macro found in 2.1 kernels, but not in older ones */
#ifndef KERNEL_VERSION
#define KERNEL_VERSION(a,b,c) (((a) << 16) + ((b) << 8) + (c))
#endif
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <fcntl.h>
#include <limits.h>
#ifdef GETOPTLONG
#include <getopt.h>
#endif /* GETOPTLONG */
#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/types.h>
#include <linux/cdrom.h>
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,0)
#include <linux/ucdrom.h>
#endif
#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>
#include <kudzu/kudzu.h>
#define IMOUNT_ERR_ERRNO 1
#define IMOUNT_ERR_OTHER 2
#define CDDEVICE "/tmp/cdrom"
/* 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 */
#define CLOSE(fd) if (close(fd)==-1) { \
perror(programName); \
exit(1); \
}
#define FCLOSE(fd) if (fclose(fd)==-1) { \
perror(programName); \
exit(1); \
}
/* Global Variables */
static 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 X_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;
static char *programName; /* used in error messages */
/*
* These are the basenames of devices which can have multiple
* partitions per device.
*/
static 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 at pobox.com)\n"
"Usage:\n"
" eject -h -- display command usage and exit\n"
" eject -V -- display program version and exit\n"
" eject [-vnrsfqpm] [<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"
" eject [-vn] -X [<name>] -- list CD-ROM available speeds\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);
#ifdef GETOPTLONG
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 -X --listspeed\n"
" -q --tape -n --noop -V --version\n"
" -p --proc -m --no-unmount -T --traytoggle\n"));
#endif /* GETOPTLONG */
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"),
DEFAULTDEVICE);
exit(1);
}
/* Handle command line options. */
static void parse_args(int argc, char **argv, char **device)
{
const char *flags = "a:c:x:dfhnqrstTXvVpm";
#ifdef GETOPTLONG
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'},
{"listspeed", no_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;
#endif /* GETOPTLONG */
int c;
#ifdef GETOPTLONG
while ((c = getopt_long(argc, argv, flags, long_options, &option_index)) != EOF) {
#else
while ((c = getopt(argc, argv, flags)) != EOF) {
#endif /* GETOPTLONG */
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 {
fprintf(stderr, _("%s: invalid argument to --auto/-a option\n"), programName);
exit(1);
}
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) {
fprintf(stderr, _("%s: invalid argument to --changerslot/-c option\n"), programName);
exit(1);
}
}
break;
case 'x':
x_option = 1;
if (!strcmp(optarg, "0"))
x_arg = 0;
else {
x_arg = atoi(optarg);
if (x_arg <= 0) {
fprintf(stderr, _("%s: invalid argument to --cdspeed/-x option\n"), programName);
exit(1);
}
}
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 'X':
X_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 at pobox.com)\n"), version);
exit(0);
break;
case '?':
exit(1);
break;
}
}
/* check for a single additional argument */
if ((argc - optind) > 1) {
fprintf(stderr, _("%s: too many arguments\n"), programName);
exit(1);
}
if ((argc - optind) == 1) { /* one argument */
*device = strdup(argv[optind]);
}
}
/* 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) {
fprintf(stderr, _("%s: could not allocate memory\n"), programName);
exit(1);
}
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, "/mnt/");
strcat(buf, name);
if (FileExists(buf))
return buf;
strcpy(buf, "/media/");
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;
if (onOff)
status = ioctl(fd, CDROM_SET_OPTIONS, CDO_AUTO_EJECT);
else
status = ioctl(fd, CDROM_CLEAR_OPTIONS, CDO_AUTO_EJECT);
if (status < 0) {
fprintf(stderr, _("%s: CD-ROM auto-eject command failed: %s\n"), programName, strerror(errno));
exit(1);
}
}
/*
* 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) {
fprintf(stderr, _("%s: CD-ROM select disc command failed: %s\n"), programName, strerror(errno));
exit(1);
}
#elif defined CDROMLOADFROMSLOT
status = ioctl(fd, CDROMLOADFROMSLOT, slot);
if (status != 0) {
fprintf(stderr, _("%s: CD-ROM load from slot command failed: %s\n"), programName, strerror(errno));
exit(1);
}
#else
fprintf(stderr, _("%s: IDE/ATAPI CD-ROM changer not supported by this kernel\n"), programName);
#endif
}
/*
* Close tray. Not supported by older kernels.
*/
static void CloseTray(int fd)
{
int status;
#ifdef CDROMCLOSETRAY
status = ioctl(fd, CDROMCLOSETRAY);
if (status != 0) {
fprintf(stderr, _("%s: CD-ROM tray close command failed: %s\n"), programName, strerror(errno));
exit(1);
}
#else
fprintf(stderr, _("%s: CD-ROM tray close command not supported by this kernel\n"), programName);
#endif
}
/*
* Toggle tray.
*
* Written by Benjamin Schwenk <benjaminschwenk at yahoo.de> and
* Sybren Stuvel <sybren at 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
fprintf(stderr, _("%s: CD-ROM tray toggle command not supported by this kernel\n"), programName);
#endif
}
/*
* Select Speed of CD-ROM drive.
* Thanks to Roland Krivanek (krivanek at 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) {
fprintf(stderr, _("%s: CD-ROM select speed command failed: %s\n"), programName, strerror(errno));
exit(1);
}
#else
fprintf(stderr, _("%s: CD-ROM select speed command not supported by this kernel\n"), programName);
#endif
}
/*
* Read Speed of CD-ROM drive. From Linux 2.6.13, the current speed is correctly reported
*/
static int ReadSpeedCdrom(const char *shortName)
{
char line[512];
char *str_speed, *str_name;
int drive_number = -1, i;
FILE *f = fopen("/proc/sys/dev/cdrom/info", "r");
if (f == NULL) {
fprintf(stderr, _("%s: unable to read the speed from /proc/sys/dev/cdrom/info\n"), programName);
exit(1);
}
while (!feof(f)) {
fgets(line, sizeof(line), f);
/* find drive number from shortName in line "drive name" */
if (drive_number == -1) {
if (strncmp(line, "drive name:", 11) == 0) {
str_name = strtok(&line[11], "\t ");
drive_number = 0;
while (strncmp(shortName, str_name, strlen(shortName)) != 0) {
drive_number++;
str_name = strtok(NULL, "\t ");
if (str_name == NULL) {
fprintf(stderr, _("%s: error while finding CD-ROM name\n"), programName);
exit(1);
}
}
}
/* find line "drive speed" and read the correct speed */
} else {
if (strncmp(line, "drive speed:", 12) == 0) {
str_speed = strtok(&line[12], "\t ");
for (i = 1; i < drive_number; i++)
str_speed = strtok(NULL, "\t ");
if (str_speed == NULL) {
fprintf(stderr, _("%s: error while reading speed\n"), programName);
exit(1);
}
return atoi(str_speed);
}
}
}
fprintf(stderr, _("%s: error while reading speed\n"), programName);
exit(1);
return -1;
}
/*
* List Speed of CD-ROM drive.
*/
static void ListSpeedCdrom(const char *fullName, int fd)
{
#ifdef CDROM_SELECT_SPEED
int max_speed, curr_speed = 0, prev_speed;
char *shortName = rindex(fullName, '/') + 1;
SelectSpeedCdrom(fd, 0);
max_speed = ReadSpeedCdrom(shortName);
while (curr_speed < max_speed) {
prev_speed = curr_speed;
SelectSpeedCdrom(fd, prev_speed + 1);
curr_speed = ReadSpeedCdrom(shortName);
if (curr_speed > prev_speed)
printf("%d ", curr_speed);
else
curr_speed = prev_speed + 1;
}
printf("\n");
#else
fprintf(stderr, _("%s: CD-ROM select speed command not supported by this kernel\n"), programName);
#endif
}
/*
* Eject using CDROMEJECT ioctl. Return 1 if successful, 0 otherwise.
*/
static int EjectCdrom(int fd)
{
int status;
int cdrom;
if ((cdrom = open(CDDEVICE, O_RDONLY|O_NONBLOCK)) < 0) {
perror("open");
exit(1);
}
if (status = ioctl(cdrom, CDROMEJECT)<0) {
perror("ioctl");
}
close(cdrom);
return (status == 0);
}
/*
* Eject using SCSI SG_IO commands. Return 1 if successful, 0 otherwise.
*/
static int EjectScsi(int fd)
{
int status, k;
sg_io_hdr_t io_hdr;
unsigned char allowRmBlk[6] = {ALLOW_MEDIUM_REMOVAL, 0, 0, 0, 0, 0};
unsigned char startStop1Blk[6] = {START_STOP, 0, 0, 0, 1, 0};
unsigned char startStop2Blk[6] = {START_STOP, 0, 0, 0, 2, 0};
unsigned char inqBuff[2];
unsigned char sense_buffer[32];
if ((ioctl(fd, SG_GET_VERSION_NUM, &k) < 0) || (k < 30000)) {
if (v_option) {
printf(_("not an sg device, or old sg driver\n"));
}
return 0;
}
memset(&io_hdr, 0, sizeof(sg_io_hdr_t));
io_hdr.interface_id = 'S';
io_hdr.cmd_len = 6;
io_hdr.mx_sb_len = sizeof(sense_buffer);
io_hdr.dxfer_direction = SG_DXFER_NONE;
io_hdr.dxfer_len = 0;
io_hdr.dxferp = inqBuff;
io_hdr.sbp = sense_buffer;
io_hdr.timeout = 2000;
io_hdr.cmdp = allowRmBlk;
status = ioctl(fd, SG_IO, (void *)&io_hdr);
if (status < 0)
return 0;
io_hdr.cmdp = startStop1Blk;
status = ioctl(fd, SG_IO, (void *)&io_hdr);
if (status < 0)
return 0;
io_hdr.cmdp = startStop2Blk;
status = ioctl(fd, SG_IO, (void *)&io_hdr);
if (status < 0)
return 0;
/* force kernel to reread partition table when new disc inserted */
status = ioctl(fd, BLKRRPART);
return 1;
}
/*
* 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);
fprintf(stderr, _("%s: unable to exec /bin/umount of `%s': %s\n"),
programName, fullName, strerror(errno));
exit(1);
break;
case -1:
fprintf(stderr, _("%s: unable to fork: %s\n"), programName, strerror(errno));
break;
default: /* parent */
wait(&status);
if (WIFEXITED(status) == 0) {
fprintf(stderr, _("%s: unmount of `%s' did not exit normally\n"), programName, fullName);
exit(1);
}
if (WEXITSTATUS(status) != 0) {
fprintf(stderr, _("%s: unmount of `%s' failed\n"), programName, fullName);
exit(1);
}
break;
}
}
/* Open a device file. */
static int OpenDevice(const char *fullName)
{
int fd = open(fullName, O_RDONLY|O_NONBLOCK);
if (fd == -1) {
fprintf(stderr, _("%s: unable to open `%s'\n"), programName, fullName);
exit(1);
}
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)
{
fprintf(stderr, _("unable to open %s: %s\n"), (p_option ? "/proc/mounts" : "/etc/mtab"), strerror(errno));
exit(1);
}
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))) {
FCLOSE(fp);
*deviceName = strdup(s1);
*mountName = strdup(s2);
return 1;
}
}
}
*deviceName = 0;
*mountName = 0;
FCLOSE(fp);
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) {
printf( _("%s: unable to open /etc/fstab: %s\n"), programName, strerror(errno));
}
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) {
FCLOSE(fp);
*deviceName = strdup(s1);
*mountName = strdup(s2);
return 1;
}
}
FCLOSE(fp);
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) {
perror(programName);
exit(1);
}
fp = fopen((p_option ? "/proc/mounts" : "/etc/mtab"), "r");
if (fp == NULL)
{
fprintf(stderr, _("unable to open %s: %s\n"),(p_option ? "/proc/mounts" : "/etc/mtab"), strerror(errno));
exit(1);
}
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)
printf(_("%s: unmounting `%s'\n"), programName, s2);
Unmount(s2);
regfree(&preg);
}
}
}
FCLOSE(fp);
}
/* 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)
printf(_("%s: `%s' is a multipartition device\n"), programName, name);
return result;
}
}
if (v_option)
printf(_("%s: `%s' is not a multipartition device\n"), programName, name);
return 0;
}
/* handle -x option */
static void HandleXOption(char *deviceName)
{
int fd; /* file descriptor for device */
if (x_option) {
if (v_option)
{
if (x_arg == 0)
printf(_("%s: setting CD-ROM speed to auto\n"), programName);
else
printf(_("%s: setting CD-ROM speed to %dX\n"), programName, x_arg);
}
fd = OpenDevice(deviceName);
SelectSpeedCdrom(fd, x_arg);
exit(0);
}
}
struct devnum {
char * name;
short major, minor;
int isChar;
};
static struct devnum devices[] = {
{ "aztcd", 29, 0, 0 },
{ "pcd", 46, 0, 0 },
{ "cdu31a", 15, 0, 0 },
{ "cdu535", 24, 0, 0 },
{ "cm206cd", 32, 0, 0 },
{ "fd0", 2, 0, 0 },
{ "fd1", 2, 1, 0 },
{ "gscd", 16, 0, 0 },
{ "input/mouse0", 13, 32, 1 },
{ "input/mouse1", 13, 33, 1 },
{ "input/mouse2", 13, 34, 1 },
{ "input/mouse3", 13, 35, 1 },
{ "lp0", 6, 0, 1 },
{ "lp1", 6, 1, 1 },
{ "lp2", 6, 2, 1 },
{ "mcd", 23, 0, 0 },
{ "mcdx", 20, 0, 0 },
{ "nst0", 9, 128, 1 },
{ "optcd", 17, 0, 0 },
{ "psaux", 10, 1, 1 },
{ "sbpcd", 25, 0, 0 },
{ "sjcd", 18, 0, 0 },
{ "ttyS0", 4, 64, 1 },
{ "ttyS1", 4, 65, 1 },
{ "ttyS2", 4, 66, 1 },
{ "ttyS3", 4, 67, 1 },
};
static int numDevices = sizeof(devices) / sizeof(struct devnum);
static int devMakeInode(char * devName, char * path) {
int i;
int major, minor;
int type;
char *ptr;
char *dir;
/* scsi devices sda - sdp: major 8, minor 0 - 255 */
/* scsi devices sdq - sdaf: major 65, minor 0 - 255 */
/* scsi devices sdqg - sdav: major 66, minor 0 - 255 */
/* etc... */
if (devName[0] == 's' && devName[1] == 'd') {
int drive = 0;
char *num = NULL;
type = S_IFBLK;
if (devName[3] && isdigit(devName[3])) {
drive = devName[2] - 'a';
num = devName + 3;
} else if (devName[3] && islower(devName[3])) {
drive = ((devName[2] - 'a' + 1) * 26) + devName[3] - 'a';
num = devName + 4;
} else
drive = devName[2] - 'a';
/* only 128 SCSI drives, sorry */
if (drive > 128)
return -1;
else if (drive < 16)
major = 8;
else
major = 64 + (drive) / 16;
minor = (drive * 16) % 256;
if (num && num[0] && num[1])
minor += (num[0] - '0') * 10 + (num[1] - '0');
else if (num && num[0])
minor += (num[0] - '0');
if (minor > 255)
return -1;
} else if (devName[0] == 'm' && devName[1] == 'd') {
type = S_IFBLK;
major = 9;
minor = atoi(devName + 2);
} else if (devName[0] == 's' && devName[1] == 'g') {
type = S_IFBLK;
major = 21;
minor = atoi(devName + 2);
} else if (!strncmp(devName, "loop", 4)) {
type = S_IFBLK;
major = 7;
minor = atoi(devName + 4);
} else if (!strncmp(devName, "scd", 3)) {
type = S_IFBLK;
major = 11;
minor = atoi(devName + 3);
} else if (devName[0] == 'h' && devName[1] == 'd') {
type = S_IFBLK;
if (devName[2] == 'a')
major = 3, minor = 0;
else if (devName[2] == 'b')
major = 3, minor = 64;
else if (devName[2] == 'c')
major = 22, minor = 0;
else if (devName[2] == 'd')
major = 22, minor = 64;
else if (devName[2] == 'e')
major = 33, minor = 0;
else if (devName[2] == 'f')
major = 33, minor = 64;
else if (devName[2] == 'g')
major = 34, minor = 0;
else if (devName[2] == 'h')
major = 34, minor = 64;
else if (devName[2] == 'i')
major = 56, minor = 0;
else if (devName[2] == 'j')
major = 56, minor = 64;
else if (devName[2] == 'k')
major = 57, minor = 0;
else if (devName[2] == 'l')
major = 57, minor = 64;
else if (devName[2] == 'm')
major = 88, minor = 0;
else if (devName[2] == 'n')
major = 88, minor = 64;
else if (devName[2] == 'o')
major = 89, minor = 0;
else if (devName[2] == 'p')
major = 89, minor = 64;
else if (devName[2] == 'q')
major = 90, minor = 0;
else if (devName[2] == 'r')
major = 90, minor = 64;
else if (devName[2] == 's')
major = 91, minor = 0;
else if (devName[2] == 't')
major = 91, minor = 64;
else
return -1;
if (devName[3] && devName[4])
minor += (devName[3] - '0') * 10 + (devName[4] - '0');
else if (devName[3])
minor += (devName[3] - '0');
} else if (!strncmp(devName, "ram", 3)) {
type = S_IFBLK;
major = 1;
minor = 1;
if (devName[3])
minor += devName[3] - '1';
#if defined (__s390__) || defined (__s390x__)
} else if (!strncmp(devName, "dasd", 4) && strlen(devName) > 4) {
/* IBM Dasd Drives */
type = S_IFBLK;
major = 94;
minor = ( devName[4] - 'a' ) * 4;
if (devName[5] && isalpha(devName[5])) {
minor += 26 * 4 + ( devName[5] - 'a' ) * 4;
if (devName[6] && isdigit(devName[6]) )
minor += devName[6] - '0';
} else if (devName[5] && isdigit(devName[5])) {
minor += devName[5] - '0';
}
} else if (!strncmp(devName, "mnd", 4)) {
/* IBM MiniDisk Drives */
type = S_IFBLK;
major = 95;
minor = devName[3] - 'a';
#endif
} else if (!strncmp(devName, "rd/", 3)) {
/* dac 960 "/rd/c0d0{p1}" */
int c, d, p;
c = d = p = 0;
sscanf(devName + 3, "c%dd%dp%d", &c, &d, &p);
type = S_IFBLK;
major = 48 + c; /* controller */
minor = d * 8; /* disk */
minor += p; /* partition */
} else if (!strncmp(devName, "ida/", 4)) {
/* Compaq Smart Array "ida/c0d0{p1} */
int c, d, p;
c = d = p = 0;
sscanf(devName + 4, "c%dd%dp%d", &c, &d, &p);
type = S_IFBLK;
major = 72 + c; /* controller */
minor = d * 16; /* disk */
minor += p; /* partition */
} else if (!strncmp(devName, "cciss/", 6)) {
/* Compaq Smart Array 5300 "cciss/c0d0{p1} */
int c, d, p;
c = d = p = 0;
sscanf(devName + 6, "c%dd%dp%d", &c, &d, &p);
type = S_IFBLK;
major = 104 + c; /* controller */
minor = d * 16; /* disk */
minor += p; /* partition */
} else if (!strncmp(devName, "ataraid/", 8)) {
type = S_IFBLK;
major = 114; /* controller */
minor = (devName[9] - '0') * 16; /* disk */
if (strlen(devName) > 10) /* partition */
minor += atoi(devName + 11);
} else if (!strncmp(devName, "sx8/", 4)) {
/* Promise SX8 "sx8/0{p1} */
int d, p;
d = p = 0;
sscanf(devName + 4, "%dp%d", &d, &p);
type = S_IFBLK;
major = 160 + (d/8); /* controller */
minor = (d % 8) * 32; /* disk */
minor += p; /* partition */
} else if (!strncmp(devName, "i2o/", 4)) {
/* I2O Block Device "i2o/hda */
type = S_IFBLK;
major = 80; /* controller */
minor = (devName[6] - 'a')*16;
if ((devName[7]) && isdigit(devName[7]))
{
minor = minor + atoi(devName + 7);
}
} else if (!strncmp(devName, "iseries/vcd", 11)) {
/* IBM virtual cdrom (iseries) */
type = S_IFBLK;
major = 113;
minor = devName[11] - 'a';
} else if (!strncmp(devName, "iseries/vd", 10)) {
int drive = 0;
char * num = NULL;
/* IBM virtual disk (iseries) */
type = S_IFBLK;
major = 112;
if (devName[11] && isdigit(devName[11])) {
drive = devName[10] - 'a';
num = devName + 11;
} else if (devName[11] && islower(devName[11])) {
drive = ((devName[10] - 'a' + 1) * 26) + devName[11] - 'a';
num = devName + 12;
} else {
drive = devName[10] - 'a';
}
minor = (drive * 8);
if (num && num[0])
minor += (num[0] - '0');
} else {
for (i = 0; i < numDevices; i++) {
if (!strcmp(devices[i].name, devName)) break;
}
if (i == numDevices) return -1;
major = devices[i].major;
minor = devices[i].minor;
if (devices[i].isChar)
type = S_IFCHR;
else
type = S_IFBLK;
}
ptr = path;
i = 0;
while (*ptr)
if (*ptr++ == '/')
i++;
if (i > 2) {
dir = alloca(strlen(path) + 1);
strcpy(dir, path);
ptr = dir + (strlen(path) - 1);
while (*ptr != '/')
*ptr-- = '\0';
mkdir(dir, 0644);
}
unlink(path);
if (mknod(path, type | 0600, makedev(major, minor))) {
return -2;
}
return 0;
}
static int doPwMount(char * dev, char * where, char * fs, int rdonly, int istty,
char * acct, char * pw, int bindmnt, int remount) {
char * buf = NULL;
char * mount_opt = NULL;
long int flag;
char * chptr __attribute__ ((unused));
/*logMessage("mounting %s on %s as type %s", dev, where, fs);*/
if ((*dev == '/' || !strcmp(dev, "none"))) {
buf = dev;
} else {
buf = alloca(200);
strcpy(buf, "/tmp/");
strcat(buf, dev);
}
flag = MS_MGC_VAL;
if (rdonly)
flag |= MS_RDONLY;
if (bindmnt)
flag |= MS_BIND;
if (remount)
flag |= MS_REMOUNT;
if (!strncmp(fs, "vfat", 4))
mount_opt="check=relaxed";
#ifdef __sparc__
if (!strncmp(fs, "ufs", 3))
mount_opt="ufstype=sun";
#endif
/*logMessage("calling mount(%s, %s, %s, %ld, %p)", buf, where, fs,
flag, mount_opt);*/
if (mount(buf, where, fs, flag, mount_opt)) {
return IMOUNT_ERR_ERRNO;
}
return 0;
}
#define LIVECD_FILE ".livecd"
static int setupCdrom(char * location) {
int i, rc;
char * buf;
struct device ** devices = NULL;
devices = probeDevices(CLASS_CDROM, BUS_UNSPEC, PROBE_LOADED);
if (!devices) {
return 0;
}
for (i = 0; devices[i]; i++) {
if (!devices[i]->device) continue;
devMakeInode(devices[i]->device, "/tmp/cdrom");
if (!doPwMount("/tmp/cdrom", location, "iso9660", 1, 0,
NULL, NULL, 0, 0)) {
char path[1024];
snprintf(path, sizeof(path), "%s/"LIVECD_FILE, location);
if (!access(path, R_OK)) {
return 1;
}
/* this wasnt the CD we were looking for, clean up and */
/* try the next CD drive */
umount(location);
unlink("/tmp/cdrom");
}
}
return 0;
}
int main(int argc, char **argv)
{
int fd;
int worked;
char *location = "/mnt/source";
int livecd;
if (livecd = setupCdrom(location)) {
umount(location);
worked = EjectCdrom(fd);
}
}
--- NEW FILE i18n.h ---
/*
i18nized by: KUN-CHUNG, HSIEH <linuxer at coventive.com>
Taiwan
Homepage: http://www.geocities.com/linux4tw/
µ{¦¡°ê»Ú¤Æ³]p: Á±X¤¤
*/
#include <features.h>
#ifndef __i18n__
#define PKG "eject"
# ifndef __UCLIBC__
#define __i18n__
#define LOCALEDIR "/usr/share/locale"
#include <locale.h>
#include <libintl.h>
#define _(str) gettext (str)
#define N_(str) (str)
#define I18NCODE setlocale(LC_ALL,""); textdomain(PKG); bindtextdomain(PKG,LOCALEDIR);
#else
#define _(str) (str)
#define N_(str) (str)
#define I18NCODE
#endif
void i18n_init (void);
#endif
More information about the fedora-extras-commits
mailing list