pkg(7): rework the arguments handling

Rework the arguments handling around using getopt_long:
* add long option support
* add -4 and -6 support to enforce ipv4 or ipv6

While here fix a regression which occured between FreeBSD 12.1 and
FreeBSD 12.2 where pkg bootstrap -y stopped working

PR:		252270
MFC after:	2 weeks
Submitted by:	evilham <contact@evilham.com>
Differential Revision:	https://reviews.freebsd.org/D27860
This commit is contained in:
Baptiste Daroussin 2021-01-06 11:35:22 +01:00
parent 99870c70ba
commit ae994fdc5b
2 changed files with 102 additions and 40 deletions

View file

@ -24,7 +24,7 @@
.\"
.\" $FreeBSD$
.\"
.Dd November 6, 2020
.Dd December 31, 2020
.Dt PKG 7
.Os
.Sh NAME
@ -36,12 +36,15 @@
.Nm
add
.Op Fl f
.Op Fl y
.Ao Pa pkg.txz Ac
.Nm
.Fl N
.Nm
.Op Fl 4 | Fl 6
bootstrap
.Op Fl f
.Op Fl y
.Sh DESCRIPTION
.Nm
is the package management tool.
@ -65,7 +68,7 @@ is not installed yet, it will be fetched, have its signature verified,
installed, and then have the original command forwarded to it.
If already installed, the command requested will be forwarded to the real
.Xr pkg 8 .
.It Nm Li add Oo Fl f Oc Ao Pa pkg.txz Ac
.It Nm Li add Oo Fl f Oc Oo Fl y Oc Ao Pa pkg.txz Ac
Install
.Xr pkg 8
from a local package instead of fetching from remote.
@ -76,21 +79,37 @@ If the
flag is specified, then
.Xr pkg 8
will be installed regardless if it is already installed.
If the
.Fl y
flag is specified, no confirmation will be asked when bootstrapping
.Xr pkg 8 .
.It Nm Fl N
Do not bootstrap, just determine if
.Xr pkg 8
is actually installed or not.
Returns 0 and the number of packages installed
if it is, otherwise 1.
.It Nm Li bootstrap Op Fl f
.It Nm Oo Fl 4 | Fl 6 Oc Li bootstrap Oo Fl f Oc Oo Fl y Oc
Attempt to bootstrap and do not forward anything to
.Xr pkg 8
after it is installed.
With
.Fl 4
and
.Fl 6 ,
.Nm
will force IPv4 or IPv6 respectively to fetch
.Xr pkg 8
and its signatures as needed.
If the
.Fl f
flag is specified, then
.Xr pkg 8
will be fetched and installed regardless if it is already installed.
If the
.Fl y
flag is specified, no confirmation will be asked when bootstrapping
.Xr pkg 8 .
.El
.Sh CONFIGURATION
Configuration varies in whether it is in a repository configuration file

View file

