Subversion Repositories public

Rev

Rev 63 | Rev 69 | Go to most recent revision | Only display areas with differences | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed

Rev 63 Rev 67
1
1
2
/// inotify cron daemon main file
2
/// inotify cron daemon main file
3
/**
3
/**
4
 * \file icd-main.cpp
4
 * \file icd-main.cpp
5
 *
5
 *
6
 * inotify cron system
6
 * inotify cron system
7
 *
7
 *
8
 * Copyright (C) 2006, 2007 Lukas Jelinek, <lukas@aiken.cz>
8
 * Copyright (C) 2006, 2007 Lukas Jelinek, <lukas@aiken.cz>
9
 *
9
 *
10
 * This program is free software; you can use it, redistribute
10
 * This program is free software; you can use it, redistribute
11
 * it and/or modify it under the terms of the GNU General Public
11
 * it and/or modify it under the terms of the GNU General Public
12
 * License, version 2 (see LICENSE-GPL).
12
 * License, version 2 (see LICENSE-GPL).
13
 *  
13
 *  
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 <fcntl.h>
20
#include <pwd.h>
20
#include <pwd.h>
21
#include <dirent.h>
21
#include <dirent.h>
22
#include <syslog.h>
22
#include <syslog.h>
23
#include <errno.h>
23
#include <errno.h>
24
#include <sys/poll.h>
24
#include <sys/poll.h>
25
#include <sys/stat.h>
25
#include <sys/stat.h>
26
26
27
#include "inotify-cxx.h"
27
#include "inotify-cxx.h"
28
28
29
#include "incron.h"
29
#include "incron.h"
30
#include "incrontab.h"
30
#include "incrontab.h"
31
#include "usertable.h"
31
#include "usertable.h"
32
32
33
/// Daemon yes/no
-
 
34
#define DAEMON true
-
 
35
33
36
/// Logging options (console as fallback, log PID)
34
/// Logging options (console as fallback, log PID)
37
#define INCRON_LOG_OPTS (LOG_CONS | LOG_PID)
35
#define INCRON_LOG_OPTS (LOG_CONS | LOG_PID)
38
36
39
/// Logging facility (use CRON)
37
/// Logging facility (use CRON)
40
#define INCRON_LOG_FACIL LOG_CRON
38
#define INCRON_LOG_FACIL LOG_CRON
41
39
-
 
40
/// Help text
-
 
41
#define INCROND_HELP_TEXT "Usage: incrond [option]\n" \
-
 
42
                          "incrond - inotify cron daemon\n" \
-
 
43
                          "(c) Lukas Jelinek, 2006, 2007\n\n" \
-
 
44
                          "-h, --help             Give this help list\n" \
-
 
45
                          "-n, --foreground       Run on foreground (don't daemonize)\n" \
-
 
46
                          "-k, --kill             Terminate running instance of incrond\n" \
-
 
47
                          "-V, --version          Print program version\n\n" \
-
 
48
                          "Report bugs to <bugs@aiken.cz>"
-
 
49
-
 
50
#define INCROND_VERSION_TEXT INCRON_DAEMON_NAME " " INCRON_VERSION
42
51
43
/// User name to user table mapping definition
-
 
44
typedef std::map<std::string, UserTable*> SUT_MAP;
-
 
45
52
46
/// User name to user table mapping table
53
/// User name to user table mapping table
47
SUT_MAP g_ut;
54
SUT_MAP g_ut;
48
55
49
/// Finish program yes/no
56
/// Finish program yes/no
50
volatile bool g_fFinish = false;
57
volatile bool g_fFinish = false;
51
58
52
/// Pipe for notifying about dead children
59
/// Pipe for notifying about dead children
53
int g_cldPipe[2];
60
int g_cldPipe[2];
54
61
55
// Buffer for emptying child pipe
62
// Buffer for emptying child pipe
56
#define CHILD_PIPE_BUF_LEN 32
63
#define CHILD_PIPE_BUF_LEN 32
57
char g_cldPipeBuf[CHILD_PIPE_BUF_LEN];
64
char g_cldPipeBuf[CHILD_PIPE_BUF_LEN];
58
65
-
 
66
/// Daemonize true/false
-
 
67
bool g_daemon = true;
59
68
60
/// Handles a signal.
69
/// Handles a signal.
61
/**
70
/**
62
 * For SIGTERM and SIGINT it sets the program finish variable.
71
 * For SIGTERM and SIGINT it sets the program finish variable.
63
 * For SIGCHLD it writes a character into the notification pipe
72
 * For SIGCHLD it writes a character into the notification pipe
64
 * (this is a workaround made due to disability to reliably
73
 * (this is a workaround made due to disability to reliably
65
 * wait for dead children).
74
 * wait for dead children).
66
 *
75
 *
67
 * \param[in] signo signal number
76
 * \param[in] signo signal number
68
 */
