1 /* Gamin
2 * Copyright (C) 2003 James Willcox, Corey Bowers
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
13 *
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free
16 * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17 */
18
19 #include "server_config.h"
20
21 #include <string.h>
22 #include <glib.h>
23 #include "gam_listener.h"
24 #include "gam_subscription.h"
25 #include "gam_server.h"
26 #include "gam_error.h"
27 #include "gam_pidname.h"
28 #ifdef ENABLE_INOTIFY
29 #include "gam_inotify.h"
30 #endif
31
32 //#define GAM_LISTENER_VERBOSE
33 /* private struct representing a single listener */
34 struct _GamListener {
35 void *service;
36 int pid;
37 char *pidname;
38 GList *subs;
39 };
40
41 /**
42 * @defgroup GamListener GamListener
43 * @ingroup Daemon
44 * @brief GamListener API.
45 *
46 * @{
47 */
48
49 /**
50 * gam_listener_new:
51 *
52 * @service: service structure used to communicate with #GamListener
53 * @pid: the unique ID for this listener
54 *
55 * Creates a #GamListener
56 *
57 * Returns a new #GamListener on success, NULL otherwise
58 */
59 GamListener *
gam_listener_new(void * service,int pid)60 gam_listener_new(void *service, int pid)
61 {
62 GamListener *listener;
63
64 g_assert(service);
65 g_assert(pid != 0);
66
67 listener = g_new0(GamListener, 1);
68 listener->service = service;
69 listener->pid = pid;
70 listener->pidname = gam_get_pidname (pid);
71 listener->subs = NULL;
72
73 #ifdef GAM_LISTENER_VERBOSE
74 GAM_DEBUG(DEBUG_INFO, "Created listener for %d\n", pid);
75 #endif
76
77 return listener;
78 }
79
80 /**
81 * gam_listener_free_subscription:
82 *
83 * @listener: the #GamListener
84 * @sub: the subscription to remove
85 *
86 * Frees a listener's subscription
87 */
88 static void
gam_listener_free_subscription(GamListener * listener,GamSubscription * sub)89 gam_listener_free_subscription(GamListener *listener,
90 GamSubscription *sub)
91 {
92 char *path;
93
94 g_assert(listener);
95 g_assert(sub);
96 g_assert(g_list_find(listener->subs, sub));
97 path = g_strdup(gam_subscription_get_path(sub));
98
99 gam_remove_subscription(sub);
100 #ifdef ENABLE_INOTIFY
101 if (gam_inotify_is_running() && (!gam_exclude_check(path))) {
102 gam_fs_mon_type type;
103
104 type = gam_fs_get_mon_type (path);
105 if (type != GFS_MT_POLL)
106 gam_subscription_free(sub);
107 }
108 #endif
109 g_free(path);
110 }
111
112 /**
113 * gam_listener_free:
114 *
115 * @listener: the #GamListener to free
116 *
117 * Frees a #GamListener returned by #gam_listener_new
118 */
119 void
gam_listener_free(GamListener * listener)120 gam_listener_free(GamListener *listener)
121 {
122 GList *cur;
123
124 g_assert(listener);
125
126 while ((cur = g_list_first(listener->subs)) != NULL) {
127 GamSubscription * sub = cur->data;
128 gam_listener_free_subscription(listener, sub);
129 listener->subs = g_list_delete_link(listener->subs, cur);
130 }
131 g_free(listener->pidname);
132 g_free(listener);
133 }
134
135 /**
136 * gam_listener_get_service:
137 *
138 * @listener: the #GamListener
139 *
140 * Gets the service associated with a #GamListener
141 *
142 * Returns the service associated with the #GamListener. The result
143 * is owned by the #GamListener and must not be freed by the caller.
144 */
145 void *
gam_listener_get_service(GamListener * listener)146 gam_listener_get_service(GamListener *listener)
147 {
148 return listener->service;
149 }
150
151 /**
152 * gam_listener_get_pid:
153 *
154 * @listener: the #GamListener
155 *
156 * Gets the unique process ID associated with a #GamListener
157 *
158 * Returns the pid associated with the #GamListener.
159 */
160 int
gam_listener_get_pid(GamListener * listener)161 gam_listener_get_pid(GamListener *listener)
162 {
163 return listener->pid;
164 }
165
166 /**
167 * gam_listener_get_pidname:
168 *
169 * @listener: the #GamListener
170 *
171 * Gets the process name associated with a #GamListener
172 *
173 * Returns the process name associated with the #GamListener.
174 */
175 const char *
gam_listener_get_pidname(GamListener * listener)176 gam_listener_get_pidname(GamListener *listener)
177 {
178 return listener->pidname;
179 }
180
181 /**
182 * gam_listener_get_subscription:
183 *
184 * @listener: the #GamListener
185 * @path: a path to a file or directory
186 *
187 * Gets the subscription to a path
188 *
189 * Returns the #GamSubscription to path, or NULL if there is none
190 */
191 GamSubscription *
gam_listener_get_subscription(GamListener * listener,const char * path)192 gam_listener_get_subscription(GamListener *listener, const char *path)
193 {
194 GList *l;
195
196 for (l = listener->subs; l; l = l->next) {
197 GamSubscription *sub = l->data;
198
199 if (strcmp(gam_subscription_get_path(sub), path) == 0)
200 return sub;
201 }
202
203 return NULL;
204 }
205
206 /**
207 * gam_listener_get_subscription_by_reqno:
208 *
209 * @listener: the #GamListener
210 * @reqno: a subscription request number
211 *
212 * Gets the subscription represented by the given reqno
213 *
214 * Returns a #GamSubscription, or NULL if it wasn't found
215 */
216 GamSubscription *
gam_listener_get_subscription_by_reqno(GamListener * listener,int reqno)217 gam_listener_get_subscription_by_reqno(GamListener * listener, int reqno)
218 {
219 GList *l;
220
221 for (l = listener->subs; l; l = l->next) {
222 GamSubscription *sub = l->data;
223
224 if (gam_subscription_get_reqno(sub) == reqno)
225 return sub;
226 }
227
228 return NULL;
229 }
230
231 /**
232 * gam_listener_is_subscribed:
233 *
234 * @listener: the #GamListener
235 * @path: the path to the file or directory
236 *
237 * Returns whether a #GamListener is subscribed to a file or directory
238 *
239 * Returns TRUE if listener has a subscription to the path, FALSE
240 * otherwise.
241 */
242 gboolean
gam_listener_is_subscribed(GamListener * listener,const char * path)243 gam_listener_is_subscribed(GamListener *listener, const char *path)
244 {
245 return gam_listener_get_subscription(listener, path) != NULL;
246 }
247
248 /**
249 * gam_listener_add_subscription:
250 *
251 * @listener: the #GamListener
252 * @sub: the #GamSubscription to add
253 *
254 * Adds a subscription to the #GamListener
255 */
256 void
gam_listener_add_subscription(GamListener * listener,GamSubscription * sub)257 gam_listener_add_subscription(GamListener *listener,
258 GamSubscription *sub)
259 {
260 g_assert(listener);
261 g_assert(sub);
262 g_assert(!g_list_find(listener->subs, sub));
263
264 listener->subs = g_list_prepend(listener->subs, sub);
265 GAM_DEBUG(DEBUG_INFO, "Adding sub %s to listener %s\n", gam_subscription_get_path (sub), listener->pidname);
266 }
267
268 /**
269 * gam_listener_remove_subscription:
270 *
271 * @listener: the #GamListener
272 * @sub: the #GamSubscription to remove
273 *
274 * Removes a subscription from the #GamListener.
275 */
276 void
gam_listener_remove_subscription(GamListener * listener,GamSubscription * sub)277 gam_listener_remove_subscription(GamListener *listener,
278 GamSubscription *sub)
279 {
280 g_assert(listener);
281 g_assert(sub);
282 g_assert(g_list_find(listener->subs, sub));
283
284 listener->subs = g_list_remove(listener->subs, sub);
285 GAM_DEBUG(DEBUG_INFO, "Removing sub %s from listener %s\n", gam_subscription_get_path (sub), listener->pidname);
286 /* There should only be one. */
287 g_assert(!g_list_find(listener->subs, sub));
288 }
289
290 /**
291 * gam_listener_get_subscriptions:
292 *
293 * @listener: the #GamListener
294 *
295 * Gets all the subscriptions a given listener has
296 *
297 * Returns a new list containing all of listener's subscriptions. It
298 * is the responsibility of the caller to free the list.
299 */
300 GList *
gam_listener_get_subscriptions(GamListener * listener)301 gam_listener_get_subscriptions(GamListener *listener)
302 {
303 g_assert(listener);
304 return g_list_copy(listener->subs);
305 }
306
307 /**
308 * gam_listener_debug:
309 *
310 * @listener: the #GamListener
311 *
312 * Print debugging information about a listener
313 */
314 void
gam_listener_debug(GamListener * listener)315 gam_listener_debug(GamListener *listener)
316 {
317 #ifdef GAM_DEBUG_ENABLED
318 GList *cur;
319
320 if (listener == NULL) {
321 GAM_DEBUG(DEBUG_INFO, " Listener is NULL\n");
322 return;
323 }
324
325 GAM_DEBUG(DEBUG_INFO, " Listener %s has %d subscriptions registered\n", listener->pidname,
326 g_list_length(listener->subs));
327 for (cur = listener->subs; cur; cur = g_list_next(cur)) {
328 gam_subscription_debug((GamSubscription *) cur->data);
329 }
330 #endif
331 }
332
333 /** @} */
334