~ubuntu-branches/ubuntu/quantal/memlockd/quantal

« back to all changes in this revision

Viewing changes to memlockd.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Russell Coker
  • Date: 2007-03-13 19:12:00 UTC
  • Revision ID: james.westby@ubuntu.com-20070313191200-x76vcg6oujqsxmys
Tags: 0.03
* Fixed section and description.

* Made it write a pidfile, and also made the restart option of the init.d
  script start a new instance unconditionally so the new instance can kill
  the old.  This means that there is no window where memlockd is not
  running.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
#include <assert.h>
 
2
#include <string.h>
 
3
#include <sys/types.h>
 
4
#include <pwd.h>
 
5
#include <sys/wait.h>
 
6
#include <sys/stat.h>
 
7
#include <fcntl.h>
 
8
#include <unistd.h>
 
9
#include <syslog.h>
 
10
#include <signal.h>
 
11
#include <stdio.h>
 
12
#include <errno.h>
 
13
#include <stdlib.h>
 
14
#include <sys/mman.h>
 
15
#include <asm/page.h>
 
16
#include <stdarg.h>
 
17
 
 
18
#define MAX_FILES 1024
 
19
#define PIDFILE "/var/run/memlockd.pid"
 
20
 
 
21
typedef struct file_data
 
22
{
 
23
  char *name;
 
24
  int fd;
 
25
  struct stat sb;
 
26
  void *start;
 
27
  int map_size;
 
28
} FILE_DATA;
 
29
 
 
30
FILE_DATA files[MAX_FILES];
 
31
FILE_DATA new_files[MAX_FILES];
 
32
int num_files = 0;
 
33
int num_new_files = 0;
 
34
const char * config = "/etc/memlockd.cfg";
 
35
int debug = 0;
 
36
uid_t uid = 0;
 
37
gid_t gid = 0;
 
38
 
 
39
#define BUF_SIZE 1024
 
40
 
 
41
void log(int priority, const char * const format, ...)
 
42
{
 
43
  va_list argp;
 
44
  va_start(argp, format);
 
45
  if(debug)
 
46
  {
 
47
    vfprintf(stderr, format, argp);
 
48
    fprintf(stderr, "\n");
 
49
  }
 
50
  else
 
51
    vsyslog(priority, format, argp);
 
52
}
 
53
 
 
54
void unmap_file(FILE_DATA *data)
 
55
{
 
56
  munmap(data->start, data->sb.st_size);
 
57
  log(LOG_INFO, "Unmapped file %s", data->name);
 
58
}
 
59
 
 
60
void unmap_close_file(FILE_DATA *data)
 
61
{
 
62
  unmap_file(data);
 
63
  free(data->name);
 
64
  data->name = NULL;
 
65
  close(data->fd);
 
66
  data->fd = -1;
 
67
}
 
68
 
 
69
// return 1 if a file is mapped
 
70
int open_map(int fd, struct stat *sb, const char * const name)
 
71
{
 
72
  new_files[num_new_files].start = mmap(NULL, sb->st_size, PROT_READ, MAP_SHARED, fd, 0);
 
73
  if(new_files[num_new_files].start == MAP_FAILED)
 
74
  {
 
75
    log(LOG_ERR, "Error mmaping %s: %s", name, strerror(errno));
 
76
    close(fd);
 
77
    return 0;
 
78
  }
 
79
  if(mlock(new_files[num_new_files].start, sb->st_size) == -1)
 
80
  {
 
81
    log(LOG_ERR, "Can't lock memory for %s, error %s", name, strerror(errno));
 
82
    munmap(new_files[num_new_files].start, sb->st_size);
 
83
    close(fd);
 
84
    return 0;
 
85
  }
 
86
  if(sb->st_size % PAGE_SIZE)
 
87
    new_files[num_new_files].map_size = sb->st_size - (sb->st_size % PAGE_SIZE)
 
88
                                      + PAGE_SIZE;
 
89
  else
 
90
    new_files[num_new_files].map_size = sb->st_size;
 
91
  new_files[num_new_files].fd = fd;
 
92
  memcpy(&new_files[num_new_files].sb, sb, sizeof(struct stat));
 
93
  new_files[num_new_files].name = strdup(name);
 
94
  num_new_files++;
 
95
  log(LOG_INFO, "Mapped file %s", name);
 
96
  return 1;
 
97
}
 
98
 
 
99
int open_file(const char * const name)
 
