1/* 2 * Copyright 2011-2014, Haiku, Inc. All Rights Reserved. 3 * Distributed under the terms of the MIT License. 4 * 5 * Authors: 6 * Oliver Tappe <zooey@hirschkaefer.de> 7 */ 8 9 10#include <package/PackageRoster.h> 11 12#include <errno.h> 13#include <sys/stat.h> 14 15#include <Directory.h> 16#include <Entry.h> 17#include <Messenger.h> 18#include <Path.h> 19#include <String.h> 20#include <StringList.h> 21 22#include <package/InstallationLocationInfo.h> 23#include <package/PackageInfo.h> 24#include <package/PackageInfoContentHandler.h> 25#include <package/PackageInfoSet.h> 26#include <package/RepositoryCache.h> 27#include <package/RepositoryConfig.h> 28 29#include <package/hpkg/PackageReader.h> 30 31 32#if defined(__HAIKU__) && !defined(HAIKU_HOST_PLATFORM_HAIKU) 33# include <package/DaemonClient.h> 34# include <RegistrarDefs.h> 35# include <RosterPrivate.h> 36#endif 37 38 39namespace BPackageKit { 40 41 42using namespace BHPKG; 43 44 45BPackageRoster::BPackageRoster() 46{ 47} 48 49 50BPackageRoster::~BPackageRoster() 51{ 52} 53 54 55bool 56BPackageRoster::IsRebootNeeded() 57{ 58 BInstallationLocationInfo info; 59 60 // We get information on the system package installation location. 61 // If we fail, we just have to assume a reboot is not needed. 62 if (GetInstallationLocationInfo(B_PACKAGE_INSTALLATION_LOCATION_SYSTEM, 63 info) != B_OK) 64 return false; 65 66 // CurrentlyActivePackageInfos() will return 0 if no packages need to be 67 // activated with a reboot. Otherwise, the method will return the total 68 // number of packages in the system package directory. 69 if (info.CurrentlyActivePackageInfos().CountInfos() != 0) 70 return true; 71 72 return false; 73} 74 75 76status_t 77BPackageRoster::GetCommonRepositoryConfigPath(BPath* path, bool create) const 78{ 79 return _GetRepositoryPath(path, create, B_SYSTEM_SETTINGS_DIRECTORY); 80} 81 82 83status_t 84BPackageRoster::GetUserRepositoryConfigPath(BPath* path, bool create) const 85{ 86 return _GetRepositoryPath(path, create, B_USER_SETTINGS_DIRECTORY); 87} 88 89 90status_t 91BPackageRoster::GetCommonRepositoryCachePath(BPath* path, bool create) const 92{ 93 return _GetRepositoryPath(path, create, B_SYSTEM_CACHE_DIRECTORY); 94} 95 96 97status_t 98BPackageRoster::GetUserRepositoryCachePath(BPath* path, bool create) const 99{ 100 return _GetRepositoryPath(path, create, B_USER_CACHE_DIRECTORY); 101} 102 103 104status_t 105BPackageRoster::VisitCommonRepositoryConfigs(BRepositoryConfigVisitor& visitor) 106{ 107 BPath commonRepositoryConfigPath; 108 status_t result 109 = GetCommonRepositoryConfigPath(&commonRepositoryConfigPath); 110 if (result != B_OK) 111 return result; 112 113 return _VisitRepositoryConfigs(commonRepositoryConfigPath, visitor); 114} 115 116 117status_t 118BPackageRoster::VisitUserRepositoryConfigs(BRepositoryConfigVisitor& visitor) 119{ 120 BPath userRepositoryConfigPath; 121 status_t result = GetUserRepositoryConfigPath(&userRepositoryConfigPath); 122 if (result != B_OK) 123 return result; 124 125 return _VisitRepositoryConfigs(userRepositoryConfigPath, visitor); 126} 127 128 129status_t 130BPackageRoster::GetRepositoryNames(BStringList& names) 131{ 132 struct RepositoryNameCollector : public BRepositoryConfigVisitor { 133 RepositoryNameCollector(BStringList& _names) 134 : names(_names) 135 { 136 } 137 status_t operator()(const BEntry& entry) 138 { 139 char name[B_FILE_NAME_LENGTH]; 140 status_t result = entry.GetName(name); 141 if (result != B_OK) 142 return result; 143 int32 count = names.CountStrings(); 144 for (int i = 0; i < count; ++i) { 145 if (names.StringAt(i).Compare(name) == 0) 146 return B_OK; 147 } 148 names.Add(name); 149 return B_OK; 150 } 151 BStringList& names; 152 }; 153 RepositoryNameCollector repositoryNameCollector(names); 154 status_t result = VisitUserRepositoryConfigs(repositoryNameCollector); 155 if (result != B_OK) 156 return result; 157 158 return VisitCommonRepositoryConfigs(repositoryNameCollector); 159} 160 161 162status_t 163BPackageRoster::GetRepositoryCache(const BString& name, 164 BRepositoryCache* repositoryCache) 165{ 166 if (repositoryCache == NULL) 167 return B_BAD_VALUE; 168 169 // user path has higher precedence than common path 170 BPath path; 171 status_t result = GetUserRepositoryCachePath(&path); 172 if (result != B_OK) 173 return result; 174 path.Append(name.String()); 175 176 BEntry repoCacheEntry(path.Path()); 177 if (repoCacheEntry.Exists()) 178 return repositoryCache->SetTo(repoCacheEntry); 179 180 if ((result = GetCommonRepositoryCachePath(&path, true)) != B_OK) 181 return result; 182 path.Append(name.String()); 183 184 result = repoCacheEntry.SetTo(path.Path()); 185 if (result != B_OK) 186 return result; 187 return repositoryCache->SetTo(repoCacheEntry); 188} 189 190 191status_t 192BPackageRoster::GetRepositoryConfig(const BString& name, 193 BRepositoryConfig* repositoryConfig) 194{ 195 if (repositoryConfig == NULL) 196 return B_BAD_VALUE; 197 198 // user path has higher precedence than common path 199 BPath path; 200 status_t result = GetUserRepositoryConfigPath(&path); 201 if (result != B_OK) 202 return result; 203 path.Append(name.String()); 204 205 BEntry repoConfigEntry(path.Path()); 206 if (repoConfigEntry.Exists()) 207 return repositoryConfig->SetTo(repoConfigEntry); 208 209 if ((result = GetCommonRepositoryConfigPath(&path, true)) != B_OK) 210 return result; 211 path.Append(name.String()); 212 213 result = repoConfigEntry.SetTo(path.Path()); 214 if (result != B_OK) 215 return result; 216 return repositoryConfig->SetTo(repoConfigEntry); 217} 218 219 220status_t 221BPackageRoster::GetInstallationLocationInfo( 222 BPackageInstallationLocation location, BInstallationLocationInfo& _info) 223{ 224// This method makes sense only on an installed Haiku, but not for the build 225// tools. 226#if defined(__HAIKU__) && !defined(HAIKU_HOST_PLATFORM_HAIKU) 227 return BPackageKit::BPrivate::BDaemonClient().GetInstallationLocationInfo( 228 location, _info); 229#else 230 return B_NOT_SUPPORTED; 231#endif 232} 233 234 235status_t 236BPackageRoster::GetActivePackages(BPackageInstallationLocation location, 237 BPackageInfoSet& packageInfos) 238{ 239// This method makes sense only on an installed Haiku, but not for the build 240// tools. 241#if defined(__HAIKU__) && !defined(HAIKU_HOST_PLATFORM_HAIKU) 242 BInstallationLocationInfo info; 243 status_t error = GetInstallationLocationInfo(location, info); 244 if (error != B_OK) 245 return error; 246 247 packageInfos = info.LatestActivePackageInfos(); 248 return B_OK; 249#else 250 return B_NOT_SUPPORTED; 251#endif 252} 253 254 255status_t 256BPackageRoster::IsPackageActive(BPackageInstallationLocation location, 257 const BPackageInfo info, bool* active) 258{ 259// This method makes sense only on an installed Haiku, but not for the build 260// tools. 261#if defined(__HAIKU__) && !defined(HAIKU_HOST_PLATFORM_HAIKU) 262 BPackageInfoSet packageInfos; 263 status_t error = GetActivePackages(location, packageInfos); 264 if (error != B_OK) 265 return error; 266 267 BRepositoryCache::Iterator it = packageInfos.GetIterator(); 268 while (const BPackageInfo* packageInfo = it.Next()) { 269 if (info.Name() == packageInfo->Name() && 270 info.Version().Compare(packageInfo->Version()) == 0) { 271 *active = true; 272 break; 273 } 274 } 275 276 return B_OK; 277#else 278 return B_NOT_SUPPORTED; 279#endif 280} 281 282 283status_t 284BPackageRoster::StartWatching(const BMessenger& target, uint32 eventMask) 285{ 286// This method makes sense only on an installed Haiku, but not for the build 287// tools. 288#if defined(__HAIKU__) && !defined(HAIKU_HOST_PLATFORM_HAIKU) 289 // compose the registrar request 290 BMessage request(::BPrivate::B_REG_PACKAGE_START_WATCHING); 291 status_t error; 292 if ((error = request.AddMessenger("target", target)) != B_OK 293 || (error = request.AddUInt32("events", eventMask)) != B_OK) { 294 return error; 295 } 296 297 // send it 298 BMessage reply; 299 error = BRoster::Private().SendTo(&request, &reply, false); 300 if (error != B_OK) 301 return error; 302 303 // get result 304 if (reply.what != ::BPrivate::B_REG_SUCCESS) { 305 int32 result; 306 if (reply.FindInt32("error", &result) != B_OK) 307 result = B_ERROR; 308 return (status_t)error; 309 } 310 311 return B_OK; 312#else 313 return B_NOT_SUPPORTED; 314#endif 315} 316 317 318status_t 319BPackageRoster::StopWatching(const BMessenger& target) 320{ 321// This method makes sense only on an installed Haiku, but not for the build 322// tools. 323#if defined(__HAIKU__) && !defined(HAIKU_HOST_PLATFORM_HAIKU) 324 // compose the registrar request 325 BMessage request(::BPrivate::B_REG_PACKAGE_STOP_WATCHING); 326 status_t error = request.AddMessenger("target", target); 327 if (error != B_OK) 328 return error; 329 330 // send it 331 BMessage reply; 332 error = BRoster::Private().SendTo(&request, &reply, false); 333 if (error != B_OK) 334 return error; 335 336 // get result 337 if (reply.what != ::BPrivate::B_REG_SUCCESS) { 338 int32 result; 339 if (reply.FindInt32("error", &result) != B_OK) 340 result = B_ERROR; 341 return (status_t)error; 342 } 343 344 return B_OK; 345#else 346 return B_NOT_SUPPORTED; 347#endif 348} 349 350 351status_t 352BPackageRoster::_GetRepositoryPath(BPath* path, bool create, 353 directory_which whichDir) const 354{ 355 if (path == NULL) 356 return B_BAD_VALUE; 357 358 status_t result = find_directory(whichDir, path); 359 if (result != B_OK) 360 return result; 361 if ((result = path->Append("package-repositories")) != B_OK) 362 return result; 363 364 if (create) { 365 BEntry entry(path->Path(), true); 366 if (!entry.Exists()) { 367 if (mkdir(path->Path(), 0755) != 0) 368 return errno; 369 } 370 } 371 372 return B_OK; 373} 374 375 376status_t 377BPackageRoster::_VisitRepositoryConfigs(const BPath& path, 378 BRepositoryConfigVisitor& visitor) 379{ 380 BDirectory directory(path.Path()); 381 status_t result = directory.InitCheck(); 382 if (result == B_ENTRY_NOT_FOUND) 383 return B_OK; 384 if (result != B_OK) 385 return result; 386 387 BEntry entry; 388 while (directory.GetNextEntry(&entry, true) == B_OK) { 389 if ((result = visitor(entry)) != B_OK) 390 return result; 391 } 392 393 return B_OK; 394} 395 396 397} // namespace BPackageKit 398