]>
git.saurik.com Git - apt.git/blob - cmdline/apt-cdrom.cc
49c7909dc9c9591b39ba27fba2c38d7d96a1f580
1 // -*- mode: cpp; mode: fold -*-
3 // $Id: apt-cdrom.cc,v 1.24 1999/05/29 04:59:52 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)
473 // Attempt to fix busted symlink support for one instance
474 string OrigFile
= File
;
475 string::size_type Start
= File
.find("binary-");
476 string::size_type End
= File
.find("/",Start
+3);
477 if (Start
!= string::npos
&& End
!= string::npos
)
479 File
.replace(Start
,End
-Start
,"binary-all");
483 if (Mangled
== false ||
484 stat(string(CDROM
+ Prefix
+ File
).c_str(),&Buf
) != 0)
487 clog
<< "Missed(2): " << OrigFile
<< endl
;
494 if ((unsigned)Buf
.st_size
!= Size
)
497 clog
<< "Wrong Size: " << File
<< endl
;
506 // Copy it to the target package file
509 if (Chop
!= 0 || Mangled
== true)
511 // Mangle the output filename
512 const char *Filename
;
513 Section
.Find("Filename",Filename
,Stop
);
515 /* We need to rewrite the filename field so we emit
516 all fields except the filename file and rewrite that one */
517 for (unsigned int I
= 0; I
!= Section
.Count(); I
++)
519 Section
.Get(Start
,Stop
,I
);
520 if (Start
<= Filename
&& Stop
> Filename
)
523 sprintf(S
,"Filename: %s\n",File
.c_str());
524 if (I
+ 1 == Section
.Count())
526 if (Target
.Write(S
,strlen(S
)) == false)
531 if (Target
.Write(Start
,Stop
-Start
) == false)
533 if (Stop
[-1] != '\n')
534 if (Target
.Write("\n",1) == false)
538 if (Target
.Write("\n",1) == false)
543 Section
.GetSection(Start
,Stop
);
544 if (Target
.Write(Start
,Stop
-Start
) == false)
550 cout
<< " Processed by using Prefix '" << Prefix
<< "' and chop " << Chop
<< endl
;
552 if (_config
->FindB("APT::CDROM::NoAct",false) == false)
554 // Move out of the partial directory
556 string 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");
561 // Copy the release file
562 sprintf(S
,"cdrom:%s/%sRelease",Name
.c_str(),(*I
).c_str() + CDROM
.length());
563 string TargetF
= _config
->FindDir("Dir::State::lists") + "partial/";
564 TargetF
+= URItoFileName(S
);
565 if (FileExists(*I
+ "Release") == true)
567 FileFd
Target(TargetF
,FileFd::WriteEmpty
);
568 FileFd
Rel(*I
+ "Release",FileFd::ReadOnly
);
569 if (_error
->PendingError() == true)
572 if (CopyFile(Rel
,Target
) == false)
577 // Empty release file
578 FileFd
Target(TargetF
,FileFd::WriteEmpty
);
581 // Rename the release file
582 FinalF
= _config
->FindDir("Dir::State::lists");
583 FinalF
+= URItoFileName(S
);
584 if (rename(TargetF
.c_str(),FinalF
.c_str()) != 0)
585 return _error
->Errno("rename","Failed to rename");
588 /* Mangle the source to be in the proper notation with
589 prefix dist [component] */
590 *I
= string(*I
,Prefix
.length());
591 ConvertToSourceList(CDROM
,*I
);
592 *I
= Prefix
+ ' ' + *I
;
594 CurrentSize
+= Pkg
.Size();
599 cout
<< "Wrote " << Packages
<< " package records" ;
601 cout
<< " with " << NotFound
<< " missing files";
602 if (NotFound
!= 0 && WrongSize
!= 0)
605 cout
<< " with " << WrongSize
<< " mismatched files";
609 return _error
->Error("No valid package records were found.");
611 if (NotFound
+ WrongSize
> 10)
612 cout
<< "Alot of package entries were discarded, perhaps this CD is funny?" << endl
;
618 // ReduceSourceList - Takes the path list and reduces it /*{{{*/
619 // ---------------------------------------------------------------------
620 /* This takes the list of source list expressed entires and collects
621 similar ones to form a single entry for each dist */
622 bool ReduceSourcelist(string CD
,vector
<string
> &List
)
624 sort(List
.begin(),List
.end());
626 // Collect similar entries
627 for (vector
<string
>::iterator I
= List
.begin(); I
!= List
.end(); I
++)
630 string::size_type Space
= (*I
).find(' ');
631 if (Space
== string::npos
)
633 string::size_type SSpace
= (*I
).find(' ',Space
+ 1);
634 if (SSpace
== string::npos
)
637 string Word1
= string(*I
,Space
,SSpace
-Space
);
638 for (vector
<string
>::iterator J
= List
.begin(); J
!= I
; J
++)
641 string::size_type Space2
= (*J
).find(' ');
642 if (Space2
== string::npos
)
644 string::size_type SSpace2
= (*J
).find(' ',Space2
+ 1);
645 if (SSpace2
== string::npos
)
648 if (string(*J
,Space2
,SSpace2
-Space2
) != Word1
)
651 *J
+= string(*I
,SSpace
);
656 // Wipe erased entries
657 for (unsigned int I
= 0; I
< List
.size();)
659 if (List
[I
].empty() == false)
662 List
.erase(List
.begin()+I
);
666 // WriteDatabase - Write the CDROM Database file /*{{{*/
667 // ---------------------------------------------------------------------
668 /* We rewrite the configuration class associated with the cdrom database. */
669 bool WriteDatabase(Configuration
&Cnf
)
671 string DFile
= _config
->FindFile("Dir::State::cdroms");
672 string NewFile
= DFile
+ ".new";
674 unlink(NewFile
.c_str());
675 ofstream
Out(NewFile
.c_str());
677 return _error
->Errno("ofstream::ofstream",
678 "Failed to open %s.new",DFile
.c_str());
680 /* Write out all of the configuration directives by walking the
681 configuration tree */
682 const Configuration::Item
*Top
= Cnf
.Tree(0);
685 // Print the config entry
686 if (Top
->Value
.empty() == false)
687 Out
<< Top
->FullTag() + " \"" << Top
->Value
<< "\";" << endl
;
695 while (Top
!= 0 && Top
->Next
== 0)
703 rename(DFile
.c_str(),string(DFile
+ '~').c_str());
704 if (rename(NewFile
.c_str(),DFile
.c_str()) != 0)
705 return _error
->Errno("rename","Failed to rename %s.new to %s",
706 DFile
.c_str(),DFile
.c_str());
711 // WriteSourceList - Write an updated sourcelist /*{{{*/
712 // ---------------------------------------------------------------------
713 /* This reads the old source list and copies it into the new one. It
714 appends the new CDROM entires just after the first block of comments.
715 This places them first in the file. It also removes any old entries
716 that were the same. */
717 bool WriteSourceList(string Name
,vector
<string
> &List
)
719 string File
= _config
->FindFile("Dir::Etc::sourcelist");
721 // Open the stream for reading
722 ifstream
F(File
.c_str(),ios::in
| ios::nocreate
);
724 return _error
->Errno("ifstream::ifstream","Opening %s",File
.c_str());
726 string NewFile
= File
+ ".new";
727 unlink(NewFile
.c_str());
728 ofstream
Out(NewFile
.c_str());
730 return _error
->Errno("ofstream::ofstream",
731 "Failed to open %s.new",File
.c_str());
733 // Create a short uri without the path
734 string ShortURI
= "cdrom:" + Name
+ "/";
739 while (F
.eof() == false)
741 F
.getline(Buffer
,sizeof(Buffer
));
743 _strtabexpand(Buffer
,sizeof(Buffer
));
747 if (Buffer
[0] == '#' || Buffer
[0] == 0)
749 Out
<< Buffer
<< endl
;
755 for (vector
<string
>::iterator I
= List
.begin(); I
!= List
.end(); I
++)
757 string::size_type Space
= (*I
).find(' ');
758 if (Space
== string::npos
)
759 return _error
->Error("Internal error");
761 Out
<< "deb \"cdrom:" << Name
<< "/" << string(*I
,0,Space
) <<
762 "\" " << string(*I
,Space
+1) << endl
;
771 if (ParseQuoteWord(C
,Type
) == false ||
772 ParseQuoteWord(C
,URI
) == false)
774 Out
<< Buffer
<< endl
;
778 // Emit lines like this one
779 if (Type
!= "deb" || string(URI
,0,ShortURI
.length()) != ShortURI
)
781 Out
<< Buffer
<< endl
;
786 // Just in case the file was empty
789 for (vector
<string
>::iterator I
= List
.begin(); I
!= List
.end(); I
++)
791 string::size_type Space
= (*I
).find(' ');
792 if (Space
== string::npos
)
793 return _error
->Error("Internal error");
795 Out
<< "deb \"cdrom:" << Name
<< "/" << string(*I
,0,Space
) <<
796 "\" " << string(*I
,Space
+1) << endl
;
802 rename(File
.c_str(),string(File
+ '~').c_str());
803 if (rename(NewFile
.c_str(),File
.c_str()) != 0)
804 return _error
->Errno("rename","Failed to rename %s.new to %s",
805 File
.c_str(),File
.c_str());
811 // Prompt - Simple prompt /*{{{*/
812 // ---------------------------------------------------------------------
814 void Prompt(const char *Text
)
817 cout
<< Text
<< ' ' << flush
;
818 read(STDIN_FILENO
,&C
,1);
823 // PromptLine - Prompt for an input line /*{{{*/
824 // ---------------------------------------------------------------------
826 string
PromptLine(const char *Text
)
828 cout
<< Text
<< ':' << endl
;
836 // DoAdd - Add a new CDROM /*{{{*/
837 // ---------------------------------------------------------------------
838 /* This does the main add bit.. We show some status and things. The
839 sequence is to mount/umount the CD, Ident it then scan it for package
840 files and reduce that list. Then we copy over the package files and
841 verify them. Then rewrite the database files */
842 bool DoAdd(CommandLine
&)
845 string CDROM
= _config
->FindDir("Acquire::cdrom::mount","/cdrom/");
847 CDROM
= SafeGetCWD() + '/' + CDROM
;
849 cout
<< "Using CD-ROM mount point " << CDROM
<< endl
;
852 Configuration Database
;
853 string DFile
= _config
->FindFile("Dir::State::cdroms");
854 if (FileExists(DFile
) == true)
856 if (ReadConfigFile(Database
,DFile
) == false)
857 return _error
->Error("Unable to read the cdrom database %s",
861 // Unmount the CD and get the user to put in the one they want
862 if (_config
->FindB("APT::CDROM::NoMount",false) == false)
864 cout
<< "Unmounting CD-ROM" << endl
;
867 // Mount the new CDROM
868 Prompt("Please insert a Disc in the drive and press enter");
869 cout
<< "Mounting CD-ROM" << endl
;
870 if (MountCdrom(CDROM
) == false)
871 return _error
->Error("Failed to mount the cdrom.");
874 // Hash the CD to get an ID
875 cout
<< "Identifying.. " << flush
;
877 if (IdentCdrom(CDROM
,ID
) == false)
883 cout
<< '[' << ID
<< ']' << endl
;
885 cout
<< "Scanning Disc for index files.. " << flush
;
886 // Get the CD structure
888 string StartDir
= SafeGetCWD();
890 if (FindPackages(CDROM
,List
,InfoDir
) == false)
896 chdir(StartDir
.c_str());
898 if (_config
->FindB("Debug::aptcdrom",false) == true)
900 cout
<< "I found:" << endl
;
901 for (vector
<string
>::iterator I
= List
.begin(); I
!= List
.end(); I
++)
908 DropBinaryArch(List
);
910 cout
<< "Found " << List
.size() << " package index files." << endl
;
912 if (List
.size() == 0)
913 return _error
->Error("Unable to locate any package files, perhaps this is not a Debian Disc");
915 // Check if the CD is in the database
917 if (Database
.Exists("CD::" + ID
) == false ||
918 _config
->FindB("APT::CDROM::Rename",false) == true)
920 // Try to use the CDs label if at all possible
921 if (InfoDir
.empty() == false &&
922 FileExists(InfoDir
+ "/info") == true)
924 ifstream
F(string(InfoDir
+ "/info").c_str());
928 if (Name
.empty() == false)
930 cout
<< "Found label '" << Name
<< "'" << endl
;
931 Database
.Set("CD::" + ID
+ "::Label",Name
);
935 if (_config
->FindB("APT::CDROM::Rename",false) == true ||
936 Name
.empty() == true)
938 cout
<< "Please provide a name for this Disc, such as 'Debian 2.1r1 Disk 1'";
941 Name
= PromptLine("");
942 if (Name
.empty() == false &&
943 Name
.find('"') == string::npos
&&
944 Name
.find(':') == string::npos
&&
945 Name
.find('/') == string::npos
)
947 cout
<< "That is not a valid name, try again " << endl
;
952 Name
= Database
.Find("CD::" + ID
);
954 string::iterator J
= Name
.begin();
955 for (; J
!= Name
.end(); J
++)
956 if (*J
== '/' || *J
== '"' || *J
== ':')
959 Database
.Set("CD::" + ID
,Name
);
960 cout
<< "This Disc is called '" << Name
<< "'" << endl
;
962 // Copy the package files to the state directory
963 if (CopyPackages(CDROM
,Name
,List
) == false)
966 ReduceSourcelist(CDROM
,List
);
968 // Write the database and sourcelist
969 if (_config
->FindB("APT::cdrom::NoAct",false) == false)
971 if (WriteDatabase(Database
) == false)
974 cout
<< "Writing new source list" << endl
;
975 if (WriteSourceList(Name
,List
) == false)
979 // Print the sourcelist entries
980 cout
<< "Source List entries for this Disc are:" << endl
;
981 for (vector
<string
>::iterator I
= List
.begin(); I
!= List
.end(); I
++)
983 string::size_type Space
= (*I
).find(' ');
984 if (Space
== string::npos
)
985 return _error
->Error("Internal error");
987 cout
<< "deb \"cdrom:" << Name
<< "/" << string(*I
,0,Space
) <<
988 "\" " << string(*I
,Space
+1) << endl
;
995 // ShowHelp - Show the help screen /*{{{*/
996 // ---------------------------------------------------------------------
1000 cout
<< PACKAGE
<< ' ' << VERSION
<< " for " << ARCHITECTURE
<<
1001 " compiled on " << __DATE__
<< " " << __TIME__
<< endl
;
1002 if (_config
->FindB("version") == true)
1005 cout
<< "Usage: apt-cdrom [options] command" << endl
;
1007 cout
<< "apt-cdrom is a tool to add CDROM's to APT's source list. The " << endl
;
1008 cout
<< "CDROM mount point and device information is taken from apt.conf" << endl
;
1009 cout
<< "and /etc/fstab." << endl
;
1011 cout
<< "Commands:" << endl
;
1012 cout
<< " add - Add a CDROM" << endl
;
1014 cout
<< "Options:" << endl
;
1015 cout
<< " -h This help text" << endl
;
1016 cout
<< " -d CD-ROM mount point" << endl
;
1017 cout
<< " -r Rename a recognized CD-ROM" << endl
;
1018 cout
<< " -m No mounting" << endl
;
1019 cout
<< " -f Fast mode, don't check package files" << endl
;
1020 cout
<< " -a Thorough scan mode" << endl
;
1021 cout
<< " -c=? Read this configuration file" << endl
;
1022 cout
<< " -o=? Set an arbitary configuration option, eg -o dir::cache=/tmp" << endl
;
1023 cout
<< "See fstab(5)" << endl
;
1028 int main(int argc
,const char *argv
[])
1030 CommandLine::Args Args
[] = {
1031 {'h',"help","help",0},
1032 {'v',"version","version",0},
1033 {'d',"cdrom","Acquire::cdrom::mount",CommandLine::HasArg
},
1034 {'r',"rename","APT::CDROM::Rename",0},
1035 {'m',"no-mount","APT::CDROM::NoMount",0},
1036 {'f',"fast","APT::CDROM::Fast",0},
1037 {'n',"just-print","APT::CDROM::NoAct",0},
1038 {'n',"recon","APT::CDROM::NoAct",0},
1039 {'n',"no-act","APT::CDROM::NoAct",0},
1040 {'a',"thorough","APT::CDROM::Thorough",0},
1041 {'c',"config-file",0,CommandLine::ConfigFile
},
1042 {'o',"option",0,CommandLine::ArbItem
},
1044 CommandLine::Dispatch Cmds
[] = {
1048 // Parse the command line and initialize the package library
1049 CommandLine
CmdL(Args
,_config
);
1050 if (pkgInitialize(*_config
) == false ||
1051 CmdL
.Parse(argc
,argv
) == false)
1053 _error
->DumpErrors();
1057 // See if the help should be shown
1058 if (_config
->FindB("help") == true ||
1059 CmdL
.FileSize() == 0)
1062 // Deal with stdout not being a tty
1063 if (ttyname(STDOUT_FILENO
) == 0 && _config
->FindI("quiet",0) < 1)
1064 _config
->Set("quiet","1");
1066 // Match the operation
1067 CmdL
.DispatchArg(Cmds
);
1069 // Print any errors or warnings found during parsing
1070 if (_error
->empty() == false)
1072 bool Errors
= _error
->PendingError();
1073 _error
->DumpErrors();
1074 return Errors
== true?100:0;