diff options
Diffstat (limited to 'src/pacman')
-rw-r--r-- | src/pacman/conf.c | 1 | ||||
-rw-r--r-- | src/pacman/conf.h | 1 | ||||
-rw-r--r-- | src/pacman/pacman.c | 115 |
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) { |