/*
 * ziptool.c -- Linux tool for Iomega ZIP/JAZ drives, Version 1.4.0
 *
 * (c) 1996   ziptool  Grant R. Guenther (grant@torque.net),
 *                     based on work of Itai Nahshon
 * (c) 1996   jaztool  Bob Willmot (bwillmot@cnct.com)
 * (c) 1997   Mirko Kraft (Mirko.Kraft@ixos.de)
 * (cl) 1999  Aaron Segura <aaronsegura@netscape.net>
 *      - Mutilated Code to add -ld -m -u -ud options, and
 *        add jaz 2g Support.
 *	  09/24/99
 * (c) 2002   Tara Milana (learfox@furry.ao.net) - Fixed "mutilated
 *            code" and various other bugfixes.
 *
 *
 *
 * 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, 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.
 * 
 * To obtain a copy of the GNU General Public License please write to
 * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139,
 * USA.
 *
 *
 * For further Information see the README file.
 */


#include <sys/stat.h>
#include <errno.h>
#include <fcntl.h>
#include <mntent.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

#include <sys/ioctl.h>

#include <linux/fs.h>
#include <linux/major.h>

#include <scsi/scsi.h>
#include <scsi/scsi_ioctl.h>


#ifndef PROG_VERSION
# define PROG_VERSION			"1.4.0"
#endif

#ifndef MNTTYPE_AUTO
# define MNTTYPE_AUTO			"auto"
#endif

/* Patched kernels will have IOMEGA_*_PROT_MODE defined. */
#ifdef IOMEGA_GET_PROT_MODE
# define HAVE_KERNEL_PATCH		1
#else
# define IOMEGA_GET_PROT_MODE		0x06
# define IOMEGA_SET_PROT_MODE		0x0c
#endif

#define IOMEGA_MAX_PASSWORD_LENGTH	33

#define IOMEGA_GET_PROTECTION_MODE	IOMEGA_GET_PROT_MODE	/* see scsi.h    */
#define IOMEGA_SET_PROTECTION_MODE	IOMEGA_SET_PROT_MODE	/* see scsi.h    */

#define IOMEGA_PROTECTION_MODE_RW	0x00	/* no protection                 */
#define IOMEGA_PROTECTION_MODE_RO	0x02	/* write-protected               */
#define IOMEGA_PROTECTION_MODE_ROPW	0x03	/* password write-protected      */
#define IOMEGA_PROTECTION_MODE_PASS	0x05	/* password read/write-protected */

#define SPIN_STOP			0x01
#define SPIN_EJECT			0x02

#define MOUNT_DISK			0x01	/* ams */
#define UMOUNT_DISK			0x02	/* ams */
#define MOUNT_CMD			"/bin/mount"
#define UMOUNT_CMD			"/bin/umount"

/*
 *	Model list, last entry must be a NULL pointer. Casing is
 *	insensitive.
 */
static char *jaz_models[] = {
	"iomega  jaz 1gb",
	"iomega  jaz 2gb",	/* ams */
	NULL
};

static char *zip_models[] = {
	"Iomega  ZIP 100",
	NULL
};


/*
 *	SCSI command structure.
 */
static struct sdata {
	int  inlen;
	int  outlen;
	char cmd[256];
} scsi_cmd;

static char	**model_list;
static char	*progname;
static int	mounted = 0;

static int jazip_check_dev(char *dev);
static int jazip_ctrldoor(
        int jazipfd,
        int door_mode   /* SCSI_REMOVAL_ALLOW or SCSI_REMOVAL_PREVENT */
);
static int jazip_ctrlspin(
        int jazipfd,
        int spin_mode   /* SPIN_EJECT or SPIN_STOP */
);
static int jazip_display_mode(int jazipfd);	/* Display media protection. */
static int jazip_eject(int jazipfd);
static int jazip_get_mode(int jazipfd);
static int jazip_get_password(
        const char *prompt, char *buf, int maxlen
);
static int jazip_set_mode(
        int jazipfd,
        int mode        /* IOMEGA_PROTECTION_MODE_RO,
                         * IOMEGA_PROTECTION_MODE_ROPW, or
                         * IOMEGA_PROTECTION_MODE_RW
                         */
);
static void jazip_usage(const char *progname);
static int jazip_ctrlmount(
        int jazipfd,
        int oper,       /* MOUNT_DISK or UMOUNT_DISK */
        char *dev,      /* Device path. */
        char *mnt       /* Mount path. */
);