77
 */
69
void on_signal(int signo)
78
void on_signal(int signo)
70
{
79
{
71
  switch (signo) {
80
  switch (signo) {
72
    case SIGTERM:
81
    case SIGTERM:
73
    case SIGINT:
82
    case SIGINT:
74
      g_fFinish = true;
83
      g_fFinish = true;
75
      break;
84
      break;
76
    case SIGCHLD:
85
    case SIGCHLD:
77
      // first empty pipe (to prevent internal buffer overflow)
86
      // first empty pipe (to prevent internal buffer overflow)
78
      do {} while (read(g_cldPipe[0], g_cldPipeBuf, CHILD_PIPE_BUF_LEN) > 0);
87
      do {} while (read(g_cldPipe[0], g_cldPipeBuf, CHILD_PIPE_BUF_LEN) > 0);
79
     
88
     
80
      // now write one character
89
      // now write one character
81
      write(g_cldPipe[1], "X", 1);
90
      write(g_cldPipe[1], "X", 1);
82
      break;
91
      break;
83
    default:;
92
    default:;
84
  }
93
  }
85
}
94
}
86
95
87
/// Checks whether an user exists and has permission to use incron.
-
 
88
/**
-
 
89
 * It searches for the given user name in the user database.
-
 
90
 * If it failes it returns 'false'. Otherwise it checks
-
 
91
 * permission files for this user (see InCronTab::CheckUser()).
-
 
92
 *
-
 
93
 * \param[in] user user name
-
 
94
 * \return true = user has permission to use incron, false = otherwise
-
 
95
 *
-
 
96
 * \sa InCronTab::CheckUser()
-
 
97
 */
-
 
98
bool check_user(const char* user)
-
 
99
{
-
 
100
  struct passwd* pw = getpwnam(user);
-
 
101
  if (pw == NULL)
-
 
102
    return false;
-
 
103
   
-
 
104
  return InCronTab::CheckUser(user);
-
 
105
}
-
 
106
96
107
/// Attempts to load all user incron tables.
97
/// Attempts to load all user incron tables.
108
/**
98
/**
109
 * Loaded tables are registered for processing events.
99
 * Loaded tables are registered for processing events.
110
 *
100
 *
111
 * \param[in] pIn inotify object
-
 
112
 * \param[in] pEd inotify event dispatcher
101
 * \param[in] pEd inotify event dispatcher
113
 *
102
 *
114
 * \throw InotifyException thrown if base table directory cannot be read
103
 * \throw InotifyException thrown if base table directory cannot be read
115
 */
104
 */
