]>
git.saurik.com Git - apt.git/blob - cmdline/apt-cdrom.cc
88f1da1020724a51fadd86c4eed805e59bf7941c
1 // -*- mode: cpp; mode: fold -*-
3 // $Id: apt-cdrom.cc,v 1.27 1999/07/11 22:42:32 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
,vector
<string
> &SList
,
42 string
&InfoDir
,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)
73 if (stat("Sources",&Buf
) == 0)
77 // Continue down if thorough is given
78 if (_config
->FindB("APT::CDROM::Thorough",false) == false)
82 DIR *D
= opendir(".");
84 return _error
->Errno("opendir","Unable to read %s",CD
.c_str());
86 // Run over the directory
87 for (struct dirent
*Dir
= readdir(D
); Dir
!= 0; Dir
= readdir(D
))
90 if (strcmp(Dir
->d_name
,".") == 0 ||
91 strcmp(Dir
->d_name
,"..") == 0 ||
92 //strcmp(Dir->d_name,"source") == 0 ||
93 strcmp(Dir
->d_name
,"experimental") == 0 ||
94 strcmp(Dir
->d_name
,"binary-all") == 0)
97 // See if the name is a sub directory
99 if (stat(Dir
->d_name
,&Buf
) != 0)
102 if (S_ISDIR(Buf
.st_mode
) == 0)
106 for (I
= 0; I
!= Depth
; I
++)
107 if (Inodes
[I
] == Buf
.st_ino
)
112 // Store the inodes weve seen
113 Inodes
[Depth
] = Buf
.st_ino
;
116 if (FindPackages(CD
+ Dir
->d_name
,List
,SList
,InfoDir
,Depth
+1) == false)
119 if (chdir(CD
.c_str()) != 0)
120 return _error
->Errno("chdir","Unable to change to ",CD
.c_str());
125 return !_error
->PendingError();
128 // DropBinaryArch - Dump dirs with a string like /binary-<foo>/ /*{{{*/
129 // ---------------------------------------------------------------------
130 /* Here we drop everything that is not this machines arch */
131 bool DropBinaryArch(vector
<string
> &List
)
134 sprintf(S
,"/binary-%s/",_config
->Find("Apt::Architecture").c_str());
136 for (unsigned int I
= 0; I
< List
.size(); I
++)
138 const char *Str
= List
[I
].c_str();
141 if ((Res
= strstr(Str
,"/binary-")) == 0)
145 if (strlen(Res
) < strlen(S
))
147 List
.erase(List
.begin() + I
);
152 // See if it is our arch
153 if (stringcmp(Res
,Res
+ strlen(S
),S
) == 0)
157 List
.erase(List
.begin() + I
);
164 // Score - We compute a 'score' for a path /*{{{*/
165 // ---------------------------------------------------------------------
166 /* Paths are scored based on how close they come to what I consider
167 normal. That is ones that have 'dist' 'stable' 'frozen' will score
168 higher than ones without. */
169 int Score(string Path
)
172 if (Path
.find("stable/") != string::npos
)
174 if (Path
.find("/binary-") != string::npos
)
176 if (Path
.find("frozen/") != string::npos
)
178 if (Path
.find("/dists/") != string::npos
)
180 if (Path
.find("/main/") != string::npos
)
182 if (Path
.find("/contrib/") != string::npos
)
184 if (Path
.find("/non-free/") != string::npos
)
186 if (Path
.find("/non-US/") != string::npos
)
191 // DropRepeats - Drop repeated files resulting from symlinks /*{{{*/
192 // ---------------------------------------------------------------------
193 /* Here we go and stat every file that we found and strip dup inodes. */
194 bool DropRepeats(vector
<string
> &List
,const char *Name
)
196 // Get a list of all the inodes
197 ino_t
*Inodes
= new ino_t
[List
.size()];
198 for (unsigned int I
= 0; I
!= List
.size(); I
++)
201 if (stat((List
[I
] + Name
).c_str(),&Buf
) != 0)
202 _error
->Errno("stat","Failed to stat %s%s",List
[I
].c_str(),
204 Inodes
[I
] = Buf
.st_ino
;
207 if (_error
->PendingError() == true)
211 for (unsigned int I
= 0; I
!= List
.size(); I
++)
213 for (unsigned int J
= I
+1; J
< List
.size(); J
++)
216 if (Inodes
[J
] != Inodes
[I
])
219 // We score the two paths.. and erase one
220 int ScoreA
= Score(List
[I
]);
221 int ScoreB
= Score(List
[J
]);
232 // Wipe erased entries
233 for (unsigned int I
= 0; I
< List
.size();)
235 if (List
[I
].empty() == false)
238 List
.erase(List
.begin()+I
);
244 // ConvertToSourceList - Convert a Path to a sourcelist entry /*{{{*/
245 // ---------------------------------------------------------------------
246 /* We look for things in dists/ notation and convert them to
247 <dist> <component> form otherwise it is left alone. This also strips
249 void ConvertToSourceList(string CD
,string
&Path
)
252 sprintf(S
,"binary-%s",_config
->Find("Apt::Architecture").c_str());
254 // Strip the cdrom base path
255 Path
= string(Path
,CD
.length());
256 if (Path
.empty() == true)
259 // Too short to be a dists/ type
260 if (Path
.length() < strlen("dists/"))
264 if (stringcmp(Path
.begin(),Path
.begin()+strlen("dists/"),"dists/") != 0)
268 string::size_type Slash
= strlen("dists/");
269 string::size_type Slash2
= Path
.find('/',Slash
+ 1);
270 if (Slash2
== string::npos
|| Slash2
+ 2 >= Path
.length())
272 string Dist
= string(Path
,Slash
,Slash2
- Slash
);
274 // Isolate the component
275 Slash
= Path
.find('/',Slash2
+1);
276 if (Slash
== string::npos
|| Slash
+ 2 >= Path
.length())
278 string Comp
= string(Path
,Slash2
+1,Slash
- Slash2
-1);
280 // Verify the trailing binar - bit
281 Slash2
= Path
.find('/',Slash
+ 1);
282 if (Slash
== string::npos
)
284 string Binary
= string(Path
,Slash
+1,Slash2
- Slash
-1);
289 Path
= Dist
+ ' ' + Comp
;
292 // GrabFirst - Return the first Depth path components /*{{{*/
293 // ---------------------------------------------------------------------
295 bool GrabFirst(string Path
,string
&To
,unsigned int Depth
)
297 string::size_type I
= 0;
300 I
= Path
.find('/',I
+1);
303 while (I
!= string::npos
&& Depth
!= 0);
305 if (I
== string::npos
)
308 To
= string(Path
,0,I
+1);
312 // ChopDirs - Chop off the leading directory components /*{{{*/
313 // ---------------------------------------------------------------------
315 string
ChopDirs(string Path
,unsigned int Depth
)
317 string::size_type I
= 0;
320 I
= Path
.find('/',I
+1);
323 while (I
!= string::npos
&& Depth
!= 0);
325 if (I
== string::npos
)
328 return string(Path
,I
+1);
331 // ReconstructPrefix - Fix strange prefixing /*{{{*/
332 // ---------------------------------------------------------------------
333 /* This prepends dir components from the path to the package files to
334 the path to the deb until it is found */
335 bool ReconstructPrefix(string
&Prefix
,string OrigPath
,string CD
,
338 bool Debug
= _config
->FindB("Debug::aptcdrom",false);
339 unsigned int Depth
= 1;
340 string MyPrefix
= Prefix
;
344 if (stat(string(CD
+ MyPrefix
+ File
).c_str(),&Buf
) != 0)
347 cout
<< "Failed, " << CD
+ MyPrefix
+ File
<< endl
;
348 if (GrabFirst(OrigPath
,MyPrefix
,Depth
++) == true)
362 // ReconstructChop - Fixes bad source paths /*{{{*/
363 // ---------------------------------------------------------------------
364 /* This removes path components from the filename and prepends the location
365 of the package files until a file is found */
366 bool ReconstructChop(unsigned long &Chop
,string Dir
,string File
)
368 // Attempt to reconstruct the filename
369 unsigned long Depth
= 0;
373 if (stat(string(Dir
+ File
).c_str(),&Buf
) != 0)
375 File
= ChopDirs(File
,1);
377 if (File
.empty() == false)
391 // CopyPackages - Copy the package files from the CD /*{{{*/
392 // ---------------------------------------------------------------------
394 bool CopyPackages(string CDROM
,string Name
,vector
<string
> &List
)
396 OpTextProgress Progress
;
398 bool NoStat
= _config
->FindB("APT::CDROM::Fast",false);
399 bool Debug
= _config
->FindB("Debug::aptcdrom",false);
401 // Prepare the progress indicator
402 unsigned long TotalSize
= 0;
403 for (vector
<string
>::iterator I
= List
.begin(); I
!= List
.end(); I
++)
406 if (stat(string(*I
+ "Packages").c_str(),&Buf
) != 0)
407 return _error
->Errno("stat","Stat failed for %s",
408 string(*I
+ "Packages").c_str());
409 TotalSize
+= Buf
.st_size
;
412 unsigned long CurrentSize
= 0;
413 unsigned int NotFound
= 0;
414 unsigned int WrongSize
= 0;
415 unsigned int Packages
= 0;
416 for (vector
<string
>::iterator I
= List
.begin(); I
!= List
.end(); I
++)
418 string OrigPath
= string(*I
,CDROM
.length());
420 // Open the package file
421 FileFd
Pkg(*I
+ "Packages",FileFd::ReadOnly
);
422 pkgTagFile
Parser(Pkg
);
423 if (_error
->PendingError() == true)
426 // Open the output file
428 sprintf(S
,"cdrom:%s/%sPackages",Name
.c_str(),(*I
).c_str() + CDROM
.length());
429 string TargetF
= _config
->FindDir("Dir::State::lists") + "partial/";
430 TargetF
+= URItoFileName(S
);
431 if (_config
->FindB("APT::CDROM::NoAct",false) == true)
432 TargetF
= "/dev/null";
433 FileFd
Target(TargetF
,FileFd::WriteEmpty
);
434 if (_error
->PendingError() == true)
437 // Setup the progress meter
438 Progress
.OverallProgress(CurrentSize
,TotalSize
,Pkg
.Size(),
439 "Reading Package Lists");
442 Progress
.SubProgress(Pkg
.Size());
443 pkgTagSection Section
;
445 unsigned long Hits
= 0;
446 unsigned long Chop
= 0;
447 while (Parser
.Step(Section
) == true)
449 Progress
.Progress(Parser
.Offset());
451 string File
= Section
.FindS("Filename");
452 unsigned long Size
= Section
.FindI("Size");
453 if (File
.empty() || Size
== 0)
454 return _error
->Error("Cannot find filename or size tag");
457 File
= OrigPath
+ ChopDirs(File
,Chop
);
459 // See if the file exists
460 bool Mangled
= false;
461 if (NoStat
== false || Hits
< 10)
463 // Attempt to fix broken structure
466 if (ReconstructPrefix(Prefix
,OrigPath
,CDROM
,File
) == false &&
467 ReconstructChop(Chop
,*I
,File
) == false)
470 clog
<< "Missed: " << File
<< endl
;
475 File
= OrigPath
+ ChopDirs(File
,Chop
);
480 if (stat(string(CDROM
+ Prefix
+ File
).c_str(),&Buf
) != 0 ||
483 // Attempt to fix busted symlink support for one instance
484 string OrigFile
= File
;
485 string::size_type Start
= File
.find("binary-");
486 string::size_type End
= File
.find("/",Start
+3);
487 if (Start
!= string::npos
&& End
!= string::npos
)
489 File
.replace(Start
,End
-Start
,"binary-all");
493 if (Mangled
== false ||
494 stat(string(CDROM
+ Prefix
+ File
).c_str(),&Buf
) != 0)
497 clog
<< "Missed(2): " << OrigFile
<< endl
;
504 if ((unsigned)Buf
.st_size
!= Size
)
507 clog
<< "Wrong Size: " << File
<< endl
;
516 // Copy it to the target package file
519 if (Chop
!= 0 || Mangled
== true)
521 // Mangle the output filename
522 const char *Filename
;
523 Section
.Find("Filename",Filename
,Stop
);
525 /* We need to rewrite the filename field so we emit
526 all fields except the filename file and rewrite that one */
527 for (unsigned int I
= 0; I
!= Section
.Count(); I
++)
529 Section
.Get(Start
,Stop
,I
);
530 if (Start
<= Filename
&& Stop
> Filename
)
533 sprintf(S
,"Filename: %s\n",File
.c_str());
534 if (I
+ 1 == Section
.Count())
536 if (Target
.Write(S
,strlen(S
)) == false)
541 if (Target
.Write(Start
,Stop
-Start
) == false)
543 if (Stop
[-1] != '\n')
544 if (Target
.Write("\n",1) == false)
548 if (Target
.Write("\n",1) == false)
553 Section
.GetSection(Start
,Stop
);
554 if (Target
.Write(Start
,Stop
-Start
) == false)
560 cout
<< " Processed by using Prefix '" << Prefix
<< "' and chop " << Chop
<< endl
;
562 if (_config
->FindB("APT::CDROM::NoAct",false) == false)
564 // Move out of the partial directory
566 string FinalF
= _config
->FindDir("Dir::State::lists");
567 FinalF
+= URItoFileName(S
);
568 if (rename(TargetF
.c_str(),FinalF
.c_str()) != 0)
569 return _error
->Errno("rename","Failed to rename");
571 // Copy the release file
572 sprintf(S
,"cdrom:%s/%sRelease",Name
.c_str(),(*I
).c_str() + CDROM
.length());
573 string TargetF
= _config
->FindDir("Dir::State::lists") + "partial/";
574 TargetF
+= URItoFileName(S
);
575 if (FileExists(*I
+ "Release") == true)
577 FileFd
Target(TargetF
,FileFd::WriteEmpty
);
578 FileFd
Rel(*I
+ "Release",FileFd::ReadOnly
);
579 if (_error
->PendingError() == true)
582 if (CopyFile(Rel
,Target
) == false)
587 // Empty release file
588 FileFd
Target(TargetF
,FileFd::WriteEmpty
);
591 // Rename the release file
592 FinalF
= _config
->FindDir("Dir::State::lists");
593 FinalF
+= URItoFileName(S
);
594 if (rename(TargetF
.c_str(),FinalF
.c_str()) != 0)
595 return _error
->Errno("rename","Failed to rename");
598 /* Mangle the source to be in the proper notation with
599 prefix dist [component] */
600 *I
= string(*I
,Prefix
.length());
601 ConvertToSourceList(CDROM
,*I
);
602 *I
= Prefix
+ ' ' + *I
;
604 CurrentSize
+= Pkg
.Size();
609 cout
<< "Wrote " << Packages
<< " package records" ;
611 cout
<< " with " << NotFound
<< " missing files";
612 if (NotFound
!= 0 && WrongSize
!= 0)
615 cout
<< " with " << WrongSize
<< " mismatched files";
619 return _error
->Error("No valid package records were found.");
621 if (NotFound
+ WrongSize
> 10)
622 cout
<< "Alot of package entries were discarded, perhaps this CD is funny?" << endl
;
628 // ReduceSourceList - Takes the path list and reduces it /*{{{*/
629 // ---------------------------------------------------------------------
630 /* This takes the list of source list expressed entires and collects
631 similar ones to form a single entry for each dist */
632 bool ReduceSourcelist(string CD
,vector
<string
> &List
)
634 sort(List
.begin(),List
.end());
636 // Collect similar entries
637 for (vector
<string
>::iterator I
= List
.begin(); I
!= List
.end(); I
++)
640 string::size_type Space
= (*I
).find(' ');
641 if (Space
== string::npos
)
643 string::size_type SSpace
= (*I
).find(' ',Space
+ 1);
644 if (SSpace
== string::npos
)
647 string Word1
= string(*I
,Space
,SSpace
-Space
);
648 for (vector
<string
>::iterator J
= List
.begin(); J
!= I
; J
++)
651 string::size_type Space2
= (*J
).find(' ');
652 if (Space2
== string::npos
)
654 string::size_type SSpace2
= (*J
).find(' ',Space2
+ 1);
655 if (SSpace2
== string::npos
)
658 if (string(*J
,Space2
,SSpace2
-Space2
) != Word1
)
661 *J
+= string(*I
,SSpace
);
666 // Wipe erased entries
667 for (unsigned int I
= 0; I
< List
.size();)
669 if (List
[I
].empty() == false)
672 List
.erase(List
.begin()+I
);
676 // WriteDatabase - Write the CDROM Database file /*{{{*/
677 // ---------------------------------------------------------------------
678 /* We rewrite the configuration class associated with the cdrom database. */
679 bool WriteDatabase(Configuration
&Cnf
)
681 string DFile
= _config
->FindFile("Dir::State::cdroms");
682 string NewFile
= DFile
+ ".new";
684 unlink(NewFile
.c_str());
685 ofstream
Out(NewFile
.c_str());
687 return _error
->Errno("ofstream::ofstream",
688 "Failed to open %s.new",DFile
.c_str());
690 /* Write out all of the configuration directives by walking the
691 configuration tree */
692 const Configuration::Item
*Top
= Cnf
.Tree(0);
695 // Print the config entry
696 if (Top
->Value
.empty() == false)
697 Out
<< Top
->FullTag() + " \"" << Top
->Value
<< "\";" << endl
;
705 while (Top
!= 0 && Top
->Next
== 0)
713 rename(DFile
.c_str(),string(DFile
+ '~').c_str());
714 if (rename(NewFile
.c_str(),DFile
.c_str()) != 0)
715 return _error
->Errno("rename","Failed to rename %s.new to %s",
716 DFile
.c_str(),DFile
.c_str());
721 // WriteSourceList - Write an updated sourcelist /*{{{*/
722 // ---------------------------------------------------------------------
723 /* This reads the old source list and copies it into the new one. It
724 appends the new CDROM entires just after the first block of comments.
725 This places them first in the file. It also removes any old entries
726 that were the same. */
727 bool WriteSourceList(string Name
,vector
<string
> &List
)
729 string File
= _config
->FindFile("Dir::Etc::sourcelist");
731 // Open the stream for reading
732 ifstream
F(File
.c_str(),ios::in
| ios::nocreate
);
734 return _error
->Errno("ifstream::ifstream","Opening %s",File
.c_str());
736 string NewFile
= File
+ ".new";
737 unlink(NewFile
.c_str());
738 ofstream
Out(NewFile
.c_str());
740 return _error
->Errno("ofstream::ofstream",
741 "Failed to open %s.new",File
.c_str());
743 // Create a short uri without the path
744 string ShortURI
= "cdrom:" + Name
+ "/";
749 while (F
.eof() == false)
751 F
.getline(Buffer
,sizeof(Buffer
));
753 _strtabexpand(Buffer
,sizeof(Buffer
));
757 if (Buffer
[0] == '#' || Buffer
[0] == 0)
759 Out
<< Buffer
<< endl
;
765 for (vector
<string
>::iterator I
= List
.begin(); I
!= List
.end(); I
++)
767 string::size_type Space
= (*I
).find(' ');
768 if (Space
== string::npos
)
769 return _error
->Error("Internal error");
771 Out
<< "deb \"cdrom:" << Name
<< "/" << string(*I
,0,Space
) <<
772 "\" " << string(*I
,Space
+1) << endl
;
781 if (ParseQuoteWord(C
,Type
) == false ||
782 ParseQuoteWord(C
,URI
) == false)
784 Out
<< Buffer
<< endl
;
788 // Emit lines like this one
789 if (Type
!= "deb" || string(URI
,0,ShortURI
.length()) != ShortURI
)
791 Out
<< Buffer
<< endl
;
796 // Just in case the file was empty
799 for (vector
<string
>::iterator I
= List
.begin(); I
!= List
.end(); I
++)
801 string::size_type Space
= (*I
).find(' ');
802 if (Space
== string::npos
)
803 return _error
->Error("Internal error");
805 Out
<< "deb \"cdrom:" << Name
<< "/" << string(*I
,0,Space
) <<
806 "\" " << string(*I
,Space
+1) << endl
;
812 rename(File
.c_str(),string(File
+ '~').c_str());
813 if (rename(NewFile
.c_str(),File
.c_str()) != 0)
814 return _error
->Errno("rename","Failed to rename %s.new to %s",
815 File
.c_str(),File
.c_str());
821 // Prompt - Simple prompt /*{{{*/
822 // ---------------------------------------------------------------------
824 void Prompt(const char *Text
)
827 cout
<< Text
<< ' ' << flush
;
828 read(STDIN_FILENO
,&C
,1);
833 // PromptLine - Prompt for an input line /*{{{*/
834 // ---------------------------------------------------------------------
836 string
PromptLine(const char *Text
)
838 cout
<< Text
<< ':' << endl
;
846 // DoAdd - Add a new CDROM /*{{{*/
847 // ---------------------------------------------------------------------
848 /* This does the main add bit.. We show some status and things. The
849 sequence is to mount/umount the CD, Ident it then scan it for package
850 files and reduce that list. Then we copy over the package files and
851 verify them. Then rewrite the database files */
852 bool DoAdd(CommandLine
&)
855 string CDROM
= _config
->FindDir("Acquire::cdrom::mount","/cdrom/");
857 CDROM
= SafeGetCWD() + '/' + CDROM
;
859 cout
<< "Using CD-ROM mount point " << CDROM
<< endl
;
862 Configuration Database
;
863 string DFile
= _config
->FindFile("Dir::State::cdroms");
864 if (FileExists(DFile
) == true)
866 if (ReadConfigFile(Database
,DFile
) == false)
867 return _error
->Error("Unable to read the cdrom database %s",
871 // Unmount the CD and get the user to put in the one they want
872 if (_config
->FindB("APT::CDROM::NoMount",false) == false)
874 cout
<< "Unmounting CD-ROM" << endl
;
877 // Mount the new CDROM
878 Prompt("Please insert a Disc in the drive and press enter");
879 cout
<< "Mounting CD-ROM" << endl
;
880 if (MountCdrom(CDROM
) == false)
881 return _error
->Error("Failed to mount the cdrom.");
884 // Hash the CD to get an ID
885 cout
<< "Identifying.. " << flush
;
887 if (IdentCdrom(CDROM
,ID
) == false)
893 cout
<< '[' << ID
<< ']' << endl
;
895 cout
<< "Scanning Disc for index files.. " << flush
;
896 // Get the CD structure
898 vector
<string
> sList
;
899 string StartDir
= SafeGetCWD();
901 if (FindPackages(CDROM
,List
,sList
,InfoDir
) == false)
907 chdir(StartDir
.c_str());
909 if (_config
->FindB("Debug::aptcdrom",false) == true)
911 cout
<< "I found:" << endl
;
912 for (vector
<string
>::iterator I
= List
.begin(); I
!= List
.end(); I
++)
919 DropBinaryArch(List
);
920 DropRepeats(List
,"Packages");
921 DropRepeats(sList
,"Sources");
922 cout
<< "Found " << List
.size() << " package indexes and " << sList
.size() <<
923 " source indexes." << endl
;
925 if (List
.size() == 0)
926 return _error
->Error("Unable to locate any package files, perhaps this is not a Debian Disc");
928 // Check if the CD is in the database
930 if (Database
.Exists("CD::" + ID
) == false ||
931 _config
->FindB("APT::CDROM::Rename",false) == true)
933 // Try to use the CDs label if at all possible
934 if (InfoDir
.empty() == false &&
935 FileExists(InfoDir
+ "/info") == true)
937 ifstream
F(string(InfoDir
+ "/info").c_str());
941 if (Name
.empty() == false)
943 cout
<< "Found label '" << Name
<< "'" << endl
;
944 Database
.Set("CD::" + ID
+ "::Label",Name
);
948 if (_config
->FindB("APT::CDROM::Rename",false) == true ||
949 Name
.empty() == true)
951 cout
<< "Please provide a name for this Disc, such as 'Debian 2.1r1 Disk 1'";
954 Name
= PromptLine("");
955 if (Name
.empty() == false &&
956 Name
.find('"') == string::npos
&&
957 Name
.find(':') == string::npos
&&
958 Name
.find('/') == string::npos
)
960 cout
<< "That is not a valid name, try again " << endl
;
965 Name
= Database
.Find("CD::" + ID
);
967 string::iterator J
= Name
.begin();
968 for (; J
!= Name
.end(); J
++)
969 if (*J
== '/' || *J
== '"' || *J
== ':')
972 Database
.Set("CD::" + ID
,Name
);
973 cout
<< "This Disc is called '" << Name
<< "'" << endl
;
975 // Copy the package files to the state directory
976 if (CopyPackages(CDROM
,Name
,List
) == false)
979 ReduceSourcelist(CDROM
,List
);
980 ReduceSourcelist(CDROM
,sList
);
982 // Write the database and sourcelist
983 if (_config
->FindB("APT::cdrom::NoAct",false) == false)
985 if (WriteDatabase(Database
) == false)
988 cout
<< "Writing new source list" << endl
;
989 if (WriteSourceList(Name
,List
) == false)
993 // Print the sourcelist entries
994 cout
<< "Source List entries for this Disc are:" << endl
;
995 for (vector
<string
>::iterator I
= List
.begin(); I
!= List
.end(); I
++)
997 string::size_type Space
= (*I
).find(' ');
998 if (Space
== string::npos
)
999 return _error
->Error("Internal error");
1001 cout
<< "deb \"cdrom:" << Name
<< "/" << string(*I
,0,Space
) <<
1002 "\" " << string(*I
,Space
+1) << endl
;
1005 for (vector
<string
>::iterator I
= sList
.begin(); I
!= sList
.end(); I
++)
1007 string::size_type Space
= (*I
).find(' ');
1008 if (Space
== string::npos
)
1009 return _error
->Error("Internal error");
1011 cout
<< "deb-src \"cdrom:" << Name
<< "/" << string(*I
,0,Space
) <<
1012 "\" " << string(*I
,Space
+1) << endl
;
1015 cout
<< "Repeat this process for the rest of the CDs in your set." << endl
;
1020 // ShowHelp - Show the help screen /*{{{*/
1021 // ---------------------------------------------------------------------
1025 cout
<< PACKAGE
<< ' ' << VERSION
<< " for " << ARCHITECTURE
<<
1026 " compiled on " << __DATE__
<< " " << __TIME__
<< endl
;
1027 if (_config
->FindB("version") == true)
1030 cout
<< "Usage: apt-cdrom [options] command" << endl
;
1032 cout
<< "apt-cdrom is a tool to add CDROM's to APT's source list. The " << endl
;
1033 cout
<< "CDROM mount point and device information is taken from apt.conf" << endl
;
1034 cout
<< "and /etc/fstab." << endl
;
1036 cout
<< "Commands:" << endl
;
1037 cout
<< " add - Add a CDROM" << endl
;
1039 cout
<< "Options:" << endl
;
1040 cout
<< " -h This help text" << endl
;
1041 cout
<< " -d CD-ROM mount point" << endl
;
1042 cout
<< " -r Rename a recognized CD-ROM" << endl
;
1043 cout
<< " -m No mounting" << endl
;
1044 cout
<< " -f Fast mode, don't check package files" << endl
;
1045 cout
<< " -a Thorough scan mode" << endl
;
1046 cout
<< " -c=? Read this configuration file" << endl
;
1047 cout
<< " -o=? Set an arbitary configuration option, eg -o dir::cache=/tmp" << endl
;
1048 cout
<< "See fstab(5)" << endl
;
1053 int main(int argc
,const char *argv
[])
1055 CommandLine::Args Args
[] = {
1056 {'h',"help","help",0},
1057 {'v',"version","version",0},
1058 {'d',"cdrom","Acquire::cdrom::mount",CommandLine::HasArg
},
1059 {'r',"rename","APT::CDROM::Rename",0},
1060 {'m',"no-mount","APT::CDROM::NoMount",0},
1061 {'f',"fast","APT::CDROM::Fast",0},
1062 {'n',"just-print","APT::CDROM::NoAct",0},
1063 {'n',"recon","APT::CDROM::NoAct",0},
1064 {'n',"no-act","APT::CDROM::NoAct",0},
1065 {'a',"thorough","APT::CDROM::Thorough",0},
1066 {'c',"config-file",0,CommandLine::ConfigFile
},
1067 {'o',"option",0,CommandLine::ArbItem
},
1069 CommandLine::Dispatch Cmds
[] = {
1073 // Parse the command line and initialize the package library
1074 CommandLine
CmdL(Args
,_config
);
1075 if (pkgInitialize(*_config
) == false ||
1076 CmdL
.Parse(argc
,argv
) == false)
1078 _error
->DumpErrors();
1082 // See if the help should be shown
1083 if (_config
->FindB("help") == true ||
1084 CmdL
.FileSize() == 0)
1087 // Deal with stdout not being a tty
1088 if (ttyname(STDOUT_FILENO
) == 0 && _config
->FindI("quiet",0) < 1)
1089 _config
->Set("quiet","1");
1091 // Match the operation
1092 CmdL
.DispatchArg(Cmds
);
1094 // Print any errors or warnings found during parsing
1095 if (_error
->empty() == false)
1097 bool Errors
= _error
->PendingError();
1098 _error
->DumpErrors();
1099 return Errors
== true?100:0;