[pacman-dev] [PATCH] pacman: don't nuke local repos with -Sc

morganamilo morganamilo at archlinux.org
Mon Jun 14 19:11:28 UTC 2021


When using a local repo as a cachedir  pacman -Scc or pacman -Sc
without KeepCurrent will delete the repo database and packages
resulting in a lost database and non functional pacman.

So special case file:/// repos in cache to not get nuked and foce
KeepCurrent on.
---
 src/pacman/sync.c | 64 ++++++++++++++++++++++++++++++++++++++++-------
 1 file changed, 55 insertions(+), 9 deletions(-)

diff --git a/src/pacman/sync.c b/src/pacman/sync.c
index b6da1a36..129d3f5c 100644
--- a/src/pacman/sync.c
+++ b/src/pacman/sync.c
@@ -151,34 +151,71 @@ static int sync_cleandb_all(void)
 	return ret;
 }
 
-static int sync_cleancache(int level)
+static int is_local_repo(char *dir)
+{
+	alpm_list_t *j, *k;
+	char *sanatized_dir = strdup(dir);
+	int len = strlen(sanatized_dir);
+	int ret = 0;
+
+	if(sanatized_dir[len - 1] == '/') {
+		sanatized_dir[len - 1] = '\0';
+	}
+
+	for(j = alpm_get_syncdbs(config->handle); j; j = alpm_list_next(j)) {
+		alpm_db_t *db = j->data;
+
+		for(k = alpm_db_get_servers(db); k; k = alpm_list_next(k)) {
+			char *server = k->data;
+
+			if(strncmp(server, "file://", 7) == 0) {
+				server += 7;
+
+				if(strcmp(server, sanatized_dir) == 0) {
+					ret = 1;
+					goto cleanup;
+				}
+			}
+		}
+
+	}
+
+cleanup:
+	free(sanatized_dir);
+	return ret;
+}
+
+static int sync_cleancache(int config_level)
 {
 	alpm_list_t *i;
 	alpm_list_t *sync_dbs = alpm_get_syncdbs(config->handle);
 	alpm_db_t *db_local = alpm_get_localdb(config->handle);
 	alpm_list_t *cachedirs = alpm_option_get_cachedirs(config->handle);
+	int config_cleanmethod = config->cleanmethod;
 	int ret = 0;
 
-	if(!config->cleanmethod) {
+	if(config_cleanmethod) {
 		/* default to KeepInstalled if user did not specify */
-		config->cleanmethod = PM_CLEAN_KEEPINST;
+		config_cleanmethod = PM_CLEAN_KEEPINST;
 	}
 
-	if(level == 1) {
+	if(config_level == 1) {
 		printf(_("Packages to keep:\n"));
-		if(config->cleanmethod & PM_CLEAN_KEEPINST) {
+		if(config_cleanmethod & PM_CLEAN_KEEPINST) {
 			printf(_("  All locally installed packages\n"));
 		}
-		if(config->cleanmethod & PM_CLEAN_KEEPCUR) {
+		if(config_cleanmethod & PM_CLEAN_KEEPCUR) {
 			printf(_("  All current sync database packages\n"));
 		}
 	}
 	printf("\n");
 
 	for(i = cachedirs; i; i = alpm_list_next(i)) {
-		const char *cachedir = i->data;
+		char *cachedir = i->data;
 		DIR *dir;
 		struct dirent *ent;
+		int cleanmethod = config_cleanmethod;
+		int level = config_level;
 
 		printf(_("Cache directory: %s\n"), (const char *)i->data);
 
@@ -196,6 +233,15 @@ static int sync_cleancache(int level)
 			printf(_("removing all files from cache...\n"));
 		}
 
+		if(is_local_repo(cachedir)) {
+			pm_printf(ALPM_LOG_DEBUG,
+				_("cachedir '%s' is a local repo, keeping packages\n"), cachedir);
+
+			level = 1;
+			cleanmethod |= PM_CLEAN_KEEPCUR;
+			cleanmethod &= ~PM_CLEAN_KEEPINST;
+		}
+
 		dir = opendir(cachedir);
 		if(dir == NULL) {
 			pm_printf(ALPM_LOG_ERROR,
@@ -258,7 +304,7 @@ static int sync_cleancache(int level)
 			local_name = alpm_pkg_get_name(localpkg);
 			local_version = alpm_pkg_get_version(localpkg);
 
-			if(config->cleanmethod & PM_CLEAN_KEEPINST) {
+			if(cleanmethod & PM_CLEAN_KEEPINST) {
 				/* check if this package is in the local DB */
 				pkg = alpm_db_get_pkg(db_local, local_name);
 				if(pkg != NULL && alpm_pkg_vercmp(local_version,
@@ -269,7 +315,7 @@ static int sync_cleancache(int level)
 					delete = 0;
 				}
 			}
-			if(config->cleanmethod & PM_CLEAN_KEEPCUR) {
+			if(cleanmethod & PM_CLEAN_KEEPCUR) {
 				alpm_list_t *j;
 				/* check if this package is in a sync DB */
 				for(j = sync_dbs; j && delete; j = alpm_list_next(j)) {
-- 
2.32.0


More information about the pacman-dev mailing list