Subversion Repositories public

Rev

Rev 47 | Go to most recent revision | Details | 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>
20
 
21
#include "usertable.h"
22
 
23
 
24
EventDispatcher::EventDispatcher(Inotify* pIn)
25
{
26
 m_pIn = pIn;
27
}
28
 
29
void EventDispatcher::DispatchEvent(InotifyEvent& rEvt)
30
{
31
  if (m_pIn == NULL)
32
    return;
33
 
34
  InotifyWatch* pW = rEvt.GetWatch();
35
  if (pW == NULL)
36
    return;
37
 
38
  UserTable* pT = FindTable(pW);
39
  if (pT == NULL)
40
    return;
41
 
42
  pT->OnEvent(rEvt);
43
}
44
 
45
void EventDispatcher::Register(InotifyWatch* pWatch, UserTable* pTab)
46
{
47
  if (pWatch != NULL && pTab != NULL)
48
    m_maps.insert(IWUT_MAP::value_type(pWatch, pTab));
49
}
50
 
51
void EventDispatcher::Unregister(InotifyWatch* pWatch)
52
{
53
  IWUT_MAP::iterator it = m_maps.find(pWatch);
54
  if (it == m_maps.end())
55
    return;
56
 
57
  m_maps.erase(it);
58
}
59
 
60
void EventDispatcher::UnregisterAll(UserTable* pTab)
61
{
62
  IWUT_MAP::iterator it = m_maps.begin();
63
  while (it != m_maps.end()) {
64
    if ((*it).second == pTab) {
65
      IWUT_MAP::iterator it2 = it;
66
      it++;
67
      m_maps.erase(it2);
68
    }
69
    else {
70
      it++;
71
    }
72
  }
73
}
74
 
75
UserTable* EventDispatcher::FindTable(InotifyWatch* pW)
76
{
77
  IWUT_MAP::iterator it = m_maps.find(pW);
78
  if (it == m_maps.end())
79
    return NULL;
80
 
81
  return (*it).second;
82
}
83
 
84
 
85
 
86
 
87
UserTable::UserTable(Inotify* pIn, EventDispatcher* pEd, const std::string& rUser)
88
: m_user(rUser)
89
{
90
  m_pIn = pIn;
91
  m_pEd = pEd;
92
}
93
 
94
UserTable::~UserTable()
95
{
96
  Dispose();
97
}
98
 
99
void UserTable::Load()
100
{
101
  m_tab.Load(InCronTab::GetUserTablePath(m_user));
102
 
103
  int cnt = m_tab.GetCount();
104
  for (int i=0; i<cnt; i++) {
105
    InCronTabEntry& rE = m_tab.GetEntry(i);
106
    InotifyWatch* pW = new InotifyWatch(rE.GetPath(), rE.GetMask());
107
    m_pIn->Add(pW);
108
    m_pEd->Register(pW, this);
109
    m_map.insert(IWCE_MAP::value_type(pW, &rE));
110
  }
111
}
112
 
113
void UserTable::Dispose()
114
{
115
  IWCE_MAP::iterator it = m_map.begin();
116
  while (it != m_map.end()) {
117
    InotifyWatch* pW = (*it).first;
118
    m_pEd->Unregister(pW);
119
    m_pIn->Remove(pW);
120
    delete pW;
121
    it++;
122
  }
123
 
124
  m_map.clear();
125
}
126
 
127
void UserTable::OnEvent(InotifyEvent& rEvt)
128
{
129
  InotifyWatch* pW = rEvt.GetWatch();
130
  InCronTabEntry* pE = FindEntry(pW);
131
 
132
  if (pE == NULL)
133
    return;
134
 
135
  std::string cmd;
136
  const std::string& cs = pE->GetCmd();
137
  size_t pos = 0;
138
  size_t oldpos = 0;
139
  size_t len = cs.length();
140
  while ((pos = cs.find('$', oldpos)) != std::string::npos) {
141
    if (pos < len - 1) {
142
      size_t px = pos + 1;
143
      if (cs[px] == '$') {
144
        cmd.append(cs.substr(oldpos, pos-oldpos+1));
145
        oldpos = pos + 2;
146
      }
147
      else if (cs[px] == '@') {
148
        cmd.append(cs.substr(oldpos, pos-oldpos));
149
        cmd.append(pW->GetPath());
150
        oldpos = pos + 2;
151
      }
152
      else if (cs[px] == '#') {
153
        cmd.append(cs.substr(oldpos, pos-oldpos));
154
        cmd.append(rEvt.GetName());
155
        oldpos = pos + 2;
156
      }
157
      else {
158
        cmd.append(cs.substr(oldpos, pos-oldpos));
159
        oldpos = pos + 1;
160
      }
161
    }
162
    else {
163
      cmd.append(cs.substr(oldpos, pos-oldpos));
164
      oldpos = pos + 1;
165
    }
166
  }    
167
  cmd.append(cs.substr(oldpos));
168
 
169
  int argc;
170
  char** argv;
171
  if (!PrepareArgs(cmd, argc, argv)) {
172
    syslog(LOG_ERR, "cannot prepare command arguments");
173
    return;
174
  }
175
 
176
  syslog(LOG_INFO, "(%s) CMD (%s)", m_user.c_str(), cmd.c_str());
177
 
178
  pid_t pid = fork();
179
  if (pid == 0) {
180
 
181
    struct passwd* pwd = getpwnam(m_user.c_str());
182
    if (pwd == NULL)
183
      _exit(1);
184
 
185
    if (setuid(pwd->pw_uid) != 0)
186
      _exit(1);
187
 
188
    if (execvp(argv[0], argv) != 0) {
189
      _exit(1);
190
    }
191
  }
192
  else if (pid > 0) {
193
 
194
  }
195
  else {
196
    syslog(LOG_ERR, "cannot fork process: %s", strerror(errno));
197
  }
198
}
199
 
200
InCronTabEntry* UserTable::FindEntry(InotifyWatch* pWatch)
201
{
202
  IWCE_MAP::iterator it = m_map.find(pWatch);
203
  if (it == m_map.end())
204
    return NULL;
205
 
206
  return (*it).second;
207
}
208
 
209
bool UserTable::PrepareArgs(const std::string& rCmd, int& argc, char**& argv)
210
{
211
  if (rCmd.empty())
212
    return false;
213
 
214
  StringTokenizer tok(rCmd, ' ');
215
  std::deque<std::string> args;
216
  while (tok.HasMoreTokens()) {
217
    args.push_back(tok.GetNextToken());
218
  }
219
 
220
  if (args.empty())
221
    return false;
222
 
223
  argc = (int) args.size();
224
  argv = new char*[argc+1];
225
  argv[argc] = NULL;
226
 
227
  for (int i=0; i<argc; i++) {
228
    const std::string& s = args[i];
229
    size_t len = s.length();
230
    argv[i] = new char[len+1];
231
    strcpy(argv[i], s.c_str());
232
  }
233
 
234
  return true;
235
}
236