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