Implemented support for working with remote repositories.

libfetch from NetBSD's pkgsrc has been imported into lib/fetch, but
the objects are embedded into libxbps. Only a public function to fetch
files has been implemented: xbps_fetch_file().

The library now is built with -fvisibility=hidden by default, and
exported symbols are the ones that use the SYMEXPORT macro.

The code works well enough, but will need many more cleanups.

--HG--
extra : convert_revision : xtraeme%40gmail.com-20091027004600-0lq9aao67lisbzxv
This commit is contained in:
Juan RP 2009-10-27 01:46:00 +01:00
parent 6a855c0272
commit 7aebea684b
41 changed files with 6039 additions and 308 deletions

View File

@ -3,6 +3,7 @@ include ../vars.mk
SUBDIRS = xbps-bin
SUBDIRS += xbps-cmpver
SUBDIRS += xbps-digest
SUBDIRS += xbps-fetch
SUBDIRS += xbps-pkgdb
SUBDIRS += xbps-repo

View File

@ -108,6 +108,91 @@ check_pkg_hashes(prop_object_iterator_t iter)
return 0;
}
static int
download_package_list(prop_object_iterator_t iter)
{
prop_object_t obj;
const char *pkgname, *version, *repoloc, *filename, *arch;
char *savedir, *binfile, *lbinfile, *repoloc_trans;
int rv = 0;
printf("Downloading binary package file(s)...\n");
while ((obj = prop_object_iterator_next(iter)) != NULL) {
prop_dictionary_get_cstring_nocopy(obj, "repository", &repoloc);
/*
* Skip packages in local repositories.
*/
if ((strncmp(repoloc, "http://", 7)) &&
(strncmp(repoloc, "ftp://", 6)))
continue;
prop_dictionary_get_cstring_nocopy(obj, "pkgname", &pkgname);
prop_dictionary_get_cstring_nocopy(obj, "version", &version);
prop_dictionary_get_cstring_nocopy(obj, "filename", &filename);
prop_dictionary_get_cstring_nocopy(obj, "architecture", &arch);
repoloc_trans = xbps_get_remote_repo_string(repoloc);
if (repoloc_trans == NULL)
return errno;
savedir = xbps_xasprintf("%s/%s/repo/%s/%s",
xbps_get_rootdir(), XBPS_META_PATH, repoloc_trans, arch);
if (savedir == NULL) {
free(repoloc_trans);
return errno;
}
lbinfile = xbps_xasprintf("%s/%s", savedir, filename);
if (lbinfile == NULL) {
free(repoloc_trans);
free(savedir);
return errno;
}
if (access(lbinfile, R_OK) == 0) {
free(savedir);
free(lbinfile);
goto change_repodir;
}
free(lbinfile);
binfile = xbps_xasprintf("%s/%s/%s", repoloc, arch, filename);
if (binfile == NULL) {
free(repoloc_trans);
free(savedir);
return errno;
}
printf("Downloading %s-%s binary package ...\n",
pkgname, version);
rv = xbps_fetch_file(binfile, savedir);
free(savedir);
free(binfile);
if (rv != 0) {
printf("Couldn't download %s from %s (%s)\n",
filename, repoloc, strerror(rv));
free(repoloc_trans);
return errno;
}
change_repodir:
/*
* If it was downloaded successfully, override repository
* path in transaction dictionary.
*/
savedir = xbps_xasprintf("%s/%s/repo/%s",
xbps_get_rootdir(), XBPS_META_PATH, repoloc_trans);
free(repoloc_trans);
if (savedir == NULL)
return errno;
prop_dictionary_set_cstring(obj, "repository", savedir);
free(savedir);
}
prop_object_iterator_reset(iter);
return 0;
}
static void
show_package_list(prop_object_iterator_t iter, const char *match)
{
@ -409,6 +494,12 @@ exec_transaction(struct transaction *trans)
}
}
/*
* Download binary packages if they are in a remote repository.
*/
if ((rv = download_package_list(trans->iter)) != 0)
return rv;
/*
* Check the SHA256 hash for all required packages.
*/

View File

