source: src-qt4/pc-mounttray/devCheck.cpp @ b34565c

enter/10releng/10.0releng/10.0.1releng/10.0.2releng/10.0.3releng/10.1releng/10.1.1releng/10.1.2
Last change on this file since b34565c was b34565c, checked in by Ken Moore <ken@…>, 19 months ago

Make sure we always perform the check for "child" devices in the mounttray. This should prevent issues with duplicate devices because they do not list the "partition"s in the file -s output.

  • Property mode set to 100644
File size: 8.7 KB
Line 
1#include <pcbsd-utils.h>
2#include "devCheck.h"
3
4
5DevCheck::DevCheck(){
6  //Initialize the lists of valid device types
7  validDevs << "da" << "ad" << "mmcsd" << "cd" << "acd" << "md" << "da";
8  validDevTypes << "USB" << "SATA" << "SD" << "CD9660" << "CD9660" << "ISO" << "SCSI";
9  for(int i=0; i<validDevs.length(); i++){
10    devFilter << validDevs[i]+"*";
11  }
12  //Initialize lists of filesystems and detection strings
13  fsDetection.clear();
14  fsMatch.clear();
15  fsDetection << "FAT" << "NTFS" << "EXT" << "ISO 9660" << "Unix Fast File system" << "Reiser" << "XFS"; //string to match for a particular filesystem
16  fsMatch << "FAT" << "NTFS" << "EXT" << "CD9660" << "UFS" << "REISERFS" << "XFS"; //internal labels for the filesystems
17  fsFilter << "fat" << "ntfs" << "ext" << "cdrom" << "ufs" << "reiser" << "xfs"; //label categories in /dev/
18  //Initialize the device directory
19  devDir = QDir(DEVICEDIR);
20}
21
22DevCheck::~DevCheck(){
23}
24
25/*
26  PUBLIC FUNCTIONS
27*/
28
29bool DevCheck::isValid(QString node){
30  bool ok = FALSE;
31  for(int i=0; i<validDevs.length(); i++){
32    if(node.startsWith(validDevs[i]) && node!="mdctl"){ 
33        ok = TRUE; 
34        break; 
35    }
36  }
37  return ok;
38}
39
40QStringList DevCheck::devChildren(QString node){
41  devDir.cd(DEVICEDIR);
42  QStringList subdevs = devDir.entryList(devFilter, QDir::NoDotAndDotDot | QDir::NoSymLinks | QDir::System, QDir::NoSort);
43  //Clean up the list of children
44  for(int i=0; i<subdevs.length(); i++){
45    if( (subdevs[i] == node) || subdevs[i].isEmpty() || !subdevs[i].startsWith(node) ){
46      subdevs.removeAt(i);
47      i--;
48    }
49  }
50  //qDebug() << "[DEBUG] " <<node << "Device Children:" << subdevs;
51  return subdevs;
52}
53
54QString DevCheck::devLabel(QString node, QString filesystem){
55  QString dlabel;
56  QStringList glout = pcbsd::Utils::runShellCommand("glabel list");
57  int index = glout.indexOf("Geom name: "+node);
58  while(index != -1){
59    for(int i=index; i<glout.length(); i++){ 
60      if(glout[i].contains("Name: ")){ index = i; break;} //should only be 1 or 2 lines to find this
61    }
62    if(index == -1){ break; } //quick check to make sure we don't error out
63    QString path = glout[index].section("Name:",1,10,QString::SectionSkipEmpty).simplified(); 
64    int fschk = fsMatch.indexOf(filesystem);
65    if(fschk != -1){
66      if(fsFilter[fschk] == path.section("/",0,0).simplified() ){
67        //good label
68        dlabel = path.section("/",-1).simplified();
69        break;
70      }
71    }
72    index = glout.indexOf("Geom name: "+node, index); //move to the next index if there is one
73  }
74  return dlabel;
75}
76
77bool DevCheck::devInfo(QString dev, QString* type, QString* label, QString* filesystem, QString* maxsize){
78  //OUTPUT: bool isGoodDevice
79  //INPUTS/OUTPUTS: type, label, filesystem, maxsize
80  //INPUT: dev = device node (da0, not /dev/da0)
81       
82  //Clear the output variables
83  type->clear(); label->clear(); filesystem->clear(); maxsize->clear();
84  //make sure to have both the full path and just node
85  QString node;
86  QString fullDev;
87  if(dev.startsWith(DEVICEDIR)){ fullDev = dev; node = dev.section("/",-1); }
88  else{ node = dev; fullDev = DEVICEDIR + dev; }
89  //Do not allow sym-links
90  if(!QFile::symLinkTarget(fullDev).isEmpty()){ return FALSE; }
91 
92  //Double check for valid device types (just in case)
93  QString detType;
94  for(int i=0; i<validDevs.length(); i++){
95    if(node.startsWith(validDevs[i]) && node != "mdctl"){ 
96        detType = validDevTypes[i]; 
97        break; 
98    }
99  }
100  QString camctl;
101  if(detType == "USB" && QFile::exists(fullDev)){
102    //make sure that it is not a SCSI device
103    camctl = pcbsd::Utils::runShellCommand( QString("camcontrol inquiry ")+node ).join(" ");
104    if(camctl.contains(" Fixed Direct Access SCSI")){ detType = "SCSI"; } //USB devices do not have any output
105    if(camctl.contains("camcontrol")){ camctl.clear(); } //error or invalid device type
106  }
107  //Make sure we quit before running commands on any invalid device nodes
108  if(detType.isEmpty() || !QFile::exists(fullDev) ){return FALSE;}
109  else{type->append(detType);}
110  bool isCD=FALSE;
111  if(detType == "CD9660" || detType == "ISO"){ isCD=TRUE; }
112 
113  //Read the Device Info using "file -s <device>"
114  QString cmd = "file -s "+fullDev;
115  QString output = pcbsd::Utils::runShellCommand(cmd).join(" ");
116  //if(isCD){ qDebug() << "File -s output:" << output; }
117 
118  // ** Get the max storage size **
119  int kb = 0;
120  bool hasPartitions = FALSE; 
121  bool isMounted = FALSE;
122  if( !isCD ){
123    QStringList tmp = output.split(",");
124    //if( !tmp.filter("partition ").isEmpty() ){
125      //Check for actual sub-devices (*s[#][a/b/c/....])
126      if( devChildren(node).length() > 0 ){ hasPartitions = TRUE; }
127    //}
128    if( !tmp.filter("last mounted on /").isEmpty() && (detType == "SATA")){
129      isMounted = TRUE;
130    }
131    //Now try to get the size of the disk
132    if( !tmp.filter("number of data blocks").isEmpty() ){
133      tmp = tmp.filter("number of data blocks");
134      kb = tmp[0].remove("number of data blocks").simplified().toInt();
135    }else if( !tmp.filter("number of blocks").isEmpty() ){
136      tmp = tmp.filter("number of blocks");
137      kb = tmp[0].remove("number of blocks").simplified().toInt();
138    }else if( !tmp.filter("hidden sectors").isEmpty()){
139      tmp = tmp.filter("hidden sectors");
140      kb = tmp[0].remove("hidden sectors").simplified().toInt();
141    }else if( !tmp.filter("sectors").isEmpty()){
142      tmp = tmp.filter("sectors");
143      //qDebug() << "Det Sectors line:"<<tmp;
144      int num=0;
145      for(int i=0; i<tmp.length(); i++){
146        int n = tmp[i].remove("sectors").section("(",0,0).simplified().toInt();
147        if(n > num){ num = n; }
148      }
149      kb = num;
150    }else{ kb = -1; }
151  } //end non-CD size and isMounted detection
152  bool oksize = (kb > 0);
153  //First try to get the device label using the "file -s" output
154  QString dlabel;
155  if(isCD){
156    if( !output.contains("ERROR:") ){
157      dlabel = output.section("'",-2).remove("'").simplified();
158      if(dlabel.contains("(")){ dlabel = dlabel.left(dlabel.indexOf("(")+1).trimmed();}
159    }
160  }else{
161   dlabel = output.section("label: \"",1,1).section("\"",0,0).simplified(); //device name
162  }
163  // - trim the label out of the output line for filesystem type detection
164  QString devFSsec, devFSsec2;
165  if(!isCD){
166    devFSsec = output.section("label:",0,0);
167    devFSsec2 = output.section("label:",1,3).section(",",1,1,QString::SectionSkipEmpty);
168  }else{
169    devFSsec = output.simplified();       
170  }
171  // ** Find the filesystem type for the device **
172  QString filesys;
173  for(int i=0; i<fsDetection.length(); i++){
174    if(devFSsec.contains(fsDetection[i]) || devFSsec2.contains(fsDetection[i]) ){
175      filesys = fsMatch[i]; 
176    }
177  }
178  //If the filesystem could not be detected or is not supported
179  bool hasFS = TRUE;
180  if(filesys.isEmpty()){ filesys = "UNKNOWN"; hasFS=FALSE; }
181 
182  //Now get the device label (if there is one) using glabel
183  bool hasLabel = FALSE;
184  QString glabel;
185  if(!isCD){ glabel = devLabel(node, filesys); }
186  //Check to see if we have a label, otherwise assign one
187  if( !glabel.isEmpty() ){ dlabel = glabel; hasLabel = TRUE; } //glabel
188  else if(!dlabel.isEmpty()){ hasLabel = TRUE; } //file -s label
189  else if( !camctl.isEmpty() ){ 
190    //not necessarily a "detected" label, but just an alternate fallback name
191    dlabel = camctl.section(">",0,0).section("<",-1).section(" ",0,0).simplified();
192  }else{
193    //Assign a device label
194    if(isCD){
195      if(detType == "ISO"){
196        dlabel = "ISO_File";
197      }else{
198        dlabel = "Optical_Disk";
199      }
200    }else{
201      dlabel = detType+"-Device"; //this is not a "detected" label
202    }
203  }
204  //make sure that a device label does not contain "(" or ")"
205  if(dlabel.contains("(")){ dlabel = dlabel.remove("(").simplified(); }
206  if(dlabel.contains(")")){ dlabel = dlabel.remove(")").simplified(); }
207  dlabel = dlabel.simplified();
208  //Now perform the final checks to see if it is a good device
209  bool good = FALSE;
210  if( isMounted ){}//Always ignore this device (local FreeBSD installation that is being used)
211  else if( hasPartitions ){} //Ignore devices that have partitions accessible as seperate devices
212  else if( hasFS && isCD ){ good = TRUE; } //CD/DVD data disks don't have as much info
213  //Allow devices that match 2 of the 3 criteria
214  else if( hasFS && oksize ){ good = TRUE; } //This will catch most good devices
215  else if( hasLabel && oksize ){ good = TRUE; } //allow unknown filesystems if there is a good size reading
216  else if( hasFS && hasLabel ){ good = TRUE; } // allow device if it has a known label and filesystem
217 
218  //Now setup the outputs as appropriate
219  maxsize->append( QString::number(kb) );
220  label->append(dlabel);
221  filesystem->append(filesys);
222 
223  if(!good){
224    qDebug() << "Invalid Device:" << node << detType << dlabel << filesys << kb; 
225    if(DEBUG_MODE){qDebug() << " -Detected Flags:" << isMounted << hasPartitions << hasLabel << hasFS << oksize;} 
226  }
227  return good;
228}
229
230/*
231  PRIVATE FUNCTIONS
232*/
233
234
Note: See TracBrowser for help on using the repository browser.