]>
git.saurik.com Git - apt.git/blob - cmdline/apt-cdrom.cc
1 // -*- mode: cpp; mode: fold -*-
3 // $Id: apt-cdrom.cc,v 1.6 1998/11/29 01:19:20 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)
63 DIR *D
= opendir(".");
65 return _error
->Errno("opendir","Unable to read %s",CD
.c_str());
67 // Run over the directory
68 for (struct dirent
*Dir
= readdir(D
); Dir
!= 0; Dir
= readdir(D
))
71 if (strcmp(Dir
->d_name
,".") == 0 ||
72 strcmp(Dir
->d_name
,"..") == 0 ||
73 strcmp(Dir
->d_name
,"source") == 0 ||
74 strcmp(Dir
->d_name
,"experimental") == 0 ||
75 strcmp(Dir
->d_name
,"binary-all") == 0)
78 // See if the name is a sub directory
80 if (stat(Dir
->d_name
,&Buf
) != 0)
83 if (S_ISDIR(Buf
.st_mode
) == 0)
87 if (FindPackages(CD
+ Dir
->d_name
,List
,Depth
+1) == false)
90 if (chdir(CD
.c_str()) != 0)
91 return _error
->Errno("chdir","Unable to change to ",CD
.c_str());
96 return !_error
->PendingError();
99 // DropBinaryArch - Dump dirs with a string like /binary-<foo>/ /*{{{*/
100 // ---------------------------------------------------------------------
101 /* Here we drop everything that is not this machines arch */
102 bool DropBinaryArch(vector
<string
> &List
)
105 sprintf(S
,"/binary-%s/",_config
->Find("Apt::Architecture").c_str());
107 for (unsigned int I
= 0; I
< List
.size(); I
++)
109 const char *Str
= List
[I
].c_str();
112 if ((Res
= strstr(Str
,"/binary-")) == 0)
116 if (strlen(Res
) < strlen(S
))
118 List
.erase(List
.begin() + I
);
123 // See if it is our arch
124 if (stringcmp(Res
,Res
+ strlen(S
),S
) == 0)
128 List
.erase(List
.begin() + I
);
135 // Score - We compute a 'score' for a path /*{{{*/
136 // ---------------------------------------------------------------------
137 /* Paths are scored based on how close they come to what I consider
138 normal. That is ones that have 'dist' 'stable' 'frozen' will score
139 higher than ones without. */
140 int Score(string Path
)
143 if (Path
.find("stable/") != string::npos
)
145 if (Path
.find("frozen/") != string::npos
)
147 if (Path
.find("/dists/") != string::npos
)
149 if (Path
.find("/main/") != string::npos
)
151 if (Path
.find("/contrib/") != string::npos
)
153 if (Path
.find("/non-free/") != string::npos
)
155 if (Path
.find("/non-US/") != string::npos
)
160 // DropRepeats - Drop repeated files resulting from symlinks /*{{{*/
161 // ---------------------------------------------------------------------
162 /* Here we go and stat every file that we found and strip dup inodes. */
163 bool DropRepeats(vector
<string
> &List
)
165 // Get a list of all the inodes
166 ino_t
*Inodes
= new ino_t
[List
.size()];
167 for (unsigned int I
= 0; I
!= List
.size(); I
++)
170 if (stat(List
[I
].c_str(),&Buf
) != 0)
171 _error
->Errno("stat","Failed to stat %s",List
[I
].c_str());
172 Inodes
[I
] = Buf
.st_ino
;
176 for (unsigned int I
= 0; I
!= List
.size(); I
++)
178 for (unsigned int J
= I
+1; J
< List
.size(); J
++)
181 if (Inodes
[J
] != Inodes
[I
])
184 // We score the two paths.. and erase one
185 int ScoreA
= Score(List
[I
]);
186 int ScoreB
= Score(List
[J
]);
197 // Wipe erased entries
198 for (unsigned int I
= 0; I
< List
.size();)
200 if (List
[I
].empty() == false)
203 List
.erase(List
.begin()+I
);
209 // ConvertToSourceList - Convert a Path to a sourcelist entry /*{{{*/
210 // ---------------------------------------------------------------------
211 /* We look for things in dists/ notation and convert them to
212 <dist> <component> form otherwise it is left alone. This also strips
214 void ConvertToSourceList(string CD
,string
&Path
)
217 sprintf(S
,"binary-%s",_config
->Find("Apt::Architecture").c_str());
219 // Strip the cdrom base path
220 Path
= string(Path
,CD
.length());
221 if (Path
.empty() == true)
224 // Too short to be a dists/ type
225 if (Path
.length() < strlen("dists/"))
229 if (stringcmp(Path
.begin(),Path
.begin()+strlen("dists/"),"dists/") != 0)
233 string::size_type Slash
= strlen("dists/");
234 string::size_type Slash2
= Path
.find('/',Slash
+ 1);
235 if (Slash2
== string::npos
|| Slash2
+ 2 >= Path
.length())
237 string Dist
= string(Path
,Slash
,Slash2
- Slash
);
239 // Isolate the component
240 Slash
= Path
.find('/',Slash2
+1);
241 if (Slash
== string::npos
|| Slash
+ 2 >= Path
.length())
243 string Comp
= string(Path
,Slash2
+1,Slash
- Slash2
-1);
245 // Verify the trailing binar - bit
246 Slash2
= Path
.find('/',Slash
+ 1);
247 if (Slash
== string::npos
)
249 string Binary
= string(Path
,Slash
+1,Slash2
- Slash
-1);
254 Path
= Dist
+ ' ' + Comp
;
257 // GrabFirst - Return the first Depth path components /*{{{*/
258 // ---------------------------------------------------------------------
260 bool GrabFirst(string Path
,string
&To
,unsigned int Depth
)
262 string::size_type I
= 0;
265 I
= Path
.find('/',I
+1);
268 while (I
!= string::npos
&& Depth
!= 0);
270 if (I
== string::npos
)
273 To
= string(Path
,0,I
+1);
277 // ChopDirs - Chop off the leading directory components /*{{{*/
278 // ---------------------------------------------------------------------
280 string
ChopDirs(string Path
,unsigned int Depth
)
282 string::size_type I
= 0;
285 I
= Path
.find('/',I
+1);
288 while (I
!= string::npos
&& Depth
!= 0);
290 if (I
== string::npos
)
293 return string(Path
,I
+1);
296 // ReconstructPrefix - Fix strange prefixing /*{{{*/
297 // ---------------------------------------------------------------------
298 /* This prepends dir components from the path to the package files to
299 the path to the deb until it is found */
300 bool ReconstructPrefix(string
&Prefix
,string OrigPath
,string CD
,
303 bool Debug
= _config
->FindB("Debug::aptcdrom",false);
304 unsigned int Depth
= 1;
305 string MyPrefix
= Prefix
;
309 if (stat(string(CD
+ MyPrefix
+ File
).c_str(),&Buf
) != 0)
312 cout
<< "Failed, " << CD
+ MyPrefix
+ File
<< endl
;
313 if (GrabFirst(OrigPath
,MyPrefix
,Depth
++) == true)
327 // ReconstructChop - Fixes bad source paths /*{{{*/
328 // ---------------------------------------------------------------------
329 /* This removes path components from the filename and prepends the location
330 of the package files until a file is found */
331 bool ReconstructChop(unsigned long &Chop
,string Dir
,string File
)
333 // Attempt to reconstruct the filename
334 unsigned long Depth
= 0;
338 if (stat(string(Dir
+ File
).c_str(),&Buf
) != 0)
340 File
= ChopDirs(File
,1);
342 if (File
.empty() == false)
356 // CopyPackages - Copy the package files from the CD /*{{{*/
357 // ---------------------------------------------------------------------
359 bool CopyPackages(string CDROM
,string Name
,vector
<string
> &List
)
361 OpTextProgress Progress
;
363 bool NoStat
= _config
->FindB("APT::CDROM::Fast",false);
364 bool Debug
= _config
->FindB("Debug::aptcdrom",false);
366 // Prepare the progress indicator
367 unsigned long TotalSize
= 0;
368 for (vector
<string
>::iterator I
= List
.begin(); I
!= List
.end(); I
++)
371 if (stat(string(*I
+ "Packages").c_str(),&Buf
) != 0)
372 return _error
->Errno("stat","Stat failed for %s",
373 string(*I
+ "Packages").c_str());
374 TotalSize
+= Buf
.st_size
;
377 unsigned long CurrentSize
= 0;
378 unsigned int NotFound
= 0;
379 unsigned int WrongSize
= 0;
380 unsigned int Packages
= 0;
381 for (vector
<string
>::iterator I
= List
.begin(); I
!= List
.end(); I
++)
383 string OrigPath
= string(*I
,CDROM
.length());
385 // Open the package file
386 FileFd
Pkg(*I
+ "Packages",FileFd::ReadOnly
);
387 pkgTagFile
Parser(Pkg
);
388 if (_error
->PendingError() == true)
391 // Open the output file
393 sprintf(S
,"cdrom:%s/%sPackages",Name
.c_str(),(*I
).c_str() + CDROM
.length());
394 string TargetF
= _config
->FindDir("Dir::State::lists") + "partial/";
395 TargetF
+= URItoFileName(S
);
396 if (_config
->FindB("APT::CDROM::NoAct",false) == true)
397 TargetF
= "/dev/null";
398 FileFd
Target(TargetF
,FileFd::WriteEmpty
);
399 if (_error
->PendingError() == true)
402 // Setup the progress meter
403 Progress
.OverallProgress(CurrentSize
,TotalSize
,Pkg
.Size(),
404 "Reading Package Lists");
407 Progress
.SubProgress(Pkg
.Size());
408 pkgTagSection Section
;
410 unsigned long Hits
= 0;
411 unsigned long Chop
= 0;
412 while (Parser
.Step(Section
) == true)
414 Progress
.Progress(Parser
.Offset());
416 string File
= Section
.FindS("Filename");
417 unsigned long Size
= Section
.FindI("Size");
418 if (File
.empty() || Size
== 0)
419 return _error
->Error("Cannot find filename or size tag");
422 File
= OrigPath
+ ChopDirs(File
,Chop
);
424 // See if the file exists
425 if (NoStat
== false || Hits
< 10)
427 // Attempt to fix broken structure
430 if (ReconstructPrefix(Prefix
,OrigPath
,CDROM
,File
) == false &&
431 ReconstructChop(Chop
,*I
,File
) == false)
437 File
= OrigPath
+ ChopDirs(File
,Chop
);
442 if (stat(string(CDROM
+ Prefix
+ File
).c_str(),&Buf
) != 0)
449 if ((unsigned)Buf
.st_size
!= Size
)
459 // Copy it to the target package file
464 // Mangle the output filename
465 const char *Filename
;
466 Section
.Find("Filename",Filename
,Stop
);
468 /* We need to rewrite the filename field so we emit
469 all fields except the filename file and rewrite that one */
470 for (unsigned int I
= 0; I
!= Section
.Count(); I
++)
472 Section
.Get(Start
,Stop
,I
);
473 if (Start
<= Filename
&& Stop
> Filename
)
476 sprintf(S
,"Filename: %s\n",File
.c_str());
477 if (I
+ 1 == Section
.Count())
479 if (Target
.Write(S
,strlen(S
)) == false)
483 if (Target
.Write(Start
,Stop
-Start
) == false)
486 if (Target
.Write("\n",1) == false)
491 Section
.GetSection(Start
,Stop
);
492 if (Target
.Write(Start
,Stop
-Start
) == false)
498 cout
<< " Processed by using Prefix '" << Prefix
<< "' and chop " << Chop
<< endl
;
500 if (_config
->FindB("APT::CDROM::NoAct",false) == false)
502 // Move out of the partial directory
504 string FinalF
= _config
->FindDir("Dir::State::lists");
505 FinalF
+= URItoFileName(S
);
506 if (rename(TargetF
.c_str(),FinalF
.c_str()) != 0)
507 return _error
->Errno("rename","Failed to rename");
509 // Copy the release file
510 sprintf(S
,"cdrom:%s/%sRelease",Name
.c_str(),(*I
).c_str() + CDROM
.length());
511 string TargetF
= _config
->FindDir("Dir::State::lists") + "partial/";
512 TargetF
+= URItoFileName(S
);
513 if (FileExists(*I
+ "Release") == true)
515 FileFd
Target(TargetF
,FileFd::WriteEmpty
);
516 FileFd
Rel(*I
+ "Release",FileFd::ReadOnly
);
517 if (_error
->PendingError() == true)
520 if (CopyFile(Rel
,Target
) == false)
525 // Empty release file
526 FileFd
Target(TargetF
,FileFd::WriteEmpty
);
529 // Rename the release file
530 FinalF
= _config
->FindDir("Dir::State::lists");
531 FinalF
+= URItoFileName(S
);
532 if (rename(TargetF
.c_str(),FinalF
.c_str()) != 0)
533 return _error
->Errno("rename","Failed to rename");
536 /* Mangle the source to be in the proper notation with
537 prefix dist [component] */
538 *I
= string(*I
,Prefix
.length());
539 ConvertToSourceList(CDROM
,*I
);
540 *I
= Prefix
+ ' ' + *I
;
542 CurrentSize
+= Pkg
.Size();
547 cout
<< "Wrote " << Packages
<< " package records" ;
549 cout
<< " with " << NotFound
<< " missing files";
550 if (NotFound
!= 0 && WrongSize
!= 0)
553 cout
<< " with " << WrongSize
<< " mismatched files";
557 return _error
->Error("No valid package records were found.");
559 if (NotFound
+ WrongSize
> 10)
560 cout
<< "Alot of package entires were discarded, perhaps this CD is funny?" << endl
;
566 // ReduceSourceList - Takes the path list and reduces it /*{{{*/
567 // ---------------------------------------------------------------------
568 /* This takes the list of source list expressed entires and collects
569 similar ones to form a single entry for each dist */
570 bool ReduceSourcelist(string CD
,vector
<string
> &List
)
572 sort(List
.begin(),List
.end());
574 // Collect similar entries
575 for (vector
<string
>::iterator I
= List
.begin(); I
!= List
.end(); I
++)
578 string::size_type Space
= (*I
).find(' ');
579 if (Space
== string::npos
)
581 string::size_type SSpace
= (*I
).find(' ',Space
+ 1);
582 if (SSpace
== string::npos
)
585 string Word1
= string(*I
,Space
,SSpace
-Space
);
586 for (vector
<string
>::iterator J
= List
.begin(); J
!= I
; J
++)
589 string::size_type Space2
= (*J
).find(' ');
590 if (Space2
== string::npos
)
592 string::size_type SSpace2
= (*J
).find(' ',Space2
+ 1);
593 if (SSpace2
== string::npos
)
596 if (string(*J
,Space2
,SSpace2
-Space2
) != Word1
)
599 *J
+= string(*I
,SSpace
);
604 // Wipe erased entries
605 for (unsigned int I
= 0; I
< List
.size();)
607 if (List
[I
].empty() == false)
610 List
.erase(List
.begin()+I
);
614 // WriteDatabase - Write the CDROM Database file /*{{{*/
615 // ---------------------------------------------------------------------
616 /* We rewrite the configuration class associated with the cdrom database. */
617 bool WriteDatabase(Configuration
&Cnf
)
619 string DFile
= _config
->FindFile("Dir::State::cdroms");
620 string NewFile
= DFile
+ ".new";
622 unlink(NewFile
.c_str());
623 ofstream
Out(NewFile
.c_str());
625 return _error
->Errno("ofstream::ofstream",
626 "Failed to open %s.new",DFile
.c_str());
628 /* Write out all of the configuration directives by walking the
629 configuration tree */
630 const Configuration::Item
*Top
= Cnf
.Tree(0);
633 // Print the config entry
634 if (Top
->Value
.empty() == false)
635 Out
<< Top
->FullTag() + " \"" << Top
->Value
<< "\";" << endl
;
643 while (Top
!= 0 && Top
->Next
== 0)
651 rename(DFile
.c_str(),string(DFile
+ '~').c_str());
652 if (rename(NewFile
.c_str(),DFile
.c_str()) != 0)
653 return _error
->Errno("rename","Failed to rename %s.new to %s",
654 DFile
.c_str(),DFile
.c_str());
659 // WriteSourceList - Write an updated sourcelist /*{{{*/
660 // ---------------------------------------------------------------------
661 /* This reads the old source list and copies it into the new one. It
662 appends the new CDROM entires just after the first block of comments.
663 This places them first in the file. It also removes any old entries
664 that were the same. */
665 bool WriteSourceList(string Name
,vector
<string
> &List
)
667 string File
= _config
->FindFile("Dir::Etc::sourcelist");
669 // Open the stream for reading
670 ifstream
F(File
.c_str(),ios::in
| ios::nocreate
);
672 return _error
->Errno("ifstream::ifstream","Opening %s",File
.c_str());
674 string NewFile
= File
+ ".new";
675 unlink(NewFile
.c_str());
676 ofstream
Out(NewFile
.c_str());
678 return _error
->Errno("ofstream::ofstream",
679 "Failed to open %s.new",File
.c_str());
681 // Create a short uri without the path
682 string ShortURI
= "cdrom:" + Name
+ "/";
687 while (F
.eof() == false)
689 F
.getline(Buffer
,sizeof(Buffer
));
691 _strtabexpand(Buffer
,sizeof(Buffer
));
695 if (Buffer
[0] == '#' || Buffer
[0] == 0)
697 Out
<< Buffer
<< endl
;
703 for (vector
<string
>::iterator I
= List
.begin(); I
!= List
.end(); I
++)
705 string::size_type Space
= (*I
).find(' ');
706 if (Space
== string::npos
)
707 return _error
->Error("Internal error");
709 Out
<< "deb \"cdrom:" << Name
<< "/" << string(*I
,0,Space
) <<
710 "\" " << string(*I
,Space
+1) << endl
;
719 if (ParseQuoteWord(C
,Type
) == false ||
720 ParseQuoteWord(C
,URI
) == false)
722 Out
<< Buffer
<< endl
;
726 // Emit lines like this one
727 if (Type
!= "deb" || string(URI
,0,ShortURI
.length()) != ShortURI
)
729 Out
<< Buffer
<< endl
;
734 // Just in case the file was empty
737 for (vector
<string
>::iterator I
= List
.begin(); I
!= List
.end(); I
++)
739 string::size_type Space
= (*I
).find(' ');
740 if (Space
== string::npos
)
741 return _error
->Error("Internal error");
743 Out
<< "deb \"cdrom:" << Name
<< "/" << string(*I
,0,Space
) <<
744 "\" " << string(*I
,Space
+1) << endl
;
750 rename(File
.c_str(),string(File
+ '~').c_str());
751 if (rename(NewFile
.c_str(),File
.c_str()) != 0)
752 return _error
->Errno("rename","Failed to rename %s.new to %s",
753 File
.c_str(),File
.c_str());
759 // Prompt - Simple prompt /*{{{*/
760 // ---------------------------------------------------------------------
762 void Prompt(const char *Text
)
765 cout
<< Text
<< ' ' << flush
;
766 read(STDIN_FILENO
,&C
,1);
771 // PromptLine - Prompt for an input line /*{{{*/
772 // ---------------------------------------------------------------------
774 string
PromptLine(const char *Text
)
776 cout
<< Text
<< ':' << endl
;
784 // DoAdd - Add a new CDROM /*{{{*/
785 // ---------------------------------------------------------------------
786 /* This does the main add bit.. We show some status and things. The
787 sequence is to mount/umount the CD, Ident it then scan it for package
788 files and reduce that list. Then we copy over the package files and
789 verify them. Then rewrite the database files */
790 bool DoAdd(CommandLine
&)
793 string CDROM
= _config
->FindDir("Acquire::cdrom::mount","/cdrom/");
794 cout
<< "Using CD-ROM mount point " << CDROM
<< endl
;
797 Configuration Database
;
798 string DFile
= _config
->FindFile("Dir::State::cdroms");
799 if (FileExists(DFile
) == true)
801 if (ReadConfigFile(Database
,DFile
) == false)
802 return _error
->Error("Unable to read the cdrom database %s",
806 // Unmount the CD and get the user to put in the one they want
807 if (_config
->FindB("APT::CDROM::NoMount",false) == false)
809 cout
<< "Unmounting CD-ROM" << endl
;
812 // Mount the new CDROM
813 Prompt("Please insert a Disc in the drive and press any key");
814 cout
<< "Mounting CD-ROM" << endl
;
815 if (MountCdrom(CDROM
) == false)
817 cout
<< "Failed to mount the cdrom." << endl
;
822 // Hash the CD to get an ID
823 cout
<< "Identifying.. " << flush
;
825 if (IdentCdrom(CDROM
,ID
) == false)
827 cout
<< '[' << ID
<< ']' << endl
;
829 cout
<< "Scanning Disc for index files.. " << flush
;
830 // Get the CD structure
832 string StartDir
= SafeGetCWD();
833 if (FindPackages(CDROM
,List
) == false)
835 chdir(StartDir
.c_str());
837 if (_config
->FindB("Debug::aptcdrom",false) == true)
839 cout
<< "I found:" << endl
;
840 for (vector
<string
>::iterator I
= List
.begin(); I
!= List
.end(); I
++)
847 DropBinaryArch(List
);
849 cout
<< "Found " << List
.size() << " package index files." << endl
;
851 if (List
.size() == 0)
852 return _error
->Error("Unable to locate any package files, perhaps this is not a Debian Disc");
854 // Check if the CD is in the database
856 if (Database
.Exists("CD::" + ID
) == false ||
857 _config
->FindB("APT::CDROM::Rename",false) == true)
859 // Try to use the CDs label if at all possible
860 if (FileExists(CDROM
+ "/.disk/info") == true)
862 ifstream
F(string(CDROM
+ "/.disk/info").c_str());
866 if (Name
.empty() == false)
868 cout
<< "Found label '" << Name
<< "'" << endl
;
869 Database
.Set("CD::" + ID
+ "::Label",Name
);
873 if (_config
->FindB("APT::CDROM::Rename",false) == true ||
874 Name
.empty() == true)
876 cout
<< "Please provide a name for this Disc, such as 'Debian 2.1r1 Disk 1'";
879 Name
= PromptLine("");
880 if (Name
.empty() == false &&
881 Name
.find('/') == string::npos
)
883 cout
<< "That is not a valid name, try again " << endl
;
889 Name
= Database
.Find("CD::" + ID
);
890 Database
.Set("CD::" + ID
,Name
);
891 cout
<< "This Disc is called '" << Name
<< "'" << endl
;
893 // Copy the package files to the state directory
894 if (CopyPackages(CDROM
,Name
,List
) == false)
897 ReduceSourcelist(CDROM
,List
);
899 // Write the database and sourcelist
900 if (_config
->FindB("APT::cdrom::NoAct",false) == false)
902 if (WriteDatabase(Database
) == false)
905 cout
<< "Writing new source list" << endl
;
906 if (WriteSourceList(Name
,List
) == false)
910 // Print the sourcelist entries
911 cout
<< "Source List entires for this Disc are:" << endl
;
912 for (vector
<string
>::iterator I
= List
.begin(); I
!= List
.end(); I
++)
914 string::size_type Space
= (*I
).find(' ');
915 if (Space
== string::npos
)
916 return _error
->Error("Internal error");
918 cout
<< "deb \"cdrom:" << Name
<< "/" << string(*I
,0,Space
) <<
919 "\" " << string(*I
,Space
+1) << endl
;
926 // ShowHelp - Show the help screen /*{{{*/
927 // ---------------------------------------------------------------------
931 cout
<< PACKAGE
<< ' ' << VERSION
<< " for " << ARCHITECTURE
<<
932 " compiled on " << __DATE__
<< " " << __TIME__
<< endl
;
934 cout
<< "Usage: apt-cdrom [options] command" << endl
;
936 cout
<< "apt-cdrom is a tool to add CDROM's to APT's source list. The " << endl
;
937 cout
<< "CDROM mount point and device information is taken from apt.conf" << endl
;
938 cout
<< "and /etc/fstab." << endl
;
940 cout
<< "Commands:" << endl
;
941 cout
<< " add - Add a CDROM" << endl
;
943 cout
<< "Options:" << endl
;
944 cout
<< " -h This help text" << endl
;
945 cout
<< " -d CD-ROM mount point" << endl
;
946 cout
<< " -r Rename a recognized CD-ROM" << endl
;
947 cout
<< " -m No mounting" << endl
;
948 cout
<< " -f Fast mode, don't check package files" << endl
;
949 cout
<< " -c=? Read this configuration file" << endl
;
950 cout
<< " -o=? Set an arbitary configuration option, ie -o dir::cache=/tmp" << endl
;
951 cout
<< "See fstab(5)" << endl
;
956 int main(int argc
,const char *argv
[])
958 CommandLine::Args Args
[] = {
959 {'h',"help","help",0},
960 {'d',"cdrom","Acquire::cdrom::mount",CommandLine::HasArg
},
961 {'r',"rename","APT::CDROM::Rename",0},
962 {'m',"no-mount","APT::CDROM::NoMount",0},
963 {'f',"fast","APT::CDROM::Fast",0},
964 {'n',"just-print","APT::CDROM::NoAct",0},
965 {'n',"recon","APT::CDROM::NoAct",0},
966 {'n',"no-act","APT::CDROM::NoAct",0},
967 {'c',"config-file",0,CommandLine::ConfigFile
},
968 {'o',"option",0,CommandLine::ArbItem
},
970 CommandLine::Dispatch Cmds
[] = {
974 // Parse the command line and initialize the package library
975 CommandLine
CmdL(Args
,_config
);
976 if (pkgInitialize(*_config
) == false ||
977 CmdL
.Parse(argc
,argv
) == false)
979 _error
->DumpErrors();
983 // See if the help should be shown
984 if (_config
->FindB("help") == true ||
985 CmdL
.FileSize() == 0)
988 // Match the operation
989 CmdL
.DispatchArg(Cmds
);
991 // Print any errors or warnings found during parsing
992 if (_error
->empty() == false)
994 bool Errors
= _error
->PendingError();
995 _error
->DumpErrors();
996 return Errors
== true?100:0;