1
0
Fork 0
mirror of https://github.com/pygos/pkg-utils.git synced 2024-11-22 12:59:46 +01:00
pkg-utils/main/cmd/install.c

277 lines
6.7 KiB
C
Raw Normal View History

/* SPDX-License-Identifier: ISC */
#include <stdbool.h>
#include <getopt.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <stdio.h>
#include <fcntl.h>
#include "pkg/pkglist.h"
#include "pkg/pkgio.h"
#include "util/util.h"
#include "command.h"
#include "config.h"
enum {
INSTALL_MODE_INSTALL = 0,
INSTALL_MODE_LIST_PKG,
INSTALL_MODE_LIST_FILES,
};
static const struct option long_opts[] = {
{ "root", required_argument, NULL, 'r' },
{ "no-chown", no_argument, NULL, 'o' },
{ "no-chmod", no_argument, NULL, 'm' },
{ "no-dependencies", no_argument, NULL, 'd' },
{ "repo-dir", required_argument, NULL, 'R' },
{ "list-packages", no_argument, NULL, 'p' },
{ "list-files", required_argument, NULL, 'l' },
{ "no-symlinks", no_argument, NULL, 'L' },
{ "no-devices", no_argument, NULL, 'D' },
{ NULL, 0, NULL, 0 },
};
static const char *short_opts = "r:omdR:pl:F:LD";
static int unpack_packages(int repofd, int rootfd, int flags,
struct pkg_dep_list *list)
{
struct pkg_dep_node *it;
pkg_reader_t *rd;
for (it = list->head; it != NULL; it = it->next) {
rd = pkg_reader_open_repo(repofd, it->name);
if (rd == NULL)
return -1;
if (pkg_unpack(rootfd, flags, rd)) {
pkg_reader_close(rd);
return -1;
}
pkg_reader_close(rd);
}
return 0;
}
static void list_packages(struct pkg_dep_list *list)
{
struct pkg_dep_node *it;
for (it = list->head; it != NULL; it = it->next)
printf("%s\n", it->name);
}
static int list_files(int repofd, const char *rootdir, TOC_FORMAT format,
struct pkg_dep_list *list)
{
struct pkg_dep_node *it;
image_entry_t *toc;
pkg_reader_t *rd;
for (it = list->head; it != NULL; it = it->next) {
rd = pkg_reader_open_repo(repofd, it->name);
if (rd == NULL)
return -1;
if (image_entry_list_from_package(rd, &toc)) {
pkg_reader_close(rd);
return -1;
}
if (toc != NULL && dump_toc(toc, rootdir, format)) {
image_entry_free_list(toc);
pkg_reader_close(rd);
return -1;
}
image_entry_free_list(toc);
pkg_reader_close(rd);
}
return 0;
}
static int cmd_install(int argc, char **argv)
{
int ret = EXIT_FAILURE, mode = INSTALL_MODE_INSTALL;
int i, rootfd = -1, repofd = -1, flags = 0;
TOC_FORMAT format = TOC_FORMAT_PRETTY;
const char *rootdir = NULL;
struct pkg_dep_list list;
bool resolve_deps = true;
memset(&list, 0, sizeof(list));
for (;;) {
i = getopt_long(argc, argv, short_opts, long_opts, NULL);
if (i == -1)
break;
switch (i) {
case 'd':
resolve_deps = false;
break;
case 'p':
mode = INSTALL_MODE_LIST_PKG;
break;
case 'l':
mode = INSTALL_MODE_LIST_FILES;
if (strcmp(optarg, "initrd") == 0) {
format = TOC_FORMAT_INITRD;
} else if (strcmp(optarg, "pkg") == 0) {
format = TOC_FORMAT_PKG;
} else if (strcmp(optarg, "detail")) {
format = TOC_FORMAT_PRETTY;
} else {
fprintf(stderr, "unknown format '%s'\n",
optarg);
goto out;
}
break;
case 'R':
if (repofd != -1) {
fputs("repo specified more than once\n",
stderr);
tell_read_help(argv[0]);
goto out;
}
repofd = open(optarg, O_RDONLY | O_DIRECTORY);
if (repofd < 0) {
perror(optarg);
goto out;
}
break;
case 'r':
if (rootfd != -1) {
fputs("root specified more than once\n",
stderr);
tell_read_help(argv[0]);
goto out;
}
if (mkdir_p(optarg))
goto out;
rootfd = open(optarg, O_RDONLY | O_DIRECTORY);
if (rootfd < 0) {
perror(optarg);
goto out;
}
rootdir = optarg;
break;
case 'o':
flags |= UNPACK_NO_CHOWN;
break;
case 'm':
flags |= UNPACK_NO_CHMOD;
break;
case 'L':
flags |= UNPACK_NO_SYMLINKS;
break;
case 'D':
flags |= UNPACK_NO_DEVICES;
break;
default:
tell_read_help(argv[0]);
goto out;
}
}
if (repofd == -1) {
repofd = open(REPODIR, O_RDONLY | O_DIRECTORY);
if (repofd < 0) {
perror(REPODIR);
goto out;
}
}
if (rootfd == -1) {
rootfd = open(INSTALLROOT, O_RDONLY | O_DIRECTORY);
if (rootfd < 0) {
perror(INSTALLROOT);
goto out;
}
}
for (i = optind; i < argc; ++i) {
if (append_pkg(&list, argv[i]) == NULL)
goto out;
}
if (resolve_deps) {
if (collect_dependencies(repofd, &list))
goto out;
if (sort_by_dependencies(&list))
goto out;
}
switch (mode) {
case INSTALL_MODE_LIST_PKG:
list_packages(&list);
break;
case INSTALL_MODE_LIST_FILES:
if (list_files(repofd, rootdir, format, &list))
goto out;
break;
default:
if (unpack_packages(repofd, rootfd, flags, &list))
goto out;
break;
}
ret = EXIT_SUCCESS;
out:
if (rootfd != -1)
close(rootfd);
if (repofd != -1)
close(repofd);
pkg_list_cleanup(&list);
return ret;
}
static command_t install = {
.cmd = "install",
.usage = "[OPTIONS...] PACKAGES...",
.s_desc = "install packages and their dependencies",
.l_desc =
"The install command fetches a number of packages from a repository directory\n"
"by name and extracts them to a specified root directory. Dependencies of the\n"
"packages are evaluated and also installed.\n"
"\n"
"Possible options:\n"
" --repo-dir, -R <path> Specify the input repository path to fetch the\n"
" packages from.\n"
" If not set, defaults to " REPODIR ".\n"
" --root, -r <path> A root directory to unpack the package.\n"
" If not set, defaults to " INSTALLROOT ".\n"
" --no-chown, -o Do not change ownership of the extracted data.\n"
" Keep the uid/gid of the user who runs the \n"
" program.\n"
" --no-chmod, -m Do not change permission flags of the extarcted\n"
" data. Use 0644 for all files and 0755 for all\n"
" directories.\n"
" --no-symlink, -L Do not create symlinks.\n"
" --no-devices, -D Do not create device files.\n"
" --no-dependencies, -d Do not resolve dependencies, only install files\n"
" packages listed on the command line.\n"
" --list-packages, -p Do not install packages, print out final\n"
" package list that would be installed.\n"
" --list-files, -l <format> Do not install packages, print out table of\n"
" contents for all packages that would be\n"
" installed in a specified format.\n"
"\n"
" If \"detail\" is specified, a human readable,\n"
" pretty printed format with details is used.\n"
"\n"
" If \"initrd\" is specified, the format of Linux\n"
" gen_init_cpio is produced.\n",
.run_cmd = cmd_install,
};
REGISTER_COMMAND(install)