util.c 16 KB

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