forked from mirrors/pacman
Compare commits
11 Commits
allan/priv
...
morganamil
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
83838214b7 | ||
|
|
4baeb8e40b | ||
|
|
18b65ec909 | ||
|
|
45ce932fd0 | ||
|
|
da4b590bce | ||
|
|
0649a66ee5 | ||
|
|
6e6d3f18e3 | ||
|
|
0a394144b2 | ||
|
|
fde59b99e8 | ||
|
|
edd57c8b96 | ||
|
|
5c75a55c7d |
@@ -207,10 +207,6 @@ Options
|
||||
positive integer. If this config option is not set then only one download
|
||||
stream is used (i.e. downloads happen sequentially).
|
||||
|
||||
*DownloadUser =* username::
|
||||
Specifies the user to switch to for downloading files. If this config
|
||||
option is not set then the downloads are done as the user running pacman.
|
||||
|
||||
|
||||
Repository Sections
|
||||
-------------------
|
||||
|
||||
@@ -1149,7 +1149,9 @@ typedef enum _alpm_progress_t {
|
||||
* make take a while to complete.
|
||||
* @param ctx user-provided context
|
||||
* @param progress the kind of event that is progressing
|
||||
* @param pkg for package operations, the name of the package being operated on
|
||||
* @param pkg the name of the package being operated on. if the progress kind
|
||||
* is a packae operation (add, upgrade, downgrade, reinstall, remove).
|
||||
* otherwise this will be an empty string.
|
||||
* @param percent the percent completion of the action
|
||||
* @param howmany the total amount of items in the action
|
||||
* @param current the current amount of items completed
|
||||
@@ -1870,28 +1872,6 @@ int alpm_option_set_gpgdir(alpm_handle_t *handle, const char *gpgdir);
|
||||
/** @} */
|
||||
|
||||
|
||||
/** @name Accessors for use sandboxuser
|
||||
*
|
||||
* This controls the user that libalpm will use for sensitive operations like
|
||||
* downloading files.
|
||||
* @{
|
||||
*/
|
||||
|
||||
/** Returns the user to switch to for sensitive operations.
|
||||
* @return the user name
|
||||
*/
|
||||
const char *alpm_option_get_sandboxuser(alpm_handle_t *handle);
|
||||
|
||||
/** Sets the user to switch to for sensitive operations.
|
||||
* @param handle the context handle
|
||||
* @param sandboxuser the user to set
|
||||
*/
|
||||
int alpm_option_set_sandboxuser(alpm_handle_t *handle, const char *sandboxuser);
|
||||
|
||||
/* End of sandboxuser accessors */
|
||||
/** @} */
|
||||
|
||||
|
||||
/** @name Accessors for use syslog
|
||||
*
|
||||
* This controls whether libalpm will also use the syslog. Even if this option
|
||||
@@ -2315,7 +2295,9 @@ typedef enum _alpm_pkgreason_t {
|
||||
/** Explicitly requested by the user. */
|
||||
ALPM_PKG_REASON_EXPLICIT = 0,
|
||||
/** Installed as a dependency for another package. */
|
||||
ALPM_PKG_REASON_DEPEND = 1
|
||||
ALPM_PKG_REASON_DEPEND = 1,
|
||||
/** Failed parsing of local database */
|
||||
ALPM_PKG_REASON_UNKNOWN = 2
|
||||
} alpm_pkgreason_t;
|
||||
|
||||
/** Location a package object was loaded from. */
|
||||
@@ -2951,12 +2933,6 @@ const char *alpm_version(void);
|
||||
* */
|
||||
int alpm_capabilities(void);
|
||||
|
||||
/** Drop privileges by switching to a different user.
|
||||
* @param sandboxuser the user to switch to
|
||||
* @return 0 on success, -1 on failure
|
||||
*/
|
||||
int alpm_sandbox_setup_child(const char *sandboxuser);
|
||||
|
||||
/* End of libalpm_misc */
|
||||
/** @} */
|
||||
|
||||
|
||||
@@ -630,6 +630,10 @@ static int local_db_populate(alpm_db_t *db)
|
||||
continue;
|
||||
}
|
||||
|
||||
/* treat local metadata errors as warning-only,
|
||||
* they are already installed and otherwise they can't be operated on */
|
||||
_alpm_pkg_check_meta(pkg);
|
||||
|
||||
/* add to the collection */
|
||||
_alpm_log(db->handle, ALPM_LOG_FUNCTION, "adding '%s' to package cache for db '%s'\n",
|
||||
pkg->name, db->treename);
|
||||
@@ -650,6 +654,17 @@ static int local_db_populate(alpm_db_t *db)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static alpm_pkgreason_t _read_pkgreason(alpm_handle_t *handle, const char *pkgname, const char *line) {
|
||||
if(strcmp(line, "0") == 0) {
|
||||
return ALPM_PKG_REASON_EXPLICIT;
|
||||
} else if(strcmp(line, "1") == 0) {
|
||||
return ALPM_PKG_REASON_DEPEND;
|
||||
} else {
|
||||
_alpm_log(handle, ALPM_LOG_ERROR, _("unknown install reason for package %s: %s\n"), pkgname, line);
|
||||
return ALPM_PKG_REASON_UNKNOWN;
|
||||
}
|
||||
}
|
||||
|
||||
/* Note: the return value must be freed by the caller */
|
||||
char *_alpm_local_db_pkgpath(alpm_db_t *db, alpm_pkg_t *info,
|
||||
const char *filename)
|
||||
@@ -772,7 +787,7 @@ static int local_db_read(alpm_pkg_t *info, int inforeq)
|
||||
READ_AND_STORE(info->packager);
|
||||
} else if(strcmp(line, "%REASON%") == 0) {
|
||||
READ_NEXT();
|
||||
info->reason = (alpm_pkgreason_t)atoi(line);
|
||||
info->reason = _read_pkgreason(db->handle, info->name, line);
|
||||
} else if(strcmp(line, "%VALIDATION%") == 0) {
|
||||
alpm_list_t *i, *v = NULL;
|
||||
READ_AND_STORE_ALL(v);
|
||||
@@ -822,6 +837,12 @@ static int local_db_read(alpm_pkg_t *info, int inforeq)
|
||||
}
|
||||
}
|
||||
FREELIST(lines);
|
||||
} else {
|
||||
_alpm_log(db->handle, ALPM_LOG_ERROR, _("%s: unknown key '%s' in sync database\n"), info->name, line);
|
||||
alpm_list_t *lines = NULL;
|
||||
READ_AND_STORE_ALL(lines);
|
||||
FREELIST(lines);
|
||||
|
||||
}
|
||||
}
|
||||
fclose(fp);
|
||||
|
||||
@@ -251,8 +251,10 @@ static int parse_descfile(alpm_handle_t *handle, struct archive *a, alpm_pkg_t *
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
const char *pkgname = newpkg->name ? newpkg->name : "error";
|
||||
_alpm_log(handle, ALPM_LOG_ERROR, _("%s: unknown key '%s' in package description\n"), pkgname, key);
|
||||
_alpm_log(handle, ALPM_LOG_DEBUG, "%s: unknown key '%s' in description file line %d\n",
|
||||
newpkg->name ? newpkg->name : "error", key, linenum);
|
||||
pkgname, key, linenum);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -652,8 +654,6 @@ alpm_pkg_t *_alpm_pkg_load_internal(alpm_handle_t *handle,
|
||||
goto pkg_invalid;
|
||||
}
|
||||
|
||||
_alpm_archive_read_free(archive);
|
||||
|
||||
/* internal fields for package struct */
|
||||
newpkg->origin = ALPM_PKG_FROM_FILE;
|
||||
STRDUP(newpkg->origin_data.file, pkgfile, goto error);
|
||||
@@ -675,6 +675,11 @@ alpm_pkg_t *_alpm_pkg_load_internal(alpm_handle_t *handle,
|
||||
newpkg->infolevel |= INFRQ_FILES;
|
||||
}
|
||||
|
||||
if(_alpm_pkg_check_meta(newpkg) != 0) {
|
||||
goto pkg_invalid;
|
||||
}
|
||||
|
||||
_alpm_archive_read_free(archive);
|
||||
close(fd);
|
||||
return newpkg;
|
||||
|
||||
|
||||
@@ -189,18 +189,6 @@ int SYMEXPORT alpm_db_update(alpm_handle_t *handle, alpm_list_t *dbs, int force)
|
||||
MALLOC(payload->filepath, len,
|
||||
FREE(payload); GOTO_ERR(handle, ALPM_ERR_MEMORY, cleanup));
|
||||
snprintf(payload->filepath, len, "%s%s", db->treename, dbext);
|
||||
|
||||
STRDUP(payload->remote_name, payload->filepath,
|
||||
_alpm_dload_payload_reset(payload); FREE(payload);
|
||||
GOTO_ERR(handle, ALPM_ERR_MEMORY, cleanup));
|
||||
payload->destfile_name = _alpm_get_fullpath(syncpath, payload->remote_name, "");
|
||||
payload->tempfile_name = _alpm_get_fullpath(syncpath, payload->remote_name, ".part");
|
||||
if(!payload->destfile_name || !payload->tempfile_name) {
|
||||
_alpm_dload_payload_reset(payload);
|
||||
FREE(payload);
|
||||
GOTO_ERR(handle, ALPM_ERR_MEMORY, cleanup);
|
||||
}
|
||||
|
||||
payload->handle = handle;
|
||||
payload->force = dbforce;
|
||||
payload->unlink_on_fail = 1;
|
||||
@@ -356,6 +344,11 @@ static alpm_pkg_t *load_pkg_for_entry(alpm_db_t *db, const char *entryname,
|
||||
pkg->ops = get_sync_pkg_ops();
|
||||
pkg->handle = db->handle;
|
||||
|
||||
if(_alpm_pkg_check_meta(pkg) != 0) {
|
||||
_alpm_pkg_free(pkg);
|
||||
RET_ERR(db->handle, ALPM_ERR_PKG_INVALID, NULL);
|
||||
}
|
||||
|
||||
/* add to the collection */
|
||||
_alpm_log(db->handle, ALPM_LOG_FUNCTION, "adding '%s' to package cache for db '%s'\n",
|
||||
pkg->name, db->treename);
|
||||
@@ -464,6 +457,14 @@ static int sync_db_populate(alpm_db_t *db)
|
||||
}
|
||||
}
|
||||
}
|
||||
/* the db file was successfully read, but contained errors */
|
||||
if(ret == -1) {
|
||||
db->status &= ~DB_STATUS_VALID;
|
||||
db->status |= DB_STATUS_INVALID;
|
||||
_alpm_db_free_pkgcache(db);
|
||||
GOTO_ERR(db->handle, ALPM_ERR_DB_INVALID, cleanup);
|
||||
}
|
||||
/* reading the db file failed */
|
||||
if(archive_ret != ARCHIVE_EOF) {
|
||||
_alpm_log(db->handle, ALPM_LOG_ERROR, _("could not read db '%s' (%s)\n"),
|
||||
db->treename, archive_error_string(archive));
|
||||
@@ -690,6 +691,11 @@ static int sync_db_read(alpm_db_t *db, struct archive *archive,
|
||||
}
|
||||
}
|
||||
FREELIST(lines);
|
||||
} else {
|
||||
_alpm_log(db->handle, ALPM_LOG_ERROR, _("%s: unknown key '%s' in local database\n"), pkg->name, line);
|
||||
alpm_list_t *lines = NULL;
|
||||
READ_AND_STORE_ALL(lines);
|
||||
FREELIST(lines);
|
||||
}
|
||||
}
|
||||
if(ret != ARCHIVE_EOF) {
|
||||
|
||||
@@ -563,18 +563,17 @@ static void free_groupcache(alpm_db_t *db)
|
||||
|
||||
void _alpm_db_free_pkgcache(alpm_db_t *db)
|
||||
{
|
||||
if(db == NULL || !(db->status & DB_STATUS_PKGCACHE)) {
|
||||
if(db == NULL || db->pkgcache == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
_alpm_log(db->handle, ALPM_LOG_DEBUG,
|
||||
"freeing package cache for repository '%s'\n", db->treename);
|
||||
|
||||
if(db->pkgcache) {
|
||||
alpm_list_free_inner(db->pkgcache->list,
|
||||
(alpm_list_fn_free)_alpm_pkg_free);
|
||||
_alpm_pkghash_free(db->pkgcache);
|
||||
}
|
||||
alpm_list_free_inner(db->pkgcache->list,
|
||||
(alpm_list_fn_free)_alpm_pkg_free);
|
||||
_alpm_pkghash_free(db->pkgcache);
|
||||
db->pkgcache = NULL;
|
||||
db->status &= ~DB_STATUS_PKGCACHE;
|
||||
|
||||
free_groupcache(db);
|
||||
|
||||
@@ -556,7 +556,7 @@ static void _alpm_select_depends(alpm_list_t **from, alpm_list_t **to,
|
||||
for(i = *from; i; i = next) {
|
||||
alpm_pkg_t *deppkg = i->data;
|
||||
next = i->next;
|
||||
if((explicit || alpm_pkg_get_reason(deppkg) != ALPM_PKG_REASON_EXPLICIT)
|
||||
if((explicit || alpm_pkg_get_reason(deppkg) == ALPM_PKG_REASON_DEPEND)
|
||||
&& _alpm_pkg_depends_on(pkg, deppkg)) {
|
||||
*to = alpm_list_add(*to, deppkg);
|
||||
*from = alpm_list_remove_item(*from, i);
|
||||
|
||||
@@ -28,9 +28,7 @@
|
||||
#include <sys/time.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/wait.h>
|
||||
#include <signal.h>
|
||||
#include <pwd.h>
|
||||
|
||||
#ifdef HAVE_NETINET_IN_H
|
||||
#include <netinet/in.h> /* IPPROTO_TCP */
|
||||
@@ -50,145 +48,6 @@
|
||||
#include "log.h"
|
||||
#include "util.h"
|
||||
#include "handle.h"
|
||||
#include "sandbox.h"
|
||||
|
||||
|
||||
static const char *get_filename(const char *url)
|
||||
{
|
||||
char *filename = strrchr(url, '/');
|
||||
if(filename != NULL) {
|
||||
return filename + 1;
|
||||
}
|
||||
|
||||
/* no slash found, it's a filename */
|
||||
return url;
|
||||
}
|
||||
|
||||
/* prefix to avoid possible future clash with getumask(3) */
|
||||
static mode_t _getumask(void)
|
||||
{
|
||||
mode_t mask = umask(0);
|
||||
umask(mask);
|
||||
return mask;
|
||||
}
|
||||
|
||||
static int touch_and_own_file(const char *filename, const char *user)
|
||||
{
|
||||
int fd;
|
||||
struct passwd const *pw = NULL;
|
||||
|
||||
ASSERT(filename != NULL, return -1);
|
||||
ASSERT(user != NULL, return -1);
|
||||
|
||||
ASSERT((fd = open(filename, O_CREAT | O_WRONLY, 0644)) != -1, return -1);
|
||||
close(fd);
|
||||
|
||||
ASSERT((pw = getpwnam(user)) != NULL, return -1);
|
||||
ASSERT(chown(filename, pw->pw_uid, pw->pw_gid) != -1, return -1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int intialize_download_file(struct dload_payload *p)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
ret = touch_and_own_file(p->tempfile_name, p->handle->sandboxuser);
|
||||
|
||||
if(ret == 0 && p->download_signature) {
|
||||
int len = strlen(p->destfile_name) + strlen(".sig") + strlen(".part") + 1;
|
||||
char * sig;
|
||||
MALLOC(sig, len, FREE(sig); RET_ERR(p->handle, ALPM_ERR_MEMORY, -1));
|
||||
snprintf(sig, len, "%s.sig.part", p->destfile_name);
|
||||
ret = touch_and_own_file(sig, p->handle->sandboxuser);
|
||||
free(sig);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int unlink_or_move(const char *file, const char* dest) {
|
||||
struct stat st;
|
||||
|
||||
ASSERT(stat(file, &st) == 0, return -1);
|
||||
|
||||
if(st.st_size == 0) {
|
||||
unlink(file);
|
||||
} else {
|
||||
ASSERT(chown(file, 0, 0) != -1, return -1);
|
||||
if(rename(file, dest)) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int finalize_download_file(struct dload_payload *p)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
ret = unlink_or_move(p->tempfile_name, p->destfile_name);
|
||||
|
||||
if(ret == -1) {
|
||||
_alpm_log(p->handle, ALPM_LOG_ERROR, _("could not rename %s to %s (%s)\n"),
|
||||
p->tempfile_name, p->destfile_name, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(p->download_signature) {
|
||||
char *sig_temp, *sig_dest;
|
||||
int len = strlen(p->destfile_name) + strlen(".sig") + 1;
|
||||
MALLOC(sig_dest, len, RET_ERR(p->handle, ALPM_ERR_MEMORY, -1));
|
||||
snprintf(sig_dest, len, "%s.sig", p->destfile_name);
|
||||
len = len + 5;
|
||||
MALLOC(sig_temp, len, FREE(sig_dest); RET_ERR(p->handle, ALPM_ERR_MEMORY, -1));
|
||||
snprintf(sig_temp, len, "%s.sig.part", p->destfile_name);
|
||||
|
||||
ret = unlink_or_move(sig_temp, sig_dest);
|
||||
if(ret == -1) {
|
||||
_alpm_log(p->handle, ALPM_LOG_ERROR, _("could not rename %s to %s (%s)\n"),
|
||||
sig_temp, sig_dest, strerror(errno));
|
||||
}
|
||||
|
||||
free(sig_dest);
|
||||
free(sig_temp);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static FILE *create_tempfile(struct dload_payload *payload, const char *localpath)
|
||||
{
|
||||
int fd;
|
||||
FILE *fp;
|
||||
char *randpath;
|
||||
size_t len;
|
||||
|
||||
/* create a random filename, which is opened with O_EXCL */
|
||||
len = strlen(localpath) + 14 + 1;
|
||||
MALLOC(randpath, len, RET_ERR(payload->handle, ALPM_ERR_MEMORY, NULL));
|
||||
snprintf(randpath, len, "%salpmtmp.XXXXXX", localpath);
|
||||
if((fd = mkstemp(randpath)) == -1 ||
|
||||
fchmod(fd, ~(_getumask()) & 0666) ||
|
||||
!(fp = fdopen(fd, payload->tempfile_openmode))) {
|
||||
unlink(randpath);
|
||||
close(fd);
|
||||
_alpm_log(payload->handle, ALPM_LOG_ERROR,
|
||||
_("failed to create temporary file for download\n"));
|
||||
free(randpath);
|
||||
return NULL;
|
||||
}
|
||||
/* fp now points to our alpmtmp.XXXXXX */
|
||||
free(payload->tempfile_name);
|
||||
payload->tempfile_name = randpath;
|
||||
free(payload->remote_name);
|
||||
STRDUP(payload->remote_name, strrchr(randpath, '/') + 1,
|
||||
fclose(fp); RET_ERR(payload->handle, ALPM_ERR_MEMORY, NULL));
|
||||
|
||||
return fp;
|
||||
}
|
||||
|
||||
|
||||
#ifdef HAVE_LIBCURL
|
||||
|
||||
@@ -196,7 +55,7 @@ static FILE *create_tempfile(struct dload_payload *payload, const char *localpat
|
||||
#define HOSTNAME_SIZE 256
|
||||
|
||||
static int curl_add_payload(alpm_handle_t *handle, CURLM *curlm,
|
||||
struct dload_payload *payload);
|
||||
struct dload_payload *payload, const char *localpath);
|
||||
static int curl_gethost(const char *url, char *buffer, size_t buf_len);
|
||||
|
||||
/* number of "soft" errors required to blacklist a server, set to 0 to disable
|
||||
@@ -314,6 +173,29 @@ static const char *payload_next_server(struct dload_payload *payload)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static const char *get_filename(const char *url)
|
||||
{
|
||||
char *filename = strrchr(url, '/');
|
||||
if(filename != NULL) {
|
||||
return filename + 1;
|
||||
}
|
||||
|
||||
/* no slash found, it's a filename */
|
||||
return url;
|
||||
}
|
||||
|
||||
static char *get_fullpath(const char *path, const char *filename,
|
||||
const char *suffix)
|
||||
{
|
||||
char *filepath;
|
||||
/* len = localpath len + filename len + suffix len + null */
|
||||
size_t len = strlen(path) + strlen(filename) + strlen(suffix) + 1;
|
||||
MALLOC(filepath, len, return NULL);
|
||||
snprintf(filepath, len, "%s%s%s", path, filename, suffix);
|
||||
|
||||
return filepath;
|
||||
}
|
||||
|
||||
enum {
|
||||
ABORT_OVER_MAXFILESIZE = 1,
|
||||
};
|
||||
@@ -424,12 +306,45 @@ static int utimes_long(const char *path, long seconds)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* prefix to avoid possible future clash with getumask(3) */
|
||||
static mode_t _getumask(void)
|
||||
{
|
||||
mode_t mask = umask(0);
|
||||
umask(mask);
|
||||
return mask;
|
||||
}
|
||||
|
||||
static size_t dload_parseheader_cb(void *ptr, size_t size, size_t nmemb, void *user)
|
||||
{
|
||||
size_t realsize = size * nmemb;
|
||||
const char *fptr, *endptr = NULL;
|
||||
const char * const cd_header = "Content-Disposition:";
|
||||
const char * const fn_key = "filename=";
|
||||
struct dload_payload *payload = (struct dload_payload *)user;
|
||||
long respcode;
|
||||
(void) ptr;
|
||||
|
||||
if(_alpm_raw_ncmp(cd_header, ptr, strlen(cd_header)) == 0) {
|
||||
if((fptr = strstr(ptr, fn_key))) {
|
||||
fptr += strlen(fn_key);
|
||||
|
||||
/* find the end of the field, which is either a semi-colon, or the end of
|
||||
* the data. As per curl_easy_setopt(3), we cannot count on headers being
|
||||
* null terminated, so we look for the closing \r\n */
|
||||
endptr = fptr + strcspn(fptr, ";\r\n") - 1;
|
||||
|
||||
/* remove quotes */
|
||||
if(*fptr == '"' && *endptr == '"') {
|
||||
fptr++;
|
||||
endptr--;
|
||||
}
|
||||
|
||||
/* avoid information leakage with badly formed headers */
|
||||
if(endptr > fptr) {
|
||||
STRNDUP(payload->content_disp_name, fptr, endptr - fptr + 1,
|
||||
RET_ERR(payload->handle, ALPM_ERR_MEMORY, realsize));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
curl_easy_getinfo(payload->curl, CURLINFO_RESPONSE_CODE, &respcode);
|
||||
if(payload->respcode != respcode) {
|
||||
@@ -503,6 +418,37 @@ static void curl_set_handle_opts(CURL *curl, struct dload_payload *payload)
|
||||
}
|
||||
}
|
||||
|
||||
static FILE *create_tempfile(struct dload_payload *payload, const char *localpath)
|
||||
{
|
||||
int fd;
|
||||
FILE *fp;
|
||||
char *randpath;
|
||||
size_t len;
|
||||
|
||||
/* create a random filename, which is opened with O_EXCL */
|
||||
len = strlen(localpath) + 14 + 1;
|
||||
MALLOC(randpath, len, RET_ERR(payload->handle, ALPM_ERR_MEMORY, NULL));
|
||||
snprintf(randpath, len, "%salpmtmp.XXXXXX", localpath);
|
||||
if((fd = mkstemp(randpath)) == -1 ||
|
||||
fchmod(fd, ~(_getumask()) & 0666) ||
|
||||
!(fp = fdopen(fd, payload->tempfile_openmode))) {
|
||||
unlink(randpath);
|
||||
close(fd);
|
||||
_alpm_log(payload->handle, ALPM_LOG_ERROR,
|
||||
_("failed to create temporary file for download\n"));
|
||||
free(randpath);
|
||||
return NULL;
|
||||
}
|
||||
/* fp now points to our alpmtmp.XXXXXX */
|
||||
free(payload->tempfile_name);
|
||||
payload->tempfile_name = randpath;
|
||||
free(payload->remote_name);
|
||||
STRDUP(payload->remote_name, strrchr(randpath, '/') + 1,
|
||||
fclose(fp); RET_ERR(payload->handle, ALPM_ERR_MEMORY, NULL));
|
||||
|
||||
return fp;
|
||||
}
|
||||
|
||||
/* Return 0 if retry was successful, -1 otherwise */
|
||||
static int curl_retry_next_server(CURLM *curlm, CURL *curl, struct dload_payload *payload)
|
||||
{
|
||||
@@ -566,7 +512,7 @@ static int curl_retry_next_server(CURLM *curlm, CURL *curl, struct dload_payload
|
||||
* Returns -2 if an error happened for an optional file
|
||||
*/
|
||||
static int curl_check_finished_download(alpm_handle_t *handle, CURLM *curlm, CURLMsg *msg,
|
||||
int *active_downloads_num)
|
||||
const char *localpath, int *active_downloads_num)
|
||||
{
|
||||
struct dload_payload *payload = NULL;
|
||||
CURL *curl = msg->easy_handle;
|
||||
@@ -627,7 +573,6 @@ static int curl_check_finished_download(alpm_handle_t *handle, CURLM *curlm, CUR
|
||||
case CURLE_ABORTED_BY_CALLBACK:
|
||||
/* handle the interrupt accordingly */
|
||||
if(dload_interrupted == ABORT_OVER_MAXFILESIZE) {
|
||||
curlerr = CURLE_FILESIZE_EXCEEDED;
|
||||
payload->unlink_on_fail = 1;
|
||||
handle->pm_errno = ALPM_ERR_LIBCURL;
|
||||
_alpm_log(handle, ALPM_LOG_ERROR,
|
||||
@@ -680,6 +625,31 @@ static int curl_check_finished_download(alpm_handle_t *handle, CURLM *curlm, CUR
|
||||
curl_easy_getinfo(curl, CURLINFO_CONDITION_UNMET, &timecond);
|
||||
curl_easy_getinfo(curl, CURLINFO_EFFECTIVE_URL, &effective_url);
|
||||
|
||||
if(payload->trust_remote_name) {
|
||||
if(payload->content_disp_name) {
|
||||
/* content-disposition header has a better name for our file */
|
||||
free(payload->destfile_name);
|
||||
payload->destfile_name = get_fullpath(localpath,
|
||||
get_filename(payload->content_disp_name), "");
|
||||
} else {
|
||||
const char *effective_filename = strrchr(effective_url, '/');
|
||||
|
||||
if(effective_filename && strlen(effective_filename) > 2) {
|
||||
effective_filename++;
|
||||
|
||||
/* if destfile was never set, we wrote to a tempfile. even if destfile is
|
||||
* set, we may have followed some redirects and the effective url may
|
||||
* have a better suggestion as to what to name our file. in either case,
|
||||
* refactor destfile to this newly derived name. */
|
||||
if(!payload->destfile_name || strcmp(effective_filename,
|
||||
strrchr(payload->destfile_name, '/') + 1) != 0) {
|
||||
free(payload->destfile_name);
|
||||
payload->destfile_name = get_fullpath(localpath, effective_filename, "");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Let's check if client requested downloading accompanion *.sig file */
|
||||
if(!payload->signature && payload->download_signature && curlerr == CURLE_OK && payload->respcode < 400) {
|
||||
struct dload_payload *sig = NULL;
|
||||
@@ -711,23 +681,22 @@ static int curl_check_finished_download(alpm_handle_t *handle, CURLM *curlm, CUR
|
||||
MALLOC(sig->fileurl, len, FREE(sig); GOTO_ERR(handle, ALPM_ERR_MEMORY, cleanup));
|
||||
snprintf(sig->fileurl, len, "%s.sig", url);
|
||||
|
||||
int remote_name_len = strlen(payload->remote_name) + 5;
|
||||
MALLOC(sig->remote_name, remote_name_len, _alpm_dload_payload_reset(sig);
|
||||
FREE(sig); GOTO_ERR(handle, ALPM_ERR_MEMORY, cleanup));
|
||||
snprintf(sig->remote_name, remote_name_len, "%s.sig", payload->remote_name);
|
||||
if(payload->trust_remote_name) {
|
||||
/* In this case server might provide a new name for the main payload.
|
||||
* Choose *.sig filename based on this new name.
|
||||
*/
|
||||
const char *final_file = get_filename(realname);
|
||||
int remote_name_len = strlen(final_file) + 5;
|
||||
MALLOC(sig->remote_name, remote_name_len, FREE(sig->fileurl); FREE(sig); GOTO_ERR(handle, ALPM_ERR_MEMORY, cleanup));
|
||||
snprintf(sig->remote_name, remote_name_len, "%s.sig", final_file);
|
||||
}
|
||||
|
||||
/* force the filename to be realname + ".sig" */
|
||||
int destfile_name_len = strlen(realname) + 5;
|
||||
MALLOC(sig->destfile_name, destfile_name_len, _alpm_dload_payload_reset(sig);
|
||||
FREE(sig); GOTO_ERR(handle, ALPM_ERR_MEMORY, cleanup));
|
||||
MALLOC(sig->destfile_name, destfile_name_len, FREE(sig->remote_name);
|
||||
FREE(sig->fileurl); FREE(sig); GOTO_ERR(handle, ALPM_ERR_MEMORY, cleanup));
|
||||
snprintf(sig->destfile_name, destfile_name_len, "%s.sig", realname);
|
||||
|
||||
int tempfile_name_len = strlen(realname) + 10;
|
||||
MALLOC(sig->tempfile_name, tempfile_name_len, _alpm_dload_payload_reset(sig);
|
||||
FREE(sig); GOTO_ERR(handle, ALPM_ERR_MEMORY, cleanup));
|
||||
snprintf(sig->tempfile_name, tempfile_name_len, "%s.sig.part", realname);
|
||||
|
||||
|
||||
sig->signature = 1;
|
||||
sig->handle = handle;
|
||||
sig->force = payload->force;
|
||||
@@ -736,7 +705,7 @@ static int curl_check_finished_download(alpm_handle_t *handle, CURLM *curlm, CUR
|
||||
/* set hard upper limit of 16KiB */
|
||||
sig->max_size = 16 * 1024;
|
||||
|
||||
curl_add_payload(handle, curlm, sig);
|
||||
curl_add_payload(handle, curlm, sig, localpath);
|
||||
(*active_downloads_num)++;
|
||||
}
|
||||
|
||||
@@ -775,7 +744,7 @@ cleanup:
|
||||
}
|
||||
|
||||
if(ret == 0) {
|
||||
if(payload->destfile_name && handle->sandboxuser == NULL) {
|
||||
if(payload->destfile_name) {
|
||||
if(rename(payload->tempfile_name, payload->destfile_name)) {
|
||||
_alpm_log(handle, ALPM_LOG_ERROR, _("could not rename %s to %s (%s)\n"),
|
||||
payload->tempfile_name, payload->destfile_name, strerror(errno));
|
||||
@@ -819,7 +788,7 @@ cleanup:
|
||||
* Returns -1 if am error happened while starting a new download
|
||||
*/
|
||||
static int curl_add_payload(alpm_handle_t *handle, CURLM *curlm,
|
||||
struct dload_payload *payload)
|
||||
struct dload_payload *payload, const char *localpath)
|
||||
{
|
||||
size_t len;
|
||||
CURL *curl = NULL;
|
||||
@@ -845,11 +814,35 @@ static int curl_add_payload(alpm_handle_t *handle, CURLM *curlm,
|
||||
}
|
||||
|
||||
payload->tempfile_openmode = "wb";
|
||||
if(!payload->remote_name) {
|
||||
STRDUP(payload->remote_name, get_filename(payload->fileurl),
|
||||
GOTO_ERR(handle, ALPM_ERR_MEMORY, cleanup));
|
||||
}
|
||||
if(curl_gethost(payload->fileurl, hostname, sizeof(hostname)) != 0) {
|
||||
_alpm_log(handle, ALPM_LOG_ERROR, _("url '%s' is invalid\n"), payload->fileurl);
|
||||
GOTO_ERR(handle, ALPM_ERR_SERVER_BAD_URL, cleanup);
|
||||
}
|
||||
|
||||
if(!payload->random_partfile && payload->remote_name && strlen(payload->remote_name) > 0) {
|
||||
if(!payload->destfile_name) {
|
||||
payload->destfile_name = get_fullpath(localpath, payload->remote_name, "");
|
||||
}
|
||||
payload->tempfile_name = get_fullpath(localpath, payload->remote_name, ".part");
|
||||
if(!payload->destfile_name || !payload->tempfile_name) {
|
||||
goto cleanup;
|
||||
}
|
||||
} else {
|
||||
/* We want a random filename or the URL does not contain a filename, so download to a
|
||||
* temporary location. We can not support resuming this kind of download; any partial
|
||||
* transfers will be destroyed */
|
||||
payload->unlink_on_fail = 1;
|
||||
|
||||
payload->localf = create_tempfile(payload, localpath);
|
||||
if(payload->localf == NULL) {
|
||||
goto cleanup;
|
||||
}
|
||||
}
|
||||
|
||||
curl_set_handle_opts(curl, payload);
|
||||
|
||||
if(payload->max_size == payload->initial_size && payload->max_size != 0) {
|
||||
@@ -907,7 +900,8 @@ static int compare_dload_payload_sizes(const void *left_ptr, const void *right_p
|
||||
* Returns 1 if no files were downloaded and all errors were non-fatal
|
||||
*/
|
||||
static int curl_download_internal(alpm_handle_t *handle,
|
||||
alpm_list_t *payloads /* struct dload_payload */)
|
||||
alpm_list_t *payloads /* struct dload_payload */,
|
||||
const char *localpath)
|
||||
{
|
||||
int active_downloads_num = 0;
|
||||
int err = 0;
|
||||
@@ -925,7 +919,7 @@ static int curl_download_internal(alpm_handle_t *handle,
|
||||
for(; active_downloads_num < max_streams && payloads; active_downloads_num++) {
|
||||
struct dload_payload *payload = payloads->data;
|
||||
|
||||
if(curl_add_payload(handle, curlm, payload) == 0) {
|
||||
if(curl_add_payload(handle, curlm, payload, localpath) == 0) {
|
||||
payloads = payloads->next;
|
||||
} else {
|
||||
/* The payload failed to start. Do not start any new downloads.
|
||||
@@ -956,7 +950,7 @@ static int curl_download_internal(alpm_handle_t *handle,
|
||||
}
|
||||
if(msg->msg == CURLMSG_DONE) {
|
||||
int ret = curl_check_finished_download(handle, curlm, msg,
|
||||
&active_downloads_num);
|
||||
localpath, &active_downloads_num);
|
||||
if(ret == -1) {
|
||||
/* if current payload failed to download then stop adding new payloads but wait for the
|
||||
* current ones
|
||||
@@ -972,160 +966,9 @@ static int curl_download_internal(alpm_handle_t *handle,
|
||||
}
|
||||
}
|
||||
|
||||
_alpm_log(handle, ALPM_LOG_DEBUG, "curl_download_internal return code is %d\n", err);
|
||||
return err ? -1 : updated ? 0 : 1;
|
||||
}
|
||||
|
||||
/* Download the requested files by launching a process inside a sandbox.
|
||||
* Returns -1 if an error happened for a required file
|
||||
* Returns 0 if a payload was actually downloaded
|
||||
* Returns 1 if no files were downloaded and all errors were non-fatal
|
||||
*/
|
||||
static int curl_download_internal_sandboxed(alpm_handle_t *handle,
|
||||
alpm_list_t *payloads /* struct dload_payload */,
|
||||
const char *localpath)
|
||||
{
|
||||
int pid, err = 0, ret = -1, callbacks_fd[2];
|
||||
sigset_t oldblock;
|
||||
struct sigaction sa_ign, oldint, oldquit;
|
||||
_alpm_sandbox_callback_context callbacks_ctx;
|
||||
|
||||
sigemptyset(&sa_ign.sa_mask);
|
||||
sa_ign.sa_handler = SIG_IGN;
|
||||
sa_ign.sa_flags=0;
|
||||
|
||||
if(pipe(callbacks_fd) != 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
sigaction(SIGINT, &sa_ign, &oldint);
|
||||
sigaction(SIGQUIT, &sa_ign, &oldquit);
|
||||
sigaddset(&sa_ign.sa_mask, SIGCHLD);
|
||||
sigprocmask(SIG_BLOCK, &sa_ign.sa_mask, &oldblock);
|
||||
|
||||
pid = fork();
|
||||
if(pid == -1) {
|
||||
/* fork failed, make sure errno is preserved after cleanup */
|
||||
err = errno;
|
||||
}
|
||||
|
||||
/* child */
|
||||
if(pid == 0) {
|
||||
close(callbacks_fd[0]);
|
||||
fcntl(callbacks_fd[1], F_SETFD, FD_CLOEXEC);
|
||||
callbacks_ctx.callback_pipe = callbacks_fd[1];
|
||||
alpm_option_set_logcb(handle, _alpm_sandbox_cb_log, &callbacks_ctx);
|
||||
alpm_option_set_dlcb(handle, _alpm_sandbox_cb_dl, &callbacks_ctx);
|
||||
alpm_option_set_fetchcb(handle, NULL, NULL);
|
||||
alpm_option_set_eventcb(handle, NULL, NULL);
|
||||
alpm_option_set_questioncb(handle, NULL, NULL);
|
||||
alpm_option_set_progresscb(handle, NULL, NULL);
|
||||
|
||||
/* restore default signal handling in the child */
|
||||
_alpm_reset_signals();
|
||||
|
||||
/* cwd to the download directory */
|
||||
ret = chdir(localpath);
|
||||
if(ret != 0) {
|
||||
handle->pm_errno = errno;
|
||||
_alpm_log(handle, ALPM_LOG_ERROR, _("could not chdir to download directory %s\n"), localpath);
|
||||
ret = -1;
|
||||
} else {
|
||||
ret = alpm_sandbox_setup_child(handle->sandboxuser);
|
||||
if (ret != 0) {
|
||||
_alpm_log(handle, ALPM_LOG_ERROR, _("switching to sandbox user '%s' failed!\n"), handle->sandboxuser);
|
||||
_Exit(ret | 128);
|
||||
}
|
||||
|
||||
ret = curl_download_internal(handle, payloads);
|
||||
}
|
||||
|
||||
/* pass the result back to the parent */
|
||||
if(ret == 0) {
|
||||
/* a payload was actually downloaded */
|
||||
_Exit(0);
|
||||
}
|
||||
else if(ret == 1) {
|
||||
/* no files were downloaded and all errors were non-fatal */
|
||||
_Exit(handle->pm_errno);
|
||||
}
|
||||
else {
|
||||
/* an error happened for a required file */
|
||||
_Exit(handle->pm_errno | 128);
|
||||
}
|
||||
}
|
||||
|
||||
/* parent */
|
||||
close(callbacks_fd[1]);
|
||||
|
||||
if(pid != -1) {
|
||||
bool had_error = false;
|
||||
while(true) {
|
||||
_alpm_sandbox_callback_t callback_type;
|
||||
ssize_t got = read(callbacks_fd[0], &callback_type, sizeof(callback_type));
|
||||
if(got < 0 || (size_t)got != sizeof(callback_type)) {
|
||||
had_error = true;
|
||||
break;
|
||||
}
|
||||
|
||||
if(callback_type == ALPM_SANDBOX_CB_DOWNLOAD) {
|
||||
if(!_alpm_sandbox_process_cb_download(handle, callbacks_fd[0])) {
|
||||
had_error = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if(callback_type == ALPM_SANDBOX_CB_LOG) {
|
||||
if(!_alpm_sandbox_process_cb_log(handle, callbacks_fd[0])) {
|
||||
had_error = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if(had_error) {
|
||||
kill(pid, SIGTERM);
|
||||
}
|
||||
|
||||
int wret;
|
||||
while((wret = waitpid(pid, &ret, 0)) == -1 && errno == EINTR);
|
||||
if(wret > 0) {
|
||||
if(!WIFEXITED(ret)) {
|
||||
/* the child did not terminate normally */
|
||||
ret = -1;
|
||||
}
|
||||
else {
|
||||
ret = WEXITSTATUS(ret);
|
||||
if(ret != 0) {
|
||||
if(ret & 128) {
|
||||
/* an error happened for a required file, or unexpected exit status */
|
||||
handle->pm_errno = ret & ~128;
|
||||
ret = -1;
|
||||
}
|
||||
else {
|
||||
handle->pm_errno = ret;
|
||||
ret = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* waitpid failed */
|
||||
err = errno;
|
||||
}
|
||||
}
|
||||
|
||||
close(callbacks_fd[0]);
|
||||
|
||||
sigaction(SIGINT, &oldint, NULL);
|
||||
sigaction(SIGQUIT, &oldquit, NULL);
|
||||
sigprocmask(SIG_SETMASK, &oldblock, NULL);
|
||||
|
||||
if(err) {
|
||||
errno = err;
|
||||
ret = -1;
|
||||
}
|
||||
return ret;
|
||||
int ret = err ? -1 : updated ? 0 : 1;
|
||||
_alpm_log(handle, ALPM_LOG_DEBUG, "curl_download_internal return code is %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1157,26 +1000,7 @@ int _alpm_download(alpm_handle_t *handle,
|
||||
{
|
||||
if(handle->fetchcb == NULL) {
|
||||
#ifdef HAVE_LIBCURL
|
||||
if(handle->sandboxuser) {
|
||||
int ret = 0;
|
||||
alpm_list_t *i;
|
||||
|
||||
for(i = payloads; i; i = i->next) {
|
||||
struct dload_payload *p = i->data;
|
||||
intialize_download_file(p);
|
||||
}
|
||||
|
||||
ret = curl_download_internal_sandboxed(handle, payloads, localpath);
|
||||
|
||||
for(i = payloads; i; i = i->next) {
|
||||
struct dload_payload *p = i->data;
|
||||
finalize_download_file(p);
|
||||
}
|
||||
|
||||
return ret;
|
||||
} else {
|
||||
return curl_download_internal(handle, payloads);
|
||||
}
|
||||
return curl_download_internal(handle, payloads, localpath);
|
||||
#else
|
||||
RET_ERR(handle, ALPM_ERR_EXTERNAL_DOWNLOAD, -1);
|
||||
#endif
|
||||
@@ -1255,34 +1079,16 @@ int SYMEXPORT alpm_fetch_pkgurl(alpm_handle_t *handle, const alpm_list_t *urls,
|
||||
CALLOC(payload, 1, sizeof(*payload), GOTO_ERR(handle, ALPM_ERR_MEMORY, err));
|
||||
STRDUP(payload->fileurl, url, FREE(payload); GOTO_ERR(handle, ALPM_ERR_MEMORY, err));
|
||||
|
||||
STRDUP(payload->remote_name, get_filename(payload->fileurl),
|
||||
GOTO_ERR(handle, ALPM_ERR_MEMORY, err));
|
||||
|
||||
c = strrchr(url, '/');
|
||||
if(payload->remote_name && strlen(payload->remote_name) > 0 && strstr(c, ".pkg")) {
|
||||
if(strstr(c, ".pkg")) {
|
||||
/* we probably have a usable package filename to download to */
|
||||
payload->destfile_name = _alpm_get_fullpath(cachedir, payload->remote_name, "");
|
||||
payload->tempfile_name = _alpm_get_fullpath(cachedir, payload->remote_name, ".part");
|
||||
payload->allow_resume = 1;
|
||||
|
||||
if(!payload->destfile_name || !payload->tempfile_name) {
|
||||
goto err;
|
||||
}
|
||||
|
||||
} else {
|
||||
/* The URL does not contain a filename, so download to a temporary location.
|
||||
* We can not support resuming this kind of download; any partial transfers
|
||||
* will be destroyed */
|
||||
payload->unlink_on_fail = 1;
|
||||
|
||||
payload->tempfile_openmode = "wb";
|
||||
payload->localf = create_tempfile(payload, cachedir);
|
||||
if(payload->localf == NULL) {
|
||||
goto err;
|
||||
}
|
||||
payload->random_partfile = 1;
|
||||
}
|
||||
|
||||
payload->handle = handle;
|
||||
payload->trust_remote_name = 1;
|
||||
payload->download_signature = (handle->siglevel & ALPM_SIG_PACKAGE);
|
||||
payload->signature_optional = (handle->siglevel & ALPM_SIG_PACKAGE_OPTIONAL);
|
||||
payloads = alpm_list_add(payloads, payload);
|
||||
@@ -1343,6 +1149,7 @@ void _alpm_dload_payload_reset(struct dload_payload *payload)
|
||||
FREE(payload->remote_name);
|
||||
FREE(payload->tempfile_name);
|
||||
FREE(payload->destfile_name);
|
||||
FREE(payload->content_disp_name);
|
||||
FREE(payload->fileurl);
|
||||
FREE(payload->filepath);
|
||||
*payload = (struct dload_payload){0};
|
||||
|
||||
@@ -26,12 +26,10 @@
|
||||
struct dload_payload {
|
||||
alpm_handle_t *handle;
|
||||
const char *tempfile_openmode;
|
||||
/* name of the remote file */
|
||||
char *remote_name;
|
||||
/* temporary file name, to which the payload is downloaded */
|
||||
char *tempfile_name;
|
||||
/* name to which the downloaded file will be renamed */
|
||||
char *destfile_name;
|
||||
char *content_disp_name;
|
||||
/* client has to provide either
|
||||
* 1) fileurl - full URL to the file
|
||||
* 2) pair of (servers, filepath), in this case ALPM iterates over the
|
||||
@@ -47,17 +45,19 @@ struct dload_payload {
|
||||
off_t prevprogress;
|
||||
int force;
|
||||
int allow_resume;
|
||||
int random_partfile;
|
||||
int errors_ok;
|
||||
int unlink_on_fail;
|
||||
int trust_remote_name;
|
||||
int download_signature; /* specifies if an accompanion *.sig file need to be downloaded*/
|
||||
int signature_optional; /* *.sig file is optional */
|
||||
#ifdef HAVE_LIBCURL
|
||||
CURL *curl;
|
||||
char error_buffer[CURL_ERROR_SIZE];
|
||||
FILE *localf; /* temp download file */
|
||||
int signature; /* specifies if this payload is for a signature file */
|
||||
int request_errors_ok; /* per-request errors-ok */
|
||||
#endif
|
||||
FILE *localf; /* temp download file */
|
||||
};
|
||||
|
||||
void _alpm_dload_payload_reset(struct dload_payload *payload);
|
||||
|
||||
@@ -101,7 +101,6 @@ void _alpm_handle_free(alpm_handle_t *handle)
|
||||
FREE(handle->lockfile);
|
||||
FREELIST(handle->architectures);
|
||||
FREE(handle->gpgdir);
|
||||
FREE(handle->sandboxuser);
|
||||
FREELIST(handle->noupgrade);
|
||||
FREELIST(handle->noextract);
|
||||
FREELIST(handle->ignorepkg);
|
||||
@@ -293,12 +292,6 @@ const char SYMEXPORT *alpm_option_get_gpgdir(alpm_handle_t *handle)
|
||||
return handle->gpgdir;
|
||||
}
|
||||
|
||||
const char SYMEXPORT *alpm_option_get_sandboxuser(alpm_handle_t *handle)
|
||||
{
|
||||
CHECK_HANDLE(handle, return NULL);
|
||||
return handle->sandboxuser;
|
||||
}
|
||||
|
||||
int SYMEXPORT alpm_option_get_usesyslog(alpm_handle_t *handle)
|
||||
{
|
||||
CHECK_HANDLE(handle, return -1);
|
||||
@@ -602,19 +595,6 @@ int SYMEXPORT alpm_option_set_gpgdir(alpm_handle_t *handle, const char *gpgdir)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int SYMEXPORT alpm_option_set_sandboxuser(alpm_handle_t *handle, const char *sandboxuser)
|
||||
{
|
||||
CHECK_HANDLE(handle, return -1);
|
||||
if(handle->sandboxuser) {
|
||||
FREE(handle->sandboxuser);
|
||||
}
|
||||
|
||||
STRDUP(handle->sandboxuser, sandboxuser, RET_ERR(handle, ALPM_ERR_MEMORY, -1));
|
||||
|
||||
_alpm_log(handle, ALPM_LOG_DEBUG, "option 'sandboxuser' = %s\n", handle->sandboxuser);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int SYMEXPORT alpm_option_set_usesyslog(alpm_handle_t *handle, int usesyslog)
|
||||
{
|
||||
CHECK_HANDLE(handle, return -1);
|
||||
|
||||
@@ -91,7 +91,6 @@ struct _alpm_handle_t {
|
||||
char *logfile; /* Name of the log file */
|
||||
char *lockfile; /* Name of the lock file */
|
||||
char *gpgdir; /* Directory where GnuPG files are stored */
|
||||
char *sandboxuser; /* User to switch to for sensitive operations */
|
||||
alpm_list_t *cachedirs; /* Paths to pacman cache directories */
|
||||
alpm_list_t *hookdirs; /* Paths to hook directories */
|
||||
alpm_list_t *overwrite_files; /* Paths that may be overwritten */
|
||||
|
||||
@@ -24,7 +24,6 @@ libalpm_sources = files('''
|
||||
pkghash.h pkghash.c
|
||||
rawstr.c
|
||||
remove.h remove.c
|
||||
sandbox.h sandbox.c
|
||||
signing.c signing.h
|
||||
sync.h sync.c
|
||||
trans.h trans.c
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <limits.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/types.h>
|
||||
@@ -844,3 +845,58 @@ int SYMEXPORT alpm_pkg_should_ignore(alpm_handle_t *handle, alpm_pkg_t *pkg)
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* check that package metadata meets our requirements */
|
||||
int _alpm_pkg_check_meta(alpm_pkg_t *pkg)
|
||||
{
|
||||
char *c;
|
||||
int error_found = 0;
|
||||
|
||||
#define EPKGMETA(error) do { \
|
||||
error_found = -1; \
|
||||
_alpm_log(pkg->handle, ALPM_LOG_ERROR, error, pkg->name, pkg->version); \
|
||||
} while(0)
|
||||
|
||||
/* sanity check */
|
||||
if(pkg->handle == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* immediate bail if package doesn't have name or version */
|
||||
if(pkg->name == NULL || pkg->name[0] == '\0'
|
||||
|| pkg->version == NULL || pkg->version[0] == '\0') {
|
||||
_alpm_log(pkg->handle, ALPM_LOG_ERROR,
|
||||
_("invalid package metadata (name or version missing)"));
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(pkg->name[0] == '-' || pkg->name[0] == '.') {
|
||||
EPKGMETA(_("invalid metadata for package %s-%s "
|
||||
"(package name cannot start with '.' or '-')\n"));
|
||||
}
|
||||
if(_alpm_fnmatch(pkg->name, "[![:alnum:]+_.@-]") == 0) {
|
||||
EPKGMETA(_("invalid metadata for package %s-%s "
|
||||
"(package name contains invalid characters)\n"));
|
||||
}
|
||||
|
||||
/* multiple '-' in pkgver can cause local db entries for different packages
|
||||
* to overlap (e.g. foo-1=2-3 and foo=1-2-3 both give foo-1-2-3) */
|
||||
if((c = strchr(pkg->version, '-')) && (strchr(c + 1, '-'))) {
|
||||
EPKGMETA(_("invalid metadata for package %s-%s "
|
||||
"(package version contains invalid characters)\n"));
|
||||
}
|
||||
if(strchr(pkg->version, '/')) {
|
||||
EPKGMETA(_("invalid metadata for package %s-%s "
|
||||
"(package version contains invalid characters)\n"));
|
||||
}
|
||||
|
||||
/* local db entry is <pkgname>-<pkgver> */
|
||||
if(strlen(pkg->name) + strlen(pkg->version) + 1 > NAME_MAX) {
|
||||
EPKGMETA(_("invalid metadata for package %s-%s "
|
||||
"(package name and version too long)\n"));
|
||||
}
|
||||
|
||||
#undef EPKGMETA
|
||||
|
||||
return error_found;
|
||||
}
|
||||
|
||||
@@ -165,4 +165,6 @@ int _alpm_pkg_compare_versions(alpm_pkg_t *local_pkg, alpm_pkg_t *pkg);
|
||||
alpm_pkg_xdata_t *_alpm_pkg_parse_xdata(const char *string);
|
||||
void _alpm_pkg_xdata_free(alpm_pkg_xdata_t *pd);
|
||||
|
||||
int _alpm_pkg_check_meta(alpm_pkg_t *pkg);
|
||||
|
||||
#endif /* ALPM_PACKAGE_H */
|
||||
|
||||
@@ -1,224 +0,0 @@
|
||||
/*
|
||||
* sandbox.c
|
||||
*
|
||||
* Copyright (c) 2021-2022 Pacman Development Team <pacman-dev@lists.archlinux.org>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
#include <grp.h>
|
||||
#include <pwd.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "alpm.h"
|
||||
#include "log.h"
|
||||
#include "sandbox.h"
|
||||
#include "util.h"
|
||||
|
||||
int SYMEXPORT alpm_sandbox_setup_child(const char* sandboxuser)
|
||||
{
|
||||
struct passwd const *pw = NULL;
|
||||
|
||||
ASSERT(sandboxuser != NULL, return EINVAL);
|
||||
ASSERT(getuid() == 0, return EPERM);
|
||||
ASSERT((pw = getpwnam(sandboxuser)), return errno);
|
||||
ASSERT(setgid(pw->pw_gid) == 0, return errno);
|
||||
ASSERT(setgroups(0, NULL) == 0, return errno);
|
||||
ASSERT(setuid(pw->pw_uid) == 0, return errno);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int should_retry(int errnum)
|
||||
{
|
||||
return errnum == EINTR;
|
||||
}
|
||||
|
||||
static int read_from_pipe(int fd, void *buf, size_t count)
|
||||
{
|
||||
size_t nread = 0;
|
||||
|
||||
ASSERT(count > 0, return -1);
|
||||
|
||||
while(nread < count) {
|
||||
ssize_t r = read(fd, (char *)buf + nread, count-nread);
|
||||
if(r < 0) {
|
||||
if(!should_retry(errno)) {
|
||||
return -1;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if(r == 0) {
|
||||
/* we hit EOF unexpectedly - bail */
|
||||
return -1;
|
||||
}
|
||||
nread += r;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int write_to_pipe(int fd, const void *buf, size_t count)
|
||||
{
|
||||
size_t nwrite = 0;
|
||||
|
||||
ASSERT(count > 0, return -1);
|
||||
|
||||
while(nwrite < count) {
|
||||
ssize_t r = write(fd, (char *)buf + nwrite, count-nwrite);
|
||||
if(r < 0) {
|
||||
if(!should_retry(errno)) {
|
||||
return -1;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
nwrite += r;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void _alpm_sandbox_cb_log(void *ctx, alpm_loglevel_t level, const char *fmt, va_list args)
|
||||
{
|
||||
_alpm_sandbox_callback_t type = ALPM_SANDBOX_CB_LOG;
|
||||
_alpm_sandbox_callback_context *context = ctx;
|
||||
char *string = NULL;
|
||||
int string_size = 0;
|
||||
|
||||
if(!context || context->callback_pipe == -1) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* compute the required size, as allowed by POSIX.1-2001 and C99 */
|
||||
/* first we need to copy the va_list as it will be consumed by the first call */
|
||||
va_list copy;
|
||||
va_copy(copy, args);
|
||||
string_size = vsnprintf(NULL, 0, fmt, copy);
|
||||
if(string_size <= 0) {
|
||||
va_end(copy);
|
||||
return;
|
||||
}
|
||||
MALLOC(string, string_size + 1, return);
|
||||
string_size = vsnprintf(string, string_size + 1, fmt, args);
|
||||
if(string_size > 0) {
|
||||
write_to_pipe(context->callback_pipe, &type, sizeof(type));
|
||||
write_to_pipe(context->callback_pipe, &level, sizeof(level));
|
||||
write_to_pipe(context->callback_pipe, &string_size, sizeof(string_size));
|
||||
write_to_pipe(context->callback_pipe, string, string_size);
|
||||
}
|
||||
va_end(copy);
|
||||
FREE(string);
|
||||
}
|
||||
|
||||
void _alpm_sandbox_cb_dl(void *ctx, const char *filename, alpm_download_event_type_t event, void *data)
|
||||
{
|
||||
_alpm_sandbox_callback_t type = ALPM_SANDBOX_CB_DOWNLOAD;
|
||||
_alpm_sandbox_callback_context *context = ctx;
|
||||
size_t filename_len;
|
||||
|
||||
if(!context || context->callback_pipe == -1) {
|
||||
return;
|
||||
}
|
||||
|
||||
ASSERT(filename != NULL, return);
|
||||
ASSERT(event == ALPM_DOWNLOAD_INIT || event == ALPM_DOWNLOAD_PROGRESS || event == ALPM_DOWNLOAD_RETRY || event == ALPM_DOWNLOAD_COMPLETED, return);
|
||||
|
||||
filename_len = strlen(filename);
|
||||
|
||||
write_to_pipe(context->callback_pipe, &type, sizeof(type));
|
||||
write_to_pipe(context->callback_pipe, &event, sizeof(event));
|
||||
switch(event) {
|
||||
case ALPM_DOWNLOAD_INIT:
|
||||
write_to_pipe(context->callback_pipe, data, sizeof(alpm_download_event_init_t));
|
||||
break;
|
||||
case ALPM_DOWNLOAD_PROGRESS:
|
||||
write_to_pipe(context->callback_pipe, data, sizeof(alpm_download_event_progress_t));
|
||||
break;
|
||||
case ALPM_DOWNLOAD_RETRY:
|
||||
write_to_pipe(context->callback_pipe, data, sizeof(alpm_download_event_retry_t));
|
||||
break;
|
||||
case ALPM_DOWNLOAD_COMPLETED:
|
||||
write_to_pipe(context->callback_pipe, data, sizeof(alpm_download_event_completed_t));
|
||||
break;
|
||||
}
|
||||
write_to_pipe(context->callback_pipe, &filename_len, sizeof(filename_len));
|
||||
write_to_pipe(context->callback_pipe, filename, filename_len);
|
||||
}
|
||||
|
||||
|
||||
bool _alpm_sandbox_process_cb_log(alpm_handle_t *handle, int callback_pipe) {
|
||||
alpm_loglevel_t level;
|
||||
char *string = NULL;
|
||||
int string_size = 0;
|
||||
|
||||
ASSERT(read_from_pipe(callback_pipe, &level, sizeof(level)) != -1, return false);
|
||||
ASSERT(read_from_pipe(callback_pipe, &string_size, sizeof(string_size)) != -1, return false);
|
||||
|
||||
MALLOC(string, string_size + 1, return false);
|
||||
|
||||
ASSERT(read_from_pipe(callback_pipe, string, string_size) != -1, FREE(string); return false);
|
||||
string[string_size] = '\0';
|
||||
|
||||
_alpm_log(handle, level, "%s", string);
|
||||
FREE(string);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool _alpm_sandbox_process_cb_download(alpm_handle_t *handle, int callback_pipe) {
|
||||
alpm_download_event_type_t type;
|
||||
char *filename = NULL;
|
||||
size_t filename_size, cb_data_size;
|
||||
union {
|
||||
alpm_download_event_init_t init;
|
||||
alpm_download_event_progress_t progress;
|
||||
alpm_download_event_retry_t retry;
|
||||
alpm_download_event_completed_t completed;
|
||||
} cb_data;
|
||||
|
||||
ASSERT(read_from_pipe(callback_pipe, &type, sizeof(type)) != -1, return false);
|
||||
|
||||
switch (type) {
|
||||
case ALPM_DOWNLOAD_INIT:
|
||||
cb_data_size = sizeof(alpm_download_event_init_t);
|
||||
ASSERT(read_from_pipe(callback_pipe, &cb_data.init, cb_data_size) != -1, return false);
|
||||
break;
|
||||
case ALPM_DOWNLOAD_PROGRESS:
|
||||
cb_data_size = sizeof(alpm_download_event_progress_t);
|
||||
ASSERT(read_from_pipe(callback_pipe, &cb_data.progress, cb_data_size) != -1, return false);
|
||||
break;
|
||||
case ALPM_DOWNLOAD_RETRY:
|
||||
cb_data_size = sizeof(alpm_download_event_retry_t);
|
||||
ASSERT(read_from_pipe(callback_pipe, &cb_data.retry, cb_data_size) != -1, return false);
|
||||
break;
|
||||
case ALPM_DOWNLOAD_COMPLETED:
|
||||
cb_data_size = sizeof(alpm_download_event_completed_t);
|
||||
ASSERT(read_from_pipe(callback_pipe, &cb_data.completed, cb_data_size) != -1, return false);
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
ASSERT(read_from_pipe(callback_pipe, &filename_size, sizeof(filename_size)) != -1, return false);;
|
||||
|
||||
MALLOC(filename, filename_size + 1, return false);
|
||||
|
||||
ASSERT(read_from_pipe(callback_pipe, filename, filename_size) != -1, FREE(filename); return false);
|
||||
filename[filename_size] = '\0';
|
||||
|
||||
handle->dlcb(handle->dlcb_ctx, filename, type, &cb_data);
|
||||
FREE(filename);
|
||||
return true;
|
||||
}
|
||||
@@ -1,51 +0,0 @@
|
||||
/*
|
||||
* sandbox.h
|
||||
*
|
||||
* Copyright (c) 2021-2022 Pacman Development Team <pacman-dev@lists.archlinux.org>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef ALPM_SANDBOX_H
|
||||
#define ALPM_SANDBOX_H
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
|
||||
/* The type of callbacks that can happen during a sandboxed operation */
|
||||
typedef enum {
|
||||
ALPM_SANDBOX_CB_LOG,
|
||||
ALPM_SANDBOX_CB_DOWNLOAD
|
||||
} _alpm_sandbox_callback_t;
|
||||
|
||||
typedef struct {
|
||||
int callback_pipe;
|
||||
} _alpm_sandbox_callback_context;
|
||||
|
||||
|
||||
/* Sandbox callbacks */
|
||||
|
||||
__attribute__((format(printf, 3, 0)))
|
||||
void _alpm_sandbox_cb_log(void *ctx, alpm_loglevel_t level, const char *fmt, va_list args);
|
||||
|
||||
void _alpm_sandbox_cb_dl(void *ctx, const char *filename, alpm_download_event_type_t event, void *data);
|
||||
|
||||
|
||||
/* Functions to capture sandbox callbacks and convert them to alpm callbacks */
|
||||
|
||||
bool _alpm_sandbox_process_cb_log(alpm_handle_t *handle, int callback_pipe);
|
||||
bool _alpm_sandbox_process_cb_download(alpm_handle_t *handle, int callback_pipe);
|
||||
|
||||
|
||||
#endif /* ALPM_SANDBOX_H */
|
||||
@@ -767,7 +767,6 @@ static int find_dl_candidates(alpm_handle_t *handle, alpm_list_t **files)
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int download_files(alpm_handle_t *handle)
|
||||
{
|
||||
const char *cachedir;
|
||||
@@ -826,15 +825,8 @@ static int download_files(alpm_handle_t *handle)
|
||||
CALLOC(payload, 1, sizeof(*payload), GOTO_ERR(handle, ALPM_ERR_MEMORY, finish));
|
||||
STRDUP(payload->remote_name, pkg->filename, FREE(payload); GOTO_ERR(handle, ALPM_ERR_MEMORY, finish));
|
||||
STRDUP(payload->filepath, pkg->filename,
|
||||
_alpm_dload_payload_reset(payload); FREE(payload);
|
||||
FREE(payload->remote_name); FREE(payload);
|
||||
GOTO_ERR(handle, ALPM_ERR_MEMORY, finish));
|
||||
payload->destfile_name = _alpm_get_fullpath(cachedir, payload->remote_name, "");
|
||||
payload->tempfile_name = _alpm_get_fullpath(cachedir, payload->remote_name, ".part");
|
||||
if(!payload->destfile_name || !payload->tempfile_name) {
|
||||
_alpm_dload_payload_reset(payload);
|
||||
FREE(payload);
|
||||
GOTO_ERR(handle, ALPM_ERR_MEMORY, finish);
|
||||
}
|
||||
payload->max_size = pkg->size;
|
||||
payload->cache_servers = pkg->origin_data.db->cache_servers;
|
||||
payload->servers = pkg->origin_data.db->servers;
|
||||
|
||||
@@ -197,23 +197,6 @@ cleanup:
|
||||
return ret;
|
||||
}
|
||||
|
||||
/** Combines a directory, filename and suffix to provide full path of a file
|
||||
* @param path directory path
|
||||
* @param filename file name
|
||||
* @param suffix suffix
|
||||
* @return file path
|
||||
*/
|
||||
char *_alpm_get_fullpath(const char *path, const char *filename, const char *suffix)
|
||||
{
|
||||
char *filepath;
|
||||
/* len = localpath len + filename len + suffix len + null */
|
||||
size_t len = strlen(path) + strlen(filename) + strlen(suffix) + 1;
|
||||
MALLOC(filepath, len, return NULL);
|
||||
snprintf(filepath, len, "%s%s%s", path, filename, suffix);
|
||||
|
||||
return filepath;
|
||||
}
|
||||
|
||||
/** Trim trailing newlines from a string (if any exist).
|
||||
* @param str a single line of text
|
||||
* @param len size of str, if known, else 0
|
||||
@@ -572,7 +555,7 @@ static int _alpm_chroot_read_from_child(alpm_handle_t *handle, int fd,
|
||||
return 0;
|
||||
}
|
||||
|
||||
void _alpm_reset_signals(void)
|
||||
static void _alpm_reset_signals(void)
|
||||
{
|
||||
/* reset POSIX defined signals (see signal.h) */
|
||||
/* there are likely more but there is no easy way
|
||||
|
||||
@@ -116,7 +116,6 @@ struct archive_read_buffer {
|
||||
int _alpm_makepath(const char *path);
|
||||
int _alpm_makepath_mode(const char *path, mode_t mode);
|
||||
int _alpm_copyfile(const char *src, const char *dest);
|
||||
char *_alpm_get_fullpath(const char *path, const char *filename, const char *suffix);
|
||||
size_t _alpm_strip_newline(char *str, size_t len);
|
||||
|
||||
int _alpm_open_archive(alpm_handle_t *handle, const char *path,
|
||||
@@ -130,7 +129,6 @@ ssize_t _alpm_files_in_directory(alpm_handle_t *handle, const char *path, int fu
|
||||
|
||||
typedef ssize_t (*_alpm_cb_io)(void *buf, ssize_t len, void *ctx);
|
||||
|
||||
void _alpm_reset_signals(void);
|
||||
int _alpm_run_chroot(alpm_handle_t *handle, const char *cmd, char *const argv[],
|
||||
_alpm_cb_io in_cb, void *in_ctx);
|
||||
int _alpm_ldconfig(alpm_handle_t *handle);
|
||||
|
||||
@@ -57,7 +57,7 @@ static alpm_list_t *output = NULL;
|
||||
#endif
|
||||
|
||||
struct pacman_progress_bar {
|
||||
char *filename;
|
||||
const char *filename;
|
||||
off_t xfered; /* Current amount of transferred data */
|
||||
off_t total_size;
|
||||
size_t downloaded;
|
||||
@@ -589,7 +589,7 @@ void cb_progress(void *ctx, alpm_progress_t event, const char *pkgname,
|
||||
} else {
|
||||
if(current != prevcurrent) {
|
||||
/* update always */
|
||||
} else if(!pkgname || percent == prevpercent ||
|
||||
} else if(pkgname[0] == '\0' || percent == prevpercent ||
|
||||
get_update_timediff(0) < UPDATE_SPEED_MS) {
|
||||
/* only update the progress bar when we have a package name, the
|
||||
* percentage has changed, and it has been long enough. */
|
||||
@@ -653,7 +653,7 @@ void cb_progress(void *ctx, alpm_progress_t event, const char *pkgname,
|
||||
* by the output, and then pad it accordingly so we fill the terminal.
|
||||
*/
|
||||
/* len = opr len + pkgname len (if available) + space + null */
|
||||
len = strlen(opr) + ((pkgname) ? strlen(pkgname) : 0) + 2;
|
||||
len = strlen(opr) + strlen(pkgname) + 2;
|
||||
wcstr = calloc(len, sizeof(wchar_t));
|
||||
/* print our strings to the alloc'ed memory */
|
||||
#if defined(HAVE_SWPRINTF)
|
||||
@@ -745,8 +745,7 @@ static void init_total_progressbar(void)
|
||||
{
|
||||
totalbar = calloc(1, sizeof(struct pacman_progress_bar));
|
||||
assert(totalbar);
|
||||
totalbar->filename = strdup(_("Total"));
|
||||
assert(totalbar->filename);
|
||||
totalbar->filename = _("Total");
|
||||
totalbar->init_time = get_time_ms();
|
||||
totalbar->total_size = list_total;
|
||||
totalbar->howmany = list_total_pkgs;
|
||||
@@ -883,8 +882,7 @@ static void dload_init_event(const char *filename, alpm_download_event_init_t *d
|
||||
|
||||
struct pacman_progress_bar *bar = calloc(1, sizeof(struct pacman_progress_bar));
|
||||
assert(bar);
|
||||
bar->filename = strdup(filename);
|
||||
assert(bar->filename);
|
||||
bar->filename = filename;
|
||||
bar->init_time = get_time_ms();
|
||||
bar->rate = 0.0;
|
||||
multibar_ui.active_downloads = alpm_list_add(multibar_ui.active_downloads, bar);
|
||||
@@ -1089,7 +1087,6 @@ static void dload_complete_event(const char *filename, alpm_download_event_compl
|
||||
multibar_ui.active_downloads = alpm_list_remove_item(
|
||||
multibar_ui.active_downloads, head);
|
||||
free(head);
|
||||
free(j->filename);
|
||||
free(j);
|
||||
} else {
|
||||
break;
|
||||
|
||||
@@ -155,7 +155,6 @@ int config_free(config_t *oldconfig)
|
||||
free(oldconfig->dbpath);
|
||||
free(oldconfig->logfile);
|
||||
free(oldconfig->gpgdir);
|
||||
free(oldconfig->sandboxuser);
|
||||
FREELIST(oldconfig->hookdirs);
|
||||
FREELIST(oldconfig->cachedirs);
|
||||
free(oldconfig->xfercommand);
|
||||
@@ -670,11 +669,6 @@ static int _parse_options(const char *key, char *value,
|
||||
config->logfile = strdup(value);
|
||||
pm_printf(ALPM_LOG_DEBUG, "config: logfile: %s\n", value);
|
||||
}
|
||||
} else if(strcmp(key, "DownloadUser") == 0) {
|
||||
if(!config->sandboxuser) {
|
||||
config->sandboxuser = strdup(value);
|
||||
pm_printf(ALPM_LOG_DEBUG, "config: sandboxuser: %s\n", value);
|
||||
}
|
||||
} else if(strcmp(key, "XferCommand") == 0) {
|
||||
char **c;
|
||||
if((config->xfercommand_argv = wordsplit(value)) == NULL) {
|
||||
@@ -927,7 +921,6 @@ static int setup_libalpm(void)
|
||||
alpm_option_set_architectures(handle, config->architectures);
|
||||
alpm_option_set_checkspace(handle, config->checkspace);
|
||||
alpm_option_set_usesyslog(handle, config->usesyslog);
|
||||
alpm_option_set_sandboxuser(handle, config->sandboxuser);
|
||||
|
||||
alpm_option_set_ignorepkgs(handle, config->ignorepkg);
|
||||
alpm_option_set_ignoregroups(handle, config->ignoregrp);
|
||||
|
||||
@@ -68,7 +68,6 @@ typedef struct __config_t {
|
||||
char *logfile;
|
||||
char *gpgdir;
|
||||
char *sysroot;
|
||||
char *sandboxuser;
|
||||
alpm_list_t *hookdirs;
|
||||
alpm_list_t *cachedirs;
|
||||
alpm_list_t *architectures;
|
||||
|
||||
@@ -252,7 +252,6 @@ static void dump_config(void)
|
||||
show_list_str("HookDir", config->hookdirs);
|
||||
show_str("GPGDir", config->gpgdir);
|
||||
show_str("LogFile", config->logfile);
|
||||
show_str("DownloadUser", config->sandboxuser);
|
||||
|
||||
show_list_str("HoldPkg", config->holdpkg);
|
||||
show_list_str("IgnorePkg", config->ignorepkg);
|
||||
@@ -353,8 +352,6 @@ static int list_directives(void)
|
||||
show_str("GPGDir", config->gpgdir);
|
||||
} else if(strcasecmp(i->data, "LogFile") == 0) {
|
||||
show_str("LogFile", config->logfile);
|
||||
} else if(strcasecmp(i->data, "DownloadUser") == 0) {
|
||||
show_str("DownloadUser", config->sandboxuser);
|
||||
|
||||
} else if(strcasecmp(i->data, "HoldPkg") == 0) {
|
||||
show_list_str("HoldPkg", config->holdpkg);
|
||||
|
||||
@@ -381,7 +381,7 @@ static int parsearg_global(int opt)
|
||||
break;
|
||||
case OP_ASK:
|
||||
config->noask = 1;
|
||||
config->ask = (unsigned int)atoi(optarg);
|
||||
config->ask = (unsigned int)strtol(optarg, NULL, 10);
|
||||
break;
|
||||
case OP_CACHEDIR:
|
||||
config->cachedirs = alpm_list_add(config->cachedirs, strdup(optarg));
|
||||
@@ -409,7 +409,7 @@ static int parsearg_global(int opt)
|
||||
* here, error and warning are set in config_new, though perhaps a
|
||||
* --quiet option will remove these later */
|
||||
if(optarg) {
|
||||
unsigned short debug = (unsigned short)atoi(optarg);
|
||||
int debug = strtol(optarg, NULL, 10);
|
||||
switch(debug) {
|
||||
case 2:
|
||||
config->logmask |= ALPM_LOG_FUNCTION;
|
||||
|
||||
@@ -462,7 +462,7 @@ static size_t string_length(const char *s)
|
||||
int iter = 0;
|
||||
for(; *s; s++) {
|
||||
if(*s == '\033') {
|
||||
while(*s != 'm') {
|
||||
while(*s != 'm' && *s != '\0') {
|
||||
s++;
|
||||
}
|
||||
} else {
|
||||
|
||||
@@ -97,6 +97,9 @@ pacman_tests = [
|
||||
'tests/pacman003.py',
|
||||
'tests/pacman004.py',
|
||||
'tests/pacman005.py',
|
||||
'tests/pkg-meta-invalid-name-file.py',
|
||||
'tests/pkg-meta-invalid-name-local.py',
|
||||
'tests/pkg-meta-invalid-name-sync.py',
|
||||
'tests/provision001.py',
|
||||
'tests/provision002.py',
|
||||
'tests/provision003.py',
|
||||
@@ -155,8 +158,6 @@ pacman_tests = [
|
||||
'tests/replace103.py',
|
||||
'tests/replace104.py',
|
||||
'tests/replace110.py',
|
||||
'tests/sandbox-download-upgrade.py',
|
||||
'tests/sandbox-download-basic.py',
|
||||
'tests/scriptlet001.py',
|
||||
'tests/scriptlet002.py',
|
||||
'tests/scriptlet-signal-handling.py',
|
||||
@@ -336,6 +337,7 @@ pacman_tests = [
|
||||
'tests/xfercommand001.py',
|
||||
'tests/upgrade-download-404.py',
|
||||
'tests/upgrade-download-pkg-and-sig-with-filename.py',
|
||||
'tests/upgrade-download-pkg-and-sig-without-filename.py',
|
||||
'tests/upgrade-download-with-xfercommand.py',
|
||||
]
|
||||
|
||||
@@ -348,6 +350,7 @@ xfail_tests = {
|
||||
'tests/sync403.py': true,
|
||||
'tests/sync406.py': true,
|
||||
'tests/upgrade078.py': true,
|
||||
'tests/upgrade-download-with-xfercommand.py': true,
|
||||
}
|
||||
|
||||
foreach input : pacman_tests
|
||||
|
||||
@@ -1,11 +0,0 @@
|
||||
self.description = "refresh databases with Optional siglevel"
|
||||
self.require_capability("curl")
|
||||
|
||||
p1 = pmpkg('pkg1', '1.0-1')
|
||||
self.addpkg2db('sync', p1)
|
||||
|
||||
self.db['sync'].option['SigLevel'] = ["Optional"]
|
||||
|
||||
self.args = '-Syy'
|
||||
|
||||
self.addrule("PACMAN_RETCODE=0")
|
||||
9
test/pacman/tests/pkg-meta-invalid-name-file.py
Normal file
9
test/pacman/tests/pkg-meta-invalid-name-file.py
Normal file
@@ -0,0 +1,9 @@
|
||||
self.description = "package name with invalid characters cannot be installed (file)"
|
||||
|
||||
p = pmpkg("-foo")
|
||||
self.addpkg(p)
|
||||
|
||||
self.args = "-U -- %s" % p.filename()
|
||||
|
||||
self.addrule("!PACMAN_RETCODE=0")
|
||||
self.addrule("!PKG_EXIST=-foo")
|
||||
9
test/pacman/tests/pkg-meta-invalid-name-local.py
Normal file
9
test/pacman/tests/pkg-meta-invalid-name-local.py
Normal file
@@ -0,0 +1,9 @@
|
||||
self.description = "local package name with invalid characters can be removed"
|
||||
|
||||
sp = pmpkg("-foo")
|
||||
self.addpkg2db("local", sp)
|
||||
|
||||
self.args = "-R -- %s" % sp.name
|
||||
|
||||
self.addrule("PACMAN_RETCODE=0")
|
||||
self.addrule("!PKG_EXIST=-foo")
|
||||
9
test/pacman/tests/pkg-meta-invalid-name-sync.py
Normal file
9
test/pacman/tests/pkg-meta-invalid-name-sync.py
Normal file
@@ -0,0 +1,9 @@
|
||||
self.description = "package name with invalid characters cannot be installed"
|
||||
|
||||
sp = pmpkg("-foo")
|
||||
self.addpkg2db("sync", sp)
|
||||
|
||||
self.args = "-S -- %s" % sp.name
|
||||
|
||||
self.addrule("!PACMAN_RETCODE=0")
|
||||
self.addrule("!PKG_EXIST=-foo")
|
||||
@@ -1,20 +0,0 @@
|
||||
self.description = "--sync with DownloadUser set"
|
||||
self.require_capability("curl")
|
||||
|
||||
p1 = pmpkg('pkg1', '1.0-1')
|
||||
self.addpkg2db('sync', p1)
|
||||
|
||||
url = self.add_simple_http_server({
|
||||
'/{}'.format(p1.filename()): p1.makepkg_bytes(),
|
||||
})
|
||||
|
||||
self.option['DownloadUser'] = ['root']
|
||||
self.db['sync'].option['Server'] = [ url ]
|
||||
self.db['sync'].syncdir = False
|
||||
self.cachepkgs = False
|
||||
|
||||
self.args = '-S pkg1'
|
||||
|
||||
self.addrule("PACMAN_RETCODE=0")
|
||||
self.addrule("PKG_EXIST=pkg1")
|
||||
self.addrule("CACHE_EXISTS=pkg1|1.0-1")
|
||||
@@ -1,17 +0,0 @@
|
||||
self.description = "--upgrade with DownloadUser set"
|
||||
self.require_capability("curl")
|
||||
|
||||
self.option['DownloadUser'] = ['root']
|
||||
|
||||
p1 = pmpkg('pkg1', '1.0-1')
|
||||
self.addpkg(p1)
|
||||
|
||||
url = self.add_simple_http_server({
|
||||
'/{}'.format(p1.filename()): p1.makepkg_bytes(),
|
||||
})
|
||||
|
||||
self.args = '-U {url}/{}'.format(p1.filename(), url=url)
|
||||
|
||||
self.addrule("PACMAN_RETCODE=0")
|
||||
self.addrule("PKG_EXIST=pkg1")
|
||||
self.addrule("CACHE_EXISTS=pkg1|1.0-1")
|
||||
@@ -10,7 +10,7 @@ url = self.add_simple_http_server({
|
||||
'body': 'simple.sig',
|
||||
},
|
||||
|
||||
# content-disposition filename is now ignored
|
||||
# content-disposition filename
|
||||
'/cd.pkg': {
|
||||
'headers': { 'Content-Disposition': 'attachment; filename="cd-alt.pkg"' },
|
||||
'body': 'cd'
|
||||
@@ -64,26 +64,19 @@ self.addrule('!PACMAN_RETCODE=0')
|
||||
self.addrule('CACHE_FCONTENTS=simple.pkg|simple')
|
||||
self.addrule('CACHE_FCONTENTS=simple.pkg.sig|simple.sig')
|
||||
|
||||
self.addrule('!CACHE_FEXISTS=cd-alt.pkg')
|
||||
self.addrule('!CACHE_FEXISTS=cd-alt.pkg.sig')
|
||||
self.addrule('CACHE_FCONTENTS=cd.pkg|cd')
|
||||
self.addrule('CACHE_FCONTENTS=cd.pkg.sig|cd.sig')
|
||||
self.addrule('!CACHE_FEXISTS=cd.pkg')
|
||||
self.addrule('!CACHE_FEXISTS=cd.pkg.sig')
|
||||
self.addrule('CACHE_FCONTENTS=cd-alt.pkg|cd')
|
||||
self.addrule('CACHE_FCONTENTS=cd-alt.pkg.sig|cd.sig')
|
||||
|
||||
self.addrule('!CACHE_FEXISTS=redir-dest.pkg')
|
||||
self.addrule('CACHE_FCONTENTS=redir.pkg|redir-dest')
|
||||
self.addrule('CACHE_FCONTENTS=redir.pkg.sig|redir-dest.sig')
|
||||
self.addrule('!CACHE_FEXISTS=redir.pkg')
|
||||
self.addrule('CACHE_FCONTENTS=redir-dest.pkg|redir-dest')
|
||||
self.addrule('CACHE_FCONTENTS=redir-dest.pkg.sig|redir-dest.sig')
|
||||
|
||||
self.addrule('CACHE_FCONTENTS=redir-cdn.pkg|redir-dest')
|
||||
self.addrule('CACHE_FCONTENTS=redir-cdn.pkg.sig|redir-dest.sig')
|
||||
self.addrule('!CACHE_FEXISTS=cd-redir.pkg')
|
||||
self.addrule('!CACHE_FEXISTS=cd-redir-dest.pkg')
|
||||
self.addrule('CACHE_FCONTENTS=cd-redir-dest-alt.pkg|cd-redir-dest')
|
||||
self.addrule('CACHE_FCONTENTS=cd-redir-dest-alt.pkg.sig|cd-redir-dest.sig')
|
||||
|
||||
self.addrule('!CACHE_FEXISTS=cd-redir-dest-alt.pkg')
|
||||
self.addrule('!CACHE_FEXISTS=cd-redir-dest-alt.pkg')
|
||||
self.addrule('CACHE_FCONTENTS=cd-redir.pkg|cd-redir-dest')
|
||||
self.addrule('CACHE_FCONTENTS=cd-redir.pkg.sig|cd-redir-dest.sig')
|
||||
|
||||
self.addrule('!CACHE_FEXISTS=cdn-3')
|
||||
self.addrule('!CACHE_FEXISTS=cdn-4')
|
||||
self.addrule('!CACHE_FEXISTS=cdn-alt.pkg')
|
||||
self.addrule('!CACHE_FEXISTS=cdn-alt.pkg.sig')
|
||||
self.addrule('CACHE_FCONTENTS=cd-redir-cdn.pkg|cdn-alt')
|
||||
self.addrule('CACHE_FCONTENTS=cd-redir-cdn.pkg.sig|cdn-alt.sig')
|
||||
self.addrule('CACHE_FCONTENTS=cdn-alt.pkg|cdn-alt')
|
||||
self.addrule('CACHE_FCONTENTS=cdn-alt.pkg.sig|cdn-alt.sig')
|
||||
|
||||
@@ -0,0 +1,63 @@
|
||||
self.description = 'download remote packages with -U without a URL filename'
|
||||
self.require_capability("gpg")
|
||||
self.require_capability("curl")
|
||||
|
||||
url = self.add_simple_http_server({
|
||||
# simple
|
||||
'/simple.pkg/': 'simple',
|
||||
'/simple.pkg/.sig': 'simple.sig',
|
||||
|
||||
# content-disposition filename
|
||||
'/cd.pkg/': {
|
||||
'headers': { 'Content-Disposition': 'attachment; filename="cd-alt.pkg"' },
|
||||
'body': 'cd'
|
||||
},
|
||||
'/cd.pkg/.sig': {
|
||||
'headers': { 'Content-Disposition': 'attachment; filename="cd-alt-bad.pkg.sig"' },
|
||||
'body': 'cd.sig'
|
||||
},
|
||||
|
||||
# redirect
|
||||
'/redir.pkg/': { 'code': 303, 'headers': { 'Location': '/redir-dest.pkg' } },
|
||||
'/redir-dest.pkg': 'redir-dest',
|
||||
'/redir-dest.pkg.sig': 'redir-dest.sig',
|
||||
|
||||
# content-disposition and redirect
|
||||
'/cd-redir.pkg/': { 'code': 303, 'headers': { 'Location': '/cd-redir-dest.pkg' } },
|
||||
'/cd-redir-dest.pkg': {
|
||||
'headers': { 'Content-Disposition': 'attachment; filename="cd-redir-dest-alt.pkg"' },
|
||||
'body': 'cd-redir-dest'
|
||||
},
|
||||
'/cd-redir-dest.pkg.sig': 'cd-redir-dest.sig',
|
||||
|
||||
# TODO: absolutely terrible hack to prevent pacman from attempting to
|
||||
# validate packages, which causes failure under --valgrind thanks to
|
||||
# a memory leak in gpgme that is too general for inclusion in valgrind.supp
|
||||
'/404': { 'code': 404 },
|
||||
|
||||
'': 'fallback',
|
||||
})
|
||||
|
||||
self.args = '-Uw {url}/simple.pkg/ {url}/cd.pkg/ {url}/redir.pkg/ {url}/cd-redir.pkg/ {url}/404'.format(url=url)
|
||||
|
||||
# packages/sigs are not valid, error is expected
|
||||
self.addrule('!PACMAN_RETCODE=0')
|
||||
|
||||
# TODO: use a predictable file name
|
||||
#self.addrule('CACHE_FCONTENTS=simple.pkg|simple')
|
||||
#self.addrule('CACHE_FCONTENTS=simple.pkg.sig|simple.sig')
|
||||
|
||||
self.addrule('!CACHE_FEXISTS=cd.pkg')
|
||||
self.addrule('CACHE_FCONTENTS=cd-alt.pkg|cd')
|
||||
self.addrule('CACHE_FCONTENTS=cd-alt.pkg.sig|cd.sig')
|
||||
|
||||
self.addrule('!CACHE_FEXISTS=redir.pkg')
|
||||
self.addrule('CACHE_FCONTENTS=redir-dest.pkg|redir-dest')
|
||||
self.addrule('CACHE_FCONTENTS=redir-dest.pkg.sig|redir-dest.sig')
|
||||
|
||||
self.addrule('!CACHE_FEXISTS=cd-redir.pkg')
|
||||
self.addrule('!CACHE_FEXISTS=cd-redir-dest.pkg')
|
||||
self.addrule('CACHE_FCONTENTS=cd-redir-dest-alt.pkg|cd-redir-dest')
|
||||
self.addrule('CACHE_FCONTENTS=cd-redir-dest-alt.pkg.sig|cd-redir-dest.sig')
|
||||
|
||||
self.addrule('!CACHE_FEXISTS=.sig')
|
||||
@@ -20,3 +20,7 @@ self.addrule("PKG_EXIST=pkg1")
|
||||
self.addrule("PKG_EXIST=pkg2")
|
||||
self.addrule("CACHE_EXISTS=pkg1|1.0-1")
|
||||
self.addrule("CACHE_EXISTS=pkg2|2.0-2")
|
||||
|
||||
# --upgrade fails hard with XferCommand because the fetch callback has no way
|
||||
# to return the file path to alpm
|
||||
self.expectfailure = True
|
||||
|
||||
Reference in New Issue
Block a user