/*
 *	Mount/unmount, door will be locked on successful mount.
 *
 *	Returns:
 *
 *	0	Success
 *	-1	General error
 */
static int jazip_ctrlmount(
	int jazipfd,
	int oper,	/* MOUNT_DISK or UMOUNT_DISK */
	char *dev,	/* Device path. */
	char *mnt	/* Mount path. */
)
{
	int result;
	char cmd[255];

	*cmd = '\0';

	/* Generate command for mounting or unmounting. */
	switch(oper)
	{
		case MOUNT_DISK:
/* Skip the device and all the options, Linux now allows
 * users to mount assuming /etc/fstab is set up properly
 * (and it must be set up properly anyways, so rely on it).
 */
/*
			strncpy(cmd, MOUNT_CMD, strlen(MOUNT_CMD) + 1);
			strncat(cmd, " -t ext2 ", 9);
			strncat(cmd, dev, strlen(dev) + 1);
			strncat(cmd, " ", 1);
			strncat(cmd, mnt, strlen(mnt) + 1);
 */
                        strncpy(cmd, MOUNT_CMD, strlen(MOUNT_CMD) + 1);
			strncat(cmd, " ", 1);
                        strncat(cmd, mnt, strlen(mnt) + 1);
			break;
		
		case UMOUNT_DISK:	
			jazip_ctrldoor(jazipfd, SCSI_REMOVAL_ALLOW);
/*
			strncpy(cmd, UMOUNT_CMD, strlen(UMOUNT_CMD) + 1);
			strncat(cmd, " ", 1);
			strncat(cmd, dev, strlen(dev));
 */
			/* Note that mnt may be NULL in this case. */
                        strncpy(cmd, UMOUNT_CMD, strlen(UMOUNT_CMD) + 1);
                        strncat(cmd, " ", 1);
                        strncat(cmd, dev, strlen(dev));
			break;
	}

	/* Execute mount or unmount command. */
	result = system(cmd);
	if(result == 0)
	{
		if(oper == MOUNT_DISK)
			jazip_ctrldoor(jazipfd, SCSI_REMOVAL_PREVENT);
	}

	return(result);
}


/*
 *	Checks if the given device dev is actually a ZIP or JAZ drive.
 *
 *	Returns:
 *
 *	fd	File descriptor to ZIP/JAZ device on success
 *	-1	General error
 */
static int jazip_check_dev(char *dev)
{
	FILE		*mtab_fp;
	char		mounts[255];
	char		**model;
	char		scsi_signature[25];
	int		i, jazipfd;

	/* Check to see if the device is mounted by reading
	 * /etc/mtab
	 */
	if(!(mtab_fp = fopen("/etc/mtab", "r")))
	{
		perror("Opening /etc/mtab");
		exit(1);
	}

	while(!feof(mtab_fp))
	{
		fgets(mounts, 254, mtab_fp);
		if(strstr(mounts, dev))
		{
			mounted = 1;
		}
	}
	fclose(mtab_fp);


	/* Now open the device and read its model signature. Check if
	 * it is the one that we expect.
	 */
	if((jazipfd = open(dev, O_RDONLY)) < 0)
	{
		(void)fprintf(
			stderr,
			"%s: Cannot open %s: %s.\n",
			progname, dev, strerror(errno)
		);
		return(-1);
	}

	scsi_cmd.inlen  = 0;
	scsi_cmd.outlen = 40;
	scsi_cmd.cmd[0] = (char)INQUIRY;
	scsi_cmd.cmd[1] = (char)0;
	scsi_cmd.cmd[2] = (char)0;
	scsi_cmd.cmd[3] = (char)0;
	scsi_cmd.cmd[4] = (char)40;
	scsi_cmd.cmd[5] = (char)0;

	if(ioctl(jazipfd, SCSI_IOCTL_SEND_COMMAND, (void *)&scsi_cmd))
	{
		(void)fprintf(
			stderr,
			"%s: Cannot read scsi model signature "
			"from %s: %s.\n",
			progname, dev, strerror(errno)
		);
		(void)close(jazipfd);
		return(-1);
	}

	for(i = 0; i < 24; i++)
		scsi_signature[i] = scsi_cmd.cmd[i + 8];
	scsi_signature[24] = 0;

	for(model = model_list; *model != NULL; ++model)
	{
		if(!strncasecmp(scsi_signature, *model, strlen(*model)))
			return(jazipfd);
	}

	(void)fprintf(
		stderr,
		"%s: Model '%s' is not supported.\n",
		progname, scsi_signature
	);

	(void)close(jazipfd);
	return(-1);
}


