X-Git-Url: https://git.saurik.com/apt.git/blobdiff_plain/018f15333c0b24232f771a675fc2b4c8cb5fe799..6f976e5dd7ccc27d48b6a000fed0c553bd017d34:/methods/cdrom.cc diff --git a/methods/cdrom.cc b/methods/cdrom.cc index 933d88fc4..bf4281e40 100644 --- a/methods/cdrom.cc +++ b/methods/cdrom.cc @@ -1,6 +1,6 @@ // -*- mode: cpp; mode: fold -*- // Description /*{{{*/ -// $Id: cdrom.cc,v 1.2 1998/12/04 22:56:55 jgg Exp $ +// $Id: cdrom.cc,v 1.20.2.1 2004/01/16 18:58:50 mdz Exp $ /* ###################################################################### CDROM URI method for APT @@ -9,23 +9,40 @@ /*}}}*/ // Include Files /*{{{*/ #include +#include #include #include #include #include +#include #include #include +#include + +#include +#include /*}}}*/ +using namespace std; + class CDROMMethod : public pkgAcqMethod { - Configuration Database; + bool DatabaseLoaded; + bool Debug; + + ::Configuration Database; string CurrentID; - + string CDROM; + bool MountedByApt; + pkgUdevCdromDevices UdevCdroms; + + bool IsCorrectCD(URI want, string MountPath, string& NewID); + bool AutoDetectAndMount(const URI, string &NewID); virtual bool Fetch(FetchItem *Itm); string GetID(string Name); - + virtual void Exit(); + public: CDROMMethod(); @@ -34,116 +51,231 @@ class CDROMMethod : public pkgAcqMethod // CDROMMethod::CDROMethod - Constructor /*{{{*/ // --------------------------------------------------------------------- /* */ -CDROMMethod::CDROMMethod() : pkgAcqMethod("1.0",SingleInstance | LocalOnly) +CDROMMethod::CDROMMethod() : pkgAcqMethod("1.0",SingleInstance | LocalOnly | + SendConfig | NeedsCleanup | + Removable), + DatabaseLoaded(false), + MountedByApt(false) { - // Read the database - string DFile = _config->FindFile("Dir::State::cdroms"); - if (FileExists(DFile) == true) - { - if (ReadConfigFile(Database,DFile) == false) - { - _error->Error("Unable to read the cdrom database %s", - DFile.c_str()); - Fail(); - } - } + UdevCdroms.Dlopen(); }; /*}}}*/ -// CDROMMethod::GetID - Get the ID hash for /*{{{*/ +// CDROMMethod::Exit - Unmount the disc if necessary /*{{{*/ // --------------------------------------------------------------------- -/* We search the configuration space for the name and then return the ID - tag associated with it. */ +/* */ +void CDROMMethod::Exit() +{ + if (MountedByApt == true) + UnmountCdrom(CDROM); +} + /*}}}*/ +// CDROMMethod::GetID - Search the database for a matching string /*{{{*/ +// --------------------------------------------------------------------- +/* */ string CDROMMethod::GetID(string Name) { - const Configuration::Item *Top = Database.Tree(0); + // Search for an ID + const Configuration::Item *Top = Database.Tree("CD"); + if (Top != 0) + Top = Top->Child; + for (; Top != 0;) - { + { if (Top->Value == Name) return Top->Tag; - + Top = Top->Next; - } - + } return string(); } /*}}}*/ +// CDROMMethod::AutoDetectAndMount /*{{{*/ +// --------------------------------------------------------------------- +/* Modifies class varaiable CDROM to the mountpoint */ +bool CDROMMethod::AutoDetectAndMount(const URI Get, string &NewID) +{ + vector v = UdevCdroms.Scan(); + + // first check if its mounted somewhere already + for (unsigned int i=0; i < v.size(); i++) + { + if (v[i].Mounted) + { + if (Debug) + clog << "Checking mounted cdrom device " << v[i].DeviceName << endl; + if (IsCorrectCD(Get, v[i].MountPath, NewID)) + { + CDROM = v[i].MountPath; + return true; + } + } + } + + // we are not supposed to mount, exit + if (_config->FindB("APT::CDROM::NoMount",false) == true) + return false; + + // check if we have the mount point + string AptMountPoint = _config->FindDir("Dir::Media::MountPath"); + if (!FileExists(AptMountPoint)) + mkdir(AptMountPoint.c_str(), 0750); + + // now try mounting + for (unsigned int i=0; i < v.size(); i++) + { + if (!v[i].Mounted) + { + if(MountCdrom(AptMountPoint, v[i].DeviceName)) + { + if (IsCorrectCD(Get, AptMountPoint, NewID)) + { + MountedByApt = true; + CDROM = AptMountPoint; + return true; + } else { + UnmountCdrom(AptMountPoint); + } + } + } + } + + return false; +} + /*}}}*/ +// CDROMMethod::IsCorrectCD /*{{{*/ +// --------------------------------------------------------------------- +/* */ +bool CDROMMethod::IsCorrectCD(URI want, string MountPath, string& NewID) +{ + for (unsigned int Version = 2; Version != 0; Version--) + { + if (IdentCdrom(MountPath,NewID,Version) == false) + return false; + + if (Debug) + clog << "ID " << Version << " " << NewID << endl; + + // A hit + if (Database.Find("CD::" + NewID) == want.Host) + return true; + } + + return false; +} + /*}}}*/ // CDROMMethod::Fetch - Fetch a file /*{{{*/ // --------------------------------------------------------------------- /* */ bool CDROMMethod::Fetch(FetchItem *Itm) { + FetchResult Res; + URI Get = Itm->Uri; string File = Get.Path; - FetchResult Res; - + Debug = _config->FindB("Debug::Acquire::cdrom", false); + + if (Debug) + clog << "CDROMMethod::Fetch " << Itm->Uri << endl; + /* All IMS queries are returned as a hit, CDROMs are readonly so time stamps never change */ if (Itm->LastModified != 0) { Res.LastModified = Itm->LastModified; Res.IMSHit = true; + Res.Filename = Itm->DestFile; URIDone(Res); return true; } - - string ID = GetID(Get.Host); - + + // Load the database + if (DatabaseLoaded == false) + { + // Read the database + string DFile = _config->FindFile("Dir::State::cdroms"); + if (FileExists(DFile) == true) + { + if (ReadConfigFile(Database,DFile) == false) + return _error->Error(_("Unable to read the cdrom database %s"), + DFile.c_str()); + } + DatabaseLoaded = true; + } + // All non IMS queries for package files fail. - if (Itm->IndexFile == true || ID.empty() == false) + if (Itm->IndexFile == true || GetID(Get.Host).empty() == true) { - Fail("Please use apt-cdrom to make this CD recognized by APT." - " apt-get update cannot be used to add new CDs"); + Fail(_("Please use apt-cdrom to make this CD-ROM recognized by APT." + " apt-get update cannot be used to add new CD-ROMs")); return true; } // We already have a CD inserted, but it is the wrong one - if (CurrentID.empty() == false && ID != CurrentID) + if (CurrentID.empty() == false && + CurrentID != "FAIL" && + Database.Find("CD::" + CurrentID) != Get.Host) { - Fail("Wrong CD",true); + Fail(_("Wrong CD-ROM"),true); return true; } - - string CDROM = _config->FindDir("Acquire::cdrom::mount","/cdrom/"); + + bool AutoDetect = _config->FindB("Acquire::cdrom::AutoDetect", true); + CDROM = _config->FindDir("Acquire::cdrom::mount","/cdrom/"); + if (Debug) + clog << "Looking for CDROM at " << CDROM << endl; + + if (CDROM[0] == '.') + CDROM= SafeGetCWD() + '/' + CDROM; + string NewID; - while (1) + while (CurrentID.empty() == true) { - if (IdentCdrom(CDROM,NewID) == false) - return false; - - // A hit - if (NewID == ID) - break; + if (AutoDetect) + AutoDetectAndMount(Get, NewID); + + if(!IsMounted(CDROM)) + MountedByApt = MountCdrom(CDROM); - UnmountCdrom(CDROM); + if (IsCorrectCD(Get, CDROM, NewID)) + break; + + // I suppose this should prompt somehow? + if (_config->FindB("APT::CDROM::NoMount",false) == false && + UnmountCdrom(CDROM) == false) + return _error->Error(_("Unable to unmount the CD-ROM in %s, it may still be in use."), + CDROM.c_str()); if (MediaFail(Get.Host,CDROM) == false) { - ID = "FAIL"; - break; + CurrentID = "FAIL"; + return _error->Error(_("Disk not found.")); } - - MountCdrom(CDROM); } - // ID matches - if (NewID == ID) - { - Res.Filename = CDROM + File; - if (FileExists(Res.Filename) == false) - return _error->Error("File not found"); - - CurrentID = ID; - Res.LastModified = Itm->LastModified; - Res.IMSHit = true; - URIDone(Res); - return true; - } + // Found a CD + Res.Filename = CDROM + File; + struct stat Buf; + if (stat(Res.Filename.c_str(),&Buf) != 0) + return _error->Error(_("File not found")); - return _error->Error("CDROM not found"); + if (NewID.empty() == false) + CurrentID = NewID; + Res.LastModified = Buf.st_mtime; + Res.Size = Buf.st_size; + + Hashes Hash; + FileFd Fd(Res.Filename, FileFd::ReadOnly); + Hash.AddFD(Fd.Fd(), Fd.Size()); + Res.TakeHashes(Hash); + + URIDone(Res); + return true; } /*}}}*/ int main() { + setlocale(LC_ALL, ""); + CDROMMethod Mth; return Mth.Run(); }