1 /*
2     Copyright 2010 Michael Zanetti <mzanetti@kde.org>
3     Copyright 2010-2012 Lukáš Tinkl <ltinkl@redhat.com>
4 
5     This library is free software; you can redistribute it and/or
6     modify it under the terms of the GNU Lesser General Public
7     License as published by the Free Software Foundation; either
8     version 2.1 of the License, or (at your option) version 3, or any
9     later version accepted by the membership of KDE e.V. (or its
10     successor approved by the membership of KDE e.V.), which shall
11     act as a proxy defined in Section 6 of version 3 of the license.
12 
13     This library is distributed in the hope that it will be useful,
14     but WITHOUT ANY WARRANTY; without even the implied warranty of
15     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16     Lesser General Public License for more details.
17 
18     You should have received a copy of the GNU Lesser General Public
19     License along with this library. If not, see <http://www.gnu.org/licenses/>.
20 */
21 
22 #include <sys/types.h>
23 #include <sys/stat.h>
24 #include <fcntl.h>
25 #include <string.h>
26 #include <errno.h>
27 #include <unistd.h>
28 #include <stdlib.h>
29 
30 #include <QFile>
31 #include <QDebug>
32 
33 #include "udisksopticaldrive.h"
34 #include "udisks2.h"
35 #include "udisksdevice.h"
36 #include "dbus/manager.h"
37 
38 using namespace Solid::Backends::UDisks2;
39 
OpticalDrive(Device * device)40 OpticalDrive::OpticalDrive(Device *device)
41     : StorageDrive(device)
42     , m_ejectInProgress(false)
43     , m_readSpeed(0)
44     , m_writeSpeed(0)
45     , m_speedsInit(false)
46 {
47     m_device->registerAction("eject", this,
48                              SLOT(slotEjectRequested()),
49                              SLOT(slotEjectDone(int, const QString&)));
50 
51     connect(m_device, SIGNAL(changed()), this, SLOT(slotChanged()));
52 }
53 
~OpticalDrive()54 OpticalDrive::~OpticalDrive()
55 {
56 }
57 
eject()58 bool OpticalDrive::eject()
59 {
60     if (m_ejectInProgress)
61         return false;
62     m_ejectInProgress = true;
63     m_device->broadcastActionRequested("eject");
64 
65     const QString path = m_device->udi();
66     QDBusConnection c = QDBusConnection::connectToBus(QDBusConnection::SystemBus, "Solid::Udisks2::OpticalDrive::" + path);
67 
68     // if the device is mounted, unmount first
69     QString blockPath;
70     org::freedesktop::DBus::ObjectManager manager(UD2_DBUS_SERVICE, UD2_DBUS_PATH, c);
71     QDBusPendingReply<DBUSManagerStruct> reply = manager.GetManagedObjects();
72     reply.waitForFinished();
73     if (!reply.isError()) {  // enum devices
74         Q_FOREACH(const QDBusObjectPath &objPath, reply.value().keys()) {
75             const QString udi = objPath.path();
76 
77             //qDebug() << "Inspecting" << udi;
78 
79             if (udi == UD2_DBUS_PATH_MANAGER || udi == UD2_UDI_DISKS_PREFIX || udi.startsWith(UD2_DBUS_PATH_JOBS))
80                 continue;
81 
82             Device device(udi);
83             if (device.drivePath() == path && device.isMounted()) {
84                 //qDebug() << "Got mounted block device:" << udi;
85                 blockPath = udi;
86                 break;
87             }
88         }
89     }
90     else  // show error
91     {
92         qWarning() << "Failed enumerating UDisks2 objects:" << reply.error().name() << "\n" << reply.error().message();
93     }
94 
95     if (!blockPath.isEmpty()) {
96         //qDebug() << "Calling unmount on" << blockPath;
97         QDBusMessage msg = QDBusMessage::createMethodCall(UD2_DBUS_SERVICE, blockPath, UD2_DBUS_INTERFACE_FILESYSTEM, "Unmount");
98         msg << QVariantMap();   // options, unused now
99         c.call(msg, QDBus::BlockWithGui);
100     }
101 
102     QDBusMessage msg = QDBusMessage::createMethodCall(UD2_DBUS_SERVICE, path, UD2_DBUS_INTERFACE_DRIVE, "Eject");
103     msg << QVariantMap();
104     return c.callWithCallback(msg, this, SLOT(slotDBusReply(const QDBusMessage &)), SLOT(slotDBusError(const QDBusError &)));
105 }
106 
slotDBusReply(const QDBusMessage &)107 void OpticalDrive::slotDBusReply(const QDBusMessage &/*reply*/)
108 {
109     m_ejectInProgress = false;
110     m_device->broadcastActionDone("eject");
111 }
112 
slotDBusError(const QDBusError & error)113 void OpticalDrive::slotDBusError(const QDBusError &error)
114 {
115     m_ejectInProgress = false;
116     m_device->broadcastActionDone("eject", m_device->errorToSolidError(error.name()),
117                                   m_device->errorToString(error.name()) + ": " +error.message());
118 }
119 
slotEjectRequested()120 void OpticalDrive::slotEjectRequested()
121 {
122     m_ejectInProgress = true;
123     Q_EMIT ejectRequested(m_device->udi());
124 }
125 
slotEjectDone(int error,const QString & errorString)126 void OpticalDrive::slotEjectDone(int error, const QString &errorString)
127 {
128     m_ejectInProgress = false;
129     Q_EMIT ejectDone(static_cast<Solid::ErrorType>(error), errorString, m_device->udi());
130 }
131 
initReadWriteSpeeds() const132 void OpticalDrive::initReadWriteSpeeds() const
133 {
134 #if 0
135     int read_speed, write_speed;
136     char *write_speeds = 0;
137     QByteArray device_file = QFile::encodeName(m_device->property("Device").toString());
138 
139     //qDebug("Doing open (\"%s\", O_RDONLY | O_NONBLOCK)", device_file.constData());
140     int fd = open(device_file, O_RDONLY | O_NONBLOCK);
141     if (fd < 0) {
142         qWarning("Cannot open %s: %s", device_file.constData(), strerror (errno));
143         return;
144     }
145 
146     if (get_read_write_speed(fd, &read_speed, &write_speed, &write_speeds) >= 0) {
147         m_readSpeed = read_speed;
148         m_writeSpeed = write_speed;
149 
150         QStringList list = QString::fromLatin1(write_speeds).split(',', QString::SkipEmptyParts);
151         Q_FOREACH (const QString & speed, list)
152             m_writeSpeeds.append(speed.toInt());
153 
154         free(write_speeds);
155 
156         m_speedsInit = true;
157     }
158 
159     close(fd);
160 #endif
161 }
162 
writeSpeeds() const163 QList<int> OpticalDrive::writeSpeeds() const
164 {
165     if (!m_speedsInit)
166         initReadWriteSpeeds();
167     //qDebug() << "solid write speeds:" << m_writeSpeeds;
168     return m_writeSpeeds;
169 }
170 
writeSpeed() const171 int OpticalDrive::writeSpeed() const
172 {
173     if (!m_speedsInit)
174         initReadWriteSpeeds();
175     return m_writeSpeed;
176 }
177 
readSpeed() const178 int OpticalDrive::readSpeed() const
179 {
180     if (!m_speedsInit)
181         initReadWriteSpeeds();
182     return m_readSpeed;
183 }
184 
supportedMedia() const185 Solid::OpticalDrive::MediumTypes OpticalDrive::supportedMedia() const
186 {
187     const QStringList mediaTypes = m_device->prop("MediaCompatibility").toStringList();
188     Solid::OpticalDrive::MediumTypes supported;
189 
190     QMap<Solid::OpticalDrive::MediumType, QString> map;
191     map[Solid::OpticalDrive::Cdr] = "optical_cd_r";
192     map[Solid::OpticalDrive::Cdrw] = "optical_cd_rw";
193     map[Solid::OpticalDrive::Dvd] = "optical_dvd";
194     map[Solid::OpticalDrive::Dvdr] = "optical_dvd_r";
195     map[Solid::OpticalDrive::Dvdrw] ="optical_dvd_rw";
196     map[Solid::OpticalDrive::Dvdram] ="optical_dvd_ram";
197     map[Solid::OpticalDrive::Dvdplusr] ="optical_dvd_plus_r";
198     map[Solid::OpticalDrive::Dvdplusrw] ="optical_dvd_plus_rw";
199     map[Solid::OpticalDrive::Dvdplusdl] ="optical_dvd_plus_r_dl";
200     map[Solid::OpticalDrive::Dvdplusdlrw] ="optical_dvd_plus_rw_dl";
201     map[Solid::OpticalDrive::Bd] ="optical_bd";
202     map[Solid::OpticalDrive::Bdr] ="optical_bd_r";
203     map[Solid::OpticalDrive::Bdre] ="optical_bd_re";
204     map[Solid::OpticalDrive::HdDvd] ="optical_hddvd";
205     map[Solid::OpticalDrive::HdDvdr] ="optical_hddvd_r";
206     map[Solid::OpticalDrive::HdDvdrw] ="optical_hddvd_rw";
207     // TODO add these to Solid
208     //map[Solid::OpticalDrive::Mo] ="optical_mo";
209     //map[Solid::OpticalDrive::Mr] ="optical_mrw";
210     //map[Solid::OpticalDrive::Mrw] ="optical_mrw_w";
211 
212     Q_FOREACH ( const Solid::OpticalDrive::MediumType & type, map.keys() )
213     {
214         if ( mediaTypes.contains( map[type] ) )
215         {
216             supported |= type;
217         }
218     }
219 
220     return supported;
221 }
222 
slotChanged()223 void OpticalDrive::slotChanged()
224 {
225     m_speedsInit = false; // reset the read/write speeds, changes eg. with an inserted media
226 }
227