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