xref: /haiku/src/servers/launch/Events.cpp (revision 44d78872dff4eeab42314062af38ed1508c056fa)
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 	\return \c true, if there is a demand event, and it has been
779 			triggered by this call. \c false if not.
780 */
781 /*static*/ bool
782 Events::TriggerDemand(Event* event)
783 {
784 	if (event == NULL || event->Triggered())
785 		return false;
786 
787 	if (EventContainer* container = dynamic_cast<EventContainer*>(event)) {
788 		for (int32 index = 0; index < container->Events().CountItems();
789 				index++) {
790 			Event* childEvent = container->Events().ItemAt(index);
791 			if (dynamic_cast<DemandEvent*>(childEvent) != NULL) {
792 				childEvent->Trigger();
793 				break;
794 			}
795 			if (dynamic_cast<EventContainer*>(childEvent) != NULL) {
796 				if (TriggerDemand(childEvent))
797 					break;
798 			}
799 		}
800 	}
801 
802 	return event->Triggered();
803 }
804