static void
term_handler(int sig)
{
- exit(1);
+exit(1);
}
when a bug in a function that calls milliwait() caused it to pass invalid data.
That's when I added the check. :-)
-We assume it to be not worth sleeping for under 100us; this value will
+We assume it to be not worth sleeping for under 50us; this value will
require revisiting as hardware advances. This avoids the issue of
a zero-valued timer setting meaning "never fire".
sigset_t sigmask;
sigset_t old_sigmask;
-if (itval->it_value.tv_usec < 100 && itval->it_value.tv_sec == 0)
+if (itval->it_value.tv_usec < 50 && itval->it_value.tv_sec == 0)
return;
(void)sigemptyset(&sigmask); /* Empty mask */
(void)sigaddset(&sigmask, SIGALRM); /* Add SIGALRM */
* Clock tick wait function *
*************************************************/
+#ifdef _POSIX_MONOTONIC_CLOCK
+/* Amount CLOCK_MONOTONIC is behind realtime, at startup. */
+static struct timespec offset_ts;
+
+static void
+exim_clock_init(void)
+{
+struct timeval tv;
+if (clock_gettime(CLOCK_MONOTONIC, &offset_ts) != 0) return;
+(void)gettimeofday(&tv, NULL);
+offset_ts.tv_sec = tv.tv_sec - offset_ts.tv_sec;
+offset_ts.tv_nsec = tv.tv_usec * 1000 - offset_ts.tv_nsec;
+if (offset_ts.tv_nsec >= 0) return;
+offset_ts.tv_sec--;
+offset_ts.tv_nsec += 1000*1000*1000;
+}
+#endif
+
+
/* Exim uses a time + a pid to generate a unique identifier in two places: its
message IDs, and in file names for maildir deliveries. Because some OS now
re-use pids within the same second, sub-second times are now being used.
clocks that go backwards.
Arguments:
- then_tv A timeval which was used to create uniqueness; its usec field
+ tgt_tv A timeval which was used to create uniqueness; its usec field
has been rounded down to the value of the resolution.
We want to be sure the current time is greater than this.
resolution The resolution that was used to divide the microseconds
*/
void
-exim_wait_tick(struct timeval *then_tv, int resolution)
+exim_wait_tick(struct timeval * tgt_tv, int resolution)
{
struct timeval now_tv;
long int now_true_usec;
-(void)gettimeofday(&now_tv, NULL);
-now_true_usec = now_tv.tv_usec;
-now_tv.tv_usec = (now_true_usec/resolution) * resolution;
+#ifdef _POSIX_MONOTONIC_CLOCK
+struct timespec now_ts;
+
+if (clock_gettime(CLOCK_MONOTONIC, &now_ts) == 0)
+ {
+ now_ts.tv_sec += offset_ts.tv_sec;
+ if ((now_ts.tv_nsec += offset_ts.tv_nsec) >= 1000*1000*1000)
+ {
+ now_ts.tv_sec++;
+ now_ts.tv_nsec -= 1000*1000*1000;
+ }
+ now_tv.tv_sec = now_ts.tv_sec;
+ now_true_usec = (now_ts.tv_nsec / (resolution * 1000)) * resolution;
+ now_tv.tv_usec = now_true_usec;
+ }
+else
+#endif
+ {
+ (void)gettimeofday(&now_tv, NULL);
+ now_true_usec = now_tv.tv_usec;
+ now_tv.tv_usec = (now_true_usec/resolution) * resolution;
+ }
-if (exim_tvcmp(&now_tv, then_tv) <= 0)
+while (exim_tvcmp(&now_tv, tgt_tv) <= 0)
{
struct itimerval itval;
itval.it_interval.tv_sec = 0;
itval.it_interval.tv_usec = 0;
- itval.it_value.tv_sec = then_tv->tv_sec - now_tv.tv_sec;
- itval.it_value.tv_usec = then_tv->tv_usec + resolution - now_true_usec;
+ itval.it_value.tv_sec = tgt_tv->tv_sec - now_tv.tv_sec;
+ itval.it_value.tv_usec = tgt_tv->tv_usec + resolution - now_true_usec;
/* We know that, overall, "now" is less than or equal to "then". Therefore, a
negative value for the microseconds is possible only in the case when "now"
- is more than a second less than "then". That means that itval.it_value.tv_sec
+ is more than a second less than "tgt". That means that itval.it_value.tv_sec
is greater than zero. The following correction is therefore safe. */
if (itval.it_value.tv_usec < 0)
if (!f.running_in_test_harness)
{
debug_printf("tick check: " TIME_T_FMT ".%06lu " TIME_T_FMT ".%06lu\n",
- then_tv->tv_sec, (long) then_tv->tv_usec,
+ tgt_tv->tv_sec, (long) tgt_tv->tv_usec,
now_tv.tv_sec, (long) now_tv.tv_usec);
- debug_printf("waiting " TIME_T_FMT ".%06lu\n",
+ debug_printf("waiting " TIME_T_FMT ".%06lu sec\n",
itval.it_value.tv_sec, (long) itval.it_value.tv_usec);
}
}
milliwait(&itval);
+
+ /* Be prapared to go around if the kernel does not implement subtick
+ granularity (GNU Hurd) */
+
+ (void)gettimeofday(&now_tv, NULL);
+ now_true_usec = now_tv.tv_usec;
+ now_tv.tv_usec = (now_true_usec/resolution) * resolution;
}
}
#ifndef DISABLE_OCSP
fprintf(fp, " OCSP");
#endif
-#ifdef SUPPORT_PIPE_CONNECT
+#ifndef DISABLE_PIPE_CONNECT
fprintf(fp, " PIPE_CONNECT");
#endif
#ifndef DISABLE_PRDR
setlocale(LC_ALL, "C");
+/* Get the offset between CLOCK_MONOTONIC and wallclock */
+
+#ifdef _POSIX_MONOTONIC_CLOCK
+exim_clock_init();
+#endif
+
/* Set up the default handler for timing using alarm(). */
os_non_restarting_signal(SIGALRM, sigalrm_handler);
msg_action = MSG_DELIVER;
deliver_give_up = TRUE;
}
+ else if (Ustrcmp(argrest, "G") == 0)
+ {
+ msg_action = MSG_SETQUEUE;
+ queue_name_dest = argv[++i];
+ }
else if (Ustrcmp(argrest, "mad") == 0)
{
msg_action = MSG_MARK_ALL_DELIVERED;
else if (Ustrcmp(argrest, "o") == 0) {}
- /* -oP <name>: set pid file path for daemon */
+ /* -oP <name>: set pid file path for daemon
+ -oPX: delete pid file of daemon */
else if (Ustrcmp(argrest, "P") == 0)
override_pid_file_path = argv[++i];
+ else if (Ustrcmp(argrest, "PX") == 0)
+ delete_pid_file();
+
/* -or <n>: set timeout for non-SMTP acceptance
-os <n>: set timeout for SMTP acceptance */
if (!f.admin_user)
{
BOOL debugset = (debug_selector & ~D_v) != 0;
- if (deliver_give_up || f.daemon_listen || malware_test_file ||
- (count_queue && queue_list_requires_admin) ||
- (list_queue && queue_list_requires_admin) ||
- (queue_interval >= 0 && prod_requires_admin) ||
- (debugset && !f.running_in_test_harness))
+ if ( deliver_give_up || f.daemon_listen || malware_test_file
+ || count_queue && queue_list_requires_admin
+ || list_queue && queue_list_requires_admin
+ || queue_interval >= 0 && prod_requires_admin
+ || queue_name_dest && prod_requires_admin
+ || debugset && !f.running_in_test_harness
+ )
exim_fail("exim:%s permission denied\n", debugset? " debugging" : "");
}
root. There will be further calls later for each message received. */
#ifdef LOAD_AVG_NEEDS_ROOT
-if (receiving_message &&
- (queue_only_load >= 0 ||
- (f.is_inetd && smtp_load_reserve >= 0)
- ))
- {
+if ( receiving_message
+ && (queue_only_load >= 0 || (f.is_inetd && smtp_load_reserve >= 0)))
load_average = OS_GETLOADAVG();
- }
#endif
/* The queue_only configuration option can be overridden by -odx on the command
for (i = msg_action_arg; i < argc; i++)
if (!queue_action(argv[i], msg_action, NULL, 0, 0))
yield = EXIT_FAILURE;
+ switch (msg_action)
+ {
+ case MSG_REMOVE: MSG_DELETE: case MSG_FREEZE: case MSG_THAW: break;
+ default: printf("\n"); break;
+ }
}
else if (!queue_action(argv[msg_action_arg], msg_action, argv, argc,
{
while (recipients_arg < argc)
{
- uschar *s = argv[recipients_arg++];
- while (*s != 0)
+ /* Supplied addresses are tainted since they come from a user */
+ uschar * s = string_copy_taint(argv[recipients_arg++], TRUE);
+ while (*s)
{
BOOL finished = FALSE;
uschar *ss = parse_find_address_end(s, FALSE);
test_address(s, flags, &exit_value);
s = ss;
if (!finished)
- while (*(++s) != 0 && (*s == ',' || isspace(*s)));
+ while (*++s == ',' || isspace(*s)) ;
}
}
}
else for (;;)
{
- uschar *s = get_stdinput(NULL, NULL);
- if (s == NULL) break;
- test_address(s, flags, &exit_value);
+ uschar * s = get_stdinput(NULL, NULL);
+ if (!s) break;
+ test_address(string_copy_taint(s, TRUE), flags, &exit_value);
}
route_tidyup();
raw_sender = string_copy(sender_address);
- /* Loop for each argument */
+ /* Loop for each argument (supplied by user hence tainted) */
for (int i = 0; i < count; i++)
{
int start, end, domain;
- uschar *errmess;
- uschar *s = list[i];
+ uschar * errmess;
+ uschar * s = string_copy_taint(list[i], TRUE);
/* Loop for each comma-separated address */