1 /*
2 * mbsync - mailbox synchronizer
3 * Copyright (C) 2000-2002 Michael R. Elkins <me@mutt.org>
4 * Copyright (C) 2002-2006,2011,2012 Oswald Buddenhagen <ossi@users.sf.net>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 *
19 * As a special exception, mbsync may be linked with the OpenSSL library,
20 * despite that library's more restrictive license.
21 */
22
23 #include "common.h"
24
25 #include <assert.h>
26 #include <stddef.h>
27 #include <stdlib.h>
28 #include <unistd.h>
29 #include <fcntl.h>
30 #include <errno.h>
31 #include <string.h>
32 #include <ctype.h>
33 #include <pwd.h>
34
35 static int need_nl;
36
37 void
flushn(void)38 flushn( void )
39 {
40 if (need_nl) {
41 putchar( '\n' );
42 fflush( stdout );
43 need_nl = 0;
44 }
45 }
46
47 static void ATTR_PRINTFLIKE(1, 0)
printn(const char * msg,va_list va)48 printn( const char *msg, va_list va )
49 {
50 if (*msg == '\v')
51 msg++;
52 else
53 flushn();
54 vprintf( msg, va );
55 fflush( stdout );
56 }
57
58 void
vdebug(int cat,const char * msg,va_list va)59 vdebug( int cat, const char *msg, va_list va )
60 {
61 if (DFlags & cat) {
62 vprintf( msg, va );
63 fflush( stdout );
64 need_nl = 0;
65 }
66 }
67
68 void
vdebugn(int cat,const char * msg,va_list va)69 vdebugn( int cat, const char *msg, va_list va )
70 {
71 if (DFlags & cat) {
72 vprintf( msg, va );
73 fflush( stdout );
74 need_nl = 1;
75 }
76 }
77
78 void
progress(const char * msg,...)79 progress( const char *msg, ... )
80 {
81 va_list va;
82
83 va_start( va, msg );
84 vprintf( msg, va );
85 va_end( va );
86 fflush( stdout );
87 need_nl = 1;
88 }
89
90 void
info(const char * msg,...)91 info( const char *msg, ... )
92 {
93 va_list va;
94
95 if (DFlags & VERBOSE) {
96 va_start( va, msg );
97 printn( msg, va );
98 va_end( va );
99 need_nl = 0;
100 }
101 }
102
103 void
infon(const char * msg,...)104 infon( const char *msg, ... )
105 {
106 va_list va;
107
108 if (DFlags & VERBOSE) {
109 va_start( va, msg );
110 printn( msg, va );
111 va_end( va );
112 need_nl = 1;
113 }
114 }
115
116 void
notice(const char * msg,...)117 notice( const char *msg, ... )
118 {
119 va_list va;
120
121 if (!(DFlags & QUIET)) {
122 va_start( va, msg );
123 printn( msg, va );
124 va_end( va );
125 need_nl = 0;
126 }
127 }
128
129 void
warn(const char * msg,...)130 warn( const char *msg, ... )
131 {
132 va_list va;
133
134 if (!(DFlags & VERYQUIET)) {
135 flushn();
136 va_start( va, msg );
137 vfprintf( stderr, msg, va );
138 va_end( va );
139 }
140 }
141
142 void
error(const char * msg,...)143 error( const char *msg, ... )
144 {
145 va_list va;
146
147 flushn();
148 va_start( va, msg );
149 vfprintf( stderr, msg, va );
150 va_end( va );
151 }
152
153 void
vsys_error(const char * msg,va_list va)154 vsys_error( const char *msg, va_list va )
155 {
156 char buf[1024];
157
158 int errno_bak = errno;
159 flushn();
160 if ((uint)vsnprintf( buf, sizeof(buf), msg, va ) >= sizeof(buf))
161 oob();
162 errno = errno_bak;
163 perror( buf );
164 }
165
166 void
sys_error(const char * msg,...)167 sys_error( const char *msg, ... )
168 {
169 va_list va;
170
171 va_start( va, msg );
172 vsys_error( msg, va );
173 va_end( va );
174 }
175
176 void
add_string_list_n(string_list_t ** list,const char * str,uint len)177 add_string_list_n( string_list_t **list, const char *str, uint len )
178 {
179 string_list_t *elem;
180
181 elem = nfmalloc( offsetof(string_list_t, string) + len + 1 );
182 elem->next = *list;
183 *list = elem;
184 memcpy( elem->string, str, len );
185 elem->string[len] = 0;
186 }
187
188 void
add_string_list(string_list_t ** list,const char * str)189 add_string_list( string_list_t **list, const char *str )
190 {
191 add_string_list_n( list, str, strlen( str ) );
192 }
193
194 void
free_string_list(string_list_t * list)195 free_string_list( string_list_t *list )
196 {
197 string_list_t *tlist;
198
199 for (; list; list = tlist) {
200 tlist = list->next;
201 free( list );
202 }
203 }
204
205 #ifndef HAVE_VASPRINTF
206 static int
vasprintf(char ** strp,const char * fmt,va_list ap)207 vasprintf( char **strp, const char *fmt, va_list ap )
208 {
209 int len;
210 char tmp[1024];
211
212 if ((len = vsnprintf( tmp, sizeof(tmp), fmt, ap )) < 0 || !(*strp = malloc( len + 1 )))
213 return -1;
214 if (len >= (int)sizeof(tmp))
215 vsprintf( *strp, fmt, ap );
216 else
217 memcpy( *strp, tmp, (size_t)len + 1 );
218 return len;
219 }
220 #endif
221
222 #ifndef HAVE_MEMRCHR
223 void *
memrchr(const void * s,int c,size_t n)224 memrchr( const void *s, int c, size_t n )
225 {
226 u_char *b = (u_char *)s, *e = b + n;
227
228 while (--e >= b)
229 if (*e == c)
230 return (void *)e;
231 return 0;
232 }
233 #endif
234
235 #ifndef HAVE_STRNLEN
236 size_t
strnlen(const char * str,size_t maxlen)237 strnlen( const char *str, size_t maxlen )
238 {
239 const char *estr = memchr( str, 0, maxlen );
240 return estr ? (size_t)(estr - str) : maxlen;
241 }
242
243 #endif
244
245 int
starts_with(const char * str,int strl,const char * cmp,uint cmpl)246 starts_with( const char *str, int strl, const char *cmp, uint cmpl )
247 {
248 if (strl < 0)
249 strl = strnlen( str, cmpl + 1 );
250 return ((uint)strl >= cmpl) && !memcmp( str, cmp, cmpl );
251 }
252
253 int
starts_with_upper(const char * str,int strl,const char * cmp,uint cmpl)254 starts_with_upper( const char *str, int strl, const char *cmp, uint cmpl )
255 {
256 if (strl < 0)
257 strl = strnlen( str, cmpl + 1 );
258 if ((uint)strl < cmpl)
259 return 0;
260 for (uint i = 0; i < cmpl; i++)
261 if (str[i] != cmp[i] && toupper( str[i] ) != cmp[i])
262 return 0;
263 return 1;
264 }
265
266 int
equals(const char * str,int strl,const char * cmp,uint cmpl)267 equals( const char *str, int strl, const char *cmp, uint cmpl )
268 {
269 if (strl < 0)
270 strl = strnlen( str, cmpl + 1 );
271 return ((uint)strl == cmpl) && !memcmp( str, cmp, cmpl );
272 }
273
274 #ifndef HAVE_TIMEGM
275 /*
276 Converts struct tm to time_t, assuming the data in tm is UTC rather
277 than local timezone.
278
279 mktime is similar but assumes struct tm, also known as the
280 "broken-down" form of time, is in local time zone. timegm
281 uses mktime to make the conversion understanding that an offset
282 will be introduced by the local time assumption.
283
284 mktime_from_utc then measures the introduced offset by applying
285 gmtime to the initial result and applying mktime to the resulting
286 "broken-down" form. The difference between the two mktime results
287 is the measured offset which is then subtracted from the initial
288 mktime result to yield a calendar time which is the value returned.
289
290 tm_isdst in struct tm is set to 0 to force mktime to introduce a
291 consistent offset (the non DST offset) since tm and tm+o might be
292 on opposite sides of a DST change.
293
294 Some implementations of mktime return -1 for the nonexistent
295 localtime hour at the beginning of DST. In this event, use
296 mktime(tm - 1hr) + 3600.
297
298 Schematically
299 mktime(tm) --> t+o
300 gmtime(t+o) --> tm+o
301 mktime(tm+o) --> t+2o
302 t+o - (t+2o - t+o) = t
303
304 Contributed by Roger Beeman <beeman@cisco.com>, with the help of
305 Mark Baushke <mdb@cisco.com> and the rest of the Gurus at CISCO.
306 Further improved by Roger with assistance from Edward J. Sabol
307 based on input by Jamie Zawinski.
308 */
309
310 static time_t
my_mktime(struct tm * t)311 my_mktime( struct tm *t )
312 {
313 time_t tl = mktime( t );
314 if (tl == -1) {
315 t->tm_hour--;
316 tl = mktime( t );
317 if (tl != -1)
318 tl += 3600;
319 }
320 return tl;
321 }
322
323 time_t
timegm(struct tm * t)324 timegm( struct tm *t )
325 {
326 time_t tl, tb;
327 struct tm *tg;
328
329 if ((tl = my_mktime( t )) == -1)
330 return tl;
331 tg = gmtime( &tl );
332 tg->tm_isdst = 0;
333 if ((tb = my_mktime( tg )) == -1)
334 return tb;
335 return tl - (tb - tl);
336 }
337 #endif
338
339 void
oob(void)340 oob( void )
341 {
342 fputs( "Fatal: buffer too small. Please report a bug.\n", stderr );
343 abort();
344 }
345
346 int
nfsnprintf(char * buf,int blen,const char * fmt,...)347 nfsnprintf( char *buf, int blen, const char *fmt, ... )
348 {
349 int ret;
350 va_list va;
351
352 va_start( va, fmt );
353 if (blen <= 0 || (uint)(ret = vsnprintf( buf, (size_t)blen, fmt, va )) >= (uint)blen)
354 oob();
355 va_end( va );
356 return ret;
357 }
358
359 void
oom(void)360 oom( void )
361 {
362 fputs( "Fatal: Out of memory\n", stderr );
363 abort();
364 }
365
366 void *
nfmalloc(size_t sz)367 nfmalloc( size_t sz )
368 {
369 void *ret;
370
371 if (!(ret = malloc( sz )))
372 oom();
373 return ret;
374 }
375
376 void *
nfcalloc(size_t sz)377 nfcalloc( size_t sz )
378 {
379 void *ret;
380
381 if (!(ret = calloc( sz, 1 )))
382 oom();
383 return ret;
384 }
385
386 void *
nfrealloc(void * mem,size_t sz)387 nfrealloc( void *mem, size_t sz )
388 {
389 char *ret;
390
391 if (!(ret = realloc( mem, sz )) && sz)
392 oom();
393 return ret;
394 }
395
396 char *
nfstrndup(const char * str,size_t nchars)397 nfstrndup( const char *str, size_t nchars )
398 {
399 char *ret = nfmalloc( nchars + 1 );
400 memcpy( ret, str, nchars );
401 ret[nchars] = 0;
402 return ret;
403 }
404
405 char *
nfstrdup(const char * str)406 nfstrdup( const char *str )
407 {
408 return nfstrndup( str, strlen( str ) );
409 }
410
411 int
nfvasprintf(char ** str,const char * fmt,va_list va)412 nfvasprintf( char **str, const char *fmt, va_list va )
413 {
414 int ret = vasprintf( str, fmt, va );
415 if (ret < 0)
416 oom();
417 return ret;
418 }
419
420 int
nfasprintf(char ** str,const char * fmt,...)421 nfasprintf( char **str, const char *fmt, ... )
422 {
423 int ret;
424 va_list va;
425
426 va_start( va, fmt );
427 ret = nfvasprintf( str, fmt, va );
428 va_end( va );
429 return ret;
430 }
431
432 /*
433 static struct passwd *
434 cur_user( void )
435 {
436 char *p;
437 struct passwd *pw;
438 uid_t uid;
439
440 uid = getuid();
441 if ((!(p = getenv("LOGNAME")) || !(pw = getpwnam( p )) || pw->pw_uid != uid) &&
442 (!(p = getenv("USER")) || !(pw = getpwnam( p )) || pw->pw_uid != uid) &&
443 !(pw = getpwuid( uid )))
444 {
445 fputs ("Cannot determinate current user\n", stderr);
446 return 0;
447 }
448 return pw;
449 }
450 */
451
452 char *
expand_strdup(const char * s)453 expand_strdup( const char *s )
454 {
455 struct passwd *pw;
456 const char *p, *q;
457 char *r;
458
459 if (*s == '~') {
460 s++;
461 if (!*s) {
462 p = NULL;
463 q = Home;
464 } else if (*s == '/') {
465 p = s;
466 q = Home;
467 } else {
468 if ((p = strchr( s, '/' ))) {
469 r = nfstrndup( s, (size_t)(p - s) );
470 pw = getpwnam( r );
471 free( r );
472 } else
473 pw = getpwnam( s );
474 if (!pw)
475 return NULL;
476 q = pw->pw_dir;
477 }
478 nfasprintf( &r, "%s%s", q, p ? p : "" );
479 return r;
480 } else
481 return nfstrdup( s );
482 }
483
484 /* Return value: 0 = ok, -1 = out found in arg, -2 = in found in arg but no out specified */
485 int
map_name(const char * arg,char ** result,uint reserve,const char * in,const char * out)486 map_name( const char *arg, char **result, uint reserve, const char *in, const char *out )
487 {
488 char *p;
489 uint i, l, ll, num, inl, outl;
490
491 assert( arg );
492 l = strlen( arg );
493 assert( in );
494 inl = strlen( in );
495 if (!inl) {
496 copy:
497 *result = nfmalloc( reserve + l + 1 );
498 memcpy( *result + reserve, arg, l + 1 );
499 return 0;
500 }
501 assert( out );
502 outl = strlen( out );
503 if (equals( in, (int)inl, out, outl ))
504 goto copy;
505 for (num = 0, i = 0; i < l; ) {
506 for (ll = 0; ll < inl; ll++)
507 if (arg[i + ll] != in[ll])
508 goto fout;
509 num++;
510 i += inl;
511 continue;
512 fout:
513 if (outl) {
514 for (ll = 0; ll < outl; ll++)
515 if (arg[i + ll] != out[ll])
516 goto fnexti;
517 return -1;
518 }
519 fnexti:
520 i++;
521 }
522 if (!num)
523 goto copy;
524 if (!outl)
525 return -2;
526 *result = nfmalloc( reserve + l + num * (outl - inl) + 1 );
527 p = *result + reserve;
528 for (i = 0; i < l; ) {
529 for (ll = 0; ll < inl; ll++)
530 if (arg[i + ll] != in[ll])
531 goto rnexti;
532 memcpy( p, out, outl );
533 p += outl;
534 i += inl;
535 continue;
536 rnexti:
537 *p++ = arg[i++];
538 }
539 *p = 0;
540 return 0;
541 }
542
543 static int
compare_uints(const void * l,const void * r)544 compare_uints( const void *l, const void *r )
545 {
546 uint li = *(const uint *)l, ri = *(const uint *)r;
547 if (li != ri) // Can't subtract, the result might not fit into signed int.
548 return li > ri ? 1 : -1;
549 return 0;
550 }
551
552 void
sort_uint_array(uint_array_t array)553 sort_uint_array( uint_array_t array )
554 {
555 qsort( array.data, array.size, sizeof(uint), compare_uints );
556 }
557
558 int
find_uint_array(uint_array_t array,uint value)559 find_uint_array( uint_array_t array, uint value )
560 {
561 uint bot = 0, top = array.size;
562 while (bot < top) {
563 uint i = (bot + top) / 2;
564 uint elt = array.data[i];
565 if (elt == value)
566 return 1;
567 if (elt < value)
568 bot = i + 1;
569 else
570 top = i;
571 }
572 return 0;
573 }
574
575
576 static struct {
577 uchar i, j, s[256];
578 } rs;
579
580 void
arc4_init(void)581 arc4_init( void )
582 {
583 int i, fd;
584 uchar j, si, dat[128];
585
586 if ((fd = open( "/dev/urandom", O_RDONLY )) < 0 && (fd = open( "/dev/random", O_RDONLY )) < 0) {
587 error( "Fatal: no random number source available.\n" );
588 exit( 3 );
589 }
590 if (read( fd, dat, 128 ) != 128) {
591 error( "Fatal: cannot read random number source.\n" );
592 exit( 3 );
593 }
594 close( fd );
595
596 for (i = 0; i < 256; i++)
597 rs.s[i] = (uchar)i;
598 for (i = j = 0; i < 256; i++) {
599 si = rs.s[i];
600 j += si + dat[i & 127];
601 rs.s[i] = rs.s[j];
602 rs.s[j] = si;
603 }
604 rs.i = rs.j = 0;
605
606 for (i = 0; i < 256; i++)
607 arc4_getbyte();
608 }
609
610 uchar
arc4_getbyte(void)611 arc4_getbyte( void )
612 {
613 uchar si, sj;
614
615 rs.i++;
616 si = rs.s[rs.i];
617 rs.j += si;
618 sj = rs.s[rs.j];
619 rs.s[rs.i] = sj;
620 rs.s[rs.j] = si;
621 return rs.s[(si + sj) & 0xff];
622 }
623
624 static const uchar prime_deltas[] = {
625 0, 0, 1, 3, 1, 5, 3, 3, 1, 9, 7, 5, 3, 17, 27, 3,
626 1, 29, 3, 21, 7, 17, 15, 9, 43, 35, 15, 0, 0, 0, 0, 0
627 };
628
629 uint
bucketsForSize(uint size)630 bucketsForSize( uint size )
631 {
632 uint base = 4, bits = 2;
633
634 for (;;) {
635 uint prime = base + prime_deltas[bits];
636 if (prime >= size)
637 return prime;
638 base <<= 1;
639 bits++;
640 }
641 }
642
643 static void
list_prepend(list_head_t * head,list_head_t * to)644 list_prepend( list_head_t *head, list_head_t *to )
645 {
646 assert( !head->next );
647 assert( to->next );
648 assert( to->prev->next == to );
649 head->next = to;
650 head->prev = to->prev;
651 head->prev->next = head;
652 to->prev = head;
653 }
654
655 static void
list_unlink(list_head_t * head)656 list_unlink( list_head_t *head )
657 {
658 assert( head->next );
659 assert( head->next->prev == head);
660 assert( head->prev->next == head);
661 head->next->prev = head->prev;
662 head->prev->next = head->next;
663 head->next = head->prev = NULL;
664 }
665
666 static notifier_t *notifiers;
667 static int changed; /* Iterator may be invalid now. */
668 #ifdef HAVE_POLL_H
669 static struct pollfd *pollfds;
670 static uint npolls, rpolls;
671 #else
672 # ifdef HAVE_SYS_SELECT_H
673 # include <sys/select.h>
674 # endif
675 #endif
676
677 void
init_notifier(notifier_t * sn,int fd,void (* cb)(int,void *),void * aux)678 init_notifier( notifier_t *sn, int fd, void (*cb)( int, void * ), void *aux )
679 {
680 #ifdef HAVE_POLL_H
681 uint idx = npolls++;
682 if (rpolls < npolls) {
683 rpolls = npolls;
684 pollfds = nfrealloc( pollfds, npolls * sizeof(*pollfds) );
685 }
686 pollfds[idx].fd = fd;
687 pollfds[idx].events = 0; /* POLLERR & POLLHUP implicit */
688 sn->index = idx;
689 #else
690 sn->fd = fd;
691 sn->events = 0;
692 #endif
693 sn->cb = cb;
694 sn->aux = aux;
695 sn->next = notifiers;
696 notifiers = sn;
697 }
698
699 void
conf_notifier(notifier_t * sn,short and_events,short or_events)700 conf_notifier( notifier_t *sn, short and_events, short or_events )
701 {
702 #ifdef HAVE_POLL_H
703 uint idx = sn->index;
704 pollfds[idx].events = (pollfds[idx].events & and_events) | or_events;
705 #else
706 sn->events = (sn->events & and_events) | or_events;
707 #endif
708 }
709
710 short
notifier_config(notifier_t * sn)711 notifier_config( notifier_t *sn )
712 {
713 #ifdef HAVE_POLL_H
714 return pollfds[sn->index].events;
715 #else
716 return sn->events;
717 #endif
718 }
719
720 void
wipe_notifier(notifier_t * sn)721 wipe_notifier( notifier_t *sn )
722 {
723 notifier_t **snp;
724 #ifdef HAVE_POLL_H
725 uint idx;
726 #endif
727
728 for (snp = ¬ifiers; *snp != sn; snp = &(*snp)->next)
729 assert( *snp );
730 *snp = sn->next;
731 sn->next = NULL;
732 changed = 1;
733
734 #ifdef HAVE_POLL_H
735 idx = sn->index;
736 memmove( pollfds + idx, pollfds + idx + 1, (--npolls - idx) * sizeof(*pollfds) );
737 for (sn = notifiers; sn; sn = sn->next) {
738 if (sn->index > idx)
739 sn->index--;
740 }
741 #endif
742 }
743
744 static time_t
get_now(void)745 get_now( void )
746 {
747 return time( NULL );
748 }
749
750 static list_head_t timers = { &timers, &timers };
751
752 void
init_wakeup(wakeup_t * tmr,void (* cb)(void *),void * aux)753 init_wakeup( wakeup_t *tmr, void (*cb)( void * ), void *aux )
754 {
755 tmr->cb = cb;
756 tmr->aux = aux;
757 tmr->links.next = tmr->links.prev = NULL;
758 }
759
760 void
wipe_wakeup(wakeup_t * tmr)761 wipe_wakeup( wakeup_t *tmr )
762 {
763 if (tmr->links.next)
764 list_unlink( &tmr->links );
765 }
766
767 void
conf_wakeup(wakeup_t * tmr,int to)768 conf_wakeup( wakeup_t *tmr, int to )
769 {
770 list_head_t *head, *succ;
771
772 if (to < 0) {
773 if (tmr->links.next)
774 list_unlink( &tmr->links );
775 } else {
776 time_t timeout = to;
777 if (!to) {
778 /* We always prepend null timers, to cluster related events. */
779 succ = timers.next;
780 } else {
781 timeout += get_now();
782 /* We start at the end in the expectation that the newest timer is likely to fire last
783 * (which will be true only if all timeouts are equal, but it's an as good guess as any). */
784 for (succ = &timers; (head = succ->prev) != &timers; succ = head) {
785 if (head != &tmr->links && timeout > ((wakeup_t *)head)->timeout)
786 break;
787 }
788 assert( head != &tmr->links );
789 }
790 tmr->timeout = timeout;
791 if (succ != &tmr->links) {
792 if (tmr->links.next)
793 list_unlink( &tmr->links );
794 list_prepend( &tmr->links, succ );
795 }
796 }
797 }
798
799 static void
event_wait(void)800 event_wait( void )
801 {
802 list_head_t *head;
803 notifier_t *sn;
804 int m;
805
806 #ifdef HAVE_POLL_H
807 int timeout = -1;
808 if ((head = timers.next) != &timers) {
809 wakeup_t *tmr = (wakeup_t *)head;
810 time_t delta = tmr->timeout;
811 if (!delta || (delta -= get_now()) <= 0) {
812 list_unlink( head );
813 tmr->cb( tmr->aux );
814 return;
815 }
816 timeout = (int)delta * 1000;
817 }
818 switch (poll( pollfds, npolls, timeout )) {
819 case 0:
820 return;
821 case -1:
822 perror( "poll() failed in event loop" );
823 abort();
824 default:
825 break;
826 }
827 for (sn = notifiers; sn; sn = sn->next) {
828 uint n = sn->index;
829 if ((m = pollfds[n].revents)) {
830 assert( !(m & POLLNVAL) );
831 sn->cb( m | shifted_bit( m, POLLHUP, POLLIN ), sn->aux );
832 if (changed) {
833 changed = 0;
834 break;
835 }
836 }
837 }
838 #else
839 struct timeval *timeout = 0;
840 struct timeval to_tv;
841 fd_set rfds, wfds, efds;
842 int fd;
843
844 if ((head = timers.next) != &timers) {
845 wakeup_t *tmr = (wakeup_t *)head;
846 time_t delta = tmr->timeout;
847 if (!delta || (delta -= get_now()) <= 0) {
848 list_unlink( head );
849 tmr->cb( tmr->aux );
850 return;
851 }
852 to_tv.tv_sec = delta;
853 to_tv.tv_usec = 0;
854 timeout = &to_tv;
855 }
856 FD_ZERO( &rfds );
857 FD_ZERO( &wfds );
858 FD_ZERO( &efds );
859 m = -1;
860 for (sn = notifiers; sn; sn = sn->next) {
861 fd = sn->fd;
862 if (sn->events & POLLIN)
863 FD_SET( fd, &rfds );
864 if (sn->events & POLLOUT)
865 FD_SET( fd, &wfds );
866 FD_SET( fd, &efds );
867 if (fd > m)
868 m = fd;
869 }
870 switch (select( m + 1, &rfds, &wfds, &efds, timeout )) {
871 case 0:
872 return;
873 case -1:
874 perror( "select() failed in event loop" );
875 abort();
876 default:
877 break;
878 }
879 for (sn = notifiers; sn; sn = sn->next) {
880 fd = sn->fd;
881 m = 0;
882 if (FD_ISSET( fd, &rfds ))
883 m |= POLLIN;
884 if (FD_ISSET( fd, &wfds ))
885 m |= POLLOUT;
886 if (FD_ISSET( fd, &efds ))
887 m |= POLLERR;
888 if (m) {
889 sn->cb( m, sn->aux );
890 if (changed) {
891 changed = 0;
892 break;
893 }
894 }
895 }
896 #endif
897 }
898
899 void
main_loop(void)900 main_loop( void )
901 {
902 while (notifiers || timers.next != &timers)
903 event_wait();
904 }
905