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