diff options
Diffstat (limited to 'main/main.c')
-rw-r--r-- | main/main.c | 378 |
1 files changed, 378 insertions, 0 deletions
diff --git a/main/main.c b/main/main.c new file mode 100644 index 000000000..565541052 --- /dev/null +++ b/main/main.c @@ -0,0 +1,378 @@ +/* + * dpkg - main program for package management + * main.c - main program + * + * Copyright (C) 1994,1995 Ian Jackson <iwj10@cus.cam.ac.uk> + * + * This is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2, + * or (at your option) any later version. + * + * This is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with dpkg; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <signal.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <sys/wait.h> +#include <errno.h> +#include <unistd.h> +#include <dirent.h> +#include <limits.h> +#include <ctype.h> + +#include "config.h" +#include "dpkg.h" +#include "dpkg-db.h" +#include "version.h" +#include "myopt.h" + +#include "main.h" + +static void printversion(void) { + if (!fputs("Debian GNU/Linux `" DPKG "' package management program version " + DPKG_VERSION_ARCH ".\n" + "Copyright 1994,1995 Ian Jackson, Bruce Perens. This is free software;\n" + "see the GNU General Public Licence version 2 or later for copying\n" + "conditions. There is NO warranty. See dpkg --licence for details.\n", + stderr)) werr("stderr"); +} + +static void usage(void) { + if (!fputs("\ +Usage: " DPKG " -i|--install <.deb file name> ... | -R|--recursive <dir> ...\n\ + " DPKG " --unpack <.deb file name> ... | -R|--recursive <dir> ...\n\ + " DPKG " -A|--avail <.deb file name> ... | -R|--recursive <dir> ...\n\ + " DPKG " --configure <package name> ... | -a|--pending\n\ + " DPKG " -r|--remove | --purge <package name> ... | -a|--pending\n\ + " DPKG " -s|--status <package-name> ...\n\ + " DPKG " -L|--listfiles <package-name> ...\n\ + " DPKG " -l|--list [<package-name-pattern> ...]\n\ + " DPKG " -S|--search <filename-search-pattern> ...\n\ + " DPKG " -C|--audit | --yet-to-unpack\n\ + " DPKG " --merge-avail | --update-avail <Packages-file>\n\ +Use " DPKG " -b|--build|-c|--contents|-e|--control|-I|--info|-f|--field|\n\ + -x|--extract|-X|--vextract|--fsys-tarfile on archives (type " BACKEND " --help.)\n\ +For internal use: " DPKG " --assert-support-predepends | --predep-package\n\ +\n\ +Options: --help --version --licence --force-help -Dh|--debug=help\n\ + --root=<directory> --admindir=<directory> --instdir=<directory>\n\ + -O|--selected-only -E|--skip-same-version -G=--refuse-downgrade\n\ + -B|--auto-deconfigure --ignore-depends=<package>,...\n\ + -D|--debug=<octal> --force-... --no-force-...|--refuse-...\n\ + --largemem|--smallmem --no-act\n\ +\n\ +Use `" DSELECT "' for user-friendly package management.\n", + stderr)) werr("stderr"); +} + +const char thisname[]= DPKG; +const char architecture[]= ARCHITECTURE; +const char printforhelp[]= + "Type " DPKG " --help for help about installing and deinstalling packages;\n" + "Use " DSELECT " for user-friendly package management;\n" + "Type " DPKG " -Dhelp for a list of " DPKG " debug flag values;\n" + "Type " DPKG " --force-help for a list of forcing options;\n" + "Type " BACKEND " --help for help about manipulating *.deb files."; + +const struct cmdinfo *cipaction= 0; +int f_pending=0, f_recursive=0, f_alsoselect=1, f_skipsame=0, f_noact=0; +int f_autodeconf=0, f_largemem=0; +unsigned long f_debug=0; +int fc_downgrade=1, fc_configureany=0, fc_hold=0, fc_removereinstreq=0, fc_overwrite= 0; +int fc_removeessential=0, fc_conflicts=0, fc_depends=0, fc_dependsversion=0; +int fc_autoselect=1, fc_badpath=0, fc_overwritediverted=0, fc_architecture=0; + +const char *admindir= ADMINDIR; +const char *instdir= ""; +struct packageinlist *ignoredependss=0; + +static const struct forceinfo { + const char *name; + int *opt; +} forceinfos[]= { + { "downgrade", &fc_downgrade }, + { "configure-any", &fc_configureany }, + { "hold", &fc_hold }, + { "remove-reinstreq", &fc_removereinstreq }, + { "remove-essential", &fc_removeessential }, + { "conflicts", &fc_conflicts }, + { "depends", &fc_depends }, + { "depends-version", &fc_dependsversion }, + { "auto-select", &fc_autoselect }, + { "bad-path", &fc_badpath }, + { "overwrite", &fc_overwrite }, + { "overwrite-diverted", &fc_overwritediverted }, + { "architecture", &fc_architecture }, + { 0 } +}; + +static void helponly(const struct cmdinfo *cip, const char *value) { + usage(); exit(0); +} +static void versiononly(const struct cmdinfo *cip, const char *value) { + printversion(); exit(0); +} + +static void setaction(const struct cmdinfo *cip, const char *value) { + if (cipaction) + badusage("conflicting actions --%s and --%s",cip->olong,cipaction->olong); + cipaction= cip; +} + +static void setdebug(const struct cmdinfo *cpi, const char *value) { + char *endp; + + if (*value == 'h') { + if (!fputs( +DPKG " debugging option, --debug=<octal> or -D<octal>:\n\n\ + number ref. in source description\n\ + 1 general Generally helpful progress information\n\ + 2 scripts Invocation and status of maintainer scripts\n\ + 10 eachfile Output for each file processed\n\ + 100 eachfiledetail Lots of output for each file processed\n\ + 20 conff Output for each configuration file\n\ + 200 conffdetail Lots of output for each configuration file\n\ + 40 depcon Dependencies and conflicts\n\ + 400 depcondetail Lots of dependencies/conflicts output\n\ + 1000 veryverbose Lots of drivel about eg the dpkg/info directory\n\ + 2000 stupidlyverbose Insane amounts of drivel\n\n\ +Debugging options are be mixed using bitwise-or.\n\ +Note that the meanings and values are subject to change.\n", + stderr)) werr("stderr"); + exit(0); + } + + f_debug= strtoul(value,&endp,8); + if (*endp) badusage("--debug requires an octal argument"); +} + +static void setroot(const struct cmdinfo *cip, const char *value) { + char *p; + instdir= value; + p= m_malloc(strlen(value) + sizeof(ADMINDIR)); + strcpy(p,value); + strcat(p,ADMINDIR); + admindir= p; +} + +static void ignoredepends(const struct cmdinfo *cip, const char *value) { + char *copy, *p; + const char *pnerr; + struct packageinlist *ni; + + copy= m_malloc(strlen(value)+2); + strcpy(copy,value); + copy[strlen(value)+1]= 0; + for (p=copy; *p; p++) { + if (*p != ',') continue; + *p++= 0; + if (!*p || *p==',' || p==copy+1) + badusage("null package name in --ignore-depends comma-separated list `%.250s'", + value); + } + p= copy; + while (*p) { + pnerr= illegal_packagename(value,0); + if (pnerr) ohshite("--ignore-depends requires a legal package name. " + "`%.250s' is not; %s", value, pnerr); + ni= m_malloc(sizeof(struct packageinlist)); + ni->pkg= findpackage(value); + ni->next= ignoredependss; + ignoredependss= ni; + p+= strlen(p)+1; + } +} + +static void setforce(const struct cmdinfo *cip, const char *value) { + const char *comma; + int l; + const struct forceinfo *fip; + + if (!strcmp(value,"help")) { + if (!fputs( +DPKG " forcing options - control behaviour when problems found:\n\ + warn but continue: --force-<thing>,<thing>,...\n\ + stop with error: --refuse-<thing>,<thing>,... | --no-force-<thing>,...\n\ + Forcing things:\n\ + auto-select [*] (De)select packages to install (remove) them\n\ + dowgrade [*] Replace a package with a lower version\n\ + configure-any Configure any package which may help this one\n\ + hold Process packages which are on hold\n\ + bad-path PATH is missing important programs, problems likely\n\ + overwrite Overwrite a file from one package with another\n\ + overwrite-diverted Overwrite a diverted file with an undiverted version\n\ + depends-version [!] Turn dependency version problems into warnings\n\ + depends [!] Turn all dependency problems into warnings\n\ + conflicts [!] Allow installation of conflicting packages\n\ + architecture [!] Process even packages with wrong architecture\n\ + remove-reinstreq [!] Remove packages which require installation\n\ + remove-essential [!] Remove an essential package\n\ +\n\ +WARNING - use of options marked [!] can seriously damage your installation.\n\ +Forcing options marked [*] are enabled by default.\n", + stderr)) werr("stderr"); + exit(0); + } + + for (;;) { + comma= strchr(value,','); + l= comma ? (int)(comma-value) : strlen(value); + for (fip=forceinfos; fip->name; fip++) + if (!strncmp(fip->name,value,l) && strlen(fip->name)==l) break; + if (!fip->name) + badusage("unknown force/refuse option `%.*s'", l<250 ? l : 250, value); + *fip->opt= cip->arg; + if (!comma) break; + value= ++comma; + } +} + +static const char *const passlongopts[]= { + "build", "contents", "control", "info", "field", "extract", + "vextract", "fsys-tarfile", 0 +}; + +static const char passshortopts[]= "bceIfxX"; +static const char okpassshortopts[]= "D"; + +static const struct cmdinfo cmdinfos[]= { + { "install", 'i', 0, 0, 0, setaction, act_install }, + { "unpack", 0, 0, 0, 0, setaction, act_unpack }, + { "avail", 'A', 0, 0, 0, setaction, act_avail }, + { "configure", 0, 0, 0, 0, setaction, act_configure }, + { "remove", 'r', 0, 0, 0, setaction, act_remove }, + { "purge", 0, 0, 0, 0, setaction, act_purge }, + { "list", 'l', 0, 0, 0, setaction, act_list }, + { "status", 's', 0, 0, 0, setaction, act_status }, + { "search", 'S', 0, 0, 0, setaction, act_search }, + { "audit", 'C', 0, 0, 0, setaction, act_audit }, + { "listfiles", 'L', 0, 0, 0, setaction, act_listfiles }, + { "update-avail", 0, 0, 0, 0, setaction, act_avreplace }, + { "merge-avail", 0, 0, 0, 0, setaction, act_avmerge }, + { "yet-to-unpack", 0, 0, 0, 0, setaction, act_unpackchk }, + { "assert-support-predepends", 0, 0, 0, 0, setaction, act_assuppredep }, + { "print-architecture", 0, 0, 0, 0, setaction, act_printarch }, + { "predep-package", 0, 0, 0, 0, setaction, act_predeppackage }, + { "pending", 'a', 0, &f_pending, 0, 0, 1 }, + { "recursive", 'R', 0, &f_recursive, 0, 0, 1 }, + { "no-act", 0, 0, &f_noact, 0, 0, 1 }, + { 0, 'G', 0, &fc_downgrade, 0, 0, /* alias for --refuse */ 0 }, + { "selected-only", 'O', 0, &f_alsoselect, 0, 0, 0 }, + { "no-also-select", 'N', 0, &f_alsoselect, 0, 0, 0 /* fixme: remove eventually */ }, + { "skip-same-version", 'E', 0, &f_skipsame, 0, 0, 1 }, + { "auto-deconfigure", 'B', 0, &f_autodeconf, 0, 0, 1 }, + { "largemem", 0, 0, &f_largemem, 0, 0, 1 }, + { "smallmem", 0, 0, &f_largemem, 0, 0, -1 }, + { "root", 0, 1, 0, 0, setroot }, + { "admindir", 0, 1, 0, &admindir, 0 }, + { "instdir", 0, 1, 0, &instdir, 0 }, + { "ignore-depends", 0, 1, 0, 0, ignoredepends }, + { "force", 0, 2, 0, 0, setforce, 1 }, + { "refuse", 0, 2, 0, 0, setforce, 0 }, + { "no-force", 0, 2, 0, 0, setforce, 0 }, + { "debug", 'D', 1, 0, 0, setdebug }, + { "help", 'h', 0, 0, 0, helponly }, + { "version", 0, 0, 0, 0, versiononly }, + { "licence",/* UK spelling */ 0,0,0,0, showcopyright }, + { "license",/* US spelling */ 0,0,0,0, showcopyright }, + { 0, 0 } +}; + +static void execbackend(int argc, const char *const *argv) { + execvp(BACKEND, (char* const*) argv); + ohshite("failed to exec " BACKEND); +} + +int main(int argc, const char *const *argv) { + jmp_buf ejbuf; + int c; + const char *argp, *const *blongopts, *const *argvs; + + if (setjmp(ejbuf)) { /* expect warning about possible clobbering of argv */ + error_unwind(ehflag_bombout); exit(2); + } + push_error_handler(&ejbuf,print_error_fatal,0); + + umask(022); /* Make sure all our status databases are readable. */ + + for (argvs=argv+1; (argp= *argvs) && *argp++=='-'; argvs++) { + if (*argp++=='-') { + if (!strcmp(argp,"-")) break; + for (blongopts=passlongopts; *blongopts; blongopts++) { + if (!strcmp(argp,*blongopts)) execbackend(argc,argv); + } + } else { + if (!*--argp) break; + while ((c= *argp++)) { + if (strchr(passshortopts,c)) execbackend(argc,argv); + if (!strchr(okpassshortopts,c)) break; + } + } + } + + myopt(&argv,cmdinfos); + if (!cipaction) badusage("need an action option"); + + setvbuf(stdout,0,_IONBF,0); + filesdbinit(); + + switch (cipaction->arg) { + case act_install: case act_unpack: case act_avail: + checkpath(); + archivefiles(argv); + break; + case act_configure: case act_remove: case act_purge: + checkpath(); + packages(argv); + break; + case act_listfiles: case act_status: + enqperpackage(argv); + break; + case act_avreplace: + availablefrompackages(argv,1); + break; + case act_avmerge: + availablefrompackages(argv,0); + break; + case act_audit: + audit(argv); + break; + case act_unpackchk: + unpackchk(argv); + break; + case act_list: + listpackages(argv); + break; + case act_search: + searchfiles(argv); + break; + case act_assuppredep: + assertsupportpredepends(argv); + break; + case act_predeppackage: + predeppackage(argv); + break; + case act_printarch: + printarchitecture(argv); + break; + default: + internerr("unknown action"); + } + + set_error_display(0,0); + error_unwind(ehflag_normaltidy); + + return reportbroken_retexitstatus(); +} |