source: src-qt4/pc-mounttray/menuItem.cpp @ dadf169

9.2-releasereleng/10.0releng/10.0.1releng/10.0.2releng/10.0.3releng/10.1
Last change on this file since dadf169 was dadf169, checked in by Ken Moore <ken@…>, 16 months ago

Add the "longnames" flag to the FAT filesystem mount command

  • Property mode set to 100644
File size: 13.1 KB
Line 
1#include <pcbsd-utils.h>
2#include "menuItem.h"
3
4
5MenuItem::MenuItem(QWidget* parent, QString newdevice, QString newlabel, QString newtype, QString newfs) : QWidgetAction(parent)
6{
7  AMFILE= QDir::homePath() + "/.pc-automounttray";   //File to save/load all the devices to be automounted
8  //Set the device info variables
9  if( !newdevice.startsWith(DEVICEDIR) ){ newdevice.prepend(DEVICEDIR); }
10  device = newdevice;
11  devType = newtype;
12  filesystem = newfs;
13  //Create the layout
14  QGridLayout* layout = new QGridLayout();
15  QHBoxLayout* hlayout = new QHBoxLayout();
16  //Create the gui items
17  devLabel = new QLabel;
18    devLabel->setToolTip(device);
19    devLabel->setText(newlabel);
20   
21  devIcon = new QLabel;
22    devIcon->setToolTip(device);
23  currentSpace = new QProgressBar;
24    currentSpace->setMinimum(0);
25  pushMount = new QPushButton;
26  checkAutomount = new QCheckBox;
27    checkAutomount->setChecked( checkSavedAutoMount() );
28    checkAutomount->setText( tr("Auto-mount this device") );
29  //Add the widgets to the layout
30  layout->addWidget(devIcon,0,0,3,1);   
31  hlayout->addWidget(devLabel);
32  hlayout->addWidget(pushMount);
33  layout->addLayout(hlayout,0,1);
34  layout->addWidget(currentSpace,1,1);
35  layout->addWidget(checkAutomount,2,1);
36  //Set the layout
37  frame = new QWidget();
38  frame->setLayout(layout);
39  this->setDefaultWidget(frame);
40
41  //Connect the signals/slots
42  connect(pushMount,SIGNAL(clicked()), this, SLOT(slotMountClicked()));
43  connect(checkAutomount,SIGNAL(toggled(bool)),this,SLOT(slotAutoMountToggled(bool)));
44
45  //Setup the device Icon based on the type
46  if(devType == "USB"){ devIcon->setPixmap(QPixmap(":icons/usb.png")); }
47  else if(devType == "SATA"){ devIcon->setPixmap(QPixmap(":icons/harddrive.png")); }
48  else if(devType == "SD"){ devIcon->setPixmap(QPixmap(":icons/sdcard.png")); }
49  else if(devType == "CD9660"){ devIcon->setPixmap(QPixmap(":icons/dvd.png")); }
50  else if(devType == "ISO"){devIcon->setPixmap(QPixmap(":icons/dvd.png")); }
51  //Start the automount procedure if necessary
52  if(checkAutomount->isChecked() || devType=="ISO"){
53    QTimer::singleShot(500,this,SLOT( slotMountClicked() ));
54  }
55  //Update the Item based upon current device status
56  updateItem();
57
58}
59
60MenuItem::~MenuItem(){
61}
62
63/*
64  PUBLIC FUNCTIONS
65*/
66
67void MenuItem::updateItem(){
68  //Update the item visuals, based upon current device status
69  if( isConnected() ){
70    if( isMounted() ){
71      if(mountpoint.isEmpty()){
72        //detect the current mountpoint
73        QString output = pcbsd::Utils::runShellCommandSearch("mount",device);
74        mountpoint = output.section(" on ",1,1).section(" (",0,0).replace(" ","-");
75      }
76      devIcon->setEnabled(TRUE);  //Make the icon full color
77      devIcon->setToolTip(device+"\n"+QString(tr("Mounted at %1")).arg(mountpoint));
78      pushMount->setText(tr("Eject"));
79      pushMount->setIcon(QIcon(":icons/eject.png"));
80      if(devType != "ISO"){ checkAutomount->setVisible(TRUE); }
81      else{ checkAutomount->setVisible(FALSE); }
82    }else{       
83      devIcon->setEnabled(FALSE); //Grey out the icon if not mounted
84      devIcon->setToolTip(device);
85      pushMount->setText(tr("Mount"));
86      pushMount->setIcon(QIcon(":icons/mount.png"));
87      checkAutomount->setVisible(FALSE);
88    }
89  }else{
90    emit itemRemoved(device);
91    return;
92  }
93  //Set visibility and sizes on progressbar
94  updateSizes();
95}
96       
97//Getters
98QString MenuItem::getDeviceName(){
99  return devLabel->text();     
100}
101       
102//Device information
103bool MenuItem::isConnected(){
104  if( QFile::exists(device) ){ return TRUE; }
105  else{ return FALSE; }
106}
107
108bool MenuItem::isMounted(){
109  //Check if device is mounted
110  QStringList chk = pcbsd::Utils::runShellCommand("mount");
111  bool mounted=false;
112  for(int i=0; i<chk.length(); i++){
113    mounted = chk[i].contains(device) || chk[i].contains(devLabel->text()) || chk[i].contains(devLabel->text().replace(" ","-"));
114    if(mounted){ 
115      //Save the mountpoint if it is mounted
116      mountpoint = chk[i].section(" on ",1,10).section("(",0,0).simplified();
117      break; 
118    }
119  }
120  return mounted;
121}
122
123//Cleanup function
124void MenuItem::cleanup(){
125  if( isMounted() ){
126    unmountItem(); //unmount and remove mountpoint
127  }else{
128    //Just check for mountpoint removal
129    if(QFile::exists(mountpoint)){
130      qDebug() << "Removing old mountpoint:" << mountpoint;
131      QString output = pcbsd::Utils::runShellCommand("rmdir "+mountpoint).join(" ");
132      if(!output.isEmpty()){ qDebug() << " -Error:" <<output; }
133    }
134  }
135}
136/*
137  PRIVATE FUNCTIONS
138*/
139void MenuItem::slotMountClicked(){
140  if( isConnected() ){
141    if( !isMounted() ){
142      mountItem();
143    }else{
144      unmountItem(); 
145    }
146  }else{
147    emit itemRemoved(device);     
148  }
149  updateItem();
150}
151
152void MenuItem::slotAutoMountToggled(bool checked){
153  qDebug() << "Auto-mount toggled for:" << device << checked;
154  QString entry = devLabel->text()+":::"+devType+":::"+filesystem;
155  if(checked){
156    //Add this entry to the auto-mount file
157    QString cmd = "echo \""+entry+"\" >> "+AMFILE;
158    system( cmd.toUtf8() );
159  }else{
160    //Remove this entry from the automount file
161    QString tmpFile = AMFILE+".tmp";
162    QString cmd = "cat "+AMFILE+" | grep -v "+entry+" > "+tmpFile+"; mv "+tmpFile+" "+AMFILE;
163    system( cmd.toUtf8() );
164  }
165}
166
167bool MenuItem::checkSavedAutoMount(){
168  if(QFile::exists(AMFILE)){
169    QString cmd = "cat "+AMFILE;
170    QString search = devLabel->text() +" "+ devType +" "+ filesystem;
171    QString chk = pcbsd::Utils::runShellCommandSearch(cmd, search);
172    if( chk.isEmpty() ){ return FALSE; }
173    else{ return TRUE; }
174  }else{
175    return FALSE;
176  }
177}
178
179void MenuItem::mountItem(){
180  //Mount the device
181 
182  //Create the full path to the mountpoint
183  QString deviceName = devLabel->text();
184  QString mntpoint = MOUNTDIR + deviceName.replace(" ","-"); //take into account spaces in the name
185
186  //Create the fileystem specific command for mounting
187  QString fstype;
188  QString fsopts="";
189  if( filesystem == "FAT" ){ fstype = "mount -t msdosfs"; fsopts = "-o large,longnames,-m=644,-M=777"; }
190  else if(filesystem == "NTFS"){ fstype = "ntfs-3g"; }
191  else if(filesystem == "EXT"){ fstype = "mount -t ext2fs"; }
192  else if(filesystem == "CD9660"){ fstype = "mount -t cd9660"; }
193  else if(filesystem == "UFS"){ fstype = "mount -t ufs"; }
194  else if(filesystem == "REISERFS"){ fstype = "mount -t reiserfs"; }
195  else if(filesystem == "XFS"){ fstype = "mount -t xfs"; }
196  else{
197    qDebug() << "Unknown device filesystem:" << device << filesystem << " attempting mount_auto command";
198    fstype = "mount_auto";
199    //QMessageBox::warning(this,tr("Unknown Device Filesystem"),tr("The filesystem on this device is unknown and cannot be mounted at this time") );
200    //return FALSE;
201  }
202  //Make sure the mntpoint is available
203  QDir mpd(mntpoint);
204  if(mpd.exists()){
205    //Remove the existing directory (will work only if it is empty)
206    mpd.cdUp();
207    mpd.rmdir(mntpoint);
208  }
209  //Prepare the commands to run
210  QString cmd1 = "mkdir " + mntpoint;
211  QString cmd2 = fstype + " " +fsopts + " " + device + " " + mntpoint;
212  QString cmd3 = "chmod 777 " + mntpoint; //to set full user/root access
213 
214  qDebug() << "Mounting device" << device << "on" << mntpoint << "("<<filesystem<<")";
215  if(DEBUG_MODE){ qDebug() << " - command:" << cmd2; }
216 
217  bool ok = FALSE;
218  QString result, title;
219  //Run the mounting commands
220  QStringList output = pcbsd::Utils::runShellCommand(cmd1);
221  if( output.join(" ").simplified().isEmpty() ){
222    //directory created, run the next commands
223    system(cmd3.toUtf8()); //set directory permissions before mounting device
224    output = pcbsd::Utils::runShellCommand(cmd2);
225    if( output.join(" ").simplified().isEmpty() ){
226      title = tr("Success");
227      result = QString( tr("%1 mounted at %2") ).arg(deviceName).arg(mntpoint);
228      ok = TRUE;
229    }else{
230      qDebug() << "pc-mounttray: Error mounting device:" << device;
231      qDebug() << " - Error message:" << output;
232      title = QString( tr("Error mounting %1 at %2") ).arg(deviceName).arg(mntpoint);
233      result =  output.join(" ");
234      //Remove the mount point just created
235      pcbsd::Utils::runShellCommand("rmdir "+mntpoint);
236    }
237  }else{
238    qDebug() << "pc-mounttray: Error creating mountpoint:" << mntpoint;
239    qDebug() << " - Error message:" << output;
240    title = QString( tr("Error mounting %1") ).arg(deviceName);
241    result =  QString( tr("Could not create mount point at %1") ).arg(mntpoint);
242  }
243  //Output the proper signals depending upon success
244  if(ok){
245    emit itemMounted(mntpoint);
246    mountpoint = mntpoint;
247  }else{
248    mountpoint.clear();
249  }
250  if( !checkAutomount->isChecked() ){
251    emit newMessage(title, result); //suppress the output message if it was automounted
252  }
253 
254}
255
256void MenuItem::unmountItem(){
257  //Unmount the device
258       
259  //Check to see if the current mountpoint exists or if it is somewhere else
260  if( !QFile::exists(mountpoint) ){
261    if( !isMounted() ){  //double check that it is actually mounted (and fix the mountpoint)
262      //it is not mounted to begin with
263      return;
264    }
265  }
266  //Make sure there are no spaces in the mounpoint path
267  QString cmd1 = "umount \"" + mountpoint +"\"";
268  QString cmd2 = "rmdir \"" + mountpoint +"\"";
269  qDebug() << "Unmounting device from" << mountpoint;
270  //Run the commands
271  QStringList output;
272  QString result, title;
273  bool ok = FALSE;
274  output = pcbsd::Utils::runShellCommand(cmd1);
275  if(output.join(" ").simplified().isEmpty()){
276    //unmounting successful, remove the mount point directory
277    output = pcbsd::Utils::runShellCommand(cmd2);
278    if(!output.join(" ").simplified().isEmpty()){
279      qDebug() << "pc-mounttray: Error removing mountpoint:" << mountpoint;
280      qDebug() << " - Error message:" << output;
281    }
282    ok = TRUE;
283    title = QString( tr("%1 has been successfully unmounted.") ).arg(devLabel->text());
284    if(devType == "ISO"){
285      result = tr("The ISO file has been completely detached from the system.");
286    }else{
287      result = tr("It is now safe to remove the device");
288    }
289  }else{
290    qDebug() << "pc-mounttray: Error unmounting mountpoint:" << mountpoint;
291    qDebug() << " - Error message:" << output;
292    title = QString( tr("Error: %1 could not be unmounted") ).arg(devLabel->text());
293    result = output.join(" ");
294  }
295  //emit the proper signals
296  if(ok){
297    mountpoint.clear();
298    if(devType=="ISO" && device.section("/",-1).startsWith("md") ){
299      //Get the md number
300      QString num = device.section("/md",-1).simplified();
301      //also remove the MD device from the system using "mdconfig"
302      qDebug() << "Detaching Memory Disk:" << num;
303      QString cmd = "mdconfig -d -u "+num;
304      system(cmd.toUtf8());
305    }
306    emit itemUnmounted(device);
307  }
308  emit newMessage(title, result);
309}
310
311void MenuItem::updateSizes(){
312  //this method only works if the device is currently mounted
313  bool ok = FALSE;
314  if(isMounted()){
315    QString cmd = "df \""+mountpoint+"\"";
316    QStringList output = systemCMD(cmd); //make sure we use the one with a 1K blocksize
317    if(output.length() > 1){
318      //parse the output (1K blocks) and save them
319      QString line = output[1].replace("\t"," ");
320      //qDebug() << "df output:" << output << cmd;
321      maxSize = line.section(" ",1,1,QString::SectionSkipEmpty).simplified();
322      currentSize = line.section(" ",2,2,QString::SectionSkipEmpty).simplified();
323      ok=TRUE;
324    }else{
325      maxSize.clear();
326      currentSize.clear();         
327    }
328  }else{
329    maxSize.clear();
330    currentSize.clear();
331  }
332  //Now setup the display progressbar display
333  if(ok){
334    currentSpace->setMaximum( maxSize.toInt() );
335    currentSpace->setValue( currentSize.toInt() );
336    currentSpace->setVisible(TRUE);
337    //display the actual size available in the tooltip
338    QString diskAvailable = getSizeDisplay( maxSize.toInt() - currentSize.toInt() );
339    //qDebug() << "MaxSize:" << maxSize << maxSize.toInt();
340    //qDebug() << "CurrentSize:" << currentSize << currentSize.toInt();
341    //qDebug() << "Disk Available:" << diskAvailable;
342    currentSpace->setToolTip( QString( tr("%1 of disk space available") ).arg(diskAvailable) );
343  }else{
344    currentSpace->setVisible(FALSE);
345  }
346       
347}
348
349QString MenuItem::getSizeDisplay(int kb){
350  //convert from KB to human readable output
351  if( kb > 1048576 ){ //display in GB
352    return QString::number( double(int( (kb*100)/1048576 )/100.0) )+"GB";
353  }else if( kb > 1024 ){ //display in MB
354    return QString::number( double(int( (kb*100)/1024 )/100.0) )+"MB";   
355  }else{ //display in KB
356    return QString::number( kb )+"KB";   
357  }
358       
359}
360
361QStringList MenuItem::systemCMD(QString command){ 
362   QProcess p;
363   QString outstr;
364   //Make sure we use the system environment to properly read system variables, etc.
365   QProcessEnvironment penv = QProcessEnvironment::systemEnvironment();
366   penv.insert("BLOCKSIZE","K"); //make sure we use a 1KB block size
367   p.setProcessEnvironment(penv);
368   //Merge the output channels to retrieve all output possible
369   p.setProcessChannelMode(QProcess::MergedChannels);   
370   p.start(command);
371   while(p.state()==QProcess::Starting || p.state() == QProcess::Running){
372     p.waitForFinished(200);
373     QCoreApplication::processEvents();
374   }
375   QString tmp = p.readAllStandardOutput();
376   outstr.append(tmp);
377   if(outstr.endsWith("\n")){outstr.chop(1);} //remove the newline at the end
378   QStringList out = outstr.split("\n");
379   return out;
380}
Note: See TracBrowser for help on using the repository browser.