ctm_smail.c (18120) | ctm_smail.c (19983) |
---|---|
1/* 2 * Send a compressed CTM delta to a recipient mailing list by encoding it | 1/* 2 * Send a compressed CTM delta to a recipient mailing list by encoding it |
3 * in safe ASCII characters, in mailer-friendly chunks, and passing it 4 * to sendmail. The encoding is almost the same as MIME BASE64, and is 5 * protected by a simple checksum. | 3 * in safe ASCII characters, in mailer-friendly chunks, and passing them 4 * to sendmail. Optionally, the chunks can be queued to be sent later by 5 * ctm_dequeue in controlled bursts. The encoding is almost the same as 6 * MIME BASE64, and is protected by a simple checksum. |
6 * 7 * Author: Stephen McKay 8 * 9 * NOTICE: This is free software. I hope you get some use from this program. 10 * In return you should think about all the nice people who give away software. 11 * Maybe you should write some free software too. 12 * | 7 * 8 * Author: Stephen McKay 9 * 10 * NOTICE: This is free software. I hope you get some use from this program. 11 * In return you should think about all the nice people who give away software. 12 * Maybe you should write some free software too. 13 * |
13 * $Id: ctm_smail.c,v 1.7 1996/09/07 18:48:44 peter Exp $ | 14 * $Id: ctm_smail.c,v 1.8 1996/09/07 21:06:19 peter Exp $ |
14 */ 15 16#include <stdio.h> 17#include <stdlib.h> 18#include <string.h> 19#include <unistd.h> 20#include <fcntl.h> 21#include <sys/types.h> 22#include <sys/stat.h> 23#include <errno.h> 24#include <paths.h> | 15 */ 16 17#include <stdio.h> 18#include <stdlib.h> 19#include <string.h> 20#include <unistd.h> 21#include <fcntl.h> 22#include <sys/types.h> 23#include <sys/stat.h> 24#include <errno.h> 25#include <paths.h> |
26#include <limits.h> |
|
25#include "error.h" 26#include "options.h" 27 28#define DEF_MAX_MSG 64000 /* Default maximum mail msg minus headers. */ 29 | 27#include "error.h" 28#include "options.h" 29 30#define DEF_MAX_MSG 64000 /* Default maximum mail msg minus headers. */ 31 |
30#define LINE_LENGTH 76 /* Chars per encode line. Divisible by 4. */ | 32#define LINE_LENGTH 76 /* Chars per encoded line. Divisible by 4. */ |
31 | 33 |
32void chop_and_send(char *delta, off_t ctm_size, long max_msg_size, | 34int chop_and_send_or_queue(FILE *dfp, char *delta, off_t ctm_size, 35 long max_msg_size, char *mail_alias, char *queue_dir); 36int chop_and_send(FILE *dfp, char *delta, long msg_size, int npieces, |
33 char *mail_alias); | 37 char *mail_alias); |
34void chop_and_queue(char *delta, off_t ctm_size, long max_msg_size, 35 char *queue_dir, char *mail_alias); 36unsigned encode_body(FILE *sm_fp, FILE *delta_fp, long msg_size); | 38int chop_and_queue(FILE *dfp, char *delta, long msg_size, int npieces, 39 char *mail_alias, char *queue_dir); 40void clean_up_queue(char *queue_dir); 41int encode_body(FILE *sm_fp, FILE *delta_fp, long msg_size, unsigned *sum); |
37void write_header(FILE *sfp, char *mail_alias, char *delta, int pce, 38 int npieces); 39void write_trailer(FILE *sfp, unsigned sum); | 42void write_header(FILE *sfp, char *mail_alias, char *delta, int pce, 43 int npieces); 44void write_trailer(FILE *sfp, unsigned sum); |
40void apologise(char *delta, off_t ctm_size, long max_ctm_size, | 45int apologise(char *delta, off_t ctm_size, long max_ctm_size, |
41 char *mail_alias); 42FILE *open_sendmail(void); 43int close_sendmail(FILE *fp); | 46 char *mail_alias); 47FILE *open_sendmail(void); 48int close_sendmail(FILE *fp); |
44int lock_queuedir(char *queue_dir); 45void free_lock(int lockf, char *queue_dir); 46void add_to_queue(char *queue_dir, char *mail_alias, char *delta, int npieces, char **tempnames); | |
47 48int 49main(int argc, char **argv) 50 { | 49 50int 51main(int argc, char **argv) 52 { |
53 int status = 0; |
|
51 char *delta_file; 52 char *mail_alias; 53 long max_msg_size = DEF_MAX_MSG; 54 long max_ctm_size = 0; 55 char *log_file = NULL; 56 char *queue_dir = NULL; | 54 char *delta_file; 55 char *mail_alias; 56 long max_msg_size = DEF_MAX_MSG; 57 long max_ctm_size = 0; 58 char *log_file = NULL; 59 char *queue_dir = NULL; |
60 char *delta; 61 FILE *dfp; |
|
57 struct stat sb; 58 59 err_prog_name(argv[0]); 60 61 OPTIONS("[-l log] [-m maxmsgsize] [-c maxctmsize] [-q queuedir] ctm-delta mail-alias") 62 NUMBER('m', max_msg_size) 63 NUMBER('c', max_ctm_size) 64 STRING('l', log_file) --- 4 unchanged lines hidden (view full) --- 69 usage(); 70 71 if (log_file != NULL) 72 err_set_log(log_file); 73 74 delta_file = argv[1]; 75 mail_alias = argv[2]; 76 | 62 struct stat sb; 63 64 err_prog_name(argv[0]); 65 66 OPTIONS("[-l log] [-m maxmsgsize] [-c maxctmsize] [-q queuedir] ctm-delta mail-alias") 67 NUMBER('m', max_msg_size) 68 NUMBER('c', max_ctm_size) 69 STRING('l', log_file) --- 4 unchanged lines hidden (view full) --- 74 usage(); 75 76 if (log_file != NULL) 77 err_set_log(log_file); 78 79 delta_file = argv[1]; 80 mail_alias = argv[2]; 81 |
77 if (stat(delta_file, &sb) < 0) | 82 if ((delta = strrchr(delta_file, '/')) == NULL) 83 delta = delta_file; 84 else 85 delta++; 86 87 if ((dfp = fopen(delta_file, "r")) == NULL || fstat(fileno(dfp), &sb) < 0) |
78 { | 88 { |
79 err("%s: %s", delta_file, strerror(errno)); | 89 err("*%s", delta_file); |
80 exit(1); 81 } 82 83 if (max_ctm_size != 0 && sb.st_size > max_ctm_size) | 90 exit(1); 91 } 92 93 if (max_ctm_size != 0 && sb.st_size > max_ctm_size) |
84 apologise(delta_file, sb.st_size, max_ctm_size, mail_alias); 85 else if (queue_dir == NULL) 86 chop_and_send(delta_file, sb.st_size, max_msg_size, mail_alias); | 94 status = apologise(delta, sb.st_size, max_ctm_size, mail_alias); |
87 else | 95 else |
88 chop_and_queue(delta_file, sb.st_size, max_msg_size, queue_dir, mail_alias); | 96 status = chop_and_send_or_queue(dfp, delta, sb.st_size, max_msg_size, 97 mail_alias, queue_dir); |
89 | 98 |
90 return 0; | 99 fclose(dfp); 100 101 return status; |
91 } 92 93 94/* | 102 } 103 104 105/* |
95 * Carve our CTM delta into pieces, encode them, and send them. | 106 * Carve our CTM delta into pieces, encode them, and send or queue them. 107 * Returns 0 on success, and 1 on failure. |
96 */ | 108 */ |
97void 98chop_and_send(char *delta, off_t ctm_size, long max_msg_size, char *mail_alias) | 109int 110chop_and_send_or_queue(FILE *dfp, char *delta, off_t ctm_size, 111 long max_msg_size, char *mail_alias, char *queue_dir) |
99 { 100 int npieces; 101 long msg_size; 102 long exp_size; | 112 { 113 int npieces; 114 long msg_size; 115 long exp_size; |
103 int pce; 104 FILE *sfp; 105 FILE *dfp; 106 unsigned sum; 107 char *deltaname; | 116 int status; |
108 | 117 |
109#ifdef howmany | |
110#undef howmany | 118#undef howmany |
111#endif | 119#define howmany(x,y) (((x)+((y)-1)) / (y)) |
112 | 120 |
113#define howmany(x, y) (((x) + ((y) - 1)) / (y)) 114 | |
115 /* 116 * Work out how many pieces we need, bearing in mind that each piece 117 * grows by 4/3 when encoded. We count the newlines too, but ignore 118 * all mail headers and piece headers. They are a "small" (almost 119 * constant) per message overhead that we make the user worry about. :-) 120 */ 121 exp_size = ctm_size * 4 / 3; 122 exp_size += howmany(exp_size, LINE_LENGTH); 123 npieces = howmany(exp_size, max_msg_size); 124 msg_size = howmany(ctm_size, npieces); 125 126#undef howmany 127 | 121 /* 122 * Work out how many pieces we need, bearing in mind that each piece 123 * grows by 4/3 when encoded. We count the newlines too, but ignore 124 * all mail headers and piece headers. They are a "small" (almost 125 * constant) per message overhead that we make the user worry about. :-) 126 */ 127 exp_size = ctm_size * 4 / 3; 128 exp_size += howmany(exp_size, LINE_LENGTH); 129 npieces = howmany(exp_size, max_msg_size); 130 msg_size = howmany(ctm_size, npieces); 131 132#undef howmany 133 |
128 if ((dfp = fopen(delta, "r")) == NULL) | 134 if (queue_dir == NULL) 135 status = chop_and_send(dfp, delta, msg_size, npieces, mail_alias); 136 else |
129 { | 137 { |
130 err("cannot open '%s' for reading.", delta); 131 exit(1); | 138 status = chop_and_queue(dfp, delta, msg_size, npieces, mail_alias, 139 queue_dir); 140 if (status) 141 clean_up_queue(queue_dir); |
132 } 133 | 142 } 143 |
134 deltaname = strrchr(delta, '/'); 135 if (deltaname) 136 deltaname++; /* skip slash */ 137 else 138 deltaname = delta; | 144 return status; 145 } |
139 | 146 |
147 148/* 149 * Carve our CTM delta into pieces, encode them, and send them. 150 * Returns 0 on success, and 1 on failure. 151 */ 152int 153chop_and_send(FILE *dfp, char *delta, long msg_size, int npieces, 154 char *mail_alias) 155 { 156 int pce; 157 FILE *sfp; 158 unsigned sum; 159 160 /* 161 * Send each chunk directly to sendmail as it is generated. 162 * No temporary files necessary. If things turn ugly, we just 163 * have to live with the fact the we have sent only part of 164 * the delta. 165 */ |
|
140 for (pce = 1; pce <= npieces; pce++) 141 { | 166 for (pce = 1; pce <= npieces; pce++) 167 { |
142 sfp = open_sendmail(); 143 if (sfp == NULL) 144 exit(1); | 168 int read_error; 169 170 if ((sfp = open_sendmail()) == NULL) 171 return 1; 172 |
145 write_header(sfp, mail_alias, delta, pce, npieces); | 173 write_header(sfp, mail_alias, delta, pce, npieces); |
146 sum = encode_body(sfp, dfp, msg_size); 147 write_trailer(sfp, sum); 148 if (!close_sendmail(sfp)) 149 exit(1); 150 err("%s %d/%d sent to %s", deltaname, pce, npieces, mail_alias); | 174 read_error = encode_body(sfp, dfp, msg_size, &sum); 175 if (!read_error) 176 write_trailer(sfp, sum); 177 178 if (!close_sendmail(sfp) || read_error) 179 return 1; 180 181 err("%s %d/%d sent to %s", delta, pce, npieces, mail_alias); |
151 } 152 | 182 } 183 |
153 fclose(dfp); | 184 return 0; |
154 } 155 | 185 } 186 |
156/* 157 * Carve our CTM delta into pieces, encode them, and drop them in the 158 * queue dir. 159 * 160 * Basic algorythm: 161 * 162 * - for (each piece) 163 * - gen. temp. file name (one which the de-queuer will ignore) 164 * - record in array 165 * - open temp. file 166 * - encode delta (including headers) into the temp file 167 * - close temp. file 168 * - end 169 * - lock queue directory 170 * - foreach (temp. file) 171 * - rename to the proper filename 172 * - end 173 * - unlock queue directory 174 * 175 * This is probably overkill, but it means that incomplete deltas 176 * don't get mailed, and also reduces the window for lock races 177 * between ctm_smail and the de-queueing process. | 187 188/* 189 * Construct the tmp queue file name of a delta piece. |
178 */ | 190 */ |
191#define mk_tmp_name(fn,qd,p) \ 192 sprintf((fn), "%s/.%08ld.%03d", (qd), (long)getpid(), (p)) |
|
179 | 193 |
180void 181chop_and_queue(char *delta, off_t ctm_size, long max_msg_size, char *queue_dir, char *mail_alias) 182{ 183 int npieces, pce, len; 184 long msg_size, exp_size; 185 FILE *sfp, *dfp; | 194/* 195 * Construct the final queue file name of a delta piece. 196 */ 197#define mk_queue_name(fn,qd,d,p,n) \ 198 sprintf((fn), "%s/%s+%03d-%03d", (qd), (d), (p), (n)) 199 200/* 201 * Carve our CTM delta into pieces, encode them, and queue them. 202 * Returns 0 on success, and 1 on failure. 203 */ 204int 205chop_and_queue(FILE *dfp, char *delta, long msg_size, int npieces, 206 char *mail_alias, char *queue_dir) 207 { 208 int pce; 209 FILE *qfp; |
186 unsigned sum; | 210 unsigned sum; |
187 char **tempnames, *tempnam, *sn; | 211 char tname[PATH_MAX]; 212 char qname[PATH_MAX]; |
188 | 213 |
189#define howmany(x, y) (((x) + ((y) - 1)) / (y)) 190 | |
191 /* | 214 /* |
192 * Work out how many pieces we need, bearing in mind that each piece 193 * grows by 4/3 when encoded. We count the newlines too, but ignore 194 * all mail headers and piece headers. They are a "small" (almost 195 * constant) per message overhead that we make the user worry about. :-) | 215 * Store each piece in the queue directory, but under temporary names, 216 * so that they can be deleted without unpleasant consequences if 217 * anything goes wrong. We could easily fill up a disk, for example. |
196 */ | 218 */ |
197 exp_size = ctm_size * 4 / 3; 198 exp_size += howmany(exp_size, LINE_LENGTH); 199 npieces = howmany(exp_size, max_msg_size); 200 msg_size = howmany(ctm_size, npieces); | 219 for (pce = 1; pce <= npieces; pce++) 220 { 221 int write_error; |
201 | 222 |
202#undef howmany | 223 mk_tmp_name(tname, queue_dir, pce); 224 if ((qfp = fopen(tname, "w")) == NULL) 225 { 226 err("cannot open '%s' for writing", tname); 227 return 1; 228 } |
203 | 229 |
230 write_header(qfp, mail_alias, delta, pce, npieces); 231 if (encode_body(qfp, dfp, msg_size, &sum)) 232 return 1; 233 write_trailer(qfp, sum); 234 235 fflush(qfp); 236 write_error = ferror(qfp); 237 fclose(qfp); 238 if (write_error) 239 { 240 err("error writing '%s'", tname); 241 return 1; 242 } 243 244 /* 245 * Give the warm success message now, instead of all in a rush 246 * during the rename phase. 247 */ 248 err("%s %d/%d queued for %s", delta, pce, npieces, mail_alias); 249 } 250 |
|
204 /* | 251 /* |
205 * allocate space for the array of filenames. Try to be portable 206 * by not assuming anything to do with sizeof(char *) | 252 * Rename the pieces into place. If an error occurs now, we are 253 * stuffed, but there is no neat way to back out. rename() should 254 * only fail now under extreme circumstances. |
207 */ | 255 */ |
208 tempnames = malloc(npieces * sizeof(char *)); 209 if (tempnames == NULL) 210 { 211 err("malloc for tempnames failed"); 212 exit(1); | 256 for (pce = 1; pce <= npieces; pce++) 257 { 258 mk_tmp_name(tname, queue_dir, pce); 259 mk_queue_name(qname, queue_dir, delta, pce, npieces); 260 if (rename(tname, qname) < 0) 261 { 262 err("*rename: '%s' to '%s'", tname, qname); 263 unlink(tname); 264 } 265 } 266 267 return 0; |
213 } | 268 } |
214 215 len = strlen(queue_dir) + 16; 216 tempnam = malloc(len); 217 if (tempnam == NULL) 218 { 219 err("malloc for tempnames failed"); 220 exit(1); 221 } 222 223 if ((dfp = fopen(delta, "r")) == NULL) 224 { 225 err("cannot open '%s' for reading.", delta); 226 exit(1); 227 } | |
228 | 269 |
229 if ((sn = strrchr(delta, '/')) == NULL) 230 sn = delta; 231 else 232 sn++; | |
233 | 270 |
234 for (pce = 1; pce <= npieces; pce++) | 271/* 272 * There may be temporary files cluttering up the queue directory. 273 */ 274void 275clean_up_queue(char *queue_dir) |
235 { | 276 { |
236 if (snprintf(tempnam, len, "%s/.%08d-%03d", queue_dir, getpid(), pce) >= len) 237 err("Whoops! tempnam isn't long enough"); | 277 int pce; 278 char tname[PATH_MAX]; |
238 | 279 |
239 tempnames[pce - 1] = strdup(tempnam); 240 if (tempnames[pce - 1] == NULL) | 280 err("discarding queued delta pieces"); 281 for (pce = 1; ; pce++) |
241 { | 282 { |
242 err("strdup failed for temp. filename"); 243 exit(1); | 283 mk_tmp_name(tname, queue_dir, pce); 284 if (unlink(tname) < 0) 285 break; |
244 } | 286 } |
245 246 sfp = fopen(tempnam, "w"); 247 if (sfp == NULL) 248 exit(1); 249 250 write_header(sfp, mail_alias, delta, pce, npieces); 251 sum = encode_body(sfp, dfp, msg_size); 252 write_trailer(sfp, sum); 253 254 if (fclose(sfp) != 0) 255 exit(1); 256 257 err("%s %d/%d created succesfully", sn, pce, npieces); | |
258 } 259 | 287 } 288 |
260 add_to_queue(queue_dir, mail_alias, delta, npieces, tempnames); | |
261 | 289 |
262 fclose(dfp); 263 264} 265 266 | |
267/* 268 * MIME BASE64 encode table. 269 */ 270static char to_b64[0x40] = 271 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; 272 273/* 274 * This cheap plastic checksum effectively rotates our checksum-so-far --- 8 unchanged lines hidden (view full) --- 283 * 284 * Characters are read from delta_fp and encoded characters are written 285 * to sm_fp. At most 'msg_size' characters should be read from delta_fp. 286 * 287 * The body consists of lines of up to LINE_LENGTH characters. Each group 288 * of 4 characters encodes 3 input characters. Each output character encodes 289 * 6 bits. Thus 64 different characters are needed in this representation. 290 */ | 290/* 291 * MIME BASE64 encode table. 292 */ 293static char to_b64[0x40] = 294 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; 295 296/* 297 * This cheap plastic checksum effectively rotates our checksum-so-far --- 8 unchanged lines hidden (view full) --- 306 * 307 * Characters are read from delta_fp and encoded characters are written 308 * to sm_fp. At most 'msg_size' characters should be read from delta_fp. 309 * 310 * The body consists of lines of up to LINE_LENGTH characters. Each group 311 * of 4 characters encodes 3 input characters. Each output character encodes 312 * 6 bits. Thus 64 different characters are needed in this representation. 313 */ |
291unsigned 292encode_body(FILE *sm_fp, FILE *delta_fp, long msg_size) | 314int 315encode_body(FILE *sm_fp, FILE *delta_fp, long msg_size, unsigned *sum) |
293 { 294 unsigned short cksum = 0xffff; 295 unsigned char *ip; 296 char *op; 297 int want, n, i; 298 unsigned char inbuf[LINE_LENGTH*3/4]; 299 char outbuf[LINE_LENGTH+1]; 300 --- 38 unchanged lines hidden (view full) --- 339 } 340 *op++ = '\n'; 341 fwrite(outbuf, sizeof(char), op - outbuf, sm_fp); 342 } 343 344 if (ferror(delta_fp)) 345 { 346 err("error reading input file."); | 316 { 317 unsigned short cksum = 0xffff; 318 unsigned char *ip; 319 char *op; 320 int want, n, i; 321 unsigned char inbuf[LINE_LENGTH*3/4]; 322 char outbuf[LINE_LENGTH+1]; 323 --- 38 unchanged lines hidden (view full) --- 362 } 363 *op++ = '\n'; 364 fwrite(outbuf, sizeof(char), op - outbuf, sm_fp); 365 } 366 367 if (ferror(delta_fp)) 368 { 369 err("error reading input file."); |
347 exit(1); | 370 return 1; |
348 } 349 | 371 } 372 |
350 if (ferror(sm_fp)) 351 { 352 err("error writing encoded file"); 353 exit(1); 354 } | 373 *sum = cksum; |
355 | 374 |
356 return cksum; | 375 return 0; |
357 } 358 359 360/* 361 * Write the mail header and data header. 362 */ 363void 364write_header(FILE *sfp, char *mail_alias, char *delta, int pce, int npieces) 365 { | 376 } 377 378 379/* 380 * Write the mail header and data header. 381 */ 382void 383write_header(FILE *sfp, char *mail_alias, char *delta, int pce, int npieces) 384 { |
366 char *sn; 367 368 if ((sn = strrchr(delta, '/')) == NULL) 369 sn = delta; 370 else 371 sn++; 372 | |
373 fprintf(sfp, "From: owner-%s\n", mail_alias); 374 fprintf(sfp, "To: %s\n", mail_alias); | 385 fprintf(sfp, "From: owner-%s\n", mail_alias); 386 fprintf(sfp, "To: %s\n", mail_alias); |
375 fprintf(sfp, "Subject: ctm-mail %s %d/%d\n\n", sn, pce, npieces); | 387 fprintf(sfp, "Subject: ctm-mail %s %d/%d\n\n", delta, pce, npieces); |
376 | 388 |
377 fprintf(sfp, "CTM_MAIL BEGIN %s %d %d\n", sn, pce, npieces); | 389 fprintf(sfp, "CTM_MAIL BEGIN %s %d %d\n", delta, pce, npieces); |
378 } 379 380 381/* 382 * Write the data trailer. 383 */ 384void 385write_trailer(FILE *sfp, unsigned sum) 386 { 387 fprintf(sfp, "CTM_MAIL END %ld\n", (long)sum); 388 } 389 390 391/* 392 * We're terribly sorry, but the delta is too big to send. | 390 } 391 392 393/* 394 * Write the data trailer. 395 */ 396void 397write_trailer(FILE *sfp, unsigned sum) 398 { 399 fprintf(sfp, "CTM_MAIL END %ld\n", (long)sum); 400 } 401 402 403/* 404 * We're terribly sorry, but the delta is too big to send. |
405 * Returns 0 on success, 1 on failure. |
|
393 */ | 406 */ |
394void | 407int |
395apologise(char *delta, off_t ctm_size, long max_ctm_size, char *mail_alias) 396 { 397 FILE *sfp; | 408apologise(char *delta, off_t ctm_size, long max_ctm_size, char *mail_alias) 409 { 410 FILE *sfp; |
398 char *sn; | |
399 400 sfp = open_sendmail(); 401 if (sfp == NULL) | 411 412 sfp = open_sendmail(); 413 if (sfp == NULL) |
402 exit(1); | 414 return 1; |
403 | 415 |
404 if ((sn = strrchr(delta, '/')) == NULL) 405 sn = delta; 406 else 407 sn++; 408 409 fprintf(sfp, "From: %s-owner\n", mail_alias); | 416 fprintf(sfp, "From: owner-%s\n", mail_alias); |
410 fprintf(sfp, "To: %s\n", mail_alias); | 417 fprintf(sfp, "To: %s\n", mail_alias); |
411 fprintf(sfp, "Subject: ctm-notice %s\n\n", sn); | 418 fprintf(sfp, "Subject: ctm-notice %s\n\n", delta); |
412 | 419 |
413 fprintf(sfp, "%s is %ld bytes. The limit is %ld bytes.\n\n", sn, | 420 fprintf(sfp, "%s is %ld bytes. The limit is %ld bytes.\n\n", delta, |
414 (long)ctm_size, max_ctm_size); | 421 (long)ctm_size, max_ctm_size); |
415 fprintf(sfp, "You can retrieve this delta via ftpmail, or your good mate at the university.\n"); | 422 fprintf(sfp, "You can retrieve this delta via ftpmail, " 423 "or your good mate at the university.\n"); |
416 417 if (!close_sendmail(sfp)) | 424 425 if (!close_sendmail(sfp)) |
418 exit(1); | 426 return 1; 427 428 return 0; |
419 } 420 421 422/* 423 * Start a pipe to sendmail. Sendmail will decode the destination 424 * from the message contents. 425 */ 426FILE * --- 25 unchanged lines hidden (view full) --- 452 return 0; 453 } 454 455 if ((status = pclose(fp)) != 0) 456 err("sendmail failed with status %d", status); 457 458 return (status == 0); 459 } | 429 } 430 431 432/* 433 * Start a pipe to sendmail. Sendmail will decode the destination 434 * from the message contents. 435 */ 436FILE * --- 25 unchanged lines hidden (view full) --- 462 return 0; 463 } 464 465 if ((status = pclose(fp)) != 0) 466 err("sendmail failed with status %d", status); 467 468 return (status == 0); 469 } |
460 461/* 462 * Lock the queuedir so we're the only guy messing about in there. 463 */ 464int 465lock_queuedir(char *queue_dir) 466{ 467 int fp, len; 468 char *buffer; 469 struct stat sb; 470 471 len = strlen(queue_dir) + 8; 472 473 buffer = malloc(len); 474 if (buffer == NULL) 475 { 476 err("malloc failed in lock_queuedir"); 477 exit(1); 478 } 479 480 if (snprintf(buffer, len, "%s/.lock", queue_dir) >= len) 481 err("Whoops. lock buffer too small in lock_queuedir"); 482 483 /* 484 * We do our own lockfile scanning to avoid unlink races. 60 485 * seconds should be enough to ensure that we won't get more races 486 * happening between the stat and the open/flock. 487 */ 488 489 while (stat(buffer, &sb) == 0) 490 sleep(60); 491 492 if ((fp = open(buffer, O_WRONLY | O_CREAT | O_EXLOCK, 0600)) < 0) 493 { 494 err("can't open `%s' in lock_queuedir", buffer); 495 exit(1); 496 } 497 498 snprintf(buffer, len, "%8ld", getpid()); 499 write(fp, buffer, 8); 500 501 free(buffer); 502 503 return(fp); 504} 505 506/* 507 * Lock the queuedir so we're the only guy messing about in there. 508 */ 509void 510free_lock(int lockf, char *queue_dir) 511{ 512 int len; 513 char *path; 514 515 /* 516 * Most important: free the lock before we do anything else! 517 */ 518 519 close(lockf); 520 521 len = strlen(queue_dir) + 7; 522 523 path = malloc(len); 524 if (path == NULL) 525 { 526 err("malloc failed in free_lock"); 527 exit(1); 528 } 529 530 if (snprintf(path, len, "%s/.lock", queue_dir) >= len) 531 err("lock path buffer too small in free_lock"); 532 533 if (unlink(path) != 0) 534 { 535 err("can't unlink lockfile `%s'", path); 536 exit(1); 537 } 538 539 free(path); 540} 541 542/* move everything into the queue directory. */ 543 544void 545add_to_queue(char *queue_dir, char *mail_alias, char *delta, int npieces, char **tempnames) 546{ 547 char *queuefile, *sn; 548 int pce, len, lockf; 549 550 if ((sn = strrchr(delta, '/')) == NULL) 551 sn = delta; 552 else 553 sn++; 554 555 /* try to malloc all we need BEFORE entering the lock loop */ 556 557 len = strlen(queue_dir) + strlen(sn) + 7; 558 queuefile = malloc(len); 559 if (queuefile == NULL) 560 { 561 err("can't malloc for queuefile"); 562 exit(1); 563 } 564 565 /* 566 * We should be the only process mucking around in the queue 567 * directory while we add the new queue files ... it could be 568 * awkward if the de-queue process starts it's job while we're 569 * adding files ... 570 */ 571 572 lockf = lock_queuedir(queue_dir); 573 for (pce = 0; pce < npieces; pce++) 574 { 575 struct stat sb; 576 577 if (snprintf(queuefile, len, "%s/%s+%03d", queue_dir, sn, pce + 1) >= len) 578 err("whoops, queuefile buffer is too small"); 579 580 if (stat(queuefile, &sb) == 0) 581 { 582 err("WOAH! Queue file `%s' already exists! Bailing out.", queuefile); 583 free_lock(lockf, queue_dir); 584 exit(1); 585 } 586 587 rename(tempnames[pce], queuefile); 588 } 589 590 free_lock(lockf, queue_dir); 591 592 free(queuefile); 593} | |