1// NodeMonitor.cpp
2
3#include <new>
4
5#include <errno.h>
6#include <sys/resource.h>
7
8#include <AutoLocker.h>
9#include <Message.h>
10#include <Node.h>
11#include <NodeMonitor.h>
12
13#include "DebugSupport.h"
14#include "NodeMonitor.h"
15#include "NodeMonitoringEvent.h"
16
17// node monitor constants
18static const int32 kDefaultNodeMonitorLimit = 4096;
19static const int32 kNodeMonitorLimitIncrement = 512;
20
21// constructor
22NodeMonitor::NodeMonitor(NodeMonitorListener* listener)
23	: BLooper("node monitor", B_DISPLAY_PRIORITY, 1000),
24	  fListener(listener),
25	  fCurrentNodeMonitorLimit(kDefaultNodeMonitorLimit)
26{
27	// set the initial limit -- just to be sure
28	struct rlimit rl;
29	rl.rlim_cur = fCurrentNodeMonitorLimit;
30	rl.rlim_max = RLIM_SAVED_MAX;
31	setrlimit(RLIMIT_NOVMON, &rl);
32
33	// start volume watching
34	watch_node(NULL, B_WATCH_MOUNT, this);
35}
36
37// destructor
38NodeMonitor::~NodeMonitor()
39{
40	// stop volume watching
41	stop_watching(this);
42}
43
44// MessageReceived
45void
46NodeMonitor::MessageReceived(BMessage* message)
47{
48	switch (message->what) {
49		case B_NODE_MONITOR:
50		{
51			NodeMonitoringEvent* event = NULL;
52			int32 opcode;
53			if (message->FindInt32("opcode", &opcode) == B_OK) {
54				switch (opcode) {
55					case B_ENTRY_CREATED:
56						event = new(std::nothrow) EntryCreatedEvent;
57						break;
58					case B_ENTRY_REMOVED:
59						event = new(std::nothrow) EntryRemovedEvent;
60						break;
61					case B_ENTRY_MOVED:
62						event = new(std::nothrow) EntryMovedEvent;
63						break;
64					case B_STAT_CHANGED:
65						event = new(std::nothrow) StatChangedEvent;
66						break;
67					case B_ATTR_CHANGED:
68						event = new(std::nothrow) AttributeChangedEvent;
69						break;
70					case B_DEVICE_MOUNTED:
71						event = new(std::nothrow) VolumeMountedEvent;
72						break;
73					case B_DEVICE_UNMOUNTED:
74						event = new(std::nothrow) VolumeUnmountedEvent;
75						break;
76				}
77			}
78			if (event) {
79				if (event->Init(message) == B_OK)
80					fListener->ProcessNodeMonitoringEvent(event);
81				else
82					delete event;
83			}
84			break;
85		}
86		default:
87			BLooper::MessageReceived(message);
88	}
89}
90
91// StartWatching
92status_t
93NodeMonitor::StartWatching(const node_ref& ref)
94{
95	uint32 flags = B_WATCH_ALL;
96	status_t error = watch_node(&ref, flags, this);
97	// If starting to watch the node fail, we allocate more node
98	// monitoring slots and try again.
99	if (error != B_OK) {
100		error = _IncreaseLimit();
101		if (error == B_OK)
102			error = watch_node(&ref, flags, this);
103	}
104	if (error == B_OK) {
105		PRINT("NodeMonitor: started watching node: "
106			"(%" B_PRIdDEV ", %" B_PRIdINO ")\n", ref.device, ref.node);
107	}
108	return error;
109}
110
111// StopWatching
112status_t
113NodeMonitor::StopWatching(const node_ref& ref)
114{
115	PRINT("NodeMonitor: stopped watching node: "
116		"(%" B_PRIdDEV ", %" B_PRIdINO ")\n", ref.device, ref.node);
117	return watch_node(&ref, B_STOP_WATCHING, this);
118}
119
120// _IncreaseLimit
121status_t
122NodeMonitor::_IncreaseLimit()
123{
124	AutoLocker<BLooper> _(this);
125
126	int32 newLimit = fCurrentNodeMonitorLimit + kNodeMonitorLimitIncrement;
127	struct rlimit rl;
128	rl.rlim_cur = newLimit;
129	rl.rlim_max = RLIM_SAVED_MAX;
130	if (setrlimit(RLIMIT_NOVMON, &rl) < 0)
131		return errno;
132
133	fCurrentNodeMonitorLimit = newLimit;
134
135	return B_OK;
136}
137
138
139// #pragma mark -
140
141// constructor
142NodeMonitorListener::NodeMonitorListener()
143{
144}
145
146// destructor
147NodeMonitorListener::~NodeMonitorListener()
148{
149}
150