100
{
 
101
  int fd = open(name, O_RDONLY);
 
102
  if(fd == -1)
 
103
  {
 
104
    log(LOG_ERR, "Can't open file %s", name);
 
105
    return 0;
 
106
  }
 
107
  struct stat sb;
 
108
  if(fstat(fd, &sb) == -1)
 
109
  {
 
110
    log(LOG_ERR, "Can't stat file %s", name);
 
111
    close(fd);
 
112
    return 0;
 
113
  }
 
114
  int i;
 
115
  for(i = 0; i < num_files; i++)
 
116
  {
 
117
    if(files[i].fd != -1 && files[i].sb.st_dev == sb.st_dev
 
118
      && files[i].sb.st_ino == sb.st_ino)
 
119
    {
 
120
      if(files[i].sb.st_size == sb.st_size
 
121
       && files[i].sb.st_mtime == sb.st_mtime)
 
122
      {
 
123
        memcpy(&new_files[num_new_files], &files[i], sizeof(FILE_DATA));
 
124
        files[i].fd = -1;
 
125
        files[i].name = NULL;
 
126
        num_new_files++;
 
127
        return 1;
 
128
      }
 
129
      else
 
130
      {
 
131
        memcpy(&new_files[num_new_files], &files[i], sizeof(FILE_DATA));
 
132
        close(fd);
 
133
        num_new_files++;
 
134
        files[i].fd = -1;
 
135
        files[i].name = NULL;
 
136
        unmap_file(&new_files[num_new_files - 1]);
 
137
        open_map(new_files[num_new_files - 1].fd
 
138
               , &new_files[num_new_files - 1].sb, name);
 
139
        return 1;
 
140
      }
 
141
    }
 
142
  }
 
143
  for(i = 0; i < num_new_files; i++)
 
144
  {
 
145
    if(new_files[i].fd != -1 && new_files[i].sb.st_ino == sb.st_ino)
 
146
    {
 
147
      close(fd);
 
148
      return 0;
 
149
    }
 
150
  }
 
151
  return open_map(fd, &sb, name);
 
152
}
 
153
 
 
154
void map_file_dependencies(const char * const name)
 
155
{
 
156
  if(!uid || !gid)
 
157
    return;
 
158
  int pipe_fd[2];
 
159
  
 
160
  if(pipe(pipe_fd) == -1)
 
161
  {
 
162
    log(LOG_ERR, "Can't create pipe, not recursing");
 
163
    uid = 0;
 
164
    return;
 
165
  }
 
166
  int rc = fork();
 
167
  if(rc == -1)
 
168
  {
 
169
    log(LOG_ERR, "Can't fork, not recursing");
 
170
    uid = 0;
 
171
    return;
 
172
  }
 
173
  if(!rc)
 
174
  {
 
175
    char buf[4096];
 
176
 
 
177
    close(pipe_fd[0]);
 
178
    close(1);
 
179
    if(dup2(pipe_fd[1], 1) == -1)
 
180
    {
 
181
      log(LOG_ERR, "Can't create pipe");
 
182
      exit(1);
 
183
    }
 
184
    if(setresgid(gid, gid, gid) == -1 || setresuid(uid, uid, uid) == -1)
 
185
    {
 
186
      log(LOG_ERR, "Can't set UID and GID");
 
187
      exit(1);
 
188
    }
 
189
    sprintf(buf, "/usr/bin/ldd %s", name);
 
190
    char *argv[3];
 
191
    argv[0] = strdup("/usr/bin/ldd");
 
192
    argv[1] = strdup(name);
 
193
    argv[2] = NULL;
 
194
    execv(argv[0], (char * const *)argv);
 
195
    log(LOG_ERR, "Can't exec ldd");
 
196
    exit(1);
 
197
  }
 
198
  close(pipe_fd[1]);
 
199
  FILE *fp = fdopen(pipe_fd[0], "r");
 
200
  if(!fp)
 
201
    return;
 
202
 
 
203
  char buf[4096];
 
204
  while(fgets(buf, sizeof(buf), fp))
 
205
  {
 
206
    char *tmp = strchr(buf, '/');
 
207
    if(!tmp)
 
208
      continue;
 
209
    strtok(tmp, " ");
 
210
    open_file(tmp);
 
211
  }
 
212
  fclose(fp);
 
213
  wait(&rc);
 
214
}
 
215
 
 
216
void parse_config(int)
 
