/*
* Copyright (C) 2023 Patrick McDermott
*
* This file is part of opkg-opk.
*
* opkg-opk is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* opkg-opk is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with opkg-opk. If not, see .
*/
#include "config.h"
#ifdef ENABLE_NLS
#include
#endif
#include
#include
#include "defs.h"
#include "i18n.h"
#include "opk.h"
#ifdef HAVE_GETOPT_LONG
#include
#else
#include
#endif
extern const char *PACKAGE_VERSION_GIT;
const char *_optstring = "bc:d:s:f:F:lLhV";
#ifdef HAVE_GETOPT_LONG
struct option _longopts[] = {
{
.name = "build",
.has_arg = 0,
.flag = NULL,
.val = 'b',
},
{
.name = "control-dir",
.has_arg = 1,
.flag = NULL,
.val = 'c',
},
{
.name = "data-dir",
.has_arg = 1,
.flag = NULL,
.val = 'd',
},
{
.name = "special",
.has_arg = 1,
.flag = NULL,
.val = 's',
},
{
.name = "control-file",
.has_arg = 1,
.flag = NULL,
.val = 'f',
},
{
.name = "data-file",
.has_arg = 1,
.flag = NULL,
.val = 'F',
},
{
.name = "list-control",
.has_arg = 0,
.flag = NULL,
.val = 'l',
},
{
.name = "list-data",
.has_arg = 0,
.flag = NULL,
.val = 'L',
},
{
.name = "help",
.has_arg = 0,
.flag = NULL,
.val = 'h',
},
{
.name = "version",
.has_arg = 0,
.flag = NULL,
.val = 'V',
},
};
#endif
static void
_help(const char *program_name)
{
printf(_("Usage: %s [-c CONTROL-DIR] [-f CONTROL-FILE] [-F DATA-FILE] "
"[-l] [-L] PACKAGE\n"), program_name);
printf(_(" or: %s -b -c CONTROL-DIR -d DATA-DIR [-s SPECIAL-FILE] "
"PACKAGE\n"),
program_name);
#ifdef HAVE_GETOPT_LONG
puts(_("Options:\n"
" -b, --build Create a package from the specified\n"
" CONTROL-DIR and DATA-DIR.\n"
" -c, --control-dir=CONTROL-DIR In build mode, read control files from\n"
" CONTROL-DIR. Otherwise, extract control\n"
" files into CONTROL-DIR.\n"
" -d, --data-dir=DATA-DIR In build mode, read data files from "
"DATA-DIR\n"
" -s, --special=SPECIAL-FILE Read device special files list from\n"
" SPECIAL-FILE.\n"
" -f, --control-file=CONTROL-FILE Print the contents of the named control "
"file.\n"
" If this option is given multiple times, the"
"\n"
" named control files will be printed in the"
"\n"
" order they appear in the package.\n"
" -F, --data-file=DATA-FILE Print the contents of the named data file."
"\n"
" If this option is given multiple times, the"
"\n"
" named data files will be printed in the "
"order\n"
" they appear in the package.\n"
" -l, --list-control List the control files.\n"
" -L, --list-data List the data files. The list is currently"
"\n"
" produced in a format similar to that\n"
" generated by GNU and BusyBox tar's verbose"
"\n"
" listing. User and group IDs and names are"
"\n"
" not checked against those on the host "
"system,\n"
" since they may differ.\n"
" -h, --help Show this help information and exit.\n"
" -V, --version Show version information and exit."));
#else
puts(_("Options:\n"
" -b Create a package from the specified CONTROL-DIR and DATA-DIR.\n"
" -c In build mode, read control files from CONTROL-DIR. Otherwise, extract"
"\n"
" control files into CONTROL-DIR.\n"
" -d In build mode, read data files from DATA-DIR\n"
" -s Read device special files list from SPECIAL-FILE.\n"
" -f Print the contents of the named control file. If this option is given\n"
" multiple times, the named control files will be printed in the order "
"they\n"
" appear in the package.\n"
" -F Print the contents of the named data file. If this option is given\n"
" multiple times, the named data files will be printed in the order they\n"
" appear in the package.\n"
" -l List the control files.\n"
" -L List the data files. The list is currently produced in a format "
"similar\n"
" to that generated by GNU and BusyBox tar's verbose listing. User and\n"
" group IDs and names are not checked against those on the host system,\n"
" since they may differ.\n"
" -h Show this help information and exit.\n"
" -V Show version information and exit."));
#endif
}
static void
_version(void)
{
printf("%s %s%s\n", PACKAGE_NAME, PACKAGE_VERSION, PACKAGE_VERSION_GIT);
/* TRANSLATORS: The "%s" conversion specifications are the copyright
* year(s) and copyright holder(s), respectively. */
printf(_("Copyright (C) %s %s\n"), "2023", "Patrick McDermott");
puts(_("License GPLv3+: GNU GPL version 3 or later "
".\n"
"This is free software: you are free to change and "
"redistribute it.\n"
"There is NO WARRANTY, to the extent permitted by "
"law.\n"));
printf(_("Please report bugs to <%s>.\n"), PACKAGE_BUGREPORT);
}
static void
_help_tip(const char *program_name)
{
/* TRANSLATORS: The "%s" conversion specifications are the program name
* and help option, respectively. */
fprintf(stderr, _("Try \"%s %s\" for more information\n"), program_name,
#ifdef HAVE_GETOPT_LONG
"--help"
#else
"-h"
#endif
);
}
static void
_opt_mutex(const char *program_name, char opt1, char opt2)
{
fprintf(stderr, _("%s: Options -%c and -%c are mutually exclusive\n"),
program_name, opt1, opt2);
_help_tip(program_name);
}
int
main(int argc, char *argv[])
{
const char *program_name;
struct opkg_opk_opk *opk;
int build;
int opt_f;
int opt_F;
int opt_l;
int opt_L;
int opt;
#ifdef ENABLE_NLS
bindtextdomain(GETTEXT_PACKAGE, LOCALEDIR);
#ifdef HAVE_BIND_TEXTDOMAIN_CODESET
bind_textdomain_codeset(PACKAGE, "UTF-8");
#endif
textdomain(PACKAGE);
setlocale(LC_ALL, "");
#endif
program_name = argv[0];
/* Initialize package. */
opk = opkg_opk_opk_init();
if (opk == NULL) {
return EXIT_FAILURE;
}
opterr = 0;
build = 0;
opt_f = 0;
opt_F = 0;
opt_l = 0;
opt_L = 0;
#ifdef HAVE_GETOPT_LONG
while ((opt = getopt_long(argc, argv, _optstring, _longopts, NULL))
!= -1) {
#else
while ((opt = getopt(argc, argv, _optstring)) != -1) {
#endif
switch(opt) {
case 'b':
build = 1;
break;
case 'c':
opkg_opk_opk_control_dir(opk, optarg);
break;
case 'd':
opkg_opk_opk_data_dir(opk, optarg);
break;
case 's':
opkg_opk_opk_specials_read(opk, optarg);
break;
case 'f':
if (opt_l > 0) {
_opt_mutex(program_name, 'f', 'l');
opkg_opk_opk_free(opk);
return EXIT_FAILURE;
}
opt_f = 1;
if (opkg_opk_opk_print_control(opk, optarg)
!= OPKG_OPK_OK) {
opkg_opk_opk_free(opk);
return EXIT_FAILURE;
}
break;
case 'F':
if (opt_L > 0) {
_opt_mutex(program_name, 'F', 'L');
opkg_opk_opk_free(opk);
return EXIT_FAILURE;
}
opt_F = 1;
if (opkg_opk_opk_print_data(opk, optarg)
!= OPKG_OPK_OK) {
opkg_opk_opk_free(opk);
return EXIT_FAILURE;
}
break;
case 'l':
if (opt_f > 0) {
_opt_mutex(program_name, 'f', 'l');
opkg_opk_opk_free(opk);
return EXIT_FAILURE;
}
opt_l = 1;
opkg_opk_opk_list_control(opk);
break;
case 'L':
if (opt_F > 0) {
_opt_mutex(program_name, 'F', 'L');
opkg_opk_opk_free(opk);
return EXIT_FAILURE;
}
opt_L = 1;
opkg_opk_opk_list_data(opk);
break;
case 'h':
_help(program_name);
opkg_opk_opk_free(opk);
return EXIT_SUCCESS;
case 'V':
_version();
opkg_opk_opk_free(opk);
return EXIT_SUCCESS;
default:
fprintf(stderr, _("%s: Invalid option: "
"\"%c\"\n"),
program_name, optopt);
_help_tip(program_name);
opkg_opk_opk_free(opk);
return EXIT_FAILURE;
}
}
argc -= optind;
argv += optind;
if (argc < 1) {
fprintf(stderr, _("%s: Missing package file operand\n"),
program_name);
_help_tip(program_name);
opkg_opk_opk_free(opk);
return EXIT_FAILURE;
} else if (argc > 1) {
fprintf(stderr, _("%s: Too many package file operands\n"),
program_name);
_help_tip(program_name);
opkg_opk_opk_free(opk);
return EXIT_FAILURE;
}
/* Read or build package. */
if (build == 1) {
if (opkg_opk_opk_write(opk, argv[0]) != OPKG_OPK_OK) {
opkg_opk_opk_free(opk);
return EXIT_FAILURE;
}
} else {
if (opkg_opk_opk_read(opk, argv[0]) != OPKG_OPK_OK) {
opkg_opk_opk_free(opk);
return EXIT_FAILURE;
}
}
opkg_opk_opk_free(opk);
return EXIT_SUCCESS;
}