Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found

Target

Select target project
  • adelie/apk-tools
  • Abu2rkyi/apk-tools
2 results
Show changes
Showing with 4082 additions and 0 deletions
apk-keys(5)
# NAME
*/etc/apk/keys* - cryptographic keys trusted by apk
# DESCRIPTION
The */etc/apk/keys* directory stores RSA public keys which are trusted by apk
to verify cryptographic signatures for packages. To trust a new key, simply add
the armored public key to this directory. See *abuild-keygen*(1) for
information on generating new keys, *abuild-sign*(1) for using these keys to
sign files, and *apk-verify*(8) for verifying keys against the apk trust store.
apk-list(8)
# NAME
apk list - list packages matching a pattern or other criteria
# SYNOPSIS
*apk list* [<_options_>...] _pattern_...
# DESCRIPTION
*apk list* searches package indicies for packages matching the given patterns
and prints any matching packages.
The patterns are matched with *fnmatch*(3), which behaves similarly to shell
globbing.
# OPTIONS
*-I, --installed*
Consider only installed packages.
*-O, --orphaned*
Consider only orphaned packages.
*-a, --available*
Consider only available packages.
*-u, --upgradable, --upgradeable*
Consider only upgradable packages.
*-o, --origin*
List packages by origin.
*-d, --depends*
List packages by dependency.
*-P, --providers*
List packages by provider.
apk-manifest(8)
# NAME
apk manifest - Show checksums of package contents
# SYNOPSIS
*apk manifest* [<_options_>...] _packages_...
# DESCRIPTION
*apk manifest* prints the checksums of files in the listed packages. One file
is printed per line, the checksum first, followed by a space, and then the path
to the file.
The checksum itself is printed in the format _algorithm_:_hash_. Supported
algorithms are:
- *md5*
- *sha1*
*sha1* is used for new packages.
# OPTIONS
*apk manifest* does not support any specific options. See *apk*(8) for global
options.
apk-policy(8)
# NAME
apk policy - show repository policy for packages
# SYNOPSIS
*apk policy* [<_options_>...] _packages_...
# DESCRIPTION
*apk policy* shows apk's repository policy for the specified packages. It
prints matching packages and their versions available from configured
repositories (see *apk-repositories*(5)), in order of installation preference.
# OPTIONS
*apk policy* does not support any specific options. See *apk*(8) for global
options.
apk-repositories(5)
# NAME
*/etc/apk/repositories* - list of package repositories
# DESCRIPTION
/etc/apk/repositories is the list of package repositories *apk*(8) uses to
retrieve package files for installation. Each line of this file specifies the
location of a package repository, and optionally a tag.
The location may be an _http://_, _https://_, or _ftp://_ URL, or the path to a
directory on the local filesystem. A tagged repository is prefixed with the
*@tag* specifier, followed by a space and the repository location. For more
information about repository tags, see *apk-world*(5).
# REPOSITORY LAYOUT
Each repository must store an index at *$repository/$arch/APKINDEX.tar.gz*. See
*apk-index*(8) for information about generating this file. The packages
themselves are stored at *$repository/$arch/$pkgname-$pkgver-r$pkgrel.apk*.
*apk*(8) verifies that each of these files has a valid cryptographic signature
unless explicitly told not to via the *--allow-untrusted* flag. See
*abuild-keygen*(1) for information about generating keys, *apk-keys*(5) to add
keys to the list of trusted keys, *abuild-sign*(1) for information about using
these keys to sign files, and *apk-verify*(8) for information about verifying
those signatures.
# UPDATING INDICIES
*apk*(8) fetches and stores the index for each package repository at
/var/lib/cache. To fetch fresh indicies for all configured repositories, use
*apk-update*(8).
apk-search(8)
# NAME
apk search - search for packages by name or description
# SYNOPSIS
*apk search* [<_options_>...] _pattern_...
# DESCRIPTION
*apk search* searches all repositories for packages matching at least one
pattern. If no pattern is given, it lists all packages in the repository. A
pattern matches if it is a case-sensitive substring of the package name.
# OPTIONS
In addition to the global options (see *apk*(8)), *apk search* supports the
following options:
*-a, --all*
Print all matching package versions. By default, *apk* only shows the
latest version.
*-d, --description*
Also search for _pattern_ in the package description. By default, *apk*
does not search package descriptions.
*-e, -x, --exact*
Match package names exactly.
*--has-origin*
Match by package origin. Shows all packages whose base package name
matches _pattern_ exactly. Implies *--all* and *--exact*.
*-o, --origin*
Print base package name.
*-r, --rdepends*
Print reverse dependencies (other packages which depend on the
package).
apk-stats(8)
# NAME
apk stats - show statistics about repositories and installations
# SYNOPSIS
*apk stats*
# DESCRIPTION
*apk stats* prints statistics about installed packages, package repositories,
and other information.
# OPTIONS
*apk stats* does not support any specific options. See *apk*(8) for global
options.
apk-update(8)
# NAME
apk update - update repository indexes
# SYNOPSIS
*apk update*
# DESCRIPTION
*apk update* forces updating of the indexes from all configured package
repositories. This command is not needed in normal operation as all applets
requiring indexes will automatically refresh them after caching time expires.
See *apk-repositories*(5) for more information on configuring package
repositories.
# OPTIONS
*apk update* does not support any specific options. See *apk*(8) for global
options.
apk-upgrade(8)
# NAME
apk upgrade - upgrade installed packages
# SYNOPSIS
*apk upgrade* [<_options_>...] [<_packages_>...]
# DESCRIPTION
*apk upgrade* upgrades installed packages to the latest version available from
configured package repositories (see *apk-repositories*(5)). When no packages
are specified, all packages are upgraded if possible. If list of packages is
provided, only those packages are upgraded along with needed dependencies.
# OPTIONS
*apk upgrade* supports the commit options described in *apk*(8), as well as the
following options:
*-a, --available*
Reset all packages to versions available from current repositories.
This resets all versioned dependencies in _world_ (see *apk-world*(5)).
Additionally, packages are selected from active repositories if possible
even if it means replacing or downgrading the package.
This is useful to reset system against new set of packages after updating
repositories.
*--ignore*
Upgrade all other packages than the ones listed. This inverts the given
package name list to mean packages that should not be upgraded.
*-l, --latest*
Always choose the latest package by version. However, the versions
considered are based on the package pinning. Primarily this overrides
the default heuristic and will cause an error to displayed if all
dependencies cannot be satisfied.
*--no-self-upgrade*
Do not do an early upgrade of the 'apk-tools' package.
*--prune*
Prune the _world_ by removing packages which are no longer available
from any configured repository.
*--self-upgrade-only*
Only perform a self-upgrade of the 'apk-tools' package.
apk-verify(8)
# NAME
apk verify - verify package integrity and signature
# SYNOPSIS
*apk verify* [<_options_>...] _files_...
# DESCRIPTION
*apk verify* verifies the integrity of the package files specified, validating
the checksums and cryptographic signature.
*apk verify* prints a summary of the results on stdout, and exits with status
code zero if all packages were successfully verified. If any failed, *apk
verify* exits with a nonzero status.
# OPTIONS
*apk verify* does not support any specific options. See *apk*(8) for global
options.
apk-version(8)
# NAME
apk version - compare package versions
# SYNOPSIS
*apk version* [<_options_>...] [_packages_...]
*apk version* -c _versions_...
*apk version* -t _version1_ _version2_
*apk version* -I
# DESCRIPTION
*apk version* compares the versions of installed packages against package
versions available from repositories (see *apk-repositories*(5)). It can also
be used to validate and compare version strings.
In default mode, if no packages are specified, all installed packages are
considered. Otherwise, the comparison is limited to the explicitly listed
packages. A summary is printed on stdout, with the difference between package
versions being represented as *>*, *=*, or *<*.
Options *-c*, *-I*, and *-t* are mutually exclusive.
# OPTIONS
These options only apply when checking installed package versions against
packages available from the repositories (when neither *-c*, *-t*, nor *-I* are
specified).
*-a, --all*
Consider packages from all repository tags.
*-c, --check* _versions_...
Check versions for validity. If a given version is invalid, it is
printed. Exits with status code zero if all versions are valid, and
non-zero otherwise.
*-I, --indexes*
Print the version and description for each repository's index. See
*apk-repositories*(5) for more information.
*-l, --limit* _operand_
Limit to packages with output matching given _operand_. The _operand_
can be specified as any combination of *>*, *=*, and *<*.
*-t, --test* _version1_ _version2_
Compare two version strings. Does not consult the database. Prints one
of *>*, *=*, or *<*, if _version1_ is, respectively, greater than,
equal to, or lesser than _version2_.
apk-world(5)
# NAME
*/etc/apk/world* - list of explicitly installed packages
# DESCRIPTION
At /etc/apk/world, apk maintains the _world_, or list of explicitly installed
packages. This is a plaintext file with one package spec per line.
If you edit this file manually, you should run *apk-fix*(8) to apply the
changes.
# PACKAGE SPECIFICATION
Specifying a package name with no other modifiers will install the latest
version of that package from the first repository in which it is available.
To pin a package to a tagged repository, use the format *pkgname@tagname*, e.g.
*busybox@edge*. See *apk-repositories*(5) for details on tagged package
repositories.
To constrain the acceptable versions of the package, use the *=*, *<*, *>*,
*>=*, or *~=* operators. Respectively, these require the package is equal to,
less than, greater than, or greater than or equal to the specified version. The
*~=* operator constrains the package to the version numbers specified, but will
not constrain any unspecified version numbers.
*busybox*
Installs busybox from the first repository from which it is available.
*busybox@edge*
Installs busybox from the first repository tagged "edge" from which
it's available. If busybox is _not_ available in repositories with this
tag, it will cause an error. When resolving dependencies of tagged
requirements, untagged repositories are preferred, but repositories
sharing the same tag will be considered if necessary.
*busybox=1.6.1*
Install busybox version 1.6.1.
*busybox>1.6.1*
Install a busybox version greater than 1.6.1.
*busybox>=1.6.1*
Install a busybox version greater than or equal to 1.6.1.
*busybox<1.6.1*
Install a busybox version less than 1.6.1.
*busybox~=1.6*
Install any busybox version between 1.6.0 (inclusive) and 1.7.0
(exclusive).
apk(8)
# NAME
apk - Alpine Package Keeper
# SYNOPSIS
*apk* [<_options_>...] _command_ [<_arguments_>...]
# DESCRIPTION
*apk* manages packages installed on the system. The set of top level packages
to install is called the _world_ (see *apk-world*(5)). *apk* supports various
sub-commands to query and manipulate _world_ and local & remote package
repositories.
# COMMANDS
Each command is documented in detail on its manual page.
## PACKAGE INSTALLATION AND REMOVAL
|[ *apk-add*(8)
:< Add packages to _world_ and commit changes
| *apk-del*(8)
: Remove packages from _world_ and commit changes
## SYSTEM MAINTENANCE
|[ *apk-fix*(8)
:< Fix, reinstall or upgrade packages without modifying _world_
| *apk-update*(8)
: Update repository indexes
| *apk-upgrade*(8)
: Install upgrades available from repositories
| *apk-cache*(8)
: Manage the local package cache
## QUERYING PACKAGE INFORMATION
|[ *apk-info*(8)
:< Give detailed information about packages or repositories
| *apk-list*(8)
: List packages matching a pattern or other criteria
| *apk-dot*(8)
: Render dependencies as graphviz graphs
| *apk-policy*(8)
: Show repository policy for packages
| *apk-search*(8)
: Search for packages by name or description
## REPOSITORY MAINTENANCE
|[ *apk-index*(8)
:< Create repository index file from packages
| *apk-fetch*(8)
: Download packages from repositories to a local directory
| *apk-manifest*(8)
: Show checksums of package contents
| *apk-verify*(8)
: Verify package integrity and signature
## MISCELLANEOUS
|[ *apk-audit*(8)
:< Audit system for changes
| *apk-stats*(8)
: Show statistics about repositories and installations
| *apk-version*(8)
: Compare package versions or perform tests on version strings
# GLOBAL OPTIONS
The following options are available for all commands.
*-f, --force*
Enable selected --force-\* options (deprecated).
*-i, --interactive*
Ask confirmation before performing certain operations.
Interactive mode can be made the default when running on a tty,
by creating /etc/apk/interactive as an empty file.
*-p, --root* _ROOT_
Manage file system at _ROOT_.
*-q, --quiet*
Print less information.
*-U, --update-cache*
Alias for '--cache-max-age 1'.
*-v, --verbose*
Print more information (can be specified twice).
*-V, --version*
Print program version and exit.
*-X, --repository* _REPO_
Specify additional package repository. This option can be specified
multiple times.
*--allow-untrusted*
Install packages with untrusted signature or no signature.
*--arch* _ARCH_
Temporarily override architecture, to be combined with --root.
*--cache-dir* _CACHEDIR_
Temporarily override the cache directory. _CACHEDIR_ is treated relative
to the _ROOT_.
*--cache-max-age* _AGE_
Maximum AGE (in minutes) for index in cache before it's refreshed.
*--force-binary-stdout*
Continue even if binary data will be printed to the terminal.
*--force-broken-world*
Continue even if _world_ cannot be satisfied.
*--force-missing-repositories*
Continue even if some of the repository indexes are not available.
*--force-non-repository*
Continue even if packages may be lost on reboot. This can happen when
running in run-from-tmpfs mode, and installing non-repository package.
*--force-old-apk*
Continue even if packages use unsupported features.
*--force-overwrite*
Overwrite files in other packages.
*--force-refresh*
Do not use cached files (local or from proxy).
*--keys-dir* _KEYSDIR_
Override directory of trusted keys. This is treated relative to _ROOT_.
*--no-cache*
Do not use any local cache path.
*--no-check-certificate*
Do not validate the HTTPS server certificates.
*--no-interactive*
Disable interactive mode.
*--no-network*
Do not use the network. The cache is still used when possible.
*--no-progress*
Disable progress bar even for TTYs.
*--print-arch*
Print default arch and exit.
*--progress*
Show progress.
*--progress-fd* _FD_
Write progress to the specified file descriptor.
*--purge*
Purge modified configuration and cached packages. Enables deletion of
modified configuration files on package removal. On cache clean action
this enables deletion of unneeded cached packages (uninstalled packages
on tmpfs installations or all packages on disk installations).
*--repositories-file* _REPOFILE_
Override system repositories, see *apk-repositories*(8). Specifying this
option overrides the normal repositories file and repositories.d directory
processing. The given _REPOFILE_ is relative to the startup directory since
apk 2.12.0_rc2.
*--timeout* _TIME_
Timeout network connections if no progress is made in TIME seconds.
The default is 60 seconds.
*--wait* _TIME_
Wait for TIME seconds to get an exclusive repository lock before
failing.
# COMMIT OPTIONS
The following options are available for all commands which commit the database.
*-s, --simulate*
Simulate the requested operation without making any changes. The database
is opened in read only mode, and auto-updating of indexes is disabled.
You may want to run "apk update" before running a simulation to make sure
it is done with up-to-date repository indexes.
*--clean-protected*
Do not create .apk-new files in configuration directories.
*--overlay-from-stdin*
Read list of overlay files from stdin. Normally this is used only during
initramfs when booting run-from-tmpfs installation.
*--no-scripts*
Do not execute any scripts. Useful for extracting a system image for
different architecture on alternative _ROOT_.
*--no-commit-hooks*
Skip pre/post hook scripts (but not other scripts).
*--initramfs-diskless-boot*
Used by initramfs when it's recreating root tmpfs. This enables selected
force options to minimize failure, and disables commit hooks, among
other features.
# SOURCE OPTIONS
The following options are available for all commands which operate on the
package indexes only.
*--from* _FROMSPEC_
Search packages from: *system* (all system sources), *repositories*
(exclude installed database), *installed* (exclude normal repositories)
or *none* (commandline repositories only).
# NOTES
This apk has coffee making abilities.
libs-y += libfetch.a
libfetch.a-objs := common.o fetch.o file.o ftp.o http.o openssl-compat.o
generate-y += ftperr.h httperr.h
CFLAGS_common.o += -DCA_CERT_FILE=\"$(CONFDIR)/ca.pem\" -DCA_CRL_FILE=\"$(CONFDIR)/crl.pem\"
CFLAGS_common.o += -DCLIENT_CERT_FILE=\"$(CONFDIR)/cert.pem\" -DCLIENT_KEY_FILE=\"$(CONFDIR)/cert.key\"
PKG_CONFIG ?= pkg-config
OPENSSL_CFLAGS := $(shell $(PKG_CONFIG) --cflags openssl)
OPENSSL_LIBS := $(shell $(PKG_CONFIG) --libs openssl)
CFLAGS_ALL += $(OPENSSL_CFLAGS)
quiet_cmd_generr = GENERR $@
cmd_generr = $(src)/errlist.sh $(basename $(<F))_errlist $(shell echo $(basename $(<F)) | tr a-z A-Z) $< > $@
$(obj)/%err.h: $(src)/%.errors
@$(call echo-cmd,generr) $(cmd_generr)
This diff is collapsed.
/* $NetBSD: common.h,v 1.24 2016/10/20 21:25:57 joerg Exp $ */
/*-
* Copyright (c) 1998-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.
*
* $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 HTTPS_DEFAULT_PORT 443
#define FTP_DEFAULT_PROXY_PORT 21
#define HTTP_DEFAULT_PROXY_PORT 3128
#include <sys/types.h>
#include <limits.h>
#include "openssl-compat.h"
#if defined(__GNUC__) && __GNUC__ >= 3
#define LIBFETCH_PRINTFLIKE(fmtarg, firstvararg) \
__attribute__((__format__ (__printf__, fmtarg, firstvararg)))
#else
#define LIBFETCH_PRINTFLIKE(fmtarg, firstvararg)
#endif
#if !defined(__sun) && !defined(__hpux) && !defined(__INTERIX) && \
!defined(__digital__) && !defined(__linux) && !defined(__MINT__) && \
!defined(__sgi) && !defined(__minix) && !defined(__CYGWIN__)
#define HAVE_SA_LEN
#endif
#ifndef IPPORT_MAX
# define IPPORT_MAX 65535
#endif
#ifndef OFF_MAX
# define OFF_MAX (((((off_t)1 << (sizeof(off_t) * CHAR_BIT - 2)) - 1) << 1) + 1)
#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 */
int buf_events; /* poll flags for the next cycle */
char *next_buf; /* pending buffer, e.g. after getln */
size_t next_len; /* size of pending buffer */
int err; /* last protocol reply code */
SSL *ssl; /* SSL handle */
SSL_CTX *ssl_ctx; /* SSL context */
X509 *ssl_cert; /* server certificate */
const SSL_METHOD *ssl_meth; /* SSL method */
char *ftp_home;
struct url *cache_url;
int cache_af;
int (*cache_close)(conn_t *);
conn_t *next_cached;
};
/* Structure used for error message lists */
struct fetcherr {
const int num;
const int cat;
const char *string;
};
void fetch_seterr(struct fetcherr *, int);
void fetch_syserr(void);
void fetch_info(const char *, ...) LIBFETCH_PRINTFLIKE(1, 2);
uintmax_t fetch_parseuint(const char *p, const char **endptr, int radix, uintmax_t max);
int fetch_default_port(const char *);
int fetch_default_proxy_port(const char *);
int fetch_bind(int, int, const char *);
conn_t *fetch_cache_get(const struct url *, int);
void fetch_cache_put(conn_t *, int (*)(conn_t *));
conn_t *fetch_connect(struct url *, struct url *, int, int);
conn_t *fetch_reopen(int);
int fetch_ssl(conn_t *, const struct url *, int);
ssize_t fetch_read(conn_t *, char *, size_t);
int fetch_getln(conn_t *);
ssize_t fetch_write(conn_t *, const void *, 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
#!/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"
This diff is collapsed.
/* $NetBSD: fetch.c,v 1.19 2009/08/11 20:48:06 joerg Exp $ */
/*-
* Copyright (c) 1998-2004 Dag-Erling Codan Smrgrav
* 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 $
*/
#include <ctype.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "fetch.h"
#include "common.h"
fetch_redirect_t fetchRedirectMethod;
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
#define URL_BAD_HOST 4
#define URL_BAD_AUTH 5
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" },
{ URL_BAD_HOST, FETCH_URL, "Invalid (or too long) hostname" },
{ URL_BAD_AUTH, FETCH_URL, "Invalid (or too long) credentials" },
{ -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;
}
/*
* Return value of the given hex digit.
*/
static int
fetch_hexval(char ch)
{
if (ch >= '0' && ch <= '9')
return (ch - '0');
else if (ch >= 'a' && ch <= 'f')
return (ch - 'a' + 10);
else if (ch >= 'A' && ch <= 'F')
return (ch - 'A' + 10);
return (-1);
}
/*
* Decode percent-encoded URL component from src into dst, stopping at end
* of string or one of the characters contained in brk. Returns a pointer
* to the unhandled part of the input string (null terminator, specified
* character). No terminator is written to dst (it is the caller's
* responsibility).
*/
static const char *
fetch_pctdecode(char *dst, const char *src, const char *brk, size_t dlen)
{
int d1, d2;
char c;
const char *s;
for (s = src; *s != '\0' && !strchr(brk, *s); s++) {
if (s[0] == '%' && (d1 = fetch_hexval(s[1])) >= 0 &&
(d2 = fetch_hexval(s[2])) >= 0 && (d1 > 0 || d2 > 0)) {
c = d1 << 4 | d2;
s += 2;
} else if (s[0] == '%') {
/* Invalid escape sequence. */
return (NULL);
} else {
c = *s;
}
if (!dlen)
return NULL;
dlen--;
*dst++ = c;
}
return (s);
}
/*
* Split a 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 */
q = URL;
q = fetch_pctdecode(u->user, q, ":@", URL_USERLEN);
if (q == NULL) {
url_seterr(URL_BAD_AUTH);
goto ouch;
}
/* password */
if (*q == ':') {
q = fetch_pctdecode(u->pwd, q + 1, "@", URL_PWDLEN);
if (q == NULL) {
url_seterr(URL_BAD_AUTH);
goto ouch;
}
}
if (*q != '@') {
url_seterr(URL_BAD_AUTH);
goto ouch;
}
p++;
} else {
p = URL;
}
/* hostname */
if (*p == '[' && (q = strchr(p + 1, ']')) != NULL &&
(*++q == '\0' || *q == '/' || *q == ':')) {
if ((i = q - p - 2) >= URL_HOSTLEN) {
url_seterr(URL_BAD_HOST);
goto ouch;
}
strncpy(u->host, ++p, i);
p = q;
} else {
for (i = 0; *p && (*p != '/') && (*p != ':'); p++) {
if (i >= URL_HOSTLEN) {
url_seterr(URL_BAD_HOST);
goto ouch;
}
u->host[i++] = *p;
}
}
/* port */
if (*p == ':') {
u->port = fetch_parseuint(p + 1, &p, 10, IPPORT_MAX);
if (*p && *p != '/') {
/* invalid port */
url_seterr(URL_BAD_PORT);
goto ouch;
}
}
/* 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;
}
This diff is collapsed.