]>
git.saurik.com Git - apt.git/blob - cmdline/apt-cdrom.cc
7875b1444c303bb3e22e27f62ab92ca59858b359
1 // -*- mode: cpp; mode: fold -*-
3 // $Id: apt-cdrom.cc,v 1.9 1998/12/09 00:11:50 jgg Exp $
4 /* ######################################################################
6 APT CDROM - Tool for handling APT's CDROM database.
8 Currently the only option is 'add' which will take the current CD
9 in the drive and add it into the database.
11 ##################################################################### */
13 // Include Files /*{{{*/
14 #include <apt-pkg/cmndline.h>
15 #include <apt-pkg/error.h>
16 #include <apt-pkg/init.h>
17 #include <apt-pkg/fileutl.h>
18 #include <apt-pkg/progress.h>
19 #include <apt-pkg/tagfile.h>
20 #include <apt-pkg/cdromutl.h>
35 // FindPackages - Find the package files on the CDROM /*{{{*/
36 // ---------------------------------------------------------------------
37 /* We look over the cdrom for package files. This is a recursive
38 search that short circuits when it his a package file in the dir.
39 This speeds it up greatly as the majority of the size is in the
41 bool FindPackages(string CD
,vector
<string
> &List
, int Depth
= 0)
46 if (CD
[CD
.length()-1] != '/')
49 if (chdir(CD
.c_str()) != 0)
50 return _error
->Errno("chdir","Unable to change to %s",CD
.c_str());
52 /* Aha! We found some package files. We assume that everything under
53 this dir is controlled by those package files so we don't look down
56 if (stat("Packages",&Buf
) == 0 ||
57 stat("Packages.gz",&Buf
) == 0)
61 // Continue down if thorough is given
62 if (_config
->FindB("APT::CDROM::Thorough",false) == false)
66 bool Thorough
= _config
->FindB("APT::CDROM::Thorough",false);
67 DIR *D
= opendir(".");
69 return _error
->Errno("opendir","Unable to read %s",CD
.c_str());
71 // Run over the directory
72 for (struct dirent
*Dir
= readdir(D
); Dir
!= 0; Dir
= readdir(D
))
75 if (strcmp(Dir
->d_name
,".") == 0 ||
76 strcmp(Dir
->d_name
,"..") == 0 ||
77 strcmp(Dir
->d_name
,"source") == 0 ||
78 strcmp(Dir
->d_name
,"experimental") == 0 ||
79 strcmp(Dir
->d_name
,"binary-all") == 0)
82 // See if the name is a sub directory
84 if (stat(Dir
->d_name
,&Buf
) != 0)
87 if (S_ISDIR(Buf
.st_mode
) == 0)
90 if (Thorough
== false && S_ISLNK(Buf
.st_mode
) != 0)
94 if (FindPackages(CD
+ Dir
->d_name
,List
,Depth
+1) == false)
97 if (chdir(CD
.c_str()) != 0)
98 return _error
->Errno("chdir","Unable to change to ",CD
.c_str());
103 return !_error
->PendingError();
106 // DropBinaryArch - Dump dirs with a string like /binary-<foo>/ /*{{{*/
107 // ---------------------------------------------------------------------
108 /* Here we drop everything that is not this machines arch */
109 bool DropBinaryArch(vector
<string
> &List
)
112 sprintf(S
,"/binary-%s/",_config
->Find("Apt::Architecture").c_str());
114 for (unsigned int I
= 0; I
< List
.size(); I
++)
116 const char *Str
= List
[I
].c_str();
119 if ((Res
= strstr(Str
,"/binary-")) == 0)
123 if (strlen(Res
) < strlen(S
))
125 List
.erase(List
.begin() + I
);
130 // See if it is our arch
131 if (stringcmp(Res
,Res
+ strlen(S
),S
) == 0)
135 List
.erase(List
.begin() + I
);
142 // Score - We compute a 'score' for a path /*{{{*/
143 // ---------------------------------------------------------------------
144 /* Paths are scored based on how close they come to what I consider
145 normal. That is ones that have 'dist' 'stable' 'frozen' will score
146 higher than ones without. */
147 int Score(string Path
)
150 if (Path
.find("stable/") != string::npos
)
152 if (Path
.find("frozen/") != string::npos
)
154 if (Path
.find("/dists/") != string::npos
)
156 if (Path
.find("/main/") != string::npos
)
158 if (Path
.find("/contrib/") != string::npos
)
160 if (Path
.find("/non-free/") != string::npos
)
162 if (Path
.find("/non-US/") != string::npos
)
167 // DropRepeats - Drop repeated files resulting from symlinks /*{{{*/
168 // ---------------------------------------------------------------------
169 /* Here we go and stat every file that we found and strip dup inodes. */
170 bool DropRepeats(vector
<string
> &List
)
172 // Get a list of all the inodes
173 ino_t
*Inodes
= new ino_t
[List
.size()];
174 for (unsigned int I
= 0; I
!= List
.size(); I
++)
177 if (stat(List
[I
].c_str(),&Buf
) != 0)
178 _error
->Errno("stat","Failed to stat %s",List
[I
].c_str());
179 Inodes
[I
] = Buf
.st_ino
;
183 for (unsigned int I
= 0; I
!= List
.size(); I
++)
185 for (unsigned int J
= I
+1; J
< List
.size(); J
++)
188 if (Inodes
[J
] != Inodes
[I
])
191 // We score the two paths.. and erase one
192 int ScoreA
= Score(List
[I
]);
193 int ScoreB
= Score(List
[J
]);
204 // Wipe erased entries
205 for (unsigned int I
= 0; I
< List
.size();)
207 if (List
[I
].empty() == false)
210 List
.erase(List
.begin()+I
);
216 // ConvertToSourceList - Convert a Path to a sourcelist entry /*{{{*/
217 // ---------------------------------------------------------------------
218 /* We look for things in dists/ notation and convert them to
219 <dist> <component> form otherwise it is left alone. This also strips
221 void ConvertToSourceList(string CD
,string
&Path
)
224 sprintf(S
,"binary-%s",_config
->Find("Apt::Architecture").c_str());
226 // Strip the cdrom base path
227 Path
= string(Path
,CD
.length());
228 if (Path
.empty() == true)
231 // Too short to be a dists/ type
232 if (Path
.length() < strlen("dists/"))
236 if (stringcmp(Path
.begin(),Path
.begin()+strlen("dists/"),"dists/") != 0)
240 string::size_type Slash
= strlen("dists/");
241 string::size_type Slash2
= Path
.find('/',Slash
+ 1);
242 if (Slash2
== string::npos
|| Slash2
+ 2 >= Path
.length())
244 string Dist
= string(Path
,Slash
,Slash2
- Slash
);
246 // Isolate the component
247 Slash
= Path
.find('/',Slash2
+1);
248 if (Slash
== string::npos
|| Slash
+ 2 >= Path
.length())
250 string Comp
= string(Path
,Slash2
+1,Slash
- Slash2
-1);
252 // Verify the trailing binar - bit
253 Slash2
= Path
.find('/',Slash
+ 1);
254 if (Slash
== string::npos
)
256 string Binary
= string(Path
,Slash
+1,Slash2
- Slash
-1);
261 Path
= Dist
+ ' ' + Comp
;
264 // GrabFirst - Return the first Depth path components /*{{{*/
265 // ---------------------------------------------------------------------
267 bool GrabFirst(string Path
,string
&To
,unsigned int Depth
)
269 string::size_type I
= 0;
272 I
= Path
.find('/',I
+1);
275 while (I
!= string::npos
&& Depth
!= 0);
277 if (I
== string::npos
)
280 To
= string(Path
,0,I
+1);
284 // ChopDirs - Chop off the leading directory components /*{{{*/
285 // ---------------------------------------------------------------------
287 string
ChopDirs(string Path
,unsigned int Depth
)
289 string::size_type I
= 0;
292 I
= Path
.find('/',I
+1);
295 while (I
!= string::npos
&& Depth
!= 0);
297 if (I
== string::npos
)
300 return string(Path
,I
+1);
303 // ReconstructPrefix - Fix strange prefixing /*{{{*/
304 // ---------------------------------------------------------------------
305 /* This prepends dir components from the path to the package files to
306 the path to the deb until it is found */
307 bool ReconstructPrefix(string
&Prefix
,string OrigPath
,string CD
,
310 bool Debug
= _config
->FindB("Debug::aptcdrom",false);
311 unsigned int Depth
= 1;
312 string MyPrefix
= Prefix
;
316 if (stat(string(CD
+ MyPrefix
+ File
).c_str(),&Buf
) != 0)
319 cout
<< "Failed, " << CD
+ MyPrefix
+ File
<< endl
;
320 if (GrabFirst(OrigPath
,MyPrefix
,Depth
++) == true)
334 // ReconstructChop - Fixes bad source paths /*{{{*/
335 // ---------------------------------------------------------------------
336 /* This removes path components from the filename and prepends the location
337 of the package files until a file is found */
338 bool ReconstructChop(unsigned long &Chop
,string Dir
,string File
)
340 // Attempt to reconstruct the filename
341 unsigned long Depth
= 0;
345 if (stat(string(Dir
+ File
).c_str(),&Buf
) != 0)
347 File
= ChopDirs(File
,1);
349 if (File
.empty() == false)
363 // CopyPackages - Copy the package files from the CD /*{{{*/
364 // ---------------------------------------------------------------------
366 bool CopyPackages(string CDROM
,string Name
,vector
<string
> &List
)
368 OpTextProgress Progress
;
370 bool NoStat
= _config
->FindB("APT::CDROM::Fast",false);
371 bool Debug
= _config
->FindB("Debug::aptcdrom",false);
373 // Prepare the progress indicator
374 unsigned long TotalSize
= 0;
375 for (vector
<string
>::iterator I
= List
.begin(); I
!= List
.end(); I
++)
378 if (stat(string(*I
+ "Packages").c_str(),&Buf
) != 0)
379 return _error
->Errno("stat","Stat failed for %s",
380 string(*I
+ "Packages").c_str());
381 TotalSize
+= Buf
.st_size
;
384 unsigned long CurrentSize
= 0;
385 unsigned int NotFound
= 0;
386 unsigned int WrongSize
= 0;
387 unsigned int Packages
= 0;
388 for (vector
<string
>::iterator I
= List
.begin(); I
!= List
.end(); I
++)
390 string OrigPath
= string(*I
,CDROM
.length());
392 // Open the package file
393 FileFd
Pkg(*I
+ "Packages",FileFd::ReadOnly
);
394 pkgTagFile
Parser(Pkg
);
395 if (_error
->PendingError() == true)
398 // Open the output file
400 sprintf(S
,"cdrom:%s/%sPackages",Name
.c_str(),(*I
).c_str() + CDROM
.length());
401 string TargetF
= _config
->FindDir("Dir::State::lists") + "partial/";
402 TargetF
+= URItoFileName(S
);
403 if (_config
->FindB("APT::CDROM::NoAct",false) == true)
404 TargetF
= "/dev/null";
405 FileFd
Target(TargetF
,FileFd::WriteEmpty
);
406 if (_error
->PendingError() == true)
409 // Setup the progress meter
410 Progress
.OverallProgress(CurrentSize
,TotalSize
,Pkg
.Size(),
411 "Reading Package Lists");
414 Progress
.SubProgress(Pkg
.Size());
415 pkgTagSection Section
;
417 unsigned long Hits
= 0;
418 unsigned long Chop
= 0;
419 while (Parser
.Step(Section
) == true)
421 Progress
.Progress(Parser
.Offset());
423 string File
= Section
.FindS("Filename");
424 unsigned long Size
= Section
.FindI("Size");
425 if (File
.empty() || Size
== 0)
426 return _error
->Error("Cannot find filename or size tag");
429 File
= OrigPath
+ ChopDirs(File
,Chop
);
431 // See if the file exists
432 if (NoStat
== false || Hits
< 10)
434 // Attempt to fix broken structure
437 if (ReconstructPrefix(Prefix
,OrigPath
,CDROM
,File
) == false &&
438 ReconstructChop(Chop
,*I
,File
) == false)
444 File
= OrigPath
+ ChopDirs(File
,Chop
);
449 if (stat(string(CDROM
+ Prefix
+ File
).c_str(),&Buf
) != 0)
456 if ((unsigned)Buf
.st_size
!= Size
)
466 // Copy it to the target package file
471 // Mangle the output filename
472 const char *Filename
;
473 Section
.Find("Filename",Filename
,Stop
);
475 /* We need to rewrite the filename field so we emit
476 all fields except the filename file and rewrite that one */
477 for (unsigned int I
= 0; I
!= Section
.Count(); I
++)
479 Section
.Get(Start
,Stop
,I
);
480 if (Start
<= Filename
&& Stop
> Filename
)
483 sprintf(S
,"Filename: %s\n",File
.c_str());
484 if (I
+ 1 == Section
.Count())
486 if (Target
.Write(S
,strlen(S
)) == false)
490 if (Target
.Write(Start
,Stop
-Start
) == false)
493 if (Target
.Write("\n",1) == false)
498 Section
.GetSection(Start
,Stop
);
499 if (Target
.Write(Start
,Stop
-Start
) == false)
505 cout
<< " Processed by using Prefix '" << Prefix
<< "' and chop " << Chop
<< endl
;
507 if (_config
->FindB("APT::CDROM::NoAct",false) == false)
509 // Move out of the partial directory
511 string FinalF
= _config
->FindDir("Dir::State::lists");
512 FinalF
+= URItoFileName(S
);
513 if (rename(TargetF
.c_str(),FinalF
.c_str()) != 0)
514 return _error
->Errno("rename","Failed to rename");
516 // Copy the release file
517 sprintf(S
,"cdrom:%s/%sRelease",Name
.c_str(),(*I
).c_str() + CDROM
.length());
518 string TargetF
= _config
->FindDir("Dir::State::lists") + "partial/";
519 TargetF
+= URItoFileName(S
);
520 if (FileExists(*I
+ "Release") == true)
522 FileFd
Target(TargetF
,FileFd::WriteEmpty
);
523 FileFd
Rel(*I
+ "Release",FileFd::ReadOnly
);
524 if (_error
->PendingError() == true)
527 if (CopyFile(Rel
,Target
) == false)
532 // Empty release file
533 FileFd
Target(TargetF
,FileFd::WriteEmpty
);
536 // Rename the release file
537 FinalF
= _config
->FindDir("Dir::State::lists");
538 FinalF
+= URItoFileName(S
);
539 if (rename(TargetF
.c_str(),FinalF
.c_str()) != 0)
540 return _error
->Errno("rename","Failed to rename");
543 /* Mangle the source to be in the proper notation with
544 prefix dist [component] */
545 *I
= string(*I
,Prefix
.length());
546 ConvertToSourceList(CDROM
,*I
);
547 *I
= Prefix
+ ' ' + *I
;
549 CurrentSize
+= Pkg
.Size();
554 cout
<< "Wrote " << Packages
<< " package records" ;
556 cout
<< " with " << NotFound
<< " missing files";
557 if (NotFound
!= 0 && WrongSize
!= 0)
560 cout
<< " with " << WrongSize
<< " mismatched files";
564 return _error
->Error("No valid package records were found.");
566 if (NotFound
+ WrongSize
> 10)
567 cout
<< "Alot of package entires were discarded, perhaps this CD is funny?" << endl
;
573 // ReduceSourceList - Takes the path list and reduces it /*{{{*/
574 // ---------------------------------------------------------------------
575 /* This takes the list of source list expressed entires and collects
576 similar ones to form a single entry for each dist */
577 bool ReduceSourcelist(string CD
,vector
<string
> &List
)
579 sort(List
.begin(),List
.end());
581 // Collect similar entries
582 for (vector
<string
>::iterator I
= List
.begin(); I
!= List
.end(); I
++)
585 string::size_type Space
= (*I
).find(' ');
586 if (Space
== string::npos
)
588 string::size_type SSpace
= (*I
).find(' ',Space
+ 1);
589 if (SSpace
== string::npos
)
592 string Word1
= string(*I
,Space
,SSpace
-Space
);
593 for (vector
<string
>::iterator J
= List
.begin(); J
!= I
; J
++)
596 string::size_type Space2
= (*J
).find(' ');
597 if (Space2
== string::npos
)
599 string::size_type SSpace2
= (*J
).find(' ',Space2
+ 1);
600 if (SSpace2
== string::npos
)
603 if (string(*J
,Space2
,SSpace2
-Space2
) != Word1
)
606 *J
+= string(*I
,SSpace
);
611 // Wipe erased entries
612 for (unsigned int I
= 0; I
< List
.size();)
614 if (List
[I
].empty() == false)
617 List
.erase(List
.begin()+I
);
621 // WriteDatabase - Write the CDROM Database file /*{{{*/
622 // ---------------------------------------------------------------------
623 /* We rewrite the configuration class associated with the cdrom database. */
624 bool WriteDatabase(Configuration
&Cnf
)
626 string DFile
= _config
->FindFile("Dir::State::cdroms");
627 string NewFile
= DFile
+ ".new";
629 unlink(NewFile
.c_str());
630 ofstream
Out(NewFile
.c_str());
632 return _error
->Errno("ofstream::ofstream",
633 "Failed to open %s.new",DFile
.c_str());
635 /* Write out all of the configuration directives by walking the
636 configuration tree */
637 const Configuration::Item
*Top
= Cnf
.Tree(0);
640 // Print the config entry
641 if (Top
->Value
.empty() == false)
642 Out
<< Top
->FullTag() + " \"" << Top
->Value
<< "\";" << endl
;
650 while (Top
!= 0 && Top
->Next
== 0)
658 rename(DFile
.c_str(),string(DFile
+ '~').c_str());
659 if (rename(NewFile
.c_str(),DFile
.c_str()) != 0)
660 return _error
->Errno("rename","Failed to rename %s.new to %s",
661 DFile
.c_str(),DFile
.c_str());
666 // WriteSourceList - Write an updated sourcelist /*{{{*/
667 // ---------------------------------------------------------------------
668 /* This reads the old source list and copies it into the new one. It
669 appends the new CDROM entires just after the first block of comments.
670 This places them first in the file. It also removes any old entries
671 that were the same. */
672 bool WriteSourceList(string Name
,vector
<string
> &List
)
674 string File
= _config
->FindFile("Dir::Etc::sourcelist");
676 // Open the stream for reading
677 ifstream
F(File
.c_str(),ios::in
| ios::nocreate
);
679 return _error
->Errno("ifstream::ifstream","Opening %s",File
.c_str());
681 string NewFile
= File
+ ".new";
682 unlink(NewFile
.c_str());
683 ofstream
Out(NewFile
.c_str());
685 return _error
->Errno("ofstream::ofstream",
686 "Failed to open %s.new",File
.c_str());
688 // Create a short uri without the path
689 string ShortURI
= "cdrom:" + Name
+ "/";
694 while (F
.eof() == false)
696 F
.getline(Buffer
,sizeof(Buffer
));
698 _strtabexpand(Buffer
,sizeof(Buffer
));
702 if (Buffer
[0] == '#' || Buffer
[0] == 0)
704 Out
<< Buffer
<< endl
;
710 for (vector
<string
>::iterator I
= List
.begin(); I
!= List
.end(); I
++)
712 string::size_type Space
= (*I
).find(' ');
713 if (Space
== string::npos
)
714 return _error
->Error("Internal error");
716 Out
<< "deb \"cdrom:" << Name
<< "/" << string(*I
,0,Space
) <<
717 "\" " << string(*I
,Space
+1) << endl
;
726 if (ParseQuoteWord(C
,Type
) == false ||
727 ParseQuoteWord(C
,URI
) == false)
729 Out
<< Buffer
<< endl
;
733 // Emit lines like this one
734 if (Type
!= "deb" || string(URI
,0,ShortURI
.length()) != ShortURI
)
736 Out
<< Buffer
<< endl
;
741 // Just in case the file was empty
744 for (vector
<string
>::iterator I
= List
.begin(); I
!= List
.end(); I
++)
746 string::size_type Space
= (*I
).find(' ');
747 if (Space
== string::npos
)
748 return _error
->Error("Internal error");
750 Out
<< "deb \"cdrom:" << Name
<< "/" << string(*I
,0,Space
) <<
751 "\" " << string(*I
,Space
+1) << endl
;
757 rename(File
.c_str(),string(File
+ '~').c_str());
758 if (rename(NewFile
.c_str(),File
.c_str()) != 0)
759 return _error
->Errno("rename","Failed to rename %s.new to %s",
760 File
.c_str(),File
.c_str());
766 // Prompt - Simple prompt /*{{{*/
767 // ---------------------------------------------------------------------
769 void Prompt(const char *Text
)
772 cout
<< Text
<< ' ' << flush
;
773 read(STDIN_FILENO
,&C
,1);
778 // PromptLine - Prompt for an input line /*{{{*/
779 // ---------------------------------------------------------------------
781 string
PromptLine(const char *Text
)
783 cout
<< Text
<< ':' << endl
;
791 // DoAdd - Add a new CDROM /*{{{*/
792 // ---------------------------------------------------------------------
793 /* This does the main add bit.. We show some status and things. The
794 sequence is to mount/umount the CD, Ident it then scan it for package
795 files and reduce that list. Then we copy over the package files and
796 verify them. Then rewrite the database files */
797 bool DoAdd(CommandLine
&)
800 string CDROM
= _config
->FindDir("Acquire::cdrom::mount","/cdrom/");
802 CDROM
= SafeGetCWD() + '/' + CDROM
;
804 cout
<< "Using CD-ROM mount point " << CDROM
<< endl
;
807 Configuration Database
;
808 string DFile
= _config
->FindFile("Dir::State::cdroms");
809 if (FileExists(DFile
) == true)
811 if (ReadConfigFile(Database
,DFile
) == false)
812 return _error
->Error("Unable to read the cdrom database %s",
816 // Unmount the CD and get the user to put in the one they want
817 if (_config
->FindB("APT::CDROM::NoMount",false) == false)
819 cout
<< "Unmounting CD-ROM" << endl
;
822 // Mount the new CDROM
823 Prompt("Please insert a Disc in the drive and press any key");
824 cout
<< "Mounting CD-ROM" << endl
;
825 if (MountCdrom(CDROM
) == false)
827 cout
<< "Failed to mount the cdrom." << endl
;
832 // Hash the CD to get an ID
833 cout
<< "Identifying.. " << flush
;
835 if (IdentCdrom(CDROM
,ID
) == false)
841 cout
<< '[' << ID
<< ']' << endl
;
843 cout
<< "Scanning Disc for index files.. " << flush
;
844 // Get the CD structure
846 string StartDir
= SafeGetCWD();
847 if (FindPackages(CDROM
,List
) == false)
853 chdir(StartDir
.c_str());
855 if (_config
->FindB("Debug::aptcdrom",false) == true)
857 cout
<< "I found:" << endl
;
858 for (vector
<string
>::iterator I
= List
.begin(); I
!= List
.end(); I
++)
865 DropBinaryArch(List
);
867 cout
<< "Found " << List
.size() << " package index files." << endl
;
869 if (List
.size() == 0)
870 return _error
->Error("Unable to locate any package files, perhaps this is not a Debian Disc");
872 // Check if the CD is in the database
874 if (Database
.Exists("CD::" + ID
) == false ||
875 _config
->FindB("APT::CDROM::Rename",false) == true)
877 // Try to use the CDs label if at all possible
878 if (FileExists(CDROM
+ "/.disk/info") == true)
880 ifstream
F(string(CDROM
+ "/.disk/info").c_str());
884 if (Name
.empty() == false)
886 cout
<< "Found label '" << Name
<< "'" << endl
;
887 Database
.Set("CD::" + ID
+ "::Label",Name
);
891 if (_config
->FindB("APT::CDROM::Rename",false) == true ||
892 Name
.empty() == true)
894 cout
<< "Please provide a name for this Disc, such as 'Debian 2.1r1 Disk 1'";
897 Name
= PromptLine("");
898 if (Name
.empty() == false &&
899 Name
.find('/') == string::npos
)
901 cout
<< "That is not a valid name, try again " << endl
;
907 Name
= Database
.Find("CD::" + ID
);
908 Database
.Set("CD::" + ID
,Name
);
909 cout
<< "This Disc is called '" << Name
<< "'" << endl
;
911 // Copy the package files to the state directory
912 if (CopyPackages(CDROM
,Name
,List
) == false)
915 ReduceSourcelist(CDROM
,List
);
917 // Write the database and sourcelist
918 if (_config
->FindB("APT::cdrom::NoAct",false) == false)
920 if (WriteDatabase(Database
) == false)
923 cout
<< "Writing new source list" << endl
;
924 if (WriteSourceList(Name
,List
) == false)
928 // Print the sourcelist entries
929 cout
<< "Source List entires for this Disc are:" << endl
;
930 for (vector
<string
>::iterator I
= List
.begin(); I
!= List
.end(); I
++)
932 string::size_type Space
= (*I
).find(' ');
933 if (Space
== string::npos
)
934 return _error
->Error("Internal error");
936 cout
<< "deb \"cdrom:" << Name
<< "/" << string(*I
,0,Space
) <<
937 "\" " << string(*I
,Space
+1) << endl
;
944 // ShowHelp - Show the help screen /*{{{*/
945 // ---------------------------------------------------------------------
949 cout
<< PACKAGE
<< ' ' << VERSION
<< " for " << ARCHITECTURE
<<
950 " compiled on " << __DATE__
<< " " << __TIME__
<< endl
;
952 cout
<< "Usage: apt-cdrom [options] command" << endl
;
954 cout
<< "apt-cdrom is a tool to add CDROM's to APT's source list. The " << endl
;
955 cout
<< "CDROM mount point and device information is taken from apt.conf" << endl
;
956 cout
<< "and /etc/fstab." << endl
;
958 cout
<< "Commands:" << endl
;
959 cout
<< " add - Add a CDROM" << endl
;
961 cout
<< "Options:" << endl
;
962 cout
<< " -h This help text" << endl
;
963 cout
<< " -d CD-ROM mount point" << endl
;
964 cout
<< " -r Rename a recognized CD-ROM" << endl
;
965 cout
<< " -m No mounting" << endl
;
966 cout
<< " -f Fast mode, don't check package files" << endl
;
967 cout
<< " -a Thorough scan mode" << endl
;
968 cout
<< " -c=? Read this configuration file" << endl
;
969 cout
<< " -o=? Set an arbitary configuration option, ie -o dir::cache=/tmp" << endl
;
970 cout
<< "See fstab(5)" << endl
;
975 int main(int argc
,const char *argv
[])
977 CommandLine::Args Args
[] = {
978 {'h',"help","help",0},
979 {'d',"cdrom","Acquire::cdrom::mount",CommandLine::HasArg
},
980 {'r',"rename","APT::CDROM::Rename",0},
981 {'m',"no-mount","APT::CDROM::NoMount",0},
982 {'f',"fast","APT::CDROM::Fast",0},
983 {'n',"just-print","APT::CDROM::NoAct",0},
984 {'n',"recon","APT::CDROM::NoAct",0},
985 {'n',"no-act","APT::CDROM::NoAct",0},
986 {'a',"thorough","APT::CDROM::Thorough",0},
987 {'c',"config-file",0,CommandLine::ConfigFile
},
988 {'o',"option",0,CommandLine::ArbItem
},
990 CommandLine::Dispatch Cmds
[] = {
994 // Parse the command line and initialize the package library
995 CommandLine
CmdL(Args
,_config
);
996 if (pkgInitialize(*_config
) == false ||
997 CmdL
.Parse(argc
,argv
) == false)
999 _error
->DumpErrors();
1003 // See if the help should be shown
1004 if (_config
->FindB("help") == true ||
1005 CmdL
.FileSize() == 0)
1008 // Match the operation
1009 CmdL
.DispatchArg(Cmds
);
1011 // Print any errors or warnings found during parsing
1012 if (_error
->empty() == false)
1014 bool Errors
= _error
->PendingError();
1015 _error
->DumpErrors();
1016 return Errors
== true?100:0;