xref: /haiku/src/kits/package/PackageRoster.cpp (revision 9bb9cc8896854f6a0a28f586f6025e8eb2623f0b)
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