/*-
* Copyright (c) 1999 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Chris Jones.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include <sys/cdefs.h>
#ifndef lint
__COPYRIGHT("@(#) Copyright (c) 1999\
The NetBSD Foundation, Inc. All rights reserved.");
#endif /* not lint */
int
main(int argc, char *argv[])
{
int ch;
int devtype;
size_t n;
char *dev_name; /* XXX - devname is declared in stdlib.h */
enum eject_op op;
devtype = -1;
dev_name = NULL;
op = OP_EJECT;
while ((ch = getopt(argc, argv, "d:flLnt:Uv")) != -1) {
switch (ch) {
case 'd':
dev_name = optarg;
break;
case 'f':
umount_f = 0;
break;
case 'l':
if (op != OP_EJECT)
usage();
op = OP_LOAD;
break;
case 'L':
if (op != OP_EJECT)
usage();
op = OP_LOCK;
break;
case 'n':
for (n = 0; n < __arraycount(nicknames); n++) {
struct nicknames_s *np = &nicknames[n];
(void)printf("%s -> %s\n",
np->name, nick2dev(np->name));
}
return 0;
case 't':
for (n = 0; n < __arraycount(devtypes); n++) {
if (strcasecmp(devtypes[n].name, optarg)
== 0) {
devtype = devtypes[n].type;
break;
}
}
if (devtype == -1)
errx(1, "%s: unknown device type", optarg);
break;
case 'U':
if (op != OP_EJECT)
usage();
op = OP_UNLOCK;
break;
case 'v':
verbose_f = 1;
break;
default:
usage();
/* NOTREACHED */
}
}
argc -= optind;
argv += optind;
if (dev_name == NULL) {
if (argc == 0)
usage();
else
dev_name = argv[0];
}
if (devtype == -1)
devtype = guess_devtype(dev_name);
if (devtype == -1)
errx(1, "%s: unable to determine type of device", dev_name);
if (verbose_f) {
(void)printf("device type == ");
if ((devtype & TYPEMASK) == TAPE)
(void)printf("tape\n");
else
(void)printf("disk, floppy, or cdrom\n");
}
if (umount_f)
unmount_dev(dev_name);
/* XXX Tapes and disks have different ioctl's: */
if ((devtype & TYPEMASK) == TAPE)
eject_tape(dev_name, op);
else
eject_disk(dev_name, op);
static int
guess_devtype(const char *dev_name)
{
size_t n;
/* Nickname match: */
for (n = 0; n < __arraycount(nicknames); n++) {
if (strncasecmp(nicknames[n].name, dev_name,
strlen(nicknames[n].name)) == 0)
return nicknames[n].type;
}
/*
* If we still don't know it, then try to compare vs. dev and
* rdev names that we know.
*/
/* dev first: */
for (n = 0; n < __arraycount(nicknames); n++) {
char *name;
name = nick2dev(nicknames[n].name);
/*
* Assume that the part of the name that distinguishes
* the instance of this device begins with a 0.
*/
*(strchr(name, '0')) = '\0';
if (strncmp(name, dev_name, strlen(name)) == 0)
return nicknames[n].type;
}
/* Now rdev: */
for (n = 0; n < __arraycount(nicknames); n++) {
char *name = nick2rdev(nicknames[n].name);
*(strchr(name, '0')) = '\0';
if (strncmp(name, dev_name, strlen(name)) == 0)
return nicknames[n].type;
}
/* Not found. */
return -1;
}
/* "floppy5" -> "/dev/fd5a". Yep, this uses a static buffer. */
static char *
nick2dev(const char *nn)
{
static char dev_name[MAXDEVLEN];
size_t n;
int devnum;
/* Unmount all filesystems attached to dev. */
static void
unmount_dev(const char *name)
{
struct statvfs *mounts;
size_t len;
int i, nmnts;
const char *dn;
nmnts = getmntinfo(&mounts, MNT_NOWAIT);
if (nmnts == 0)
err(1, "getmntinfo");
/* Make sure we have a device name: */
dn = nick2dev(name);
if (dn == NULL)
dn = name;
/* Set len to strip off the partition name: */
len = strlen(dn);
if (!isdigit((unsigned char)dn[len - 1]))
len--;
if (!isdigit((unsigned char)dn[len - 1]))
errx(1, "Can't figure out base name for dev name %s", dn);
for (i = 0; i < nmnts; i++) {
if (strncmp(mounts[i].f_mntfromname, dn, len) == 0) {
if (verbose_f)
(void)printf("Unmounting %s from %s...\n",
mounts[i].f_mntfromname,
mounts[i].f_mntonname);