@ -43,6 +43,7 @@ __FBSDID("$FreeBSD$");
#include <errno.h>
#include <fcntl.h>
#include <fetch.h>
#include <getopt.h>
#include <libutil.h>
#include <paths.h>
#include <stdbool.h>
@ -173,7 +174,7 @@ install_pkg_static(const char *path, const char *pkgpath, bool force)
}
static int
fetch_to_fd(const char *url, char *path)
fetch_to_fd(const char *url, char *path, const char *fetchOpts)
{
struct url *u;
struct dns_srvinfo *mirrors, *current;
@ -225,7 +226,7 @@ fetch_to_fd(const char *url, char *path)
u->port = current->port;
}
remote = fetchXGet(u, &st, "");
remote = fetchXGet(u, &st, fetchOpts);
if (remote == NULL) {
--retry;
if (retry <= 0)
@ -828,7 +829,7 @@ verify_signature(int fd_pkg, int fd_sig)
}
static int
bootstrap_pkg(bool force)
bootstrap_pkg(bool force, const char *fetchOpts)
{
int fd_pkg, fd_sig;
int ret;
@ -865,7 +866,7 @@ bootstrap_pkg(bool force)
snprintf(tmppkg, MAXPATHLEN, "%s/pkg.txz.XXXXXX",
getenv("TMPDIR") ? getenv("TMPDIR") : _PATH_TMP);
if ((fd_pkg = fetch_to_fd(url, tmppkg)) == -1)
if ((fd_pkg = fetch_to_fd(url, tmppkg, fetchOpts)) == -1)
goto fetchfail;
if (signature_type != NULL &&
@ -877,7 +878,7 @@ bootstrap_pkg(bool force)
snprintf(url, MAXPATHLEN, "%s/Latest/pkg.txz.sig",
packagesite);
if ((fd_sig = fetch_to_fd(url, tmpsig)) == -1) {
if ((fd_sig = fetch_to_fd(url, tmpsig, fetchOpts)) == -1) {
fprintf(stderr, "Signature for pkg not "
"available.\n");
goto fetchfail;
@ -893,7 +894,7 @@ bootstrap_pkg(bool force)
snprintf(url, MAXPATHLEN, "%s/Latest/pkg.txz.pubkeysig",
packagesite);
if ((fd_sig = fetch_to_fd(url, tmpsig)) == -1) {
if ((fd_sig = fetch_to_fd(url, tmpsig, fetchOpts)) == -1) {
fprintf(stderr, "Signature for pkg not "
"available.\n");
goto fetchfail;
@ -948,6 +949,14 @@ static const char non_interactive_message[] =
"Please set ASSUME_ALWAYS_YES=yes environment variable to be able to bootstrap "
"in non-interactive (stdin not being a tty)\n";
static const char args_bootstrap_message[] =
"Too many arguments\n"
"Usage: pkg [-4|-6] bootstrap [-f] [-y]\n";
static const char args_add_message[] =
"Too many arguments\n"
"Usage: pkg add [-f] [-y] {pkg.txz}\n";
static int
pkg_query_yes_no(void)
{
@ -1037,27 +1046,74 @@ main(int argc, char *argv[])
{
char pkgpath[MAXPATHLEN];
const char *pkgarg;
int i;
bool bootstrap_only, force, yes;
bool activation_test, add_pkg, bootstrap_only, force, yes;
signed char ch;
const char *fetchOpts;
char *command;
activation_test = false;
add_pkg = false;
bootstrap_only = false;
command = NULL;
fetchOpts = "";
force = false;
pkgarg = NULL;
yes = false;
struct option longopts[] = {
{ "force", no_argument, NULL, 'f' },
{ "only-ipv4", no_argument, NULL, '4' },
{ "only-ipv6", no_argument, NULL, '6' },
{ "yes", no_argument, NULL, 'y' },
{ NULL, 0, NULL, 0 },
};
snprintf(pkgpath, MAXPATHLEN, "%s/sbin/pkg", getlocalbase());
if (argc > 1 && strcmp(argv[1], "bootstrap") == 0) {
bootstrap_only = true;
if (argc > 3) {
fprintf(stderr, "Too many arguments\nUsage: pkg bootstrap [-f]\n");
exit(EXIT_FAILURE);
}
if (argc == 3 && strcmp(argv[2], "-f") == 0) {
while ((ch = getopt_long(argc, argv, "-:fyN46", longopts, NULL)) != -1) {
switch (ch) {
case 'f':
force = true;
} else if (argc == 3) {
fprintf(stderr, "Invalid argument specified\nUsage: pkg bootstrap [-f]\n");
exit(EXIT_FAILURE);
break;
case 'N':
activation_test = true;
break;
case 'y':
yes = true;
break;
case '4':
fetchOpts = "4";
break;
case '6':
fetchOpts = "6";
break;
case 1:
// Non-option arguments, first one is the command
if (command == NULL) {
command = argv[optind-1];
if (strcmp(command, "add") == 0) {
add_pkg = true;
}
else if (strcmp(command, "bootstrap") == 0) {
bootstrap_only = true;
}
}
// bootstrap doesn't accept other arguments
else if (bootstrap_only) {
fprintf(stderr, args_bootstrap_message);
exit(EXIT_FAILURE);
}
// For add, we accept exactly one further argument
else if (add_pkg && pkgarg != NULL) {
fprintf(stderr, args_add_message);
exit(EXIT_FAILURE);
}
else if (add_pkg) {
pkgarg = argv[optind-1];
}
break;
default:
break;
}
}
@ -1065,19 +1121,14 @@ main(int argc, char *argv[])
/*
* To allow 'pkg -N' to be used as a reliable test for whether
* a system is configured to use pkg, don't bootstrap pkg
* when that argument is given as argv[1].
* when that that option is passed.
*/
if (argv[1] != NULL && strcmp(argv[1], "-N") == 0)
if (activation_test)
errx(EXIT_FAILURE, "pkg is not installed");
config_init();
if (argc > 1 && strcmp(argv[1], "add") == 0) {
if (argc > 2 && strcmp(argv[2], "-f") == 0) {
force = true;
pkgarg = argv[3];
} else
pkgarg = argv[2];
if (add_pkg) {
if (pkgarg == NULL) {
fprintf(stderr, "Path to pkg.txz required\n");
exit(EXIT_FAILURE);
@ -1095,16 +1146,8 @@ main(int argc, char *argv[])
* not tty. Check the environment to see if user has answer
* tucked in there already.
*/
config_bool(ASSUME_ALWAYS_YES, &yes);
if (!yes) {
for (i = 1; i < argc; i++) {
if (strcmp(argv[i], "-y") == 0 ||
strcmp(argv[i], "--yes") == 0) {
yes = true;
break;
}
}
}
if (!yes)
config_bool(ASSUME_ALWAYS_YES, &yes);
if (!yes) {
if (!isatty(fileno(stdin))) {
fprintf(stderr, non_interactive_message);
@ -1115,7 +1158,7 @@ main(int argc, char *argv[])
if (pkg_query_yes_no() == 0)
exit(EXIT_FAILURE);
}
if (bootstrap_pkg(force) != 0)
if (bootstrap_pkg(force, fetchOpts) != 0)
exit(EXIT_FAILURE);
config_finish();