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 : :
|