116
void load_tables(Inotify* pIn, EventDispatcher* pEd) throw (InotifyException)
105
void load_tables(EventDispatcher* pEd) throw (InotifyException)
117
{
106
{
-
 
107
  // WARNING - this function has not been optimized!!!
-
 
108
 
118
  DIR* d = opendir(INCRON_TABLE_BASE);
109
  DIR* d = opendir(INCRON_SYS_TABLE_BASE);
-
 
110
  if (d != NULL) {
-
 
111
    syslog(LOG_NOTICE, "loading system tables");
-
 
112
     
-
 
113
    struct dirent* pDe = NULL;
-
 
114
    while ((pDe = readdir(d)) != NULL) {
-
 
115
      std::string un(pDe->d_name);
-
 
116
     
-
 
117
      bool ok = pDe->d_type == DT_REG;
-
 
118
      if (pDe->d_type == DT_UNKNOWN) {
-
 
119
        struct stat st;
-
 
120
        if (stat(pDe->d_name, &st) == 0)
-
 
121
          ok = S_ISREG(st.st_mode);
-
 
122
      }
-
 
123
     
-
 
124
      if (ok) {
-
 
125
        syslog(LOG_INFO, "loading table %s", pDe->d_name);
-
 
126
        UserTable* pUt = new UserTable(pEd, un, true);
-
 
127
        g_ut.insert(SUT_MAP::value_type(std::string(INCRON_SYS_TABLE_BASE) + un, pUt));
-
 
128
        pUt->Load();
-
 
129
      }
-
 
130
    }
-
 
131
   
-
 
132
    closedir(d);
-
 
133
  }
-
 
134
  else {
-
 
135
    syslog(LOG_WARNING, "cannot open system table directory (ignoring)");
-
 
136
  }
-
 
137
 
-
 
138
 
-
 
139
  d = opendir(INCRON_USER_TABLE_BASE);
119
  if (d == NULL)
140
  if (d == NULL)
120
    throw InotifyException("cannot open table directory", errno);
141
    throw InotifyException("cannot open user table directory", errno);
121
 
142
 
122
  syslog(LOG_NOTICE, "loading user tables");
143
  syslog(LOG_NOTICE, "loading user tables");
123
   
144
   
124
  struct dirent* pDe = NULL;
145
  struct dirent* pDe = NULL;
125
  while ((pDe = readdir(d)) != NULL) {
146
  while ((pDe = readdir(d)) != NULL) {
126
    std::string un(pDe->d_name);
147
    std::string un(pDe->d_name);
127
   
148
   
128
    bool ok = pDe->d_type == DT_REG;
149
    bool ok = pDe->d_type == DT_REG;
129
    if (pDe->d_type == DT_UNKNOWN) {
150
    if (pDe->d_type == DT_UNKNOWN) {
130
      struct stat st;
151
      struct stat st;
131
      if (stat(pDe->d_name, &st) == 0)
152
      if (stat(pDe->d_name, &st) == 0)
132
        ok = S_ISREG(st.st_mode);
153
        ok = S_ISREG(st.st_mode);
133
    }
154
    }
134
   
155
   
135
    if (ok) {
156
    if (ok) {
136
      if (check_user(pDe->d_name)) {
157
      if (UserTable::CheckUser(pDe->d_name)) {
137
        syslog(LOG_INFO, "loading table for user %s", pDe->d_name);
158
        syslog(LOG_INFO, "loading table for user %s", pDe->d_name);
138
        UserTable* pUt = new UserTable(pIn, pEd, un);
159
        UserTable* pUt = new UserTable(pEd, un, false);
139
        g_ut.insert(SUT_MAP::value_type(un, pUt));
160
        g_ut.insert(SUT_MAP::value_type(std::string(INCRON_USER_TABLE_BASE) + un, pUt));
140
        pUt->Load();
161
        pUt->Load();
141
      }
162
      }
142
      else {
163
      else {
143
        syslog(LOG_WARNING, "table for invalid user %s found (ignored)", pDe->d_name);
164
        syslog(LOG_WARNING, "table for invalid user %s found (ignored)", pDe->d_name);
144
      }
165
      }
145
    }
166
    }
146
  }
167
  }
147
 
168
 
148
  closedir(d);
169
  closedir(d);
149
}
170
}
150
171
151
/// Prepares a 'dead/done child' notification pipe.
172
/// Prepares a 'dead/done child' notification pipe.
152
/**
173
/**
153
 * This function returns no value at all and on error it
174
 * This function returns no value at all and on error it
154
 * throws an exception.
175
 * throws an exception.
155
 */
176
 */
