/*
* Copyright (c) 1995-2000 Shunsuke Akiyama <akiyama@FreeBSD.org>.
* All rights reserved.
*
* 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 AUTHOR 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 AUTHOR 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.
*
* $Id: eject.c,v 1.10 2000/09/06 13:40:12 akiyama Exp $
*/
#include <stdio.h>
#include <errno.h>
#include <fcntl.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <unistd.h>
#include <sys/param.h>
#include <sys/ucred.h>
#include <sys/mount.h>
#include <sys/cdio.h>
#include <sys/ioctl.h>
#include <sys/stat.h>
extern int optind;
void usage(void);
int check_device(char *, char **);
int unmount_fs(char *, char **);
int eject(char *, char *);
char *program = "eject";
int fflag; /* force unmount filesystem */
int nflag; /* not execute operation */
int vflag; /* verbose operation */
/*
* simple eject program
*
* usage: eject [-fnv] <device name>
*/
main(argc, argv)
int argc;
char *argv[];
{
int ch;
int sts;
char *device, *name;
char *err;
char *defdev;
fflag = nflag = vflag = 0;
defdev = getenv("EJECT");
while ((ch = getopt(argc, argv, "fnv?")) != EOF) {
switch (ch) {
case 'f' :
fflag = 1;
break;
case 'n' :
nflag = 1;
break;
case 'v' :
vflag = 1;
break;
case '?' :
default :
usage();
}
}
argc -= optind;
argv += optind;
if (defdev == NULL) {
if (argc == 0) {
usage();
}
name = strdup(*argv);
} else {
name = strdup(defdev);
}
sts = check_device(name, &device);
if (sts < 0) {
perror(program);
exit(1);
}
sts = unmount_fs(name, &err);
if (sts < 0) {
perror(err);
exit(1);
}
sts = eject(name, device);
if (sts < 0) {
perror(program);
exit(1);
}
exit(0);
}
/*
* check whether device exists.
*/
int
check_device(name, device)
char *name;
char **device;
{
int sts;
struct stat sb;
if (strncmp("/dev/", name, strlen("/dev/")) == 0) {
if (asprintf(device, "%s", name) == -1)
return sts;
}
else {
if (asprintf(device, "/dev/%s", name) == -1)
return sts;
}
if (vflag || nflag) {
printf("%s: using device %s\n", program, device);
}
sts = stat(*device, &sb);
return sts;
}
/*
* unmount all ejectable filesystems.
*/
struct mntlist {
struct mntlist *next;
char *mntonname;
char *mntfromname;
};
int
unmount_fs(name, err)
char *name;
char **err;
{
int mnts;
struct statfs *mntbuf;
int len, i, n;
char *p, *q;
int sts, flag;
struct mntlist *head, *mp, *nextp;
head = NULL;
mnts = getmntinfo(&mntbuf, MNT_NOWAIT);
if (mnts == 0) {
return -1;
}
/* get proper mount information into the list */
len = strlen(name);
for (n = 0; n < mnts; n++) {
if (strncmp("/dev/", name, strlen("/dev/")) == 0)
p = mntbuf[n].f_mntfromname;
else {
p = rindex(mntbuf[n].f_mntfromname, '/');
if (p == NULL)
continue;
++p;
}
for (i = 0, p, q = name; *p != '\0' && *q != '\0'; ++i, ++p, ++q) {
if (*p != *q) {
break;
}
}
if (i == len) {
if (*p == '\0' || strchr("abcdefghs", *p) != NULL) {
if (nflag || vflag) {
printf("%s: %s mounted on %s\n", program,
mntbuf[n].f_mntfromname, mntbuf[n].f_mntonname);
}
mp = malloc(sizeof (struct mntlist));
if (mp == NULL) {
return -1;
}
if (head) {
mp->next = head;
} else {
mp->next = NULL;
}
mp->mntfromname = mntbuf[n].f_mntfromname;
mp->mntonname = mntbuf[n].f_mntonname;
head = mp;
}
}
}
/* unmount filesystem(s) */
for (mp = head; mp != NULL; mp = nextp) {
if (nflag || vflag) {
printf("%s: ", program);
if (fflag) {
printf("force ");
}
printf("unmounting %s\n", mp->mntonname);
}
if (!nflag) {
sync();
flag = fflag ? MNT_FORCE : 0;
sts = unmount(mp->mntonname, flag);
} else {
sts = 0;
}
if (sts < 0 && fflag == 0) {
asprintf(err, "%s: %s", program, mp->mntonname);
return sts;
}
nextp = mp->next;
free(mp);
}
return 0;
}
/*
* eject media from device
*/
int
eject(name, device)
char *name;
char *device;
{
int fd, sts;
fd = open(device, O_RDONLY);
if (fd < 0) {
if (errno == ENXIO) {
/* It's might be no medium */
if (vflag) {
printf("%s: no media in %s\n", program, name);
}
return 0;
}
return -1;
}
if (!nflag) {
if (vflag) {
printf("%s: ejecting media from %s\n", program, name);
}
sts = ioctl(fd, CDIOCALLOW);
if (sts >= 0) {
sts = ioctl(fd, CDIOCEJECT);
}
} else {
printf("%s: ejecting media from %s\n", program, name);
sts = 0;
}
close(fd);
return sts;
}
/*
* print short usage
*/
void
usage(void)
{
fprintf(stderr, "usage: %s [-fnv] device\n", program);
exit(1);
}
syntax highlighted by Code2HTML, v. 0.9.1