xref: /haiku/src/servers/launch/Events.cpp (revision 71452e98334eaac603bf542d159e24788a46bebb)
1 /*
2  * Copyright 2015, 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();
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()
209 {
210 	fTriggered = true;
211 	if (fParent != NULL)
212 		fParent->Trigger();
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()
340 {
341 	Event::Trigger();
342 
343 	if (Parent() == NULL && Owner() != NULL) {
344 		BMessage message(kMsgEventTriggered);
345 		message.AddString("owner", Owner()->Name());
346 		fTarget.SendMessage(&message);
347 	}
348 }
349 
350 
351 BaseJob*
352 EventContainer::Owner() const
353 {
354 	return fOwner;
355 }
356 
357 
358 void
359 EventContainer::SetOwner(BaseJob* owner)
360 {
361 	Event::SetOwner(owner);
362 	fOwner = owner;
363 }
364 
365 
366 void
367 EventContainer::AddEventsToString(BString& string) const
368 {
369 	string += "[";
370 
371 	for (int32 index = 0; index < fEvents.CountItems(); index++) {
372 		if (index != 0)
373 			string += ", ";
374 		string += fEvents.ItemAt(index)->ToString();
375 	}
376 	string += "]";
377 }
378 
379 
380 // #pragma mark - or
381 
382 
383 OrEvent::OrEvent(Event* parent, const BMessenger* target, const BMessage& args)
384 	:
385 	EventContainer(parent, target, args)
386 {
387 }
388 
389 
390 OrEvent::OrEvent(BaseJob* owner, const BMessenger& target)
391 	:
392 	EventContainer(owner, target)
393 {
394 }
395 
396 
397 void
398 OrEvent::ResetTrigger()
399 {
400 	fTriggered = false;
401 
402 	int32 count = fEvents.CountItems();
403 	for (int32 index = 0; index < count; index++) {
404 		Event* event = fEvents.ItemAt(index);
405 		event->ResetTrigger();
406 		fTriggered |= event->Triggered();
407 	}
408 }
409 
410 
411 BString
412 OrEvent::ToString() const
413 {
414 	BString string = "or ";
415 	EventContainer::AddEventsToString(string);
416 	return string;
417 }
418 
419 
420 // #pragma mark - StickyEvent
421 
422 
423 StickyEvent::StickyEvent(Event* parent)
424 	:
425 	Event(parent)
426 {
427 }
428 
429 
430 StickyEvent::~StickyEvent()
431 {
432 }
433 
434 
435 void
436 StickyEvent::ResetSticky()
437 {
438 	Event::ResetTrigger();
439 }
440 
441 
442 void
443 StickyEvent::ResetTrigger()
444 {
445 	// This is a sticky event; we don't reset the trigger here
446 }
447 
448 
449 // #pragma mark - demand
450 
451 
452 DemandEvent::DemandEvent(Event* parent)
453 	:
454 	Event(parent)
455 {
456 }
457 
458 
459 status_t
460 DemandEvent::Register(EventRegistrator& registrator)
461 {
462 	return B_OK;
463 }
464 
465 
466 void
467 DemandEvent::Unregister(EventRegistrator& registrator)
468 {
469 }
470 
471 
472 BString
473 DemandEvent::ToString() const
474 {
475 	return "demand";
476 }
477 
478 
479 // #pragma mark - External event
480 
481 
482 ExternalEvent::ExternalEvent(Event* parent, const char* name,
483 	const BMessage& args)
484 	:
485 	Event(parent),
486 	fName(name),
487 	fFlags(0),
488 	fResolved(false)
489 {
490 	const char* argument;
491 	for (int32 index = 0; args.FindString("args", index, &argument) == B_OK;
492 			index++) {
493 		fArguments.Add(argument);
494 	}
495 }
496 
497 
498 const BString&
499 ExternalEvent::Name() const
500 {
501 	return fName;
502 }
503 
504 
505 bool
506 ExternalEvent::Resolve(uint32 flags)
507 {
508 	if (fResolved)
509 		return false;
510 
511 	fResolved = true;
512 	fFlags = flags;
513 	return true;
514 }
515 
516 
517 void
518 ExternalEvent::ResetSticky()
519 {
520 	if ((fFlags & B_STICKY_EVENT) != 0)
521 		Event::ResetTrigger();
522 }
523 
524 
525 void
526 ExternalEvent::ResetTrigger()
527 {
528 	if ((fFlags & B_STICKY_EVENT) == 0)
529 		Event::ResetTrigger();
530 }
531 
532 
533 status_t
534 ExternalEvent::Register(EventRegistrator& registrator)
535 {
536 	return registrator.RegisterExternalEvent(this, Name().String(), fArguments);
537 }
538 
539 
540 void
541 ExternalEvent::Unregister(EventRegistrator& registrator)
542 {
543 	registrator.UnregisterExternalEvent(this, Name().String());
544 }
545 
546 
547 BString
548 ExternalEvent::ToString() const
549 {
550 	return fName;
551 }
552 
553 
554 // #pragma mark - file_created
555 
556 
557 FileCreatedEvent::FileCreatedEvent(Event* parent, const BMessage& args)
558 	:
559 	Event(parent)
560 {
561 	fPath.SetTo(args.GetString("args", NULL));
562 }
563 
564 
565 status_t
566 FileCreatedEvent::Register(EventRegistrator& registrator)
567 {
568 	// TODO: implement!
569 	return B_ERROR;
570 }
571 
572 
573 void
574 FileCreatedEvent::Unregister(EventRegistrator& registrator)
575 {
576 }
577 
578 
579 BString
580 FileCreatedEvent::ToString() const
581 {
582 	BString string = "file_created ";
583 	string << fPath.Path();
584 	return string;
585 }
586 
587 
588 // #pragma mark -
589 
590 
591 VolumeMountedEvent::VolumeMountedEvent(Event* parent, const BMessage& args)
592 	:
593 	Event(parent)
594 {
595 }
596 
597 
598 status_t
599 VolumeMountedEvent::Register(EventRegistrator& registrator)
600 {
601 	VolumeWatcher::Register(this);
602 	return B_OK;
603 }
604 
605 
606 void
607 VolumeMountedEvent::Unregister(EventRegistrator& registrator)
608 {
609 	VolumeWatcher::Unregister(this);
610 }
611 
612 
613 BString
614 VolumeMountedEvent::ToString() const
615 {
616 	return "volume_mounted";
617 }
618 
619 
620 void
621 VolumeMountedEvent::VolumeMounted(dev_t device)
622 {
623 	Trigger();
624 }
625 
626 
627 void
628 VolumeMountedEvent::VolumeUnmounted(dev_t device)
629 {
630 }
631 
632 
633 // #pragma mark -
634 
635 
636 NetworkAvailableEvent::NetworkAvailableEvent(Event* parent,
637 	const BMessage& args)
638 	:
639 	StickyEvent(parent)
640 {
641 }
642 
643 
644 status_t
645 NetworkAvailableEvent::Register(EventRegistrator& registrator)
646 {
647 	NetworkWatcher::Register(this);
648 	return B_OK;
649 }
650 
651 
652 void
653 NetworkAvailableEvent::Unregister(EventRegistrator& registrator)
654 {
655 	NetworkWatcher::Unregister(this);
656 }
657 
658 
659 BString
660 NetworkAvailableEvent::ToString() const
661 {
662 	return "network_available";
663 }
664 
665 
666 void
667 NetworkAvailableEvent::NetworkAvailabilityChanged(bool available)
668 {
669 	if (available)
670 		Trigger();
671 	else
672 		ResetSticky();
673 }
674 
675 
676 // #pragma mark -
677 
678 
679 /*static*/ Event*
680 Events::FromMessage(const BMessenger& target, const BMessage& message)
681 {
682 	return create_event(NULL, "or", &target, message);
683 }
684 
685 
686 /*static*/ Event*
687 Events::AddOnDemand(const BMessenger& target, Event* event)
688 {
689 	OrEvent* orEvent = dynamic_cast<OrEvent*>(event);
690 	if (orEvent == NULL) {
691 		EventContainer* container = dynamic_cast<EventContainer*>(event);
692 		if (container != NULL)
693 			orEvent = new OrEvent(container->Owner(), container->Target());
694 		else
695 			orEvent = new OrEvent(NULL, target);
696 	}
697 	if (orEvent != event && event != NULL)
698 		orEvent->AddEvent(event);
699 
700 	orEvent->AddEvent(new DemandEvent(orEvent));
701 	return orEvent;
702 }
703 
704 
705 /*static*/ bool
706 Events::ResolveExternalEvent(Event* event, const char* name, uint32 flags)
707 {
708 	if (event == NULL)
709 		return false;
710 
711 	if (EventContainer* container = dynamic_cast<EventContainer*>(event)) {
712 		for (int32 index = 0; index < container->Events().CountItems();
713 				index++) {
714 			Event* event = container->Events().ItemAt(index);
715 			if (ExternalEvent* external = dynamic_cast<ExternalEvent*>(event)) {
716 				if (external->Name() == name && external->Resolve(flags))
717 					return true;
718 			} else if (dynamic_cast<EventContainer*>(event) != NULL) {
719 				if (ResolveExternalEvent(event, name, flags))
720 					return true;
721 			}
722 		}
723 	}
724 	return false;
725 }
726 
727 
728 /*static*/ void
729 Events::TriggerExternalEvent(Event* event, const char* name)
730 {
731 	if (event == NULL)
732 		return;
733 
734 	if (EventContainer* container = dynamic_cast<EventContainer*>(event)) {
735 		for (int32 index = 0; index < container->Events().CountItems();
736 				index++) {
737 			Event* event = container->Events().ItemAt(index);
738 			if (ExternalEvent* external = dynamic_cast<ExternalEvent*>(event)) {
739 				if (external->Name() == name) {
740 					external->Trigger();
741 					return;
742 				}
743 			} else if (dynamic_cast<EventContainer*>(event) != NULL) {
744 				TriggerExternalEvent(event, name);
745 			}
746 		}
747 	}
748 	return;
749 }
750 
751 
752 /*static*/ void
753 Events::ResetStickyExternalEvent(Event* event, const char* name)
754 {
755 	if (event == NULL)
756 		return;
757 
758 	if (EventContainer* container = dynamic_cast<EventContainer*>(event)) {
759 		for (int32 index = 0; index < container->Events().CountItems();
760 				index++) {
761 			Event* event = container->Events().ItemAt(index);
762 			if (ExternalEvent* external = dynamic_cast<ExternalEvent*>(event)) {
763 				if (external->Name() == name) {
764 					external->ResetSticky();
765 					return;
766 				}
767 			} else if (dynamic_cast<EventContainer*>(event) != NULL) {
768 				ResetStickyExternalEvent(event, name);
769 			}
770 		}
771 	}
772 	return;
773 }
774 
775 
776 /*!	This will trigger a demand event, if it exists.
777 
778 	\param testOnly If \c true, the deman will not actually be triggered,
779 			it will only be checked if it could.
780 	\return \c true, if there is a demand event, and it has been
781 			triggered by this call. \c false if not.
782 */
783 /*static*/ bool
784 Events::TriggerDemand(Event* event, bool testOnly)
785 {
786 	if (event == NULL || event->Triggered())
787 		return false;
788 
789 	if (EventContainer* container = dynamic_cast<EventContainer*>(event)) {
790 		for (int32 index = 0; index < container->Events().CountItems();
791 				index++) {
792 			Event* childEvent = container->Events().ItemAt(index);
793 			if (dynamic_cast<DemandEvent*>(childEvent) != NULL) {
794 				if (testOnly)
795 					return true;
796 
797 				childEvent->Trigger();
798 				break;
799 			}
800 			if (dynamic_cast<EventContainer*>(childEvent) != NULL) {
801 				if (TriggerDemand(childEvent, testOnly))
802 					break;
803 			}
804 		}
805 	}
806 
807 	return event->Triggered();
808 }
809