156
void prepare_pipe()
177
void prepare_pipe()
157
{
178
{
158
  g_cldPipe[0] = -1;
179
  g_cldPipe[0] = -1;
159
  g_cldPipe[1] = -1;
180
  g_cldPipe[1] = -1;
160
 
181
 
161
  if (pipe(g_cldPipe) != 0)
182
  if (pipe(g_cldPipe) != 0)
162
      throw InotifyException("cannot create notification pipe", errno, NULL);
183
      throw InotifyException("cannot create notification pipe", errno, NULL);
163
 
184
 
164
  for (int i=0; i<2; i++) {
185
  for (int i=0; i<2; i++) {
165
    int res = fcntl(g_cldPipe[i], F_GETFL);
186
    int res = fcntl(g_cldPipe[i], F_GETFL);
166
    if (res == -1)
187
    if (res == -1)
167
      throw InotifyException("cannot get pipe flags", errno, NULL);
188
      throw InotifyException("cannot get pipe flags", errno, NULL);
168
   
189
   
169
    res |= O_NONBLOCK;
190
    res |= O_NONBLOCK;
170
       
191
       
171
    if (fcntl(g_cldPipe[i], F_SETFL, res) == -1)
192
    if (fcntl(g_cldPipe[i], F_SETFL, res) == -1)
172
      throw InotifyException("cannot set pipe flags", errno, NULL);
193
      throw InotifyException("cannot set pipe flags", errno, NULL);
-
 
194
     
-
 
195
    res = fcntl(g_cldPipe[i], F_GETFD);
-
 
196
    if (res == -1)
-
 
197
      throw InotifyException("cannot get pipe flags", errno, NULL);
-
 
198
   
-
 
199
    res |= FD_CLOEXEC;
-
 
200
       
-
 
201
    if (fcntl(g_cldPipe[i], F_SETFD, res) == -1)
-
 
202
      throw InotifyException("cannot set pipe flags", errno, NULL);
173
  }
203
  }
174
}
204
}
175
205
-
 
206
/// Checks whether a parameter string is a specific command.
-
 
207
/**
-
 
208
 * The string is accepted if it equals either the short or long
-
 
209
 * form of the command.
-
 
210
 *
-
 
211
 * \param[in] s checked string
-
 
212
 * \param[in] shortCmd short form of command
-
 
213
 * \param[in] longCmd long form of command
-
 
214
 * \return true = string accepted, false = otherwise
-
 
215
 */  
-
 
216
bool check_parameter(const char* s, const char* shortCmd, const char* longCmd)
-
 
217
{
-
 
218
  return strcmp(s, shortCmd)  == 0
-
 
219
      || strcmp(s, longCmd)   == 0;
-
 
220
}
-
 
221
-
 
222
/// Attempts to kill all running instances of incrond.
-
 
223
/**
-
 
224
 * It kills only instances which use the same executable image
-
 
225
 * as the currently running one.
-
 
226
 *
-
 
227
 * \return true = at least one instance killed, false = otherwise
-
 
228
 * \attention More than one instance may be currently run simultaneously.
-
 
229
 */
-
 
230
bool kill_incrond()
-
 
