LCOV - code coverage report
Current view: top level - src - main.c (source / functions) Hit Total Coverage
Test: cov.info Lines: 169 363 46.6 %
Date: 2015-08-15 Functions: 8 12 66.7 %

          Line data    Source code
       1             : /*-
       2             :  * Copyright (c) 2011-2013 Baptiste Daroussin <bapt@FreeBSD.org>
       3             :  * Copyright (c) 2011-2012 Julien Laffaye <jlaffaye@FreeBSD.org>
       4             :  * Copyright (c) 2011 Will Andrews <will@FreeBSD.org>
       5             :  * Copyright (c) 2011-2012 Marin Atanasov Nikolov <dnaeon@gmail.com>
       6             :  * Copyright (c) 2014-2015 Matthew Seaman <matthew@FreeBSD.org>
       7             :  * Copyright (c) 2014 Vsevolod Stakhov <vsevolod@FreeBSD.org>
       8             :  * All rights reserved.
       9             :  *
      10             :  * Redistribution and use in source and binary forms, with or without
      11             :  * modification, are permitted provided that the following conditions
      12             :  * are met:
      13             :  * 1. Redistributions of source code must retain the above copyright
      14             :  *    notice, this list of conditions and the following disclaimer
      15             :  *    in this position and unchanged.
      16             :  * 2. Redistributions in binary form must reproduce the above copyright
      17             :  *    notice, this list of conditions and the following disclaimer in the
      18             :  *    documentation and/or other materials provided with the distribution.
      19             :  *
      20             :  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
      21             :  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
      22             :  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
      23             :  * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
      24             :  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
      25             :  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
      26             :  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
      27             :  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
      28             :  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
      29             :  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
      30             :  */
      31             : 
      32             : #ifdef HAVE_CONFIG_H
      33             : #include "pkg_config.h"
      34             : #endif
      35             : 
      36             : #include <sys/param.h>
      37             : 
      38             : #include <sys/stat.h>
      39             : #include <sys/queue.h>
      40             : #include <sys/sbuf.h>
      41             : #include <sys/types.h>
      42             : #include <sys/wait.h>
      43             : 
      44             : #include <assert.h>
      45             : #include <ctype.h>
      46             : #include <err.h>
      47             : #include <errno.h>
      48             : #include <getopt.h>
      49             : #include <inttypes.h>
      50             : #include <stdio.h>
      51             : #include <stdlib.h>
      52             : #include <string.h>
      53             : #include <sysexits.h>
      54             : #include <unistd.h>
      55             : #ifdef HAVE_LIBJAIL
      56             : #include <jail.h>
      57             : #include <sys/jail.h>
      58             : #endif
      59             : #include <signal.h>
      60             : 
      61             : #include <pkg.h>
      62             : 
      63             : #include "pkgcli.h"
      64             : 
      65             : /* Used to define why do we show usage message to a user */
      66             : enum pkg_usage_reason {
      67             :         PKG_USAGE_ERROR,
      68             :         PKG_USAGE_UNKNOWN_COMMAND,
      69             :         PKG_USAGE_INVALID_ARGUMENTS,
      70             :         PKG_USAGE_HELP
      71             : };
      72             : 
      73             : static void usage(const char *, const char *, FILE *, enum pkg_usage_reason, ...);
      74             : static void usage_help(void);
      75             : static int exec_help(int, char **);
      76             : 
      77             : static struct commands {
      78             :         const char * const name;
      79             :         const char * const desc;
      80             :         int (*exec)(int argc, char **argv);
      81             :         void (* const usage)(void);
      82             : } cmd[] = {
      83             :         { "add", "Compatibility interface to install a package", exec_add, usage_add},
      84             :         { "alias", "List the command line aliases", exec_alias, usage_alias},
      85             :         { "annotate", "Add, modify or delete tag-value style annotations on packages", exec_annotate, usage_annotate},
      86             :         { "audit", "Reports vulnerable packages", exec_audit, usage_audit},
      87             :         { "autoremove", "Removes orphan packages", exec_autoremove, usage_autoremove},
      88             :         { "backup", "Backs-up and restores the local package database", exec_backup, usage_backup},
      89             :         { "check", "Checks for missing dependencies and database consistency", exec_check, usage_check},
      90             :         { "clean", "Cleans old packages from the cache", exec_clean, usage_clean},
      91             :         { "config", "Display the value of the configuration options", exec_config, usage_config},
      92             :         { "convert", "Convert database from/to pkgng", exec_convert, usage_convert},
      93             :         { "create", "Creates software package distributions", exec_create, usage_create},
      94             :         { "delete", "Deletes packages from the database and the system", exec_delete, usage_delete},
      95             :         { "fetch", "Fetches packages from a remote repository", exec_fetch, usage_fetch},
      96             :         { "help", "Displays help information", exec_help, usage_help},
      97             :         { "info", "Displays information about installed packages", exec_info, usage_info},
      98             :         { "install", "Installs packages from remote package repositories and local archives", exec_install, usage_install},
      99             :         { "lock", "Locks package against modifications or deletion", exec_lock, usage_lock},
     100             :         { "plugins", "Manages plugins and displays information about plugins", exec_plugins, usage_plugins},
     101             :         { "query", "Queries information about installed packages", exec_query, usage_query},
     102             :         { "register", "Registers a package into the local database", exec_register, usage_register},
     103             :         { "remove", "Deletes packages from the database and the system", exec_delete, usage_delete},
     104             :         { "repo", "Creates a package repository catalogue", exec_repo, usage_repo},
     105             :         { "rquery", "Queries information in repository catalogues", exec_rquery, usage_rquery},
     106             :         { "search", "Performs a search of package repository catalogues", exec_search, usage_search},
     107             :         { "set", "Modifies information about packages in the local database", exec_set, usage_set},
     108             :         { "ssh", "Package server (to be used via ssh)", exec_ssh, usage_ssh},
     109             :         { "shell", "Opens a debug shell", exec_shell, usage_shell},
     110             :         { "shlib", "Displays which packages link against a specific shared library", exec_shlib, usage_shlib},
     111             :         { "stats", "Displays package database statistics", exec_stats, usage_stats},
     112             :         { "unlock", "Unlocks a package, allowing modification or deletion", exec_unlock, usage_lock},
     113             :         { "update", "Updates package repository catalogues", exec_update, usage_update},
     114             :         { "updating", "Displays UPDATING information for a package", exec_updating, usage_updating},
     115             :         { "upgrade", "Performs upgrades of packaged software distributions", exec_upgrade, usage_upgrade},
     116             :         { "version", "Displays the versions of installed packages", exec_version, usage_version},
     117             :         { "which", "Displays which package installed a specific file", exec_which, usage_which},
     118             : };
     119             : 
     120             : static const unsigned int cmd_len = NELEM(cmd);
     121             : 
     122             : static STAILQ_HEAD(, plugcmd) plugins = STAILQ_HEAD_INITIALIZER(plugins);
     123             : struct plugcmd {
     124             :         const char *name;
     125             :         const char *desc;
     126             :         int (*exec)(int argc, char **argv);
     127             :         STAILQ_ENTRY(plugcmd) next;
     128             : };
     129             : 
     130             : typedef int (register_cmd)(int idx, const char **name, const char **desc, int (**exec)(int argc, char **argv));
     131             : typedef int (nb_cmd)(void);
     132             : 
     133             : static void
     134           0 : show_command_names(void)
     135             : {
     136             :         unsigned        i;
     137             : 
     138           0 :         for(i = 0; i < cmd_len; i++)
     139           0 :                 printf("%s\n", cmd[i].name);
     140             : 
     141           0 :         return;
     142             : }
     143             : 
     144             : static void
     145           0 : usage(const char *conffile, const char *reposdir, FILE *out, enum pkg_usage_reason reason, ...)
     146             : {
     147             :         struct plugcmd *c;
     148           0 :         bool plugins_enabled = false;
     149             :         unsigned int i;
     150             :         const char *arg;
     151             :         va_list vp;
     152             : 
     153           0 :         if (reason == PKG_USAGE_UNKNOWN_COMMAND) {
     154           0 :                 va_start(vp, reason);
     155           0 :                 arg = va_arg(vp, const char *);
     156           0 :                 va_end(vp);
     157           0 :                 fprintf(out, "pkg: unknown command: %s\n", arg);
     158           0 :                 goto out;
     159             :         }
     160           0 :         else if (reason == PKG_USAGE_INVALID_ARGUMENTS) {
     161           0 :                 va_start(vp, reason);
     162           0 :                 arg = va_arg(vp, const char *);
     163           0 :                 va_end(vp);
     164           0 :                 fprintf(out, "pkg: %s\n", arg);
     165             :         }
     166             : 
     167             : #ifdef HAVE_LIBJAIL
     168             : #define JAIL_ARG        "-j <jail name or id>|"
     169             : #else
     170             : #define JAIL_ARG
     171             : #endif
     172           0 :         fprintf(out, "Usage: pkg [-v] [-d] [-l] [-N] ["JAIL_ARG"-c <chroot path>|-r <rootdir>] [-C <configuration file>] [-R <repo config dir>] [-o var=value] [-4|-6] <command> [<args>]\n");
     173           0 :         if (reason == PKG_USAGE_HELP) {
     174           0 :                 fprintf(out, "Global options supported:\n");
     175           0 :                 fprintf(out, "\t%-15s%s\n", "-d", "Increment debug level");
     176             : #ifdef HAVE_LIBJAIL
     177           0 :                 fprintf(out, "\t%-15s%s\n", "-j", "Execute pkg(8) inside a jail(8)");
     178             : #endif
     179           0 :                 fprintf(out, "\t%-15s%s\n", "-R", "Execute pkg(8) using relocating installation to <rootdir>");
     180           0 :                 fprintf(out, "\t%-15s%s\n", "-c", "Execute pkg(8) inside a chroot(8)");
     181           0 :                 fprintf(out, "\t%-15s%s\n", "-C", "Use the specified configuration file");
     182           0 :                 fprintf(out, "\t%-15s%s\n", "-R", "Directory to search for individual repository configurations");
     183           0 :                 fprintf(out, "\t%-15s%s\n", "-l", "List available commands and exit");
     184           0 :                 fprintf(out, "\t%-15s%s\n", "-v", "Display pkg(8) version");
     185           0 :                 fprintf(out, "\t%-15s%s\n", "-N", "Test if pkg(8) is activated and avoid auto-activation");
     186           0 :                 fprintf(out, "\t%-15s%s\n", "-o", "Override configuration option from the command line");
     187           0 :                 fprintf(out, "\t%-15s%s\n", "-4", "Only use IPv4");
     188           0 :                 fprintf(out, "\t%-15s%s\n", "-6", "Only use IPv6");
     189           0 :                 fprintf(out, "\nCommands supported:\n");
     190             : 
     191           0 :                 for (i = 0; i < cmd_len; i++)
     192           0 :                         fprintf(out, "\t%-15s%s\n", cmd[i].name, cmd[i].desc);
     193             : 
     194           0 :                 if (!pkg_initialized() && pkg_ini(conffile, reposdir, 0) != EPKG_OK)
     195           0 :                         errx(EX_SOFTWARE, "Cannot parse configuration file!");
     196             : 
     197           0 :                 plugins_enabled = pkg_object_bool(pkg_config_get("PKG_ENABLE_PLUGINS"));
     198             : 
     199           0 :                 if (plugins_enabled) {
     200           0 :                         if (pkg_plugins_init() != EPKG_OK)
     201           0 :                                 errx(EX_SOFTWARE, "Plugins cannot be loaded");
     202             : 
     203           0 :                         fprintf(out, "\nCommands provided by plugins:\n");
     204             : 
     205           0 :                         STAILQ_FOREACH(c, &plugins, next)
     206           0 :                         fprintf(out, "\t%-15s%s\n", c->name, c->desc);
     207             :                 }
     208           0 :                 fprintf(out, "\nFor more information on the different commands"
     209             :                                         " see 'pkg help <command>'.\n");
     210           0 :                 exit(EXIT_SUCCESS);
     211             :         }
     212             : 
     213             : out:
     214           0 :         fprintf(out, "\nFor more information on available commands and options see 'pkg help'.\n");
     215           0 :         exit(EX_USAGE);
     216             : }
     217             : 
     218             : static void
     219           0 : usage_help(void)
     220             : {
     221           0 :         usage(NULL, NULL, stdout, PKG_USAGE_HELP);
     222           0 : }
     223             : 
     224             : static int
     225           0 : exec_help(int argc, char **argv)
     226             : {
     227             :         char *manpage;
     228           0 :         bool plugins_enabled = false;
     229             :         struct plugcmd *c;
     230             :         unsigned int i;
     231             :         const pkg_object *all_aliases;
     232             :         const pkg_object *alias;
     233           0 :         pkg_iter it = NULL;
     234             : 
     235           0 :         if ((argc != 2) || (strcmp("help", argv[1]) == 0)) {
     236           0 :                 usage_help();
     237           0 :                 return(EX_USAGE);
     238             :         }
     239             : 
     240           0 :         for (i = 0; i < cmd_len; i++) {
     241           0 :                 if (strcmp(cmd[i].name, argv[1]) == 0) {
     242           0 :                         if (asprintf(&manpage, "/usr/bin/man pkg-%s", cmd[i].name) == -1)
     243           0 :                                 errx(EX_SOFTWARE, "cannot allocate memory");
     244             : 
     245           0 :                         system(manpage);
     246           0 :                         free(manpage);
     247             : 
     248           0 :                         return (0);
     249             :                 }
     250             :         }
     251             : 
     252           0 :         plugins_enabled = pkg_object_bool(pkg_config_get("PKG_ENABLE_PLUGINS"));
     253             : 
     254           0 :         if (plugins_enabled) {
     255           0 :                 STAILQ_FOREACH(c, &plugins, next) {
     256           0 :                         if (strcmp(c->name, argv[1]) == 0) {
     257           0 :                                 if (asprintf(&manpage, "/usr/bin/man pkg-%s", c->name) == -1)
     258           0 :                                         errx(EX_SOFTWARE, "cannot allocate memory");
     259             : 
     260           0 :                                 system(manpage);
     261           0 :                                 free(manpage);
     262             : 
     263           0 :                                 return (0);
     264             :                         }
     265             :                 }
     266             :         }
     267             : 
     268           0 :         if (strcmp(argv[1], "pkg") == 0) {
     269           0 :                 system("/usr/bin/man 8 pkg");
     270           0 :                 return (0);
     271           0 :         } else if (strcmp(argv[1], "pkg.conf") == 0) {
     272           0 :                 system("/usr/bin/man 5 pkg.conf");
     273           0 :                 return (0);
     274             :         }
     275             : 
     276             :         /* Try aliases */
     277           0 :         all_aliases = pkg_config_get("ALIAS");
     278           0 :         while ((alias = pkg_object_iterate(all_aliases, &it))) {
     279           0 :                 if (strcmp(argv[1], pkg_object_key(alias)) == 0) {
     280           0 :                         printf("`%s` is an alias to `%s`\n", argv[1], pkg_object_string(alias));
     281           0 :                         return (0);
     282             :                 }
     283             :         }
     284             : 
     285             :         /* Command name not found */
     286           0 :         warnx("'%s' is not a valid command.\n", argv[1]);
     287             : 
     288           0 :         fprintf(stderr, "See 'pkg help' for more information on the commands.\n");
     289             : 
     290           0 :         return (EX_USAGE);
     291             : }
     292             : 
     293             : static void
     294           2 : show_plugin_info(void)
     295             : {
     296             :         const pkg_object        *conf;
     297           2 :         struct pkg_plugin       *p = NULL;
     298             : 
     299           4 :         while (pkg_plugins(&p) == EPKG_OK) {
     300           0 :                 conf = pkg_plugin_conf(p);
     301           0 :                 printf("Configuration for plugin: %s\n",
     302             :                     pkg_plugin_get(p, PKG_PLUGIN_NAME));
     303             : 
     304           0 :                 printf("%s\n", pkg_object_dump(conf));
     305             :         }
     306           2 : }
     307             : 
     308             : static void
     309           2 : show_repository_info(void)
     310             : {
     311             :         const char      *mirror, *sig;
     312           2 :         struct pkg_repo *repo = NULL;
     313             : 
     314           2 :         printf("\nRepositories:\n");
     315           7 :         while (pkg_repos(&repo) == EPKG_OK) {
     316           3 :                 switch (pkg_repo_mirror_type(repo)) {
     317             :                 case SRV:
     318           0 :                         mirror = "SRV";
     319           0 :                         break;
     320             :                 case HTTP:
     321           0 :                         mirror = "HTTP";
     322           0 :                         break;
     323             :                 case NOMIRROR:
     324           3 :                         mirror = "NONE";
     325           3 :                         break;
     326             :                 default:
     327           0 :                         mirror = "-unknown-";
     328           0 :                         break;
     329             :                 }
     330           3 :                 switch (pkg_repo_signature_type(repo)) {
     331             :                 case SIG_PUBKEY:
     332           0 :                         sig = "PUBKEY";
     333           0 :                         break;
     334             :                 case SIG_FINGERPRINT:
     335           0 :                         sig = "FINGERPRINTS";
     336           0 :                         break;
     337             :                 case SIG_NONE:
     338           3 :                         sig = "NONE";
     339           3 :                         break;
     340             :                 default:
     341           0 :                         sig = "-unknown-";
     342           0 :                         break;
     343             :                 }
     344             : 
     345           6 :                 printf("  %s: { \n    %-16s: \"%s\",\n    %-16s: %s,\n"
     346             :                        "    %-16s: %u",
     347             :                     pkg_repo_name(repo),
     348             :                     "url", pkg_repo_url(repo),
     349           3 :                     "enabled", pkg_repo_enabled(repo) ? "yes" : "no",
     350             :                     "priority", pkg_repo_priority(repo));
     351             : 
     352           3 :                 if (pkg_repo_mirror_type(repo) != NOMIRROR)
     353           0 :                         printf(",\n    %-16s: \"%s\"",
     354             :                             "mirror_type", mirror);
     355           3 :                 if (pkg_repo_signature_type(repo) != SIG_NONE)
     356           0 :                         printf(",\n    %-16s: \"%s\"",
     357             :                             "signature_type", sig);
     358           3 :                 if (pkg_repo_fingerprints(repo) != NULL)
     359           0 :                         printf(",\n    %-16s: \"%s\"",
     360             :                             "fingerprints", pkg_repo_fingerprints(repo));
     361           3 :                 if (pkg_repo_key(repo) != NULL)
     362           0 :                         printf(",\n    %-16s: \"%s\"",
     363             :                             "pubkey", pkg_repo_key(repo));
     364           3 :                 printf("\n  }\n");
     365             :         }
     366           2 : }
     367             : 
     368             : static void
     369           2 : show_version_info(int version)
     370             : {
     371           2 :         if (version > 1)
     372           2 :                 printf("%-24s: ", "Version");
     373             : 
     374           2 :         printf(PKG_PORTVERSION""GITHASH"\n");
     375             : 
     376           2 :         if (version == 1)
     377           0 :                 exit(EX_OK);
     378             : 
     379           2 :         printf("%s\n", pkg_config_dump());
     380           2 :         show_plugin_info();
     381           2 :         show_repository_info();
     382             : 
     383           2 :         exit(EX_OK);
     384             :         /* NOTREACHED */
     385             : }
     386             : 
     387             : static void
     388           1 : do_activation_test(int argc)
     389             : {
     390             :         int     count;
     391             : 
     392             :         /* Test to see if pkg(8) has been activated.  Exit with an
     393             :            error code if not.  Can be combined with -c and -j to test
     394             :            if pkg is activated in chroot or jail. If there are no
     395             :            other arguments, and pkg(8) has been activated, show how
     396             :            many packages have been installed. */
     397             : 
     398           1 :         switch (pkg_status(&count)) {
     399             :         case PKG_STATUS_UNINSTALLED: /* This case shouldn't ever happen... */
     400           0 :                 errx(EX_UNAVAILABLE, "can't execute " PKG_EXEC_NAME
     401             :                     " or " PKG_STATIC_NAME "\n");
     402             :                 /* NOTREACHED */
     403             :         case PKG_STATUS_NODB:
     404           1 :                 errx(EX_UNAVAILABLE, "package database non-existent");
     405             :                 /* NOTREACHED */
     406             :         case PKG_STATUS_NOPACKAGES:
     407           0 :                 errx(EX_UNAVAILABLE, "no packages registered");
     408             :                 /* NOTREACHED */
     409             :         case PKG_STATUS_ACTIVE:
     410           0 :                 if (argc == 0) {
     411           0 :                         warnx("%d packages installed", count);
     412           0 :                         exit(EX_OK);
     413             :                 }
     414           0 :                 break;
     415             :         }
     416           0 :         return;
     417             : }
     418             : 
     419             : static void
     420          57 : export_arg_option (char *arg)
     421             : {
     422             :         char *eqp;
     423             :         const char *opt;
     424             : 
     425          57 :         if ((eqp = strchr(arg, '=')) != NULL) {
     426          57 :                 *eqp = '\0';
     427             : 
     428          57 :                 if ((opt = getenv (arg)) != NULL) {
     429           0 :                         warnx("option %s is defined in the environment to '%s' but command line "
     430             :                                         "option redefines it", arg, opt);
     431           0 :                         setenv(arg, eqp + 1, 1);
     432             :                 }
     433             :                 else {
     434          57 :                         setenv(arg, eqp + 1, 0);
     435             :                 }
     436             : 
     437          57 :                 *eqp = '=';
     438             :         }
     439          57 : }
     440             : 
     441             : static void
     442         381 : start_process_worker(char *const *save_argv)
     443             : {
     444         381 :         int     ret = EX_OK;
     445             :         int     status;
     446             :         pid_t   child_pid;
     447             : 
     448             :         /* Fork off a child process to do the actual package work.
     449             :          * The child may be jailed or chrooted.  If a restart is required
     450             :          * (eg. pkg(8) inself was upgraded) the child can exit with
     451             :          * 'EX_NEEDRESTART' and the same forking process will be
     452             :          * replayed.  This function returns control in the child
     453             :          * process only. */
     454             : 
     455             :         while (1) {
     456         381 :                 child_pid = fork();
     457             : 
     458         381 :                 if (child_pid == 0) {
     459             :                         /* Load the new Pkg image */
     460         200 :                         if (ret == EX_NEEDRESTART)
     461           0 :                                 execvp(getprogname(), save_argv);
     462         400 :                         return;
     463             :                 } else {
     464         181 :                         if (child_pid == -1)
     465           0 :                                 err(EX_OSERR, "Failed to fork worker process");
     466             : 
     467         362 :                         while (waitpid(child_pid, &status, 0) == -1) {
     468           0 :                                 if (errno != EINTR)
     469           0 :                                         err(EX_OSERR, "Child process pid=%d", (int)child_pid);
     470             :                         }
     471             : 
     472         181 :                         ret = WEXITSTATUS(status);
     473             : 
     474         181 :                         if (WIFEXITED(status) && ret != EX_NEEDRESTART)
     475         181 :                                 break;
     476           0 :                         if (WIFSIGNALED(status)) {
     477             :                                 /* Process got some terminating signal, hence stop the loop */
     478           0 :                                 fprintf(stderr, "Child process pid=%d terminated abnormally: %s\n",
     479             :                                                 (int)child_pid, strsignal (WTERMSIG(status)));
     480           0 :                                 ret = -(WTERMSIG(status));
     481           0 :                                 break;
     482             :                         }
     483             :                 }
     484           0 :         }
     485             : 
     486         181 :         exit(ret);
     487             :         /* NOTREACHED */
     488             : }
     489             : 
     490             : static int
     491         199 : expand_aliases(int argc, char ***argv)
     492             : {
     493         199 :         pkg_iter                  it = NULL;
     494             :         const pkg_object         *all_aliases;
     495             :         const pkg_object         *alias;
     496             :         const char               *alias_value;
     497             :         void                     *buf;
     498         199 :         char                    **oldargv = *argv;
     499             :         char                    **newargv;
     500             :         char                     *args;
     501             :         int                       newargc;
     502             :         int                       spaces;
     503             :         int                       i;
     504             :         size_t                    veclen;
     505             :         size_t                    arglen;
     506         199 :         bool                      matched = false;
     507             : 
     508         199 :         all_aliases = pkg_config_get("ALIAS");
     509             : 
     510         199 :         while ((alias = pkg_object_iterate(all_aliases, &it))) {
     511        4292 :                 if (strcmp(oldargv[0], pkg_object_key(alias)) == 0) {
     512           2 :                         matched = true;
     513           2 :                         break;
     514             :                 }
     515             :         }
     516             : 
     517         199 :         if (!matched || (alias_value = pkg_object_string(alias)) == NULL)
     518         197 :                 return (argc);  /* Nothing to do */
     519             : 
     520             :         /* Estimate how many args alias_value will split into by
     521             :          * counting the number of whitespace characters in it. This
     522             :          * will be at minimum one less than the final argc. We'll be
     523             :          * consuming one of the orginal argv, so that balances
     524             :          * out. */
     525             : 
     526           2 :         spaces = pkg_utils_count_spaces(alias_value);
     527           2 :         arglen = strlen(alias_value) + 1;
     528           2 :         veclen = sizeof(char *) * (spaces + argc + 1);
     529           2 :         buf = malloc(veclen + arglen);
     530           2 :         if (buf == NULL)
     531           0 :                 err(EX_OSERR, "expanding aliases");
     532             : 
     533           2 :         newargv = (char **) buf;
     534           2 :         args = (char *) (buf + veclen);
     535           2 :         strlcpy(args, alias_value, arglen);
     536             : 
     537           2 :         newargc = 0;
     538           8 :         while(args != NULL) {
     539           4 :                 newargv[newargc++] = pkg_utils_tokenize(&args);
     540             :         }
     541           2 :         for (i = 1; i < argc; i++) {
     542           0 :                 newargv[newargc++] = oldargv[i];
     543             :         }
     544           2 :         newargv[newargc] = NULL;
     545             : 
     546           2 :         *argv = newargv;
     547           2 :         return (newargc);
     548             : }
     549             : 
     550             : int
     551         383 : main(int argc, char **argv)
     552             : {
     553             :         unsigned int      i;
     554         383 :         struct commands  *command = NULL;
     555         383 :         unsigned int      ambiguous = 0;
     556         383 :         const char       *chroot_path = NULL;
     557         383 :         const char       *rootdir = NULL;
     558             : #ifdef HAVE_LIBJAIL
     559             :         int               jid;
     560             : #endif
     561         383 :         const char       *jail_str = NULL;
     562             :         size_t            len;
     563             :         signed char       ch;
     564         383 :         int64_t           debug = 0;
     565         383 :         int               version = 0;
     566         383 :         int               ret = EX_OK;
     567         383 :         bool              plugins_enabled = false;
     568         383 :         bool              plugin_found = false;
     569         383 :         bool              show_commands = false;
     570         383 :         bool              activation_test = false;
     571         383 :         pkg_init_flags    init_flags = 0;
     572             :         struct plugcmd   *c;
     573         383 :         const char       *conffile = NULL;
     574         383 :         const char       *reposdir = NULL;
     575             :         char            **save_argv;
     576             :         int               j;
     577             : 
     578         383 :         struct option longopts[] = {
     579             :                 { "debug",            no_argument,            NULL,   'd' },
     580             : #ifdef HAVE_LIBJAIL
     581             :                 { "jail",             required_argument,      NULL,   'j' },
     582             : #endif
     583             :                 { "chroot",           required_argument,      NULL,   'c' },
     584             :                 { "config",           required_argument,      NULL,   'C' },
     585             :                 { "repo-conf-dir",    required_argument,      NULL,   'R' },
     586             :                 { "rootdir",          required_argument,      NULL,   'r' },
     587             :                 { "list",             no_argument,            NULL,   'l' },
     588             :                 { "version",          no_argument,            NULL,   'v' },
     589             :                 { "option",           required_argument,      NULL,   'o' },
     590             :                 { "only-ipv4",                no_argument,            NULL,   '4' },
     591             :                 { "only-ipv6",                no_argument,            NULL,   '6' },
     592             :                 { NULL,                 0,                      NULL,   0   },
     593             :         };
     594             : 
     595             :         /* Set stdout unbuffered */
     596         383 :         setvbuf(stdout, NULL, _IONBF, 0);
     597             : 
     598             :         /* Ignore SIGPIPE */
     599         383 :         signal(SIGPIPE, SIG_IGN);
     600             : 
     601         383 :         if (argc < 2)
     602           0 :                 usage(NULL, NULL, stderr, PKG_USAGE_INVALID_ARGUMENTS, "not enough arguments");
     603             : 
     604             :         /* getopt_long() will permute the arg-list unless
     605             :          * POSIXLY_CORRECT is set in the environment.  This is a
     606             :          * difference to the original getopt() we were using, and
     607             :          * screws up our 'pkg {pkg-opts} verb {verb-opts}' command
     608             :          * line concept. */
     609             : 
     610         383 :         if (setenv("POSIXLY_CORRECT", "1",  1) == -1)
     611           0 :                 err(EX_SOFTWARE, "setenv() failed");
     612             : 
     613         383 :         save_argv = argv;
     614             : 
     615             : #ifdef HAVE_LIBJAIL
     616             : #define JAIL_OPT        "j:"
     617             : #else
     618             : #define JAIL_OPT
     619             : #endif
     620         859 :         while ((ch = getopt_long(argc, argv, "+d"JAIL_OPT"c:C:R:r:lNvo:46", longopts, NULL)) != -1) {
     621          93 :                 switch (ch) {
     622             :                 case 'd':
     623           0 :                         debug++;
     624           0 :                         break;
     625             :                 case 'c':
     626           0 :                         chroot_path = optarg;
     627           0 :                         break;
     628             :                 case 'C':
     629          25 :                         conffile = optarg;
     630          25 :                         break;
     631             :                 case 'R':
     632           3 :                         reposdir = optarg;
     633           3 :                         break;
     634             :                 case 'r':
     635           2 :                         rootdir = optarg;
     636           2 :                         break;
     637             : #ifdef HAVE_LIBJAIL
     638             :                 case 'j':
     639           0 :                         jail_str = optarg;
     640           0 :                         break;
     641             : #endif
     642             :                 case 'l':
     643           0 :                         show_commands = true;
     644           0 :                         break;
     645             :                 case 'N':
     646           2 :                         activation_test = true;
     647           2 :                         break;
     648             :                 case 'v':
     649           4 :                         version++;
     650           4 :                         break;
     651             :                 case 'o':
     652          57 :                         export_arg_option (optarg);
     653          57 :                         break;
     654             :                 case '4':
     655           0 :                         init_flags = PKG_INIT_FLAG_USE_IPV4;
     656           0 :                         break;
     657             :                 case '6':
     658           0 :                         init_flags = PKG_INIT_FLAG_USE_IPV6;
     659           0 :                         break;
     660             :                 default:
     661           0 :                         break;
     662             :                 }
     663             :         }
     664         383 :         argc -= optind;
     665         383 :         argv += optind;
     666             : 
     667         383 :         pkg_set_debug_level(debug);
     668             : 
     669         383 :         if (version == 1)
     670           0 :                 show_version_info(version);
     671             : 
     672         383 :         if (show_commands && version == 0) {
     673           0 :                 show_command_names();
     674           0 :                 exit(EX_OK);
     675             :         }
     676             : 
     677         383 :         if (argc == 0 && version == 0 && !activation_test)
     678           0 :                 usage(conffile, reposdir, stderr, PKG_USAGE_INVALID_ARGUMENTS, "no commands specified");
     679             : 
     680         383 :         umask(022);
     681         383 :         pkg_event_register(&event_callback, &debug);
     682             : 
     683             :         /* reset getopt for the next call */
     684         383 :         optreset = 1;
     685         383 :         optind = 1;
     686             : 
     687         383 :         if (debug == 0 && version == 0)
     688         381 :                 start_process_worker(save_argv);
     689             : 
     690             : #ifdef HAVE_ARC4RANDOM
     691             :         /* Ensure that random is stirred after a possible fork */
     692         202 :         arc4random_stir();
     693             : #endif
     694             : 
     695         202 :         if ((jail_str != NULL && (chroot_path != NULL || rootdir != NULL)) ||
     696           0 :             (chroot_path != NULL && (jail_str != NULL || rootdir != NULL)) ||
     697           1 :             (rootdir != NULL && (jail_str != NULL || chroot_path != NULL)))  {
     698           0 :                 usage(conffile, reposdir, stderr, PKG_USAGE_INVALID_ARGUMENTS,
     699             :                     "-j, -c and/or -r cannot be used at the same time!\n");
     700             :         }
     701             : 
     702         202 :         if (chroot_path != NULL)
     703           0 :                 if (chroot(chroot_path) == -1)
     704           0 :                         errx(EX_SOFTWARE, "chroot failed!");
     705             : 
     706             : #ifdef HAVE_LIBJAIL
     707         202 :         if (jail_str != NULL) {
     708           0 :                 jid = jail_getid(jail_str);
     709           0 :                 if (jid < 0)
     710           0 :                         errx(1, "%s", jail_errmsg);
     711             : 
     712           0 :                 if (jail_attach(jid) == -1)
     713           0 :                         err(1, "jail_attach(%s)", jail_str);
     714             :         }
     715             : 
     716         202 :         if (jail_str != NULL || chroot_path != NULL)
     717           0 :                 if (chdir("/") == -1)
     718           0 :                         errx(EX_SOFTWARE, "chdir() failed");
     719             : #endif
     720             : 
     721         202 :         if (rootdir != NULL) {
     722           1 :                 if (chdir(rootdir) == -1)
     723           0 :                         errx(EX_SOFTWARE, "chdir() failed");
     724           1 :                 pkg_set_rootdir(rootdir);
     725             :         }
     726             : 
     727         202 :         if (pkg_ini(conffile, reposdir, init_flags) != EPKG_OK)
     728           0 :                 errx(EX_SOFTWARE, "Cannot parse configuration file!");
     729             : 
     730         202 :         if (debug > 0)
     731           0 :                 pkg_set_debug_level(debug);
     732             : 
     733         202 :         if (atexit(&pkg_shutdown) != 0)
     734           0 :                 errx(EX_SOFTWARE, "register pkg_shutdown() to run at exit");
     735             : 
     736         202 :         if (!pkg_compiled_for_same_os_major())
     737           0 :                 warnx("Warning: Major OS version upgrade detected.  Running "
     738             :                     "\"pkg-static install -f pkg\" recommended");
     739             : 
     740             : 
     741         202 :         plugins_enabled = pkg_object_bool(pkg_config_get("PKG_ENABLE_PLUGINS"));
     742             : 
     743         202 :         if (plugins_enabled) {
     744         202 :                 struct pkg_plugin       *p = NULL;
     745             : 
     746         202 :                 if (pkg_plugins_init() != EPKG_OK)
     747           0 :                         errx(EX_SOFTWARE, "Plugins cannot be loaded");
     748             : 
     749         202 :                 if (atexit(&pkg_plugins_shutdown) != 0)
     750           0 :                         errx(EX_SOFTWARE,
     751             :                             "register pkg_plugins_shutdown() to run at exit");
     752             : 
     753             :                 /* load commands plugins */
     754         404 :                 while (pkg_plugins(&p) != EPKG_END) {
     755             :                         int n;
     756             : 
     757           0 :                         nb_cmd *ncmd = pkg_plugin_func(p, "pkg_register_cmd_count");
     758           0 :                         register_cmd *reg = pkg_plugin_func(p, "pkg_register_cmd");
     759           0 :                         if (reg != NULL && ncmd != NULL) {
     760           0 :                                 n = ncmd();
     761           0 :                                 for (j = 0; j < n ; j++) {
     762           0 :                                         c = malloc(sizeof(struct plugcmd));
     763           0 :                                         reg(j, &c->name, &c->desc, &c->exec);
     764           0 :                                         STAILQ_INSERT_TAIL(&plugins, c, next);
     765             :                                 }
     766             :                         }
     767             :                 }
     768             :         }
     769             : 
     770         202 :         if (version > 1)
     771           2 :                 show_version_info(version);
     772             : 
     773         200 :         if (activation_test)
     774           1 :                 do_activation_test(argc);
     775             : 
     776         199 :         if (argc >= 1 && strcmp(argv[0], "bootstrap") == 0) {
     777           0 :                 if (argc == 1) {
     778           0 :                         printf("pkg(8) already installed, use -f to force.\n");
     779           0 :                         exit(EXIT_SUCCESS);
     780           0 :                 } else if (argc == 2 && strcmp(argv[1], "-f") == 0) {
     781           0 :                         if (access("/usr/sbin/pkg", R_OK) == 0) {
     782             :                                 /* Only 10.0+ supported 'bootstrap -f' */
     783             : #if __FreeBSD_version < 1000502
     784             :                                 printf("Execute these steps to rebootstrap"
     785             :                                      " pkg(8):\n");
     786             :                                 printf("# pkg delete -f pkg\n");
     787             :                                 printf("# /usr/sbin/pkg -v\n");
     788             :                                 exit(EXIT_SUCCESS);
     789             : #endif
     790           0 :                                 printf("pkg(8) is already installed. Forcing "
     791             :                                     "reinstallation through pkg(7).\n");
     792           0 :                                 execl("/usr/sbin/pkg", "pkg", "bootstrap",
     793             :                                     "-f", NULL);
     794             :                                 /* NOTREACHED */
     795             :                         } else
     796           0 :                                 errx(EXIT_FAILURE, "pkg(7) bootstrapper not"
     797             :                                     " found at /usr/sbin/pkg.");
     798             :                 }
     799             :         }
     800             : 
     801         199 :         save_argv = argv;
     802         199 :         argc = expand_aliases(argc, &argv);
     803             : 
     804         199 :         len = strlen(argv[0]);
     805        2897 :         for (i = 0; i < cmd_len; i++) {
     806        2897 :                 if (strncmp(argv[0], cmd[i].name, len) == 0) {
     807             :                         /* if we have the exact cmd */
     808         199 :                         if (len == strlen(cmd[i].name)) {
     809         199 :                                 command = &cmd[i];
     810         199 :                                 ambiguous = 0;
     811         199 :                                 break;
     812             :                         }
     813             : 
     814             :                         /*
     815             :                          * we already found a partial match so `argv[0]' is
     816             :                          * an ambiguous shortcut
     817             :                          */
     818           0 :                         ambiguous++;
     819             : 
     820           0 :                         command = &cmd[i];
     821             :                 }
     822             :         }
     823             : 
     824         199 :         set_globals();
     825             : 
     826         199 :         if (command == NULL) {
     827             :                 /* Check if a plugin provides the requested command */
     828           0 :                 ret = EPKG_FATAL;
     829           0 :                 if (plugins_enabled) {
     830           0 :                         STAILQ_FOREACH(c, &plugins, next) {
     831           0 :                                 if (strcmp(c->name, argv[0]) == 0) {
     832           0 :                                         plugin_found = true;
     833           0 :                                         ret = c->exec(argc, argv);
     834           0 :                                         break;
     835             :                                 }
     836             :                         }
     837             :                 }
     838             : 
     839           0 :                 if (!plugin_found)
     840           0 :                         usage(conffile, reposdir, stderr, PKG_USAGE_UNKNOWN_COMMAND, argv[0]);
     841             : 
     842           0 :                 return (ret);
     843             :         }
     844             : 
     845         199 :         if (ambiguous <= 1) {
     846         199 :                 assert(command->exec != NULL);
     847         199 :                 ret = command->exec(argc, argv);
     848             :         } else {
     849           0 :                 usage(conffile, reposdir, stderr, PKG_USAGE_UNKNOWN_COMMAND, argv[0]);
     850             :         }
     851             : 
     852         177 :         if (save_argv != argv)
     853           2 :                 free(argv);
     854             : 
     855         177 :         if (ret == EX_OK && newpkgversion)
     856           0 :                 return (EX_NEEDRESTART);
     857             : 
     858         177 :         return (ret);
     859             : }
     860             : 

Generated by: LCOV version 1.10