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