]>
git.saurik.com Git - apt.git/blob - cmdline/apt-cdrom.cc
1 // -*- mode: cpp; mode: fold -*-
3 // $Id: apt-cdrom.cc,v 1.22 1999/04/07 06:00: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>
21 #include <apt-pkg/strutl.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
,string
&InfoDir
,
42 unsigned int Depth
= 0)
44 static ino_t Inodes
[9];
48 if (CD
[CD
.length()-1] != '/')
51 if (chdir(CD
.c_str()) != 0)
52 return _error
->Errno("chdir","Unable to change to %s",CD
.c_str());
54 /* Aha! We found some package files. We assume that everything under
55 this dir is controlled by those package files so we don't look down
58 if (stat("Packages",&Buf
) == 0)
62 // Continue down if thorough is given
63 if (_config
->FindB("APT::CDROM::Thorough",false) == false)
67 // Look for a .disk subdirectory
68 if (stat(".disk",&Buf
) == 0)
70 if (InfoDir
.empty() == true)
71 InfoDir
= CD
+ ".disk/";
74 DIR *D
= opendir(".");
76 return _error
->Errno("opendir","Unable to read %s",CD
.c_str());
78 // Run over the directory
79 for (struct dirent
*Dir
= readdir(D
); Dir
!= 0; Dir
= readdir(D
))
82 if (strcmp(Dir
->d_name
,".") == 0 ||
83 strcmp(Dir
->d_name
,"..") == 0 ||
84 strcmp(Dir
->d_name
,"source") == 0 ||
85 strcmp(Dir
->d_name
,"experimental") == 0 ||
86 strcmp(Dir
->d_name
,"binary-all") == 0)
89 // See if the name is a sub directory
91 if (stat(Dir
->d_name
,&Buf
) != 0)
94 if (S_ISDIR(Buf
.st_mode
) == 0)
98 for (I
= 0; I
!= Depth
; I
++)
99 if (Inodes
[I
] == Buf
.st_ino
)
104 // Store the inodes weve seen
105 Inodes
[Depth
] = Buf
.st_ino
;
108 if (FindPackages(CD
+ Dir
->d_name
,List
,InfoDir
,Depth
+1) == false)
111 if (chdir(CD
.c_str()) != 0)
112 return _error
->Errno("chdir","Unable to change to ",CD
.c_str());
117 return !_error
->PendingError();
120 // DropBinaryArch - Dump dirs with a string like /binary-<foo>/ /*{{{*/
121 // ---------------------------------------------------------------------
122 /* Here we drop everything that is not this machines arch */
123 bool DropBinaryArch(vector
<string
> &List
)
126 sprintf(S
,"/binary-%s/",_config
->Find("Apt::Architecture").c_str());
128 for (unsigned int I
= 0; I
< List
.size(); I
++)
130 const char *Str
= List
[I
].c_str();
133 if ((Res
= strstr(Str
,"/binary-")) == 0)
137 if (strlen(Res
) < strlen(S
))
139 List
.erase(List
.begin() + I
);
144 // See if it is our arch
145 if (stringcmp(Res
,Res
+ strlen(S
),S
) == 0)
149 List
.erase(List
.begin() + I
);
156 // Score - We compute a 'score' for a path /*{{{*/
157 // ---------------------------------------------------------------------
158 /* Paths are scored based on how close they come to what I consider
159 normal. That is ones that have 'dist' 'stable' 'frozen' will score
160 higher than ones without. */
161 int Score(string Path
)
164 if (Path
.find("stable/") != string::npos
)
166 if (Path
.find("/binary-") != string::npos
)
168 if (Path
.find("frozen/") != string::npos
)
170 if (Path
.find("/dists/") != string::npos
)
172 if (Path
.find("/main/") != string::npos
)
174 if (Path
.find("/contrib/") != string::npos
)
176 if (Path
.find("/non-free/") != string::npos
)
178 if (Path
.find("/non-US/") != string::npos
)
183 // DropRepeats - Drop repeated files resulting from symlinks /*{{{*/
184 // ---------------------------------------------------------------------
185 /* Here we go and stat every file that we found and strip dup inodes. */
186 bool DropRepeats(vector
<string
> &List
)
188 // Get a list of all the inodes
189 ino_t
*Inodes
= new ino_t
[List
.size()];
190 for (unsigned int I
= 0; I
!= List
.size(); I
++)
193 if (stat((List
[I
] + "Packages").c_str(),&Buf
) != 0)
194 _error
->Errno("stat","Failed to stat %sPackages",List
[I
].c_str());
195 Inodes
[I
] = Buf
.st_ino
;
198 if (_error
->PendingError() == true)
202 for (unsigned int I
= 0; I
!= List
.size(); I
++)
204 for (unsigned int J
= I
+1; J
< List
.size(); J
++)
207 if (Inodes
[J
] != Inodes
[I
])
210 // We score the two paths.. and erase one
211 int ScoreA
= Score(List
[I
]);
212 int ScoreB
= Score(List
[J
]);
223 // Wipe erased entries
224 for (unsigned int I
= 0; I
< List
.size();)
226 if (List
[I
].empty() == false)
229 List
.erase(List
.begin()+I
);
235 // ConvertToSourceList - Convert a Path to a sourcelist entry /*{{{*/
236 // ---------------------------------------------------------------------
237 /* We look for things in dists/ notation and convert them to
238 <dist> <component> form otherwise it is left alone. This also strips
240 void ConvertToSourceList(string CD
,string
&Path
)
243 sprintf(S
,"binary-%s",_config
->Find("Apt::Architecture").c_str());
245 // Strip the cdrom base path
246 Path
= string(Path
,CD
.length());
247 if (Path
.empty() == true)
250 // Too short to be a dists/ type
251 if (Path
.length() < strlen("dists/"))
255 if (stringcmp(Path
.begin(),Path
.begin()+strlen("dists/"),"dists/") != 0)
259 string::size_type Slash
= strlen("dists/");
260 string::size_type Slash2
= Path
.find('/',Slash
+ 1);
261 if (Slash2
== string::npos
|| Slash2
+ 2 >= Path
.length())
263 string Dist
= string(Path
,Slash
,Slash2
- Slash
);
265 // Isolate the component
266 Slash
= Path
.find('/',Slash2
+1);
267 if (Slash
== string::npos
|| Slash
+ 2 >= Path
.length())
269 string Comp
= string(Path
,Slash2
+1,Slash
- Slash2
-1);
271 // Verify the trailing binar - bit
272 Slash2
= Path
.find('/',Slash
+ 1);
273 if (Slash
== string::npos
)
275 string Binary
= string(Path
,Slash
+1,Slash2
- Slash
-1);
280 Path
= Dist
+ ' ' + Comp
;
283 // GrabFirst - Return the first Depth path components /*{{{*/
284 // ---------------------------------------------------------------------
286 bool GrabFirst(string Path
,string
&To
,unsigned int Depth
)
288 string::size_type I
= 0;
291 I
= Path
.find('/',I
+1);
294 while (I
!= string::npos
&& Depth
!= 0);
296 if (I
== string::npos
)
299 To
= string(Path
,0,I
+1);
303 // ChopDirs - Chop off the leading directory components /*{{{*/
304 // ---------------------------------------------------------------------
306 string
ChopDirs(string Path
,unsigned int Depth
)
308 string::size_type I
= 0;
311 I
= Path
.find('/',I
+1);
314 while (I
!= string::npos
&& Depth
!= 0);
316 if (I
== string::npos
)
319 return string(Path
,I
+1);
322 // ReconstructPrefix - Fix strange prefixing /*{{{*/
323 // ---------------------------------------------------------------------
324 /* This prepends dir components from the path to the package files to
325 the path to the deb until it is found */
326 bool ReconstructPrefix(string
&Prefix
,string OrigPath
,string CD
,
329 bool Debug
= _config
->FindB("Debug::aptcdrom",false);
330 unsigned int Depth
= 1;
331 string MyPrefix
= Prefix
;
335 if (stat(string(CD
+ MyPrefix
+ File
).c_str(),&Buf
) != 0)
338 cout
<< "Failed, " << CD
+ MyPrefix
+ File
<< endl
;
339 if (GrabFirst(OrigPath
,MyPrefix
,Depth
++) == true)
353 // ReconstructChop - Fixes bad source paths /*{{{*/
354 // ---------------------------------------------------------------------
355 /* This removes path components from the filename and prepends the location
356 of the package files until a file is found */
357 bool ReconstructChop(unsigned long &Chop
,string Dir
,string File
)
359 // Attempt to reconstruct the filename
360 unsigned long Depth
= 0;
364 if (stat(string(Dir
+ File
).c_str(),&Buf
) != 0)
366 File
= ChopDirs(File
,1);
368 if (File
.empty() == false)
382 // CopyPackages - Copy the package files from the CD /*{{{*/
383 // ---------------------------------------------------------------------
385 bool CopyPackages(string CDROM
,string Name
,vector
<string
> &List
)
387 OpTextProgress Progress
;
389 bool NoStat
= _config
->FindB("APT::CDROM::Fast",false);
390 bool Debug
= _config
->FindB("Debug::aptcdrom",false);
392 // Prepare the progress indicator
393 unsigned long TotalSize
= 0;
394 for (vector
<string
>::iterator I
= List
.begin(); I
!= List
.end(); I
++)
397 if (stat(string(*I
+ "Packages").c_str(),&Buf
) != 0)
398 return _error
->Errno("stat","Stat failed for %s",
399 string(*I
+ "Packages").c_str());
400 TotalSize
+= Buf
.st_size
;
403 unsigned long CurrentSize
= 0;
404 unsigned int NotFound
= 0;
405 unsigned int WrongSize
= 0;
406 unsigned int Packages
= 0;
407 for (vector
<string
>::iterator I
= List
.begin(); I
!= List
.end(); I
++)
409 string OrigPath
= string(*I
,CDROM
.length());
411 // Open the package file
412 FileFd
Pkg(*I
+ "Packages",FileFd::ReadOnly
);
413 pkgTagFile
Parser(Pkg
);
414 if (_error
->PendingError() == true)
417 // Open the output file
419 sprintf(S
,"cdrom:%s/%sPackages",Name
.c_str(),(*I
).c_str() + CDROM
.length());
420 string TargetF
= _config
->FindDir("Dir::State::lists") + "partial/";
421 TargetF
+= URItoFileName(S
);
422 if (_config
->FindB("APT::CDROM::NoAct",false) == true)
423 TargetF
= "/dev/null";
424 FileFd
Target(TargetF
,FileFd::WriteEmpty
);
425 if (_error
->PendingError() == true)
428 // Setup the progress meter
429 Progress
.OverallProgress(CurrentSize
,TotalSize
,Pkg
.Size(),
430 "Reading Package Lists");
433 Progress
.SubProgress(Pkg
.Size());
434 pkgTagSection Section
;
436 unsigned long Hits
= 0;
437 unsigned long Chop
= 0;
438 while (Parser
.Step(Section
) == true)
440 Progress
.Progress(Parser
.Offset());
442 string File
= Section
.FindS("Filename");
443 unsigned long Size
= Section
.FindI("Size");
444 if (File
.empty() || Size
== 0)
445 return _error
->Error("Cannot find filename or size tag");
448 File
= OrigPath
+ ChopDirs(File
,Chop
);
450 // See if the file exists
451 if (NoStat
== false || Hits
< 10)
453 // Attempt to fix broken structure
456 if (ReconstructPrefix(Prefix
,OrigPath
,CDROM
,File
) == false &&
457 ReconstructChop(Chop
,*I
,File
) == false)
463 File
= OrigPath
+ ChopDirs(File
,Chop
);
468 if (stat(string(CDROM
+ Prefix
+ File
).c_str(),&Buf
) != 0)
475 if ((unsigned)Buf
.st_size
!= Size
)
485 // Copy it to the target package file
490 // Mangle the output filename
491 const char *Filename
;
492 Section
.Find("Filename",Filename
,Stop
);
494 /* We need to rewrite the filename field so we emit
495 all fields except the filename file and rewrite that one */
496 for (unsigned int I
= 0; I
!= Section
.Count(); I
++)
498 Section
.Get(Start
,Stop
,I
);
499 if (Start
<= Filename
&& Stop
> Filename
)
502 sprintf(S
,"Filename: %s\n",File
.c_str());
503 if (I
+ 1 == Section
.Count())
505 if (Target
.Write(S
,strlen(S
)) == false)
509 if (Target
.Write(Start
,Stop
-Start
) == false)
512 if (Target
.Write("\n",1) == false)
517 Section
.GetSection(Start
,Stop
);
518 if (Target
.Write(Start
,Stop
-Start
) == false)
524 cout
<< " Processed by using Prefix '" << Prefix
<< "' and chop " << Chop
<< endl
;
526 if (_config
->FindB("APT::CDROM::NoAct",false) == false)
528 // Move out of the partial directory
530 string 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");
535 // Copy the release file
536 sprintf(S
,"cdrom:%s/%sRelease",Name
.c_str(),(*I
).c_str() + CDROM
.length());
537 string TargetF
= _config
->FindDir("Dir::State::lists") + "partial/";
538 TargetF
+= URItoFileName(S
);
539 if (FileExists(*I
+ "Release") == true)
541 FileFd
Target(TargetF
,FileFd::WriteEmpty
);
542 FileFd
Rel(*I
+ "Release",FileFd::ReadOnly
);
543 if (_error
->PendingError() == true)
546 if (CopyFile(Rel
,Target
) == false)
551 // Empty release file
552 FileFd
Target(TargetF
,FileFd::WriteEmpty
);
555 // Rename the release file
556 FinalF
= _config
->FindDir("Dir::State::lists");
557 FinalF
+= URItoFileName(S
);
558 if (rename(TargetF
.c_str(),FinalF
.c_str()) != 0)
559 return _error
->Errno("rename","Failed to rename");
562 /* Mangle the source to be in the proper notation with
563 prefix dist [component] */
564 *I
= string(*I
,Prefix
.length());
565 ConvertToSourceList(CDROM
,*I
);
566 *I
= Prefix
+ ' ' + *I
;
568 CurrentSize
+= Pkg
.Size();
573 cout
<< "Wrote " << Packages
<< " package records" ;
575 cout
<< " with " << NotFound
<< " missing files";
576 if (NotFound
!= 0 && WrongSize
!= 0)
579 cout
<< " with " << WrongSize
<< " mismatched files";
583 return _error
->Error("No valid package records were found.");
585 if (NotFound
+ WrongSize
> 10)
586 cout
<< "Alot of package entires were discarded, perhaps this CD is funny?" << endl
;
592 // ReduceSourceList - Takes the path list and reduces it /*{{{*/
593 // ---------------------------------------------------------------------
594 /* This takes the list of source list expressed entires and collects
595 similar ones to form a single entry for each dist */
596 bool ReduceSourcelist(string CD
,vector
<string
> &List
)
598 sort(List
.begin(),List
.end());
600 // Collect similar entries
601 for (vector
<string
>::iterator I
= List
.begin(); I
!= List
.end(); I
++)
604 string::size_type Space
= (*I
).find(' ');
605 if (Space
== string::npos
)
607 string::size_type SSpace
= (*I
).find(' ',Space
+ 1);
608 if (SSpace
== string::npos
)
611 string Word1
= string(*I
,Space
,SSpace
-Space
);
612 for (vector
<string
>::iterator J
= List
.begin(); J
!= I
; J
++)
615 string::size_type Space2
= (*J
).find(' ');
616 if (Space2
== string::npos
)
618 string::size_type SSpace2
= (*J
).find(' ',Space2
+ 1);
619 if (SSpace2
== string::npos
)
622 if (string(*J
,Space2
,SSpace2
-Space2
) != Word1
)
625 *J
+= string(*I
,SSpace
);
630 // Wipe erased entries
631 for (unsigned int I
= 0; I
< List
.size();)
633 if (List
[I
].empty() == false)
636 List
.erase(List
.begin()+I
);
640 // WriteDatabase - Write the CDROM Database file /*{{{*/
641 // ---------------------------------------------------------------------
642 /* We rewrite the configuration class associated with the cdrom database. */
643 bool WriteDatabase(Configuration
&Cnf
)
645 string DFile
= _config
->FindFile("Dir::State::cdroms");
646 string NewFile
= DFile
+ ".new";
648 unlink(NewFile
.c_str());
649 ofstream
Out(NewFile
.c_str());
651 return _error
->Errno("ofstream::ofstream",
652 "Failed to open %s.new",DFile
.c_str());
654 /* Write out all of the configuration directives by walking the
655 configuration tree */
656 const Configuration::Item
*Top
= Cnf
.Tree(0);
659 // Print the config entry
660 if (Top
->Value
.empty() == false)
661 Out
<< Top
->FullTag() + " \"" << Top
->Value
<< "\";" << endl
;
669 while (Top
!= 0 && Top
->Next
== 0)
677 rename(DFile
.c_str(),string(DFile
+ '~').c_str());
678 if (rename(NewFile
.c_str(),DFile
.c_str()) != 0)
679 return _error
->Errno("rename","Failed to rename %s.new to %s",
680 DFile
.c_str(),DFile
.c_str());
685 // WriteSourceList - Write an updated sourcelist /*{{{*/
686 // ---------------------------------------------------------------------
687 /* This reads the old source list and copies it into the new one. It
688 appends the new CDROM entires just after the first block of comments.
689 This places them first in the file. It also removes any old entries
690 that were the same. */
691 bool WriteSourceList(string Name
,vector
<string
> &List
)
693 string File
= _config
->FindFile("Dir::Etc::sourcelist");
695 // Open the stream for reading
696 ifstream
F(File
.c_str(),ios::in
| ios::nocreate
);
698 return _error
->Errno("ifstream::ifstream","Opening %s",File
.c_str());
700 string NewFile
= File
+ ".new";
701 unlink(NewFile
.c_str());
702 ofstream
Out(NewFile
.c_str());
704 return _error
->Errno("ofstream::ofstream",
705 "Failed to open %s.new",File
.c_str());
707 // Create a short uri without the path
708 string ShortURI
= "cdrom:" + Name
+ "/";
713 while (F
.eof() == false)
715 F
.getline(Buffer
,sizeof(Buffer
));
717 _strtabexpand(Buffer
,sizeof(Buffer
));
721 if (Buffer
[0] == '#' || Buffer
[0] == 0)
723 Out
<< Buffer
<< endl
;
729 for (vector
<string
>::iterator I
= List
.begin(); I
!= List
.end(); I
++)
731 string::size_type Space
= (*I
).find(' ');
732 if (Space
== string::npos
)
733 return _error
->Error("Internal error");
735 Out
<< "deb \"cdrom:" << Name
<< "/" << string(*I
,0,Space
) <<
736 "\" " << string(*I
,Space
+1) << endl
;
745 if (ParseQuoteWord(C
,Type
) == false ||
746 ParseQuoteWord(C
,URI
) == false)
748 Out
<< Buffer
<< endl
;
752 // Emit lines like this one
753 if (Type
!= "deb" || string(URI
,0,ShortURI
.length()) != ShortURI
)
755 Out
<< Buffer
<< endl
;
760 // Just in case the file was empty
763 for (vector
<string
>::iterator I
= List
.begin(); I
!= List
.end(); I
++)
765 string::size_type Space
= (*I
).find(' ');
766 if (Space
== string::npos
)
767 return _error
->Error("Internal error");
769 Out
<< "deb \"cdrom:" << Name
<< "/" << string(*I
,0,Space
) <<
770 "\" " << string(*I
,Space
+1) << endl
;
776 rename(File
.c_str(),string(File
+ '~').c_str());
777 if (rename(NewFile
.c_str(),File
.c_str()) != 0)
778 return _error
->Errno("rename","Failed to rename %s.new to %s",
779 File
.c_str(),File
.c_str());
785 // Prompt - Simple prompt /*{{{*/
786 // ---------------------------------------------------------------------
788 void Prompt(const char *Text
)
791 cout
<< Text
<< ' ' << flush
;
792 read(STDIN_FILENO
,&C
,1);
797 // PromptLine - Prompt for an input line /*{{{*/
798 // ---------------------------------------------------------------------
800 string
PromptLine(const char *Text
)
802 cout
<< Text
<< ':' << endl
;
810 // DoAdd - Add a new CDROM /*{{{*/
811 // ---------------------------------------------------------------------
812 /* This does the main add bit.. We show some status and things. The
813 sequence is to mount/umount the CD, Ident it then scan it for package
814 files and reduce that list. Then we copy over the package files and
815 verify them. Then rewrite the database files */
816 bool DoAdd(CommandLine
&)
819 string CDROM
= _config
->FindDir("Acquire::cdrom::mount","/cdrom/");
821 CDROM
= SafeGetCWD() + '/' + CDROM
;
823 cout
<< "Using CD-ROM mount point " << CDROM
<< endl
;
826 Configuration Database
;
827 string DFile
= _config
->FindFile("Dir::State::cdroms");
828 if (FileExists(DFile
) == true)
830 if (ReadConfigFile(Database
,DFile
) == false)
831 return _error
->Error("Unable to read the cdrom database %s",
835 // Unmount the CD and get the user to put in the one they want
836 if (_config
->FindB("APT::CDROM::NoMount",false) == false)
838 cout
<< "Unmounting CD-ROM" << endl
;
841 // Mount the new CDROM
842 Prompt("Please insert a Disc in the drive and press enter");
843 cout
<< "Mounting CD-ROM" << endl
;
844 if (MountCdrom(CDROM
) == false)
845 return _error
->Error("Failed to mount the cdrom.");
848 // Hash the CD to get an ID
849 cout
<< "Identifying.. " << flush
;
851 if (IdentCdrom(CDROM
,ID
) == false)
857 cout
<< '[' << ID
<< ']' << endl
;
859 cout
<< "Scanning Disc for index files.. " << flush
;
860 // Get the CD structure
862 string StartDir
= SafeGetCWD();
864 if (FindPackages(CDROM
,List
,InfoDir
) == false)
870 chdir(StartDir
.c_str());
872 if (_config
->FindB("Debug::aptcdrom",false) == true)
874 cout
<< "I found:" << endl
;
875 for (vector
<string
>::iterator I
= List
.begin(); I
!= List
.end(); I
++)
882 DropBinaryArch(List
);
884 cout
<< "Found " << List
.size() << " package index files." << endl
;
886 if (List
.size() == 0)
887 return _error
->Error("Unable to locate any package files, perhaps this is not a Debian Disc");
889 // Check if the CD is in the database
891 if (Database
.Exists("CD::" + ID
) == false ||
892 _config
->FindB("APT::CDROM::Rename",false) == true)
894 // Try to use the CDs label if at all possible
895 if (InfoDir
.empty() == false &&
896 FileExists(InfoDir
+ "/info") == true)
898 ifstream
F(string(InfoDir
+ "/info").c_str());
902 if (Name
.empty() == false)
904 cout
<< "Found label '" << Name
<< "'" << endl
;
905 Database
.Set("CD::" + ID
+ "::Label",Name
);
909 if (_config
->FindB("APT::CDROM::Rename",false) == true ||
910 Name
.empty() == true)
912 cout
<< "Please provide a name for this Disc, such as 'Debian 2.1r1 Disk 1'";
915 Name
= PromptLine("");
916 if (Name
.empty() == false &&
917 Name
.find('"') == string::npos
&&
918 Name
.find(':') == string::npos
&&
919 Name
.find('/') == string::npos
)
921 cout
<< "That is not a valid name, try again " << endl
;
926 Name
= Database
.Find("CD::" + ID
);
928 string::iterator J
= Name
.begin();
929 for (; J
!= Name
.end(); J
++)
930 if (*J
== '/' || *J
== '"' || *J
== ':')
933 Database
.Set("CD::" + ID
,Name
);
934 cout
<< "This Disc is called '" << Name
<< "'" << endl
;
936 // Copy the package files to the state directory
937 if (CopyPackages(CDROM
,Name
,List
) == false)
940 ReduceSourcelist(CDROM
,List
);
942 // Write the database and sourcelist
943 if (_config
->FindB("APT::cdrom::NoAct",false) == false)
945 if (WriteDatabase(Database
) == false)
948 cout
<< "Writing new source list" << endl
;
949 if (WriteSourceList(Name
,List
) == false)
953 // Print the sourcelist entries
954 cout
<< "Source List entries for this Disc are:" << endl
;
955 for (vector
<string
>::iterator I
= List
.begin(); I
!= List
.end(); I
++)
957 string::size_type Space
= (*I
).find(' ');
958 if (Space
== string::npos
)
959 return _error
->Error("Internal error");
961 cout
<< "deb \"cdrom:" << Name
<< "/" << string(*I
,0,Space
) <<
962 "\" " << string(*I
,Space
+1) << endl
;
969 // ShowHelp - Show the help screen /*{{{*/
970 // ---------------------------------------------------------------------
974 cout
<< PACKAGE
<< ' ' << VERSION
<< " for " << ARCHITECTURE
<<
975 " compiled on " << __DATE__
<< " " << __TIME__
<< endl
;
976 if (_config
->FindB("version") == true)
979 cout
<< "Usage: apt-cdrom [options] command" << endl
;
981 cout
<< "apt-cdrom is a tool to add CDROM's to APT's source list. The " << endl
;
982 cout
<< "CDROM mount point and device information is taken from apt.conf" << endl
;
983 cout
<< "and /etc/fstab." << endl
;
985 cout
<< "Commands:" << endl
;
986 cout
<< " add - Add a CDROM" << endl
;
988 cout
<< "Options:" << endl
;
989 cout
<< " -h This help text" << endl
;
990 cout
<< " -d CD-ROM mount point" << endl
;
991 cout
<< " -r Rename a recognized CD-ROM" << endl
;
992 cout
<< " -m No mounting" << endl
;
993 cout
<< " -f Fast mode, don't check package files" << endl
;
994 cout
<< " -a Thorough scan mode" << endl
;
995 cout
<< " -c=? Read this configuration file" << endl
;
996 cout
<< " -o=? Set an arbitary configuration option, eg -o dir::cache=/tmp" << endl
;
997 cout
<< "See fstab(5)" << endl
;
1002 int main(int argc
,const char *argv
[])
1004 CommandLine::Args Args
[] = {
1005 {'h',"help","help",0},
1006 {'v',"version","version",0},
1007 {'d',"cdrom","Acquire::cdrom::mount",CommandLine::HasArg
},
1008 {'r',"rename","APT::CDROM::Rename",0},
1009 {'m',"no-mount","APT::CDROM::NoMount",0},
1010 {'f',"fast","APT::CDROM::Fast",0},
1011 {'n',"just-print","APT::CDROM::NoAct",0},
1012 {'n',"recon","APT::CDROM::NoAct",0},
1013 {'n',"no-act","APT::CDROM::NoAct",0},
1014 {'a',"thorough","APT::CDROM::Thorough",0},
1015 {'c',"config-file",0,CommandLine::ConfigFile
},
1016 {'o',"option",0,CommandLine::ArbItem
},
1018 CommandLine::Dispatch Cmds
[] = {
1022 // Parse the command line and initialize the package library
1023 CommandLine
CmdL(Args
,_config
);
1024 if (pkgInitialize(*_config
) == false ||
1025 CmdL
.Parse(argc
,argv
) == false)
1027 _error
->DumpErrors();
1031 // See if the help should be shown
1032 if (_config
->FindB("help") == true ||
1033 CmdL
.FileSize() == 0)
1036 // Deal with stdout not being a tty
1037 if (ttyname(STDOUT_FILENO
) == 0 && _config
->FindI("quiet",0) < 1)
1038 _config
->Set("quiet","1");
1040 // Match the operation
1041 CmdL
.DispatchArg(Cmds
);
1043 // Print any errors or warnings found during parsing
1044 if (_error
->empty() == false)
1046 bool Errors
= _error
->PendingError();
1047 _error
->DumpErrors();
1048 return Errors
== true?100:0;