dbus-sysdeps-util.c

00001 /* -*- mode: C; c-file-style: "gnu" -*- */
00002 /* dbus-sysdeps-util.c Would be in dbus-sysdeps.c, but not used in libdbus
00003  * 
00004  * Copyright (C) 2002, 2003, 2004, 2005  Red Hat, Inc.
00005  * Copyright (C) 2003 CodeFactory AB
00006  *
00007  * Licensed under the Academic Free License version 2.1
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 #include "dbus-sysdeps.h"
00025 #include "dbus-internals.h"
00026 #include "dbus-protocol.h"
00027 #include "dbus-string.h"
00028 #define DBUS_USERDB_INCLUDES_PRIVATE 1
00029 #include "dbus-userdb.h"
00030 #include "dbus-test.h"
00031 
00032 #include <sys/types.h>
00033 #include <stdlib.h>
00034 #include <string.h>
00035 #include <signal.h>
00036 #include <unistd.h>
00037 #include <stdio.h>
00038 #include <errno.h>
00039 #include <fcntl.h>
00040 #include <sys/stat.h>
00041 #include <grp.h>
00042 #include <sys/socket.h>
00043 #include <dirent.h>
00044 #include <sys/un.h>
00045 #include <sys/wait.h>
00046 
00047 #ifndef O_BINARY
00048 #define O_BINARY 0
00049 #endif
00050 
00064 dbus_bool_t
00065 _dbus_become_daemon (const DBusString *pidfile,
00066                      int               print_pid_fd,
00067                      DBusError        *error)
00068 {
00069   const char *s;
00070   pid_t child_pid;
00071   int dev_null_fd;
00072 
00073   _dbus_verbose ("Becoming a daemon...\n");
00074 
00075   _dbus_verbose ("chdir to /\n");
00076   if (chdir ("/") < 0)
00077     {
00078       dbus_set_error (error, DBUS_ERROR_FAILED,
00079                       "Could not chdir() to root directory");
00080       return FALSE;
00081     }
00082 
00083   _dbus_verbose ("forking...\n");
00084   switch ((child_pid = fork ()))
00085     {
00086     case -1:
00087       _dbus_verbose ("fork failed\n");
00088       dbus_set_error (error, _dbus_error_from_errno (errno),
00089                       "Failed to fork daemon: %s", _dbus_strerror (errno));
00090       return FALSE;
00091       break;
00092 
00093     case 0:
00094       _dbus_verbose ("in child, closing std file descriptors\n");
00095 
00096       /* silently ignore failures here, if someone
00097        * doesn't have /dev/null we may as well try
00098        * to continue anyhow
00099        */
00100       
00101       dev_null_fd = open ("/dev/null", O_RDWR);
00102       if (dev_null_fd >= 0)
00103         {
00104           dup2 (dev_null_fd, 0);
00105           dup2 (dev_null_fd, 1);
00106           
00107           s = _dbus_getenv ("DBUS_DEBUG_OUTPUT");
00108           if (s == NULL || *s == '\0')
00109             dup2 (dev_null_fd, 2);
00110           else
00111             _dbus_verbose ("keeping stderr open due to DBUS_DEBUG_OUTPUT\n");
00112         }
00113 
00114       /* Get a predictable umask */
00115       _dbus_verbose ("setting umask\n");
00116       umask (022);
00117       break;
00118 
00119     default:
00120       if (pidfile)
00121         {
00122           _dbus_verbose ("parent writing pid file\n");
00123           if (!_dbus_write_pid_file (pidfile,
00124                                      child_pid,
00125                                      error))
00126             {
00127               _dbus_verbose ("pid file write failed, killing child\n");
00128               kill (child_pid, SIGTERM);
00129               return FALSE;
00130             }
00131         }
00132 
00133       /* Write PID if requested */
00134       if (print_pid_fd >= 0)
00135         {
00136           DBusString pid;
00137           int bytes;
00138           
00139           if (!_dbus_string_init (&pid))
00140             {
00141               _DBUS_SET_OOM (error);
00142               kill (child_pid, SIGTERM);
00143               return FALSE;
00144             }
00145           
00146           if (!_dbus_string_append_int (&pid, child_pid) ||
00147               !_dbus_string_append (&pid, "\n"))
00148             {
00149               _dbus_string_free (&pid);
00150               _DBUS_SET_OOM (error);
00151               kill (child_pid, SIGTERM);
00152               return FALSE;
00153             }
00154           
00155           bytes = _dbus_string_get_length (&pid);
00156           if (_dbus_write (print_pid_fd, &pid, 0, bytes) != bytes)
00157             {
00158               dbus_set_error (error, DBUS_ERROR_FAILED,
00159                               "Printing message bus PID: %s\n",
00160                               _dbus_strerror (errno));
00161               _dbus_string_free (&pid);
00162               kill (child_pid, SIGTERM);
00163               return FALSE;
00164             }
00165           
00166           _dbus_string_free (&pid);
00167         }
00168       _dbus_verbose ("parent exiting\n");
00169       _exit (0);
00170       break;
00171     }
00172 
00173   _dbus_verbose ("calling setsid()\n");
00174   if (setsid () == -1)
00175     _dbus_assert_not_reached ("setsid() failed");
00176   
00177   return TRUE;
00178 }
00179 
00180 
00189 dbus_bool_t
00190 _dbus_write_pid_file (const DBusString *filename,
00191                       unsigned long     pid,
00192                       DBusError        *error)
00193 {
00194   const char *cfilename;
00195   int fd;
00196   FILE *f;
00197 
00198   cfilename = _dbus_string_get_const_data (filename);
00199   
00200   fd = open (cfilename, O_WRONLY|O_CREAT|O_EXCL|O_BINARY, 0644);
00201   
00202   if (fd < 0)
00203     {
00204       dbus_set_error (error, _dbus_error_from_errno (errno),
00205                       "Failed to open \"%s\": %s", cfilename,
00206                       _dbus_strerror (errno));
00207       return FALSE;
00208     }
00209 
00210   if ((f = fdopen (fd, "w")) == NULL)
00211     {
00212       dbus_set_error (error, _dbus_error_from_errno (errno),
00213                       "Failed to fdopen fd %d: %s", fd, _dbus_strerror (errno));
00214       close (fd);
00215       return FALSE;
00216     }
00217   
00218   if (fprintf (f, "%lu\n", pid) < 0)
00219     {
00220       dbus_set_error (error, _dbus_error_from_errno (errno),
00221                       "Failed to write to \"%s\": %s", cfilename,
00222                       _dbus_strerror (errno));
00223       return FALSE;
00224     }
00225 
00226   if (fclose (f) == EOF)
00227     {
00228       dbus_set_error (error, _dbus_error_from_errno (errno),
00229                       "Failed to close \"%s\": %s", cfilename,
00230                       _dbus_strerror (errno));
00231       return FALSE;
00232     }
00233   
00234   return TRUE;
00235 }
00236 
00237 
00246 dbus_bool_t
00247 _dbus_change_identity  (dbus_uid_t     uid,
00248                         dbus_gid_t     gid,
00249                         DBusError     *error)
00250 {
00251   /* setgroups() only works if we are a privileged process,
00252    * so we don't return error on failure; the only possible
00253    * failure is that we don't have perms to do it.
00254    * FIXME not sure this is right, maybe if setuid()
00255    * is going to work then setgroups() should also work.
00256    */
00257   if (setgroups (0, NULL) < 0)
00258     _dbus_warn ("Failed to drop supplementary groups: %s\n",
00259                 _dbus_strerror (errno));
00260   
00261   /* Set GID first, or the setuid may remove our permission
00262    * to change the GID
00263    */
00264   if (setgid (gid) < 0)
00265     {
00266       dbus_set_error (error, _dbus_error_from_errno (errno),
00267                       "Failed to set GID to %lu: %s", gid,
00268                       _dbus_strerror (errno));
00269       return FALSE;
00270     }
00271   
00272   if (setuid (uid) < 0)
00273     {
00274       dbus_set_error (error, _dbus_error_from_errno (errno),
00275                       "Failed to set UID to %lu: %s", uid,
00276                       _dbus_strerror (errno));
00277       return FALSE;
00278     }
00279   
00280   return TRUE;
00281 }
00282 
00288 void
00289 _dbus_set_signal_handler (int               sig,
00290                           DBusSignalHandler handler)
00291 {
00292   struct sigaction act;
00293   sigset_t empty_mask;
00294   
00295   sigemptyset (&empty_mask);
00296   act.sa_handler = handler;
00297   act.sa_mask    = empty_mask;
00298   act.sa_flags   = 0;
00299   sigaction (sig,  &act, 0);
00300 }
00301 
00302 
00310 dbus_bool_t
00311 _dbus_delete_directory (const DBusString *filename,
00312                         DBusError        *error)
00313 {
00314   const char *filename_c;
00315   
00316   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
00317 
00318   filename_c = _dbus_string_get_const_data (filename);
00319 
00320   if (rmdir (filename_c) != 0)
00321     {
00322       dbus_set_error (error, DBUS_ERROR_FAILED,
00323                       "Failed to remove directory %s: %s\n",
00324                       filename_c, _dbus_strerror (errno));
00325       return FALSE;
00326     }
00327   
00328   return TRUE;
00329 }
00330 
00336 dbus_bool_t 
00337 _dbus_file_exists (const char *file)
00338 {
00339   return (access (file, F_OK) == 0);
00340 }
00341 
00348 dbus_bool_t 
00349 _dbus_user_at_console (const char *username,
00350                        DBusError  *error)
00351 {
00352 
00353   DBusString f;
00354   dbus_bool_t result;
00355   int console;
00356   pid_t fgconsole;
00357 
00358   result = FALSE;
00359 
00360   fgconsole = fork();
00361   if (fgconsole == 0) 
00362     {
00363       execl (DBUS_FOREGROUND_CONSOLE_COMMAND, DBUS_FOREGROUND_CONSOLE_COMMAND, NULL);
00364       exit (0);
00365     } else if (fgconsole < 0) 
00366     {
00367       dbus_set_error (error, DBUS_ERROR_FAILED,
00368                       "Failed to fork(): %s\n", _dbus_strerror (errno));
00369       return FALSE;
00370     }
00371 
00372   if (wait (&console) < 0 || !WIFEXITED (console))
00373     {
00374       dbus_set_error (error, DBUS_ERROR_FAILED,
00375                       "Failed to execute %s: %s\n",
00376                       DBUS_FOREGROUND_CONSOLE_COMMAND, _dbus_strerror (errno));
00377       return FALSE;
00378     }
00379 
00380   console = WEXITSTATUS(console);
00381 
00382   /* Consoles start at 1, so 0 denotes failure */
00383   if (console == 0)
00384     {
00385       return FALSE;
00386     }
00387       
00388   
00389   if (!_dbus_string_init (&f))
00390     {
00391       _DBUS_SET_OOM (error);
00392       return FALSE;
00393     }
00394 
00395   if (!_dbus_string_append (&f, DBUS_CONSOLE_AUTH_DIR))
00396     {
00397       _DBUS_SET_OOM (error);
00398       goto out;
00399     }
00400 
00401   if (!_dbus_string_append (&f, username))
00402     {
00403       _DBUS_SET_OOM (error);
00404       goto out;
00405     }
00406 
00407   /* : is used as a separator, since . is a valid username character */
00408   if (!_dbus_string_append (&f, ":"))
00409     {
00410       _DBUS_SET_OOM (error);
00411       goto out;
00412     }
00413 
00414   if (!_dbus_string_append_int (&f, console))
00415     {
00416       _DBUS_SET_OOM (error);
00417       goto out;
00418     }
00419 
00420   result = _dbus_file_exists (_dbus_string_get_const_data (&f));
00421 
00422  out:
00423   _dbus_string_free (&f);
00424 
00425   return result;
00426 }
00427 
00428 
00435 dbus_bool_t
00436 _dbus_path_is_absolute (const DBusString *filename)
00437 {
00438   if (_dbus_string_get_length (filename) > 0)
00439     return _dbus_string_get_byte (filename, 0) == '/';
00440   else
00441     return FALSE;
00442 }
00443 
00452 dbus_bool_t
00453 _dbus_stat (const DBusString *filename,
00454             DBusStat         *statbuf,
00455             DBusError        *error)
00456 {
00457   const char *filename_c;
00458   struct stat sb;
00459 
00460   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
00461   
00462   filename_c = _dbus_string_get_const_data (filename);
00463 
00464   if (stat (filename_c, &sb) < 0)
00465     {
00466       dbus_set_error (error, _dbus_error_from_errno (errno),
00467                       "%s", _dbus_strerror (errno));
00468       return FALSE;
00469     }
00470 
00471   statbuf->mode = sb.st_mode;
00472   statbuf->nlink = sb.st_nlink;
00473   statbuf->uid = sb.st_uid;
00474   statbuf->gid = sb.st_gid;
00475   statbuf->size = sb.st_size;
00476   statbuf->atime = sb.st_atime;
00477   statbuf->mtime = sb.st_mtime;
00478   statbuf->ctime = sb.st_ctime;
00479 
00480   return TRUE;
00481 }
00482 
00483 
00487 struct DBusDirIter
00488 {
00489   DIR *d; 
00491 };
00492 
00500 DBusDirIter*
00501 _dbus_directory_open (const DBusString *filename,
00502                       DBusError        *error)
00503 {
00504   DIR *d;
00505   DBusDirIter *iter;
00506   const char *filename_c;
00507 
00508   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
00509   
00510   filename_c = _dbus_string_get_const_data (filename);
00511 
00512   d = opendir (filename_c);
00513   if (d == NULL)
00514     {
00515       dbus_set_error (error, _dbus_error_from_errno (errno),
00516                       "Failed to read directory \"%s\": %s",
00517                       filename_c,
00518                       _dbus_strerror (errno));
00519       return NULL;
00520     }
00521   iter = dbus_new0 (DBusDirIter, 1);
00522   if (iter == NULL)
00523     {
00524       closedir (d);
00525       dbus_set_error (error, DBUS_ERROR_NO_MEMORY,
00526                       "Could not allocate memory for directory iterator");
00527       return NULL;
00528     }
00529 
00530   iter->d = d;
00531 
00532   return iter;
00533 }
00534 
00548 dbus_bool_t
00549 _dbus_directory_get_next_file (DBusDirIter      *iter,
00550                                DBusString       *filename,
00551                                DBusError        *error)
00552 {
00553   struct dirent *ent;
00554 
00555   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
00556   
00557  again:
00558   errno = 0;
00559   ent = readdir (iter->d);
00560   if (ent == NULL)
00561     {
00562       if (errno != 0)
00563         dbus_set_error (error,
00564                         _dbus_error_from_errno (errno),
00565                         "%s", _dbus_strerror (errno));
00566       return FALSE;
00567     }
00568   else if (ent->d_name[0] == '.' &&
00569            (ent->d_name[1] == '\0' ||
00570             (ent->d_name[1] == '.' && ent->d_name[2] == '\0')))
00571     goto again;
00572   else
00573     {
00574       _dbus_string_set_length (filename, 0);
00575       if (!_dbus_string_append (filename, ent->d_name))
00576         {
00577           dbus_set_error (error, DBUS_ERROR_NO_MEMORY,
00578                           "No memory to read directory entry");
00579           return FALSE;
00580         }
00581       else
00582         return TRUE;
00583     }
00584 }
00585 
00589 void
00590 _dbus_directory_close (DBusDirIter *iter)
00591 {
00592   closedir (iter->d);
00593   dbus_free (iter);
00594 }
00595 
00596 static dbus_bool_t
00597 fill_user_info_from_group (struct group  *g,
00598                            DBusGroupInfo *info,
00599                            DBusError     *error)
00600 {
00601   _dbus_assert (g->gr_name != NULL);
00602   
00603   info->gid = g->gr_gid;
00604   info->groupname = _dbus_strdup (g->gr_name);
00605 
00606   /* info->members = dbus_strdupv (g->gr_mem) */
00607   
00608   if (info->groupname == NULL)
00609     {
00610       dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
00611       return FALSE;
00612     }
00613 
00614   return TRUE;
00615 }
00616 
00617 static dbus_bool_t
00618 fill_group_info (DBusGroupInfo    *info,
00619                  dbus_gid_t        gid,
00620                  const DBusString *groupname,
00621                  DBusError        *error)
00622 {
00623   const char *group_c_str;
00624 
00625   _dbus_assert (groupname != NULL || gid != DBUS_GID_UNSET);
00626   _dbus_assert (groupname == NULL || gid == DBUS_GID_UNSET);
00627 
00628   if (groupname)
00629     group_c_str = _dbus_string_get_const_data (groupname);
00630   else
00631     group_c_str = NULL;
00632   
00633   /* For now assuming that the getgrnam() and getgrgid() flavors
00634    * always correspond to the pwnam flavors, if not we have
00635    * to add more configure checks.
00636    */
00637   
00638 #if defined (HAVE_POSIX_GETPWNAM_R) || defined (HAVE_NONPOSIX_GETPWNAM_R)
00639   {
00640     struct group *g;
00641     int result;
00642     char buf[1024];
00643     struct group g_str;
00644 
00645     g = NULL;
00646 #ifdef HAVE_POSIX_GETPWNAM_R
00647 
00648     if (group_c_str)
00649       result = getgrnam_r (group_c_str, &g_str, buf, sizeof (buf),
00650                            &g);
00651     else
00652       result = getgrgid_r (gid, &g_str, buf, sizeof (buf),
00653                            &g);
00654 #else
00655     g = getgrnam_r (group_c_str, &g_str, buf, sizeof (buf));
00656     result = 0;
00657 #endif /* !HAVE_POSIX_GETPWNAM_R */
00658     if (result == 0 && g == &g_str)
00659       {
00660         return fill_user_info_from_group (g, info, error);
00661       }
00662     else
00663       {
00664         dbus_set_error (error, _dbus_error_from_errno (errno),
00665                         "Group %s unknown or failed to look it up\n",
00666                         group_c_str ? group_c_str : "???");
00667         return FALSE;
00668       }
00669   }
00670 #else /* ! HAVE_GETPWNAM_R */
00671   {
00672     /* I guess we're screwed on thread safety here */
00673     struct group *g;
00674 
00675     g = getgrnam (group_c_str);
00676 
00677     if (g != NULL)
00678       {
00679         return fill_user_info_from_group (g, info, error);
00680       }
00681     else
00682       {
00683         dbus_set_error (error, _dbus_error_from_errno (errno),
00684                         "Group %s unknown or failed to look it up\n",
00685                         group_c_str ? group_c_str : "???");
00686         return FALSE;
00687       }
00688   }
00689 #endif  /* ! HAVE_GETPWNAM_R */
00690 }
00691 
00701 dbus_bool_t
00702 _dbus_group_info_fill (DBusGroupInfo    *info,
00703                        const DBusString *groupname,
00704                        DBusError        *error)
00705 {
00706   return fill_group_info (info, DBUS_GID_UNSET,
00707                           groupname, error);
00708 
00709 }
00710 
00720 dbus_bool_t
00721 _dbus_group_info_fill_gid (DBusGroupInfo *info,
00722                            dbus_gid_t     gid,
00723                            DBusError     *error)
00724 {
00725   return fill_group_info (info, gid, NULL, error);
00726 }
00727 
00733 void
00734 _dbus_group_info_free (DBusGroupInfo    *info)
00735 {
00736   dbus_free (info->groupname);
00737 }
00738  /* End of DBusInternalsUtils functions */
00740 
00752 dbus_bool_t
00753 _dbus_string_get_dirname  (const DBusString *filename,
00754                            DBusString       *dirname)
00755 {
00756   int sep;
00757   
00758   _dbus_assert (filename != dirname);
00759   _dbus_assert (filename != NULL);
00760   _dbus_assert (dirname != NULL);
00761 
00762   /* Ignore any separators on the end */
00763   sep = _dbus_string_get_length (filename);
00764   if (sep == 0)
00765     return _dbus_string_append (dirname, "."); /* empty string passed in */
00766     
00767   while (sep > 0 && _dbus_string_get_byte (filename, sep - 1) == '/')
00768     --sep;
00769 
00770   _dbus_assert (sep >= 0);
00771   
00772   if (sep == 0)
00773     return _dbus_string_append (dirname, "/");
00774   
00775   /* Now find the previous separator */
00776   _dbus_string_find_byte_backward (filename, sep, '/', &sep);
00777   if (sep < 0)
00778     return _dbus_string_append (dirname, ".");
00779   
00780   /* skip multiple separators */
00781   while (sep > 0 && _dbus_string_get_byte (filename, sep - 1) == '/')
00782     --sep;
00783 
00784   _dbus_assert (sep >= 0);
00785   
00786   if (sep == 0 &&
00787       _dbus_string_get_byte (filename, 0) == '/')
00788     return _dbus_string_append (dirname, "/");
00789   else
00790     return _dbus_string_copy_len (filename, 0, sep - 0,
00791                                   dirname, _dbus_string_get_length (dirname));
00792 } /* DBusString stuff */
00794 
00795 
00796 #ifdef DBUS_BUILD_TESTS
00797 #include <stdlib.h>
00798 static void
00799 check_dirname (const char *filename,
00800                const char *dirname)
00801 {
00802   DBusString f, d;
00803   
00804   _dbus_string_init_const (&f, filename);
00805 
00806   if (!_dbus_string_init (&d))
00807     _dbus_assert_not_reached ("no memory");
00808 
00809   if (!_dbus_string_get_dirname (&f, &d))
00810     _dbus_assert_not_reached ("no memory");
00811 
00812   if (!_dbus_string_equal_c_str (&d, dirname))
00813     {
00814       _dbus_warn ("For filename \"%s\" got dirname \"%s\" and expected \"%s\"\n",
00815                   filename,
00816                   _dbus_string_get_const_data (&d),
00817                   dirname);
00818       exit (1);
00819     }
00820 
00821   _dbus_string_free (&d);
00822 }
00823 
00824 static void
00825 check_path_absolute (const char *path,
00826                      dbus_bool_t expected)
00827 {
00828   DBusString p;
00829 
00830   _dbus_string_init_const (&p, path);
00831 
00832   if (_dbus_path_is_absolute (&p) != expected)
00833     {
00834       _dbus_warn ("For path \"%s\" expected absolute = %d got %d\n",
00835                   path, expected, _dbus_path_is_absolute (&p));
00836       exit (1);
00837     }
00838 }
00839 
00845 dbus_bool_t
00846 _dbus_sysdeps_test (void)
00847 {
00848   DBusString str;
00849   double val;
00850   int pos;
00851   
00852   check_dirname ("foo", ".");
00853   check_dirname ("foo/bar", "foo");
00854   check_dirname ("foo//bar", "foo");
00855   check_dirname ("foo///bar", "foo");
00856   check_dirname ("foo/bar/", "foo");
00857   check_dirname ("foo//bar/", "foo");
00858   check_dirname ("foo///bar/", "foo");
00859   check_dirname ("foo/bar//", "foo");
00860   check_dirname ("foo//bar////", "foo");
00861   check_dirname ("foo///bar///////", "foo");
00862   check_dirname ("/foo", "/");
00863   check_dirname ("////foo", "/");
00864   check_dirname ("/foo/bar", "/foo");
00865   check_dirname ("/foo//bar", "/foo");
00866   check_dirname ("/foo///bar", "/foo");
00867   check_dirname ("/", "/");
00868   check_dirname ("///", "/");
00869   check_dirname ("", ".");  
00870 
00871 
00872   _dbus_string_init_const (&str, "3.5");
00873   if (!_dbus_string_parse_double (&str,
00874                                   0, &val, &pos))
00875     {
00876       _dbus_warn ("Failed to parse double");
00877       exit (1);
00878     }
00879   if (ABS(3.5 - val) > 1e-6)
00880     {
00881       _dbus_warn ("Failed to parse 3.5 correctly, got: %f", val);
00882       exit (1);
00883     }
00884   if (pos != 3)
00885     {
00886       _dbus_warn ("_dbus_string_parse_double of \"3.5\" returned wrong position %d", pos);
00887       exit (1);
00888     }
00889 
00890   _dbus_string_init_const (&str, "0xff");
00891   if (!_dbus_string_parse_double (&str,
00892                                   0, &val, &pos))
00893     {
00894       _dbus_warn ("Failed to parse double");
00895       exit (1);
00896     }
00897   if (ABS (0xff - val) > 1e-6)
00898     {
00899       _dbus_warn ("Failed to parse 0xff correctly, got: %f\n", val);
00900       exit (1);
00901     }
00902   if (pos != 4)
00903     {
00904       _dbus_warn ("_dbus_string_parse_double of \"0xff\" returned wrong position %d", pos);
00905       exit (1);
00906     }
00907   
00908   check_path_absolute ("/", TRUE);
00909   check_path_absolute ("/foo", TRUE);
00910   check_path_absolute ("", FALSE);
00911   check_path_absolute ("foo", FALSE);
00912   check_path_absolute ("foo/bar", FALSE);
00913   
00914   return TRUE;
00915 }
00916 #endif /* DBUS_BUILD_TESTS */

Generated on Tue Jul 7 15:14:00 2009 for D-BUS by  doxygen 1.4.6