Hi, This seems similar to the hooks mechanism the we have been discussing but less general. Have a look at http://wiki.archlinux.org/index.php/User:Allan/Pacman_Hooks for more information. So in short, I like the idea but would want a more general approach taken. Allan Mårten Olsson wrote:
Hi all!
Wasn't sure if I could include additonal text in "patch-mail". So I hope it is ok to send an additonal mail with extra info:
At some places the code needs cleanup which I will do if the concept shown is accepted (didn't want to take to much time on that if the concept is disliked and never will be accpeted for that reason). I want to fix the code-duplication issue (one function) and make the parsign so one can have arguments with spaces inside " ".
I wasn't sure if this functionality can be considered dangerous because it will run a script with full access to the system, but I guess the same problem could show up if you make "bad" packages with an install script.
BR, Mårten
----- Original Message ----- From: "Mårten Olsson" <marten.olsson@purplescout.se> To: pacman-dev@archlinux.org Sent: Sunday, February 1, 2009 2:36:46 AM GMT +01:00 Amsterdam / Berlin / Bern / Rome / Stockholm / Vienna Subject: [pacman-dev] [PATCH] Add support for user defined per package post install actions
This adds suport for user to add per package post install actions, somewhat similar to post-install scripts in packages but controlled by local user and not part of package/not done by package maintainer. The actions is performed by "system" call and can't contain spaces (not even when inside "). Syntax in logfile is PostInstallAction = <packagename>:<action> Functionality added inside libalpm, add support for configuring in pacman.
Signed-off-by: Mårten Olsson <marten.olsson_at_purplescout.se> --- lib/libalpm/add.c | 43 +++++++++++++++++++++++++++++++++ lib/libalpm/alpm.h | 3 ++ lib/libalpm/handle.c | 65 ++++++++++++++++++++++++++++++++++++++++++++++++++ lib/libalpm/handle.h | 6 ++++ src/pacman/pacman.c | 20 +++++++++++++++ 5 files changed, 137 insertions(+), 0 deletions(-)
diff --git a/lib/libalpm/add.c b/lib/libalpm/add.c index 6eb2085..1cd6e28 100644 --- a/lib/libalpm/add.c +++ b/lib/libalpm/add.c @@ -632,6 +632,46 @@ static int extract_single_file(struct archive *archive, return(errors); }
+static int postinstallcompare(const void *postinstalldata, const void *pkgname) +{ + const postinstallaction_t *postinstallaction=postinstalldata; + + if( (pkgname != NULL) && (postinstallaction->pkgname != NULL) && (strcmp(postinstallaction->pkgname, pkgname) == 0)) { + return(0); + } + + return(1); +} + +/** Test if a package has a postinstallaction associated with it and executes the action. + * + * Checks if the package has a postinstallaction associated with it + * and if so executes the action by the system call + * + * @param pkg the package to test + * + * @return 0 if no action found or if the associated action completed succesfully, 1 otherwise + */ +static int check_run_postinstallaction(pmpkg_t *pkg) +{ + postinstallaction_t *postinstallaction = NULL; + + _alpm_log(PM_LOG_DEBUG, "PostInstallAction: finding PostInstallAction for package: %s\n", alpm_pkg_get_name(pkg)); + + postinstallaction=alpm_list_find(handle->postinstallactions, alpm_pkg_get_name(pkg), postinstallcompare); + + if( postinstallaction != NULL) { + _alpm_log(PM_LOG_DEBUG, "PostInstallAction: package: %s action: %s \n", postinstallaction->pkgname, postinstallaction->action); + + /* should this be more like the install-scriptlet code */ + if( system(postinstallaction->action) != 0) { + return(1); + } + } + + return(0); +} + static int commit_single_pkg(pmpkg_t *newpkg, int pkg_current, int pkg_count, pmtrans_t *trans, pmdb_t *db) { @@ -847,6 +887,9 @@ static int commit_single_pkg(pmpkg_t *newpkg, int pkg_current, int pkg_count, } }
+ /* check and run postinstall action */ + check_run_postinstallaction(newpkg); + if(is_upgrade) { EVENT(trans, PM_TRANS_EVT_UPGRADE_DONE, newpkg, oldpkg); } else { diff --git a/lib/libalpm/alpm.h b/lib/libalpm/alpm.h index 7b7ca4e..04ff886 100644 --- a/lib/libalpm/alpm.h +++ b/lib/libalpm/alpm.h @@ -122,6 +122,9 @@ void alpm_option_add_noupgrade(const char *pkg); void alpm_option_set_noupgrades(alpm_list_t *noupgrade); int alpm_option_remove_noupgrade(const char *pkg);
+int alpm_option_add_postinstallaction(const char *pkg, const char *action); +int alpm_option_remove_postinstallaction(const char *pkg); + alpm_list_t *alpm_option_get_noextracts(); void alpm_option_add_noextract(const char *pkg); void alpm_option_set_noextracts(alpm_list_t *noextract); diff --git a/lib/libalpm/handle.c b/lib/libalpm/handle.c index 813f439..504157d 100644 --- a/lib/libalpm/handle.c +++ b/lib/libalpm/handle.c @@ -53,6 +53,23 @@ pmhandle_t *_alpm_handle_new() return(handle); }
+void postinstallactionfree(void *data) +{ + postinstallaction_t *postinstallaction=data; + + if(postinstallaction->pkgname != NULL) + { + free(postinstallaction->pkgname); + } + + if(postinstallaction->action != NULL) + { + free(postinstallaction->action); + } + + free(postinstallaction); +} + void _alpm_handle_free(pmhandle_t *handle) { ALPM_LOG_FUNC; @@ -84,6 +101,8 @@ void _alpm_handle_free(pmhandle_t *handle) FREELIST(handle->noextract); FREELIST(handle->ignorepkg); FREELIST(handle->ignoregrp); + alpm_list_free_inner(handle->postinstallactions, postinstallactionfree); + alpm_list_free(handle->postinstallactions); FREE(handle); }
@@ -453,6 +472,52 @@ int SYMEXPORT alpm_option_remove_noupgrade(const char *pkg) return(0); }
+int SYMEXPORT alpm_option_add_postinstallaction(const char *pkg, const char *action) +{ + postinstallaction_t *postinstallaction=0; + + postinstallaction=malloc(sizeof(postinstallaction_t)); + + if(postinstallaction == NULL) { + return(1); + } + + postinstallaction->pkgname = strdup(pkg); + postinstallaction->action= strdup(action); + + handle->postinstallactions = alpm_list_add(handle->postinstallactions, postinstallaction); + + return(0); +} + +/* Duplicated here for now, cleanup needed */ +static int postinstallcompare(const void *postinstalldata, const void *pkgname) +{ + const postinstallaction_t *postinstallaction=postinstalldata; + + if( (pkgname != NULL) && (postinstallaction->pkgname != NULL) && (strcmp(postinstallaction->pkgname, pkgname) == 0)) { + return(0); + } + + return(1); +} + +int SYMEXPORT alpm_option_remove_postinstallaction(const char *pkg) +{ + postinstallaction_t *postinstallaction=0; + + handle->postinstallactions=alpm_list_remove(handle->postinstallactions, pkg, postinstallcompare, (void *)&postinstallaction ); + + if( postinstallaction != NULL) { + free(postinstallaction->pkgname); + free(postinstallaction->action); + free(postinstallaction); + return(1); + } + + return(0); +} + void SYMEXPORT alpm_option_add_noextract(const char *pkg) { handle->noextract = alpm_list_add(handle->noextract, strdup(pkg)); diff --git a/lib/libalpm/handle.h b/lib/libalpm/handle.h index ad7666d..c53e7f6 100644 --- a/lib/libalpm/handle.h +++ b/lib/libalpm/handle.h @@ -28,6 +28,11 @@ #include "alpm.h" #include "trans.h"
+typedef struct _postinstallaction_t { + char *pkgname; + char *action; +} postinstallaction_t; + typedef struct _pmhandle_t { /* internal usage */ pmdb_t *db_local; /* local db pointer */ @@ -53,6 +58,7 @@ typedef struct _pmhandle_t { alpm_list_t *noextract; /* List of files NOT to extract */ alpm_list_t *ignorepkg; /* List of packages to ignore */ alpm_list_t *ignoregrp; /* List of groups to ignore */ + alpm_list_t *postinstallactions; /* List of packages to perform actions postinstall */
/* options */ unsigned short usesyslog; /* Use syslog instead of logfile? */ /* TODO move to frontend */ diff --git a/src/pacman/pacman.c b/src/pacman/pacman.c index 59916d6..1f1371d 100644 --- a/src/pacman/pacman.c +++ b/src/pacman/pacman.c @@ -549,6 +549,24 @@ static void option_add_syncfirst(const char *name) { config->syncfirst = alpm_list_add(config->syncfirst, strdup(name)); }
+/* helper for being used with setrepeatingoption, additional parsing done here*/ +static void option_add_postinstallaction(const char *string) { + char *name = (char *)string; + char *action = 0; + + action=strchr(string,':'); + + if( action != NULL) { + *action = '\0'; + action++; + + pm_printf(PM_LOG_DEBUG, "config: Postinstallaction package %s action: %s\n", name, action); + + alpm_option_add_postinstallaction(name, action); + } + +} + /** Add repeating options such as NoExtract, NoUpgrade, etc to libalpm * settings. Refactored out of the parseconfig code since all of them did * the exact same thing and duplicated code. @@ -710,6 +728,8 @@ static int _parseconfig(const char *file, const char *givensection, setrepeatingoption(ptr, "HoldPkg", option_add_holdpkg); } else if(strcmp(key, "SyncFirst") == 0) { setrepeatingoption(ptr, "SyncFirst", option_add_syncfirst); + } else if(strcmp(key, "PostInstallAction") == 0) { + setrepeatingoption(ptr, "PostInstallAction", option_add_postinstallaction); } else if(strcmp(key, "DBPath") == 0) { /* don't overwrite a path specified on the command line */ if(!config->dbpath) {