00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024 #include "dbus-sysdeps.h"
00025 #include "dbus-sysdeps-unix.h"
00026 #include "dbus-internals.h"
00027 #include "dbus-protocol.h"
00028 #include "dbus-string.h"
00029 #define DBUS_USERDB_INCLUDES_PRIVATE 1
00030 #include "dbus-userdb.h"
00031 #include "dbus-test.h"
00032
00033 #include <sys/types.h>
00034 #include <stdlib.h>
00035 #include <string.h>
00036 #include <signal.h>
00037 #include <unistd.h>
00038 #include <stdio.h>
00039 #include <errno.h>
00040 #include <fcntl.h>
00041 #include <sys/stat.h>
00042 #include <grp.h>
00043 #include <sys/socket.h>
00044 #include <dirent.h>
00045 #include <sys/un.h>
00046 #include <glob.h>
00047 #ifdef HAVE_LIBAUDIT
00048 #include <sys/prctl.h>
00049 #include <sys/capability.h>
00050 #include <libaudit.h>
00051 #endif
00052
00053 #ifdef HAVE_SYS_SYSLIMITS_H
00054 #include <sys/syslimits.h>
00055 #endif
00056
00057 #ifndef O_BINARY
00058 #define O_BINARY 0
00059 #endif
00060
00074 dbus_bool_t
00075 _dbus_become_daemon (const DBusString *pidfile,
00076 DBusPipe *print_pid_pipe,
00077 DBusError *error)
00078 {
00079 const char *s;
00080 pid_t child_pid;
00081 int dev_null_fd;
00082
00083 _dbus_verbose ("Becoming a daemon...\n");
00084
00085 _dbus_verbose ("chdir to /\n");
00086 if (chdir ("/") < 0)
00087 {
00088 dbus_set_error (error, DBUS_ERROR_FAILED,
00089 "Could not chdir() to root directory");
00090 return FALSE;
00091 }
00092
00093 _dbus_verbose ("forking...\n");
00094 switch ((child_pid = fork ()))
00095 {
00096 case -1:
00097 _dbus_verbose ("fork failed\n");
00098 dbus_set_error (error, _dbus_error_from_errno (errno),
00099 "Failed to fork daemon: %s", _dbus_strerror (errno));
00100 return FALSE;
00101 break;
00102
00103 case 0:
00104 _dbus_verbose ("in child, closing std file descriptors\n");
00105
00106
00107
00108
00109
00110
00111 dev_null_fd = open ("/dev/null", O_RDWR);
00112 if (dev_null_fd >= 0)
00113 {
00114 dup2 (dev_null_fd, 0);
00115 dup2 (dev_null_fd, 1);
00116
00117 s = _dbus_getenv ("DBUS_DEBUG_OUTPUT");
00118 if (s == NULL || *s == '\0')
00119 dup2 (dev_null_fd, 2);
00120 else
00121 _dbus_verbose ("keeping stderr open due to DBUS_DEBUG_OUTPUT\n");
00122 }
00123
00124
00125 _dbus_verbose ("setting umask\n");
00126 umask (022);
00127 break;
00128
00129 default:
00130 if (pidfile)
00131 {
00132 _dbus_verbose ("parent writing pid file\n");
00133 if (!_dbus_write_pid_file (pidfile,
00134 child_pid,
00135 error))
00136 {
00137 _dbus_verbose ("pid file write failed, killing child\n");
00138 kill (child_pid, SIGTERM);
00139 return FALSE;
00140 }
00141 }
00142
00143
00144 if (print_pid_pipe != NULL && _dbus_pipe_is_valid (print_pid_pipe))
00145 {
00146 DBusString pid;
00147 int bytes;
00148
00149 if (!_dbus_string_init (&pid))
00150 {
00151 _DBUS_SET_OOM (error);
00152 kill (child_pid, SIGTERM);
00153 return FALSE;
00154 }
00155
00156 if (!_dbus_string_append_int (&pid, child_pid) ||
00157 !_dbus_string_append (&pid, "\n"))
00158 {
00159 _dbus_string_free (&pid);
00160 _DBUS_SET_OOM (error);
00161 kill (child_pid, SIGTERM);
00162 return FALSE;
00163 }
00164
00165 bytes = _dbus_string_get_length (&pid);
00166 if (_dbus_pipe_write (print_pid_pipe, &pid, 0, bytes, error) != bytes)
00167 {
00168
00169 if (error != NULL && !dbus_error_is_set(error))
00170 {
00171 dbus_set_error (error, DBUS_ERROR_FAILED,
00172 "Printing message bus PID: did not write enough bytes\n");
00173 }
00174 _dbus_string_free (&pid);
00175 kill (child_pid, SIGTERM);
00176 return FALSE;
00177 }
00178
00179 _dbus_string_free (&pid);
00180 }
00181 _dbus_verbose ("parent exiting\n");
00182 _exit (0);
00183 break;
00184 }
00185
00186 _dbus_verbose ("calling setsid()\n");
00187 if (setsid () == -1)
00188 _dbus_assert_not_reached ("setsid() failed");
00189
00190 return TRUE;
00191 }
00192
00193
00202 dbus_bool_t
00203 _dbus_write_pid_file (const DBusString *filename,
00204 unsigned long pid,
00205 DBusError *error)
00206 {
00207 const char *cfilename;
00208 int fd;
00209 FILE *f;
00210
00211 cfilename = _dbus_string_get_const_data (filename);
00212
00213 fd = open (cfilename, O_WRONLY|O_CREAT|O_EXCL|O_BINARY, 0644);
00214
00215 if (fd < 0)
00216 {
00217 dbus_set_error (error, _dbus_error_from_errno (errno),
00218 "Failed to open \"%s\": %s", cfilename,
00219 _dbus_strerror (errno));
00220 return FALSE;
00221 }
00222
00223 if ((f = fdopen (fd, "w")) == NULL)
00224 {
00225 dbus_set_error (error, _dbus_error_from_errno (errno),
00226 "Failed to fdopen fd %d: %s", fd, _dbus_strerror (errno));
00227 _dbus_close (fd, NULL);
00228 return FALSE;
00229 }
00230
00231 if (fprintf (f, "%lu\n", pid) < 0)
00232 {
00233 dbus_set_error (error, _dbus_error_from_errno (errno),
00234 "Failed to write to \"%s\": %s", cfilename,
00235 _dbus_strerror (errno));
00236
00237 fclose (f);
00238 return FALSE;
00239 }
00240
00241 if (fclose (f) == EOF)
00242 {
00243 dbus_set_error (error, _dbus_error_from_errno (errno),
00244 "Failed to close \"%s\": %s", cfilename,
00245 _dbus_strerror (errno));
00246 return FALSE;
00247 }
00248
00249 return TRUE;
00250 }
00251
00258 dbus_bool_t
00259 _dbus_verify_daemon_user (const char *user)
00260 {
00261 DBusString u;
00262
00263 _dbus_string_init_const (&u, user);
00264
00265 return _dbus_get_user_id_and_primary_group (&u, NULL, NULL);
00266 }
00267
00275 dbus_bool_t
00276 _dbus_change_to_daemon_user (const char *user,
00277 DBusError *error)
00278 {
00279 dbus_uid_t uid;
00280 dbus_gid_t gid;
00281 DBusString u;
00282 #ifdef HAVE_LIBAUDIT
00283 dbus_bool_t we_were_root;
00284 cap_t new_caps;
00285 #endif
00286
00287 _dbus_string_init_const (&u, user);
00288
00289 if (!_dbus_get_user_id_and_primary_group (&u, &uid, &gid))
00290 {
00291 dbus_set_error (error, DBUS_ERROR_FAILED,
00292 "User '%s' does not appear to exist?",
00293 user);
00294 return FALSE;
00295 }
00296
00297 #ifdef HAVE_LIBAUDIT
00298 we_were_root = _dbus_getuid () == 0;
00299 new_caps = NULL;
00300
00301
00302
00303
00304 if (!we_were_root)
00305 {
00306 cap_value_t new_cap_list[] = { CAP_AUDIT_WRITE };
00307 cap_value_t tmp_cap_list[] = { CAP_AUDIT_WRITE, CAP_SETUID, CAP_SETGID };
00308 cap_t tmp_caps = cap_init();
00309
00310 if (!tmp_caps || !(new_caps = cap_init ()))
00311 {
00312 dbus_set_error (error, DBUS_ERROR_FAILED,
00313 "Failed to initialize drop of capabilities: %s\n",
00314 _dbus_strerror (errno));
00315
00316 if (tmp_caps)
00317 cap_free (tmp_caps);
00318
00319 return FALSE;
00320 }
00321
00322
00323 cap_set_flag (new_caps, CAP_PERMITTED, 1, new_cap_list, CAP_SET);
00324 cap_set_flag (new_caps, CAP_EFFECTIVE, 1, new_cap_list, CAP_SET);
00325 cap_set_flag (tmp_caps, CAP_PERMITTED, 3, tmp_cap_list, CAP_SET);
00326 cap_set_flag (tmp_caps, CAP_EFFECTIVE, 3, tmp_cap_list, CAP_SET);
00327
00328 if (prctl (PR_SET_KEEPCAPS, 1, 0, 0, 0) == -1)
00329 {
00330 dbus_set_error (error, _dbus_error_from_errno (errno),
00331 "Failed to set keep-capabilities: %s\n",
00332 _dbus_strerror (errno));
00333 cap_free (tmp_caps);
00334 goto fail;
00335 }
00336
00337 if (cap_set_proc (tmp_caps) == -1)
00338 {
00339 dbus_set_error (error, DBUS_ERROR_FAILED,
00340 "Failed to drop capabilities: %s\n",
00341 _dbus_strerror (errno));
00342 cap_free (tmp_caps);
00343 goto fail;
00344 }
00345 cap_free (tmp_caps);
00346 }
00347 #endif
00348
00349
00350
00351
00352
00353
00354
00355
00356 if (setgroups (0, NULL) < 0)
00357 _dbus_warn ("Failed to drop supplementary groups: %s\n",
00358 _dbus_strerror (errno));
00359
00360
00361
00362
00363 if (setgid (gid) < 0)
00364 {
00365 dbus_set_error (error, _dbus_error_from_errno (errno),
00366 "Failed to set GID to %lu: %s", gid,
00367 _dbus_strerror (errno));
00368 goto fail;
00369 }
00370
00371 if (setuid (uid) < 0)
00372 {
00373 dbus_set_error (error, _dbus_error_from_errno (errno),
00374 "Failed to set UID to %lu: %s", uid,
00375 _dbus_strerror (errno));
00376 goto fail;
00377 }
00378
00379 #ifdef HAVE_LIBAUDIT
00380 if (!we_were_root)
00381 {
00382 if (cap_set_proc (new_caps))
00383 {
00384 dbus_set_error (error, DBUS_ERROR_FAILED,
00385 "Failed to drop capabilities: %s\n",
00386 _dbus_strerror (errno));
00387 goto fail;
00388 }
00389 cap_free (new_caps);
00390
00391
00392 if (prctl (PR_SET_KEEPCAPS, 0, 0, 0, 0) == -1)
00393 {
00394 dbus_set_error (error, _dbus_error_from_errno (errno),
00395 "Failed to unset keep-capabilities: %s\n",
00396 _dbus_strerror (errno));
00397 return FALSE;
00398 }
00399 }
00400 #endif
00401
00402 return TRUE;
00403
00404 fail:
00405 #ifdef HAVE_LIBAUDIT
00406 if (!we_were_root)
00407 {
00408
00409 prctl (PR_SET_KEEPCAPS, 0, 0, 0, 0);
00410 cap_free (new_caps);
00411 }
00412 #endif
00413
00414 return FALSE;
00415 }
00416
00422 void
00423 _dbus_set_signal_handler (int sig,
00424 DBusSignalHandler handler)
00425 {
00426 struct sigaction act;
00427 sigset_t empty_mask;
00428
00429 sigemptyset (&empty_mask);
00430 act.sa_handler = handler;
00431 act.sa_mask = empty_mask;
00432 act.sa_flags = 0;
00433 sigaction (sig, &act, NULL);
00434 }
00435
00436
00444 dbus_bool_t
00445 _dbus_delete_directory (const DBusString *filename,
00446 DBusError *error)
00447 {
00448 const char *filename_c;
00449
00450 _DBUS_ASSERT_ERROR_IS_CLEAR (error);
00451
00452 filename_c = _dbus_string_get_const_data (filename);
00453
00454 if (rmdir (filename_c) != 0)
00455 {
00456 dbus_set_error (error, DBUS_ERROR_FAILED,
00457 "Failed to remove directory %s: %s\n",
00458 filename_c, _dbus_strerror (errno));
00459 return FALSE;
00460 }
00461
00462 return TRUE;
00463 }
00464
00470 dbus_bool_t
00471 _dbus_file_exists (const char *file)
00472 {
00473 return (access (file, F_OK) == 0);
00474 }
00475
00482 dbus_bool_t
00483 _dbus_user_at_console (const char *username,
00484 DBusError *error)
00485 {
00486
00487 DBusString f;
00488 dbus_bool_t result;
00489 glob_t gl;
00490
00491 result = FALSE;
00492 if (!_dbus_string_init (&f))
00493 {
00494 _DBUS_SET_OOM (error);
00495 return FALSE;
00496 }
00497
00498 if (!_dbus_string_append (&f, DBUS_CONSOLE_AUTH_DIR))
00499 {
00500 _DBUS_SET_OOM (error);
00501 goto out;
00502 }
00503
00504
00505 if (!_dbus_string_append (&f, username))
00506 {
00507 _DBUS_SET_OOM (error);
00508 goto out;
00509 }
00510
00511
00512 if (!_dbus_string_append (&f, ":*"))
00513 {
00514 _DBUS_SET_OOM (error);
00515 goto out;
00516 }
00517
00518 if (glob (_dbus_string_get_const_data (&f), 0, NULL, &gl))
00519 goto out;
00520
00521 result = gl.gl_pathc > 0;
00522 globfree (&gl);
00523
00524 out:
00525 _dbus_string_free (&f);
00526
00527 return result;
00528 }
00529
00530
00537 dbus_bool_t
00538 _dbus_path_is_absolute (const DBusString *filename)
00539 {
00540 if (_dbus_string_get_length (filename) > 0)
00541 return _dbus_string_get_byte (filename, 0) == '/';
00542 else
00543 return FALSE;
00544 }
00545
00554 dbus_bool_t
00555 _dbus_stat (const DBusString *filename,
00556 DBusStat *statbuf,
00557 DBusError *error)
00558 {
00559 const char *filename_c;
00560 struct stat sb;
00561
00562 _DBUS_ASSERT_ERROR_IS_CLEAR (error);
00563
00564 filename_c = _dbus_string_get_const_data (filename);
00565
00566 if (stat (filename_c, &sb) < 0)
00567 {
00568 dbus_set_error (error, _dbus_error_from_errno (errno),
00569 "%s", _dbus_strerror (errno));
00570 return FALSE;
00571 }
00572
00573 statbuf->mode = sb.st_mode;
00574 statbuf->nlink = sb.st_nlink;
00575 statbuf->uid = sb.st_uid;
00576 statbuf->gid = sb.st_gid;
00577 statbuf->size = sb.st_size;
00578 statbuf->atime = sb.st_atime;
00579 statbuf->mtime = sb.st_mtime;
00580 statbuf->ctime = sb.st_ctime;
00581
00582 return TRUE;
00583 }
00584
00585
00589 struct DBusDirIter
00590 {
00591 DIR *d;
00593 };
00594
00602 DBusDirIter*
00603 _dbus_directory_open (const DBusString *filename,
00604 DBusError *error)
00605 {
00606 DIR *d;
00607 DBusDirIter *iter;
00608 const char *filename_c;
00609
00610 _DBUS_ASSERT_ERROR_IS_CLEAR (error);
00611
00612 filename_c = _dbus_string_get_const_data (filename);
00613
00614 d = opendir (filename_c);
00615 if (d == NULL)
00616 {
00617 dbus_set_error (error, _dbus_error_from_errno (errno),
00618 "Failed to read directory \"%s\": %s",
00619 filename_c,
00620 _dbus_strerror (errno));
00621 return NULL;
00622 }
00623 iter = dbus_new0 (DBusDirIter, 1);
00624 if (iter == NULL)
00625 {
00626 closedir (d);
00627 dbus_set_error (error, DBUS_ERROR_NO_MEMORY,
00628 "Could not allocate memory for directory iterator");
00629 return NULL;
00630 }
00631
00632 iter->d = d;
00633
00634 return iter;
00635 }
00636
00637
00638
00639
00640
00641
00642
00643
00644
00645 static dbus_bool_t
00646 dirent_buf_size(DIR * dirp, size_t *size)
00647 {
00648 long name_max;
00649 # if defined(HAVE_FPATHCONF) && defined(_PC_NAME_MAX)
00650 # if defined(HAVE_DIRFD)
00651 name_max = fpathconf(dirfd(dirp), _PC_NAME_MAX);
00652 # elif defined(HAVE_DDFD)
00653 name_max = fpathconf(dirp->dd_fd, _PC_NAME_MAX);
00654 # else
00655 name_max = fpathconf(dirp->__dd_fd, _PC_NAME_MAX);
00656 # endif
00657 if (name_max == -1)
00658 # if defined(NAME_MAX)
00659 name_max = NAME_MAX;
00660 # else
00661 return FALSE;
00662 # endif
00663 # elif defined(MAXNAMELEN)
00664 name_max = MAXNAMELEN;
00665 # else
00666 # if defined(NAME_MAX)
00667 name_max = NAME_MAX;
00668 # else
00669 # error "buffer size for readdir_r cannot be determined"
00670 # endif
00671 # endif
00672 if (size)
00673 *size = (size_t)offsetof(struct dirent, d_name) + name_max + 1;
00674 else
00675 return FALSE;
00676
00677 return TRUE;
00678 }
00679
00690 dbus_bool_t
00691 _dbus_directory_get_next_file (DBusDirIter *iter,
00692 DBusString *filename,
00693 DBusError *error)
00694 {
00695 struct dirent *d, *ent;
00696 size_t buf_size;
00697 int err;
00698
00699 _DBUS_ASSERT_ERROR_IS_CLEAR (error);
00700
00701 if (!dirent_buf_size (iter->d, &buf_size))
00702 {
00703 dbus_set_error (error, DBUS_ERROR_FAILED,
00704 "Can't calculate buffer size when reading directory");
00705 return FALSE;
00706 }
00707
00708 d = (struct dirent *)dbus_malloc (buf_size);
00709 if (!d)
00710 {
00711 dbus_set_error (error, DBUS_ERROR_NO_MEMORY,
00712 "No memory to read directory entry");
00713 return FALSE;
00714 }
00715
00716 again:
00717 err = readdir_r (iter->d, d, &ent);
00718 if (err || !ent)
00719 {
00720 if (err != 0)
00721 dbus_set_error (error,
00722 _dbus_error_from_errno (err),
00723 "%s", _dbus_strerror (err));
00724
00725 dbus_free (d);
00726 return FALSE;
00727 }
00728 else if (ent->d_name[0] == '.' &&
00729 (ent->d_name[1] == '\0' ||
00730 (ent->d_name[1] == '.' && ent->d_name[2] == '\0')))
00731 goto again;
00732 else
00733 {
00734 _dbus_string_set_length (filename, 0);
00735 if (!_dbus_string_append (filename, ent->d_name))
00736 {
00737 dbus_set_error (error, DBUS_ERROR_NO_MEMORY,
00738 "No memory to read directory entry");
00739 dbus_free (d);
00740 return FALSE;
00741 }
00742 else
00743 {
00744 dbus_free (d);
00745 return TRUE;
00746 }
00747 }
00748 }
00749
00753 void
00754 _dbus_directory_close (DBusDirIter *iter)
00755 {
00756 closedir (iter->d);
00757 dbus_free (iter);
00758 }
00759
00760 static dbus_bool_t
00761 fill_user_info_from_group (struct group *g,
00762 DBusGroupInfo *info,
00763 DBusError *error)
00764 {
00765 _dbus_assert (g->gr_name != NULL);
00766
00767 info->gid = g->gr_gid;
00768 info->groupname = _dbus_strdup (g->gr_name);
00769
00770
00771
00772 if (info->groupname == NULL)
00773 {
00774 dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
00775 return FALSE;
00776 }
00777
00778 return TRUE;
00779 }
00780
00781 static dbus_bool_t
00782 fill_group_info (DBusGroupInfo *info,
00783 dbus_gid_t gid,
00784 const DBusString *groupname,
00785 DBusError *error)
00786 {
00787 const char *group_c_str;
00788
00789 _dbus_assert (groupname != NULL || gid != DBUS_GID_UNSET);
00790 _dbus_assert (groupname == NULL || gid == DBUS_GID_UNSET);
00791
00792 if (groupname)
00793 group_c_str = _dbus_string_get_const_data (groupname);
00794 else
00795 group_c_str = NULL;
00796
00797
00798
00799
00800
00801
00802 #if defined (HAVE_POSIX_GETPWNAM_R) || defined (HAVE_NONPOSIX_GETPWNAM_R)
00803 {
00804 struct group *g;
00805 int result;
00806 char buf[1024];
00807 struct group g_str;
00808
00809 g = NULL;
00810 #ifdef HAVE_POSIX_GETPWNAM_R
00811
00812 if (group_c_str)
00813 result = getgrnam_r (group_c_str, &g_str, buf, sizeof (buf),
00814 &g);
00815 else
00816 result = getgrgid_r (gid, &g_str, buf, sizeof (buf),
00817 &g);
00818 #else
00819 g = getgrnam_r (group_c_str, &g_str, buf, sizeof (buf));
00820 result = 0;
00821 #endif
00822 if (result == 0 && g == &g_str)
00823 {
00824 return fill_user_info_from_group (g, info, error);
00825 }
00826 else
00827 {
00828 dbus_set_error (error, _dbus_error_from_errno (errno),
00829 "Group %s unknown or failed to look it up\n",
00830 group_c_str ? group_c_str : "???");
00831 return FALSE;
00832 }
00833 }
00834 #else
00835 {
00836
00837 struct group *g;
00838
00839 g = getgrnam (group_c_str);
00840
00841 if (g != NULL)
00842 {
00843 return fill_user_info_from_group (g, info, error);
00844 }
00845 else
00846 {
00847 dbus_set_error (error, _dbus_error_from_errno (errno),
00848 "Group %s unknown or failed to look it up\n",
00849 group_c_str ? group_c_str : "???");
00850 return FALSE;
00851 }
00852 }
00853 #endif
00854 }
00855
00865 dbus_bool_t
00866 _dbus_group_info_fill (DBusGroupInfo *info,
00867 const DBusString *groupname,
00868 DBusError *error)
00869 {
00870 return fill_group_info (info, DBUS_GID_UNSET,
00871 groupname, error);
00872
00873 }
00874
00884 dbus_bool_t
00885 _dbus_group_info_fill_gid (DBusGroupInfo *info,
00886 dbus_gid_t gid,
00887 DBusError *error)
00888 {
00889 return fill_group_info (info, gid, NULL, error);
00890 }
00891
00900 dbus_bool_t
00901 _dbus_parse_unix_user_from_config (const DBusString *username,
00902 dbus_uid_t *uid_p)
00903 {
00904 return _dbus_get_user_id (username, uid_p);
00905
00906 }
00907
00916 dbus_bool_t
00917 _dbus_parse_unix_group_from_config (const DBusString *groupname,
00918 dbus_gid_t *gid_p)
00919 {
00920 return _dbus_get_group_id (groupname, gid_p);
00921 }
00922
00933 dbus_bool_t
00934 _dbus_unix_groups_from_uid (dbus_uid_t uid,
00935 dbus_gid_t **group_ids,
00936 int *n_group_ids)
00937 {
00938 return _dbus_groups_from_uid (uid, group_ids, n_group_ids);
00939 }
00940
00950 dbus_bool_t
00951 _dbus_unix_user_is_at_console (dbus_uid_t uid,
00952 DBusError *error)
00953 {
00954 return _dbus_is_console_user (uid, error);
00955
00956 }
00957
00965 dbus_bool_t
00966 _dbus_unix_user_is_process_owner (dbus_uid_t uid)
00967 {
00968 return uid == _dbus_getuid ();
00969 }
00970
00978 dbus_bool_t
00979 _dbus_windows_user_is_process_owner (const char *windows_sid)
00980 {
00981 return FALSE;
00982 }
00983
00985
00997 dbus_bool_t
00998 _dbus_string_get_dirname (const DBusString *filename,
00999 DBusString *dirname)
01000 {
01001 int sep;
01002
01003 _dbus_assert (filename != dirname);
01004 _dbus_assert (filename != NULL);
01005 _dbus_assert (dirname != NULL);
01006
01007
01008 sep = _dbus_string_get_length (filename);
01009 if (sep == 0)
01010 return _dbus_string_append (dirname, ".");
01011
01012 while (sep > 0 && _dbus_string_get_byte (filename, sep - 1) == '/')
01013 --sep;
01014
01015 _dbus_assert (sep >= 0);
01016
01017 if (sep == 0)
01018 return _dbus_string_append (dirname, "/");
01019
01020
01021 _dbus_string_find_byte_backward (filename, sep, '/', &sep);
01022 if (sep < 0)
01023 return _dbus_string_append (dirname, ".");
01024
01025
01026 while (sep > 0 && _dbus_string_get_byte (filename, sep - 1) == '/')
01027 --sep;
01028
01029 _dbus_assert (sep >= 0);
01030
01031 if (sep == 0 &&
01032 _dbus_string_get_byte (filename, 0) == '/')
01033 return _dbus_string_append (dirname, "/");
01034 else
01035 return _dbus_string_copy_len (filename, 0, sep - 0,
01036 dirname, _dbus_string_get_length (dirname));
01037 }
01039