[pacman-dev] [PATCH] Add option MaxDlSpeed to limit download speed

Olivier Brunel jjk at jjacky.com
Fri Aug 19 18:12:44 UTC 2016


Signed-off-by: Olivier Brunel <jjk at jjacky.com>
---
 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


More information about the pacman-dev mailing list