/*
 *	Lock or unlock the drive door.
 *
 *	If door_mode is SCSI_REMOVAL_ALLOW, then the device's door
 *	will be unlocked so that the media can be removed.
 *
 *	If door_mode is SCSI_REMOVAL_PREVENT, then the device's door
 *	will be locked so that the media cannot be removed.
 *
 *	Note that for the ZIP drives, this means that the eject button
 *	on the actual device will not respond.
 *
 *	Returns:
 *
 *	0	Success
 *	-1	General error
 */
static int jazip_ctrldoor(
	int jazipfd,
	int door_mode	/* SCSI_REMOVAL_ALLOW or SCSI_REMOVAL_PREVENT */
)
{
	switch(door_mode)
	{
	    case SCSI_REMOVAL_ALLOW:
	    case SCSI_REMOVAL_PREVENT:
		scsi_cmd.inlen  = 0;
		scsi_cmd.outlen = 0;
		scsi_cmd.cmd[0] = (char)ALLOW_MEDIUM_REMOVAL;
		scsi_cmd.cmd[1] = (char)0;
		scsi_cmd.cmd[2] = (char)0;
		scsi_cmd.cmd[3] = (char)0;
		scsi_cmd.cmd[4] = (char)door_mode;
		scsi_cmd.cmd[5] = (char)0;

		return(ioctl(
			jazipfd, SCSI_IOCTL_SEND_COMMAND,
			(void *)&scsi_cmd)
		);
	}

	return(-1);
}


/*
 *	Spins down the device or ejects the media.
 *
 *	If spin_mode is SPIN_EJECT, then the media will be ejected.
 *	It is unknown why ejecting the media is controlled by 
 *	START_STOP.
 *
 *	If spin_mode is SPIN_STOP, then the device will be spinned
 *	down.
 *
 *	Returns:
 *
 *	0	Success
 *	-1	General error
 */
static int jazip_ctrlspin(
	int jazipfd,
	int spin_mode	/* SPIN_EJECT or SPIN_STOP */
)
{
	switch(spin_mode)
	{
	    case SPIN_EJECT:
	    case SPIN_STOP:
		scsi_cmd.inlen  = 0;
		scsi_cmd.outlen = 0;
		scsi_cmd.cmd[0] = (char)START_STOP;
		scsi_cmd.cmd[1] = (char)0;
		scsi_cmd.cmd[2] = (char)0;
		scsi_cmd.cmd[3] = (char)0;
		scsi_cmd.cmd[4] = (char)spin_mode;
		scsi_cmd.cmd[5] = (char)0;

		return(ioctl(
			jazipfd, SCSI_IOCTL_SEND_COMMAND,
			(void *)&scsi_cmd)
		);
	}

	return(-1);
}


/*
 *	Prints the media's protection status, if it is protected,
 *	password protected, or unprotected.
 *
 *	Returns:
 *
 *	0	Success
 *	-1	General error
 */
