kmountpoint.cpp
00001 /* 00002 * 00003 * This file is part of the KDE libraries 00004 * Copyright (c) 2003 Waldo Bastian <bastian@kde.org> 00005 * 00006 * $Id: kmountpoint.cpp 526329 2006-04-04 13:44:00Z hasso $ 00007 * 00008 * This library is free software; you can redistribute it and/or 00009 * modify it under the terms of the GNU Library General Public 00010 * License version 2 as published by the Free Software Foundation. 00011 * 00012 * This library is distributed in the hope that it will be useful, 00013 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00015 * Library General Public License for more details. 00016 * 00017 * You should have received a copy of the GNU Library General Public License 00018 * along with this library; see the file COPYING.LIB. If not, write to 00019 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 00020 * Boston, MA 02110-1301, USA. 00021 **/ 00022 00023 #include <config.h> 00024 #include <stdlib.h> 00025 00026 #include <qfile.h> 00027 00028 #include "kstandarddirs.h" 00029 00030 #include "kmountpoint.h" 00031 00032 #ifdef HAVE_VOLMGT 00033 #include <volmgt.h> 00034 #endif 00035 #ifdef HAVE_SYS_MNTTAB_H 00036 #include <sys/mnttab.h> 00037 #endif 00038 #ifdef HAVE_MNTENT_H 00039 #include <mntent.h> 00040 #elif defined(HAVE_SYS_MNTENT_H) 00041 #include <sys/mntent.h> 00042 #endif 00043 00044 // This is the *BSD branch 00045 #ifdef HAVE_SYS_MOUNT_H 00046 #ifdef HAVE_SYS_TYPES_H 00047 #include <sys/types.h> 00048 #endif 00049 #ifdef HAVE_SYS_PARAM_H 00050 #include <sys/param.h> 00051 #endif 00052 #include <sys/mount.h> 00053 #endif 00054 00055 #ifdef HAVE_FSTAB_H 00056 #include <fstab.h> 00057 #endif 00058 #if defined(_AIX) 00059 #include <sys/mntctl.h> 00060 #include <sys/vmount.h> 00061 #include <sys/vfs.h> 00062 /* AIX does not prototype mntctl anywhere that I can find */ 00063 #ifndef mntctl 00064 extern "C" { 00065 int mntctl(int command, int size, void* buffer); 00066 } 00067 #endif 00068 extern "C" struct vfs_ent *getvfsbytype(int vfsType); 00069 extern "C" void endvfsent( ); 00070 #endif 00071 00072 00073 #ifndef HAVE_GETMNTINFO 00074 # ifdef _PATH_MOUNTED 00075 // On some Linux, MNTTAB points to /etc/fstab ! 00076 # undef MNTTAB 00077 # define MNTTAB _PATH_MOUNTED 00078 # else 00079 # ifndef MNTTAB 00080 # ifdef MTAB_FILE 00081 # define MNTTAB MTAB_FILE 00082 # else 00083 # define MNTTAB "/etc/mnttab" 00084 # endif 00085 # endif 00086 # endif 00087 #endif 00088 00089 00090 00091 #ifdef _OS_SOLARIS_ 00092 #define FSTAB "/etc/vfstab" 00093 #else 00094 #define FSTAB "/etc/fstab" 00095 #endif 00096 00097 00098 00099 KMountPoint::KMountPoint() 00100 { 00101 } 00102 00103 KMountPoint::~KMountPoint() 00104 { 00105 } 00106 00107 #ifdef HAVE_SETMNTENT 00108 #define SETMNTENT setmntent 00109 #define ENDMNTENT endmntent 00110 #define STRUCT_MNTENT struct mntent * 00111 #define STRUCT_SETMNTENT FILE * 00112 #define GETMNTENT(file, var) ((var = getmntent(file)) != 0) 00113 #define MOUNTPOINT(var) var->mnt_dir 00114 #define MOUNTTYPE(var) var->mnt_type 00115 #define MOUNTOPTIONS(var) var->mnt_opts 00116 #define FSNAME(var) var->mnt_fsname 00117 #else 00118 #define SETMNTENT fopen 00119 #define ENDMNTENT fclose 00120 #define STRUCT_MNTENT struct mnttab 00121 #define STRUCT_SETMNTENT FILE * 00122 #define GETMNTENT(file, var) (getmntent(file, &var) == 0) 00123 #define MOUNTPOINT(var) var.mnt_mountp 00124 #define MOUNTTYPE(var) var.mnt_fstype 00125 #define MOUNTOPTIONS(var) var.mnt_mntopts 00126 #define FSNAME(var) var.mnt_special 00127 #endif 00128 00129 KMountPoint::List KMountPoint::possibleMountPoints(int infoNeeded) 00130 { 00131 KMountPoint::List result; 00132 00133 #ifdef HAVE_SETMNTENT 00134 STRUCT_SETMNTENT fstab; 00135 if ((fstab = SETMNTENT(FSTAB, "r")) == 0) 00136 return result; 00137 00138 STRUCT_MNTENT fe; 00139 while (GETMNTENT(fstab, fe)) 00140 { 00141 KMountPoint *mp = new KMountPoint(); 00142 mp->m_mountedFrom = QFile::decodeName(FSNAME(fe)); 00143 00144 mp->m_mountPoint = QFile::decodeName(MOUNTPOINT(fe)); 00145 mp->m_mountType = QFile::decodeName(MOUNTTYPE(fe)); 00146 00147 //Devices using supermount have their device names in the mount options 00148 //instead of the device field. That's why we need to read the mount options 00149 if (infoNeeded & NeedMountOptions || (mp->m_mountType == "supermount")) 00150 { 00151 QString options = QFile::decodeName(MOUNTOPTIONS(fe)); 00152 mp->m_mountOptions = QStringList::split(',', options); 00153 } 00154 00155 if(mp->m_mountType == "supermount") 00156 mp->m_mountedFrom = devNameFromOptions(mp->m_mountOptions); 00157 00158 if (infoNeeded & NeedRealDeviceName) 00159 { 00160 if (mp->m_mountedFrom.startsWith("/")) 00161 mp->m_device = KStandardDirs::realPath(mp->m_mountedFrom); 00162 } 00163 // TODO: Strip trailing '/' ? 00164 result.append(mp); 00165 } 00166 ENDMNTENT(fstab); 00167 #else 00168 QFile f(FSTAB); 00169 if ( !f.open(IO_ReadOnly) ) 00170 return result; 00171 00172 QTextStream t (&f); 00173 QString s; 00174 00175 while (! t.eof()) 00176 { 00177 s=t.readLine().simplifyWhiteSpace(); 00178 if ( s.isEmpty() || (s[0] == '#')) 00179 continue; 00180 00181 // not empty or commented out by '#' 00182 QStringList item = QStringList::split(' ', s); 00183 00184 #ifdef _OS_SOLARIS_ 00185 if (item.count() < 5) 00186 continue; 00187 #else 00188 if (item.count() < 4) 00189 continue; 00190 #endif 00191 00192 KMountPoint *mp = new KMountPoint(); 00193 00194 int i = 0; 00195 mp->m_mountedFrom = item[i++]; 00196 #ifdef _OS_SOLARIS_ 00197 //device to fsck 00198 i++; 00199 #endif 00200 mp->m_mountPoint = item[i++]; 00201 mp->m_mountType = item[i++]; 00202 QString options = item[i++]; 00203 00204 if (infoNeeded & NeedMountOptions) 00205 { 00206 mp->m_mountOptions = QStringList::split(',', options); 00207 } 00208 00209 if (infoNeeded & NeedRealDeviceName) 00210 { 00211 if (mp->m_mountedFrom.startsWith("/")) 00212 mp->m_device = KStandardDirs::realPath(mp->m_mountedFrom); 00213 } 00214 // TODO: Strip trailing '/' ? 00215 result.append(mp); 00216 } //while 00217 00218 f.close(); 00219 #endif 00220 return result; 00221 } 00222 00223 KMountPoint::List KMountPoint::currentMountPoints(int infoNeeded) 00224 { 00225 KMountPoint::List result; 00226 00227 #ifdef HAVE_GETMNTINFO 00228 00229 #ifdef GETMNTINFO_USES_STATVFS 00230 struct statvfs *mounted; 00231 #else 00232 struct statfs *mounted; 00233 #endif 00234 00235 int num_fs = getmntinfo(&mounted, MNT_NOWAIT); 00236 00237 for (int i=0;i<num_fs;i++) 00238 { 00239 KMountPoint *mp = new KMountPoint(); 00240 mp->m_mountedFrom = QFile::decodeName(mounted[i].f_mntfromname); 00241 mp->m_mountPoint = QFile::decodeName(mounted[i].f_mntonname); 00242 00243 #ifdef __osf__ 00244 mp->m_mountType = QFile::decodeName(mnt_names[mounted[i].f_type]); 00245 #else 00246 mp->m_mountType = QFile::decodeName(mounted[i].f_fstypename); 00247 #endif 00248 00249 if (infoNeeded & NeedMountOptions) 00250 { 00251 struct fstab *ft = getfsfile(mounted[i].f_mntonname); 00252 QString options = QFile::decodeName(ft->fs_mntops); 00253 mp->m_mountOptions = QStringList::split(',', options); 00254 } 00255 00256 if (infoNeeded & NeedRealDeviceName) 00257 { 00258 if (mp->m_mountedFrom.startsWith("/")) 00259 mp->m_device = KStandardDirs::realPath(mp->m_mountedFrom); 00260 } 00261 // TODO: Strip trailing '/' ? 00262 result.append(mp); 00263 } 00264 00265 #elif defined(_AIX) 00266 00267 struct vmount *mntctl_buffer; 00268 struct vmount *vm; 00269 char *mountedfrom; 00270 char *mountedto; 00271 int fsname_len, num; 00272 int buf_sz = 4096; 00273 00274 mntctl_buffer = (struct vmount*)malloc(buf_sz); 00275 num = mntctl(MCTL_QUERY, buf_sz, mntctl_buffer); 00276 if (num == 0) 00277 { 00278 buf_sz = *(int*)mntctl_buffer; 00279 free(mntctl_buffer); 00280 mntctl_buffer = (struct vmount*)malloc(buf_sz); 00281 num = mntctl(MCTL_QUERY, buf_sz, mntctl_buffer); 00282 } 00283 00284 if (num > 0) 00285 { 00286 /* iterate through items in the vmount structure: */ 00287 vm = (struct vmount *)mntctl_buffer; 00288 for ( ; num > 0; num-- ) 00289 { 00290 /* get the name of the mounted file systems: */ 00291 fsname_len = vmt2datasize(vm, VMT_STUB); 00292 mountedto = (char*)malloc(fsname_len + 1); 00293 mountedto[fsname_len] = '\0'; 00294 strncpy(mountedto, (char *)vmt2dataptr(vm, VMT_STUB), fsname_len); 00295 00296 fsname_len = vmt2datasize(vm, VMT_OBJECT); 00297 mountedfrom = (char*)malloc(fsname_len + 1); 00298 mountedfrom[fsname_len] = '\0'; 00299 strncpy(mountedfrom, (char *)vmt2dataptr(vm, VMT_OBJECT), fsname_len); 00300 00301 /* Look up the string for the file system type, 00302 * as listed in /etc/vfs. 00303 * ex.: nfs,jfs,afs,cdrfs,sfs,cachefs,nfs3,autofs 00304 */ 00305 struct vfs_ent* ent = getvfsbytype(vm->vmt_gfstype); 00306 00307 KMountPoint *mp = new KMountPoint(); 00308 mp->m_mountedFrom = QFile::decodeName(mountedfrom); 00309 mp->m_mountPoint = QFile::decodeName(mountedto); 00310 mp->m_mountType = QFile::decodeName(ent->vfsent_name); 00311 00312 free(mountedfrom); 00313 free(mountedto); 00314 00315 if (infoNeeded & NeedMountOptions) 00316 { 00317 // TODO 00318 } 00319 00320 if (infoNeeded & NeedRealDeviceName) 00321 { 00322 if (mp->m_mountedFrom.startsWith("/")) 00323 mp->m_device = KStandardDirs::realPath(mp->m_mountedFrom); 00324 } 00325 00326 result.append(mp); 00327 00328 /* goto the next vmount structure: */ 00329 vm = (struct vmount *)((char *)vm + vm->vmt_length); 00330 } 00331 00332 endvfsent( ); 00333 } 00334 00335 free( mntctl_buffer ); 00336 #elif defined(Q_WS_WIN) 00337 //TODO? 00338 #else 00339 STRUCT_SETMNTENT mnttab; 00340 if ((mnttab = SETMNTENT(MNTTAB, "r")) == 0) 00341 return result; 00342 00343 STRUCT_MNTENT fe; 00344 while (GETMNTENT(mnttab, fe)) 00345 { 00346 KMountPoint *mp = new KMountPoint(); 00347 mp->m_mountedFrom = QFile::decodeName(FSNAME(fe)); 00348 00349 mp->m_mountPoint = QFile::decodeName(MOUNTPOINT(fe)); 00350 mp->m_mountType = QFile::decodeName(MOUNTTYPE(fe)); 00351 00352 //Devices using supermount have their device names in the mount options 00353 //instead of the device field. That's why we need to read the mount options 00354 if (infoNeeded & NeedMountOptions || (mp->m_mountType == "supermount")) 00355 { 00356 QString options = QFile::decodeName(MOUNTOPTIONS(fe)); 00357 mp->m_mountOptions = QStringList::split(',', options); 00358 } 00359 00360 if (mp->m_mountType == "supermount") 00361 mp->m_mountedFrom = devNameFromOptions(mp->m_mountOptions); 00362 00363 if (infoNeeded & NeedRealDeviceName) 00364 { 00365 if (mp->m_mountedFrom.startsWith("/")) 00366 mp->m_device = KStandardDirs::realPath(mp->m_mountedFrom); 00367 } 00368 // TODO: Strip trailing '/' ? 00369 result.append(mp); 00370 } 00371 ENDMNTENT(mnttab); 00372 #endif 00373 return result; 00374 } 00375 00376 QString KMountPoint::devNameFromOptions(const QStringList &options) 00377 { 00378 // Search options to find the device name 00379 for ( QStringList::ConstIterator it = options.begin(); it != options.end(); ++it) 00380 { 00381 if( (*it).startsWith("dev=")) 00382 return QString(*it).remove("dev="); 00383 } 00384 return QString("none"); 00385 }