diff options
Diffstat (limited to '')
-rw-r--r-- | apt-pkg/cdrom.cc | 989 |
1 files changed, 989 insertions, 0 deletions
diff --git a/apt-pkg/cdrom.cc b/apt-pkg/cdrom.cc new file mode 100644 index 0000000..ea10d10 --- /dev/null +++ b/apt-pkg/cdrom.cc @@ -0,0 +1,989 @@ +/* + */ +#include <config.h> + +#include <apt-pkg/aptconfiguration.h> +#include <apt-pkg/cdrom.h> +#include <apt-pkg/cdromutl.h> +#include <apt-pkg/configuration.h> +#include <apt-pkg/error.h> +#include <apt-pkg/fileutl.h> +#include <apt-pkg/indexcopy.h> +#include <apt-pkg/strutl.h> + +#include <algorithm> +#include <fstream> +#include <iostream> +#include <iostream> +#include <sstream> +#include <string> +#include <vector> +#include <dirent.h> +#include <dlfcn.h> +#include <stdio.h> +#include <string.h> +#include <sys/stat.h> +#include <unistd.h> + +#include <apti18n.h> + +#ifdef HAVE_UDEV +#include <libudev.h> +#endif + +using namespace std; + +// FindPackages - Find the package files on the CDROM /*{{{*/ +// --------------------------------------------------------------------- +/* We look over the cdrom for package files. This is a recursive + search that short circuits when it his a package file in the dir. + This speeds it up greatly as the majority of the size is in the + binary-* sub dirs. */ +bool pkgCdrom::FindPackages(string CD, + vector<string> &List, + vector<string> &SList, + vector<string> &SigList, + vector<string> &TransList, + string &InfoDir, pkgCdromStatus *log, + unsigned int Depth) +{ + static ino_t Inodes[9]; + DIR *D; + + // if we have a look we "pulse" now + if(log) + log->Update(); + + if (Depth >= 7) + return true; + + if (CD[CD.length()-1] != '/') + CD += '/'; + + if (chdir(CD.c_str()) != 0) + return _error->Errno("chdir","Unable to change to %s",CD.c_str()); + + // Look for a .disk subdirectory + if (InfoDir.empty() == true) + { + if (DirectoryExists(".disk") == true) + InfoDir = InfoDir + CD + ".disk/"; + } + + // Don't look into directories that have been marked to ignore. + if (RealFileExists(".aptignr") == true) + return true; + + /* Check _first_ for a signature file as apt-cdrom assumes that all files + under a Packages/Source file are in control of that file and stops + the scanning + */ + if (RealFileExists("Release.gpg") == true || RealFileExists("InRelease") == true) + { + SigList.push_back(CD); + } + + /* Aha! We found some package files. We assume that everything under + this dir is controlled by those package files so we don't look down + anymore */ + std::vector<APT::Configuration::Compressor> const compressor = APT::Configuration::getCompressors(); + for (std::vector<APT::Configuration::Compressor>::const_iterator c = compressor.begin(); + c != compressor.end(); ++c) + { + if (RealFileExists(std::string("Packages").append(c->Extension).c_str()) == false) + continue; + + if (_config->FindB("Debug::aptcdrom",false) == true) + std::clog << "Found Packages in " << CD << std::endl; + List.push_back(CD); + + // Continue down if thorough is given + if (_config->FindB("APT::CDROM::Thorough",false) == false) + return true; + break; + } + for (std::vector<APT::Configuration::Compressor>::const_iterator c = compressor.begin(); + c != compressor.end(); ++c) + { + if (RealFileExists(std::string("Sources").append(c->Extension).c_str()) == false) + continue; + + if (_config->FindB("Debug::aptcdrom",false) == true) + std::clog << "Found Sources in " << CD << std::endl; + SList.push_back(CD); + + // Continue down if thorough is given + if (_config->FindB("APT::CDROM::Thorough",false) == false) + return true; + break; + } + + // see if we find translation indices + if (DirectoryExists("i18n") == true) + { + D = opendir("i18n"); + for (struct dirent *Dir = readdir(D); Dir != 0; Dir = readdir(D)) + { + if(strncmp(Dir->d_name, "Translation-", strlen("Translation-")) != 0) + continue; + string file = Dir->d_name; + for (std::vector<APT::Configuration::Compressor>::const_iterator c = compressor.begin(); + c != compressor.end(); ++c) + { + string fileext = flExtension(file); + if (file == fileext) + fileext.clear(); + else if (fileext.empty() == false) + fileext = "." + fileext; + + if (c->Extension == fileext) + { + if (_config->FindB("Debug::aptcdrom",false) == true) + std::clog << "Found translation " << Dir->d_name << " in " << CD << "i18n/" << std::endl; + file.erase(file.size() - fileext.size()); + TransList.push_back(CD + "i18n/" + file); + break; + } + } + } + closedir(D); + } + + D = opendir("."); + if (D == 0) + return _error->Errno("opendir","Unable to read %s",CD.c_str()); + + // Run over the directory + for (struct dirent *Dir = readdir(D); Dir != 0; Dir = readdir(D)) + { + // Skip some files.. + if (strcmp(Dir->d_name,".") == 0 || + strcmp(Dir->d_name,"..") == 0 || + strcmp(Dir->d_name,".disk") == 0 || + strcmp(Dir->d_name,"debian-installer") == 0) + continue; + + // See if the name is a sub directory + struct stat Buf; + if (stat(Dir->d_name,&Buf) != 0) + continue; + + if (S_ISDIR(Buf.st_mode) == 0) + continue; + + unsigned int I; + for (I = 0; I != Depth; I++) + if (Inodes[I] == Buf.st_ino) + break; + if (I != Depth) + continue; + + // Store the inodes weve seen + Inodes[Depth] = Buf.st_ino; + + // Descend + if (FindPackages(CD + Dir->d_name,List,SList,SigList,TransList,InfoDir,log,Depth+1) == false) + break; + + if (chdir(CD.c_str()) != 0) + { + _error->Errno("chdir","Unable to change to %s", CD.c_str()); + closedir(D); + return false; + } + }; + + closedir(D); + + return !_error->PendingError(); +} + /*}}}*/ +// Score - We compute a 'score' for a path /*{{{*/ +// --------------------------------------------------------------------- +/* Paths are scored based on how close they come to what I consider + normal. That is ones that have 'dist' 'stable' 'testing' will score + higher than ones without. */ +int pkgCdrom::Score(string Path) +{ + int Res = 0; + if (Path.find("stable/") != string::npos) + Res += 29; + if (Path.find("/binary-") != string::npos) + Res += 20; + if (Path.find("testing/") != string::npos) + Res += 28; + if (Path.find("unstable/") != string::npos) + Res += 27; + if (Path.find("/dists/") != string::npos) + Res += 40; + if (Path.find("/main/") != string::npos) + Res += 20; + if (Path.find("/contrib/") != string::npos) + Res += 20; + if (Path.find("/non-free/") != string::npos) + Res += 20; + if (Path.find("/non-free-firmware/") != string::npos) + Res += 20; + if (Path.find("/non-US/") != string::npos) + Res += 20; + if (Path.find("/source/") != string::npos) + Res += 10; + if (Path.find("/debian/") != string::npos) + Res -= 10; + + // check for symlinks in the patch leading to the actual file + // a symlink gets a big penalty + struct stat Buf; + string statPath = flNotFile(Path); + string cdromPath = _config->FindDir("Acquire::cdrom::mount"); + while(statPath != cdromPath && statPath != "./") { + statPath.resize(statPath.size()-1); // remove the trailing '/' + if (lstat(statPath.c_str(),&Buf) == 0) { + if(S_ISLNK(Buf.st_mode)) { + Res -= 60; + break; + } + } + statPath = flNotFile(statPath); // descent + } + + return Res; +} + /*}}}*/ +// DropBinaryArch - Dump dirs with a string like /binary-<foo>/ /*{{{*/ +// --------------------------------------------------------------------- +/* Here we drop everything that is not this machines arch */ +bool pkgCdrom::DropBinaryArch(vector<string> &List) +{ + + for (unsigned int I = 0; I < List.size(); I++) + { + const char *Str = List[I].c_str(); + const char *Start, *End; + if ((Start = strstr(Str,"/binary-")) == 0) + continue; + + // Between Start and End is the architecture + Start += 8; + if ((End = strstr(Start,"/")) != 0 && Start != End && + APT::Configuration::checkArchitecture(string(Start, End)) == true) + continue; // okay, architecture is accepted + + // not accepted -> Erase it + List.erase(List.begin() + I); + --I; // the next entry is at the same index after the erase + } + + return true; +} + /*}}}*/ +// DropTranslation - Dump unwanted Translation-<lang> files /*{{{*/ +// --------------------------------------------------------------------- +/* Here we drop everything that is not configured in Acquire::Languages */ +bool pkgCdrom::DropTranslation(vector<string> &List) +{ + for (unsigned int I = 0; I < List.size(); I++) + { + const char *Start; + if ((Start = strstr(List[I].c_str(), "/Translation-")) == NULL) + continue; + Start += strlen("/Translation-"); + + if (APT::Configuration::checkLanguage(Start, true) == true) + continue; + + // not accepted -> Erase it + List.erase(List.begin() + I); + --I; // the next entry is at the same index after the erase + } + + return true; +} + /*}}}*/ +// DropRepeats - Drop repeated files resulting from symlinks /*{{{*/ +// --------------------------------------------------------------------- +/* Here we go and stat every file that we found and strip dup inodes. */ +bool pkgCdrom::DropRepeats(vector<string> &List,const char *Name) +{ + bool couldFindAllFiles = true; + // Get a list of all the inodes + ino_t *Inodes = new ino_t[List.size()]; + for (unsigned int I = 0; I != List.size(); ++I) + { + struct stat Buf; + bool found = false; + + std::vector<APT::Configuration::Compressor> const compressor = APT::Configuration::getCompressors(); + for (std::vector<APT::Configuration::Compressor>::const_iterator c = compressor.begin(); + c != compressor.end(); ++c) + { + std::string const filename = List[I] + Name + c->Extension; + if (stat(filename.c_str(), &Buf) != 0) + continue; + Inodes[I] = Buf.st_ino; + found = true; + break; + } + + if (found == false) + { + _error->Errno("stat","Failed to stat %s%s",List[I].c_str(), Name); + couldFindAllFiles = false; + Inodes[I] = 0; + } + } + + // Look for dups + for (unsigned int I = 0; I != List.size(); I++) + { + if (Inodes[I] == 0) + continue; + for (unsigned int J = I+1; J < List.size(); J++) + { + // No match + if (Inodes[J] == 0 || Inodes[J] != Inodes[I]) + continue; + + // We score the two paths.. and erase one + int ScoreA = Score(List[I]); + int ScoreB = Score(List[J]); + if (ScoreA < ScoreB) + { + List[I] = string(); + break; + } + + List[J] = string(); + } + } + delete[] Inodes; + + // Wipe erased entries + for (unsigned int I = 0; I < List.size();) + { + if (List[I].empty() == false) + I++; + else + List.erase(List.begin()+I); + } + + return couldFindAllFiles; +} + /*}}}*/ +// ReduceSourceList - Takes the path list and reduces it /*{{{*/ +// --------------------------------------------------------------------- +/* This takes the list of source list expressed entries and collects + similar ones to form a single entry for each dist */ +void pkgCdrom::ReduceSourcelist(string /*CD*/,vector<string> &List) +{ + sort(List.begin(),List.end()); + + // Collect similar entries + for (vector<string>::iterator I = List.begin(); I != List.end(); ++I) + { + // Find a space.. + string::size_type Space = (*I).find(' '); + if (Space == string::npos) + continue; + string::size_type SSpace = (*I).find(' ',Space + 1); + if (SSpace == string::npos) + continue; + + string Word1 = string(*I,Space,SSpace-Space); + string Prefix = string(*I,0,Space); + string Component = string(*I,SSpace); + for (vector<string>::iterator J = List.begin(); J != I; ++J) + { + // Find a space.. + string::size_type Space2 = (*J).find(' '); + if (Space2 == string::npos) + continue; + string::size_type SSpace2 = (*J).find(' ',Space2 + 1); + if (SSpace2 == string::npos) + continue; + + if (string(*J,0,Space2) != Prefix) + continue; + if (string(*J,Space2,SSpace2-Space2) != Word1) + continue; + + string Component2 = string(*J, SSpace2) + " "; + if (Component2.find(Component + " ") == std::string::npos) + *J += Component; + I->clear(); + } + } + + // Wipe erased entries + for (unsigned int I = 0; I < List.size();) + { + if (List[I].empty() == false) + I++; + else + List.erase(List.begin()+I); + } +} + /*}}}*/ +// WriteDatabase - Write the CDROM Database file /*{{{*/ +// --------------------------------------------------------------------- +/* We rewrite the configuration class associated with the cdrom database. */ +bool pkgCdrom::WriteDatabase(Configuration &Cnf) +{ + string DFile = _config->FindFile("Dir::State::cdroms"); + string NewFile = DFile + ".new"; + + RemoveFile("WriteDatabase", NewFile); + ofstream Out(NewFile.c_str()); + if (!Out) + return _error->Errno("ofstream::ofstream", + "Failed to open %s.new",DFile.c_str()); + + /* Write out all of the configuration directives by walking the + configuration tree */ + Cnf.Dump(Out, NULL, "%F \"%v\";\n", false); + + Out.close(); + + if (FileExists(DFile) == true) + rename(DFile.c_str(), (DFile + '~').c_str()); + if (rename(NewFile.c_str(),DFile.c_str()) != 0) + return _error->Errno("rename","Failed to rename %s.new to %s", + DFile.c_str(),DFile.c_str()); + + return true; +} + /*}}}*/ +// WriteSourceList - Write an updated sourcelist /*{{{*/ +// --------------------------------------------------------------------- +/* This reads the old source list and copies it into the new one. It + appends the new CDROM entries just after the first block of comments. + This places them first in the file. It also removes any old entries + that were the same. */ +bool pkgCdrom::WriteSourceList(string Name,vector<string> &List,bool Source) +{ + if (List.empty() == true) + return true; + + string File = _config->FindFile("Dir::Etc::sourcelist"); + + FileFd F(FileExists(File) ? File : "/dev/null", FileFd::ReadOnly); + if (not F.IsOpen() || F.Failed()) + return _error->Errno("WriteSourceList", "Opening %s failed", File.c_str()); + + string NewFile = File + ".new"; + RemoveFile("WriteSourceList", NewFile); + ofstream Out(NewFile.c_str()); + if (!Out) + return _error->Errno("ofstream::ofstream", + "Failed to open %s.new",File.c_str()); + + // Create a short uri without the path + string ShortURI = "cdrom:[" + Name + "]/"; + string ShortURI2 = "cdrom:" + Name + "/"; // For Compatibility + + string Type; + if (Source == true) + Type = "deb-src"; + else + Type = "deb"; + + int CurLine = 0; + bool First = true; + std::string Buffer; + while (F.ReadLine(Buffer)) + { + ++CurLine; + auto const Cleaned = APT::String::Strip(SubstVar(Buffer, "\t", " ")); + + // Comment or blank + if (Cleaned.empty() || Cleaned[0] == '#') + { + Out << Buffer << endl; + continue; + } + + if (First == true) + { + for (vector<string>::iterator I = List.begin(); I != List.end(); ++I) + { + string::size_type Space = (*I).find(' '); + if (Space == string::npos) + return _error->Error("Internal error"); + Out << Type << " cdrom:[" << Name << "]/" << string(*I,0,Space) << + " " << string(*I,Space+1) << endl; + } + } + First = false; + + // Grok it + string cType; + string URI; + const char *C = Cleaned.c_str(); + if (ParseQuoteWord(C,cType) == false || + ParseQuoteWord(C,URI) == false) + { + Out << Buffer << endl; + continue; + } + + // Emit lines like this one + if (cType != Type || (string(URI,0,ShortURI.length()) != ShortURI && + string(URI,0,ShortURI.length()) != ShortURI2)) + { + Out << Buffer << endl; + continue; + } + } + + // Just in case the file was empty + if (First == true) + { + for (vector<string>::iterator I = List.begin(); I != List.end(); ++I) + { + string::size_type Space = (*I).find(' '); + if (Space == string::npos) + return _error->Error("Internal error"); + + Out << "deb cdrom:[" << Name << "]/" << string(*I,0,Space) << + " " << string(*I,Space+1) << endl; + } + } + + Out.close(); + + rename(File.c_str(), (File + '~').c_str()); + if (rename(NewFile.c_str(),File.c_str()) != 0) + return _error->Errno("rename","Failed to rename %s.new to %s", + File.c_str(),File.c_str()); + + return true; +} + /*}}}*/ +bool pkgCdrom::UnmountCDROM(std::string const &CDROM, pkgCdromStatus * const log)/*{{{*/ +{ + if (_config->FindB("APT::CDROM::NoMount",false) == true) + return true; + if (log != NULL) + log->Update(_("Unmounting CD-ROM...\n"), STEP_LAST); + return UnmountCdrom(CDROM); +} + /*}}}*/ +bool pkgCdrom::MountAndIdentCDROM(Configuration &Database, std::string &CDROM, std::string &ident, pkgCdromStatus * const log, bool const interactive)/*{{{*/ +{ + // Startup + CDROM = _config->FindDir("Acquire::cdrom::mount"); + if (CDROM[0] == '.') + CDROM= SafeGetCWD() + '/' + CDROM; + + if (log != NULL) + { + string msg; + log->SetTotal(STEP_LAST); + strprintf(msg, _("Using CD-ROM mount point %s\n"), CDROM.c_str()); + log->Update(msg, STEP_PREPARE); + } + + // Unmount the CD and get the user to put in the one they want + if (_config->FindB("APT::CDROM::NoMount", false) == false) + { + if (interactive == true) + { + UnmountCDROM(CDROM, log); + + if(log != NULL) + { + log->Update(_("Waiting for disc...\n"), STEP_WAIT); + if(!log->ChangeCdrom()) { + // user aborted + return false; + } + } + } + + // Mount the new CDROM + if(log != NULL) + log->Update(_("Mounting CD-ROM...\n"), STEP_MOUNT); + + if (MountCdrom(CDROM) == false) + return _error->Error("Failed to mount the cdrom."); + } + + if (IsMounted(CDROM) == false) + return _error->Error("Failed to mount the cdrom."); + + // Hash the CD to get an ID + if (log != NULL) + log->Update(_("Identifying... "), STEP_IDENT); + + if (IdentCdrom(CDROM,ident) == false) + { + ident = ""; + if (log != NULL) + log->Update("\n"); + UnmountCDROM(CDROM, NULL); + return false; + } + + if (log != NULL) + { + string msg; + strprintf(msg, "[%s]\n", ident.c_str()); + log->Update(msg); + } + + // Read the database + string DFile = _config->FindFile("Dir::State::cdroms"); + if (FileExists(DFile) == true) + { + if (ReadConfigFile(Database,DFile) == false) + { + UnmountCDROM(CDROM, NULL); + return _error->Error("Unable to read the cdrom database %s", + DFile.c_str()); + } + } + return true; +} + /*}}}*/ +bool pkgCdrom::Ident(string &ident, pkgCdromStatus *log) /*{{{*/ +{ + Configuration Database; + std::string CDROM; + if (MountAndIdentCDROM(Database, CDROM, ident, log, false) == false) + return false; + + if (log != NULL) + { + string msg; + strprintf(msg, _("Stored label: %s\n"), + Database.Find("CD::"+ident).c_str()); + log->Update(msg); + } + + // Unmount and finish + UnmountCDROM(CDROM, log); + return true; +} + /*}}}*/ +bool pkgCdrom::Add(pkgCdromStatus *log) /*{{{*/ +{ + Configuration Database; + std::string ID, CDROM; + if (MountAndIdentCDROM(Database, CDROM, ID, log, true) == false) + return false; + + if(log != NULL) + log->Update(_("Scanning disc for index files...\n"),STEP_SCAN); + + // Get the CD structure + vector<string> List; + vector<string> SourceList; + vector<string> SigList; + vector<string> TransList; + string StartDir = SafeGetCWD(); + string InfoDir; + if (FindPackages(CDROM,List,SourceList, SigList,TransList,InfoDir,log) == false) + { + if (log != NULL) + log->Update("\n"); + UnmountCDROM(CDROM, NULL); + return false; + } + + if (chdir(StartDir.c_str()) != 0) + { + UnmountCDROM(CDROM, NULL); + return _error->Errno("chdir","Unable to change to %s", StartDir.c_str()); + } + + if (_config->FindB("Debug::aptcdrom",false) == true) + { + cout << "I found (binary):" << endl; + for (vector<string>::iterator I = List.begin(); I != List.end(); ++I) + cout << *I << endl; + cout << "I found (source):" << endl; + for (vector<string>::iterator I = SourceList.begin(); I != SourceList.end(); ++I) + cout << *I << endl; + cout << "I found (Signatures):" << endl; + for (vector<string>::iterator I = SigList.begin(); I != SigList.end(); ++I) + cout << *I << endl; + } + + //log->Update(_("Cleaning package lists..."), STEP_CLEAN); + + // Fix up the list + DropBinaryArch(List); + DropRepeats(List,"Packages"); + DropRepeats(SourceList,"Sources"); + // FIXME: We ignore stat() errors here as we usually have only one of those in use + // This has little potential to drop 'valid' stat() errors as we know that one of these + // files need to exist, but it would be better if we would check it here + _error->PushToStack(); + DropRepeats(SigList,"Release.gpg"); + DropRepeats(SigList,"InRelease"); + _error->RevertToStack(); + DropRepeats(TransList,""); + if (_config->FindB("APT::CDROM::DropTranslation", true) == true) + DropTranslation(TransList); + if(log != NULL) { + string msg; + strprintf(msg, _("Found %zu package indexes, %zu source indexes, " + "%zu translation indexes and %zu signatures\n"), + List.size(), SourceList.size(), TransList.size(), + SigList.size()); + log->Update(msg, STEP_SCAN); + } + + if (List.empty() == true && SourceList.empty() == true) + { + UnmountCDROM(CDROM, NULL); + return _error->Error(_("Unable to locate any package files, perhaps this is not a Debian Disc or the wrong architecture?")); + } + + // Check if the CD is in the database + string Name; + if (Database.Exists("CD::" + ID) == false || + _config->FindB("APT::CDROM::Rename",false) == true) + { + // Try to use the CDs label if at all possible + if (InfoDir.empty() == false && + FileExists(InfoDir + "/info") == true) + { + ifstream F((InfoDir + "/info").c_str()); + if (F.good() == true) + getline(F,Name); + + if (Name.empty() == false) + { + // Escape special characters + string::iterator J = Name.begin(); + for (; J != Name.end(); ++J) + if (*J == '"' || *J == ']' || *J == '[') + *J = '_'; + + if(log != NULL) + { + string msg; + strprintf(msg, _("Found label '%s'\n"), Name.c_str()); + log->Update(msg); + } + Database.Set("CD::" + ID + "::Label",Name); + } + } + + if (_config->FindB("APT::CDROM::Rename",false) == true || + Name.empty() == true) + { + if(log == NULL) + { + UnmountCDROM(CDROM, NULL); + return _error->Error("No disc name found and no way to ask for it"); + } + + while(true) { + if(!log->AskCdromName(Name)) { + // user canceld + UnmountCDROM(CDROM, NULL); + return false; + } + cout << "Name: '" << Name << "'" << endl; + + if (Name.empty() == false && + Name.find('"') == string::npos && + Name.find('[') == string::npos && + Name.find(']') == string::npos) + break; + log->Update(_("That is not a valid name, try again.\n")); + } + } + } + else + Name = Database.Find("CD::" + ID); + + // Escape special characters + string::iterator J = Name.begin(); + for (; J != Name.end(); ++J) + if (*J == '"' || *J == ']' || *J == '[') + *J = '_'; + + Database.Set("CD::" + ID,Name); + if(log != NULL) + { + string msg; + strprintf(msg, _("This disc is called: \n'%s'\n"), Name.c_str()); + log->Update(msg); + log->Update(_("Copying package lists..."), STEP_COPY); + } + + // check for existence and possibly create state directory for copying + string const listDir = _config->FindDir("Dir::State::lists"); + string const partialListDir = listDir + "partial/"; + mode_t const mode = umask(S_IWGRP | S_IWOTH); + bool const creation_fail = (CreateAPTDirectoryIfNeeded(_config->FindDir("Dir::State"), partialListDir) == false && + CreateAPTDirectoryIfNeeded(listDir, partialListDir) == false); + umask(mode); + if (creation_fail == true) + { + UnmountCDROM(CDROM, NULL); + return _error->Errno("cdrom", _("List directory %s is missing."), (listDir + "partial").c_str()); + } + + // take care of the signatures and copy them if they are ok + // (we do this before PackageCopy as it modifies "List" and "SourceList") + SigVerify SignVerify; + SignVerify.CopyAndVerify(CDROM, Name, SigList, List, SourceList); + + // Copy the package files to the state directory + PackageCopy Copy; + SourceCopy SrcCopy; + TranslationsCopy TransCopy; + if (Copy.CopyPackages(CDROM,Name,List, log) == false || + SrcCopy.CopyPackages(CDROM,Name,SourceList, log) == false || + TransCopy.CopyTranslations(CDROM,Name,TransList, log) == false) + { + UnmountCDROM(CDROM, NULL); + return false; + } + + // reduce the List so that it takes less space in sources.list + ReduceSourcelist(CDROM,List); + ReduceSourcelist(CDROM,SourceList); + + // Write the database and sourcelist + if (_config->FindB("APT::cdrom::NoAct",false) == false) + { + if (WriteDatabase(Database) == false) + { + UnmountCDROM(CDROM, NULL); + return false; + } + + if(log != NULL) + log->Update(_("Writing new source list\n"), STEP_WRITE); + if (WriteSourceList(Name,List,false) == false || + WriteSourceList(Name,SourceList,true) == false) + { + UnmountCDROM(CDROM, NULL); + return false; + } + } + + // Print the sourcelist entries + if(log != NULL) + log->Update(_("Source list entries for this disc are:\n")); + + for (vector<string>::iterator I = List.begin(); I != List.end(); ++I) + { + string::size_type Space = (*I).find(' '); + if (Space == string::npos) + { + UnmountCDROM(CDROM, NULL); + return _error->Error("Internal error"); + } + + if(log != NULL) + { + stringstream msg; + msg << "deb cdrom:[" << Name << "]/" << string(*I,0,Space) << + " " << string(*I,Space+1) << endl; + log->Update(msg.str()); + } + } + + for (vector<string>::iterator I = SourceList.begin(); I != SourceList.end(); ++I) + { + string::size_type Space = (*I).find(' '); + if (Space == string::npos) + { + UnmountCDROM(CDROM, NULL); + return _error->Error("Internal error"); + } + + if(log != NULL) { + stringstream msg; + msg << "deb-src cdrom:[" << Name << "]/" << string(*I,0,Space) << + " " << string(*I,Space+1) << endl; + log->Update(msg.str()); + } + } + + // Unmount and finish + UnmountCDROM(CDROM, log); + return true; +} + /*}}}*/ + +pkgUdevCdromDevices::pkgUdevCdromDevices() /*{{{*/ + : d(NULL) +{ +} + /*}}}*/ +// convenience interface, this will just call ScanForRemovable /*{{{*/ +vector<CdromDevice> pkgUdevCdromDevices::Scan() +{ + bool CdromOnly = _config->FindB("APT::cdrom::CdromOnly", true); + return ScanForRemovable(CdromOnly); +} + /*}}}*/ +vector<CdromDevice> pkgUdevCdromDevices::ScanForRemovable(bool CdromOnly)/*{{{*/ +{ + vector<CdromDevice> cdrom_devices; +#ifdef HAVE_UDEV + struct udev_enumerate *enumerate; + struct udev_list_entry *l, *devices; + struct udev *udev_ctx; + + udev_ctx = udev_new(); + enumerate = udev_enumerate_new (udev_ctx); + if (CdromOnly) + udev_enumerate_add_match_property(enumerate, "ID_CDROM", "1"); + else { + udev_enumerate_add_match_sysattr(enumerate, "removable", "1"); + } + + udev_enumerate_scan_devices (enumerate); + devices = udev_enumerate_get_list_entry (enumerate); + for (l = devices; l != NULL; l = udev_list_entry_get_next (l)) + { + CdromDevice cdrom; + struct udev_device *udevice; + udevice = udev_device_new_from_syspath (udev_enumerate_get_udev (enumerate), udev_list_entry_get_name (l)); + if (udevice == NULL) + continue; + const char* devnode = udev_device_get_devnode(udevice); + + // try fstab_dir first + string mountpath; + const char* mp = udev_device_get_property_value(udevice, "FSTAB_DIR"); + if (mp) + mountpath = string(mp); + else + mountpath = FindMountPointForDevice(devnode); + + // fill in the struct + cdrom.DeviceName = string(devnode); + if (mountpath != "") { + cdrom.MountPath = mountpath; + string s = mountpath; + cdrom.Mounted = IsMounted(s); + } else { + cdrom.Mounted = false; + cdrom.MountPath = ""; + } + cdrom_devices.push_back(cdrom); + } +#endif + return cdrom_devices; +} + /*}}}*/ + +pkgUdevCdromDevices::~pkgUdevCdromDevices() /*{{{*/ +{ +} + /*}}}*/ + +pkgCdromStatus::pkgCdromStatus() : d(NULL), totalSteps(0) {} +pkgCdromStatus::~pkgCdromStatus() {} + +pkgCdrom::pkgCdrom() : d(NULL) {} +pkgCdrom::~pkgCdrom() {} |