1 /*
2 * Compiz configuration system library
3 *
4 * Copyright (C) 2007 Danny Baumann <maniac@opencompositing.org>
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19 */
20
21 #ifdef HAVE_CONFIG_H
22 # include "../config.h"
23 #endif
24
25 #define _GNU_SOURCE
26 #include <stdlib.h>
27 #include <stdio.h>
28 #include <string.h>
29 #include <unistd.h>
30 #include <stdlib.h>
31
32 #if HAVE_SYS_INOTIFY_H
33 #include <sys/inotify.h>
34 #endif
35
36 #include <fcntl.h>
37
38 #include <ccs.h>
39 #include "ccs-private.h"
40
41 typedef struct _FilewatchData
42 {
43 char *fileName;
44 int watchDesc;
45 unsigned int watchId;
46 FileWatchCallbackProc callback;
47 void *closure;
48 }
49
50 FilewatchData;
51
52 static FilewatchData *fwData = NULL;
53 static int fwDataSize = 0;
54 static int inotifyFd = 0;
55
56 static inline int
findDataIndexById(unsigned int watchId)57 findDataIndexById (unsigned int watchId)
58 {
59 int i, index = -1;
60
61 for (i = 0; i < fwDataSize; i++)
62 if (fwData[i].watchId == watchId)
63 {
64 index = i;
65 break;
66 }
67
68 return index;
69 }
70
ccsCheckFileWatches(void)71 void ccsCheckFileWatches (void)
72 {
73 #if HAVE_SYS_INOTIFY_H
74 char buf[256 * (sizeof (struct inotify_event) + 16)];
75 struct inotify_event *event;
76 int len, i = 0, j;
77
78 if (!inotifyFd)
79 return;
80
81 len = read (inotifyFd, buf, sizeof (buf));
82 if (len < 0)
83 return;
84
85 while (i < len)
86 {
87 event = (struct inotify_event *) & buf[i];
88
89 for (j = 0; j < fwDataSize; j++)
90 if ((fwData[j].watchDesc == event->wd) && fwData[j].callback)
91 (*fwData[j].callback) (fwData[j].watchId, fwData[j].closure);
92
93 i += sizeof (*event) + event->len;
94 }
95 #endif
96 }
97
ccsAddFileWatch(const char * fileName,Bool enable,FileWatchCallbackProc callback,void * closure)98 unsigned int ccsAddFileWatch (const char *fileName,
99 Bool enable,
100 FileWatchCallbackProc callback,
101 void *closure)
102 {
103 unsigned int i, maxWatchId = 0;
104
105 #if HAVE_SYS_INOTIFY_H
106 if (!inotifyFd)
107 {
108 inotifyFd = inotify_init ();
109 fcntl (inotifyFd, F_SETFL, O_NONBLOCK);
110 }
111 #endif
112
113 fwData = realloc (fwData, (fwDataSize + 1) * sizeof (FilewatchData));
114 if (!fwData)
115 {
116 fwDataSize = 0;
117 return 0;
118 }
119
120 fwData[fwDataSize].fileName = strdup (fileName);
121
122 #if HAVE_SYS_INOTIFY_H
123 if (enable)
124 fwData[fwDataSize].watchDesc =
125 inotify_add_watch (inotifyFd, fileName,
126 IN_MODIFY | IN_MOVE | IN_MOVE_SELF |
127 IN_DELETE_SELF | IN_CREATE | IN_DELETE);
128 else
129 #endif
130 fwData[fwDataSize].watchDesc = 0;
131
132 fwData[fwDataSize].callback = callback;
133 fwData[fwDataSize].closure = closure;
134
135 /* determine current highest ID */
136 for (i = 0; i < fwDataSize; i++)
137 if (fwData[i].watchId > maxWatchId)
138 maxWatchId = fwData[i].watchId;
139
140 fwData[fwDataSize].watchId = maxWatchId + 1;
141 fwDataSize++;
142
143 return (maxWatchId + 1);
144 }
145
146 void
ccsRemoveFileWatch(unsigned int watchId)147 ccsRemoveFileWatch (unsigned int watchId)
148
149 {
150 int selectedIndex, i;
151
152 selectedIndex = findDataIndexById (watchId);
153 /* not found */
154 if (selectedIndex < 0)
155 return;
156
157 /* clear entry */
158 free (fwData[selectedIndex].fileName);
159
160 #if HAVE_SYS_INOTIFY_H
161 if (fwData[selectedIndex].watchDesc)
162 inotify_rm_watch (inotifyFd, fwData[selectedIndex].watchDesc);
163 #endif
164
165 /* shrink array */
166 for (i = selectedIndex; i < (fwDataSize - 1); i++)
167 fwData[i] = fwData[i+1];
168
169 fwDataSize--;
170
171 if (fwDataSize > 0)
172 {
173 fwData = realloc (fwData, fwDataSize * sizeof (FilewatchData));
174 if (!fwData)
175 fwDataSize = 0;
176 }
177 else
178 {
179 free (fwData);
180 fwData = NULL;
181 }
182
183 if (!fwDataSize)
184 {
185 if (inotifyFd)
186 close (inotifyFd);
187 inotifyFd = 0;
188 }
189 }
190
191 void
ccsDisableFileWatch(unsigned int watchId)192 ccsDisableFileWatch (unsigned int watchId)
193 {
194 int index;
195
196 index = findDataIndexById (watchId);
197 if (index < 0)
198 return;
199
200 #if HAVE_SYS_INOTIFY_H
201 if (fwData[index].watchDesc)
202 {
203 inotify_rm_watch (inotifyFd, fwData[index].watchDesc);
204 fwData[index].watchDesc = 0;
205 }
206 #endif
207 }
208
209 void
ccsEnableFileWatch(unsigned int watchId)210 ccsEnableFileWatch (unsigned int watchId)
211 {
212 int index;
213
214 index = findDataIndexById (watchId);
215 if (index < 0)
216 return;
217
218 #if HAVE_SYS_INOTIFY_H
219 if (!fwData[index].watchDesc)
220 fwData[index].watchDesc =
221 inotify_add_watch (inotifyFd,
222 fwData[index].fileName,
223 IN_MODIFY | IN_MOVE | IN_MOVE_SELF |
224 IN_DELETE_SELF | IN_CREATE | IN_DELETE);
225 #endif
226 }
227
228