* Umount before ejecting

* Ultra simple eject command
This commit is contained in:
gmerlin
2006-10-21 10:55:18 +00:00
parent c1f11393ac
commit 63d8add85e
3 changed files with 197 additions and 6 deletions

View File

@@ -1,5 +1,5 @@
/*
$Id: gnu_linux.c,v 1.24 2006/08/02 11:00:31 rocky Exp $
$Id: gnu_linux.c,v 1.25 2006/10/21 10:55:18 gmerlin Exp $
Copyright (C) 2001 Herbert Valerio Riedel <hvr@gnu.org>
Copyright (C) 2002, 2003, 2004, 2005, 2006 Rocky Bernstein
@@ -28,9 +28,12 @@
# include "config.h"
#endif
static const char _rcsid[] = "$Id: gnu_linux.c,v 1.24 2006/08/02 11:00:31 rocky Exp $";
static const char _rcsid[] = "$Id: gnu_linux.c,v 1.25 2006/10/21 10:55:18 gmerlin Exp $";
#include <string.h>
#include <limits.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <cdio/sector.h>
#include <cdio/util.h>
@@ -592,6 +595,107 @@ get_track_msf_linux(void *p_user_data, track_t i_track, msf_t *msf)
}
}
/*!
Follow symlinks until we have the real device file
(idea taken from libunieject).
*/
static void follow_symlink (const char * src, char * dst) {
char tmp_src[PATH_MAX];
char tmp_dst[PATH_MAX];
int len;
strcpy(tmp_src, src);
while(1) {
len = readlink(tmp_src, tmp_dst, PATH_MAX);
if(len < 0) {
strcpy(dst, tmp_src);
return;
}
else {
tmp_dst[len] = '\0';
strcpy(tmp_src, tmp_dst);
}
}
}
/*!
Check, if a device is mounted and return the target (=mountpoint)
needed for umounting (idea taken from libunieject).
*/
static int is_mounted (const char * device, char * target) {
FILE * fp;
char real_device_1[PATH_MAX];
char real_device_2[PATH_MAX];
char file_device[PATH_MAX];
char file_target[PATH_MAX];
fp = fopen ( "/proc/mounts", "r");
/* Older systems just have /etc/mtab */
if(!fp)
fp = fopen ( "/etc/mtab", "r");
/* Neither /proc/mounts nor /etc/mtab could be opened, give up here */
if(!fp) return 0;
/* Get real device */
follow_symlink(device, real_device_1);
/* Read entries */
while ( fscanf(fp, "%s %s %*s %*s %*d %*d\n", file_device, file_target) != EOF ) {
follow_symlink(file_device, real_device_2);
if(!strcmp(real_device_1, real_device_2)) {
strcpy(target, file_target);
fclose(fp);
return 1;
}
}
fclose(fp);
return 0;
}
/*!
Umount a filesystem specified by it's mountpoint. We must do this
by forking and calling the umount command, because the raw umount
(or umount2) system calls will *always* trigger an EPERM even if
we are allowed to umount the filesystem. The umount command is
suid root.
Code here is inspired by the standard linux eject command by
Jeff Tranter and Frank Lichtenheld.
*/
static int do_umount(char * target) {
int status;
switch (fork()) {
case 0: /* child */
execlp("pumount", "pumount", target, NULL);
execlp("umount", "umount", target, NULL);
return -1;
break;
case -1:
return -1;
break;
default: /* parent */
wait(&status);
if (WIFEXITED(status) == 0) {
return -1;
}
if (WEXITSTATUS(status) != 0) {
return -1;
}
break;
}
return 0;
}
/*!
Eject media in CD-ROM drive. Return DRIVER_OP_SUCCESS if successful,
DRIVER_OP_ERROR on error.
@@ -603,10 +707,15 @@ eject_media_linux (void *p_user_data) {
_img_private_t *p_env = p_user_data;
driver_return_code_t ret=DRIVER_OP_SUCCESS;
int status;
int was_open = 0;
char mount_target[PATH_MAX];
if ( p_env->gen.fd <= -1 ) {
p_env->gen.fd = open (p_env->gen.source_name, O_RDONLY|O_NONBLOCK);
}
else {
was_open = 1;
}
if ( p_env->gen.fd <= -1 ) return DRIVER_OP_ERROR;
@@ -622,6 +731,23 @@ eject_media_linux (void *p_user_data) {
cdio_info ("Unknown state of CD-ROM (%d)\n", status);
/* Fall through */
case CDS_DISC_OK:
/* Some systems automount the drive, so we must umount it.
We check if the drive is actually mounted */
if(is_mounted (p_env->gen.source_name, mount_target)) {
/* Try to umount the drive */
if(do_umount(mount_target)) {
cdio_log(CDIO_LOG_WARN, "Could not umount %s\n",
p_env->gen.source_name);
ret=DRIVER_OP_ERROR;
break;
}
/* For some reason, we must close and reopen the device after
it got umounted (at least the commandline eject program
opens the device just after umounting it) */
close(p_env->gen.fd);
p_env->gen.fd = open (p_env->gen.source_name, O_RDONLY|O_NONBLOCK);
}
if((ret = ioctl(p_env->gen.fd, CDROMEJECT)) != 0) {
int eject_error = errno;
/* Try ejecting the MMC way... */
@@ -642,7 +768,10 @@ eject_media_linux (void *p_user_data) {
cdio_warn ("CDROM_DRIVE_STATUS failed: %s\n", strerror(errno));
ret=DRIVER_OP_ERROR;
}
p_env->gen.fd = -1;
if(!was_open) {
close(p_env->gen.fd);
p_env->gen.fd = -1;
}
return ret;
}