[pacman-dev] add front-end provided context to callbacks

Message ID 20210425213201.80920-1-andrew.gregory.8@gmail.com
State Accepted, archived
Headers show
Series [pacman-dev] add front-end provided context to callbacks | expand

Commit Message

Andrew Gregory April 25, 2021, 9:32 p.m. UTC
Our callbacks require front-ends to maintain state in order to provide
reasonable output.  The new download callback in particular requires
much more complex state information to be saved.  Without the ability to
provide context, state must be saved globally, which may not be possible
for all front-ends.  Scripting language bindings in particular have no
way to register per-handle callbacks without some form of context.

Implements: FS#12721

Signed-off-by: Andrew Gregory <andrew.gregory.8@gmail.com>
---
 lib/libalpm/alpm.h    | 73 +++++++++++++++++++++++++++++++++++--------
 lib/libalpm/dload.c   | 11 ++++---
 lib/libalpm/handle.c  | 54 ++++++++++++++++++++++++++++----
 lib/libalpm/handle.h  | 12 +++++--
 lib/libalpm/log.c     |  2 +-
 src/pacman/callback.c | 18 +++++++----
 src/pacman/callback.h | 14 ++++-----
 src/pacman/conf.c     | 18 ++++++-----
 src/util/testpkg.c    |  7 +++--
 9 files changed, 157 insertions(+), 52 deletions(-)

Comments

Allan McRae April 26, 2021, 7:47 a.m. UTC | #1
On 26/4/21 7:32 am, Andrew Gregory wrote:
> Our callbacks require front-ends to maintain state in order to provide
> reasonable output.  The new download callback in particular requires
> much more complex state information to be saved.  Without the ability to
> provide context, state must be saved globally, which may not be possible
> for all front-ends.  Scripting language bindings in particular have no
> way to register per-handle callbacks without some form of context.
> 
> Implements: FS#12721
> 
> Signed-off-by: Andrew Gregory <andrew.gregory.8@gmail.com>

I'm adding this despite the slushy freeze.  Near zero risk for
alpm/pacman given the nature of the patch and Andrew asked nicely!

A

Patch

