ifdef for i18n stuff
[ntk/apt.git] / cmdline / apt-cdrom.cc
CommitLineData
83d89a9f
AL
1// -*- mode: cpp; mode: fold -*-
2// Description /*{{{*/
201e83c2 3// $Id: apt-cdrom.cc,v 1.40 2001/08/18 22:23:38 jgg Exp $
83d89a9f
AL
4/* ######################################################################
5
18444708
AL
6 APT CDROM - Tool for handling APT's CDROM database.
7
8 Currently the only option is 'add' which will take the current CD
9 in the drive and add it into the database.
83d89a9f
AL
10
11 ##################################################################### */
12 /*}}}*/
13// Include Files /*{{{*/
14#include <apt-pkg/cmndline.h>
15#include <apt-pkg/error.h>
16#include <apt-pkg/init.h>
83d89a9f
AL
17#include <apt-pkg/fileutl.h>
18#include <apt-pkg/progress.h>
65ae8fab 19#include <apt-pkg/cdromutl.h>
cdcc6d34 20#include <apt-pkg/strutl.h>
83d89a9f 21#include <config.h>
b2e465d6
AL
22#include <apti18n.h>
23
143abaeb
AL
24#include "indexcopy.h"
25
83d89a9f 26#include <iostream>
18444708 27#include <fstream>
83d89a9f
AL
28#include <vector>
29#include <algorithm>
83d89a9f
AL
30#include <sys/stat.h>
31#include <fcntl.h>
32#include <dirent.h>
33#include <unistd.h>
34#include <stdio.h>
35 /*}}}*/
36
076d01b0
AL
37using namespace std;
38
4dfaa253 39// FindPackages - Find the package files on the CDROM /*{{{*/
83d89a9f
AL
40// ---------------------------------------------------------------------
41/* We look over the cdrom for package files. This is a recursive
42 search that short circuits when it his a package file in the dir.
43 This speeds it up greatly as the majority of the size is in the
44 binary-* sub dirs. */
13d87e2e
AL
45bool FindPackages(string CD,vector<string> &List,vector<string> &SList,
46 string &InfoDir,unsigned int Depth = 0)
83d89a9f 47{
2c78c00b 48 static ino_t Inodes[9];
4dfaa253 49 if (Depth >= 7)
83d89a9f
AL
50 return true;
51
52 if (CD[CD.length()-1] != '/')
53 CD += '/';
143abaeb 54
83d89a9f
AL
55 if (chdir(CD.c_str()) != 0)
56 return _error->Errno("chdir","Unable to change to %s",CD.c_str());
57
dafaee52
AL
58 // Look for a .disk subdirectory
59 struct stat Buf;
60 if (stat(".disk",&Buf) == 0)
61 {
62 if (InfoDir.empty() == true)
63 InfoDir = CD + ".disk/";
64 }
65
dd27443e 66 // Don't look into directories that have been marked to ingore.
201e83c2 67 if (stat(".aptignr",&Buf) == 0)
dd27443e
AL
68 return true;
69
83d89a9f
AL
70 /* Aha! We found some package files. We assume that everything under
71 this dir is controlled by those package files so we don't look down
72 anymore */
bd37d248 73 if (stat("Packages",&Buf) == 0 || stat("Packages.gz",&Buf) == 0)
83d89a9f
AL
74 {
75 List.push_back(CD);
c60d151b
AL
76
77 // Continue down if thorough is given
78 if (_config->FindB("APT::CDROM::Thorough",false) == false)
79 return true;
83d89a9f 80 }
143abaeb 81 if (stat("Sources.gz",&Buf) == 0 || stat("Sources",&Buf) == 0)
13d87e2e
AL
82 {
83 SList.push_back(CD);
84
85 // Continue down if thorough is given
86 if (_config->FindB("APT::CDROM::Thorough",false) == false)
87 return true;
88 }
22177db9 89
83d89a9f
AL
90 DIR *D = opendir(".");
91 if (D == 0)
92 return _error->Errno("opendir","Unable to read %s",CD.c_str());
93
94 // Run over the directory
95 for (struct dirent *Dir = readdir(D); Dir != 0; Dir = readdir(D))
96 {
97 // Skip some files..
98 if (strcmp(Dir->d_name,".") == 0 ||
99 strcmp(Dir->d_name,"..") == 0 ||
13d87e2e 100 //strcmp(Dir->d_name,"source") == 0 ||
ed51f28e 101 strcmp(Dir->d_name,".disk") == 0 ||
83d89a9f
AL
102 strcmp(Dir->d_name,"experimental") == 0 ||
103 strcmp(Dir->d_name,"binary-all") == 0)
104 continue;
105
106 // See if the name is a sub directory
107 struct stat Buf;
108 if (stat(Dir->d_name,&Buf) != 0)
4dfaa253 109 continue;
83d89a9f
AL
110
111 if (S_ISDIR(Buf.st_mode) == 0)
112 continue;
113
e02343ac
AL
114 unsigned int I;
115 for (I = 0; I != Depth; I++)
116 if (Inodes[I] == Buf.st_ino)
117 break;
f1663bdf 118 if (I != Depth)
9bf3ee5c 119 continue;
f1663bdf 120
e02343ac
AL
121 // Store the inodes weve seen
122 Inodes[Depth] = Buf.st_ino;
123
83d89a9f 124 // Descend
13d87e2e 125 if (FindPackages(CD + Dir->d_name,List,SList,InfoDir,Depth+1) == false)
83d89a9f
AL
126 break;
127
128 if (chdir(CD.c_str()) != 0)
b2e465d6 129 return _error->Errno("chdir","Unable to change to %s",CD.c_str());
83d89a9f
AL
130 };
131
132 closedir(D);
133
134 return !_error->PendingError();
135}
136 /*}}}*/
83d89a9f
AL
137// DropBinaryArch - Dump dirs with a string like /binary-<foo>/ /*{{{*/
138// ---------------------------------------------------------------------
139/* Here we drop everything that is not this machines arch */
140bool DropBinaryArch(vector<string> &List)
141{
142 char S[300];
20ebd488
AL
143 snprintf(S,sizeof(S),"/binary-%s/",
144 _config->Find("Apt::Architecture").c_str());
83d89a9f
AL
145
146 for (unsigned int I = 0; I < List.size(); I++)
147 {
148 const char *Str = List[I].c_str();
149
150 const char *Res;
151 if ((Res = strstr(Str,"/binary-")) == 0)
152 continue;
153
154 // Weird, remove it.
155 if (strlen(Res) < strlen(S))
156 {
157 List.erase(List.begin() + I);
158 I--;
159 continue;
160 }
161
162 // See if it is our arch
163 if (stringcmp(Res,Res + strlen(S),S) == 0)
164 continue;
165
166 // Erase it
167 List.erase(List.begin() + I);
168 I--;
169 }
170
171 return true;
172}
173 /*}}}*/
174// Score - We compute a 'score' for a path /*{{{*/
175// ---------------------------------------------------------------------
176/* Paths are scored based on how close they come to what I consider
177 normal. That is ones that have 'dist' 'stable' 'frozen' will score
178 higher than ones without. */
179int Score(string Path)
180{
181 int Res = 0;
182 if (Path.find("stable/") != string::npos)
5633a7c2 183 Res += 29;
f1663bdf 184 if (Path.find("/binary-") != string::npos)
5633a7c2 185 Res += 20;
83d89a9f 186 if (Path.find("frozen/") != string::npos)
5633a7c2
AL
187 Res += 28;
188 if (Path.find("unstable/") != string::npos)
189 Res += 27;
83d89a9f 190 if (Path.find("/dists/") != string::npos)
5633a7c2 191 Res += 40;
83d89a9f 192 if (Path.find("/main/") != string::npos)
5633a7c2 193 Res += 20;
83d89a9f 194 if (Path.find("/contrib/") != string::npos)
5633a7c2 195 Res += 20;
83d89a9f 196 if (Path.find("/non-free/") != string::npos)
5633a7c2 197 Res += 20;
83d89a9f 198 if (Path.find("/non-US/") != string::npos)
5633a7c2 199 Res += 20;
143abaeb 200 if (Path.find("/source/") != string::npos)
5633a7c2 201 Res += 10;
7834cb57 202 if (Path.find("/debian/") != string::npos)
5633a7c2 203 Res -= 10;
83d89a9f
AL
204 return Res;
205}
206 /*}}}*/
207// DropRepeats - Drop repeated files resulting from symlinks /*{{{*/
208// ---------------------------------------------------------------------
209/* Here we go and stat every file that we found and strip dup inodes. */
13d87e2e 210bool DropRepeats(vector<string> &List,const char *Name)
83d89a9f
AL
211{
212 // Get a list of all the inodes
213 ino_t *Inodes = new ino_t[List.size()];
214 for (unsigned int I = 0; I != List.size(); I++)
215 {
216 struct stat Buf;
143abaeb
AL
217 if (stat((List[I] + Name).c_str(),&Buf) != 0 &&
218 stat((List[I] + Name + ".gz").c_str(),&Buf) != 0)
13d87e2e
AL
219 _error->Errno("stat","Failed to stat %s%s",List[I].c_str(),
220 Name);
83d89a9f
AL
221 Inodes[I] = Buf.st_ino;
222 }
223
988d60d1
AL
224 if (_error->PendingError() == true)
225 return false;
226
83d89a9f
AL
227 // Look for dups
228 for (unsigned int I = 0; I != List.size(); I++)
229 {
230 for (unsigned int J = I+1; J < List.size(); J++)
231 {
232 // No match
233 if (Inodes[J] != Inodes[I])
234 continue;
235
236 // We score the two paths.. and erase one
237 int ScoreA = Score(List[I]);
238 int ScoreB = Score(List[J]);
239 if (ScoreA < ScoreB)
240 {
241 List[I] = string();
242 break;
243 }
244
245 List[J] = string();
246 }
247 }
248
249 // Wipe erased entries
250 for (unsigned int I = 0; I < List.size();)
251 {
252 if (List[I].empty() == false)
253 I++;
254 else
255 List.erase(List.begin()+I);
256 }
257
258 return true;
259}
260 /*}}}*/
4dfaa253
AL
261
262// ReduceSourceList - Takes the path list and reduces it /*{{{*/
263// ---------------------------------------------------------------------
264/* This takes the list of source list expressed entires and collects
265 similar ones to form a single entry for each dist */
b2e465d6 266void ReduceSourcelist(string CD,vector<string> &List)
4dfaa253
AL
267{
268 sort(List.begin(),List.end());
83d89a9f
AL
269
270 // Collect similar entries
271 for (vector<string>::iterator I = List.begin(); I != List.end(); I++)
272 {
273 // Find a space..
274 string::size_type Space = (*I).find(' ');
275 if (Space == string::npos)
276 continue;
4dfaa253
AL
277 string::size_type SSpace = (*I).find(' ',Space + 1);
278 if (SSpace == string::npos)
279 continue;
b2e465d6 280
4dfaa253 281 string Word1 = string(*I,Space,SSpace-Space);
b2e465d6 282 string Prefix = string(*I,0,Space);
83d89a9f
AL
283 for (vector<string>::iterator J = List.begin(); J != I; J++)
284 {
285 // Find a space..
286 string::size_type Space2 = (*J).find(' ');
287 if (Space2 == string::npos)
288 continue;
4dfaa253
AL
289 string::size_type SSpace2 = (*J).find(' ',Space2 + 1);
290 if (SSpace2 == string::npos)
291 continue;
83d89a9f 292
b2e465d6
AL
293 if (string(*J,0,Space2) != Prefix)
294 continue;
4dfaa253 295 if (string(*J,Space2,SSpace2-Space2) != Word1)
83d89a9f
AL
296 continue;
297
4dfaa253 298 *J += string(*I,SSpace);
83d89a9f
AL
299 *I = string();
300 }
301 }
302
303 // Wipe erased entries
304 for (unsigned int I = 0; I < List.size();)
305 {
306 if (List[I].empty() == false)
307 I++;
308 else
309 List.erase(List.begin()+I);
310 }
311}
312 /*}}}*/
18444708
AL
313// WriteDatabase - Write the CDROM Database file /*{{{*/
314// ---------------------------------------------------------------------
4dfaa253 315/* We rewrite the configuration class associated with the cdrom database. */
18444708
AL
316bool WriteDatabase(Configuration &Cnf)
317{
318 string DFile = _config->FindFile("Dir::State::cdroms");
4dfaa253
AL
319 string NewFile = DFile + ".new";
320
321 unlink(NewFile.c_str());
322 ofstream Out(NewFile.c_str());
18444708 323 if (!Out)
4dfaa253
AL
324 return _error->Errno("ofstream::ofstream",
325 "Failed to open %s.new",DFile.c_str());
18444708
AL
326
327 /* Write out all of the configuration directives by walking the
328 configuration tree */
329 const Configuration::Item *Top = Cnf.Tree(0);
330 for (; Top != 0;)
331 {
332 // Print the config entry
333 if (Top->Value.empty() == false)
334 Out << Top->FullTag() + " \"" << Top->Value << "\";" << endl;
335
336 if (Top->Child != 0)
337 {
338 Top = Top->Child;
339 continue;
340 }
341
342 while (Top != 0 && Top->Next == 0)
343 Top = Top->Parent;
344 if (Top != 0)
345 Top = Top->Next;
346 }
347
348 Out.close();
349
350 rename(DFile.c_str(),string(DFile + '~').c_str());
4dfaa253 351 if (rename(NewFile.c_str(),DFile.c_str()) != 0)
18444708
AL
352 return _error->Errno("rename","Failed to rename %s.new to %s",
353 DFile.c_str(),DFile.c_str());
354
355 return true;
356}
357 /*}}}*/
358// WriteSourceList - Write an updated sourcelist /*{{{*/
359// ---------------------------------------------------------------------
4dfaa253
AL
360/* This reads the old source list and copies it into the new one. It
361 appends the new CDROM entires just after the first block of comments.
362 This places them first in the file. It also removes any old entries
363 that were the same. */
143abaeb 364bool WriteSourceList(string Name,vector<string> &List,bool Source)
18444708 365{
143abaeb
AL
366 if (List.size() == 0)
367 return true;
368
4dfaa253
AL
369 string File = _config->FindFile("Dir::Etc::sourcelist");
370
371 // Open the stream for reading
b2e465d6 372 ifstream F((FileExists(File)?File.c_str():"/dev/null"),
076d01b0 373 ios::in );
4dfaa253
AL
374 if (!F != 0)
375 return _error->Errno("ifstream::ifstream","Opening %s",File.c_str());
376
377 string NewFile = File + ".new";
378 unlink(NewFile.c_str());
379 ofstream Out(NewFile.c_str());
380 if (!Out)
381 return _error->Errno("ofstream::ofstream",
382 "Failed to open %s.new",File.c_str());
383
384 // Create a short uri without the path
7834cb57
AL
385 string ShortURI = "cdrom:[" + Name + "]/";
386 string ShortURI2 = "cdrom:" + Name + "/"; // For Compatibility
143abaeb
AL
387
388 const char *Type;
389 if (Source == true)
390 Type = "deb-src";
391 else
392 Type = "deb";
4dfaa253
AL
393
394 char Buffer[300];
395 int CurLine = 0;
396 bool First = true;
397 while (F.eof() == false)
398 {
399 F.getline(Buffer,sizeof(Buffer));
400 CurLine++;
401 _strtabexpand(Buffer,sizeof(Buffer));
402 _strstrip(Buffer);
403
404 // Comment or blank
405 if (Buffer[0] == '#' || Buffer[0] == 0)
406 {
407 Out << Buffer << endl;
408 continue;
409 }
410
411 if (First == true)
412 {
413 for (vector<string>::iterator I = List.begin(); I != List.end(); I++)
414 {
415 string::size_type Space = (*I).find(' ');
416 if (Space == string::npos)
417 return _error->Error("Internal error");
7834cb57
AL
418 Out << Type << " cdrom:[" << Name << "]/" << string(*I,0,Space) <<
419 " " << string(*I,Space+1) << endl;
4dfaa253
AL
420 }
421 }
422 First = false;
423
424 // Grok it
143abaeb 425 string cType;
4dfaa253 426 string URI;
5b76e7f2 427 const char *C = Buffer;
143abaeb 428 if (ParseQuoteWord(C,cType) == false ||
4dfaa253
AL
429 ParseQuoteWord(C,URI) == false)
430 {
431 Out << Buffer << endl;
432 continue;
433 }
434
435 // Emit lines like this one
7834cb57
AL
436 if (cType != Type || (string(URI,0,ShortURI.length()) != ShortURI &&
437 string(URI,0,ShortURI.length()) != ShortURI2))
4dfaa253
AL
438 {
439 Out << Buffer << endl;
440 continue;
441 }
442 }
443
444 // Just in case the file was empty
445 if (First == true)
446 {
447 for (vector<string>::iterator I = List.begin(); I != List.end(); I++)
448 {
449 string::size_type Space = (*I).find(' ');
450 if (Space == string::npos)
451 return _error->Error("Internal error");
452
7834cb57
AL
453 Out << "deb cdrom:[" << Name << "]/" << string(*I,0,Space) <<
454 " " << string(*I,Space+1) << endl;
4dfaa253
AL
455 }
456 }
457
458 Out.close();
459
460 rename(File.c_str(),string(File + '~').c_str());
461 if (rename(NewFile.c_str(),File.c_str()) != 0)
462 return _error->Errno("rename","Failed to rename %s.new to %s",
463 File.c_str(),File.c_str());
464
18444708
AL
465 return true;
466}
467 /*}}}*/
83d89a9f
AL
468
469// Prompt - Simple prompt /*{{{*/
470// ---------------------------------------------------------------------
471/* */
472void Prompt(const char *Text)
473{
474 char C;
475 cout << Text << ' ' << flush;
476 read(STDIN_FILENO,&C,1);
477 if (C != '\n')
478 cout << endl;
479}
480 /*}}}*/
481// PromptLine - Prompt for an input line /*{{{*/
482// ---------------------------------------------------------------------
483/* */
484string PromptLine(const char *Text)
485{
486 cout << Text << ':' << endl;
487
488 string Res;
489 getline(cin,Res);
490 return Res;
491}
492 /*}}}*/
493
494// DoAdd - Add a new CDROM /*{{{*/
495// ---------------------------------------------------------------------
4dfaa253
AL
496/* This does the main add bit.. We show some status and things. The
497 sequence is to mount/umount the CD, Ident it then scan it for package
498 files and reduce that list. Then we copy over the package files and
499 verify them. Then rewrite the database files */
83d89a9f
AL
500bool DoAdd(CommandLine &)
501{
502 // Startup
503 string CDROM = _config->FindDir("Acquire::cdrom::mount","/cdrom/");
ac49a1e5
AL
504 if (CDROM[0] == '.')
505 CDROM= SafeGetCWD() + '/' + CDROM;
83d89a9f 506
ac49a1e5
AL
507 cout << "Using CD-ROM mount point " << CDROM << endl;
508
83d89a9f
AL
509 // Read the database
510 Configuration Database;
511 string DFile = _config->FindFile("Dir::State::cdroms");
512 if (FileExists(DFile) == true)
513 {
514 if (ReadConfigFile(Database,DFile) == false)
515 return _error->Error("Unable to read the cdrom database %s",
516 DFile.c_str());
517 }
518
519 // Unmount the CD and get the user to put in the one they want
520 if (_config->FindB("APT::CDROM::NoMount",false) == false)
521 {
522 cout << "Unmounting CD-ROM" << endl;
523 UnmountCdrom(CDROM);
18444708 524
83d89a9f 525 // Mount the new CDROM
6c907975 526 Prompt("Please insert a Disc in the drive and press enter");
83d89a9f
AL
527 cout << "Mounting CD-ROM" << endl;
528 if (MountCdrom(CDROM) == false)
6c907975 529 return _error->Error("Failed to mount the cdrom.");
83d89a9f
AL
530 }
531
532 // Hash the CD to get an ID
18444708 533 cout << "Identifying.. " << flush;
83d89a9f
AL
534 string ID;
535 if (IdentCdrom(CDROM,ID) == false)
ac49a1e5
AL
536 {
537 cout << endl;
83d89a9f 538 return false;
ac49a1e5
AL
539 }
540
83d89a9f
AL
541 cout << '[' << ID << ']' << endl;
542
543 cout << "Scanning Disc for index files.. " << flush;
544 // Get the CD structure
545 vector<string> List;
13d87e2e 546 vector<string> sList;
83d89a9f 547 string StartDir = SafeGetCWD();
22177db9 548 string InfoDir;
13d87e2e 549 if (FindPackages(CDROM,List,sList,InfoDir) == false)
ac49a1e5
AL
550 {
551 cout << endl;
83d89a9f 552 return false;
ac49a1e5
AL
553 }
554
83d89a9f 555 chdir(StartDir.c_str());
4dfaa253
AL
556
557 if (_config->FindB("Debug::aptcdrom",false) == true)
558 {
ed51f28e 559 cout << "I found (binary):" << endl;
4dfaa253 560 for (vector<string>::iterator I = List.begin(); I != List.end(); I++)
4dfaa253 561 cout << *I << endl;
ed51f28e
AL
562 cout << "I found (source):" << endl;
563 for (vector<string>::iterator I = sList.begin(); I != sList.end(); I++)
564 cout << *I << endl;
4dfaa253 565 }
83d89a9f
AL
566
567 // Fix up the list
568 DropBinaryArch(List);
13d87e2e
AL
569 DropRepeats(List,"Packages");
570 DropRepeats(sList,"Sources");
571 cout << "Found " << List.size() << " package indexes and " << sList.size() <<
572 " source indexes." << endl;
83d89a9f 573
5633a7c2 574 if (List.size() == 0 && sList.size() == 0)
4dfaa253 575 return _error->Error("Unable to locate any package files, perhaps this is not a Debian Disc");
83d89a9f
AL
576
577 // Check if the CD is in the database
578 string Name;
579 if (Database.Exists("CD::" + ID) == false ||
580 _config->FindB("APT::CDROM::Rename",false) == true)
581 {
4dfaa253 582 // Try to use the CDs label if at all possible
22177db9 583 if (InfoDir.empty() == false &&
1886ebc3 584 FileExists(InfoDir + "/info") == true)
4dfaa253 585 {
1886ebc3 586 ifstream F(string(InfoDir + "/info").c_str());
4dfaa253
AL
587 if (!F == 0)
588 getline(F,Name);
589
590 if (Name.empty() == false)
591 {
b2e465d6
AL
592 // Escape special characters
593 string::iterator J = Name.begin();
594 for (; J != Name.end(); J++)
595 if (*J == '"' || *J == ']' || *J == '[')
596 *J = '_';
597
4dfaa253
AL
598 cout << "Found label '" << Name << "'" << endl;
599 Database.Set("CD::" + ID + "::Label",Name);
600 }
601 }
602
603 if (_config->FindB("APT::CDROM::Rename",false) == true ||
179ce12b 604 Name.empty() == true)
4dfaa253
AL
605 {
606 cout << "Please provide a name for this Disc, such as 'Debian 2.1r1 Disk 1'";
607 while (1)
608 {
609 Name = PromptLine("");
610 if (Name.empty() == false &&
735a058b 611 Name.find('"') == string::npos &&
459681d3
AL
612 Name.find('[') == string::npos &&
613 Name.find(']') == string::npos)
4dfaa253
AL
614 break;
615 cout << "That is not a valid name, try again " << endl;
735a058b 616 }
4dfaa253 617 }
83d89a9f
AL
618 }
619 else
620 Name = Database.Find("CD::" + ID);
5633a7c2
AL
621
622 // Escape special characters
735a058b
AL
623 string::iterator J = Name.begin();
624 for (; J != Name.end(); J++)
7834cb57 625 if (*J == '"' || *J == ']' || *J == '[')
735a058b
AL
626 *J = '_';
627
18444708 628 Database.Set("CD::" + ID,Name);
7834cb57 629 cout << "This Disc is called:" << endl << " '" << Name << "'" << endl;
83d89a9f
AL
630
631 // Copy the package files to the state directory
143abaeb
AL
632 PackageCopy Copy;
633 SourceCopy SrcCopy;
634 if (Copy.CopyPackages(CDROM,Name,List) == false ||
635 SrcCopy.CopyPackages(CDROM,Name,sList) == false)
83d89a9f
AL
636 return false;
637
4dfaa253 638 ReduceSourcelist(CDROM,List);
13d87e2e 639 ReduceSourcelist(CDROM,sList);
18444708
AL
640
641 // Write the database and sourcelist
642 if (_config->FindB("APT::cdrom::NoAct",false) == false)
643 {
644 if (WriteDatabase(Database) == false)
645 return false;
4dfaa253
AL
646
647 cout << "Writing new source list" << endl;
143abaeb
AL
648 if (WriteSourceList(Name,List,false) == false ||
649 WriteSourceList(Name,sList,true) == false)
4dfaa253 650 return false;
18444708 651 }
4dfaa253
AL
652
653 // Print the sourcelist entries
ab5498ab 654 cout << "Source List entries for this Disc are:" << endl;
4dfaa253
AL
655 for (vector<string>::iterator I = List.begin(); I != List.end(); I++)
656 {
657 string::size_type Space = (*I).find(' ');
658 if (Space == string::npos)
659 return _error->Error("Internal error");
660
7834cb57
AL
661 cout << "deb cdrom:[" << Name << "]/" << string(*I,0,Space) <<
662 " " << string(*I,Space+1) << endl;
4dfaa253 663 }
281daf46 664
13d87e2e
AL
665 for (vector<string>::iterator I = sList.begin(); I != sList.end(); I++)
666 {
667 string::size_type Space = (*I).find(' ');
668 if (Space == string::npos)
669 return _error->Error("Internal error");
670
7834cb57
AL
671 cout << "deb-src cdrom:[" << Name << "]/" << string(*I,0,Space) <<
672 " " << string(*I,Space+1) << endl;
13d87e2e
AL
673 }
674
281daf46 675 cout << "Repeat this process for the rest of the CDs in your set." << endl;
7834cb57
AL
676
677 // Unmount and finish
678 if (_config->FindB("APT::CDROM::NoMount",false) == false)
679 UnmountCdrom(CDROM);
680
83d89a9f
AL
681 return true;
682}
683 /*}}}*/
b2e465d6
AL
684// DoIdent - Ident a CDROM /*{{{*/
685// ---------------------------------------------------------------------
686/* */
687bool DoIdent(CommandLine &)
688{
689 // Startup
690 string CDROM = _config->FindDir("Acquire::cdrom::mount","/cdrom/");
691 if (CDROM[0] == '.')
692 CDROM= SafeGetCWD() + '/' + CDROM;
693
694 cout << "Using CD-ROM mount point " << CDROM << endl;
695 cout << "Mounting CD-ROM" << endl;
696 if (MountCdrom(CDROM) == false)
697 return _error->Error("Failed to mount the cdrom.");
698
699 // Hash the CD to get an ID
700 cout << "Identifying.. " << flush;
701 string ID;
702 if (IdentCdrom(CDROM,ID) == false)
703 {
704 cout << endl;
705 return false;
706 }
707
708 cout << '[' << ID << ']' << endl;
709
710 // Read the database
711 Configuration Database;
712 string DFile = _config->FindFile("Dir::State::cdroms");
713 if (FileExists(DFile) == true)
714 {
715 if (ReadConfigFile(Database,DFile) == false)
716 return _error->Error("Unable to read the cdrom database %s",
717 DFile.c_str());
718 }
719 cout << "Stored Label: '" << Database.Find("CD::" + ID) << "'" << endl;
720 return true;
721}
722 /*}}}*/
83d89a9f
AL
723
724// ShowHelp - Show the help screen /*{{{*/
725// ---------------------------------------------------------------------
726/* */
727int ShowHelp()
728{
b2e465d6
AL
729 ioprintf(cout,_("%s %s for %s %s compiled on %s %s\n"),PACKAGE,VERSION,
730 COMMON_OS,COMMON_CPU,__DATE__,__TIME__);
04aa15a8 731 if (_config->FindB("version") == true)
b2e465d6
AL
732 return 0;
733
734 cout <<
735 "Usage: apt-cdrom [options] command\n"
736 "\n"
737 "apt-cdrom is a tool to add CDROM's to APT's source list. The\n"
738 "CDROM mount point and device information is taken from apt.conf\n"
739 "and /etc/fstab.\n"
740 "\n"
741 "Commands:\n"
742 " add - Add a CDROM\n"
743 " ident - Report the identity of a CDROM\n"
744 "\n"
745 "Options:\n"
746 " -h This help text\n"
747 " -d CD-ROM mount point\n"
748 " -r Rename a recognized CD-ROM\n"
749 " -m No mounting\n"
750 " -f Fast mode, don't check package files\n"
751 " -a Thorough scan mode\n"
752 " -c=? Read this configuration file\n"
753 " -o=? Set an arbitary configuration option, eg -o dir::cache=/tmp\n"
754 "See fstab(5)\n";
755 return 0;
83d89a9f
AL
756}
757 /*}}}*/
758
759int main(int argc,const char *argv[])
760{
761 CommandLine::Args Args[] = {
762 {'h',"help","help",0},
04aa15a8 763 {'v',"version","version",0},
83d89a9f
AL
764 {'d',"cdrom","Acquire::cdrom::mount",CommandLine::HasArg},
765 {'r',"rename","APT::CDROM::Rename",0},
766 {'m',"no-mount","APT::CDROM::NoMount",0},
767 {'f',"fast","APT::CDROM::Fast",0},
c60d151b 768 {'n',"just-print","APT::CDROM::NoAct",0},
18444708 769 {'n',"recon","APT::CDROM::NoAct",0},
c60d151b
AL
770 {'n',"no-act","APT::CDROM::NoAct",0},
771 {'a',"thorough","APT::CDROM::Thorough",0},
83d89a9f
AL
772 {'c',"config-file",0,CommandLine::ConfigFile},
773 {'o',"option",0,CommandLine::ArbItem},
774 {0,0,0,0}};
775 CommandLine::Dispatch Cmds[] = {
776 {"add",&DoAdd},
b2e465d6 777 {"ident",&DoIdent},
83d89a9f
AL
778 {0,0}};
779
780 // Parse the command line and initialize the package library
781 CommandLine CmdL(Args,_config);
b2e465d6
AL
782 if (pkgInitConfig(*_config) == false ||
783 CmdL.Parse(argc,argv) == false ||
784 pkgInitSystem(*_config,_system) == false)
83d89a9f
AL
785 {
786 _error->DumpErrors();
787 return 100;
788 }
789
790 // See if the help should be shown
5633a7c2 791 if (_config->FindB("help") == true || _config->FindB("version") == true ||
83d89a9f
AL
792 CmdL.FileSize() == 0)
793 return ShowHelp();
a9a5908d
AL
794
795 // Deal with stdout not being a tty
796 if (ttyname(STDOUT_FILENO) == 0 && _config->FindI("quiet",0) < 1)
797 _config->Set("quiet","1");
83d89a9f
AL
798
799 // Match the operation
800 CmdL.DispatchArg(Cmds);
801
802 // Print any errors or warnings found during parsing
803 if (_error->empty() == false)
804 {
805 bool Errors = _error->PendingError();
806 _error->DumpErrors();
807 return Errors == true?100:0;
808 }
809
810 return 0;
811}