Subversion Repositories public

Rev

Rev 59 | Rev 63 | Go to most recent revision | Show entire file | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed

Rev 59 Rev 61
Line 14... Line 14...
14
 */
14
 */
15
15
16
#include <map>
16
#include <map>
17
#include <signal.h>
17
#include <signal.h>
18
#include <wait.h>
18
#include <wait.h>
-
 
19
#include <fcntl.h>
19
#include <pwd.h>
20
#include <pwd.h>
20
#include <dirent.h>
21
#include <dirent.h>
21
#include <syslog.h>
22
#include <syslog.h>
22
#include <errno.h>
23
#include <errno.h>
23
#include <sys/poll.h>
24
#include <sys/poll.h>
Line 46... Line 47...
46
SUT_MAP g_ut;
47
SUT_MAP g_ut;
47
48
48
/// Finish program yes/no
49
/// Finish program yes/no
49
volatile bool g_fFinish = false;
50
volatile bool g_fFinish = false;
50
51
-
 
52
/// Pipe for notifying about dead children
-
 
53
int g_cldPipe[2];
-
 
54
-
 
55
// Buffer for emptying child pipe
-
 
56
#define CHILD_PIPE_BUF_LEN 32
-
 
57
char g_cldPipeBuf[CHILD_PIPE_BUF_LEN];
-
 
58
51
59
52
/// Handles a signal.
60
/// Handles a signal.
53
/**
61
/**
54
 * For SIGTERM and SIGINT it sets the program finish variable.
62
 * For SIGTERM and SIGINT it sets the program finish variable.
-
 
63
 * For SIGCHLD it writes a character into the notification pipe
-
 
64
 * (this is a workaround made due to disability to reliably
-
 
65
 * wait for dead children).
55
 *
66
 *
56
 * \param[in] signo signal number
67
 * \param[in] signo signal number
57
 */
68
 */
58
void on_signal(int signo)
69
void on_signal(int signo)
59
{
70
{
-
 
71
  switch (signo) {
-
 
72
    case SIGTERM:
60
  if (signo == SIGTERM || signo == SIGINT)
73
    case SIGINT:
61
    g_fFinish = true;
74
      g_fFinish = true;
-
 
75
      break;
-
 
76
    case SIGCHLD:
-
 
77
      // first empty pipe (to prevent internal buffer overflow)
-
 
78
      do {} while (read(g_cldPipe[0], g_cldPipeBuf, CHILD_PIPE_BUF_LEN) > 0);
-
 
79
     
-
 
80
      // now write one character
-
 
81
      write(g_cldPipe[1], "X", 1);
-
 
82
      break;
-
 
83
    default:;
-
 
84
  }
62
}
85
}
63
86
64
/// Checks whether an user exists and has permission to use incron.
87
/// Checks whether an user exists and has permission to use incron.
65
/**
88
/**
66
 * It searches for the given user name in the user database.
89
 * It searches for the given user name in the user database.
Line 123... Line 146...
123
  }
146
  }
124
 
147
 
125
  closedir(d);
148
  closedir(d);
126
}
149
}
127
150
-
 
151
/// Prepares a 'dead/done child' notification pipe.
-
 
152
/**
-
 
153
 * This function returns no value at all and on error it
-
 
154
 * throws an exception.
-
 
155
 */
-
 
156
void prepare_pipe()
-
 
157
{
-
 
158
  g_cldPipe[0] = -1;
-
 
159
  g_cldPipe[1] = -1;
-
 
160
 
-
 
161
  if (pipe(g_cldPipe) != 0)
-
 
162
      throw InotifyException("cannot create notification pipe", errno, NULL);
-
 
163
 
-
 
164
  for (int i=0; i<2; i++) {
-
 
165
    int res = fcntl(g_cldPipe[i], F_GETFL);
-
 
166
    if (res == -1)
-
 
167
      throw InotifyException("cannot get pipe flags", errno, NULL);
-
 
168
   
-
 
169
    res |= O_NONBLOCK;
-
 
170
       
-
 
171
    if (fcntl(g_cldPipe[i], F_SETFL, res) == -1)
-
 
172
      throw InotifyException("cannot set pipe flags", errno, NULL);
-
 
173
  }
-
 
174
}
-
 
