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