]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/sendmail/src/sched.c
Merge commit '850ef5ae11d69ea3381bd310f564f025fc8caea3'
[FreeBSD/FreeBSD.git] / contrib / sendmail / src / sched.c
1 /*
2  * Copyright (c) 2021 Proofpoint, Inc. and its suppliers.
3  *      All rights reserved.
4  *
5  * By using this file, you agree to the terms and conditions set
6  * forth in the LICENSE file which can be found at the top level of
7  * the sendmail distribution.
8  *
9  */
10
11 #include <sendmail.h>
12
13 #if _FFR_DMTRIGGER
14 #include <sm/sendmail.h>
15 #include <sm/notify.h>
16
17 static ENVELOPE QmEnvelope;
18
19 /*
20 **  Macro for fork():
21 **  FORK_P1(): parent
22 **  FORK_C1(): child
23 **  Note: these are not "universal", e.g.,
24 **  proc_list_add() might be used in parent or child.
25 **  maybe check pname != NULL to invoke proc_list_add()?
26 */
27
28 #define FORK_P1(emsg, pname, ptype)     \
29         do {    \
30                 (void) sm_blocksignal(SIGCHLD); \
31                 (void) sm_signal(SIGCHLD, reapchild);   \
32                 \
33                 pid = dofork(); \
34                 if (pid == -1)  \
35                 {       \
36                         const char *msg = emsg; \
37                         const char *err = sm_errstring(errno);  \
38                 \
39                         if (LogLevel > 8)       \
40                                 sm_syslog(LOG_INFO, NOQID, "%s: %s",    \
41                                           msg, err);    \
42                         (void) sm_releasesignal(SIGCHLD);       \
43                         return false;   \
44                 }       \
45                 if (pid != 0)   \
46                 {       \
47                         proc_list_add(pid, pname, ptype, 0, -1, NULL); \
48                         /* parent -- pick up intermediate zombie */     \
49                         (void) sm_releasesignal(SIGCHLD);       \
50                         return true;    \
51                 }       \
52         } while (0)
53
54 #define FORK_C1()       \
55         do {    \
56                 /* child -- clean up signals */ \
57                 \
58                 /* Reset global flags */        \
59                 RestartRequest = NULL;  \
60                 RestartWorkGroup = false;       \
61                 ShutdownRequest = NULL; \
62                 PendingSignal = 0;      \
63                 CurrentPid = getpid();  \
64                 close_sendmail_pid();   \
65                 \
66                 /*      \
67                 **  Initialize exception stack and default exception    \
68                 **  handler for child process.  \
69                 */      \
70                 \
71                 sm_exc_newthread(fatal_error);  \
72                 clrcontrol();   \
73                 proc_list_clear();      \
74                 \
75                 (void) sm_releasesignal(SIGCHLD);       \
76                 (void) sm_signal(SIGCHLD, SIG_DFL);     \
77                 (void) sm_signal(SIGHUP, SIG_DFL);      \
78                 (void) sm_signal(SIGTERM, intsig);      \
79                 \
80                 /* drop privileges */   \
81                 if (geteuid() == (uid_t) 0)     \
82                         (void) drop_privileges(false);  \
83                 disconnect(1, NULL);    \
84                 QuickAbort = false;     \
85                 \
86         } while (0)
87
88 /*
89 **  QM -- queue "manager"
90 **
91 **      Parameters:
92 **              none.
93 **
94 **      Returns:
95 **              false on error
96 **
97 **      Side Effects:
98 **              fork()s and runs as process to deliver queue entries
99 */
100
101 bool
102 qm()
103 {
104         int r;
105         pid_t pid;
106         long tmo;
107
108         sm_syslog(LOG_DEBUG, NOQID, "queue manager: start");
109
110         FORK_P1("Queue manager -- fork() failed", "QM", PROC_QM);
111         FORK_C1();
112
113         r = sm_notify_start(true, 0);
114         if (r != 0)
115                 syserr("sm_notify_start() failed=%d", r);
116
117         /*
118         **  Initially wait indefinitely, then only wait
119         **  until something needs to get done (not yet implemented).
120         */
121
122         tmo = -1;
123         while (true)
124         {
125                 char buf[64];
126                 ENVELOPE *e;
127                 SM_RPOOL_T *rpool;
128
129 /*
130 **  TODO: This should try to receive multiple ids:
131 **  after it got one, check for more with a very short timeout
132 **  and collect them in a list.
133 **  but them some other code should be used to run all of them.
134 */
135
136                 sm_syslog(LOG_DEBUG, NOQID, "queue manager: rcv=start");
137                 r = sm_notify_rcv(buf, sizeof(buf), tmo);
138                 if (-ETIMEDOUT == r)
139                 {
140                         sm_syslog(LOG_DEBUG, NOQID, "queue manager: rcv=timed_out");
141                         continue;
142                 }
143                 if (r < 0)
144                 {
145                         sm_syslog(LOG_DEBUG, NOQID, "queue manager: rcv=%d", r);
146                         goto end;
147                 }
148                 if (r > 0 && r < sizeof(buf))
149                         buf[r] = '\0';
150                 buf[sizeof(buf) - 1] = '\0';
151                 sm_syslog(LOG_DEBUG, NOQID, "queue manager: got=%s", buf);
152                 CurEnv = &QmEnvelope;
153                 rpool = sm_rpool_new_x(NULL);
154                 e = newenvelope(&QmEnvelope, CurEnv, rpool);
155                 e->e_flags = BlankEnvelope.e_flags;
156                 e->e_parent = NULL;
157                 r = sm_io_sscanf(buf, "N:%d:%d:%s", &e->e_qgrp, &e->e_qdir, e->e_id);
158                 if (r != 3)
159                 {
160                         sm_syslog(LOG_DEBUG, NOQID, "queue manager: buf=%s, scan=%d", buf, r);
161                         goto end;
162                 }
163                 dowork(e->e_qgrp, e->e_qdir, e->e_id, true, false, e);
164         }
165
166   end:
167         sm_syslog(LOG_DEBUG, NOQID, "queue manager: stop");
168         finis(false, false, EX_OK);
169         /* NOTREACHED */
170         return false;
171 }
172 #endif /* _FFR_DMTRIGGER */