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