summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorSebastian Nowicki <sebnow@gmail.com>2009-04-04 10:17:30 +0200
committerDan McGee <dan@archlinux.org>2009-07-23 04:27:46 +0200
commit30c4d53ce5c16cbbb17a88fe1ad14faf53d91999 (patch)
treeb2f41fd8fc49733f6487c3a4ecf7dbc919fdde43 /src
parent1d19f0896ccc1560a7e2f5b93cfe095b4aefe84a (diff)
downloadpacman-30c4d53ce5c16cbbb17a88fe1ad14faf53d91999.tar.gz
pacman-30c4d53ce5c16cbbb17a88fe1ad14faf53d91999.tar.xz
Add a fetch callback to allow front-end download support
This allows a frontend to define its own download algorithm so that the libfetch dependency can be omitted without using an external process. The callback will be used when if it is defined, otherwise the old behavior applies. Signed-off-by: Sebastian Nowicki <sebnow@gmail.com> [Dan: minor cleanups] Signed-off-by: Dan McGee <dan@archlinux.org>
Diffstat (limited to 'src')
-rw-r--r--src/pacman/conf.c1
-rw-r--r--src/pacman/conf.h1
-rw-r--r--src/pacman/pacman.c115
3 files changed, 116 insertions, 1 deletions
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) {