175
128
/// Main application function.
176
/// Main application function.
129
/**
177
/**
130
 * \param[in] argc argument count
178
 * \param[in] argc argument count
131
 * \param[in] argv argument array
179
 * \param[in] argv argument array
132
 * \return 0 on success, 1 on error
180
 * \return 0 on success, 1 on error
Line 153... Line 201...
153
      syslog(LOG_NOTICE, "stopping service");
201
      syslog(LOG_NOTICE, "stopping service");
154
      closelog();
202
      closelog();
155
      return 1;
203
      return 1;
156
    }
204
    }
157
   
205
   
-
 
206
    if (DAEMON)
-
 
207
      daemon(0, 0);
-
 
208
   
-
 
209
    prepare_pipe();
-
 
210
   
158
    signal(SIGTERM, on_signal);
211
    signal(SIGTERM, on_signal);
159
    signal(SIGINT, on_signal);
212
    signal(SIGINT, on_signal);
160
    signal(SIGCHLD, on_signal);
213
    signal(SIGCHLD, on_signal);
161
   
214
   
162
    if (DAEMON)
-
 
163
      daemon(0, 0);
-
 
164
   
-
 
165
    uint32_t wm = IN_CLOSE_WRITE | IN_DELETE | IN_MOVE | IN_DELETE_SELF | IN_UNMOUNT;
215
    uint32_t wm = IN_CLOSE_WRITE | IN_DELETE | IN_MOVE | IN_DELETE_SELF | IN_UNMOUNT;
166
    InotifyWatch watch(INCRON_TABLE_BASE, wm);
216
    InotifyWatch watch(INCRON_TABLE_BASE, wm);
167
    in.Add(watch);
217
    in.Add(watch);
168
   
218
   
169
    syslog(LOG_NOTICE, "ready to process filesystem events");
219
    syslog(LOG_NOTICE, "ready to process filesystem events");
170
   
220
   
171
    InotifyEvent e;
221
    InotifyEvent e;
172
   
222
   
173
    struct pollfd pfd;
223
    struct pollfd pfd[2];
174
    pfd.fd = in.GetDescriptor();
224
    pfd[0].fd = in.GetDescriptor();
175
    pfd.events = (short) POLLIN;
225
    pfd[0].events = (short) POLLIN;
-
 
226
    pfd[0].revents = (short) 0;
-
 
227
    pfd[1].fd = g_cldPipe[0];
-
 
228
    pfd[1].events = (short) POLLIN;
176
    pfd.revents = (short) 0;
229
    pfd[1].revents = (short) 0;
177
   
230
   
178
    while (!g_fFinish) {
231
    while (!g_fFinish) {
179
     
232
     
180
      int res = poll(&pfd, 1, -1);
233
      int res = poll(pfd, 2, -1);
-
 
234
     
181
      if (res > 0) {
235
      if (res > 0) {
-
 
236
        if (pfd[1].revents & ((short) POLLIN)) {
-
 
237
          char c;
-
 
238
          while (read(pfd[1].fd, &c, 1) > 0) {}
-
 
239
          UserTable::FinishDone();
-
 
240
        }
-
 
241
        else {
182
        in.WaitForEvents(true);
242
          in.WaitForEvents(true);
-
 
243
        }
183
      }
244
      }
184
      else if (res < 0) {
245
      else if (res < 0) {
185
        if (errno != EINTR)
246
        if (errno != EINTR)
186
          throw InotifyException("polling failed", errno, NULL);
247
          throw InotifyException("polling failed", errno, NULL);
187
      }
248
      }
188
     
249
     
189
      UserTable::FinishDone();
-
 
190
     
-
 
191
      while (in.GetEvent(e)) {
250
      while (in.GetEvent(e)) {
192
       
251
       
193
        if (e.GetWatch() == &watch) {
252
        if (e.GetWatch() == &watch) {
194
          if (e.IsType(IN_DELETE_SELF) || e.IsType(IN_UNMOUNT)) {
253
          if (e.IsType(IN_DELETE_SELF) || e.IsType(IN_UNMOUNT)) {
195
            syslog(LOG_CRIT, "base directory destroyed, exitting");
254
            syslog(LOG_CRIT, "base directory destroyed, exitting");
Line 221... Line 280...
221
          }
280
          }
222
        }
281
        }
223
        else {
282
        else {
224
          ed.DispatchEvent(e);
283
          ed.DispatchEvent(e);
225
        }
284
        }
-
 
285
       
226
      }
286
      }
227
    }
287
    }
-
 
288
   
-
 
289
    if (g_cldPipe[0] != -1)
-
 
290
      close(g_cldPipe[0]);
-
 
291
    if (g_cldPipe[1] != -1)
-
 
292
      close(g_cldPipe[1]);
228
  } catch (InotifyException e) {
293
  } catch (InotifyException e) {
229
    int err = e.GetErrorNumber();
294
    int err = e.GetErrorNumber();
230
    syslog(LOG_CRIT, "*** unhandled exception occurred ***");
295
    syslog(LOG_CRIT, "*** unhandled exception occurred ***");
231
    syslog(LOG_CRIT, "  %s", e.GetMessage().c_str());
296
    syslog(LOG_CRIT, "  %s", e.GetMessage().c_str());
232
    syslog(LOG_CRIT, "  error: (%i) %s", err, strerror(err));
297
    syslog(LOG_CRIT, "  error: (%i) %s", err, strerror(err));