static int jazip_display_mode(int jazipfd)
{
	int mode;


	if((mode = jazip_get_mode(jazipfd)) < 0)
	{
		(void)fprintf(
			stderr,
			"%s: reading current protection mode "
			"failed.\n", progname
		);
		return(-1);
	}

	/* Iomega offers more modes than we can handle (e.g. this
	 * infamous read and write password protected mode). So if we
	 * have an unsupported mode just it's decimal number is reported.
	 */
	switch(mode)
	{
	    case IOMEGA_PROTECTION_MODE_RW:
		(void)printf(
			"%s: Media is not protected.\n",
			progname
		);
		break;
	    case IOMEGA_PROTECTION_MODE_RO:
		(void)printf(
			"%s: Media is write-protected.\n",
			progname
		);
		break;
	    case IOMEGA_PROTECTION_MODE_ROPW:
		(void)printf(
			"%s: Media is password write-protected.\n",
			progname
		);
		break;
	    default:
		(void)fprintf(
			stderr,
			"%s: Current protection mode %d is not supported.\n",
			progname, mode
		);
		break;
	}

	return(0);
}


/*
 *	Unlocks the drive door, spins down the device, and ejects
 *	the media.
 *
 *	Returns:
 *
 *	0	Success
 *	-1	General error
 */
static int jazip_eject(int jazipfd)
{
	/* Unlock drive door. */
	if(jazip_ctrldoor(jazipfd, SCSI_REMOVAL_ALLOW))
	{
		(void)fprintf(
			stderr,
			"%s: Cannot unlock drive door.\n",
			progname
		);
		return(-1);
	}

	/* Spin down drive. */
	if(jazip_ctrlspin(jazipfd, SPIN_STOP))
	{
		(void)fprintf(
			stderr,
			"%s: Cannot spin down drive.\n",
			progname
		);
		return(-1);
	}

	/* Eject media. */
	if(jazip_ctrlspin(jazipfd, SPIN_EJECT))
	{
		(void)fprintf(
			stderr,
			"%s: Cannot eject media.\n",
			progname
		);
		return(-1);
	}

	return(0);
}


/*
 *	Returns the protection mode or -1 on error.
 */
static int jazip_get_mode(int jazipfd)
{
	scsi_cmd.inlen  = 0;
	scsi_cmd.outlen = 256;
	scsi_cmd.cmd[0] = (char)IOMEGA_GET_PROTECTION_MODE;
	scsi_cmd.cmd[1] = (char)0;
	scsi_cmd.cmd[2] = (char)2;
	scsi_cmd.cmd[3] = (char)0;
	scsi_cmd.cmd[4] = (char)128;
	scsi_cmd.cmd[5] = (char)0;

	if(ioctl(jazipfd, SCSI_IOCTL_SEND_COMMAND, (void *)&scsi_cmd))
		return(-1);

	return((int)(scsi_cmd.cmd[21] & 0x0f));
}


/*
 *	Querys stdin stream for password.
 *
 *	First a prompt is sent to stdout, then waits for stdin
 *	to receive a newline terminated string which will be coppied
 *	to the given buffer buf with no more than maxlen characters.
 *
 *	Returns the password length on success or -1 on error.
 */
static int jazip_get_password(
	const char *prompt, char *buf, int maxlen
)
{
	int len;

	/* Send prompt to stdout, then wait for input from stdin.
	 * Keep reading from stdin until a newline '\n' character
	 * is received.
	 */
	(void)printf(prompt);
	(void)fflush(stdout);

	*buf = '\0';
	if(fgets(buf, maxlen, stdin) == NULL)
		return(-1);

	if((len = strlen(buf)) > 0)
	{
		if(*(buf + len - 1) == '\n')
		{
			*(buf + len - 1) = '\0';
			--len;
		}
		else if(len == (maxlen - 1))
		{
			while(fgetc(stdin) != (int)'\n');
		}
	}

	return(len);
}


