xref: /haiku/src/servers/launch/Events.cpp (revision c237c4ce593ee823d9867fd997e51e4c447f5623)
1 /*
2  * Copyright 2015-2018, Axel Dörfler, axeld@pinc-software.de.
3  * Distributed under the terms of the MIT License.
4  */
5 
6 
7 #include "Events.h"
8 
9 #include <stdio.h>
10 
11 #include <Entry.h>
12 #include <LaunchRoster.h>
13 #include <Message.h>
14 #include <ObjectList.h>
15 #include <Path.h>
16 #include <StringList.h>
17 
18 #include "BaseJob.h"
19 #include "LaunchDaemon.h"
20 #include "NetworkWatcher.h"
21 #include "Utility.h"
22 #include "VolumeWatcher.h"
23 
24 
25 class EventContainer : public Event {
26 protected:
27 								EventContainer(Event* parent,
28 									const BMessenger* target,
29 									const BMessage& args);
30 								EventContainer(BaseJob* owner,
31 									const BMessenger& target);
32 
33 public:
34 			void				AddEvent(Event* event);
35 			BObjectList<Event>&	Events();
36 
37 			const BMessenger&	Target() const;
38 
39 	virtual	status_t			Register(EventRegistrator& registrator);
40 	virtual	void				Unregister(EventRegistrator& registrator);
41 
42 	virtual	void				Trigger(Event* origin);
43 
44 	virtual	BaseJob*			Owner() const;
45 	virtual	void				SetOwner(BaseJob* owner);
46 
47 protected:
48 			void				AddEventsToString(BString& string) const;
49 
50 protected:
51 			BaseJob*			fOwner;
52 			BMessenger			fTarget;
53 			BObjectList<Event>	fEvents;
54 			bool				fRegistered;
55 };
56 
57 
58 class OrEvent : public EventContainer {
59 public:
60 								OrEvent(Event* parent, const BMessenger* target,
61 									const BMessage& args);
62 								OrEvent(BaseJob* owner,
63 									const BMessenger& target);
64 
65 	virtual	void				ResetTrigger();
66 
67 	virtual	BString				ToString() const;
68 };
69 
70 
71 class StickyEvent : public Event {
72 public:
73 								StickyEvent(Event* parent);
74 	virtual						~StickyEvent();
75 
76 	virtual	void				ResetSticky();
77 	virtual	void				ResetTrigger();
78 };
79 
80 
81 class DemandEvent : public Event {
82 public:
83 								DemandEvent(Event* parent);
84 
85 	virtual	status_t			Register(EventRegistrator& registrator);
86 	virtual	void				Unregister(EventRegistrator& registrator);
87 
88 	virtual	BString				ToString() const;
89 };
90 
91 
92 class ExternalEvent : public Event {
93 public:
94 								ExternalEvent(Event* parent, const char* name,
95 									const BMessage& args);
96 
97 			const BString&		Name() const;
98 			bool				Resolve(uint32 flags);
99 
100 			void				ResetSticky();
101 	virtual	void				ResetTrigger();
102 
103 	virtual	status_t			Register(EventRegistrator& registrator);
104 	virtual	void				Unregister(EventRegistrator& registrator);
105 
106 	virtual	BString				ToString() const;
107 
108 private:
109 			BString				fName;
110 			BStringList			fArguments;
111 			uint32				fFlags;
112 			bool				fResolved;
113 };
114 
115 
116 class FileCreatedEvent : public Event {
117 public:
118 								FileCreatedEvent(Event* parent,
119 									const BMessage& args);
120 
121 	virtual	status_t			Register(EventRegistrator& registrator);
122 	virtual	void				Unregister(EventRegistrator& registrator);
123 
124 	virtual	BString				ToString() const;
125 
126 private:
127 			BPath				fPath;
128 };
129 
130 
131 class VolumeMountedEvent : public Event, public VolumeListener {
132 public:
133 								VolumeMountedEvent(Event* parent,
134 									const BMessage& args);
135 
136 	virtual	status_t			Register(EventRegistrator& registrator);
137 	virtual	void				Unregister(EventRegistrator& registrator);
138 
139 	virtual	BString				ToString() const;
140 
141 	virtual	void				VolumeMounted(dev_t device);
142 	virtual	void				VolumeUnmounted(dev_t device);
143 };
144 
145 
146 class NetworkAvailableEvent : public StickyEvent, public NetworkListener {
147 public:
148 								NetworkAvailableEvent(Event* parent,
149 									const BMessage& args);
150 
151 	virtual	status_t			Register(EventRegistrator& registrator);
152 	virtual	void				Unregister(EventRegistrator& registrator);
153 
154 	virtual	BString				ToString() const;
155 
156 	virtual	void				NetworkAvailabilityChanged(bool available);
157 };
158 
159 
160 static Event*
161 create_event(Event* parent, const char* name, const BMessenger* target,
162 	const BMessage& args)
163 {
164 	if (strcmp(name, "or") == 0) {
165 		if (args.IsEmpty())
166 			return NULL;
167 
168 		return new OrEvent(parent, target, args);
169 	}
170 
171 	if (strcmp(name, "demand") == 0)
172 		return new DemandEvent(parent);
173 	if (strcmp(name, "file_created") == 0)
174 		return new FileCreatedEvent(parent, args);
175 	if (strcmp(name, "volume_mounted") == 0)
176 		return new VolumeMountedEvent(parent, args);
177 	if (strcmp(name, "network_available") == 0)
178 		return new NetworkAvailableEvent(parent, args);
179 
180 	return new ExternalEvent(parent, name, args);
181 }
182 
183 
184 // #pragma mark -
185 
186 
187 Event::Event(Event* parent)
188 	:
189 	fParent(parent),
190 	fTriggered(false)
191 {
192 }
193 
194 
195 Event::~Event()
196 {
197 }
198 
199 
200 bool
201 Event::Triggered() const
202 {
203 	return fTriggered;
204 }
205 
206 
207 void
208 Event::Trigger(Event* origin)
209 {
210 	fTriggered = true;
211 	if (fParent != NULL)
212 		fParent->Trigger(origin);
213 }
214 
215 
216 void
217 Event::ResetTrigger()
218 {
219 	fTriggered = false;
220 }
221 
222 
223 BaseJob*
224 Event::Owner() const
225 {
226 	if (fParent != NULL)
227 		return fParent->Owner();
228 
229 	return NULL;
230 }
231 
232 
233 void
234 Event::SetOwner(BaseJob* owner)
235 {
236 	if (fParent != NULL)
237 		fParent->SetOwner(owner);
238 }
239 
240 
241 Event*
242 Event::Parent() const
243 {
244 	return fParent;
245 }
246 
247 
248 // #pragma mark -
249 
250 
251 EventContainer::EventContainer(Event* parent, const BMessenger* target,
252 	const BMessage& args)
253 	:
254 	Event(parent),
255 	fEvents(5, true),
256 	fRegistered(false)
257 {
258 	if (target != NULL)
259 		fTarget = *target;
260 
261 	char* name;
262 	type_code type;
263 	int32 count;
264 	for (int32 index = 0; args.GetInfo(B_MESSAGE_TYPE, index, &name, &type,
265 			&count) == B_OK; index++) {
266 		BMessage message;
267 		for (int32 messageIndex = 0; args.FindMessage(name, messageIndex,
268 				&message) == B_OK; messageIndex++) {
269 			AddEvent(create_event(this, name, target, message));
270 		}
271 	}
272 }
273 
274 
275 EventContainer::EventContainer(BaseJob* owner, const BMessenger& target)
276 	:
277 	Event(NULL),
278 	fOwner(owner),
279 	fTarget(target),
280 	fEvents(5, true),
281 	fRegistered(false)
282 {
283 }
284 
285 
286 void
287 EventContainer::AddEvent(Event* event)
288 {
289 	if (event != NULL)
290 		fEvents.AddItem(event);
291 }
292 
293 
294 BObjectList<Event>&
295 EventContainer::Events()
296 {
297 	return fEvents;
298 }
299 
300 
301 const BMessenger&
302 EventContainer::Target() const
303 {
304 	return fTarget;
305 }
306 
307 
308 status_t
309 EventContainer::Register(EventRegistrator& registrator)
310 {
311 	if (fRegistered)
312 		return B_OK;
313 
314 	int32 count = fEvents.CountItems();
315 	for (int32 index = 0; index < count; index++) {
316 		Event* event = fEvents.ItemAt(index);
317 		status_t status = event->Register(registrator);
318 		if (status != B_OK)
319 			return status;
320 	}
321 
322 	fRegistered = true;
323 	return B_OK;
324 }
325 
326 
327 void
328 EventContainer::Unregister(EventRegistrator& registrator)
329 {
330 	int32 count = fEvents.CountItems();
331 	for (int32 index = 0; index < count; index++) {
332 		Event* event = fEvents.ItemAt(index);
333 		event->Unregister(registrator);
334 	}
335 }
336 
337 
338 void
339 EventContainer::Trigger(Event* origin)
340 {
341 	Event::Trigger(origin);
342 
343 	if (Parent() == NULL && Owner() != NULL) {
344 		BMessage message(kMsgEventTriggered);
345 		message.AddPointer("event", origin);
346 		message.AddString("owner", Owner()->Name());
347 		fTarget.SendMessage(&message);
348 	}
349 }
350 
351 
352 BaseJob*
353 EventContainer::Owner() const
354 {
355 	return fOwner;
356 }
357 
358 
359 void
360 EventContainer::SetOwner(BaseJob* owner)
361 {
362 	Event::SetOwner(owner);
363 	fOwner = owner;
364 }
365 
366 
367 void
368 EventContainer::AddEventsToString(BString& string) const
369 {
370 	string += "[";
371 
372 	for (int32 index = 0; index < fEvents.CountItems(); index++) {
373 		if (index != 0)
374 			string += ", ";
375 		string += fEvents.ItemAt(index)->ToString();
376 	}
377 	string += "]";
378 }
379 
380 
381 // #pragma mark - or
382 
383 
384 OrEvent::OrEvent(Event* parent, const BMessenger* target, const BMessage& args)
385 	:
386 	EventContainer(parent, target, args)
387 {
388 }
389 
390 
391 OrEvent::OrEvent(BaseJob* owner, const BMessenger& target)
392 	:
393 	EventContainer(owner, target)
394 {
395 }
396 
397 
398 void
399 OrEvent::ResetTrigger()
400 {
401 	fTriggered = false;
402 
403 	int32 count = fEvents.CountItems();
404 	for (int32 index = 0; index < count; index++) {
405 		Event* event = fEvents.ItemAt(index);
406 		event->ResetTrigger();
407 		fTriggered |= event->Triggered();
408 	}
409 }
410 
411 
412 BString
413 OrEvent::ToString() const
414 {
415 	BString string = "or ";
416 	EventContainer::AddEventsToString(string);
417 	return string;
418 }
419 
420 
421 // #pragma mark - StickyEvent
422 
423 
424 StickyEvent::StickyEvent(Event* parent)
425 	:
426 	Event(parent)
427 {
428 }
429 
430 
431 StickyEvent::~StickyEvent()
432 {
433 }
434 
435 
436 void
437 StickyEvent::ResetSticky()
438 {
439 	Event::ResetTrigger();
440 }
441 
442 
443 void
444 StickyEvent::ResetTrigger()
445 {
446 	// This is a sticky event; we don't reset the trigger here
447 }
448 
449 
450 // #pragma mark - demand
451 
452 
453 DemandEvent::DemandEvent(Event* parent)
454 	:
455 	Event(parent)
456 {
457 }
458 
459 
460 status_t
461 DemandEvent::Register(EventRegistrator& registrator)
462 {
463 	return B_OK;
464 }
465 
466 
467 void
468 DemandEvent::Unregister(EventRegistrator& registrator)
469 {
470 }
471 
472 
473 BString
474 DemandEvent::ToString() const
475 {
476 	return "demand";
477 }
478 
479 
480 // #pragma mark - External event
481 
482 
483 ExternalEvent::ExternalEvent(Event* parent, const char* name,
484 	const BMessage& args)
485 	:
486 	Event(parent),
487 	fName(name),
488 	fFlags(0),
489 	fResolved(false)
490 {
491 	const char* argument;
492 	for (int32 index = 0; args.FindString("args", index, &argument) == B_OK;
493 			index++) {
494 		fArguments.Add(argument);
495 	}
496 }
497 
498 
499 const BString&
500 ExternalEvent::Name() const
501 {
502 	return fName;
503 }
504 
505 
506 bool
507 ExternalEvent::Resolve(uint32 flags)
508 {
509 	if (fResolved)
510 		return false;
511 
512 	fResolved = true;
513 	fFlags = flags;
514 	return true;
515 }
516 
517 
518 void
519 ExternalEvent::ResetSticky()
520 {
521 	if ((fFlags & B_STICKY_EVENT) != 0)
522 		Event::ResetTrigger();
523 }
524 
525 
526 void
527 ExternalEvent::ResetTrigger()
528 {
529 	if ((fFlags & B_STICKY_EVENT) == 0)
530 		Event::ResetTrigger();
531 }
532 
533 
534 status_t
535 ExternalEvent::Register(EventRegistrator& registrator)
536 {
537 	return registrator.RegisterExternalEvent(this, Name().String(), fArguments);
538 }
539 
540 
541 void
542 ExternalEvent::Unregister(EventRegistrator& registrator)
543 {
544 	registrator.UnregisterExternalEvent(this, Name().String());
545 }
546 
547 
548 BString
549 ExternalEvent::ToString() const
550 {
551 	return fName;
552 }
553 
554 
555 // #pragma mark - file_created
556 
557 
558 FileCreatedEvent::FileCreatedEvent(Event* parent, const BMessage& args)
559 	:
560 	Event(parent)
561 {
562 	fPath.SetTo(args.GetString("args", NULL));
563 }
564 
565 
566 status_t
567 FileCreatedEvent::Register(EventRegistrator& registrator)
568 {
569 	// TODO: implement!
570 	return B_ERROR;
571 }
572 
573 
574 void
575 FileCreatedEvent::Unregister(EventRegistrator& registrator)
576 {
577 }
578 
579 
580 BString
581 FileCreatedEvent::ToString() const
582 {
583 	BString string = "file_created ";
584 	string << fPath.Path();
585 	return string;
586 }
587 
588 
589 // #pragma mark -
590 
591 
592 VolumeMountedEvent::VolumeMountedEvent(Event* parent, const BMessage& args)
593 	:
594 	Event(parent)
595 {
596 }
597 
598 
599 status_t
600 VolumeMountedEvent::Register(EventRegistrator& registrator)
601 {
602 	VolumeWatcher::Register(this);
603 	return B_OK;
604 }
605 
606 
607 void
608 VolumeMountedEvent::Unregister(EventRegistrator& registrator)
609 {
610 	VolumeWatcher::Unregister(this);
611 }
612 
613 
614 BString
615 VolumeMountedEvent::ToString() const
616 {
617 	return "volume_mounted";
618 }
619 
620 
621 void
622 VolumeMountedEvent::VolumeMounted(dev_t device)
623 {
624 	Trigger(this);
625 }
626 
627 
628 void
629 VolumeMountedEvent::VolumeUnmounted(dev_t device)
630 {
631 }
632 
633 
634 // #pragma mark -
635 
636 
637 NetworkAvailableEvent::NetworkAvailableEvent(Event* parent,
638 	const BMessage& args)
639 	:
640 	StickyEvent(parent)
641 {
642 }
643 
644 
645 status_t
646 NetworkAvailableEvent::Register(EventRegistrator& registrator)
647 {
648 	NetworkWatcher::Register(this);
649 	return B_OK;
650 }
651 
652 
653 void
654 NetworkAvailableEvent::Unregister(EventRegistrator& registrator)
655 {
656 	NetworkWatcher::Unregister(this);
657 }
658 
659 
660 BString
661 NetworkAvailableEvent::ToString() const
662 {
663 	return "network_available";
664 }
665 
666 
667 void
668 NetworkAvailableEvent::NetworkAvailabilityChanged(bool available)
669 {
670 	if (available)
671 		Trigger(this);
672 	else
673 		ResetSticky();
674 }
675 
676 
677 // #pragma mark -
678 
679 
680 /*static*/ Event*
681 Events::FromMessage(const BMessenger& target, const BMessage& message)
682 {
683 	return create_event(NULL, "or", &target, message);
684 }
685 
686 
687 /*static*/ Event*
688 Events::AddOnDemand(const BMessenger& target, Event* event)
689 {
690 	OrEvent* orEvent = dynamic_cast<OrEvent*>(event);
691 	if (orEvent == NULL) {
692 		EventContainer* container = dynamic_cast<EventContainer*>(event);
693 		if (container != NULL)
694 			orEvent = new OrEvent(container->Owner(), container->Target());
695 		else
696 			orEvent = new OrEvent(NULL, target);
697 	}
698 	if (orEvent != event && event != NULL)
699 		orEvent->AddEvent(event);
700 
701 	orEvent->AddEvent(new DemandEvent(orEvent));
702 	return orEvent;
703 }
704 
705 
706 /*static*/ Event*
707 Events::ResolveExternalEvent(Event* event, const char* name, uint32 flags)
708 {
709 	if (event == NULL)
710 		return NULL;
711 
712 	if (EventContainer* container = dynamic_cast<EventContainer*>(event)) {
713 		for (int32 index = 0; index < container->Events().CountItems();
714 				index++) {
715 			Event* event = ResolveExternalEvent(container->Events().ItemAt(index), name, flags);
716 			if (event != NULL)
717 				return event;
718 		}
719 	} else if (ExternalEvent* external = dynamic_cast<ExternalEvent*>(event)) {
720 		if (external->Name() == name && external->Resolve(flags))
721 			return external;
722 	}
723 
724 	return NULL;
725 }
726 
727 
728 /*static*/ void
729 Events::TriggerExternalEvent(Event* event)
730 {
731 	if (event == NULL)
732 		return;
733 
734 	ExternalEvent* external = dynamic_cast<ExternalEvent*>(event);
735 	if (external == NULL)
736 		return;
737 
738 	external->Trigger(external);
739 }
740 
741 
742 /*static*/ void
743 Events::ResetStickyExternalEvent(Event* event)
744 {
745 	if (event == NULL)
746 		return;
747 
748 	ExternalEvent* external = dynamic_cast<ExternalEvent*>(event);
749 	if (external == NULL)
750 		return;
751 
752 	external->ResetSticky();
753 }
754 
755 
756 /*!	This will trigger a demand event, if it exists.
757 
758 	\param testOnly If \c true, the deman will not actually be triggered,
759 			it will only be checked if it could.
760 	\return \c true, if there is a demand event, and it has been
761 			triggered by this call. \c false if not.
762 */
763 /*static*/ bool
764 Events::TriggerDemand(Event* event, bool testOnly)
765 {
766 	if (event == NULL || event->Triggered())
767 		return false;
768 
769 	if (EventContainer* container = dynamic_cast<EventContainer*>(event)) {
770 		for (int32 index = 0; index < container->Events().CountItems();
771 				index++) {
772 			Event* childEvent = container->Events().ItemAt(index);
773 			if (dynamic_cast<DemandEvent*>(childEvent) != NULL) {
774 				if (testOnly)
775 					return true;
776 
777 				childEvent->Trigger(childEvent);
778 				break;
779 			}
780 			if (dynamic_cast<EventContainer*>(childEvent) != NULL) {
781 				if (TriggerDemand(childEvent, testOnly))
782 					break;
783 			}
784 		}
785 	}
786 
787 	return event->Triggered();
788 }
789