Main Page | Modules | Data Structures | File List | Data Fields | Related Pages

dbus-sysdeps.c

00001 /* -*- mode: C; c-file-style: "gnu" -*- */
00002 /* dbus-sysdeps.c Wrappers around system/libc features (internal to D-BUS implementation)
00003  * 
00004  * Copyright (C) 2002, 2003  Red Hat, Inc.
00005  * Copyright (C) 2003 CodeFactory AB
00006  *
00007  * Licensed under the Academic Free License version 2.0
00008  * 
00009  * This program is free software; you can redistribute it and/or modify
00010  * it under the terms of the GNU General Public License as published by
00011  * the Free Software Foundation; either version 2 of the License, or
00012  * (at your option) any later version.
00013  *
00014  * This program is distributed in the hope that it will be useful,
00015  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00016  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00017  * GNU General Public License for more details.
00018  * 
00019  * You should have received a copy of the GNU General Public License
00020  * along with this program; if not, write to the Free Software
00021  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00022  *
00023  */
00024 
00025 #include "dbus-internals.h"
00026 #include "dbus-sysdeps.h"
00027 #include "dbus-threads.h"
00028 #include "dbus-test.h"
00029 #include <sys/types.h>
00030 #include <stdlib.h>
00031 #include <string.h>
00032 #include <signal.h>
00033 #include <unistd.h>
00034 #include <stdio.h>
00035 #include <errno.h>
00036 #include <fcntl.h>
00037 #include <sys/socket.h>
00038 #include <dirent.h>
00039 #include <sys/un.h>
00040 #include <pwd.h>
00041 #include <time.h>
00042 #include <locale.h>
00043 #include <sys/time.h>
00044 #include <sys/stat.h>
00045 #include <sys/wait.h>
00046 #include <netinet/in.h>
00047 #include <netdb.h>
00048 #include <grp.h>
00049 
00050 #ifdef HAVE_WRITEV
00051 #include <sys/uio.h>
00052 #endif
00053 #ifdef HAVE_POLL
00054 #include <sys/poll.h>
00055 #endif
00056 #ifdef HAVE_BACKTRACE
00057 #include <execinfo.h>
00058 #endif
00059 
00060 
00061 #ifndef O_BINARY
00062 #define O_BINARY 0
00063 #endif
00064 
00065 #ifndef HAVE_SOCKLEN_T
00066 #define socklen_t int
00067 #endif
00068 
00076 void
00077 _dbus_abort (void)
00078 {
00079 #ifdef DBUS_ENABLE_VERBOSE_MODE
00080   const char *s;
00081   s = _dbus_getenv ("DBUS_PRINT_BACKTRACE");
00082   if (s && *s)
00083     _dbus_print_backtrace ();
00084 #endif
00085   abort ();
00086   _exit (1); /* in case someone manages to ignore SIGABRT */
00087 }
00088 
00100 dbus_bool_t
00101 _dbus_setenv (const char *varname,
00102               const char *value)
00103 {
00104   _dbus_assert (varname != NULL);
00105   
00106   if (value == NULL)
00107     {
00108 #ifdef HAVE_UNSETENV
00109       unsetenv (varname);
00110       return TRUE;
00111 #else
00112       char *putenv_value;
00113       size_t len;
00114 
00115       len = strlen (varname);
00116 
00117       /* Use system malloc to avoid memleaks that dbus_malloc
00118        * will get upset about.
00119        */
00120       
00121       putenv_value = malloc (len + 1);
00122       if (putenv_value == NULL)
00123         return FALSE;
00124 
00125       strcpy (putenv_value, varname);
00126       
00127       return (putenv (putenv_value) == 0);
00128 #endif
00129     }
00130   else
00131     {
00132 #ifdef HAVE_SETENV
00133       return (setenv (varname, value, TRUE) == 0);
00134 #else
00135       char *putenv_value;
00136       size_t len;
00137       size_t varname_len;
00138       size_t value_len;
00139 
00140       varname_len = strlen (varname);
00141       value_len = strlen (value);
00142       
00143       len = varname_len + value_len + 1 /* '=' */ ;
00144 
00145       /* Use system malloc to avoid memleaks that dbus_malloc
00146        * will get upset about.
00147        */
00148       
00149       putenv_value = malloc (len + 1);
00150       if (putenv_value == NULL)
00151         return FALSE;
00152 
00153       strcpy (putenv_value, varname);
00154       strcpy (putenv_value + varname_len, "=");
00155       strcpy (putenv_value + varname_len + 1, value);
00156       
00157       return (putenv (putenv_value) == 0);
00158 #endif
00159     }
00160 }
00161 
00168 const char*
00169 _dbus_getenv (const char *varname)
00170 {  
00171   return getenv (varname);
00172 }
00173 
00187 int
00188 _dbus_read (int               fd,
00189             DBusString       *buffer,
00190             int               count)
00191 {
00192   int bytes_read;
00193   int start;
00194   char *data;
00195 
00196   _dbus_assert (count >= 0);
00197   
00198   start = _dbus_string_get_length (buffer);
00199 
00200   if (!_dbus_string_lengthen (buffer, count))
00201     {
00202       errno = ENOMEM;
00203       return -1;
00204     }
00205 
00206   data = _dbus_string_get_data_len (buffer, start, count);
00207 
00208  again:
00209   
00210   bytes_read = read (fd, data, count);
00211 
00212   if (bytes_read < 0)
00213     {
00214       if (errno == EINTR)
00215         goto again;
00216       else
00217         {
00218           /* put length back (note that this doesn't actually realloc anything) */
00219           _dbus_string_set_length (buffer, start);
00220           return -1;
00221         }
00222     }
00223   else
00224     {
00225       /* put length back (doesn't actually realloc) */
00226       _dbus_string_set_length (buffer, start + bytes_read);
00227 
00228 #if 0
00229       if (bytes_read > 0)
00230         _dbus_verbose_bytes_of_string (buffer, start, bytes_read);
00231 #endif
00232       
00233       return bytes_read;
00234     }
00235 }
00236 
00247 int
00248 _dbus_write (int               fd,
00249              const DBusString *buffer,
00250              int               start,
00251              int               len)
00252 {
00253   const char *data;
00254   int bytes_written;
00255   
00256   data = _dbus_string_get_const_data_len (buffer, start, len);
00257   
00258  again:
00259 
00260   bytes_written = write (fd, data, len);
00261 
00262   if (bytes_written < 0 && errno == EINTR)
00263     goto again;
00264 
00265 #if 0
00266   if (bytes_written > 0)
00267     _dbus_verbose_bytes_of_string (buffer, start, bytes_written);
00268 #endif
00269   
00270   return bytes_written;
00271 }
00272 
00293 int
00294 _dbus_write_two (int               fd,
00295                  const DBusString *buffer1,
00296                  int               start1,
00297                  int               len1,
00298                  const DBusString *buffer2,
00299                  int               start2,
00300                  int               len2)
00301 {
00302   _dbus_assert (buffer1 != NULL);
00303   _dbus_assert (start1 >= 0);
00304   _dbus_assert (start2 >= 0);
00305   _dbus_assert (len1 >= 0);
00306   _dbus_assert (len2 >= 0);
00307   
00308 #ifdef HAVE_WRITEV
00309   {
00310     struct iovec vectors[2];
00311     const char *data1;
00312     const char *data2;
00313     int bytes_written;
00314 
00315     data1 = _dbus_string_get_const_data_len (buffer1, start1, len1);
00316 
00317     if (buffer2 != NULL)
00318       data2 = _dbus_string_get_const_data_len (buffer2, start2, len2);
00319     else
00320       {
00321         data2 = NULL;
00322         start2 = 0;
00323         len2 = 0;
00324       }
00325    
00326     vectors[0].iov_base = (char*) data1;
00327     vectors[0].iov_len = len1;
00328     vectors[1].iov_base = (char*) data2;
00329     vectors[1].iov_len = len2;
00330 
00331   again:
00332    
00333     bytes_written = writev (fd,
00334                             vectors,
00335                             data2 ? 2 : 1);
00336 
00337     if (bytes_written < 0 && errno == EINTR)
00338       goto again;
00339    
00340     return bytes_written;
00341   }
00342 #else /* HAVE_WRITEV */
00343   {
00344     int ret1;
00345     
00346     ret1 = _dbus_write (fd, buffer1, start1, len1);
00347     if (ret1 == len1 && buffer2 != NULL)
00348       {
00349         ret2 = _dbus_write (fd, buffer2, start2, len2);
00350         if (ret2 < 0)
00351           ret2 = 0; /* we can't report an error as the first write was OK */
00352        
00353         return ret1 + ret2;
00354       }
00355     else
00356       return ret1;
00357   }
00358 #endif /* !HAVE_WRITEV */   
00359 }
00360 
00361 #define _DBUS_MAX_SUN_PATH_LENGTH 99
00362 
00390 int
00391 _dbus_connect_unix_socket (const char     *path,
00392                            dbus_bool_t     abstract,
00393                            DBusError      *error)
00394 {
00395   int fd;
00396   struct sockaddr_un addr;  
00397 
00398   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
00399 
00400   _dbus_verbose ("connecting to unix socket %s abstract=%d\n",
00401                  path, abstract);
00402   
00403   fd = socket (PF_UNIX, SOCK_STREAM, 0);
00404   
00405   if (fd < 0)
00406     {
00407       dbus_set_error (error,
00408                       _dbus_error_from_errno (errno),
00409                       "Failed to create socket: %s",
00410                       _dbus_strerror (errno)); 
00411       
00412       return -1;
00413     }
00414 
00415   _DBUS_ZERO (addr);
00416   addr.sun_family = AF_UNIX;
00417 
00418   if (abstract)
00419     {
00420 #ifdef HAVE_ABSTRACT_SOCKETS
00421       /* remember that abstract names aren't nul-terminated so we rely
00422        * on sun_path being filled in with zeroes above.
00423        */
00424       addr.sun_path[0] = '\0'; /* this is what says "use abstract" */
00425       strncpy (&addr.sun_path[1], path, _DBUS_MAX_SUN_PATH_LENGTH - 2);
00426       /* _dbus_verbose_bytes (addr.sun_path, sizeof (addr.sun_path)); */
00427 #else /* HAVE_ABSTRACT_SOCKETS */
00428       dbus_set_error (error, DBUS_ERROR_NOT_SUPPORTED,
00429                       "Operating system does not support abstract socket namespace\n");
00430       close (fd);
00431       return -1;
00432 #endif /* ! HAVE_ABSTRACT_SOCKETS */
00433     }
00434   else
00435     {
00436       strncpy (addr.sun_path, path, _DBUS_MAX_SUN_PATH_LENGTH - 1);
00437     }
00438   
00439   if (connect (fd, (struct sockaddr*) &addr, sizeof (addr)) < 0)
00440     {      
00441       dbus_set_error (error,
00442                       _dbus_error_from_errno (errno),
00443                       "Failed to connect to socket %s: %s",
00444                       path, _dbus_strerror (errno));
00445 
00446       close (fd);
00447       fd = -1;
00448       
00449       return -1;
00450     }
00451 
00452   if (!_dbus_set_fd_nonblocking (fd, error))
00453     {
00454       _DBUS_ASSERT_ERROR_IS_SET (error);
00455       
00456       close (fd);
00457       fd = -1;
00458 
00459       return -1;
00460     }
00461 
00462   return fd;
00463 }
00464 
00480 int
00481 _dbus_listen_unix_socket (const char     *path,
00482                           dbus_bool_t     abstract,
00483                           DBusError      *error)
00484 {
00485   int listen_fd;
00486   struct sockaddr_un addr;
00487 
00488   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
00489 
00490   _dbus_verbose ("listening on unix socket %s abstract=%d\n",
00491                  path, abstract);
00492   
00493   listen_fd = socket (PF_UNIX, SOCK_STREAM, 0);
00494   
00495   if (listen_fd < 0)
00496     {
00497       dbus_set_error (error, _dbus_error_from_errno (errno),
00498                       "Failed to create socket \"%s\": %s",
00499                       path, _dbus_strerror (errno));
00500       return -1;
00501     }
00502 
00503   _DBUS_ZERO (addr);
00504   addr.sun_family = AF_UNIX;
00505   
00506   if (abstract)
00507     {
00508 #ifdef HAVE_ABSTRACT_SOCKETS
00509       /* remember that abstract names aren't nul-terminated so we rely
00510        * on sun_path being filled in with zeroes above.
00511        */
00512       addr.sun_path[0] = '\0'; /* this is what says "use abstract" */
00513       strncpy (&addr.sun_path[1], path, _DBUS_MAX_SUN_PATH_LENGTH - 2);
00514       /* _dbus_verbose_bytes (addr.sun_path, sizeof (addr.sun_path)); */
00515 #else /* HAVE_ABSTRACT_SOCKETS */
00516       dbus_set_error (error, DBUS_ERROR_NOT_SUPPORTED,
00517                       "Operating system does not support abstract socket namespace\n");
00518       close (listen_fd);
00519       return -1;
00520 #endif /* ! HAVE_ABSTRACT_SOCKETS */
00521     }
00522   else
00523     {
00524       /* FIXME discussed security implications of this with Nalin,
00525        * and we couldn't think of where it would kick our ass, but
00526        * it still seems a bit sucky. It also has non-security suckage;
00527        * really we'd prefer to exit if the socket is already in use.
00528        * But there doesn't seem to be a good way to do this.
00529        *
00530        * Just to be extra careful, I threw in the stat() - clearly
00531        * the stat() can't *fix* any security issue, but it at least
00532        * avoids inadvertent/accidental data loss.
00533        */
00534       {
00535         struct stat sb;
00536 
00537         if (stat (path, &sb) == 0 &&
00538             S_ISSOCK (sb.st_mode))
00539           unlink (path);
00540       }
00541 
00542       strncpy (addr.sun_path, path, _DBUS_MAX_SUN_PATH_LENGTH - 1);
00543     }
00544   
00545   if (bind (listen_fd, (struct sockaddr*) &addr, sizeof (addr)) < 0)
00546     {
00547       dbus_set_error (error, _dbus_error_from_errno (errno),
00548                       "Failed to bind socket \"%s\": %s",
00549                       path, _dbus_strerror (errno));
00550       close (listen_fd);
00551       return -1;
00552     }
00553 
00554   if (listen (listen_fd, 30 /* backlog */) < 0)
00555     {
00556       dbus_set_error (error, _dbus_error_from_errno (errno),
00557                       "Failed to listen on socket \"%s\": %s",
00558                       path, _dbus_strerror (errno));
00559       close (listen_fd);
00560       return -1;
00561     }
00562 
00563   if (!_dbus_set_fd_nonblocking (listen_fd, error))
00564     {
00565       _DBUS_ASSERT_ERROR_IS_SET (error);
00566       close (listen_fd);
00567       return -1;
00568     }
00569   
00570   /* Try opening up the permissions, but if we can't, just go ahead
00571    * and continue, maybe it will be good enough.
00572    */
00573   if (!abstract && chmod (path, 0777) < 0)
00574     _dbus_warn ("Could not set mode 0777 on socket %s\n",
00575                 path);
00576   
00577   return listen_fd;
00578 }
00579 
00590 int
00591 _dbus_connect_tcp_socket (const char     *host,
00592                           dbus_uint32_t   port,
00593                           DBusError      *error)
00594 {
00595   int fd;
00596   struct sockaddr_in addr;
00597   struct hostent *he;
00598   struct in_addr *haddr;
00599 
00600   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
00601   
00602   fd = socket (AF_INET, SOCK_STREAM, 0);
00603   
00604   if (fd < 0)
00605     {
00606       dbus_set_error (error,
00607                       _dbus_error_from_errno (errno),
00608                       "Failed to create socket: %s",
00609                       _dbus_strerror (errno)); 
00610       
00611       return -1;
00612     }
00613 
00614   if (host == NULL)
00615     host = "localhost";
00616 
00617   he = gethostbyname (host);
00618   if (he == NULL) 
00619     {
00620       dbus_set_error (error,
00621                       _dbus_error_from_errno (errno),
00622                       "Failed to lookup hostname: %s",
00623                       host);
00624       return -1;
00625     }
00626   
00627   haddr = ((struct in_addr *) (he->h_addr_list)[0]);
00628 
00629   _DBUS_ZERO (addr);
00630   memcpy (&addr.sin_addr, haddr, sizeof(struct in_addr));
00631   addr.sin_family = AF_INET;
00632   addr.sin_port = htons (port);
00633   
00634   if (connect (fd, (struct sockaddr*) &addr, sizeof (addr)) < 0)
00635     {      
00636       dbus_set_error (error,
00637                        _dbus_error_from_errno (errno),
00638                       "Failed to connect to socket %s: %s:%d",
00639                       host, _dbus_strerror (errno), port);
00640 
00641       close (fd);
00642       fd = -1;
00643       
00644       return -1;
00645     }
00646 
00647   if (!_dbus_set_fd_nonblocking (fd, error))
00648     {
00649       close (fd);
00650       fd = -1;
00651 
00652       return -1;
00653     }
00654 
00655   return fd;
00656 }
00657 
00668 int
00669 _dbus_listen_tcp_socket (const char     *host,
00670                          dbus_uint32_t   port,
00671                          DBusError      *error)
00672 {
00673   int listen_fd;
00674   struct sockaddr_in addr;
00675   struct hostent *he;
00676   struct in_addr *haddr;
00677 
00678   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
00679   
00680   listen_fd = socket (AF_INET, SOCK_STREAM, 0);
00681   
00682   if (listen_fd < 0)
00683     {
00684       dbus_set_error (error, _dbus_error_from_errno (errno),
00685                       "Failed to create socket \"%s:%d\": %s",
00686                       host, port, _dbus_strerror (errno));
00687       return -1;
00688     }
00689 
00690   if (host == NULL)
00691     host = "localhost";
00692   
00693   he = gethostbyname (host);
00694   if (he == NULL) 
00695     {
00696       dbus_set_error (error,
00697                       _dbus_error_from_errno (errno),
00698                       "Failed to lookup hostname: %s",
00699                       host);
00700       return -1;
00701     }
00702   
00703   haddr = ((struct in_addr *) (he->h_addr_list)[0]);
00704 
00705   _DBUS_ZERO (addr);
00706   memcpy (&addr.sin_addr, haddr, sizeof (struct in_addr));
00707   addr.sin_family = AF_INET;
00708   addr.sin_port = htons (port);
00709 
00710   if (bind (listen_fd, (struct sockaddr*) &addr, sizeof (struct sockaddr)))
00711     {
00712       dbus_set_error (error, _dbus_error_from_errno (errno),
00713                       "Failed to bind socket \"%s:%d\": %s",
00714                       host, port, _dbus_strerror (errno));
00715       close (listen_fd);
00716       return -1;
00717     }
00718 
00719   if (listen (listen_fd, 30 /* backlog */) < 0)
00720     {
00721       dbus_set_error (error, _dbus_error_from_errno (errno),  
00722                       "Failed to listen on socket \"%s:%d\": %s",
00723                       host, port, _dbus_strerror (errno));
00724       close (listen_fd);
00725       return -1;
00726     }
00727 
00728   if (!_dbus_set_fd_nonblocking (listen_fd, error))
00729     {
00730       close (listen_fd);
00731       return -1;
00732     }
00733   
00734   return listen_fd;
00735 }
00736 
00737 static dbus_bool_t
00738 write_credentials_byte (int             server_fd,
00739                         DBusError      *error)
00740 {
00741   int bytes_written;
00742   char buf[1] = { '\0' };
00743 
00744   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
00745   
00746  again:
00747 
00748   bytes_written = write (server_fd, buf, 1);
00749 
00750   if (bytes_written < 0 && errno == EINTR)
00751     goto again;
00752 
00753   if (bytes_written < 0)
00754     {
00755       dbus_set_error (error, _dbus_error_from_errno (errno),
00756                       "Failed to write credentials byte: %s",
00757                      _dbus_strerror (errno));
00758       return FALSE;
00759     }
00760   else if (bytes_written == 0)
00761     {
00762       dbus_set_error (error, DBUS_ERROR_IO_ERROR,
00763                       "wrote zero bytes writing credentials byte");
00764       return FALSE;
00765     }
00766   else
00767     {
00768       _dbus_assert (bytes_written == 1);
00769       _dbus_verbose ("wrote credentials byte\n");
00770       return TRUE;
00771     }
00772 }
00773 
00792 dbus_bool_t
00793 _dbus_read_credentials_unix_socket  (int              client_fd,
00794                                      DBusCredentials *credentials,
00795                                      DBusError       *error)
00796 {
00797   struct msghdr msg;
00798   struct iovec iov;
00799   char buf;
00800 
00801 #ifdef HAVE_CMSGCRED 
00802   char cmsgmem[CMSG_SPACE (sizeof (struct cmsgcred))];
00803   struct cmsghdr *cmsg = (struct cmsghdr *) cmsgmem;
00804 #endif
00805 
00806   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
00807   
00808   /* The POSIX spec certainly doesn't promise this, but
00809    * we need these assertions to fail as soon as we're wrong about
00810    * it so we can do the porting fixups
00811    */
00812   _dbus_assert (sizeof (pid_t) <= sizeof (credentials->pid));
00813   _dbus_assert (sizeof (uid_t) <= sizeof (credentials->uid));
00814   _dbus_assert (sizeof (gid_t) <= sizeof (credentials->gid));
00815 
00816   _dbus_credentials_clear (credentials);
00817 
00818 #if defined(LOCAL_CREDS) && defined(HAVE_CMSGCRED)
00819   /* Set the socket to receive credentials on the next message */
00820   {
00821     int on = 1;
00822     if (setsockopt (client_fd, 0, LOCAL_CREDS, &on, sizeof (on)) < 0)
00823       {
00824         _dbus_verbose ("Unable to set LOCAL_CREDS socket option\n");
00825         return FALSE;
00826       }
00827   }
00828 #endif
00829 
00830   iov.iov_base = &buf;
00831   iov.iov_len = 1;
00832 
00833   memset (&msg, 0, sizeof (msg));
00834   msg.msg_iov = &iov;
00835   msg.msg_iovlen = 1;
00836 
00837 #ifdef HAVE_CMSGCRED
00838   memset (cmsgmem, 0, sizeof (cmsgmem));
00839   msg.msg_control = cmsgmem;
00840   msg.msg_controllen = sizeof (cmsgmem);
00841 #endif
00842 
00843  again:
00844   if (recvmsg (client_fd, &msg, 0) < 0)
00845     {
00846       if (errno == EINTR)
00847         goto again;
00848 
00849       dbus_set_error (error, _dbus_error_from_errno (errno),
00850                       "Failed to read credentials byte: %s",
00851                       _dbus_strerror (errno));
00852       return FALSE;
00853     }
00854 
00855   if (buf != '\0')
00856     {
00857       dbus_set_error (error, DBUS_ERROR_FAILED,
00858                       "Credentials byte was not nul");
00859       return FALSE;
00860     }
00861 
00862 #ifdef HAVE_CMSGCRED
00863   if (cmsg->cmsg_len < sizeof (cmsgmem) || cmsg->cmsg_type != SCM_CREDS)
00864     {
00865       dbus_set_error (error, DBUS_ERROR_FAILED);
00866       _dbus_verbose ("Message from recvmsg() was not SCM_CREDS\n");
00867       return FALSE;
00868     }
00869 #endif
00870 
00871   _dbus_verbose ("read credentials byte\n");
00872 
00873   {
00874 #ifdef SO_PEERCRED
00875     struct ucred cr;   
00876     int cr_len = sizeof (cr);
00877    
00878     if (getsockopt (client_fd, SOL_SOCKET, SO_PEERCRED, &cr, &cr_len) == 0 &&
00879         cr_len == sizeof (cr))
00880       {
00881         credentials->pid = cr.pid;
00882         credentials->uid = cr.uid;
00883         credentials->gid = cr.gid;
00884       }
00885     else
00886       {
00887         _dbus_verbose ("Failed to getsockopt() credentials, returned len %d/%d: %s\n",
00888                        cr_len, (int) sizeof (cr), _dbus_strerror (errno));
00889       }
00890 #elif defined(HAVE_CMSGCRED)
00891     struct cmsgcred *cred;
00892 
00893     cred = (struct cmsgcred *) CMSG_DATA (cmsg);
00894 
00895     credentials->pid = cred->cmcred_pid;
00896     credentials->uid = cred->cmcred_euid;
00897     credentials->gid = cred->cmcred_groups[0];
00898 #else /* !SO_PEERCRED && !HAVE_CMSGCRED */
00899     _dbus_verbose ("Socket credentials not supported on this OS\n");
00900 #endif
00901   }
00902 
00903   _dbus_verbose ("Credentials:"
00904                  "  pid "DBUS_PID_FORMAT
00905                  "  uid "DBUS_UID_FORMAT
00906                  "  gid "DBUS_GID_FORMAT"\n",
00907                  credentials->pid,
00908                  credentials->uid,
00909                  credentials->gid);
00910     
00911   return TRUE;
00912 }
00913 
00931 dbus_bool_t
00932 _dbus_send_credentials_unix_socket  (int              server_fd,
00933                                      DBusError       *error)
00934 {
00935   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
00936   
00937   if (write_credentials_byte (server_fd, error))
00938     return TRUE;
00939   else
00940     return FALSE;
00941 }
00942 
00950 int
00951 _dbus_accept  (int listen_fd)
00952 {
00953   int client_fd;
00954   struct sockaddr addr;
00955   socklen_t addrlen;
00956 
00957   addrlen = sizeof (addr);
00958   
00959  retry:
00960   client_fd = accept (listen_fd, &addr, &addrlen);
00961   
00962   if (client_fd < 0)
00963     {
00964       if (errno == EINTR)
00965         goto retry;
00966     }
00967   
00968   return client_fd;
00969 }
00970 
00985 dbus_bool_t
00986 _dbus_string_append_int (DBusString *str,
00987                          long        value)
00988 {
00989   /* this calculation is from comp.lang.c faq */
00990 #define MAX_LONG_LEN ((sizeof (long) * 8 + 2) / 3 + 1)  /* +1 for '-' */
00991   int orig_len;
00992   int i;
00993   char *buf;
00994   
00995   orig_len = _dbus_string_get_length (str);
00996 
00997   if (!_dbus_string_lengthen (str, MAX_LONG_LEN))
00998     return FALSE;
00999 
01000   buf = _dbus_string_get_data_len (str, orig_len, MAX_LONG_LEN);
01001 
01002   snprintf (buf, MAX_LONG_LEN, "%ld", value);
01003 
01004   i = 0;
01005   while (*buf)
01006     {
01007       ++buf;
01008       ++i;
01009     }
01010   
01011   _dbus_string_shorten (str, MAX_LONG_LEN - i);
01012   
01013   return TRUE;
01014 }
01015 
01023 dbus_bool_t
01024 _dbus_string_append_uint (DBusString    *str,
01025                           unsigned long  value)
01026 {
01027   /* this is wrong, but definitely on the high side. */
01028 #define MAX_ULONG_LEN (MAX_LONG_LEN * 2)
01029   int orig_len;
01030   int i;
01031   char *buf;
01032   
01033   orig_len = _dbus_string_get_length (str);
01034 
01035   if (!_dbus_string_lengthen (str, MAX_ULONG_LEN))
01036     return FALSE;
01037 
01038   buf = _dbus_string_get_data_len (str, orig_len, MAX_ULONG_LEN);
01039 
01040   snprintf (buf, MAX_ULONG_LEN, "%lu", value);
01041 
01042   i = 0;
01043   while (*buf)
01044     {
01045       ++buf;
01046       ++i;
01047     }
01048   
01049   _dbus_string_shorten (str, MAX_ULONG_LEN - i);
01050   
01051   return TRUE;
01052 }
01053 
01061 dbus_bool_t
01062 _dbus_string_append_double (DBusString *str,
01063                             double      value)
01064 {
01065 #define MAX_DOUBLE_LEN 64 /* this is completely made up :-/ */
01066   int orig_len;
01067   char *buf;
01068   int i;
01069   
01070   orig_len = _dbus_string_get_length (str);
01071 
01072   if (!_dbus_string_lengthen (str, MAX_DOUBLE_LEN))
01073     return FALSE;
01074 
01075   buf = _dbus_string_get_data_len (str, orig_len, MAX_DOUBLE_LEN);
01076 
01077   snprintf (buf, MAX_LONG_LEN, "%g", value);
01078 
01079   i = 0;
01080   while (*buf)
01081     {
01082       ++buf;
01083       ++i;
01084     }
01085   
01086   _dbus_string_shorten (str, MAX_DOUBLE_LEN - i);
01087   
01088   return TRUE;
01089 }
01090 
01103 dbus_bool_t
01104 _dbus_string_parse_int (const DBusString *str,
01105                         int               start,
01106                         long             *value_return,
01107                         int              *end_return)
01108 {
01109   long v;
01110   const char *p;
01111   char *end;
01112 
01113   p = _dbus_string_get_const_data_len (str, start,
01114                                        _dbus_string_get_length (str) - start);
01115 
01116   end = NULL;
01117   errno = 0;
01118   v = strtol (p, &end, 0);
01119   if (end == NULL || end == p || errno != 0)
01120     return FALSE;
01121 
01122   if (value_return)
01123     *value_return = v;
01124   if (end_return)
01125     *end_return = start + (end - p);
01126 
01127   return TRUE;
01128 }
01129 
01130 #ifdef DBUS_BUILD_TESTS
01131 /* Not currently used, so only built when tests are enabled */
01144 dbus_bool_t
01145 _dbus_string_parse_uint (const DBusString *str,
01146                          int               start,
01147                          unsigned long    *value_return,
01148                          int              *end_return)
01149 {
01150   unsigned long v;
01151   const char *p;
01152   char *end;
01153 
01154   p = _dbus_string_get_const_data_len (str, start,
01155                                        _dbus_string_get_length (str) - start);
01156 
01157   end = NULL;
01158   errno = 0;
01159   v = strtoul (p, &end, 0);
01160   if (end == NULL || end == p || errno != 0)
01161     return FALSE;
01162 
01163   if (value_return)
01164     *value_return = v;
01165   if (end_return)
01166     *end_return = start + (end - p);
01167 
01168   return TRUE;
01169 }
01170 #endif /* DBUS_BUILD_TESTS */
01171 
01172 static dbus_bool_t
01173 ascii_isspace (char c)
01174 {
01175   return (c == ' ' ||
01176           c == '\f' ||
01177           c == '\n' ||
01178           c == '\r' ||
01179           c == '\t' ||
01180           c == '\v');
01181 }
01182 
01183 static dbus_bool_t
01184 ascii_isdigit (char c)
01185 {
01186   return c >= '0' && c <= '9';
01187 }
01188 
01189 static dbus_bool_t
01190 ascii_isxdigit (char c)
01191 {
01192   return (ascii_isdigit (c) ||
01193           (c >= 'a' && c <= 'f') ||
01194           (c >= 'A' && c <= 'F'));
01195 }
01196 
01197 
01198 /* Calls strtod in a locale-independent fashion, by looking at
01199  * the locale data and patching the decimal comma to a point.
01200  *
01201  * Relicensed from glib.
01202  */
01203 static double
01204 ascii_strtod (const char *nptr,
01205               char      **endptr)
01206 {
01207   char *fail_pos;
01208   double val;
01209   struct lconv *locale_data;
01210   const char *decimal_point;
01211   int decimal_point_len;
01212   const char *p, *decimal_point_pos;
01213   const char *end = NULL; /* Silence gcc */
01214 
01215   fail_pos = NULL;
01216 
01217   locale_data = localeconv ();
01218   decimal_point = locale_data->decimal_point;
01219   decimal_point_len = strlen (decimal_point);
01220 
01221   _dbus_assert (decimal_point_len != 0);
01222   
01223   decimal_point_pos = NULL;
01224   if (decimal_point[0] != '.' ||
01225       decimal_point[1] != 0)
01226     {
01227       p = nptr;
01228       /* Skip leading space */
01229       while (ascii_isspace (*p))
01230         p++;
01231       
01232       /* Skip leading optional sign */
01233       if (*p == '+' || *p == '-')
01234         p++;
01235       
01236       if (p[0] == '0' &&
01237           (p[1] == 'x' || p[1] == 'X'))
01238         {
01239           p += 2;
01240           /* HEX - find the (optional) decimal point */
01241           
01242           while (ascii_isxdigit (*p))
01243             p++;
01244           
01245           if (*p == '.')
01246             {
01247               decimal_point_pos = p++;
01248               
01249               while (ascii_isxdigit (*p))
01250                 p++;
01251               
01252               if (*p == 'p' || *p == 'P')
01253                 p++;
01254               if (*p == '+' || *p == '-')
01255                 p++;
01256               while (ascii_isdigit (*p))
01257                 p++;
01258               end = p;
01259             }
01260         }
01261       else
01262         {
01263           while (ascii_isdigit (*p))
01264             p++;
01265           
01266           if (*p == '.')
01267             {
01268               decimal_point_pos = p++;
01269               
01270               while (ascii_isdigit (*p))
01271                 p++;
01272               
01273               if (*p == 'e' || *p == 'E')
01274                 p++;
01275               if (*p == '+' || *p == '-')
01276                 p++;
01277               while (ascii_isdigit (*p))
01278                 p++;
01279               end = p;
01280             }
01281         }
01282       /* For the other cases, we need not convert the decimal point */
01283     }
01284 
01285   /* Set errno to zero, so that we can distinguish zero results
01286      and underflows */
01287   errno = 0;
01288   
01289   if (decimal_point_pos)
01290     {
01291       char *copy, *c;
01292 
01293       /* We need to convert the '.' to the locale specific decimal point */
01294       copy = dbus_malloc (end - nptr + 1 + decimal_point_len);
01295       
01296       c = copy;
01297       memcpy (c, nptr, decimal_point_pos - nptr);
01298       c += decimal_point_pos - nptr;
01299       memcpy (c, decimal_point, decimal_point_len);
01300       c += decimal_point_len;
01301       memcpy (c, decimal_point_pos + 1, end - (decimal_point_pos + 1));
01302       c += end - (decimal_point_pos + 1);
01303       *c = 0;
01304 
01305       val = strtod (copy, &fail_pos);
01306 
01307       if (fail_pos)
01308         {
01309           if (fail_pos > decimal_point_pos)
01310             fail_pos = (char *)nptr + (fail_pos - copy) - (decimal_point_len - 1);
01311           else
01312             fail_pos = (char *)nptr + (fail_pos - copy);
01313         }
01314       
01315       dbus_free (copy);
01316           
01317     }
01318   else
01319     val = strtod (nptr, &fail_pos);
01320 
01321   if (endptr)
01322     *endptr = fail_pos;
01323   
01324   return val;
01325 }
01326 
01327 
01340 dbus_bool_t
01341 _dbus_string_parse_double (const DBusString *str,
01342                            int               start,
01343                            double           *value_return,
01344                            int              *end_return)
01345 {
01346   double v;
01347   const char *p;
01348   char *end;
01349 
01350   p = _dbus_string_get_const_data_len (str, start,
01351                                        _dbus_string_get_length (str) - start);
01352 
01353   end = NULL;
01354   errno = 0;
01355   v = ascii_strtod (p, &end);
01356   if (end == NULL || end == p || errno != 0)
01357     return FALSE;
01358 
01359   if (value_return)
01360     *value_return = v;
01361   if (end_return)
01362     *end_return = start + (end - p);
01363 
01364   return TRUE;
01365 }
01366  /* DBusString group */
01368 
01373 static dbus_bool_t
01374 fill_user_info_from_passwd (struct passwd *p,
01375                             DBusUserInfo  *info,
01376                             DBusError     *error)
01377 {
01378   _dbus_assert (p->pw_name != NULL);
01379   _dbus_assert (p->pw_dir != NULL);
01380   
01381   info->uid = p->pw_uid;
01382   info->primary_gid = p->pw_gid;
01383   info->username = _dbus_strdup (p->pw_name);
01384   info->homedir = _dbus_strdup (p->pw_dir);
01385   
01386   if (info->username == NULL ||
01387       info->homedir == NULL)
01388     {
01389       dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
01390       return FALSE;
01391     }
01392 
01393   return TRUE;
01394 }
01395 
01396 static dbus_bool_t
01397 fill_user_info (DBusUserInfo       *info,
01398                 dbus_uid_t          uid,
01399                 const DBusString   *username,
01400                 DBusError          *error)
01401 {
01402   const char *username_c;
01403   
01404   /* exactly one of username/uid provided */
01405   _dbus_assert (username != NULL || uid != DBUS_UID_UNSET);
01406   _dbus_assert (username == NULL || uid == DBUS_UID_UNSET);
01407 
01408   info->uid = DBUS_UID_UNSET;
01409   info->primary_gid = DBUS_GID_UNSET;
01410   info->group_ids = NULL;
01411   info->n_group_ids = 0;
01412   info->username = NULL;
01413   info->homedir = NULL;
01414   
01415   if (username != NULL)
01416     username_c = _dbus_string_get_const_data (username);
01417   else
01418     username_c = NULL;
01419 
01420   /* For now assuming that the getpwnam() and getpwuid() flavors
01421    * are always symmetrical, if not we have to add more configure
01422    * checks
01423    */
01424   
01425 #if defined (HAVE_POSIX_GETPWNAME_R) || defined (HAVE_NONPOSIX_GETPWNAME_R)
01426   {
01427     struct passwd *p;
01428     int result;
01429     char buf[1024];
01430     struct passwd p_str;
01431 
01432     p = NULL;
01433 #ifdef HAVE_POSIX_GETPWNAME_R
01434     if (uid >= 0)
01435       result = getpwuid_r (uid, &p_str, buf, sizeof (buf),
01436                            &p);
01437     else
01438       result = getpwnam_r (username_c, &p_str, buf, sizeof (buf),
01439                            &p);
01440 #else
01441     if (uid != DBUS_UID_UNSET)
01442       p = getpwuid_r (uid, &p_str, buf, sizeof (buf));
01443     else
01444       p = getpwnam_r (username_c, &p_str, buf, sizeof (buf));
01445     result = 0;
01446 #endif /* !HAVE_POSIX_GETPWNAME_R */
01447     if (result == 0 && p == &p_str)
01448       {
01449         if (!fill_user_info_from_passwd (p, info, error))
01450           return FALSE;
01451       }
01452     else
01453       {
01454         dbus_set_error (error, _dbus_error_from_errno (errno),
01455                         "User \"%s\" unknown or no memory to allocate password entry\n",
01456                         username_c ? username_c : "???");
01457         _dbus_verbose ("User %s unknown\n", username_c ? username_c : "???");
01458         return FALSE;
01459       }
01460   }
01461 #else /* ! HAVE_GETPWNAM_R */
01462   {
01463     /* I guess we're screwed on thread safety here */
01464     struct passwd *p;
01465 
01466     if (uid != DBUS_UID_UNSET)
01467       p = getpwuid (uid);
01468     else
01469       p = getpwnam (username_c);
01470 
01471     if (p != NULL)
01472       {
01473         if (!fill_user_info_from_passwd (p, info, error))
01474           return FALSE;
01475       }
01476     else
01477       {
01478         dbus_set_error (error, _dbus_error_from_errno (errno),
01479                         "User \"%s\" unknown or no memory to allocate password entry\n",
01480                         username_c ? username_c : "???");
01481         _dbus_verbose ("User %s unknown\n", username_c ? username_c : "???");
01482         return FALSE;
01483       }
01484   }
01485 #endif  /* ! HAVE_GETPWNAM_R */
01486 
01487   /* Fill this in so we can use it to get groups */
01488   username_c = info->username;
01489   
01490 #ifdef HAVE_GETGROUPLIST
01491   {
01492     gid_t *buf;
01493     int buf_count;
01494     int i;
01495     
01496     buf_count = 17;
01497     buf = dbus_new (gid_t, buf_count);
01498     if (buf == NULL)
01499       {
01500         dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
01501         goto failed;
01502       }
01503     
01504     if (getgrouplist (username_c,
01505                       info->primary_gid,
01506                       buf, &buf_count) < 0)
01507       {
01508         gid_t *new = dbus_realloc (buf, buf_count * sizeof (buf[0]));
01509         if (new == NULL)
01510           {
01511             dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
01512             dbus_free (buf);
01513             goto failed;
01514           }
01515         
01516         buf = new;
01517 
01518         errno = 0;
01519         if (getgrouplist (username_c, info->primary_gid, buf, &buf_count) < 0)
01520           {
01521             dbus_set_error (error,
01522                             _dbus_error_from_errno (errno),
01523                             "Failed to get groups for username \"%s\" primary GID "
01524                             DBUS_GID_FORMAT ": %s\n",
01525                             username_c, info->primary_gid,
01526                             _dbus_strerror (errno));
01527             dbus_free (buf);
01528             goto failed;
01529           }
01530       }
01531 
01532     info->group_ids = dbus_new (dbus_gid_t, buf_count);
01533     if (info->group_ids == NULL)
01534       {
01535         dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
01536         dbus_free (buf);
01537         goto failed;
01538       }
01539     
01540     for (i = 0; i < buf_count; ++i)
01541       info->group_ids[i] = buf[i];
01542 
01543     info->n_group_ids = buf_count;
01544     
01545     dbus_free (buf);
01546   }
01547 #else  /* HAVE_GETGROUPLIST */
01548   {
01549     /* We just get the one group ID */
01550     info->group_ids = dbus_new (dbus_gid_t, 1);
01551     if (info->group_ids == NULL)
01552       {
01553         dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
01554         goto out;
01555       }
01556 
01557     info->n_group_ids = 1;
01558 
01559     (info->group_ids)[0] = info->primary_gid;
01560   }
01561 #endif /* HAVE_GETGROUPLIST */
01562 
01563   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
01564   
01565   return TRUE;
01566   
01567  failed:
01568   _DBUS_ASSERT_ERROR_IS_SET (error);
01569   _dbus_user_info_free (info);
01570   return FALSE;
01571 }
01572 
01581 dbus_bool_t
01582 _dbus_user_info_fill (DBusUserInfo     *info,
01583                       const DBusString *username,
01584                       DBusError        *error)
01585 {
01586   return fill_user_info (info, DBUS_UID_UNSET,
01587                          username, error);
01588 }
01589 
01598 dbus_bool_t
01599 _dbus_user_info_fill_uid (DBusUserInfo *info,
01600                           dbus_uid_t    uid,
01601                           DBusError    *error)
01602 {
01603   return fill_user_info (info, uid,
01604                          NULL, error);
01605 }
01606 
01612 void
01613 _dbus_user_info_free (DBusUserInfo *info)
01614 {
01615   dbus_free (info->group_ids);
01616   dbus_free (info->username);
01617   dbus_free (info->homedir);
01618 }
01619 
01620 static dbus_bool_t
01621 fill_user_info_from_group (struct group  *g,
01622                            DBusGroupInfo *info,
01623                            DBusError     *error)
01624 {
01625   _dbus_assert (g->gr_name != NULL);
01626   
01627   info->gid = g->gr_gid;
01628   info->groupname = _dbus_strdup (g->gr_name);
01629 
01630   /* info->members = dbus_strdupv (g->gr_mem) */
01631   
01632   if (info->groupname == NULL)
01633     {
01634       dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
01635       return FALSE;
01636     }
01637 
01638   return TRUE;
01639 }
01640 
01641 static dbus_bool_t
01642 fill_group_info (DBusGroupInfo    *info,
01643                  dbus_gid_t        gid,
01644                  const DBusString *groupname,
01645                  DBusError        *error)
01646 {
01647   const char *group_c_str;
01648 
01649   _dbus_assert (groupname != NULL || gid != DBUS_GID_UNSET);
01650   _dbus_assert (groupname == NULL || gid == DBUS_GID_UNSET);
01651 
01652   if (groupname)
01653     group_c_str = _dbus_string_get_const_data (groupname);
01654   else
01655     group_c_str = NULL;
01656   
01657   /* For now assuming that the getgrnam() and getgrgid() flavors
01658    * always correspond to the pwnam flavors, if not we have
01659    * to add more configure checks.
01660    */
01661   
01662 #if defined (HAVE_POSIX_GETPWNAME_R) || defined (HAVE_NONPOSIX_GETPWNAME_R)
01663   {
01664     struct group *g;
01665     int result;
01666     char buf[1024];
01667     struct group g_str;
01668 
01669     g = NULL;
01670 #ifdef HAVE_POSIX_GETPWNAME_R
01671 
01672     if (group_c_str)
01673       result = getgrnam_r (group_c_str, &g_str, buf, sizeof (buf),
01674                            &g);
01675     else
01676       result = getgrgid_r (gid, &g_str, buf, sizeof (buf),
01677                            &g);
01678 #else
01679     p = getgrnam_r (group_c_str, &g_str, buf, sizeof (buf));
01680     result = 0;
01681 #endif /* !HAVE_POSIX_GETPWNAME_R */
01682     if (result == 0 && g == &g_str)
01683       {
01684         return fill_user_info_from_group (g, info, error);
01685       }
01686     else
01687       {
01688         dbus_set_error (error, _dbus_error_from_errno (errno),
01689                         "Group %s unknown or failed to look it up\n",
01690                         group_c_str ? group_c_str : "???");
01691         return FALSE;
01692       }
01693   }
01694 #else /* ! HAVE_GETPWNAM_R */
01695   {
01696     /* I guess we're screwed on thread safety here */
01697     struct group *g;
01698 
01699     g = getgrnam (group_c_str);
01700 
01701     if (g != NULL)
01702       {
01703         return fill_user_info_from_group (g, info, error);
01704       }
01705     else
01706       {
01707         dbus_set_error (error, _dbus_error_from_errno (errno),
01708                         "Group %s unknown or failed to look it up\n",
01709                         group_c_str ? group_c_str : "???");
01710         return FALSE;
01711       }
01712   }
01713 #endif  /* ! HAVE_GETPWNAM_R */
01714 }
01715 
01725 dbus_bool_t
01726 _dbus_group_info_fill (DBusGroupInfo    *info,
01727                        const DBusString *groupname,
01728                        DBusError        *error)
01729 {
01730   return fill_group_info (info, DBUS_GID_UNSET,
01731                           groupname, error);
01732 
01733 }
01734 
01744 dbus_bool_t
01745 _dbus_group_info_fill_gid (DBusGroupInfo *info,
01746                            dbus_gid_t     gid,
01747                            DBusError     *error)
01748 {
01749   return fill_group_info (info, gid, NULL, error);
01750 }
01751 
01757 void
01758 _dbus_group_info_free (DBusGroupInfo    *info)
01759 {
01760   dbus_free (info->groupname);
01761 }
01762 
01769 void
01770 _dbus_credentials_clear (DBusCredentials *credentials)
01771 {
01772   credentials->pid = DBUS_PID_UNSET;
01773   credentials->uid = DBUS_UID_UNSET;
01774   credentials->gid = DBUS_GID_UNSET;
01775 }
01776 
01782 void
01783 _dbus_credentials_from_current_process (DBusCredentials *credentials)
01784 {
01785   /* The POSIX spec certainly doesn't promise this, but
01786    * we need these assertions to fail as soon as we're wrong about
01787    * it so we can do the porting fixups
01788    */
01789   _dbus_assert (sizeof (pid_t) <= sizeof (credentials->pid));
01790   _dbus_assert (sizeof (uid_t) <= sizeof (credentials->uid));
01791   _dbus_assert (sizeof (gid_t) <= sizeof (credentials->gid));
01792   
01793   credentials->pid = getpid ();
01794   credentials->uid = getuid ();
01795   credentials->gid = getgid ();
01796 }
01797 
01806 dbus_bool_t
01807 _dbus_credentials_match (const DBusCredentials *expected_credentials,
01808                          const DBusCredentials *provided_credentials)
01809 {
01810   if (provided_credentials->uid == DBUS_UID_UNSET)
01811     return FALSE;
01812   else if (expected_credentials->uid == DBUS_UID_UNSET)
01813     return FALSE;
01814   else if (provided_credentials->uid == 0)
01815     return TRUE;
01816   else if (provided_credentials->uid == expected_credentials->uid)
01817     return TRUE;
01818   else
01819     return FALSE;
01820 }
01821 
01826 unsigned long
01827 _dbus_getpid (void)
01828 {
01829   return getpid ();
01830 }
01831 
01835 dbus_uid_t
01836 _dbus_getuid (void)
01837 {
01838   return getuid ();
01839 }
01840 
01844 dbus_gid_t
01845 _dbus_getgid (void)
01846 {
01847   return getgid ();
01848 }
01849 
01850 _DBUS_DEFINE_GLOBAL_LOCK (atomic);
01851 
01852 #ifdef DBUS_USE_ATOMIC_INT_486
01853 /* Taken from CVS version 1.7 of glibc's sysdeps/i386/i486/atomicity.h */
01854 /* Since the asm stuff here is gcc-specific we go ahead and use "inline" also */
01855 static inline dbus_int32_t
01856 atomic_exchange_and_add (DBusAtomic            *atomic,
01857                          volatile dbus_int32_t  val)
01858 {
01859   register dbus_int32_t result;
01860 
01861   __asm__ __volatile__ ("lock; xaddl %0,%1"
01862                         : "=r" (result), "=m" (atomic->value)
01863                         : "0" (val), "m" (atomic->value));
01864   return result;
01865 }
01866 #endif
01867 
01876 dbus_int32_t
01877 _dbus_atomic_inc (DBusAtomic *atomic)
01878 {
01879 #ifdef DBUS_USE_ATOMIC_INT_486
01880   return atomic_exchange_and_add (atomic, 1);
01881 #else
01882   dbus_int32_t res;
01883   _DBUS_LOCK (atomic);
01884   res = atomic->value;
01885   atomic->value += 1;
01886   _DBUS_UNLOCK (atomic);
01887   return res;
01888 #endif
01889 }
01890 
01899 dbus_int32_t
01900 _dbus_atomic_dec (DBusAtomic *atomic)
01901 {
01902 #ifdef DBUS_USE_ATOMIC_INT_486
01903   return atomic_exchange_and_add (atomic, -1);
01904 #else
01905   dbus_int32_t res;
01906   
01907   _DBUS_LOCK (atomic);
01908   res = atomic->value;
01909   atomic->value -= 1;
01910   _DBUS_UNLOCK (atomic);
01911   return res;
01912 #endif
01913 }
01914 
01925 int
01926 _dbus_poll (DBusPollFD *fds,
01927             int         n_fds,
01928             int         timeout_milliseconds)
01929 {
01930 #ifdef HAVE_POLL
01931   /* This big thing is a constant expression and should get optimized
01932    * out of existence. So it's more robust than a configure check at
01933    * no cost.
01934    */
01935   if (_DBUS_POLLIN == POLLIN &&
01936       _DBUS_POLLPRI == POLLPRI &&
01937       _DBUS_POLLOUT == POLLOUT &&
01938       _DBUS_POLLERR == POLLERR &&
01939       _DBUS_POLLHUP == POLLHUP &&
01940       _DBUS_POLLNVAL == POLLNVAL &&
01941       sizeof (DBusPollFD) == sizeof (struct pollfd) &&
01942       _DBUS_STRUCT_OFFSET (DBusPollFD, fd) ==
01943       _DBUS_STRUCT_OFFSET (struct pollfd, fd) &&
01944       _DBUS_STRUCT_OFFSET (DBusPollFD, events) ==
01945       _DBUS_STRUCT_OFFSET (struct pollfd, events) &&
01946       _DBUS_STRUCT_OFFSET (DBusPollFD, revents) ==
01947       _DBUS_STRUCT_OFFSET (struct pollfd, revents))
01948     {
01949       return poll ((struct pollfd*) fds,
01950                    n_fds, 
01951                    timeout_milliseconds);
01952     }
01953   else
01954     {
01955       /* We have to convert the DBusPollFD to an array of
01956        * struct pollfd, poll, and convert back.
01957        */
01958       _dbus_warn ("didn't implement poll() properly for this system yet\n");
01959       return -1;
01960     }
01961 #else /* ! HAVE_POLL */
01962 
01963   fd_set read_set, write_set, err_set;
01964   int max_fd = 0;
01965   int i;
01966   struct timeval tv;
01967   int ready;
01968   
01969   FD_ZERO (&read_set);
01970   FD_ZERO (&write_set);
01971   FD_ZERO (&err_set);
01972 
01973   for (i = 0; i < n_fds; i++)
01974     {
01975       DBusPollFD f = fds[i];
01976 
01977       if (f.events & _DBUS_POLLIN)
01978         FD_SET (f.fd, &read_set);
01979 
01980       if (f.events & _DBUS_POLLOUT)
01981         FD_SET (f.fd, &write_set);
01982 
01983       FD_SET (f.fd, &err_set);
01984 
01985       max_fd = MAX (max_fd, f.fd);
01986     }
01987     
01988   tv.tv_sec = timeout_milliseconds / 1000;
01989   tv.tv_usec = (timeout_milliseconds % 1000) * 1000;
01990 
01991   ready = select (max_fd + 1, &read_set, &write_set, &err_set, &tv);
01992 
01993   if (ready > 0)
01994     {
01995       for (i = 0; i < n_fds; i++)
01996         {
01997           DBusPollFD f = fds[i];
01998 
01999           f.revents = 0;
02000 
02001           if (FD_ISSET (f.fd, &read_set))
02002             f.revents |= _DBUS_POLLIN;
02003 
02004           if (FD_ISSET (f.fd, &write_set))
02005             f.revents |= _DBUS_POLLOUT;
02006 
02007           if (FD_ISSET (f.fd, &err_set))
02008             f.revents |= _DBUS_POLLERR;
02009         }
02010     }
02011 
02012   return ready;
02013 #endif
02014 }
02015 
02017 #define NANOSECONDS_PER_SECOND       1000000000
02018 
02019 #define MICROSECONDS_PER_SECOND      1000000
02020 
02021 #define MILLISECONDS_PER_SECOND      1000
02022 
02023 #define NANOSECONDS_PER_MILLISECOND  1000000
02024 
02025 #define MICROSECONDS_PER_MILLISECOND 1000
02026 
02031 void
02032 _dbus_sleep_milliseconds (int milliseconds)
02033 {
02034 #ifdef HAVE_NANOSLEEP
02035   struct timespec req;
02036   struct timespec rem;
02037 
02038   req.tv_sec = milliseconds / MILLISECONDS_PER_SECOND;
02039   req.tv_nsec = (milliseconds % MILLISECONDS_PER_SECOND) * NANOSECONDS_PER_MILLISECOND;
02040   rem.tv_sec = 0;
02041   rem.tv_nsec = 0;
02042 
02043   while (nanosleep (&req, &rem) < 0 && errno == EINTR)
02044     req = rem;
02045 #elif defined (HAVE_USLEEP)
02046   usleep (milliseconds * MICROSECONDS_PER_MILLISECOND);
02047 #else /* ! HAVE_USLEEP */
02048   sleep (MAX (milliseconds / 1000, 1));
02049 #endif
02050 }
02051 
02058 void
02059 _dbus_get_current_time (long *tv_sec,
02060                         long *tv_usec)
02061 {
02062   struct timeval t;
02063 
02064   gettimeofday (&t, NULL);
02065 
02066   if (tv_sec)
02067     *tv_sec = t.tv_sec;
02068   if (tv_usec)
02069     *tv_usec = t.tv_usec;
02070 }
02071 
02082 dbus_bool_t
02083 _dbus_file_get_contents (DBusString       *str,
02084                          const DBusString *filename,
02085                          DBusError        *error)
02086 {
02087   int fd;
02088   struct stat sb;
02089   int orig_len;
02090   int total;
02091   const char *filename_c;
02092 
02093   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
02094   
02095   filename_c = _dbus_string_get_const_data (filename);
02096   
02097   /* O_BINARY useful on Cygwin */
02098   fd = open (filename_c, O_RDONLY | O_BINARY);
02099   if (fd < 0)
02100     {
02101       dbus_set_error (error, _dbus_error_from_errno (errno),
02102                       "Failed to open \"%s\": %s",
02103                       filename_c,
02104                       _dbus_strerror (errno));
02105       return FALSE;
02106     }
02107 
02108   if (fstat (fd, &sb) < 0)
02109     {
02110       dbus_set_error (error, _dbus_error_from_errno (errno),
02111                       "Failed to stat \"%s\": %s",
02112                       filename_c,
02113                       _dbus_strerror (errno));
02114 
02115       _dbus_verbose ("fstat() failed: %s",
02116                      _dbus_strerror (errno));
02117       
02118       close (fd);
02119       
02120       return FALSE;
02121     }
02122 
02123   if (sb.st_size > _DBUS_ONE_MEGABYTE)
02124     {
02125       dbus_set_error (error, DBUS_ERROR_FAILED,
02126                       "File size %lu of \"%s\" is too large.",
02127                       filename_c, (unsigned long) sb.st_size);
02128       close (fd);
02129       return FALSE;
02130     }
02131   
02132   total = 0;
02133   orig_len = _dbus_string_get_length (str);
02134   if (sb.st_size > 0 && S_ISREG (sb.st_mode))
02135     {
02136       int bytes_read;
02137 
02138       while (total < (int) sb.st_size)
02139         {
02140           bytes_read = _dbus_read (fd, str,
02141                                    sb.st_size - total);
02142           if (bytes_read <= 0)
02143             {
02144               dbus_set_error (error, _dbus_error_from_errno (errno),
02145                               "Error reading \"%s\": %s",
02146                               filename_c,
02147                               _dbus_strerror (errno));
02148 
02149               _dbus_verbose ("read() failed: %s",
02150                              _dbus_strerror (errno));
02151               
02152               close (fd);
02153               _dbus_string_set_length (str, orig_len);
02154               return FALSE;
02155             }
02156           else
02157             total += bytes_read;
02158         }
02159 
02160       close (fd);
02161       return TRUE;
02162     }
02163   else if (sb.st_size != 0)
02164     {
02165       _dbus_verbose ("Can only open regular files at the moment.\n");
02166       dbus_set_error (error, DBUS_ERROR_FAILED,
02167                       "\"%s\" is not a regular file",
02168                       filename_c);
02169       close (fd);
02170       return FALSE;
02171     }
02172   else
02173     {
02174       close (fd);
02175       return TRUE;
02176     }
02177 }
02178 
02188 dbus_bool_t
02189 _dbus_string_save_to_file (const DBusString *str,
02190                            const DBusString *filename,
02191                            DBusError        *error)
02192 {
02193   int fd;
02194   int bytes_to_write;
02195   const char *filename_c;
02196   DBusString tmp_filename;
02197   const char *tmp_filename_c;
02198   int total;
02199   dbus_bool_t need_unlink;
02200   dbus_bool_t retval;
02201 
02202   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
02203   
02204   fd = -1;
02205   retval = FALSE;
02206   need_unlink = FALSE;
02207   
02208   if (!_dbus_string_init (&tmp_filename))
02209     {
02210       dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
02211       return FALSE;
02212     }
02213 
02214   if (!_dbus_string_copy (filename, 0, &tmp_filename, 0))
02215     {
02216       dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
02217       _dbus_string_free (&tmp_filename);
02218       return FALSE;
02219     }
02220   
02221   if (!_dbus_string_append (&tmp_filename, "."))
02222     {
02223       dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
02224       _dbus_string_free (&tmp_filename);
02225       return FALSE;
02226     }
02227 
02228 #define N_TMP_FILENAME_RANDOM_BYTES 8
02229   if (!_dbus_generate_random_ascii (&tmp_filename, N_TMP_FILENAME_RANDOM_BYTES))
02230     {
02231       dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
02232       _dbus_string_free (&tmp_filename);
02233       return FALSE;
02234     }
02235     
02236   filename_c = _dbus_string_get_const_data (filename);
02237   tmp_filename_c = _dbus_string_get_const_data (&tmp_filename);
02238 
02239   fd = open (tmp_filename_c, O_WRONLY | O_BINARY | O_EXCL | O_CREAT,
02240              0600);
02241   if (fd < 0)
02242     {
02243       dbus_set_error (error, _dbus_error_from_errno (errno),
02244                       "Could not create %s: %s", tmp_filename_c,
02245                       _dbus_strerror (errno));
02246       goto out;
02247     }
02248 
02249   need_unlink = TRUE;
02250   
02251   total = 0;
02252   bytes_to_write = _dbus_string_get_length (str);
02253 
02254   while (total < bytes_to_write)
02255     {
02256       int bytes_written;
02257 
02258       bytes_written = _dbus_write (fd, str, total,
02259                                    bytes_to_write - total);
02260 
02261       if (bytes_written <= 0)
02262         {
02263           dbus_set_error (error, _dbus_error_from_errno (errno),
02264                           "Could not write to %s: %s", tmp_filename_c,
02265                           _dbus_strerror (errno));
02266           
02267           goto out;
02268         }
02269 
02270       total += bytes_written;
02271     }
02272 
02273   if (close (fd) < 0)
02274     {
02275       dbus_set_error (error, _dbus_error_from_errno (errno),
02276                       "Could not close file %s: %s",
02277                       tmp_filename_c, _dbus_strerror (errno));
02278 
02279       goto out;
02280     }
02281 
02282   fd = -1;
02283   
02284   if (rename (tmp_filename_c, filename_c) < 0)
02285     {
02286       dbus_set_error (error, _dbus_error_from_errno (errno),
02287                       "Could not rename %s to %s: %s",
02288                       tmp_filename_c, filename_c,
02289                       _dbus_strerror (errno));
02290 
02291       goto out;
02292     }
02293 
02294   need_unlink = FALSE;
02295   
02296   retval = TRUE;
02297   
02298  out:
02299   /* close first, then unlink, to prevent ".nfs34234235" garbage
02300    * files
02301    */
02302 
02303   if (fd >= 0)
02304     close (fd);
02305         
02306   if (need_unlink && unlink (tmp_filename_c) < 0)
02307     _dbus_verbose ("Failed to unlink temp file %s: %s\n",
02308                    tmp_filename_c, _dbus_strerror (errno));
02309 
02310   _dbus_string_free (&tmp_filename);
02311 
02312   if (!retval)
02313     _DBUS_ASSERT_ERROR_IS_SET (error);
02314   
02315   return retval;
02316 }
02317 
02324 dbus_bool_t
02325 _dbus_create_file_exclusively (const DBusString *filename,
02326                                DBusError        *error)
02327 {
02328   int fd;
02329   const char *filename_c;
02330 
02331   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
02332   
02333   filename_c = _dbus_string_get_const_data (filename);
02334   
02335   fd = open (filename_c, O_WRONLY | O_BINARY | O_EXCL | O_CREAT,
02336              0600);
02337   if (fd < 0)
02338     {
02339       dbus_set_error (error,
02340                       DBUS_ERROR_FAILED,
02341                       "Could not create file %s: %s\n",
02342                       filename_c,
02343                       _dbus_strerror (errno));
02344       return FALSE;
02345     }
02346 
02347   if (close (fd) < 0)
02348     {
02349       dbus_set_error (error,
02350                       DBUS_ERROR_FAILED,
02351                       "Could not close file %s: %s\n",
02352                       filename_c,
02353                       _dbus_strerror (errno));
02354       return FALSE;
02355     }
02356   
02357   return TRUE;
02358 }
02359 
02368 dbus_bool_t
02369 _dbus_delete_file (const DBusString *filename,
02370                    DBusError        *error)
02371 {
02372   const char *filename_c;
02373 
02374   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
02375   
02376   filename_c = _dbus_string_get_const_data (filename);
02377 
02378   if (unlink (filename_c) < 0)
02379     {
02380       dbus_set_error (error, DBUS_ERROR_FAILED,
02381                       "Failed to delete file %s: %s\n",
02382                       filename_c, _dbus_strerror (errno));
02383       return FALSE;
02384     }
02385   else
02386     return TRUE;
02387 }
02388 
02397 dbus_bool_t
02398 _dbus_create_directory (const DBusString *filename,
02399                         DBusError        *error)
02400 {
02401   const char *filename_c;
02402 
02403   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
02404   
02405   filename_c = _dbus_string_get_const_data (filename);
02406 
02407   if (mkdir (filename_c, 0700) < 0)
02408     {
02409       if (errno == EEXIST)
02410         return TRUE;
02411       
02412       dbus_set_error (error, DBUS_ERROR_FAILED,
02413                       "Failed to create directory %s: %s\n",
02414                       filename_c, _dbus_strerror (errno));
02415       return FALSE;
02416     }
02417   else
02418     return TRUE;
02419 }
02420 
02428 dbus_bool_t
02429 _dbus_delete_directory (const DBusString *filename,
02430                         DBusError        *error)
02431 {
02432   const char *filename_c;
02433   
02434   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
02435 
02436   filename_c = _dbus_string_get_const_data (filename);
02437 
02438   if (rmdir (filename_c) != 0)
02439     {
02440       dbus_set_error (error, DBUS_ERROR_FAILED,
02441                       "Failed to remove directory %s: %s\n",
02442                       filename_c, _dbus_strerror (errno));
02443       return FALSE;
02444     }
02445   
02446   return TRUE;
02447 }
02448 
02459 dbus_bool_t
02460 _dbus_concat_dir_and_file (DBusString       *dir,
02461                            const DBusString *next_component)
02462 {
02463   dbus_bool_t dir_ends_in_slash;
02464   dbus_bool_t file_starts_with_slash;
02465 
02466   if (_dbus_string_get_length (dir) == 0 ||
02467       _dbus_string_get_length (next_component) == 0)
02468     return TRUE;
02469   
02470   dir_ends_in_slash = '/' == _dbus_string_get_byte (dir,
02471                                                     _dbus_string_get_length (dir) - 1);
02472 
02473   file_starts_with_slash = '/' == _dbus_string_get_byte (next_component, 0);
02474 
02475   if (dir_ends_in_slash && file_starts_with_slash)
02476     {
02477       _dbus_string_shorten (dir, 1);
02478     }
02479   else if (!(dir_ends_in_slash || file_starts_with_slash))
02480     {
02481       if (!_dbus_string_append_byte (dir, '/'))
02482         return FALSE;
02483     }
02484 
02485   return _dbus_string_copy (next_component, 0, dir,
02486                             _dbus_string_get_length (dir));
02487 }
02488 
02495 dbus_bool_t
02496 _dbus_string_get_dirname  (const DBusString *filename,
02497                            DBusString       *dirname)
02498 {
02499   int sep;
02500   
02501   _dbus_assert (filename != dirname);
02502   _dbus_assert (filename != NULL);
02503   _dbus_assert (dirname != NULL);
02504 
02505   /* Ignore any separators on the end */
02506   sep = _dbus_string_get_length (filename);
02507   if (sep == 0)
02508     return _dbus_string_append (dirname, "."); /* empty string passed in */
02509     
02510   while (sep > 0 && _dbus_string_get_byte (filename, sep - 1) == '/')
02511     --sep;
02512 
02513   _dbus_assert (sep >= 0);
02514   
02515   if (sep == 0)
02516     return _dbus_string_append (dirname, "/");
02517   
02518   /* Now find the previous separator */
02519   _dbus_string_find_byte_backward (filename, sep, '/', &sep);
02520   if (sep < 0)
02521     return _dbus_string_append (dirname, ".");
02522   
02523   /* skip multiple separators */
02524   while (sep > 0 && _dbus_string_get_byte (filename, sep - 1) == '/')
02525     --sep;
02526 
02527   _dbus_assert (sep >= 0);
02528   
02529   if (sep == 0 &&
02530       _dbus_string_get_byte (filename, 0) == '/')
02531     return _dbus_string_append (dirname, "/");
02532   else
02533     return _dbus_string_copy_len (filename, 0, sep - 0,
02534                                   dirname, _dbus_string_get_length (dirname));
02535 }
02536 
02543 dbus_bool_t
02544 _dbus_path_is_absolute (const DBusString *filename)
02545 {
02546   if (_dbus_string_get_length (filename) > 0)
02547     return _dbus_string_get_byte (filename, 0) == '/';
02548   else
02549     return FALSE;
02550 }
02551 
02555 struct DBusDirIter
02556 {
02557   DIR *d; 
02559 };
02560 
02568 DBusDirIter*
02569 _dbus_directory_open (const DBusString *filename,
02570                       DBusError        *error)
02571 {
02572   DIR *d;
02573   DBusDirIter *iter;
02574   const char *filename_c;
02575 
02576   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
02577   
02578   filename_c = _dbus_string_get_const_data (filename);
02579 
02580   d = opendir (filename_c);
02581   if (d == NULL)
02582     {
02583       dbus_set_error (error, _dbus_error_from_errno (errno),
02584                       "Failed to read directory \"%s\": %s",
02585                       filename_c,
02586                       _dbus_strerror (errno));
02587       return NULL;
02588     }
02589   iter = dbus_new0 (DBusDirIter, 1);
02590   if (iter == NULL)
02591     {
02592       closedir (d);
02593       dbus_set_error (error, DBUS_ERROR_NO_MEMORY,
02594                       "Could not allocate memory for directory iterator");
02595       return NULL;
02596     }
02597 
02598   iter->d = d;
02599 
02600   return iter;
02601 }
02602 
02616 dbus_bool_t
02617 _dbus_directory_get_next_file (DBusDirIter      *iter,
02618                                DBusString       *filename,
02619                                DBusError        *error)
02620 {
02621   struct dirent *ent;
02622 
02623   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
02624   
02625  again:
02626   errno = 0;
02627   ent = readdir (iter->d);
02628   if (ent == NULL)
02629     {
02630       if (errno != 0)
02631         dbus_set_error (error,
02632                         _dbus_error_from_errno (errno),
02633                         "%s", _dbus_strerror (errno));
02634       return FALSE;
02635     }
02636   else if (ent->d_name[0] == '.' &&
02637            (ent->d_name[1] == '\0' ||
02638             (ent->d_name[1] == '.' && ent->d_name[2] == '\0')))
02639     goto again;
02640   else
02641     {
02642       _dbus_string_set_length (filename, 0);
02643       if (!_dbus_string_append (filename, ent->d_name))
02644         {
02645           dbus_set_error (error, DBUS_ERROR_NO_MEMORY,
02646                           "No memory to read directory entry");
02647           return FALSE;
02648         }
02649       else
02650         return TRUE;
02651     }
02652 }
02653 
02657 void
02658 _dbus_directory_close (DBusDirIter *iter)
02659 {
02660   closedir (iter->d);
02661   dbus_free (iter);
02662 }
02663 
02664 static dbus_bool_t
02665 pseudorandom_generate_random_bytes (DBusString *str,
02666                                     int         n_bytes)
02667 {
02668   int old_len;
02669   unsigned long tv_usec;
02670   int i;
02671   
02672   old_len = _dbus_string_get_length (str);
02673 
02674   /* fall back to pseudorandom */
02675   _dbus_verbose ("Falling back to pseudorandom for %d bytes\n",
02676                  n_bytes);
02677   
02678   _dbus_get_current_time (NULL, &tv_usec);
02679   srand (tv_usec);
02680   
02681   i = 0;
02682   while (i < n_bytes)
02683     {
02684       double r;
02685       unsigned int b;
02686           
02687       r = rand ();
02688       b = (r / (double) RAND_MAX) * 255.0;
02689           
02690       if (!_dbus_string_append_byte (str, b))
02691         goto failed;
02692           
02693       ++i;
02694     }
02695 
02696   return TRUE;
02697 
02698  failed:
02699   _dbus_string_set_length (str, old_len);
02700   return FALSE;
02701 }
02702 
02711 dbus_bool_t
02712 _dbus_generate_random_bytes (DBusString *str,
02713                              int         n_bytes)
02714 {
02715   int old_len;
02716   int fd;
02717 
02718   /* FALSE return means "no memory", if it could
02719    * mean something else then we'd need to return
02720    * a DBusError. So we always fall back to pseudorandom
02721    * if the I/O fails.
02722    */
02723   
02724   old_len = _dbus_string_get_length (str);
02725   fd = -1;
02726 
02727   /* note, urandom on linux will fall back to pseudorandom */
02728   fd = open ("/dev/urandom", O_RDONLY);
02729   if (fd < 0)
02730     return pseudorandom_generate_random_bytes (str, n_bytes);
02731 
02732   if (_dbus_read (fd, str, n_bytes) != n_bytes)
02733     {
02734       close (fd);
02735       _dbus_string_set_length (str, old_len);
02736       return pseudorandom_generate_random_bytes (str, n_bytes);
02737     }
02738 
02739   _dbus_verbose ("Read %d bytes from /dev/urandom\n",
02740                  n_bytes);
02741   
02742   close (fd);
02743   
02744   return TRUE;
02745 }
02746 
02755 dbus_bool_t
02756 _dbus_generate_random_ascii (DBusString *str,
02757                              int         n_bytes)
02758 {
02759   static const char letters[] =
02760     "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyz";
02761   int i;
02762   int len;
02763   
02764   if (!_dbus_generate_random_bytes (str, n_bytes))
02765     return FALSE;
02766   
02767   len = _dbus_string_get_length (str);
02768   i = len - n_bytes;
02769   while (i < len)
02770     {
02771       _dbus_string_set_byte (str, i,
02772                              letters[_dbus_string_get_byte (str, i) %
02773                                      (sizeof (letters) - 1)]);
02774 
02775       ++i;
02776     }
02777 
02778   _dbus_assert (_dbus_string_validate_ascii (str, len - n_bytes,
02779                                              n_bytes));
02780 
02781   return TRUE;
02782 }
02783 
02791 const char*
02792 _dbus_strerror (int error_number)
02793 {
02794   const char *msg;
02795   
02796   msg = strerror (error_number);
02797   if (msg == NULL)
02798     msg = "unknown";
02799 
02800   return msg;
02801 }
02802 
02806 void
02807 _dbus_disable_sigpipe (void)
02808 {
02809   signal (SIGPIPE, SIG_IGN);
02810 }
02811 
02819 void
02820 _dbus_fd_set_close_on_exec (int fd)
02821 {
02822   int val;
02823   
02824   val = fcntl (fd, F_GETFD, 0);
02825   
02826   if (val < 0)
02827     return;
02828 
02829   val |= FD_CLOEXEC;
02830   
02831   fcntl (fd, F_SETFD, val);
02832 }
02833 
02843 const char*
02844 _dbus_error_from_errno (int error_number)
02845 {
02846   switch (error_number)
02847     {
02848     case 0:
02849       return DBUS_ERROR_FAILED;
02850       
02851 #ifdef EPROTONOSUPPORT
02852     case EPROTONOSUPPORT:
02853       return DBUS_ERROR_NOT_SUPPORTED;
02854 #endif
02855 #ifdef EAFNOSUPPORT
02856     case EAFNOSUPPORT:
02857       return DBUS_ERROR_NOT_SUPPORTED;
02858 #endif
02859 #ifdef ENFILE
02860     case ENFILE:
02861       return DBUS_ERROR_LIMITS_EXCEEDED; /* kernel out of memory */
02862 #endif
02863 #ifdef EMFILE
02864     case EMFILE:
02865       return DBUS_ERROR_LIMITS_EXCEEDED;
02866 #endif
02867 #ifdef EACCES
02868     case EACCES:
02869       return DBUS_ERROR_ACCESS_DENIED;
02870 #endif
02871 #ifdef EPERM
02872     case EPERM:
02873       return DBUS_ERROR_ACCESS_DENIED;
02874 #endif
02875 #ifdef ENOBUFS
02876     case ENOBUFS:
02877       return DBUS_ERROR_NO_MEMORY;
02878 #endif
02879 #ifdef ENOMEM
02880     case ENOMEM:
02881       return DBUS_ERROR_NO_MEMORY;
02882 #endif
02883 #ifdef EINVAL
02884     case EINVAL:
02885       return DBUS_ERROR_FAILED;
02886 #endif
02887 #ifdef EBADF
02888     case EBADF:
02889       return DBUS_ERROR_FAILED;
02890 #endif
02891 #ifdef EFAULT
02892     case EFAULT:
02893       return DBUS_ERROR_FAILED;
02894 #endif
02895 #ifdef ENOTSOCK
02896     case ENOTSOCK:
02897       return DBUS_ERROR_FAILED;
02898 #endif
02899 #ifdef EISCONN
02900     case EISCONN:
02901       return DBUS_ERROR_FAILED;
02902 #endif
02903 #ifdef ECONNREFUSED
02904     case ECONNREFUSED:
02905       return DBUS_ERROR_NO_SERVER;
02906 #endif
02907 #ifdef ETIMEDOUT
02908     case ETIMEDOUT:
02909       return DBUS_ERROR_TIMEOUT;
02910 #endif
02911 #ifdef ENETUNREACH
02912     case ENETUNREACH:
02913       return DBUS_ERROR_NO_NETWORK;
02914 #endif
02915 #ifdef EADDRINUSE
02916     case EADDRINUSE:
02917       return DBUS_ERROR_ADDRESS_IN_USE;
02918 #endif
02919 #ifdef EEXIST
02920     case EEXIST:
02921       return DBUS_ERROR_FILE_NOT_FOUND;
02922 #endif
02923 #ifdef ENOENT
02924     case ENOENT:
02925       return DBUS_ERROR_FILE_NOT_FOUND;
02926 #endif
02927     }
02928 
02929   return DBUS_ERROR_FAILED;
02930 }
02931 
02937 void
02938 _dbus_exit (int code)
02939 {
02940   _exit (code);
02941 }
02942 
02951 dbus_bool_t
02952 _dbus_stat (const DBusString *filename,
02953             DBusStat         *statbuf,
02954             DBusError        *error)
02955 {
02956   const char *filename_c;
02957   struct stat sb;
02958 
02959   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
02960   
02961   filename_c = _dbus_string_get_const_data (filename);
02962 
02963   if (stat (filename_c, &sb) < 0)
02964     {
02965       dbus_set_error (error, _dbus_error_from_errno (errno),
02966                       "%s", _dbus_strerror (errno));
02967       return FALSE;
02968     }
02969 
02970   statbuf->mode = sb.st_mode;
02971   statbuf->nlink = sb.st_nlink;
02972   statbuf->uid = sb.st_uid;
02973   statbuf->gid = sb.st_gid;
02974   statbuf->size = sb.st_size;
02975   statbuf->atime = sb.st_atime;
02976   statbuf->mtime = sb.st_mtime;
02977   statbuf->ctime = sb.st_ctime;
02978 
02979   return TRUE;
02980 }
02981 
02992 dbus_bool_t
02993 _dbus_full_duplex_pipe (int        *fd1,
02994                         int        *fd2,
02995                         dbus_bool_t blocking,
02996                         DBusError  *error)
02997 {
02998 #ifdef HAVE_SOCKETPAIR
02999   int fds[2];
03000 
03001   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
03002   
03003   if (socketpair (AF_UNIX, SOCK_STREAM, 0, fds) < 0)
03004     {
03005       dbus_set_error (error, _dbus_error_from_errno (errno),
03006                       "Could not create full-duplex pipe");
03007       return FALSE;
03008     }
03009 
03010   if (!blocking &&
03011       (!_dbus_set_fd_nonblocking (fds[0], NULL) ||
03012        !_dbus_set_fd_nonblocking (fds[1], NULL)))
03013     {
03014       dbus_set_error (error, _dbus_error_from_errno (errno),
03015                       "Could not set full-duplex pipe nonblocking");
03016       
03017       close (fds[0]);
03018       close (fds[1]);
03019       
03020       return FALSE;
03021     }
03022   
03023   *fd1 = fds[0];
03024   *fd2 = fds[1];
03025   
03026   return TRUE;  
03027 #else
03028   _dbus_warn ("_dbus_full_duplex_pipe() not implemented on this OS\n");
03029   dbus_set_error (error, DBUS_ERROR_FAILED,
03030                   "_dbus_full_duplex_pipe() not implemented on this OS");
03031   return FALSE;
03032 #endif
03033 }
03034 
03042 dbus_bool_t
03043 _dbus_close (int        fd,
03044              DBusError *error)
03045 {
03046   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
03047   
03048  again:
03049   if (close (fd) < 0)
03050     {
03051       if (errno == EINTR)
03052         goto again;
03053 
03054       dbus_set_error (error, _dbus_error_from_errno (errno),
03055                       "Could not close fd %d", fd);
03056       return FALSE;
03057     }
03058 
03059   return TRUE;
03060 }
03061 
03069 dbus_bool_t
03070 _dbus_set_fd_nonblocking (int             fd,
03071                           DBusError      *error)
03072 {
03073   int val;
03074 
03075   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
03076   
03077   val = fcntl (fd, F_GETFL, 0);
03078   if (val < 0)
03079     {
03080       dbus_set_error (error, _dbus_error_from_errno (errno),
03081                       "Failed to get flags from file descriptor %d: %s",
03082                       fd, _dbus_strerror (errno));
03083       _dbus_verbose ("Failed to get flags for fd %d: %s\n", fd,
03084                      _dbus_strerror (errno));
03085       return FALSE;
03086     }
03087 
03088   if (fcntl (fd, F_SETFL, val | O_NONBLOCK) < 0)
03089     {
03090       dbus_set_error (error, _dbus_error_from_errno (errno),
03091                       "Failed to set nonblocking flag of file descriptor %d: %s",
03092                       fd, _dbus_strerror (errno));
03093       _dbus_verbose ("Failed to set fd %d nonblocking: %s\n",
03094                      fd, _dbus_strerror (errno));
03095 
03096       return FALSE;
03097     }
03098 
03099   return TRUE;
03100 }
03101 
03107 void
03108 _dbus_print_backtrace (void)
03109 {
03110 #if defined (HAVE_BACKTRACE) && defined (DBUS_ENABLE_VERBOSE_MODE)
03111   void *bt[500];
03112   int bt_size;
03113   int i;
03114   char **syms;
03115   
03116   bt_size = backtrace (bt, 500);
03117 
03118   syms = backtrace_symbols (bt, bt_size);
03119   
03120   i = 0;
03121   while (i < bt_size)
03122     {
03123       _dbus_verbose ("  %s\n", syms[i]);
03124       ++i;
03125     }
03126 
03127   free (syms);
03128 #else
03129   _dbus_verbose ("  D-BUS not compiled with backtrace support\n");
03130 #endif
03131 }
03132 
03140 dbus_bool_t
03141 _dbus_become_daemon (const DBusString *pidfile,
03142                      DBusError        *error)
03143 {
03144   const char *s;
03145   pid_t child_pid;
03146   int dev_null_fd;
03147 
03148   _dbus_verbose ("Becoming a daemon...\n");
03149 
03150   _dbus_verbose ("chdir to /\n");
03151   if (chdir ("/") < 0)
03152     {
03153       dbus_set_error (error, DBUS_ERROR_FAILED,
03154                       "Could not chdir() to root directory");
03155       return FALSE;
03156     }
03157 
03158   _dbus_verbose ("forking...\n");
03159   switch ((child_pid = fork ()))
03160     {
03161     case -1:
03162       _dbus_verbose ("fork failed\n");
03163       dbus_set_error (error, _dbus_error_from_errno (errno),
03164                       "Failed to fork daemon: %s", _dbus_strerror (errno));
03165       return FALSE;
03166       break;
03167 
03168     case 0:
03169       _dbus_verbose ("in child, closing std file descriptors\n");
03170 
03171       /* silently ignore failures here, if someone
03172        * doesn't have /dev/null we may as well try
03173        * to continue anyhow
03174        */
03175       
03176       dev_null_fd = open ("/dev/null", O_RDWR);
03177       if (dev_null_fd >= 0)
03178         {
03179           dup2 (dev_null_fd, 0);
03180           dup2 (dev_null_fd, 1);
03181           
03182           s = _dbus_getenv ("DBUS_DEBUG_OUTPUT");
03183           if (s == NULL || *s == '\0')
03184             dup2 (dev_null_fd, 2);
03185           else
03186             _dbus_verbose ("keeping stderr open due to DBUS_DEBUG_OUTPUT\n");
03187         }
03188 
03189       /* Get a predictable umask */
03190       _dbus_verbose ("setting umask\n");
03191       umask (022);
03192       break;
03193 
03194     default:
03195       if (pidfile)
03196         {
03197           _dbus_verbose ("parent writing pid file\n");
03198           if (!_dbus_write_pid_file (pidfile,
03199                                      child_pid,
03200                                      error))
03201             {
03202               _dbus_verbose ("pid file write failed, killing child\n");
03203               kill (child_pid, SIGTERM);
03204               return FALSE;
03205             }
03206         }
03207       _dbus_verbose ("parent exiting\n");
03208       _exit (0);
03209       break;
03210     }
03211 
03212   _dbus_verbose ("calling setsid()\n");
03213   if (setsid () == -1)
03214     _dbus_assert_not_reached ("setsid() failed");
03215   
03216   return TRUE;
03217 }
03218 
03227 dbus_bool_t
03228 _dbus_write_pid_file (const DBusString *filename,
03229                       unsigned long     pid,
03230                       DBusError        *error)
03231 {
03232   const char *cfilename;
03233   int fd;
03234   FILE *f;
03235 
03236   cfilename = _dbus_string_get_const_data (filename);
03237   
03238   fd = open (cfilename, O_WRONLY|O_CREAT|O_EXCL|O_BINARY, 0644);
03239   
03240   if (fd < 0)
03241     {
03242       dbus_set_error (error, _dbus_error_from_errno (errno),
03243                       "Failed to open \"%s\": %s", cfilename,
03244                       _dbus_strerror (errno));
03245       return FALSE;
03246     }
03247 
03248   if ((f = fdopen (fd, "w")) == NULL)
03249     {
03250       dbus_set_error (error, _dbus_error_from_errno (errno),
03251                       "Failed to fdopen fd %d: %s", fd, _dbus_strerror (errno));
03252       close (fd);
03253       return FALSE;
03254     }
03255   
03256   if (fprintf (f, "%lu\n", pid) < 0)
03257     {
03258       dbus_set_error (error, _dbus_error_from_errno (errno),
03259                       "Failed to write to \"%s\": %s", cfilename,
03260                       _dbus_strerror (errno));
03261       return FALSE;
03262     }
03263 
03264   if (fclose (f) == EOF)
03265     {
03266       dbus_set_error (error, _dbus_error_from_errno (errno),
03267                       "Failed to close \"%s\": %s", cfilename,
03268                       _dbus_strerror (errno));
03269       return FALSE;
03270     }
03271   
03272   return TRUE;
03273 }
03274 
03283 dbus_bool_t
03284 _dbus_change_identity  (dbus_uid_t     uid,
03285                         dbus_gid_t     gid,
03286                         DBusError     *error)
03287 {
03288   /* Set GID first, or the setuid may remove our permission
03289    * to change the GID
03290    */
03291   if (setgid (gid) < 0)
03292     {
03293       dbus_set_error (error, _dbus_error_from_errno (errno),
03294                       "Failed to set GID to %lu: %s", gid,
03295                       _dbus_strerror (errno));
03296       return FALSE;
03297     }
03298   
03299   if (setuid (uid) < 0)
03300     {
03301       dbus_set_error (error, _dbus_error_from_errno (errno),
03302                       "Failed to set UID to %lu: %s", uid,
03303                       _dbus_strerror (errno));
03304       return FALSE;
03305     }
03306   
03307   return TRUE;
03308 }
03309 
03315 void
03316 _dbus_set_signal_handler (int               sig,
03317                           DBusSignalHandler handler)
03318 {
03319   struct sigaction act;
03320   sigset_t empty_mask;
03321   
03322   sigemptyset (&empty_mask);
03323   act.sa_handler = handler;
03324   act.sa_mask    = empty_mask;
03325   act.sa_flags   = 0;
03326   sigaction (sig,  &act, 0);
03327 }
03328 
03329 
03330 #ifdef DBUS_BUILD_TESTS
03331 #include <stdlib.h>
03332 static void
03333 check_dirname (const char *filename,
03334                const char *dirname)
03335 {
03336   DBusString f, d;
03337   
03338   _dbus_string_init_const (&f, filename);
03339 
03340   if (!_dbus_string_init (&d))
03341     _dbus_assert_not_reached ("no memory");
03342 
03343   if (!_dbus_string_get_dirname (&f, &d))
03344     _dbus_assert_not_reached ("no memory");
03345 
03346   if (!_dbus_string_equal_c_str (&d, dirname))
03347     {
03348       _dbus_warn ("For filename \"%s\" got dirname \"%s\" and expected \"%s\"\n",
03349                   filename,
03350                   _dbus_string_get_const_data (&d),
03351                   dirname);
03352       exit (1);
03353     }
03354 
03355   _dbus_string_free (&d);
03356 }
03357 
03358 static void
03359 check_path_absolute (const char *path,
03360                      dbus_bool_t expected)
03361 {
03362   DBusString p;
03363 
03364   _dbus_string_init_const (&p, path);
03365 
03366   if (_dbus_path_is_absolute (&p) != expected)
03367     {
03368       _dbus_warn ("For path \"%s\" expected absolute = %d got %d\n",
03369                   path, expected, _dbus_path_is_absolute (&p));
03370       exit (1);
03371     }
03372 }
03373 
03379 dbus_bool_t
03380 _dbus_sysdeps_test (void)
03381 {
03382   DBusString str;
03383   double val;
03384   int pos;
03385   
03386   check_dirname ("foo", ".");
03387   check_dirname ("foo/bar", "foo");
03388   check_dirname ("foo//bar", "foo");
03389   check_dirname ("foo///bar", "foo");
03390   check_dirname ("foo/bar/", "foo");
03391   check_dirname ("foo//bar/", "foo");
03392   check_dirname ("foo///bar/", "foo");
03393   check_dirname ("foo/bar//", "foo");
03394   check_dirname ("foo//bar////", "foo");
03395   check_dirname ("foo///bar///////", "foo");
03396   check_dirname ("/foo", "/");
03397   check_dirname ("
03398   check_dirname ("/foo/bar", "/foo");
03399   check_dirname ("/foo//bar", "/foo");
03400   check_dirname ("/foo///bar", "/foo");
03401   check_dirname ("/", "/");
03402   check_dirname ("
03403   check_dirname ("", ".");  
03404 
03405 
03406   _dbus_string_init_const (&str, "3.5");
03407   if (!_dbus_string_parse_double (&str,
03408                                   0, &val, &pos))
03409     {
03410       _dbus_warn ("Failed to parse double");
03411       exit (1);
03412     }
03413   if (val != 3.5)
03414     {
03415       _dbus_warn ("Failed to parse 3.5 correctly, got: %f", val);
03416       exit (1);
03417     }
03418   if (pos != 3)
03419     {
03420       _dbus_warn ("_dbus_string_parse_double of \"3.5\" returned wrong position %d", pos);
03421       exit (1);
03422     }
03423 
03424   _dbus_string_init_const (&str, "0xff");
03425   if (!_dbus_string_parse_double (&str,
03426                                   0, &val, &pos))
03427     {
03428       _dbus_warn ("Failed to parse double");
03429       exit (1);
03430     }
03431   if (val != 0xff)
03432     {
03433       _dbus_warn ("Failed to parse 0xff correctly, got: %f", val);
03434       exit (1);
03435     }
03436   if (pos != 4)
03437     {
03438       _dbus_warn ("_dbus_string_parse_double of \"0xff\" returned wrong position %d", pos);
03439       exit (1);
03440     }
03441   
03442   check_path_absolute ("/", TRUE);
03443   check_path_absolute ("/foo", TRUE);
03444   check_path_absolute ("", FALSE);
03445   check_path_absolute ("foo", FALSE);
03446   check_path_absolute ("foo/bar", FALSE);
03447   
03448   return TRUE;
03449 }
03450 #endif /* DBUS_BUILD_TESTS */
03451 

Generated on Sun Mar 21 03:52:06 2004 for D-BUS by doxygen 1.3.6-20040222