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 39 namespace BPackageKit { 40 41 42 using namespace BHPKG; 43 44 45 BPackageRoster::BPackageRoster() 46 { 47 } 48 49 50 BPackageRoster::~BPackageRoster() 51 { 52 } 53 54 55 bool 56 BPackageRoster::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 76 status_t 77 BPackageRoster::GetCommonRepositoryConfigPath(BPath* path, bool create) const 78 { 79 return _GetRepositoryPath(path, create, B_SYSTEM_SETTINGS_DIRECTORY); 80 } 81 82 83 status_t 84 BPackageRoster::GetUserRepositoryConfigPath(BPath* path, bool create) const 85 { 86 return _GetRepositoryPath(path, create, B_USER_SETTINGS_DIRECTORY); 87 } 88 89 90 status_t 91 BPackageRoster::GetCommonRepositoryCachePath(BPath* path, bool create) const 92 { 93 return _GetRepositoryPath(path, create, B_SYSTEM_CACHE_DIRECTORY); 94 } 95 96 97 status_t 98 BPackageRoster::GetUserRepositoryCachePath(BPath* path, bool create) const 99 { 100 return _GetRepositoryPath(path, create, B_USER_CACHE_DIRECTORY); 101 } 102 103 104 status_t 105 BPackageRoster::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 117 status_t 118 BPackageRoster::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 129 status_t 130 BPackageRoster::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 162 status_t 163 BPackageRoster::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 191 status_t 192 BPackageRoster::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 220 status_t 221 BPackageRoster::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 235 status_t 236 BPackageRoster::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 255 status_t 256 BPackageRoster::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 283 status_t 284 BPackageRoster::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 318 status_t 319 BPackageRoster::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 351 status_t 352 BPackageRoster::_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 376 status_t 377 BPackageRoster::_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