This source file includes following definitions.
- temp_file
- file_size
- username
- xputenv
- setup_env
- run_job
- xwrite
- xwait
- launch_mailer
- tend_mailer
- launch_job
- tend_job
- tend_children
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25 #include <errno.h>
26 #include <unistd.h>
27 #include <stdlib.h>
28 #include <sys/stat.h>
29 #include <pwd.h>
30 #include <sys/types.h>
31 #include <sys/wait.h>
32 #include <fcntl.h>
33 #include <signal.h>
34 #include <stdio.h>
35 #include <string.h>
36 #include <limits.h>
37 #include "global.h"
38
39 #include <langinfo.h>
40
41 static int
42 temp_file(job_rec *jr)
43
44 {
45 char *dir;
46 char template[PATH_MAX+1];
47 int fdin = -1;
48 int fdout;
49 int len;
50
51 dir = getenv("TMPDIR");
52 if (dir == NULL || *dir == '\0')
53 dir = P_tmpdir;
54
55 len = snprintf(template, sizeof(template), "%s/$anacronXXXXXX", dir);
56 if (len >= sizeof(template))
57 die_e("TMPDIR too long");
58
59 fdout = mkstemp(template);
60 if (fdout == -1) die_e("Can't open temporary file for writing");
61
62 fdin = open(template, O_RDONLY, S_IRUSR | S_IWUSR);
63 if (fdin == -1) die_e("Can't open temporary file for reading");
64
65 if (unlink(template)) die_e("Can't unlink temporary file");
66
67 fcntl(fdout, F_SETFD, FD_CLOEXEC);
68 fcntl(fdin, F_SETFD, FD_CLOEXEC);
69
70 jr->input_fd = fdin;
71 jr->output_fd = fdout;
72
73 return fdout;
74 }
75
76 static off_t
77 file_size(int fd)
78
79 {
80 struct stat st;
81
82 if (fstat(fd, &st)) die_e("Can't fstat temporary file");
83 return st.st_size;
84 }
85
86 static char *
87 username(void)
88 {
89 struct passwd *ps;
90 static char *user;
91
92 if (user)
93 return user;
94
95 ps = getpwuid(geteuid());
96 if (ps == NULL || ps->pw_name == NULL) die_e("getpwuid() error");
97
98 user = strdup(ps->pw_name);
99 if (user == NULL) die_e("memory allocation error");
100
101 return user;
102 }
103
104 static void
105 xputenv(const char *s)
106 {
107 char *name = NULL, *val = NULL;
108 char *eq_ptr;
109 const char *errmsg;
110 size_t eq_index;
111
112 if (s == NULL) {
113 die_e("Invalid environment string");
114 }
115
116 eq_ptr = strchr(s, '=');
117 if (eq_ptr == NULL) {
118 die_e("Invalid environment string");
119 }
120
121 eq_index = (size_t) (eq_ptr - s);
122
123 name = malloc((eq_index + 1) * sizeof(char));
124 if (name == NULL) {
125 die_e("Not enough memory to set the environment");
126 }
127
128 val = malloc((strlen(s) - eq_index) * sizeof(char));
129 if (val == NULL) {
130 die_e("Not enough memory to set the environment");
131 }
132
133 strncpy(name, s, eq_index);
134 name[eq_index] = '\0';
135 strcpy(val, s + eq_index + 1);
136
137 if (setenv(name, val, 1)) {
138 die_e("Can't set the environment");
139 }
140
141 free(name);
142 free(val);
143 return;
144
145 }
146
147 static void
148 setup_env(const job_rec *jr)
149
150 {
151 env_rec *er;
152
153 er = first_env_rec;
154 if (er == NULL || jr->prev_env_rec == NULL) return;
155 xputenv(er->assign);
156 while (er != jr->prev_env_rec)
157 {
158 er = er->next;
159 xputenv(er->assign);
160 }
161 }
162
163 static void
164 run_job(const job_rec *jr)
165
166 {
167
168 xclose(1);
169 xclose(2);
170 if (dup2(jr->output_fd, 1) != 1 || dup2(jr->output_fd, 2) != 2)
171 die_e("dup2() error");
172 in_background = 0;
173 if (chdir("/")) die_e("Can't chdir to '/'");
174
175 if (sigprocmask(SIG_SETMASK, &old_sigmask, NULL))
176 die_e("sigprocmask error");
177 xcloselog();
178 execl("/bin/sh", "/bin/sh", "-c", jr->command, (char *)NULL);
179 die_e("execl() error");
180 }
181
182 static void
183 xwrite(int fd, const char *string)
184
185
186 {
187 if (write(fd, string, strlen(string)) == -1)
188 die_e("Can't write to temporary file");
189 }
190
191 static int
192 xwait(pid_t pid , int *status)
193
194
195
196 {
197 pid_t r;
198
199 r = waitpid(pid, status, WNOHANG);
200 if (r == -1) die_e("waitpid() error");
201 if (r == 0) return 0;
202 return 1;
203 }
204
205 static void
206 launch_mailer(job_rec *jr)
207 {
208 pid_t pid;
209 struct stat buf;
210
211 if (jr->mailto == NULL)
212 {
213 explain("Empty MAILTO set, not mailing output");
214 return;
215 }
216
217
218 if(stat(SENDMAIL, &buf))
219 {
220 complain("Can't find sendmail at %s, not mailing output", SENDMAIL);
221 return;
222 }
223
224 pid = xfork();
225 if (pid == 0)
226 {
227
228 in_background = 1;
229
230 xclose(STDIN_FILENO);
231 if (dup2(jr->input_fd, STDIN_FILENO) != 0) die_e("Can't dup2()");
232 if (lseek(STDIN_FILENO, 0, SEEK_SET) != 0) die_e("Can't lseek()");
233 if (sigprocmask(SIG_SETMASK, &old_sigmask, NULL))
234 die_e("sigprocmask error");
235 xcloselog();
236
237
238 xclose(STDOUT_FILENO); xopen(STDOUT_FILENO, "/dev/null", O_WRONLY);
239 xclose(STDERR_FILENO); xopen(STDERR_FILENO, "/dev/null", O_WRONLY);
240 xclose(jr->output_fd);
241
242
243
244
245
246
247
248
249
250 execl(SENDMAIL, SENDMAIL, "-FAnacron", "-odi",
251 jr->mailto, (char *)NULL);
252 die_e("Can't exec " SENDMAIL);
253 }
254
255
256 jr->mailer_pid = pid;
257 running_mailers++;
258 }
259
260 static void
261 tend_mailer(job_rec *jr, int status)
262 {
263 if (WIFEXITED(status) && WEXITSTATUS(status) != 0)
264 complain("Tried to mail output of job `%s', "
265 "but mailer process (" SENDMAIL ") exited with status %d",
266 jr->ident, WEXITSTATUS(status));
267 else if (!WIFEXITED(status) && WIFSIGNALED(status))
268 complain("Tried to mail output of job `%s', "
269 "but mailer process (" SENDMAIL ") got signal %d",
270 jr->ident, WTERMSIG(status));
271 else if (!WIFEXITED(status) && !WIFSIGNALED(status))
272 complain("Tried to mail output of job `%s', "
273 "but mailer process (" SENDMAIL ") terminated abnormally"
274 , jr->ident);
275
276 jr->mailer_pid = 0;
277 running_mailers--;
278 }
279
280 void
281 launch_job(job_rec *jr)
282 {
283 pid_t pid;
284 int fd;
285 char hostname[512];
286 char *mailto;
287 char *mailfrom;
288
289
290 if (gethostname(hostname, 512)) {
291 strcpy (hostname,"unknown machine");
292 }
293
294 setup_env(jr);
295
296
297 mailto = getenv("MAILTO");
298
299 if (mailto == NULL)
300 mailto = username();
301
302
303 mailfrom = getenv("MAILFROM");
304 if (mailfrom == NULL)
305 mailfrom = username();
306
307
308 temp_file(jr); fd = jr->output_fd;
309
310 xwrite(fd, "From: ");
311 xwrite(fd, "Anacron <");
312 xwrite(fd, mailfrom);
313 xwrite(fd, ">\n");
314 xwrite(fd, "To: ");
315 xwrite(fd, mailto);
316 xwrite(fd, "\n");
317 xwrite(fd, "MIME-Version: 1.0\n");
318 xwrite(fd, "Content-Type: text/plain; charset=\"");
319 xwrite(fd, nl_langinfo(CODESET));
320 xwrite(fd, "\"\n");
321 xwrite(fd, "Subject: Anacron job '");
322 xwrite(fd, jr->ident);
323 xwrite(fd, "' on ");
324 xwrite(fd, hostname);
325 xwrite(fd, "\n\n");
326
327 if (*mailto == '\0')
328 jr->mailto = NULL;
329 else
330
331 jr->mailto = mailto;
332
333 jr->mail_header_size = file_size(fd);
334
335 pid = xfork();
336 if (pid == 0)
337 {
338
339 in_background = 1;
340 run_job(jr);
341
342 }
343
344 explain("Job `%s' started", jr->ident);
345 jr->job_pid = pid;
346 running_jobs++;
347 }
348
349 static void
350 tend_job(job_rec *jr, int status)
351
352 {
353 int mail_output;
354 const char *m;
355
356 update_timestamp(jr);
357 unlock(jr);
358 if (file_size(jr->output_fd) > jr->mail_header_size) mail_output = 1;
359 else mail_output = 0;
360
361 m = mail_output ? " (produced output)" : "";
362 if (WIFEXITED(status) && WEXITSTATUS(status) == 0)
363 explain("Job `%s' terminated%s", jr->ident, m);
364 else if (WIFEXITED(status))
365 explain("Job `%s' terminated (exit status: %d)%s",
366 jr->ident, WEXITSTATUS(status), m);
367 else if (WIFSIGNALED(status))
368 complain("Job `%s' terminated due to signal %d%s",
369 jr->ident, WTERMSIG(status), m);
370 else
371 complain("Job `%s' terminated abnormally%s", jr->ident, m);
372
373 jr->job_pid = 0;
374 running_jobs--;
375 if (mail_output) launch_mailer(jr);
376 xclose(jr->output_fd);
377 xclose(jr->input_fd);
378 }
379
380 void
381 tend_children(void)
382
383
384
385 {
386 int j;
387 int status;
388
389 j = 0;
390 while (j < njobs)
391 {
392 if (job_array[j]->mailer_pid != 0 &&
393 xwait(job_array[j]->mailer_pid, &status))
394 tend_mailer(job_array[j], status);
395 if (job_array[j]->job_pid != 0 &&
396 xwait(job_array[j]->job_pid, &status))
397 tend_job(job_array[j], status);
398 j++;
399 }
400 }