]> git.sesse.net Git - vlc/blob - src/interface/intf_eject.c
intf_Eject: remove Linux <= 2.0 support, fix error handling
[vlc] / src / interface / intf_eject.c
1 /*****************************************************************************
2  * intf_eject.c: CD/DVD-ROM ejection handling functions
3  *****************************************************************************
4  * Copyright (C) 2001-2004 the VideoLAN team
5  * $Id$
6  *
7  * Authors: Julien Blache <jb@technologeek.org> for the Linux part
8  *                with code taken from the Linux "eject" command
9  *          Jon Lech Johansen <jon-vl@nanocrew.net> for Darwin
10  *          Gildas Bazin <gbazin@netcourrier.com> for Win32
11  *
12  * This program is free software; you can redistribute it and/or modify
13  * it under the terms of the GNU General Public License as published by
14  * the Free Software Foundation; either version 2 of the License, or
15  * (at your option) any later version.
16  *
17  * This program is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20  * GNU General Public License for more details.
21  *
22  * You should have received a copy of the GNU General Public License
23  * along with this program; if not, write to the Free Software
24  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
25  *****************************************************************************/
26
27 /**
28  *  \file
29  *  This file contain functions to eject CD and DVD drives
30  */
31
32 #ifdef HAVE_CONFIG_H
33 # include "config.h"
34 #endif
35
36 #include <vlc_common.h>
37 #include <vlc_fs.h>
38 #include <vlc_interface.h>
39
40 #if defined( WIN32 ) && !defined( UNDER_CE )
41 #   include <mmsystem.h>
42 #elif defined(__linux__)
43 #   include <sys/types.h>
44 #   include <unistd.h>
45 #   include <fcntl.h>
46 #   include <sys/ioctl.h>
47 #   include <sys/mount.h>
48
49 #   include <linux/cdrom.h>
50
51 #   include <scsi/scsi.h>
52 #   include <scsi/sg.h>
53 #   include <scsi/scsi_ioctl.h>
54 #elif defined (HAVE_DVD_H)
55 #   include <unistd.h>
56 #   include <fcntl.h>
57 #   include <dvd.h>
58 #endif
59
60 #if defined(__linux__)
61 /**
62  * \brief Ejects the CD /DVD using SCSI commands
63  * \ingroup vlc_interface
64  * This function is local
65  * \param i_fd a device nummber
66  * \return 0 on success, VLC_EGENERIC on failure
67  */
68 static int EjectSCSI( int i_fd )
69 {
70     struct sdata
71     {
72         int  inlen;
73         int  outlen;
74         char cmd[256];
75     } scsi_cmd;
76
77     scsi_cmd.inlen  = 0;
78     scsi_cmd.outlen = 0;
79     scsi_cmd.cmd[0] = ALLOW_MEDIUM_REMOVAL;
80     scsi_cmd.cmd[1] = 0;
81     scsi_cmd.cmd[2] = 0;
82     scsi_cmd.cmd[3] = 0;
83     scsi_cmd.cmd[4] = 0;
84     scsi_cmd.cmd[5] = 0;
85     if( ioctl( i_fd, SCSI_IOCTL_SEND_COMMAND, (void *)&scsi_cmd ) < 0 )
86         return VLC_EGENERIC;
87
88     scsi_cmd.inlen  = 0;
89     scsi_cmd.outlen = 0;
90     scsi_cmd.cmd[0] = START_STOP;
91     scsi_cmd.cmd[1] = 0;
92     scsi_cmd.cmd[2] = 0;
93     scsi_cmd.cmd[3] = 0;
94     scsi_cmd.cmd[4] = 1;
95     scsi_cmd.cmd[5] = 0;
96     if( ioctl( i_fd, SCSI_IOCTL_SEND_COMMAND, (void *)&scsi_cmd ) < 0 )
97         return VLC_EGENERIC;
98
99     scsi_cmd.inlen  = 0;
100     scsi_cmd.outlen = 0;
101     scsi_cmd.cmd[0] = START_STOP;
102     scsi_cmd.cmd[1] = 0;
103     scsi_cmd.cmd[2] = 0;
104     scsi_cmd.cmd[3] = 0;
105     scsi_cmd.cmd[4] = 2;
106     scsi_cmd.cmd[5] = 0;
107     if( ioctl( i_fd, SCSI_IOCTL_SEND_COMMAND, (void *)&scsi_cmd ) < 0 )
108         return VLC_EGENERIC;
109
110     /* Force kernel to reread partition table when new disc inserted */
111     ioctl( i_fd, BLKRRPART );
112     return VLC_SUCCESS;
113 }
114 #endif
115
116 #undef intf_Eject
117 /**
118  * \brief Ejects the CD /DVD
119  * \ingroup vlc_interface
120  * \param p_this the calling vlc_object_t
121  * \param psz_device the CD/DVD to eject
122  * \return 0 on success, 1 on failure, -1 if not implemented
123  */
124 int intf_Eject( vlc_object_t *p_this, const char *psz_device )
125 {
126     VLC_UNUSED(p_this);
127
128 #ifdef __APPLE__
129     FILE *p_eject;
130     char *psz_disk;
131     char sz_cmd[32];
132     int i_ret;
133
134     /*
135      * The only way to cleanly unmount the disc under MacOS X
136      * is to use the 'disktool' command line utility. It uses
137      * the non-public Disk Arbitration API, which can not be
138      * used by Cocoa or Carbon applications.
139      */
140
141     if( ( psz_disk = (char *)strstr( psz_device, "disk" ) ) != NULL &&
142         strlen( psz_disk ) > 4 )
143     {
144 #define EJECT_CMD "/usr/sbin/disktool -e %s 0"
145         snprintf( sz_cmd, sizeof(sz_cmd), EJECT_CMD, psz_disk );
146 #undef EJECT_CMD
147
148         if( ( p_eject = popen( sz_cmd, "r" ) ) != NULL )
149         {
150             char psz_result[0x200];
151             i_ret = fread( psz_result, 1, sizeof(psz_result) - 1, p_eject );
152
153             if( i_ret == 0 && ferror( p_eject ) != 0 )
154             {
155                 pclose( p_eject );
156                 return VLC_EGENERIC;
157             }
158
159             pclose( p_eject );
160
161             psz_result[ i_ret ] = 0;
162
163             if( strstr( psz_result, "Disk Ejected" ) != NULL )
164             {
165                 return VLC_SUCCESS;
166             }
167         }
168     }
169
170     return VLC_EGENERIC;
171
172 #elif defined(WIN32)
173     MCI_OPEN_PARMS op;
174     DWORD i_flags;
175     char psz_drive[4];
176
177     memset( &op, 0, sizeof(MCI_OPEN_PARMS) );
178     op.lpstrDeviceType = (LPCSTR)MCI_DEVTYPE_CD_AUDIO;
179
180     strcpy( psz_drive, "X:" );
181     psz_drive[0] = psz_device[0];
182     op.lpstrElementName = psz_drive;
183
184     /* Set the flags for the device type */
185     i_flags = MCI_OPEN_TYPE | MCI_OPEN_TYPE_ID |
186               MCI_OPEN_ELEMENT | MCI_OPEN_SHAREABLE;
187
188     if( mciSendCommand( 0, MCI_OPEN, i_flags, (uintptr_t)&op ) )
189         return VLC_EGENERIC;
190
191     /* Eject disc */
192     mciSendCommand( op.wDeviceID, MCI_SET, MCI_SET_DOOR_OPEN, 0 );
193     /* Release access to the device */
194     mciSendCommand( op.wDeviceID, MCI_CLOSE, MCI_WAIT, 0 );
195
196     return VLC_SUCCESS;
197
198 #elif defined (__linux__) || defined (HAVE_DVD_H)
199     /* This code could be extended to support CD/DVD-ROM chargers */
200     int fd = vlc_open( psz_device, O_RDONLY | O_NONBLOCK );
201     if( fd == -1 )
202     {
203         msg_Err( p_this, "could not open device %s", psz_device );
204         return VLC_EGENERIC;
205     }
206
207 # if defined(__linux__)
208     /* Try a simple ATAPI eject */
209     if( ioctl( fd, CDROMEJECT, 0 ) < 0
210      && EjectSCSI( fd ) )
211 # else
212     if( ioctl( fd, CDROMEJECT, 0 ) < 0 )
213 # endif
214     {
215         msg_Err( p_this, "could not eject %s", psz_device );
216         close( fd );
217         return VLC_EGENERIC;
218     }
219     return VLC_SUCCESS;
220
221 #else
222     msg_Warn( p_this, "CD-Rom ejection unsupported on this platform" );
223     return VLC_EGENERIC;
224 #endif
225 }