dpkg (1.1.4); priority=MEDIUM
[dpkg/dpkg.git] / main / main.c
1 /*
2  * dpkg - main program for package management
3  * main.c - main program
4  *
5  * Copyright (C) 1994,1995 Ian Jackson <iwj10@cus.cam.ac.uk>
6  *
7  * This is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as
9  * published by the Free Software Foundation; either version 2,
10  * or (at your option) any later version.
11  *
12  * This is distributed in the hope that it will be useful, but
13  * WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public
18  * License along with dpkg; if not, write to the Free Software
19  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20  */
21
22 #include <stdio.h>
23 #include <string.h>
24 #include <stdlib.h>
25 #include <signal.h>
26 #include <sys/stat.h>
27 #include <sys/types.h>
28 #include <sys/wait.h>
29 #include <errno.h>
30 #include <unistd.h>
31 #include <dirent.h>
32 #include <limits.h>
33 #include <ctype.h>
34
35 #include "config.h"
36 #include "dpkg.h"
37 #include "dpkg-db.h"
38 #include "version.h"
39 #include "myopt.h"
40
41 #include "main.h"
42
43 static void printversion(void) {
44   if (!fputs("Debian GNU/Linux `" DPKG "' package management program version "
45               DPKG_VERSION_ARCH ".\n"
46              "Copyright 1994,1995 Ian Jackson, Bruce Perens.  This is free software;\n"
47              "see the GNU General Public Licence version 2 or later for copying\n"
48              "conditions.  There is NO warranty.  See dpkg --licence for details.\n",
49              stderr)) werr("stderr");
50 }
51
52 static void usage(void) {
53   if (!fputs("\
54 Usage: " DPKG " -i|--install    <.deb file name> ... | -R|--recursive <dir> ...\n\
55        " DPKG " --unpack        <.deb file name> ... | -R|--recursive <dir> ...\n\
56        " DPKG " -A|--avail      <.deb file name> ... | -R|--recursive <dir> ...\n\
57        " DPKG " --configure     <package name> ... | -a|--pending\n\
58        " DPKG " -r|--remove | --purge <package name> ... | -a|--pending\n\
59        " DPKG " -s|--status       <package-name> ...\n\
60        " DPKG " -L|--listfiles    <package-name> ...\n\
61        " DPKG " -l|--list         [<package-name-pattern> ...]\n\
62        " DPKG " -S|--search       <filename-search-pattern> ...\n\
63        " DPKG " -C|--audit | --yet-to-unpack\n\
64        " DPKG " --merge-avail | --update-avail <Packages-file>\n\
65 Use " DPKG " -b|--build|-c|--contents|-e|--control|-I|--info|-f|--field|\n\
66  -x|--extract|-X|--vextract|--fsys-tarfile  on archives (type " BACKEND " --help.)\n\
67 For internal use: " DPKG " --assert-support-predepends | --predep-package\n\
68 \n\
69 Options: --help --version --licence   --force-help  -Dh|--debug=help\n\
70          --root=<directory>   --admindir=<directory>   --instdir=<directory>\n\
71          -O|--selected-only   -E|--skip-same-version   -G=--refuse-downgrade\n\
72          -B|--auto-deconfigure   --ignore-depends=<package>,...\n\
73          -D|--debug=<octal>   --force-...  --no-force-...|--refuse-...\n\
74          --largemem|--smallmem   --no-act\n\
75 \n\
76 Use `" DSELECT "' for user-friendly package management.\n",
77              stderr)) werr("stderr");
78 }
79
80 const char thisname[]= DPKG;
81 const char architecture[]= ARCHITECTURE;
82 const char printforhelp[]=
83  "Type " DPKG " --help for help about installing and deinstalling packages;\n"
84  "Use " DSELECT " for user-friendly package management;\n"
85  "Type " DPKG " -Dhelp for a list of " DPKG " debug flag values;\n"
86  "Type " DPKG " --force-help for a list of forcing options;\n"
87  "Type " BACKEND " --help for help about manipulating *.deb files.";
88
89 const struct cmdinfo *cipaction= 0;
90 int f_pending=0, f_recursive=0, f_alsoselect=1, f_skipsame=0, f_noact=0;
91 int f_autodeconf=0, f_largemem=0;
92 unsigned long f_debug=0;
93 int fc_downgrade=1, fc_configureany=0, fc_hold=0, fc_removereinstreq=0, fc_overwrite= 0;
94 int fc_removeessential=0, fc_conflicts=0, fc_depends=0, fc_dependsversion=0;
95 int fc_autoselect=1, fc_badpath=0, fc_overwritediverted=0, fc_architecture=0;
96
97 const char *admindir= ADMINDIR;
98 const char *instdir= "";
99 struct packageinlist *ignoredependss=0;
100
101 static const struct forceinfo {
102   const char *name;
103   int *opt;
104 } forceinfos[]= {
105   { "downgrade",           &fc_downgrade                },
106   { "configure-any",       &fc_configureany             },
107   { "hold",                &fc_hold                     },
108   { "remove-reinstreq",    &fc_removereinstreq          },
109   { "remove-essential",    &fc_removeessential          },
110   { "conflicts",           &fc_conflicts                },
111   { "depends",             &fc_depends                  },
112   { "depends-version",     &fc_dependsversion           },
113   { "auto-select",         &fc_autoselect               },
114   { "bad-path",            &fc_badpath                  },
115   { "overwrite",           &fc_overwrite                },
116   { "overwrite-diverted",  &fc_overwritediverted        },
117   { "architecture",        &fc_architecture             },
118   {  0                                                  }
119 };
120
121 static void helponly(const struct cmdinfo *cip, const char *value) {
122   usage(); exit(0);
123 }
124 static void versiononly(const struct cmdinfo *cip, const char *value) {
125   printversion(); exit(0);
126 }
127
128 static void setaction(const struct cmdinfo *cip, const char *value) {
129   if (cipaction)
130     badusage("conflicting actions --%s and --%s",cip->olong,cipaction->olong);
131   cipaction= cip;
132 }
133
134 static void setdebug(const struct cmdinfo *cpi, const char *value) {
135   char *endp;
136
137   if (*value == 'h') {
138     if (!fputs(
139 DPKG " debugging option, --debug=<octal> or -D<octal>:\n\n\
140  number  ref. in source   description\n\
141       1   general           Generally helpful progress information\n\
142       2   scripts           Invocation and status of maintainer scripts\n\
143      10   eachfile          Output for each file processed\n\
144     100   eachfiledetail    Lots of output for each file processed\n\
145      20   conff             Output for each configuration file\n\
146     200   conffdetail       Lots of output for each configuration file\n\
147      40   depcon            Dependencies and conflicts\n\
148     400   depcondetail      Lots of dependencies/conflicts output\n\
149    1000   veryverbose       Lots of drivel about eg the dpkg/info directory\n\
150    2000   stupidlyverbose   Insane amounts of drivel\n\n\
151 Debugging options are be mixed using bitwise-or.\n\
152 Note that the meanings and values are subject to change.\n",
153              stderr)) werr("stderr");
154     exit(0);
155   }
156   
157   f_debug= strtoul(value,&endp,8);
158   if (*endp) badusage("--debug requires an octal argument");
159 }
160
161 static void setroot(const struct cmdinfo *cip, const char *value) {
162   char *p;
163   instdir= value;
164   p= m_malloc(strlen(value) + sizeof(ADMINDIR));
165   strcpy(p,value);
166   strcat(p,ADMINDIR);
167   admindir= p;
168 }
169
170 static void ignoredepends(const struct cmdinfo *cip, const char *value) {
171   char *copy, *p;
172   const char *pnerr;
173   struct packageinlist *ni;
174
175   copy= m_malloc(strlen(value)+2);
176   strcpy(copy,value);
177   copy[strlen(value)+1]= 0;
178   for (p=copy; *p; p++) {
179     if (*p != ',') continue;
180     *p++= 0;
181     if (!*p || *p==',' || p==copy+1)
182       badusage("null package name in --ignore-depends comma-separated list `%.250s'",
183                value);
184   }
185   p= copy;
186   while (*p) {
187     pnerr= illegal_packagename(value,0);
188     if (pnerr) ohshite("--ignore-depends requires a legal package name. "
189                        "`%.250s' is not; %s", value, pnerr);
190     ni= m_malloc(sizeof(struct packageinlist));
191     ni->pkg= findpackage(value);
192     ni->next= ignoredependss;
193     ignoredependss= ni;
194     p+= strlen(p)+1;
195   }
196 }
197
198 static void setforce(const struct cmdinfo *cip, const char *value) {
199   const char *comma;
200   int l;
201   const struct forceinfo *fip;
202
203   if (!strcmp(value,"help")) {
204     if (!fputs(
205 DPKG " forcing options - control behaviour when problems found:\n\
206   warn but continue:  --force-<thing>,<thing>,...\n\
207   stop with error:    --refuse-<thing>,<thing>,... | --no-force-<thing>,...\n\
208  Forcing things:\n\
209   auto-select [*]        (De)select packages to install (remove) them\n\
210   dowgrade [*]           Replace a package with a lower version\n\
211   configure-any          Configure any package which may help this one\n\
212   hold                   Process packages which are on hold\n\
213   bad-path               PATH is missing important programs, problems likely\n\
214   overwrite              Overwrite a file from one package with another\n\
215   overwrite-diverted     Overwrite a diverted file with an undiverted version\n\
216   depends-version [!]    Turn dependency version problems into warnings\n\
217   depends [!]            Turn all dependency problems into warnings\n\
218   conflicts [!]          Allow installation of conflicting packages\n\
219   architecture [!]       Process even packages with wrong architecture\n\
220   remove-reinstreq [!]   Remove packages which require installation\n\
221   remove-essential [!]   Remove an essential package\n\
222 \n\
223 WARNING - use of options marked [!] can seriously damage your installation.\n\
224 Forcing options marked [*] are enabled by default.\n",
225                stderr)) werr("stderr");
226     exit(0);
227   }
228
229   for (;;) {
230     comma= strchr(value,',');
231     l= comma ? (int)(comma-value) : strlen(value);
232     for (fip=forceinfos; fip->name; fip++)
233       if (!strncmp(fip->name,value,l) && strlen(fip->name)==l) break;
234     if (!fip->name)
235       badusage("unknown force/refuse option `%.*s'", l<250 ? l : 250, value);
236     *fip->opt= cip->arg;
237     if (!comma) break;
238     value= ++comma;
239   }
240 }
241
242 static const char *const passlongopts[]= {
243   "build", "contents", "control", "info", "field", "extract",
244   "vextract", "fsys-tarfile", 0
245 };
246
247 static const char passshortopts[]= "bceIfxX";
248 static const char okpassshortopts[]= "D";
249
250 static const struct cmdinfo cmdinfos[]= {
251   { "install",           'i',  0,  0, 0,               setaction,     act_install    },
252   { "unpack",             0,   0,  0, 0,               setaction,     act_unpack     },
253   { "avail",             'A',  0,  0, 0,               setaction,     act_avail      },
254   { "configure",          0,   0,  0, 0,               setaction,     act_configure  },
255   { "remove",            'r',  0,  0, 0,               setaction,     act_remove     },
256   { "purge",              0,   0,  0, 0,               setaction,     act_purge      },
257   { "list",              'l',  0,  0, 0,               setaction,     act_list       },
258   { "status",            's',  0,  0, 0,               setaction,     act_status     },
259   { "search",            'S',  0,  0, 0,               setaction,     act_search     },
260   { "audit",             'C',  0,  0, 0,               setaction,     act_audit      },
261   { "listfiles",         'L',  0,  0, 0,               setaction,     act_listfiles  },
262   { "update-avail",       0,   0,  0, 0,               setaction,     act_avreplace  },
263   { "merge-avail",        0,   0,  0, 0,               setaction,     act_avmerge    },
264   { "yet-to-unpack",      0,   0,  0, 0,               setaction,     act_unpackchk  },
265   { "assert-support-predepends", 0, 0,  0, 0,          setaction,    act_assuppredep },
266   { "print-architecture", 0,   0,  0, 0,               setaction,     act_printarch  },
267   { "predep-package",     0,   0,  0, 0,               setaction,  act_predeppackage },
268   { "pending",           'a',  0,  &f_pending,     0,  0,             1              },
269   { "recursive",         'R',  0,  &f_recursive,   0,  0,             1              },
270   { "no-act",             0,   0,  &f_noact,       0,  0,             1              },
271   {  0,                  'G',  0,  &fc_downgrade,  0,  0, /* alias for --refuse */ 0 },
272   { "selected-only",     'O',  0,  &f_alsoselect,  0,  0,             0              },
273   { "no-also-select",  'N', 0, &f_alsoselect, 0, 0, 0 /* fixme: remove eventually */ },
274   { "skip-same-version", 'E',  0,  &f_skipsame,    0,  0,             1              },
275   { "auto-deconfigure",  'B',  0,  &f_autodeconf,  0,  0,             1              },
276   { "largemem",           0,   0,  &f_largemem,    0,  0,             1              },
277   { "smallmem",           0,   0,  &f_largemem,    0,  0,            -1              },
278   { "root",               0,   1,  0, 0,               setroot                       },
279   { "admindir",           0,   1,  0, &admindir,       0                             },
280   { "instdir",            0,   1,  0, &instdir,        0                             },
281   { "ignore-depends",     0,   1,  0, 0,               ignoredepends                 },
282   { "force",              0,   2,  0, 0,               setforce,      1              },
283   { "refuse",             0,   2,  0, 0,               setforce,      0              },
284   { "no-force",           0,   2,  0, 0,               setforce,      0              },
285   { "debug",             'D',  1,  0, 0,               setdebug                      },
286   { "help",              'h',  0,  0, 0,               helponly                      },
287   { "version",            0,   0,  0, 0,               versiononly                   },
288   { "licence",/* UK spelling */ 0,0,0,0,               showcopyright                 },
289   { "license",/* US spelling */ 0,0,0,0,               showcopyright                 },
290   {  0,                   0                                                          }
291 };
292
293 static void execbackend(int argc, const char *const *argv) {
294   execvp(BACKEND, (char* const*) argv);
295   ohshite("failed to exec " BACKEND);
296 }
297
298 int main(int argc, const char *const *argv) {
299   jmp_buf ejbuf;
300   int c;
301   const char *argp, *const *blongopts, *const *argvs;
302
303   if (setjmp(ejbuf)) { /* expect warning about possible clobbering of argv */
304     error_unwind(ehflag_bombout); exit(2);
305   }
306   push_error_handler(&ejbuf,print_error_fatal,0);
307
308   umask(022); /* Make sure all our status databases are readable. */
309   
310   for (argvs=argv+1; (argp= *argvs) && *argp++=='-'; argvs++) {
311     if (*argp++=='-') {
312       if (!strcmp(argp,"-")) break;
313       for (blongopts=passlongopts; *blongopts; blongopts++) {
314         if (!strcmp(argp,*blongopts)) execbackend(argc,argv);
315       }
316     } else {
317       if (!*--argp) break;
318       while ((c= *argp++)) {
319         if (strchr(passshortopts,c)) execbackend(argc,argv);
320         if (!strchr(okpassshortopts,c)) break;
321       }
322     }
323   }
324
325   myopt(&argv,cmdinfos);
326   if (!cipaction) badusage("need an action option");
327
328   setvbuf(stdout,0,_IONBF,0);
329   filesdbinit();
330   
331   switch (cipaction->arg) {
332   case act_install: case act_unpack: case act_avail:
333     checkpath();
334     archivefiles(argv);
335     break;
336   case act_configure: case act_remove: case act_purge:
337     checkpath();
338     packages(argv);
339     break;
340   case act_listfiles: case act_status:
341     enqperpackage(argv);
342     break;
343   case act_avreplace: 
344     availablefrompackages(argv,1);
345     break;
346   case act_avmerge:
347     availablefrompackages(argv,0);
348     break;
349   case act_audit:
350     audit(argv);
351     break;
352   case act_unpackchk:
353     unpackchk(argv);
354     break;
355   case act_list:
356     listpackages(argv);
357     break;
358   case act_search:
359     searchfiles(argv);
360     break;
361   case act_assuppredep:
362     assertsupportpredepends(argv);
363     break;
364   case act_predeppackage:
365     predeppackage(argv);
366     break;
367   case act_printarch:
368     printarchitecture(argv);
369     break;
370   default:
371     internerr("unknown action");
372   }
373
374   set_error_display(0,0);
375   error_unwind(ehflag_normaltidy);
376
377   return reportbroken_retexitstatus();
378 }