xref: /haiku/src/kits/storage/NodeMonitor.cpp (revision 93aeb8c3bc3f13cb1f282e3e749258a23790d947)
1 //----------------------------------------------------------------------
2 //  This software is part of the OpenBeOS distribution and is covered
3 //  by the OpenBeOS license.
4 //---------------------------------------------------------------------
5 
6 #include <AppMisc.h>
7 #include <Looper.h>
8 #include <Messenger.h>
9 #include <NodeMonitor.h>
10 
11 #include <syscalls.h>
12 
13 // TODO: Tests!
14 
15 
16 // watch_node
17 /*!	\brief Subscribes a target to node and/or mount watching, or unsubscribes
18 		   it from node watching.
19 
20 	Depending of \a flags the action performed by this function varies:
21 	- \a flags is \c 0: The target is unsubscribed from watching the node.
22 	  \a node must not be \c NULL in this case.
23 	- \a flags contains \c B_WATCH_MOUNT: The target is subscribed to mount
24 	  watching.
25 	- \a flags contains at least one of \c B_WATCH_NAME, \c B_WATCH_STAT,
26 	  \c B_WATCH_ATTR, or \c B_WATCH_DIRECTORY: The target is subscribed to
27 	  watching the specified aspects of the node. \a node must not be \c NULL
28 	  in this case.
29 
30 	Note, that the latter two cases are not mutual exlusive, i.e. mount and
31 	node watching can be requested with a single call.
32 
33 	\param node node_ref referring to the node to be watched. May be \c NULL,
34 		   if only mount watching is requested.
35 	\param flags Flags indicating the actions to be performed.
36 	\param target Messenger referring to the target. Must be valid.
37 	\return \c B_OK, if everything went fine, another error code otherwise.
38 */
39 status_t
40 watch_node(const node_ref *node, uint32 flags, BMessenger target)
41 {
42 	status_t error = (target.IsValid() ? B_OK : B_BAD_VALUE);
43 	if (error == B_OK) {
44 		BLooper *looper = NULL;
45 		BHandler *handler = target.Target(&looper);
46 		error = watch_node(node, flags, handler, looper);
47 	}
48 	return error;
49 }
50 
51 // watch_node
52 /*!	\brief Subscribes a target to node and/or mount watching, or unsubscribes
53 		   it from node watching.
54 
55 	Depending of \a flags the action performed by this function varies:
56 	- \a flags is \c 0: The target is unsubscribed from watching the node.
57 	  \a node must not be \c NULL in this case.
58 	- \a flags contains \c B_WATCH_MOUNT: The target is subscribed to mount
59 	  watching.
60 	- \a flags contains at least one of \c B_WATCH_NAME, \c B_WATCH_STAT,
61 	  \c B_WATCH_ATTR, or \c B_WATCH_DIRECTORY: The target is subscribed to
62 	  watching the specified aspects of the node. \a node must not be \c NULL
63 	  in this case.
64 
65 	Note, that the latter two cases are not mutual exlusive, i.e. mount and
66 	node watching can be requested with a single call.
67 
68 	\param node node_ref referring to the node to be watched. May be \c NULL,
69 		   if only mount watching is requested.
70 	\param flags Flags indicating the actions to be performed.
71 	\param handler The target handler. May be \c NULL, if \a looper is not
72 		   \c NULL. Then the preferred handler of the looper is targeted.
73 	\param looper The target looper. May be \c NULL, if \a handler is not
74 		   \c NULL. Then the handler's looper is the target looper.
75 	\return \c B_OK, if everything went fine, another error code otherwise.
76 */
77 status_t
78 watch_node(const node_ref *node, uint32 flags, const BHandler *handler,
79 		   const BLooper *looper)
80 {
81 	status_t error = B_OK;
82 	// check looper and handler and get the handler token
83 	int32 handlerToken = -2;
84 	if (handler) {
85 		handlerToken = _get_object_token_(handler);
86 		if (looper) {
87 			if (looper != handler->Looper())
88 				error = B_BAD_VALUE;
89 		} else {
90 			looper = handler->Looper();
91 			if (!looper)
92 				error = B_BAD_VALUE;
93 		}
94 	} else if (!looper)
95 		error = B_BAD_VALUE;
96 	if (error == B_OK) {
97 		port_id port = _get_looper_port_(looper);
98 		if (flags == B_STOP_WATCHING) {
99 			// unsubscribe from node node watching
100 			if (node)
101 				error = _kern_stop_watching(node->device, node->node, flags, port, handlerToken);
102 			else
103 				error = B_BAD_VALUE;
104 		} else {
105 			// subscribe to...
106 			// mount watching
107 			if (flags & B_WATCH_MOUNT) {
108 				error = _kern_start_watching((dev_t)-1, (ino_t)-1, 0, port, handlerToken);
109 				flags &= ~B_WATCH_MOUNT;
110 			}
111 			// node watching
112 			if (error == B_OK && flags)
113 				error = _kern_start_watching(node->device, node->node, flags, port, handlerToken);
114 		}
115 	}
116 	return error;
117 }
118 
119 // stop_watching
120 /*!	\brief Unsubscribes a target from node and mount monitoring.
121 	\param target Messenger referring to the target. Must be valid.
122 	\return \c B_OK, if everything went fine, another error code otherwise.
123 */
124 status_t
125 stop_watching(BMessenger target)
126 {
127 	status_t error = (target.IsValid() ? B_OK : B_BAD_VALUE);
128 	if (error == B_OK) {
129 		BLooper *looper = NULL;
130 		BHandler *handler = target.Target(&looper);
131 		error = stop_watching(handler, looper);
132 	}
133 	return error;
134 }
135 
136 // stop_watching
137 /*!	\brief Unsubscribes a target from node and mount monitoring.
138 	\param handler The target handler. May be \c NULL, if \a looper is not
139 		   \c NULL. Then the preferred handler of the looper is targeted.
140 	\param looper The target looper. May be \c NULL, if \a handler is not
141 		   \c NULL. Then the handler's looper is the target looper.
142 	\return \c B_OK, if everything went fine, another error code otherwise.
143 */
144 status_t
145 stop_watching(const BHandler *handler, const BLooper *looper)
146 {
147 	status_t error = B_OK;
148 	// check looper and handler and get the handler token
149 	int32 handlerToken = -2;
150 	if (handler) {
151 		handlerToken = _get_object_token_(handler);
152 		if (looper) {
153 			if (looper != handler->Looper())
154 				error = B_BAD_VALUE;
155 		} else {
156 			looper = handler->Looper();
157 			if (!looper)
158 				error = B_BAD_VALUE;
159 		}
160 	} else if (!looper)
161 		error = B_BAD_VALUE;
162 	// unsubscribe
163 	if (error == B_OK) {
164 		port_id port = _get_looper_port_(looper);
165 		error = _kern_stop_notifying(port, handlerToken);
166 	}
167 	return error;
168 }
169 
170