2003-03-04 Havoc Pennington <hp@pobox.com>
[platform/upstream/dbus.git] / dbus / dbus-sysdeps.c
1 /* -*- mode: C; c-file-style: "gnu" -*- */
2 /* dbus-sysdeps.c Wrappers around system/libc features (internal to D-BUS implementation)
3  * 
4  * Copyright (C) 2002  Red Hat, Inc.
5  *
6  * Licensed under the Academic Free License version 1.2
7  * 
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or
11  * (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  * 
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
21  *
22  */
23
24 #include "dbus-internals.h"
25 #include "dbus-sysdeps.h"
26 #include "dbus-threads.h"
27 #include <sys/types.h>
28 #include <stdlib.h>
29 #include <string.h>
30 #include <signal.h>
31 #include <unistd.h>
32 #include <stdio.h>
33 #include <errno.h>
34 #include <unistd.h>
35 #include <fcntl.h>
36 #include <sys/socket.h>
37 #include <dirent.h>
38 #include <sys/un.h>
39 #include <pwd.h>
40 #include <time.h>
41 #include <sys/time.h>
42 #include <sys/stat.h>
43 #include <sys/wait.h>
44 #include <netinet/in.h>
45 #include <netdb.h>
46
47 #ifdef HAVE_WRITEV
48 #include <sys/uio.h>
49 #endif
50 #ifdef HAVE_POLL
51 #include <sys/poll.h>
52 #endif
53
54 #ifndef O_BINARY
55 #define O_BINARY 0
56 #endif
57
58 #ifndef SUN_LEN
59 /* This system is not POSIX.1g.         */
60 #define SUN_LEN(ptr) ((size_t) (((struct sockaddr_un *) 0)->sun_path)  \
61        + strlen ((ptr)->sun_path))
62 #endif
63
64 /**
65  * @addtogroup DBusInternalsUtils
66  * @{
67  */
68 /**
69  * Aborts the program with SIGABRT (dumping core).
70  */
71 void
72 _dbus_abort (void)
73 {
74   abort ();
75   _exit (1); /* in case someone manages to ignore SIGABRT */
76 }
77
78 /**
79  * Wrapper for setenv().
80  *
81  * @param varname name of environment variable
82  * @param value value of environment variable
83  * @returns #TRUE on success.
84  */
85 dbus_bool_t
86 _dbus_setenv (const char *varname, const char *value)
87 {
88 #ifdef HAVE_SETENV
89   return (setenv (varname, value, TRUE) == 0);
90 #else
91   DBusString str;
92   char *putenv_value;
93
94   if (!_dbus_string_init (&str, _DBUS_INT_MAX))
95     return FALSE;
96
97   if (!_dbus_string_append (&str, varname) ||
98       !_dbus_string_append (&str, "=") ||
99       !_dbus_string_append (&str, value) ||
100       !_dbus_string_steal_data (&str, &putenv_value))
101     {
102       _dbus_string_free (&str);
103       return FALSE;
104     }
105
106   _dbus_string_free (&str);
107
108   return (putenv (putenv_value) == 0);
109 #endif
110 }
111
112 /**
113  * Wrapper for getenv().
114  *
115  * @param varname name of environment variable
116  * @returns value of environment variable or #NULL if unset
117  */
118 const char*
119 _dbus_getenv (const char *varname)
120 {  
121   return getenv (varname);
122 }
123
124 /**
125  * Thin wrapper around the read() system call that appends
126  * the data it reads to the DBusString buffer. It appends
127  * up to the given count, and returns the same value
128  * and same errno as read(). The only exception is that
129  * _dbus_read() handles EINTR for you.
130  *
131  * @param fd the file descriptor to read from
132  * @param buffer the buffer to append data to
133  * @param count the amount of data to read
134  * @returns the number of bytes read or -1
135  */
136 int
137 _dbus_read (int               fd,
138             DBusString       *buffer,
139             int               count)
140 {
141   int bytes_read;
142   int start;
143   char *data;
144
145   _dbus_assert (count >= 0);
146   
147   start = _dbus_string_get_length (buffer);
148
149   if (!_dbus_string_lengthen (buffer, count))
150     {
151       errno = ENOMEM;
152       return -1;
153     }
154
155   _dbus_string_get_data_len (buffer, &data, start, count);
156
157  again:
158   
159   bytes_read = read (fd, data, count);
160
161   if (bytes_read < 0)
162     {
163       if (errno == EINTR)
164         goto again;
165       else
166         {
167           /* put length back (note that this doesn't actually realloc anything) */
168           _dbus_string_set_length (buffer, start);
169           return -1;
170         }
171     }
172   else
173     {
174       /* put length back (doesn't actually realloc) */
175       _dbus_string_set_length (buffer, start + bytes_read);
176
177 #if 0
178       if (bytes_read > 0)
179         _dbus_verbose_bytes_of_string (buffer, start, bytes_read);
180 #endif
181       
182       return bytes_read;
183     }
184 }
185
186 /**
187  * Thin wrapper around the write() system call that writes a part of a
188  * DBusString and handles EINTR for you.
189  * 
190  * @param fd the file descriptor to write
191  * @param buffer the buffer to write data from
192  * @param start the first byte in the buffer to write
193  * @param len the number of bytes to try to write
194  * @returns the number of bytes written or -1 on error
195  */
196 int
197 _dbus_write (int               fd,
198              const DBusString *buffer,
199              int               start,
200              int               len)
201 {
202   const char *data;
203   int bytes_written;
204   
205   _dbus_string_get_const_data_len (buffer, &data, start, len);
206   
207  again:
208
209   bytes_written = write (fd, data, len);
210
211   if (bytes_written < 0 && errno == EINTR)
212     goto again;
213
214 #if 0
215   if (bytes_written > 0)
216     _dbus_verbose_bytes_of_string (buffer, start, bytes_written);
217 #endif
218   
219   return bytes_written;
220 }
221
222 /**
223  * Like _dbus_write() but will use writev() if possible
224  * to write both buffers in sequence. The return value
225  * is the number of bytes written in the first buffer,
226  * plus the number written in the second. If the first
227  * buffer is written successfully and an error occurs
228  * writing the second, the number of bytes in the first
229  * is returned (i.e. the error is ignored), on systems that
230  * don't have writev. Handles EINTR for you.
231  * The second buffer may be #NULL.
232  *
233  * @param fd the file descriptor
234  * @param buffer1 first buffer
235  * @param start1 first byte to write in first buffer
236  * @param len1 number of bytes to write from first buffer
237  * @param buffer2 second buffer, or #NULL
238  * @param start2 first byte to write in second buffer
239  * @param len2 number of bytes to write in second buffer
240  * @returns total bytes written from both buffers, or -1 on error
241  */
242 int
243 _dbus_write_two (int               fd,
244                  const DBusString *buffer1,
245                  int               start1,
246                  int               len1,
247                  const DBusString *buffer2,
248                  int               start2,
249                  int               len2)
250 {
251   _dbus_assert (buffer1 != NULL);
252   _dbus_assert (start1 >= 0);
253   _dbus_assert (start2 >= 0);
254   _dbus_assert (len1 >= 0);
255   _dbus_assert (len2 >= 0);
256   
257 #ifdef HAVE_WRITEV
258   {
259     struct iovec vectors[2];
260     const char *data1;
261     const char *data2;
262     int bytes_written;
263
264     _dbus_string_get_const_data_len (buffer1, &data1, start1, len1);
265
266     if (buffer2 != NULL)
267       _dbus_string_get_const_data_len (buffer2, &data2, start2, len2);
268     else
269       {
270         data2 = NULL;
271         start2 = 0;
272         len2 = 0;
273       }
274    
275     vectors[0].iov_base = (char*) data1;
276     vectors[0].iov_len = len1;
277     vectors[1].iov_base = (char*) data2;
278     vectors[1].iov_len = len2;
279
280   again:
281    
282     bytes_written = writev (fd,
283                             vectors,
284                             data2 ? 2 : 1);
285
286     if (bytes_written < 0 && errno == EINTR)
287       goto again;
288    
289     return bytes_written;
290   }
291 #else /* HAVE_WRITEV */
292   {
293     int ret1;
294     
295     ret1 = _dbus_write (fd, buffer1, start1, len1);
296     if (ret1 == len1 && buffer2 != NULL)
297       {
298         ret2 = _dbus_write (fd, buffer2, start2, len2);
299         if (ret2 < 0)
300           ret2 = 0; /* we can't report an error as the first write was OK */
301        
302         return ret1 + ret2;
303       }
304     else
305       return ret1;
306   }
307 #endif /* !HAVE_WRITEV */   
308 }
309
310 /**
311  * Creates a socket and connects it to the UNIX domain socket at the
312  * given path.  The connection fd is returned, and is set up as
313  * nonblocking.
314  *
315  * @param path the path to UNIX domain socket
316  * @param result return location for error code
317  * @returns connection file descriptor or -1 on error
318  */
319 int
320 _dbus_connect_unix_socket (const char     *path,
321                            DBusResultCode *result)
322 {
323   int fd;
324   struct sockaddr_un addr;  
325   
326   fd = socket (PF_UNIX, SOCK_STREAM, 0);
327   
328   if (fd < 0)
329     {
330       dbus_set_result (result,
331                        _dbus_result_from_errno (errno));
332       
333       _dbus_verbose ("Failed to create socket: %s\n",
334                      _dbus_strerror (errno)); 
335       
336       return -1;
337     }
338
339   _DBUS_ZERO (addr);
340   addr.sun_family = AF_UNIX;
341   strncpy (addr.sun_path, path, _DBUS_MAX_SUN_PATH_LENGTH);
342   addr.sun_path[_DBUS_MAX_SUN_PATH_LENGTH] = '\0';
343   
344   if (connect (fd, (struct sockaddr*) &addr, sizeof (addr)) < 0)
345     {      
346       dbus_set_result (result,
347                        _dbus_result_from_errno (errno));
348
349       _dbus_verbose ("Failed to connect to socket %s: %s\n",
350                      path, _dbus_strerror (errno));
351
352       close (fd);
353       fd = -1;
354       
355       return -1;
356     }
357
358   if (!_dbus_set_fd_nonblocking (fd, result))
359     {
360       close (fd);
361       fd = -1;
362
363       return -1;
364     }
365
366   return fd;
367 }
368
369 /**
370  * Creates a socket and binds it to the given path,
371  * then listens on the socket. The socket is
372  * set to be nonblocking. 
373  *
374  * @param path the socket name
375  * @param result return location for errors
376  * @returns the listening file descriptor or -1 on error
377  */
378 int
379 _dbus_listen_unix_socket (const char     *path,
380                           DBusResultCode *result)
381 {
382   int listen_fd;
383   struct sockaddr_un addr;
384
385   listen_fd = socket (PF_UNIX, SOCK_STREAM, 0);
386   
387   if (listen_fd < 0)
388     {
389       dbus_set_result (result, _dbus_result_from_errno (errno));
390       _dbus_verbose ("Failed to create socket \"%s\": %s\n",
391                      path, _dbus_strerror (errno));
392       return -1;
393     }
394
395   _DBUS_ZERO (addr);
396   addr.sun_family = AF_UNIX;
397   strncpy (addr.sun_path, path, _DBUS_MAX_SUN_PATH_LENGTH);
398   addr.sun_path[_DBUS_MAX_SUN_PATH_LENGTH] = '\0';
399   
400   if (bind (listen_fd, (struct sockaddr*) &addr, SUN_LEN (&addr)) < 0)
401     {
402       dbus_set_result (result, _dbus_result_from_errno (errno));
403       _dbus_verbose ("Failed to bind socket \"%s\": %s\n",
404                      path, _dbus_strerror (errno));
405       close (listen_fd);
406       return -1;
407     }
408
409   if (listen (listen_fd, 30 /* backlog */) < 0)
410     {
411       dbus_set_result (result, _dbus_result_from_errno (errno));      
412       _dbus_verbose ("Failed to listen on socket \"%s\": %s\n",
413                      path, _dbus_strerror (errno));
414       close (listen_fd);
415       return -1;
416     }
417
418   if (!_dbus_set_fd_nonblocking (listen_fd, result))
419     {
420       close (listen_fd);
421       return -1;
422     }
423   
424   return listen_fd;
425 }
426
427 /**
428  * Creates a socket and connects to a socket at the given host 
429  * and port. The connection fd is returned, and is set up as
430  * nonblocking.
431  *
432  * @param host the host name to connect to
433  * @param port the prot to connect to
434  * @param result return location for error code
435  * @returns connection file descriptor or -1 on error
436  */
437 int
438 _dbus_connect_tcp_socket (const char     *host,
439                           dbus_uint32_t   port,
440                           DBusResultCode *result)
441 {
442   int fd;
443   struct sockaddr_in addr;
444   struct hostent *he;
445   struct in_addr *haddr;
446   
447   fd = socket (AF_INET, SOCK_STREAM, 0);
448   
449   if (fd < 0)
450     {
451       dbus_set_result (result,
452                        _dbus_result_from_errno (errno));
453       
454       _dbus_verbose ("Failed to create socket: %s\n",
455                      _dbus_strerror (errno)); 
456       
457       return -1;
458     }
459
460   if (host == NULL)
461     host = "localhost";
462
463   he = gethostbyname (host);
464   if (he == NULL) 
465     {
466       dbus_set_result (result,
467                        _dbus_result_from_errno (errno));
468       _dbus_verbose ("Failed to lookup hostname: %s\n",
469                      host);
470       return -1;
471     }
472   
473   haddr = ((struct in_addr *) (he->h_addr_list)[0]);
474
475   _DBUS_ZERO (addr);
476   memcpy (&addr.sin_addr, haddr, sizeof(struct in_addr));
477   addr.sin_family = AF_INET;
478   addr.sin_port = htons (port);
479   
480   if (connect (fd, (struct sockaddr*) &addr, sizeof (addr)) < 0)
481     {      
482       dbus_set_result (result,
483                        _dbus_result_from_errno (errno));
484
485       _dbus_verbose ("Failed to connect to socket %s: %s:%d\n",
486                      host, port, _dbus_strerror (errno));
487
488       close (fd);
489       fd = -1;
490       
491       return -1;
492     }
493
494   if (!_dbus_set_fd_nonblocking (fd, result))
495     {
496       close (fd);
497       fd = -1;
498
499       return -1;
500     }
501
502   return fd;
503 }
504
505 /**
506  * Creates a socket and binds it to the given path,
507  * then listens on the socket. The socket is
508  * set to be nonblocking. 
509  *
510  * @param host the host name to listen on
511  * @param port the prot to listen on
512  * @param result return location for errors
513  * @returns the listening file descriptor or -1 on error
514  */
515 int
516 _dbus_listen_tcp_socket (const char     *host,
517                          dbus_uint32_t   port,
518                          DBusResultCode *result)
519 {
520   int listen_fd;
521   struct sockaddr_in addr;
522   struct hostent *he;
523   struct in_addr *haddr;
524   
525   listen_fd = socket (AF_INET, SOCK_STREAM, 0);
526   
527   if (listen_fd < 0)
528     {
529       dbus_set_result (result, _dbus_result_from_errno (errno));
530       _dbus_verbose ("Failed to create socket \"%s:%d\": %s\n",
531                      host, port, _dbus_strerror (errno));
532       return -1;
533     }
534
535   if (host == NULL)
536     host = "localhost";
537   
538   he = gethostbyname (host);
539   if (he == NULL) 
540     {
541       dbus_set_result (result,
542                        _dbus_result_from_errno (errno));
543       _dbus_verbose ("Failed to lookup hostname: %s\n",
544                      host);
545       return -1;
546     }
547   
548   haddr = ((struct in_addr *) (he->h_addr_list)[0]);
549
550   _DBUS_ZERO (addr);
551   memcpy (&addr.sin_addr, haddr, sizeof (struct in_addr));
552   addr.sin_family = AF_INET;
553   addr.sin_port = htons (port);
554
555   if (bind (listen_fd, (struct sockaddr*) &addr, sizeof (struct sockaddr)))
556     {
557       dbus_set_result (result, _dbus_result_from_errno (errno));
558       _dbus_verbose ("Failed to bind socket \"%s:%d\": %s\n",
559                      host, port, _dbus_strerror (errno));
560       close (listen_fd);
561       return -1;
562     }
563
564   if (listen (listen_fd, 30 /* backlog */) < 0)
565     {
566       dbus_set_result (result, _dbus_result_from_errno (errno));      
567       _dbus_verbose ("Failed to listen on socket \"%s:%d\": %s\n",
568                      host, port, _dbus_strerror (errno));
569       close (listen_fd);
570       return -1;
571     }
572
573   if (!_dbus_set_fd_nonblocking (listen_fd, result))
574     {
575       close (listen_fd);
576       return -1;
577     }
578   
579   return listen_fd;
580 }
581
582 static dbus_bool_t
583 write_credentials_byte (int             server_fd,
584                         DBusResultCode *result)
585 {
586   int bytes_written;
587   char buf[1] = { '\0' };
588   
589  again:
590
591   bytes_written = write (server_fd, buf, 1);
592
593   if (bytes_written < 0 && errno == EINTR)
594     goto again;
595
596   if (bytes_written < 0)
597     {
598       dbus_set_result (result, _dbus_result_from_errno (errno));      
599       _dbus_verbose ("Failed to write credentials byte: %s\n",
600                      _dbus_strerror (errno));
601       return FALSE;
602     }
603   else if (bytes_written == 0)
604     {
605       dbus_set_result (result, DBUS_RESULT_IO_ERROR);
606       _dbus_verbose ("wrote zero bytes writing credentials byte\n");
607       return FALSE;
608     }
609   else
610     {
611       _dbus_assert (bytes_written == 1);
612       _dbus_verbose ("wrote credentials byte\n");
613       return TRUE;
614     }
615 }
616
617 /**
618  * Reads a single byte which must be nul (an error occurs otherwise),
619  * and reads unix credentials if available. Fills in pid/uid/gid with
620  * -1 if no credentials are available. Return value indicates whether
621  * a byte was read, not whether we got valid credentials. On some
622  * systems, such as Linux, reading/writing the byte isn't actually
623  * required, but we do it anyway just to avoid multiple codepaths.
624  * 
625  * Fails if no byte is available, so you must select() first.
626  *
627  * The point of the byte is that on some systems we have to
628  * use sendmsg()/recvmsg() to transmit credentials.
629  *
630  * @param client_fd the client file descriptor
631  * @param credentials struct to fill with credentials of client
632  * @param result location to store result code
633  * @returns #TRUE on success
634  */
635 dbus_bool_t
636 _dbus_read_credentials_unix_socket  (int              client_fd,
637                                      DBusCredentials *credentials,
638                                      DBusResultCode  *result)
639 {
640   struct msghdr msg;
641   struct iovec iov;
642   char buf;
643
644 #ifdef HAVE_CMSGCRED 
645   char cmsgmem[CMSG_SPACE (sizeof (struct cmsgcred))];
646   struct cmsghdr *cmsg = (struct cmsghdr *) cmsgmem;
647 #endif
648
649   credentials->pid = -1;
650   credentials->uid = -1;
651   credentials->gid = -1;
652
653 #if defined(LOCAL_CREDS) && defined(HAVE_CMSGCRED)
654   /* Set the socket to receive credentials on the next message */
655   {
656     int on = 1;
657     if (setsockopt (client_fd, 0, LOCAL_CREDS, &on, sizeof (on)) < 0)
658       {
659         _dbus_verbose ("Unable to set LOCAL_CREDS socket option\n");
660         return FALSE;
661       }
662   }
663 #endif
664
665   iov.iov_base = &buf;
666   iov.iov_len = 1;
667
668   memset (&msg, 0, sizeof (msg));
669   msg.msg_iov = &iov;
670   msg.msg_iovlen = 1;
671
672 #ifdef HAVE_CMSGCRED
673   memset (cmsgmem, 0, sizeof (cmsgmem));
674   msg.msg_control = cmsgmem;
675   msg.msg_controllen = sizeof (cmsgmem);
676 #endif
677
678  again:
679   if (recvmsg (client_fd, &msg, 0) < 0)
680     {
681       if (errno == EINTR)
682         goto again;
683
684       dbus_set_result (result, _dbus_result_from_errno (errno));
685       _dbus_verbose ("Failed to read credentials byte: %s\n",
686                      _dbus_strerror (errno));
687       return FALSE;
688     }
689
690   if (buf != '\0')
691     {
692       dbus_set_result (result, DBUS_RESULT_FAILED);
693       _dbus_verbose ("Credentials byte was not nul\n");
694       return FALSE;
695     }
696
697 #ifdef HAVE_CMSGCRED
698   if (cmsg->cmsg_len < sizeof (cmsgmem) || cmsg->cmsg_type != SCM_CREDS)
699     {
700       dbus_set_result (result, DBUS_RESULT_FAILED);
701       _dbus_verbose ("Message from recvmsg() was not SCM_CREDS\n");
702       return FALSE;
703     }
704 #endif
705
706   _dbus_verbose ("read credentials byte\n");
707
708   {
709 #ifdef SO_PEERCRED
710     struct ucred cr;   
711     int cr_len = sizeof (cr);
712    
713     if (getsockopt (client_fd, SOL_SOCKET, SO_PEERCRED, &cr, &cr_len) == 0 &&
714         cr_len == sizeof (cr))
715       {
716         credentials->pid = cr.pid;
717         credentials->uid = cr.uid;
718         credentials->gid = cr.gid;
719       }
720     else
721       {
722         _dbus_verbose ("Failed to getsockopt() credentials, returned len %d/%d: %s\n",
723                        cr_len, (int) sizeof (cr), _dbus_strerror (errno));
724       }
725 #elif defined(HAVE_CMSGCRED)
726     struct cmsgcred *cred;
727
728     cred = (struct cmsgcred *) CMSG_DATA (cmsg);
729
730     credentials->pid = cred->cmcred_pid;
731     credentials->uid = cred->cmcred_euid;
732     credentials->gid = cred->cmcred_groups[0];
733 #else /* !SO_PEERCRED && !HAVE_CMSGCRED */
734     _dbus_verbose ("Socket credentials not supported on this OS\n");
735 #endif
736   }
737
738   _dbus_verbose ("Credentials: pid %d  uid %d  gid %d\n",
739                  credentials->pid,
740                  credentials->uid,
741                  credentials->gid);
742     
743   return TRUE;
744 }
745
746 /**
747  * Sends a single nul byte with our UNIX credentials as ancillary
748  * data.  Returns #TRUE if the data was successfully written.  On
749  * systems that don't support sending credentials, just writes a byte,
750  * doesn't send any credentials.  On some systems, such as Linux,
751  * reading/writing the byte isn't actually required, but we do it
752  * anyway just to avoid multiple codepaths.
753  *
754  * Fails if no byte can be written, so you must select() first.
755  *
756  * The point of the byte is that on some systems we have to
757  * use sendmsg()/recvmsg() to transmit credentials.
758  *
759  * @param server_fd file descriptor for connection to server
760  * @param result return location for error code
761  * @returns #TRUE if the byte was sent
762  */
763 dbus_bool_t
764 _dbus_send_credentials_unix_socket  (int              server_fd,
765                                      DBusResultCode  *result)
766 {
767   if (write_credentials_byte (server_fd, result))
768     return TRUE;
769   else
770     return FALSE;
771 }
772
773 /**
774  * Accepts a connection on a listening socket.
775  * Handles EINTR for you.
776  *
777  * @param listen_fd the listen file descriptor
778  * @returns the connection fd of the client, or -1 on error
779  */
780 int
781 _dbus_accept  (int listen_fd)
782 {
783   int client_fd;
784   
785  retry:
786   client_fd = accept (listen_fd, NULL, NULL);
787   
788   if (client_fd < 0)
789     {
790       if (errno == EINTR)
791         goto retry;
792     }
793   
794   return client_fd;
795 }
796
797 /** @} */
798
799 /**
800  * @addtogroup DBusString
801  *
802  * @{
803  */
804 /**
805  * Appends an integer to a DBusString.
806  * 
807  * @param str the string
808  * @param value the integer value
809  * @returns #FALSE if not enough memory or other failure.
810  */
811 dbus_bool_t
812 _dbus_string_append_int (DBusString *str,
813                          long        value)
814 {
815   /* this calculation is from comp.lang.c faq */
816 #define MAX_LONG_LEN ((sizeof (long) * 8 + 2) / 3 + 1)  /* +1 for '-' */
817   int orig_len;
818   int i;
819   char *buf;
820   
821   orig_len = _dbus_string_get_length (str);
822
823   if (!_dbus_string_lengthen (str, MAX_LONG_LEN))
824     return FALSE;
825
826   _dbus_string_get_data_len (str, &buf, orig_len, MAX_LONG_LEN);
827
828   snprintf (buf, MAX_LONG_LEN, "%ld", value);
829
830   i = 0;
831   while (*buf)
832     {
833       ++buf;
834       ++i;
835     }
836   
837   _dbus_string_shorten (str, MAX_LONG_LEN - i);
838   
839   return TRUE;
840 }
841
842 /**
843  * Appends an unsigned integer to a DBusString.
844  * 
845  * @param str the string
846  * @param value the integer value
847  * @returns #FALSE if not enough memory or other failure.
848  */
849 dbus_bool_t
850 _dbus_string_append_uint (DBusString    *str,
851                           unsigned long  value)
852 {
853   /* this is wrong, but definitely on the high side. */
854 #define MAX_ULONG_LEN (MAX_LONG_LEN * 2)
855   int orig_len;
856   int i;
857   char *buf;
858   
859   orig_len = _dbus_string_get_length (str);
860
861   if (!_dbus_string_lengthen (str, MAX_ULONG_LEN))
862     return FALSE;
863
864   _dbus_string_get_data_len (str, &buf, orig_len, MAX_ULONG_LEN);
865
866   snprintf (buf, MAX_ULONG_LEN, "%lu", value);
867
868   i = 0;
869   while (*buf)
870     {
871       ++buf;
872       ++i;
873     }
874   
875   _dbus_string_shorten (str, MAX_ULONG_LEN - i);
876   
877   return TRUE;
878 }
879
880 /**
881  * Appends a double to a DBusString.
882  * 
883  * @param str the string
884  * @param value the floating point value
885  * @returns #FALSE if not enough memory or other failure.
886  */
887 dbus_bool_t
888 _dbus_string_append_double (DBusString *str,
889                             double      value)
890 {
891 #define MAX_DOUBLE_LEN 64 /* this is completely made up :-/ */
892   int orig_len;
893   char *buf;
894   int i;
895   
896   orig_len = _dbus_string_get_length (str);
897
898   if (!_dbus_string_lengthen (str, MAX_DOUBLE_LEN))
899     return FALSE;
900
901   _dbus_string_get_data_len (str, &buf, orig_len, MAX_DOUBLE_LEN);
902
903   snprintf (buf, MAX_LONG_LEN, "%g", value);
904
905   i = 0;
906   while (*buf)
907     {
908       ++buf;
909       ++i;
910     }
911   
912   _dbus_string_shorten (str, MAX_DOUBLE_LEN - i);
913   
914   return TRUE;
915 }
916
917 /**
918  * Parses an integer contained in a DBusString. Either return parameter
919  * may be #NULL if you aren't interested in it. The integer is parsed
920  * and stored in value_return. Return parameters are not initialized
921  * if the function returns #FALSE.
922  *
923  * @param str the string
924  * @param start the byte index of the start of the integer
925  * @param value_return return location of the integer value or #NULL
926  * @param end_return return location of the end of the integer, or #NULL
927  * @returns #TRUE on success
928  */
929 dbus_bool_t
930 _dbus_string_parse_int (const DBusString *str,
931                         int               start,
932                         long             *value_return,
933                         int              *end_return)
934 {
935   long v;
936   const char *p;
937   char *end;
938
939   _dbus_string_get_const_data_len (str, &p, start,
940                                    _dbus_string_get_length (str) - start);
941
942   end = NULL;
943   errno = 0;
944   v = strtol (p, &end, 0);
945   if (end == NULL || end == p || errno != 0)
946     return FALSE;
947
948   if (value_return)
949     *value_return = v;
950   if (end_return)
951     *end_return = start + (end - p);
952
953   return TRUE;
954 }
955
956 /**
957  * Parses an unsigned integer contained in a DBusString. Either return
958  * parameter may be #NULL if you aren't interested in it. The integer
959  * is parsed and stored in value_return. Return parameters are not
960  * initialized if the function returns #FALSE.
961  *
962  * @param str the string
963  * @param start the byte index of the start of the integer
964  * @param value_return return location of the integer value or #NULL
965  * @param end_return return location of the end of the integer, or #NULL
966  * @returns #TRUE on success
967  */
968 dbus_bool_t
969 _dbus_string_parse_uint (const DBusString *str,
970                          int               start,
971                          unsigned long    *value_return,
972                          int              *end_return)
973 {
974   unsigned long v;
975   const char *p;
976   char *end;
977
978   _dbus_string_get_const_data_len (str, &p, start,
979                                    _dbus_string_get_length (str) - start);
980
981   end = NULL;
982   errno = 0;
983   v = strtoul (p, &end, 0);
984   if (end == NULL || end == p || errno != 0)
985     return FALSE;
986
987   if (value_return)
988     *value_return = v;
989   if (end_return)
990     *end_return = start + (end - p);
991
992   return TRUE;
993 }
994
995 /**
996  * Parses a floating point number contained in a DBusString. Either
997  * return parameter may be #NULL if you aren't interested in it. The
998  * integer is parsed and stored in value_return. Return parameters are
999  * not initialized if the function returns #FALSE.
1000  *
1001  * @todo this function is currently locale-dependent. Should
1002  * ask alexl to relicense g_ascii_strtod() code and put that in
1003  * here instead, so it's locale-independent.
1004  *
1005  * @param str the string
1006  * @param start the byte index of the start of the float
1007  * @param value_return return location of the float value or #NULL
1008  * @param end_return return location of the end of the float, or #NULL
1009  * @returns #TRUE on success
1010  */
1011 dbus_bool_t
1012 _dbus_string_parse_double (const DBusString *str,
1013                            int               start,
1014                            double           *value_return,
1015                            int              *end_return)
1016 {
1017   double v;
1018   const char *p;
1019   char *end;
1020
1021   _dbus_warn ("_dbus_string_parse_double() needs to be made locale-independent\n");
1022   
1023   _dbus_string_get_const_data_len (str, &p, start,
1024                                    _dbus_string_get_length (str) - start);
1025
1026   end = NULL;
1027   errno = 0;
1028   v = strtod (p, &end);
1029   if (end == NULL || end == p || errno != 0)
1030     return FALSE;
1031
1032   if (value_return)
1033     *value_return = v;
1034   if (end_return)
1035     *end_return = start + (end - p);
1036
1037   return TRUE;
1038 }
1039
1040 /** @} */ /* DBusString group */
1041
1042 /**
1043  * @addtogroup DBusInternalsUtils
1044  * @{
1045  */
1046
1047 static dbus_bool_t
1048 store_user_info (struct passwd    *p,
1049                  DBusCredentials  *credentials,
1050                  DBusString       *homedir,
1051                  DBusString       *username_out)
1052 {
1053   int old_homedir_len;
1054   
1055   if (credentials != NULL)
1056     {
1057       credentials->uid = p->pw_uid;
1058       credentials->gid = p->pw_gid;
1059     }
1060
1061   old_homedir_len = 0;
1062   if (homedir != NULL)
1063     {
1064       old_homedir_len = _dbus_string_get_length (homedir);
1065       
1066       if (!_dbus_string_append (homedir, p->pw_dir))
1067         {
1068           _dbus_verbose ("No memory to get homedir\n");
1069           return FALSE;
1070         }
1071     }
1072   
1073   if (username_out &&
1074       !_dbus_string_append (username_out, p->pw_name))
1075     {
1076       if (homedir)
1077         _dbus_string_set_length (homedir, old_homedir_len);
1078       _dbus_verbose ("No memory to get username\n");
1079       return FALSE;
1080     }
1081       
1082   _dbus_verbose ("Username %s has uid %d gid %d homedir %s\n",
1083                  p->pw_name, (int) p->pw_uid, (int) p->pw_gid,
1084                  p->pw_dir);
1085
1086   return TRUE;
1087 }
1088   
1089 /**
1090  * Gets user info using either username or uid. Only
1091  * one of these may be passed in, either username
1092  * must be #NULL or uid must be < 0.
1093  *
1094  * @param username the username
1095  * @param uid the user ID
1096  * @param credentials to fill in or #NULL
1097  * @param homedir string to append homedir to or #NULL
1098  * @param username_out string to append username to or #NULL
1099  *
1100  * @returns #TRUE on success
1101  */
1102 static dbus_bool_t
1103 get_user_info (const DBusString *username,
1104                int               uid,
1105                DBusCredentials  *credentials,
1106                DBusString       *homedir,
1107                DBusString       *username_out)
1108 {
1109   const char *username_c_str;
1110       
1111   /* exactly one of username/uid provided */
1112   _dbus_assert (username != NULL || uid >= 0);
1113   _dbus_assert (username == NULL || uid < 0);
1114
1115   if (credentials)
1116     {
1117       credentials->pid = -1;
1118       credentials->uid = -1;
1119       credentials->gid = -1;
1120     }
1121   
1122   if (username != NULL)
1123     _dbus_string_get_const_data (username, &username_c_str);
1124   else
1125     username_c_str = NULL;
1126
1127   /* For now assuming that the getpwnam() and getpwuid() flavors
1128    * are always symmetrical, if not we have to add more configure
1129    * checks
1130    */
1131   
1132 #if defined (HAVE_POSIX_GETPWNAME_R) || defined (HAVE_NONPOSIX_GETPWNAME_R)
1133   {
1134     struct passwd *p;
1135     int result;
1136     char buf[1024];
1137     struct passwd p_str;
1138
1139     p = NULL;
1140 #ifdef HAVE_POSIX_GETPWNAME_R
1141     if (uid >= 0)
1142       result = getpwuid_r (uid, &p_str, buf, sizeof (buf),
1143                            &p);
1144     else
1145       result = getpwnam_r (username_c_str, &p_str, buf, sizeof (buf),
1146                            &p);
1147 #else
1148     if (uid >= 0)
1149       p = getpwuid_r (uid, &p_str, buf, sizeof (buf));
1150     else
1151       p = getpwnam_r (username_c_str, &p_str, buf, sizeof (buf));
1152     result = 0;
1153 #endif /* !HAVE_POSIX_GETPWNAME_R */
1154     if (result == 0 && p == &p_str)
1155       {
1156         return store_user_info (p, credentials, homedir,
1157                                 username_out);
1158       }
1159     else
1160       {
1161         _dbus_verbose ("User %s unknown\n", username_c_str);
1162         return FALSE;
1163       }
1164   }
1165 #else /* ! HAVE_GETPWNAM_R */
1166   {
1167     /* I guess we're screwed on thread safety here */
1168     struct passwd *p;
1169
1170     if (uid >= 0)
1171       p = getpwuid (uid);
1172     else
1173       p = getpwnam (username_c_str);
1174
1175     if (p != NULL)
1176       {
1177         return store_user_info (p, credentials, homedir,
1178                                 username_out);
1179       }
1180     else
1181       {
1182         _dbus_verbose ("User %s unknown\n", username_c_str);
1183         return FALSE;
1184       }
1185   }
1186 #endif  /* ! HAVE_GETPWNAM_R */
1187 }
1188
1189 /**
1190  * Gets the credentials corresponding to the given username.
1191  *
1192  * @param username the username
1193  * @param credentials credentials to fill in
1194  * @returns #TRUE if the username existed and we got some credentials
1195  */
1196 dbus_bool_t
1197 _dbus_credentials_from_username (const DBusString *username,
1198                                  DBusCredentials  *credentials)
1199 {
1200   return get_user_info (username, -1, credentials, NULL, NULL);
1201 }
1202
1203 static DBusMutex *user_info_lock = NULL;
1204 /**
1205  * Initializes the global mutex for the process's user information.
1206  *
1207  * @returns the mutex
1208  */
1209 DBusMutex *
1210 _dbus_user_info_init_lock (void)
1211 {
1212   user_info_lock = dbus_mutex_new ();
1213   return user_info_lock;
1214 }
1215
1216 /**
1217  * Gets information about the user running this process.
1218  *
1219  * @param username return location for username or #NULL
1220  * @param homedir return location for home directory or #NULL
1221  * @param credentials return location for credentials or #NULL
1222  * @returns #TRUE on success
1223  */
1224 dbus_bool_t
1225 _dbus_user_info_from_current_process (const DBusString      **username,
1226                                       const DBusString      **homedir,
1227                                       const DBusCredentials **credentials)
1228 {
1229   static DBusString name;
1230   static DBusString dir;
1231   static DBusCredentials creds;
1232   static dbus_bool_t initialized = FALSE;
1233   
1234   if (!dbus_mutex_lock (user_info_lock))
1235     return FALSE;
1236
1237   if (!initialized)
1238     {
1239       if (!_dbus_string_init (&name, _DBUS_INT_MAX))
1240         {
1241           dbus_mutex_unlock (user_info_lock);
1242           return FALSE;
1243         }
1244
1245       if (!_dbus_string_init (&dir, _DBUS_INT_MAX))
1246         {
1247           _dbus_string_free (&name);
1248           dbus_mutex_unlock (user_info_lock);
1249           return FALSE;
1250         }
1251       
1252       creds.uid = -1;
1253       creds.gid = -1;
1254       creds.pid = -1;
1255
1256       if (!get_user_info (NULL, getuid (),
1257                           &creds, &dir, &name))
1258         {
1259           _dbus_string_free (&name);
1260           _dbus_string_free (&dir);
1261           dbus_mutex_unlock (user_info_lock);
1262           return FALSE;
1263         }
1264
1265       initialized = TRUE;
1266     }
1267
1268   if (username)
1269     *username = &name;
1270   if (homedir)
1271     *homedir = &dir;
1272   if (credentials)
1273     *credentials = &creds;
1274   
1275   dbus_mutex_unlock (user_info_lock);
1276
1277   return TRUE;
1278 }
1279
1280 /**
1281  * Gets the home directory for the given user.
1282  *
1283  * @param username the username
1284  * @param homedir string to append home directory to
1285  * @returns #TRUE if user existed and we appended their homedir
1286  */
1287 dbus_bool_t
1288 _dbus_homedir_from_username (const DBusString *username,
1289                              DBusString       *homedir)
1290 {
1291   return get_user_info (username, -1, NULL, homedir, NULL);
1292 }
1293
1294 /**
1295  * Gets credentials from a UID string. (Parses a string to a UID
1296  * and converts to a DBusCredentials.)
1297  *
1298  * @param uid_str the UID in string form
1299  * @param credentials credentials to fill in
1300  * @returns #TRUE if successfully filled in some credentials
1301  */
1302 dbus_bool_t
1303 _dbus_credentials_from_uid_string (const DBusString      *uid_str,
1304                                    DBusCredentials       *credentials)
1305 {
1306   int end;
1307   long uid;
1308
1309   credentials->pid = -1;
1310   credentials->uid = -1;
1311   credentials->gid = -1;
1312   
1313   if (_dbus_string_get_length (uid_str) == 0)
1314     {
1315       _dbus_verbose ("UID string was zero length\n");
1316       return FALSE;
1317     }
1318
1319   uid = -1;
1320   end = 0;
1321   if (!_dbus_string_parse_int (uid_str, 0, &uid,
1322                                &end))
1323     {
1324       _dbus_verbose ("could not parse string as a UID\n");
1325       return FALSE;
1326     }
1327   
1328   if (end != _dbus_string_get_length (uid_str))
1329     {
1330       _dbus_verbose ("string contained trailing stuff after UID\n");
1331       return FALSE;
1332     }
1333
1334   credentials->uid = uid;
1335
1336   return TRUE;
1337 }
1338
1339 /**
1340  * Gets the credentials of the current process.
1341  *
1342  * @param credentials credentials to fill in.
1343  */
1344 void
1345 _dbus_credentials_from_current_process (DBusCredentials *credentials)
1346 {
1347   credentials->pid = getpid ();
1348   credentials->uid = getuid ();
1349   credentials->gid = getgid ();
1350 }
1351
1352 /**
1353  * Checks whether the provided_credentials are allowed to log in
1354  * as the expected_credentials.
1355  *
1356  * @param expected_credentials credentials we're trying to log in as
1357  * @param provided_credentials credentials we have
1358  * @returns #TRUE if we can log in
1359  */
1360 dbus_bool_t
1361 _dbus_credentials_match (const DBusCredentials *expected_credentials,
1362                          const DBusCredentials *provided_credentials)
1363 {
1364   if (provided_credentials->uid < 0)
1365     return FALSE;
1366   else if (expected_credentials->uid < 0)
1367     return FALSE;
1368   else if (provided_credentials->uid == 0)
1369     return TRUE;
1370   else if (provided_credentials->uid == expected_credentials->uid)
1371     return TRUE;
1372   else
1373     return FALSE;
1374 }
1375
1376 /**
1377  * Appends the uid of the current process to the given string.
1378  *
1379  * @param str the string to append to
1380  * @returns #TRUE on success
1381  */
1382 dbus_bool_t
1383 _dbus_string_append_our_uid (DBusString *str)
1384 {
1385   return _dbus_string_append_int (str, getuid ());
1386 }
1387
1388
1389 static DBusMutex *atomic_lock = NULL;
1390 /**
1391  * Initializes the global mutex for the fallback implementation
1392  * of atomic integers.
1393  *
1394  * @returns the mutex
1395  */
1396 DBusMutex *
1397 _dbus_atomic_init_lock (void)
1398 {
1399   atomic_lock = dbus_mutex_new ();
1400   return atomic_lock;
1401 }
1402
1403 /**
1404  * Atomically increments an integer
1405  *
1406  * @param atomic pointer to the integer to increment
1407  * @returns the value after incrementing
1408  *
1409  * @todo implement arch-specific faster atomic ops
1410  */
1411 dbus_atomic_t
1412 _dbus_atomic_inc (dbus_atomic_t *atomic)
1413 {
1414   dbus_atomic_t res;
1415   
1416   dbus_mutex_lock (atomic_lock);
1417   *atomic += 1;
1418   res = *atomic;
1419   dbus_mutex_unlock (atomic_lock);
1420   return res;
1421 }
1422
1423 /**
1424  * Atomically decrement an integer
1425  *
1426  * @param atomic pointer to the integer to decrement
1427  * @returns the value after decrementing
1428  *
1429  * @todo implement arch-specific faster atomic ops
1430  */
1431 dbus_atomic_t
1432 _dbus_atomic_dec (dbus_atomic_t *atomic)
1433 {
1434   dbus_atomic_t res;
1435   
1436   dbus_mutex_lock (atomic_lock);
1437   *atomic -= 1;
1438   res = *atomic;
1439   dbus_mutex_unlock (atomic_lock);
1440   return res;
1441 }
1442
1443 /**
1444  * Wrapper for poll().
1445  *
1446  * @todo need a fallback implementation using select()
1447  *
1448  * @param fds the file descriptors to poll
1449  * @param n_fds number of descriptors in the array
1450  * @param timeout_milliseconds timeout or -1 for infinite
1451  * @returns numbers of fds with revents, or <0 on error
1452  */
1453 int
1454 _dbus_poll (DBusPollFD *fds,
1455             int         n_fds,
1456             int         timeout_milliseconds)
1457 {
1458 #ifdef HAVE_POLL
1459   /* This big thing is a constant expression and should get optimized
1460    * out of existence. So it's more robust than a configure check at
1461    * no cost.
1462    */
1463   if (_DBUS_POLLIN == POLLIN &&
1464       _DBUS_POLLPRI == POLLPRI &&
1465       _DBUS_POLLOUT == POLLOUT &&
1466       _DBUS_POLLERR == POLLERR &&
1467       _DBUS_POLLHUP == POLLHUP &&
1468       _DBUS_POLLNVAL == POLLNVAL &&
1469       sizeof (DBusPollFD) == sizeof (struct pollfd) &&
1470       _DBUS_STRUCT_OFFSET (DBusPollFD, fd) ==
1471       _DBUS_STRUCT_OFFSET (struct pollfd, fd) &&
1472       _DBUS_STRUCT_OFFSET (DBusPollFD, events) ==
1473       _DBUS_STRUCT_OFFSET (struct pollfd, events) &&
1474       _DBUS_STRUCT_OFFSET (DBusPollFD, revents) ==
1475       _DBUS_STRUCT_OFFSET (struct pollfd, revents))
1476     {
1477       return poll ((struct pollfd*) fds,
1478                    n_fds, 
1479                    timeout_milliseconds);
1480     }
1481   else
1482     {
1483       /* We have to convert the DBusPollFD to an array of
1484        * struct pollfd, poll, and convert back.
1485        */
1486       _dbus_warn ("didn't implement poll() properly for this system yet\n");
1487       return -1;
1488     }
1489 #else /* ! HAVE_POLL */
1490
1491   fd_set read_set, write_set, err_set;
1492   int max_fd = 0;
1493   int i;
1494   struct timeval tv;
1495   int ready;
1496   
1497   FD_ZERO (&read_set);
1498   FD_ZERO (&write_set);
1499   FD_ZERO (&err_set);
1500
1501   for (i = 0; i < n_fds; i++)
1502     {
1503       DBusPollFD f = fds[i];
1504
1505       if (f.events & _DBUS_POLLIN)
1506         FD_SET (f.fd, &read_set);
1507
1508       if (f.events & _DBUS_POLLOUT)
1509         FD_SET (f.fd, &write_set);
1510
1511       FD_SET (f.fd, &err_set);
1512
1513       max_fd = MAX (max_fd, f.fd);
1514     }
1515     
1516   tv.tv_sec = timeout_milliseconds / 1000;
1517   tv.tv_usec = (timeout_milliseconds % 1000) * 1000;
1518
1519   ready = select (max_fd + 1, &read_set, &write_set, &err_set, &tv);
1520
1521   if (ready > 0)
1522     {
1523       for (i = 0; i < n_fds; i++)
1524         {
1525           DBusPollFD f = fds[i];
1526
1527           f.revents = 0;
1528
1529           if (FD_ISSET (f.fd, &read_set))
1530             f.revents |= _DBUS_POLLIN;
1531
1532           if (FD_ISSET (f.fd, &write_set))
1533             f.revents |= _DBUS_POLLOUT;
1534
1535           if (FD_ISSET (f.fd, &err_set))
1536             f.revents |= _DBUS_POLLERR;
1537         }
1538     }
1539
1540   return ready;
1541 #endif
1542 }
1543
1544 /** nanoseconds in a second */
1545 #define NANOSECONDS_PER_SECOND       1000000000
1546 /** microseconds in a second */
1547 #define MICROSECONDS_PER_SECOND      1000000
1548 /** milliseconds in a second */
1549 #define MILLISECONDS_PER_SECOND      1000
1550 /** nanoseconds in a millisecond */
1551 #define NANOSECONDS_PER_MILLISECOND  1000000
1552 /** microseconds in a millisecond */
1553 #define MICROSECONDS_PER_MILLISECOND 1000
1554
1555 /**
1556  * Sleeps the given number of milliseconds.
1557  * @param milliseconds number of milliseconds
1558  */
1559 void
1560 _dbus_sleep_milliseconds (int milliseconds)
1561 {
1562 #ifdef HAVE_NANOSLEEP
1563   struct timespec req;
1564   struct timespec rem;
1565
1566   req.tv_sec = milliseconds / MILLISECONDS_PER_SECOND;
1567   req.tv_nsec = (milliseconds % MILLISECONDS_PER_SECOND) * NANOSECONDS_PER_MILLISECOND;
1568   rem.tv_sec = 0;
1569   rem.tv_nsec = 0;
1570
1571   while (nanosleep (&req, &rem) < 0 && errno == EINTR)
1572     req = rem;
1573 #elif defined (HAVE_USLEEP)
1574   usleep (milliseconds * MICROSECONDS_PER_MILLISECOND);
1575 #else /* ! HAVE_USLEEP */
1576   sleep (MAX (milliseconds / 1000, 1));
1577 #endif
1578 }
1579
1580 /**
1581  * Get current time, as in gettimeofday().
1582  *
1583  * @param tv_sec return location for number of seconds
1584  * @param tv_usec return location for number of microseconds (thousandths)
1585  */
1586 void
1587 _dbus_get_current_time (long *tv_sec,
1588                         long *tv_usec)
1589 {
1590   struct timeval t;
1591
1592   gettimeofday (&t, NULL);
1593
1594   if (tv_sec)
1595     *tv_sec = t.tv_sec;
1596   if (tv_usec)
1597     *tv_usec = t.tv_usec;
1598 }
1599
1600 /**
1601  * Appends the contents of the given file to the string,
1602  * returning result code. At the moment, won't open a file
1603  * more than a megabyte in size.
1604  *
1605  * @param str the string to append to
1606  * @param filename filename to load
1607  * @returns result
1608  */
1609 DBusResultCode
1610 _dbus_file_get_contents (DBusString       *str,
1611                          const DBusString *filename)
1612 {
1613   int fd;
1614   struct stat sb;
1615   int orig_len;
1616   int total;
1617   const char *filename_c;
1618
1619   _dbus_string_get_const_data (filename, &filename_c);
1620   
1621   /* O_BINARY useful on Cygwin */
1622   fd = open (filename_c, O_RDONLY | O_BINARY);
1623   if (fd < 0)
1624     return _dbus_result_from_errno (errno);
1625
1626   if (fstat (fd, &sb) < 0)
1627     {
1628       DBusResultCode result;      
1629
1630       result = _dbus_result_from_errno (errno); /* prior to close() */
1631
1632       _dbus_verbose ("fstat() failed: %s",
1633                      _dbus_strerror (errno));
1634       
1635       close (fd);
1636       
1637       return result;
1638     }
1639
1640   if (sb.st_size > _DBUS_ONE_MEGABYTE)
1641     {
1642       _dbus_verbose ("File size %lu is too large.\n",
1643                      (unsigned long) sb.st_size);
1644       close (fd);
1645       return DBUS_RESULT_FAILED;
1646     }
1647   
1648   total = 0;
1649   orig_len = _dbus_string_get_length (str);
1650   if (sb.st_size > 0 && S_ISREG (sb.st_mode))
1651     {
1652       int bytes_read;
1653
1654       while (total < (int) sb.st_size)
1655         {
1656           bytes_read = _dbus_read (fd, str,
1657                                    sb.st_size - total);
1658           if (bytes_read <= 0)
1659             {
1660               DBusResultCode result;
1661               
1662               result = _dbus_result_from_errno (errno); /* prior to close() */
1663
1664               _dbus_verbose ("read() failed: %s",
1665                              _dbus_strerror (errno));
1666               
1667               close (fd);
1668               _dbus_string_set_length (str, orig_len);
1669               return result;
1670             }
1671           else
1672             total += bytes_read;
1673         }
1674
1675       close (fd);
1676       return DBUS_RESULT_SUCCESS;
1677     }
1678   else if (sb.st_size != 0)
1679     {
1680       _dbus_verbose ("Can only open regular files at the moment.\n");
1681       close (fd);
1682       return DBUS_RESULT_FAILED;
1683     }
1684   else
1685     {
1686       close (fd);
1687       return DBUS_RESULT_SUCCESS;
1688     }
1689 }
1690
1691 static dbus_bool_t
1692 append_unique_chars (DBusString *str)
1693 {
1694   static const char letters[] =
1695     "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
1696   int i;
1697   int len;
1698
1699 #define N_UNIQUE_CHARS 8
1700   
1701   if (!_dbus_generate_random_bytes (str, N_UNIQUE_CHARS))
1702     return FALSE;
1703   
1704   len = _dbus_string_get_length (str);
1705   i = len - N_UNIQUE_CHARS;
1706   while (i < len)
1707     {
1708       _dbus_string_set_byte (str, i,
1709                              letters[_dbus_string_get_byte (str, i) %
1710                                      (sizeof (letters) - 1)]);
1711
1712       ++i;
1713     }
1714
1715   _dbus_assert (_dbus_string_validate_ascii (str, len - N_UNIQUE_CHARS,
1716                                              N_UNIQUE_CHARS));
1717
1718   return TRUE;
1719 }
1720
1721 /**
1722  * Writes a string out to a file. If the file exists,
1723  * it will be atomically overwritten by the new data.
1724  *
1725  * @param str the string to write out
1726  * @param filename the file to save string to
1727  * @returns result code
1728  */
1729 DBusResultCode
1730 _dbus_string_save_to_file (const DBusString *str,
1731                            const DBusString *filename)
1732 {
1733   int fd;
1734   int bytes_to_write;
1735   const char *filename_c;
1736   DBusString tmp_filename;
1737   const char *tmp_filename_c;
1738   int total;
1739   DBusResultCode result;
1740   dbus_bool_t need_unlink;
1741   
1742   fd = -1;
1743   result = DBUS_RESULT_FAILED;
1744   need_unlink = FALSE;
1745   
1746   if (!_dbus_string_init (&tmp_filename, _DBUS_INT_MAX))
1747     return DBUS_RESULT_NO_MEMORY;
1748
1749   if (!_dbus_string_copy (filename, 0, &tmp_filename, 0))
1750     return DBUS_RESULT_NO_MEMORY;
1751   
1752   if (!_dbus_string_append (&tmp_filename, "."))
1753     return DBUS_RESULT_NO_MEMORY;
1754   
1755   if (!append_unique_chars (&tmp_filename))
1756     return DBUS_RESULT_NO_MEMORY;
1757     
1758   _dbus_string_get_const_data (filename, &filename_c);
1759   _dbus_string_get_const_data (&tmp_filename, &tmp_filename_c);
1760
1761   fd = open (tmp_filename_c, O_WRONLY | O_BINARY | O_EXCL | O_CREAT,
1762              0600);
1763   if (fd < 0)
1764     {
1765       result = _dbus_result_from_errno (errno);
1766       goto out;
1767     }
1768
1769   need_unlink = TRUE;
1770   
1771   total = 0;
1772   bytes_to_write = _dbus_string_get_length (str);
1773
1774   while (total < bytes_to_write)
1775     {
1776       int bytes_written;
1777
1778       bytes_written = _dbus_write (fd, str, total,
1779                                    bytes_to_write - total);
1780
1781       if (bytes_written <= 0)
1782         {
1783           DBusResultCode result;
1784           
1785           result = _dbus_result_from_errno (errno); /* prior to close() */
1786           
1787           _dbus_verbose ("write() failed: %s",
1788                          _dbus_strerror (errno));
1789           
1790           goto out;
1791         }
1792
1793       total += bytes_written;
1794     }
1795
1796   if (close (fd) < 0)
1797     {
1798       _dbus_verbose ("close() failed: %s\n", _dbus_strerror (errno));
1799       goto out;
1800     }
1801
1802   fd = -1;
1803   
1804   if (rename (tmp_filename_c, filename_c) < 0)
1805     {
1806       _dbus_verbose ("rename() failed: %s\n", _dbus_strerror (errno));
1807       goto out;
1808     }
1809
1810   need_unlink = FALSE;
1811   
1812   result = DBUS_RESULT_SUCCESS;
1813   
1814  out:
1815   /* close first, then unlink, to prevent ".nfs34234235" garbage
1816    * files
1817    */
1818
1819   if (fd >= 0)
1820     close (fd);
1821         
1822   if (need_unlink && unlink (tmp_filename_c) < 0)
1823     _dbus_verbose ("Failed to unlink temp file %s: %s\n",
1824                    tmp_filename_c, _dbus_strerror (errno));
1825
1826   _dbus_string_free (&tmp_filename);
1827   
1828   return result;
1829 }
1830
1831 /** Creates the given file, failing if the file already exists.
1832  *
1833  * @param filename the filename
1834  * @param error error location
1835  * @returns #TRUE if we created the file and it didn't exist
1836  */
1837 dbus_bool_t
1838 _dbus_create_file_exclusively (const DBusString *filename,
1839                                DBusError        *error)
1840 {
1841   int fd;
1842   const char *filename_c;
1843
1844   _dbus_string_get_const_data (filename, &filename_c);
1845   
1846   fd = open (filename_c, O_WRONLY | O_BINARY | O_EXCL | O_CREAT,
1847              0600);
1848   if (fd < 0)
1849     {
1850       dbus_set_error (error,
1851                       DBUS_ERROR_FAILED,
1852                       "Could not create file %s: %s\n",
1853                       filename_c,
1854                       _dbus_errno_to_string (errno));
1855       return FALSE;
1856     }
1857
1858   if (close (fd) < 0)
1859     {
1860       dbus_set_error (error,
1861                       DBUS_ERROR_FAILED,
1862                       "Could not close file %s: %s\n",
1863                       filename_c,
1864                       _dbus_errno_to_string (errno));
1865       return FALSE;
1866     }
1867   
1868   return TRUE;
1869 }
1870
1871 /**
1872  * Deletes the given file.
1873  *
1874  * @param filename the filename
1875  * @param error error location
1876  * 
1877  * @returns #TRUE if unlink() succeeded
1878  */
1879 dbus_bool_t
1880 _dbus_delete_file (const DBusString *filename,
1881                    DBusError        *error)
1882 {
1883   const char *filename_c;
1884
1885   _dbus_string_get_const_data (filename, &filename_c);
1886
1887   if (unlink (filename_c) < 0)
1888     {
1889       dbus_set_error (error, DBUS_ERROR_FAILED,
1890                       "Failed to delete file %s: %s\n",
1891                       filename_c, _dbus_strerror (errno));
1892       return FALSE;
1893     }
1894   else
1895     return TRUE;
1896 }
1897
1898 /**
1899  * Creates a directory; succeeds if the directory
1900  * is created or already existed.
1901  *
1902  * @param filename directory filename
1903  * @param error initialized error object
1904  * @returns #TRUE on success
1905  */
1906 dbus_bool_t
1907 _dbus_create_directory (const DBusString *filename,
1908                         DBusError        *error)
1909 {
1910   const char *filename_c;
1911
1912   _dbus_string_get_const_data (filename, &filename_c);
1913
1914   if (mkdir (filename_c, 0700) < 0)
1915     {
1916       if (errno == EEXIST)
1917         return TRUE;
1918       
1919       dbus_set_error (error, DBUS_ERROR_FAILED,
1920                       "Failed to create directory %s: %s\n",
1921                       filename_c, _dbus_strerror (errno));
1922       return FALSE;
1923     }
1924   else
1925     return TRUE;
1926 }
1927
1928 /**
1929  * Appends the given filename to the given directory.
1930  *
1931  * @param dir the directory name
1932  * @param next_component the filename
1933  * @returns #TRUE on success
1934  */
1935 dbus_bool_t
1936 _dbus_concat_dir_and_file (DBusString       *dir,
1937                            const DBusString *next_component)
1938 {
1939   dbus_bool_t dir_ends_in_slash;
1940   dbus_bool_t file_starts_with_slash;
1941
1942   if (_dbus_string_get_length (dir) == 0 ||
1943       _dbus_string_get_length (next_component) == 0)
1944     return TRUE;
1945   
1946   dir_ends_in_slash = '/' == _dbus_string_get_byte (dir,
1947                                                     _dbus_string_get_length (dir) - 1);
1948
1949   file_starts_with_slash = '/' == _dbus_string_get_byte (next_component, 0);
1950
1951   if (dir_ends_in_slash && file_starts_with_slash)
1952     {
1953       _dbus_string_shorten (dir, 1);
1954     }
1955   else if (!(dir_ends_in_slash || file_starts_with_slash))
1956     {
1957       if (!_dbus_string_append_byte (dir, '/'))
1958         return FALSE;
1959     }
1960
1961   return _dbus_string_copy (next_component, 0, dir,
1962                             _dbus_string_get_length (dir));
1963 }
1964
1965 struct DBusDirIter
1966 {
1967   DIR *d;
1968   
1969 };
1970
1971 /**
1972  * Open a directory to iterate over.
1973  *
1974  * @param filename the directory name
1975  * @param result return location for error code if #NULL returned
1976  * @returns new iterator, or #NULL on error
1977  */
1978 DBusDirIter*
1979 _dbus_directory_open (const DBusString *filename,
1980                       DBusResultCode   *result)
1981 {
1982   DIR *d;
1983   DBusDirIter *iter;
1984   const char *filename_c;
1985
1986   _dbus_string_get_const_data (filename, &filename_c);
1987
1988   d = opendir (filename_c);
1989   if (d == NULL)
1990     {
1991       dbus_set_result (result, _dbus_result_from_errno (errno));
1992       return NULL;
1993     }
1994   
1995   iter = dbus_new0 (DBusDirIter, 1);
1996   if (iter == NULL)
1997     {
1998       closedir (d);
1999       dbus_set_result (result, DBUS_RESULT_NO_MEMORY);
2000       return NULL;
2001     }
2002
2003   iter->d = d;
2004
2005   return iter;
2006 }
2007
2008 /**
2009  * Get next file in the directory. Will not return "." or ".."
2010  * on UNIX. If an error occurs, the contents of "filename"
2011  * are undefined. #DBUS_RESULT_SUCCESS is always returned
2012  * in result if no error occurs.
2013  *
2014  * @todo for thread safety, I think we have to use
2015  * readdir_r(). (GLib has the same issue, should file a bug.)
2016  *
2017  * @param iter the iterator
2018  * @param filename string to be set to the next file in the dir
2019  * @param result return location for error, or #DBUS_RESULT_SUCCESS
2020  * @returns #TRUE if filename was filled in with a new filename
2021  */
2022 dbus_bool_t
2023 _dbus_directory_get_next_file (DBusDirIter      *iter,
2024                                DBusString       *filename,
2025                                DBusResultCode   *result)
2026 {
2027   /* we always have to put something in result, since return
2028    * value means whether there's a filename and doesn't
2029    * reliably indicate whether an error was set.
2030    */
2031   struct dirent *ent;
2032   
2033   dbus_set_result (result, DBUS_RESULT_SUCCESS);
2034
2035  again:
2036   errno = 0;
2037   ent = readdir (iter->d);
2038   if (ent == NULL)
2039     {
2040       dbus_set_result (result,
2041                        _dbus_result_from_errno (errno));
2042       return FALSE;
2043     }
2044   else if (ent->d_name[0] == '.' &&
2045            (ent->d_name[1] == '\0' ||
2046             (ent->d_name[1] == '.' && ent->d_name[2] == '\0')))
2047     goto again;
2048   else
2049     {
2050       _dbus_string_set_length (filename, 0);
2051       if (!_dbus_string_append (filename, ent->d_name))
2052         {
2053           dbus_set_result (result, DBUS_RESULT_NO_MEMORY);
2054           return FALSE;
2055         }
2056       else
2057         return TRUE;
2058     }
2059 }
2060
2061 /**
2062  * Closes a directory iteration.
2063  */
2064 void
2065 _dbus_directory_close (DBusDirIter *iter)
2066 {
2067   closedir (iter->d);
2068   dbus_free (iter);
2069 }
2070
2071 /**
2072  * Generates the given number of random bytes,
2073  * using the best mechanism we can come up with.
2074  *
2075  * @param str the string
2076  * @param n_bytes the number of random bytes to append to string
2077  * @returns #TRUE on success, #FALSE if no memory or other failure
2078  */
2079 dbus_bool_t
2080 _dbus_generate_random_bytes (DBusString *str,
2081                              int         n_bytes)
2082 {
2083   int old_len;
2084   int fd;
2085   
2086   old_len = _dbus_string_get_length (str);
2087   fd = -1;
2088
2089   /* note, urandom on linux will fall back to pseudorandom */
2090   fd = open ("/dev/urandom", O_RDONLY);
2091   if (fd < 0)
2092     {
2093       unsigned long tv_usec;
2094       int i;
2095
2096       /* fall back to pseudorandom */
2097       _dbus_verbose ("Falling back to pseudorandom for %d bytes\n",
2098                      n_bytes);
2099       
2100       _dbus_get_current_time (NULL, &tv_usec);
2101       srand (tv_usec);
2102       
2103       i = 0;
2104       while (i < n_bytes)
2105         {
2106           double r;
2107           unsigned int b;
2108           
2109           r = rand ();
2110           b = (r / (double) RAND_MAX) * 255.0;
2111           
2112           if (!_dbus_string_append_byte (str, b))
2113             goto failed;
2114           
2115           ++i;
2116         }
2117
2118       return TRUE;
2119     }
2120   else
2121     {
2122       if (_dbus_read (fd, str, n_bytes) != n_bytes)
2123         goto failed;
2124
2125       _dbus_verbose ("Read %d bytes from /dev/urandom\n",
2126                      n_bytes);
2127       
2128       close (fd);
2129
2130       return TRUE;
2131     }
2132
2133  failed:
2134   _dbus_string_set_length (str, old_len);
2135   if (fd >= 0)
2136     close (fd);
2137   return FALSE;
2138 }
2139
2140 /**
2141  * A wrapper around strerror()
2142  *
2143  * @todo get rid of this function, it's the same as
2144  * _dbus_strerror().
2145  * 
2146  * @param errnum the errno
2147  * @returns an error message (never #NULL)
2148  */
2149 const char *
2150 _dbus_errno_to_string (int errnum)
2151 {
2152   const char *msg;
2153   
2154   msg = strerror (errnum);
2155   if (msg == NULL)
2156     msg = "unknown";
2157
2158   return msg;
2159 }
2160
2161 /**
2162  * A wrapper around strerror() because some platforms
2163  * may be lame and not have strerror().
2164  *
2165  * @param error_number errno.
2166  * @returns error description.
2167  */
2168 const char*
2169 _dbus_strerror (int error_number)
2170 {
2171   const char *msg;
2172   
2173   msg = strerror (error_number);
2174   if (msg == NULL)
2175     msg = "unknown";
2176
2177   return msg;
2178 }
2179
2180 /* Avoids a danger in threaded situations (calling close()
2181  * on a file descriptor twice, and another thread has
2182  * re-opened it since the first close)
2183  */
2184 static int
2185 close_and_invalidate (int *fd)
2186 {
2187   int ret;
2188
2189   if (*fd < 0)
2190     return -1;
2191   else
2192     {
2193       ret = close (*fd);
2194       *fd = -1;
2195     }
2196
2197   return ret;
2198 }
2199
2200 static dbus_bool_t
2201 make_pipe (int        p[2],
2202            DBusError *error)
2203 {
2204   if (pipe (p) < 0)
2205     {
2206       dbus_set_error (error,
2207                       DBUS_ERROR_SPAWN_FAILED,
2208                       "Failed to create pipe for communicating with child process (%s)",
2209                       _dbus_errno_to_string (errno));
2210       return FALSE;
2211     }
2212   else
2213     {
2214       _dbus_fd_set_close_on_exec (p[0]);
2215       _dbus_fd_set_close_on_exec (p[1]);      
2216       return TRUE;
2217     }
2218 }
2219
2220 enum
2221 {
2222   CHILD_CHDIR_FAILED,
2223   CHILD_EXEC_FAILED,
2224   CHILD_DUP2_FAILED,
2225   CHILD_FORK_FAILED
2226 };
2227
2228 static void
2229 write_err_and_exit (int fd, int msg)
2230 {
2231   int en = errno;
2232   
2233   write (fd, &msg, sizeof(msg));
2234   write (fd, &en, sizeof(en));
2235   
2236   _exit (1);
2237 }
2238
2239 static dbus_bool_t
2240 read_ints (int        fd,
2241            int       *buf,
2242            int        n_ints_in_buf,
2243            int       *n_ints_read,
2244            DBusError *error)
2245 {
2246   size_t bytes = 0;    
2247   
2248   while (TRUE)
2249     {
2250       size_t chunk;    
2251
2252       if (bytes >= sizeof(int)*2)
2253         break; /* give up, who knows what happened, should not be
2254                 * possible.
2255                 */
2256           
2257     again:
2258       chunk = read (fd,
2259                     ((char*)buf) + bytes,
2260                     sizeof(int) * n_ints_in_buf - bytes);
2261       if (chunk < 0 && errno == EINTR)
2262         goto again;
2263           
2264       if (chunk < 0)
2265         {
2266           /* Some weird shit happened, bail out */
2267               
2268           dbus_set_error (error,
2269                           DBUS_ERROR_SPAWN_FAILED,
2270                           "Failed to read from child pipe (%s)",
2271                           _dbus_errno_to_string (errno));
2272
2273           return FALSE;
2274         }
2275       else if (chunk == 0)
2276         break; /* EOF */
2277       else /* chunk > 0 */
2278         bytes += chunk;
2279     }
2280
2281   *n_ints_read = (int)(bytes / sizeof(int));
2282
2283   return TRUE;
2284 }
2285
2286 static void
2287 do_exec (int                       child_err_report_fd,
2288          char                    **argv,
2289          DBusSpawnChildSetupFunc   child_setup,
2290          void                     *user_data)
2291 {
2292 #ifdef DBUS_BUILD_TESTS
2293   int i, max_open;
2294 #endif
2295
2296   if (child_setup)
2297     (* child_setup) (user_data);
2298
2299 #ifdef DBUS_BUILD_TESTS
2300   max_open = sysconf (_SC_OPEN_MAX);
2301   
2302   for (i = 3; i < max_open; i++)
2303     {
2304       int retval;
2305
2306       retval = fcntl (i, F_GETFD);
2307
2308       if (retval != -1 && !(retval & FD_CLOEXEC))
2309         _dbus_warn ("Fd %d did not have the close-on-exec flag set!\n", i);
2310     }
2311 #endif
2312   
2313   execv (argv[0], argv);
2314
2315   /* Exec failed */
2316   write_err_and_exit (child_err_report_fd,
2317                       CHILD_EXEC_FAILED);
2318   
2319 }
2320
2321 /**
2322  * Spawns a new process. The executable name and argv[0]
2323  * are the same, both are provided in argv[0]. The child_setup
2324  * function is passed the given user_data and is run in the child
2325  * just before calling exec().
2326  *
2327  * @todo this code should be reviewed/double-checked as it's fairly
2328  * complex and no one has reviewed it yet.
2329  *
2330  * @param argv the executable and arguments
2331  * @param child_setup function to call in child pre-exec()
2332  * @param user_data user data for setup function
2333  * @param error error object to be filled in if function fails
2334  * @returns #TRUE on success, #FALSE if error is filled in
2335  */
2336 dbus_bool_t
2337 _dbus_spawn_async (char                    **argv,
2338                    DBusSpawnChildSetupFunc   child_setup,
2339                    void                     *user_data,
2340                    DBusError                *error)
2341 {
2342   int pid = -1, grandchild_pid;
2343   int child_err_report_pipe[2] = { -1, -1 };
2344   int status;
2345   
2346   if (!make_pipe (child_err_report_pipe, error))
2347     return FALSE;
2348
2349   pid = fork ();
2350   
2351   if (pid < 0)
2352     {
2353       dbus_set_error (error,
2354                       DBUS_ERROR_SPAWN_FORK_FAILED,
2355                       "Failed to fork (%s)",
2356                       _dbus_errno_to_string (errno));
2357       return FALSE;
2358     }
2359   else if (pid == 0)
2360     {
2361       /* Immediate child. */
2362       
2363       /* Be sure we crash if the parent exits
2364        * and we write to the err_report_pipe
2365        */
2366       signal (SIGPIPE, SIG_DFL);
2367
2368       /* Close the parent's end of the pipes;
2369        * not needed in the close_descriptors case,
2370        * though
2371        */
2372       close_and_invalidate (&child_err_report_pipe[0]);
2373
2374       /* We need to fork an intermediate child that launches the
2375        * final child. The purpose of the intermediate child
2376        * is to exit, so we can waitpid() it immediately.
2377        * Then the grandchild will not become a zombie.
2378        */
2379       grandchild_pid = fork ();
2380       
2381       if (grandchild_pid < 0)
2382         {
2383           write_err_and_exit (child_err_report_pipe[1],
2384                               CHILD_FORK_FAILED);              
2385         }
2386       else if (grandchild_pid == 0)
2387         {
2388           do_exec (child_err_report_pipe[1],
2389                    argv,
2390                    child_setup, user_data);
2391         }
2392       else
2393         {
2394           _exit (0);
2395         }
2396     }
2397   else
2398     {
2399       /* Parent */
2400
2401       int buf[2];
2402       int n_ints = 0;    
2403       
2404       /* Close the uncared-about ends of the pipes */
2405       close_and_invalidate (&child_err_report_pipe[1]);
2406
2407     wait_again:
2408       if (waitpid (pid, &status, 0) < 0)
2409         {
2410           if (errno == EINTR)
2411             goto wait_again;
2412           else if (errno == ECHILD)
2413             ; /* do nothing, child already reaped */
2414           else
2415             _dbus_warn ("waitpid() should not fail in "
2416                         "'_dbus_spawn_async'");
2417         }
2418
2419       if (!read_ints (child_err_report_pipe[0],
2420                       buf, 2, &n_ints,
2421                       error))
2422           goto cleanup_and_fail;
2423       
2424       if (n_ints >= 2)
2425         {
2426           /* Error from the child. */
2427           switch (buf[0])
2428             {
2429             default:
2430               dbus_set_error (error,
2431                               DBUS_ERROR_SPAWN_FAILED,
2432                               "Unknown error executing child process \"%s\"",
2433                               argv[0]);
2434               break;
2435             }
2436
2437           goto cleanup_and_fail;
2438         }
2439
2440
2441       /* Success against all odds! return the information */
2442       close_and_invalidate (&child_err_report_pipe[0]);
2443
2444       return TRUE;
2445     }
2446
2447  cleanup_and_fail:
2448
2449   /* There was an error from the Child, reap the child to avoid it being
2450      a zombie.
2451   */
2452   if (pid > 0)
2453     {
2454     wait_failed:
2455       if (waitpid (pid, NULL, 0) < 0)
2456         {
2457           if (errno == EINTR)
2458             goto wait_failed;
2459           else if (errno == ECHILD)
2460             ; /* do nothing, child already reaped */
2461           else
2462             _dbus_warn ("waitpid() should not fail in "
2463                         "'_dbus_spawn_async'");
2464         }
2465     }
2466   
2467   close_and_invalidate (&child_err_report_pipe[0]);
2468   close_and_invalidate (&child_err_report_pipe[1]);
2469
2470   return FALSE;
2471 }
2472
2473 /**
2474  * signal (SIGPIPE, SIG_IGN);
2475  */
2476 void
2477 _dbus_disable_sigpipe (void)
2478 {
2479   signal (SIGPIPE, SIG_IGN);
2480 }
2481
2482 /**
2483  * Sets the file descriptor to be close
2484  * on exec. Should be called for all file
2485  * descriptors in D-BUS code.
2486  *
2487  * @param fd the file descriptor
2488  */
2489 void
2490 _dbus_fd_set_close_on_exec (int fd)
2491 {
2492   int val;
2493   
2494   val = fcntl (fd, F_GETFD, 0);
2495   
2496   if (val < 0)
2497     return;
2498
2499   val |= FD_CLOEXEC;
2500   
2501   fcntl (fd, F_SETFD, val);
2502 }
2503
2504 /** @} end of sysdeps */