LCOV - code coverage report
Current view: top level - src - main.c (source / functions) Hit Total Coverage
Test: plop Lines: 195 389 50.1 %
Date: 2024-12-30 07:09:03 Functions: 8 12 66.7 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 47 138 34.1 %

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

Generated by: LCOV version 1.15