217
{
 
218
  FILE *fp = fopen(config, "r");
 
219
  if(!fp)
 
220
  {
 
221
    log(LOG_ERR, "Can't open config file %s", config);
 
222
    exit(1);
 
223
  }
 
224
  num_new_files = 0;
 
225
  char buf[BUF_SIZE];
 
226
  while(fgets(buf, BUF_SIZE, fp))
 
227
  {
 
228
    int len = strlen(buf) - 1;
 
229
    if(buf[0] == '#')
 
230
      continue;
 
231
    if(buf[len] == '\n')
 
232
      buf[len] = 0;
 
233
    const char *ptr = buf;
 
234
    int map_dependencies = 0;
 
235
    if(*ptr == '+')
 
236
    {
 
237
       ptr++;
 
238
       map_dependencies = 1;
 
239
    }
 
240
    if(*ptr != '/')
 
241
      continue;
 
242
    open_file(ptr);
 
243
    if(map_dependencies)
 
244
      map_file_dependencies(ptr);
 
245
  }
 
246
  fclose(fp);
 
247
  for(int i = 0; i < num_files; i++)
 
248
    if(files[i].fd != -1)
 
249
      unmap_close_file(&files[i]);
 
250
  if(!num_new_files)
 
251
  {
 
252
    log(LOG_INFO, "No files to lock - exiting");
 
253
    exit(0);
 
254
  }
 
255
  memcpy(files, new_files, sizeof(FILE_DATA) * num_new_files);
 
256
  num_files = num_new_files;
 
257
  num_new_files = 0;
 
258
}
 
259
 
 
260
void usage()
 
261
{
 
262
  fprintf(stderr, "Usage: memlockd [-c config-file] [-d]\n"
 
263
                  "       -d is for debugging mode (running in foreground)\n");
 
264
  exit(1);
 
265
}
 
266
int main(int argc, char **argv)
 
267
{
 
268
  int c;
 
269
  pid_t old_pid = 0;
 
270
  while(-1 != (c = getopt(argc, argv, "dc:u:")) )
 
271
  {
 
272
    switch(char(c))
 
273
    {
 
274
      case '?':
 
275
      case ':':
 
276
        usage();
 
277
      break;
 
278
      case 'c':
 
279
        config = optarg;
 
280
      break;
 
281
      case 'd':
 
282
        debug = 1;
 
283
      break;
 
284
      case 'u':
 
285
        struct passwd *pw = getpwnam(optarg);
 
286
        if(!pw)
 
287
        {
 
288
          log(LOG_ERR, "Can't look up user %s", optarg);
 
289
          exit(1);
 
290
        }
 
291
        uid = pw->pw_uid;
 
292
        gid = pw->pw_gid;
 
293
        endpwent();
 
294
      break;
 
295
    }
 
296
  }
 
297
 
 
298
  openlog("memlockd", LOG_CONS, LOG_DAEMON);
 
299
 
 
300
  int write_pidfile = 1;
 
301
  if(debug || getuid())
 
302
    write_pidfile = 0;
 
303
 
 
304
  if(!debug)
 
305
    daemon(0, 0);
 
306
  if(write_pidfile)
 
307
  {
 
308
    FILE *fp = fopen(PIDFILE, "r");
 
309
    char buf[20];
 
310
    if(fp)
 
311
    {
 
312
      if(fgets(buf, sizeof(buf), fp))
 
313
        old_pid = atoi(buf);
 
314
      else
 
315
        log(LOG_ERR, "Can't read pidfile " PIDFILE);
 
316
      fclose(fp);
 
317
    }
 
318
  }
 
319
 
 
320
  if(mlockall(MCL_CURRENT|MCL_FUTURE) == -1)
 
321
  {
 
322
    log(LOG_ERR, "Can't lock memory, exiting");
 
323
    exit(1);
 
324
  }
 
325
  parse_config(0);
 
326
 
 
327
  struct sigaction sa;
 
328
  sa.sa_sigaction = NULL;
 
329
  sa.sa_flags = SA_SIGINFO;
 
330
  sa.sa_handler = parse_config;
 
331
  if(sigaction(SIGHUP, &sa, NULL))
 
332
    log(LOG_ERR, "Can't handle sighup");
 
333
  if(!debug)
 
334
  {
 
335
    FILE *fp = fopen(PIDFILE, "w");
 
336
    if(fp)
 
337
    {
 
338
      if(fprintf(fp, "%d", (int)getpid()) <= 0)
 
339
      {
 
340
        log(LOG_ERR, "Can't write to " PIDFILE);
 
341
        unlink(PIDFILE);
 
342
      }
 
343
      fclose(fp);
 
344
    }
 
345
    else
 
346
      log(LOG_ERR, "Can't open " PIDFILE " for writing");
 
347
  }
 
348
  if(old_pid)
 
349
    kill(old_pid, SIGKILL);
 
350
  while(1)
 
351
    sleep(3600);
 
352
  return 0;
 
353
}