xbps/lib/initend.c

290 lines
8.1 KiB
C

/*-
* Copyright (c) 2011-2013 Juan Romero Pardines.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <sys/utsname.h>
#include <sys/types.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <stdarg.h>
#include <dirent.h>
#include "xbps_api_impl.h"
#ifdef __clang__
#pragma clang diagnostic ignored "-Wformat-nonliteral"
#endif
/**
* @file lib/initend.c
* @brief Initialization and finalization routines
* @defgroup initend Initialization and finalization functions
*
* Use these functions to initialize some parameters before start
* using libxbps and finalize usage to release resources at the end.
*/
static int
cb_validate_virtual(cfg_t *cfg, cfg_opt_t *opt)
{
for (unsigned int i = 0; i < cfg_size(cfg, "virtual-package"); i++) {
cfg_t *sec = cfg_opt_getnsec(opt, i);
if (cfg_getstr(sec, "targets") == 0) {
cfg_error(cfg, "targets must be set for "
"virtual-package %s", cfg_title(sec));
return -1;
}
}
return 0;
}
int
xbps_init(struct xbps_handle *xhp)
{
cfg_opt_t vpkg_opts[] = {
CFG_STR_LIST(__UNCONST("targets"), NULL, CFGF_NONE),
CFG_END()
};
cfg_opt_t opts[] = {
/* Defaults if not set in configuration file */
CFG_STR(__UNCONST("rootdir"), __UNCONST("/"), CFGF_NONE),
CFG_STR(__UNCONST("cachedir"),
__UNCONST(XBPS_CACHE_PATH), CFGF_NONE),
CFG_INT(__UNCONST("FetchCacheConnections"),
XBPS_FETCH_CACHECONN, CFGF_NONE),
CFG_INT(__UNCONST("FetchCacheConnectionsPerHost"),
XBPS_FETCH_CACHECONN_HOST, CFGF_NONE),
CFG_INT(__UNCONST("FetchTimeoutConnection"),
XBPS_FETCH_TIMEOUT, CFGF_NONE),
CFG_BOOL(__UNCONST("syslog"), true, CFGF_NONE),
CFG_STR_LIST(__UNCONST("repositories"), NULL, CFGF_MULTI),
CFG_SEC(__UNCONST("virtual-package"),
vpkg_opts, CFGF_MULTI|CFGF_TITLE),
CFG_FUNC(__UNCONST("include"), &cfg_include),
CFG_END()
};
struct utsname un;
char *buf;
const char *repodir;
int rv, cc, cch;
bool syslog_enabled = false;
assert(xhp != NULL);
if (xhp->conffile == NULL)
xhp->conffile = XBPS_CONF_DEF;
/* parse configuration file */
xhp->cfg = cfg_init(opts, CFGF_NOCASE);
cfg_set_validate_func(xhp->cfg, "virtual-package", &cb_validate_virtual);
if ((rv = cfg_parse(xhp->cfg, xhp->conffile)) != CFG_SUCCESS) {
if (rv == CFG_FILE_ERROR) {
/*
* Don't error out if config file not found.
* If a default repository is set, use it; otherwise
* use defaults (no repos and no virtual packages).
*/
if (errno != ENOENT)
return rv;
} else if (rv == CFG_PARSE_ERROR) {
/*
* Parser error from configuration file.
*/
return ENOTSUP;
}
}
xbps_dbg_printf(xhp, "Configuration file: %s\n",
xhp->conffile ? xhp->conffile : "not found");
/* Set rootdir */
if (xhp->rootdir[0] == '\0') {
if (xhp->cfg != NULL) {
strlcpy(xhp->rootdir,
cfg_getstr(xhp->cfg, "rootdir"),
sizeof(xhp->rootdir));
} else {
xhp->rootdir[0] = '/';
xhp->rootdir[1] = '\0';
}
} else if (xhp->rootdir[0] != '/') {
/* relative path */
char path[PATH_MAX-1];
if (getcwd(path, sizeof(path)) == NULL)
return ENOTSUP;
buf = strdup(xhp->rootdir);
snprintf(xhp->rootdir, sizeof(xhp->rootdir),
"%s/%s", path, buf);
free(buf);
}
/* Set cachedir */
if (xhp->cachedir[0] == '\0') {
snprintf(xhp->cachedir, sizeof(xhp->cachedir),
"%s/%s", strcmp(xhp->rootdir, "/") ? xhp->rootdir : "",
xhp->cfg ? cfg_getstr(xhp->cfg, "cachedir") : XBPS_CACHE_PATH);
} else if (xhp->cachedir[0] != '/') {
/* relative path */
buf = strdup(xhp->cachedir);
snprintf(xhp->cachedir, sizeof(xhp->cachedir),
"%s/%s", strcmp(xhp->rootdir, "/") ? xhp->rootdir : "", buf);
free(buf);
}
/* Set metadir */
if (xhp->metadir[0] == '\0') {
snprintf(xhp->metadir, sizeof(xhp->metadir),
"%s/%s", strcmp(xhp->rootdir, "/") ? xhp->rootdir : "",
XBPS_META_PATH);
} else if (xhp->metadir[0] != '/') {
/* relative path */
buf = strdup(xhp->metadir);
snprintf(xhp->metadir, sizeof(xhp->metadir),
"%s/%s", strcmp(xhp->rootdir, "/") ? xhp->rootdir : "", buf);
free(buf);
}
xhp->target_arch = getenv("XBPS_TARGET_ARCH");
uname(&un);
strlcpy(xhp->native_arch, un.machine, sizeof(xhp->native_arch));
assert(xhp->native_arch);
if (xhp->cfg == NULL) {
xhp->flags |= XBPS_FLAG_SYSLOG;
xhp->fetch_timeout = XBPS_FETCH_TIMEOUT;
cc = XBPS_FETCH_CACHECONN;
cch = XBPS_FETCH_CACHECONN_HOST;
} else {
if (cfg_getbool(xhp->cfg, "syslog"))
xhp->flags |= XBPS_FLAG_SYSLOG;
xhp->fetch_timeout = cfg_getint(xhp->cfg, "FetchTimeoutConnection");
cc = cfg_getint(xhp->cfg, "FetchCacheConnections");
cch = cfg_getint(xhp->cfg, "FetchCacheConnectionsPerHost");
}
if (xhp->flags & XBPS_FLAG_SYSLOG)
syslog_enabled = true;
xbps_fetch_set_cache_connection(cc, cch);
xbps_dbg_printf(xhp, "Rootdir=%s\n", xhp->rootdir);
xbps_dbg_printf(xhp, "Metadir=%s\n", xhp->metadir);
xbps_dbg_printf(xhp, "Cachedir=%s\n", xhp->cachedir);
xbps_dbg_printf(xhp, "FetchTimeout=%u\n", xhp->fetch_timeout);
xbps_dbg_printf(xhp, "FetchCacheconn=%u\n", cc);
xbps_dbg_printf(xhp, "FetchCacheconnHost=%u\n", cch);
xbps_dbg_printf(xhp, "Syslog=%u\n", syslog_enabled);
xbps_dbg_printf(xhp, "Architecture: %s\n", xhp->native_arch);
xbps_dbg_printf(xhp, "Target Architecture: %s\n", xhp->target_arch);
/*
* Append repository list specified in configuration file.
*/
for (unsigned int i = 0; i < cfg_size(xhp->cfg, "repositories"); i++) {
if (xhp->repositories == NULL)
xhp->repositories = xbps_array_create();
xbps_array_add_cstring_nocopy(xhp->repositories,
cfg_getnstr(xhp->cfg, "repositories", i));
}
if (xhp->flags & XBPS_FLAG_DEBUG) {
for (unsigned int i = 0; i < xbps_array_count(xhp->repositories); i++) {
xbps_array_get_cstring_nocopy(xhp->repositories, i, &repodir);
xbps_dbg_printf(xhp, "Repository[%u]=%s\n", i, repodir);
}
}
return 0;
}
void
xbps_end(struct xbps_handle *xhp)
{
assert(xhp);
xbps_pkgdb_release(xhp);
if (xbps_object_type(xhp->pkgdb_revdeps) != XBPS_TYPE_UNKNOWN)
xbps_object_release(xhp->pkgdb_revdeps);
xbps_fetch_unset_cache_connection();
cfg_free(xhp->cfg);
}
static void
common_printf(FILE *f, const char *msg, const char *fmt, va_list ap)
{
if (msg != NULL)
fprintf(f, "%s", msg);
vfprintf(f, fmt, ap);
}
void
xbps_dbg_printf_append(struct xbps_handle *xhp, const char *fmt, ...)
{
va_list ap;
if ((xhp->flags & XBPS_FLAG_DEBUG) == 0)
return;
va_start(ap, fmt);
common_printf(stderr, NULL, fmt, ap);
va_end(ap);
}
void
xbps_dbg_printf(struct xbps_handle *xhp, const char *fmt, ...)
{
va_list ap;
if ((xhp->flags & XBPS_FLAG_DEBUG) == 0)
return;
va_start(ap, fmt);
common_printf(stderr, "[DEBUG] ", fmt, ap);
va_end(ap);
}
void
xbps_error_printf(const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
common_printf(stderr, "ERROR: ", fmt, ap);
va_end(ap);
}
void
xbps_warn_printf(const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
common_printf(stderr, "WARNING: ", fmt, ap);
va_end(ap);
}