1 /* direvent - directory content watcher daemon
2 Copyright (C) 2012-2016 Sergey Poznyakoff
3
4 Direvent is free software; you can redistribute it and/or modify it
5 under the terms of the GNU General Public License as published by the
6 Free Software Foundation; either version 3 of the License, or (at your
7 option) any later version.
8
9 Direvent is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License along
15 with direvent. If not, see <http://www.gnu.org/licenses/>. */
16
17 #include "direvent.h"
18 #include <time.h>
19 #include <pwd.h>
20 #include <grp.h>
21 #include <signal.h>
22 #include <sys/wait.h>
23 #include "wordsplit.h"
24
25 /* Process list */
26
27 /* Redirector codes */
28 #define REDIR_OUT 0
29 #define REDIR_ERR 1
30
31 #define PROC_HANDLER 0
32 #define PROC_REDIR 1
33
34 /* A running process is described by this structure */
35 struct process {
36 struct process *next, *prev;
37 int type; /* Process type */
38 unsigned timeout; /* Timeout in seconds */
39 pid_t pid; /* PID */
40 time_t start; /* Time when the process started */
41 union {
42 struct process *redir[2];
43 /* Pointers to the redirector processes, if
44 type == PROC_HANDLER (NULL if no redirector) */
45 struct process *master;
46 /* Master process, if type == PROC_REDIR */
47 } v;
48 };
49
50 /* List of running processes */
51 struct process *proc_list;
52 /* List of available process slots */
53 struct process *proc_avail;
54
55 /* Declare functions for handling process lists */
56 struct process *
proc_unlink(struct process ** root,struct process * p)57 proc_unlink(struct process **root, struct process *p)
58 {
59 if (p->prev)
60 p->prev->next = p->next;
61 else
62 *root = p->next;
63 if (p->next)
64 p->next->prev = p->prev;
65 p->next = p->prev = NULL;
66 return p;
67 }
68
69 struct process *
proc_pop(struct process ** pp)70 proc_pop(struct process **pp)
71 {
72 if (*pp)
73 return proc_unlink(pp, *pp);
74 return NULL;
75 }
76
77 void
proc_push(struct process ** pp,struct process * p)78 proc_push(struct process **pp, struct process *p)
79 {
80 p->prev = NULL;
81 p->next = *pp;
82 if (*pp)
83 (*pp)->prev = p;
84 *pp = p;
85 }
86
87
88 /* Process list handling (high-level) */
89
90 struct process *
register_process(int type,pid_t pid,time_t t,unsigned timeout)91 register_process(int type, pid_t pid, time_t t, unsigned timeout)
92 {
93 struct process *p;
94
95 if (proc_avail)
96 p = proc_pop(&proc_avail);
97 else
98 p = emalloc(sizeof(*p));
99 memset(p, 0, sizeof(*p));
100 p->type = type;
101 p->timeout = timeout;
102 p->pid = pid;
103 p->start = t;
104 proc_push(&proc_list, p);
105 return p;
106 }
107
108 void
deregister_process(pid_t pid,time_t t)109 deregister_process(pid_t pid, time_t t)
110 {
111 struct process *p;
112
113 for (p = proc_list; p; p = p->next)
114 if (p->pid == pid) {
115 if (p->prev)
116 p->prev->next = p->next;
117 else
118 proc_list = p;
119 if (p->next)
120 p->next->prev = p->prev;
121 free(p);
122 break;
123 }
124 }
125
126 struct process *
process_lookup(pid_t pid)127 process_lookup(pid_t pid)
128 {
129 struct process *p;
130
131 for (p = proc_list; p; p = p->next)
132 if (p->pid == pid)
133 return p;
134 return NULL;
135 }
136
137 static void
print_status(pid_t pid,int status,sigset_t * mask)138 print_status(pid_t pid, int status, sigset_t *mask)
139 {
140 if (WIFEXITED(status)) {
141 if (WEXITSTATUS(status) == 0)
142 debug(1, (_("process %lu exited successfully"),
143 (unsigned long) pid));
144 else
145 diag(LOG_ERR, _("process %lu failed with status %d"),
146 (unsigned long) pid, WEXITSTATUS(status));
147 } else if (WIFSIGNALED(status)) {
148 int prio;
149
150 if (sigismember(mask, WTERMSIG(status)))
151 prio = LOG_DEBUG;
152 else
153 prio = LOG_ERR;
154
155 diag(prio, _("process %lu terminated on signal %d"),
156 (unsigned long) pid, WTERMSIG(status));
157 } else if (WIFSTOPPED(status))
158 diag(LOG_ERR, _("process %lu stopped on signal %d"),
159 (unsigned long) pid, WSTOPSIG(status));
160 #ifdef WCOREDUMP
161 else if (WCOREDUMP(status))
162 diag(LOG_ERR,
163 _("process %lu dumped core"), (unsigned long) pid);
164 #endif
165 else
166 diag(LOG_ERR,
167 _("process %lu terminated with unrecognized status"),
168 (unsigned long) pid);
169 }
170
171 void
process_cleanup(int expect_term)172 process_cleanup(int expect_term)
173 {
174 pid_t pid;
175 int status;
176
177 while ((pid = waitpid(-1, &status, WNOHANG)) > 0) {
178 sigset_t set;
179 sigemptyset(&set);
180
181 if (pid == self_test_pid) {
182 sigaddset(&set, SIGHUP);
183 print_status(pid, status, &set);
184
185 if (WIFEXITED(status))
186 exit_code = WEXITSTATUS(status);
187 else if (WIFSIGNALED(status)) {
188 if (WTERMSIG(status) == SIGHUP)
189 exit_code = 0;
190 else
191 exit_code = 2;
192 } else
193 exit_code = 2;
194 stop = 1;
195 } else {
196 struct process *p = process_lookup(pid);
197
198 if (expect_term)
199 sigaddset(&set, SIGTERM);
200 if (!p) {
201 sigaddset(&set, SIGTERM);
202 sigaddset(&set, SIGKILL);
203 }
204 print_status(pid, status, &set);
205 if (!p)
206 continue;
207
208 if (p->type == PROC_HANDLER) {
209 if (p->v.redir[REDIR_OUT])
210 p->v.redir[REDIR_OUT]->v.master = NULL;
211 if (p->v.redir[REDIR_ERR])
212 p->v.redir[REDIR_ERR]->v.master = NULL;
213 }
214 p->pid = 0;
215 proc_unlink(&proc_list, p);
216 proc_push(&proc_avail, p);
217 }
218 }
219 }
220
221 void
process_timeouts()222 process_timeouts()
223 {
224 struct process *p;
225 time_t now = time(NULL);
226 time_t alarm_time = 0, x;
227
228 debug(2, (_("begin scanning process list")));
229 for (p = proc_list; p; p = p->next) {
230 x = now - p->start;
231 if (x >= p->timeout) {
232 diag(LOG_ERR, _("process %lu timed out"),
233 (unsigned long) p->pid);
234 kill(p->pid, SIGKILL);
235 } else if (alarm_time == 0 ||
236 p->timeout - x < alarm_time)
237 alarm_time = p->timeout - x;
238 }
239
240 if (alarm_time) {
241 debug(2, (_("scheduling alarm in %lu seconds"),
242 (unsigned long) alarm_time));
243 alarm(alarm_time);
244 }
245 debug(2, ("end scanning process list"));
246 }
247
248 int
switchpriv(struct prog_handler * hp)249 switchpriv(struct prog_handler *hp)
250 {
251 if (hp->uid == 0 || hp->uid == getuid())
252 return 0;
253
254 if (setgroups(hp->gidc, hp->gidv) < 0) {
255 diag(LOG_CRIT, "setgroups: %s",
256 strerror(errno));
257 return 1;
258 }
259 if (setregid(hp->gidv[0], hp->gidv[0]) < 0) {
260 diag(LOG_CRIT, "setregid(%lu,%lu): %s",
261 (unsigned long) hp->gidv[0],
262 (unsigned long) hp->gidv[0],
263 strerror(errno));
264 return 1;
265 }
266 if (setreuid(hp->uid, hp->uid) < 0) {
267 diag(LOG_CRIT, "setreuid(%lu,%lu): %s",
268 (unsigned long) hp->uid,
269 (unsigned long) hp->uid,
270 strerror(errno));
271 return 1;
272 }
273 return 0;
274 }
275
276 typedef fd_set *bigfd_set;
277
278 #define BIGFD_SET_COUNT \
279 ((sysconf(_SC_OPEN_MAX) + FD_SETSIZE - 1) / FD_SETSIZE)
280
281 #define BIGFD_SET_ALLOC() \
282 ecalloc(BIGFD_SET_COUNT, sizeof(fd_set))
283
284 #define BIGFD_ZERO(fds) \
285 memset(fds, 0, sizeof(*bigfd_set) * BIGFD_SET_COUNT)
286 #define BIGFD_SET(n, fds) \
287 FD_SET((n) % FD_SETSIZE, (fds) + (n) / FD_SETSIZE)
288 #define BIGFD_ISSET(n, fds) \
289 FD_ISSET((n) % FD_SETSIZE, (fds) + (n) / FD_SETSIZE)
290
291 static void
close_fds(bigfd_set fdset)292 close_fds(bigfd_set fdset)
293 {
294 int i;
295
296 for (i = dup(0); i >= 0; i--) {
297 if (fdset && BIGFD_ISSET(i, fdset))
298 continue;
299 close(i);
300 }
301 }
302
303 /* Operations with handlers and redirections */
304
305 static void
redir_exit(int sig)306 redir_exit(int sig)
307 {
308 _exit(0);
309 }
310
311 int
open_redirector(const char * tag,int prio,struct process ** return_proc)312 open_redirector(const char *tag, int prio, struct process **return_proc)
313 {
314 int p[2];
315 FILE *fp;
316 char buf[512];
317 pid_t pid;
318 bigfd_set fdset;
319
320 if (pipe(p)) {
321 diag(LOG_ERR,
322 _("cannot start redirector for %s, pipe failed: %s"),
323 tag, strerror(errno));
324 return -1;
325 }
326 switch (pid = fork()) {
327 case 0:
328 /* Redirector process */
329 fdset = BIGFD_SET_ALLOC();
330 BIGFD_SET(p[0], fdset);
331 if (facility <= 0)
332 BIGFD_SET(2, fdset);
333 close_fds(fdset);
334
335 alarm(0);
336 signal_setup(redir_exit);
337
338 fp = fdopen(p[0], "r");
339 if (fp == NULL)
340 _exit(1);
341 if (facility > 0)
342 openlog(tag, LOG_PID, facility);
343
344 while (fgets(buf, sizeof(buf), fp) > 0) {
345 int len = strlen(buf);
346 if (len && buf[len-1] == '\n')
347 buf[len-1] = 0;
348 diag(prio, "%s", buf);
349 }
350 _exit(0);
351
352 case -1:
353 diag(LOG_CRIT,
354 _("cannot run redirector `%s': fork failed: %s"),
355 tag, strerror(errno));
356 return -1;
357
358 default:
359 debug(1, (_("redirector for %s started, pid=%lu"),
360 tag, (unsigned long) pid));
361 close(p[0]);
362 *return_proc = register_process(PROC_REDIR, pid,
363 time(NULL), 0);
364 return p[1];
365 }
366 }
367
368 static void
runcmd(const char * cmd,char ** envhint,event_mask * event,const char * file,int shell)369 runcmd(const char *cmd, char **envhint, event_mask *event, const char *file,
370 int shell)
371 {
372 char *kve[13];
373 char *p,*q;
374 char buf[1024];
375 int i = 0, j;
376 char **argv;
377 char *xargv[4];
378 struct wordsplit ws;
379
380 kve[i++] = "file";
381 kve[i++] = (char*) file;
382
383 snprintf(buf, sizeof buf, "%d", event->sys_mask);
384 kve[i++] = "sysev_code";
385 kve[i++] = estrdup(buf);
386
387 if (self_test_pid) {
388 snprintf(buf, sizeof buf, "%lu", (unsigned long)self_test_pid);
389 kve[i++] = "self_test_pid";
390 kve[i++] = estrdup(buf);
391 }
392
393 q = buf;
394 for (p = trans_tokfirst(sysev_transtab, event->sys_mask, &j); p;
395 p = trans_toknext(sysev_transtab, event->sys_mask, &j)) {
396 if (q > buf)
397 *q++ = ' ';
398 while (*p)
399 *q++ = *p++;
400 }
401 *q = 0;
402 if (q > buf) {
403 kve[i++] = "sysev_name";
404 kve[i++] = estrdup(buf);
405 }
406 p = trans_toktostr(genev_transtab, event->gen_mask);
407 if (p) {
408 snprintf(buf, sizeof buf, "%d", event->gen_mask);
409 kve[i++] = "genev_code";
410 kve[i++] = estrdup(buf);
411 kve[i++] = "genev_name";
412 kve[i++] = p;
413 }
414 kve[i++] = 0;
415
416 ws.ws_env = (const char **) kve;
417 if (wordsplit(cmd, &ws,
418 WRDSF_NOCMD | WRDSF_QUOTE
419 | WRDSF_SQUEEZE_DELIMS | WRDSF_CESCAPES
420 | WRDSF_ENV | WRDSF_ENV_KV
421 | (shell ? WRDSF_NOSPLIT : 0))) {
422 diag(LOG_CRIT, "wordsplit: %s",
423 wordsplit_strerror (&ws));
424 _exit(127);
425 }
426
427 if (shell) {
428 xargv[0] = "/bin/sh";
429 xargv[1] = "-c";
430 xargv[2] = ws.ws_wordv[0];
431 xargv[3] = NULL;
432 argv = xargv;
433 } else
434 argv = ws.ws_wordv;
435
436 execve(argv[0], argv, environ_setup(envhint, kve));
437
438 diag(LOG_ERR, "execve: %s \"%s\": %s", argv[0], cmd, strerror(errno));
439 _exit(127);
440 }
441
442 static int
prog_handler_run(struct watchpoint * wp,event_mask * event,const char * dirname,const char * file,void * data)443 prog_handler_run(struct watchpoint *wp, event_mask *event,
444 const char *dirname, const char *file, void *data)
445 {
446 pid_t pid;
447 int redir_fd[2] = { -1, -1 };
448 struct process *redir_proc[2] = { NULL, NULL };
449 struct process *p;
450 struct prog_handler *hp = data;
451
452 if (!hp->command)
453 return 0;
454
455 debug(1, (_("starting %s, dir=%s, file=%s"),
456 hp->command, dirname, file));
457 if (hp->flags & HF_STDERR)
458 redir_fd[REDIR_ERR] = open_redirector(hp->command, LOG_ERR,
459 &redir_proc[REDIR_ERR]);
460 if (hp->flags & HF_STDOUT)
461 redir_fd[REDIR_OUT] = open_redirector(hp->command, LOG_INFO,
462 &redir_proc[REDIR_OUT]);
463
464 pid = fork();
465 if (pid == -1) {
466 diag(LOG_ERR, "fork: %s", strerror(errno));
467 close(redir_fd[REDIR_OUT]);
468 close(redir_fd[REDIR_ERR]);
469 if (redir_proc[REDIR_OUT])
470 kill(redir_proc[REDIR_OUT]->pid, SIGKILL);
471 if (redir_proc[REDIR_ERR])
472 kill(redir_proc[REDIR_ERR]->pid, SIGKILL);
473 return -1;
474 }
475
476 if (pid == 0) {
477 /* child */
478 bigfd_set fdset = BIGFD_SET_ALLOC();
479
480 if (switchpriv(hp))
481 _exit(127);
482
483 if (chdir(dirname)) {
484 diag(LOG_CRIT, _("cannot change to %s: %s"),
485 dirname, strerror(errno));
486 _exit(127);
487 }
488
489 if (redir_fd[REDIR_OUT] != -1) {
490 if (redir_fd[REDIR_OUT] != 1 &&
491 dup2(redir_fd[REDIR_OUT], 1) == -1) {
492 diag(LOG_ERR, "dup2: %s", strerror(errno));
493 _exit(127);
494 }
495 BIGFD_SET(1, fdset);
496 }
497 if (redir_fd[REDIR_ERR] != -1) {
498 if (redir_fd[REDIR_ERR] != 2 &&
499 dup2(redir_fd[REDIR_ERR], 2) == -1) {
500 diag(LOG_ERR, "dup2: %s", strerror(errno));
501 _exit(127);
502 }
503 BIGFD_SET(2, fdset);
504 }
505 close_fds(fdset);
506 alarm(0);
507 signal_setup(SIG_DFL);
508 runcmd(hp->command, hp->env, event, file, hp->flags & HF_SHELL);
509 }
510
511 /* master */
512 debug(1, (_("%s running; dir=%s, file=%s, pid=%lu"),
513 hp->command, dirname, file, (unsigned long)pid));
514
515 p = register_process(PROC_HANDLER, pid, time(NULL), hp->timeout);
516
517 if (redir_proc[REDIR_OUT]) {
518 redir_proc[REDIR_OUT]->v.master = p;
519 redir_proc[REDIR_OUT]->timeout = hp->timeout;
520 }
521 if (redir_proc[REDIR_ERR]) {
522 redir_proc[REDIR_ERR]->v.master = p;
523 redir_proc[REDIR_ERR]->timeout = hp->timeout;
524 }
525 memcpy(p->v.redir, redir_proc, sizeof(p->v.redir));
526
527 close(redir_fd[REDIR_OUT]);
528 close(redir_fd[REDIR_ERR]);
529
530 if (hp->flags & HF_NOWAIT) {
531 return 0;
532 }
533
534 debug(1, (_("waiting for %s (%lu) to terminate"),
535 hp->command, (unsigned long)pid));
536 while (time(NULL) - p->start < 2 * p->timeout) {
537 sleep(1);
538 process_cleanup(1);
539 if (p->pid == 0)
540 break;
541 }
542 return 0;
543 }
544
545 static void
envfree(char ** env)546 envfree(char **env)
547 {
548 int i;
549
550 if (!env)
551 return;
552 for (i = 0; env[i]; i++)
553 free(env[i]);
554 free(env);
555 }
556
557 void
prog_handler_free(struct prog_handler * hp)558 prog_handler_free(struct prog_handler *hp)
559 {
560 free(hp->command);
561 free(hp->gidv);
562 envfree(hp->env);
563 }
564
565 static void
prog_handler_free_data(void * ptr)566 prog_handler_free_data(void *ptr)
567 {
568 prog_handler_free((struct prog_handler *)ptr);
569 }
570
571 struct handler *
prog_handler_alloc(event_mask ev_mask,filpatlist_t fpat,struct prog_handler * p)572 prog_handler_alloc(event_mask ev_mask, filpatlist_t fpat,
573 struct prog_handler *p)
574 {
575 struct handler *hp = handler_alloc(ev_mask);
576 struct prog_handler *mem;
577
578 hp->fnames = fpat;
579 hp->run = prog_handler_run;
580 hp->free = prog_handler_free_data;
581 mem = emalloc(sizeof(*mem));
582 *mem = *p;
583 hp->data = mem;
584 memset(p, 0, sizeof(*p));
585 return hp;
586 }
587
588 /* Reallocate environment of handler HP to accomodate COUNT more
589 entries (not bytes) plus a final NULL entry.
590
591 Return offset of the first unused entry.
592 */
593 size_t
prog_handler_envrealloc(struct prog_handler * hp,size_t count)594 prog_handler_envrealloc(struct prog_handler *hp, size_t count)
595 {
596 size_t i;
597
598 if (!hp->env) {
599 hp->env = ecalloc(count + 1, sizeof(hp->env[0]));
600 i = 0;
601 } else {
602 for (i = 0; hp->env[i]; i++)
603 ;
604 hp->env = erealloc(hp->env,
605 (i + count + 1) * sizeof(hp->env[0]));
606 memset(hp->env + i, 0, (count + 1) * sizeof(hp->env[0]));
607 }
608 return i;
609 }
610
611
612
613
614
615