1/*
2 * disks.cpp
3 *
4 * Copyright (c) 1998 Michael Kropfberger <michael.kropfberger@gmx.net>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19 */
20
21#include "disks.h"
22
23#include <unistd.h>
24#include <sys/types.h>
25
26#include <QtCore/QFileInfo>
27#include <QtCore/QDir>
28
29#include <kglobal.h>
30#include <kdebug.h>
31#include <kprocess.h>
32#include <klocale.h>
33//#include <solid/device.h>
34
35/****************************************************/
36/********************* DiskEntry ********************/
37/****************************************************/
38
39/**
40 * Constructor
41**/
42void DiskEntry::init(const char *name)
43{
44 setObjectName( QLatin1String( name ) );
45 device.clear();
46 type.clear();
47 mountedOn.clear();
48 options.clear();
49 size=0;
50 used=0;
51 avail=0;
52 isMounted=false;
53 mntcmd.clear();
54 umntcmd.clear();
55 iconSetByUser=false;
56 icoName.clear();
57
58
59 // BackgroundProcesses ****************************************
60
61 sysProc = new KProcess();
62 Q_CHECK_PTR(sysProc);
63 sysProc->setOutputChannelMode( KProcess::MergedChannels );
64 connect( sysProc, SIGNAL(readyReadStandardError()),
65 this, SLOT (receivedSysStdErrOut()) );
66 connect( sysProc, SIGNAL(readyReadStandardOutput()),
67 this, SLOT (receivedSysStdErrOut()) );
68 readingSysStdErrOut=false;
69
70
71}
72
73DiskEntry::DiskEntry(QObject *parent, const char *name)
74 : QObject (parent)
75{
76 init(name);
77}
78
79DiskEntry::DiskEntry(const QString & deviceName, QObject *parent, const char *name)
80 : QObject (parent)
81{
82 init(name);
83
84 setDeviceName(deviceName);
85}
86DiskEntry::~DiskEntry()
87{
88 disconnect(this);
89 if ( sysProc->state() == QProcess::Running )
90 {
91 sysProc->terminate();
92 sysProc->waitForFinished(-1);
93 }
94 delete sysProc;
95}
96
97int DiskEntry::toggleMount()
98{
99 if (!mounted())
100 return mount();
101 else
102 return umount();
103}
104
105int DiskEntry::mount()
106{
107 QString cmdS=mntcmd;
108 if ( cmdS.isEmpty() )
109 { // generate default mount cmd
110 if ( getuid()!=0 ) // user mountable
111 {
112 cmdS = QLatin1String( "mount %d" );
113 }
114 else // root mounts with all params/options
115 {
116 // FreeBSD's mount(8) is picky: -o _must_ go before
117 // the device and mountpoint.
118 cmdS = QLatin1String( "mount -t%t -o%o %d %m" );
119 }
120 }
121
122 cmdS.replace( QLatin1String( "%d" ), deviceName() );
123 cmdS.replace( QLatin1String( "%m" ), mountPoint() );
124 cmdS.replace( QLatin1String( "%t" ), fsType() );
125 cmdS.replace( QLatin1String( "%o" ), mountOptions() );
126
127 kDebug() << "mount-cmd: [" << cmdS << "]" ;
128 int e = sysCall( cmdS );
129 if (!e)
130 setMounted( true );
131 kDebug() << "mount-cmd: e=" << e ;
132 return e;
133}
134
135int DiskEntry::umount()
136{
137 kDebug() << "umounting" ;
138 QString cmdS = umntcmd;
139 if ( cmdS.isEmpty() ) // generate default umount cmd
140 cmdS = QLatin1String( "umount %d" );
141
142 cmdS.replace( QLatin1String( "%d" ), deviceName() );
143 cmdS.replace( QLatin1String( "%m" ), mountPoint() );
144
145 kDebug() << "umount-cmd: [" << cmdS << "]" ;
146 int e = sysCall( cmdS );
147 if ( !e )
148 setMounted( false );
149 kDebug() << "umount-cmd: e=" << e ;
150
151 return e;
152}
153
154int DiskEntry::remount()
155{
156 if ( mntcmd.isEmpty() && umntcmd.isEmpty() // default mount/umount commands
157 && ( getuid()==0) ) // you are root
158 {
159 QString oldOpt = options;
160 if (options.isEmpty())
161 options = QLatin1String( "remount" );
162 else
163 options += QLatin1String( ",remount" );
164
165 int e = mount();
166 options = oldOpt;
167 return e;
168 } else
169 {
170 if ( int e=umount() )
171 return mount();
172 else
173 return e;
174 }
175}
176
177void DiskEntry::setMountCommand(const QString & mnt)
178{
179 mntcmd=mnt;
180}
181
182void DiskEntry::setUmountCommand(const QString & umnt)
183{
184 umntcmd=umnt;
185}
186
187void DiskEntry::setIconName(const QString & iconName)
188{
189 iconSetByUser=true;
190 icoName=iconName;
191 if ( icoName.right(6) == QLatin1String( "_mount" ) )
192 icoName.truncate(icoName.length()-6);
193 else if ( icoName.right(8) == QLatin1String( "_unmount" ) )
194 icoName.truncate(icoName.length()-8);
195
196 emit iconNameChanged();
197}
198
199void DiskEntry::setIconToDefault()
200{
201 iconSetByUser = false;
202 icoName.clear();
203
204}
205
206QString DiskEntry::iconName()
207{
208 if (iconSetByUser)
209 return icoName;
210 else
211 return guessIconName();
212}
213
214//TODO: Need porting to solid
215QString DiskEntry::guessIconName()
216{
217 QString iconName;
218
219 /*
220 //List Solid Devices
221 foreach (const Solid::Device &device, Solid::Device::listFromType(Solid::DeviceInterface::StorageVolume))
222 {
223 kDebug() << device.udi().toLatin1().constData() << device.vendor() << device.product() << device.icon();
224 }
225 Solid::Device * device = new Solid::Device(deviceName());
226 kDebug() << "guess" << deviceName() << device->icon();
227 delete device;
228 */
229 // try to be intelligent
230 if (mountPoint().contains(QLatin1String( "cdrom" ),Qt::CaseInsensitive))
231 iconName+=QLatin1String( "media-optical" );
232 else if (deviceName().contains(QLatin1String( "cdrom" ),Qt::CaseInsensitive))
233 iconName+=QLatin1String( "media-optical" );
234 else if (mountPoint().contains(QLatin1String( "writer" ),Qt::CaseInsensitive))
235 iconName+=QLatin1String( "media-optical-recordable" );
236 else if (deviceName().contains(QLatin1String( "writer" ),Qt::CaseInsensitive))
237 iconName+=QLatin1String( "media-optical-recordable" );
238 else if (mountPoint().contains(QLatin1String( "mo" ),Qt::CaseInsensitive))
239 iconName+=QLatin1String( "mo" ); //TODO
240 else if (deviceName().contains(QLatin1String( "mo" ),Qt::CaseInsensitive))
241 iconName+=QLatin1String( "mo" ); //TODO
242 else if (deviceName().contains(QLatin1String( "fd" ),Qt::CaseInsensitive))
243 {
244 if (deviceName().contains(QLatin1String( "360" ),Qt::CaseInsensitive))
245 iconName+=QLatin1String( "5floppy" ); //TODO
246 if (deviceName().contains(QLatin1String( "1200" ),Qt::CaseInsensitive))
247 iconName+=QLatin1String( "5floppy" ); //TODO
248 else
249 iconName+=QLatin1String( "media-floppy" );
250 }
251 else if (mountPoint().contains(QLatin1String( "floppy" ),Qt::CaseInsensitive))
252 iconName+=QLatin1String( "media-floppy" );
253 else if (mountPoint().contains(QLatin1String( "zip" ),Qt::CaseInsensitive))
254 iconName+=QLatin1String( "zip" ); //TODO
255 else if (fsType().contains(QLatin1String( "nfs" ),Qt::CaseInsensitive))
256 iconName+=QLatin1String( "nfs" ); //TODO
257 else
258 iconName+=QLatin1String( "drive-harddisk" );
259 ///mounted() ? iconName+="_mount" : iconName+="_unmount";
260 // if ( !mountOptions().contains("user",Qt::CaseInsensitive) )
261 // iconName.prepend("root_"); // special root icon, normal user can't mount
262
263 //debug("device %s is %s",deviceName().latin1(),iconName.latin1());
264
265 //emit iconNameChanged();
266 return iconName;
267}
268
269
270/***************************************************************************
271 * starts a command on the underlying system via /bin/sh
272**/
273int DiskEntry::sysCall(QString & completeCommand)
274{
275 if (readingSysStdErrOut || sysProc->state() == QProcess::Running )
276 return -1;
277
278 sysStringErrOut=i18n("Called: %1\n\n", completeCommand); // put the called command on ErrOut
279 sysProc->clearProgram();
280
281 //Split command and arguments to use the new API, otherwise it doesn't work
282 QTextStream tS(&completeCommand);
283
284 QString command;
285 tS >> command;
286
287 QString tmp;
288 QStringList args;
289 while( !tS.atEnd() )
290 {
291 tS >> tmp;
292 args << tmp;
293 }
294
295 sysProc->setProgram(command, args);
296 sysProc->start();
297
298 if ( !sysProc->waitForStarted(-1) )
299 kFatal() << i18n("could not execute %1", command) ;
300
301 sysProc->waitForFinished(-1);
302
303 if (sysProc->exitCode()!=0)
304 emit sysCallError(this, sysProc->exitStatus());
305
306 return (sysProc->exitCode());
307}
308
309
310/***************************************************************************
311 * is called, when the Sys-command writes on StdOut or StdErr
312**/
313void DiskEntry::receivedSysStdErrOut()
314{
315 QString stdOut = QString::fromLocal8Bit( sysProc->readAllStandardOutput() );
316 QString stdErr = QString::fromLocal8Bit( sysProc->readAllStandardError() );
317
318 sysStringErrOut.append( stdOut );
319 sysStringErrOut.append( stdErr );
320}
321
322float DiskEntry::percentFull() const
323{
324 if (size != 0)
325 {
326 return 100 - ( ((float)avail / (float)size) * 100 );
327 }
328 else
329 {
330 return -1;
331 }
332}
333
334void DiskEntry::setDeviceName(const QString & deviceName)
335{
336 device=deviceName;
337 emit deviceNameChanged();
338}
339
340QString DiskEntry::deviceRealName() const
341{
342 QFileInfo inf( device );
343 QDir dir( inf.absolutePath() );
344 QString relPath = inf.fileName();
345 if ( inf.isSymLink() )
346 {
347 QString link = inf.readLink();
348 if ( link.startsWith( QLatin1Char( '/' ) ) )
349 return link;
350 relPath = link;
351 }
352 return dir.canonicalPath() + QLatin1Char( '/' ) + relPath;
353}
354
355void DiskEntry::setMountPoint(const QString & mountPoint)
356{
357 mountedOn=mountPoint;
358 emit mountPointChanged();
359}
360
361QString DiskEntry::realMountPoint() const
362{
363 QDir dir( mountedOn );
364 return dir.canonicalPath();
365}
366
367void DiskEntry::setMountOptions(const QString & mountOptions)
368{
369 options=mountOptions;
370 emit mountOptionsChanged();
371}
372
373void DiskEntry::setFsType(const QString & fsType)
374{
375 type=fsType;
376 emit fsTypeChanged();
377}
378
379void DiskEntry::setMounted(bool nowMounted)
380{
381 isMounted=nowMounted;
382 emit mountedChanged();
383}
384
385void DiskEntry::setKBSize(qulonglong kb_size)
386{
387 size=kb_size;
388 emit kBSizeChanged();
389}
390
391void DiskEntry::setKBUsed(qulonglong kb_used)
392{
393 used=kb_used;
394 if ( size < (used+avail) )
395 { //adjust kBAvail
396 kWarning() << "device " << device << ": kBAvail(" << avail << ")+*kBUsed(" << used << ") exceeds kBSize(" << size << ")" ;
397 setKBAvail(size-used);
398 }
399 emit kBUsedChanged();
400}
401
402void DiskEntry::setKBAvail(qulonglong kb_avail)
403{
404 avail=kb_avail;
405 if ( size < (used+avail) )
406 { //adjust kBUsed
407 kWarning() << "device " << device << ": *kBAvail(" << avail << ")+kBUsed(" << used << ") exceeds kBSize(" << size << ")" ;
408 setKBUsed(size-avail);
409 }
410 emit kBAvailChanged();
411}
412
413#include "disks.moc"
414
415