apt  2.2.4
About: Apt (Advanced Package Tool) is a management system for software packages (Debian/Ubuntu). Release series 2.2.
  Fossies Dox: apt-2.2.4.tar.gz  ("unofficial" and yet experimental doxygen-generated source code documentation)  

cdrom.cc
Go to the documentation of this file.
1 /*
2  */
3 #include <config.h>
4 
6 #include <apt-pkg/cdrom.h>
7 #include <apt-pkg/cdromutl.h>
8 #include <apt-pkg/configuration.h>
9 #include <apt-pkg/error.h>
10 #include <apt-pkg/fileutl.h>
11 #include <apt-pkg/indexcopy.h>
12 #include <apt-pkg/strutl.h>
13 
14 #include <algorithm>
15 #include <fstream>
16 #include <iostream>
17 #include <iostream>
18 #include <sstream>
19 #include <string>
20 #include <vector>
21 #include <dirent.h>
22 #include <dlfcn.h>
23 #include <stdio.h>
24 #include <string.h>
25 #include <sys/stat.h>
26 #include <unistd.h>
27 
28 #include <apti18n.h>
29 
30 #ifdef HAVE_UDEV
31 #include <libudev.h>
32 #endif
33 
34 using namespace std;
35 
36 // FindPackages - Find the package files on the CDROM /*{{{*/
37 // ---------------------------------------------------------------------
38 /* We look over the cdrom for package files. This is a recursive
39  search that short circuits when it his a package file in the dir.
40  This speeds it up greatly as the majority of the size is in the
41  binary-* sub dirs. */
42 bool pkgCdrom::FindPackages(string CD,
43  vector<string> &List,
44  vector<string> &SList,
45  vector<string> &SigList,
46  vector<string> &TransList,
47  string &InfoDir, pkgCdromStatus *log,
48  unsigned int Depth)
49 {
50  static ino_t Inodes[9];
51  DIR *D;
52 
53  // if we have a look we "pulse" now
54  if(log)
55  log->Update();
56 
57  if (Depth >= 7)
58  return true;
59 
60  if (CD[CD.length()-1] != '/')
61  CD += '/';
62 
63  if (chdir(CD.c_str()) != 0)
64  return _error->Errno("chdir","Unable to change to %s",CD.c_str());
65 
66  // Look for a .disk subdirectory
67  if (InfoDir.empty() == true)
68  {
69  if (DirectoryExists(".disk") == true)
70  InfoDir = InfoDir + CD + ".disk/";
71  }
72 
73  // Don't look into directories that have been marked to ignore.
74  if (RealFileExists(".aptignr") == true)
75  return true;
76 
77  /* Check _first_ for a signature file as apt-cdrom assumes that all files
78  under a Packages/Source file are in control of that file and stops
79  the scanning
80  */
81  if (RealFileExists("Release.gpg") == true || RealFileExists("InRelease") == true)
82  {
83  SigList.push_back(CD);
84  }
85 
86  /* Aha! We found some package files. We assume that everything under
87  this dir is controlled by those package files so we don't look down
88  anymore */
89  std::vector<APT::Configuration::Compressor> const compressor = APT::Configuration::getCompressors();
90  for (std::vector<APT::Configuration::Compressor>::const_iterator c = compressor.begin();
91  c != compressor.end(); ++c)
92  {
93  if (RealFileExists(std::string("Packages").append(c->Extension).c_str()) == false)
94  continue;
95 
96  if (_config->FindB("Debug::aptcdrom",false) == true)
97  std::clog << "Found Packages in " << CD << std::endl;
98  List.push_back(CD);
99 
100  // Continue down if thorough is given
101  if (_config->FindB("APT::CDROM::Thorough",false) == false)
102  return true;
103  break;
104  }
105  for (std::vector<APT::Configuration::Compressor>::const_iterator c = compressor.begin();
106  c != compressor.end(); ++c)
107  {
108  if (RealFileExists(std::string("Sources").append(c->Extension).c_str()) == false)
109  continue;
110 
111  if (_config->FindB("Debug::aptcdrom",false) == true)
112  std::clog << "Found Sources in " << CD << std::endl;
113  SList.push_back(CD);
114 
115  // Continue down if thorough is given
116  if (_config->FindB("APT::CDROM::Thorough",false) == false)
117  return true;
118  break;
119  }
120 
121  // see if we find translation indices
122  if (DirectoryExists("i18n") == true)
123  {
124  D = opendir("i18n");
125  for (struct dirent *Dir = readdir(D); Dir != 0; Dir = readdir(D))
126  {
127  if(strncmp(Dir->d_name, "Translation-", strlen("Translation-")) != 0)
128  continue;
129  string file = Dir->d_name;
130  for (std::vector<APT::Configuration::Compressor>::const_iterator c = compressor.begin();
131  c != compressor.end(); ++c)
132  {
133  string fileext = flExtension(file);
134  if (file == fileext)
135  fileext.clear();
136  else if (fileext.empty() == false)
137  fileext = "." + fileext;
138 
139  if (c->Extension == fileext)
140  {
141  if (_config->FindB("Debug::aptcdrom",false) == true)
142  std::clog << "Found translation " << Dir->d_name << " in " << CD << "i18n/" << std::endl;
143  file.erase(file.size() - fileext.size());
144  TransList.push_back(CD + "i18n/" + file);
145  break;
146  }
147  }
148  }
149  closedir(D);
150  }
151 
152  D = opendir(".");
153  if (D == 0)
154  return _error->Errno("opendir","Unable to read %s",CD.c_str());
155 
156  // Run over the directory
157  for (struct dirent *Dir = readdir(D); Dir != 0; Dir = readdir(D))
158  {
159  // Skip some files..
160  if (strcmp(Dir->d_name,".") == 0 ||
161  strcmp(Dir->d_name,"..") == 0 ||
162  strcmp(Dir->d_name,".disk") == 0 ||
163  strcmp(Dir->d_name,"debian-installer") == 0)
164  continue;
165 
166  // See if the name is a sub directory
167  struct stat Buf;
168  if (stat(Dir->d_name,&Buf) != 0)
169  continue;
170 
171  if (S_ISDIR(Buf.st_mode) == 0)
172  continue;
173 
174  unsigned int I;
175  for (I = 0; I != Depth; I++)
176  if (Inodes[I] == Buf.st_ino)
177  break;
178  if (I != Depth)
179  continue;
180 
181  // Store the inodes weve seen
182  Inodes[Depth] = Buf.st_ino;
183 
184  // Descend
185  if (FindPackages(CD + Dir->d_name,List,SList,SigList,TransList,InfoDir,log,Depth+1) == false)
186  break;
187 
188  if (chdir(CD.c_str()) != 0)
189  {
190  _error->Errno("chdir","Unable to change to %s", CD.c_str());
191  closedir(D);
192  return false;
193  }
194  };
195 
196  closedir(D);
197 
198  return !_error->PendingError();
199 }
200  /*}}}*/
201 // Score - We compute a 'score' for a path /*{{{*/
202 // ---------------------------------------------------------------------
203 /* Paths are scored based on how close they come to what I consider
204  normal. That is ones that have 'dist' 'stable' 'testing' will score
205  higher than ones without. */
206 int pkgCdrom::Score(string Path)
207 {
208  int Res = 0;
209  if (Path.find("stable/") != string::npos)
210  Res += 29;
211  if (Path.find("/binary-") != string::npos)
212  Res += 20;
213  if (Path.find("testing/") != string::npos)
214  Res += 28;
215  if (Path.find("unstable/") != string::npos)
216  Res += 27;
217  if (Path.find("/dists/") != string::npos)
218  Res += 40;
219  if (Path.find("/main/") != string::npos)
220  Res += 20;
221  if (Path.find("/contrib/") != string::npos)
222  Res += 20;
223  if (Path.find("/non-free/") != string::npos)
224  Res += 20;
225  if (Path.find("/non-US/") != string::npos)
226  Res += 20;
227  if (Path.find("/source/") != string::npos)
228  Res += 10;
229  if (Path.find("/debian/") != string::npos)
230  Res -= 10;
231 
232  // check for symlinks in the patch leading to the actual file
233  // a symlink gets a big penalty
234  struct stat Buf;
235  string statPath = flNotFile(Path);
236  string cdromPath = _config->FindDir("Acquire::cdrom::mount");
237  while(statPath != cdromPath && statPath != "./") {
238  statPath.resize(statPath.size()-1); // remove the trailing '/'
239  if (lstat(statPath.c_str(),&Buf) == 0) {
240  if(S_ISLNK(Buf.st_mode)) {
241  Res -= 60;
242  break;
243  }
244  }
245  statPath = flNotFile(statPath); // descent
246  }
247 
248  return Res;
249 }
250  /*}}}*/
251 // DropBinaryArch - Dump dirs with a string like /binary-<foo>/ /*{{{*/
252 // ---------------------------------------------------------------------
253 /* Here we drop everything that is not this machines arch */
254 bool pkgCdrom::DropBinaryArch(vector<string> &List)
255 {
256 
257  for (unsigned int I = 0; I < List.size(); I++)
258  {
259  const char *Str = List[I].c_str();
260  const char *Start, *End;
261  if ((Start = strstr(Str,"/binary-")) == 0)
262  continue;
263 
264  // Between Start and End is the architecture
265  Start += 8;
266  if ((End = strstr(Start,"/")) != 0 && Start != End &&
267  APT::Configuration::checkArchitecture(string(Start, End)) == true)
268  continue; // okay, architecture is accepted
269 
270  // not accepted -> Erase it
271  List.erase(List.begin() + I);
272  --I; // the next entry is at the same index after the erase
273  }
274 
275  return true;
276 }
277  /*}}}*/
278 // DropTranslation - Dump unwanted Translation-<lang> files /*{{{*/
279 // ---------------------------------------------------------------------
280 /* Here we drop everything that is not configured in Acquire::Languages */
281 bool pkgCdrom::DropTranslation(vector<string> &List)
282 {
283  for (unsigned int I = 0; I < List.size(); I++)
284  {
285  const char *Start;
286  if ((Start = strstr(List[I].c_str(), "/Translation-")) == NULL)
287  continue;
288  Start += strlen("/Translation-");
289 
290  if (APT::Configuration::checkLanguage(Start, true) == true)
291  continue;
292 
293  // not accepted -> Erase it
294  List.erase(List.begin() + I);
295  --I; // the next entry is at the same index after the erase
296  }
297 
298  return true;
299 }
300  /*}}}*/
301 // DropRepeats - Drop repeated files resulting from symlinks /*{{{*/
302 // ---------------------------------------------------------------------
303 /* Here we go and stat every file that we found and strip dup inodes. */
304 bool pkgCdrom::DropRepeats(vector<string> &List,const char *Name)
305 {
306  bool couldFindAllFiles = true;
307  // Get a list of all the inodes
308  ino_t *Inodes = new ino_t[List.size()];
309  for (unsigned int I = 0; I != List.size(); ++I)
310  {
311  struct stat Buf;
312  bool found = false;
313 
314  std::vector<APT::Configuration::Compressor> const compressor = APT::Configuration::getCompressors();
315  for (std::vector<APT::Configuration::Compressor>::const_iterator c = compressor.begin();
316  c != compressor.end(); ++c)
317  {
318  std::string const filename = List[I] + Name + c->Extension;
319  if (stat(filename.c_str(), &Buf) != 0)
320  continue;
321  Inodes[I] = Buf.st_ino;
322  found = true;
323  break;
324  }
325 
326  if (found == false)
327  {
328  _error->Errno("stat","Failed to stat %s%s",List[I].c_str(), Name);
329  couldFindAllFiles = false;
330  Inodes[I] = 0;
331  }
332  }
333 
334  // Look for dups
335  for (unsigned int I = 0; I != List.size(); I++)
336  {
337  if (Inodes[I] == 0)
338  continue;
339  for (unsigned int J = I+1; J < List.size(); J++)
340  {
341  // No match
342  if (Inodes[J] == 0 || Inodes[J] != Inodes[I])
343  continue;
344 
345  // We score the two paths.. and erase one
346  int ScoreA = Score(List[I]);
347  int ScoreB = Score(List[J]);
348  if (ScoreA < ScoreB)
349  {
350  List[I] = string();
351  break;
352  }
353 
354  List[J] = string();
355  }
356  }
357  delete[] Inodes;
358 
359  // Wipe erased entries
360  for (unsigned int I = 0; I < List.size();)
361  {
362  if (List[I].empty() == false)
363  I++;
364  else
365  List.erase(List.begin()+I);
366  }
367 
368  return couldFindAllFiles;
369 }
370  /*}}}*/
371 // ReduceSourceList - Takes the path list and reduces it /*{{{*/
372 // ---------------------------------------------------------------------
373 /* This takes the list of source list expressed entries and collects
374  similar ones to form a single entry for each dist */
375 void pkgCdrom::ReduceSourcelist(string /*CD*/,vector<string> &List)
376 {
377  sort(List.begin(),List.end());
378 
379  // Collect similar entries
380  for (vector<string>::iterator I = List.begin(); I != List.end(); ++I)
381  {
382  // Find a space..
383  string::size_type Space = (*I).find(' ');
384  if (Space == string::npos)
385  continue;
386  string::size_type SSpace = (*I).find(' ',Space + 1);
387  if (SSpace == string::npos)
388  continue;
389 
390  string Word1 = string(*I,Space,SSpace-Space);
391  string Prefix = string(*I,0,Space);
392  string Component = string(*I,SSpace);
393  for (vector<string>::iterator J = List.begin(); J != I; ++J)
394  {
395  // Find a space..
396  string::size_type Space2 = (*J).find(' ');
397  if (Space2 == string::npos)
398  continue;
399  string::size_type SSpace2 = (*J).find(' ',Space2 + 1);
400  if (SSpace2 == string::npos)
401  continue;
402 
403  if (string(*J,0,Space2) != Prefix)
404  continue;
405  if (string(*J,Space2,SSpace2-Space2) != Word1)
406  continue;
407 
408  string Component2 = string(*J, SSpace2) + " ";
409  if (Component2.find(Component + " ") == std::string::npos)
410  *J += Component;
411  I->clear();
412  }
413  }
414 
415  // Wipe erased entries
416  for (unsigned int I = 0; I < List.size();)
417  {
418  if (List[I].empty() == false)
419  I++;
420  else
421  List.erase(List.begin()+I);
422  }
423 }
424  /*}}}*/
425 // WriteDatabase - Write the CDROM Database file /*{{{*/
426 // ---------------------------------------------------------------------
427 /* We rewrite the configuration class associated with the cdrom database. */
429 {
430  string DFile = _config->FindFile("Dir::State::cdroms");
431  string NewFile = DFile + ".new";
432 
433  RemoveFile("WriteDatabase", NewFile);
434  ofstream Out(NewFile.c_str());
435  if (!Out)
436  return _error->Errno("ofstream::ofstream",
437  "Failed to open %s.new",DFile.c_str());
438 
439  /* Write out all of the configuration directives by walking the
440  configuration tree */
441  Cnf.Dump(Out, NULL, "%F \"%v\";\n", false);
442 
443  Out.close();
444 
445  if (FileExists(DFile) == true)
446  rename(DFile.c_str(), (DFile + '~').c_str());
447  if (rename(NewFile.c_str(),DFile.c_str()) != 0)
448  return _error->Errno("rename","Failed to rename %s.new to %s",
449  DFile.c_str(),DFile.c_str());
450 
451  return true;
452 }
453  /*}}}*/
454 // WriteSourceList - Write an updated sourcelist /*{{{*/
455 // ---------------------------------------------------------------------
456 /* This reads the old source list and copies it into the new one. It
457  appends the new CDROM entries just after the first block of comments.
458  This places them first in the file. It also removes any old entries
459  that were the same. */
460 bool pkgCdrom::WriteSourceList(string Name,vector<string> &List,bool Source)
461 {
462  if (List.empty() == true)
463  return true;
464 
465  string File = _config->FindFile("Dir::Etc::sourcelist");
466 
467  FileFd F(FileExists(File) ? File : "/dev/null", FileFd::ReadOnly);
468  if (not F.IsOpen() || F.Failed())
469  return _error->Errno("WriteSourceList", "Opening %s failed", File.c_str());
470 
471  string NewFile = File + ".new";
472  RemoveFile("WriteSourceList", NewFile);
473  ofstream Out(NewFile.c_str());
474  if (!Out)
475  return _error->Errno("ofstream::ofstream",
476  "Failed to open %s.new",File.c_str());
477 
478  // Create a short uri without the path
479  string ShortURI = "cdrom:[" + Name + "]/";
480  string ShortURI2 = "cdrom:" + Name + "/"; // For Compatibility
481 
482  string Type;
483  if (Source == true)
484  Type = "deb-src";
485  else
486  Type = "deb";
487 
488  int CurLine = 0;
489  bool First = true;
490  std::string Buffer;
491  while (F.ReadLine(Buffer))
492  {
493  ++CurLine;
494  auto const Cleaned = APT::String::Strip(SubstVar(Buffer, "\t", " "));
495 
496  // Comment or blank
497  if (Cleaned.empty() || Cleaned[0] == '#')
498  {
499  Out << Buffer << endl;
500  continue;
501  }
502 
503  if (First == true)
504  {
505  for (vector<string>::iterator I = List.begin(); I != List.end(); ++I)
506  {
507  string::size_type Space = (*I).find(' ');
508  if (Space == string::npos)
509  return _error->Error("Internal error");
510  Out << Type << " cdrom:[" << Name << "]/" << string(*I,0,Space) <<
511  " " << string(*I,Space+1) << endl;
512  }
513  }
514  First = false;
515 
516  // Grok it
517  string cType;
518  string URI;
519  const char *C = Cleaned.c_str();
520  if (ParseQuoteWord(C,cType) == false ||
521  ParseQuoteWord(C,URI) == false)
522  {
523  Out << Buffer << endl;
524  continue;
525  }
526 
527  // Emit lines like this one
528  if (cType != Type || (string(URI,0,ShortURI.length()) != ShortURI &&
529  string(URI,0,ShortURI.length()) != ShortURI2))
530  {
531  Out << Buffer << endl;
532  continue;
533  }
534  }
535 
536  // Just in case the file was empty
537  if (First == true)
538  {
539  for (vector<string>::iterator I = List.begin(); I != List.end(); ++I)
540  {
541  string::size_type Space = (*I).find(' ');
542  if (Space == string::npos)
543  return _error->Error("Internal error");
544 
545  Out << "deb cdrom:[" << Name << "]/" << string(*I,0,Space) <<
546  " " << string(*I,Space+1) << endl;
547  }
548  }
549 
550  Out.close();
551 
552  rename(File.c_str(), (File + '~').c_str());
553  if (rename(NewFile.c_str(),File.c_str()) != 0)
554  return _error->Errno("rename","Failed to rename %s.new to %s",
555  File.c_str(),File.c_str());
556 
557  return true;
558 }
559  /*}}}*/
560 bool pkgCdrom::UnmountCDROM(std::string const &CDROM, pkgCdromStatus * const log)/*{{{*/
561 {
562  if (_config->FindB("APT::CDROM::NoMount",false) == true)
563  return true;
564  if (log != NULL)
565  log->Update(_("Unmounting CD-ROM...\n"), STEP_LAST);
566  return UnmountCdrom(CDROM);
567 }
568  /*}}}*/
569 bool pkgCdrom::MountAndIdentCDROM(Configuration &Database, std::string &CDROM, std::string &ident, pkgCdromStatus * const log, bool const interactive)/*{{{*/
570 {
571  // Startup
572  CDROM = _config->FindDir("Acquire::cdrom::mount");
573  if (CDROM[0] == '.')
574  CDROM= SafeGetCWD() + '/' + CDROM;
575 
576  if (log != NULL)
577  {
578  string msg;
579  log->SetTotal(STEP_LAST);
580  strprintf(msg, _("Using CD-ROM mount point %s\n"), CDROM.c_str());
581  log->Update(msg, STEP_PREPARE);
582  }
583 
584  // Unmount the CD and get the user to put in the one they want
585  if (_config->FindB("APT::CDROM::NoMount", false) == false)
586  {
587  if (interactive == true)
588  {
589  UnmountCDROM(CDROM, log);
590 
591  if(log != NULL)
592  {
593  log->Update(_("Waiting for disc...\n"), STEP_WAIT);
594  if(!log->ChangeCdrom()) {
595  // user aborted
596  return false;
597  }
598  }
599  }
600 
601  // Mount the new CDROM
602  if(log != NULL)
603  log->Update(_("Mounting CD-ROM...\n"), STEP_MOUNT);
604 
605  if (MountCdrom(CDROM) == false)
606  return _error->Error("Failed to mount the cdrom.");
607  }
608 
609  if (IsMounted(CDROM) == false)
610  return _error->Error("Failed to mount the cdrom.");
611 
612  // Hash the CD to get an ID
613  if (log != NULL)
614  log->Update(_("Identifying... "), STEP_IDENT);
615 
616  if (IdentCdrom(CDROM,ident) == false)
617  {
618  ident = "";
619  if (log != NULL)
620  log->Update("\n");
621  UnmountCDROM(CDROM, NULL);
622  return false;
623  }
624 
625  if (log != NULL)
626  {
627  string msg;
628  strprintf(msg, "[%s]\n", ident.c_str());
629  log->Update(msg);
630  }
631 
632  // Read the database
633  string DFile = _config->FindFile("Dir::State::cdroms");
634  if (FileExists(DFile) == true)
635  {
636  if (ReadConfigFile(Database,DFile) == false)
637  {
638  UnmountCDROM(CDROM, NULL);
639  return _error->Error("Unable to read the cdrom database %s",
640  DFile.c_str());
641  }
642  }
643  return true;
644 }
645  /*}}}*/
646 bool pkgCdrom::Ident(string &ident, pkgCdromStatus *log) /*{{{*/
647 {
648  Configuration Database;
649  std::string CDROM;
650  if (MountAndIdentCDROM(Database, CDROM, ident, log, false) == false)
651  return false;
652 
653  if (log != NULL)
654  {
655  string msg;
656  strprintf(msg, _("Stored label: %s\n"),
657  Database.Find("CD::"+ident).c_str());
658  log->Update(msg);
659  }
660 
661  // Unmount and finish
662  UnmountCDROM(CDROM, log);
663  return true;
664 }
665  /*}}}*/
666 bool pkgCdrom::Add(pkgCdromStatus *log) /*{{{*/
667 {
668  Configuration Database;
669  std::string ID, CDROM;
670  if (MountAndIdentCDROM(Database, CDROM, ID, log, true) == false)
671  return false;
672 
673  if(log != NULL)
674  log->Update(_("Scanning disc for index files...\n"),STEP_SCAN);
675 
676  // Get the CD structure
677  vector<string> List;
678  vector<string> SourceList;
679  vector<string> SigList;
680  vector<string> TransList;
681  string StartDir = SafeGetCWD();
682  string InfoDir;
683  if (FindPackages(CDROM,List,SourceList, SigList,TransList,InfoDir,log) == false)
684  {
685  if (log != NULL)
686  log->Update("\n");
687  UnmountCDROM(CDROM, NULL);
688  return false;
689  }
690 
691  if (chdir(StartDir.c_str()) != 0)
692  {
693  UnmountCDROM(CDROM, NULL);
694  return _error->Errno("chdir","Unable to change to %s", StartDir.c_str());
695  }
696 
697  if (_config->FindB("Debug::aptcdrom",false) == true)
698  {
699  cout << "I found (binary):" << endl;
700  for (vector<string>::iterator I = List.begin(); I != List.end(); ++I)
701  cout << *I << endl;
702  cout << "I found (source):" << endl;
703  for (vector<string>::iterator I = SourceList.begin(); I != SourceList.end(); ++I)
704  cout << *I << endl;
705  cout << "I found (Signatures):" << endl;
706  for (vector<string>::iterator I = SigList.begin(); I != SigList.end(); ++I)
707  cout << *I << endl;
708  }
709 
710  //log->Update(_("Cleaning package lists..."), STEP_CLEAN);
711 
712  // Fix up the list
713  DropBinaryArch(List);
714  DropRepeats(List,"Packages");
715  DropRepeats(SourceList,"Sources");
716  // FIXME: We ignore stat() errors here as we usually have only one of those in use
717  // This has little potential to drop 'valid' stat() errors as we know that one of these
718  // files need to exist, but it would be better if we would check it here
719  _error->PushToStack();
720  DropRepeats(SigList,"Release.gpg");
721  DropRepeats(SigList,"InRelease");
722  _error->RevertToStack();
723  DropRepeats(TransList,"");
724  if (_config->FindB("APT::CDROM::DropTranslation", true) == true)
725  DropTranslation(TransList);
726  if(log != NULL) {
727  string msg;
728  strprintf(msg, _("Found %zu package indexes, %zu source indexes, "
729  "%zu translation indexes and %zu signatures\n"),
730  List.size(), SourceList.size(), TransList.size(),
731  SigList.size());
732  log->Update(msg, STEP_SCAN);
733  }
734 
735  if (List.empty() == true && SourceList.empty() == true)
736  {
737  UnmountCDROM(CDROM, NULL);
738  return _error->Error(_("Unable to locate any package files, perhaps this is not a Debian Disc or the wrong architecture?"));
739  }
740 
741  // Check if the CD is in the database
742  string Name;
743  if (Database.Exists("CD::" + ID) == false ||
744  _config->FindB("APT::CDROM::Rename",false) == true)
745  {
746  // Try to use the CDs label if at all possible
747  if (InfoDir.empty() == false &&
748  FileExists(InfoDir + "/info") == true)
749  {
750  ifstream F((InfoDir + "/info").c_str());
751  if (F.good() == true)
752  getline(F,Name);
753 
754  if (Name.empty() == false)
755  {
756  // Escape special characters
757  string::iterator J = Name.begin();
758  for (; J != Name.end(); ++J)
759  if (*J == '"' || *J == ']' || *J == '[')
760  *J = '_';
761 
762  if(log != NULL)
763  {
764  string msg;
765  strprintf(msg, _("Found label '%s'\n"), Name.c_str());
766  log->Update(msg);
767  }
768  Database.Set("CD::" + ID + "::Label",Name);
769  }
770  }
771 
772  if (_config->FindB("APT::CDROM::Rename",false) == true ||
773  Name.empty() == true)
774  {
775  if(log == NULL)
776  {
777  UnmountCDROM(CDROM, NULL);
778  return _error->Error("No disc name found and no way to ask for it");
779  }
780 
781  while(true) {
782  if(!log->AskCdromName(Name)) {
783  // user canceld
784  UnmountCDROM(CDROM, NULL);
785  return false;
786  }
787  cout << "Name: '" << Name << "'" << endl;
788 
789  if (Name.empty() == false &&
790  Name.find('"') == string::npos &&
791  Name.find('[') == string::npos &&
792  Name.find(']') == string::npos)
793  break;
794  log->Update(_("That is not a valid name, try again.\n"));
795  }
796  }
797  }
798  else
799  Name = Database.Find("CD::" + ID);
800 
801  // Escape special characters
802  string::iterator J = Name.begin();
803  for (; J != Name.end(); ++J)
804  if (*J == '"' || *J == ']' || *J == '[')
805  *J = '_';
806 
807  Database.Set("CD::" + ID,Name);
808  if(log != NULL)
809  {
810  string msg;
811  strprintf(msg, _("This disc is called: \n'%s'\n"), Name.c_str());
812  log->Update(msg);
813  log->Update(_("Copying package lists..."), STEP_COPY);
814  }
815 
816  // check for existence and possibly create state directory for copying
817  string const listDir = _config->FindDir("Dir::State::lists");
818  string const partialListDir = listDir + "partial/";
819  mode_t const mode = umask(S_IWGRP | S_IWOTH);
820  bool const creation_fail = (CreateAPTDirectoryIfNeeded(_config->FindDir("Dir::State"), partialListDir) == false &&
821  CreateAPTDirectoryIfNeeded(listDir, partialListDir) == false);
822  umask(mode);
823  if (creation_fail == true)
824  {
825  UnmountCDROM(CDROM, NULL);
826  return _error->Errno("cdrom", _("List directory %s is missing."), (listDir + "partial").c_str());
827  }
828 
829  // take care of the signatures and copy them if they are ok
830  // (we do this before PackageCopy as it modifies "List" and "SourceList")
831  SigVerify SignVerify;
832  SignVerify.CopyAndVerify(CDROM, Name, SigList, List, SourceList);
833 
834  // Copy the package files to the state directory
835  PackageCopy Copy;
836  SourceCopy SrcCopy;
837  TranslationsCopy TransCopy;
838  if (Copy.CopyPackages(CDROM,Name,List, log) == false ||
839  SrcCopy.CopyPackages(CDROM,Name,SourceList, log) == false ||
840  TransCopy.CopyTranslations(CDROM,Name,TransList, log) == false)
841  {
842  UnmountCDROM(CDROM, NULL);
843  return false;
844  }
845 
846  // reduce the List so that it takes less space in sources.list
847  ReduceSourcelist(CDROM,List);
848  ReduceSourcelist(CDROM,SourceList);
849 
850  // Write the database and sourcelist
851  if (_config->FindB("APT::cdrom::NoAct",false) == false)
852  {
853  if (WriteDatabase(Database) == false)
854  {
855  UnmountCDROM(CDROM, NULL);
856  return false;
857  }
858 
859  if(log != NULL)
860  log->Update(_("Writing new source list\n"), STEP_WRITE);
861  if (WriteSourceList(Name,List,false) == false ||
862  WriteSourceList(Name,SourceList,true) == false)
863  {
864  UnmountCDROM(CDROM, NULL);
865  return false;
866  }
867  }
868 
869  // Print the sourcelist entries
870  if(log != NULL)
871  log->Update(_("Source list entries for this disc are:\n"));
872 
873  for (vector<string>::iterator I = List.begin(); I != List.end(); ++I)
874  {
875  string::size_type Space = (*I).find(' ');
876  if (Space == string::npos)
877  {
878  UnmountCDROM(CDROM, NULL);
879  return _error->Error("Internal error");
880  }
881 
882  if(log != NULL)
883  {
884  stringstream msg;
885  msg << "deb cdrom:[" << Name << "]/" << string(*I,0,Space) <<
886  " " << string(*I,Space+1) << endl;
887  log->Update(msg.str());
888  }
889  }
890 
891  for (vector<string>::iterator I = SourceList.begin(); I != SourceList.end(); ++I)
892  {
893  string::size_type Space = (*I).find(' ');
894  if (Space == string::npos)
895  {
896  UnmountCDROM(CDROM, NULL);
897  return _error->Error("Internal error");
898  }
899 
900  if(log != NULL) {
901  stringstream msg;
902  msg << "deb-src cdrom:[" << Name << "]/" << string(*I,0,Space) <<
903  " " << string(*I,Space+1) << endl;
904  log->Update(msg.str());
905  }
906  }
907 
908  // Unmount and finish
909  UnmountCDROM(CDROM, log);
910  return true;
911 }
912  /*}}}*/
913 
915  : d(NULL)
916 {
917 }
918  /*}}}*/
919 // convenience interface, this will just call ScanForRemovable /*{{{*/
920 vector<CdromDevice> pkgUdevCdromDevices::Scan()
921 {
922  bool CdromOnly = _config->FindB("APT::cdrom::CdromOnly", true);
923  return ScanForRemovable(CdromOnly);
924 }
925  /*}}}*/
926 vector<CdromDevice> pkgUdevCdromDevices::ScanForRemovable(bool CdromOnly)/*{{{*/
927 {
928  vector<CdromDevice> cdrom_devices;
929 #ifdef HAVE_UDEV
930  struct udev_enumerate *enumerate;
931  struct udev_list_entry *l, *devices;
932  struct udev *udev_ctx;
933 
934  udev_ctx = udev_new();
935  enumerate = udev_enumerate_new (udev_ctx);
936  if (CdromOnly)
937  udev_enumerate_add_match_property(enumerate, "ID_CDROM", "1");
938  else {
939  udev_enumerate_add_match_sysattr(enumerate, "removable", "1");
940  }
941 
942  udev_enumerate_scan_devices (enumerate);
943  devices = udev_enumerate_get_list_entry (enumerate);
944  for (l = devices; l != NULL; l = udev_list_entry_get_next (l))
945  {
946  CdromDevice cdrom;
947  struct udev_device *udevice;
948  udevice = udev_device_new_from_syspath (udev_enumerate_get_udev (enumerate), udev_list_entry_get_name (l));
949  if (udevice == NULL)
950  continue;
951  const char* devnode = udev_device_get_devnode(udevice);
952 
953  // try fstab_dir first
954  string mountpath;
955  const char* mp = udev_device_get_property_value(udevice, "FSTAB_DIR");
956  if (mp)
957  mountpath = string(mp);
958  else
959  mountpath = FindMountPointForDevice(devnode);
960 
961  // fill in the struct
962  cdrom.DeviceName = string(devnode);
963  if (mountpath != "") {
964  cdrom.MountPath = mountpath;
965  string s = mountpath;
966  cdrom.Mounted = IsMounted(s);
967  } else {
968  cdrom.Mounted = false;
969  cdrom.MountPath = "";
970  }
971  cdrom_devices.push_back(cdrom);
972  }
973 #endif
974  return cdrom_devices;
975 }
976  /*}}}*/
977 
979 {
980 }
981  /*}}}*/
982 
983 pkgCdromStatus::pkgCdromStatus() : d(NULL), totalSteps(0) {}
985 
986 pkgCdrom::pkgCdrom() : d(NULL) {}
strprintf(m, msg, repo.c_str())
static bool std::string const metaIndex const *const pkgAcqMetaClearSig *const pkgAcquire::Item *const I
static char const *const msg
bool MountCdrom(string Path, string DeviceName)
Definition: cdromutl.cc:130
bool IdentCdrom(string CD, string &Res, unsigned int Version)
Definition: cdromutl.cc:182
bool UnmountCdrom(string Path)
Definition: cdromutl.cc:75
bool IsMounted(string &Path)
Definition: cdromutl.cc:44
string FindMountPointForDevice(const char *devnode)
Definition: cdromutl.cc:262
Provide access methods to various configuration settings.
Definition: fileutl.h:39
bool IsOpen()
Definition: fileutl.h:150
@ ReadOnly
Definition: fileutl.h:59
bool Failed()
Definition: fileutl.h:151
char * ReadLine(char *To, unsigned long long const Size)
Definition: fileutl.cc:2776
bool CopyPackages(std::string CDROM, std::string Name, std::vector< std::string > &List, pkgCdromStatus *log)
Definition: indexcopy.cc:44
bool CopyAndVerify(std::string CDROM, std::string Name, std::vector< std::string > &SigList, std::vector< std::string > PkgList, std::vector< std::string > SrcList)
Definition: indexcopy.cc:551
bool CopyTranslations(std::string CDROM, std::string Name, std::vector< std::string > &List, pkgCdromStatus *log)
Definition: indexcopy.cc:643
Definition: strutl.h:193
pkgCdromStatus()
Definition: cdrom.cc:983
virtual bool ChangeCdrom()=0
virtual void SetTotal(int total)
Definition: cdrom.h:26
virtual bool AskCdromName(std::string &Name)=0
virtual void Update(std::string text="", int current=0)=0
virtual ~pkgCdromStatus()
Definition: cdrom.cc:984
bool FindPackages(std::string CD, std::vector< std::string > &List, std::vector< std::string > &SList, std::vector< std::string > &SigList, std::vector< std::string > &TransList, std::string &InfoDir, pkgCdromStatus *log, unsigned int Depth=0)
Definition: cdrom.cc:42
bool WriteDatabase(Configuration &Cnf)
Definition: cdrom.cc:428
pkgCdrom()
Definition: cdrom.cc:986
bool Add(pkgCdromStatus *log)
Definition: cdrom.cc:666
bool DropRepeats(std::vector< std::string > &List, const char *Name)
Definition: cdrom.cc:304
APT_HIDDEN bool UnmountCDROM(std::string const &CDROM, pkgCdromStatus *const log)
Definition: cdrom.cc:560
void ReduceSourcelist(std::string CD, std::vector< std::string > &List)
Definition: cdrom.cc:375
bool WriteSourceList(std::string Name, std::vector< std::string > &List, bool Source)
Definition: cdrom.cc:460
@ STEP_IDENT
Definition: cdrom.h:46
@ STEP_PREPARE
Definition: cdrom.h:42
@ STEP_WRITE
Definition: cdrom.h:49
@ STEP_MOUNT
Definition: cdrom.h:45
@ STEP_WAIT
Definition: cdrom.h:44
@ STEP_COPY
Definition: cdrom.h:48
@ STEP_LAST
Definition: cdrom.h:51
@ STEP_SCAN
Definition: cdrom.h:47
bool DropBinaryArch(std::vector< std::string > &List)
Definition: cdrom.cc:254
bool Ident(std::string &ident, pkgCdromStatus *log)
Definition: cdrom.cc:646
APT_HIDDEN bool MountAndIdentCDROM(Configuration &Database, std::string &CDROM, std::string &ident, pkgCdromStatus *const log, bool const interactive)
Definition: cdrom.cc:569
bool DropTranslation(std::vector< std::string > &List)
Definition: cdrom.cc:281
int Score(std::string Path)
Definition: cdrom.cc:206
virtual ~pkgCdrom()
Definition: cdrom.cc:987
virtual ~pkgUdevCdromDevices()
Definition: cdrom.cc:978
std::vector< CdromDevice > Scan()
Definition: cdrom.cc:920
std::vector< CdromDevice > ScanForRemovable(bool CdromOnly)
Definition: cdrom.cc:926
bool ReadConfigFile(Configuration &Conf, const string &FName, bool const &AsSectional, unsigned const &Depth)
DIR
Configuration * _config
string flNotFile(string File)
Definition: fileutl.cc:676
string flExtension(string File)
Definition: fileutl.cc:688
bool DirectoryExists(string const &Path)
Definition: fileutl.cc:348
bool CreateAPTDirectoryIfNeeded(string const &Parent, string const &Path)
Ensure the existence of the given Path.
Definition: fileutl.cc:400
bool FileExists(string File)
Definition: fileutl.cc:326
bool RemoveFile(char const *const Function, std::string const &FileName)
Definition: fileutl.cc:198
bool RealFileExists(string File)
Definition: fileutl.cc:337
string SafeGetCWD()
Definition: fileutl.cc:637
APT_PUBLIC bool checkLanguage(std::string Lang, bool const All=false)
Are we interested in the given Language?
APT_PUBLIC std::vector< Compressor > const getCompressors(bool const Cached=true)
Return a vector of Compressors supported for data.tar's.
APT_PUBLIC bool checkArchitecture(std::string const &Arch)
Are we interested in the given Architecture?
std::string Strip(const std::string &str)
Definition: strutl.cc:55
std::string MountPath
Definition: cdrom.h:92
bool Mounted
Definition: cdrom.h:91
std::string DeviceName
Definition: cdrom.h:90
string SubstVar(const string &Str, const string &Subst, const string &Contents)
Definition: strutl.cc:502
bool ParseQuoteWord(const char *&String, string &Res)
Definition: strutl.cc:288