xref: /haiku/src/servers/launch/Events.cpp (revision d0ac609964842f8cdb6d54b3c539c6c15293e172)
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 {
191 }
192 
193 
194 Event::~Event()
195 {
196 }
197 
198 
199 bool
200 Event::Triggered() const
201 {
202 	return fTriggered;
203 }
204 
205 
206 void
207 Event::Trigger()
208 {
209 	fTriggered = true;
210 	if (fParent != NULL)
211 		fParent->Trigger();
212 }
213 
214 
215 void
216 Event::ResetTrigger()
217 {
218 	fTriggered = false;
219 }
220 
221 
222 BaseJob*
223 Event::Owner() const
224 {
225 	if (fParent != NULL)
226 		return fParent->Owner();
227 
228 	return NULL;
229 }
230 
231 
232 void
233 Event::SetOwner(BaseJob* owner)
234 {
235 	if (fParent != NULL)
236 		fParent->SetOwner(owner);
237 }
238 
239 
240 Event*
241 Event::Parent() const
242 {
243 	return fParent;
244 }
245 
246 
247 // #pragma mark -
248 
249 
250 EventContainer::EventContainer(Event* parent, const BMessenger* target,
251 	const BMessage& args)
252 	:
253 	Event(parent),
254 	fEvents(5, true),
255 	fRegistered(false)
256 {
257 	if (target != NULL)
258 		fTarget = *target;
259 
260 	char* name;
261 	type_code type;
262 	int32 count;
263 	for (int32 index = 0; args.GetInfo(B_MESSAGE_TYPE, index, &name, &type,
264 			&count) == B_OK; index++) {
265 		BMessage message;
266 		for (int32 messageIndex = 0; args.FindMessage(name, messageIndex,
267 				&message) == B_OK; messageIndex++) {
268 			AddEvent(create_event(this, name, target, message));
269 		}
270 	}
271 }
272 
273 
274 EventContainer::EventContainer(BaseJob* owner, const BMessenger& target)
275 	:
276 	Event(NULL),
277 	fOwner(owner),
278 	fTarget(target),
279 	fEvents(5, true),
280 	fRegistered(false)
281 {
282 }
283 
284 
285 void
286 EventContainer::AddEvent(Event* event)
287 {
288 	if (event != NULL)
289 		fEvents.AddItem(event);
290 }
291 
292 
293 BObjectList<Event>&
294 EventContainer::Events()
295 {
296 	return fEvents;
297 }
298 
299 
300 const BMessenger&
301 EventContainer::Target() const
302 {
303 	return fTarget;
304 }
305 
306 
307 status_t
308 EventContainer::Register(EventRegistrator& registrator)
309 {
310 	if (fRegistered)
311 		return B_OK;
312 
313 	int32 count = fEvents.CountItems();
314 	for (int32 index = 0; index < count; index++) {
315 		Event* event = fEvents.ItemAt(index);
316 		status_t status = event->Register(registrator);
317 		if (status != B_OK)
318 			return status;
319 	}
320 
321 	fRegistered = true;
322 	return B_OK;
323 }
324 
325 
326 void
327 EventContainer::Unregister(EventRegistrator& registrator)
328 {
329 	int32 count = fEvents.CountItems();
330 	for (int32 index = 0; index < count; index++) {
331 		Event* event = fEvents.ItemAt(index);
332 		event->Unregister(registrator);
333 	}
334 }
335 
336 
337 void
338 EventContainer::Trigger()
339 {
340 	Event::Trigger();
341 
342 	if (Parent() == NULL && Owner() != NULL) {
343 		BMessage message(kMsgEventTriggered);
344 		message.AddString("owner", Owner()->Name());
345 		fTarget.SendMessage(&message);
346 	}
347 }
348 
349 
350 BaseJob*
351 EventContainer::Owner() const
352 {
353 	return fOwner;
354 }
355 
356 
357 void
358 EventContainer::SetOwner(BaseJob* owner)
359 {
360 	Event::SetOwner(owner);
361 	fOwner = owner;
362 }
363 
364 
365 void
366 EventContainer::AddEventsToString(BString& string) const
367 {
368 	string += "[";
369 
370 	for (int32 index = 0; index < fEvents.CountItems(); index++) {
371 		if (index != 0)
372 			string += ", ";
373 		string += fEvents.ItemAt(index)->ToString();
374 	}
375 	string += "]";
376 }
377 
378 
379 // #pragma mark - or
380 
381 
382 OrEvent::OrEvent(Event* parent, const BMessenger* target, const BMessage& args)
383 	:
384 	EventContainer(parent, target, args)
385 {
386 }
387 
388 
389 OrEvent::OrEvent(BaseJob* owner, const BMessenger& target)
390 	:
391 	EventContainer(owner, target)
392 {
393 }
394 
395 
396 void
397 OrEvent::ResetTrigger()
398 {
399 	fTriggered = false;
400 
401 	int32 count = fEvents.CountItems();
402 	for (int32 index = 0; index < count; index++) {
403 		Event* event = fEvents.ItemAt(index);
404 		event->ResetTrigger();
405 		fTriggered |= event->Triggered();
406 	}
407 }
408 
409 
410 BString
411 OrEvent::ToString() const
412 {
413 	BString string = "or ";
414 	EventContainer::AddEventsToString(string);
415 	return string;
416 }
417 
418 
419 // #pragma mark - StickyEvent
420 
421 
422 StickyEvent::StickyEvent(Event* parent)
423 	:
424 	Event(parent)
425 {
426 }
427 
428 
429 StickyEvent::~StickyEvent()
430 {
431 }
432 
433 
434 void
435 StickyEvent::ResetSticky()
436 {
437 	Event::ResetTrigger();
438 }
439 
440 
441 void
442 StickyEvent::ResetTrigger()
443 {
444 	// This is a sticky event; we don't reset the trigger here
445 }
446 
447 
448 // #pragma mark - demand
449 
450 
451 DemandEvent::DemandEvent(Event* parent)
452 	:
453 	Event(parent)
454 {
455 }
456 
457 
458 status_t
459 DemandEvent::Register(EventRegistrator& registrator)
460 {
461 	return B_OK;
462 }
463 
464 
465 void
466 DemandEvent::Unregister(EventRegistrator& registrator)
467 {
468 }
469 
470 
471 BString
472 DemandEvent::ToString() const
473 {
474 	return "event";
475 }
476 
477 
478 // #pragma mark - External event
479 
480 
481 ExternalEvent::ExternalEvent(Event* parent, const char* name,
482 	const BMessage& args)
483 	:
484 	Event(parent),
485 	fName(name),
486 	fFlags(0),
487 	fResolved(false)
488 {
489 	const char* argument;
490 	for (int32 index = 0; args.FindString("args", index, &argument) == B_OK;
491 			index++) {
492 		fArguments.Add(argument);
493 	}
494 }
495 
496 
497 const BString&
498 ExternalEvent::Name() const
499 {
500 	return fName;
501 }
502 
503 
504 bool
505 ExternalEvent::Resolve(uint32 flags)
506 {
507 	if (fResolved)
508 		return false;
509 
510 	fResolved = true;
511 	fFlags = flags;
512 	return true;
513 }
514 
515 
516 void
517 ExternalEvent::ResetSticky()
518 {
519 	if ((fFlags & B_STICKY_EVENT) != 0)
520 		Event::ResetTrigger();
521 }
522 
523 
524 void
525 ExternalEvent::ResetTrigger()
526 {
527 	if ((fFlags & B_STICKY_EVENT) == 0)
528 		Event::ResetTrigger();
529 }
530 
531 
532 status_t
533 ExternalEvent::Register(EventRegistrator& registrator)
534 {
535 	return registrator.RegisterExternalEvent(this, Name().String(), fArguments);
536 }
537 
538 
539 void
540 ExternalEvent::Unregister(EventRegistrator& registrator)
541 {
542 	registrator.UnregisterExternalEvent(this, Name().String());
543 }
544 
545 
546 BString
547 ExternalEvent::ToString() const
548 {
549 	return fName;
550 }
551 
552 
553 // #pragma mark - file_created
554 
555 
556 FileCreatedEvent::FileCreatedEvent(Event* parent, const BMessage& args)
557 	:
558 	Event(parent)
559 {
560 	fPath.SetTo(args.GetString("args", NULL));
561 }
562 
563 
564 status_t
565 FileCreatedEvent::Register(EventRegistrator& registrator)
566 {
567 	// TODO: implement!
568 	return B_ERROR;
569 }
570 
571 
572 void
573 FileCreatedEvent::Unregister(EventRegistrator& registrator)
574 {
575 }
576 
577 
578 BString
579 FileCreatedEvent::ToString() const
580 {
581 	BString string = "file_created ";
582 	string << fPath.Path();
583 	return string;
584 }
585 
586 
587 // #pragma mark -
588 
589 
590 VolumeMountedEvent::VolumeMountedEvent(Event* parent, const BMessage& args)
591 	:
592 	Event(parent)
593 {
594 }
595 
596 
597 status_t
598 VolumeMountedEvent::Register(EventRegistrator& registrator)
599 {
600 	VolumeWatcher::Register(this);
601 	return B_OK;
602 }
603 
604 
605 void
606 VolumeMountedEvent::Unregister(EventRegistrator& registrator)
607 {
608 	VolumeWatcher::Unregister(this);
609 }
610 
611 
612 BString
613 VolumeMountedEvent::ToString() const
614 {
615 	return "volume_mounted";
616 }
617 
618 
619 void
620 VolumeMountedEvent::VolumeMounted(dev_t device)
621 {
622 	Trigger();
623 }
624 
625 
626 void
627 VolumeMountedEvent::VolumeUnmounted(dev_t device)
628 {
629 }
630 
631 
632 // #pragma mark -
633 
634 
635 NetworkAvailableEvent::NetworkAvailableEvent(Event* parent,
636 	const BMessage& args)
637 	:
638 	StickyEvent(parent)
639 {
640 }
641 
642 
643 status_t
644 NetworkAvailableEvent::Register(EventRegistrator& registrator)
645 {
646 	NetworkWatcher::Register(this);
647 	return B_OK;
648 }
649 
650 
651 void
652 NetworkAvailableEvent::Unregister(EventRegistrator& registrator)
653 {
654 	NetworkWatcher::Unregister(this);
655 }
656 
657 
658 BString
659 NetworkAvailableEvent::ToString() const
660 {
661 	return "network_available";
662 }
663 
664 
665 void
666 NetworkAvailableEvent::NetworkAvailabilityChanged(bool available)
667 {
668 	if (available)
669 		Trigger();
670 	else
671 		ResetSticky();
672 }
673 
674 
675 // #pragma mark -
676 
677 
678 /*static*/ Event*
679 Events::FromMessage(const BMessenger& target, const BMessage& message)
680 {
681 	return create_event(NULL, "or", &target, message);
682 }
683 
684 
685 /*static*/ Event*
686 Events::AddOnDemand(const BMessenger& target, Event* event)
687 {
688 	OrEvent* orEvent = dynamic_cast<OrEvent*>(event);
689 	if (orEvent == NULL) {
690 		EventContainer* container = dynamic_cast<EventContainer*>(event);
691 		if (container != NULL)
692 			orEvent = new OrEvent(container->Owner(), container->Target());
693 		else
694 			orEvent = new OrEvent(NULL, target);
695 	}
696 	if (orEvent != event && event != NULL)
697 		orEvent->AddEvent(event);
698 
699 	orEvent->AddEvent(new DemandEvent(orEvent));
700 	return orEvent;
701 }
702 
703 
704 /*static*/ bool
705 Events::ResolveExternalEvent(Event* event, const char* name, uint32 flags)
706 {
707 	if (event == NULL)
708 		return false;
709 
710 	if (EventContainer* container = dynamic_cast<EventContainer*>(event)) {
711 		for (int32 index = 0; index < container->Events().CountItems();
712 				index++) {
713 			Event* event = container->Events().ItemAt(index);
714 			if (ExternalEvent* external = dynamic_cast<ExternalEvent*>(event)) {
715 				if (external->Name() == name && external->Resolve(flags))
716 					return true;
717 			} else if (dynamic_cast<EventContainer*>(event) != NULL) {
718 				if (ResolveExternalEvent(event, name, flags))
719 					return true;
720 			}
721 		}
722 	}
723 	return false;
724 }
725 
726 
727 /*static*/ void
728 Events::TriggerExternalEvent(Event* event, const char* name)
729 {
730 	if (event == NULL)
731 		return;
732 
733 	if (EventContainer* container = dynamic_cast<EventContainer*>(event)) {
734 		for (int32 index = 0; index < container->Events().CountItems();
735 				index++) {
736 			Event* event = container->Events().ItemAt(index);
737 			if (ExternalEvent* external = dynamic_cast<ExternalEvent*>(event)) {
738 				if (external->Name() == name) {
739 					external->Trigger();
740 					return;
741 				}
742 			} else if (dynamic_cast<EventContainer*>(event) != NULL) {
743 				TriggerExternalEvent(event, name);
744 			}
745 		}
746 	}
747 	return;
748 }
749 
750 
751 /*static*/ void
752 Events::ResetStickyExternalEvent(Event* event, const char* name)
753 {
754 	if (event == NULL)
755 		return;
756 
757 	if (EventContainer* container = dynamic_cast<EventContainer*>(event)) {
758 		for (int32 index = 0; index < container->Events().CountItems();
759 				index++) {
760 			Event* event = container->Events().ItemAt(index);
761 			if (ExternalEvent* external = dynamic_cast<ExternalEvent*>(event)) {
762 				if (external->Name() == name) {
763 					external->ResetSticky();
764 					return;
765 				}
766 			} else if (dynamic_cast<EventContainer*>(event) != NULL) {
767 				ResetStickyExternalEvent(event, name);
768 			}
769 		}
770 	}
771 	return;
772 }
773 
774 
775 /*!	This will trigger a demand event, if it exists.
776 
777 	\return \c true, if there is a demand event, and it has been
778 			triggered by this call. \c false if not.
779 */
780 /*static*/ bool
781 Events::TriggerDemand(Event* event)
782 {
783 	if (event == NULL || event->Triggered())
784 		return false;
785 
786 	if (EventContainer* container = dynamic_cast<EventContainer*>(event)) {
787 		for (int32 index = 0; index < container->Events().CountItems();
788 				index++) {
789 			Event* childEvent = container->Events().ItemAt(index);
790 			if (dynamic_cast<DemandEvent*>(childEvent) != NULL) {
791 				childEvent->Trigger();
792 				break;
793 			}
794 			if (dynamic_cast<EventContainer*>(childEvent) != NULL) {
795 				if (TriggerDemand(childEvent))
796 					break;
797 			}
798 		}
799 	}
800 
801 	return event->Triggered();
802 }
803