00001
00002
00003
00004
00005
00006
00007
00008
00013 #include "zypp/base/Logger.h"
00014 #include "zypp/base/String.h"
00015 #include "zypp/media/Mount.h"
00016 #include "zypp/media/MediaDISK.h"
00017 #include "zypp/media/MediaManager.h"
00018
00019 #include <iostream>
00020 #include <fstream>
00021 #include <sstream>
00022
00023 #include <sys/types.h>
00024 #include <sys/mount.h>
00025 #include <errno.h>
00026 #include <dirent.h>
00027
00028
00029
00030
00031 #define DELAYED_VERIFY 1
00032
00033
00034
00035
00036
00037 #define REUSE_FOREIGN_MOUNTS 2
00038
00039
00040
00041
00042 #define VOL_ID_TOOL_PATHS { "/sbin/vol_id", "/lib/udev/vol_id", NULL}
00043
00044 using namespace std;
00045
00046 namespace zypp {
00047 namespace media {
00048
00050
00051
00052
00054
00056
00057
00058
00059
00060
00061
00062
00063 MediaDISK::MediaDISK( const Url & url_r,
00064 const Pathname & attach_point_hint_r )
00065 : MediaHandler( url_r, attach_point_hint_r,
00066 url_r.getPathName(),
00067 false )
00068 {
00069 MIL << "MediaDISK::MediaDISK(" << url_r << ", " << attach_point_hint_r << ")" << endl;
00070
00071 _device = Pathname(_url.getQueryParam("device")).asString();
00072 if( _device.empty())
00073 {
00074 ERR << "Media url does not contain a device specification" << std::endl;
00075 ZYPP_THROW(MediaBadUrlEmptyDestinationException(_url));
00076 }
00077 #if DELAYED_VERIFY
00078 DBG << "Verify of " << _device << " delayed" << std::endl;
00079 #else
00080 if( !verifyIfDiskVolume( _device))
00081 {
00082 ZYPP_THROW(MediaBadUrlEmptyDestinationException(_url));
00083 }
00084 #endif
00085
00086 _filesystem = _url.getQueryParam("filesystem");
00087 if(_filesystem.empty())
00088 _filesystem="auto";
00089
00090 }
00091
00093
00094
00095
00096
00097
00098
00099
00100 bool MediaDISK::verifyIfDiskVolume(const Pathname &dev_name)
00101 {
00102 if( dev_name.empty() ||
00103 dev_name.asString().compare(0, sizeof("/dev/")-1, "/dev/"))
00104 {
00105 ERR << "Specified device name " << dev_name
00106 << " is not allowed" << std::endl;
00107 return false;
00108 }
00109
00110 PathInfo dev_info(dev_name);
00111 if( !dev_info.isBlk())
00112 {
00113 ERR << "Specified device name " << dev_name
00114 << " is not a block device" << std::endl;
00115 return false;
00116 }
00117
00118
00119 {
00120 Pathname dpath("/dev/disk/by-uuid");
00121 std::list<Pathname> dlist;
00122 if( zypp::filesystem::readdir(dlist, dpath) == 0)
00123 {
00124 std::list<Pathname>::const_iterator it;
00125 for(it = dlist.begin(); it != dlist.end(); ++it)
00126 {
00127 PathInfo vol_info(*it);
00128 if( vol_info.isBlk() && vol_info.major() == dev_info.major() &&
00129 vol_info.minor() == dev_info.minor())
00130 {
00131 DBG << "Specified device name " << dev_name
00132 << " is a volume (disk/by-uuid link "
00133 << vol_info.path() << ")"
00134 << std::endl;
00135 return true;
00136 }
00137 }
00138 }
00139 }
00140
00141
00142
00143 {
00144 Pathname dpath("/dev/disk/by-label");
00145 std::list<Pathname> dlist;
00146 if( zypp::filesystem::readdir(dlist, dpath) == 0)
00147 {
00148 std::list<Pathname>::const_iterator it;
00149 for(it = dlist.begin(); it != dlist.end(); ++it)
00150 {
00151 PathInfo vol_info(*it);
00152 if( vol_info.isBlk() && vol_info.major() == dev_info.major() &&
00153 vol_info.minor() == dev_info.minor())
00154 {
00155 DBG << "Specified device name " << dev_name
00156 << " is a volume (disk/by-label link "
00157 << vol_info.path() << ")"
00158 << std::endl;
00159 return true;
00160 }
00161 }
00162 }
00163 }
00164
00165
00166
00167 for(const char *vol_id_paths[] = VOL_ID_TOOL_PATHS,
00168 **vol_id_path = vol_id_paths;
00169 vol_id_path != NULL && *vol_id_path != NULL;
00170 vol_id_path++)
00171 {
00172 PathInfo vol_id_info(*vol_id_path);
00173 if( !vol_id_info.isFile() || !vol_id_info.isXUsr())
00174 continue;
00175
00176 const char *cmd[3];
00177 cmd[0] = *vol_id_path;
00178 cmd[1] = dev_name.asString().c_str();
00179 cmd[2] = NULL;
00180
00181 ExternalProgram vol_id(cmd, ExternalProgram::Stderr_To_Stdout);
00182
00183 std::string vol_fs_usage;
00184 std::string vol_fs_uuid;
00185 std::string vol_fs_type;
00186
00187 for(std::string out( vol_id.receiveLine());
00188 out.length(); out = vol_id.receiveLine())
00189 {
00190 out = str::rtrim(out);
00191
00192 if( out.compare(0, sizeof("ID_FS_USAGE=")-1, "ID_FS_USAGE=") == 0)
00193 {
00194 vol_fs_usage = out.substr(sizeof("ID_FS_USAGE=")-1);
00195 }
00196 else
00197 if( out.compare(0, sizeof("ID_FS_TYPE=")-1, "ID_FS_TYPE=") == 0)
00198 {
00199 vol_fs_type = out.substr(sizeof("ID_FS_TYPE=")-1);
00200 }
00201 else
00202 if( out.compare(0, sizeof("ID_FS_UUID=")-1, "ID_FS_UUID=") == 0)
00203 {
00204 vol_fs_uuid = out.substr(sizeof("ID_FS_UUID=")-1);
00205 }
00206 }
00207
00208 if( vol_id.close() == 0)
00209 {
00210 if( vol_fs_usage == "filesystem")
00211 {
00212 if(vol_fs_type == "iso9660" || vol_fs_type == "udf")
00213 {
00214 DBG << "Specified device name " << dev_name
00215 << " is a CD/DVD volume (type " << vol_fs_type << ")"
00216 << std::endl;
00217 return true;
00218 }
00219 else
00220 if(!vol_fs_type.empty() && !vol_fs_uuid.empty())
00221 {
00222 DBG << "Specified device name " << dev_name
00223 << " is a volume (type " << vol_fs_type
00224 << ", uuid " << vol_fs_uuid << ")"
00225 << std::endl;
00226 return true;
00227 }
00228 }
00229 }
00230 }
00231
00232 ERR << "Specified device name " << dev_name
00233 << " is not a usable disk volume"
00234 << std::endl;
00235 return false;
00236 }
00237
00239
00240
00241
00242
00243
00244
00245
00246 void MediaDISK::attachTo(bool next)
00247 {
00248 if(next)
00249 ZYPP_THROW(MediaNotSupportedException(url()));
00250
00251
00252
00253
00254
00255
00256 if(_device.empty())
00257 ZYPP_THROW(MediaBadUrlEmptyDestinationException(url()));
00258
00259 PathInfo dev_info(_device);
00260 if(!dev_info.isBlk())
00261 ZYPP_THROW(MediaBadUrlEmptyDestinationException(url()));
00262 #if DELAYED_VERIFY
00263 DBG << "Verifying " << _device << " ..." << std::endl;
00264 if( !verifyIfDiskVolume( _device))
00265 {
00266 ZYPP_THROW(MediaBadUrlEmptyDestinationException(_url));
00267 }
00268 #endif
00269
00270 if(_filesystem.empty())
00271 ZYPP_THROW(MediaBadUrlEmptyFilesystemException(url()));
00272
00273 MediaSourceRef media( new MediaSource(
00274 "disk", _device, dev_info.major(), dev_info.minor()
00275 ));
00276 AttachedMedia ret( findAttachedMedia( media));
00277
00278 if( ret.mediaSource &&
00279 ret.attachPoint &&
00280 !ret.attachPoint->empty())
00281 {
00282 DBG << "Using a shared media "
00283 << ret.mediaSource->name
00284 << " attached on "
00285 << ret.attachPoint->path
00286 << endl;
00287
00288 removeAttachPoint();
00289 setAttachPoint(ret.attachPoint);
00290 setMediaSource(ret.mediaSource);
00291 return;
00292 }
00293
00294 MediaManager manager;
00295 MountEntries entries( manager.getMountEntries());
00296 MountEntries::const_iterator e;
00297 for( e = entries.begin(); e != entries.end(); ++e)
00298 {
00299 bool is_device = false;
00300 std::string dev_path(Pathname(e->src).asString());
00301 PathInfo dev_info;
00302
00303 if( dev_path.compare(0, sizeof("/dev/")-1, "/dev/") == 0 &&
00304 dev_info(e->src) && dev_info.isBlk())
00305 {
00306 is_device = true;
00307 }
00308
00309 if( is_device && media->maj_nr == dev_info.major() &&
00310 media->min_nr == dev_info.minor())
00311 {
00312 #if REUSE_FOREIGN_MOUNTS > 0
00313 AttachPointRef ap( new AttachPoint(e->dir, false));
00314 AttachedMedia am( media, ap);
00315
00316
00317
00318 #if REUSE_FOREIGN_MOUNTS == 1
00319 if( isAutoMountedMedia(am))
00320 #endif
00321 {
00322 DBG << "Using a system mounted media "
00323 << media->name
00324 << " attached on "
00325 << ap->path
00326 << endl;
00327
00328 media->iown = false;
00329
00330 setMediaSource(media);
00331 setAttachPoint(ap);
00332 return;
00333 }
00334 #else
00335 media->bdir = e->dir;
00336 #endif
00337 }
00338 }
00339
00340 Mount mount;
00341 std::string mountpoint = attachPoint().asString();
00342 if( !isUseableAttachPoint(attachPoint()))
00343 {
00344 mountpoint = createAttachPoint().asString();
00345 if( mountpoint.empty())
00346 ZYPP_THROW( MediaBadAttachPointException(url()));
00347 setAttachPoint( mountpoint, true);
00348 }
00349
00350 string options = _url.getQueryParam("mountoptions");
00351 if(options.empty())
00352 {
00353 options = "ro";
00354 }
00355
00356 if( !media->bdir.empty())
00357 {
00358 options += ",bind";
00359 mount.mount(media->bdir, mountpoint, "none", options);
00360 }
00361 else
00362 {
00363 mount.mount(_device, mountpoint, _filesystem, options);
00364 }
00365
00366 setMediaSource(media);
00367
00368
00369
00370 int limit = 3;
00371 bool mountsucceeded;
00372 while( !(mountsucceeded=isAttached()) && --limit)
00373 {
00374 sleep(1);
00375 }
00376
00377 if( !mountsucceeded)
00378 {
00379 setMediaSource(MediaSourceRef());
00380 try
00381 {
00382 mount.umount(attachPoint().asString());
00383 }
00384 catch (const MediaException & excpt_r)
00385 {
00386 ZYPP_CAUGHT(excpt_r);
00387 }
00388 ZYPP_THROW(MediaMountException(
00389 "Unable to verify that the media was mounted",
00390 _device, mountpoint
00391 ));
00392 }
00393 }
00394
00396
00397
00398
00399
00400
00401
00402 bool
00403 MediaDISK::isAttached() const
00404 {
00405 return checkAttached(false);
00406 }
00407
00409
00410
00411
00412
00413
00414
00415
00416 void MediaDISK::releaseFrom( const std::string & ejectDev )
00417 {
00418 AttachedMedia am( attachedMedia());
00419 if(am.mediaSource && am.mediaSource->iown)
00420 {
00421 Mount mount;
00422 mount.umount(attachPoint().asString());
00423 }
00424 }
00425
00427
00428
00429
00430
00431
00432
00433 void MediaDISK::getFile (const Pathname & filename) const
00434 {
00435 MediaHandler::getFile( filename );
00436 }
00437
00439
00440
00441
00442
00443
00444
00445 void MediaDISK::getDir( const Pathname & dirname, bool recurse_r ) const
00446 {
00447 MediaHandler::getDir( dirname, recurse_r );
00448 }
00449
00451
00452
00453
00454
00455
00456
00457
00458 void MediaDISK::getDirInfo( std::list<std::string> & retlist,
00459 const Pathname & dirname, bool dots ) const
00460 {
00461 MediaHandler::getDirInfo( retlist, dirname, dots );
00462 }
00463
00465
00466
00467
00468
00469
00470
00471
00472 void MediaDISK::getDirInfo( filesystem::DirContent & retlist,
00473 const Pathname & dirname, bool dots ) const
00474 {
00475 MediaHandler::getDirInfo( retlist, dirname, dots );
00476 }
00477
00478 bool MediaDISK::getDoesFileExist( const Pathname & filename ) const
00479 {
00480 return MediaHandler::getDoesFileExist( filename );
00481 }
00482
00483 }
00484 }
00485