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