aboutsummaryrefslogtreecommitdiff
path: root/dircond.c
diff options
context:
space:
mode:
Diffstat (limited to 'dircond.c')
-rw-r--r--dircond.c1062
1 files changed, 1062 insertions, 0 deletions
diff --git a/dircond.c b/dircond.c
new file mode 100644
index 0000000..682e1c3
--- /dev/null
+++ b/dircond.c
@@ -0,0 +1,1062 @@
1#include <stdio.h>
2#include <stdlib.h>
3#include <stdarg.h>
4#include <fcntl.h>
5#include <syslog.h>
6#include <unistd.h>
7#include <getopt.h>
8#include <string.h>
9#include <errno.h>
10#include <pwd.h>
11#include <signal.h>
12#include <time.h>
13#include <sys/inotify.h>
14#include <sys/wait.h>
15#include <sys/stat.h>
16
17/* Configuration settings */
18const char *program_name; /* This program name */
19int foreground; /* Remain in the foreground */
20int facility = -1; /* Use this syslog facility for logging.
21 -1 means log to stderr */
22int debug_level; /* Debug verbosity level */
23unsigned handler_timeout = 5; /* Timeout for handler program (seconds) */
24int autowatch; /* Automatically add directories created
25 under watchpoints to the watcher. If set
26 to -1, nesting level is not limited. If
27 set to a positive value, this value limits
28 the nesting depth. */
29
30/* Event codes */
31enum {
32 evt_create, /* file has been created */
33 evt_delete, /* file has been deleted */
34 evt_close, /* file has been modified and closed */
35 evt_max /* number of handled events */
36};
37
38/* Handler flags. */
39#define HF_NOWAIT 0x01 /* Don't wait for termination */
40#define HF_STDOUT 0x02 /* Capture stdout */
41#define HF_STDERR 0x04 /* Capture stderr */
42
43/* Handler structure */
44struct handler {
45 int flags; /* Handler flags */
46 const char *prog; /* Handler program (no arguments allowed) */
47};
48
49/* Array of handlers for each event */
50struct handler handler[evt_max];
51
52/* Process list */
53
54/* Redirector codes */
55#define REDIR_OUT 0
56#define REDIR_ERR 1
57
58/* A running process is described by this structure */
59struct process {
60 struct process *next, *prev;
61 int master; /* Master process or redirector */
62 pid_t pid; /* PID */
63 time_t start; /* Time when the process started */
64 pid_t redir[2]; /* If master==1, holds PIDs of redirector
65 processes (0 if no redirector) */
66};
67
68/* List of running processes */
69struct process *proc_list;
70/* List of available process slots */
71struct process *proc_avail;
72/* Declare functions for handling process lists */
73#define LIST process
74#define LIST_PUSH proc_push
75#define LIST_POP proc_pop
76#define LIST_UNLINK proc_unlink
77#include "dlist.c"
78
79/* Diagnostic functions */
80const char *
81severity(int prio)
82{
83 switch (prio) {
84 case LOG_EMERG:
85 return "EMERG";
86 case LOG_ALERT:
87 return "ALERT";
88 case LOG_CRIT:
89 return "CRIT";
90 case LOG_ERR:
91 return "ERROR";
92 case LOG_WARNING:
93 return "WARNING";
94 case LOG_NOTICE:
95 return "NOTICE";
96 case LOG_INFO:
97 return "INFO";
98 case LOG_DEBUG:
99 return "DEBUG";
100 }
101 return NULL;
102}
103
104void
105vdiag(int prio, const char *fmt, va_list ap)
106{
107 const char *s;
108
109 if (facility <= 0) {
110 fprintf(stderr, "%s: ", program_name);
111 s = severity(prio);
112 if (s)
113 fprintf(stderr, "[%s] ", s);
114 vfprintf(stderr, fmt, ap);
115 fputc('\n', stderr);
116 } else {
117 vsyslog(prio, fmt, ap);
118 }
119}
120
121void
122diag(int prio, const char *fmt, ...)
123{
124 va_list ap;
125
126 va_start(ap, fmt);
127 vdiag(prio, fmt, ap);
128 va_end(ap);
129}
130
131static void
132debugprt(const char *fmt, ...)
133{
134 va_list ap;
135
136 va_start(ap, fmt);
137 vdiag(LOG_DEBUG, fmt, ap);
138 va_end(ap);
139}
140
141#define debug(l, c) do { if (debug_level>=(l)) debugprt c; } while(0)
142
143/* Command line processing and auxiliary functions */
144
145static void
146set_program_name(const char *arg)
147{
148 char *p = strrchr(arg, '/');
149 if (p)
150 program_name = p + 1;
151 else
152 program_name = arg;
153}
154
155static int
156read_facility(const char *arg)
157{
158 static struct transtab { int f; char *s; } ftab[] = {
159 { LOG_AUTH, "auth" },
160 { LOG_AUTHPRIV, "authpriv" },
161 { LOG_CRON, "cron" },
162 { LOG_DAEMON, "daemon" },
163 { LOG_FTP, "ftp" },
164 { LOG_LOCAL0, "local0" },
165 { LOG_LOCAL1, "local1" },
166 { LOG_LOCAL2, "local2" },
167 { LOG_LOCAL3, "local3" },
168 { LOG_LOCAL4, "local4" },
169 { LOG_LOCAL5, "local5" },
170 { LOG_LOCAL6, "local6" },
171 { LOG_LOCAL7, "local7" },
172 { LOG_LPR, "lpr" },
173 { LOG_MAIL, "mail" },
174 { LOG_NEWS, "news" },
175 { LOG_USER, "user" },
176 { LOG_UUCP, "uucp" },
177 { 0, NULL }
178 };
179 struct transtab *p;
180 char *s;
181 unsigned long n;
182
183 for (p = ftab; p->s; p++) {
184 if (strcmp(p->s, arg) == 0)
185 return p->f;
186 }
187 n = strtoul(arg, &s, 10);
188 if (*s) {
189 diag(LOG_CRIT, "unknown facility: %s", arg);
190 exit(1);
191 }
192 if (n > 256) {
193 diag(LOG_CRIT, "facility out of range: %s", arg);
194 exit(1);
195 }
196 return n;
197}
198
199void
200set_handler(const char *arg)
201{
202 int len;
203 int n = -1;
204
205 /* Event code */
206 len = strcspn(arg,",");
207 if (strncmp(arg, "create", len) == 0)
208 n = evt_create;
209 else if (strncmp(arg, "delete", len) == 0)
210 n = evt_delete;
211 else if (strncmp(arg, "close", len) == 0)
212 n = evt_close;
213 else {
214 diag(LOG_CRIT, "unrecognized event: %*.*s", len, len, arg);
215 exit(1);
216 }
217
218 /* flag */
219 handler[n].flags = 0;
220
221 for (arg += len; *arg == ','; arg += len) {
222 ++arg;
223 len = strcspn(arg, ",");
224 if (arg[len] == 0)
225 break;
226 if (strncmp(arg, "wait", len) == 0)
227 handler[n].flags &= ~HF_NOWAIT;
228 else if (strncmp(arg, "nowait", len) == 0)
229 handler[n].flags |= HF_NOWAIT;
230 else if (strncmp(arg, "stdout", len) == 0)
231 handler[n].flags |= HF_STDOUT;
232 else if (strncmp(arg, "stderr", len) == 0)
233 handler[n].flags |= HF_STDERR;
234 else {
235 diag(LOG_CRIT, "unknown flag %*.*s", len, len, arg);
236 exit(1);
237 }
238 }
239
240 if (*arg == 0) {
241 diag(LOG_CRIT, "bad handler specification: %s", arg);
242 exit(1);
243 }
244 handler[n].prog = arg;
245}
246
247/* Memory allocation with error checking */
248void *
249emalloc(size_t size)
250{
251 void *p = malloc(size);
252 if (!p) {