/*
 *	Sets the protection mode on the media.
 *
 *	If mode is IOMEGA_PROTECTION_MODE_RO, then the media will
 *	be locked in read-only mode.
 *
 *	If mode is IOMEGA_PROTECTION_MODE_ROPW, then the media will
 *	be locked in read-only mode with a password protection.
 *
 *	If mode is IOMEGA_PROTECTION_MODE_RW, then the media will
 *	be unlocked (as needed) and returned to normal read/write
 *	mode.
 *
 *	Returns the protection mode on success or -1 on error.
 */
static int jazip_set_mode(
	int jazipfd,
	int mode	/* IOMEGA_PROTECTION_MODE_RO,
			 * IOMEGA_PROTECTION_MODE_ROPW, or
			 * IOMEGA_PROTECTION_MODE_RW
			 */
)
{
	char	password[IOMEGA_MAX_PASSWORD_LENGTH + 1];
	int	i, len, oldmode;


	/* Get the current mode. */
	switch(oldmode = jazip_get_mode (jazipfd))
	{
	    /* The media is currently password write-protected.
	     * Further actions depend from the new mode.
	     */
	    case IOMEGA_PROTECTION_MODE_ROPW:
		switch(mode)
		{
/*
 * A big TODO here:
 * The new mode is also password write-protected. This is equivalent
 * to a password change.
 *
 * AT THE MOMENT I DON'T KNOW HOW A PASSWORD CHANGE IS DONE, I.E. IF
 * THERE IS A SEPERATE SCSI COMMAND OR IF IT IS DONE BY SWITCHING
 * MODES FROM P/W WRITE-PROTECTED TO NOT OR WRITE PROTECTED AND THEN
 * BACK TO P/W WRITE-PROTECTED. SO THIS FEATURE IS CURRENTLY NOT
 * SUPPORTED.
 */
		    case IOMEGA_PROTECTION_MODE_ROPW:
			(void)fprintf(
				stderr, "%s: sorry. changing password is "
				"currently not supported.\n",
				progname
			);
			return(-1);
			break;

		    /* The new mode is normal write-protected or
		     * unprotected. Prompt for the password and then
		     * add it to the SCSI command.
		     */
		    case IOMEGA_PROTECTION_MODE_RO:
		    case IOMEGA_PROTECTION_MODE_RW:
			if((len = jazip_get_password("Password: ", password,
				IOMEGA_MAX_PASSWORD_LENGTH + 1)) < 0
			)
			{
				(void)fprintf(
					stderr,
					"%s: reading password failed.\n",
					progname
				);
				return(-1);
			}
			for(i = 0; i < len; i++)
				scsi_cmd.cmd[6 + i] = password[i];
			break;

		    /* An unsupported new mode was specified. */
		    default:
			(void)fprintf(
				stderr,
				"%s: sorry. setting protection to "
				"mode %d is not supported.\n",
				progname, mode
			);
			return(-1);
			break;
		}
		break;

	    /* The media is currently normal write-protected or
	     * unprotected. Further actions depend from the new mode.
	     */
	    case IOMEGA_PROTECTION_MODE_RO:
	    case IOMEGA_PROTECTION_MODE_RW:
		switch(mode)
		{
		    /* The new mode is password write-protected.
		     * Prompt for a password and then add it to the
		     * SCSI command.
		     */
		    case IOMEGA_PROTECTION_MODE_ROPW:
			if((len = jazip_get_password ("Password: ", password,
				IOMEGA_MAX_PASSWORD_LENGTH + 1)) < 0
			)
			{
				(void)fprintf(
					stderr,
					"%s: reading password failed.\n",
					progname
				);
				return(-1);
			}
			for(i = 0; i < len; i++)
				scsi_cmd.cmd[6 + i] = password[i];
			break;

		    /* The new mode is normal write-protected or
		     * unprotected. Nothing needs to be done here.
		     */
		    case IOMEGA_PROTECTION_MODE_RO:
		    case IOMEGA_PROTECTION_MODE_RW:
			len = 0;
			break;

		    /* An unsupported new mode was specified. */
		    default:
			(void)fprintf(
				stderr,
				"%s: sorry. setting protection to "
				"mode %d is not supported.\n",
				progname, mode
			);
			return(-1);
			break;
		}
		break;

	    /* Something went wrong when getting the current
	     * protection mode.
	     */
	    case -1:
		(void)fprintf(
			stderr,
			"%s: reading current protection mode "
			"failed.\n",
			progname
		);
		return(-1);
		break;

	    /* The current protection mode of the media is one that
	     * is not (yet) supported by this tool.
	     */
	    default:
		(void)fprintf(
			stderr,
			"%s: current protection mode %d is "
			"unsupported.\n",
			progname, oldmode
		);
		return(-1);
		break;
	}

	/* Set the new mode. */
	scsi_cmd.inlen  = len;
	scsi_cmd.outlen = 0;
	scsi_cmd.cmd[0] = (char)IOMEGA_SET_PROTECTION_MODE;
	scsi_cmd.cmd[1] = (char)mode;
	scsi_cmd.cmd[2] = (char)0;
	scsi_cmd.cmd[3] = (char)0;
	scsi_cmd.cmd[4] = (char)len;
	scsi_cmd.cmd[5] = (char)0;

	if(ioctl(jazipfd, SCSI_IOCTL_SEND_COMMAND, (void *)&scsi_cmd))
	{
		(void)fprintf(
			stderr,
			"%s: Cannot set protection mode to %d.\n",
			progname, mode
		);
		return(-1);
	}

	/* Verify the new mode. If we found an unpatched kernel, we
	 * must eject the media afterwards to ensure the kernel
	 * recognizes the new protection mode.
	 */
	(void)jazip_display_mode(jazipfd);

#ifndef HAVE_KERNEL_PATCH
#if 0
/* Linux 2.2.15 and later seem to recognize when the protection mode
 * on the media has been updated, so even if we do not have the
 * kernel patch, Linux knows about the update.
 */
	if(jazip_eject(jazipfd))
	{
		(void)fprintf(
			stderr,
			"%s: Kernel: Please eject media manually.\n",
			progname
		);
		return(-1);
	}
#endif
#endif
	return(0);
}


