]>
git.saurik.com Git - apt.git/blob - cmdline/apt-cdrom.cc
a4b60e4574c85ef2f0d1081c0d228d4f45e718fc
1 // -*- mode: cpp; mode: fold -*-
3 // $Id: apt-cdrom.cc,v 1.11 1998/12/09 00:55:23 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
, unsigned int Depth
= 0)
43 static ino_t Inodes
[9];
47 if (CD
[CD
.length()-1] != '/')
50 if (chdir(CD
.c_str()) != 0)
51 return _error
->Errno("chdir","Unable to change to %s",CD
.c_str());
53 /* Aha! We found some package files. We assume that everything under
54 this dir is controlled by those package files so we don't look down
57 if (stat("Packages",&Buf
) == 0 ||
58 stat("Packages.gz",&Buf
) == 0)
62 // Continue down if thorough is given
63 if (_config
->FindB("APT::CDROM::Thorough",false) == 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)
91 for (I
= 0; I
!= Depth
; I
++)
92 if (Inodes
[I
] == Buf
.st_ino
)
94 if (Inodes
[I
] == Buf
.st_ino
)
97 // Store the inodes weve seen
98 Inodes
[Depth
] = Buf
.st_ino
;
101 if (FindPackages(CD
+ Dir
->d_name
,List
,Depth
+1) == false)
104 if (chdir(CD
.c_str()) != 0)
105 return _error
->Errno("chdir","Unable to change to ",CD
.c_str());
110 return !_error
->PendingError();
113 // DropBinaryArch - Dump dirs with a string like /binary-<foo>/ /*{{{*/
114 // ---------------------------------------------------------------------
115 /* Here we drop everything that is not this machines arch */
116 bool DropBinaryArch(vector
<string
> &List
)
119 sprintf(S
,"/binary-%s/",_config
->Find("Apt::Architecture").c_str());
121 for (unsigned int I
= 0; I
< List
.size(); I
++)
123 const char *Str
= List
[I
].c_str();
126 if ((Res
= strstr(Str
,"/binary-")) == 0)
130 if (strlen(Res
) < strlen(S
))
132 List
.erase(List
.begin() + I
);
137 // See if it is our arch
138 if (stringcmp(Res
,Res
+ strlen(S
),S
) == 0)
142 List
.erase(List
.begin() + I
);
149 // Score - We compute a 'score' for a path /*{{{*/
150 // ---------------------------------------------------------------------
151 /* Paths are scored based on how close they come to what I consider
152 normal. That is ones that have 'dist' 'stable' 'frozen' will score
153 higher than ones without. */
154 int Score(string Path
)
157 if (Path
.find("stable/") != string::npos
)
159 if (Path
.find("frozen/") != string::npos
)
161 if (Path
.find("/dists/") != string::npos
)
163 if (Path
.find("/main/") != string::npos
)
165 if (Path
.find("/contrib/") != string::npos
)
167 if (Path
.find("/non-free/") != string::npos
)
169 if (Path
.find("/non-US/") != string::npos
)
174 // DropRepeats - Drop repeated files resulting from symlinks /*{{{*/
175 // ---------------------------------------------------------------------
176 /* Here we go and stat every file that we found and strip dup inodes. */
177 bool DropRepeats(vector
<string
> &List
)
179 // Get a list of all the inodes
180 ino_t
*Inodes
= new ino_t
[List
.size()];
181 for (unsigned int I
= 0; I
!= List
.size(); I
++)
184 if (stat((List
[I
] + "Packages").c_str(),&Buf
) != 0)
185 _error
->Errno("stat","Failed to stat %s",List
[I
].c_str());
186 Inodes
[I
] = Buf
.st_ino
;
190 for (unsigned int I
= 0; I
!= List
.size(); I
++)
192 for (unsigned int J
= I
+1; J
< List
.size(); J
++)
195 if (Inodes
[J
] != Inodes
[I
])
198 // We score the two paths.. and erase one
199 int ScoreA
= Score(List
[I
]);
200 int ScoreB
= Score(List
[J
]);
211 // Wipe erased entries
212 for (unsigned int I
= 0; I
< List
.size();)
214 if (List
[I
].empty() == false)
217 List
.erase(List
.begin()+I
);
223 // ConvertToSourceList - Convert a Path to a sourcelist entry /*{{{*/
224 // ---------------------------------------------------------------------
225 /* We look for things in dists/ notation and convert them to
226 <dist> <component> form otherwise it is left alone. This also strips
228 void ConvertToSourceList(string CD
,string
&Path
)
231 sprintf(S
,"binary-%s",_config
->Find("Apt::Architecture").c_str());
233 // Strip the cdrom base path
234 Path
= string(Path
,CD
.length());
235 if (Path
.empty() == true)
238 // Too short to be a dists/ type
239 if (Path
.length() < strlen("dists/"))
243 if (stringcmp(Path
.begin(),Path
.begin()+strlen("dists/"),"dists/") != 0)
247 string::size_type Slash
= strlen("dists/");
248 string::size_type Slash2
= Path
.find('/',Slash
+ 1);
249 if (Slash2
== string::npos
|| Slash2
+ 2 >= Path
.length())
251 string Dist
= string(Path
,Slash
,Slash2
- Slash
);
253 // Isolate the component
254 Slash
= Path
.find('/',Slash2
+1);
255 if (Slash
== string::npos
|| Slash
+ 2 >= Path
.length())
257 string Comp
= string(Path
,Slash2
+1,Slash
- Slash2
-1);
259 // Verify the trailing binar - bit
260 Slash2
= Path
.find('/',Slash
+ 1);
261 if (Slash
== string::npos
)
263 string Binary
= string(Path
,Slash
+1,Slash2
- Slash
-1);
268 Path
= Dist
+ ' ' + Comp
;
271 // GrabFirst - Return the first Depth path components /*{{{*/
272 // ---------------------------------------------------------------------
274 bool GrabFirst(string Path
,string
&To
,unsigned int Depth
)
276 string::size_type I
= 0;
279 I
= Path
.find('/',I
+1);
282 while (I
!= string::npos
&& Depth
!= 0);
284 if (I
== string::npos
)
287 To
= string(Path
,0,I
+1);
291 // ChopDirs - Chop off the leading directory components /*{{{*/
292 // ---------------------------------------------------------------------
294 string
ChopDirs(string Path
,unsigned int Depth
)
296 string::size_type I
= 0;
299 I
= Path
.find('/',I
+1);
302 while (I
!= string::npos
&& Depth
!= 0);
304 if (I
== string::npos
)
307 return string(Path
,I
+1);
310 // ReconstructPrefix - Fix strange prefixing /*{{{*/
311 // ---------------------------------------------------------------------
312 /* This prepends dir components from the path to the package files to
313 the path to the deb until it is found */
314 bool ReconstructPrefix(string
&Prefix
,string OrigPath
,string CD
,
317 bool Debug
= _config
->FindB("Debug::aptcdrom",false);
318 unsigned int Depth
= 1;
319 string MyPrefix
= Prefix
;
323 if (stat(string(CD
+ MyPrefix
+ File
).c_str(),&Buf
) != 0)
326 cout
<< "Failed, " << CD
+ MyPrefix
+ File
<< endl
;
327 if (GrabFirst(OrigPath
,MyPrefix
,Depth
++) == true)
341 // ReconstructChop - Fixes bad source paths /*{{{*/
342 // ---------------------------------------------------------------------
343 /* This removes path components from the filename and prepends the location
344 of the package files until a file is found */
345 bool ReconstructChop(unsigned long &Chop
,string Dir
,string File
)
347 // Attempt to reconstruct the filename
348 unsigned long Depth
= 0;
352 if (stat(string(Dir
+ File
).c_str(),&Buf
) != 0)
354 File
= ChopDirs(File
,1);
356 if (File
.empty() == false)
370 // CopyPackages - Copy the package files from the CD /*{{{*/
371 // ---------------------------------------------------------------------
373 bool CopyPackages(string CDROM
,string Name
,vector
<string
> &List
)
375 OpTextProgress Progress
;
377 bool NoStat
= _config
->FindB("APT::CDROM::Fast",false);
378 bool Debug
= _config
->FindB("Debug::aptcdrom",false);
380 // Prepare the progress indicator
381 unsigned long TotalSize
= 0;
382 for (vector
<string
>::iterator I
= List
.begin(); I
!= List
.end(); I
++)
385 if (stat(string(*I
+ "Packages").c_str(),&Buf
) != 0)
386 return _error
->Errno("stat","Stat failed for %s",
387 string(*I
+ "Packages").c_str());
388 TotalSize
+= Buf
.st_size
;
391 unsigned long CurrentSize
= 0;
392 unsigned int NotFound
= 0;
393 unsigned int WrongSize
= 0;
394 unsigned int Packages
= 0;
395 for (vector
<string
>::iterator I
= List
.begin(); I
!= List
.end(); I
++)
397 string OrigPath
= string(*I
,CDROM
.length());
399 // Open the package file
400 FileFd
Pkg(*I
+ "Packages",FileFd::ReadOnly
);
401 pkgTagFile
Parser(Pkg
);
402 if (_error
->PendingError() == true)
405 // Open the output file
407 sprintf(S
,"cdrom:%s/%sPackages",Name
.c_str(),(*I
).c_str() + CDROM
.length());
408 string TargetF
= _config
->FindDir("Dir::State::lists") + "partial/";
409 TargetF
+= URItoFileName(S
);
410 if (_config
->FindB("APT::CDROM::NoAct",false) == true)
411 TargetF
= "/dev/null";
412 FileFd
Target(TargetF
,FileFd::WriteEmpty
);
413 if (_error
->PendingError() == true)
416 // Setup the progress meter
417 Progress
.OverallProgress(CurrentSize
,TotalSize
,Pkg
.Size(),
418 "Reading Package Lists");
421 Progress
.SubProgress(Pkg
.Size());
422 pkgTagSection Section
;
424 unsigned long Hits
= 0;
425 unsigned long Chop
= 0;
426 while (Parser
.Step(Section
) == true)
428 Progress
.Progress(Parser
.Offset());
430 string File
= Section
.FindS("Filename");
431 unsigned long Size
= Section
.FindI("Size");
432 if (File
.empty() || Size
== 0)
433 return _error
->Error("Cannot find filename or size tag");
436 File
= OrigPath
+ ChopDirs(File
,Chop
);
438 // See if the file exists
439 if (NoStat
== false || Hits
< 10)
441 // Attempt to fix broken structure
444 if (ReconstructPrefix(Prefix
,OrigPath
,CDROM
,File
) == false &&
445 ReconstructChop(Chop
,*I
,File
) == false)
451 File
= OrigPath
+ ChopDirs(File
,Chop
);
456 if (stat(string(CDROM
+ Prefix
+ File
).c_str(),&Buf
) != 0)
463 if ((unsigned)Buf
.st_size
!= Size
)
473 // Copy it to the target package file
478 // Mangle the output filename
479 const char *Filename
;
480 Section
.Find("Filename",Filename
,Stop
);
482 /* We need to rewrite the filename field so we emit
483 all fields except the filename file and rewrite that one */
484 for (unsigned int I
= 0; I
!= Section
.Count(); I
++)
486 Section
.Get(Start
,Stop
,I
);
487 if (Start
<= Filename
&& Stop
> Filename
)
490 sprintf(S
,"Filename: %s\n",File
.c_str());
491 if (I
+ 1 == Section
.Count())
493 if (Target
.Write(S
,strlen(S
)) == false)
497 if (Target
.Write(Start
,Stop
-Start
) == false)
500 if (Target
.Write("\n",1) == false)
505 Section
.GetSection(Start
,Stop
);
506 if (Target
.Write(Start
,Stop
-Start
) == false)
512 cout
<< " Processed by using Prefix '" << Prefix
<< "' and chop " << Chop
<< endl
;
514 if (_config
->FindB("APT::CDROM::NoAct",false) == false)
516 // Move out of the partial directory
518 string FinalF
= _config
->FindDir("Dir::State::lists");
519 FinalF
+= URItoFileName(S
);
520 if (rename(TargetF
.c_str(),FinalF
.c_str()) != 0)
521 return _error
->Errno("rename","Failed to rename");
523 // Copy the release file
524 sprintf(S
,"cdrom:%s/%sRelease",Name
.c_str(),(*I
).c_str() + CDROM
.length());
525 string TargetF
= _config
->FindDir("Dir::State::lists") + "partial/";
526 TargetF
+= URItoFileName(S
);
527 if (FileExists(*I
+ "Release") == true)
529 FileFd
Target(TargetF
,FileFd::WriteEmpty
);
530 FileFd
Rel(*I
+ "Release",FileFd::ReadOnly
);
531 if (_error
->PendingError() == true)
534 if (CopyFile(Rel
,Target
) == false)
539 // Empty release file
540 FileFd
Target(TargetF
,FileFd::WriteEmpty
);
543 // Rename the release file
544 FinalF
= _config
->FindDir("Dir::State::lists");
545 FinalF
+= URItoFileName(S
);
546 if (rename(TargetF
.c_str(),FinalF
.c_str()) != 0)
547 return _error
->Errno("rename","Failed to rename");
550 /* Mangle the source to be in the proper notation with
551 prefix dist [component] */
552 *I
= string(*I
,Prefix
.length());
553 ConvertToSourceList(CDROM
,*I
);
554 *I
= Prefix
+ ' ' + *I
;
556 CurrentSize
+= Pkg
.Size();
561 cout
<< "Wrote " << Packages
<< " package records" ;
563 cout
<< " with " << NotFound
<< " missing files";
564 if (NotFound
!= 0 && WrongSize
!= 0)
567 cout
<< " with " << WrongSize
<< " mismatched files";
571 return _error
->Error("No valid package records were found.");
573 if (NotFound
+ WrongSize
> 10)
574 cout
<< "Alot of package entires were discarded, perhaps this CD is funny?" << endl
;
580 // ReduceSourceList - Takes the path list and reduces it /*{{{*/
581 // ---------------------------------------------------------------------
582 /* This takes the list of source list expressed entires and collects
583 similar ones to form a single entry for each dist */
584 bool ReduceSourcelist(string CD
,vector
<string
> &List
)
586 sort(List
.begin(),List
.end());
588 // Collect similar entries
589 for (vector
<string
>::iterator I
= List
.begin(); I
!= List
.end(); I
++)
592 string::size_type Space
= (*I
).find(' ');
593 if (Space
== string::npos
)
595 string::size_type SSpace
= (*I
).find(' ',Space
+ 1);
596 if (SSpace
== string::npos
)
599 string Word1
= string(*I
,Space
,SSpace
-Space
);
600 for (vector
<string
>::iterator J
= List
.begin(); J
!= I
; J
++)
603 string::size_type Space2
= (*J
).find(' ');
604 if (Space2
== string::npos
)
606 string::size_type SSpace2
= (*J
).find(' ',Space2
+ 1);
607 if (SSpace2
== string::npos
)
610 if (string(*J
,Space2
,SSpace2
-Space2
) != Word1
)
613 *J
+= string(*I
,SSpace
);
618 // Wipe erased entries
619 for (unsigned int I
= 0; I
< List
.size();)
621 if (List
[I
].empty() == false)
624 List
.erase(List
.begin()+I
);
628 // WriteDatabase - Write the CDROM Database file /*{{{*/
629 // ---------------------------------------------------------------------
630 /* We rewrite the configuration class associated with the cdrom database. */
631 bool WriteDatabase(Configuration
&Cnf
)
633 string DFile
= _config
->FindFile("Dir::State::cdroms");
634 string NewFile
= DFile
+ ".new";
636 unlink(NewFile
.c_str());
637 ofstream
Out(NewFile
.c_str());
639 return _error
->Errno("ofstream::ofstream",
640 "Failed to open %s.new",DFile
.c_str());
642 /* Write out all of the configuration directives by walking the
643 configuration tree */
644 const Configuration::Item
*Top
= Cnf
.Tree(0);
647 // Print the config entry
648 if (Top
->Value
.empty() == false)
649 Out
<< Top
->FullTag() + " \"" << Top
->Value
<< "\";" << endl
;
657 while (Top
!= 0 && Top
->Next
== 0)
665 rename(DFile
.c_str(),string(DFile
+ '~').c_str());
666 if (rename(NewFile
.c_str(),DFile
.c_str()) != 0)
667 return _error
->Errno("rename","Failed to rename %s.new to %s",
668 DFile
.c_str(),DFile
.c_str());
673 // WriteSourceList - Write an updated sourcelist /*{{{*/
674 // ---------------------------------------------------------------------
675 /* This reads the old source list and copies it into the new one. It
676 appends the new CDROM entires just after the first block of comments.
677 This places them first in the file. It also removes any old entries
678 that were the same. */
679 bool WriteSourceList(string Name
,vector
<string
> &List
)
681 string File
= _config
->FindFile("Dir::Etc::sourcelist");
683 // Open the stream for reading
684 ifstream
F(File
.c_str(),ios::in
| ios::nocreate
);
686 return _error
->Errno("ifstream::ifstream","Opening %s",File
.c_str());
688 string NewFile
= File
+ ".new";
689 unlink(NewFile
.c_str());
690 ofstream
Out(NewFile
.c_str());
692 return _error
->Errno("ofstream::ofstream",
693 "Failed to open %s.new",File
.c_str());
695 // Create a short uri without the path
696 string ShortURI
= "cdrom:" + Name
+ "/";
701 while (F
.eof() == false)
703 F
.getline(Buffer
,sizeof(Buffer
));
705 _strtabexpand(Buffer
,sizeof(Buffer
));
709 if (Buffer
[0] == '#' || Buffer
[0] == 0)
711 Out
<< Buffer
<< endl
;
717 for (vector
<string
>::iterator I
= List
.begin(); I
!= List
.end(); I
++)
719 string::size_type Space
= (*I
).find(' ');
720 if (Space
== string::npos
)
721 return _error
->Error("Internal error");
723 Out
<< "deb \"cdrom:" << Name
<< "/" << string(*I
,0,Space
) <<
724 "\" " << string(*I
,Space
+1) << endl
;
733 if (ParseQuoteWord(C
,Type
) == false ||
734 ParseQuoteWord(C
,URI
) == false)
736 Out
<< Buffer
<< endl
;
740 // Emit lines like this one
741 if (Type
!= "deb" || string(URI
,0,ShortURI
.length()) != ShortURI
)
743 Out
<< Buffer
<< endl
;
748 // Just in case the file was empty
751 for (vector
<string
>::iterator I
= List
.begin(); I
!= List
.end(); I
++)
753 string::size_type Space
= (*I
).find(' ');
754 if (Space
== string::npos
)
755 return _error
->Error("Internal error");
757 Out
<< "deb \"cdrom:" << Name
<< "/" << string(*I
,0,Space
) <<
758 "\" " << string(*I
,Space
+1) << endl
;
764 rename(File
.c_str(),string(File
+ '~').c_str());
765 if (rename(NewFile
.c_str(),File
.c_str()) != 0)
766 return _error
->Errno("rename","Failed to rename %s.new to %s",
767 File
.c_str(),File
.c_str());
773 // Prompt - Simple prompt /*{{{*/
774 // ---------------------------------------------------------------------
776 void Prompt(const char *Text
)
779 cout
<< Text
<< ' ' << flush
;
780 read(STDIN_FILENO
,&C
,1);
785 // PromptLine - Prompt for an input line /*{{{*/
786 // ---------------------------------------------------------------------
788 string
PromptLine(const char *Text
)
790 cout
<< Text
<< ':' << endl
;
798 // DoAdd - Add a new CDROM /*{{{*/
799 // ---------------------------------------------------------------------
800 /* This does the main add bit.. We show some status and things. The
801 sequence is to mount/umount the CD, Ident it then scan it for package
802 files and reduce that list. Then we copy over the package files and
803 verify them. Then rewrite the database files */
804 bool DoAdd(CommandLine
&)
807 string CDROM
= _config
->FindDir("Acquire::cdrom::mount","/cdrom/");
809 CDROM
= SafeGetCWD() + '/' + CDROM
;
811 cout
<< "Using CD-ROM mount point " << CDROM
<< endl
;
814 Configuration Database
;
815 string DFile
= _config
->FindFile("Dir::State::cdroms");
816 if (FileExists(DFile
) == true)
818 if (ReadConfigFile(Database
,DFile
) == false)
819 return _error
->Error("Unable to read the cdrom database %s",
823 // Unmount the CD and get the user to put in the one they want
824 if (_config
->FindB("APT::CDROM::NoMount",false) == false)
826 cout
<< "Unmounting CD-ROM" << endl
;
829 // Mount the new CDROM
830 Prompt("Please insert a Disc in the drive and press any key");
831 cout
<< "Mounting CD-ROM" << endl
;
832 if (MountCdrom(CDROM
) == false)
834 cout
<< "Failed to mount the cdrom." << endl
;
839 // Hash the CD to get an ID
840 cout
<< "Identifying.. " << flush
;
842 if (IdentCdrom(CDROM
,ID
) == false)
848 cout
<< '[' << ID
<< ']' << endl
;
850 cout
<< "Scanning Disc for index files.. " << flush
;
851 // Get the CD structure
853 string StartDir
= SafeGetCWD();
854 if (FindPackages(CDROM
,List
) == false)
860 chdir(StartDir
.c_str());
862 if (_config
->FindB("Debug::aptcdrom",false) == true)
864 cout
<< "I found:" << endl
;
865 for (vector
<string
>::iterator I
= List
.begin(); I
!= List
.end(); I
++)
872 DropBinaryArch(List
);
874 cout
<< "Found " << List
.size() << " package index files." << endl
;
876 if (List
.size() == 0)
877 return _error
->Error("Unable to locate any package files, perhaps this is not a Debian Disc");
879 // Check if the CD is in the database
881 if (Database
.Exists("CD::" + ID
) == false ||
882 _config
->FindB("APT::CDROM::Rename",false) == true)
884 // Try to use the CDs label if at all possible
885 if (FileExists(CDROM
+ "/.disk/info") == true)
887 ifstream
F(string(CDROM
+ "/.disk/info").c_str());
891 if (Name
.empty() == false)
893 cout
<< "Found label '" << Name
<< "'" << endl
;
894 Database
.Set("CD::" + ID
+ "::Label",Name
);
898 if (_config
->FindB("APT::CDROM::Rename",false) == true ||
899 Name
.empty() == true)
901 cout
<< "Please provide a name for this Disc, such as 'Debian 2.1r1 Disk 1'";
904 Name
= PromptLine("");
905 if (Name
.empty() == false &&
906 Name
.find('/') == string::npos
)
908 cout
<< "That is not a valid name, try again " << endl
;
914 Name
= Database
.Find("CD::" + ID
);
915 Database
.Set("CD::" + ID
,Name
);
916 cout
<< "This Disc is called '" << Name
<< "'" << endl
;
918 // Copy the package files to the state directory
919 if (CopyPackages(CDROM
,Name
,List
) == false)
922 ReduceSourcelist(CDROM
,List
);
924 // Write the database and sourcelist
925 if (_config
->FindB("APT::cdrom::NoAct",false) == false)
927 if (WriteDatabase(Database
) == false)
930 cout
<< "Writing new source list" << endl
;
931 if (WriteSourceList(Name
,List
) == false)
935 // Print the sourcelist entries
936 cout
<< "Source List entires for this Disc are:" << endl
;
937 for (vector
<string
>::iterator I
= List
.begin(); I
!= List
.end(); I
++)
939 string::size_type Space
= (*I
).find(' ');
940 if (Space
== string::npos
)
941 return _error
->Error("Internal error");
943 cout
<< "deb \"cdrom:" << Name
<< "/" << string(*I
,0,Space
) <<
944 "\" " << string(*I
,Space
+1) << endl
;
951 // ShowHelp - Show the help screen /*{{{*/
952 // ---------------------------------------------------------------------
956 cout
<< PACKAGE
<< ' ' << VERSION
<< " for " << ARCHITECTURE
<<
957 " compiled on " << __DATE__
<< " " << __TIME__
<< endl
;
959 cout
<< "Usage: apt-cdrom [options] command" << endl
;
961 cout
<< "apt-cdrom is a tool to add CDROM's to APT's source list. The " << endl
;
962 cout
<< "CDROM mount point and device information is taken from apt.conf" << endl
;
963 cout
<< "and /etc/fstab." << endl
;
965 cout
<< "Commands:" << endl
;
966 cout
<< " add - Add a CDROM" << endl
;
968 cout
<< "Options:" << endl
;
969 cout
<< " -h This help text" << endl
;
970 cout
<< " -d CD-ROM mount point" << endl
;
971 cout
<< " -r Rename a recognized CD-ROM" << endl
;
972 cout
<< " -m No mounting" << endl
;
973 cout
<< " -f Fast mode, don't check package files" << endl
;
974 cout
<< " -a Thorough scan mode" << endl
;
975 cout
<< " -c=? Read this configuration file" << endl
;
976 cout
<< " -o=? Set an arbitary configuration option, ie -o dir::cache=/tmp" << endl
;
977 cout
<< "See fstab(5)" << endl
;
982 int main(int argc
,const char *argv
[])
984 CommandLine::Args Args
[] = {
985 {'h',"help","help",0},
986 {'d',"cdrom","Acquire::cdrom::mount",CommandLine::HasArg
},
987 {'r',"rename","APT::CDROM::Rename",0},
988 {'m',"no-mount","APT::CDROM::NoMount",0},
989 {'f',"fast","APT::CDROM::Fast",0},
990 {'n',"just-print","APT::CDROM::NoAct",0},
991 {'n',"recon","APT::CDROM::NoAct",0},
992 {'n',"no-act","APT::CDROM::NoAct",0},
993 {'a',"thorough","APT::CDROM::Thorough",0},
994 {'c',"config-file",0,CommandLine::ConfigFile
},
995 {'o',"option",0,CommandLine::ArbItem
},
997 CommandLine::Dispatch Cmds
[] = {
1001 // Parse the command line and initialize the package library
1002 CommandLine
CmdL(Args
,_config
);
1003 if (pkgInitialize(*_config
) == false ||
1004 CmdL
.Parse(argc
,argv
) == false)
1006 _error
->DumpErrors();
1010 // See if the help should be shown
1011 if (_config
->FindB("help") == true ||
1012 CmdL
.FileSize() == 0)
1015 // Match the operation
1016 CmdL
.DispatchArg(Cmds
);
1018 // Print any errors or warnings found during parsing
1019 if (_error
->empty() == false)
1021 bool Errors
= _error
->PendingError();
1022 _error
->DumpErrors();
1023 return Errors
== true?100:0;