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 = &notifiers; *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