Home | History | Annotate | Line # | Download | only in eject
eject.c revision 1.26.6.1
      1  1.26.6.1      yamt /*	$NetBSD: eject.c,v 1.26.6.1 2012/10/30 19:00:16 yamt Exp $	*/
      2       1.8      tron 
      3       1.8      tron /*-
      4       1.8      tron  * Copyright (c) 1999 The NetBSD Foundation, Inc.
      5       1.8      tron  * All rights reserved.
      6       1.8      tron  *
      7       1.8      tron  * This code is derived from software contributed to The NetBSD Foundation
      8       1.8      tron  * by Chris Jones.
      9       1.2        pk  *
     10       1.2        pk  * Redistribution and use in source and binary forms, with or without
     11       1.2        pk  * modification, are permitted provided that the following conditions
     12       1.2        pk  * are met:
     13       1.2        pk  * 1. Redistributions of source code must retain the above copyright
     14       1.2        pk  *    notice, this list of conditions and the following disclaimer.
     15       1.2        pk  * 2. Redistributions in binary form must reproduce the above copyright
     16       1.2        pk  *    notice, this list of conditions and the following disclaimer in the
     17       1.2        pk  *    documentation and/or other materials provided with the distribution.
     18       1.2        pk  *
     19       1.8      tron  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     20       1.8      tron  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     21       1.8      tron  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     22      1.15     bjh21  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     23       1.8      tron  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     24       1.8      tron  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     25       1.8      tron  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     26       1.8      tron  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     27       1.8      tron  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     28       1.8      tron  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     29       1.8      tron  * POSSIBILITY OF SUCH DAMAGE.
     30       1.2        pk  */
     31       1.2        pk 
     32       1.8      tron #include <sys/cdefs.h>
     33       1.8      tron #ifndef lint
     34      1.22     lukem __COPYRIGHT("@(#) Copyright (c) 1999\
     35      1.22     lukem  The NetBSD Foundation, Inc.  All rights reserved.");
     36      1.15     bjh21 #endif				/* not lint */
     37       1.9       cjs 
     38       1.9       cjs #ifndef lint
     39  1.26.6.1      yamt __RCSID("$NetBSD: eject.c,v 1.26.6.1 2012/10/30 19:00:16 yamt Exp $");
     40      1.15     bjh21 #endif				/* not lint */
     41       1.8      tron 
     42      1.14        ad #include <sys/types.h>
     43      1.14        ad #include <sys/cdio.h>
     44      1.14        ad #include <sys/disklabel.h>
     45      1.14        ad #include <sys/ioctl.h>
     46      1.14        ad #include <sys/param.h>
     47      1.14        ad #include <sys/ucred.h>
     48      1.14        ad #include <sys/mount.h>
     49      1.14        ad #include <sys/mtio.h>
     50      1.14        ad 
     51       1.8      tron #include <ctype.h>
     52       1.8      tron #include <err.h>
     53       1.8      tron #include <fcntl.h>
     54       1.8      tron #include <stdio.h>
     55       1.8      tron #include <stdlib.h>
     56       1.8      tron #include <string.h>
     57       1.8      tron #include <unistd.h>
     58      1.14        ad #include <util.h>
     59       1.8      tron 
     60      1.25  christos #ifdef AMD_SUPPORT
     61      1.25  christos # include "am_glue.h"
     62      1.25  christos #endif
     63      1.25  christos 
     64       1.8      tron struct nicknames_s {
     65      1.23  christos 	const char *name;	/* The name given on the command line. */
     66      1.23  christos 	const char *devname;	/* The base name of the device */
     67      1.15     bjh21 	int type;		/* The type of device, for determining what
     68      1.15     bjh21 				 * ioctl to use. */
     69      1.23  christos # define TAPE 0x10
     70      1.23  christos # define DISK 0x20
     71      1.15     bjh21 	/* OR one of the above with one of the below: */
     72      1.23  christos # define NOTLOADABLE 0x00
     73      1.23  christos # define LOADABLE 0x01
     74      1.23  christos # define FLOPPY 0x2
     75      1.23  christos # define TYPEMASK ((int)~0x01)
     76      1.23  christos } nicknames[] = {
     77  1.26.6.1      yamt 	{ "diskette", "fd",   DISK | FLOPPY | NOTLOADABLE },
     78  1.26.6.1      yamt 	{ "floppy",   "fd",   DISK | FLOPPY | NOTLOADABLE },
     79  1.26.6.1      yamt 	{ "fd",       "fd",   DISK | FLOPPY | NOTLOADABLE },
     80  1.26.6.1      yamt 	{ "sd",       "sd",   DISK | NOTLOADABLE },
     81  1.26.6.1      yamt 	{ "cdrom",    "cd",   DISK | LOADABLE },
     82  1.26.6.1      yamt 	{ "cd",       "cd",   DISK | LOADABLE },
     83  1.26.6.1      yamt 	{ "racd",     "racd", DISK | LOADABLE },
     84  1.26.6.1      yamt 	{ "cdr",      "cd",   DISK | LOADABLE },
     85  1.26.6.1      yamt 	{ "cdrw",     "cd",   DISK | LOADABLE },
     86  1.26.6.1      yamt 	{ "dvdrom",   "cd",   DISK | LOADABLE },
     87  1.26.6.1      yamt 	{ "dvd",      "cd",   DISK | LOADABLE },
     88  1.26.6.1      yamt 	{ "dvdr",     "cd",   DISK | LOADABLE },
     89  1.26.6.1      yamt 	{ "dvdrw",    "cd",   DISK | LOADABLE },
     90  1.26.6.1      yamt 	{ "mcd",      "mcd",  DISK | LOADABLE },	/* XXX Is this true? */
     91  1.26.6.1      yamt 	{ "tape",     "st",   TAPE | NOTLOADABLE },
     92  1.26.6.1      yamt 	{ "st",       "st",   TAPE | NOTLOADABLE },
     93  1.26.6.1      yamt 	{ "dat",      "st",   TAPE | NOTLOADABLE },
     94  1.26.6.1      yamt 	{ "exabyte",  "st",   TAPE | NOTLOADABLE }
     95       1.8      tron };
     96      1.15     bjh21 #define MAXNICKLEN 12		/* at least enough room for the longest
     97      1.15     bjh21 				 * nickname */
     98      1.15     bjh21 #define MAXDEVLEN (MAXNICKLEN + 7)	/* "/dev/r" ... "a" */
     99       1.8      tron 
    100       1.8      tron struct devtypes_s {
    101      1.23  christos 	const char *name;
    102      1.15     bjh21 	int type;
    103      1.23  christos } devtypes[] = {
    104      1.15     bjh21 	{ "diskette", DISK | NOTLOADABLE },
    105      1.23  christos 	{ "floppy",   DISK | NOTLOADABLE },
    106      1.23  christos 	{ "cdrom",    DISK | LOADABLE },
    107      1.23  christos 	{ "disk",     DISK | NOTLOADABLE },
    108      1.23  christos 	{ "tape",     TAPE | NOTLOADABLE }
    109       1.8      tron };
    110       1.8      tron 
    111      1.16     bjh21 enum eject_op {
    112      1.16     bjh21 	OP_EJECT, OP_LOAD, OP_LOCK, OP_UNLOCK
    113      1.16     bjh21 };
    114      1.16     bjh21 
    115       1.8      tron int verbose_f = 0;
    116       1.8      tron int umount_f = 1;
    117       1.8      tron 
    118      1.15     bjh21 int main(int, char *[]);
    119      1.23  christos __dead static void usage(void);
    120      1.23  christos static char *nick2dev(const char *);
    121      1.23  christos static char *nick2rdev(const char *);
    122      1.23  christos static int guess_devtype(const char *);
    123      1.23  christos static void eject_disk(const char *, enum eject_op);
    124      1.23  christos static void eject_tape(const char *, enum eject_op);
    125      1.23  christos static void unmount_dev(const char *);
    126       1.8      tron 
    127       1.8      tron int
    128      1.15     bjh21 main(int argc, char *argv[])
    129       1.7    bouyer {
    130      1.15     bjh21 	int ch;
    131      1.23  christos 	int devtype;
    132      1.24     lukem 	size_t n;
    133      1.23  christos 	char *dev_name;		/* XXX - devname is declared in stdlib.h */
    134      1.23  christos 	enum eject_op op;
    135      1.23  christos 
    136      1.23  christos 	devtype = -1;
    137      1.23  christos 	dev_name = NULL;
    138      1.23  christos 	op = OP_EJECT;
    139      1.15     bjh21 
    140      1.16     bjh21 	while ((ch = getopt(argc, argv, "d:flLnt:Uv")) != -1) {
    141      1.15     bjh21 		switch (ch) {
    142      1.15     bjh21 		case 'd':
    143      1.23  christos 			dev_name = optarg;
    144      1.15     bjh21 			break;
    145      1.15     bjh21 		case 'f':
    146      1.15     bjh21 			umount_f = 0;
    147      1.15     bjh21 			break;
    148      1.15     bjh21 		case 'l':
    149      1.16     bjh21 			if (op != OP_EJECT)
    150      1.16     bjh21 				usage();
    151      1.16     bjh21 			op = OP_LOAD;
    152      1.16     bjh21 			break;
    153      1.16     bjh21 		case 'L':
    154      1.16     bjh21 			if (op != OP_EJECT)
    155      1.16     bjh21 				usage();
    156      1.16     bjh21 			op = OP_LOCK;
    157      1.15     bjh21 			break;
    158      1.15     bjh21 		case 'n':
    159      1.23  christos 			for (n = 0; n < __arraycount(nicknames); n++) {
    160      1.15     bjh21 				struct nicknames_s *np = &nicknames[n];
    161      1.15     bjh21 
    162      1.23  christos 				(void)printf("%s -> %s\n",
    163      1.23  christos 				    np->name, nick2dev(np->name));
    164      1.15     bjh21 			}
    165      1.23  christos 			return 0;
    166      1.15     bjh21 		case 't':
    167      1.24     lukem 			for (n = 0; n < __arraycount(devtypes); n++) {
    168      1.24     lukem 				if (strcasecmp(devtypes[n].name, optarg)
    169      1.23  christos 				    == 0) {
    170      1.24     lukem 					devtype = devtypes[n].type;
    171      1.15     bjh21 					break;
    172      1.15     bjh21 				}
    173      1.15     bjh21 			}
    174      1.15     bjh21 			if (devtype == -1)
    175      1.16     bjh21 				errx(1, "%s: unknown device type", optarg);
    176      1.16     bjh21 			break;
    177      1.16     bjh21 		case 'U':
    178      1.16     bjh21 			if (op != OP_EJECT)
    179      1.16     bjh21 				usage();
    180      1.16     bjh21 			op = OP_UNLOCK;
    181      1.15     bjh21 			break;
    182      1.15     bjh21 		case 'v':
    183      1.15     bjh21 			verbose_f = 1;
    184      1.15     bjh21 			break;
    185      1.15     bjh21 		default:
    186      1.15     bjh21 			usage();
    187      1.15     bjh21 			/* NOTREACHED */
    188       1.8      tron 		}
    189      1.15     bjh21 	}
    190      1.15     bjh21 	argc -= optind;
    191      1.15     bjh21 	argv += optind;
    192       1.8      tron 
    193      1.23  christos 	if (dev_name == NULL) {
    194      1.23  christos 		if (argc == 0)
    195      1.15     bjh21 			usage();
    196      1.23  christos 		else
    197      1.23  christos 			dev_name = argv[0];
    198      1.15     bjh21 	}
    199      1.15     bjh21 	if (devtype == -1)
    200      1.23  christos 		devtype = guess_devtype(dev_name);
    201      1.15     bjh21 	if (devtype == -1)
    202      1.23  christos 		errx(1, "%s: unable to determine type of device", dev_name);
    203      1.15     bjh21 	if (verbose_f) {
    204      1.23  christos 		(void)printf("device type == ");
    205      1.15     bjh21 		if ((devtype & TYPEMASK) == TAPE)
    206      1.23  christos 			(void)printf("tape\n");
    207      1.15     bjh21 		else
    208      1.23  christos 			(void)printf("disk, floppy, or cdrom\n");
    209      1.15     bjh21 	}
    210      1.15     bjh21 	if (umount_f)
    211      1.23  christos 		unmount_dev(dev_name);
    212       1.8      tron 
    213      1.15     bjh21 	/* XXX Tapes and disks have different ioctl's: */
    214      1.15     bjh21 	if ((devtype & TYPEMASK) == TAPE)
    215      1.23  christos 		eject_tape(dev_name, op);
    216      1.15     bjh21 	else
    217      1.23  christos 		eject_disk(dev_name, op);
    218       1.8      tron 
    219      1.15     bjh21 	if (verbose_f)
    220      1.23  christos 		(void)printf("done.\n");
    221       1.8      tron 
    222      1.23  christos 	return 0;
    223       1.7    bouyer }
    224       1.7    bouyer 
    225      1.23  christos __dead
    226      1.23  christos static void
    227       1.8      tron usage(void)
    228       1.8      tron {
    229      1.15     bjh21 
    230      1.23  christos 	(void)fprintf(stderr, "usage: eject [-fv] [-l | -L | -U] "
    231      1.16     bjh21 	    "[-t device-type] [-d] device\n");
    232      1.23  christos 	(void)fprintf(stderr, "       eject -n\n");
    233      1.16     bjh21 	exit(1);
    234       1.8      tron }
    235       1.2        pk 
    236      1.23  christos static int
    237      1.23  christos guess_devtype(const char *dev_name)
    238       1.2        pk {
    239      1.24     lukem 	size_t n;
    240      1.15     bjh21 
    241      1.15     bjh21 	/* Nickname match: */
    242      1.23  christos 	for (n = 0; n < __arraycount(nicknames); n++) {
    243      1.23  christos 		if (strncasecmp(nicknames[n].name, dev_name,
    244      1.15     bjh21 			strlen(nicknames[n].name)) == 0)
    245      1.23  christos 			return nicknames[n].type;
    246      1.15     bjh21 	}
    247       1.2        pk 
    248       1.8      tron 	/*
    249      1.23  christos          * If we still don't know it, then try to compare vs. dev and
    250      1.23  christos          * rdev names that we know.
    251      1.15     bjh21          */
    252      1.15     bjh21 	/* dev first: */
    253      1.23  christos 	for (n = 0; n < __arraycount(nicknames); n++) {
    254      1.15     bjh21 		char *name;
    255      1.15     bjh21 		name = nick2dev(nicknames[n].name);
    256      1.15     bjh21 		/*
    257      1.23  christos 		 * Assume that the part of the name that distinguishes
    258      1.23  christos 		 * the instance of this device begins with a 0.
    259      1.15     bjh21 		 */
    260      1.15     bjh21 		*(strchr(name, '0')) = '\0';
    261      1.23  christos 		if (strncmp(name, dev_name, strlen(name)) == 0)
    262      1.23  christos 			return nicknames[n].type;
    263      1.15     bjh21 	}
    264      1.15     bjh21 
    265      1.15     bjh21 	/* Now rdev: */
    266      1.23  christos 	for (n = 0; n < __arraycount(nicknames); n++) {
    267      1.15     bjh21 		char *name = nick2rdev(nicknames[n].name);
    268      1.15     bjh21 		*(strchr(name, '0')) = '\0';
    269      1.23  christos 		if (strncmp(name, dev_name, strlen(name)) == 0)
    270      1.23  christos 			return nicknames[n].type;
    271      1.15     bjh21 	}
    272       1.8      tron 
    273      1.15     bjh21 	/* Not found. */
    274      1.23  christos 	return -1;
    275       1.8      tron }
    276      1.23  christos 
    277       1.8      tron /* "floppy5" -> "/dev/fd5a".  Yep, this uses a static buffer. */
    278      1.23  christos static char *
    279      1.23  christos nick2dev(const char *nn)
    280       1.8      tron {
    281      1.23  christos 	static char dev_name[MAXDEVLEN];
    282      1.24     lukem 	size_t n;
    283      1.23  christos 	int devnum;
    284      1.15     bjh21 
    285      1.23  christos 	devnum = 0;
    286      1.23  christos 	for (n = 0; n < __arraycount(nicknames); n++) {
    287      1.15     bjh21 		if (strncasecmp(nicknames[n].name, nn,
    288      1.15     bjh21 			strlen(nicknames[n].name)) == 0) {
    289      1.23  christos 			(void)sscanf(nn, "%*[^0-9]%d", &devnum);
    290      1.23  christos 			(void)sprintf(dev_name, "/dev/%s%d",
    291      1.23  christos 			    nicknames[n].devname, devnum);
    292      1.15     bjh21 			if ((nicknames[n].type & TYPEMASK) != TAPE)
    293      1.23  christos 				(void)strcat(dev_name, "a");
    294      1.23  christos 			return dev_name;
    295      1.15     bjh21 		}
    296       1.2        pk 	}
    297      1.23  christos 	return NULL;
    298      1.23  christos }
    299       1.2        pk 
    300       1.8      tron /* "floppy5" -> "/dev/rfd5c".  Static buffer. */
    301      1.23  christos static char *
    302      1.23  christos nick2rdev(const char *nn)
    303       1.8      tron {
    304      1.23  christos 	static char dev_name[MAXDEVLEN];
    305      1.24     lukem 	size_t n;
    306      1.23  christos 	int devnum;
    307      1.15     bjh21 
    308      1.23  christos 	devnum = 0;
    309      1.23  christos 	for (n = 0; n < __arraycount(nicknames); n++) {
    310      1.15     bjh21 		if (strncasecmp(nicknames[n].name, nn,
    311      1.15     bjh21 			strlen(nicknames[n].name)) == 0) {
    312      1.23  christos 			(void)sscanf(nn, "%*[^0-9]%d", &devnum);
    313      1.23  christos 			(void)sprintf(dev_name, "/dev/r%s%d",
    314      1.23  christos 			    nicknames[n].devname, devnum);
    315      1.15     bjh21 			if ((nicknames[n].type & TYPEMASK) != TAPE) {
    316      1.23  christos 				(void)strcat(dev_name, "a");
    317      1.20   xtraeme 				if ((nicknames[n].type & FLOPPY) != FLOPPY)
    318      1.23  christos 					dev_name[strlen(dev_name) - 1]
    319      1.23  christos 					    += getrawpartition();
    320      1.15     bjh21 			}
    321      1.23  christos 			return dev_name;
    322      1.15     bjh21 		}
    323       1.2        pk 	}
    324      1.23  christos 	return NULL;
    325      1.23  christos }
    326       1.2        pk 
    327       1.8      tron /* Unmount all filesystems attached to dev. */
    328      1.23  christos static void
    329      1.23  christos unmount_dev(const char *name)
    330       1.2        pk {
    331      1.18  christos 	struct statvfs *mounts;
    332      1.23  christos 	size_t len;
    333      1.23  christos 	int i, nmnts;
    334      1.23  christos 	const char *dn;
    335      1.15     bjh21 
    336      1.15     bjh21 	nmnts = getmntinfo(&mounts, MNT_NOWAIT);
    337      1.23  christos 	if (nmnts == 0)
    338      1.15     bjh21 		err(1, "getmntinfo");
    339      1.23  christos 
    340      1.15     bjh21 	/* Make sure we have a device name: */
    341      1.15     bjh21 	dn = nick2dev(name);
    342      1.15     bjh21 	if (dn == NULL)
    343      1.15     bjh21 		dn = name;
    344      1.15     bjh21 
    345      1.15     bjh21 	/* Set len to strip off the partition name: */
    346      1.15     bjh21 	len = strlen(dn);
    347      1.19       dsl 	if (!isdigit((unsigned char)dn[len - 1]))
    348      1.15     bjh21 		len--;
    349      1.23  christos 	if (!isdigit((unsigned char)dn[len - 1]))
    350      1.15     bjh21 		errx(1, "Can't figure out base name for dev name %s", dn);
    351      1.23  christos 
    352      1.15     bjh21 	for (i = 0; i < nmnts; i++) {
    353      1.15     bjh21 		if (strncmp(mounts[i].f_mntfromname, dn, len) == 0) {
    354      1.15     bjh21 			if (verbose_f)
    355      1.23  christos 				(void)printf("Unmounting %s from %s...\n",
    356      1.15     bjh21 				    mounts[i].f_mntfromname,
    357      1.15     bjh21 				    mounts[i].f_mntonname);
    358      1.15     bjh21 
    359      1.25  christos 			if (
    360      1.25  christos #ifdef AMD_SUPPORT
    361      1.25  christos 			    am_unmount(mounts[i].f_mntonname) != 0 &&
    362      1.25  christos #endif
    363      1.25  christos 			    unmount(mounts[i].f_mntonname, 0) == -1)
    364      1.15     bjh21 				err(1, "unmount: %s", mounts[i].f_mntonname);
    365      1.15     bjh21 		}
    366       1.2        pk 	}
    367      1.15     bjh21 	return;
    368       1.8      tron }
    369       1.2        pk 
    370      1.23  christos static void
    371      1.23  christos eject_tape(const char *name, enum eject_op op)
    372       1.8      tron {
    373      1.15     bjh21 	struct mtop m;
    374      1.15     bjh21 	int fd;
    375      1.23  christos 	const char *dn;
    376      1.15     bjh21 
    377      1.15     bjh21 	dn = nick2rdev(name);
    378      1.15     bjh21 	if (dn == NULL)
    379      1.15     bjh21 		dn = name;	/* Hope for the best. */
    380      1.15     bjh21 	fd = open(dn, O_RDONLY);
    381      1.15     bjh21 	if (fd == -1)
    382      1.15     bjh21 		err(1, "open: %s", dn);
    383      1.16     bjh21 	switch (op) {
    384      1.16     bjh21 	case OP_EJECT:
    385      1.16     bjh21 		if (verbose_f)
    386      1.23  christos 			(void)printf("Ejecting %s...\n", dn);
    387      1.15     bjh21 
    388      1.16     bjh21 		m.mt_op = MTOFFL;
    389      1.16     bjh21 		m.mt_count = 0;
    390      1.16     bjh21 		if (ioctl(fd, MTIOCTOP, &m) == -1)
    391      1.16     bjh21 			err(1, "ioctl: MTIOCTOP: %s", dn);
    392      1.16     bjh21 		break;
    393      1.16     bjh21 	case OP_LOAD:
    394      1.16     bjh21 		errx(1, "cannot load tapes");
    395      1.16     bjh21 		/* NOTREACHED */
    396      1.16     bjh21 	case OP_LOCK:
    397      1.16     bjh21 		errx(1, "cannot lock tapes");
    398      1.16     bjh21 		/* NOTREACHED */
    399      1.16     bjh21 	case OP_UNLOCK:
    400      1.16     bjh21 		errx(1, "cannot unlock tapes");
    401      1.16     bjh21 		/* NOTREACHED */
    402      1.16     bjh21 	}
    403      1.23  christos 	(void)close(fd);
    404      1.15     bjh21 	return;
    405       1.8      tron }
    406       1.2        pk 
    407      1.23  christos static void
    408      1.23  christos eject_disk(const char *name, enum eject_op op)
    409       1.8      tron {
    410      1.15     bjh21 	int fd;
    411      1.23  christos 	const char *dn;
    412      1.15     bjh21 	int arg;
    413      1.15     bjh21 
    414      1.15     bjh21 	dn = nick2rdev(name);
    415      1.15     bjh21 	if (dn == NULL)
    416      1.15     bjh21 		dn = name;	/* Hope for the best. */
    417      1.15     bjh21 	fd = open(dn, O_RDONLY);
    418      1.15     bjh21 	if (fd == -1)
    419      1.15     bjh21 		err(1, "open: %s", dn);
    420      1.16     bjh21 	switch (op) {
    421      1.16     bjh21 	case OP_LOAD:
    422      1.15     bjh21 		if (verbose_f)
    423      1.23  christos 			(void)printf("Closing %s...\n", dn);
    424      1.15     bjh21 
    425      1.15     bjh21 		if (ioctl(fd, CDIOCCLOSE, NULL) == -1)
    426      1.15     bjh21 			err(1, "ioctl: CDIOCCLOSE: %s", dn);
    427      1.16     bjh21 		break;
    428      1.16     bjh21 	case OP_EJECT:
    429      1.15     bjh21 		if (verbose_f)
    430      1.23  christos 			(void)printf("Ejecting %s...\n", dn);
    431      1.15     bjh21 
    432      1.15     bjh21 		arg = 0;
    433      1.15     bjh21 		if (umount_f == 0) {
    434      1.15     bjh21 			/* force eject, unlock the device first */
    435      1.15     bjh21 			if (ioctl(fd, DIOCLOCK, &arg) == -1)
    436      1.16     bjh21 				err(1, "ioctl: DIOCLOCK: %s", dn);
    437      1.15     bjh21 			arg = 1;
    438      1.15     bjh21 		}
    439      1.15     bjh21 		if (ioctl(fd, DIOCEJECT, &arg) == -1)
    440      1.15     bjh21 			err(1, "ioctl: DIOCEJECT: %s", dn);
    441      1.16     bjh21 		break;
    442      1.16     bjh21 	case OP_LOCK:
    443      1.16     bjh21 		if (verbose_f)
    444      1.23  christos 			(void)printf("Locking %s...\n", dn);
    445      1.16     bjh21 
    446      1.16     bjh21 		arg = 1;
    447      1.16     bjh21 		if (ioctl(fd, DIOCLOCK, &arg) == -1)
    448      1.16     bjh21 			err(1, "ioctl: DIOCLOCK: %s", dn);
    449      1.16     bjh21 		break;
    450      1.16     bjh21 	case OP_UNLOCK:
    451      1.16     bjh21 		if (verbose_f)
    452      1.23  christos 			(void)printf("Unlocking %s...\n", dn);
    453      1.16     bjh21 
    454      1.16     bjh21 		arg = 0;
    455      1.16     bjh21 		if (ioctl(fd, DIOCLOCK, &arg) == -1)
    456      1.16     bjh21 			err(1, "ioctl: DIOCLOCK: %s", dn);
    457      1.16     bjh21 		break;
    458      1.15     bjh21 	}
    459       1.2        pk 
    460      1.23  christos 	(void)close(fd);
    461      1.15     bjh21 	return;
    462       1.2        pk }
    463