231
{
-
 
232
  unsigned pid_self = (unsigned) getpid(); // self PID
-
 
233
 
-
 
234
  char s[PATH_MAX];
-
 
235
  snprintf(s, PATH_MAX, "/proc/%u/exe", pid_self);
-
 
236
 
-
 
237
  char path_self[PATH_MAX];
-
 
238
  ssize_t len = readlink(s, path_self, PATH_MAX-1);
-
 
239
  if (len <= 0)
-
 
240
    return false;
-
 
241
  path_self[len] = '\0';
-
 
242
 
-
 
243
  DIR* d = opendir("/proc");
-
 
244
  if (d == NULL)
-
 
245
    return false;
-
 
246
   
-
 
247
  bool ok = false;
-
 
248
   
-
 
249
  char path[PATH_MAX];
-
 
250
  struct dirent* de = NULL;
-
 
251
  while ((de = readdir(d)) != NULL) {
-
 
252
    bool to = false;
-
 
253
    if (de->d_type == DT_DIR)
-
 
254
      to = true;
-
 
255
    else if (de->d_type == DT_UNKNOWN) {
-
 
256
      // fallback way
-
 
257
      snprintf(s, PATH_MAX, "/proc/%s", de->d_name);
-
 
258
      struct stat st;
-
 
259
      if (stat(s, &st) == 0 && S_ISDIR(st.st_mode))
-
 
260
        to = true;
-
 
261
    }
-
 
262
   
-
 
263
    if (to) {
-
 
264
      unsigned pid;
-
 
265
      if (sscanf(de->d_name, "%u", &pid) == 1   // PID successfully retrieved
-
 
266
          && pid != pid_self)                   // don't do suicide!
-
 
267
      {
-
 
268
        snprintf(s, PATH_MAX, "/proc/%u/exe", pid);
-
 
269
        len = readlink(s, path, PATH_MAX-1);
-
 
270
        if (len > 0) {
-
 
271
          path[len] = '\0';
-
 
272
          if (    strcmp(path, path_self) == 0
-
 
273
              &&  kill((pid_t) pid, SIGTERM) == 0)
-
 
274
            ok = true;
-
 
275
        }
-
 
276
      }
-
 
277
    }
-
 
278
  }
-
 
279
 
-
 
280
  closedir(d);
-
 
281
 
-
 
282
  return ok;
-
 
283
}
-
 
284
-
 
285
/// Initializes a poll array.
-
 
286
/**
-
 
287
 * \param[in] pipefd pipe file descriptor
-
 
288
 * \param[in] infd inotify infrastructure file descriptor
-
 
289
 */
-
 
290
void init_poll_array(struct pollfd pfd[], int pipefd, int infd)
-
 
291
{
-
 
292
  pfd[0].fd = pipefd;
-
 
293
  pfd[0].events = (short) POLLIN;
-
 
294
  pfd[0].revents = (short) 0;
-
 
295
  pfd[1].fd = infd;
-
 
296
  pfd[1].events = (short) POLLIN;
-
 
297
  pfd[1].revents = (short) 0;
-
 
298
}
-
 
299
-
 
300
176
/// Main application function.
301
/// Main application function.
177
/**
302
/**
178
 * \param[in] argc argument count
303
 * \param[in] argc argument count
179
 * \param[in] argv argument array
304
 * \param[in] argv argument array
180
 * \return 0 on success, 1 on error
305
 * \return 0 on success, 1 on error
181
 *
306
 *
182
 * \attention In daemon mode, it finishes immediately.
307
 * \attention In daemon mode, it finishes immediately.
183
 */
308
 */