diff --git a/lib/libalpm/alpm.h b/lib/libalpm/alpm.h
index 833df829..496732d7 100644
--- a/lib/libalpm/alpm.h
+++ b/lib/libalpm/alpm.h
@@ -971,8 +971,9 @@  typedef union _alpm_event_t {
 /** Event callback.
  *
  * Called when an event occurs
+ * @param ctx user-provided context
  * @param event the event that occurred */
-typedef void (*alpm_cb_event)(alpm_event_t *);
+typedef void (*alpm_cb_event)(void *ctx, alpm_event_t *);
 
 /**
  * Type of question.
@@ -1114,9 +1115,10 @@  typedef union _alpm_question_t {
 /** Question callback.
  *
  * This callback allows user to give input and decide what to do during certain events
+ * @param ctx user-provided context
  * @param question the question being asked.
  */
-typedef void (*alpm_cb_question)(alpm_question_t *);
+typedef void (*alpm_cb_question)(void *ctx, alpm_question_t *);
 
 /** An enum over different kinds of progress alerts. */
 typedef enum _alpm_progress_t {
@@ -1147,6 +1149,7 @@  typedef enum _alpm_progress_t {
  * Alert the front end about the progress of certain events.
  * Allows the implementation of loading bars for events that
  * make take a while to complete.
+ * @param ctx user-provided context
  * @param progress the kind of event that is progressing
  * @param pkg for package operations, the name of the package being operated on
  * @param percent the percent completion of the action
@@ -1154,7 +1157,7 @@  typedef enum _alpm_progress_t {
  * @param current the current amount of items completed
  */
 /** Progress callback */
-typedef void (*alpm_cb_progress)(alpm_progress_t progress, const char *pkg,
+typedef void (*alpm_cb_progress)(void *ctx, alpm_progress_t progress, const char *pkg,
 		int percent, size_t howmany, size_t current);
 
 /*
@@ -1201,22 +1204,24 @@  typedef struct _alpm_download_event_completed_t {
 } alpm_download_event_completed_t;
 
 /** Type of download progress callbacks.
+ * @param ctx user-provided context
  * @param filename the name of the file being downloaded
  * @param event the event type
  * @param data the event data of type alpm_download_event_*_t
  */
-typedef void (*alpm_cb_download)(const char *filename,
+typedef void (*alpm_cb_download)(void *ctx, const char *filename,
 		alpm_download_event_type_t event, void *data);
 
 
 /** A callback for downloading files
+ * @param ctx user-provided context
  * @param url the URL of the file to be downloaded
  * @param localpath the directory to which the file should be downloaded
  * @param force whether to force an update, even if the file is the same
  * @return 0 on success, 1 if the file exists and is identical, -1 on
  * error.
  */
-typedef int (*alpm_cb_fetch)(const char *url, const char *localpath,
+typedef int (*alpm_cb_fetch)(void *ctx, const char *url, const char *localpath,
 		int force);
 
 /* End of libalpm_cb */
@@ -1464,11 +1469,12 @@  typedef enum _alpm_loglevel_t {
  * libalpm will call this function whenever something is to be logged.
  * many libalpm will produce log output. Additionally any calls to \link alpm_logaction
  * \endlink will also call this callback.
+ * @param ctx user-provided context
  * @param level the currently set loglevel
  * @param fmt the printf like format string
  * @param args printf like arguments
  */
-typedef void (*alpm_cb_log)(alpm_loglevel_t level, const char *fmt, va_list args);
+typedef void (*alpm_cb_log)(void *ctx, alpm_loglevel_t level, const char *fmt, va_list args);
 
 /** A printf-like function for logging.
  * @param handle the context handle
@@ -1498,12 +1504,19 @@  int alpm_logaction(alpm_handle_t *handle, const char *prefix,
  */
 alpm_cb_log alpm_option_get_logcb(alpm_handle_t *handle);
 
+/** Returns the callback used for logging.
+ * @param handle the context handle
+ * @return the currently set log callback context
+ */
+void *alpm_option_get_logcb_ctx(alpm_handle_t *handle);
+
 /** Sets the callback used for logging.
  * @param handle the context handle
  * @param cb the cb to use
+ * @param ctx user-provided context to pass to cb
  * @return 0 on success, -1 on error (pm_errno is set accordingly)
  */
-int alpm_option_set_logcb(alpm_handle_t *handle, alpm_cb_log cb);
+int alpm_option_set_logcb(alpm_handle_t *handle, alpm_cb_log cb, void *ctx);
 
 /** Returns the callback used to report download progress.
  * @param handle the context handle
@@ -1511,12 +1524,19 @@  int alpm_option_set_logcb(alpm_handle_t *handle, alpm_cb_log cb);
  */
 alpm_cb_download alpm_option_get_dlcb(alpm_handle_t *handle);
 
+/** Returns the callback used to report download progress.
+ * @param handle the context handle
+ * @return the currently set download callback context
+ */
+void *alpm_option_get_dlcb_ctx(alpm_handle_t *handle);
+
 /** Sets the callback used to report download progress.
  * @param handle the context handle
  * @param cb the cb to use
+ * @param ctx user-provided context to pass to cb
  * @return 0 on success, -1 on error (pm_errno is set accordingly)
  */
-int alpm_option_set_dlcb(alpm_handle_t *handle, alpm_cb_download cb);
+int alpm_option_set_dlcb(alpm_handle_t *handle, alpm_cb_download cb, void *ctx);
 
 /** Returns the downloading callback.
  * @param handle the context handle
@@ -1524,12 +1544,19 @@  int alpm_option_set_dlcb(alpm_handle_t *handle, alpm_cb_download cb);
  */
 alpm_cb_fetch alpm_option_get_fetchcb(alpm_handle_t *handle);
 
+/** Returns the downloading callback.
+ * @param handle the context handle
+ * @return the currently set fetch callback context
+ */
+void *alpm_option_get_fetchcb_ctx(alpm_handle_t *handle);
+
 /** Sets the downloading callback.
  * @param handle the context handle
  * @param cb the cb to use
+ * @param ctx user-provided context to pass to cb
  * @return 0 on success, -1 on error (pm_errno is set accordingly)
  */
-int alpm_option_set_fetchcb(alpm_handle_t *handle, alpm_cb_fetch cb);
+int alpm_option_set_fetchcb(alpm_handle_t *handle, alpm_cb_fetch cb, void *ctx);
 
 /** Returns the callback used for events.
  * @param handle the context handle
@@ -1537,12 +1564,19 @@  int alpm_option_set_fetchcb(alpm_handle_t *handle, alpm_cb_fetch cb);
  */
 alpm_cb_event alpm_option_get_eventcb(alpm_handle_t *handle);
 
+/** Returns the callback used for events.
+ * @param handle the context handle
+ * @return the currently set event callback context
+ */
+void *alpm_option_get_eventcb_ctx(alpm_handle_t *handle);
+
 /** Sets the callback used for events.
  * @param handle the context handle
  * @param cb the cb to use
+ * @param ctx user-provided context to pass to cb
  * @return 0 on success, -1 on error (pm_errno is set accordingly)
  */
-int alpm_option_set_eventcb(alpm_handle_t *handle, alpm_cb_event cb);
+int alpm_option_set_eventcb(alpm_handle_t *handle, alpm_cb_event cb, void *ctx);
 
 /** Returns the callback used for questions.
  * @param handle the context handle
@@ -1550,13 +1584,19 @@  int alpm_option_set_eventcb(alpm_handle_t *handle, alpm_cb_event cb);
  */
 alpm_cb_question alpm_option_get_questioncb(alpm_handle_t *handle);
 
+/** Returns the callback used for questions.
+ * @param handle the context handle
+ * @return the currently set question callback context
+ */
+void *alpm_option_get_questioncb_ctx(alpm_handle_t *handle);
+
 /** Sets the callback used for questions.
  * @param handle the context handle
  * @param cb the cb to use
+ * @param ctx user-provided context to pass to cb
  * @return 0 on success, -1 on error (pm_errno is set accordingly)
  */
-int alpm_option_set_questioncb(alpm_handle_t *handle, alpm_cb_question cb);
-
+int alpm_option_set_questioncb(alpm_handle_t *handle, alpm_cb_question cb, void *ctx);
 
 /**Returns the callback used for operation progress.
  * @param handle the context handle
@@ -1564,12 +1604,19 @@  int alpm_option_set_questioncb(alpm_handle_t *handle, alpm_cb_question cb);
  */
 alpm_cb_progress alpm_option_get_progresscb(alpm_handle_t *handle);
 
+/**Returns the callback used for operation progress.
+ * @param handle the context handle
+ * @return the currently set progress callback context
+ */
+void *alpm_option_get_progresscb_ctx(alpm_handle_t *handle);
+
 /** Sets the callback used for operation progress.
  * @param handle the context handle
  * @param cb the cb to use
+ * @param ctx user-provided context to pass to cb
  * @return 0 on success, -1 on error (pm_errno is set accordingly)
  */
-int alpm_option_set_progresscb(alpm_handle_t *handle, alpm_cb_progress cb);
+int alpm_option_set_progresscb(alpm_handle_t *handle, alpm_cb_progress cb, void *ctx);
 /* End of callback accessors */
 /** @} */
 
diff --git a/lib/libalpm/dload.c b/lib/libalpm/dload.c
index a4c42f8d..70ec318a 100644
--- a/lib/libalpm/dload.c
+++ b/lib/libalpm/dload.c
@@ -209,7 +209,8 @@  static int dload_progress_cb(void *file, curl_off_t dltotal, curl_off_t dlnow,
 	 * download_size (nor included in the total download size callback) */
 	cb_data.total = dltotal;
 	cb_data.downloaded = dlnow;
-	payload->handle->dlcb(payload->remote_name, ALPM_DOWNLOAD_PROGRESS, &cb_data);
+	payload->handle->dlcb(payload->handle->dlcb_ctx,
+			payload->remote_name, ALPM_DOWNLOAD_PROGRESS, &cb_data);
 	payload->prevprogress = current_size;
 
 	return 0;
@@ -672,7 +673,7 @@  cleanup:
 		alpm_download_event_completed_t cb_data = {0};
 		cb_data.total = bytes_dl;
 		cb_data.result = ret;
-		handle->dlcb(payload->remote_name, ALPM_DOWNLOAD_COMPLETED, &cb_data);
+		handle->dlcb(handle->dlcb_ctx, payload->remote_name, ALPM_DOWNLOAD_COMPLETED, &cb_data);
 	}
 
 	curl_multi_remove_handle(curlm, curl);
@@ -806,7 +807,7 @@  static int curl_download_internal(alpm_handle_t *handle,
 			if(curl_add_payload(handle, curlm, payload, localpath) == 0) {
 				if(handle->dlcb && !payload->signature) {
 					alpm_download_event_init_t cb_data = {.optional = payload->errors_ok};
-					handle->dlcb(payload->remote_name, ALPM_DOWNLOAD_INIT, &cb_data);
+					handle->dlcb(handle->dlcb_ctx, payload->remote_name, ALPM_DOWNLOAD_INIT, &cb_data);
 				}
 
 				payloads = payloads->next;
@@ -877,7 +878,7 @@  int _alpm_download(alpm_handle_t *handle,
 			int success = 0;
 
 			if(payload->fileurl) {
-				if (handle->fetchcb(payload->fileurl, localpath, payload->force) != -1) {
+				if (handle->fetchcb(handle->fetchcb_ctx, payload->fileurl, localpath, payload->force) != -1) {
 					success = 1;
 					break;
 				}
@@ -891,7 +892,7 @@  int _alpm_download(alpm_handle_t *handle,
 					MALLOC(fileurl, len, RET_ERR(handle, ALPM_ERR_MEMORY, -1));
 					snprintf(fileurl, len, "%s/%s", server, payload->filepath);
 
-					ret = handle->fetchcb(fileurl, localpath, payload->force);
+					ret = handle->fetchcb(handle->fetchcb_ctx, fileurl, localpath, payload->force);
 					free(fileurl);
 
 					if (ret != -1) {
diff --git a/lib/libalpm/handle.c b/lib/libalpm/handle.c
index 7b8cb1da..86361070 100644
--- a/lib/libalpm/handle.c
+++ b/lib/libalpm/handle.c
@@ -162,36 +162,72 @@  alpm_cb_log SYMEXPORT alpm_option_get_logcb(alpm_handle_t *handle)
 	return handle->logcb;
 }
 
+void SYMEXPORT *alpm_option_get_logcb_ctx(alpm_handle_t *handle)
+{
+	CHECK_HANDLE(handle, return NULL);
+	return handle->logcb_ctx;
+}
+
 alpm_cb_download SYMEXPORT alpm_option_get_dlcb(alpm_handle_t *handle)
 {
 	CHECK_HANDLE(handle, return NULL);
 	return handle->dlcb;
 }
 
+void SYMEXPORT *alpm_option_get_dlcb_ctx(alpm_handle_t *handle)
+{
+	CHECK_HANDLE(handle, return NULL);
+	return handle->dlcb_ctx;
+}
+
 alpm_cb_fetch SYMEXPORT alpm_option_get_fetchcb(alpm_handle_t *handle)
 {
 	CHECK_HANDLE(handle, return NULL);
 	return handle->fetchcb;
 }
 
+void SYMEXPORT *alpm_option_get_fetchcb_ctx(alpm_handle_t *handle)
+{
+	CHECK_HANDLE(handle, return NULL);
+	return handle->fetchcb_ctx;
+}
+
 alpm_cb_event SYMEXPORT alpm_option_get_eventcb(alpm_handle_t *handle)
 {
 	CHECK_HANDLE(handle, return NULL);
 	return handle->eventcb;
 }
 
+void SYMEXPORT *alpm_option_get_eventcb_ctx(alpm_handle_t *handle)
+{
+	CHECK_HANDLE(handle, return NULL);
+	return handle->eventcb_ctx;
+}
+
 alpm_cb_question SYMEXPORT alpm_option_get_questioncb(alpm_handle_t *handle)
 {
 	CHECK_HANDLE(handle, return NULL);
 	return handle->questioncb;
 }
 
+void SYMEXPORT *alpm_option_get_questioncb_ctx(alpm_handle_t *handle)
+{
+	CHECK_HANDLE(handle, return NULL);
+	return handle->questioncb_ctx;
+}
+
 alpm_cb_progress SYMEXPORT alpm_option_get_progresscb(alpm_handle_t *handle)
 {
 	CHECK_HANDLE(handle, return NULL);
 	return handle->progresscb;
 }
 
+void SYMEXPORT *alpm_option_get_progresscb_ctx(alpm_handle_t *handle)
+{
+	CHECK_HANDLE(handle, return NULL);
+	return handle->progresscb_ctx;
+}
+
 const char SYMEXPORT *alpm_option_get_root(alpm_handle_t *handle)
 {
 	CHECK_HANDLE(handle, return NULL);
@@ -300,45 +336,51 @@  int SYMEXPORT alpm_option_get_parallel_downloads(alpm_handle_t *handle)
 	return handle->parallel_downloads;
 }
 
-int SYMEXPORT alpm_option_set_logcb(alpm_handle_t *handle, alpm_cb_log cb)
+int SYMEXPORT alpm_option_set_logcb(alpm_handle_t *handle, alpm_cb_log cb, void *ctx)
 {
 	CHECK_HANDLE(handle, return -1);
 	handle->logcb = cb;
+	handle->logcb_ctx = ctx;
 	return 0;
 }
 
-int SYMEXPORT alpm_option_set_dlcb(alpm_handle_t *handle, alpm_cb_download cb)
+int SYMEXPORT alpm_option_set_dlcb(alpm_handle_t *handle, alpm_cb_download cb, void *ctx)
 {
 	CHECK_HANDLE(handle, return -1);
 	handle->dlcb = cb;
+	handle->dlcb_ctx = ctx;
 	return 0;
 }
 
-int SYMEXPORT alpm_option_set_fetchcb(alpm_handle_t *handle, alpm_cb_fetch cb)
+int SYMEXPORT alpm_option_set_fetchcb(alpm_handle_t *handle, alpm_cb_fetch cb, void *ctx)
 {
 	CHECK_HANDLE(handle, return -1);
 	handle->fetchcb = cb;
+	handle->fetchcb_ctx = ctx;
 	return 0;
 }
 
-int SYMEXPORT alpm_option_set_eventcb(alpm_handle_t *handle, alpm_cb_event cb)
+int SYMEXPORT alpm_option_set_eventcb(alpm_handle_t *handle, alpm_cb_event cb, void *ctx)
 {
 	CHECK_HANDLE(handle, return -1);
 	handle->eventcb = cb;
+	handle->eventcb_ctx = ctx;
 	return 0;
 }
 
-int SYMEXPORT alpm_option_set_questioncb(alpm_handle_t *handle, alpm_cb_question cb)
+int SYMEXPORT alpm_option_set_questioncb(alpm_handle_t *handle, alpm_cb_question cb, void *ctx)
 {
 	CHECK_HANDLE(handle, return -1);
 	handle->questioncb = cb;
+	handle->questioncb_ctx = ctx;
 	return 0;
 }
 
-int SYMEXPORT alpm_option_set_progresscb(alpm_handle_t *handle, alpm_cb_progress cb)
+int SYMEXPORT alpm_option_set_progresscb(alpm_handle_t *handle, alpm_cb_progress cb, void *ctx)
 {
 	CHECK_HANDLE(handle, return -1);
 	handle->progresscb = cb;
+	handle->progresscb_ctx = ctx;
 	return 0;
 }
 
diff --git a/lib/libalpm/handle.h b/lib/libalpm/handle.h
index 2d8d0f9e..9d938d18 100644
--- a/lib/libalpm/handle.h
+++ b/lib/libalpm/handle.h
@@ -34,19 +34,19 @@ 
 #define EVENT(h, e) \
 do { \
 	if((h)->eventcb) { \
-		(h)->eventcb((alpm_event_t *) (e)); \
+		(h)->eventcb((h)->eventcb_ctx, (alpm_event_t *) (e)); \
 	} \
 } while(0)
 #define QUESTION(h, q) \
 do { \
 	if((h)->questioncb) { \
-		(h)->questioncb((alpm_question_t *) (q)); \
+		(h)->questioncb((h)->questioncb_ctx, (alpm_question_t *) (q)); \
 	} \
 } while(0)
 #define PROGRESS(h, e, p, per, n, r) \
 do { \
 	if((h)->progresscb) { \
-		(h)->progresscb(e, p, per, n, r); \
+		(h)->progresscb((h)->progresscb_ctx, e, p, per, n, r); \
 	} \
 } while(0)
 
@@ -72,11 +72,17 @@  struct __alpm_handle_t {
 
 	/* callback functions */
 	alpm_cb_log logcb;          /* Log callback function */
+	void *logcb_ctx;
 	alpm_cb_download dlcb;      /* Download callback function */
+	void *dlcb_ctx;
 	alpm_cb_fetch fetchcb;      /* Download file callback function */
+	void *fetchcb_ctx;
 	alpm_cb_event eventcb;
+	void *eventcb_ctx;
 	alpm_cb_question questioncb;
+	void *questioncb_ctx;
 	alpm_cb_progress progresscb;
+	void *progresscb_ctx;
 
 	/* filesystem paths */
 	char *root;              /* Root path, default '/' */
diff --git a/lib/libalpm/log.c b/lib/libalpm/log.c
index 4c781ea2..c4d291cb 100644
--- a/lib/libalpm/log.c
+++ b/lib/libalpm/log.c
@@ -107,6 +107,6 @@  void _alpm_log(alpm_handle_t *handle, alpm_loglevel_t flag, const char *fmt, ...
 	}
 
 	va_start(args, fmt);
-	handle->logcb(flag, fmt, args);
+	handle->logcb(handle->logcb_ctx, flag, fmt, args);
 	va_end(args);
 }
diff --git a/src/pacman/callback.c b/src/pacman/callback.c
index a28a79a9..13e38122 100644
--- a/src/pacman/callback.c
+++ b/src/pacman/callback.c
@@ -232,8 +232,9 @@  static int number_length(size_t n)
 }
 
 /* callback to handle messages/notifications from libalpm transactions */
-void cb_event(alpm_event_t *event)
+void cb_event(void *ctx, alpm_event_t *event)
 {
+	(void)ctx;
 	if(config->print) {
 		console_cursor_move_end();
 		return;
@@ -434,8 +435,9 @@  void cb_event(alpm_event_t *event)
 }
 
 /* callback to handle questions from libalpm transactions (yes/no) */
-void cb_question(alpm_question_t *question)
+void cb_question(void *ctx, alpm_question_t *question)
 {
+	(void)ctx;
 	if(config->print) {
 		switch(question->type) {
 			case ALPM_QUESTION_INSTALL_IGNOREPKG:
@@ -556,8 +558,8 @@  void cb_question(alpm_question_t *question)
 }
 
 /* callback to handle display of transaction progress */
-void cb_progress(alpm_progress_t event, const char *pkgname, int percent,
-                       size_t howmany, size_t current)
+void cb_progress(void *ctx, alpm_progress_t event, const char *pkgname,
+		int percent, size_t howmany, size_t current)
 {
 	static int prevpercent;
 	static size_t prevcurrent;
@@ -571,6 +573,8 @@  void cb_progress(alpm_progress_t event, const char *pkgname, int percent,
 
 	const unsigned short cols = getcols();
 
+	(void)ctx;
+
 	if(config->noprogressbar || cols == 0) {
 		return;
 	}
@@ -1069,8 +1073,9 @@  static void dload_complete_event(const char *filename, alpm_download_event_compl
 }
 
 /* Callback to handle display of download progress */
-void cb_download(const char *filename, alpm_download_event_type_t event, void *data)
+void cb_download(void *ctx, const char *filename, alpm_download_event_type_t event, void *data)
 {
+	(void)ctx;
 	if(event == ALPM_DOWNLOAD_INIT) {
 		dload_init_event(filename, data);
 	} else if(event == ALPM_DOWNLOAD_PROGRESS) {
@@ -1084,8 +1089,9 @@  void cb_download(const char *filename, alpm_download_event_type_t event, void *d
 }
 
 /* Callback to handle notifications from the library */
-void cb_log(alpm_loglevel_t level, const char *fmt, va_list args)
+void cb_log(void *ctx, alpm_loglevel_t level, const char *fmt, va_list args)
 {
+	(void)ctx;
 	if(!fmt || strlen(fmt) == 0) {
 		return;
 	}
diff --git a/src/pacman/callback.h b/src/pacman/callback.h
index 8ac9d960..83cf8cdd 100644
--- a/src/pacman/callback.h
+++ b/src/pacman/callback.h
@@ -26,22 +26,22 @@ 
 #include <alpm.h>
 
 /* callback to handle messages/notifications from libalpm */
-void cb_event(alpm_event_t *event);
+void cb_event(void *ctx, alpm_event_t *event);
 
 /* callback to handle questions from libalpm (yes/no) */
-void cb_question(alpm_question_t *question);
+void cb_question(void *ctx, alpm_question_t *question);
 
 /* callback to handle display of progress */
-void cb_progress(alpm_progress_t event, const char *pkgname, int percent,
-                   size_t howmany, size_t remain);
+void cb_progress(void *ctx, alpm_progress_t event, const char *pkgname,
+		int percent, size_t howmany, size_t remain);
 
 /* callback to handle display of download progress */
-void cb_download(const char *filename, alpm_download_event_type_t event,
+void cb_download(void *ctx, const char *filename, alpm_download_event_type_t event,
 		void *data);
 
 /* callback to handle messages/notifications from pacman library */
-__attribute__((format(printf, 2, 0)))
-void cb_log(alpm_loglevel_t level, const char *fmt, va_list args);
+__attribute__((format(printf, 3, 0)))
+void cb_log(void *ctx, alpm_loglevel_t level, const char *fmt, va_list args);
 
 /* specify if multibar UI should move completed bars to the top of the screen */
 void multibar_move_completed_up(bool value);
diff --git a/src/pacman/conf.c b/src/pacman/conf.c
index a4f2ba35..877913b0 100644
--- a/src/pacman/conf.c
+++ b/src/pacman/conf.c
@@ -277,8 +277,8 @@  static int systemvp(const char *file, char *const argv[])
 }
 
 /** External fetch callback */
-static int download_with_xfercommand(const char *url, const char *localpath,
-		int force)
+static int download_with_xfercommand(void *ctx, const char *url,
+		const char *localpath, int force)
 {
 	int ret = 0, retval;
 	int usepart = 0;
@@ -288,6 +288,8 @@  static int download_with_xfercommand(const char *url, const char *localpath,
 	const char **argv;
 	size_t i;
 
+	(void)ctx;
+
 	if(!config->xfercommand_argv) {
 		return -1;
 	}
@@ -836,11 +838,11 @@  static int setup_libalpm(void)
 	}
 	config->handle = handle;
 
-	alpm_option_set_logcb(handle, cb_log);
-	alpm_option_set_dlcb(handle, cb_download);
-	alpm_option_set_eventcb(handle, cb_event);
-	alpm_option_set_questioncb(handle, cb_question);
-	alpm_option_set_progresscb(handle, cb_progress);
+	alpm_option_set_logcb(handle, cb_log, NULL);
+	alpm_option_set_dlcb(handle, cb_download, NULL);
+	alpm_option_set_eventcb(handle, cb_event, NULL);
+	alpm_option_set_questioncb(handle, cb_question, NULL);
+	alpm_option_set_progresscb(handle, cb_progress, NULL);
 
 	if(config->op == PM_OP_FILES) {
 		alpm_option_set_dbext(handle, ".files");
@@ -887,7 +889,7 @@  static int setup_libalpm(void)
 	}
 
 	if(config->xfercommand) {
-		alpm_option_set_fetchcb(handle, download_with_xfercommand);
+		alpm_option_set_fetchcb(handle, download_with_xfercommand, NULL);
 	} else if(!(alpm_capabilities() & ALPM_CAPABILITY_DOWNLOADER)) {
 		pm_printf(ALPM_LOG_WARNING, _("no '%s' configured\n"), "XferCommand");
 	}
diff --git a/src/util/testpkg.c b/src/util/testpkg.c
index 28dcdc50..26600a9d 100644
--- a/src/util/testpkg.c
+++ b/src/util/testpkg.c
@@ -24,9 +24,10 @@ 
 #include <alpm.h>
 #include "util.h" /* For Localization */
 
-__attribute__((format(printf, 2, 0)))
-static void output_cb(alpm_loglevel_t level, const char *fmt, va_list args)
+__attribute__((format(printf, 3, 0)))
+static void output_cb(void *ctx, alpm_loglevel_t level, const char *fmt, va_list args)
 {
+	(void)ctx;
 	if(fmt[0] == '\0') {
 		return;
 	}
@@ -64,7 +65,7 @@  int main(int argc, char *argv[])
 	}
 
 	/* let us get log messages from libalpm */
-	alpm_option_set_logcb(handle, output_cb);
+	alpm_option_set_logcb(handle, output_cb, NULL);
 
 	/* set gpgdir to default */
 	alpm_option_set_gpgdir(handle, GPGDIR);