Subversion Repositories public

Rev

Rev 47 | Rev 55 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

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