]> git.saurik.com Git - apt.git/blame - cmdline/apt-cdrom.cc
re-add 0.3.13, forgot to check it in originally
[apt.git] / cmdline / apt-cdrom.cc
CommitLineData
83d89a9f
AL
1// -*- mode: cpp; mode: fold -*-
2// Description /*{{{*/
ed51f28e 3// $Id: apt-cdrom.cc,v 1.32 1999/09/03 05:46:48 jgg Exp $
83d89a9f
AL
4/* ######################################################################
5
18444708
AL
6 APT CDROM - Tool for handling APT's CDROM database.
7
8 Currently the only option is 'add' which will take the current CD
9 in the drive and add it into the database.
83d89a9f
AL
10
11 ##################################################################### */
12 /*}}}*/
13// Include Files /*{{{*/
14#include <apt-pkg/cmndline.h>
15#include <apt-pkg/error.h>
16#include <apt-pkg/init.h>
83d89a9f
AL
17#include <apt-pkg/fileutl.h>
18#include <apt-pkg/progress.h>
65ae8fab 19#include <apt-pkg/cdromutl.h>
cdcc6d34 20#include <apt-pkg/strutl.h>
83d89a9f
AL
21#include <config.h>
22
143abaeb
AL
23#include "indexcopy.h"
24
83d89a9f 25#include <iostream>
18444708 26#include <fstream>
83d89a9f
AL
27#include <vector>
28#include <algorithm>
83d89a9f
AL
29#include <sys/stat.h>
30#include <fcntl.h>
31#include <dirent.h>
32#include <unistd.h>
33#include <stdio.h>
34 /*}}}*/
35
4dfaa253 36// FindPackages - Find the package files on the CDROM /*{{{*/
83d89a9f
AL
37// ---------------------------------------------------------------------
38/* We look over the cdrom for package files. This is a recursive
39 search that short circuits when it his a package file in the dir.
40 This speeds it up greatly as the majority of the size is in the
41 binary-* sub dirs. */
13d87e2e
AL
42bool FindPackages(string CD,vector<string> &List,vector<string> &SList,
43 string &InfoDir,unsigned int Depth = 0)
83d89a9f 44{
2c78c00b 45 static ino_t Inodes[9];
4dfaa253 46 if (Depth >= 7)
83d89a9f
AL
47 return true;
48
49 if (CD[CD.length()-1] != '/')
50 CD += '/';
143abaeb 51
83d89a9f
AL
52 if (chdir(CD.c_str()) != 0)
53 return _error->Errno("chdir","Unable to change to %s",CD.c_str());
54
dafaee52
AL
55 // Look for a .disk subdirectory
56 struct stat Buf;
57 if (stat(".disk",&Buf) == 0)
58 {
59 if (InfoDir.empty() == true)
60 InfoDir = CD + ".disk/";
61 }
62
83d89a9f
AL
63 /* Aha! We found some package files. We assume that everything under
64 this dir is controlled by those package files so we don't look down
65 anymore */
bd37d248 66 if (stat("Packages",&Buf) == 0 || stat("Packages.gz",&Buf) == 0)
83d89a9f
AL
67 {
68 List.push_back(CD);
c60d151b
AL
69
70 // Continue down if thorough is given
71 if (_config->FindB("APT::CDROM::Thorough",false) == false)
72 return true;
83d89a9f 73 }
143abaeb 74 if (stat("Sources.gz",&Buf) == 0 || stat("Sources",&Buf) == 0)
13d87e2e
AL
75 {
76 SList.push_back(CD);
77
78 // Continue down if thorough is given
79 if (_config->FindB("APT::CDROM::Thorough",false) == false)
80 return true;
81 }
22177db9 82
83d89a9f
AL
83 DIR *D = opendir(".");
84 if (D == 0)
85 return _error->Errno("opendir","Unable to read %s",CD.c_str());
86
87 // Run over the directory
88 for (struct dirent *Dir = readdir(D); Dir != 0; Dir = readdir(D))
89 {
90 // Skip some files..
91 if (strcmp(Dir->d_name,".") == 0 ||
92 strcmp(Dir->d_name,"..") == 0 ||
13d87e2e 93 //strcmp(Dir->d_name,"source") == 0 ||
ed51f28e 94 strcmp(Dir->d_name,".disk") == 0 ||
83d89a9f
AL
95 strcmp(Dir->d_name,"experimental") == 0 ||
96 strcmp(Dir->d_name,"binary-all") == 0)
97 continue;
98
99 // See if the name is a sub directory
100 struct stat Buf;
101 if (stat(Dir->d_name,&Buf) != 0)
4dfaa253 102 continue;
83d89a9f
AL
103
104 if (S_ISDIR(Buf.st_mode) == 0)
105 continue;
106
e02343ac
AL
107 unsigned int I;
108 for (I = 0; I != Depth; I++)
109 if (Inodes[I] == Buf.st_ino)
110 break;
f1663bdf 111 if (I != Depth)
9bf3ee5c 112 continue;
f1663bdf 113
e02343ac
AL
114 // Store the inodes weve seen
115 Inodes[Depth] = Buf.st_ino;
116
83d89a9f 117 // Descend
13d87e2e 118 if (FindPackages(CD + Dir->d_name,List,SList,InfoDir,Depth+1) == false)
83d89a9f
AL
119 break;
120
121 if (chdir(CD.c_str()) != 0)
122 return _error->Errno("chdir","Unable to change to ",CD.c_str());
123 };
124
125 closedir(D);
126
127 return !_error->PendingError();
128}
129 /*}}}*/
83d89a9f
AL
130// DropBinaryArch - Dump dirs with a string like /binary-<foo>/ /*{{{*/
131// ---------------------------------------------------------------------
132/* Here we drop everything that is not this machines arch */
133bool DropBinaryArch(vector<string> &List)
134{
135 char S[300];
136 sprintf(S,"/binary-%s/",_config->Find("Apt::Architecture").c_str());
137
138 for (unsigned int I = 0; I < List.size(); I++)
139 {
140 const char *Str = List[I].c_str();
141
142 const char *Res;
143 if ((Res = strstr(Str,"/binary-")) == 0)
144 continue;
145
146 // Weird, remove it.
147 if (strlen(Res) < strlen(S))
148 {
149 List.erase(List.begin() + I);
150 I--;
151 continue;
152 }
153
154 // See if it is our arch
155 if (stringcmp(Res,Res + strlen(S),S) == 0)
156 continue;
157
158 // Erase it
159 List.erase(List.begin() + I);
160 I--;
161 }
162
163 return true;
164}
165 /*}}}*/
166// Score - We compute a 'score' for a path /*{{{*/
167// ---------------------------------------------------------------------
168/* Paths are scored based on how close they come to what I consider
169 normal. That is ones that have 'dist' 'stable' 'frozen' will score
170 higher than ones without. */
171int Score(string Path)
172{
173 int Res = 0;
174 if (Path.find("stable/") != string::npos)
175 Res += 2;
f1663bdf
AL
176 if (Path.find("/binary-") != string::npos)
177 Res += 2;
83d89a9f
AL
178 if (Path.find("frozen/") != string::npos)
179 Res += 2;
180 if (Path.find("/dists/") != string::npos)
181 Res += 4;
182 if (Path.find("/main/") != string::npos)
183 Res += 2;
184 if (Path.find("/contrib/") != string::npos)
185 Res += 2;
186 if (Path.find("/non-free/") != string::npos)
187 Res += 2;
188 if (Path.find("/non-US/") != string::npos)
189 Res += 2;
143abaeb
AL
190 if (Path.find("/source/") != string::npos)
191 Res += 1;
83d89a9f
AL
192 return Res;
193}
194 /*}}}*/
195// DropRepeats - Drop repeated files resulting from symlinks /*{{{*/
196// ---------------------------------------------------------------------
197/* Here we go and stat every file that we found and strip dup inodes. */
13d87e2e 198bool DropRepeats(vector<string> &List,const char *Name)
83d89a9f
AL
199{
200 // Get a list of all the inodes
201 ino_t *Inodes = new ino_t[List.size()];
202 for (unsigned int I = 0; I != List.size(); I++)
203 {
204 struct stat Buf;
143abaeb
AL
205 if (stat((List[I] + Name).c_str(),&Buf) != 0 &&
206 stat((List[I] + Name + ".gz").c_str(),&Buf) != 0)
13d87e2e
AL
207 _error->Errno("stat","Failed to stat %s%s",List[I].c_str(),
208 Name);
83d89a9f
AL
209 Inodes[I] = Buf.st_ino;
210 }
211
988d60d1
AL
212 if (_error->PendingError() == true)
213 return false;
214
83d89a9f
AL
215 // Look for dups
216 for (unsigned int I = 0; I != List.size(); I++)
217 {
218 for (unsigned int J = I+1; J < List.size(); J++)
219 {
220 // No match
221 if (Inodes[J] != Inodes[I])
222 continue;
223
224 // We score the two paths.. and erase one
225 int ScoreA = Score(List[I]);
226 int ScoreB = Score(List[J]);
227 if (ScoreA < ScoreB)
228 {
229 List[I] = string();
230 break;
231 }
232
233 List[J] = string();
234 }
235 }
236
237 // Wipe erased entries
238 for (unsigned int I = 0; I < List.size();)
239 {
240 if (List[I].empty() == false)
241 I++;
242 else
243 List.erase(List.begin()+I);
244 }
245
246 return true;
247}
248 /*}}}*/
4dfaa253
AL
249
250// ReduceSourceList - Takes the path list and reduces it /*{{{*/
251// ---------------------------------------------------------------------
252/* This takes the list of source list expressed entires and collects
253 similar ones to form a single entry for each dist */
254bool ReduceSourcelist(string CD,vector<string> &List)
255{
256 sort(List.begin(),List.end());
83d89a9f
AL
257
258 // Collect similar entries
259 for (vector<string>::iterator I = List.begin(); I != List.end(); I++)
260 {
261 // Find a space..
262 string::size_type Space = (*I).find(' ');
263 if (Space == string::npos)
264 continue;
4dfaa253
AL
265 string::size_type SSpace = (*I).find(' ',Space + 1);
266 if (SSpace == string::npos)
267 continue;
83d89a9f 268
4dfaa253 269 string Word1 = string(*I,Space,SSpace-Space);
83d89a9f
AL
270 for (vector<string>::iterator J = List.begin(); J != I; J++)
271 {
272 // Find a space..
273 string::size_type Space2 = (*J).find(' ');
274 if (Space2 == string::npos)
275 continue;
4dfaa253
AL
276 string::size_type SSpace2 = (*J).find(' ',Space2 + 1);
277 if (SSpace2 == string::npos)
278 continue;
83d89a9f 279
4dfaa253 280 if (string(*J,Space2,SSpace2-Space2) != Word1)
83d89a9f
AL
281 continue;
282
4dfaa253 283 *J += string(*I,SSpace);
83d89a9f
AL
284 *I = string();
285 }
286 }
287
288 // Wipe erased entries
289 for (unsigned int I = 0; I < List.size();)
290 {
291 if (List[I].empty() == false)
292 I++;
293 else
294 List.erase(List.begin()+I);
295 }
296}
297 /*}}}*/
18444708
AL
298// WriteDatabase - Write the CDROM Database file /*{{{*/
299// ---------------------------------------------------------------------
4dfaa253 300/* We rewrite the configuration class associated with the cdrom database. */
18444708
AL
301bool WriteDatabase(Configuration &Cnf)
302{
303 string DFile = _config->FindFile("Dir::State::cdroms");
4dfaa253
AL
304 string NewFile = DFile + ".new";
305
306 unlink(NewFile.c_str());
307 ofstream Out(NewFile.c_str());
18444708 308 if (!Out)
4dfaa253
AL
309 return _error->Errno("ofstream::ofstream",
310 "Failed to open %s.new",DFile.c_str());
18444708
AL
311
312 /* Write out all of the configuration directives by walking the
313 configuration tree */
314 const Configuration::Item *Top = Cnf.Tree(0);
315 for (; Top != 0;)
316 {
317 // Print the config entry
318 if (Top->Value.empty() == false)
319 Out << Top->FullTag() + " \"" << Top->Value << "\";" << endl;
320
321 if (Top->Child != 0)
322 {
323 Top = Top->Child;
324 continue;
325 }
326
327 while (Top != 0 && Top->Next == 0)
328 Top = Top->Parent;
329 if (Top != 0)
330 Top = Top->Next;
331 }
332
333 Out.close();
334
335 rename(DFile.c_str(),string(DFile + '~').c_str());
4dfaa253 336 if (rename(NewFile.c_str(),DFile.c_str()) != 0)
18444708
AL
337 return _error->Errno("rename","Failed to rename %s.new to %s",
338 DFile.c_str(),DFile.c_str());
339
340 return true;
341}
342 /*}}}*/
343// WriteSourceList - Write an updated sourcelist /*{{{*/
344// ---------------------------------------------------------------------
4dfaa253
AL
345/* This reads the old source list and copies it into the new one. It
346 appends the new CDROM entires just after the first block of comments.
347 This places them first in the file. It also removes any old entries
348 that were the same. */
143abaeb 349bool WriteSourceList(string Name,vector<string> &List,bool Source)
18444708 350{
143abaeb
AL
351 if (List.size() == 0)
352 return true;
353
4dfaa253
AL
354 string File = _config->FindFile("Dir::Etc::sourcelist");
355
356 // Open the stream for reading
357 ifstream F(File.c_str(),ios::in | ios::nocreate);
358 if (!F != 0)
359 return _error->Errno("ifstream::ifstream","Opening %s",File.c_str());
360
361 string NewFile = File + ".new";
362 unlink(NewFile.c_str());
363 ofstream Out(NewFile.c_str());
364 if (!Out)
365 return _error->Errno("ofstream::ofstream",
366 "Failed to open %s.new",File.c_str());
367
368 // Create a short uri without the path
369 string ShortURI = "cdrom:" + Name + "/";
143abaeb
AL
370
371 const char *Type;
372 if (Source == true)
373 Type = "deb-src";
374 else
375 Type = "deb";
4dfaa253
AL
376
377 char Buffer[300];
378 int CurLine = 0;
379 bool First = true;
380 while (F.eof() == false)
381 {
382 F.getline(Buffer,sizeof(Buffer));
383 CurLine++;
384 _strtabexpand(Buffer,sizeof(Buffer));
385 _strstrip(Buffer);
386
387 // Comment or blank
388 if (Buffer[0] == '#' || Buffer[0] == 0)
389 {
390 Out << Buffer << endl;
391 continue;
392 }
393
394 if (First == true)
395 {
396 for (vector<string>::iterator I = List.begin(); I != List.end(); I++)
397 {
398 string::size_type Space = (*I).find(' ');
399 if (Space == string::npos)
400 return _error->Error("Internal error");
143abaeb 401 Out << Type << " \"cdrom:" << Name << "/" << string(*I,0,Space) <<
4dfaa253
AL
402 "\" " << string(*I,Space+1) << endl;
403 }
404 }
405 First = false;
406
407 // Grok it
143abaeb 408 string cType;
4dfaa253 409 string URI;
5b76e7f2 410 const char *C = Buffer;
143abaeb 411 if (ParseQuoteWord(C,cType) == false ||
4dfaa253
AL
412 ParseQuoteWord(C,URI) == false)
413 {
414 Out << Buffer << endl;
415 continue;
416 }
417
418 // Emit lines like this one
143abaeb 419 if (cType != Type || string(URI,0,ShortURI.length()) != ShortURI)
4dfaa253
AL
420 {
421 Out << Buffer << endl;
422 continue;
423 }
424 }
425
426 // Just in case the file was empty
427 if (First == true)
428 {
429 for (vector<string>::iterator I = List.begin(); I != List.end(); I++)
430 {
431 string::size_type Space = (*I).find(' ');
432 if (Space == string::npos)
433 return _error->Error("Internal error");
434
435 Out << "deb \"cdrom:" << Name << "/" << string(*I,0,Space) <<
436 "\" " << string(*I,Space+1) << endl;
437 }
438 }
439
440 Out.close();
441
442 rename(File.c_str(),string(File + '~').c_str());
443 if (rename(NewFile.c_str(),File.c_str()) != 0)
444 return _error->Errno("rename","Failed to rename %s.new to %s",
445 File.c_str(),File.c_str());
446
18444708
AL
447 return true;
448}
449 /*}}}*/
83d89a9f
AL
450
451// Prompt - Simple prompt /*{{{*/
452// ---------------------------------------------------------------------
453/* */
454void Prompt(const char *Text)
455{
456 char C;
457 cout << Text << ' ' << flush;
458 read(STDIN_FILENO,&C,1);
459 if (C != '\n')
460 cout << endl;
461}
462 /*}}}*/
463// PromptLine - Prompt for an input line /*{{{*/
464// ---------------------------------------------------------------------
465/* */
466string PromptLine(const char *Text)
467{
468 cout << Text << ':' << endl;
469
470 string Res;
471 getline(cin,Res);
472 return Res;
473}
474 /*}}}*/
475
476// DoAdd - Add a new CDROM /*{{{*/
477// ---------------------------------------------------------------------
4dfaa253
AL
478/* This does the main add bit.. We show some status and things. The
479 sequence is to mount/umount the CD, Ident it then scan it for package
480 files and reduce that list. Then we copy over the package files and
481 verify them. Then rewrite the database files */
83d89a9f
AL
482bool DoAdd(CommandLine &)
483{
484 // Startup
485 string CDROM = _config->FindDir("Acquire::cdrom::mount","/cdrom/");
ac49a1e5
AL
486 if (CDROM[0] == '.')
487 CDROM= SafeGetCWD() + '/' + CDROM;
83d89a9f 488
ac49a1e5
AL
489 cout << "Using CD-ROM mount point " << CDROM << endl;
490
83d89a9f
AL
491 // Read the database
492 Configuration Database;
493 string DFile = _config->FindFile("Dir::State::cdroms");
494 if (FileExists(DFile) == true)
495 {
496 if (ReadConfigFile(Database,DFile) == false)
497 return _error->Error("Unable to read the cdrom database %s",
498 DFile.c_str());
499 }
500
501 // Unmount the CD and get the user to put in the one they want
502 if (_config->FindB("APT::CDROM::NoMount",false) == false)
503 {
504 cout << "Unmounting CD-ROM" << endl;
505 UnmountCdrom(CDROM);
18444708 506
83d89a9f 507 // Mount the new CDROM
6c907975 508 Prompt("Please insert a Disc in the drive and press enter");
83d89a9f
AL
509 cout << "Mounting CD-ROM" << endl;
510 if (MountCdrom(CDROM) == false)
6c907975 511 return _error->Error("Failed to mount the cdrom.");
83d89a9f
AL
512 }
513
514 // Hash the CD to get an ID
18444708 515 cout << "Identifying.. " << flush;
83d89a9f
AL
516 string ID;
517 if (IdentCdrom(CDROM,ID) == false)
ac49a1e5
AL
518 {
519 cout << endl;
83d89a9f 520 return false;
ac49a1e5
AL
521 }
522
83d89a9f
AL
523 cout << '[' << ID << ']' << endl;
524
525 cout << "Scanning Disc for index files.. " << flush;
526 // Get the CD structure
527 vector<string> List;
13d87e2e 528 vector<string> sList;
83d89a9f 529 string StartDir = SafeGetCWD();
22177db9 530 string InfoDir;
13d87e2e 531 if (FindPackages(CDROM,List,sList,InfoDir) == false)
ac49a1e5
AL
532 {
533 cout << endl;
83d89a9f 534 return false;
ac49a1e5
AL
535 }
536
83d89a9f 537 chdir(StartDir.c_str());
4dfaa253
AL
538
539 if (_config->FindB("Debug::aptcdrom",false) == true)
540 {
ed51f28e 541 cout << "I found (binary):" << endl;
4dfaa253 542 for (vector<string>::iterator I = List.begin(); I != List.end(); I++)
4dfaa253 543 cout << *I << endl;
ed51f28e
AL
544 cout << "I found (source):" << endl;
545 for (vector<string>::iterator I = sList.begin(); I != sList.end(); I++)
546 cout << *I << endl;
4dfaa253 547 }
83d89a9f
AL
548
549 // Fix up the list
550 DropBinaryArch(List);
13d87e2e
AL
551 DropRepeats(List,"Packages");
552 DropRepeats(sList,"Sources");
553 cout << "Found " << List.size() << " package indexes and " << sList.size() <<
554 " source indexes." << endl;
83d89a9f
AL
555
556 if (List.size() == 0)
4dfaa253 557 return _error->Error("Unable to locate any package files, perhaps this is not a Debian Disc");
83d89a9f
AL
558
559 // Check if the CD is in the database
560 string Name;
561 if (Database.Exists("CD::" + ID) == false ||
562 _config->FindB("APT::CDROM::Rename",false) == true)
563 {
4dfaa253 564 // Try to use the CDs label if at all possible
22177db9 565 if (InfoDir.empty() == false &&
1886ebc3 566 FileExists(InfoDir + "/info") == true)
4dfaa253 567 {
1886ebc3 568 ifstream F(string(InfoDir + "/info").c_str());
4dfaa253
AL
569 if (!F == 0)
570 getline(F,Name);
571
572 if (Name.empty() == false)
573 {
574 cout << "Found label '" << Name << "'" << endl;
575 Database.Set("CD::" + ID + "::Label",Name);
576 }
577 }
578
579 if (_config->FindB("APT::CDROM::Rename",false) == true ||
179ce12b 580 Name.empty() == true)
4dfaa253
AL
581 {
582 cout << "Please provide a name for this Disc, such as 'Debian 2.1r1 Disk 1'";
583 while (1)
584 {
585 Name = PromptLine("");
586 if (Name.empty() == false &&
735a058b
AL
587 Name.find('"') == string::npos &&
588 Name.find(':') == string::npos &&
4dfaa253
AL
589 Name.find('/') == string::npos)
590 break;
591 cout << "That is not a valid name, try again " << endl;
735a058b 592 }
4dfaa253 593 }
83d89a9f
AL
594 }
595 else
596 Name = Database.Find("CD::" + ID);
735a058b
AL
597
598 string::iterator J = Name.begin();
599 for (; J != Name.end(); J++)
600 if (*J == '/' || *J == '"' || *J == ':')
601 *J = '_';
602
18444708 603 Database.Set("CD::" + ID,Name);
83d89a9f
AL
604 cout << "This Disc is called '" << Name << "'" << endl;
605
606 // Copy the package files to the state directory
143abaeb
AL
607 PackageCopy Copy;
608 SourceCopy SrcCopy;
609 if (Copy.CopyPackages(CDROM,Name,List) == false ||
610 SrcCopy.CopyPackages(CDROM,Name,sList) == false)
83d89a9f
AL
611 return false;
612
4dfaa253 613 ReduceSourcelist(CDROM,List);
13d87e2e 614 ReduceSourcelist(CDROM,sList);
18444708
AL
615
616 // Write the database and sourcelist
617 if (_config->FindB("APT::cdrom::NoAct",false) == false)
618 {
619 if (WriteDatabase(Database) == false)
620 return false;
4dfaa253
AL
621
622 cout << "Writing new source list" << endl;
143abaeb
AL
623 if (WriteSourceList(Name,List,false) == false ||
624 WriteSourceList(Name,sList,true) == false)
4dfaa253 625 return false;
18444708 626 }
4dfaa253
AL
627
628 // Print the sourcelist entries
ab5498ab 629 cout << "Source List entries for this Disc are:" << endl;
4dfaa253
AL
630 for (vector<string>::iterator I = List.begin(); I != List.end(); I++)
631 {
632 string::size_type Space = (*I).find(' ');
633 if (Space == string::npos)
634 return _error->Error("Internal error");
635
636 cout << "deb \"cdrom:" << Name << "/" << string(*I,0,Space) <<
637 "\" " << string(*I,Space+1) << endl;
638 }
281daf46 639
13d87e2e
AL
640 for (vector<string>::iterator I = sList.begin(); I != sList.end(); I++)
641 {
642 string::size_type Space = (*I).find(' ');
643 if (Space == string::npos)
644 return _error->Error("Internal error");
645
646 cout << "deb-src \"cdrom:" << Name << "/" << string(*I,0,Space) <<
647 "\" " << string(*I,Space+1) << endl;
648 }
649
281daf46 650 cout << "Repeat this process for the rest of the CDs in your set." << endl;
83d89a9f
AL
651 return true;
652}
653 /*}}}*/
654
655// ShowHelp - Show the help screen /*{{{*/
656// ---------------------------------------------------------------------
657/* */
658int ShowHelp()
659{
660 cout << PACKAGE << ' ' << VERSION << " for " << ARCHITECTURE <<
661 " compiled on " << __DATE__ << " " << __TIME__ << endl;
04aa15a8
AL
662 if (_config->FindB("version") == true)
663 return 100;
83d89a9f
AL
664
665 cout << "Usage: apt-cdrom [options] command" << endl;
666 cout << endl;
667 cout << "apt-cdrom is a tool to add CDROM's to APT's source list. The " << endl;
668 cout << "CDROM mount point and device information is taken from apt.conf" << endl;
669 cout << "and /etc/fstab." << endl;
670 cout << endl;
671 cout << "Commands:" << endl;
672 cout << " add - Add a CDROM" << endl;
673 cout << endl;
674 cout << "Options:" << endl;
675 cout << " -h This help text" << endl;
676 cout << " -d CD-ROM mount point" << endl;
677 cout << " -r Rename a recognized CD-ROM" << endl;
678 cout << " -m No mounting" << endl;
18444708 679 cout << " -f Fast mode, don't check package files" << endl;
9bf3ee5c 680 cout << " -a Thorough scan mode" << endl;
83d89a9f 681 cout << " -c=? Read this configuration file" << endl;
7974b907 682 cout << " -o=? Set an arbitary configuration option, eg -o dir::cache=/tmp" << endl;
83d89a9f
AL
683 cout << "See fstab(5)" << endl;
684 return 100;
685}
686 /*}}}*/
687
688int main(int argc,const char *argv[])
689{
690 CommandLine::Args Args[] = {
691 {'h',"help","help",0},
04aa15a8 692 {'v',"version","version",0},
83d89a9f
AL
693 {'d',"cdrom","Acquire::cdrom::mount",CommandLine::HasArg},
694 {'r',"rename","APT::CDROM::Rename",0},
695 {'m',"no-mount","APT::CDROM::NoMount",0},
696 {'f',"fast","APT::CDROM::Fast",0},
c60d151b 697 {'n',"just-print","APT::CDROM::NoAct",0},
18444708 698 {'n',"recon","APT::CDROM::NoAct",0},
c60d151b
AL
699 {'n',"no-act","APT::CDROM::NoAct",0},
700 {'a',"thorough","APT::CDROM::Thorough",0},
83d89a9f
AL
701 {'c',"config-file",0,CommandLine::ConfigFile},
702 {'o',"option",0,CommandLine::ArbItem},
703 {0,0,0,0}};
704 CommandLine::Dispatch Cmds[] = {
705 {"add",&DoAdd},
706 {0,0}};
707
708 // Parse the command line and initialize the package library
709 CommandLine CmdL(Args,_config);
710 if (pkgInitialize(*_config) == false ||
711 CmdL.Parse(argc,argv) == false)
712 {
713 _error->DumpErrors();
714 return 100;
715 }
716
717 // See if the help should be shown
718 if (_config->FindB("help") == true ||
719 CmdL.FileSize() == 0)
720 return ShowHelp();
a9a5908d
AL
721
722 // Deal with stdout not being a tty
723 if (ttyname(STDOUT_FILENO) == 0 && _config->FindI("quiet",0) < 1)
724 _config->Set("quiet","1");
83d89a9f
AL
725
726 // Match the operation
727 CmdL.DispatchArg(Cmds);
728
729 // Print any errors or warnings found during parsing
730 if (_error->empty() == false)
731 {
732 bool Errors = _error->PendingError();
733 _error->DumpErrors();
734 return Errors == true?100:0;
735 }
736
737 return 0;
738}