1/*
2 * Copyright 2015-2017 Haiku, Inc. All rights reserved.
3 * Distributed under the terms of the MIT License.
4 *
5 * Authors:
6 *		Axel D��rfler, axeld@pinc-software.de
7 */
8
9
10#include <LaunchRoster.h>
11
12#include <Application.h>
13#include <String.h>
14#include <StringList.h>
15
16#include <launch.h>
17#include <LaunchDaemonDefs.h>
18#include <LaunchRosterPrivate.h>
19#include <MessengerPrivate.h>
20
21
22using namespace BPrivate;
23
24
25BLaunchRoster::Private::Private(BLaunchRoster* roster)
26	:
27	fRoster(roster)
28{
29}
30
31
32BLaunchRoster::Private::Private(BLaunchRoster& roster)
33	:
34	fRoster(&roster)
35{
36}
37
38
39status_t
40BLaunchRoster::Private::RegisterSessionDaemon(const BMessenger& daemon)
41{
42	BMessage request(B_REGISTER_SESSION_DAEMON);
43	status_t status = request.AddInt32("user", getuid());
44	if (status == B_OK)
45		status = request.AddMessenger("daemon", daemon);
46	if (status != B_OK)
47		return status;
48
49	// send the request
50	BMessage result;
51	status = fRoster->fMessenger.SendMessage(&request, &result);
52
53	// evaluate the reply
54	if (status == B_OK)
55		status = result.what;
56
57	return status;
58}
59
60
61// #pragma mark -
62
63
64BLaunchRoster::BLaunchRoster()
65{
66	_InitMessenger();
67}
68
69
70BLaunchRoster::~BLaunchRoster()
71{
72}
73
74
75status_t
76BLaunchRoster::InitCheck() const
77{
78	return fMessenger.Team() >= 0 ? B_OK : B_ERROR;
79}
80
81
82status_t
83BLaunchRoster::GetData(BMessage& data)
84{
85	if (be_app == NULL)
86		return B_BAD_VALUE;
87
88	return GetData(be_app->Signature(), data);
89}
90
91
92status_t
93BLaunchRoster::GetData(const char* signature, BMessage& data)
94{
95	if (signature == NULL || signature[0] == '\0')
96		return B_BAD_VALUE;
97
98	BMessage request(B_GET_LAUNCH_DATA);
99	status_t status = request.AddString("name", signature);
100	if (status == B_OK)
101		status = request.AddInt32("user", getuid());
102	if (status != B_OK)
103		return status;
104
105	return _SendRequest(request, data);
106}
107
108
109port_id
110BLaunchRoster::GetPort(const char* name)
111{
112	if (be_app == NULL)
113		return B_BAD_VALUE;
114
115	return GetPort(be_app->Signature(), name);
116}
117
118
119port_id
120BLaunchRoster::GetPort(const char* signature, const char* name)
121{
122	BMessage data;
123	status_t status = GetData(signature, data);
124	if (status == B_OK) {
125		BString fieldName;
126		if (name != NULL)
127			fieldName << name << "_";
128		fieldName << "port";
129
130		port_id port = data.GetInt32(fieldName.String(), B_NAME_NOT_FOUND);
131		if (port >= 0)
132			return port;
133	}
134
135	return -1;
136}
137
138
139status_t
140BLaunchRoster::Target(const char* name, const BMessage& data,
141	const char* baseName)
142{
143	return Target(name, &data, baseName);
144}
145
146
147status_t
148BLaunchRoster::Target(const char* name, const BMessage* data,
149	const char* baseName)
150{
151	if (name == NULL)
152		return B_BAD_VALUE;
153
154	BMessage request(B_LAUNCH_TARGET);
155	status_t status = request.AddInt32("user", getuid());
156	if (status == B_OK)
157		status = request.AddString("target", name);
158	if (status == B_OK && data != NULL && !data->IsEmpty())
159		status = request.AddMessage("data", data);
160	if (status == B_OK && baseName != NULL)
161		status = request.AddString("base target", baseName);
162	if (status != B_OK)
163		return status;
164
165	return _SendRequest(request);
166}
167
168
169status_t
170BLaunchRoster::StopTarget(const char* name, bool force)
171{
172	if (name == NULL)
173		return B_BAD_VALUE;
174
175	BMessage request(B_STOP_LAUNCH_TARGET);
176	status_t status = request.AddInt32("user", getuid());
177	if (status == B_OK)
178		status = request.AddString("target", name);
179	if (status == B_OK)
180		status = request.AddBool("force", force);
181	if (status != B_OK)
182		return status;
183
184	return _SendRequest(request);
185}
186
187
188status_t
189BLaunchRoster::Start(const char* name)
190{
191	if (name == NULL)
192		return B_BAD_VALUE;
193
194	BMessage request(B_LAUNCH_JOB);
195	status_t status = request.AddInt32("user", getuid());
196	if (status == B_OK)
197		status = request.AddString("name", name);
198	if (status != B_OK)
199		return status;
200
201	return _SendRequest(request);
202}
203
204
205status_t
206BLaunchRoster::Stop(const char* name, bool force)
207{
208	if (name == NULL)
209		return B_BAD_VALUE;
210
211	BMessage request(B_STOP_LAUNCH_JOB);
212	status_t status = request.AddInt32("user", getuid());
213	if (status == B_OK)
214		status = request.AddString("name", name);
215	if (status == B_OK)
216		status = request.AddBool("force", force);
217	if (status != B_OK)
218		return status;
219
220	return _SendRequest(request);
221}
222
223
224status_t
225BLaunchRoster::SetEnabled(const char* name, bool enable)
226{
227	if (name == NULL)
228		return B_BAD_VALUE;
229
230	BMessage request(B_ENABLE_LAUNCH_JOB);
231	status_t status = request.AddInt32("user", getuid());
232	if (status == B_OK)
233		status = request.AddString("name", name);
234	if (status == B_OK)
235		status = request.AddBool("enable", enable);
236	if (status != B_OK)
237		return status;
238
239	return _SendRequest(request);
240}
241
242
243status_t
244BLaunchRoster::StartSession(const char* login)
245{
246	if (login == NULL)
247		return B_BAD_VALUE;
248
249	BMessage request(B_LAUNCH_SESSION);
250	status_t status = request.AddInt32("user", getuid());
251	if (status == B_OK)
252		status = request.AddString("login", login);
253	if (status != B_OK)
254		return status;
255
256	return _SendRequest(request);
257}
258
259
260status_t
261BLaunchRoster::RegisterEvent(const BMessenger& source, const char* name,
262	uint32 flags)
263{
264	return _UpdateEvent(B_REGISTER_LAUNCH_EVENT, source, name, flags);
265}
266
267
268status_t
269BLaunchRoster::UnregisterEvent(const BMessenger& source, const char* name)
270{
271	return _UpdateEvent(B_UNREGISTER_LAUNCH_EVENT, source, name);
272}
273
274
275status_t
276BLaunchRoster::NotifyEvent(const BMessenger& source, const char* name)
277{
278	return _UpdateEvent(B_NOTIFY_LAUNCH_EVENT, source, name);
279}
280
281
282status_t
283BLaunchRoster::ResetStickyEvent(const BMessenger& source, const char* name)
284{
285	return _UpdateEvent(B_RESET_STICKY_LAUNCH_EVENT, source, name);
286}
287
288
289status_t
290BLaunchRoster::GetTargets(BStringList& targets)
291{
292	BMessage request(B_GET_LAUNCH_TARGETS);
293	status_t status = request.AddInt32("user", getuid());
294	if (status != B_OK)
295		return status;
296
297	// send the request
298	BMessage result;
299	status = _SendRequest(request, result);
300	if (status == B_OK)
301		status = result.FindStrings("target", &targets);
302
303	return status;
304}
305
306
307status_t
308BLaunchRoster::GetTargetInfo(const char* name, BMessage& info)
309{
310	return _GetInfo(B_GET_LAUNCH_TARGET_INFO, name, info);
311}
312
313
314status_t
315BLaunchRoster::GetJobs(const char* target, BStringList& jobs)
316{
317	BMessage request(B_GET_LAUNCH_JOBS);
318	status_t status = request.AddInt32("user", getuid());
319	if (status == B_OK && target != NULL)
320		status = request.AddString("target", target);
321	if (status != B_OK)
322		return status;
323
324	// send the request
325	BMessage result;
326	status = _SendRequest(request, result);
327	if (status == B_OK)
328		status = result.FindStrings("job", &jobs);
329
330	return status;
331}
332
333
334status_t
335BLaunchRoster::GetJobInfo(const char* name, BMessage& info)
336{
337	return _GetInfo(B_GET_LAUNCH_JOB_INFO, name, info);
338}
339
340
341status_t
342BLaunchRoster::GetLog(BMessage& info)
343{
344	return _GetLog(NULL, info);
345}
346
347
348status_t
349BLaunchRoster::GetLog(const BMessage& filter, BMessage& info)
350{
351	return _GetLog(&filter, info);
352}
353
354
355void
356BLaunchRoster::_InitMessenger()
357{
358#ifdef TEST_MODE
359	port_id daemonPort = find_port(B_LAUNCH_DAEMON_PORT_NAME);
360#else
361	// find the launch_daemon port
362	port_id daemonPort = BPrivate::get_launch_daemon_port();
363#endif
364	port_info info;
365	if (daemonPort >= 0 && get_port_info(daemonPort, &info) == B_OK) {
366		BMessenger::Private(fMessenger).SetTo(info.team, daemonPort,
367			B_PREFERRED_TOKEN);
368	}
369}
370
371
372status_t
373BLaunchRoster::_SendRequest(BMessage& request)
374{
375	BMessage result;
376	return _SendRequest(request, result);
377}
378
379
380status_t
381BLaunchRoster::_SendRequest(BMessage& request, BMessage& result)
382{
383	// Send the request, and evaluate the reply
384	status_t status = fMessenger.SendMessage(&request, &result);
385	if (status == B_OK)
386		status = result.what;
387
388	return status;
389}
390
391
392status_t
393BLaunchRoster::_UpdateEvent(uint32 what, const BMessenger& source,
394	const char* name, uint32 flags)
395{
396	if (be_app == NULL || name == NULL || name[0] == '\0')
397		return B_BAD_VALUE;
398
399	BMessage request(what);
400	status_t status = request.AddInt32("user", getuid());
401	if (status == B_OK)
402		status = request.AddMessenger("source", source);
403	if (status == B_OK)
404		status = request.AddString("owner", be_app->Signature());
405	if (status == B_OK)
406		status = request.AddString("name", name);
407	if (status == B_OK && flags != 0)
408		status = request.AddUInt32("flags", flags);
409	if (status != B_OK)
410		return status;
411
412	return _SendRequest(request);
413}
414
415
416status_t
417BLaunchRoster::_GetInfo(uint32 what, const char* name, BMessage& info)
418{
419	if (name == NULL || name[0] == '\0')
420		return B_BAD_VALUE;
421
422	BMessage request(what);
423	status_t status = request.AddInt32("user", getuid());
424	if (status == B_OK)
425		status = request.AddString("name", name);
426	if (status != B_OK)
427		return status;
428
429	return _SendRequest(request, info);
430}
431
432
433status_t
434BLaunchRoster::_GetLog(const BMessage* filter, BMessage& info)
435{
436	BMessage request(B_GET_LAUNCH_LOG);
437	status_t status = request.AddInt32("user", getuid());
438	if (status == B_OK && filter != NULL)
439		status = request.AddMessage("filter", filter);
440	if (status != B_OK)
441		return status;
442
443	return _SendRequest(request, info);
444}
445