Signed-off-by: Olivier Brunel <[email protected]>
---
 doc/pacman.8.txt      |  5 +++++
 doc/pacman.conf.5.txt |  6 ++++++
 lib/libalpm/alpm.h    |  3 +++
 lib/libalpm/dload.c   |  1 +
 lib/libalpm/handle.c  | 26 ++++++++++++++++++++++++++
 lib/libalpm/handle.h  |  1 +
 src/pacman/conf.c     | 11 +++++++++++
 src/pacman/conf.h     |  4 +++-
 src/pacman/pacman.c   | 11 +++++++++++
 src/pacman/util.c     | 45 +++++++++++++++++++++++++++++++++++++++++++++
 src/pacman/util.h     |  2 ++
 11 files changed, 114 insertions(+), 1 deletion(-)

diff --git a/doc/pacman.8.txt b/doc/pacman.8.txt
index 231e0bc..1890cd9 100644
--- a/doc/pacman.8.txt
+++ b/doc/pacman.8.txt
@@ -266,6 +266,11 @@ Upgrade Options (apply to '-S' and '-U')[[UO]]
 *\--needed*::
        Do not reinstall the targets that are already up-to-date.
 
+*\--maxdlspeed* <speed>::
+       Sets the maximum download speed to the specified speed in bytes/s, 
unless a
+       suffix is appended. Suffix 'k' or 'K' will count as KiB/s, 'm' or 'M' as
+       MiB/s, and 'g' or 'G' as GiB/s.
+
 
 Query Options (apply to '-Q')[[QO]]
 -----------------------------------
diff --git a/doc/pacman.conf.5.txt b/doc/pacman.conf.5.txt
index c665870..49ce63b 100644
--- a/doc/pacman.conf.5.txt
+++ b/doc/pacman.conf.5.txt
@@ -201,6 +201,12 @@ Options
        bar is still based solely on the current file download.
        This option won't work if XferCommand is used.
 
+*MaxDlSpeed*::
+       Sets the maximum download speed to the specified speed in bytes/s, 
unless a
+       suffix is appended. Suffix 'k' or 'K' will count as KiB/s, 'm' or 'M' as
+       MiB/s, and 'g' or 'G' as GiB/s.
+       This option won't work if XferCommand is used.
+
 *CheckSpace*::
        Performs an approximate check for adequate available disk space before
        installing packages.
