Subversion Repositories public

Rev

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

Rev 45 Rev 47
1
1
2
/// inotify cron daemon user tables implementation
2
/// inotify cron daemon user tables implementation
3
/**
3
/**
4
 * \file usertable.cpp
4
 * \file usertable.cpp
5
 *
5
 *
6
 * inotify cron system
6
 * inotify cron system
7
 *
7
 *
8
 * Copyright (C) 2006 Lukas Jelinek, <lukas@aiken.cz>
8
 * Copyright (C) 2006 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
16
17
#include <pwd.h>
17
#include <pwd.h>
18
#include <syslog.h>
18
#include <syslog.h>
19
#include <errno.h>
19
#include <errno.h>
-
 
20
#include <sys/wait.h>
20
21
21
#include "usertable.h"
22
#include "usertable.h"
22
23
23
24
-
 
25
PROC_LIST UserTable::s_procList;
-
 
26
-
 
27
-
 
28
void on_proc_done(InotifyWatch* pW)
-
 
29
{
-
 
30
  pW->SetEnabled(true);
-
 
31
}
-
 
32
-
 
33
24
EventDispatcher::EventDispatcher(Inotify* pIn)
34
EventDispatcher::EventDispatcher(Inotify* pIn)
25
{
35
{
26
 m_pIn = pIn;
36
 m_pIn = pIn;
27
}
37
}
28
38
29
void EventDispatcher::DispatchEvent(InotifyEvent& rEvt)
39
void EventDispatcher::DispatchEvent(InotifyEvent& rEvt)
30
{
40
{
31
  if (m_pIn == NULL)
41
  if (m_pIn == NULL)
32
    return;
42
    return;
33
   
43
   
34
  InotifyWatch* pW = rEvt.GetWatch();
44
  InotifyWatch* pW = rEvt.GetWatch();
35
  if (pW == NULL)
45
  if (pW == NULL)
36
    return;
46
    return;
37
   
47
   
38
  UserTable* pT = FindTable(pW);
48
  UserTable* pT = FindTable(pW);
39
  if (pT == NULL)
49
  if (pT == NULL)
40
    return;
50
    return;
41
   
51
   
42
  pT->OnEvent(rEvt);
52
  pT->OnEvent(rEvt);
43
}
53
}
44
 
54
 
45
void EventDispatcher::Register(InotifyWatch* pWatch, UserTable* pTab)
55
void EventDispatcher::Register(InotifyWatch* pWatch, UserTable* pTab)
46
{
56
{
47
  if (pWatch != NULL && pTab != NULL)
57
  if (pWatch != NULL && pTab != NULL)
48
    m_maps.insert(IWUT_MAP::value_type(pWatch, pTab));
58
    m_maps.insert(IWUT_MAP::value_type(pWatch, pTab));
49
}
59
}
50
 
60
 
51
void EventDispatcher::Unregister(InotifyWatch* pWatch)
61
void EventDispatcher::Unregister(InotifyWatch* pWatch)
52
{
62
{
53
  IWUT_MAP::iterator it = m_maps.find(pWatch);
63
  IWUT_MAP::iterator it = m_maps.find(pWatch);
54
  if (it == m_maps.end())
64
  if (it == m_maps.end())
55
    return;
65
    return;
56
   
66
   
57
  m_maps.erase(it);
67
  m_maps.erase(it);
58
}
68
}
59
 
69
 
60
void EventDispatcher::UnregisterAll(UserTable* pTab)
70
void EventDispatcher::UnregisterAll(UserTable* pTab)
61
{
71
{
62
  IWUT_MAP::iterator it = m_maps.begin();
72
  IWUT_MAP::iterator it = m_maps.begin();
63
  while (it != m_maps.end()) {
73
  while (it != m_maps.end()) {
64
    if ((*it).second == pTab) {
74
    if ((*it).second == pTab) {
65
      IWUT_MAP::iterator it2 = it;
75
      IWUT_MAP::iterator it2 = it;
66
      it++;
76
      it++;
67
      m_maps.erase(it2);
77
      m_maps.erase(it2);
68
    }
78
    }
69
    else {
79
    else {
70
      it++;
80
      it++;
71
    }
81
    }
72
  }
82
  }
73
}
83
}
74
84
75
UserTable* EventDispatcher::FindTable(InotifyWatch* pW)
85
UserTable* EventDispatcher::FindTable(InotifyWatch* pW)
76
{
86
{
77
  IWUT_MAP::iterator it = m_maps.find(pW);
87
  IWUT_MAP::iterator it = m_maps.find(pW);
78
  if (it == m_maps.end())
88
  if (it == m_maps.end())
79
    return NULL;
89
    return NULL;
80
   
90
   
81
  return (*it).second;
91
  return (*it).second;
82
}
92
}
83
93
84
94
85
95
86
96
87
UserTable::UserTable(Inotify* pIn, EventDispatcher* pEd, const std::string& rUser)
97
UserTable::UserTable(Inotify* pIn, EventDispatcher* pEd, const std::string& rUser)
88
: m_user(rUser)
98
: m_user(rUser)
89
{
99
{
90
  m_pIn = pIn;
100
  m_pIn = pIn;
91
  m_pEd = pEd;
101
  m_pEd = pEd;
92
}
102
}
93
103
94
UserTable::~UserTable()
104
UserTable::~UserTable()
95
{
105
{
96
  Dispose();
106
  Dispose();
97
}
107
}
98
 
108
 
99
void UserTable::Load()
109
void UserTable::Load()
100
{
110
{
101
  m_tab.Load(InCronTab::GetUserTablePath(m_user));
111
  m_tab.Load(InCronTab::GetUserTablePath(m_user));
102
 
112
 
103
  int cnt = m_tab.GetCount();
113
  int cnt = m_tab.GetCount();
104
  for (int i=0; i<cnt; i++) {
114
  for (int i=0; i<cnt; i++) {
105
    InCronTabEntry& rE = m_tab.GetEntry(i);
115
    InCronTabEntry& rE = m_tab.GetEntry(i);
106
    InotifyWatch* pW = new InotifyWatch(rE.GetPath(), rE.GetMask());
116
    InotifyWatch* pW = new InotifyWatch(rE.GetPath(), rE.GetMask());
-
 
117
    try {
107
    m_pIn->Add(pW);
118
      m_pIn->Add(pW);
108
    m_pEd->Register(pW, this);
119
      m_pEd->Register(pW, this);
109
    m_map.insert(IWCE_MAP::value_type(pW, &rE));
120
      m_map.insert(IWCE_MAP::value_type(pW, &rE));
-
 
121
    } catch (InotifyException e) {
-
 
122
      syslog(LOG_ERR, "cannot create watch for user %s", m_user.c_str());
-
 
123
      delete pW;
-
 
124
    }
110
  }
125
  }
111
}
126
}
112
127
113
void UserTable::Dispose()
128
void UserTable::Dispose()
114
{
129
{
115
  IWCE_MAP::iterator it = m_map.begin();
130
  IWCE_MAP::iterator it = m_map.begin();
116
  while (it != m_map.end()) {
131
  while (it != m_map.end()) {
117
    InotifyWatch* pW = (*it).first;
132
    InotifyWatch* pW = (*it).first;
118
    m_pEd->Unregister(pW);
133
    m_pEd->Unregister(pW);
119
    m_pIn->Remove(pW);
134
    m_pIn->Remove(pW);
120
    delete pW;
135
    delete pW;
121
    it++;
136
    it++;
122
  }
137
  }
123
 
138
 
124
  m_map.clear();
139
  m_map.clear();
125
}
140
}
126
 
141
 
127
void UserTable::OnEvent(InotifyEvent& rEvt)
142
void UserTable::OnEvent(InotifyEvent& rEvt)
128
{
143
{
129
  InotifyWatch* pW = rEvt.GetWatch();
144
  InotifyWatch* pW = rEvt.GetWatch();
130
  InCronTabEntry* pE = FindEntry(pW);
145
  InCronTabEntry* pE = FindEntry(pW);
131
 
146
 
132
  if (pE == NULL)
147
  if (pE == NULL)
133
    return;
148
    return;
134
 
149
 
135
  std::string cmd;
150
  std::string cmd;
136
  const std::string& cs = pE->GetCmd();
151
  const std::string& cs = pE->GetCmd();
137
  size_t pos = 0;
152
  size_t pos = 0;
138
  size_t oldpos = 0;
153
  size_t oldpos = 0;
139
  size_t len = cs.length();
154
  size_t len = cs.length();
140
  while ((pos = cs.find('$', oldpos)) != std::string::npos) {
155
  while ((pos = cs.find('$', oldpos)) != std::string::npos) {
141
    if (pos < len - 1) {
156
    if (pos < len - 1) {
142
      size_t px = pos + 1;
157
      size_t px = pos + 1;
143
      if (cs[px] == '$') {
158
      if (cs[px] == '$') {
144
        cmd.append(cs.substr(oldpos, pos-oldpos+1));
159
        cmd.append(cs.substr(oldpos, pos-oldpos+1));
145
        oldpos = pos + 2;
160
        oldpos = pos + 2;
146
      }
161
      }
147
      else if (cs[px] == '@') {
162
      else if (cs[px] == '@') {
148
        cmd.append(cs.substr(oldpos, pos-oldpos));
163
        cmd.append(cs.substr(oldpos, pos-oldpos));
149
        cmd.append(pW->GetPath());
164
        cmd.append(pW->GetPath());
150
        oldpos = pos + 2;
165
        oldpos = pos + 2;
151
      }
166
      }
152
      else if (cs[px] == '#') {
167
      else if (cs[px] == '#') {
153
        cmd.append(cs.substr(oldpos, pos-oldpos));
168
        cmd.append(cs.substr(oldpos, pos-oldpos));
154
        cmd.append(rEvt.GetName());
169
        cmd.append(rEvt.GetName());
155
        oldpos = pos + 2;
170
        oldpos = pos + 2;
156
      }
171
      }
157
      else {
172
      else {
158
        cmd.append(cs.substr(oldpos, pos-oldpos));
173
        cmd.append(cs.substr(oldpos, pos-oldpos));
159
        oldpos = pos + 1;
174
        oldpos = pos + 1;
160
      }
175
      }
161
    }
176
    }
162
    else {
177
    else {
163
      cmd.append(cs.substr(oldpos, pos-oldpos));
178
      cmd.append(cs.substr(oldpos, pos-oldpos));
164
      oldpos = pos + 1;
179
      oldpos = pos + 1;
165
    }
180
    }
166
  }    
181
  }    
167
  cmd.append(cs.substr(oldpos));
182
  cmd.append(cs.substr(oldpos));
168
 
183
 
169
  int argc;
184
  int argc;
170
  char** argv;
185
  char** argv;
171
  if (!PrepareArgs(cmd, argc, argv)) {
186
  if (!PrepareArgs(cmd, argc, argv)) {
172
    syslog(LOG_ERR, "cannot prepare command arguments");
187
    syslog(LOG_ERR, "cannot prepare command arguments");
173
    return;
188
    return;
174
  }
189
  }
175
 
190
 
176
  syslog(LOG_INFO, "(%s) CMD (%s)", m_user.c_str(), cmd.c_str());
191
  syslog(LOG_INFO, "(%s) CMD (%s)", m_user.c_str(), cmd.c_str());
177
 
192
 
-
 
193
  if (pE->IsNoLoop())
-
 
194
    pW->SetEnabled(false);
-
 
195
 
-
 
196
  ProcData_t pd;
178
  pid_t pid = fork();
197
  pd.pid = fork();
179
  if (pid == 0) {
198
  if (pd.pid == 0) {
180
   
199
   
181
    struct passwd* pwd = getpwnam(m_user.c_str());
200
    struct passwd* pwd = getpwnam(m_user.c_str());
182
    if (pwd == NULL)
201
    if (pwd == NULL)
183
      _exit(1);
202
      _exit(1);
184
     
203
     
185
    if (setuid(pwd->pw_uid) != 0)
204
    if (setuid(pwd->pw_uid) != 0)
186
      _exit(1);
205
      _exit(1);
187
   
206
   
188
    if (execvp(argv[0], argv) != 0) {
207
    if (execvp(argv[0], argv) != 0) {
189
      _exit(1);
208
      _exit(1);
190
    }
209
    }
191
  }
210
  }
192
  else if (pid > 0) {
211
  else if (pd.pid > 0) {
-
 
212
    if (pE->IsNoLoop()) {
-
 
213
      pd.onDone = on_proc_done;
-
 
214
      pd.pWatch = pW;
-
 
215
    }
-
 
216
    else {
-
 
217
      pd.onDone = NULL;
-
 
218
      pd.pWatch = NULL;
-
 
219
    }
193
   
220
   
-
 
221
    s_procList.push_back(pd);
194
  }
222
  }
195
  else {
223
  else {
-
 
224
    if (pE->IsNoLoop())
-
 
225
      pW->SetEnabled(true);
-
 
226
     
196
    syslog(LOG_ERR, "cannot fork process: %s", strerror(errno));
227
    syslog(LOG_ERR, "cannot fork process: %s", strerror(errno));
197
  }
228
  }
198
}
229
}
199
230
200
InCronTabEntry* UserTable::FindEntry(InotifyWatch* pWatch)
231
InCronTabEntry* UserTable::FindEntry(InotifyWatch* pWatch)
201
{
232
{
202
  IWCE_MAP::iterator it = m_map.find(pWatch);
233
  IWCE_MAP::iterator it = m_map.find(pWatch);
203
  if (it == m_map.end())
234
  if (it == m_map.end())
204
    return NULL;
235
    return NULL;
205
   
236
   
206
  return (*it).second;
237
  return (*it).second;
207
}
238
}
208
239
209
bool UserTable::PrepareArgs(const std::string& rCmd, int& argc, char**& argv)
240
bool UserTable::PrepareArgs(const std::string& rCmd, int& argc, char**& argv)
210
{
241
{
211
  if (rCmd.empty())
242
  if (rCmd.empty())
212
    return false;
243
    return false;
213
   
244
   
214
  StringTokenizer tok(rCmd, ' ');
245
  StringTokenizer tok(rCmd, ' ');
215
  std::deque<std::string> args;
246
  std::deque<std::string> args;
216
  while (tok.HasMoreTokens()) {
247
  while (tok.HasMoreTokens()) {
217
    args.push_back(tok.GetNextToken());
248
    args.push_back(tok.GetNextToken());
218
  }
249
  }
219
 
250
 
220
  if (args.empty())
251
  if (args.empty())
221
    return false;
252
    return false;
222
 
253
 
223
  argc = (int) args.size();
254
  argc = (int) args.size();
224
  argv = new char*[argc+1];
255
  argv = new char*[argc+1];
225
  argv[argc] = NULL;
256
  argv[argc] = NULL;
226
 
257
 
227
  for (int i=0; i<argc; i++) {
258
  for (int i=0; i<argc; i++) {
228
    const std::string& s = args[i];
259
    const std::string& s = args[i];
229
    size_t len = s.length();
260
    size_t len = s.length();
230
    argv[i] = new char[len+1];
261
    argv[i] = new char[len+1];
231
    strcpy(argv[i], s.c_str());
262
    strcpy(argv[i], s.c_str());
232
  }
263
  }
233
 
264
 
234
  return true;
265
  return true;
235
}
266
}
236
267
-
 
268
void UserTable::FinishDone()
-
 
269
{
-
 
270
  PROC_LIST::iterator it = s_procList.begin();
-
 
271
  while (it != s_procList.end()) {
-
 
272
    ProcData_t& pd = *it;
-
 
273
    int status = 0;
-
 
274
    int res = waitpid(pd.pid, &status, WNOHANG);
-
 
275
    if (res == pd.pid && (WIFEXITED(status) || WIFSIGNALED(status))) {
-
 
276
      if (pd.onDone != NULL)
-
 
277
        (*pd.onDone)(pd.pWatch);
-
 
278
      it = s_procList.erase(it);
-
 
279
    }
-
 
280
    else {
-
 
281
      it++;
-
 
282
    }
-
 
283
  }  
-
 
284
}
-
 
285
-
 
286
237
 
287