Make UEFI boot-platform build again
[haiku.git] / src / servers / launch / Job.cpp
bloba742518a9a1bc55b740c45affc13645322d18816
1 /*
2 * Copyright 2015-2016, Axel Dörfler, axeld@pinc-software.de.
3 * Distributed under the terms of the MIT License.
4 */
7 #include "Job.h"
9 #include <stdlib.h>
11 #include <Entry.h>
12 #include <Looper.h>
13 #include <Message.h>
14 #include <Roster.h>
16 #include <MessagePrivate.h>
17 #include <RosterPrivate.h>
18 #include <user_group.h>
20 #include "Target.h"
21 #include "Utility.h"
24 Job::Job(const char* name)
26 BaseJob(name),
27 fEnabled(true),
28 fService(false),
29 fCreateDefaultPort(false),
30 fLaunching(false),
31 fInitStatus(B_NO_INIT),
32 fTeam(-1),
33 fDefaultPort(-1),
34 fToken((uint32)B_PREFERRED_TOKEN),
35 fLaunchStatus(B_NO_INIT),
36 fTarget(NULL),
37 fPendingLaunchDataReplies(0, false)
39 mutex_init(&fLaunchStatusLock, "launch status lock");
43 Job::Job(const Job& other)
45 BaseJob(other.Name()),
46 fEnabled(other.IsEnabled()),
47 fService(other.IsService()),
48 fCreateDefaultPort(other.CreateDefaultPort()),
49 fLaunching(other.IsLaunching()),
50 fInitStatus(B_NO_INIT),
51 fTeam(-1),
52 fDefaultPort(-1),
53 fToken((uint32)B_PREFERRED_TOKEN),
54 fLaunchStatus(B_NO_INIT),
55 fTarget(other.Target()),
56 fPendingLaunchDataReplies(0, false)
58 mutex_init(&fLaunchStatusLock, "launch status lock");
60 fCondition = other.fCondition;
61 // TODO: copy events
62 //fEvent = other.fEvent;
63 fEnvironment = other.fEnvironment;
64 fSourceFiles = other.fSourceFiles;
66 for (int32 i = 0; i < other.Arguments().CountStrings(); i++)
67 AddArgument(other.Arguments().StringAt(i));
69 for (int32 i = 0; i < other.Requirements().CountStrings(); i++)
70 AddRequirement(other.Requirements().StringAt(i));
72 PortMap::const_iterator constIterator = other.Ports().begin();
73 for (; constIterator != other.Ports().end(); constIterator++) {
74 fPortMap.insert(
75 std::make_pair(constIterator->first, constIterator->second));
78 PortMap::iterator iterator = fPortMap.begin();
79 for (; iterator != fPortMap.end(); iterator++)
80 iterator->second.RemoveData("port");
84 Job::~Job()
86 _DeletePorts();
90 ::TeamRegistrator*
91 Job::TeamRegistrator() const
93 return fTeamRegistrator;
97 void
98 Job::SetTeamRegistrator(::TeamRegistrator* registrator)
100 fTeamRegistrator = registrator;
104 bool
105 Job::IsEnabled() const
107 return fEnabled;
111 void
112 Job::SetEnabled(bool enable)
114 fEnabled = enable;
118 bool
119 Job::IsService() const
121 return fService;
125 void
126 Job::SetService(bool service)
128 fService = service;
132 bool
133 Job::CreateDefaultPort() const
135 return fCreateDefaultPort;
139 void
140 Job::SetCreateDefaultPort(bool createPort)
142 fCreateDefaultPort = createPort;
146 void
147 Job::AddPort(BMessage& data)
149 const char* name = data.GetString("name");
150 fPortMap.insert(std::pair<BString, BMessage>(BString(name), data));
154 const BStringList&
155 Job::Arguments() const
157 return fArguments;
161 BStringList&
162 Job::Arguments()
164 return fArguments;
168 void
169 Job::AddArgument(const char* argument)
171 fArguments.Add(argument);
175 ::Target*
176 Job::Target() const
178 return fTarget;
182 void
183 Job::SetTarget(::Target* target)
185 fTarget = target;
189 const BStringList&
190 Job::Requirements() const
192 return fRequirements;
196 BStringList&
197 Job::Requirements()
199 return fRequirements;
203 void
204 Job::AddRequirement(const char* requirement)
206 fRequirements.Add(requirement);
210 const BStringList&
211 Job::Pending() const
213 return fPendingJobs;
217 BStringList&
218 Job::Pending()
220 return fPendingJobs;
224 void
225 Job::AddPending(const char* pending)
227 fPendingJobs.Add(pending);
231 bool
232 Job::CheckCondition(ConditionContext& context) const
234 if (Target() != NULL && !Target()->HasLaunched())
235 return false;
237 return BaseJob::CheckCondition(context);
241 status_t
242 Job::Init(const Finder& finder, std::set<BString>& dependencies)
244 // Only initialize the jobs once
245 if (fInitStatus != B_NO_INIT)
246 return fInitStatus;
248 fInitStatus = B_OK;
250 if (fTarget != NULL)
251 fTarget->AddDependency(this);
253 // Check dependencies
255 for (int32 index = 0; index < Requirements().CountStrings(); index++) {
256 const BString& requires = Requirements().StringAt(index);
257 if (dependencies.find(requires) != dependencies.end()) {
258 // Found a cyclic dependency
259 // TODO: log error
260 return fInitStatus = B_ERROR;
262 dependencies.insert(requires);
264 Job* dependency = finder.FindJob(requires);
265 if (dependency != NULL) {
266 std::set<BString> subDependencies = dependencies;
268 fInitStatus = dependency->Init(finder, subDependencies);
269 if (fInitStatus != B_OK) {
270 // TODO: log error
271 return fInitStatus;
274 fInitStatus = _AddRequirement(dependency);
275 } else {
276 ::Target* target = finder.FindTarget(requires);
277 if (target != NULL)
278 fInitStatus = _AddRequirement(dependency);
279 else {
280 // Could not find dependency
281 fInitStatus = B_NAME_NOT_FOUND;
284 if (fInitStatus != B_OK) {
285 // TODO: log error
286 return fInitStatus;
290 return fInitStatus;
294 status_t
295 Job::InitCheck() const
297 return fInitStatus;
301 team_id
302 Job::Team() const
304 return fTeam;
308 const PortMap&
309 Job::Ports() const
311 return fPortMap;
315 port_id
316 Job::Port(const char* name) const
318 PortMap::const_iterator found = fPortMap.find(name);
319 if (found != fPortMap.end())
320 return found->second.GetInt32("port", -1);
322 return B_NAME_NOT_FOUND;
326 port_id
327 Job::DefaultPort() const
329 return fDefaultPort;
333 void
334 Job::SetDefaultPort(port_id port)
336 fDefaultPort = port;
338 PortMap::iterator iterator = fPortMap.begin();
339 for (; iterator != fPortMap.end(); iterator++) {
340 BString name;
341 if (iterator->second.HasString("name"))
342 continue;
344 iterator->second.SetInt32("port", (int32)port);
345 break;
350 status_t
351 Job::Launch()
353 // Build environment
355 std::vector<const char*> environment;
356 for (const char** variable = (const char**)environ; variable[0] != NULL;
357 variable++) {
358 environment.push_back(variable[0]);
361 if (Target() != NULL)
362 _AddStringList(environment, Target()->Environment());
363 _AddStringList(environment, Environment());
365 // Resolve source files
366 BStringList sourceFilesEnvironment;
367 GetSourceFilesEnvironment(sourceFilesEnvironment);
368 _AddStringList(environment, sourceFilesEnvironment);
370 environment.push_back(NULL);
372 if (fArguments.IsEmpty()) {
373 // Launch by signature
374 BString signature("application/");
375 signature << Name();
377 return _Launch(signature.String(), NULL, 0, NULL, &environment[0]);
380 // Build argument vector
382 entry_ref ref;
383 status_t status = get_ref_for_path(
384 Utility::TranslatePath(fArguments.StringAt(0).String()), &ref);
385 if (status != B_OK) {
386 _SetLaunchStatus(status);
387 return status;
390 std::vector<BString> strings;
391 std::vector<const char*> args;
393 size_t count = fArguments.CountStrings() - 1;
394 if (count > 0) {
395 for (int32 i = 1; i < fArguments.CountStrings(); i++) {
396 strings.push_back(Utility::TranslatePath(fArguments.StringAt(i)));
397 args.push_back(strings.back());
399 args.push_back(NULL);
402 // Launch via entry_ref
403 return _Launch(NULL, &ref, count, &args[0], &environment[0]);
407 bool
408 Job::IsLaunched() const
410 return fLaunchStatus != B_NO_INIT;
414 bool
415 Job::IsRunning() const
417 return fTeam >= 0;
421 void
422 Job::TeamDeleted()
424 fTeam = -1;
425 fDefaultPort = -1;
427 if (IsService())
428 SetState(B_JOB_STATE_WAITING_TO_RUN);
430 MutexLocker locker(fLaunchStatusLock);
431 fLaunchStatus = B_NO_INIT;
435 bool
436 Job::CanBeLaunched() const
438 // Services cannot be launched while they are running
439 return IsEnabled() && !IsLaunching() && (!IsService() || !IsRunning());
443 bool
444 Job::IsLaunching() const
446 return fLaunching;
450 void
451 Job::SetLaunching(bool launching)
453 fLaunching = launching;
457 status_t
458 Job::HandleGetLaunchData(BMessage* message)
460 MutexLocker launchLocker(fLaunchStatusLock);
461 if (IsLaunched())
462 return _SendLaunchDataReply(message);
464 return fPendingLaunchDataReplies.AddItem(message) ? B_OK : B_NO_MEMORY;
468 status_t
469 Job::GetMessenger(BMessenger& messenger)
471 if (fDefaultPort < 0)
472 return B_NAME_NOT_FOUND;
474 BMessenger::Private(messenger).SetTo(fTeam, fDefaultPort, fToken);
475 return B_OK;
479 status_t
480 Job::Run()
482 status_t status = BJob::Run();
484 // Jobs can be relaunched at any time
485 if (!IsService())
486 SetState(B_JOB_STATE_WAITING_TO_RUN);
488 return status;
492 status_t
493 Job::Execute()
495 status_t status = B_OK;
496 if (!IsRunning() || !IsService())
497 status = Launch();
498 else
499 debug_printf("Ignore launching %s\n", Name());
501 fLaunching = false;
502 return status;
506 void
507 Job::_DeletePorts()
509 PortMap::const_iterator iterator = Ports().begin();
510 for (; iterator != Ports().end(); iterator++) {
511 port_id port = iterator->second.GetInt32("port", -1);
512 if (port >= 0)
513 delete_port(port);
518 status_t
519 Job::_AddRequirement(BJob* dependency)
521 if (dependency == NULL)
522 return B_OK;
524 switch (dependency->State()) {
525 case B_JOB_STATE_WAITING_TO_RUN:
526 case B_JOB_STATE_STARTED:
527 case B_JOB_STATE_IN_PROGRESS:
528 AddDependency(dependency);
529 break;
531 case B_JOB_STATE_SUCCEEDED:
532 // Just queue it without any dependencies
533 break;
535 case B_JOB_STATE_FAILED:
536 case B_JOB_STATE_ABORTED:
537 // TODO: return appropriate error
538 return B_BAD_VALUE;
541 return B_OK;
545 void
546 Job::_AddStringList(std::vector<const char*>& array, const BStringList& list)
548 int32 count = list.CountStrings();
549 for (int32 index = 0; index < count; index++) {
550 array.push_back(list.StringAt(index).String());
555 void
556 Job::_SetLaunchStatus(status_t launchStatus)
558 MutexLocker launchLocker(fLaunchStatusLock);
559 fLaunchStatus = launchStatus != B_NO_INIT ? launchStatus : B_ERROR;
560 launchLocker.Unlock();
562 _SendPendingLaunchDataReplies();
566 status_t
567 Job::_SendLaunchDataReply(BMessage* message)
569 BMessage reply(fTeam < 0 ? fTeam : (uint32)B_OK);
570 if (reply.what == B_OK) {
571 reply.AddInt32("team", fTeam);
573 PortMap::const_iterator iterator = fPortMap.begin();
574 for (; iterator != fPortMap.end(); iterator++) {
575 BString name;
576 if (iterator->second.HasString("name"))
577 name << iterator->second.GetString("name") << "_";
578 name << "port";
580 reply.AddInt32(name.String(),
581 iterator->second.GetInt32("port", -1));
585 message->SendReply(&reply);
586 delete message;
587 return B_OK;
591 void
592 Job::_SendPendingLaunchDataReplies()
594 for (int32 i = 0; i < fPendingLaunchDataReplies.CountItems(); i++)
595 _SendLaunchDataReply(fPendingLaunchDataReplies.ItemAt(i));
597 fPendingLaunchDataReplies.MakeEmpty();
601 /*! Creates the ports for a newly launched job. If the registrar already
602 pre-registered the application, \c fDefaultPort will already be set, and
603 honored when filling the ports message.
605 status_t
606 Job::_CreateAndTransferPorts()
608 // TODO: prefix system ports with "system:"
610 bool defaultPort = false;
612 for (PortMap::iterator iterator = fPortMap.begin();
613 iterator != fPortMap.end(); iterator++) {
614 BString name(Name());
615 const char* suffix = iterator->second.GetString("name");
616 if (suffix != NULL)
617 name << ':' << suffix;
618 else
619 defaultPort = true;
621 const int32 capacity = iterator->second.GetInt32("capacity",
622 B_LOOPER_PORT_DEFAULT_CAPACITY);
624 port_id port = -1;
625 if (suffix != NULL || fDefaultPort < 0) {
626 port = _CreateAndTransferPort(name.String(), capacity);
627 if (port < 0)
628 return port;
630 if (suffix == NULL)
631 fDefaultPort = port;
632 } else if (suffix == NULL)
633 port = fDefaultPort;
635 iterator->second.SetInt32("port", port);
637 if (name == "x-vnd.haiku-registrar:auth") {
638 // Allow the launch_daemon to access the registrar authentication
639 BPrivate::set_registrar_authentication_port(port);
643 if (fCreateDefaultPort && !defaultPort) {
644 BMessage data;
645 data.AddInt32("capacity", B_LOOPER_PORT_DEFAULT_CAPACITY);
647 port_id port = -1;
648 if (fDefaultPort < 0) {
649 port = _CreateAndTransferPort(Name(),
650 B_LOOPER_PORT_DEFAULT_CAPACITY);
651 if (port < 0)
652 return port;
654 fDefaultPort = port;
655 } else
656 port = fDefaultPort;
658 data.SetInt32("port", port);
659 AddPort(data);
662 return B_OK;
666 port_id
667 Job::_CreateAndTransferPort(const char* name, int32 capacity)
669 port_id port = create_port(B_LOOPER_PORT_DEFAULT_CAPACITY, Name());
670 if (port < 0)
671 return port;
673 status_t status = set_port_owner(port, fTeam);
674 if (status != B_OK) {
675 delete_port(port);
676 return status;
679 return port;
683 status_t
684 Job::_Launch(const char* signature, entry_ref* ref, int argCount,
685 const char* const* args, const char** environment)
687 thread_id mainThread = -1;
688 status_t result = BRoster::Private().Launch(signature, ref, NULL, argCount,
689 args, environment, &fTeam, &mainThread, &fDefaultPort, NULL, true);
690 if (result == B_OK) {
691 result = _CreateAndTransferPorts();
693 if (result == B_OK) {
694 resume_thread(mainThread);
696 if (fTeamRegistrator != NULL)
697 fTeamRegistrator->RegisterTeam(this);
698 } else
699 kill_thread(mainThread);
702 _SetLaunchStatus(result);
703 return result;