@ -1,5 +1,5 @@
/*-
* Copyright (c) 2008 Juan Romero Pardines.
* Copyright (c) 2008-2009 Juan Romero Pardines.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -30,7 +30,6 @@
#include <string.h>
#include <xbps_api.h>
#include "sha256.h"
static void
usage(void)
@ -42,35 +41,21 @@ usage(void)
int
main(int argc, char **argv)
{
SHA256_CTX ctx;
uint8_t buffer[BUFSIZ * 20], *digest;
ssize_t bytes;
int i, fd;
char *hash;
int i;
if (argc < 2)
usage();
for (i = 1; i < argc; i++) {
if ((fd = open(argv[i], O_RDONLY)) == -1) {
printf("xbps-digest: cannot open %s (%s)\n", argv[i],
strerror(errno));
hash = xbps_get_file_hash(argv[i]);
if (hash == NULL) {
printf("Couldn't get hash for %s (%s)\n",
argv[i], strerror(errno));
exit(EXIT_FAILURE);
}
digest = malloc(SHA256_DIGEST_STRING_LENGTH);
if (digest == NULL) {
printf("xbps-digest: malloc failed (%s)\n",
strerror(errno));
exit(EXIT_FAILURE);
}
SHA256_Init(&ctx);
while ((bytes = read(fd, buffer, sizeof(buffer))) > 0)
SHA256_Update(&ctx, buffer, (size_t)bytes);
printf("%s\n", SHA256_End(&ctx, digest));
free(digest);
close(fd);
printf("%s\n", hash);
free(hash);
}
exit(EXIT_SUCCESS);

6
bin/xbps-fetch/Makefile Normal file
View File

@ -0,0 +1,6 @@
TOPDIR = ../..
include $(TOPDIR)/vars.mk
BIN = xbps-fetch
include $(TOPDIR)/prog.mk

14
bin/xbps-fetch/main.c Normal file
View File

@ -0,0 +1,14 @@
#include <stdio.h>
#include <stdlib.h>
#include <xbps_api.h>
int
main(int argc, char **argv)
{
if (argc != 2) {
printf("Usage: xbps-fetch [options] URL\n");
exit(EXIT_FAILURE);
}
return xbps_fetch_file(argv[1], ".");
}

View File

@ -63,8 +63,6 @@ repoidx_getdict(const char *pkgdir)
prop_dictionary_set(dict, "packages", array);
prop_object_release(array);
prop_dictionary_set_cstring_nocopy(dict,
"location-local", pkgdir);
prop_dictionary_set_cstring_nocopy(dict,
"pkgindex-version", XBPS_PKGINDEX_VERSION);
}

View File

@ -37,8 +37,6 @@
typedef struct repository_info {
const char *index_version;
const char *location_local;
const char *location_remote;
uint64_t total_pkgs;
} repo_info_t;
@ -84,14 +82,6 @@ pkgindex_getinfo(prop_dictionary_t dict, repo_info_t *ri)
"pkgindex-version", &ri->index_version))
return false;
if (!prop_dictionary_get_cstring_nocopy(dict,
"location-local", &ri->location_local))
return false;
/* This one is optional, thus don't panic */
prop_dictionary_get_cstring_nocopy(dict, "location-remote",
&ri->location_remote);
if (!prop_dictionary_get_uint64(dict, "total-pkgs",
&ri->total_pkgs))
return false;
@ -144,13 +134,79 @@ out:
return rv;
}
static int
add_repository(const char *uri, bool remote)
{
prop_dictionary_t dict;
repo_info_t *rinfo;
char *plist, idxstr[PATH_MAX];
int rv = 0;
if (remote) {
rv = xbps_sync_repository_pkg_index(uri);
if (rv != 0)
return rv;
plist = xbps_get_pkg_index_plist(uri);
} else {
if (!sanitize_localpath(idxstr, uri))
return errno;
plist = xbps_get_pkg_index_plist(idxstr);
}
if (plist == NULL)
return errno;
dict = prop_dictionary_internalize_from_file(plist);
if (dict == NULL) {
printf("Repository %s does not contain any "
"xbps pkgindex file.\n", idxstr);
rv = errno;
goto out;
}
rinfo = malloc(sizeof(*rinfo));
if (rinfo == NULL) {
rv = errno;
goto out;
}
if (!pkgindex_getinfo(dict, rinfo)) {
printf("'%s' is incomplete.\n", plist);
rv = EINVAL;
goto out;
}
if (remote)
rv = xbps_register_repository(uri);
else
rv = xbps_register_repository(idxstr);
if (rv != 0) {
printf("ERROR: couldn't register repository (%s)\n",
strerror(rv));
goto out;
}
printf("Added repository at %s (%s) with %ju packages.\n",
uri, rinfo->index_version, rinfo->total_pkgs);
out:
if (dict != NULL)
prop_object_release(dict);
if (rinfo != NULL)
free(rinfo);
if (plist != NULL)
free(plist);
return rv;
}
int
main(int argc, char **argv)
{
prop_dictionary_t dict;
repo_info_t *rinfo = NULL;
char dpkgidx[PATH_MAX], *plist, *root = NULL;
char dpkgidx[PATH_MAX], *root = NULL;
int c, rv = 0;
bool remote_repo = false;
while ((c = getopt(argc, argv, "Vr:")) != -1) {
switch (c) {
@ -179,53 +235,11 @@ main(int argc, char **argv)
if (argc != 2)
usage();
if (!sanitize_localpath(dpkgidx, argv[1]))
exit(EXIT_FAILURE);
if ((strncmp(argv[1], "http://", 7) == 0) ||
(strncmp(argv[1], "ftp://", 6) == 0))
remote_repo = true;
/* Temp buffer to verify pkgindex file. */
plist = xbps_get_pkg_index_plist(dpkgidx);
if (plist == NULL)
exit(EXIT_FAILURE);
dict = prop_dictionary_internalize_from_file(plist);
if (dict == NULL) {
printf("Directory %s does not contain any "
"xbps pkgindex file.\n", dpkgidx);
free(plist);
exit(EXIT_FAILURE);
}
rinfo = malloc(sizeof(*rinfo));
if (rinfo == NULL) {
prop_object_release(dict);
free(plist);
exit(EXIT_FAILURE);
}
if (!pkgindex_getinfo(dict, rinfo)) {
printf("'%s' is incomplete.\n", plist);
prop_object_release(dict);
free(rinfo);
free(plist);
exit(EXIT_FAILURE);
}
if ((rv = xbps_register_repository(dpkgidx)) != 0) {
printf("ERROR: couldn't register repository (%s)\n",
strerror(rv));
prop_object_release(dict);
free(rinfo);
free(plist);
exit(EXIT_FAILURE);
}
printf("Added repository at %s (%s) with %ju packages.\n",
rinfo->location_local, rinfo->index_version,
rinfo->total_pkgs);
prop_object_release(dict);
free(rinfo);
free(plist);
rv = add_repository(argv[1], remote_repo);
} else if (strcasecmp(argv[0], "list") == 0) {
/* Lists all repositories registered in pool. */

View File

@ -248,10 +248,8 @@ int
show_pkg_info_from_repolist(prop_object_t obj, void *arg, bool *loop_done)
{
prop_dictionary_t dict, pkgdict;
prop_string_t oloc;
const char *repofile, *repoloc;
const char *repofile;
char *plist;
assert(prop_object_type(obj) == PROP_TYPE_STRING);
/* Get the location */
@ -276,19 +274,7 @@ show_pkg_info_from_repolist(prop_object_t obj, void *arg, bool *loop_done)
return 0;
}
oloc = prop_dictionary_get(dict, "location-remote");
if (oloc == NULL)
oloc = prop_dictionary_get(dict, "location-local");
if (oloc && prop_object_type(oloc) == PROP_TYPE_STRING)
repoloc = prop_string_cstring_nocopy(oloc);
else {
prop_object_release(dict);
free(plist);
return EINVAL;
}
printf("Repository: %s\n", repoloc);
printf("Repository: %s\n", repofile);
show_pkg_info(pkgdict);
*loop_done = true;
prop_object_release(dict);

View File

@ -11,13 +11,8 @@ a "dictionary per package". Additional objects are added into the
main dictionary to specify more info, like:
- pkgindex-version: version used to build the index.
- location-local: local path to the repository.
- location-remote: remote URI repository.
- total-pkgs: total of number of available packages.
"location-local" will always be created, and it might be exported via
a remote location specified with "location-remote".
The package dictionary will be the same than the one available in
package's metadata directory "/var/db/xbps/metadata/$pkgname/props.plist",
but some additional objects are added to provide enough info for
@ -32,10 +27,6 @@ Here's how the package index plist file shall look like in a repository:
<dict>
<key>pkgindex-version</key>
<string>1.0</string>
<key>location-local</key>
<string>/xbps/repo/local</string>
<key>location-remote</key>
<string>http://www.xbps-remote.org/repo/public</string>
<key>total-pkgs</key>
<integer>666</integer>
<key>available-packages</key>

183
include/fetch.h Normal file
View File

@ -0,0 +1,183 @@
/* $NetBSD: fetch.h,v 1.15 2009/10/15 12:36:57 joerg Exp $ */
/*-
* Copyright (c) 1998-2004 Dag-Erling Coïdn Smorgrav
* 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
* in this position and unchanged.
* 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.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission
*
* 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.
*
* $FreeBSD: fetch.h,v 1.26 2004/09/21 18:35:20 des Exp $
*/
#ifndef _FETCH_H_INCLUDED
#define _FETCH_H_INCLUDED
#include <sys/types.h>
#include <limits.h>
#include <stdio.h>
#define _LIBFETCH_VER "libfetch/2.0"
#define URL_HOSTLEN 255
#define URL_SCHEMELEN 16
#define URL_USERLEN 256
#define URL_PWDLEN 256
typedef struct fetchIO fetchIO;
struct url {
char scheme[URL_SCHEMELEN + 1];
char user[URL_USERLEN + 1];
char pwd[URL_PWDLEN + 1];
char host[URL_HOSTLEN + 1];
int port;
char *doc;
off_t offset;
size_t length;
time_t last_modified;
};
struct url_stat {
off_t size;
time_t atime;
time_t mtime;
};
struct url_list {
size_t length;
size_t alloc_size;
struct url *urls;
};
/* Recognized schemes */
#define SCHEME_FTP "ftp"
#define SCHEME_HTTP "http"
#define SCHEME_HTTPS "https"
#define SCHEME_FILE "file"
/* Error codes */
#define FETCH_ABORT 1
#define FETCH_AUTH 2
#define FETCH_DOWN 3
#define FETCH_EXISTS 4
#define FETCH_FULL 5
#define FETCH_INFO 6
#define FETCH_MEMORY 7
#define FETCH_MOVED 8
#define FETCH_NETWORK 9
#define FETCH_OK 10
#define FETCH_PROTO 11
#define FETCH_RESOLV 12
#define FETCH_SERVER 13
#define FETCH_TEMP 14
#define FETCH_TIMEOUT 15
#define FETCH_UNAVAIL 16
#define FETCH_UNKNOWN 17
#define FETCH_URL 18
#define FETCH_VERBOSE 19
#define FETCH_UNCHANGED 20
#if defined(__cplusplus)
extern "C" {
#endif
void fetchIO_close(fetchIO *);
ssize_t fetchIO_read(fetchIO *, void *, size_t);
ssize_t fetchIO_write(fetchIO *, const void *, size_t);
/* fetchIO-specific functions */
fetchIO *fetchXGetFile(struct url *, struct url_stat *, const char *);
fetchIO *fetchGetFile(struct url *, const char *);
fetchIO *fetchPutFile(struct url *, const char *);
int fetchStatFile(struct url *, struct url_stat *, const char *);
int fetchListFile(struct url_list *, struct url *, const char *,
const char *);
/* HTTP-specific functions */
fetchIO *fetchXGetHTTP(struct url *, struct url_stat *, const char *);
fetchIO *fetchGetHTTP(struct url *, const char *);
fetchIO *fetchPutHTTP(struct url *, const char *);
int fetchStatHTTP(struct url *, struct url_stat *, const char *);
int fetchListHTTP(struct url_list *, struct url *, const char *,
const char *);
/* FTP-specific functions */
fetchIO *fetchXGetFTP(struct url *, struct url_stat *, const char *);
fetchIO *fetchGetFTP(struct url *, const char *);
fetchIO *fetchPutFTP(struct url *, const char *);
int fetchStatFTP(struct url *, struct url_stat *, const char *);
int fetchListFTP(struct url_list *, struct url *, const char *,
const char *);
/* Generic functions */
fetchIO *fetchXGetURL(const char *, struct url_stat *, const char *);
fetchIO *fetchGetURL(const char *, const char *);
fetchIO *fetchPutURL(const char *, const char *);
int fetchStatURL(const char *, struct url_stat *, const char *);
int fetchListURL(struct url_list *, const char *, const char *,
const char *);
fetchIO *fetchXGet(struct url *, struct url_stat *, const char *);
fetchIO *fetchGet(struct url *, const char *);
fetchIO *fetchPut(struct url *, const char *);
int fetchStat(struct url *, struct url_stat *, const char *);
int fetchList(struct url_list *, struct url *, const char *,
const char *);
/* URL parsing */
struct url *fetchMakeURL(const char *, const char *, int,
const char *, const char *, const char *);
struct url *fetchParseURL(const char *);
struct url *fetchCopyURL(const struct url *);
char *fetchStringifyURL(const struct url *);
void fetchFreeURL(struct url *);
/* URL listening */
void fetchInitURLList(struct url_list *);
int fetchAppendURLList(struct url_list *, const struct url_list *);
void fetchFreeURLList(struct url_list *);
char *fetchUnquotePath(struct url *);
char *fetchUnquoteFilename(struct url *);
/* Authentication */
typedef int (*auth_t)(struct url *);
extern auth_t fetchAuthMethod;
/* Last error code */
extern int fetchLastErrCode;
#define MAXERRSTRING 256
extern char fetchLastErrString[MAXERRSTRING];
/* I/O timeout */
extern int fetchTimeout;
/* Restart interrupted syscalls */
extern volatile int fetchRestartCalls;
/* Extra verbosity */
extern int fetchDebug;
#if defined(__cplusplus)
}
#endif
#endif

View File

@ -68,17 +68,29 @@
#define __UNCONST(a) ((void *)(unsigned long)(const void *)(a))
#endif
#if __GNUC__ >= 4
#define SYMEXPORT __attribute__ ((visibility("default")))
#else
#define SYMEXPORT
#endif
/* From lib/configure.c */
int xbps_configure_pkg(const char *, const char *, bool);
int xbps_configure_all_pkgs(void);
int SYMEXPORT xbps_configure_pkg(const char *, const char *, bool);
int SYMEXPORT xbps_configure_all_pkgs(void);
/* from lib/cmpver.c */
int xbps_cmpver(const char *, const char *);
int SYMEXPORT xbps_cmpver(const char *, const char *);
/* From lib/download.c */
int SYMEXPORT xbps_fetch_file(const char *, const char *);
void SYMEXPORT (*xbps_fetch_start_cb)(const char *, off_t *, off_t *);
void SYMEXPORT (*xbps_fetch_update_cb)(off_t *);
void SYMEXPORT (*xbps_fetch_end_cb)(void);
/* From lib/fexec.c */
int xbps_file_exec(const char *, ...);
int xbps_file_exec_skipempty(const char *, ...);
int xbps_file_chdir_exec(const char *, const char *, ...);
int SYMEXPORT xbps_file_exec(const char *, ...);
int SYMEXPORT xbps_file_exec_skipempty(const char *, ...);
int SYMEXPORT xbps_file_chdir_exec(const char *, const char *, ...);
/* From lib/humanize_number.c */
#define HN_DECIMAL 0x01
@ -88,85 +100,89 @@ int xbps_file_chdir_exec(const char *, const char *, ...);
#define HN_GETSCALE 0x10
#define HN_AUTOSCALE 0x20
int xbps_humanize_number(char *, size_t, int64_t, const char *,
int SYMEXPORT xbps_humanize_number(char *, size_t, int64_t, const char *,
int, int);
/* From lib/findpkg.c */
struct repository_data {
SIMPLEQ_ENTRY(repository_data) chain;
prop_dictionary_t rd_repod;
char *rd_uri;
};
SIMPLEQ_HEAD(, repository_data) repodata_queue;
SYMEXPORT SIMPLEQ_HEAD(, repository_data) repodata_queue;
int xbps_prepare_pkg(const char *);
int xbps_find_new_pkg(const char *, prop_dictionary_t);
int xbps_find_new_packages(void);
int xbps_prepare_repolist_data(void);
void xbps_release_repolist_data(void);
prop_dictionary_t xbps_get_pkg_props(void);
int SYMEXPORT xbps_prepare_pkg(const char *);
int SYMEXPORT xbps_find_new_pkg(const char *, prop_dictionary_t);
int SYMEXPORT xbps_find_new_packages(void);
int SYMEXPORT xbps_prepare_repolist_data(void);
void SYMEXPORT xbps_release_repolist_data(void);
prop_dictionary_t SYMEXPORT xbps_get_pkg_props(void);
/* From lib/depends.c */
int xbps_find_deps_in_pkg(prop_dictionary_t, prop_dictionary_t);
int SYMEXPORT xbps_find_deps_in_pkg(prop_dictionary_t, prop_dictionary_t);
/* From lib/orphans.c */
prop_array_t xbps_find_orphan_packages(void);
prop_array_t SYMEXPORT xbps_find_orphan_packages(void);
/* From lib/plist.c */
bool xbps_add_obj_to_dict(prop_dictionary_t, prop_object_t,
bool SYMEXPORT xbps_add_obj_to_dict(prop_dictionary_t, prop_object_t,
const char *);
bool xbps_add_obj_to_array(prop_array_t, prop_object_t);
bool SYMEXPORT xbps_add_obj_to_array(prop_array_t, prop_object_t);
int xbps_callback_array_iter_in_dict(prop_dictionary_t,
int SYMEXPORT xbps_callback_array_iter_in_dict(prop_dictionary_t,
const char *,
int (*fn)(prop_object_t, void *, bool *),
void *);
int xbps_callback_array_iter_reverse_in_dict(prop_dictionary_t,
int SYMEXPORT xbps_callback_array_iter_reverse_in_dict(prop_dictionary_t,
const char *,
int (*fn)(prop_object_t, void *, bool *),
void *);
int xbps_callback_array_iter_in_repolist(int (*fn)(prop_object_t,
int SYMEXPORT xbps_callback_array_iter_in_repolist(int (*fn)(prop_object_t,
void *, bool *), void *);
prop_dictionary_t xbps_find_pkg_in_dict(prop_dictionary_t,
prop_dictionary_t SYMEXPORT xbps_find_pkg_in_dict(prop_dictionary_t,
const char *, const char *);
prop_dictionary_t xbps_find_pkg_from_plist(const char *, const char *);
prop_dictionary_t xbps_find_pkg_installed_from_plist(const char *);
bool xbps_find_string_in_array(prop_array_t, const char *);
prop_dictionary_t SYMEXPORT xbps_find_pkg_from_plist(const char *,
const char *);
prop_dictionary_t SYMEXPORT xbps_find_pkg_installed_from_plist(const char *);
bool SYMEXPORT xbps_find_string_in_array(prop_array_t, const char *);
prop_dictionary_t xbps_prepare_regpkgdb_dict(void);
void xbps_release_regpkgdb_dict(void);
prop_object_iterator_t xbps_get_array_iter_from_dict(prop_dictionary_t,
const char *);
prop_dictionary_t SYMEXPORT xbps_prepare_regpkgdb_dict(void);
void SYMEXPORT xbps_release_regpkgdb_dict(void);
prop_object_iterator_t SYMEXPORT
xbps_get_array_iter_from_dict(prop_dictionary_t, const char *);
prop_dictionary_t xbps_read_dict_from_archive_entry(struct archive *,
struct archive_entry *);
prop_dictionary_t SYMEXPORT xbps_read_dict_from_archive_entry(struct archive *,
struct archive_entry *);
int xbps_remove_pkg_dict_from_file(const char *, const char *);
int xbps_remove_pkg_from_dict(prop_dictionary_t, const char *,
int SYMEXPORT xbps_remove_pkg_dict_from_file(const char *, const char *);
int SYMEXPORT xbps_remove_pkg_from_dict(prop_dictionary_t, const char *,
const char *);
int xbps_remove_string_from_array(prop_array_t, const char *);
int SYMEXPORT xbps_remove_string_from_array(prop_array_t, const char *);
/* From lib/purge.c */
int xbps_purge_pkg(const char *, bool);
int xbps_purge_all_pkgs(void);
int SYMEXPORT xbps_purge_pkg(const char *, bool);
int SYMEXPORT xbps_purge_all_pkgs(void);
/* From lib/register.c */
int xbps_register_pkg(prop_dictionary_t, bool);
int xbps_unregister_pkg(const char *);
int SYMEXPORT xbps_register_pkg(prop_dictionary_t, bool);
int SYMEXPORT xbps_unregister_pkg(const char *);
/* From lib/remove.c */
int xbps_remove_pkg(const char *, const char *, bool);
int SYMEXPORT xbps_remove_pkg(const char *, const char *, bool);
/* From lib/repository.c */
int xbps_register_repository(const char *);
int xbps_unregister_repository(const char *);
int SYMEXPORT xbps_register_repository(const char *);
int SYMEXPORT xbps_unregister_repository(const char *);
int SYMEXPORT xbps_sync_repository_pkg_index(const char *);
char SYMEXPORT *xbps_get_remote_repo_string(const char *);
/* From lib/requiredby.c */
int xbps_requiredby_pkg_add(prop_array_t, prop_dictionary_t);
int xbps_requiredby_pkg_remove(const char *);
int SYMEXPORT xbps_requiredby_pkg_add(prop_array_t, prop_dictionary_t);
int SYMEXPORT xbps_requiredby_pkg_remove(const char *);
/* From lib/sortdeps.c */
int xbps_sort_pkg_deps(prop_dictionary_t);
int SYMEXPORT xbps_sort_pkg_deps(prop_dictionary_t);
/* From lib/state.c */
typedef enum pkg_state {
@ -176,31 +192,31 @@ typedef enum pkg_state {
XBPS_PKG_STATE_CONFIG_FILES,
XBPS_PKG_STATE_NOT_INSTALLED
} pkg_state_t;
int xbps_get_pkg_state_installed(const char *, pkg_state_t *);
int xbps_get_pkg_state_dictionary(prop_dictionary_t, pkg_state_t *);
int xbps_set_pkg_state_installed(const char *, pkg_state_t);
int xbps_set_pkg_state_dictionary(prop_dictionary_t, pkg_state_t);
int SYMEXPORT xbps_get_pkg_state_installed(const char *, pkg_state_t *);
int SYMEXPORT xbps_get_pkg_state_dictionary(prop_dictionary_t, pkg_state_t *);
int SYMEXPORT xbps_set_pkg_state_installed(const char *, pkg_state_t);
int SYMEXPORT xbps_set_pkg_state_dictionary(prop_dictionary_t, pkg_state_t);
/* From lib/unpack.c */
int xbps_unpack_binary_pkg(prop_dictionary_t, bool);
int SYMEXPORT xbps_unpack_binary_pkg(prop_dictionary_t, bool);
/* From lib/util.c */
char * xbps_xasprintf(const char *, ...);
char * xbps_get_file_hash(const char *);
int xbps_check_file_hash(const char *, const char *);
int xbps_check_pkg_file_hash(prop_dictionary_t, const char *);
int xbps_check_is_installed_pkg(const char *);
bool xbps_check_is_installed_pkgname(const char *);
char * xbps_get_pkg_index_plist(const char *);
char * xbps_get_pkg_name(const char *);
const char * xbps_get_pkg_version(const char *);
const char * xbps_get_pkg_revision(const char *);
bool xbps_pkg_has_rundeps(prop_dictionary_t);
void xbps_set_rootdir(const char *);
const char * xbps_get_rootdir(void);
void xbps_set_flags(int);
int xbps_get_flags(void);
bool xbps_yesno(const char *, ...);
bool xbps_noyes(const char *, ...);
char SYMEXPORT *xbps_xasprintf(const char *, ...);
char SYMEXPORT *xbps_get_file_hash(const char *);
int SYMEXPORT xbps_check_file_hash(const char *, const char *);
int SYMEXPORT xbps_check_pkg_file_hash(prop_dictionary_t, const char *);
int SYMEXPORT xbps_check_is_installed_pkg(const char *);
bool SYMEXPORT xbps_check_is_installed_pkgname(const char *);
char SYMEXPORT *xbps_get_pkg_index_plist(const char *);
char SYMEXPORT *xbps_get_pkg_name(const char *);
const char SYMEXPORT *xbps_get_pkg_version(const char *);
const char SYMEXPORT *xbps_get_pkg_revision(const char *);
bool SYMEXPORT xbps_pkg_has_rundeps(prop_dictionary_t);
void SYMEXPORT xbps_set_rootdir(const char *);
const char SYMEXPORT *xbps_get_rootdir(void);
void SYMEXPORT xbps_set_flags(int);
int SYMEXPORT xbps_get_flags(void);
bool SYMEXPORT xbps_yesno(const char *, ...);
bool SYMEXPORT xbps_noyes(const char *, ...);
#endif /* !_XBPS_API_H_ */

View File

@ -1,49 +1,65 @@
include ../vars.mk
# The shared library.
MAJOR = 0
MINOR = 0
MICRO = 0
LIBXBPS_SO = $(LIBXBPS).$(MAJOR).$(MINOR).$(MICRO)
LIBXBPS = libxbps.so
LIBXBPS_STATIC = libxbps.a
LIBXBPS_LDFLAGS = -larchive -lprop -shared -Wl,-soname,$(LIBXBPS).$(MAJOR)
INET6 ?= yes
SSL ?= yes
LIBS = -larchive -lprop
OBJECTS = configure.o cmpver.o depends.o fexec.o findpkg.o
OBJECTS += humanize_number.o orphans.o plist.o purge.o register.o remove.o
OBJECTS += repository.o requiredby.o sha256.o sortdeps.o state.o unpack.o
OBJECTS += util.o
ifdef SSL
CPPFLAGS += -DWITH_SSL
LIBS += -lssl -lcrypto
endif
all: $(LIBXBPS) $(LIBXBPS_STATIC)
ifdef INET6
CPPFLAGS += -DINET6
endif
ifdef DEBUG
CPPFLAGS += -DDEBUG
endif
LIBMAJOR = 0
LIBMINOR = 0
LIBMICRO = 0
LIBXBPS_SHLIB = libxbps.so.$(LIBMAJOR).$(LIBMINOR).$(LIBMICRO)
LIBXBPS_LDFLAGS = $(LIBS) -shared -Wl,-soname,libxbps.so.$(LIBMAJOR)
# libfetch
OBJS = fetch/common.o fetch/fetch.o fetch/file.o fetch/ftp.o fetch/http.o
# libxbps
OBJS += configure.o cmpver.o depends.o download.o fexec.o findpkg.o
OBJS += humanize_number.o orphans.o plist.o purge.o register.o remove.o
OBJS += repository.o requiredby.o sha256.o sortdeps.o state.o unpack.o
OBJS += util.o
all: libfetch libxbps.so libxbps.a
.PHONY: all
$(LIBXBPS): $(OBJECTS)
$(CC) $(LIBXBPS_LDFLAGS) $^ -o $(LIBXBPS_SO)
-ln -sf $(LIBXBPS_SO) $(LIBXBPS).$(MAJOR)
-ln -sf $(LIBXBPS_SO) $(LIBXBPS)
libfetch:
$(MAKE) -C fetch
$(LIBXBPS_STATIC): $(OBJECTS)
libxbps.so: $(OBJS)
$(CC) $(LIBXBPS_LDFLAGS) $^ -o $(LIBXBPS_SHLIB)
-ln -sf $(LIBXBPS_SHLIB) libxbps.so.$(LIBMAJOR)
-ln -sf $(LIBXBPS_SHLIB) libxbps.so
libxbps.a: $(OBJS)
$(AR) rcs $@ $^
ranlib $@
.PHONY: install
install: $(LIBXBPS) $(LIBXBPS_STATIC)
install: all
install -d $(LIBDIR)
install -m 644 $(LIBXBPS_STATIC) $(LIBDIR)
install -m 644 $(LIBXBPS_SO) $(LIBDIR)
cp -a $(LIBXBPS) $(LIBDIR)
cp -a $(LIBXBPS).$(MAJOR) $(LIBDIR)
install -m 644 libxbps.a $(LIBDIR)
install -m 644 $(LIBXBPS_SHLIB) $(LIBDIR)
cp -a libxbps.so $(LIBDIR)
cp -a libxbps.so.$(LIBMAJOR) $(LIBDIR)
.PHONY: uninstall
uninstall:
-rm -f $(LIBDIR)/libxbps.*
.PHONY: clean
clean: clean-lib clean-objs
clean-lib:
-rm -f $(LIBXBPS)*
-rm -f $(LIBXBPS_STATIC)
clean-objs:
-rm -f *.o
clean:
-rm -f libxbps* $(OBJS)
$(MAKE) -C fetch clean

View File

@ -223,7 +223,7 @@ get_component(const char *position, version_component *component)
* of the version should conform to the porting guidelines. It can contain
* multiple components, separated by a period, including letters.
*/
int
int SYMEXPORT
xbps_cmpver(const char *pkg1, const char *pkg2)
{
const char *v1, *v2, *ve1, *ve2;

View File

@ -33,7 +33,7 @@
/*
* Configure all packages currently in unpacked state.
*/
int
int SYMEXPORT
xbps_configure_all_pkgs(void)
{
prop_dictionary_t d;
@ -71,7 +71,7 @@ xbps_configure_all_pkgs(void)
* post INSTALL action if required and updates package state to
* to installed.
*/
int
int SYMEXPORT
xbps_configure_pkg(const char *pkgname, const char *version, bool check_state)
{
prop_dictionary_t pkgd;

View File

@ -31,27 +31,28 @@
#include <xbps_api.h>
static int add_missing_reqdep(prop_dictionary_t, const char *, const char *);
static int find_repo_deps(prop_dictionary_t, prop_dictionary_t, prop_array_t);
static int find_repo_missing_deps(prop_dictionary_t, prop_dictionary_t);
static int find_repo_deps(prop_dictionary_t, prop_dictionary_t,
const char *, prop_array_t);
static int find_repo_missing_deps(prop_dictionary_t, prop_dictionary_t,
const char *);
static int
store_dependency(prop_dictionary_t master, prop_dictionary_t depd,
prop_dictionary_t repod)
const char *repoloc)
{
prop_dictionary_t dict;
prop_array_t array;
const char *repoloc, *pkgname;
const char *pkgname;
int rv = 0;
pkg_state_t state = 0;
assert(master != NULL);
assert(depd != NULL);
assert(repod != NULL);
assert(repoloc != NULL);
/*
* Get some info about dependencies and current repository.
*/
prop_dictionary_get_cstring_nocopy(depd, "pkgname", &pkgname);
prop_dictionary_get_cstring_nocopy(repod, "location-local", &repoloc);
dict = prop_dictionary_copy(depd);
if (dict == NULL)
@ -136,7 +137,7 @@ add_missing_reqdep(prop_dictionary_t master, const char *pkgname,
return 0;
}
int
int SYMEXPORT
xbps_find_deps_in_pkg(prop_dictionary_t master, prop_dictionary_t pkg)
{
prop_array_t pkg_rdeps, missing_rdeps;
@ -161,7 +162,8 @@ xbps_find_deps_in_pkg(prop_dictionary_t master, prop_dictionary_t pkg)
* if any of them is not there it will be added
* into the missing_deps array.
*/
rv = find_repo_deps(master, rdata->rd_repod, pkg_rdeps);
rv = find_repo_deps(master, rdata->rd_repod,
rdata->rd_uri, pkg_rdeps);
if (rv != 0) {
if (rv == ENOENT) {
rv = 0;
@ -181,7 +183,8 @@ xbps_find_deps_in_pkg(prop_dictionary_t master, prop_dictionary_t pkg)
* just in case that indirect deps weren't found.
*/
SIMPLEQ_FOREACH(rdata, &repodata_queue, chain) {
rv = find_repo_missing_deps(master, rdata->rd_repod);
rv = find_repo_missing_deps(master, rdata->rd_repod,
rdata->rd_uri);
if (rv != 0 && rv != ENOENT)
return rv;
}
@ -193,7 +196,8 @@ xbps_find_deps_in_pkg(prop_dictionary_t master, prop_dictionary_t pkg)
}
static int
find_repo_missing_deps(prop_dictionary_t master, prop_dictionary_t repo)
find_repo_missing_deps(prop_dictionary_t master, prop_dictionary_t repo,
const char *repoloc)
{
prop_array_t array;
prop_dictionary_t curpkgd;
@ -233,7 +237,7 @@ find_repo_missing_deps(prop_dictionary_t master, prop_dictionary_t repo)
/*
* Package is on repo, add it into the dictionary.
*/
if ((rv = store_dependency(master, curpkgd, repo)) != 0)
if ((rv = store_dependency(master, curpkgd, repoloc)) != 0)
break;
/*
* Remove package from missing_deps array now.
@ -252,7 +256,7 @@ find_repo_missing_deps(prop_dictionary_t master, prop_dictionary_t repo)
static int
find_repo_deps(prop_dictionary_t master, prop_dictionary_t repo,
prop_array_t pkg_rdeps)
const char *repoloc, prop_array_t pkg_rdeps)
{
prop_dictionary_t curpkgd, tmpd = NULL;
prop_array_t curpkg_rdeps;
@ -321,7 +325,7 @@ find_repo_deps(prop_dictionary_t master, prop_dictionary_t repo,
/*
* Package is on repo, add it into the dictionary.
*/
if ((rv = store_dependency(master, curpkgd, repo)) != 0) {
if ((rv = store_dependency(master, curpkgd, repoloc)) != 0) {
free(pkgname);
break;
}
@ -344,7 +348,7 @@ find_repo_deps(prop_dictionary_t master, prop_dictionary_t repo,
/*
* Iterate on required pkg to find more deps.
*/
if (!find_repo_deps(master, repo, curpkg_rdeps))
if (!find_repo_deps(master, repo, repoloc, curpkg_rdeps))
continue;
}
prop_object_iterator_release(iter);

300
lib/download.c Normal file
View File

@ -0,0 +1,300 @@
/*-
* Copyright (c) 2009 Juan Romero Pardines
* Copyright (c) 2000-2004 Dag-Erling Coïdan Smørgrav
* 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
* in this position and unchanged.
* 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.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission
*
* 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.
*
* From FreeBSD fetch(8):
* $FreeBSD: src/usr.bin/fetch/fetch.c,v 1.84.2.1 2009/08/03 08:13:06 kensmith Exp $
*/
#include <sys/param.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <fcntl.h>
#include <xbps_api.h>
#include "fetch.h"
struct xferstat {
struct timeval start;
struct timeval last;
off_t size;
off_t offset;
off_t rcvd;
const char *name;
};
/*
* Compute and display ETA
*/
static const char *
stat_eta(struct xferstat *xsp)
{
static char str[16];
long elapsed, eta;
off_t received, expected;
elapsed = xsp->last.tv_sec - xsp->start.tv_sec;
received = xsp->rcvd - xsp->offset;
expected = xsp->size - xsp->rcvd;
eta = (long)(elapsed * expected / received);
if (eta > 3600)
snprintf(str, sizeof str, "%02ldh%02ldm",
eta / 3600, (eta % 3600) / 60);
else
snprintf(str, sizeof str, "%02ldm%02lds",
eta / 60, eta % 60);
return str;
}
/*
* Compute and display transfer rate
*/
static const char *
stat_bps(struct xferstat *xsp)
{
static char str[16];
char size[32];
double delta, bps;
delta = (xsp->last.tv_sec + (xsp->last.tv_usec / 1.e6))
- (xsp->start.tv_sec + (xsp->start.tv_usec / 1.e6));
if (delta == 0.0) {
snprintf(str, sizeof str, "stalled");
} else {
bps = ((double)(xsp->rcvd - xsp->offset) / delta);
(void)xbps_humanize_number(size, 6, (int64_t)bps, "",
HN_AUTOSCALE, HN_DECIMAL);
snprintf(str, sizeof str, "%sB/s", size);
}
return str;
}
/*
* Update the stats display
*/
static void
stat_display(struct xferstat *xsp)
{
struct timeval now;
char totsize[32], recvsize[32];
gettimeofday(&now, NULL);
if (now.tv_sec <= xsp->last.tv_sec)
return;
xsp->last = now;
printf("Downloading %s ... ", xsp->name);
(void)xbps_humanize_number(totsize, 8, (int64_t)xsp->size, "",
HN_AUTOSCALE, HN_DECIMAL);
(void)xbps_humanize_number(recvsize, 8, (int64_t)xsp->rcvd, "",
HN_AUTOSCALE, HN_DECIMAL);
printf("%sB [%d%% of %sB]", recvsize,
(int)((double)(100.0 * (double)xsp->rcvd) / (double)xsp->size), totsize);
printf(" %s", stat_bps(xsp));
if (xsp->size > 0 && xsp->rcvd > 0 &&
xsp->last.tv_sec >= xsp->start.tv_sec + 10)
printf(" ETA: %s", stat_eta(xsp));
printf("\n\033[1A\033[K");
}
/*
* Initialize the transfer statistics
*/
static void
stat_start(struct xferstat *xsp, const char *name, off_t *size, off_t *offset)
{
gettimeofday(&xsp->start, NULL);
xsp->last.tv_sec = xsp->last.tv_usec = 0;
xsp->name = name;
xsp->size = *size;
xsp->offset = *offset;
xsp->rcvd = *offset;
}
/*
* Update the transfer statistics
*/
static void
stat_update(struct xferstat *xsp, off_t rcvd)
{
xsp->rcvd = rcvd + xsp->offset;
stat_display(xsp);
}
/*
* Finalize the transfer statistics
*/
static void
stat_end(struct xferstat *xsp)
{
char size[32];
(void)xbps_humanize_number(size, 8, (int64_t)xsp->size, "",
HN_AUTOSCALE, HN_DECIMAL);
printf("Downloaded %s successfully (%sB at %s)\n",
xsp->name, size, stat_bps(xsp));
}
int SYMEXPORT
xbps_fetch_file(const char *uri, const char *outputdir)
{
struct stat st;
struct xferstat xs;
struct url *url = NULL;
struct url_stat url_st;
struct fetchIO *fio = NULL;
struct timeval tv[2];
ssize_t bytes_read, bytes_written;
off_t bytes_dld = -1;
char buf[32768], *filename, *destfile = NULL;
int fd = -1, rv = 0;
bool restart = false;
bytes_read = bytes_written = -1;
/*
* Get the filename specified in URI argument.
*/
filename = strrchr(uri, '/');
if (filename == NULL)
return EINVAL;
filename++;
/*
* Compute destination file path.
*/
destfile = xbps_xasprintf("%s/%s", outputdir, filename);
if (destfile == NULL) {
rv = errno;
goto out;
}
if (stat(destfile, &st) == 0)
restart = true;
else {
if (errno != ENOENT) {
rv = errno;
goto out;
}
}
/*
* Prepare stuff for libfetch.
*/
if ((url = fetchParseURL(uri)) == NULL) {
rv = fetchLastErrCode;
goto out;
}
if ((rv = fetchStat(url, &url_st, "i")) == -1) {
rv = fetchLastErrCode;
goto out;
}
/*
* Nothing to do if both files do have same size/mtime.
*/
if (url_st.size == st.st_size && url_st.mtime == st.st_mtime)
goto out;
if (restart)
url->offset = st.st_size;
fio = fetchXGet(url, &url_st, "i");
if (fio == NULL) {
rv = fetchLastErrCode;
goto out;
}
printf("Connected to %s.\n", url->host);
/*
* If restarting, open the file for appending otherwise create it.
*/
if (restart)
fd = open(destfile, O_WRONLY|O_APPEND);
else
fd = open(destfile, O_WRONLY|O_CREAT, 0644);
if (fd == -1) {
rv = errno;
goto out;
}
/*
* Start fetching requested file.
*/
if (xbps_fetch_start_cb != NULL)
(*xbps_fetch_start_cb)(filename, &url_st.size, &url->offset);
else
stat_start(&xs, filename, &url_st.size, &url->offset);
while ((bytes_read = fetchIO_read(fio, buf, sizeof(buf))) > 0) {
bytes_written = write(fd, buf, (size_t)bytes_read);
if (bytes_written != bytes_read) {
rv = errno;
goto out;
}
bytes_dld += bytes_read;
if (xbps_fetch_update_cb != NULL)
(*xbps_fetch_update_cb)(&bytes_dld);
else
stat_update(&xs, bytes_dld);
}
if (bytes_read == -1) {
rv = EINVAL;
goto out;
}
if (xbps_fetch_end_cb != NULL)
(*xbps_fetch_end_cb)();
else
stat_end(&xs);
/*
* Update mtime to match remote file if download was successful.
*/
tv[0].tv_sec = url_st.atime ? url_st.atime : url_st.mtime;
tv[1].tv_sec = url_st.mtime;
tv[0].tv_usec = tv[1].tv_usec = 0;
rv = utimes(destfile, tv);
out:
if (fd != -1)
(void)close(fd);
if (fio)
fetchIO_close(fio);
if (url)
fetchFreeURL(url);
if (destfile)
free(destfile);
return rv;
}

25
lib/fetch/Makefile Normal file
View File

@ -0,0 +1,25 @@
TOPDIR = ../..
include $(TOPDIR)/vars.mk
CFLAGS += -Wno-unused-macros -Wno-conversion
CPPFLAGS += -DFTP_COMBINE_CWDS -DNETBSD -I$(TOPDIR)/include
OBJS= fetch.o common.o ftp.o http.o file.o
INCS= common.h
GEN = ftperr.h httperr.h
.PHONY: all
all: $(OBJS)
%.o: %.c $(INCS) $(GEN)
$(CC) $(CPPFLAGS) $(CFLAGS) -c $<
ftperr.h: ftp.errors
./errlist.sh ftp_errlist FTP ftp.errors > $@
httperr.h: http.errors
./errlist.sh http_errlist HTTP http.errors > $@
.PHONY: clean
clean:
-rm -f $(GEN) $(OBJS)

985
lib/fetch/common.c Normal file
View File

@ -0,0 +1,985 @@
/* $NetBSD: common.c,v 1.21 2009/10/15 12:36:57 joerg Exp $ */
/*-
* Copyright (c) 1998-2004 Dag-Erling Coïdan Smørav
* Copyright (c) 2008 Joerg Sonnenberger <joerg@NetBSD.org>
* 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
* in this position and unchanged.
* 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.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission
*
* 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.
*
* $FreeBSD: common.c,v 1.53 2007/12/19 00:26:36 des Exp $
*/
#if HAVE_CONFIG_H
#include "config.h"
#endif
#ifndef NETBSD
#include <nbcompat.h>
#endif
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <sys/uio.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <ctype.h>
#include <errno.h>
#if defined(HAVE_INTTYPES_H) || defined(NETBSD)
#include <inttypes.h>
#endif
#ifndef NETBSD
#include <nbcompat/netdb.h>
#else
#include <netdb.h>
#endif
#include <pwd.h>
#include <stdarg.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include "fetch.h"
#include "common.h"
#define DECONST(x,y) ((x)(uintptr_t)(y))
/*** Local data **************************************************************/
/*
* Error messages for resolver errors
*/
static struct fetcherr netdb_errlist[] = {
#ifdef EAI_NODATA
{ EAI_NODATA, FETCH_RESOLV, "Host not found" },
#endif
{ EAI_AGAIN, FETCH_TEMP, "Transient resolver failure" },
{ EAI_FAIL, FETCH_RESOLV, "Non-recoverable resolver failure" },
{ EAI_NONAME, FETCH_RESOLV, "No address record" },
{ -1, FETCH_UNKNOWN, "Unknown resolver error" }
};
/* End-of-Line */
static const char ENDL[2] = "\r\n";
/*** Error-reporting functions ***********************************************/
/*
* Map error code to string
*/
static struct fetcherr *
fetch_finderr(struct fetcherr *p, int e)
{
while (p->num != -1 && p->num != e)
p++;
return (p);
}
/*
* Set error code
*/
void
fetch_seterr(struct fetcherr *p, int e)
{
p = fetch_finderr(p, e);
fetchLastErrCode = p->cat;
snprintf(fetchLastErrString, MAXERRSTRING, "%s", p->string);
}
/*
* Set error code according to errno
*/
void
fetch_syserr(void)
{
switch (errno) {
case 0:
fetchLastErrCode = FETCH_OK;
break;
case EPERM:
case EACCES:
case EROFS:
#ifdef EAUTH
case EAUTH:
#endif
#ifdef ENEEDAUTH
case ENEEDAUTH:
#endif
fetchLastErrCode = FETCH_AUTH;
break;
case ENOENT:
case EISDIR: /* XXX */
fetchLastErrCode = FETCH_UNAVAIL;
break;
case ENOMEM:
fetchLastErrCode = FETCH_MEMORY;
break;
case EBUSY:
case EAGAIN:
fetchLastErrCode = FETCH_TEMP;
break;
case EEXIST:
fetchLastErrCode = FETCH_EXISTS;
break;
case ENOSPC:
fetchLastErrCode = FETCH_FULL;
break;
case EADDRINUSE:
case EADDRNOTAVAIL:
case ENETDOWN:
case ENETUNREACH:
case ENETRESET:
case EHOSTUNREACH:
fetchLastErrCode = FETCH_NETWORK;
break;
case ECONNABORTED:
case ECONNRESET:
fetchLastErrCode = FETCH_ABORT;
break;
case ETIMEDOUT:
fetchLastErrCode = FETCH_TIMEOUT;
break;
case ECONNREFUSED:
case EHOSTDOWN:
fetchLastErrCode = FETCH_DOWN;
break;
default:
fetchLastErrCode = FETCH_UNKNOWN;
}
snprintf(fetchLastErrString, MAXERRSTRING, "%s", strerror(errno));
}
/*
* Emit status message
*/
void
fetch_info(const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
vfprintf(stderr, fmt, ap);
va_end(ap);
fputc('\n', stderr);
}
/*** Network-related utility functions ***************************************/
/*
* Return the default port for a scheme
*/
int
fetch_default_port(const char *scheme)
{
struct servent *se;
if ((se = getservbyname(scheme, "tcp")) != NULL)
return (ntohs(se->s_port));
if (strcasecmp(scheme, SCHEME_FTP) == 0)
return (FTP_DEFAULT_PORT);
if (strcasecmp(scheme, SCHEME_HTTP) == 0)
return (HTTP_DEFAULT_PORT);
return (0);
}
/*
* Return the default proxy port for a scheme
*/
int
fetch_default_proxy_port(const char *scheme)
{
if (strcasecmp(scheme, SCHEME_FTP) == 0)
return (FTP_DEFAULT_PROXY_PORT);
if (strcasecmp(scheme, SCHEME_HTTP) == 0)
return (HTTP_DEFAULT_PROXY_PORT);
return (0);
}
/*
* Create a connection for an existing descriptor.
*/
conn_t *
fetch_reopen(int sd)
{
conn_t *conn;
/* allocate and fill connection structure */
if ((conn = calloc(1, sizeof(*conn))) == NULL)
return (NULL);
conn->next_buf = NULL;
conn->next_len = 0;
conn->sd = sd;
conn->is_active = 0;
++conn->ref;
return (conn);
}
/*
* Bump a connection's reference count.
*/
conn_t *
fetch_ref(conn_t *conn)
{
++conn->ref;
return (conn);
}
/*
* Bind a socket to a specific local address
*/
int
fetch_bind(int sd, int af, const char *addr)
{
struct addrinfo hints, *res, *res0;
memset(&hints, 0, sizeof(hints));
hints.ai_family = af;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = 0;
if (getaddrinfo(addr, NULL, &hints, &res0))
return (-1);
for (res = res0; res; res = res->ai_next) {
if (bind(sd, res->ai_addr, res->ai_addrlen) == 0)
return (0);
}
return (-1);
}
/*
* Establish a TCP connection to the specified port on the specified host.
*/
conn_t *
fetch_connect(const char *host, int port, int af, int verbose)
{
conn_t *conn;
char pbuf[10];
const char *bindaddr;
struct addrinfo hints, *res, *res0;
int sd, error;
if (verbose)
fetch_info("looking up %s", host);
/* look up host name and set up socket address structure */
snprintf(pbuf, sizeof(pbuf), "%d", port);
memset(&hints, 0, sizeof(hints));
hints.ai_family = af;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = 0;
if ((error = getaddrinfo(host, pbuf, &hints, &res0)) != 0) {
netdb_seterr(error);
return (NULL);
}
bindaddr = getenv("FETCH_BIND_ADDRESS");
if (verbose)
fetch_info("connecting to %s:%d", host, port);
/* try to connect */
for (sd = -1, res = res0; res; sd = -1, res = res->ai_next) {
if ((sd = socket(res->ai_family, res->ai_socktype,
res->ai_protocol)) == -1)
continue;
if (bindaddr != NULL && *bindaddr != '\0' &&
fetch_bind(sd, res->ai_family, bindaddr) != 0) {
fetch_info("failed to bind to '%s'", bindaddr);
close(sd);
continue;
}
if (connect(sd, res->ai_addr, res->ai_addrlen) == 0)
break;
close(sd);
}
freeaddrinfo(res0);
if (sd == -1) {
fetch_syserr();
return (NULL);
}
if ((conn = fetch_reopen(sd)) == NULL) {
fetch_syserr();
close(sd);
}
return (conn);
}
/*
* Enable SSL on a connection.
*/
int
fetch_ssl(conn_t *conn, int verbose)
{
#ifdef WITH_SSL
/* Init the SSL library and context */
if (!SSL_library_init()){
fprintf(stderr, "SSL library init failed\n");
return (-1);
}
SSL_load_error_strings();
conn->ssl_meth = SSLv23_client_method();
conn->ssl_ctx = SSL_CTX_new(conn->ssl_meth);
SSL_CTX_set_mode(conn->ssl_ctx, SSL_MODE_AUTO_RETRY);
conn->ssl = SSL_new(conn->ssl_ctx);
if (conn->ssl == NULL){
fprintf(stderr, "SSL context creation failed\n");
return (-1);
}
SSL_set_fd(conn->ssl, conn->sd);
if (SSL_connect(conn->ssl) == -1){
ERR_print_errors_fp(stderr);
return (-1);
}
if (verbose) {
X509_NAME *name;
char *str;
fprintf(stderr, "SSL connection established using %s\n",
SSL_get_cipher(conn->ssl));
conn->ssl_cert = SSL_get_peer_certificate(conn->ssl);
name = X509_get_subject_name(conn->ssl_cert);
str = X509_NAME_oneline(name, 0, 0);
printf("Certificate subject: %s\n", str);
free(str);
name = X509_get_issuer_name(conn->ssl_cert);
str = X509_NAME_oneline(name, 0, 0);
printf("Certificate issuer: %s\n", str);
free(str);
}
return (0);
#else
(void)conn;
(void)verbose;
fprintf(stderr, "SSL support disabled\n");
return (-1);
#endif
}
/*
* Read a character from a connection w/ timeout
*/
ssize_t
fetch_read(conn_t *conn, char *buf, size_t len)
{
struct timeval now, timeout, waittv;
fd_set readfds;
ssize_t rlen;
int r;
if (len == 0)
return 0;
if (conn->next_len != 0) {
if (conn->next_len < len)
len = conn->next_len;
memmove(buf, conn->next_buf, len);
conn->next_len -= len;
conn->next_buf += len;
return len;
}
if (fetchTimeout) {
FD_ZERO(&readfds);
gettimeofday(&timeout, NULL);
timeout.tv_sec += fetchTimeout;
}
for (;;) {
while (fetchTimeout && !FD_ISSET(conn->sd, &readfds)) {
FD_SET(conn->sd, &readfds);
gettimeofday(&now, NULL);
waittv.tv_sec = timeout.tv_sec - now.tv_sec;
waittv.tv_usec = timeout.tv_usec - now.tv_usec;
if (waittv.tv_usec < 0) {
waittv.tv_usec += 1000000;
waittv.tv_sec--;
}
if (waittv.tv_sec < 0) {
errno = ETIMEDOUT;
fetch_syserr();
return (-1);
}
errno = 0;
r = select(conn->sd + 1, &readfds, NULL, NULL, &waittv);
if (r == -1) {
if (errno == EINTR && fetchRestartCalls)
continue;
fetch_syserr();
return (-1);
}
}
#ifdef WITH_SSL
if (conn->ssl != NULL)
rlen = SSL_read(conn->ssl, buf, len);
else
#endif
rlen = read(conn->sd, buf, len);
if (rlen >= 0)
break;
if (errno != EINTR || !fetchRestartCalls)
return (-1);
}
return (rlen);
}
/*
* Read a line of text from a connection w/ timeout
*/
#define MIN_BUF_SIZE 1024
int
fetch_getln(conn_t *conn)
{
char *tmp, *next;
size_t tmpsize;
ssize_t len;
if (conn->buf == NULL) {
if ((conn->buf = malloc(MIN_BUF_SIZE)) == NULL) {
errno = ENOMEM;
return (-1);
}
conn->bufsize = MIN_BUF_SIZE;
}
conn->buflen = 0;
next = NULL;
do {
/*
* conn->bufsize != conn->buflen at this point,
* so the buffer can be NUL-terminated below for
* the case of len == 0.
*/
len = fetch_read(conn, conn->buf + conn->buflen,
conn->bufsize - conn->buflen);
if (len == -1)
return (-1);
if (len == 0)
break;
next = memchr(conn->buf + conn->buflen, '\n', len);
conn->buflen += len;
if (conn->buflen == conn->bufsize && next == NULL) {
tmp = conn->buf;
tmpsize = conn->bufsize * 2;
if (tmpsize < conn->bufsize) {
errno = ENOMEM;
return (-1);
}
if ((tmp = realloc(tmp, tmpsize)) == NULL) {
errno = ENOMEM;
return (-1);
}
conn->buf = tmp;
conn->bufsize = tmpsize;
}
} while (next == NULL);
if (next != NULL) {
*next = '\0';
conn->next_buf = next + 1;
conn->next_len = conn->buflen - (conn->next_buf - conn->buf);
conn->buflen = next - conn->buf;
} else {
conn->buf[conn->buflen] = '\0';
conn->next_len = 0;
}
return (0);
}
/*
* Write to a connection w/ timeout
*/
ssize_t
fetch_write(conn_t *conn, const char *buf, size_t len)
{
struct iovec iov;
iov.iov_base = DECONST(char *, buf);
iov.iov_len = len;
return fetch_writev(conn, &iov, 1);
}
/*
* Write a vector to a connection w/ timeout
* Note: can modify the iovec.
*/
ssize_t
fetch_writev(conn_t *conn, struct iovec *iov, int iovcnt)
{
struct timeval now, timeout, waittv;
fd_set writefds;
ssize_t wlen, total;
int r;
if (fetchTimeout) {
FD_ZERO(&writefds);
gettimeofday(&timeout, NULL);
timeout.tv_sec += fetchTimeout;
}
total = 0;
while (iovcnt > 0) {
while (fetchTimeout && !FD_ISSET(conn->sd, &writefds)) {
FD_SET(conn->sd, &writefds);
gettimeofday(&now, NULL);
waittv.tv_sec = timeout.tv_sec - now.tv_sec;
waittv.tv_usec = timeout.tv_usec - now.tv_usec;
if (waittv.tv_usec < 0) {
waittv.tv_usec += 1000000;
waittv.tv_sec--;
}
if (waittv.tv_sec < 0) {
errno = ETIMEDOUT;
fetch_syserr();
return (-1);
}
errno = 0;
r = select(conn->sd + 1, NULL, &writefds, NULL, &waittv);
if (r == -1) {
if (errno == EINTR && fetchRestartCalls)
continue;
return (-1);
}
}
errno = 0;
#ifdef WITH_SSL
if (conn->ssl != NULL)
wlen = SSL_write(conn->ssl,
iov->iov_base, iov->iov_len);
else
#endif
wlen = writev(conn->sd, iov, iovcnt);
if (wlen == 0) {
/* we consider a short write a failure */
errno = EPIPE;
fetch_syserr();
return (-1);
}
if (wlen < 0) {
if (errno == EINTR && fetchRestartCalls)
continue;
return (-1);
}
total += wlen;
while (iovcnt > 0 && wlen >= (ssize_t)iov->iov_len) {
wlen -= iov->iov_len;
iov++;
iovcnt--;
}
if (iovcnt > 0) {
iov->iov_len -= wlen;
iov->iov_base = DECONST(char *, iov->iov_base) + wlen;
}
}
return (total);
}
/*
* Write a line of text to a connection w/ timeout
*/
int
fetch_putln(conn_t *conn, const char *str, size_t len)
{
struct iovec iov[2];
ssize_t ret;
iov[0].iov_base = DECONST(char *, str);
iov[0].iov_len = len;
iov[1].iov_base = DECONST(char *, ENDL);
iov[1].iov_len = sizeof(ENDL);
if (len == 0)
ret = fetch_writev(conn, &iov[1], 1);
else
ret = fetch_writev(conn, iov, 2);
if (ret == -1)
return (-1);
return (0);
}
/*
* Close connection
*/
int
fetch_close(conn_t *conn)
{
int ret;
if (--conn->ref > 0)
return (0);
ret = close(conn->sd);
free(conn->buf);
free(conn);
return (ret);
}
/*** Directory-related utility functions *************************************/
int
fetch_add_entry(struct url_list *ue, struct url *base, const char *name,
int pre_quoted)
{
struct url *tmp;
char *tmp_name;
size_t base_doc_len, name_len, i;
unsigned char c;
if (strchr(name, '/') != NULL ||
strcmp(name, "..") == 0 ||
strcmp(name, ".") == 0)
return 0;
if (strcmp(base->doc, "/") == 0)
base_doc_len = 0;
else
base_doc_len = strlen(base->doc);
name_len = 1;
for (i = 0; name[i] != '\0'; ++i) {
if ((!pre_quoted && name[i] == '%') ||
!fetch_urlpath_safe(name[i]))
name_len += 3;
else
++name_len;
}
tmp_name = malloc( base_doc_len + name_len + 1);
if (tmp_name == NULL) {
errno = ENOMEM;
fetch_syserr();
return (-1);
}
if (ue->length + 1 >= ue->alloc_size) {
tmp = realloc(ue->urls, (ue->alloc_size * 2 + 1) * sizeof(*tmp));
if (tmp == NULL) {
free(tmp_name);
errno = ENOMEM;
fetch_syserr();
return (-1);
}
ue->alloc_size = ue->alloc_size * 2 + 1;
ue->urls = tmp;
}
tmp = ue->urls + ue->length;
strcpy(tmp->scheme, base->scheme);
strcpy(tmp->user, base->user);
strcpy(tmp->pwd, base->pwd);
strcpy(tmp->host, base->host);
tmp->port = base->port;
tmp->doc = tmp_name;
memcpy(tmp->doc, base->doc, base_doc_len);
tmp->doc[base_doc_len] = '/';
for (i = base_doc_len + 1; *name != '\0'; ++name) {
if ((!pre_quoted && *name == '%') ||
!fetch_urlpath_safe(*name)) {
tmp->doc[i++] = '%';
c = (unsigned char)*name / 16;
if (c < 10)
tmp->doc[i++] = '0' + c;
else
tmp->doc[i++] = 'a' - 10 + c;
c = (unsigned char)*name % 16;
if (c < 10)
tmp->doc[i++] = '0' + c;
else
tmp->doc[i++] = 'a' - 10 + c;
} else {
tmp->doc[i++] = *name;
}
}
tmp->doc[i] = '\0';
tmp->offset = 0;
tmp->length = 0;
tmp->last_modified = -1;
++ue->length;
return (0);
}
void
fetchInitURLList(struct url_list *ue)
{
ue->length = ue->alloc_size = 0;
ue->urls = NULL;
}
int
fetchAppendURLList(struct url_list *dst, const struct url_list *src)
{
size_t i, j, len;
len = dst->length + src->length;
if (len > dst->alloc_size) {
struct url *tmp;
tmp = realloc(dst->urls, len * sizeof(*tmp));
if (tmp == NULL) {
errno = ENOMEM;
fetch_syserr();
return (-1);
}
dst->alloc_size = len;
dst->urls = tmp;
}
for (i = 0, j = dst->length; i < src->length; ++i, ++j) {
dst->urls[j] = src->urls[i];
dst->urls[j].doc = strdup(src->urls[i].doc);
if (dst->urls[j].doc == NULL) {
while (i-- > 0)
free(dst->urls[j].doc);
fetch_syserr();
return -1;
}
}
dst->length = len;
return 0;
}
void
fetchFreeURLList(struct url_list *ue)
{
size_t i;
for (i = 0; i < ue->length; ++i)
free(ue->urls[i].doc);
free(ue->urls);
ue->length = ue->alloc_size = 0;
}
/*** Authentication-related utility functions ********************************/
static const char *
fetch_read_word(FILE *f)
{
static char word[1024];
if (fscanf(f, " %1023s ", word) != 1)
return (NULL);
return (word);
}
/*
* Get authentication data for a URL from .netrc
*/
int
fetch_netrc_auth(struct url *url)
{
char fn[PATH_MAX];
const char *word;
char *p;
FILE *f;
if ((p = getenv("NETRC")) != NULL) {
if (snprintf(fn, sizeof(fn), "%s", p) >= (int)sizeof(fn)) {
fetch_info("$NETRC specifies a file name "
"longer than PATH_MAX");
return (-1);
}
} else {
if ((p = getenv("HOME")) != NULL) {
struct passwd *pwd;
if ((pwd = getpwuid(getuid())) == NULL ||
(p = pwd->pw_dir) == NULL)
return (-1);
}
if (snprintf(fn, sizeof(fn), "%s/.netrc", p) >= (int)sizeof(fn))
return (-1);
}
if ((f = fopen(fn, "r")) == NULL)
return (-1);
while ((word = fetch_read_word(f)) != NULL) {
if (strcmp(word, "default") == 0)
break;
if (strcmp(word, "machine") == 0 &&
(word = fetch_read_word(f)) != NULL &&
strcasecmp(word, url->host) == 0) {
break;
}
}
if (word == NULL)
goto ferr;
while ((word = fetch_read_word(f)) != NULL) {
if (strcmp(word, "login") == 0) {
if ((word = fetch_read_word(f)) == NULL)
goto ferr;
if (snprintf(url->user, sizeof(url->user),
"%s", word) > (int)sizeof(url->user)) {
fetch_info("login name in .netrc is too long");
url->user[0] = '\0';
}
} else if (strcmp(word, "password") == 0) {
if ((word = fetch_read_word(f)) == NULL)
goto ferr;
if (snprintf(url->pwd, sizeof(url->pwd),
"%s", word) > (int)sizeof(url->pwd)) {
fetch_info("password in .netrc is too long");
url->pwd[0] = '\0';
}
} else if (strcmp(word, "account") == 0) {
if ((word = fetch_read_word(f)) == NULL)
goto ferr;
/* XXX not supported! */
} else {
break;
}
}
fclose(f);
return (0);
ferr:
fclose(f);
return (-1);
}
/*
* The no_proxy environment variable specifies a set of domains for
* which the proxy should not be consulted; the contents is a comma-,
* or space-separated list of domain names. A single asterisk will
* override all proxy variables and no transactions will be proxied
* (for compatability with lynx and curl, see the discussion at
* <http://curl.haxx.se/mail/archive_pre_oct_99/0009.html>).
*/
int
fetch_no_proxy_match(const char *host)
{
const char *no_proxy, *p, *q;
size_t h_len, d_len;
if ((no_proxy = getenv("NO_PROXY")) == NULL &&
(no_proxy = getenv("no_proxy")) == NULL)
return (0);
/* asterisk matches any hostname */
if (strcmp(no_proxy, "*") == 0)
return (1);
h_len = strlen(host);
p = no_proxy;
do {
/* position p at the beginning of a domain suffix */
while (*p == ',' || isspace((unsigned char)*p))
p++;
/* position q at the first separator character */
for (q = p; *q; ++q)
if (*q == ',' || isspace((unsigned char)*q))
break;
d_len = q - p;
if (d_len > 0 && h_len > d_len &&
strncasecmp(host + h_len - d_len,
p, d_len) == 0) {
/* domain name matches */
return (1);
}
p = q + 1;
} while (*q);
return (0);
}
struct fetchIO {
void *io_cookie;
ssize_t (*io_read)(void *, void *, size_t);
ssize_t (*io_write)(void *, const void *, size_t);
void (*io_close)(void *);
};
void
fetchIO_close(fetchIO *f)
{
if (f->io_close != NULL)
(*f->io_close)(f->io_cookie);
free(f);
}
fetchIO *
fetchIO_unopen(void *io_cookie, ssize_t (*io_read)(void *, void *, size_t),
ssize_t (*io_write)(void *, const void *, size_t),
void (*io_close)(void *))
{
fetchIO *f;
f = malloc(sizeof(*f));
if (f == NULL)
return f;
f->io_cookie = io_cookie;
f->io_read = io_read;
f->io_write = io_write;
f->io_close = io_close;
return f;
}
ssize_t
fetchIO_read(fetchIO *f, void *buf, size_t len)
{
if (f->io_read == NULL)
return EBADF;
return (*f->io_read)(f->io_cookie, buf, len);
}
ssize_t
fetchIO_write(fetchIO *f, const void *buf, size_t len)
{
if (f->io_read == NULL)
return EBADF;
return (*f->io_write)(f->io_cookie, buf, len);
}

137
lib/fetch/common.h Normal file
View File

@ -0,0 +1,137 @@
/* $NetBSD: common.h,v 1.12 2009/08/16 20:31:29 joerg Exp $ */
/*-
* Copyright (c) 1998-2004 Dag-Erling Coïdan Smørav
* 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
* in this position and unchanged.
* 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.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission
*
* 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.
*
* $FreeBSD: common.h,v 1.30 2007/12/18 11:03:07 des Exp $
*/
#ifndef _COMMON_H_INCLUDED
#define _COMMON_H_INCLUDED
#define FTP_DEFAULT_PORT 21
#define HTTP_DEFAULT_PORT 80
#define FTP_DEFAULT_PROXY_PORT 21
#define HTTP_DEFAULT_PROXY_PORT 3128
#ifdef WITH_SSL
#include <openssl/crypto.h>
#include <openssl/x509.h>
#include <openssl/pem.h>
#include <openssl/ssl.h>
#include <openssl/err.h>
#endif
#if !defined(__sun) && !defined(__hpux) && !defined(__INTERIX) && \
!defined(__digital__) && !defined(__linux) && !defined(__MINT__) && \
!defined(__sgi)
#define HAVE_SA_LEN
#endif
/* Connection */
typedef struct fetchconn conn_t;
struct fetchconn {
int sd; /* socket descriptor */
char *buf; /* buffer */
size_t bufsize; /* buffer size */
size_t buflen; /* length of buffer contents */
char *next_buf; /* pending buffer, e.g. after getln */
size_t next_len; /* size of pending buffer */
int err; /* last protocol reply code */
#ifdef WITH_SSL
SSL *ssl; /* SSL handle */
SSL_CTX *ssl_ctx; /* SSL context */
X509 *ssl_cert; /* server certificate */
# if OPENSSL_VERSION_NUMBER < 0x00909000L
SSL_METHOD *ssl_meth; /* SSL method */
# else
const SSL_METHOD *ssl_meth; /* SSL method */
# endif
#endif
int ref; /* reference count */
int is_active;
};
/* Structure used for error message lists */
struct fetcherr {
const int num;
const int cat;
const char *string;
};
/* for fetch_writev */
struct iovec;
void fetch_seterr(struct fetcherr *, int);
void fetch_syserr(void);
void fetch_info(const char *, ...);
int fetch_default_port(const char *);
int fetch_default_proxy_port(const char *);
int fetch_bind(int, int, const char *);
conn_t *fetch_connect(const char *, int, int, int);
conn_t *fetch_reopen(int);
conn_t *fetch_ref(conn_t *);
int fetch_ssl(conn_t *, int);
ssize_t fetch_read(conn_t *, char *, size_t);
int fetch_getln(conn_t *);
ssize_t fetch_write(conn_t *, const char *, size_t);
ssize_t fetch_writev(conn_t *, struct iovec *, int);
int fetch_putln(conn_t *, const char *, size_t);
int fetch_close(conn_t *);
int fetch_add_entry(struct url_list *, struct url *, const char *, int);
int fetch_netrc_auth(struct url *url);
int fetch_no_proxy_match(const char *);
int fetch_urlpath_safe(char);
#define ftp_seterr(n) fetch_seterr(ftp_errlist, n)
#define http_seterr(n) fetch_seterr(http_errlist, n)
#define netdb_seterr(n) fetch_seterr(netdb_errlist, n)
#define url_seterr(n) fetch_seterr(url_errlist, n)
fetchIO *fetchIO_unopen(void *, ssize_t (*)(void *, void *, size_t),
ssize_t (*)(void *, const void *, size_t), void (*)(void *));
/*
* I don't really like exporting http_request() and ftp_request(),
* but the HTTP and FTP code occasionally needs to cross-call
* eachother, and this saves me from adding a lot of special-case code
* to handle those cases.
*
* Note that _*_request() free purl, which is way ugly but saves us a
* whole lot of trouble.
*/
fetchIO *http_request(struct url *, const char *,
struct url_stat *, struct url *, const char *);
fetchIO *ftp_request(struct url *, const char *, const char *,
struct url_stat *, struct url *, const char *);
/*
* Check whether a particular flag is set
*/
#define CHECK_FLAG(x) (flags && strchr(flags, (x)))
#endif

11
lib/fetch/errlist.sh Executable file
View File

@ -0,0 +1,11 @@
#!/bin/sh
# $NetBSD: errlist.sh,v 1.2 2008/10/06 12:58:29 joerg Exp $
printf "static struct fetcherr $1[] = {\n"
while read code type msg; do
[ "${code}" = "#" ] && continue
printf "\t{ ${code}, FETCH_${type}, \"${msg}\" },\n"
done < $3
printf "\t{ -1, FETCH_UNKNOWN, \"Unknown $2 error\" }\n"
printf "};\n"

627
lib/fetch/fetch.c Normal file
View File

@ -0,0 +1,627 @@
/* $NetBSD: fetch.c,v 1.19 2009/08/11 20:48:06 joerg Exp $ */
/*-
* Copyright (c) 1998-2004 Dag-Erling Coïdan Smørav
* Copyright (c) 2008 Joerg Sonnenberger <joerg@NetBSD.org>
* 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
* in this position and unchanged.
* 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.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission
*
* 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.
*
* $FreeBSD: fetch.c,v 1.41 2007/12/19 00:26:36 des Exp $
*/
#if HAVE_CONFIG_H
#include "config.h"
#endif
#ifndef NETBSD
#include <nbcompat.h>
#endif
#include <ctype.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "fetch.h"
#include "common.h"
auth_t fetchAuthMethod;
int fetchLastErrCode;
char fetchLastErrString[MAXERRSTRING];
int fetchTimeout;
volatile int fetchRestartCalls = 1;
int fetchDebug;
/*** Local data **************************************************************/
/*
* Error messages for parser errors
*/
#define URL_MALFORMED 1
#define URL_BAD_SCHEME 2
#define URL_BAD_PORT 3
static struct fetcherr url_errlist[] = {
{ URL_MALFORMED, FETCH_URL, "Malformed URL" },
{ URL_BAD_SCHEME, FETCH_URL, "Invalid URL scheme" },
{ URL_BAD_PORT, FETCH_URL, "Invalid server port" },
{ -1, FETCH_UNKNOWN, "Unknown parser error" }
};
/*** Public API **************************************************************/
/*
* Select the appropriate protocol for the URL scheme, and return a
* read-only stream connected to the document referenced by the URL.
* Also fill out the struct url_stat.
*/
fetchIO *
fetchXGet(struct url *URL, struct url_stat *us, const char *flags)
{
if (us != NULL) {
us->size = -1;
us->atime = us->mtime = 0;
}
if (strcasecmp(URL->scheme, SCHEME_FILE) == 0)
return (fetchXGetFile(URL, us, flags));
else if (strcasecmp(URL->scheme, SCHEME_FTP) == 0)
return (fetchXGetFTP(URL, us, flags));
else if (strcasecmp(URL->scheme, SCHEME_HTTP) == 0)
return (fetchXGetHTTP(URL, us, flags));
else if (strcasecmp(URL->scheme, SCHEME_HTTPS) == 0)
return (fetchXGetHTTP(URL, us, flags));
url_seterr(URL_BAD_SCHEME);
return (NULL);
}
/*
* Select the appropriate protocol for the URL scheme, and return a
* read-only stream connected to the document referenced by the URL.
*/
fetchIO *
fetchGet(struct url *URL, const char *flags)
{
return (fetchXGet(URL, NULL, flags));
}
/*
* Select the appropriate protocol for the URL scheme, and return a
* write-only stream connected to the document referenced by the URL.
*/
fetchIO *
fetchPut(struct url *URL, const char *flags)
{
if (strcasecmp(URL->scheme, SCHEME_FILE) == 0)
return (fetchPutFile(URL, flags));
else if (strcasecmp(URL->scheme, SCHEME_FTP) == 0)
return (fetchPutFTP(URL, flags));
else if (strcasecmp(URL->scheme, SCHEME_HTTP) == 0)
return (fetchPutHTTP(URL, flags));
else if (strcasecmp(URL->scheme, SCHEME_HTTPS) == 0)
return (fetchPutHTTP(URL, flags));
url_seterr(URL_BAD_SCHEME);
return (NULL);
}
/*
* Select the appropriate protocol for the URL scheme, and return the
* size of the document referenced by the URL if it exists.
*/
int
fetchStat(struct url *URL, struct url_stat *us, const char *flags)
{
if (us != NULL) {
us->size = -1;
us->atime = us->mtime = 0;
}
if (strcasecmp(URL->scheme, SCHEME_FILE) == 0)
return (fetchStatFile(URL, us, flags));
else if (strcasecmp(URL->scheme, SCHEME_FTP) == 0)
return (fetchStatFTP(URL, us, flags));
else if (strcasecmp(URL->scheme, SCHEME_HTTP) == 0)
return (fetchStatHTTP(URL, us, flags));
else if (strcasecmp(URL->scheme, SCHEME_HTTPS) == 0)
return (fetchStatHTTP(URL, us, flags));
url_seterr(URL_BAD_SCHEME);
return (-1);
}
/*
* Select the appropriate protocol for the URL scheme, and return a
* list of files in the directory pointed to by the URL.
*/
int
fetchList(struct url_list *ue, struct url *URL, const char *pattern,
const char *flags)
{
if (strcasecmp(URL->scheme, SCHEME_FILE) == 0)
return (fetchListFile(ue, URL, pattern, flags));
else if (strcasecmp(URL->scheme, SCHEME_FTP) == 0)
return (fetchListFTP(ue, URL, pattern, flags));
else if (strcasecmp(URL->scheme, SCHEME_HTTP) == 0)
return (fetchListHTTP(ue, URL, pattern, flags));
else if (strcasecmp(URL->scheme, SCHEME_HTTPS) == 0)
return (fetchListHTTP(ue, URL, pattern, flags));
url_seterr(URL_BAD_SCHEME);
return -1;
}
/*
* Attempt to parse the given URL; if successful, call fetchXGet().
*/
fetchIO *
fetchXGetURL(const char *URL, struct url_stat *us, const char *flags)
{
struct url *u;
fetchIO *f;
if ((u = fetchParseURL(URL)) == NULL)
return (NULL);
f = fetchXGet(u, us, flags);
fetchFreeURL(u);
return (f);
}
/*
* Attempt to parse the given URL; if successful, call fetchGet().
*/
fetchIO *
fetchGetURL(const char *URL, const char *flags)
{
return (fetchXGetURL(URL, NULL, flags));
}
/*
* Attempt to parse the given URL; if successful, call fetchPut().
*/
fetchIO *
fetchPutURL(const char *URL, const char *flags)
{
struct url *u;
fetchIO *f;
if ((u = fetchParseURL(URL)) == NULL)
return (NULL);
f = fetchPut(u, flags);
fetchFreeURL(u);
return (f);
}
/*
* Attempt to parse the given URL; if successful, call fetchStat().
*/
int
fetchStatURL(const char *URL, struct url_stat *us, const char *flags)
{
struct url *u;
int s;
if ((u = fetchParseURL(URL)) == NULL)
return (-1);
s = fetchStat(u, us, flags);
fetchFreeURL(u);
return (s);
}
/*
* Attempt to parse the given URL; if successful, call fetchList().
*/
int
fetchListURL(struct url_list *ue, const char *URL, const char *pattern,
const char *flags)
{
struct url *u;
int rv;
if ((u = fetchParseURL(URL)) == NULL)
return -1;
rv = fetchList(ue, u, pattern, flags);
fetchFreeURL(u);
return rv;
}
/*
* Make a URL
*/
struct url *
fetchMakeURL(const char *scheme, const char *host, int port, const char *doc,
const char *user, const char *pwd)
{
struct url *u;
if (!scheme || (!host && !doc)) {
url_seterr(URL_MALFORMED);
return (NULL);
}
if (port < 0 || port > 65535) {
url_seterr(URL_BAD_PORT);
return (NULL);
}
/* allocate struct url */
if ((u = calloc(1, sizeof(*u))) == NULL) {
fetch_syserr();
return (NULL);
}
if ((u->doc = strdup(doc ? doc : "/")) == NULL) {
fetch_syserr();
free(u);
return (NULL);
}
#define seturl(x) snprintf(u->x, sizeof(u->x), "%s", x)
seturl(scheme);
seturl(host);
seturl(user);
seturl(pwd);
#undef seturl
u->port = port;
return (u);
}
int
fetch_urlpath_safe(char x)
{
if ((x >= '0' && x <= '9') || (x >= 'A' && x <= 'Z') ||
(x >= 'a' && x <= 'z'))
return 1;
switch (x) {
case '$':
case '-':
case '_':
case '.':
case '+':
case '!':
case '*':
case '\'':
case '(':
case ')':
case ',':
/* The following are allowed in segment and path components: */
case '?':
case ':':
case '@':
case '&':
case '=':
case '/':
case ';':
/* If something is already quoted... */
case '%':
return 1;
default:
return 0;
}
}
/*
* Copy an existing URL.
*/
struct url *
fetchCopyURL(const struct url *src)
{
struct url *dst;
char *doc;
/* allocate struct url */
if ((dst = malloc(sizeof(*dst))) == NULL) {
fetch_syserr();
return (NULL);
}
if ((doc = strdup(src->doc)) == NULL) {
fetch_syserr();
free(dst);
return (NULL);
}
*dst = *src;
dst->doc = doc;
return dst;
}
/*
* Split an URL into components. URL syntax is:
* [method:/][/[user[:pwd]@]host[:port]/][document]
* This almost, but not quite, RFC1738 URL syntax.
*/
struct url *
fetchParseURL(const char *URL)
{
const char *p, *q;
struct url *u;
size_t i, count;
int pre_quoted;
/* allocate struct url */
if ((u = calloc(1, sizeof(*u))) == NULL) {
fetch_syserr();
return (NULL);
}
if (*URL == '/') {
pre_quoted = 0;
strcpy(u->scheme, SCHEME_FILE);
p = URL;
goto quote_doc;
}
if (strncmp(URL, "file:", 5) == 0) {
pre_quoted = 1;
strcpy(u->scheme, SCHEME_FILE);
URL += 5;
if (URL[0] != '/' || URL[1] != '/' || URL[2] != '/') {
url_seterr(URL_MALFORMED);
goto ouch;
}
p = URL + 2;
goto quote_doc;
}
if (strncmp(URL, "http:", 5) == 0 ||
strncmp(URL, "https:", 6) == 0) {
pre_quoted = 1;
if (URL[4] == ':') {
strcpy(u->scheme, SCHEME_HTTP);
URL += 5;
} else {
strcpy(u->scheme, SCHEME_HTTPS);
URL += 6;
}
if (URL[0] != '/' || URL[1] != '/') {
url_seterr(URL_MALFORMED);
goto ouch;
}
URL += 2;
p = URL;
goto find_user;
}
if (strncmp(URL, "ftp:", 4) == 0) {
pre_quoted = 1;
strcpy(u->scheme, SCHEME_FTP);
URL += 4;
if (URL[0] != '/' || URL[1] != '/') {
url_seterr(URL_MALFORMED);
goto ouch;
}
URL += 2;
p = URL;
goto find_user;
}
url_seterr(URL_BAD_SCHEME);
goto ouch;
find_user:
p = strpbrk(URL, "/@");
if (p != NULL && *p == '@') {
/* username */
for (q = URL, i = 0; (*q != ':') && (*q != '@'); q++) {
if (i < URL_USERLEN)
u->user[i++] = *q;
}
/* password */
if (*q == ':') {
for (q++, i = 0; (*q != '@'); q++)
if (i < URL_PWDLEN)
u->pwd[i++] = *q;
}
p++;
} else {
p = URL;
}
/* hostname */
#ifdef INET6
if (*p == '[' && (q = strchr(p + 1, ']')) != NULL &&
(*++q == '\0' || *q == '/' || *q == ':')) {
if ((i = q - p - 2) > URL_HOSTLEN)
i = URL_HOSTLEN;
strncpy(u->host, ++p, i);
p = q;
} else
#endif
for (i = 0; *p && (*p != '/') && (*p != ':'); p++)
if (i < URL_HOSTLEN)
u->host[i++] = *p;
/* port */
if (*p == ':') {
for (q = ++p; *q && (*q != '/'); q++)
if (isdigit((unsigned char)*q))
u->port = u->port * 10 + (*q - '0');
else {
/* invalid port */
url_seterr(URL_BAD_PORT);
goto ouch;
}
p = q;
}
/* document */
if (!*p)
p = "/";
quote_doc:
count = 1;
for (i = 0; p[i] != '\0'; ++i) {
if ((!pre_quoted && p[i] == '%') ||
!fetch_urlpath_safe(p[i]))
count += 3;
else
++count;
}
if ((u->doc = malloc(count)) == NULL) {
fetch_syserr();
goto ouch;
}
for (i = 0; *p != '\0'; ++p) {
if ((!pre_quoted && *p == '%') ||
!fetch_urlpath_safe(*p)) {
u->doc[i++] = '%';
if ((unsigned char)*p < 160)
u->doc[i++] = '0' + ((unsigned char)*p) / 16;
else
u->doc[i++] = 'a' - 10 + ((unsigned char)*p) / 16;
if ((unsigned char)*p % 16 < 10)
u->doc[i++] = '0' + ((unsigned char)*p) % 16;
else
u->doc[i++] = 'a' - 10 + ((unsigned char)*p) % 16;
} else
u->doc[i++] = *p;
}
u->doc[i] = '\0';
return (u);
ouch:
free(u);
return (NULL);
}
/*
* Free a URL
*/
void
fetchFreeURL(struct url *u)
{
free(u->doc);
free(u);
}
static char
xdigit2digit(char digit)
{
digit = tolower((unsigned char)digit);
if (digit >= 'a' && digit <= 'f')
digit = digit - 'a' + 10;
else
digit = digit - '0';
return digit;
}
/*
* Unquote whole URL.
* Skips optional parts like query or fragment identifier.
*/
char *
fetchUnquotePath(struct url *url)
{
char *unquoted;
const char *iter;
size_t i;
if ((unquoted = malloc(strlen(url->doc) + 1)) == NULL)
return NULL;
for (i = 0, iter = url->doc; *iter != '\0'; ++iter) {
if (*iter == '#' || *iter == '?')
break;
if (iter[0] != '%' ||
!isxdigit((unsigned char)iter[1]) ||
!isxdigit((unsigned char)iter[2])) {
unquoted[i++] = *iter;
continue;
}
unquoted[i++] = xdigit2digit(iter[1]) * 16 +
xdigit2digit(iter[2]);
iter += 2;
}
unquoted[i] = '\0';
return unquoted;
}
/*
* Extract the file name component of a URL.
*/
char *
fetchUnquoteFilename(struct url *url)
{
char *unquoted, *filename;
const char *last_slash;
if ((unquoted = fetchUnquotePath(url)) == NULL)
return NULL;
if ((last_slash = strrchr(unquoted, '/')) == NULL)
return unquoted;
filename = strdup(last_slash + 1);
free(unquoted);
return filename;
}
char *
fetchStringifyURL(const struct url *url)
{
size_t total;
char *doc;
/* scheme :// user : pwd @ host :port doc */
total = strlen(url->scheme) + 3 + strlen(url->user) + 1 +
strlen(url->pwd) + 1 + strlen(url->host) + 6 + strlen(url->doc) + 1;
if ((doc = malloc(total)) == NULL)
return NULL;
if (url->port != 0)
snprintf(doc, total, "%s%s%s%s%s%s%s:%d%s",
url->scheme,
url->scheme[0] != '\0' ? "://" : "",
url->user,
url->pwd[0] != '\0' ? ":" : "",
url->pwd,
url->user[0] != '\0' || url->pwd[0] != '\0' ? "@" : "",
url->host,
(int)url->port,
url->doc);
else {
snprintf(doc, total, "%s%s%s%s%s%s%s%s",
url->scheme,
url->scheme[0] != '\0' ? "://" : "",
url->user,
url->pwd[0] != '\0' ? ":" : "",
url->pwd,
url->user[0] != '\0' || url->pwd[0] != '\0' ? "@" : "",
url->host,
url->doc);
}
return doc;
}

269
lib/fetch/file.c Normal file
View File

@ -0,0 +1,269 @@
/* $NetBSD: file.c,v 1.15 2009/10/15 12:36:57 joerg Exp $ */
/*-
* Copyright (c) 1998-2004 Dag-Erling Coïdan Smørav
* Copyright (c) 2008, 2009 Joerg Sonnenberger <joerg@NetBSD.org>
* 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
* in this position and unchanged.
* 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.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission
*
* 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.
*
* $FreeBSD: file.c,v 1.18 2007/12/14 10:26:58 des Exp $
*/
#if HAVE_CONFIG_H
#include "config.h"
#endif
#ifndef NETBSD
#include <nbcompat.h>
#endif
#include <sys/stat.h>
#include <dirent.h>
#include <fcntl.h>
#include <fnmatch.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "fetch.h"
#include "common.h"
static int fetch_stat_file(int, struct url_stat *);
static ssize_t
fetchFile_read(void *cookie, void *buf, size_t len)
{
return read(*(int *)cookie, buf, len);
}
static ssize_t
fetchFile_write(void *cookie, const void *buf, size_t len)
{
return write(*(int *)cookie, buf, len);
}
static void
fetchFile_close(void *cookie)
{
int fd = *(int *)cookie;
free(cookie);
close(fd);
}
fetchIO *
fetchXGetFile(struct url *u, struct url_stat *us, const char *flags)
{
char *path;
fetchIO *f;
struct url_stat local_us;
int if_modified_since, fd, *cookie;
if_modified_since = CHECK_FLAG('i');
if (if_modified_since && us == NULL)
us = &local_us;
if ((path = fetchUnquotePath(u)) == NULL) {
fetch_syserr();
return NULL;
}
fd = open(path, O_RDONLY);
free(path);
if (fd == -1) {
fetch_syserr();
return NULL;
}
if (us && fetch_stat_file(fd, us) == -1) {
close(fd);
fetch_syserr();
return NULL;
}
if (if_modified_since && u->last_modified > 0 &&
u->last_modified >= us->mtime) {
close(fd);
fetchLastErrCode = FETCH_UNCHANGED;
snprintf(fetchLastErrString, MAXERRSTRING, "Unchanged");
return NULL;
}
if (u->offset && lseek(fd, u->offset, SEEK_SET) == -1) {
close(fd);
fetch_syserr();
return NULL;
}
cookie = malloc(sizeof(int));
if (cookie == NULL) {
close(fd);
fetch_syserr();
return NULL;
}
*cookie = fd;
f = fetchIO_unopen(cookie, fetchFile_read, fetchFile_write, fetchFile_close);
if (f == NULL) {
close(fd);
free(cookie);
}
return f;
}
fetchIO *
fetchGetFile(struct url *u, const char *flags)
{
return (fetchXGetFile(u, NULL, flags));
}
fetchIO *
fetchPutFile(struct url *u, const char *flags)
{
char *path;
fetchIO *f;
int fd, *cookie;
if ((path = fetchUnquotePath(u)) == NULL) {
fetch_syserr();
return NULL;
}
if (CHECK_FLAG('a'))
fd = open(path, O_WRONLY | O_APPEND);
else
fd = open(path, O_WRONLY);
free(path);
if (fd == -1) {
fetch_syserr();
return NULL;
}
if (u->offset && lseek(fd, u->offset, SEEK_SET) == -1) {
close(fd);
fetch_syserr();
return NULL;
}
cookie = malloc(sizeof(int));
if (cookie == NULL) {
close(fd);
fetch_syserr();
return NULL;
}
*cookie = fd;
f = fetchIO_unopen(cookie, fetchFile_read, fetchFile_write, fetchFile_close);
if (f == NULL) {
close(fd);
free(cookie);
}
return f;
}
static int
fetch_stat_file(int fd, struct url_stat *us)
{
struct stat sb;
us->size = -1;
us->atime = us->mtime = 0;
if (fstat(fd, &sb) == -1) {
fetch_syserr();
return (-1);
}
us->size = sb.st_size;
us->atime = sb.st_atime;
us->mtime = sb.st_mtime;
return (0);
}
int
fetchStatFile(struct url *u, struct url_stat *us, const char *flags)
{
char *path;
int fd, rv;
(void)flags;
if ((path = fetchUnquotePath(u)) == NULL) {
fetch_syserr();
return -1;
}
fd = open(path, O_RDONLY);
free(path);
if (fd == -1) {
fetch_syserr();
return -1;
}
rv = fetch_stat_file(fd, us);
close(fd);
return rv;
}
int
fetchListFile(struct url_list *ue, struct url *u, const char *pattern, const char *flags)
{
char *path;
struct dirent *de;
DIR *dir;
int ret;
(void)flags;
if ((path = fetchUnquotePath(u)) == NULL) {
fetch_syserr();
return -1;
}
dir = opendir(path);
free(path);
if (dir == NULL) {
fetch_syserr();
return -1;
}
ret = 0;
while ((de = readdir(dir)) != NULL) {
if (pattern && fnmatch(pattern, de->d_name, 0) != 0)
continue;
ret = fetch_add_entry(ue, u, de->d_name, 0);
if (ret)
break;
}
closedir(dir);
return ret;
}

1299
lib/fetch/ftp.c Normal file

File diff suppressed because it is too large Load Diff

48
lib/fetch/ftp.errors Normal file
View File

@ -0,0 +1,48 @@
# $NetBSD: ftp.errors,v 1.2 2008/10/06 12:58:29 joerg Exp $
# $FreeBSD: ftp.errors,v 1.6 2002/10/30 06:06:16 des Exp $
#
# This list is taken from RFC 959.
# It probably needs a going over.
#
110 OK Restart marker reply
120 TEMP Service ready in a few minutes
125 OK Data connection already open; transfer starting
150 OK File status okay; about to open data connection
200 OK Command okay
202 PROTO Command not implemented, superfluous at this site
211 INFO System status, or system help reply
212 INFO Directory status
213 INFO File status
214 INFO Help message
215 INFO Set system type
220 OK Service ready for new user
221 OK Service closing control connection
225 OK Data connection open; no transfer in progress
226 OK Requested file action successful
227 OK Entering Passive Mode
229 OK Entering Extended Passive Mode
230 OK User logged in, proceed
250 OK Requested file action okay, completed
257 OK File/directory created
331 AUTH User name okay, need password
332 AUTH Need account for login
350 OK Requested file action pending further information
421 DOWN Service not available, closing control connection
425 NETWORK Can't open data connection
426 ABORT Connection closed; transfer aborted
450 UNAVAIL File unavailable (e.g., file busy)
451 SERVER Requested action aborted: local error in processing
452 FULL Insufficient storage space in system
500 PROTO Syntax error, command unrecognized
501 PROTO Syntax error in parameters or arguments
502 PROTO Command not implemented
503 PROTO Bad sequence of commands
504 PROTO Command not implemented for that parameter
530 AUTH Not logged in
532 AUTH Need account for storing files
535 PROTO Bug in MediaHawk Video Kernel FTP server
550 UNAVAIL File unavailable (e.g., file not found, no access)
551 PROTO Requested action aborted. Page type unknown
552 FULL Exceeded storage allocation
553 EXISTS File name not allowed
999 PROTO Protocol error

1460
lib/fetch/http.c Normal file

File diff suppressed because it is too large Load Diff

46
lib/fetch/http.errors Normal file
View File

@ -0,0 +1,46 @@
# $FreeBSD: http.errors,v 1.5 2001/05/23 18:52:02 des Exp $
# $NetBSD: http.errors,v 1.3 2009/02/05 16:59:45 joerg Exp $
#
# This list is taken from RFC 2068.
#
100 OK Continue
101 OK Switching Protocols
200 OK OK
201 OK Created
202 OK Accepted
203 INFO Non-Authoritative Information
204 OK No Content
205 OK Reset Content
206 OK Partial Content
300 MOVED Multiple Choices
301 MOVED Moved Permanently
302 MOVED Moved Temporarily
303 MOVED See Other
304 UNCHANGED Not Modified
305 INFO Use Proxy
307 MOVED Temporary Redirect
400 PROTO Bad Request
401 AUTH Unauthorized
402 AUTH Payment Required
403 AUTH Forbidden
404 UNAVAIL Not Found
405 PROTO Method Not Allowed
406 PROTO Not Acceptable
407 AUTH Proxy Authentication Required
408 TIMEOUT Request Time-out
409 EXISTS Conflict
410 UNAVAIL Gone
411 PROTO Length Required
412 SERVER Precondition Failed
413 PROTO Request Entity Too Large
414 PROTO Request-URI Too Large
415 PROTO Unsupported Media Type
416 UNAVAIL Requested Range Not Satisfiable
417 SERVER Expectation Failed
500 SERVER Internal Server Error
501 PROTO Not Implemented
502 SERVER Bad Gateway
503 TEMP Service Unavailable
504 TIMEOUT Gateway Time-out
505 PROTO HTTP Version not supported
999 PROTO Protocol error

View File

@ -128,7 +128,7 @@ vfcexec(const char *path, int skipempty, const char *arg, va_list ap)
return retval;
}
int
int SYMEXPORT
xbps_file_exec(const char *arg, ...)
{
va_list ap;
@ -141,7 +141,7 @@ xbps_file_exec(const char *arg, ...)
return result;
}
int
int SYMEXPORT
xbps_file_exec_skipempty(const char *arg, ...)
{
va_list ap;
@ -154,7 +154,7 @@ xbps_file_exec_skipempty(const char *arg, ...)
return result;
}
int
int SYMEXPORT
xbps_file_chdir_exec(const char *path, const char *arg, ...)
{
va_list ap;

View File

@ -84,7 +84,7 @@ fail:
return rv;
}
prop_dictionary_t
prop_dictionary_t SYMEXPORT
xbps_get_pkg_props(void)
{
if (pkg_props_initialized == false)
@ -93,7 +93,7 @@ xbps_get_pkg_props(void)
return pkg_props;
}
int
int SYMEXPORT
xbps_prepare_repolist_data(void)
{
prop_dictionary_t dict = NULL;
@ -160,6 +160,7 @@ xbps_prepare_repolist_data(void)
goto out2;
}
rdata->rd_uri = prop_string_cstring(obj);
rdata->rd_repod = prop_dictionary_internalize_from_file(plist);
if (rdata->rd_repod == NULL) {
free(plist);
@ -184,7 +185,7 @@ out:
}
void
void SYMEXPORT
xbps_release_repolist_data(void)
{
struct repository_data *rdata;
@ -192,11 +193,12 @@ xbps_release_repolist_data(void)
while ((rdata = SIMPLEQ_FIRST(&repodata_queue)) != NULL) {
SIMPLEQ_REMOVE(&repodata_queue, rdata, repository_data, chain);
prop_object_release(rdata->rd_repod);
free(rdata->rd_uri);
free(rdata);
}
}
int
int SYMEXPORT
xbps_find_new_packages(void)
{
prop_dictionary_t dict;
@ -249,13 +251,13 @@ xbps_find_new_packages(void)
return rv;
}
int
int SYMEXPORT
xbps_find_new_pkg(const char *pkgname, prop_dictionary_t instpkg)
{
prop_dictionary_t pkgrd = NULL;
prop_array_t unsorted;
struct repository_data *rdata;
const char *repoloc, *repover, *instver;
const char *repover, *instver;
int rv = 0;
bool newpkg_found = false;
@ -304,12 +306,7 @@ xbps_find_new_pkg(const char *pkgname, prop_dictionary_t instpkg)
/*
* Set repository in pkg dictionary.
*/
if (!prop_dictionary_get_cstring_nocopy(rdata->rd_repod,
"location-local", &repoloc)) {
rv = EINVAL;
goto out;
}
prop_dictionary_set_cstring(pkgrd, "repository", repoloc);
prop_dictionary_set_cstring(pkgrd, "repository", rdata->rd_uri);
/*
* Construct the dependency chain for this package.
@ -370,13 +367,12 @@ set_pkg_state(prop_dictionary_t pkgd, const char *pkgname)
return rv;
}
int
int SYMEXPORT
xbps_prepare_pkg(const char *pkgname)
{
prop_dictionary_t pkgrd = NULL;
prop_array_t pkgs_array;
struct repository_data *rdata;
const char *repoloc;
int rv = 0;
assert(pkgname != NULL);
@ -408,12 +404,7 @@ xbps_prepare_pkg(const char *pkgname)
/*
* Set repository in pkg dictionary.
*/
if (!prop_dictionary_get_cstring_nocopy(rdata->rd_repod,
"location-local", &repoloc)) {
rv = EINVAL;
goto out;
}
prop_dictionary_set_cstring(pkgrd, "repository", repoloc);
prop_dictionary_set_cstring(pkgrd, "repository", rdata->rd_uri);
prop_dictionary_set_cstring(pkg_props, "origin", pkgname);
/*

View File

@ -39,7 +39,7 @@
#include <xbps_api.h>
int
int SYMEXPORT
xbps_humanize_number(char *buf, size_t len, int64_t bytes,
const char *suffix, int scale, int flags)
{

View File

@ -120,7 +120,7 @@ cleanup(void)
}
}
prop_array_t
prop_array_t SYMEXPORT
xbps_find_orphan_packages(void)
{
prop_array_t array;

View File

@ -34,7 +34,7 @@
static prop_dictionary_t regpkgdb_dict;
static bool regpkgdb_initialized;
bool
bool SYMEXPORT
xbps_add_obj_to_dict(prop_dictionary_t dict, prop_object_t obj,
const char *key)
{
@ -51,7 +51,7 @@ xbps_add_obj_to_dict(prop_dictionary_t dict, prop_object_t obj,
return true;
}
bool
bool SYMEXPORT
xbps_add_obj_to_array(prop_array_t array, prop_object_t obj)
{
assert(array != NULL);
@ -66,7 +66,7 @@ xbps_add_obj_to_array(prop_array_t array, prop_object_t obj)
return true;
}
int
int SYMEXPORT
xbps_callback_array_iter_in_repolist(int (*fn)(prop_object_t, void *, bool *),
void *arg)
{
@ -103,7 +103,7 @@ xbps_callback_array_iter_in_repolist(int (*fn)(prop_object_t, void *, bool *),
return rv;
}
int
int SYMEXPORT
xbps_callback_array_iter_in_dict(prop_dictionary_t dict, const char *key,
int (*fn)(prop_object_t, void *, bool *),
void *arg)
@ -131,7 +131,7 @@ xbps_callback_array_iter_in_dict(prop_dictionary_t dict, const char *key,
return rv;
}
int
int SYMEXPORT
xbps_callback_array_iter_reverse_in_dict(prop_dictionary_t dict,
const char *key, int (*fn)(prop_object_t, void *, bool *), void *arg)
{
@ -162,7 +162,7 @@ xbps_callback_array_iter_reverse_in_dict(prop_dictionary_t dict,
return rv;
}
prop_dictionary_t
prop_dictionary_t SYMEXPORT
xbps_find_pkg_from_plist(const char *plist, const char *pkgname)
{
prop_dictionary_t dict, obj, res;
@ -189,7 +189,7 @@ xbps_find_pkg_from_plist(const char *plist, const char *pkgname)
return res;
}
prop_dictionary_t
prop_dictionary_t SYMEXPORT
xbps_find_pkg_installed_from_plist(const char *pkgname)
{
prop_dictionary_t d, pkgd;
@ -215,7 +215,7 @@ xbps_find_pkg_installed_from_plist(const char *pkgname)
}
}
prop_dictionary_t
prop_dictionary_t SYMEXPORT
xbps_find_pkg_in_dict(prop_dictionary_t dict, const char *key,
const char *pkgname)
{
@ -241,7 +241,7 @@ xbps_find_pkg_in_dict(prop_dictionary_t dict, const char *key,
return obj;
}
prop_dictionary_t
prop_dictionary_t SYMEXPORT
xbps_prepare_regpkgdb_dict(void)
{
const char *rootdir;
@ -266,7 +266,7 @@ xbps_prepare_regpkgdb_dict(void)
return regpkgdb_dict;
}
void
void SYMEXPORT
xbps_release_regpkgdb_dict(void)
{
if (regpkgdb_initialized == false)
@ -277,7 +277,7 @@ xbps_release_regpkgdb_dict(void)
regpkgdb_initialized = false;
}
bool
bool SYMEXPORT
xbps_find_string_in_array(prop_array_t array, const char *val)
{
prop_object_iterator_t iter;
@ -303,7 +303,7 @@ xbps_find_string_in_array(prop_array_t array, const char *val)
return false;
}
prop_object_iterator_t
prop_object_iterator_t SYMEXPORT
xbps_get_array_iter_from_dict(prop_dictionary_t dict, const char *key)
{
prop_array_t array;
@ -318,7 +318,7 @@ xbps_get_array_iter_from_dict(prop_dictionary_t dict, const char *key)
return prop_array_iterator(array);
}
int
int SYMEXPORT
xbps_remove_string_from_array(prop_array_t array, const char *str)
{
prop_object_t obj;
@ -351,7 +351,7 @@ xbps_remove_string_from_array(prop_array_t array, const char *str)
return 0;
}
int
int SYMEXPORT
xbps_remove_pkg_from_dict(prop_dictionary_t dict, const char *key,
const char *pkgname)
{
@ -393,7 +393,7 @@ xbps_remove_pkg_from_dict(prop_dictionary_t dict, const char *key,
return 0;
}
int
int SYMEXPORT
xbps_remove_pkg_dict_from_file(const char *pkg, const char *plist)
{
prop_dictionary_t pdict;
@ -422,7 +422,7 @@ xbps_remove_pkg_dict_from_file(const char *pkg, const char *plist)
return 0;
}
prop_dictionary_t
prop_dictionary_t SYMEXPORT
xbps_read_dict_from_archive_entry(struct archive *ar,
struct archive_entry *entry)
{

View File

@ -33,7 +33,7 @@
static int remove_pkg_metadata(const char *);
int
int SYMEXPORT
xbps_purge_all_pkgs(void)
{
@ -71,7 +71,7 @@ xbps_purge_all_pkgs(void)
* This removes configuration files if they weren't modified,
* removes metadata files and fully unregisters the package.
*/
int
int SYMEXPORT
xbps_purge_pkg(const char *pkgname, bool check_state)
{
prop_dictionary_t dict;

View File

@ -30,7 +30,7 @@
#include <xbps_api.h>
int
int SYMEXPORT
xbps_register_pkg(prop_dictionary_t pkgrd, bool automatic)
{
prop_dictionary_t dict, pkgd;
@ -92,7 +92,7 @@ out:
return rv;
}
int
int SYMEXPORT
xbps_unregister_pkg(const char *pkgname)
{
const char *rootdir;

View File

@ -183,7 +183,7 @@ dirs:
return 0;
}
int
int SYMEXPORT
xbps_remove_pkg(const char *pkgname, const char *version, bool update)
{
prop_dictionary_t dict;

View File

@ -23,14 +23,18 @@
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <sys/utsname.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <xbps_api.h>
#include "fetch.h"
int
static int mkpath(char *, mode_t);
int SYMEXPORT
xbps_register_repository(const char *uri)
{
prop_dictionary_t dict;
@ -54,8 +58,8 @@ xbps_register_repository(const char *uri)
/* Looks like not, create it. */
dict = prop_dictionary_create();
if (dict == NULL) {
rv = errno;
goto out2;
free(plist);
return errno;
}
/* Create the array and add the repository URI on it. */
array = prop_array_create();
@ -98,16 +102,17 @@ xbps_register_repository(const char *uri)
if (obj)
prop_object_release(obj);
rv = errno;
goto out;
}
out:
prop_object_release(dict);
out2:
free(plist);
return rv;
}
int
int SYMEXPORT
xbps_unregister_repository(const char *uri)
{
prop_dictionary_t dict;
@ -149,3 +154,204 @@ out:
return rv;
}
char SYMEXPORT *
xbps_get_remote_repo_string(const char *uri)
{
struct url *url;
size_t i;
char *p;
if ((url = fetchParseURL(uri)) == NULL)
return NULL;
/*
* Replace dots and slashes with underscores, so that
* provided URL:
*
* www.foo.org/blah/xbps/binpkg-repo
*
* becomes:
*
* www_foo_org_blah_xbps_binpkg_repo
*
*/
p = xbps_xasprintf("%s%s", url->host, url->doc);
fetchFreeURL(url);
if (p == NULL)
return NULL;
for (i = 0; i < strlen(p); i++) {
if (p[i] == '.' || p[i] == '/')
p[i] = '_';
}
return p;
}
int SYMEXPORT
xbps_sync_repository_pkg_index(const char *uri)
{
struct url *url;
struct utsname un;
const char *rootdir = xbps_get_rootdir();
char *rpidx, *dir, *lrepodir, *uri_fixedp = NULL;
int rv = 0;
if (uname(&un) == -1)
return errno;
if ((url = fetchParseURL(uri)) == NULL)
return errno;
uri_fixedp = xbps_get_remote_repo_string(uri);
if (uri_fixedp == NULL) {
fetchFreeURL(url);
return errno;
}
/*
* Create local arch repodir:
*
* <rootdir>/var/db/xbps/repo/<url_path_blah>/<arch>
*/
lrepodir = xbps_xasprintf("%s/%s/repo/%s/%s",
rootdir, XBPS_META_PATH, uri_fixedp, un.machine);
if (lrepodir == NULL) {
fetchFreeURL(url);
free(uri_fixedp);
return errno;
}
if (mkpath(lrepodir, 0755) == -1) {
free(lrepodir);
free(uri_fixedp);
fetchFreeURL(url);
return errno;
}
/*
* Create local noarch repodir:
*
* <rootdir>/var/db/xbps/repo/<url_path_blah>/noarch
*/
dir = xbps_xasprintf("%s/%s/repo/%s/noarch",
rootdir, XBPS_META_PATH, uri_fixedp);
free(uri_fixedp);
fetchFreeURL(url);
if (dir == NULL) {
free(lrepodir);
return errno;
}
if (mkpath(dir, 0755) == -1) {
free(dir);
free(lrepodir);
return errno;
}
free(dir);
/*
* Download pkg-index.plist file from repository.
*/
rpidx = xbps_xasprintf("%s/%s/%s", uri, un.machine, XBPS_PKGINDEX);
if (rpidx == NULL) {
free(lrepodir);
return errno;
}
rv = xbps_fetch_file(rpidx, lrepodir);
free(rpidx);
free(lrepodir);
return rv;
}
/*
* The following is a modified function from NetBSD's src/bin/mkdir/mkdir.c
*/
/*
* Copyright (c) 1983, 1992, 1993
* The Regents of the University of California. 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.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``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 REGENTS OR CONTRIBUTORS 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.
*/
/*
* mkpath -- create directories.
* path - path
* mode - file mode of terminal directory
*/
static int
mkpath(char *path, mode_t mode)
{
struct stat sb;
char *slash = path;
int done = 0, rv;
mode_t dir_mode;
/*
* The default file mode is a=rwx (0777) with selected permissions
* removed in accordance with the file mode creation mask. For
* intermediate path name components, the mode is the default modified
* by u+wx so that the subdirectories can always be created.
*/
if (mode == 0)
mode = (S_IRWXU | S_IRWXG | S_IRWXO) & ~umask(0);
dir_mode = mode | S_IWUSR | S_IXUSR;
for (;;) {
slash += strspn(slash, "/");
slash += strcspn(slash, "/");
done = (*slash == '\0');
*slash = '\0';
rv = mkdir(path, done ? mode : dir_mode);
if (rv < 0) {
/*
* Can't create; path exists or no perms.
* stat() path to determine what's there now.
*/
int sverrno;
sverrno = errno;
if (stat(path, &sb) < 0) {
/* Not there; use mkdir()s error */
errno = sverrno;
return -1;
}
if (!S_ISDIR(sb.st_mode)) {
/* Is there, but isn't a directory */
errno = ENOTDIR;
return -1;
}
}
if (done)
break;
*slash = '/';
}
return 0;
}

View File

@ -116,7 +116,7 @@ remove_pkg_from_reqby(prop_object_t obj, void *arg, bool *loop_done)
return 0;
}
int
int SYMEXPORT
xbps_requiredby_pkg_remove(const char *pkgname)
{
prop_dictionary_t dict;
@ -149,7 +149,7 @@ xbps_requiredby_pkg_remove(const char *pkgname)
return rv;
}
int
int SYMEXPORT
xbps_requiredby_pkg_add(prop_array_t regar, prop_dictionary_t pkg)
{
prop_array_t rdeps;

View File

@ -54,7 +54,7 @@ find_sorteddep_by_name(const char *pkgname)
return sdep;
}
int
int SYMEXPORT
xbps_sort_pkg_deps(prop_dictionary_t chaindeps)
{
prop_array_t sorted, unsorted, rundeps;

View File

@ -92,7 +92,7 @@ get_state(prop_dictionary_t dict)
return state;
}
int
int SYMEXPORT
xbps_get_pkg_state_installed(const char *pkgname, pkg_state_t *state)
{
prop_dictionary_t dict, pkgd;
@ -128,7 +128,7 @@ xbps_get_pkg_state_installed(const char *pkgname, pkg_state_t *state)
return 0;
}
int
int SYMEXPORT
xbps_get_pkg_state_dictionary(prop_dictionary_t dict, pkg_state_t *state)
{
assert(dict != NULL);
@ -139,7 +139,7 @@ xbps_get_pkg_state_dictionary(prop_dictionary_t dict, pkg_state_t *state)
return 0;
}
int
int SYMEXPORT
xbps_set_pkg_state_dictionary(prop_dictionary_t dict, pkg_state_t state)
{
assert(dict != NULL);
@ -147,7 +147,7 @@ xbps_set_pkg_state_dictionary(prop_dictionary_t dict, pkg_state_t state)
return set_new_state(dict, state);
}
int
int SYMEXPORT
xbps_set_pkg_state_installed(const char *pkgname, pkg_state_t state)
{
prop_dictionary_t dict, pkgd;

View File

@ -35,7 +35,7 @@
static int unpack_archive_fini(struct archive *, prop_dictionary_t, bool);
static void set_extract_flags(int *);
int
int SYMEXPORT
xbps_unpack_binary_pkg(prop_dictionary_t pkg, bool essential)
{
prop_string_t filename, repoloc, arch;

View File

@ -41,7 +41,7 @@ static bool question(bool, const char *, va_list);
static const char *rootdir;
static int flags;
char *
char SYMEXPORT *
xbps_get_file_hash(const char *file)
{
SHA256_CTX ctx;
@ -62,7 +62,7 @@ xbps_get_file_hash(const char *file)
return hash;
}
int
int SYMEXPORT
xbps_check_file_hash(const char *path, const char *sha256)
{
char *res;
@ -80,7 +80,7 @@ xbps_check_file_hash(const char *path, const char *sha256)
return 0;
}
int
int SYMEXPORT
xbps_check_pkg_file_hash(prop_dictionary_t pkgd, const char *repoloc)
{
const char *sha256, *arch, *filename;
@ -109,7 +109,7 @@ xbps_check_pkg_file_hash(prop_dictionary_t pkgd, const char *repoloc)
return rv;
}
int
int SYMEXPORT
xbps_check_is_installed_pkg(const char *pkg)
{
prop_dictionary_t dict;
@ -156,7 +156,7 @@ xbps_check_is_installed_pkg(const char *pkg)
return rv;
}
bool
bool SYMEXPORT
xbps_check_is_installed_pkgname(const char *pkgname)
{
prop_dictionary_t pkgd;
@ -172,7 +172,7 @@ xbps_check_is_installed_pkgname(const char *pkgname)
return false;
}
const char *
const char SYMEXPORT *
xbps_get_pkg_version(const char *pkg)
{
const char *tmp;
@ -187,7 +187,7 @@ xbps_get_pkg_version(const char *pkg)
return tmp + 1; /* skip first '-' */
}
const char *
const char SYMEXPORT *
xbps_get_pkg_revision(const char *pkg)
{
const char *tmp;
@ -202,7 +202,7 @@ xbps_get_pkg_revision(const char *pkg)
return tmp + 1; /* skip first '_' */
}
char *
char SYMEXPORT *
xbps_get_pkg_name(const char *pkg)
{
const char *tmp;
@ -225,20 +225,44 @@ xbps_get_pkg_name(const char *pkg)
return pkgname;
}
char *
xbps_get_pkg_index_plist(const char *path)
static char *
get_pkg_index_remote_plist(const char *uri, const char *machine)
{
char *uri_fixed, *repodir;
uri_fixed = xbps_get_remote_repo_string(uri);
if (uri_fixed == NULL)
return NULL;
repodir = xbps_xasprintf("%s/%s/repo/%s/%s/%s",
xbps_get_rootdir(), XBPS_META_PATH, uri_fixed,
machine, XBPS_PKGINDEX);
if (repodir == NULL) {
free(uri_fixed);
return NULL;
}
return repodir;
}
char SYMEXPORT *
xbps_get_pkg_index_plist(const char *uri)
{
struct utsname un;
assert(path != NULL);
assert(uri != NULL);
if (uname(&un) == -1)
return NULL;
return xbps_xasprintf("%s/%s/%s", path, un.machine, XBPS_PKGINDEX);
if ((strncmp(uri, "http://", 7) == 0) ||
(strncmp(uri, "ftp://", 6) == 0))
return get_pkg_index_remote_plist(uri, un.machine);
return xbps_xasprintf("%s/%s/%s", uri, un.machine, XBPS_PKGINDEX);
}
bool
bool SYMEXPORT
xbps_pkg_has_rundeps(prop_dictionary_t pkg)
{
prop_array_t array;
@ -251,14 +275,14 @@ xbps_pkg_has_rundeps(prop_dictionary_t pkg)
return false;
}
void
void SYMEXPORT
xbps_set_rootdir(const char *dir)
{
assert(dir != NULL);
rootdir = dir;
}
const char *
const char SYMEXPORT *
xbps_get_rootdir(void)
{
if (rootdir == NULL)
@ -267,19 +291,19 @@ xbps_get_rootdir(void)
return rootdir;
}
void
void SYMEXPORT
xbps_set_flags(int lflags)
{
flags = lflags;
}
int
int SYMEXPORT
xbps_get_flags(void)
{
return flags;
}
char *
char SYMEXPORT *
xbps_xasprintf(const char *fmt, ...)
{
va_list ap;
@ -293,11 +317,7 @@ xbps_xasprintf(const char *fmt, ...)
return buf;
}
/*
* The following functions were taken from pacman (src/pacman/util.c)
* Copyright (c) 2002-2007 by Judd Vinet <jvinet@zeroflux.org>
*/
bool
bool SYMEXPORT
xbps_yesno(const char *fmt, ...)
{
va_list ap;
@ -310,7 +330,7 @@ xbps_yesno(const char *fmt, ...)
return res;
}
bool
bool SYMEXPORT
xbps_noyes(const char *fmt, ...)
{
va_list ap;

View File

@ -14,7 +14,9 @@ endif
STATIC_LIBS ?= -lprop -lpthread -larchive
LDFLAGS += -L$(TOPDIR)/lib -L$(PREFIX)/lib -lxbps
CPPFLAGS += -I$(TOPDIR)/include -D_XOPEN_SOURCE=600 -D_GNU_SOURCE
CPPFLAGS += -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE -D_LARGE_FILES
WARNFLAGS ?= -pedantic -std=c99 -Wall -Wextra -Werror -Wshadow -Wformat=2
WARNFLAGS += -Wmissing-declarations -Wcomment -Wunused-macros -Wendif-labels
WARNFLAGS += -Wcast-qual -Wcast-align -Wconversion -Wstack-protector
WARNFLAGS += -Wcast-qual -Wcast-align -Wstack-protector
CFLAGS = $(DEBUG_FLAGS) $(WARNFLAGS) -fstack-protector-all -O2 -fPIC -DPIC
CFLAGS += -fvisibility=hidden