diff --git a/lib/libalpm/alpm.h b/lib/libalpm/alpm.h
index 168d71b..7e4e9da 100644
--- a/lib/libalpm/alpm.h
+++ b/lib/libalpm/alpm.h
@@ -925,6 +925,9 @@ int alpm_option_set_local_file_siglevel(alpm_handle_t 
*handle, alpm_siglevel_t l
 alpm_siglevel_t alpm_option_get_remote_file_siglevel(alpm_handle_t *handle);
 int alpm_option_set_remote_file_siglevel(alpm_handle_t *handle, 
alpm_siglevel_t level);
 
+off_t alpm_option_get_maxdlspeed(alpm_handle_t *handle);
+int alpm_option_set_maxdlspeed(alpm_handle_t *handle, off_t speed);
+
 /** @} */
 
 /** @addtogroup alpm_api_databases Database Functions
diff --git a/lib/libalpm/dload.c b/lib/libalpm/dload.c
index 31ae82c..8c6d6af 100644
--- a/lib/libalpm/dload.c
+++ b/lib/libalpm/dload.c
@@ -295,6 +295,7 @@ static void curl_set_handle_opts(struct dload_payload 
*payload,
        curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);
        curl_easy_setopt(curl, CURLOPT_PROGRESSFUNCTION, dload_progress_cb);
        curl_easy_setopt(curl, CURLOPT_PROGRESSDATA, (void *)payload);
+       curl_easy_setopt(curl, CURLOPT_MAX_RECV_SPEED_LARGE, 
handle->maxdlspeed);
        curl_easy_setopt(curl, CURLOPT_LOW_SPEED_LIMIT, 1L);
        curl_easy_setopt(curl, CURLOPT_LOW_SPEED_TIME, 10L);
        curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, dload_parseheader_cb);
diff --git a/lib/libalpm/handle.c b/lib/libalpm/handle.c
index e9439a0..9cab5da 100644
--- a/lib/libalpm/handle.c
+++ b/lib/libalpm/handle.c
@@ -844,4 +844,30 @@ alpm_siglevel_t SYMEXPORT 
alpm_option_get_remote_file_siglevel(alpm_handle_t *ha
        }
 }
 
+off_t SYMEXPORT alpm_option_get_maxdlspeed(alpm_handle_t *handle)
+{
+       CHECK_HANDLE(handle, return -1);
+#ifdef HAVE_LIBCURL
+       return (off_t) handle->maxdlspeed;
+#else
+       return 0;
+#endif
+}
+
+int SYMEXPORT alpm_option_set_maxdlspeed(alpm_handle_t *handle, off_t speed)
+{
+       CHECK_HANDLE(handle, return -1);
+#ifdef HAVE_LIBCURL
+       if(speed >= 0) {
+               handle->maxdlspeed = (curl_off_t) speed;
+               return 0;
+       } else
+#else
+       if(speed == 0)
+               return 0;
+       else
+#endif
+               RET_ERR(handle, ALPM_ERR_WRONG_ARGS, -1);
+}
+
 /* vim: set noet: */
diff --git a/lib/libalpm/handle.h b/lib/libalpm/handle.h
index a1d0f9a..f55b6ed 100644
--- a/lib/libalpm/handle.h
+++ b/lib/libalpm/handle.h
@@ -60,6 +60,7 @@ struct __alpm_handle_t {
 #ifdef HAVE_LIBCURL
        /* libcurl handle */
        CURL *curl;             /* reusable curl_easy handle */
+       curl_off_t maxdlspeed;  /* maximum download speed (B/s) */
 #endif
 
 #ifdef HAVE_LIBGPGME
diff --git a/src/pacman/conf.c b/src/pacman/conf.c
index 25de7af..39cc15c 100644
--- a/src/pacman/conf.c
+++ b/src/pacman/conf.c
@@ -544,6 +544,16 @@ static int _parse_options(const char *key, char *value,
                        }
                        config->deltaratio = ratio;
                        pm_printf(ALPM_LOG_DEBUG, "config: usedelta = %f\n", 
ratio);
+               } else if(strcmp(key, "MaxDlSpeed") == 0) {
+                       off_t speed = parsesize(value);
+                       if(speed < 0) {
+                               pm_printf(ALPM_LOG_ERROR,
+                                               _("config file %s, line %d: 
invalid value for '%s' : '%s'\n"),
+                                               file, linenum, "MaxDlSpeed", 
value);
+                               return 1;
+                       }
+                       config->maxdlspeed = speed;
+                       pm_printf(ALPM_LOG_DEBUG, "config: maxdlspeed = %jd\n", 
(intmax_t) speed);
                } else if(strcmp(key, "DBPath") == 0) {
                        /* don't overwrite a path specified on the command line 
*/
                        if(!config->dbpath) {
@@ -810,6 +820,7 @@ static int setup_libalpm(void)
        alpm_option_set_checkspace(handle, config->checkspace);
        alpm_option_set_usesyslog(handle, config->usesyslog);
        alpm_option_set_deltaratio(handle, config->deltaratio);
+       alpm_option_set_maxdlspeed(handle, config->maxdlspeed);
 
        alpm_option_set_ignorepkgs(handle, config->ignorepkg);
        alpm_option_set_ignoregroups(handle, config->ignoregrp);
diff --git a/src/pacman/conf.h b/src/pacman/conf.h
index 2aba8bf..77353a2 100644
--- a/src/pacman/conf.h
+++ b/src/pacman/conf.h
@@ -56,6 +56,7 @@ typedef struct __config_t {
        unsigned short usesyslog;
        unsigned short color;
        double deltaratio;
+       off_t maxdlspeed;
        char *arch;
        char *print_format;
        /* unfortunately, we have to keep track of paths both here and in the 
library
@@ -201,7 +202,8 @@ enum {
        OP_VERBOSE,
        OP_DOWNLOADONLY,
        OP_REFRESH,
-       OP_ASSUMEINSTALLED
+       OP_ASSUMEINSTALLED,
+       OP_MAXDLSPEED
 };
 
 /* clean method */
diff --git a/src/pacman/pacman.c b/src/pacman/pacman.c
index be52d1b..91f8500 100644
--- a/src/pacman/pacman.c
+++ b/src/pacman/pacman.c
@@ -194,6 +194,8 @@ static void usage(int op, const char * const myname)
                                addlist(_("      --ignore <pkg>   ignore a 
package upgrade (can be used more than once)\n"));
                                addlist(_("      --ignoregroup <grp>\n"
                                          "                       ignore a 
group upgrade (can be used more than once)\n"));
+                               addlist(_("      --maxdlspeed <speed>\n"
+                                         "                       set the 
maximum download speed\n"));
                                /* pass through */
                        case PM_OP_REMOVE:
                                addlist(_("  -d, --nodeps         skip 
dependency version checks (-dd to skip all checks)\n"));
@@ -713,6 +715,14 @@ static int parsearg_upgrade(int opt)
                case OP_IGNOREGROUP:
                        parsearg_util_addlist(&(config->ignoregrp));
                        break;
+               case OP_MAXDLSPEED:
+                       {
+                               off_t speed = parsesize(optarg);
+                               if(speed < 0)
+                                       return 1;
+                               config->maxdlspeed = speed;
+                               break;
+                       }
                default: return 1;
        }
        return 0;
@@ -929,6 +939,7 @@ static int parseargs(int argc, char *argv[])
                {"ignoregroup", required_argument, 0, OP_IGNOREGROUP},
                {"needed",     no_argument,       0, OP_NEEDED},
                {"asexplicit",     no_argument,   0, OP_ASEXPLICIT},
+               {"maxdlspeed", required_argument, 0, OP_MAXDLSPEED},
                {"arch",       required_argument, 0, OP_ARCH},
                {"print-format", required_argument, 0, OP_PRINTFORMAT},
                {"gpgdir",     required_argument, 0, OP_GPGDIR},
diff --git a/src/pacman/util.c b/src/pacman/util.c
index 81780f7..35b4f23 100644
--- a/src/pacman/util.c
+++ b/src/pacman/util.c
@@ -1763,4 +1763,49 @@ int pm_vfprintf(FILE *stream, alpm_loglevel_t level, 
const char *format, va_list
        return ret;
 }
 
+off_t parsesize(const char *str)
+{
+       long size;
+       char *endptr;
+
+       size = strtol(str, &endptr, 10);
+       if((size == LONG_MIN || size == LONG_MAX) && errno == ERANGE) {
+               return -1;
+       }
+       if(*endptr != '\0') {
+               if(endptr[1] != '\0') {
+                       return -1;
+               }
+               switch(*endptr) {
+                       case 'g':
+                       case 'G':
+                               if(size > LONG_MAX / 1024) {
+                                       return -1;
+                               }
+                               size *= 1024;
+                               /* fallthrough */
+                       case 'm':
+                       case 'M':
+                               if(size > LONG_MAX / 1024) {
+                                       return -1;
+                               }
+                               size *= 1024;
+                               /* fallthrough */
+                       case 'k':
+                       case 'K':
+                               if(size > LONG_MAX / 1024) {
+                                       return -1;
+                               }
+                               size *= 1024;
+                               break;
+                       default:
+                               return -1;
+               }
+       }
+       if(size < 0) {
+               return -1;
+       }
+       return (off_t) size;
+}
+
 /* vim: set noet: */
diff --git a/src/pacman/util.h b/src/pacman/util.h
index f5e37c8..7d0a897 100644
--- a/src/pacman/util.h
+++ b/src/pacman/util.h
@@ -82,6 +82,8 @@ int pm_vfprintf(FILE *stream, alpm_loglevel_t level, const 
char *format, va_list
 int pm_sprintf(char **string, alpm_loglevel_t level, const char *format, ...) 
__attribute__((format(printf,3,4)));
 int pm_vasprintf(char **string, alpm_loglevel_t level, const char *format, 
va_list args) __attribute__((format(printf,3,0)));
 
+off_t parsesize(const char *str);
+
 #endif /* _PM_UTIL_H */
 
 /* vim: set noet: */
-- 
2.9.3

Reply via email to