/*
 *	Prints the usage, with progname prefixed as this program's name.
 */
static void jazip_usage(const char *progname)
{
	(void)fprintf(
/*		stderr,	*/
		stdout,		/* Should send this to stdout! */
"usage: %s -e  <dev>        Eject media.\n"
"       %s -p  <dev>        Spin down drive.\n"
"       %s -s  <dev>        Print media protection status.\n"
"       %s -ro <dev>        Set media protection to read only.\n"
"       %s -rp <dev>        Set media protection to read only with password.\n"
"       %s -rw <dev>        Set media protection to read and write.\n"
"       %s -ld <dev>        Lock the door on the drive (must be mounted!).\n"
"       %s -ud <dev>        Unlock the door on the drive.\n"
"       %s -m  <dev> <dir>  Mounts the <dev> on <dir> and locks the door.\n"
"       %s -u  <dev>        Unmounts the <dev>.\n"
"       %s --help           Prints (this) help message and exits.\n"
"       %s --version        Prints version information and exits.\n"
"\n",
		progname, progname, progname, progname, progname,
		progname, progname, progname, progname, progname,
		progname, progname
	);
}


int main(int argc, char *argv[])
{
/*	char	partition[10]; */
	char	*ptr;
	int	result = 1;
	int	jazipfd;


	/* Check how we are called by examining the program's name.
	 * Currently "ziptool" and "jaztool" are supported. The name
	 * determines what type of device we are looking for.
	 */
	if((ptr = strrchr (argv[0], '/')) != NULL)
		progname = ptr + 1;
	else
		progname = argv[0];

	if(!strcmp(progname, "jaztool"))
	{
		model_list = jaz_models;
	}
	else if(!strcmp(progname, "ziptool"))
	{
		model_list = zip_models;
	}
	else
	{
		jazip_usage("ziptool");
		jazip_usage("jaztool");
		exit(1);
	}

	/* Check for --help and --version arguments first. */
	if(argc >= 2)
	{
		const char *arg_ptr = argv[1];

		if(!strcmp(arg_ptr, "--help") ||
		   !strcmp(arg_ptr, "-help") ||
		   !strcmp(arg_ptr, "--h") ||
		   !strcmp(arg_ptr, "-h") ||
		   !strcmp(arg_ptr, "-?")
		)
		{
			jazip_usage(progname);
			return(0);
		}
		else if(!strcmp(arg_ptr, "--version") ||
                        !strcmp(arg_ptr, "-version")
                )
                {
                        printf(
				"%s %s\n",
				progname, PROG_VERSION
			);
                        return(0);
                }
	}

	/* Check parameters and call appropriate functions. Supported
	 * parameters are:
	 *
	 *	-e	Eject media.
	 *	-p	Spin down drive.
	 *	-s	Get protection status of current media.
	 *	-ro	Set normal write-protected mode.
	 *	-rp	Set password write-protected mode.
	 *	-rw	Remove any protection.
	 *	-ld	Lock the door on a mounted drive.
	 *	-ud	Unlock the door.
	 *	-m	Mount and automatically lock the media (takes
	 *		additional parameters).
	 *	-u	Umount (takes additional parameters).
	 */

	/* Got atleast 2 arguments? */
	if(argc >= 3)
	{
		if((jazipfd = jazip_check_dev(argv[2])) >= 0)
		{
			if(!strcmp(argv[1], "-e"))
			{
				if(!mounted)
					result = jazip_eject(jazipfd);
				else 
					printf("Device is mounted.\n");
			}
                        else if(!strcmp(argv[1], "-p"))
                        {
				result = jazip_ctrlspin(jazipfd, SPIN_STOP);
				if(result)
					(void)fprintf(
						stderr,
						"%s: Cannot spin down drive.\n",
						progname
					);
                        }
			else if(!strcmp(argv[1], "-s"))
			{
				result = jazip_display_mode(jazipfd);
			}
			else if(!strcmp(argv[1], "-ro"))
			{
				if(!mounted)
					result = jazip_set_mode(jazipfd, IOMEGA_PROTECTION_MODE_RO);
				else
					printf("Device is mounted.\n");
			}
			else if(!strcmp(argv[1], "-rp"))
			{
				if(!mounted)
					result = jazip_set_mode(jazipfd, IOMEGA_PROTECTION_MODE_ROPW);
				else
					printf("Device is mounted.\n");
			}
			else if(!strcmp(argv[1], "-rw"))
			{
				if(!mounted)
					result = jazip_set_mode(jazipfd, IOMEGA_PROTECTION_MODE_RW);
				else
					printf("Device is mounted.\n");
			}
			else if(!strcmp(argv[1], "-ld"))
			{
				if(!mounted)
					printf("Device isn't mounted.\n");
				else
					result = jazip_ctrldoor(jazipfd, SCSI_REMOVAL_PREVENT);
			}
			else if(!strcmp(argv[1], "-ud"))
			{
				if(!mounted)
					printf("Device isn't Locked.\n");
				else
					result = jazip_ctrldoor(jazipfd, SCSI_REMOVAL_ALLOW);
			}
			else if((!strcmp(argv[1], "-m")) && (argc >= 4))
			{
				printf("Mounting %s on %s\n", argv[2], argv[3]);
				result = jazip_ctrlmount(
				    jazipfd, MOUNT_DISK,
				    argv[2], argv[3]
				);
			}
			else if((!strcmp(argv[1], "-u")) && (argc >= 3))
			{
				result = jazip_ctrlmount(
				    jazipfd, UMOUNT_DISK,
				    argv[2],
				    (argc >= 4) ? argv[3] : NULL
				);
			}
			else
			{
				jazip_usage (progname);
			}
			(void)close(jazipfd);
		}
	}
	else
	{
		jazip_usage(progname);
	}

	exit(abs(result));
}
