[pacman-dev] [PATCH] Timeout when download problems occur

Dan McGee dan at archlinux.org
Tue Feb 15 18:53:56 EST 2011


We already set fetchTimeout to 10 seconds, but this does not apply for some
of the connection setup steps such as connect(). This left us hanging in a
few places where we would normally be stuck in a system call for an
indeterminate amount of time.

This addresses FS#15369, which has grown to include and duplicate several
other bugs and failures such as specifying a non-existent FTP server, DSL
disconnections, etc.

Signed-off-by: Dan McGee <dan at archlinux.org>
---

Anyone that wants to look this over, it was pretty simple and kills one of our
long-lingering issues before a 3.5.0 release.

The output isn't necessarily beautiful, but it at least doesn't hang forever
now. I tested this by adding a line like
    Server = ftp://192.168.4.4/$repo/os/$arch
to my /etc/pacman.d/mirrorlist file, and then running pacman -Sy.

$ sudo ./src/pacman/pacman -Sy
Password: 
:: Synchronizing package databases...
 testing is up to date
error: failed retrieving file 'core.db' from 192.168.4.4 : Interrupted system call
 core is up to date
error: failed retrieving file 'extra.db' from 192.168.4.4 : Interrupted system call
 extra is up to date
 community-testing is up to date
error: failed retrieving file 'multilib.db' from 192.168.4.4 : Interrupted system call
 multilib is up to date
error: failed retrieving file 'community.db' from 192.168.4.4 : Interrupted system call
 community is up to date

-Dan

 lib/libalpm/dload.c |   21 +++++++++++++++++----
 1 files changed, 17 insertions(+), 4 deletions(-)

diff --git a/lib/libalpm/dload.c b/lib/libalpm/dload.c
index 7a98eb1..44ff17c 100644
--- a/lib/libalpm/dload.c
+++ b/lib/libalpm/dload.c
@@ -88,10 +88,10 @@ static const char *gethost(struct url *fileurl)
 int dload_interrupted;
 static void inthandler(int signum)
 {
-	dload_interrupted = 1;
+	dload_interrupted = signum;
 }
 
-#define check_stop() if(dload_interrupted) { ret = -1; goto cleanup; }
+#define check_stop() do { alarm(0); if(dload_interrupted) { ret = -1; goto cleanup; } } while(0)
 enum sighandlers { OLD = 0, NEW = 1 };
 
 static int download_internal(const char *url, const char *localpath,
@@ -102,7 +102,7 @@ static int download_internal(const char *url, const char *localpath,
 	off_t dl_thisfile = 0;
 	ssize_t nread = 0;
 	char *tempfile, *destfile, *filename;
-	struct sigaction sig_pipe[2], sig_int[2];
+	struct sigaction sig_pipe[2], sig_int[2], sig_alrm[2];
 
 	off_t local_size = 0;
 	time_t local_time = 0;
@@ -169,6 +169,12 @@ static int download_internal(const char *url, const char *localpath,
 	sigaction(SIGINT, NULL, &sig_int[OLD]);
 	sigaction(SIGINT, &sig_int[NEW], NULL);
 
+	sig_alrm[NEW].sa_handler = &inthandler;
+	sigemptyset(&sig_alrm[NEW].sa_mask);
+	sig_alrm[NEW].sa_flags = 0;
+	sigaction(SIGALRM, NULL, &sig_alrm[OLD]);
+	sigaction(SIGALRM, &sig_alrm[NEW], NULL);
+
 	/* NOTE: libfetch does not reset the error code, be sure to do it before
 	 * calls into the library */
 
@@ -184,7 +190,9 @@ static int download_internal(const char *url, const char *localpath,
 	 * trouble in trying to do both size and "if-modified-since" logic in a
 	 * non-stat request, so avoid it. */
 	fetchLastErrCode = 0;
+	alarm(fetchTimeout);
 	if(fetchStat(fileurl, &ust, "") == -1) {
+		alarm(0);
 		pm_errno = PM_ERR_LIBFETCH;
 		_alpm_log(PM_LOG_ERROR, _("failed retrieving file '%s' from %s : %s\n"),
 				filename, gethost(fileurl), fetchLastErrString);
@@ -211,6 +219,7 @@ static int download_internal(const char *url, const char *localpath,
 	}
 
 	fetchLastErrCode = 0;
+	alarm(fetchTimeout);
 	dlf = fetchGet(fileurl, "");
 	check_stop();
 
@@ -252,6 +261,7 @@ static int download_internal(const char *url, const char *localpath,
 		handle->dlcb(filename, 0, ust.size);
 	}
 
+	alarm(fetchTimeout);
 	while((nread = fetchIO_read(dlf, buffer, PM_DLBUF_LEN)) > 0) {
 		check_stop();
 		size_t nwritten = 0;
@@ -268,7 +278,9 @@ static int download_internal(const char *url, const char *localpath,
 		if(handle->dlcb) {
 			handle->dlcb(filename, dl_thisfile, ust.size);
 		}
+		alarm(fetchTimeout);
 	}
+	alarm(0);
 
 	/* did the transfer complete normally? */
 	if (nread == -1) {
@@ -333,10 +345,11 @@ cleanup:
 	fetchFreeURL(fileurl);
 
 	/* restore the old signal handlers */
+	sigaction(SIGALRM, &sig_alrm[OLD], NULL);
 	sigaction(SIGINT, &sig_int[OLD], NULL);
 	sigaction(SIGPIPE, &sig_pipe[OLD], NULL);
 	/* if we were interrupted, trip the old handler */
-	if(dload_interrupted) {
+	if(dload_interrupted == SIGINT) {
 		raise(SIGINT);
 	}
 
-- 
1.7.4



More information about the pacman-dev mailing list