diff options
Diffstat (limited to 'dircond.c')
-rw-r--r-- | dircond.c | 1062 |
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 */ | ||
18 | const char *program_name; /* This program name */ | ||
19 | int foreground; /* Remain in the foreground */ | ||
20 | int facility = -1; /* Use this syslog facility for logging. | ||
21 | -1 means log to stderr */ | ||
22 | int debug_level; /* Debug verbosity level */ | ||
23 | unsigned handler_timeout = 5; /* Timeout for handler program (seconds) */ | ||
24 | int 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 */ | ||
31 | enum { | ||
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 */ | ||
44 | struct handler { | ||
45 | int flags; /* Handler flags */ | ||
46 | const char *prog; /* Handler program (no arguments allowed) */ | ||
47 | }; | ||
48 | |||
49 | /* Array of handlers for each event */ | ||
50 | struct 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 */ | ||
59 | struct 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 */ | ||
69 | struct process *proc_list; | ||
70 | /* List of available process slots */ | ||
71 | struct 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 */ | ||
80 | const char * | ||
81 | severity(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 | |||
104 | void | ||
105 | vdiag(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 | |||
121 | void | ||
122 | diag(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 | |||
131 | static void | ||
132 | debugprt(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 | |||
145 | static void | ||
146 | set_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 | |||
155 | static int | ||
156 | read_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 | |||
199 | void | ||
200 | set_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 */ | ||
248 | void * | ||
249 | emalloc(size_t size) | ||
250 | { | ||
251 | void *p = malloc(size); | ||
252 | if (!p) { | ||