]>
git.saurik.com Git - apt.git/blob - cmdline/apt-cdrom.cc
1 // -*- mode: cpp; mode: fold -*-
3 // $Id: apt-cdrom.cc,v 1.25 1999/05/29 21:49:58 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 // Look for a .disk subdirectory
56 if (stat(".disk",&Buf
) == 0)
58 if (InfoDir
.empty() == true)
59 InfoDir
= CD
+ ".disk/";
62 /* Aha! We found some package files. We assume that everything under
63 this dir is controlled by those package files so we don't look down
65 if (stat("Packages",&Buf
) == 0)
69 // Continue down if thorough is given
70 if (_config
->FindB("APT::CDROM::Thorough",false) == false)
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 bool Mangled
= false;
452 if (NoStat
== false || Hits
< 10)
454 // Attempt to fix broken structure
457 if (ReconstructPrefix(Prefix
,OrigPath
,CDROM
,File
) == false &&
458 ReconstructChop(Chop
,*I
,File
) == false)
461 clog
<< "Missed: " << File
<< endl
;
466 File
= OrigPath
+ ChopDirs(File
,Chop
);
471 if (stat(string(CDROM
+ Prefix
+ File
).c_str(),&Buf
) != 0 ||
474 // Attempt to fix busted symlink support for one instance
475 string OrigFile
= File
;
476 string::size_type Start
= File
.find("binary-");
477 string::size_type End
= File
.find("/",Start
+3);
478 if (Start
!= string::npos
&& End
!= string::npos
)
480 File
.replace(Start
,End
-Start
,"binary-all");
484 if (Mangled
== false ||
485 stat(string(CDROM
+ Prefix
+ File
).c_str(),&Buf
) != 0)
488 clog
<< "Missed(2): " << OrigFile
<< endl
;
495 if ((unsigned)Buf
.st_size
!= Size
)
498 clog
<< "Wrong Size: " << File
<< endl
;
507 // Copy it to the target package file
510 if (Chop
!= 0 || Mangled
== true)
512 // Mangle the output filename
513 const char *Filename
;
514 Section
.Find("Filename",Filename
,Stop
);
516 /* We need to rewrite the filename field so we emit
517 all fields except the filename file and rewrite that one */
518 for (unsigned int I
= 0; I
!= Section
.Count(); I
++)
520 Section
.Get(Start
,Stop
,I
);
521 if (Start
<= Filename
&& Stop
> Filename
)
524 sprintf(S
,"Filename: %s\n",File
.c_str());
525 if (I
+ 1 == Section
.Count())
527 if (Target
.Write(S
,strlen(S
)) == false)
532 if (Target
.Write(Start
,Stop
-Start
) == false)
534 if (Stop
[-1] != '\n')
535 if (Target
.Write("\n",1) == false)
539 if (Target
.Write("\n",1) == false)
544 Section
.GetSection(Start
,Stop
);
545 if (Target
.Write(Start
,Stop
-Start
) == false)
551 cout
<< " Processed by using Prefix '" << Prefix
<< "' and chop " << Chop
<< endl
;
553 if (_config
->FindB("APT::CDROM::NoAct",false) == false)
555 // Move out of the partial directory
557 string FinalF
= _config
->FindDir("Dir::State::lists");
558 FinalF
+= URItoFileName(S
);
559 if (rename(TargetF
.c_str(),FinalF
.c_str()) != 0)
560 return _error
->Errno("rename","Failed to rename");
562 // Copy the release file
563 sprintf(S
,"cdrom:%s/%sRelease",Name
.c_str(),(*I
).c_str() + CDROM
.length());
564 string TargetF
= _config
->FindDir("Dir::State::lists") + "partial/";
565 TargetF
+= URItoFileName(S
);
566 if (FileExists(*I
+ "Release") == true)
568 FileFd
Target(TargetF
,FileFd::WriteEmpty
);
569 FileFd
Rel(*I
+ "Release",FileFd::ReadOnly
);
570 if (_error
->PendingError() == true)
573 if (CopyFile(Rel
,Target
) == false)
578 // Empty release file
579 FileFd
Target(TargetF
,FileFd::WriteEmpty
);
582 // Rename the release file
583 FinalF
= _config
->FindDir("Dir::State::lists");
584 FinalF
+= URItoFileName(S
);
585 if (rename(TargetF
.c_str(),FinalF
.c_str()) != 0)
586 return _error
->Errno("rename","Failed to rename");
589 /* Mangle the source to be in the proper notation with
590 prefix dist [component] */
591 *I
= string(*I
,Prefix
.length());
592 ConvertToSourceList(CDROM
,*I
);
593 *I
= Prefix
+ ' ' + *I
;
595 CurrentSize
+= Pkg
.Size();
600 cout
<< "Wrote " << Packages
<< " package records" ;
602 cout
<< " with " << NotFound
<< " missing files";
603 if (NotFound
!= 0 && WrongSize
!= 0)
606 cout
<< " with " << WrongSize
<< " mismatched files";
610 return _error
->Error("No valid package records were found.");
612 if (NotFound
+ WrongSize
> 10)
613 cout
<< "Alot of package entries were discarded, perhaps this CD is funny?" << endl
;
619 // ReduceSourceList - Takes the path list and reduces it /*{{{*/
620 // ---------------------------------------------------------------------
621 /* This takes the list of source list expressed entires and collects
622 similar ones to form a single entry for each dist */
623 bool ReduceSourcelist(string CD
,vector
<string
> &List
)
625 sort(List
.begin(),List
.end());
627 // Collect similar entries
628 for (vector
<string
>::iterator I
= List
.begin(); I
!= List
.end(); I
++)
631 string::size_type Space
= (*I
).find(' ');
632 if (Space
== string::npos
)
634 string::size_type SSpace
= (*I
).find(' ',Space
+ 1);
635 if (SSpace
== string::npos
)
638 string Word1
= string(*I
,Space
,SSpace
-Space
);
639 for (vector
<string
>::iterator J
= List
.begin(); J
!= I
; J
++)
642 string::size_type Space2
= (*J
).find(' ');
643 if (Space2
== string::npos
)
645 string::size_type SSpace2
= (*J
).find(' ',Space2
+ 1);
646 if (SSpace2
== string::npos
)
649 if (string(*J
,Space2
,SSpace2
-Space2
) != Word1
)
652 *J
+= string(*I
,SSpace
);
657 // Wipe erased entries
658 for (unsigned int I
= 0; I
< List
.size();)
660 if (List
[I
].empty() == false)
663 List
.erase(List
.begin()+I
);
667 // WriteDatabase - Write the CDROM Database file /*{{{*/
668 // ---------------------------------------------------------------------
669 /* We rewrite the configuration class associated with the cdrom database. */
670 bool WriteDatabase(Configuration
&Cnf
)
672 string DFile
= _config
->FindFile("Dir::State::cdroms");
673 string NewFile
= DFile
+ ".new";
675 unlink(NewFile
.c_str());
676 ofstream
Out(NewFile
.c_str());
678 return _error
->Errno("ofstream::ofstream",
679 "Failed to open %s.new",DFile
.c_str());
681 /* Write out all of the configuration directives by walking the
682 configuration tree */
683 const Configuration::Item
*Top
= Cnf
.Tree(0);
686 // Print the config entry
687 if (Top
->Value
.empty() == false)
688 Out
<< Top
->FullTag() + " \"" << Top
->Value
<< "\";" << endl
;
696 while (Top
!= 0 && Top
->Next
== 0)
704 rename(DFile
.c_str(),string(DFile
+ '~').c_str());
705 if (rename(NewFile
.c_str(),DFile
.c_str()) != 0)
706 return _error
->Errno("rename","Failed to rename %s.new to %s",
707 DFile
.c_str(),DFile
.c_str());
712 // WriteSourceList - Write an updated sourcelist /*{{{*/
713 // ---------------------------------------------------------------------
714 /* This reads the old source list and copies it into the new one. It
715 appends the new CDROM entires just after the first block of comments.
716 This places them first in the file. It also removes any old entries
717 that were the same. */
718 bool WriteSourceList(string Name
,vector
<string
> &List
)
720 string File
= _config
->FindFile("Dir::Etc::sourcelist");
722 // Open the stream for reading
723 ifstream
F(File
.c_str(),ios::in
| ios::nocreate
);
725 return _error
->Errno("ifstream::ifstream","Opening %s",File
.c_str());
727 string NewFile
= File
+ ".new";
728 unlink(NewFile
.c_str());
729 ofstream
Out(NewFile
.c_str());
731 return _error
->Errno("ofstream::ofstream",
732 "Failed to open %s.new",File
.c_str());
734 // Create a short uri without the path
735 string ShortURI
= "cdrom:" + Name
+ "/";
740 while (F
.eof() == false)
742 F
.getline(Buffer
,sizeof(Buffer
));
744 _strtabexpand(Buffer
,sizeof(Buffer
));
748 if (Buffer
[0] == '#' || Buffer
[0] == 0)
750 Out
<< Buffer
<< endl
;
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
;
772 if (ParseQuoteWord(C
,Type
) == false ||
773 ParseQuoteWord(C
,URI
) == false)
775 Out
<< Buffer
<< endl
;
779 // Emit lines like this one
780 if (Type
!= "deb" || string(URI
,0,ShortURI
.length()) != ShortURI
)
782 Out
<< Buffer
<< endl
;
787 // Just in case the file was empty
790 for (vector
<string
>::iterator I
= List
.begin(); I
!= List
.end(); I
++)
792 string::size_type Space
= (*I
).find(' ');
793 if (Space
== string::npos
)
794 return _error
->Error("Internal error");
796 Out
<< "deb \"cdrom:" << Name
<< "/" << string(*I
,0,Space
) <<
797 "\" " << string(*I
,Space
+1) << endl
;
803 rename(File
.c_str(),string(File
+ '~').c_str());
804 if (rename(NewFile
.c_str(),File
.c_str()) != 0)
805 return _error
->Errno("rename","Failed to rename %s.new to %s",
806 File
.c_str(),File
.c_str());
812 // Prompt - Simple prompt /*{{{*/
813 // ---------------------------------------------------------------------
815 void Prompt(const char *Text
)
818 cout
<< Text
<< ' ' << flush
;
819 read(STDIN_FILENO
,&C
,1);
824 // PromptLine - Prompt for an input line /*{{{*/
825 // ---------------------------------------------------------------------
827 string
PromptLine(const char *Text
)
829 cout
<< Text
<< ':' << endl
;
837 // DoAdd - Add a new CDROM /*{{{*/
838 // ---------------------------------------------------------------------
839 /* This does the main add bit.. We show some status and things. The
840 sequence is to mount/umount the CD, Ident it then scan it for package
841 files and reduce that list. Then we copy over the package files and
842 verify them. Then rewrite the database files */
843 bool DoAdd(CommandLine
&)
846 string CDROM
= _config
->FindDir("Acquire::cdrom::mount","/cdrom/");
848 CDROM
= SafeGetCWD() + '/' + CDROM
;
850 cout
<< "Using CD-ROM mount point " << CDROM
<< endl
;
853 Configuration Database
;
854 string DFile
= _config
->FindFile("Dir::State::cdroms");
855 if (FileExists(DFile
) == true)
857 if (ReadConfigFile(Database
,DFile
) == false)
858 return _error
->Error("Unable to read the cdrom database %s",
862 // Unmount the CD and get the user to put in the one they want
863 if (_config
->FindB("APT::CDROM::NoMount",false) == false)
865 cout
<< "Unmounting CD-ROM" << endl
;
868 // Mount the new CDROM
869 Prompt("Please insert a Disc in the drive and press enter");
870 cout
<< "Mounting CD-ROM" << endl
;
871 if (MountCdrom(CDROM
) == false)
872 return _error
->Error("Failed to mount the cdrom.");
875 // Hash the CD to get an ID
876 cout
<< "Identifying.. " << flush
;
878 if (IdentCdrom(CDROM
,ID
) == false)
884 cout
<< '[' << ID
<< ']' << endl
;
886 cout
<< "Scanning Disc for index files.. " << flush
;
887 // Get the CD structure
889 string StartDir
= SafeGetCWD();
891 if (FindPackages(CDROM
,List
,InfoDir
) == false)
897 chdir(StartDir
.c_str());
899 if (_config
->FindB("Debug::aptcdrom",false) == true)
901 cout
<< "I found:" << endl
;
902 for (vector
<string
>::iterator I
= List
.begin(); I
!= List
.end(); I
++)
909 DropBinaryArch(List
);
911 cout
<< "Found " << List
.size() << " package index files." << endl
;
913 if (List
.size() == 0)
914 return _error
->Error("Unable to locate any package files, perhaps this is not a Debian Disc");
916 // Check if the CD is in the database
918 if (Database
.Exists("CD::" + ID
) == false ||
919 _config
->FindB("APT::CDROM::Rename",false) == true)
921 // Try to use the CDs label if at all possible
922 if (InfoDir
.empty() == false &&
923 FileExists(InfoDir
+ "/info") == true)
925 ifstream
F(string(InfoDir
+ "/info").c_str());
929 if (Name
.empty() == false)
931 cout
<< "Found label '" << Name
<< "'" << endl
;
932 Database
.Set("CD::" + ID
+ "::Label",Name
);
936 if (_config
->FindB("APT::CDROM::Rename",false) == true ||
937 Name
.empty() == true)
939 cout
<< "Please provide a name for this Disc, such as 'Debian 2.1r1 Disk 1'";
942 Name
= PromptLine("");
943 if (Name
.empty() == false &&
944 Name
.find('"') == string::npos
&&
945 Name
.find(':') == string::npos
&&
946 Name
.find('/') == string::npos
)
948 cout
<< "That is not a valid name, try again " << endl
;
953 Name
= Database
.Find("CD::" + ID
);
955 string::iterator J
= Name
.begin();
956 for (; J
!= Name
.end(); J
++)
957 if (*J
== '/' || *J
== '"' || *J
== ':')
960 Database
.Set("CD::" + ID
,Name
);
961 cout
<< "This Disc is called '" << Name
<< "'" << endl
;
963 // Copy the package files to the state directory
964 if (CopyPackages(CDROM
,Name
,List
) == false)
967 ReduceSourcelist(CDROM
,List
);
969 // Write the database and sourcelist
970 if (_config
->FindB("APT::cdrom::NoAct",false) == false)
972 if (WriteDatabase(Database
) == false)
975 cout
<< "Writing new source list" << endl
;
976 if (WriteSourceList(Name
,List
) == false)
980 // Print the sourcelist entries
981 cout
<< "Source List entries for this Disc are:" << endl
;
982 for (vector
<string
>::iterator I
= List
.begin(); I
!= List
.end(); I
++)
984 string::size_type Space
= (*I
).find(' ');
985 if (Space
== string::npos
)
986 return _error
->Error("Internal error");
988 cout
<< "deb \"cdrom:" << Name
<< "/" << string(*I
,0,Space
) <<
989 "\" " << string(*I
,Space
+1) << endl
;
996 // ShowHelp - Show the help screen /*{{{*/
997 // ---------------------------------------------------------------------
1001 cout
<< PACKAGE
<< ' ' << VERSION
<< " for " << ARCHITECTURE
<<
1002 " compiled on " << __DATE__
<< " " << __TIME__
<< endl
;
1003 if (_config
->FindB("version") == true)
1006 cout
<< "Usage: apt-cdrom [options] command" << endl
;
1008 cout
<< "apt-cdrom is a tool to add CDROM's to APT's source list. The " << endl
;
1009 cout
<< "CDROM mount point and device information is taken from apt.conf" << endl
;
1010 cout
<< "and /etc/fstab." << endl
;
1012 cout
<< "Commands:" << endl
;
1013 cout
<< " add - Add a CDROM" << endl
;
1015 cout
<< "Options:" << endl
;
1016 cout
<< " -h This help text" << endl
;
1017 cout
<< " -d CD-ROM mount point" << endl
;
1018 cout
<< " -r Rename a recognized CD-ROM" << endl
;
1019 cout
<< " -m No mounting" << endl
;
1020 cout
<< " -f Fast mode, don't check package files" << endl
;
1021 cout
<< " -a Thorough scan mode" << endl
;
1022 cout
<< " -c=? Read this configuration file" << endl
;
1023 cout
<< " -o=? Set an arbitary configuration option, eg -o dir::cache=/tmp" << endl
;
1024 cout
<< "See fstab(5)" << endl
;
1029 int main(int argc
,const char *argv
[])
1031 CommandLine::Args Args
[] = {
1032 {'h',"help","help",0},
1033 {'v',"version","version",0},
1034 {'d',"cdrom","Acquire::cdrom::mount",CommandLine::HasArg
},
1035 {'r',"rename","APT::CDROM::Rename",0},
1036 {'m',"no-mount","APT::CDROM::NoMount",0},
1037 {'f',"fast","APT::CDROM::Fast",0},
1038 {'n',"just-print","APT::CDROM::NoAct",0},
1039 {'n',"recon","APT::CDROM::NoAct",0},
1040 {'n',"no-act","APT::CDROM::NoAct",0},
1041 {'a',"thorough","APT::CDROM::Thorough",0},
1042 {'c',"config-file",0,CommandLine::ConfigFile
},
1043 {'o',"option",0,CommandLine::ArbItem
},
1045 CommandLine::Dispatch Cmds
[] = {
1049 // Parse the command line and initialize the package library
1050 CommandLine
CmdL(Args
,_config
);
1051 if (pkgInitialize(*_config
) == false ||
1052 CmdL
.Parse(argc
,argv
) == false)
1054 _error
->DumpErrors();
1058 // See if the help should be shown
1059 if (_config
->FindB("help") == true ||
1060 CmdL
.FileSize() == 0)
1063 // Deal with stdout not being a tty
1064 if (ttyname(STDOUT_FILENO
) == 0 && _config
->FindI("quiet",0) < 1)
1065 _config
->Set("quiet","1");
1067 // Match the operation
1068 CmdL
.DispatchArg(Cmds
);
1070 // Print any errors or warnings found during parsing
1071 if (_error
->empty() == false)
1073 bool Errors
= _error
->PendingError();
1074 _error
->DumpErrors();
1075 return Errors
== true?100:0;