|
|
1.1 root 1: /*
2: * Copyright (c) 1983 Eric P. Allman
3: * Copyright (c) 1988 Regents of the University of California.
4: * All rights reserved.
5: *
6: * Redistribution and use in source and binary forms are permitted
7: * provided that the above copyright notice and this paragraph are
8: * duplicated in all such forms and that any documentation,
9: * advertising materials, and other materials related to such
10: * distribution and use acknowledge that the software was developed
11: * by the University of California, Berkeley. The name of the
12: * University may not be used to endorse or promote products derived
13: * from this software without specific prior written permission.
14: * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
15: * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
16: * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
17: */
18:
19: # include "sendmail.h"
20:
21: #ifndef lint
22: #ifdef QUEUE
23: static char sccsid[] = "@(#)queue.c 5.24 (Berkeley) 6/30/88 (with queueing)";
24: #else
25: static char sccsid[] = "@(#)queue.c 5.24 (Berkeley) 6/30/88 (without queueing)";
26: #endif
27: #endif /* not lint */
28:
29: # include <sys/stat.h>
30: # include <sys/dir.h>
31: # include <signal.h>
32: # include <errno.h>
33:
34: # ifdef QUEUE
35:
36: /*
37: ** Work queue.
38: */
39:
40: struct work
41: {
42: char *w_name; /* name of control file */
43: long w_pri; /* priority of message, see below */
44: time_t w_ctime; /* creation time of message */
45: struct work *w_next; /* next in queue */
46: };
47:
48: typedef struct work WORK;
49:
50: WORK *WorkQ; /* queue of things to be done */
51: /*
52: ** QUEUEUP -- queue a message up for future transmission.
53: **
54: ** Parameters:
55: ** e -- the envelope to queue up.
56: ** queueall -- if TRUE, queue all addresses, rather than
57: ** just those with the QQUEUEUP flag set.
58: ** announce -- if TRUE, tell when you are queueing up.
59: **
60: ** Returns:
61: ** none.
62: **
63: ** Side Effects:
64: ** The current request are saved in a control file.
65: */
66:
67: queueup(e, queueall, announce)
68: register ENVELOPE *e;
69: bool queueall;
70: bool announce;
71: {
72: char *tf;
73: char *qf;
74: char buf[MAXLINE];
75: register FILE *tfp;
76: register HDR *h;
77: register ADDRESS *q;
78: MAILER nullmailer;
79:
80: /*
81: ** Create control file.
82: */
83:
84: tf = newstr(queuename(e, 't'));
85: tfp = fopen(tf, "w");
86: if (tfp == NULL)
87: {
88: syserr("queueup: cannot create temp file %s", tf);
89: return;
90: }
91: (void) chmod(tf, FileMode);
92:
93: # ifdef DEBUG
94: if (tTd(40, 1))
95: printf("queueing %s\n", e->e_id);
96: # endif DEBUG
97:
98: /*
99: ** If there is no data file yet, create one.
100: */
101:
102: if (e->e_df == NULL)
103: {
104: register FILE *dfp;
105: extern putbody();
106:
107: e->e_df = newstr(queuename(e, 'd'));
108: dfp = fopen(e->e_df, "w");
109: if (dfp == NULL)
110: {
111: syserr("queueup: cannot create %s", e->e_df);
112: (void) fclose(tfp);
113: return;
114: }
115: (void) chmod(e->e_df, FileMode);
116: (*e->e_putbody)(dfp, ProgMailer, e);
117: (void) fclose(dfp);
118: e->e_putbody = putbody;
119: }
120:
121: /*
122: ** Output future work requests.
123: ** Priority and creation time should be first, since
124: ** they are required by orderq.
125: */
126:
127: /* output message priority */
128: fprintf(tfp, "P%ld\n", e->e_msgpriority);
129:
130: /* output creation time */
131: fprintf(tfp, "T%ld\n", e->e_ctime);
132:
133: /* output name of data file */
134: fprintf(tfp, "D%s\n", e->e_df);
135:
136: /* message from envelope, if it exists */
137: if (e->e_message != NULL)
138: fprintf(tfp, "M%s\n", e->e_message);
139:
140: /* output name of sender */
141: fprintf(tfp, "S%s\n", e->e_from.q_paddr);
142:
143: /* output list of recipient addresses */
144: for (q = e->e_sendqueue; q != NULL; q = q->q_next)
145: {
146: if (queueall ? !bitset(QDONTSEND, q->q_flags) :
147: bitset(QQUEUEUP, q->q_flags))
148: {
149: fprintf(tfp, "R%s\n", q->q_paddr);
150: if (announce)
151: {
152: e->e_to = q->q_paddr;
153: message(Arpa_Info, "queued");
154: if (LogLevel > 4)
155: logdelivery("queued");
156: e->e_to = NULL;
157: }
158: #ifdef DEBUG
159: if (tTd(40, 1))
160: {
161: printf("queueing ");
162: printaddr(q, FALSE);
163: }
164: #endif DEBUG
165: }
166: }
167:
168: /* output list of error recipients */
169: for (q = e->e_errorqueue; q != NULL; q = q->q_next)
170: {
171: if (!bitset(QDONTSEND, q->q_flags))
172: fprintf(tfp, "E%s\n", q->q_paddr);
173: }
174:
175: /*
176: ** Output headers for this message.
177: ** Expand macros completely here. Queue run will deal with
178: ** everything as absolute headers.
179: ** All headers that must be relative to the recipient
180: ** can be cracked later.
181: ** We set up a "null mailer" -- i.e., a mailer that will have
182: ** no effect on the addresses as they are output.
183: */
184:
185: bzero((char *) &nullmailer, sizeof nullmailer);
186: nullmailer.m_r_rwset = nullmailer.m_s_rwset = -1;
187: nullmailer.m_eol = "\n";
188:
189: define('g', "\001f", e);
190: for (h = e->e_header; h != NULL; h = h->h_link)
191: {
192: extern bool bitzerop();
193:
194: /* don't output null headers */
195: if (h->h_value == NULL || h->h_value[0] == '\0')
196: continue;
197:
198: /* don't output resent headers on non-resent messages */
199: if (bitset(H_RESENT, h->h_flags) && !bitset(EF_RESENT, e->e_flags))
200: continue;
201:
202: /* output this header */
203: fprintf(tfp, "H");
204:
205: /* if conditional, output the set of conditions */
206: if (!bitzerop(h->h_mflags) && bitset(H_CHECK|H_ACHECK, h->h_flags))
207: {
208: int j;
209:
210: (void) putc('?', tfp);
211: for (j = '\0'; j <= '\177'; j++)
212: if (bitnset(j, h->h_mflags))
213: (void) putc(j, tfp);
214: (void) putc('?', tfp);
215: }
216:
217: /* output the header: expand macros, convert addresses */
218: if (bitset(H_DEFAULT, h->h_flags))
219: {
220: (void) expand(h->h_value, buf, &buf[sizeof buf], e);
221: fprintf(tfp, "%s: %s\n", h->h_field, buf);
222: }
223: else if (bitset(H_FROM|H_RCPT, h->h_flags))
224: {
225: commaize(h, h->h_value, tfp, bitset(EF_OLDSTYLE, e->e_flags),
226: &nullmailer);
227: }
228: else
229: fprintf(tfp, "%s: %s\n", h->h_field, h->h_value);
230: }
231:
232: /*
233: ** Clean up.
234: */
235:
236: (void) fclose(tfp);
237: qf = queuename(e, 'q');
238: if (tf != NULL)
239: {
240: (void) unlink(qf);
241: if (rename(tf, qf) < 0)
242: syserr("cannot unlink(%s, %s), df=%s", tf, qf, e->e_df);
243: errno = 0;
244: }
245:
246: # ifdef LOG
247: /* save log info */
248: if (LogLevel > 15)
249: syslog(LOG_DEBUG, "%s: queueup, qf=%s, df=%s\n", e->e_id, qf, e->e_df);
250: # endif LOG
251: }
252: /*
253: ** RUNQUEUE -- run the jobs in the queue.
254: **
255: ** Gets the stuff out of the queue in some presumably logical
256: ** order and processes them.
257: **
258: ** Parameters:
259: ** forkflag -- TRUE if the queue scanning should be done in
260: ** a child process. We double-fork so it is not our
261: ** child and we don't have to clean up after it.
262: **
263: ** Returns:
264: ** none.
265: **
266: ** Side Effects:
267: ** runs things in the mail queue.
268: */
269:
270: runqueue(forkflag)
271: bool forkflag;
272: {
273: extern bool shouldqueue();
274:
275: /*
276: ** If no work will ever be selected, don't even bother reading
277: ** the queue.
278: */
279:
280: if (shouldqueue(-100000000L))
281: {
282: if (Verbose)
283: printf("Skipping queue run -- load average too high\n");
284:
285: if (forkflag)
286: return;
287: finis();
288: }
289:
290: /*
291: ** See if we want to go off and do other useful work.
292: */
293:
294: if (forkflag)
295: {
296: int pid;
297:
298: pid = dofork();
299: if (pid != 0)
300: {
301: extern reapchild();
302:
303: /* parent -- pick up intermediate zombie */
304: #ifndef SIGCHLD
305: (void) waitfor(pid);
306: #else SIGCHLD
307: (void) signal(SIGCHLD, reapchild);
308: #endif SIGCHLD
309: if (QueueIntvl != 0)
310: (void) setevent(QueueIntvl, runqueue, TRUE);
311: return;
312: }
313: /* child -- double fork */
314: #ifndef SIGCHLD
315: if (fork() != 0)
316: exit(EX_OK);
317: #else SIGCHLD
318: (void) signal(SIGCHLD, SIG_DFL);
319: #endif SIGCHLD
320: }
321:
322: setproctitle("running queue");
323:
324: # ifdef LOG
325: if (LogLevel > 11)
326: syslog(LOG_DEBUG, "runqueue %s, pid=%d", QueueDir, getpid());
327: # endif LOG
328:
329: /*
330: ** Release any resources used by the daemon code.
331: */
332:
333: # ifdef DAEMON
334: clrdaemon();
335: # endif DAEMON
336:
337: /*
338: ** Make sure the alias database is open.
339: */
340:
341: initaliases(AliasFile, FALSE);
342:
343: /*
344: ** Start making passes through the queue.
345: ** First, read and sort the entire queue.
346: ** Then, process the work in that order.
347: ** But if you take too long, start over.
348: */
349:
350: /* order the existing work requests */
351: (void) orderq(FALSE);
352:
353: /* process them once at a time */
354: while (WorkQ != NULL)
355: {
356: WORK *w = WorkQ;
357:
358: WorkQ = WorkQ->w_next;
359: dowork(w);
360: free(w->w_name);
361: free((char *) w);
362: }
363:
364: /* exit without the usual cleanup */
365: exit(ExitStat);
366: }
367: /*
368: ** ORDERQ -- order the work queue.
369: **
370: ** Parameters:
371: ** doall -- if set, include everything in the queue (even
372: ** the jobs that cannot be run because the load
373: ** average is too high). Otherwise, exclude those
374: ** jobs.
375: **
376: ** Returns:
377: ** The number of request in the queue (not necessarily
378: ** the number of requests in WorkQ however).
379: **
380: ** Side Effects:
381: ** Sets WorkQ to the queue of available work, in order.
382: */
383:
384: # define NEED_P 001
385: # define NEED_T 002
386:
387: orderq(doall)
388: bool doall;
389: {
390: register struct direct *d;
391: register WORK *w;
392: DIR *f;
393: register int i;
394: WORK wlist[QUEUESIZE+1];
395: int wn = -1;
396: extern workcmpf();
397:
398: /* clear out old WorkQ */
399: for (w = WorkQ; w != NULL; )
400: {
401: register WORK *nw = w->w_next;
402:
403: WorkQ = nw;
404: free(w->w_name);
405: free((char *) w);
406: w = nw;
407: }
408:
409: /* open the queue directory */
410: f = opendir(".");
411: if (f == NULL)
412: {
413: syserr("orderq: cannot open \"%s\" as \".\"", QueueDir);
414: return (0);
415: }
416:
417: /*
418: ** Read the work directory.
419: */
420:
421: while ((d = readdir(f)) != NULL)
422: {
423: FILE *cf;
424: char lbuf[MAXNAME];
425:
426: /* is this an interesting entry? */
427: if (d->d_name[0] != 'q' || d->d_name[1] != 'f')
428: continue;
429:
430: /* yes -- open control file (if not too many files) */
431: if (++wn >= QUEUESIZE)
432: continue;
433: cf = fopen(d->d_name, "r");
434: if (cf == NULL)
435: {
436: /* this may be some random person sending hir msgs */
437: /* syserr("orderq: cannot open %s", cbuf); */
438: #ifdef DEBUG
439: if (tTd(41, 2))
440: printf("orderq: cannot open %s (%d)\n",
441: d->d_name, errno);
442: #endif DEBUG
443: errno = 0;
444: wn--;
445: continue;
446: }
447: w = &wlist[wn];
448: w->w_name = newstr(d->d_name);
449:
450: /* make sure jobs in creation don't clog queue */
451: w->w_pri = 0x7fffffff;
452: w->w_ctime = 0;
453:
454: /* extract useful information */
455: i = NEED_P | NEED_T;
456: while (i != 0 && fgets(lbuf, sizeof lbuf, cf) != NULL)
457: {
458: extern long atol();
459:
460: switch (lbuf[0])
461: {
462: case 'P':
463: w->w_pri = atol(&lbuf[1]);
464: i &= ~NEED_P;
465: break;
466:
467: case 'T':
468: w->w_ctime = atol(&lbuf[1]);
469: i &= ~NEED_T;
470: break;
471: }
472: }
473: (void) fclose(cf);
474:
475: if (!doall && shouldqueue(w->w_pri))
476: {
477: /* don't even bother sorting this job in */
478: wn--;
479: }
480: }
481: (void) closedir(f);
482: wn++;
483:
484: /*
485: ** Sort the work directory.
486: */
487:
488: qsort((char *) wlist, min(wn, QUEUESIZE), sizeof *wlist, workcmpf);
489:
490: /*
491: ** Convert the work list into canonical form.
492: ** Should be turning it into a list of envelopes here perhaps.
493: */
494:
495: WorkQ = NULL;
496: for (i = min(wn, QUEUESIZE); --i >= 0; )
497: {
498: w = (WORK *) xalloc(sizeof *w);
499: w->w_name = wlist[i].w_name;
500: w->w_pri = wlist[i].w_pri;
501: w->w_ctime = wlist[i].w_ctime;
502: w->w_next = WorkQ;
503: WorkQ = w;
504: }
505:
506: # ifdef DEBUG
507: if (tTd(40, 1))
508: {
509: for (w = WorkQ; w != NULL; w = w->w_next)
510: printf("%32s: pri=%ld\n", w->w_name, w->w_pri);
511: }
512: # endif DEBUG
513:
514: return (wn);
515: }
516: /*
517: ** WORKCMPF -- compare function for ordering work.
518: **
519: ** Parameters:
520: ** a -- the first argument.
521: ** b -- the second argument.
522: **
523: ** Returns:
524: ** -1 if a < b
525: ** 0 if a == b
526: ** +1 if a > b
527: **
528: ** Side Effects:
529: ** none.
530: */
531:
532: workcmpf(a, b)
533: register WORK *a;
534: register WORK *b;
535: {
536: long pa = a->w_pri + a->w_ctime;
537: long pb = b->w_pri + b->w_ctime;
538:
539: if (pa == pb)
540: return (0);
541: else if (pa > pb)
542: return (1);
543: else
544: return (-1);
545: }
546: /*
547: ** DOWORK -- do a work request.
548: **
549: ** Parameters:
550: ** w -- the work request to be satisfied.
551: **
552: ** Returns:
553: ** none.
554: **
555: ** Side Effects:
556: ** The work request is satisfied if possible.
557: */
558:
559: dowork(w)
560: register WORK *w;
561: {
562: register int i;
563: extern bool shouldqueue();
564:
565: # ifdef DEBUG
566: if (tTd(40, 1))
567: printf("dowork: %s pri %ld\n", w->w_name, w->w_pri);
568: # endif DEBUG
569:
570: /*
571: ** Ignore jobs that are too expensive for the moment.
572: */
573:
574: if (shouldqueue(w->w_pri))
575: {
576: if (Verbose)
577: printf("\nSkipping %s\n", w->w_name + 2);
578: return;
579: }
580:
581: /*
582: ** Fork for work.
583: */
584:
585: if (ForkQueueRuns)
586: {
587: i = fork();
588: if (i < 0)
589: {
590: syserr("dowork: cannot fork");
591: return;
592: }
593: }
594: else
595: {
596: i = 0;
597: }
598:
599: if (i == 0)
600: {
601: /*
602: ** CHILD
603: ** Lock the control file to avoid duplicate deliveries.
604: ** Then run the file as though we had just read it.
605: ** We save an idea of the temporary name so we
606: ** can recover on interrupt.
607: */
608:
609: /* set basic modes, etc. */
610: (void) alarm(0);
611: clearenvelope(CurEnv, FALSE);
612: QueueRun = TRUE;
613: ErrorMode = EM_MAIL;
614: CurEnv->e_id = &w->w_name[2];
615: # ifdef LOG
616: if (LogLevel > 11)
617: syslog(LOG_DEBUG, "%s: dowork, pid=%d", CurEnv->e_id,
618: getpid());
619: # endif LOG
620:
621: /* don't use the headers from sendmail.cf... */
622: CurEnv->e_header = NULL;
623:
624: /* lock the control file during processing */
625: if (link(w->w_name, queuename(CurEnv, 'l')) < 0)
626: {
627: /* being processed by another queuer */
628: # ifdef LOG
629: if (LogLevel > 4)
630: syslog(LOG_DEBUG, "%s: locked", CurEnv->e_id);
631: # endif LOG
632: if (ForkQueueRuns)
633: exit(EX_OK);
634: else
635: return;
636: }
637:
638: /* do basic system initialization */
639: initsys();
640:
641: /* read the queue control file */
642: readqf(CurEnv, TRUE);
643: CurEnv->e_flags |= EF_INQUEUE;
644: eatheader(CurEnv);
645:
646: /* do the delivery */
647: if (!bitset(EF_FATALERRS, CurEnv->e_flags))
648: sendall(CurEnv, SM_DELIVER);
649:
650: /* finish up and exit */
651: if (ForkQueueRuns)
652: finis();
653: else
654: dropenvelope(CurEnv);
655: }
656: else
657: {
658: /*
659: ** Parent -- pick up results.
660: */
661:
662: errno = 0;
663: (void) waitfor(i);
664: }
665: }
666: /*
667: ** READQF -- read queue file and set up environment.
668: **
669: ** Parameters:
670: ** e -- the envelope of the job to run.
671: ** full -- if set, read in all information. Otherwise just
672: ** read in info needed for a queue print.
673: **
674: ** Returns:
675: ** none.
676: **
677: ** Side Effects:
678: ** cf is read and created as the current job, as though
679: ** we had been invoked by argument.
680: */
681:
682: readqf(e, full)
683: register ENVELOPE *e;
684: bool full;
685: {
686: char *qf;
687: register FILE *qfp;
688: char buf[MAXFIELD];
689: extern char *fgetfolded();
690: extern long atol();
691:
692: /*
693: ** Read and process the file.
694: */
695:
696: qf = queuename(e, 'q');
697: qfp = fopen(qf, "r");
698: if (qfp == NULL)
699: {
700: syserr("readqf: no control file %s", qf);
701: return;
702: }
703: FileName = qf;
704: LineNumber = 0;
705: if (Verbose && full)
706: printf("\nRunning %s\n", e->e_id);
707: while (fgetfolded(buf, sizeof buf, qfp) != NULL)
708: {
709: # ifdef DEBUG
710: if (tTd(40, 4))
711: printf("+++++ %s\n", buf);
712: # endif DEBUG
713: switch (buf[0])
714: {
715: case 'R': /* specify recipient */
716: sendtolist(&buf[1], (ADDRESS *) NULL, &e->e_sendqueue);
717: break;
718:
719: case 'E': /* specify error recipient */
720: sendtolist(&buf[1], (ADDRESS *) NULL, &e->e_errorqueue);
721: break;
722:
723: case 'H': /* header */
724: if (full)
725: (void) chompheader(&buf[1], FALSE);
726: break;
727:
728: case 'M': /* message */
729: e->e_message = newstr(&buf[1]);
730: break;
731:
732: case 'S': /* sender */
733: setsender(newstr(&buf[1]));
734: break;
735:
736: case 'D': /* data file name */
737: if (!full)
738: break;
739: e->e_df = newstr(&buf[1]);
740: e->e_dfp = fopen(e->e_df, "r");
741: if (e->e_dfp == NULL)
742: syserr("readqf: cannot open %s", e->e_df);
743: break;
744:
745: case 'T': /* init time */
746: e->e_ctime = atol(&buf[1]);
747: break;
748:
749: case 'P': /* message priority */
750: e->e_msgpriority = atol(&buf[1]) + WkTimeFact;
751: break;
752:
753: case '\0': /* blank line; ignore */
754: break;
755:
756: default:
757: syserr("readqf(%s:%d): bad line \"%s\"", e->e_id,
758: LineNumber, buf);
759: break;
760: }
761: }
762:
763: (void) fclose(qfp);
764: FileName = NULL;
765:
766: /*
767: ** If we haven't read any lines, this queue file is empty.
768: ** Arrange to remove it without referencing any null pointers.
769: */
770:
771: if (LineNumber == 0)
772: {
773: errno = 0;
774: e->e_flags |= EF_CLRQUEUE | EF_FATALERRS | EF_RESPONSE;
775: }
776: }
777: /*
778: ** PRINTQUEUE -- print out a representation of the mail queue
779: **
780: ** Parameters:
781: ** none.
782: **
783: ** Returns:
784: ** none.
785: **
786: ** Side Effects:
787: ** Prints a listing of the mail queue on the standard output.
788: */
789:
790: printqueue()
791: {
792: register WORK *w;
793: FILE *f;
794: int nrequests;
795: char buf[MAXLINE];
796:
797: /*
798: ** Read and order the queue.
799: */
800:
801: nrequests = orderq(TRUE);
802:
803: /*
804: ** Print the work list that we have read.
805: */
806:
807: /* first see if there is anything */
808: if (nrequests <= 0)
809: {
810: printf("Mail queue is empty\n");
811: return;
812: }
813:
814: printf("\t\tMail Queue (%d request%s", nrequests, nrequests == 1 ? "" : "s");
815: if (nrequests > QUEUESIZE)
816: printf(", only %d printed", QUEUESIZE);
817: if (Verbose)
818: printf(")\n--QID-- --Size-- -Priority- ---Q-Time--- -----------Sender/Recipient-----------\n");
819: else
820: printf(")\n--QID-- --Size-- -----Q-Time----- ------------Sender/Recipient------------\n");
821: for (w = WorkQ; w != NULL; w = w->w_next)
822: {
823: struct stat st;
824: auto time_t submittime = 0;
825: long dfsize = -1;
826: char lf[20];
827: char message[MAXLINE];
828: extern bool shouldqueue();
829:
830: f = fopen(w->w_name, "r");
831: if (f == NULL)
832: {
833: errno = 0;
834: continue;
835: }
836: printf("%7s", w->w_name + 2);
837: (void) strcpy(lf, w->w_name);
838: lf[0] = 'l';
839: if (stat(lf, &st) >= 0)
840: printf("*");
841: else if (shouldqueue(w->w_pri))
842: printf("X");
843: else
844: printf(" ");
845: errno = 0;
846:
847: message[0] = '\0';
848: while (fgets(buf, sizeof buf, f) != NULL)
849: {
850: fixcrlf(buf, TRUE);
851: switch (buf[0])
852: {
853: case 'M': /* error message */
854: (void) strcpy(message, &buf[1]);
855: break;
856:
857: case 'S': /* sender name */
858: if (Verbose)
859: printf("%8ld %10ld %.12s %.38s", dfsize,
860: w->w_pri, ctime(&submittime) + 4,
861: &buf[1]);
862: else
863: printf("%8ld %.16s %.45s", dfsize,
864: ctime(&submittime), &buf[1]);
865: if (message[0] != '\0')
866: printf("\n\t\t (%.60s)", message);
867: break;
868:
869: case 'R': /* recipient name */
870: if (Verbose)
871: printf("\n\t\t\t\t\t %.38s", &buf[1]);
872: else
873: printf("\n\t\t\t\t %.45s", &buf[1]);
874: break;
875:
876: case 'T': /* creation time */
877: submittime = atol(&buf[1]);
878: break;
879:
880: case 'D': /* data file name */
881: if (stat(&buf[1], &st) >= 0)
882: dfsize = st.st_size;
883: break;
884: }
885: }
886: if (submittime == (time_t) 0)
887: printf(" (no control file)");
888: printf("\n");
889: (void) fclose(f);
890: }
891: }
892:
893: # endif QUEUE
894: /*
895: ** QUEUENAME -- build a file name in the queue directory for this envelope.
896: **
897: ** Assigns an id code if one does not already exist.
898: ** This code is very careful to avoid trashing existing files
899: ** under any circumstances.
900: ** We first create an nf file that is only used when
901: ** assigning an id. This file is always empty, so that
902: ** we can never accidently truncate an lf file.
903: **
904: ** Parameters:
905: ** e -- envelope to build it in/from.
906: ** type -- the file type, used as the first character
907: ** of the file name.
908: **
909: ** Returns:
910: ** a pointer to the new file name (in a static buffer).
911: **
912: ** Side Effects:
913: ** Will create the lf and qf files if no id code is
914: ** already assigned. This will cause the envelope
915: ** to be modified.
916: */
917:
918: char *
919: queuename(e, type)
920: register ENVELOPE *e;
921: char type;
922: {
923: static char buf[MAXNAME];
924: static int pid = -1;
925: char c1 = 'A';
926: char c2 = 'A';
927:
928: if (e->e_id == NULL)
929: {
930: char qf[20];
931: char nf[20];
932: char lf[20];
933:
934: /* find a unique id */
935: if (pid != getpid())
936: {
937: /* new process -- start back at "AA" */
938: pid = getpid();
939: c1 = 'A';
940: c2 = 'A' - 1;
941: }
942: (void) sprintf(qf, "qfAA%05d", pid);
943: (void) strcpy(lf, qf);
944: lf[0] = 'l';
945: (void) strcpy(nf, qf);
946: nf[0] = 'n';
947:
948: while (c1 < '~' || c2 < 'Z')
949: {
950: int i;
951:
952: if (c2 >= 'Z')
953: {
954: c1++;
955: c2 = 'A' - 1;
956: }
957: lf[2] = nf[2] = qf[2] = c1;
958: lf[3] = nf[3] = qf[3] = ++c2;
959: # ifdef DEBUG
960: if (tTd(7, 20))
961: printf("queuename: trying \"%s\"\n", nf);
962: # endif DEBUG
963:
964: # ifdef QUEUE
965: if (access(lf, 0) >= 0 || access(qf, 0) >= 0)
966: continue;
967: errno = 0;
968: i = creat(nf, FileMode);
969: if (i < 0)
970: {
971: (void) unlink(nf); /* kernel bug */
972: continue;
973: }
974: (void) close(i);
975: i = link(nf, lf);
976: (void) unlink(nf);
977: if (i < 0)
978: continue;
979: if (link(lf, qf) >= 0)
980: break;
981: (void) unlink(lf);
982: # else QUEUE
983: if (close(creat(qf, FileMode)) >= 0)
984: break;
985: # endif QUEUE
986: }
987: if (c1 >= '~' && c2 >= 'Z')
988: {
989: syserr("queuename: Cannot create \"%s\" in \"%s\"",
990: qf, QueueDir);
991: exit(EX_OSERR);
992: }
993: e->e_id = newstr(&qf[2]);
994: define('i', e->e_id, e);
995: # ifdef DEBUG
996: if (tTd(7, 1))
997: printf("queuename: assigned id %s, env=%x\n", e->e_id, e);
998: # ifdef LOG
999: if (LogLevel > 16)
1000: syslog(LOG_DEBUG, "%s: assigned id", e->e_id);
1001: # endif LOG
1002: # endif DEBUG
1003: }
1004:
1005: if (type == '\0')
1006: return (NULL);
1007: (void) sprintf(buf, "%cf%s", type, e->e_id);
1008: # ifdef DEBUG
1009: if (tTd(7, 2))
1010: printf("queuename: %s\n", buf);
1011: # endif DEBUG
1012: return (buf);
1013: }
1014: /*
1015: ** UNLOCKQUEUE -- unlock the queue entry for a specified envelope
1016: **
1017: ** Parameters:
1018: ** e -- the envelope to unlock.
1019: **
1020: ** Returns:
1021: ** none
1022: **
1023: ** Side Effects:
1024: ** unlocks the queue for `e'.
1025: */
1026:
1027: unlockqueue(e)
1028: ENVELOPE *e;
1029: {
1030: /* remove the transcript */
1031: #ifdef DEBUG
1032: # ifdef LOG
1033: if (LogLevel > 19)
1034: syslog(LOG_DEBUG, "%s: unlock", e->e_id);
1035: # endif LOG
1036: if (!tTd(51, 4))
1037: #endif DEBUG
1038: xunlink(queuename(e, 'x'));
1039:
1040: # ifdef QUEUE
1041: /* last but not least, remove the lock */
1042: xunlink(queuename(e, 'l'));
1043: # endif QUEUE
1044: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.