xref: /netbsd-src/usr.bin/eject/eject.c (revision 39bbc68a3b8731308f39852383f5430560168a91)
1*39bbc68aSsevan /*	$NetBSD: eject.c,v 1.28 2016/09/05 00:40:28 sevan Exp $	*/
2a651e1a0Stron 
3a651e1a0Stron /*-
4a651e1a0Stron  * Copyright (c) 1999 The NetBSD Foundation, Inc.
5a651e1a0Stron  * All rights reserved.
6a651e1a0Stron  *
7a651e1a0Stron  * This code is derived from software contributed to The NetBSD Foundation
8a651e1a0Stron  * by Chris Jones.
9764fa4b6Spk  *
10764fa4b6Spk  * Redistribution and use in source and binary forms, with or without
11764fa4b6Spk  * modification, are permitted provided that the following conditions
12764fa4b6Spk  * are met:
13764fa4b6Spk  * 1. Redistributions of source code must retain the above copyright
14764fa4b6Spk  *    notice, this list of conditions and the following disclaimer.
15764fa4b6Spk  * 2. Redistributions in binary form must reproduce the above copyright
16764fa4b6Spk  *    notice, this list of conditions and the following disclaimer in the
17764fa4b6Spk  *    documentation and/or other materials provided with the distribution.
18764fa4b6Spk  *
19a651e1a0Stron  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20a651e1a0Stron  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21a651e1a0Stron  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22a651e1a0Stron  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23a651e1a0Stron  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24a651e1a0Stron  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25a651e1a0Stron  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26a651e1a0Stron  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27a651e1a0Stron  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28a651e1a0Stron  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29a651e1a0Stron  * POSSIBILITY OF SUCH DAMAGE.
30764fa4b6Spk  */
31764fa4b6Spk 
32a651e1a0Stron #include <sys/cdefs.h>
33a651e1a0Stron #ifndef lint
3498e5374cSlukem __COPYRIGHT("@(#) Copyright (c) 1999\
3598e5374cSlukem  The NetBSD Foundation, Inc.  All rights reserved.");
3603cb143eScjs #endif				/* not lint */
3703cb143eScjs 
3803cb143eScjs #ifndef lint
39*39bbc68aSsevan __RCSID("$NetBSD: eject.c,v 1.28 2016/09/05 00:40:28 sevan Exp $");
4003cb143eScjs #endif				/* not lint */
41a651e1a0Stron 
42d78020d1Sad #include <sys/types.h>
43d78020d1Sad #include <sys/cdio.h>
44d78020d1Sad #include <sys/disklabel.h>
45d78020d1Sad #include <sys/ioctl.h>
46d78020d1Sad #include <sys/param.h>
47d78020d1Sad #include <sys/ucred.h>
48d78020d1Sad #include <sys/mount.h>
49d78020d1Sad #include <sys/mtio.h>
50d78020d1Sad 
51a651e1a0Stron #include <ctype.h>
52a651e1a0Stron #include <err.h>
53a651e1a0Stron #include <fcntl.h>
54a651e1a0Stron #include <stdio.h>
55a651e1a0Stron #include <stdlib.h>
56a651e1a0Stron #include <string.h>
57a651e1a0Stron #include <unistd.h>
58d78020d1Sad #include <util.h>
59a651e1a0Stron 
6052f56a8cSchristos #ifdef AMD_SUPPORT
6152f56a8cSchristos # include "am_glue.h"
6252f56a8cSchristos #endif
6352f56a8cSchristos 
64a651e1a0Stron struct nicknames_s {
65a127d189Schristos 	const char *name;	/* The name given on the command line. */
66a127d189Schristos 	const char *devname;	/* The base name of the device */
67ccb8f4d3Sbjh21 	int type;		/* The type of device, for determining what
68ccb8f4d3Sbjh21 				 * ioctl to use. */
69a651e1a0Stron # define TAPE 0x10
70a651e1a0Stron # define DISK 0x20
71a651e1a0Stron 	/* OR one of the above with one of the below: */
72a651e1a0Stron # define NOTLOADABLE 0x00
73a651e1a0Stron # define LOADABLE 0x01
74f3751075Sxtraeme # define FLOPPY 0x2
75a651e1a0Stron # define TYPEMASK ((int)~0x01)
76a651e1a0Stron } nicknames[] = {
77f3751075Sxtraeme 	{ "diskette", "fd",   DISK | FLOPPY | NOTLOADABLE },
78f3751075Sxtraeme 	{ "floppy",   "fd",   DISK | FLOPPY | NOTLOADABLE },
79f3751075Sxtraeme 	{ "fd",       "fd",   DISK | FLOPPY | NOTLOADABLE },
803dcf0c67Sbouyer 	{ "sd",       "sd",   DISK | NOTLOADABLE },
8180f0af1aSbouyer 	{ "cdrom",    "cd",   DISK | LOADABLE },
8280f0af1aSbouyer 	{ "cd",       "cd",   DISK | LOADABLE },
832a4ad09fSabs 	{ "racd",     "racd", DISK | LOADABLE },
843c317264Smycroft 	{ "cdr",      "cd",   DISK | LOADABLE },
853c317264Smycroft 	{ "cdrw",     "cd",   DISK | LOADABLE },
863c317264Smycroft 	{ "dvdrom",   "cd",   DISK | LOADABLE },
873c317264Smycroft 	{ "dvd",      "cd",   DISK | LOADABLE },
883c317264Smycroft 	{ "dvdr",     "cd",   DISK | LOADABLE },
893c317264Smycroft 	{ "dvdrw",    "cd",   DISK | LOADABLE },
9080f0af1aSbouyer 	{ "mcd",      "mcd",  DISK | LOADABLE },	/* XXX Is this true? */
91a651e1a0Stron 	{ "tape",     "st",   TAPE | NOTLOADABLE },
92a651e1a0Stron 	{ "st",       "st",   TAPE | NOTLOADABLE },
93a651e1a0Stron 	{ "dat",      "st",   TAPE | NOTLOADABLE },
94a127d189Schristos 	{ "exabyte",  "st",   TAPE | NOTLOADABLE }
95a651e1a0Stron };
96ccb8f4d3Sbjh21 #define MAXNICKLEN 12		/* at least enough room for the longest
97ccb8f4d3Sbjh21 				 * nickname */
98a651e1a0Stron #define MAXDEVLEN (MAXNICKLEN + 7)	/* "/dev/r" ... "a" */
99a651e1a0Stron 
100a651e1a0Stron struct devtypes_s {
101a127d189Schristos 	const char *name;
102a651e1a0Stron 	int type;
103a651e1a0Stron } devtypes[] = {
104a651e1a0Stron 	{ "diskette", DISK | NOTLOADABLE },
105a651e1a0Stron 	{ "floppy",   DISK | NOTLOADABLE },
10680f0af1aSbouyer 	{ "cdrom",    DISK | LOADABLE },
107a651e1a0Stron 	{ "disk",     DISK | NOTLOADABLE },
108a127d189Schristos 	{ "tape",     TAPE | NOTLOADABLE }
109a651e1a0Stron };
110a651e1a0Stron 
11179931f7bSbjh21 enum eject_op {
11279931f7bSbjh21 	OP_EJECT, OP_LOAD, OP_LOCK, OP_UNLOCK
11379931f7bSbjh21 };
11479931f7bSbjh21 
115a651e1a0Stron int verbose_f = 0;
116a651e1a0Stron int umount_f = 1;
117a651e1a0Stron 
118a127d189Schristos __dead static void usage(void);
119a127d189Schristos static char *nick2dev(const char *);
120a127d189Schristos static char *nick2rdev(const char *);
121a127d189Schristos static int guess_devtype(const char *);
122a127d189Schristos static void eject_disk(const char *, enum eject_op);
123a127d189Schristos static void eject_tape(const char *, enum eject_op);
124a127d189Schristos static void unmount_dev(const char *);
125a651e1a0Stron 
126a651e1a0Stron int
main(int argc,char * argv[])127ccb8f4d3Sbjh21 main(int argc, char *argv[])
128a651e1a0Stron {
129a651e1a0Stron 	int ch;
130a127d189Schristos 	int devtype;
131c402ba6fSlukem 	size_t n;
132a127d189Schristos 	char *dev_name;		/* XXX - devname is declared in stdlib.h */
133a127d189Schristos 	enum eject_op op;
134a127d189Schristos 
135a127d189Schristos 	devtype = -1;
136a127d189Schristos 	dev_name = NULL;
137a127d189Schristos 	op = OP_EJECT;
138764fa4b6Spk 
13979931f7bSbjh21 	while ((ch = getopt(argc, argv, "d:flLnt:Uv")) != -1) {
140764fa4b6Spk 		switch (ch) {
141764fa4b6Spk 		case 'd':
142a127d189Schristos 			dev_name = optarg;
143764fa4b6Spk 			break;
144764fa4b6Spk 		case 'f':
145a651e1a0Stron 			umount_f = 0;
146764fa4b6Spk 			break;
147425c9945Sbouyer 		case 'l':
14879931f7bSbjh21 			if (op != OP_EJECT)
14979931f7bSbjh21 				usage();
15079931f7bSbjh21 			op = OP_LOAD;
15179931f7bSbjh21 			break;
15279931f7bSbjh21 		case 'L':
15379931f7bSbjh21 			if (op != OP_EJECT)
15479931f7bSbjh21 				usage();
15579931f7bSbjh21 			op = OP_LOCK;
156425c9945Sbouyer 			break;
157764fa4b6Spk 		case 'n':
158a127d189Schristos 			for (n = 0; n < __arraycount(nicknames); n++) {
159a651e1a0Stron 				struct nicknames_s *np = &nicknames[n];
160a651e1a0Stron 
161a127d189Schristos 				(void)printf("%s -> %s\n",
162a127d189Schristos 				    np->name, nick2dev(np->name));
1637b5f411eSmsaitoh 			}
164a127d189Schristos 			return 0;
165764fa4b6Spk 		case 't':
166c402ba6fSlukem 			for (n = 0; n < __arraycount(devtypes); n++) {
167c402ba6fSlukem 				if (strcasecmp(devtypes[n].name, optarg)
168a127d189Schristos 				    == 0) {
169c402ba6fSlukem 					devtype = devtypes[n].type;
170764fa4b6Spk 					break;
171764fa4b6Spk 				}
172764fa4b6Spk 			}
173ccb8f4d3Sbjh21 			if (devtype == -1)
17479931f7bSbjh21 				errx(1, "%s: unknown device type", optarg);
17579931f7bSbjh21 			break;
17679931f7bSbjh21 		case 'U':
17779931f7bSbjh21 			if (op != OP_EJECT)
17879931f7bSbjh21 				usage();
17979931f7bSbjh21 			op = OP_UNLOCK;
180764fa4b6Spk 			break;
181764fa4b6Spk 		case 'v':
182a651e1a0Stron 			verbose_f = 1;
183764fa4b6Spk 			break;
184764fa4b6Spk 		default:
185764fa4b6Spk 			usage();
186764fa4b6Spk 			/* NOTREACHED */
187764fa4b6Spk 		}
188764fa4b6Spk 	}
189764fa4b6Spk 	argc -= optind;
190764fa4b6Spk 	argv += optind;
191764fa4b6Spk 
192a127d189Schristos 	if (dev_name == NULL) {
193a127d189Schristos 		if (argc == 0)
194a651e1a0Stron 			usage();
195a127d189Schristos 		else
196a127d189Schristos 			dev_name = argv[0];
197764fa4b6Spk 	}
198ccb8f4d3Sbjh21 	if (devtype == -1)
199a127d189Schristos 		devtype = guess_devtype(dev_name);
200ccb8f4d3Sbjh21 	if (devtype == -1)
201a127d189Schristos 		errx(1, "%s: unable to determine type of device", dev_name);
202a651e1a0Stron 	if (verbose_f) {
203a127d189Schristos 		(void)printf("device type == ");
204a651e1a0Stron 		if ((devtype & TYPEMASK) == TAPE)
205a127d189Schristos 			(void)printf("tape\n");
206a651e1a0Stron 		else
207a127d189Schristos 			(void)printf("disk, floppy, or cdrom\n");
208a651e1a0Stron 	}
209a651e1a0Stron 	if (umount_f)
210a127d189Schristos 		unmount_dev(dev_name);
211a651e1a0Stron 
21280f0af1aSbouyer 	/* XXX Tapes and disks have different ioctl's: */
213a651e1a0Stron 	if ((devtype & TYPEMASK) == TAPE)
214a127d189Schristos 		eject_tape(dev_name, op);
215a651e1a0Stron 	else
216a127d189Schristos 		eject_disk(dev_name, op);
217a651e1a0Stron 
218a651e1a0Stron 	if (verbose_f)
219a127d189Schristos 		(void)printf("done.\n");
220a651e1a0Stron 
221a127d189Schristos 	return 0;
222a651e1a0Stron }
223a651e1a0Stron 
224a127d189Schristos __dead
225a127d189Schristos static void
usage(void)226a651e1a0Stron usage(void)
227a651e1a0Stron {
228ccb8f4d3Sbjh21 
229a127d189Schristos 	(void)fprintf(stderr, "usage: eject [-fv] [-l | -L | -U] "
23079931f7bSbjh21 	    "[-t device-type] [-d] device\n");
231a127d189Schristos 	(void)fprintf(stderr, "       eject -n\n");
23279931f7bSbjh21 	exit(1);
233a651e1a0Stron }
234a651e1a0Stron 
235a127d189Schristos static int
guess_devtype(const char * dev_name)236a127d189Schristos guess_devtype(const char *dev_name)
237a651e1a0Stron {
238c402ba6fSlukem 	size_t n;
239a651e1a0Stron 
240a651e1a0Stron 	/* Nickname match: */
241a127d189Schristos 	for (n = 0; n < __arraycount(nicknames); n++) {
242a127d189Schristos 		if (strncasecmp(nicknames[n].name, dev_name,
243a651e1a0Stron 			strlen(nicknames[n].name)) == 0)
244a127d189Schristos 			return nicknames[n].type;
245a651e1a0Stron 	}
246a651e1a0Stron 
247a651e1a0Stron 	/*
248a127d189Schristos          * If we still don't know it, then try to compare vs. dev and
249a127d189Schristos          * rdev names that we know.
250a651e1a0Stron          */
251a651e1a0Stron 	/* dev first: */
252a127d189Schristos 	for (n = 0; n < __arraycount(nicknames); n++) {
253a651e1a0Stron 		char *name;
254a651e1a0Stron 		name = nick2dev(nicknames[n].name);
255a651e1a0Stron 		/*
256a127d189Schristos 		 * Assume that the part of the name that distinguishes
257a127d189Schristos 		 * the instance of this device begins with a 0.
258a651e1a0Stron 		 */
259a651e1a0Stron 		*(strchr(name, '0')) = '\0';
260a127d189Schristos 		if (strncmp(name, dev_name, strlen(name)) == 0)
261a127d189Schristos 			return nicknames[n].type;
262a651e1a0Stron 	}
263a651e1a0Stron 
264a651e1a0Stron 	/* Now rdev: */
265a127d189Schristos 	for (n = 0; n < __arraycount(nicknames); n++) {
266a651e1a0Stron 		char *name = nick2rdev(nicknames[n].name);
267a651e1a0Stron 		*(strchr(name, '0')) = '\0';
268a127d189Schristos 		if (strncmp(name, dev_name, strlen(name)) == 0)
269a127d189Schristos 			return nicknames[n].type;
270a651e1a0Stron 	}
271a651e1a0Stron 
272a651e1a0Stron 	/* Not found. */
273a127d189Schristos 	return -1;
274a651e1a0Stron }
275a127d189Schristos 
276a651e1a0Stron /* "floppy5" -> "/dev/fd5a".  Yep, this uses a static buffer. */
277a127d189Schristos static char *
nick2dev(const char * nn)278a127d189Schristos nick2dev(const char *nn)
279a651e1a0Stron {
280a127d189Schristos 	static char dev_name[MAXDEVLEN];
281c402ba6fSlukem 	size_t n;
282a127d189Schristos 	int devnum;
283a651e1a0Stron 
284a127d189Schristos 	devnum = 0;
285a127d189Schristos 	for (n = 0; n < __arraycount(nicknames); n++) {
286a651e1a0Stron 		if (strncasecmp(nicknames[n].name, nn,
287a651e1a0Stron 			strlen(nicknames[n].name)) == 0) {
288a127d189Schristos 			(void)sscanf(nn, "%*[^0-9]%d", &devnum);
289a127d189Schristos 			(void)sprintf(dev_name, "/dev/%s%d",
290a127d189Schristos 			    nicknames[n].devname, devnum);
291a651e1a0Stron 			if ((nicknames[n].type & TYPEMASK) != TAPE)
292a127d189Schristos 				(void)strcat(dev_name, "a");
293a127d189Schristos 			return dev_name;
294a651e1a0Stron 		}
295a651e1a0Stron 	}
296a127d189Schristos 	return NULL;
297a127d189Schristos }
298a651e1a0Stron 
299a651e1a0Stron /* "floppy5" -> "/dev/rfd5c".  Static buffer. */
300a127d189Schristos static char *
nick2rdev(const char * nn)301a127d189Schristos nick2rdev(const char *nn)
302a651e1a0Stron {
303a127d189Schristos 	static char dev_name[MAXDEVLEN];
304c402ba6fSlukem 	size_t n;
305a127d189Schristos 	int devnum;
306a651e1a0Stron 
307a127d189Schristos 	devnum = 0;
308a127d189Schristos 	for (n = 0; n < __arraycount(nicknames); n++) {
309a651e1a0Stron 		if (strncasecmp(nicknames[n].name, nn,
310a651e1a0Stron 			strlen(nicknames[n].name)) == 0) {
311a127d189Schristos 			(void)sscanf(nn, "%*[^0-9]%d", &devnum);
312a127d189Schristos 			(void)sprintf(dev_name, "/dev/r%s%d",
313a127d189Schristos 			    nicknames[n].devname, devnum);
314a651e1a0Stron 			if ((nicknames[n].type & TYPEMASK) != TAPE) {
315a127d189Schristos 				(void)strcat(dev_name, "a");
316f3751075Sxtraeme 				if ((nicknames[n].type & FLOPPY) != FLOPPY)
317a127d189Schristos 					dev_name[strlen(dev_name) - 1]
318a127d189Schristos 					    += getrawpartition();
319a651e1a0Stron 			}
320a127d189Schristos 			return dev_name;
321a651e1a0Stron 		}
322a651e1a0Stron 	}
323a127d189Schristos 	return NULL;
324a127d189Schristos }
325a651e1a0Stron 
326a651e1a0Stron /* Unmount all filesystems attached to dev. */
327a127d189Schristos static void
unmount_dev(const char * name)328a127d189Schristos unmount_dev(const char *name)
329a651e1a0Stron {
3306bd1d6d4Schristos 	struct statvfs *mounts;
331a127d189Schristos 	size_t len;
332a127d189Schristos 	int i, nmnts;
333a127d189Schristos 	const char *dn;
334a651e1a0Stron 
335a651e1a0Stron 	nmnts = getmntinfo(&mounts, MNT_NOWAIT);
336a127d189Schristos 	if (nmnts == 0)
337a651e1a0Stron 		err(1, "getmntinfo");
338a127d189Schristos 
339a651e1a0Stron 	/* Make sure we have a device name: */
340a651e1a0Stron 	dn = nick2dev(name);
341a651e1a0Stron 	if (dn == NULL)
342a651e1a0Stron 		dn = name;
343a651e1a0Stron 
344a651e1a0Stron 	/* Set len to strip off the partition name: */
345a651e1a0Stron 	len = strlen(dn);
34643371ff1Sdsl 	if (!isdigit((unsigned char)dn[len - 1]))
347a651e1a0Stron 		len--;
348a127d189Schristos 	if (!isdigit((unsigned char)dn[len - 1]))
349a651e1a0Stron 		errx(1, "Can't figure out base name for dev name %s", dn);
350a127d189Schristos 
351a651e1a0Stron 	for (i = 0; i < nmnts; i++) {
352a651e1a0Stron 		if (strncmp(mounts[i].f_mntfromname, dn, len) == 0) {
353a651e1a0Stron 			if (verbose_f)
354a127d189Schristos 				(void)printf("Unmounting %s from %s...\n",
355a651e1a0Stron 				    mounts[i].f_mntfromname,
356a651e1a0Stron 				    mounts[i].f_mntonname);
357a651e1a0Stron 
35852f56a8cSchristos 			if (
35952f56a8cSchristos #ifdef AMD_SUPPORT
36052f56a8cSchristos 			    am_unmount(mounts[i].f_mntonname) != 0 &&
36152f56a8cSchristos #endif
36252f56a8cSchristos 			    unmount(mounts[i].f_mntonname, 0) == -1)
363a651e1a0Stron 				err(1, "unmount: %s", mounts[i].f_mntonname);
364a651e1a0Stron 		}
365a651e1a0Stron 	}
366a651e1a0Stron 	return;
367a651e1a0Stron }
368a651e1a0Stron 
369a127d189Schristos static void
eject_tape(const char * name,enum eject_op op)370a127d189Schristos eject_tape(const char *name, enum eject_op op)
371a651e1a0Stron {
372a651e1a0Stron 	struct mtop m;
373a651e1a0Stron 	int fd;
374a127d189Schristos 	const char *dn;
375a651e1a0Stron 
376a651e1a0Stron 	dn = nick2rdev(name);
377ccb8f4d3Sbjh21 	if (dn == NULL)
378a651e1a0Stron 		dn = name;	/* Hope for the best. */
379a651e1a0Stron 	fd = open(dn, O_RDONLY);
380ccb8f4d3Sbjh21 	if (fd == -1)
381a651e1a0Stron 		err(1, "open: %s", dn);
38279931f7bSbjh21 	switch (op) {
38379931f7bSbjh21 	case OP_EJECT:
384a651e1a0Stron 		if (verbose_f)
385a127d189Schristos 			(void)printf("Ejecting %s...\n", dn);
386a651e1a0Stron 
387a651e1a0Stron 		m.mt_op = MTOFFL;
388a651e1a0Stron 		m.mt_count = 0;
389ccb8f4d3Sbjh21 		if (ioctl(fd, MTIOCTOP, &m) == -1)
390a651e1a0Stron 			err(1, "ioctl: MTIOCTOP: %s", dn);
39179931f7bSbjh21 		break;
39279931f7bSbjh21 	case OP_LOAD:
39379931f7bSbjh21 		errx(1, "cannot load tapes");
39479931f7bSbjh21 		/* NOTREACHED */
39579931f7bSbjh21 	case OP_LOCK:
39679931f7bSbjh21 		errx(1, "cannot lock tapes");
39779931f7bSbjh21 		/* NOTREACHED */
39879931f7bSbjh21 	case OP_UNLOCK:
39979931f7bSbjh21 		errx(1, "cannot unlock tapes");
40079931f7bSbjh21 		/* NOTREACHED */
40179931f7bSbjh21 	}
402a127d189Schristos 	(void)close(fd);
403a651e1a0Stron 	return;
404a651e1a0Stron }
405a651e1a0Stron 
406a127d189Schristos static void
eject_disk(const char * name,enum eject_op op)407a127d189Schristos eject_disk(const char *name, enum eject_op op)
408a651e1a0Stron {
409a651e1a0Stron 	int fd;
410a127d189Schristos 	const char *dn;
411a651e1a0Stron 	int arg;
412a651e1a0Stron 
413a651e1a0Stron 	dn = nick2rdev(name);
414ccb8f4d3Sbjh21 	if (dn == NULL)
415a651e1a0Stron 		dn = name;	/* Hope for the best. */
416a651e1a0Stron 	fd = open(dn, O_RDONLY);
417ccb8f4d3Sbjh21 	if (fd == -1)
418a651e1a0Stron 		err(1, "open: %s", dn);
41979931f7bSbjh21 	switch (op) {
42079931f7bSbjh21 	case OP_LOAD:
421a651e1a0Stron 		if (verbose_f)
422a127d189Schristos 			(void)printf("Closing %s...\n", dn);
423a651e1a0Stron 
424ccb8f4d3Sbjh21 		if (ioctl(fd, CDIOCCLOSE, NULL) == -1)
425a651e1a0Stron 			err(1, "ioctl: CDIOCCLOSE: %s", dn);
42679931f7bSbjh21 		break;
42779931f7bSbjh21 	case OP_EJECT:
428a651e1a0Stron 		if (verbose_f)
429a127d189Schristos 			(void)printf("Ejecting %s...\n", dn);
430a651e1a0Stron 
431a651e1a0Stron 		arg = 0;
43280f0af1aSbouyer 		if (umount_f == 0) {
43380f0af1aSbouyer 			/* force eject, unlock the device first */
43480f0af1aSbouyer 			if (ioctl(fd, DIOCLOCK, &arg) == -1)
43579931f7bSbjh21 				err(1, "ioctl: DIOCLOCK: %s", dn);
43680f0af1aSbouyer 			arg = 1;
43780f0af1aSbouyer 		}
438a651e1a0Stron 		if (ioctl(fd, DIOCEJECT, &arg) == -1)
439a651e1a0Stron 			err(1, "ioctl: DIOCEJECT: %s", dn);
44079931f7bSbjh21 		break;
44179931f7bSbjh21 	case OP_LOCK:
44279931f7bSbjh21 		if (verbose_f)
443a127d189Schristos 			(void)printf("Locking %s...\n", dn);
44479931f7bSbjh21 
44579931f7bSbjh21 		arg = 1;
44679931f7bSbjh21 		if (ioctl(fd, DIOCLOCK, &arg) == -1)
44779931f7bSbjh21 			err(1, "ioctl: DIOCLOCK: %s", dn);
44879931f7bSbjh21 		break;
44979931f7bSbjh21 	case OP_UNLOCK:
45079931f7bSbjh21 		if (verbose_f)
451a127d189Schristos 			(void)printf("Unlocking %s...\n", dn);
45279931f7bSbjh21 
45379931f7bSbjh21 		arg = 0;
45479931f7bSbjh21 		if (ioctl(fd, DIOCLOCK, &arg) == -1)
45579931f7bSbjh21 			err(1, "ioctl: DIOCLOCK: %s", dn);
45679931f7bSbjh21 		break;
457764fa4b6Spk 	}
458764fa4b6Spk 
459a127d189Schristos 	(void)close(fd);
460a651e1a0Stron 	return;
461764fa4b6Spk }
462