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