From 6262ccbbe8b5d6d3b5d6e4c18f378d66cbbe7ba0 Mon Sep 17 00:00:00 2001 From: Adrien Destugues Date: Thu, 18 Aug 2016 19:27:07 +0200 Subject: [PATCH] Fix use of findpaths from inside chroot The package kit needs to provide the package daemon with the node_ref of the root directory, so the package daemon gives the correct results when the request comes from inside a chroot. Moreover, the package kit must be able to handle a root with a system but no home package dir, as is the case inside the chroot environment created by haikuporter. Fixes #12602. --- src/bin/findpaths.cpp | 50 ++++++++++++++------- src/kits/package/DaemonClient.cpp | 15 ++++++- src/kits/package/manager/PackageManager.cpp | 22 ++++++--- src/servers/package/PackageDaemon.cpp | 17 ++++++- 4 files changed, 78 insertions(+), 26 deletions(-) diff --git a/src/bin/findpaths.cpp b/src/bin/findpaths.cpp index e2beb599f2..0bf795052c 100644 --- a/src/bin/findpaths.cpp +++ b/src/bin/findpaths.cpp @@ -10,11 +10,15 @@ #include #include +#include #include #include #include +using namespace BPackageKit::BManager::BPrivate; + + extern const char* __progname; const char* kCommandName = __progname; @@ -245,25 +249,37 @@ main(int argc, const char* const* argv) } if (referencePath != NULL || resolvable != NULL) { - BPathFinder pathFinder; - if (referencePath != NULL) { - pathFinder.SetTo(referencePath, dependency); - } else { - pathFinder.SetTo( - BPackageKit::BPackageResolvableExpression(resolvable), - dependency); - } + try { + BPathFinder pathFinder; + if (referencePath != NULL) { + pathFinder.SetTo(referencePath, dependency); + } else { + pathFinder.SetTo( + BPackageKit::BPackageResolvableExpression(resolvable), + dependency); + } - BPath path; - status_t error = pathFinder.FindPath(architecture, baseDirectory, - subPath, existingOnly ? B_FIND_PATH_EXISTING_ONLY : 0, path); - if (error != B_OK) { - fprintf(stderr, "Error: Failed to find path: %s\n", - strerror(error)); - exit(1); - } + BPath path; + status_t error = pathFinder.FindPath(architecture, baseDirectory, + subPath, existingOnly ? B_FIND_PATH_EXISTING_ONLY : 0, path); + if (error != B_OK) { + fprintf(stderr, "Error: Failed to find path: %s\n", + strerror(error)); + exit(1); + } - printf("%s\n", path.Path()); + printf("%s\n", path.Path()); + } catch(BFatalErrorException& exception) { + if (!exception.Details().IsEmpty()) + fprintf(stderr, "%s", exception.Details().String()); + if (exception.Error() == B_OK) { + fprintf(stderr, "Error: %s\n", exception.Message().String()); + } else { + fprintf(stderr, "Error: %s: %s\n", exception.Message().String(), + strerror(exception.Error())); + } + return 1; + } } else { BStringList paths; status_t error = BPathFinder::FindPaths(architecture, baseDirectory, diff --git a/src/kits/package/DaemonClient.cpp b/src/kits/package/DaemonClient.cpp index ee0e7c2cd8..7a9ca03990 100644 --- a/src/kits/package/DaemonClient.cpp +++ b/src/kits/package/DaemonClient.cpp @@ -45,12 +45,25 @@ BDaemonClient::GetInstallationLocationInfo( if (error != B_OK) return error; - // send the request BMessage request(B_MESSAGE_GET_INSTALLATION_LOCATION_INFO); error = request.AddInt32("location", location); if (error != B_OK) return error; + // Get our filesystem root node. If we are in a chroot this is not the same + // as the package_daemon root node, so we must provide it. + struct stat st; + if (stat("/boot", &st) == 0) + { + error = request.AddInt32("volume", st.st_dev); + if (error != B_OK) + return error; + error = request.AddInt64("root", st.st_ino); + if (error != B_OK) + return error; + } + + // send the request BMessage reply; fDaemonMessenger.SendMessage(&request, &reply); if (reply.what != B_MESSAGE_GET_INSTALLATION_LOCATION_INFO_REPLY) diff --git a/src/kits/package/manager/PackageManager.cpp b/src/kits/package/manager/PackageManager.cpp index 901b856233..6d9ccd8c53 100644 --- a/src/kits/package/manager/PackageManager.cpp +++ b/src/kits/package/manager/PackageManager.cpp @@ -110,8 +110,12 @@ BPackageManager::Init(uint32 flags) // well. But we can easily filter those out. _AddInstalledRepository(fSystemRepository); - if (!fSystemRepository->IsInstalled()) - _AddInstalledRepository(fHomeRepository); + try { + if (!fSystemRepository->IsInstalled()) + _AddInstalledRepository(fHomeRepository); + } catch(BFatalErrorException& exception) { + // No home repository found. This is ok for haikuporter chroots. + } } // add other repositories @@ -787,11 +791,15 @@ BPackageManager::_AddLocalPackage(const char* fileName) bool BPackageManager::_NextSpecificInstallationLocation() { - if (fLocation == B_PACKAGE_INSTALLATION_LOCATION_SYSTEM) { - fLocation = B_PACKAGE_INSTALLATION_LOCATION_HOME; - fSystemRepository->SetInstalled(false); - _AddInstalledRepository(fHomeRepository); - return true; + try { + if (fLocation == B_PACKAGE_INSTALLATION_LOCATION_SYSTEM) { + fLocation = B_PACKAGE_INSTALLATION_LOCATION_HOME; + fSystemRepository->SetInstalled(false); + _AddInstalledRepository(fHomeRepository); + return true; + } + } catch (BFatalErrorException& e) { + // No home repo. This is acceptable for example when we are in an haikuporter chroot. } return false; diff --git a/src/servers/package/PackageDaemon.cpp b/src/servers/package/PackageDaemon.cpp index 0c052137d3..4b35cb1b0f 100644 --- a/src/servers/package/PackageDaemon.cpp +++ b/src/servers/package/PackageDaemon.cpp @@ -83,8 +83,23 @@ PackageDaemon::MessageReceived(BMessage* message) case B_MESSAGE_GET_INSTALLATION_LOCATION_INFO: case B_MESSAGE_COMMIT_TRANSACTION: { - if (fSystemRoot != NULL) + status_t error; + node_ref nodeRef; + + // Get the node_ref of the filesystem root to see which one it is + error = message->FindInt32("volume", &nodeRef.device); + if (error == B_OK) + error = message->FindInt64("root", &nodeRef.node); + + if (fSystemRoot != NULL && (error != B_OK + || fSystemRoot->NodeRef() == nodeRef)) fSystemRoot->HandleRequest(DetachCurrentMessage()); + else { + Root* root = _FindRoot(nodeRef); + if (root != NULL) { + root->HandleRequest(DetachCurrentMessage()); + } + } break; }