]>
git.saurik.com Git - apt.git/blob - cmdline/apt-cdrom.cc
1 // -*- mode: cpp; mode: fold -*-
3 // $Id: apt-cdrom.cc,v 1.13 1998/12/09 05:57:17 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
)
96 cout
<< "Inode throw away " << Dir
->d_name
<< endl
;
100 // Store the inodes weve seen
101 Inodes
[Depth
] = Buf
.st_ino
;
104 if (FindPackages(CD
+ Dir
->d_name
,List
,Depth
+1) == false)
107 if (chdir(CD
.c_str()) != 0)
108 return _error
->Errno("chdir","Unable to change to ",CD
.c_str());
113 return !_error
->PendingError();
116 // DropBinaryArch - Dump dirs with a string like /binary-<foo>/ /*{{{*/
117 // ---------------------------------------------------------------------
118 /* Here we drop everything that is not this machines arch */
119 bool DropBinaryArch(vector
<string
> &List
)
122 sprintf(S
,"/binary-%s/",_config
->Find("Apt::Architecture").c_str());
124 for (unsigned int I
= 0; I
< List
.size(); I
++)
126 const char *Str
= List
[I
].c_str();
129 if ((Res
= strstr(Str
,"/binary-")) == 0)
133 if (strlen(Res
) < strlen(S
))
135 List
.erase(List
.begin() + I
);
140 // See if it is our arch
141 if (stringcmp(Res
,Res
+ strlen(S
),S
) == 0)
145 List
.erase(List
.begin() + I
);
152 // Score - We compute a 'score' for a path /*{{{*/
153 // ---------------------------------------------------------------------
154 /* Paths are scored based on how close they come to what I consider
155 normal. That is ones that have 'dist' 'stable' 'frozen' will score
156 higher than ones without. */
157 int Score(string Path
)
160 if (Path
.find("stable/") != string::npos
)
162 if (Path
.find("/binary-") != string::npos
)
164 if (Path
.find("frozen/") != string::npos
)
166 if (Path
.find("/dists/") != string::npos
)
168 if (Path
.find("/main/") != string::npos
)
170 if (Path
.find("/contrib/") != string::npos
)
172 if (Path
.find("/non-free/") != string::npos
)
174 if (Path
.find("/non-US/") != string::npos
)
179 // DropRepeats - Drop repeated files resulting from symlinks /*{{{*/
180 // ---------------------------------------------------------------------
181 /* Here we go and stat every file that we found and strip dup inodes. */
182 bool DropRepeats(vector
<string
> &List
)
184 // Get a list of all the inodes
185 ino_t
*Inodes
= new ino_t
[List
.size()];
186 for (unsigned int I
= 0; I
!= List
.size(); I
++)
189 if (stat((List
[I
] + "Packages").c_str(),&Buf
) != 0)
190 _error
->Errno("stat","Failed to stat %s",List
[I
].c_str());
191 Inodes
[I
] = Buf
.st_ino
;
195 for (unsigned int I
= 0; I
!= List
.size(); I
++)
197 for (unsigned int J
= I
+1; J
< List
.size(); J
++)
200 if (Inodes
[J
] != Inodes
[I
])
203 // We score the two paths.. and erase one
204 int ScoreA
= Score(List
[I
]);
205 int ScoreB
= Score(List
[J
]);
216 // Wipe erased entries
217 for (unsigned int I
= 0; I
< List
.size();)
219 if (List
[I
].empty() == false)
222 List
.erase(List
.begin()+I
);
228 // ConvertToSourceList - Convert a Path to a sourcelist entry /*{{{*/
229 // ---------------------------------------------------------------------
230 /* We look for things in dists/ notation and convert them to
231 <dist> <component> form otherwise it is left alone. This also strips
233 void ConvertToSourceList(string CD
,string
&Path
)
236 sprintf(S
,"binary-%s",_config
->Find("Apt::Architecture").c_str());
238 // Strip the cdrom base path
239 Path
= string(Path
,CD
.length());
240 if (Path
.empty() == true)
243 // Too short to be a dists/ type
244 if (Path
.length() < strlen("dists/"))
248 if (stringcmp(Path
.begin(),Path
.begin()+strlen("dists/"),"dists/") != 0)
252 string::size_type Slash
= strlen("dists/");
253 string::size_type Slash2
= Path
.find('/',Slash
+ 1);
254 if (Slash2
== string::npos
|| Slash2
+ 2 >= Path
.length())
256 string Dist
= string(Path
,Slash
,Slash2
- Slash
);
258 // Isolate the component
259 Slash
= Path
.find('/',Slash2
+1);
260 if (Slash
== string::npos
|| Slash
+ 2 >= Path
.length())
262 string Comp
= string(Path
,Slash2
+1,Slash
- Slash2
-1);
264 // Verify the trailing binar - bit
265 Slash2
= Path
.find('/',Slash
+ 1);
266 if (Slash
== string::npos
)
268 string Binary
= string(Path
,Slash
+1,Slash2
- Slash
-1);
273 Path
= Dist
+ ' ' + Comp
;
276 // GrabFirst - Return the first Depth path components /*{{{*/
277 // ---------------------------------------------------------------------
279 bool GrabFirst(string Path
,string
&To
,unsigned int Depth
)
281 string::size_type I
= 0;
284 I
= Path
.find('/',I
+1);
287 while (I
!= string::npos
&& Depth
!= 0);
289 if (I
== string::npos
)
292 To
= string(Path
,0,I
+1);
296 // ChopDirs - Chop off the leading directory components /*{{{*/
297 // ---------------------------------------------------------------------
299 string
ChopDirs(string Path
,unsigned int Depth
)
301 string::size_type I
= 0;
304 I
= Path
.find('/',I
+1);
307 while (I
!= string::npos
&& Depth
!= 0);
309 if (I
== string::npos
)
312 return string(Path
,I
+1);
315 // ReconstructPrefix - Fix strange prefixing /*{{{*/
316 // ---------------------------------------------------------------------
317 /* This prepends dir components from the path to the package files to
318 the path to the deb until it is found */
319 bool ReconstructPrefix(string
&Prefix
,string OrigPath
,string CD
,
322 bool Debug
= _config
->FindB("Debug::aptcdrom",false);
323 unsigned int Depth
= 1;
324 string MyPrefix
= Prefix
;
328 if (stat(string(CD
+ MyPrefix
+ File
).c_str(),&Buf
) != 0)
331 cout
<< "Failed, " << CD
+ MyPrefix
+ File
<< endl
;
332 if (GrabFirst(OrigPath
,MyPrefix
,Depth
++) == true)
346 // ReconstructChop - Fixes bad source paths /*{{{*/
347 // ---------------------------------------------------------------------
348 /* This removes path components from the filename and prepends the location
349 of the package files until a file is found */
350 bool ReconstructChop(unsigned long &Chop
,string Dir
,string File
)
352 // Attempt to reconstruct the filename
353 unsigned long Depth
= 0;
357 if (stat(string(Dir
+ File
).c_str(),&Buf
) != 0)
359 File
= ChopDirs(File
,1);
361 if (File
.empty() == false)
375 // CopyPackages - Copy the package files from the CD /*{{{*/
376 // ---------------------------------------------------------------------
378 bool CopyPackages(string CDROM
,string Name
,vector
<string
> &List
)
380 OpTextProgress Progress
;
382 bool NoStat
= _config
->FindB("APT::CDROM::Fast",false);
383 bool Debug
= _config
->FindB("Debug::aptcdrom",false);
385 // Prepare the progress indicator
386 unsigned long TotalSize
= 0;
387 for (vector
<string
>::iterator I
= List
.begin(); I
!= List
.end(); I
++)
390 if (stat(string(*I
+ "Packages").c_str(),&Buf
) != 0)
391 return _error
->Errno("stat","Stat failed for %s",
392 string(*I
+ "Packages").c_str());
393 TotalSize
+= Buf
.st_size
;
396 unsigned long CurrentSize
= 0;
397 unsigned int NotFound
= 0;
398 unsigned int WrongSize
= 0;
399 unsigned int Packages
= 0;
400 for (vector
<string
>::iterator I
= List
.begin(); I
!= List
.end(); I
++)
402 string OrigPath
= string(*I
,CDROM
.length());
404 // Open the package file
405 FileFd
Pkg(*I
+ "Packages",FileFd::ReadOnly
);
406 pkgTagFile
Parser(Pkg
);
407 if (_error
->PendingError() == true)
410 // Open the output file
412 sprintf(S
,"cdrom:%s/%sPackages",Name
.c_str(),(*I
).c_str() + CDROM
.length());
413 string TargetF
= _config
->FindDir("Dir::State::lists") + "partial/";
414 TargetF
+= URItoFileName(S
);
415 if (_config
->FindB("APT::CDROM::NoAct",false) == true)
416 TargetF
= "/dev/null";
417 FileFd
Target(TargetF
,FileFd::WriteEmpty
);
418 if (_error
->PendingError() == true)
421 // Setup the progress meter
422 Progress
.OverallProgress(CurrentSize
,TotalSize
,Pkg
.Size(),
423 "Reading Package Lists");
426 Progress
.SubProgress(Pkg
.Size());
427 pkgTagSection Section
;
429 unsigned long Hits
= 0;
430 unsigned long Chop
= 0;
431 while (Parser
.Step(Section
) == true)
433 Progress
.Progress(Parser
.Offset());
435 string File
= Section
.FindS("Filename");
436 unsigned long Size
= Section
.FindI("Size");
437 if (File
.empty() || Size
== 0)
438 return _error
->Error("Cannot find filename or size tag");
441 File
= OrigPath
+ ChopDirs(File
,Chop
);
443 // See if the file exists
444 if (NoStat
== false || Hits
< 10)
446 // Attempt to fix broken structure
449 if (ReconstructPrefix(Prefix
,OrigPath
,CDROM
,File
) == false &&
450 ReconstructChop(Chop
,*I
,File
) == false)
456 File
= OrigPath
+ ChopDirs(File
,Chop
);
461 if (stat(string(CDROM
+ Prefix
+ File
).c_str(),&Buf
) != 0)
468 if ((unsigned)Buf
.st_size
!= Size
)
478 // Copy it to the target package file
483 // Mangle the output filename
484 const char *Filename
;
485 Section
.Find("Filename",Filename
,Stop
);
487 /* We need to rewrite the filename field so we emit
488 all fields except the filename file and rewrite that one */
489 for (unsigned int I
= 0; I
!= Section
.Count(); I
++)
491 Section
.Get(Start
,Stop
,I
);
492 if (Start
<= Filename
&& Stop
> Filename
)
495 sprintf(S
,"Filename: %s\n",File
.c_str());
496 if (I
+ 1 == Section
.Count())
498 if (Target
.Write(S
,strlen(S
)) == false)
502 if (Target
.Write(Start
,Stop
-Start
) == false)
505 if (Target
.Write("\n",1) == false)
510 Section
.GetSection(Start
,Stop
);
511 if (Target
.Write(Start
,Stop
-Start
) == false)
517 cout
<< " Processed by using Prefix '" << Prefix
<< "' and chop " << Chop
<< endl
;
519 if (_config
->FindB("APT::CDROM::NoAct",false) == false)
521 // Move out of the partial directory
523 string FinalF
= _config
->FindDir("Dir::State::lists");
524 FinalF
+= URItoFileName(S
);
525 if (rename(TargetF
.c_str(),FinalF
.c_str()) != 0)
526 return _error
->Errno("rename","Failed to rename");
528 // Copy the release file
529 sprintf(S
,"cdrom:%s/%sRelease",Name
.c_str(),(*I
).c_str() + CDROM
.length());
530 string TargetF
= _config
->FindDir("Dir::State::lists") + "partial/";
531 TargetF
+= URItoFileName(S
);
532 if (FileExists(*I
+ "Release") == true)
534 FileFd
Target(TargetF
,FileFd::WriteEmpty
);
535 FileFd
Rel(*I
+ "Release",FileFd::ReadOnly
);
536 if (_error
->PendingError() == true)
539 if (CopyFile(Rel
,Target
) == false)
544 // Empty release file
545 FileFd
Target(TargetF
,FileFd::WriteEmpty
);
548 // Rename the release file
549 FinalF
= _config
->FindDir("Dir::State::lists");
550 FinalF
+= URItoFileName(S
);
551 if (rename(TargetF
.c_str(),FinalF
.c_str()) != 0)
552 return _error
->Errno("rename","Failed to rename");
555 /* Mangle the source to be in the proper notation with
556 prefix dist [component] */
557 *I
= string(*I
,Prefix
.length());
558 ConvertToSourceList(CDROM
,*I
);
559 *I
= Prefix
+ ' ' + *I
;
561 CurrentSize
+= Pkg
.Size();
566 cout
<< "Wrote " << Packages
<< " package records" ;
568 cout
<< " with " << NotFound
<< " missing files";
569 if (NotFound
!= 0 && WrongSize
!= 0)
572 cout
<< " with " << WrongSize
<< " mismatched files";
576 return _error
->Error("No valid package records were found.");
578 if (NotFound
+ WrongSize
> 10)
579 cout
<< "Alot of package entires were discarded, perhaps this CD is funny?" << endl
;
585 // ReduceSourceList - Takes the path list and reduces it /*{{{*/
586 // ---------------------------------------------------------------------
587 /* This takes the list of source list expressed entires and collects
588 similar ones to form a single entry for each dist */
589 bool ReduceSourcelist(string CD
,vector
<string
> &List
)
591 sort(List
.begin(),List
.end());
593 // Collect similar entries
594 for (vector
<string
>::iterator I
= List
.begin(); I
!= List
.end(); I
++)
597 string::size_type Space
= (*I
).find(' ');
598 if (Space
== string::npos
)
600 string::size_type SSpace
= (*I
).find(' ',Space
+ 1);
601 if (SSpace
== string::npos
)
604 string Word1
= string(*I
,Space
,SSpace
-Space
);
605 for (vector
<string
>::iterator J
= List
.begin(); J
!= I
; J
++)
608 string::size_type Space2
= (*J
).find(' ');
609 if (Space2
== string::npos
)
611 string::size_type SSpace2
= (*J
).find(' ',Space2
+ 1);
612 if (SSpace2
== string::npos
)
615 if (string(*J
,Space2
,SSpace2
-Space2
) != Word1
)
618 *J
+= string(*I
,SSpace
);
623 // Wipe erased entries
624 for (unsigned int I
= 0; I
< List
.size();)
626 if (List
[I
].empty() == false)
629 List
.erase(List
.begin()+I
);
633 // WriteDatabase - Write the CDROM Database file /*{{{*/
634 // ---------------------------------------------------------------------
635 /* We rewrite the configuration class associated with the cdrom database. */
636 bool WriteDatabase(Configuration
&Cnf
)
638 string DFile
= _config
->FindFile("Dir::State::cdroms");
639 string NewFile
= DFile
+ ".new";
641 unlink(NewFile
.c_str());
642 ofstream
Out(NewFile
.c_str());
644 return _error
->Errno("ofstream::ofstream",
645 "Failed to open %s.new",DFile
.c_str());
647 /* Write out all of the configuration directives by walking the
648 configuration tree */
649 const Configuration::Item
*Top
= Cnf
.Tree(0);
652 // Print the config entry
653 if (Top
->Value
.empty() == false)
654 Out
<< Top
->FullTag() + " \"" << Top
->Value
<< "\";" << endl
;
662 while (Top
!= 0 && Top
->Next
== 0)
670 rename(DFile
.c_str(),string(DFile
+ '~').c_str());
671 if (rename(NewFile
.c_str(),DFile
.c_str()) != 0)
672 return _error
->Errno("rename","Failed to rename %s.new to %s",
673 DFile
.c_str(),DFile
.c_str());
678 // WriteSourceList - Write an updated sourcelist /*{{{*/
679 // ---------------------------------------------------------------------
680 /* This reads the old source list and copies it into the new one. It
681 appends the new CDROM entires just after the first block of comments.
682 This places them first in the file. It also removes any old entries
683 that were the same. */
684 bool WriteSourceList(string Name
,vector
<string
> &List
)
686 string File
= _config
->FindFile("Dir::Etc::sourcelist");
688 // Open the stream for reading
689 ifstream
F(File
.c_str(),ios::in
| ios::nocreate
);
691 return _error
->Errno("ifstream::ifstream","Opening %s",File
.c_str());
693 string NewFile
= File
+ ".new";
694 unlink(NewFile
.c_str());
695 ofstream
Out(NewFile
.c_str());
697 return _error
->Errno("ofstream::ofstream",
698 "Failed to open %s.new",File
.c_str());
700 // Create a short uri without the path
701 string ShortURI
= "cdrom:" + Name
+ "/";
706 while (F
.eof() == false)
708 F
.getline(Buffer
,sizeof(Buffer
));
710 _strtabexpand(Buffer
,sizeof(Buffer
));
714 if (Buffer
[0] == '#' || Buffer
[0] == 0)
716 Out
<< Buffer
<< endl
;
722 for (vector
<string
>::iterator I
= List
.begin(); I
!= List
.end(); I
++)
724 string::size_type Space
= (*I
).find(' ');
725 if (Space
== string::npos
)
726 return _error
->Error("Internal error");
728 Out
<< "deb \"cdrom:" << Name
<< "/" << string(*I
,0,Space
) <<
729 "\" " << string(*I
,Space
+1) << endl
;
738 if (ParseQuoteWord(C
,Type
) == false ||
739 ParseQuoteWord(C
,URI
) == false)
741 Out
<< Buffer
<< endl
;
745 // Emit lines like this one
746 if (Type
!= "deb" || string(URI
,0,ShortURI
.length()) != ShortURI
)
748 Out
<< Buffer
<< endl
;
753 // Just in case the file was empty
756 for (vector
<string
>::iterator I
= List
.begin(); I
!= List
.end(); I
++)
758 string::size_type Space
= (*I
).find(' ');
759 if (Space
== string::npos
)
760 return _error
->Error("Internal error");
762 Out
<< "deb \"cdrom:" << Name
<< "/" << string(*I
,0,Space
) <<
763 "\" " << string(*I
,Space
+1) << endl
;
769 rename(File
.c_str(),string(File
+ '~').c_str());
770 if (rename(NewFile
.c_str(),File
.c_str()) != 0)
771 return _error
->Errno("rename","Failed to rename %s.new to %s",
772 File
.c_str(),File
.c_str());
778 // Prompt - Simple prompt /*{{{*/
779 // ---------------------------------------------------------------------
781 void Prompt(const char *Text
)
784 cout
<< Text
<< ' ' << flush
;
785 read(STDIN_FILENO
,&C
,1);
790 // PromptLine - Prompt for an input line /*{{{*/
791 // ---------------------------------------------------------------------
793 string
PromptLine(const char *Text
)
795 cout
<< Text
<< ':' << endl
;
803 // DoAdd - Add a new CDROM /*{{{*/
804 // ---------------------------------------------------------------------
805 /* This does the main add bit.. We show some status and things. The
806 sequence is to mount/umount the CD, Ident it then scan it for package
807 files and reduce that list. Then we copy over the package files and
808 verify them. Then rewrite the database files */
809 bool DoAdd(CommandLine
&)
812 string CDROM
= _config
->FindDir("Acquire::cdrom::mount","/cdrom/");
814 CDROM
= SafeGetCWD() + '/' + CDROM
;
816 cout
<< "Using CD-ROM mount point " << CDROM
<< endl
;
819 Configuration Database
;
820 string DFile
= _config
->FindFile("Dir::State::cdroms");
821 if (FileExists(DFile
) == true)
823 if (ReadConfigFile(Database
,DFile
) == false)
824 return _error
->Error("Unable to read the cdrom database %s",
828 // Unmount the CD and get the user to put in the one they want
829 if (_config
->FindB("APT::CDROM::NoMount",false) == false)
831 cout
<< "Unmounting CD-ROM" << endl
;
834 // Mount the new CDROM
835 Prompt("Please insert a Disc in the drive and press any key");
836 cout
<< "Mounting CD-ROM" << endl
;
837 if (MountCdrom(CDROM
) == false)
839 cout
<< "Failed to mount the cdrom." << endl
;
844 // Hash the CD to get an ID
845 cout
<< "Identifying.. " << flush
;
847 if (IdentCdrom(CDROM
,ID
) == false)
853 cout
<< '[' << ID
<< ']' << endl
;
855 cout
<< "Scanning Disc for index files.. " << flush
;
856 // Get the CD structure
858 string StartDir
= SafeGetCWD();
859 if (FindPackages(CDROM
,List
) == false)
865 chdir(StartDir
.c_str());
867 if (_config
->FindB("Debug::aptcdrom",false) == true)
869 cout
<< "I found:" << endl
;
870 for (vector
<string
>::iterator I
= List
.begin(); I
!= List
.end(); I
++)
877 DropBinaryArch(List
);
879 cout
<< "Found " << List
.size() << " package index files." << endl
;
881 if (List
.size() == 0)
882 return _error
->Error("Unable to locate any package files, perhaps this is not a Debian Disc");
884 // Check if the CD is in the database
886 if (Database
.Exists("CD::" + ID
) == false ||
887 _config
->FindB("APT::CDROM::Rename",false) == true)
889 // Try to use the CDs label if at all possible
890 if (FileExists(CDROM
+ "/.disk/info") == true)
892 ifstream
F(string(CDROM
+ "/.disk/info").c_str());
896 if (Name
.empty() == false)
898 cout
<< "Found label '" << Name
<< "'" << endl
;
899 Database
.Set("CD::" + ID
+ "::Label",Name
);
903 if (_config
->FindB("APT::CDROM::Rename",false) == true ||
904 Name
.empty() == true)
906 cout
<< "Please provide a name for this Disc, such as 'Debian 2.1r1 Disk 1'";
909 Name
= PromptLine("");
910 if (Name
.empty() == false &&
911 Name
.find('/') == string::npos
)
913 cout
<< "That is not a valid name, try again " << endl
;
919 Name
= Database
.Find("CD::" + ID
);
920 Database
.Set("CD::" + ID
,Name
);
921 cout
<< "This Disc is called '" << Name
<< "'" << endl
;
923 // Copy the package files to the state directory
924 if (CopyPackages(CDROM
,Name
,List
) == false)
927 ReduceSourcelist(CDROM
,List
);
929 // Write the database and sourcelist
930 if (_config
->FindB("APT::cdrom::NoAct",false) == false)
932 if (WriteDatabase(Database
) == false)
935 cout
<< "Writing new source list" << endl
;
936 if (WriteSourceList(Name
,List
) == false)
940 // Print the sourcelist entries
941 cout
<< "Source List entries for this Disc are:" << endl
;
942 for (vector
<string
>::iterator I
= List
.begin(); I
!= List
.end(); I
++)
944 string::size_type Space
= (*I
).find(' ');
945 if (Space
== string::npos
)
946 return _error
->Error("Internal error");
948 cout
<< "deb \"cdrom:" << Name
<< "/" << string(*I
,0,Space
) <<
949 "\" " << string(*I
,Space
+1) << endl
;
956 // ShowHelp - Show the help screen /*{{{*/
957 // ---------------------------------------------------------------------
961 cout
<< PACKAGE
<< ' ' << VERSION
<< " for " << ARCHITECTURE
<<
962 " compiled on " << __DATE__
<< " " << __TIME__
<< endl
;
964 cout
<< "Usage: apt-cdrom [options] command" << endl
;
966 cout
<< "apt-cdrom is a tool to add CDROM's to APT's source list. The " << endl
;
967 cout
<< "CDROM mount point and device information is taken from apt.conf" << endl
;
968 cout
<< "and /etc/fstab." << endl
;
970 cout
<< "Commands:" << endl
;
971 cout
<< " add - Add a CDROM" << endl
;
973 cout
<< "Options:" << endl
;
974 cout
<< " -h This help text" << endl
;
975 cout
<< " -d CD-ROM mount point" << endl
;
976 cout
<< " -r Rename a recognized CD-ROM" << endl
;
977 cout
<< " -m No mounting" << endl
;
978 cout
<< " -f Fast mode, don't check package files" << endl
;
979 cout
<< " -a Thorough scan mode" << endl
;
980 cout
<< " -c=? Read this configuration file" << endl
;
981 cout
<< " -o=? Set an arbitary configuration option, ie -o dir::cache=/tmp" << endl
;
982 cout
<< "See fstab(5)" << endl
;
987 int main(int argc
,const char *argv
[])
989 CommandLine::Args Args
[] = {
990 {'h',"help","help",0},
991 {'d',"cdrom","Acquire::cdrom::mount",CommandLine::HasArg
},
992 {'r',"rename","APT::CDROM::Rename",0},
993 {'m',"no-mount","APT::CDROM::NoMount",0},
994 {'f',"fast","APT::CDROM::Fast",0},
995 {'n',"just-print","APT::CDROM::NoAct",0},
996 {'n',"recon","APT::CDROM::NoAct",0},
997 {'n',"no-act","APT::CDROM::NoAct",0},
998 {'a',"thorough","APT::CDROM::Thorough",0},
999 {'c',"config-file",0,CommandLine::ConfigFile
},
1000 {'o',"option",0,CommandLine::ArbItem
},
1002 CommandLine::Dispatch Cmds
[] = {
1006 // Parse the command line and initialize the package library
1007 CommandLine
CmdL(Args
,_config
);
1008 if (pkgInitialize(*_config
) == false ||
1009 CmdL
.Parse(argc
,argv
) == false)
1011 _error
->DumpErrors();
1015 // See if the help should be shown
1016 if (_config
->FindB("help") == true ||
1017 CmdL
.FileSize() == 0)
1020 // Match the operation
1021 CmdL
.DispatchArg(Cmds
);
1023 // Print any errors or warnings found during parsing
1024 if (_error
->empty() == false)
1026 bool Errors
= _error
->PendingError();
1027 _error
->DumpErrors();
1028 return Errors
== true?100:0;