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 <syslog.h>
00047 #include <syslog.h>
00048 #ifdef HAVE_LIBAUDIT
00049 #include <cap-ng.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
00076 dbus_bool_t
00077 _dbus_become_daemon (const DBusString *pidfile,
00078 DBusPipe *print_pid_pipe,
00079 DBusError *error,
00080 dbus_bool_t keep_umask)
00081 {
00082 const char *s;
00083 pid_t child_pid;
00084 int dev_null_fd;
00085
00086 _dbus_verbose ("Becoming a daemon...\n");
00087
00088 _dbus_verbose ("chdir to /\n");
00089 if (chdir ("/") < 0)
00090 {
00091 dbus_set_error (error, DBUS_ERROR_FAILED,
00092 "Could not chdir() to root directory");
00093 return FALSE;
00094 }
00095
00096 _dbus_verbose ("forking...\n");
00097 switch ((child_pid = fork ()))
00098 {
00099 case -1:
00100 _dbus_verbose ("fork failed\n");
00101 dbus_set_error (error, _dbus_error_from_errno (errno),
00102 "Failed to fork daemon: %s", _dbus_strerror (errno));
00103 return FALSE;
00104 break;
00105
00106 case 0:
00107 _dbus_verbose ("in child, closing std file descriptors\n");
00108
00109
00110
00111
00112
00113
00114 dev_null_fd = open ("/dev/null", O_RDWR);
00115 if (dev_null_fd >= 0)
00116 {
00117 dup2 (dev_null_fd, 0);
00118 dup2 (dev_null_fd, 1);
00119
00120 s = _dbus_getenv ("DBUS_DEBUG_OUTPUT");
00121 if (s == NULL || *s == '\0')
00122 dup2 (dev_null_fd, 2);
00123 else
00124 _dbus_verbose ("keeping stderr open due to DBUS_DEBUG_OUTPUT\n");
00125 }
00126
00127 if (!keep_umask)
00128 {
00129
00130 _dbus_verbose ("setting umask\n");
00131 umask (022);
00132 }
00133
00134 _dbus_verbose ("calling setsid()\n");
00135 if (setsid () == -1)
00136 _dbus_assert_not_reached ("setsid() failed");
00137
00138 break;
00139
00140 default:
00141 if (!_dbus_write_pid_to_file_and_pipe (pidfile, print_pid_pipe,
00142 child_pid, error))
00143 {
00144 _dbus_verbose ("pid file or pipe write failed: %s\n",
00145 error->message);
00146 kill (child_pid, SIGTERM);
00147 return FALSE;
00148 }
00149
00150 _dbus_verbose ("parent exiting\n");
00151 _exit (0);
00152 break;
00153 }
00154
00155 return TRUE;
00156 }
00157
00158
00167 static dbus_bool_t
00168 _dbus_write_pid_file (const DBusString *filename,
00169 unsigned long pid,
00170 DBusError *error)
00171 {
00172 const char *cfilename;
00173 int fd;
00174 FILE *f;
00175
00176 cfilename = _dbus_string_get_const_data (filename);
00177
00178 fd = open (cfilename, O_WRONLY|O_CREAT|O_EXCL|O_BINARY, 0644);
00179
00180 if (fd < 0)
00181 {
00182 dbus_set_error (error, _dbus_error_from_errno (errno),
00183 "Failed to open \"%s\": %s", cfilename,
00184 _dbus_strerror (errno));
00185 return FALSE;
00186 }
00187
00188 if ((f = fdopen (fd, "w")) == NULL)
00189 {
00190 dbus_set_error (error, _dbus_error_from_errno (errno),
00191 "Failed to fdopen fd %d: %s", fd, _dbus_strerror (errno));
00192 _dbus_close (fd, NULL);
00193 return FALSE;
00194 }
00195
00196 if (fprintf (f, "%lu\n", pid) < 0)
00197 {
00198 dbus_set_error (error, _dbus_error_from_errno (errno),
00199 "Failed to write to \"%s\": %s", cfilename,
00200 _dbus_strerror (errno));
00201
00202 fclose (f);
00203 return FALSE;
00204 }
00205
00206 if (fclose (f) == EOF)
00207 {
00208 dbus_set_error (error, _dbus_error_from_errno (errno),
00209 "Failed to close \"%s\": %s", cfilename,
00210 _dbus_strerror (errno));
00211 return FALSE;
00212 }
00213
00214 return TRUE;
00215 }
00216
00228 dbus_bool_t
00229 _dbus_write_pid_to_file_and_pipe (const DBusString *pidfile,
00230 DBusPipe *print_pid_pipe,
00231 dbus_pid_t pid_to_write,
00232 DBusError *error)
00233 {
00234 if (pidfile)
00235 {
00236 _dbus_verbose ("writing pid file %s\n", _dbus_string_get_const_data (pidfile));
00237 if (!_dbus_write_pid_file (pidfile,
00238 pid_to_write,
00239 error))
00240 {
00241 _dbus_verbose ("pid file write failed\n");
00242 _DBUS_ASSERT_ERROR_IS_SET(error);
00243 return FALSE;
00244 }
00245 }
00246 else
00247 {
00248 _dbus_verbose ("No pid file requested\n");
00249 }
00250
00251 if (print_pid_pipe != NULL && _dbus_pipe_is_valid (print_pid_pipe))
00252 {
00253 DBusString pid;
00254 int bytes;
00255
00256 _dbus_verbose ("writing our pid to pipe %d\n", print_pid_pipe->fd_or_handle);
00257
00258 if (!_dbus_string_init (&pid))
00259 {
00260 _DBUS_SET_OOM (error);
00261 return FALSE;
00262 }
00263
00264 if (!_dbus_string_append_int (&pid, pid_to_write) ||
00265 !_dbus_string_append (&pid, "\n"))
00266 {
00267 _dbus_string_free (&pid);
00268 _DBUS_SET_OOM (error);
00269 return FALSE;
00270 }
00271
00272 bytes = _dbus_string_get_length (&pid);
00273 if (_dbus_pipe_write (print_pid_pipe, &pid, 0, bytes, error) != bytes)
00274 {
00275
00276 if (error != NULL && !dbus_error_is_set(error))
00277 {
00278 dbus_set_error (error, DBUS_ERROR_FAILED,
00279 "Printing message bus PID: did not write enough bytes\n");
00280 }
00281 _dbus_string_free (&pid);
00282 return FALSE;
00283 }
00284
00285 _dbus_string_free (&pid);
00286 }
00287 else
00288 {
00289 _dbus_verbose ("No pid pipe to write to\n");
00290 }
00291
00292 return TRUE;
00293 }
00294
00301 dbus_bool_t
00302 _dbus_verify_daemon_user (const char *user)
00303 {
00304 DBusString u;
00305
00306 _dbus_string_init_const (&u, user);
00307
00308 return _dbus_get_user_id_and_primary_group (&u, NULL, NULL);
00309 }
00310
00318 dbus_bool_t
00319 _dbus_change_to_daemon_user (const char *user,
00320 DBusError *error)
00321 {
00322 dbus_uid_t uid;
00323 dbus_gid_t gid;
00324 DBusString u;
00325
00326 _dbus_string_init_const (&u, user);
00327
00328 if (!_dbus_get_user_id_and_primary_group (&u, &uid, &gid))
00329 {
00330 dbus_set_error (error, DBUS_ERROR_FAILED,
00331 "User '%s' does not appear to exist?",
00332 user);
00333 return FALSE;
00334 }
00335
00336 #ifdef HAVE_LIBAUDIT
00337
00338 if (_dbus_geteuid () == 0)
00339 {
00340 int rc;
00341
00342 capng_clear(CAPNG_SELECT_BOTH);
00343 capng_update(CAPNG_ADD, CAPNG_EFFECTIVE|CAPNG_PERMITTED,
00344 CAP_AUDIT_WRITE);
00345 rc = capng_change_id(uid, gid, 0);
00346 if (rc)
00347 {
00348 switch (rc) {
00349 default:
00350 dbus_set_error (error, DBUS_ERROR_FAILED,
00351 "Failed to drop capabilities: %s\n",
00352 _dbus_strerror (errno));
00353 break;
00354 case -4:
00355 dbus_set_error (error, _dbus_error_from_errno (errno),
00356 "Failed to set GID to %lu: %s", gid,
00357 _dbus_strerror (errno));
00358 break;
00359 case -5:
00360 _dbus_warn ("Failed to drop supplementary groups: %s\n",
00361 _dbus_strerror (errno));
00362 break;
00363 case -6:
00364 dbus_set_error (error, _dbus_error_from_errno (errno),
00365 "Failed to set UID to %lu: %s", uid,
00366 _dbus_strerror (errno));
00367 break;
00368 case -7:
00369 dbus_set_error (error, _dbus_error_from_errno (errno),
00370 "Failed to unset keep-capabilities: %s\n",
00371 _dbus_strerror (errno));
00372 break;
00373 }
00374 return FALSE;
00375 }
00376 }
00377 #endif
00378
00379 return TRUE;
00380 }
00381
00382 void
00383 _dbus_init_system_log (void)
00384 {
00385 openlog ("dbus", LOG_PID, LOG_DAEMON);
00386 }
00387
00395 void
00396 _dbus_log_info (const char *msg, va_list args)
00397 {
00398 vsyslog (LOG_DAEMON|LOG_NOTICE, msg, args);
00399 }
00400
00408 void
00409 _dbus_log_security (const char *msg, va_list args)
00410 {
00411 vsyslog (LOG_AUTH|LOG_NOTICE, msg, args);
00412 }
00413
00419 void
00420 _dbus_set_signal_handler (int sig,
00421 DBusSignalHandler handler)
00422 {
00423 struct sigaction act;
00424 sigset_t empty_mask;
00425
00426 sigemptyset (&empty_mask);
00427 act.sa_handler = handler;
00428 act.sa_mask = empty_mask;
00429 act.sa_flags = 0;
00430 sigaction (sig, &act, NULL);
00431 }
00432
00433
00441 dbus_bool_t
00442 _dbus_delete_directory (const DBusString *filename,
00443 DBusError *error)
00444 {
00445 const char *filename_c;
00446
00447 _DBUS_ASSERT_ERROR_IS_CLEAR (error);
00448
00449 filename_c = _dbus_string_get_const_data (filename);
00450
00451 if (rmdir (filename_c) != 0)
00452 {
00453 dbus_set_error (error, DBUS_ERROR_FAILED,
00454 "Failed to remove directory %s: %s\n",
00455 filename_c, _dbus_strerror (errno));
00456 return FALSE;
00457 }
00458
00459 return TRUE;
00460 }
00461
00467 dbus_bool_t
00468 _dbus_file_exists (const char *file)
00469 {
00470 return (access (file, F_OK) == 0);
00471 }
00472
00479 dbus_bool_t
00480 _dbus_user_at_console (const char *username,
00481 DBusError *error)
00482 {
00483
00484 DBusString f;
00485 dbus_bool_t result;
00486
00487 result = FALSE;
00488 if (!_dbus_string_init (&f))
00489 {
00490 _DBUS_SET_OOM (error);
00491 return FALSE;
00492 }
00493
00494 if (!_dbus_string_append (&f, DBUS_CONSOLE_AUTH_DIR))
00495 {
00496 _DBUS_SET_OOM (error);
00497 goto out;
00498 }
00499
00500
00501 if (!_dbus_string_append (&f, username))
00502 {
00503 _DBUS_SET_OOM (error);
00504 goto out;
00505 }
00506
00507 result = _dbus_file_exists (_dbus_string_get_const_data (&f));
00508
00509 out:
00510 _dbus_string_free (&f);
00511
00512 return result;
00513 }
00514
00515
00522 dbus_bool_t
00523 _dbus_path_is_absolute (const DBusString *filename)
00524 {
00525 if (_dbus_string_get_length (filename) > 0)
00526 return _dbus_string_get_byte (filename, 0) == '/';
00527 else
00528 return FALSE;
00529 }
00530
00539 dbus_bool_t
00540 _dbus_stat (const DBusString *filename,
00541 DBusStat *statbuf,
00542 DBusError *error)
00543 {
00544 const char *filename_c;
00545 struct stat sb;
00546
00547 _DBUS_ASSERT_ERROR_IS_CLEAR (error);
00548
00549 filename_c = _dbus_string_get_const_data (filename);
00550
00551 if (stat (filename_c, &sb) < 0)
00552 {
00553 dbus_set_error (error, _dbus_error_from_errno (errno),
00554 "%s", _dbus_strerror (errno));
00555 return FALSE;
00556 }
00557
00558 statbuf->mode = sb.st_mode;
00559 statbuf->nlink = sb.st_nlink;
00560 statbuf->uid = sb.st_uid;
00561 statbuf->gid = sb.st_gid;
00562 statbuf->size = sb.st_size;
00563 statbuf->atime = sb.st_atime;
00564 statbuf->mtime = sb.st_mtime;
00565 statbuf->ctime = sb.st_ctime;
00566
00567 return TRUE;
00568 }
00569
00570
00574 struct DBusDirIter
00575 {
00576 DIR *d;
00578 };
00579
00587 DBusDirIter*
00588 _dbus_directory_open (const DBusString *filename,
00589 DBusError *error)
00590 {
00591 DIR *d;
00592 DBusDirIter *iter;
00593 const char *filename_c;
00594
00595 _DBUS_ASSERT_ERROR_IS_CLEAR (error);
00596
00597 filename_c = _dbus_string_get_const_data (filename);
00598
00599 d = opendir (filename_c);
00600 if (d == NULL)
00601 {
00602 dbus_set_error (error, _dbus_error_from_errno (errno),
00603 "Failed to read directory \"%s\": %s",
00604 filename_c,
00605 _dbus_strerror (errno));
00606 return NULL;
00607 }
00608 iter = dbus_new0 (DBusDirIter, 1);
00609 if (iter == NULL)
00610 {
00611 closedir (d);
00612 dbus_set_error (error, DBUS_ERROR_NO_MEMORY,
00613 "Could not allocate memory for directory iterator");
00614 return NULL;
00615 }
00616
00617 iter->d = d;
00618
00619 return iter;
00620 }
00621
00622
00623
00624
00625
00626
00627
00628
00629
00630 static dbus_bool_t
00631 dirent_buf_size(DIR * dirp, size_t *size)
00632 {
00633 long name_max;
00634 # if defined(HAVE_FPATHCONF) && defined(_PC_NAME_MAX)
00635 # if defined(HAVE_DIRFD)
00636 name_max = fpathconf(dirfd(dirp), _PC_NAME_MAX);
00637 # elif defined(HAVE_DDFD)
00638 name_max = fpathconf(dirp->dd_fd, _PC_NAME_MAX);
00639 # else
00640 name_max = fpathconf(dirp->__dd_fd, _PC_NAME_MAX);
00641 # endif
00642 if (name_max == -1)
00643 # if defined(NAME_MAX)
00644 name_max = NAME_MAX;
00645 # else
00646 return FALSE;
00647 # endif
00648 # elif defined(MAXNAMELEN)
00649 name_max = MAXNAMELEN;
00650 # else
00651 # if defined(NAME_MAX)
00652 name_max = NAME_MAX;
00653 # else
00654 # error "buffer size for readdir_r cannot be determined"
00655 # endif
00656 # endif
00657 if (size)
00658 *size = (size_t)offsetof(struct dirent, d_name) + name_max + 1;
00659 else
00660 return FALSE;
00661
00662 return TRUE;
00663 }
00664
00675 dbus_bool_t
00676 _dbus_directory_get_next_file (DBusDirIter *iter,
00677 DBusString *filename,
00678 DBusError *error)
00679 {
00680 struct dirent *d, *ent;
00681 size_t buf_size;
00682 int err;
00683
00684 _DBUS_ASSERT_ERROR_IS_CLEAR (error);
00685
00686 if (!dirent_buf_size (iter->d, &buf_size))
00687 {
00688 dbus_set_error (error, DBUS_ERROR_FAILED,
00689 "Can't calculate buffer size when reading directory");
00690 return FALSE;
00691 }
00692
00693 d = (struct dirent *)dbus_malloc (buf_size);
00694 if (!d)
00695 {
00696 dbus_set_error (error, DBUS_ERROR_NO_MEMORY,
00697 "No memory to read directory entry");
00698 return FALSE;
00699 }
00700
00701 again:
00702 err = readdir_r (iter->d, d, &ent);
00703 if (err || !ent)
00704 {
00705 if (err != 0)
00706 dbus_set_error (error,
00707 _dbus_error_from_errno (err),
00708 "%s", _dbus_strerror (err));
00709
00710 dbus_free (d);
00711 return FALSE;
00712 }
00713 else if (ent->d_name[0] == '.' &&
00714 (ent->d_name[1] == '\0' ||
00715 (ent->d_name[1] == '.' && ent->d_name[2] == '\0')))
00716 goto again;
00717 else
00718 {
00719 _dbus_string_set_length (filename, 0);
00720 if (!_dbus_string_append (filename, ent->d_name))
00721 {
00722 dbus_set_error (error, DBUS_ERROR_NO_MEMORY,
00723 "No memory to read directory entry");
00724 dbus_free (d);
00725 return FALSE;
00726 }
00727 else
00728 {
00729 dbus_free (d);
00730 return TRUE;
00731 }
00732 }
00733 }
00734
00738 void
00739 _dbus_directory_close (DBusDirIter *iter)
00740 {
00741 closedir (iter->d);
00742 dbus_free (iter);
00743 }
00744
00745 static dbus_bool_t
00746 fill_user_info_from_group (struct group *g,
00747 DBusGroupInfo *info,
00748 DBusError *error)
00749 {
00750 _dbus_assert (g->gr_name != NULL);
00751
00752 info->gid = g->gr_gid;
00753 info->groupname = _dbus_strdup (g->gr_name);
00754
00755
00756
00757 if (info->groupname == NULL)
00758 {
00759 dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
00760 return FALSE;
00761 }
00762
00763 return TRUE;
00764 }
00765
00766 static dbus_bool_t
00767 fill_group_info (DBusGroupInfo *info,
00768 dbus_gid_t gid,
00769 const DBusString *groupname,
00770 DBusError *error)
00771 {
00772 const char *group_c_str;
00773
00774 _dbus_assert (groupname != NULL || gid != DBUS_GID_UNSET);
00775 _dbus_assert (groupname == NULL || gid == DBUS_GID_UNSET);
00776
00777 if (groupname)
00778 group_c_str = _dbus_string_get_const_data (groupname);
00779 else
00780 group_c_str = NULL;
00781
00782
00783
00784
00785
00786
00787 #if defined (HAVE_POSIX_GETPWNAM_R) || defined (HAVE_NONPOSIX_GETPWNAM_R)
00788 {
00789 struct group *g;
00790 int result;
00791 size_t buflen;
00792 char *buf;
00793 struct group g_str;
00794 dbus_bool_t b;
00795
00796
00797 buflen = sysconf (_SC_GETGR_R_SIZE_MAX);
00798
00799
00800
00801
00802
00803 if ((long) buflen <= 0)
00804 buflen = 1024;
00805
00806 result = -1;
00807 while (1)
00808 {
00809 buf = dbus_malloc (buflen);
00810 if (buf == NULL)
00811 {
00812 dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
00813 return FALSE;
00814 }
00815
00816 g = NULL;
00817 #ifdef HAVE_POSIX_GETPWNAM_R
00818 if (group_c_str)
00819 result = getgrnam_r (group_c_str, &g_str, buf, buflen,
00820 &g);
00821 else
00822 result = getgrgid_r (gid, &g_str, buf, buflen,
00823 &g);
00824 #else
00825 g = getgrnam_r (group_c_str, &g_str, buf, buflen);
00826 result = 0;
00827 #endif
00828
00829
00830
00831 if (result == ERANGE && buflen < 512 * 1024)
00832 {
00833 dbus_free (buf);
00834 buflen *= 2;
00835 }
00836 else
00837 {
00838 break;
00839 }
00840 }
00841
00842 if (result == 0 && g == &g_str)
00843 {
00844 b = fill_user_info_from_group (g, info, error);
00845 dbus_free (buf);
00846 return b;
00847 }
00848 else
00849 {
00850 dbus_set_error (error, _dbus_error_from_errno (errno),
00851 "Group %s unknown or failed to look it up\n",
00852 group_c_str ? group_c_str : "???");
00853 dbus_free (buf);
00854 return FALSE;
00855 }
00856 }
00857 #else
00858 {
00859
00860 struct group *g;
00861
00862 g = getgrnam (group_c_str);
00863
00864 if (g != NULL)
00865 {
00866 return fill_user_info_from_group (g, info, error);
00867 }
00868 else
00869 {
00870 dbus_set_error (error, _dbus_error_from_errno (errno),
00871 "Group %s unknown or failed to look it up\n",
00872 group_c_str ? group_c_str : "???");
00873 return FALSE;
00874 }
00875 }
00876 #endif
00877 }
00878
00888 dbus_bool_t
00889 _dbus_group_info_fill (DBusGroupInfo *info,
00890 const DBusString *groupname,
00891 DBusError *error)
00892 {
00893 return fill_group_info (info, DBUS_GID_UNSET,
00894 groupname, error);
00895
00896 }
00897
00907 dbus_bool_t
00908 _dbus_group_info_fill_gid (DBusGroupInfo *info,
00909 dbus_gid_t gid,
00910 DBusError *error)
00911 {
00912 return fill_group_info (info, gid, NULL, error);
00913 }
00914
00923 dbus_bool_t
00924 _dbus_parse_unix_user_from_config (const DBusString *username,
00925 dbus_uid_t *uid_p)
00926 {
00927 return _dbus_get_user_id (username, uid_p);
00928
00929 }
00930
00939 dbus_bool_t
00940 _dbus_parse_unix_group_from_config (const DBusString *groupname,
00941 dbus_gid_t *gid_p)
00942 {
00943 return _dbus_get_group_id (groupname, gid_p);
00944 }
00945
00956 dbus_bool_t
00957 _dbus_unix_groups_from_uid (dbus_uid_t uid,
00958 dbus_gid_t **group_ids,
00959 int *n_group_ids)
00960 {
00961 return _dbus_groups_from_uid (uid, group_ids, n_group_ids);
00962 }
00963
00973 dbus_bool_t
00974 _dbus_unix_user_is_at_console (dbus_uid_t uid,
00975 DBusError *error)
00976 {
00977 return _dbus_is_console_user (uid, error);
00978
00979 }
00980
00988 dbus_bool_t
00989 _dbus_unix_user_is_process_owner (dbus_uid_t uid)
00990 {
00991 return uid == _dbus_geteuid ();
00992 }
00993
01001 dbus_bool_t
01002 _dbus_windows_user_is_process_owner (const char *windows_sid)
01003 {
01004 return FALSE;
01005 }
01006
01008
01020 dbus_bool_t
01021 _dbus_string_get_dirname (const DBusString *filename,
01022 DBusString *dirname)
01023 {
01024 int sep;
01025
01026 _dbus_assert (filename != dirname);
01027 _dbus_assert (filename != NULL);
01028 _dbus_assert (dirname != NULL);
01029
01030
01031 sep = _dbus_string_get_length (filename);
01032 if (sep == 0)
01033 return _dbus_string_append (dirname, ".");
01034
01035 while (sep > 0 && _dbus_string_get_byte (filename, sep - 1) == '/')
01036 --sep;
01037
01038 _dbus_assert (sep >= 0);
01039
01040 if (sep == 0)
01041 return _dbus_string_append (dirname, "/");
01042
01043
01044 _dbus_string_find_byte_backward (filename, sep, '/', &sep);
01045 if (sep < 0)
01046 return _dbus_string_append (dirname, ".");
01047
01048
01049 while (sep > 0 && _dbus_string_get_byte (filename, sep - 1) == '/')
01050 --sep;
01051
01052 _dbus_assert (sep >= 0);
01053
01054 if (sep == 0 &&
01055 _dbus_string_get_byte (filename, 0) == '/')
01056 return _dbus_string_append (dirname, "/");
01057 else
01058 return _dbus_string_copy_len (filename, 0, sep - 0,
01059 dirname, _dbus_string_get_length (dirname));
01060 }
01062
01063 static void
01064 string_squash_nonprintable (DBusString *str)
01065 {
01066 char *buf;
01067 int i, len;
01068
01069 buf = _dbus_string_get_data (str);
01070 len = _dbus_string_get_length (str);
01071
01072 for (i = 0; i < len; i++)
01073 {
01074 unsigned char c = (unsigned char) buf[i];
01075 if (c == '\0')
01076 c = ' ';
01077 else if (c < 0x20 || c > 127)
01078 c = '?';
01079 }
01080 }
01081
01096 dbus_bool_t
01097 _dbus_command_for_pid (unsigned long pid,
01098 DBusString *str,
01099 int max_len,
01100 DBusError *error)
01101 {
01102
01103 DBusString path;
01104 DBusString cmdline;
01105 int fd;
01106
01107 if (!_dbus_string_init (&path))
01108 {
01109 _DBUS_SET_OOM (error);
01110 return FALSE;
01111 }
01112
01113 if (!_dbus_string_init (&cmdline))
01114 {
01115 _DBUS_SET_OOM (error);
01116 _dbus_string_free (&path);
01117 return FALSE;
01118 }
01119
01120 if (!_dbus_string_append_printf (&path, "/proc/%ld/cmdline", pid))
01121 goto oom;
01122
01123 fd = open (_dbus_string_get_const_data (&path), O_RDONLY);
01124 if (fd < 0)
01125 {
01126 dbus_set_error (error,
01127 _dbus_error_from_errno (errno),
01128 "Failed to open \"%s\": %s",
01129 _dbus_string_get_const_data (&path),
01130 _dbus_strerror (errno));
01131 goto fail;
01132 }
01133
01134 if (!_dbus_read (fd, &cmdline, max_len))
01135 {
01136 dbus_set_error (error,
01137 _dbus_error_from_errno (errno),
01138 "Failed to read from \"%s\": %s",
01139 _dbus_string_get_const_data (&path),
01140 _dbus_strerror (errno));
01141 goto fail;
01142 }
01143
01144 if (!_dbus_close (fd, error))
01145 goto fail;
01146
01147 string_squash_nonprintable (&cmdline);
01148
01149 if (!_dbus_string_copy (&cmdline, 0, str, _dbus_string_get_length (str)))
01150 goto oom;
01151
01152 _dbus_string_free (&cmdline);
01153 _dbus_string_free (&path);
01154 return TRUE;
01155 oom:
01156 _DBUS_SET_OOM (error);
01157 fail:
01158 _dbus_string_free (&cmdline);
01159 _dbus_string_free (&path);
01160 return FALSE;
01161 }