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

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

Add an additional check to remove the camcontrol inquiry output if it contains "camcontrol". There was probably an error and it should not be used. (can mess up labels).

  • Property mode set to 100644
File size: 8.8 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    if(camctl.contains("camcontrol")){ camctl.clear(); } //error or invalid device type
110  }
111  //Make sure we quit before running commands on any invalid device nodes
112  if(detType.isEmpty() || !QFile::exists(fullDev) ){return FALSE;}
113  else{type->append(detType);}
114  bool isCD=FALSE;
115  if(detType == "CD9660" || detType == "ISO"){ isCD=TRUE; }
116 
117  //Read the Device Info using "file -s <device>"
118  QString cmd = "file -s "+fullDev;
119  QString output = pcbsd::Utils::runShellCommand(cmd).join(" ");
120  //if(isCD){ qDebug() << "File -s output:" << output; }
121 
122  // ** Get the max storage size **
123  int kb = 0;
124  bool hasPartitions = FALSE; 
125  bool isMounted = FALSE;
126  if( !isCD ){
127    QStringList tmp = output.split(",");
128    if( !tmp.filter("partition ").isEmpty() ){
129      //Check for actual sub-devices (*s[#][a/b/c/....])
130      if( devChildren(node).length() > 0 ){ hasPartitions = TRUE; }
131    }
132    if( !tmp.filter("last mounted on /").isEmpty() && (detType == "SATA")){
133      isMounted = TRUE;
134    }
135    //Now try to get the size of the disk
136    if( !tmp.filter("number of data blocks").isEmpty() ){
137      tmp = tmp.filter("number of data blocks");
138      kb = tmp[0].remove("number of data blocks").simplified().toInt();
139    }else if( !tmp.filter("number of blocks").isEmpty() ){
140      tmp = tmp.filter("number of blocks");
141      kb = tmp[0].remove("number of blocks").simplified().toInt();
142    }else if( !tmp.filter("hidden sectors").isEmpty()){
143      tmp = tmp.filter("hidden sectors");
144      kb = tmp[0].remove("hidden sectors").simplified().toInt();
145    }else if( !tmp.filter("sectors").isEmpty()){
146      tmp = tmp.filter("sectors");
147      //qDebug() << "Det Sectors line:"<<tmp;
148      int num=0;
149      for(int i=0; i<tmp.length(); i++){
150        int n = tmp[i].remove("sectors").section("(",0,0).simplified().toInt();
151        if(n > num){ num = n; }
152      }
153      kb = num;
154    }else{ kb = -1; }
155  } //end non-CD size and isMounted detection
156  bool oksize = (kb > 0);
157  //First try to get the device label using the "file -s" output
158  QString dlabel;
159  if(isCD){
160    if( !output.contains("ERROR:") ){
161      dlabel = output.section("'",-2).remove("'").simplified();
162      if(dlabel.contains("(")){ dlabel = dlabel.left(dlabel.indexOf("(")+1).trimmed();}
163    }
164  }else{
165   dlabel = output.section("label: \"",1,1).section("\"",0,0).simplified(); //device name
166  }
167  // - trim the label out of the output line for filesystem type detection
168  QString devFSsec, devFSsec2;
169  if(!isCD){
170    devFSsec = output.section("label:",0,0);
171    devFSsec2 = output.section("label:",1,3).section(",",1,1,QString::SectionSkipEmpty);
172  }else{
173    devFSsec = output.simplified();       
174  }
175  // ** Find the filesystem type for the device **
176  QString filesys;
177  for(int i=0; i<fsDetection.length(); i++){
178    if(devFSsec.contains(fsDetection[i]) || devFSsec2.contains(fsDetection[i]) ){
179      filesys = fsMatch[i]; 
180    }
181  }
182  //If the filesystem could not be detected or is not supported
183  bool hasFS = TRUE;
184  if(filesys.isEmpty()){ filesys = "UNKNOWN"; hasFS=FALSE; }
185 
186  //Now get the device label (if there is one) using glabel
187  bool hasLabel = FALSE;
188  QString glabel;
189  if(!isCD){ glabel = devLabel(node, filesys); }
190  //Check to see if we have a label, otherwise assign one
191  if( !glabel.isEmpty() ){ dlabel = glabel; hasLabel = TRUE; } //glabel
192  else if(!dlabel.isEmpty()){ hasLabel = TRUE; } //file -s label
193  else if( !camctl.isEmpty() ){ 
194    //not necessarily a "detected" label, but just an alternate fallback name
195    dlabel = camctl.section(">",0,0).section("<",-1).section(" ",0,0).simplified();
196  }else{
197    //Assign a device label
198    if(isCD){
199      if(detType == "ISO"){
200        dlabel = "ISO_File";
201      }else{
202        dlabel = "Optical_Disk";
203      }
204    }else{
205      dlabel = detType+"-Device"; //this is not a "detected" label
206    }
207  }
208  //make sure that a device label does not contain "(" or ")"
209  if(dlabel.contains("(")){ dlabel.remove("(").simplified(); }
210  if(dlabel.contains(")")){ dlabel.remove(")").simplified(); }
211  dlabel = dlabel.simplified();
212  //Now perform the final checks to see if it is a good device
213  bool good = FALSE;
214  if( isMounted ){}//Always ignore this device (local FreeBSD installation that is being used)
215  else if( hasPartitions ){} //Ignore devices that have partitions accessible as seperate devices
216  else if( hasFS && isCD ){ good = TRUE; } //CD/DVD data disks don't have as much info
217  //Allow devices that match 2 of the 3 criteria
218  else if( hasFS && oksize ){ good = TRUE; } //This will catch most good devices
219  else if( hasLabel && oksize ){ good = TRUE; } //allow unknown filesystems if there is a good size reading
220  else if( hasFS && hasLabel ){ good = TRUE; } // allow device if it has a known label and filesystem
221 
222  //Now setup the outputs as appropriate
223  maxsize->append( QString::number(kb) );
224  label->append(dlabel);
225  filesystem->append(filesys);
226 
227  if(!good){
228    qDebug() << "Invalid Device:" << node << detType << dlabel << filesys << kb; 
229    if(DEBUG_MODE){qDebug() << " -Detected Flags:" << isMounted << hasPartitions << hasLabel << hasFS << oksize;} 
230  }
231  return good;
232}
233
234/*
235  PRIVATE FUNCTIONS
236*/
237
238
Note: See TracBrowser for help on using the repository browser.