diff --git a/client/api.c b/client/api.c index 71a0f60..4ce3f99 100644 --- a/client/api.c +++ b/client/api.c @@ -1580,12 +1580,6 @@ TDNFResolve( queue_init(&queueGoal); } - if(nAlterType == ALTER_AUTOERASE) - { - dwError = ERROR_TDNF_AUTOERASE_UNSUPPORTED; - BAIL_ON_TDNF_ERROR(dwError); - } - dwError = TDNFValidateCmdArgs(pTdnf); BAIL_ON_TDNF_ERROR(dwError); diff --git a/client/defines.h b/client/defines.h index bafc66e..979ffdb 100644 --- a/client/defines.h +++ b/client/defines.h @@ -127,6 +127,9 @@ typedef enum #define TDNF_REPO_METALINK_FILE_NAME "metalink" #define TDNF_REPO_BASEURL_FILE_NAME "baseurl" +#define TDNF_AUTOINSTALLED_FILE "autoinstalled" +#define TDNF_DEFAULT_DATA_LOCATION "/var/lib/tdnf" + // repo defaults #define TDNF_DEFAULT_REPO_LOCATION "/etc/yum.repos.d" #define TDNF_DEFAULT_CACHE_LOCATION "/var/cache/tdnf" diff --git a/client/goal.c b/client/goal.c index a9315c2..58201d7 100644 --- a/client/goal.c +++ b/client/goal.c @@ -316,6 +316,7 @@ TDNFGoal( int nProblems = 0; char** ppszExcludes = NULL; uint32_t dwExcludeCount = 0; + char **ppszAutoInstalled = NULL; if(!pTdnf || !ppInfo || !pQueuePkgList) { @@ -357,8 +358,9 @@ TDNFGoal( { nFlags = nFlags | SOLVER_FORCEBEST; } - - if (pTdnf->pConf->nCleanRequirementsOnRemove) + if ((pTdnf->pConf->nCleanRequirementsOnRemove && + !pTdnf->pArgs->nNoAutoRemove) || + nAlterType == ALTER_AUTOERASE) { nFlags = nFlags | SOLVER_CLEANDEPS; } @@ -394,6 +396,12 @@ TDNFGoal( nAlterType == ALTER_ERASE || nAlterType == ALTER_AUTOERASE) { + dwError = TDNFReadAutoInstalled(pTdnf, &ppszAutoInstalled); + BAIL_ON_TDNF_ERROR(dwError); + + dwError = SolvAddUserInstalledToJobs(&queueJobs, pTdnf->pSack->pPool, ppszAutoInstalled); + BAIL_ON_TDNF_ERROR(dwError); + solver_set_flag(pSolv, SOLVER_FLAG_ALLOW_UNINSTALL, 1); } solver_set_flag(pSolv, SOLVER_FLAG_BEST_OBEY_POLICY, 1); @@ -412,7 +420,7 @@ TDNFGoal( if (nAlterType == ALTER_UPGRADE && dwExcludeCount != 0 && ppszExcludes) { - /* if we had packages to exclude, then we'd have diabled ones too */ + /* if we had packages to exclude, then we'd have disabled ones too */ dwSkipProblem |= SKIPPROBLEM_DISABLED; } @@ -434,16 +442,22 @@ TDNFGoal( } dwError = TDNFGoalGetAllResultsIgnoreNoData( - nAlterType, pTrans, pSolv, &pInfoTemp, pTdnf); BAIL_ON_TDNF_ERROR(dwError); + if (nAlterType == ALTER_INSTALL) + { + dwError = TDNFAddUserInstall(pTdnf, pQueuePkgList, pInfoTemp); + BAIL_ON_TDNF_ERROR(dwError); + } + *ppInfo = pInfoTemp; cleanup: + TDNF_SAFE_FREE_STRINGARRAY(ppszAutoInstalled); TDNF_SAFE_FREE_STRINGARRAY(ppszExcludes); queue_free(&queueJobs); if(pTrans) @@ -465,6 +479,211 @@ error: goto cleanup; } +uint32_t +TDNFAddUserInstall( + PTDNF pTdnf, + Queue* pQueueGoal, + PTDNF_SOLVED_PKG_INFO ppInfo + ) +{ + uint32_t dwError = 0; + int i; + char **ppszPkgsUserInstall = NULL; + + if (!pTdnf || !pQueueGoal || !ppInfo) + { + dwError = ERROR_TDNF_INVALID_PARAMETER; + BAIL_ON_TDNF_ERROR(dwError); + } + + dwError = TDNFAllocateMemory(pQueueGoal->count + 1, + sizeof(char **), + (void **)&ppszPkgsUserInstall); + BAIL_ON_TDNF_ERROR(dwError); + + for (i = 0; i < pQueueGoal->count; i++) + { + dwError = SolvGetPkgNameFromId( + pTdnf->pSack, + pQueueGoal->elements[i], + &ppszPkgsUserInstall[i]); + BAIL_ON_TDNF_ERROR(dwError); + } + + ppInfo->ppszPkgsUserInstall = ppszPkgsUserInstall; +cleanup: + return dwError; +error: + TDNF_SAFE_FREE_MEMORY(ppszPkgsUserInstall); + goto cleanup; +} + +uint32_t +TDNFMarkAutoInstalledSinglePkg( + PTDNF pTdnf, + const char *pszPkgName +) +{ + uint32_t dwError = 0; + char **ppszAutoInstalled = NULL; + char *pszAutoFile = NULL; + int i; + FILE *fp = NULL; + + if (!pTdnf || !pszPkgName) + { + dwError = ERROR_TDNF_INVALID_PARAMETER; + BAIL_ON_TDNF_ERROR(dwError); + } + + dwError = TDNFReadAutoInstalled(pTdnf, &ppszAutoInstalled); + BAIL_ON_TDNF_ERROR(dwError); + + dwError = TDNFJoinPath(&pszAutoFile, + pTdnf->pArgs->pszInstallRoot, + TDNF_DEFAULT_DATA_LOCATION, + TDNF_AUTOINSTALLED_FILE, + NULL); + BAIL_ON_TDNF_ERROR(dwError); + + fp = fopen(pszAutoFile, "w"); + if(!fp) + { + dwError = errno; + BAIL_ON_TDNF_SYSTEM_ERROR(dwError); + } + + for (i = 0; ppszAutoInstalled[i]; i++) + { + if (strcmp(ppszAutoInstalled[i], pszPkgName) == 0) + { + pr_info("marking %s as user installed\n", pszPkgName); + continue; + } + fprintf(fp, "%s\n", ppszAutoInstalled[i]); + } + fclose(fp); + +cleanup: + TDNF_SAFE_FREE_MEMORY(pszAutoFile); + TDNF_SAFE_FREE_STRINGARRAY(ppszAutoInstalled); + return dwError; +error: + if (fp) + { + fclose(fp); + } + goto cleanup; +} + +uint32_t +TDNFMarkAutoInstalled( + PTDNF pTdnf, + PTDNF_SOLVED_PKG_INFO ppInfo + ) +{ + uint32_t dwError = 0; + PTDNF_PKG_INFO pPkgInfo = NULL; + char **ppszAutoInstalled = NULL; + int i, j; + int nCount = 0; + int nCountOld = 0; + FILE *fp = NULL; + char *pszAutoFile = NULL; + char *pszDataDir = NULL; + + if (!pTdnf || !ppInfo) + { + dwError = ERROR_TDNF_INVALID_PARAMETER; + BAIL_ON_TDNF_ERROR(dwError); + } + + dwError = TDNFReadAutoInstalled(pTdnf, &ppszAutoInstalled); + BAIL_ON_TDNF_ERROR(dwError); + + if (ppszAutoInstalled != NULL) + { + dwError = TDNFStringArrayCount(ppszAutoInstalled, &nCount); + BAIL_ON_TDNF_ERROR(dwError); + } + + nCountOld = nCount; + for (pPkgInfo = ppInfo->pPkgsToInstall; pPkgInfo; pPkgInfo = pPkgInfo->pNext) + { + nCount++; + } + + dwError = TDNFReAllocateMemory((nCount+1) * sizeof(char **), (void **)&ppszAutoInstalled); + BAIL_ON_TDNF_ERROR(dwError); + ppszAutoInstalled[nCount] = NULL; + + for (pPkgInfo = ppInfo->pPkgsToInstall; pPkgInfo; pPkgInfo = pPkgInfo->pNext) + { + dwError = TDNFAllocateString(pPkgInfo->pszName, &ppszAutoInstalled[nCountOld++]); + BAIL_ON_TDNF_ERROR(dwError); + } + + dwError = TDNFStringArraySort(ppszAutoInstalled); + BAIL_ON_TDNF_ERROR(dwError); + + dwError = TDNFJoinPath(&pszDataDir, + pTdnf->pArgs->pszInstallRoot, + TDNF_DEFAULT_DATA_LOCATION, + NULL); + BAIL_ON_TDNF_ERROR(dwError); + + dwError = TDNFUtilsMakeDir(pszDataDir); + BAIL_ON_TDNF_ERROR(dwError); + + dwError = TDNFJoinPath(&pszAutoFile, + pTdnf->pArgs->pszInstallRoot, + TDNF_DEFAULT_DATA_LOCATION, + TDNF_AUTOINSTALLED_FILE, + NULL); + BAIL_ON_TDNF_ERROR(dwError); + + fp = fopen(pszAutoFile, "w"); + if(!fp) + { + dwError = errno; + BAIL_ON_TDNF_SYSTEM_ERROR(dwError); + } + + for (i = 0; ppszAutoInstalled[i]; i++) + { + if (i > 0 && strcmp(ppszAutoInstalled[i-1], ppszAutoInstalled[i]) == 0) + { + continue; + } + if (ppInfo->ppszPkgsUserInstall) + { + for (j = 0; ppInfo->ppszPkgsUserInstall[j]; j++) + { + if (strcmp(ppszAutoInstalled[i], + ppInfo->ppszPkgsUserInstall[j]) == 0) + { + break; + } + } + } + if (!ppInfo->ppszPkgsUserInstall || ppInfo->ppszPkgsUserInstall[j] == NULL) + { + fprintf(fp, "%s\n", ppszAutoInstalled[i]); + } + } + fclose(fp); + +cleanup: + TDNF_SAFE_FREE_MEMORY(pszAutoFile); + TDNF_SAFE_FREE_STRINGARRAY(ppszAutoInstalled); + return dwError; +error: + if (fp) + { + fclose(fp); + } + goto cleanup; +} uint32_t TDNFAddGoal( @@ -521,6 +740,7 @@ TDNFAddGoal( BAIL_ON_TDNF_ERROR(dwError); break; case ALTER_ERASE: + case ALTER_AUTOERASE: dwError = SolvAddPkgEraseJob(pQueueJobs, dwId); BAIL_ON_TDNF_ERROR(dwError); break; @@ -530,10 +750,6 @@ TDNFAddGoal( dwError = SolvAddPkgInstallJob(pQueueJobs, dwId); BAIL_ON_TDNF_ERROR(dwError); break; - case ALTER_AUTOERASE: - dwError = SolvAddPkgUserInstalledJob(pQueueJobs, dwId); - BAIL_ON_TDNF_ERROR(dwError); - break; default: dwError = ERROR_TDNF_INVALID_RESOLVE_ARG; BAIL_ON_TDNF_ERROR(dwError); @@ -549,7 +765,6 @@ error: uint32_t TDNFGoalGetAllResultsIgnoreNoData( - int nResolveFor, Transaction* pTrans, Solver* pSolv, PTDNF_SOLVED_PKG_INFO* ppInfo, @@ -596,14 +811,6 @@ TDNFGoalGetAllResultsIgnoreNoData( &pInfo->pPkgsToRemove); BAIL_ON_TDNF_ERROR(dwError); - if(nResolveFor == ALTER_AUTOERASE) - { - dwError = TDNFGetUnneededPackages( - pSolv, - pTdnf, - &pInfo->pPkgsUnNeeded); - BAIL_ON_TDNF_ERROR(dwError); - } dwError = TDNFGetReinstallPackages( pTrans, pTdnf, diff --git a/client/init.c b/client/init.c index 871dae7..7809f5f 100644 --- a/client/init.c +++ b/client/init.c @@ -57,6 +57,7 @@ TDNFCloneCmdArgs( pCmdArgs->nIPv6 = pCmdArgsIn->nIPv6; pCmdArgs->nDisableExcludes = pCmdArgsIn->nDisableExcludes; pCmdArgs->nDownloadOnly = pCmdArgsIn->nDownloadOnly; + pCmdArgs->nNoAutoRemove = pCmdArgsIn->nNoAutoRemove; dwError = TDNFAllocateString( pCmdArgsIn->pszInstallRoot, diff --git a/client/prototypes.h b/client/prototypes.h index 295063b..0ce83d9 100644 --- a/client/prototypes.h +++ b/client/prototypes.h @@ -447,6 +447,25 @@ TDNFGoal( TDNF_ALTERTYPE nAlterType ); +uint32_t +TDNFAddUserInstall( + PTDNF pTdnf, + Queue* pQueueGoal, + PTDNF_SOLVED_PKG_INFO ppInfo + ); + +uint32_t +TDNFMarkAutoInstalledSinglePkg( + PTDNF pTdnf, + const char *pszPkgName +); + +uint32_t +TDNFMarkAutoInstalled( + PTDNF pTdnf, + PTDNF_SOLVED_PKG_INFO ppInfo + ); + uint32_t TDNFAddGoal( PTDNF pTdnf, @@ -459,7 +478,6 @@ TDNFAddGoal( uint32_t TDNFGoalGetAllResultsIgnoreNoData( - int nResolveFor, Transaction* pTrans, Solver* pSolv, PTDNF_SOLVED_PKG_INFO* ppInfo, @@ -1076,6 +1094,12 @@ TDNFGetCmdOpt( PTDNF_CMD_OPT *ppOpt ); +uint32_t +TDNFReadAutoInstalled( + PTDNF pTdnf, + char ***pppszAutoInstalled + ); + //validate.c uint32_t TDNFValidateCmdArgs( diff --git a/client/resolve.c b/client/resolve.c index ad33da0..3f66ad2 100644 --- a/client/resolve.c +++ b/client/resolve.c @@ -84,10 +84,9 @@ TDNFPrepareAllPackages( pCmdArgs = pTdnf->pArgs; nAlterType = *pAlterType; - if(nAlterType == ALTER_DOWNGRADEALL || - nAlterType == ALTER_AUTOERASE) + if(nAlterType == ALTER_DOWNGRADEALL) { - dwError = TDNFFilterPackages( + dwError = TDNFFilterPackages( pTdnf, nAlterType, ppszPkgsNotResolved, @@ -384,6 +383,12 @@ TDNFPrepareSinglePkg( pSack, queueGoal, pszPkgName); + if (dwError == ERROR_TDNF_ALREADY_INSTALLED) + { + dwError = TDNFMarkAutoInstalledSinglePkg(pTdnf, pszPkgName); + BAIL_ON_TDNF_ERROR(dwError); + dwError = ERROR_TDNF_ALREADY_INSTALLED; + } BAIL_ON_TDNF_ERROR(dwError); } else if (nAlterType == ALTER_UPGRADE) diff --git a/client/rpmtrans.c b/client/rpmtrans.c index 8fa055a..3d3235e 100644 --- a/client/rpmtrans.c +++ b/client/rpmtrans.c @@ -102,6 +102,9 @@ TDNFRpmExecTransaction( BAIL_ON_TDNF_ERROR(dwError); } + dwError = TDNFMarkAutoInstalled(pTdnf, pSolvedInfo); + BAIL_ON_TDNF_ERROR(dwError); + cleanup: if(ts.pTS) { diff --git a/client/utils.c b/client/utils.c index 77705ca..73eb2f4 100644 --- a/client/utils.c +++ b/client/utils.c @@ -759,3 +759,41 @@ error: return dwError; } +uint32_t +TDNFReadAutoInstalled( + PTDNF pTdnf, + char ***pppszAutoInstalled + ) +{ + uint32_t dwError = 0; + char **ppszAutoInstalled = NULL; + char *pszAutoFile = NULL; + + if (!pTdnf || !pppszAutoInstalled) + { + dwError = ERROR_TDNF_INVALID_PARAMETER; + BAIL_ON_TDNF_ERROR(dwError); + } + + dwError = TDNFAllocateStringPrintf(&pszAutoFile, "%s/%s/%s", + pTdnf->pArgs->pszInstallRoot, + TDNF_DEFAULT_DATA_LOCATION, + TDNF_AUTOINSTALLED_FILE); + BAIL_ON_TDNF_ERROR(dwError); + + dwError = TDNFReadFileToStringArray(pszAutoFile, &ppszAutoInstalled); + if (dwError == ERROR_TDNF_SYSTEM_BASE + ENOENT) + { + dwError = 0; + } + BAIL_ON_TDNF_ERROR(dwError); + + *pppszAutoInstalled = ppszAutoInstalled; +cleanup: + TDNF_SAFE_FREE_MEMORY(pszAutoFile); + return dwError; +error: + TDNF_SAFE_FREE_STRINGARRAY(ppszAutoInstalled); + goto cleanup; +} + diff --git a/common/utils.c b/common/utils.c index 726e31f..889914f 100644 --- a/common/utils.c +++ b/common/utils.c @@ -260,7 +260,6 @@ TDNFFreeSolvedPackageInfo( PTDNF_SOLVED_PKG_INFO pSolvedPkgInfo ) { - int i = 0; if(pSolvedPkgInfo) { TDNF_SAFE_FREE_PKGINFO(pSolvedPkgInfo->pPkgsNotAvailable); @@ -274,15 +273,8 @@ TDNFFreeSolvedPackageInfo( TDNF_SAFE_FREE_PKGINFO(pSolvedPkgInfo->pPkgsObsoleted); TDNF_SAFE_FREE_PKGINFO(pSolvedPkgInfo->pPkgsRemovedByDowngrade); - if(pSolvedPkgInfo->ppszPkgsNotResolved) - { - while(pSolvedPkgInfo->ppszPkgsNotResolved[i]) - { - TDNF_SAFE_FREE_MEMORY( - pSolvedPkgInfo->ppszPkgsNotResolved[i++]); - } - } - TDNF_SAFE_FREE_MEMORY(pSolvedPkgInfo->ppszPkgsNotResolved); + TDNF_SAFE_FREE_STRINGARRAY(pSolvedPkgInfo->ppszPkgsNotResolved); + TDNF_SAFE_FREE_STRINGARRAY(pSolvedPkgInfo->ppszPkgsUserInstall); } TDNF_SAFE_FREE_MEMORY(pSolvedPkgInfo); } diff --git a/etc/tdnf/tdnf.conf b/etc/tdnf/tdnf.conf index f8cbc96..f08fa3b 100644 --- a/etc/tdnf/tdnf.conf +++ b/etc/tdnf/tdnf.conf @@ -1,6 +1,5 @@ [main] gpgcheck=1 installonly_limit=3 -clean_requirements_on_remove=true repodir=/etc/yum.repos.d cachedir=/var/cache/tdnf diff --git a/include/tdnftypes.h b/include/tdnftypes.h index e30fc48..6cea5ed 100644 --- a/include/tdnftypes.h +++ b/include/tdnftypes.h @@ -199,6 +199,7 @@ typedef struct _TDNF_SOLVED_PKG_INFO PTDNF_PKG_INFO pPkgsObsoleted; PTDNF_PKG_INFO pPkgsRemovedByDowngrade; char** ppszPkgsNotResolved; + char** ppszPkgsUserInstall; }TDNF_SOLVED_PKG_INFO, *PTDNF_SOLVED_PKG_INFO; /* @@ -249,6 +250,7 @@ typedef struct _TDNF_CMD_ARGS int nIPv6; //resolve to IPv6 addresses only int nDisableExcludes; //disable excludes from tdnf.conf int nDownloadOnly; //download packages only, no install + int nNoAutoRemove; //overide clean_requirements_on_remove config option char* pszDownloadDir; //directory for download, if nDownloadOnly is set char* pszInstallRoot; //set install root char* pszConfFile; //set conf file location diff --git a/solv/prototypes.h b/solv/prototypes.h index 04e877e..ffcf2e1 100644 --- a/solv/prototypes.h +++ b/solv/prototypes.h @@ -444,6 +444,13 @@ SolvAddPkgUserInstalledJob( Id dwId ); +uint32_t +SolvAddUserInstalledToJobs( + Queue* pQueueJobs, + Pool *pPool, + char **ppszAutoInstalled + ); + uint32_t SolvGetUpdateAdvisories( PSolvSack pSack, diff --git a/solv/tdnfquery.c b/solv/tdnfquery.c index 4689dbc..8f58cf3 100644 --- a/solv/tdnfquery.c +++ b/solv/tdnfquery.c @@ -76,6 +76,61 @@ error: goto cleanup; } +uint32_t +SolvAddUserInstalledToJobs( + Queue* pQueueJobs, + Pool *pPool, + char **ppszAutoInstalled + ) +{ + uint32_t dwError = 0; + Id p; + Solvable *s; + Queue queueAutoInstalled = {0}; + Id idAuto; + int i; + + if(!pQueueJobs || !pPool) + { + dwError = ERROR_TDNF_INVALID_PARAMETER; + BAIL_ON_TDNF_LIBSOLV_ERROR(dwError); + } + + queue_init(&queueAutoInstalled); + if (ppszAutoInstalled) + { + for(i = 0; ppszAutoInstalled[i] != NULL; i++) + { + idAuto = pool_str2id(pPool, ppszAutoInstalled[i], 0); + if (idAuto) + { + queue_push(&queueAutoInstalled, idAuto); + } + } + } + + FOR_REPO_SOLVABLES(pPool->installed, p, s) + { + for (i = 0; i < queueAutoInstalled.count; i++) + { + if (queueAutoInstalled.elements[i] == s->name) + { + break; + } + } + if (i >= queueAutoInstalled.count) + { + queue_push2(pQueueJobs, SOLVER_SOLVABLE_NAME|SOLVER_USERINSTALLED, s->name); + } + } +cleanup: + queue_free(&queueAutoInstalled); + return dwError; + +error: + goto cleanup; +} + uint32_t SolvAddPkgInstallJob( Queue* pQueueJobs, diff --git a/tools/cli/lib/parseargs.c b/tools/cli/lib/parseargs.c index a022e13..46c0d8c 100644 --- a/tools/cli/lib/parseargs.c +++ b/tools/cli/lib/parseargs.c @@ -115,6 +115,7 @@ static struct option pstOptions[] = {"disableexcludes", no_argument, &_opt.nDisableExcludes, 1}, //--disableexcludes {"downloadonly", no_argument, &_opt.nDownloadOnly, 1}, //--downloadonly {"downloaddir", required_argument, 0, 0}, //--downloaddir + {"noautoremove", no_argument, &_opt.nNoAutoRemove, 1}, // reposync options {"arch", required_argument, 0, 0}, {"delete", no_argument, 0, 0}, @@ -344,6 +345,7 @@ TDNFCopyOptions( pArgs->nIPv6 = pOptionArgs->nIPv6; pArgs->nDisableExcludes = pOptionArgs->nDisableExcludes; pArgs->nDownloadOnly = pOptionArgs->nDownloadOnly; + pArgs->nNoAutoRemove = pOptionArgs->nNoAutoRemove; cleanup: return dwError;