184
int main(int argc, char** argv)
309
int main(int argc, char** argv)
185
{
310
{
-
 
311
  if (argc > 2) {
-
 
312
    fprintf(stderr, "error: too many parameters\n");
-
 
313
    fprintf(stderr, "give --help or -h for more information\n");
-
 
314
    return 1;
-
 
315
  }
-
 
316
 
-
 
317
  if (argc == 2) {
-
 
318
    if (check_parameter(argv[1], "-h", "--help")) {
-
 
319
      printf("%s\n", INCROND_HELP_TEXT);
-
 
320
      return 0;
-
 
321
    }
-
 
322
    else if (check_parameter(argv[1], "-n", "--foreground")) {
-
 
323
      g_daemon = false;
-
 
324
    }
-
 
325
    else if (check_parameter(argv[1], "-k", "--kill")) {
-
 
326
      fprintf(stderr, "attempting to terminate a running instance of incrond...\n");
-
 
327
      if (kill_incrond()) {
-
 
328
        fprintf(stderr, "instance(s) notified, going down\n");
-
 
329
        return 0;
-
 
330
      }
-
 
331
      else {
-
 
332
        fprintf(stderr, "error - incrond probably not running\n");
-
 
333
        return 1;
-
 
334
      }
-
 
335
    }
-
 
336
    else if (check_parameter(argv[1], "-V", "--version")) {
-
 
337
      printf("%s\n", INCROND_VERSION_TEXT);
-
 
338
      return 0;
-
 
339
    }
-
 
340
    else {
-
 
341
      fprintf(stderr, "error - unrecognized parameter: %s\n", argv[1]);
-
 
342
      return 1;
-
 
343
    }
-
 
344
  }
-
 
345
 
186
  openlog(INCRON_DAEMON_NAME, INCRON_LOG_OPTS, INCRON_LOG_FACIL);
346
  openlog(INCRON_DAEMON_NAME, INCRON_LOG_OPTS, INCRON_LOG_FACIL);
187
 
347
 
188
  syslog(LOG_NOTICE, "starting service (version %s, built on %s %s)", INCRON_VERSION, __DATE__, __TIME__);
348
  syslog(LOG_NOTICE, "starting service (version %s, built on %s %s)", INCRON_VERSION, __DATE__, __TIME__);
189
 
349
 
190
  try {
350
  try {
-
 
351
    if (g_daemon)
-
 
352
      daemon(0, 0);
-
 
353
   
-
 
354
    prepare_pipe();
-
 
355
   
191
    Inotify in;
356
    Inotify in;
192
    in.SetNonBlock(true);
357
    in.SetNonBlock(true);
-
 
358
    in.SetCloseOnExec(true);
-
 
359
   
-
 
360
    uint32_t wm = IN_CLOSE_WRITE | IN_DELETE | IN_MOVE | IN_DELETE_SELF | IN_UNMOUNT;
-
 
361
    InotifyWatch stw(INCRON_SYS_TABLE_BASE, wm);
-
 
362
    in.Add(stw);
-
 
363
    InotifyWatch utw(INCRON_USER_TABLE_BASE, wm);
-
 
364
    in.Add(utw);
193
   
365
   
194
    EventDispatcher ed(&in);
366
    EventDispatcher ed(g_cldPipe[0], &in, &stw, &utw);
195
   
367
   
196
    try {
368
    try {
197
      load_tables(&in, &ed);
369
      load_tables(&ed);
198
    } catch (InotifyException e) {
370
    } catch (InotifyException e) {
199
      int err = e.GetErrorNumber();
371
      int err = e.GetErrorNumber();
200
      syslog(LOG_CRIT, "%s: (%i) %s", e.GetMessage().c_str(), err, strerror(err));
372
      syslog(LOG_CRIT, "%s: (%i) %s", e.GetMessage().c_str(), err, strerror(err));
201
      syslog(LOG_NOTICE, "stopping service");
373
      syslog(LOG_NOTICE, "stopping service");
202
      closelog();
374
      closelog();
203
      return 1;
375
      return 1;
204
    }
376
    }
205
   
377
   
206
    if (DAEMON)
-
 
207
      daemon(0, 0);
-
 
208
   
-
 
209
    prepare_pipe();
-
 
210
   
-
 
211
    signal(SIGTERM, on_signal);
378
    signal(SIGTERM, on_signal);
212
    signal(SIGINT, on_signal);
379
    signal(SIGINT, on_signal);
213
    signal(SIGCHLD, on_signal);
380
    signal(SIGCHLD, on_signal);
214
   
381
   
215
    uint32_t wm = IN_CLOSE_WRITE | IN_DELETE | IN_MOVE | IN_DELETE_SELF | IN_UNMOUNT;
-
 
216
    InotifyWatch watch(INCRON_TABLE_BASE, wm);
-
 
217
    in.Add(watch);
-
 
218
   
-
 
219
    syslog(LOG_NOTICE, "ready to process filesystem events");
382
    syslog(LOG_NOTICE, "ready to process filesystem events");
220
   
383
   
221
    InotifyEvent e;
-
 
222
   
-
 
223
    struct pollfd pfd[2];
-
 
224
    pfd[0].fd = in.GetDescriptor();
-
 
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;
-
 
229
    pfd[1].revents = (short) 0;
-
 
230
   
-
 
231
    while (!g_fFinish) {
384
    while (!g_fFinish) {
232
     
385
     
233
      int res = poll(pfd, 2, -1);
386
      int res = poll(ed.GetPollData(), ed.GetSize(), -1);
234
     
387
     
235
      if (res > 0) {
388
      if (res > 0) {
236
        if (pfd[1].revents & ((short) POLLIN)) {
389
        if (ed.ProcessEvents())
237
          char c;
-
 
238
          while (read(pfd[1].fd, &c, 1) > 0) {}
-
 
239
          UserTable::FinishDone();
390
          UserTable::FinishDone();
240
        }
-
 
241
        else {
-
 
242
          in.WaitForEvents(true);
-
 
243
        }
-
 
244
      }
391
      }
245
      else if (res < 0) {
392
      else if (res < 0) {
246
        if (errno != EINTR)
393
        if (errno != EINTR)
247
          throw InotifyException("polling failed", errno, NULL);
394
          throw InotifyException("polling failed", errno, NULL);
248
      }
395
      }
-
 
396
      /*
249
     
397
     
250
      while (in.GetEvent(e)) {
398
      while (in.GetEvent(e)) {
251
       
399
       
252
        if (e.GetWatch() == &watch) {
400
        if (e.GetWatch() == &stw) {
-
 
401
          if (e.IsType(IN_DELETE_SELF) || e.IsType(IN_UNMOUNT)) {
-
 
402
            syslog(LOG_CRIT, "base directory destroyed, exitting");
-
 
403
            g_fFinish = true;
-
 
404
          }
-
 
405
          else if (!e.GetName().empty()) {
-
 
406
            SUT_MAP::iterator it = g_ut.find(stw.GetPath() + e.GetName());
-
 
407
            if (it != g_ut.end()) {
-
 
408
              UserTable* pUt = (*it).second;
-
 
409
              if (e.IsType(IN_CLOSE_WRITE) || e.IsType(IN_MOVED_TO)) {
-
 
410
                syslog(LOG_INFO, "system table %s changed, reloading", e.GetName().c_str());
-
 
411
                pUt->Dispose();
-
 
412
                pUt->Load();
-
 
413
              }
-
 
414
              else if (e.IsType(IN_MOVED_FROM) || e.IsType(IN_DELETE)) {
-
 
415
                syslog(LOG_INFO, "system table %s destroyed, removing", e.GetName().c_str());
-
 
416
                delete pUt;
-
 
417
                g_ut.erase(it);
-
 
418
              }
-
 
419
            }
-
 
420
            else if (e.IsType(IN_CLOSE_WRITE) || e.IsType(IN_MOVED_TO)) {
-
 
421
              syslog(LOG_INFO, "system table %s created, loading", e.GetName().c_str());
-
 
422
              UserTable* pUt = new UserTable(&in, &ed, e.GetName(), true);
-
 
423
              g_ut.insert(SUT_MAP::value_type(std::string(INCRON_SYS_TABLE_BASE) + e.GetName(), pUt));
-
 
424
              pUt->Load();
-
 
425
            }
-
 
426
          }
-
 
427
        }
-
 
428
        else if (e.GetWatch() == &utw) {
253
          if (e.IsType(IN_DELETE_SELF) || e.IsType(IN_UNMOUNT)) {
429
          if (e.IsType(IN_DELETE_SELF) || e.IsType(IN_UNMOUNT)) {
254
            syslog(LOG_CRIT, "base directory destroyed, exitting");
430
            syslog(LOG_CRIT, "base directory destroyed, exitting");
255
            g_fFinish = true;
431
            g_fFinish = true;
256
          }
432
          }
257
          else if (!e.GetName().empty()) {
433
          else if (!e.GetName().empty()) {
258
            SUT_MAP::iterator it = g_ut.find(e.GetName());
434
            SUT_MAP::iterator it = g_ut.find(e.GetWatch()->GetPath() + e.GetName());
259
            if (it != g_ut.end()) {
435
            if (it != g_ut.end()) {
260
              UserTable* pUt = (*it).second;
436
              UserTable* pUt = (*it).second;
261
              if (e.IsType(IN_CLOSE_WRITE) || e.IsType(IN_MOVED_TO)) {
437
              if (e.IsType(IN_CLOSE_WRITE) || e.IsType(IN_MOVED_TO)) {
262
                syslog(LOG_INFO, "table for user %s changed, reloading", e.GetName().c_str());
438
                syslog(LOG_INFO, "table for user %s changed, reloading", e.GetName().c_str());
263
                pUt->Dispose();
439
                pUt->Dispose();
264
                pUt->Load();
440
                pUt->Load();
265
              }
441
              }
266
              else if (e.IsType(IN_MOVED_FROM) || e.IsType(IN_DELETE)) {
442
              else if (e.IsType(IN_MOVED_FROM) || e.IsType(IN_DELETE)) {
267
                syslog(LOG_INFO, "table for user %s destroyed, removing", e.GetName().c_str());
443
                syslog(LOG_INFO, "table for user %s destroyed, removing",  e.GetName().c_str());
268
                delete pUt;
444
                delete pUt;
269
                g_ut.erase(it);
445
                g_ut.erase(it);
270
              }
446
              }
271
            }
447
            }
272
            else if (e.IsType(IN_CLOSE_WRITE) || e.IsType(IN_MOVED_TO)) {
448
            else if (e.IsType(IN_CLOSE_WRITE) || e.IsType(IN_MOVED_TO)) {
273
              if (check_user(e.GetName().c_str())) {
449
              if (check_user(e.GetName().c_str())) {
274
                syslog(LOG_INFO, "table for user %s created, loading", e.GetName().c_str());
450
                syslog(LOG_INFO, "table for user %s created, loading", e.GetName().c_str());
275
                UserTable* pUt = new UserTable(&in, &ed, e.GetName());
451
                UserTable* pUt = new UserTable(&in, &ed, e.GetName(), false);
276
                g_ut.insert(SUT_MAP::value_type(e.GetName(), pUt));
452
                g_ut.insert(SUT_MAP::value_type(std::string(INCRON_USER_TABLE_BASE) + e.GetName(), pUt));
277
                pUt->Load();
453
                pUt->Load();
278
              }
454
              }
279
            }
455
            }
280
          }
456
          }
281
        }
457
        }
282
        else {
458
        else {
283
          ed.DispatchEvent(e);
459
          ed.DispatchEvent(e);
284
        }
460
        }
285
       
461
       
286
      }
462
      }
-
 
463
     
-
 
464
      */
287
    }
465
    }
288
   
466
   
289
    if (g_cldPipe[0] != -1)
467
    if (g_cldPipe[0] != -1)
290
      close(g_cldPipe[0]);
468
      close(g_cldPipe[0]);
291
    if (g_cldPipe[1] != -1)
469
    if (g_cldPipe[1] != -1)
292
      close(g_cldPipe[1]);
470
      close(g_cldPipe[1]);
293
  } catch (InotifyException e) {
471
  } catch (InotifyException e) {
294
    int err = e.GetErrorNumber();
472
    int err = e.GetErrorNumber();
295
    syslog(LOG_CRIT, "*** unhandled exception occurred ***");
473
    syslog(LOG_CRIT, "*** unhandled exception occurred ***");
296
    syslog(LOG_CRIT, "  %s", e.GetMessage().c_str());
474
    syslog(LOG_CRIT, "  %s", e.GetMessage().c_str());
297
    syslog(LOG_CRIT, "  error: (%i) %s", err, strerror(err));
475
    syslog(LOG_CRIT, "  error: (%i) %s", err, strerror(err));
298
  }
476
  }
299
477
300
  syslog(LOG_NOTICE, "stopping service");
478
  syslog(LOG_NOTICE, "stopping service");
301
 
479
 
302
  closelog();
480
  closelog();
303
 
481
 
304
  return 0;
482
  return 0;
305
}
483
}
306
 
484