1 /* $NetBSD: eject.c,v 1.24 2009/01/15 03:18:30 lukem Exp $ */
4 * Copyright (c) 1999 The NetBSD Foundation, Inc.
7 * This code is derived from software contributed to The NetBSD Foundation
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
32 #include <sys/cdefs.h>
34 __COPYRIGHT("@(#) Copyright (c) 1999\
35 The NetBSD Foundation, Inc. All rights reserved.");
39 __RCSID("$NetBSD: eject.c,v 1.24 2009/01/15 03:18:30 lukem Exp $");
42 #include <sys/types.h>
44 #include <sys/disklabel.h>
45 #include <sys/ioctl.h>
46 #include <sys/param.h>
47 #include <sys/ucred.h>
48 #include <sys/mount.h>
65 const char *name
; /* The name given on the command line. */
66 const char *devname
; /* The base name of the device */
67 int type
; /* The type of device, for determining what
71 /* OR one of the above with one of the below: */
72 # define NOTLOADABLE 0x00
73 # define LOADABLE 0x01
75 # define TYPEMASK ((int)~0x01)
77 { "diskette", "fd", DISK
| FLOPPY
| NOTLOADABLE
},
78 { "floppy", "fd", DISK
| FLOPPY
| NOTLOADABLE
},
79 { "fd", "fd", DISK
| FLOPPY
| NOTLOADABLE
},
80 { "sd", "sd", DISK
| NOTLOADABLE
},
81 { "cdrom", "cd", DISK
| LOADABLE
},
82 { "cd", "cd", DISK
| LOADABLE
},
83 { "cdr", "cd", DISK
| LOADABLE
},
84 { "cdrw", "cd", DISK
| LOADABLE
},
85 { "dvdrom", "cd", DISK
| LOADABLE
},
86 { "dvd", "cd", DISK
| LOADABLE
},
87 { "dvdr", "cd", DISK
| LOADABLE
},
88 { "dvdrw", "cd", DISK
| LOADABLE
},
89 { "mcd", "mcd", DISK
| LOADABLE
}, /* XXX Is this true? */
90 { "tape", "st", TAPE
| NOTLOADABLE
},
91 { "st", "st", TAPE
| NOTLOADABLE
},
92 { "dat", "st", TAPE
| NOTLOADABLE
},
93 { "exabyte", "st", TAPE
| NOTLOADABLE
}
95 #define MAXNICKLEN 12 /* at least enough room for the longest
97 #define MAXDEVLEN (MAXNICKLEN + 7) /* "/dev/r" ... "a" */
103 { "diskette", DISK
| NOTLOADABLE
},
104 { "floppy", DISK
| NOTLOADABLE
},
105 { "cdrom", DISK
| LOADABLE
},
106 { "disk", DISK
| NOTLOADABLE
},
107 { "tape", TAPE
| NOTLOADABLE
}
111 OP_EJECT
, OP_LOAD
, OP_LOCK
, OP_UNLOCK
117 int main(int, char *[]);
118 __dead
static void usage(void);
119 static char *nick2dev(const char *);
120 static char *nick2rdev(const char *);
121 static int guess_devtype(const char *);
122 static void eject_disk(const char *, enum eject_op
);
123 static void eject_tape(const char *, enum eject_op
);
124 static void unmount_dev(const char *);
127 main(int argc
, char *argv
[])
132 char *dev_name
; /* XXX - devname is declared in stdlib.h */
139 while ((ch
= getopt(argc
, argv
, "d:flLnt:Uv")) != -1) {
158 for (n
= 0; n
< __arraycount(nicknames
); n
++) {
159 struct nicknames_s
*np
= &nicknames
[n
];
161 (void)printf("%s -> %s\n",
162 np
->name
, nick2dev(np
->name
));
166 for (n
= 0; n
< __arraycount(devtypes
); n
++) {
167 if (strcasecmp(devtypes
[n
].name
, optarg
)
169 devtype
= devtypes
[n
].type
;
174 errx(1, "%s: unknown device type", optarg
);
192 if (dev_name
== NULL
) {
199 devtype
= guess_devtype(dev_name
);
201 errx(1, "%s: unable to determine type of device", dev_name
);
203 (void)printf("device type == ");
204 if ((devtype
& TYPEMASK
) == TAPE
)
205 (void)printf("tape\n");
207 (void)printf("disk, floppy, or cdrom\n");
210 unmount_dev(dev_name
);
212 /* XXX Tapes and disks have different ioctl's: */
213 if ((devtype
& TYPEMASK
) == TAPE
)
214 eject_tape(dev_name
, op
);
216 eject_disk(dev_name
, op
);
219 (void)printf("done.\n");
229 (void)fprintf(stderr
, "usage: eject [-fv] [-l | -L | -U] "
230 "[-t device-type] [-d] device\n");
231 (void)fprintf(stderr
, " eject -n\n");
236 guess_devtype(const char *dev_name
)
240 /* Nickname match: */
241 for (n
= 0; n
< __arraycount(nicknames
); n
++) {
242 if (strncasecmp(nicknames
[n
].name
, dev_name
,
243 strlen(nicknames
[n
].name
)) == 0)
244 return nicknames
[n
].type
;
248 * If we still don't know it, then try to compare vs. dev and
249 * rdev names that we know.
252 for (n
= 0; n
< __arraycount(nicknames
); n
++) {
254 name
= nick2dev(nicknames
[n
].name
);
256 * Assume that the part of the name that distinguishes
257 * the instance of this device begins with a 0.
259 *(strchr(name
, '0')) = '\0';
260 if (strncmp(name
, dev_name
, strlen(name
)) == 0)
261 return nicknames
[n
].type
;
265 for (n
= 0; n
< __arraycount(nicknames
); n
++) {
266 char *name
= nick2rdev(nicknames
[n
].name
);
267 *(strchr(name
, '0')) = '\0';
268 if (strncmp(name
, dev_name
, strlen(name
)) == 0)
269 return nicknames
[n
].type
;
276 /* "floppy5" -> "/dev/fd5a". Yep, this uses a static buffer. */
278 nick2dev(const char *nn
)
280 static char dev_name
[MAXDEVLEN
];
285 for (n
= 0; n
< __arraycount(nicknames
); n
++) {
286 if (strncasecmp(nicknames
[n
].name
, nn
,
287 strlen(nicknames
[n
].name
)) == 0) {
288 (void)sscanf(nn
, "%*[^0-9]%d", &devnum
);
289 (void)sprintf(dev_name
, "/dev/%s%d",
290 nicknames
[n
].devname
, devnum
);
291 if ((nicknames
[n
].type
& TYPEMASK
) != TAPE
)
292 (void)strcat(dev_name
, "a");
299 /* "floppy5" -> "/dev/rfd5c". Static buffer. */
301 nick2rdev(const char *nn
)
303 static char dev_name
[MAXDEVLEN
];
308 for (n
= 0; n
< __arraycount(nicknames
); n
++) {
309 if (strncasecmp(nicknames
[n
].name
, nn
,
310 strlen(nicknames
[n
].name
)) == 0) {
311 (void)sscanf(nn
, "%*[^0-9]%d", &devnum
);
312 (void)sprintf(dev_name
, "/dev/r%s%d",
313 nicknames
[n
].devname
, devnum
);
314 if ((nicknames
[n
].type
& TYPEMASK
) != TAPE
) {
315 (void)strcat(dev_name
, "a");
316 if ((nicknames
[n
].type
& FLOPPY
) != FLOPPY
)
317 dev_name
[strlen(dev_name
) - 1]
318 += getrawpartition();
326 /* Unmount all filesystems attached to dev. */
328 unmount_dev(const char *name
)
330 struct statvfs
*mounts
;
338 nmnts
= getmntinfo(&mounts
, MNT_NOWAIT
);
340 err(1, "getmntinfo");
342 /* Make sure we have a device name: */
347 /* Set len to strip off the partition name: */
349 if (!isdigit((unsigned char)dn
[len
- 1]))
351 if (!isdigit((unsigned char)dn
[len
- 1]))
352 errx(1, "Can't figure out base name for dev name %s", dn
);
354 for (i
= 0; i
< nmnts
; i
++) {
355 if (strncmp(mounts
[i
].f_mntfromname
, dn
, len
) == 0) {
357 (void)printf("Unmounting %s from %s...\n",
358 mounts
[i
].f_mntfromname
,
359 mounts
[i
].f_mntonname
);
363 am_unmount(mounts
[i
].f_mntonname
) != 0 &&
365 unmount(mounts
[i
].f_mntonname
, 0) == -1)
366 err(1, "unmount: %s", mounts
[i
].f_mntonname
);
373 eject_tape(const char *name
, enum eject_op op
)
379 dn
= nick2rdev(name
);
381 dn
= name
; /* Hope for the best. */
382 fd
= open(dn
, O_RDONLY
);
384 err(1, "open: %s", dn
);
388 (void)printf("Ejecting %s...\n", dn
);
392 if (ioctl(fd
, MTIOCTOP
, &m
) == -1)
393 err(1, "ioctl: MTIOCTOP: %s", dn
);
396 errx(1, "cannot load tapes");
399 errx(1, "cannot lock tapes");
402 errx(1, "cannot unlock tapes");
410 eject_disk(const char *name
, enum eject_op op
)
416 dn
= nick2rdev(name
);
418 dn
= name
; /* Hope for the best. */
419 fd
= open(dn
, O_RDONLY
);
421 err(1, "open: %s", dn
);
425 (void)printf("Closing %s...\n", dn
);
427 if (ioctl(fd
, CDIOCCLOSE
, NULL
) == -1)
428 err(1, "ioctl: CDIOCCLOSE: %s", dn
);
432 (void)printf("Ejecting %s...\n", dn
);
436 /* force eject, unlock the device first */
437 if (ioctl(fd
, DIOCLOCK
, &arg
) == -1)
438 err(1, "ioctl: DIOCLOCK: %s", dn
);
441 if (ioctl(fd
, DIOCEJECT
, &arg
) == -1)
442 err(1, "ioctl: DIOCEJECT: %s", dn
);
446 (void)printf("Locking %s...\n", dn
);
449 if (ioctl(fd
, DIOCLOCK
, &arg
) == -1)
450 err(1, "ioctl: DIOCLOCK: %s", dn
);
454 (void)printf("Unlocking %s...\n", dn
);
457 if (ioctl(fd
, DIOCLOCK
, &arg
) == -1)
458 err(1, "ioctl: DIOCLOCK: %s", dn
);