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

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

Now the SCSI/USB distinctions should be resolved in naming/icon conventions for the mount tray. One additional result of this is a much better default naming convention for USB sticks.

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