summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/libalpm/alpm.h17
-rw-r--r--lib/libalpm/dload.c104
-rw-r--r--lib/libalpm/handle.c34
-rw-r--r--lib/libalpm/handle.h2
-rw-r--r--src/pacman/conf.c1
-rw-r--r--src/pacman/conf.h1
-rw-r--r--src/pacman/pacman.c115
7 files changed, 156 insertions, 118 deletions
diff --git a/lib/libalpm/alpm.h b/lib/libalpm/alpm.h
index 5285ac39..ce8c6919 100644
--- a/lib/libalpm/alpm.h
+++ b/lib/libalpm/alpm.h
@@ -83,6 +83,17 @@ int alpm_logaction(char *fmt, ...);
typedef void (*alpm_cb_download)(const char *filename,
off_t xfered, off_t total);
typedef void (*alpm_cb_totaldl)(off_t total);
+/** A callback for downloading files
+ * @param url the URL of the file to be downloaded
+ * @param localpath the directory to which the file should be downloaded
+ * @param mtimeold the modification time of the file previously downloaded
+ * @param mtimenew the modification time of the newly downloaded file.
+ * This should be set by the callback.
+ * @return 0 on success, 1 if the modification times are identical, -1 on
+ * error.
+ */
+typedef int (*alpm_cb_fetch)(const char *url, const char *localpath,
+ time_t mtimeold, time_t *mtimenew);
/*
* Options
@@ -94,6 +105,9 @@ void alpm_option_set_logcb(alpm_cb_log cb);
alpm_cb_download alpm_option_get_dlcb();
void alpm_option_set_dlcb(alpm_cb_download cb);
+alpm_cb_fetch alpm_option_get_fetchcb();
+void alpm_option_set_fetchcb(alpm_cb_fetch cb);
+
alpm_cb_totaldl alpm_option_get_totaldlcb();
void alpm_option_set_totaldlcb(alpm_cb_totaldl cb);
@@ -137,9 +151,6 @@ void alpm_option_add_ignoregrp(const char *grp);
void alpm_option_set_ignoregrps(alpm_list_t *ignoregrps);
int alpm_option_remove_ignoregrp(const char *grp);
-const char *alpm_option_get_xfercommand();
-void alpm_option_set_xfercommand(const char *cmd);
-
unsigned short alpm_option_get_nopassiveftp();
void alpm_option_set_nopassiveftp(unsigned short nopasv);
void alpm_option_set_usedelta(unsigned short usedelta);
diff --git a/lib/libalpm/dload.c b/lib/libalpm/dload.c
index c8296f52..6b163ce6 100644
--- a/lib/libalpm/dload.c
+++ b/lib/libalpm/dload.c
@@ -263,111 +263,21 @@ cleanup:
}
#endif
-static int download_external(const char *url, const char *localpath,
- time_t mtimeold, time_t *mtimenew) {
- int ret = 0;
- int retval;
- int usepart = 0;
- char *ptr1, *ptr2;
- char origCmd[PATH_MAX];
- char parsedCmd[PATH_MAX] = "";
- char cwd[PATH_MAX];
- char *destfile, *tempfile, *filename;
-
- if(!handle->xfercommand) {
- RET_ERR(PM_ERR_EXTERNAL_DOWNLOAD, -1);
- }
-
- filename = get_filename(url);
- if(!filename) {
- RET_ERR(PM_ERR_EXTERNAL_DOWNLOAD, -1);
- }
- destfile = get_destfile(localpath, filename);
- tempfile = get_tempfile(localpath, filename);
-
- /* replace all occurrences of %o with fn.part */
- strncpy(origCmd, handle->xfercommand, sizeof(origCmd));
- ptr1 = origCmd;
- while((ptr2 = strstr(ptr1, "%o"))) {
- usepart = 1;
- ptr2[0] = '\0';
- strcat(parsedCmd, ptr1);
- strcat(parsedCmd, tempfile);
- ptr1 = ptr2 + 2;
- }
- strcat(parsedCmd, ptr1);
- /* replace all occurrences of %u with the download URL */
- strncpy(origCmd, parsedCmd, sizeof(origCmd));
- parsedCmd[0] = '\0';
- ptr1 = origCmd;
- while((ptr2 = strstr(ptr1, "%u"))) {
- ptr2[0] = '\0';
- strcat(parsedCmd, ptr1);
- strcat(parsedCmd, url);
- ptr1 = ptr2 + 2;
- }
- strcat(parsedCmd, ptr1);
- /* cwd to the download directory */
- getcwd(cwd, PATH_MAX);
- if(chdir(localpath)) {
- _alpm_log(PM_LOG_WARNING, _("could not chdir to %s\n"), localpath);
- pm_errno = PM_ERR_EXTERNAL_DOWNLOAD;
- ret = -1;
- goto cleanup;
- }
- /* execute the parsed command via /bin/sh -c */
- _alpm_log(PM_LOG_DEBUG, "running command: %s\n", parsedCmd);
- retval = system(parsedCmd);
-
- if(retval == -1) {
- _alpm_log(PM_LOG_WARNING, _("running XferCommand: fork failed!\n"));
- pm_errno = PM_ERR_EXTERNAL_DOWNLOAD;
- ret = -1;
- } else if(retval != 0) {
- /* download failed */
- _alpm_log(PM_LOG_DEBUG, "XferCommand command returned non-zero status "
- "code (%d)\n", retval);
- ret = -1;
- } else {
- /* download was successful */
- if(usepart) {
- rename(tempfile, destfile);
- }
- ret = 0;
- }
-
-cleanup:
- chdir(cwd);
- if(ret == -1) {
- /* hack to let an user the time to cancel a download */
- sleep(2);
- }
- FREE(destfile);
- FREE(tempfile);
-
- return(ret);
-}
-
static int download(const char *url, const char *localpath,
time_t mtimeold, time_t *mtimenew) {
- int ret;
-
- /* We have a few things to take into account here.
- * 1. If we have both internal/external available, choose based on
- * whether xfercommand is populated.
- * 2. If we only have external available, we should first check
- * if a command was provided before we drop into download_external.
- */
- if(handle->xfercommand == NULL) {
+ if(handle->fetchcb == NULL) {
#if defined(INTERNAL_DOWNLOAD)
- ret = download_internal(url, localpath, mtimeold, mtimenew);
+ return(download_internal(url, localpath, mtimeold, mtimenew));
#else
RET_ERR(PM_ERR_EXTERNAL_DOWNLOAD, -1);
#endif
} else {
- ret = download_external(url, localpath, mtimeold, mtimenew);
+ int ret = handle->fetchcb(url, localpath, mtimeold, mtimenew);
+ if(ret == -1) {
+ RET_ERR(PM_ERR_EXTERNAL_DOWNLOAD, -1);
+ }
+ return(ret);
}
- return(ret);
}
/*
diff --git a/lib/libalpm/handle.c b/lib/libalpm/handle.c
index 34115b38..d1a35ad9 100644
--- a/lib/libalpm/handle.c
+++ b/lib/libalpm/handle.c
@@ -79,7 +79,6 @@ void _alpm_handle_free(pmhandle_t *handle)
FREELIST(handle->cachedirs);
FREE(handle->logfile);
FREE(handle->lockfile);
- FREE(handle->xfercommand);
FREELIST(handle->dbs_sync);
FREELIST(handle->noupgrade);
FREELIST(handle->noextract);
@@ -106,6 +105,15 @@ alpm_cb_download SYMEXPORT alpm_option_get_dlcb()
return handle->dlcb;
}
+alpm_cb_fetch SYMEXPORT alpm_option_get_fetchcb()
+{
+ if (handle == NULL) {
+ pm_errno = PM_ERR_HANDLE_NULL;
+ return NULL;
+ }
+ return handle->fetchcb;
+}
+
alpm_cb_totaldl SYMEXPORT alpm_option_get_totaldlcb()
{
if (handle == NULL) {
@@ -205,15 +213,6 @@ alpm_list_t SYMEXPORT *alpm_option_get_ignoregrps()
return handle->ignoregrp;
}
-const char SYMEXPORT *alpm_option_get_xfercommand()
-{
- if (handle == NULL) {
- pm_errno = PM_ERR_HANDLE_NULL;
- return NULL;
- }
- return handle->xfercommand;
-}
-
unsigned short SYMEXPORT alpm_option_get_nopassiveftp()
{
if (handle == NULL) {
@@ -259,6 +258,15 @@ void SYMEXPORT alpm_option_set_dlcb(alpm_cb_download cb)
handle->dlcb = cb;
}
+void SYMEXPORT alpm_option_set_fetchcb(alpm_cb_fetch cb)
+{
+ if (handle == NULL) {
+ pm_errno = PM_ERR_HANDLE_NULL;
+ return;
+ }
+ handle->fetchcb = cb;
+}
+
void SYMEXPORT alpm_option_set_totaldlcb(alpm_cb_totaldl cb)
{
if (handle == NULL) {
@@ -521,12 +529,6 @@ int SYMEXPORT alpm_option_remove_ignoregrp(const char *grp)
return(0);
}
-void SYMEXPORT alpm_option_set_xfercommand(const char *cmd)
-{
- if(handle->xfercommand) FREE(handle->xfercommand);
- if(cmd) handle->xfercommand = strdup(cmd);
-}
-
void SYMEXPORT alpm_option_set_nopassiveftp(unsigned short nopasv)
{
handle->nopassiveftp = nopasv;
diff --git a/lib/libalpm/handle.h b/lib/libalpm/handle.h
index 2ef94bd2..c7c262cf 100644
--- a/lib/libalpm/handle.h
+++ b/lib/libalpm/handle.h
@@ -41,6 +41,7 @@ typedef struct _pmhandle_t {
alpm_cb_log logcb; /* Log callback function */
alpm_cb_download dlcb; /* Download callback function */
alpm_cb_totaldl totaldlcb; /* Total download callback function */
+ alpm_cb_fetch fetchcb; /* Download file callback function */
/* filesystem paths */
char *root; /* Root path, default '/' */
@@ -58,7 +59,6 @@ typedef struct _pmhandle_t {
/* options */
unsigned short usesyslog; /* Use syslog instead of logfile? */ /* TODO move to frontend */
unsigned short nopassiveftp; /* Don't use PASV ftp connections */
- char *xfercommand; /* External download command */
unsigned short usedelta; /* Download deltas if possible */
} pmhandle_t;
diff --git a/src/pacman/conf.c b/src/pacman/conf.c
index e25f8b72..92c6f4eb 100644
--- a/src/pacman/conf.c
+++ b/src/pacman/conf.c
@@ -61,6 +61,7 @@ int config_free(config_t *oldconfig)
free(oldconfig->rootdir);
free(oldconfig->dbpath);
free(oldconfig->logfile);
+ free(oldconfig->xfercommand);
free(oldconfig);
oldconfig = NULL;
diff --git a/src/pacman/conf.h b/src/pacman/conf.h
index 6523d490..2d3de987 100644
--- a/src/pacman/conf.h
+++ b/src/pacman/conf.h
@@ -73,6 +73,7 @@ typedef struct __config_t {
unsigned short cleanmethod; /* select -Sc behavior */
alpm_list_t *holdpkg;
alpm_list_t *syncfirst;
+ char *xfercommand;
} config_t;
/* Operations */
diff --git a/src/pacman/pacman.c b/src/pacman/pacman.c
index d5e600a5..7cecd905 100644
--- a/src/pacman/pacman.c
+++ b/src/pacman/pacman.c
@@ -581,6 +581,118 @@ static void setrepeatingoption(const char *ptr, const char *option,
pm_printf(PM_LOG_DEBUG, "config: %s: %s\n", option, p);
}
+static char *get_filename(const char *url) {
+ char *filename = strrchr(url, '/');
+ if(filename != NULL) {
+ filename++;
+ }
+ return(filename);
+}
+
+static char *get_destfile(const char *path, const char *filename) {
+ char *destfile;
+ /* len = localpath len + filename len + null */
+ int len = strlen(path) + strlen(filename) + 1;
+ destfile = calloc(len, sizeof(char));
+ snprintf(destfile, len, "%s%s", path, filename);
+
+ return(destfile);
+}
+
+static char *get_tempfile(const char *path, const char *filename) {
+ char *tempfile;
+ /* len = localpath len + filename len + '.part' len + null */
+ int len = strlen(path) + strlen(filename) + 6;
+ tempfile = calloc(len, sizeof(char));
+ snprintf(tempfile, len, "%s%s.part", path, filename);
+
+ return(tempfile);
+}
+
+/** External fetch callback */
+int download_with_xfercommand(const char *url, const char *localpath,
+ time_t mtimeold, time_t *mtimenew) {
+ int ret = 0;
+ int retval;
+ int usepart = 0;
+ char *ptr1, *ptr2;
+ char origCmd[PATH_MAX];
+ char parsedCmd[PATH_MAX] = "";
+ char cwd[PATH_MAX];
+ char *destfile, *tempfile, *filename;
+
+ if(!config->xfercommand) {
+ return -1;
+ }
+
+ filename = get_filename(url);
+ if(!filename) {
+ return -1;
+ }
+ destfile = get_destfile(localpath, filename);
+ tempfile = get_tempfile(localpath, filename);
+
+ strncpy(origCmd, config->xfercommand, sizeof(origCmd));
+ /* replace all occurrences of %o with fn.part */
+ ptr1 = origCmd;
+ while((ptr2 = strstr(ptr1, "%o"))) {
+ usepart = 1;
+ ptr2[0] = '\0';
+ strcat(parsedCmd, ptr1);
+ strcat(parsedCmd, tempfile);
+ ptr1 = ptr2 + 2;
+ }
+ strcat(parsedCmd, ptr1);
+ /* replace all occurrences of %u with the download URL */
+ strncpy(origCmd, parsedCmd, sizeof(origCmd));
+ parsedCmd[0] = '\0';
+ ptr1 = origCmd;
+ while((ptr2 = strstr(ptr1, "%u"))) {
+ ptr2[0] = '\0';
+ strcat(parsedCmd, ptr1);
+ strcat(parsedCmd, url);
+ ptr1 = ptr2 + 2;
+ }
+ strcat(parsedCmd, ptr1);
+ /* cwd to the download directory */
+ getcwd(cwd, PATH_MAX);
+ if(chdir(localpath)) {
+ pm_printf(PM_LOG_WARNING, "could not chdir to %s\n", localpath);
+ ret = -1;
+ goto cleanup;
+ }
+ /* execute the parsed command via /bin/sh -c */
+ pm_printf(PM_LOG_DEBUG, "running command: %s\n", parsedCmd);
+ retval = system(parsedCmd);
+
+ if(retval == -1) {
+ pm_printf(PM_LOG_WARNING, "running XferCommand: fork failed!\n");
+ ret = -1;
+ } else if(retval != 0) {
+ /* download failed */
+ pm_printf(PM_LOG_DEBUG, "XferCommand command returned non-zero status "
+ "code (%d)\n", retval);
+ ret = -1;
+ } else {
+ /* download was successful */
+ if(usepart) {
+ rename(tempfile, destfile);
+ }
+ ret = 0;
+ }
+
+cleanup:
+ chdir(cwd);
+ if(ret == -1) {
+ /* hack to let an user the time to cancel a download */
+ sleep(2);
+ }
+ free(destfile);
+ free(tempfile);
+
+ return(ret);
+}
+
/* The real parseconfig. Called with a null section argument by the publicly
* visible parseconfig so we can recall from within ourself on an include */
static int _parseconfig(const char *file, const char *givensection,
@@ -744,7 +856,8 @@ static int _parseconfig(const char *file, const char *givensection,
pm_printf(PM_LOG_DEBUG, "config: logfile: %s\n", ptr);
}
} else if (strcmp(key, "XferCommand") == 0) {
- alpm_option_set_xfercommand(ptr);
+ config->xfercommand = strdup(ptr);
+ alpm_option_set_fetchcb(download_with_xfercommand);
pm_printf(PM_LOG_DEBUG, "config: xfercommand: %s\n", ptr);
} else if (strcmp(key, "CleanMethod") == 0) {
if (strcmp(ptr, "KeepInstalled") == 0) {