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 repoCacheEntry.SetTo(path.Path()); 185 return repositoryCache->SetTo(repoCacheEntry); 186 } 187 188 189 status_t 190 BPackageRoster::GetRepositoryConfig(const BString& name, 191 BRepositoryConfig* repositoryConfig) 192 { 193 if (repositoryConfig == NULL) 194 return B_BAD_VALUE; 195 196 // user path has higher precedence than common path 197 BPath path; 198 status_t result = GetUserRepositoryConfigPath(&path); 199 if (result != B_OK) 200 return result; 201 path.Append(name.String()); 202 203 BEntry repoConfigEntry(path.Path()); 204 if (repoConfigEntry.Exists()) 205 return repositoryConfig->SetTo(repoConfigEntry); 206 207 if ((result = GetCommonRepositoryConfigPath(&path, true)) != B_OK) 208 return result; 209 path.Append(name.String()); 210 211 repoConfigEntry.SetTo(path.Path()); 212 return repositoryConfig->SetTo(repoConfigEntry); 213 } 214 215 216 status_t 217 BPackageRoster::GetInstallationLocationInfo( 218 BPackageInstallationLocation location, BInstallationLocationInfo& _info) 219 { 220 // This method makes sense only on an installed Haiku, but not for the build 221 // tools. 222 #if defined(__HAIKU__) && !defined(HAIKU_HOST_PLATFORM_HAIKU) 223 return BPackageKit::BPrivate::BDaemonClient().GetInstallationLocationInfo( 224 location, _info); 225 #else 226 return B_NOT_SUPPORTED; 227 #endif 228 } 229 230 231 status_t 232 BPackageRoster::GetActivePackages(BPackageInstallationLocation location, 233 BPackageInfoSet& packageInfos) 234 { 235 // This method makes sense only on an installed Haiku, but not for the build 236 // tools. 237 #if defined(__HAIKU__) && !defined(HAIKU_HOST_PLATFORM_HAIKU) 238 BInstallationLocationInfo info; 239 status_t error = GetInstallationLocationInfo(location, info); 240 if (error != B_OK) 241 return error; 242 243 packageInfos = info.LatestActivePackageInfos(); 244 return B_OK; 245 #else 246 return B_NOT_SUPPORTED; 247 #endif 248 } 249 250 251 status_t 252 BPackageRoster::StartWatching(const BMessenger& target, uint32 eventMask) 253 { 254 // This method makes sense only on an installed Haiku, but not for the build 255 // tools. 256 #if defined(__HAIKU__) && !defined(HAIKU_HOST_PLATFORM_HAIKU) 257 // compose the registrar request 258 BMessage request(::BPrivate::B_REG_PACKAGE_START_WATCHING); 259 status_t error; 260 if ((error = request.AddMessenger("target", target)) != B_OK 261 || (error = request.AddUInt32("events", eventMask)) != B_OK) { 262 return error; 263 } 264 265 // send it 266 BMessage reply; 267 error = BRoster::Private().SendTo(&request, &reply, false); 268 if (error != B_OK) 269 return error; 270 271 // get result 272 if (reply.what != ::BPrivate::B_REG_SUCCESS) { 273 int32 result; 274 if (reply.FindInt32("error", &result) != B_OK) 275 result = B_ERROR; 276 return (status_t)error; 277 } 278 279 return B_OK; 280 #else 281 return B_NOT_SUPPORTED; 282 #endif 283 } 284 285 286 status_t 287 BPackageRoster::StopWatching(const BMessenger& target) 288 { 289 // This method makes sense only on an installed Haiku, but not for the build 290 // tools. 291 #if defined(__HAIKU__) && !defined(HAIKU_HOST_PLATFORM_HAIKU) 292 // compose the registrar request 293 BMessage request(::BPrivate::B_REG_PACKAGE_STOP_WATCHING); 294 status_t error = request.AddMessenger("target", target); 295 if (error != B_OK) 296 return error; 297 298 // send it 299 BMessage reply; 300 error = BRoster::Private().SendTo(&request, &reply, false); 301 if (error != B_OK) 302 return error; 303 304 // get result 305 if (reply.what != ::BPrivate::B_REG_SUCCESS) { 306 int32 result; 307 if (reply.FindInt32("error", &result) != B_OK) 308 result = B_ERROR; 309 return (status_t)error; 310 } 311 312 return B_OK; 313 #else 314 return B_NOT_SUPPORTED; 315 #endif 316 } 317 318 319 status_t 320 BPackageRoster::_GetRepositoryPath(BPath* path, bool create, 321 directory_which whichDir) const 322 { 323 if (path == NULL) 324 return B_BAD_VALUE; 325 326 status_t result = find_directory(whichDir, path); 327 if (result != B_OK) 328 return result; 329 if ((result = path->Append("package-repositories")) != B_OK) 330 return result; 331 332 if (create) { 333 BEntry entry(path->Path(), true); 334 if (!entry.Exists()) { 335 if (mkdir(path->Path(), 0755) != 0) 336 return errno; 337 } 338 } 339 340 return B_OK; 341 } 342 343 344 status_t 345 BPackageRoster::_VisitRepositoryConfigs(const BPath& path, 346 BRepositoryConfigVisitor& visitor) 347 { 348 BDirectory directory(path.Path()); 349 status_t result = directory.InitCheck(); 350 if (result == B_ENTRY_NOT_FOUND) 351 return B_OK; 352 if (result != B_OK) 353 return result; 354 355 BEntry entry; 356 while (directory.GetNextEntry(&entry, true) == B_OK) { 357 if ((result = visitor(entry)) != B_OK) 358 return result; 359 } 360 361 return B_OK; 362 } 363 364 365 } // namespace BPackageKit 366