Fix a bug when '-f -H' is used and the target already exists. cpdup was
[dragonfly.git] / contrib / sendmail-8.13.8 / libsm / clock.c
1 /*
2  * Copyright (c) 1998-2004 Sendmail, Inc. and its suppliers.
3  *      All rights reserved.
4  * Copyright (c) 1983, 1995-1997 Eric P. Allman.  All rights reserved.
5  * Copyright (c) 1988, 1993
6  *      The Regents of the University of California.  All rights reserved.
7  *
8  * By using this file, you agree to the terms and conditions set
9  * forth in the LICENSE file which can be found at the top level of
10  * the sendmail distribution.
11  *
12  */
13
14 #include <sm/gen.h>
15 SM_RCSID("@(#)$Id: clock.c,v 1.47 2005/06/14 23:07:20 ca Exp $")
16 #include <unistd.h>
17 #include <time.h>
18 #include <errno.h>
19 #if SM_CONF_SETITIMER
20 # include <sm/time.h>
21 #endif /* SM_CONF_SETITIMER */
22 #include <sm/heap.h>
23 #include <sm/debug.h>
24 #include <sm/bitops.h>
25 #include <sm/clock.h>
26 #include "local.h"
27 #if _FFR_SLEEP_USE_SELECT > 0
28 # include <sys/types.h>
29 #endif /* _FFR_SLEEP_USE_SELECT > 0 */
30 #if defined(_FFR_MAX_SLEEP_TIME) && _FFR_MAX_SLEEP_TIME > 2
31 # include <syslog.h>
32 #endif /* defined(_FFR_MAX_SLEEP_TIME) && _FFR_MAX_SLEEP_TIME > 2 */
33
34 #ifndef sigmask
35 # define sigmask(s)     (1 << ((s) - 1))
36 #endif /* ! sigmask */
37
38
39 /*
40 **  SM_SETEVENTM -- set an event to happen at a specific time in milliseconds.
41 **
42 **      Events are stored in a sorted list for fast processing.
43 **      An event only applies to the process that set it.
44 **      Source is #ifdef'd to work with older OS's that don't have setitimer()
45 **      (that is, don't have a timer granularity less than 1 second).
46 **
47 **      Parameters:
48 **              intvl -- interval until next event occurs (milliseconds).
49 **              func -- function to call on event.
50 **              arg -- argument to func on event.
51 **
52 **      Returns:
53 **              On success returns the SM_EVENT entry created.
54 **              On failure returns NULL.
55 **
56 **      Side Effects:
57 **              none.
58 */
59
60 static SM_EVENT *volatile SmEventQueue;         /* head of event queue */
61 static SM_EVENT *volatile SmFreeEventList;      /* list of free events */
62
63 SM_EVENT *
64 sm_seteventm(intvl, func, arg)
65         int intvl;
66         void (*func)__P((int));
67         int arg;
68 {
69         ENTER_CRITICAL();
70         if (SmFreeEventList == NULL)
71         {
72                 SmFreeEventList = (SM_EVENT *) sm_pmalloc_x(sizeof *SmFreeEventList);
73                 SmFreeEventList->ev_link = NULL;
74         }
75         LEAVE_CRITICAL();
76
77         return sm_sigsafe_seteventm(intvl, func, arg);
78 }
79
80 /*
81 **      NOTE:   THIS CAN BE CALLED FROM A SIGNAL HANDLER.  DO NOT ADD
82 **              ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE
83 **              DOING.
84 */
85
86 SM_EVENT *
87 sm_sigsafe_seteventm(intvl, func, arg)
88         int intvl;
89         void (*func)__P((int));
90         int arg;
91 {
92         register SM_EVENT **evp;
93         register SM_EVENT *ev;
94 #if SM_CONF_SETITIMER
95         auto struct timeval now, nowi, ival;
96         auto struct itimerval itime;
97 #else /*  SM_CONF_SETITIMER */
98         auto time_t now, nowi;
99 #endif /*  SM_CONF_SETITIMER */
100         int wasblocked;
101
102         /* negative times are not allowed */
103         if (intvl <= 0)
104                 return NULL;
105
106         wasblocked = sm_blocksignal(SIGALRM);
107 #if SM_CONF_SETITIMER
108         ival.tv_sec = intvl / 1000;
109         ival.tv_usec = (intvl - ival.tv_sec * 1000) * 10;
110         (void) gettimeofday(&now, NULL);
111         nowi = now;
112         timeradd(&now, &ival, &nowi);
113 #else /*  SM_CONF_SETITIMER */
114         now = time(NULL);
115         nowi = now + (time_t)(intvl / 1000);
116 #endif /*  SM_CONF_SETITIMER */
117
118         /* search event queue for correct position */
119         for (evp = (SM_EVENT **) (&SmEventQueue);
120              (ev = *evp) != NULL;
121              evp = &ev->ev_link)
122         {
123 #if SM_CONF_SETITIMER
124                 if (timercmp(&(ev->ev_time), &nowi, >=))
125 #else /* SM_CONF_SETITIMER */
126                 if (ev->ev_time >= nowi)
127 #endif /* SM_CONF_SETITIMER */
128                         break;
129         }
130
131         ENTER_CRITICAL();
132         if (SmFreeEventList == NULL)
133         {
134                 /*
135                 **  This shouldn't happen.  If called from sm_seteventm(),
136                 **  we have just malloced a SmFreeEventList entry.  If
137                 **  called from a signal handler, it should have been
138                 **  from an existing event which sm_tick() just added to
139                 **  SmFreeEventList.
140                 */
141
142                 LEAVE_CRITICAL();
143                 if (wasblocked == 0)
144                         (void) sm_releasesignal(SIGALRM);
145                 return NULL;
146         }
147         else
148         {
149                 ev = SmFreeEventList;
150                 SmFreeEventList = ev->ev_link;
151         }
152         LEAVE_CRITICAL();
153
154         /* insert new event */
155         ev->ev_time = nowi;
156         ev->ev_func = func;
157         ev->ev_arg = arg;
158         ev->ev_pid = getpid();
159         ENTER_CRITICAL();
160         ev->ev_link = *evp;
161         *evp = ev;
162         LEAVE_CRITICAL();
163
164         (void) sm_signal(SIGALRM, sm_tick);
165 # if SM_CONF_SETITIMER
166         timersub(&SmEventQueue->ev_time, &now, &itime.it_value);
167         itime.it_interval.tv_sec = 0;
168         itime.it_interval.tv_usec = 0;
169         if (itime.it_value.tv_sec < 0)
170                 itime.it_value.tv_sec = 0;
171         if (itime.it_value.tv_sec == 0 && itime.it_value.tv_usec == 0)
172                 itime.it_value.tv_usec = 1000;
173         (void) setitimer(ITIMER_REAL, &itime, NULL);
174 # else /* SM_CONF_SETITIMER */
175         intvl = SmEventQueue->ev_time - now;
176         (void) alarm((unsigned) (intvl < 1 ? 1 : intvl));
177 # endif /* SM_CONF_SETITIMER */
178         if (wasblocked == 0)
179                 (void) sm_releasesignal(SIGALRM);
180         return ev;
181 }
182 /*
183 **  SM_CLREVENT -- remove an event from the event queue.
184 **
185 **      Parameters:
186 **              ev -- pointer to event to remove.
187 **
188 **      Returns:
189 **              none.
190 **
191 **      Side Effects:
192 **              arranges for event ev to not happen.
193 */
194
195 void
196 sm_clrevent(ev)
197         register SM_EVENT *ev;
198 {
199         register SM_EVENT **evp;
200         int wasblocked;
201 # if SM_CONF_SETITIMER
202         struct itimerval clr;
203 # endif /* SM_CONF_SETITIMER */
204
205         if (ev == NULL)
206                 return;
207
208         /* find the parent event */
209         wasblocked = sm_blocksignal(SIGALRM);
210         for (evp = (SM_EVENT **) (&SmEventQueue);
211              *evp != NULL;
212              evp = &(*evp)->ev_link)
213         {
214                 if (*evp == ev)
215                         break;
216         }
217
218         /* now remove it */
219         if (*evp != NULL)
220         {
221                 ENTER_CRITICAL();
222                 *evp = ev->ev_link;
223                 ev->ev_link = SmFreeEventList;
224                 SmFreeEventList = ev;
225                 LEAVE_CRITICAL();
226         }
227
228         /* restore clocks and pick up anything spare */
229         if (wasblocked == 0)
230                 (void) sm_releasesignal(SIGALRM);
231         if (SmEventQueue != NULL)
232                 (void) kill(getpid(), SIGALRM);
233         else
234         {
235                 /* nothing left in event queue, no need for an alarm */
236 # if SM_CONF_SETITIMER
237                 clr.it_interval.tv_sec = 0;
238                 clr.it_interval.tv_usec = 0;
239                 clr.it_value.tv_sec = 0;
240                 clr.it_value.tv_usec = 0;
241                 (void) setitimer(ITIMER_REAL, &clr, NULL);
242 # else /* SM_CONF_SETITIMER */
243                 (void) alarm(0);
244 # endif /* SM_CONF_SETITIMER */
245         }
246 }
247 /*
248 **  SM_CLEAR_EVENTS -- remove all events from the event queue.
249 **
250 **      Parameters:
251 **              none.
252 **
253 **      Returns:
254 **              none.
255 */
256
257 void
258 sm_clear_events()
259 {
260         register SM_EVENT *ev;
261 #if SM_CONF_SETITIMER
262         struct itimerval clr;
263 #endif /* SM_CONF_SETITIMER */
264         int wasblocked;
265
266         /* nothing will be left in event queue, no need for an alarm */
267 #if SM_CONF_SETITIMER
268         clr.it_interval.tv_sec = 0;
269         clr.it_interval.tv_usec = 0;
270         clr.it_value.tv_sec = 0;
271         clr.it_value.tv_usec = 0;
272         (void) setitimer(ITIMER_REAL, &clr, NULL);
273 #else /* SM_CONF_SETITIMER */
274         (void) alarm(0);
275 #endif /* SM_CONF_SETITIMER */
276
277         if (SmEventQueue == NULL)
278                 return;
279
280         wasblocked = sm_blocksignal(SIGALRM);
281
282         /* find the end of the EventQueue */
283         for (ev = SmEventQueue; ev->ev_link != NULL; ev = ev->ev_link)
284                 continue;
285
286         ENTER_CRITICAL();
287         ev->ev_link = SmFreeEventList;
288         SmFreeEventList = SmEventQueue;
289         SmEventQueue = NULL;
290         LEAVE_CRITICAL();
291
292         /* restore clocks and pick up anything spare */
293         if (wasblocked == 0)
294                 (void) sm_releasesignal(SIGALRM);
295 }
296 /*
297 **  SM_TICK -- take a clock tick
298 **
299 **      Called by the alarm clock.  This routine runs events as needed.
300 **      Always called as a signal handler, so we assume that SIGALRM
301 **      has been blocked.
302 **
303 **      Parameters:
304 **              One that is ignored; for compatibility with signal handlers.
305 **
306 **      Returns:
307 **              none.
308 **
309 **      Side Effects:
310 **              calls the next function in EventQueue.
311 **
312 **      NOTE:   THIS CAN BE CALLED FROM A SIGNAL HANDLER.  DO NOT ADD
313 **              ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE
314 **              DOING.
315 */
316
317 /* ARGSUSED */
318 SIGFUNC_DECL
319 sm_tick(sig)
320         int sig;
321 {
322         register SM_EVENT *ev;
323         pid_t mypid;
324         int save_errno = errno;
325 #if SM_CONF_SETITIMER
326         struct itimerval clr;
327         struct timeval now;
328 #else /* SM_CONF_SETITIMER */
329         register time_t now;
330 #endif /* SM_CONF_SETITIMER */
331
332 #if SM_CONF_SETITIMER
333         clr.it_interval.tv_sec = 0;
334         clr.it_interval.tv_usec = 0;
335         clr.it_value.tv_sec = 0;
336         clr.it_value.tv_usec = 0;
337         (void) setitimer(ITIMER_REAL, &clr, NULL);
338         gettimeofday(&now, NULL);
339 #else /* SM_CONF_SETITIMER */
340         (void) alarm(0);
341         now = time(NULL);
342 #endif /* SM_CONF_SETITIMER */
343
344         FIX_SYSV_SIGNAL(sig, sm_tick);
345         errno = save_errno;
346         CHECK_CRITICAL(sig);
347
348         mypid = getpid();
349         while (PendingSignal != 0)
350         {
351                 int sigbit = 0;
352                 int sig = 0;
353
354                 if (bitset(PEND_SIGHUP, PendingSignal))
355                 {
356                         sigbit = PEND_SIGHUP;
357                         sig = SIGHUP;
358                 }
359                 else if (bitset(PEND_SIGINT, PendingSignal))
360                 {
361                         sigbit = PEND_SIGINT;
362                         sig = SIGINT;
363                 }
364                 else if (bitset(PEND_SIGTERM, PendingSignal))
365                 {
366                         sigbit = PEND_SIGTERM;
367                         sig = SIGTERM;
368                 }
369                 else if (bitset(PEND_SIGUSR1, PendingSignal))
370                 {
371                         sigbit = PEND_SIGUSR1;
372                         sig = SIGUSR1;
373                 }
374                 else
375                 {
376                         /* If we get here, we are in trouble */
377                         abort();
378                 }
379                 PendingSignal &= ~sigbit;
380                 kill(mypid, sig);
381         }
382
383 #if SM_CONF_SETITIMER
384         gettimeofday(&now, NULL);
385 #else /* SM_CONF_SETITIMER */
386         now = time(NULL);
387 #endif /* SM_CONF_SETITIMER */
388         while ((ev = SmEventQueue) != NULL &&
389                (ev->ev_pid != mypid ||
390 #if SM_CONF_SETITIMER
391                 timercmp(&ev->ev_time, &now, <=)
392 #else /* SM_CONF_SETITIMER */
393                 ev->ev_time <= now
394 #endif /* SM_CONF_SETITIMER */
395                 ))
396         {
397                 void (*f)__P((int));
398                 int arg;
399                 pid_t pid;
400
401                 /* process the event on the top of the queue */
402                 ev = SmEventQueue;
403                 SmEventQueue = SmEventQueue->ev_link;
404
405                 /* we must be careful in here because ev_func may not return */
406                 f = ev->ev_func;
407                 arg = ev->ev_arg;
408                 pid = ev->ev_pid;
409                 ENTER_CRITICAL();
410                 ev->ev_link = SmFreeEventList;
411                 SmFreeEventList = ev;
412                 LEAVE_CRITICAL();
413                 if (pid != getpid())
414                         continue;
415                 if (SmEventQueue != NULL)
416                 {
417 #if SM_CONF_SETITIMER
418                         if (timercmp(&SmEventQueue->ev_time, &now, >))
419                         {
420                                 timersub(&SmEventQueue->ev_time, &now,
421                                          &clr.it_value);
422                                 clr.it_interval.tv_sec = 0;
423                                 clr.it_interval.tv_usec = 0;
424                                 if (clr.it_value.tv_sec < 0)
425                                         clr.it_value.tv_sec = 0;
426                                 if (clr.it_value.tv_sec == 0 &&
427                                     clr.it_value.tv_usec == 0)
428                                         clr.it_value.tv_usec = 1000;
429                                 (void) setitimer(ITIMER_REAL, &clr, NULL);
430                         }
431                         else
432                         {
433                                 clr.it_interval.tv_sec = 0;
434                                 clr.it_interval.tv_usec = 0;
435                                 clr.it_value.tv_sec = 3;
436                                 clr.it_value.tv_usec = 0;
437                                 (void) setitimer(ITIMER_REAL, &clr, NULL);
438                         }
439 #else /* SM_CONF_SETITIMER */
440                         if (SmEventQueue->ev_time > now)
441                                 (void) alarm((unsigned) (SmEventQueue->ev_time
442                                                          - now));
443                         else
444                                 (void) alarm(3);
445 #endif /* SM_CONF_SETITIMER */
446                 }
447
448                 /* call ev_func */
449                 errno = save_errno;
450                 (*f)(arg);
451 #if SM_CONF_SETITIMER
452                 clr.it_interval.tv_sec = 0;
453                 clr.it_interval.tv_usec = 0;
454                 clr.it_value.tv_sec = 0;
455                 clr.it_value.tv_usec = 0;
456                 (void) setitimer(ITIMER_REAL, &clr, NULL);
457                 gettimeofday(&now, NULL);
458 #else /* SM_CONF_SETITIMER */
459                 (void) alarm(0);
460                 now = time(NULL);
461 #endif /* SM_CONF_SETITIMER */
462         }
463         if (SmEventQueue != NULL)
464         {
465 #if SM_CONF_SETITIMER
466                 timersub(&SmEventQueue->ev_time, &now, &clr.it_value);
467                 clr.it_interval.tv_sec = 0;
468                 clr.it_interval.tv_usec = 0;
469                 if (clr.it_value.tv_sec < 0)
470                         clr.it_value.tv_sec = 0;
471                 if (clr.it_value.tv_sec == 0 && clr.it_value.tv_usec == 0)
472                         clr.it_value.tv_usec = 1000;
473                 (void) setitimer(ITIMER_REAL, &clr, NULL);
474 #else /* SM_CONF_SETITIMER */
475                 (void) alarm((unsigned) (SmEventQueue->ev_time - now));
476 #endif /* SM_CONF_SETITIMER */
477         }
478         errno = save_errno;
479         return SIGFUNC_RETURN;
480 }
481 /*
482 **  SLEEP -- a version of sleep that works with this stuff
483 **
484 **      Because Unix sleep uses the alarm facility, I must reimplement
485 **      it here.
486 **
487 **      Parameters:
488 **              intvl -- time to sleep.
489 **
490 **      Returns:
491 **              zero.
492 **
493 **      Side Effects:
494 **              waits for intvl time.  However, other events can
495 **              be run during that interval.
496 */
497
498
499 # if !HAVE_NANOSLEEP
500 static void     sm_endsleep __P((int));
501 static bool     volatile SmSleepDone;
502 # endif /* !HAVE_NANOSLEEP */
503
504 #ifndef SLEEP_T
505 # define SLEEP_T        unsigned int
506 #endif /* ! SLEEP_T */
507
508 SLEEP_T
509 sleep(intvl)
510         unsigned int intvl;
511 {
512 #if HAVE_NANOSLEEP
513         struct timespec rqtp;
514
515         if (intvl == 0)
516                 return (SLEEP_T) 0;
517         rqtp.tv_sec = intvl;
518         rqtp.tv_nsec = 0;
519         nanosleep(&rqtp, NULL);
520         return (SLEEP_T) 0;
521 #else /* HAVE_NANOSLEEP */
522         int was_held;
523         SM_EVENT *ev;
524 #if _FFR_SLEEP_USE_SELECT > 0
525         int r;
526 # if _FFR_SLEEP_USE_SELECT > 0
527         struct timeval sm_io_to;
528 # endif /* _FFR_SLEEP_USE_SELECT > 0 */
529 #endif /* _FFR_SLEEP_USE_SELECT > 0 */
530 #if SM_CONF_SETITIMER
531         struct timeval now, begin, diff;
532 # if _FFR_SLEEP_USE_SELECT > 0
533         struct timeval slpv;
534 # endif /* _FFR_SLEEP_USE_SELECT > 0 */
535 #else /*  SM_CONF_SETITIMER */
536         time_t begin, now;
537 #endif /*  SM_CONF_SETITIMER */
538
539         if (intvl == 0)
540                 return (SLEEP_T) 0;
541 #if defined(_FFR_MAX_SLEEP_TIME) && _FFR_MAX_SLEEP_TIME > 2
542         if (intvl > _FFR_MAX_SLEEP_TIME)
543         {
544                 syslog(LOG_ERR, "sleep: interval=%u exceeds max value %d",
545                         intvl, _FFR_MAX_SLEEP_TIME);
546 # if 0
547                 SM_ASSERT(intvl < (unsigned int) INT_MAX);
548 # endif /* 0 */
549                 intvl = _FFR_MAX_SLEEP_TIME;
550         }
551 #endif /* defined(_FFR_MAX_SLEEP_TIME) && _FFR_MAX_SLEEP_TIME > 2 */
552         SmSleepDone = false;
553
554 #if SM_CONF_SETITIMER
555 # if _FFR_SLEEP_USE_SELECT > 0
556         slpv.tv_sec = intvl;
557         slpv.tv_usec = 0;
558 # endif /* _FFR_SLEEP_USE_SELECT > 0 */
559         (void) gettimeofday(&now, NULL);
560         begin = now;
561 #else /*  SM_CONF_SETITIMER */
562         now = begin = time(NULL);
563 #endif /*  SM_CONF_SETITIMER */
564
565         ev = sm_setevent((time_t) intvl, sm_endsleep, 0);
566         if (ev == NULL)
567         {
568                 /* COMPLAIN */
569 #if 0
570                 syslog(LOG_ERR, "sleep: sm_setevent(%u) failed", intvl);
571 #endif /* 0 */
572                 SmSleepDone = true;
573         }
574         was_held = sm_releasesignal(SIGALRM);
575
576         while (!SmSleepDone)
577         {
578 #if SM_CONF_SETITIMER
579                 (void) gettimeofday(&now, NULL);
580                 timersub(&now, &begin, &diff);
581                 if (diff.tv_sec < 0 ||
582                     (diff.tv_sec == 0 && diff.tv_usec == 0))
583                         break;
584 # if _FFR_SLEEP_USE_SELECT > 0
585                 timersub(&slpv, &diff, &sm_io_to);
586 # endif /* _FFR_SLEEP_USE_SELECT > 0 */
587 #else /* SM_CONF_SETITIMER */
588                 now = time(NULL);
589
590                 /*
591                 **  Check whether time expired before signal is released.
592                 **  Due to the granularity of time() add 1 to be on the
593                 **  safe side.
594                 */
595
596                 if (!(begin + (time_t) intvl + 1 > now))
597                         break;
598 # if _FFR_SLEEP_USE_SELECT > 0
599                 sm_io_to.tv_sec = intvl - (now - begin);
600                 if (sm_io_to.tv_sec <= 0)
601                         sm_io_to.tv_sec = 1;
602                 sm_io_to.tv_usec = 0;
603 # endif /* _FFR_SLEEP_USE_SELECT > 0 */
604 #endif /* SM_CONF_SETITIMER */
605 #if _FFR_SLEEP_USE_SELECT > 0
606                 if (intvl <= _FFR_SLEEP_USE_SELECT)
607                 {
608                         r = select(0, NULL, NULL, NULL, &sm_io_to);
609                         if (r == 0)
610                                 break;
611                 }
612                 else
613 #endif /* _FFR_SLEEP_USE_SELECT > 0 */
614                 (void) pause();
615         }
616
617         /* if out of the loop without the event being triggered remove it */
618         if (!SmSleepDone)
619                 sm_clrevent(ev);
620         if (was_held > 0)
621                 (void) sm_blocksignal(SIGALRM);
622         return (SLEEP_T) 0;
623 #endif /* HAVE_NANOSLEEP */
624 }
625
626 #if !HAVE_NANOSLEEP
627 static void
628 sm_endsleep(ignore)
629         int ignore;
630 {
631         /*
632         **  NOTE: THIS CAN BE CALLED FROM A SIGNAL HANDLER.  DO NOT ADD
633         **      ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE
634         **      DOING.
635         */
636
637         SmSleepDone = true;
638 }
639 #endif /* !HAVE_NANOSLEEP */
640