/* * Copyright (c) 1995-2000 Shunsuke Akiyama . * 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 #include #include #include #include #include #include #include #include #include #include #include #include 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] */ 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); }