1 /* -*- mode: C; c-file-style: "gnu" -*- */
2 /* dbus-sysdeps-util.c Would be in dbus-sysdeps.c, but not used in libdbus
4 * Copyright (C) 2002, 2003, 2004, 2005 Red Hat, Inc.
5 * Copyright (C) 2003 CodeFactory AB
7 * Licensed under the Academic Free License version 2.1
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24 #include "dbus-sysdeps.h"
25 #include "dbus-internals.h"
26 #include "dbus-protocol.h"
27 #include "dbus-string.h"
28 #define DBUS_USERDB_INCLUDES_PRIVATE 1
29 #include "dbus-userdb.h"
30 #include "dbus-test.h"
32 #include <sys/types.h>
42 #include <sys/socket.h>
51 * @addtogroup DBusInternalsUtils
56 * Does the chdir, fork, setsid, etc. to become a daemon process.
58 * @param pidfile #NULL, or pidfile to create
59 * @param print_pid_fd file descriptor to print daemon's pid to, or -1 for none
60 * @param error return location for errors
61 * @returns #FALSE on failure
64 _dbus_become_daemon (const DBusString *pidfile,
72 _dbus_verbose ("Becoming a daemon...\n");
74 _dbus_verbose ("chdir to /\n");
77 dbus_set_error (error, DBUS_ERROR_FAILED,
78 "Could not chdir() to root directory");
82 _dbus_verbose ("forking...\n");
83 switch ((child_pid = fork ()))
86 _dbus_verbose ("fork failed\n");
87 dbus_set_error (error, _dbus_error_from_errno (errno),
88 "Failed to fork daemon: %s", _dbus_strerror (errno));
93 _dbus_verbose ("in child, closing std file descriptors\n");
95 /* silently ignore failures here, if someone
96 * doesn't have /dev/null we may as well try
100 dev_null_fd = open ("/dev/null", O_RDWR);
101 if (dev_null_fd >= 0)
103 dup2 (dev_null_fd, 0);
104 dup2 (dev_null_fd, 1);
106 s = _dbus_getenv ("DBUS_DEBUG_OUTPUT");
107 if (s == NULL || *s == '\0')
108 dup2 (dev_null_fd, 2);
110 _dbus_verbose ("keeping stderr open due to DBUS_DEBUG_OUTPUT\n");
113 /* Get a predictable umask */
114 _dbus_verbose ("setting umask\n");
121 _dbus_verbose ("parent writing pid file\n");
122 if (!_dbus_write_pid_file (pidfile,
126 _dbus_verbose ("pid file write failed, killing child\n");
127 kill (child_pid, SIGTERM);
132 /* Write PID if requested */
133 if (print_pid_fd >= 0)
138 if (!_dbus_string_init (&pid))
140 _DBUS_SET_OOM (error);
141 kill (child_pid, SIGTERM);
145 if (!_dbus_string_append_int (&pid, child_pid) ||
146 !_dbus_string_append (&pid, "\n"))
148 _dbus_string_free (&pid);
149 _DBUS_SET_OOM (error);
150 kill (child_pid, SIGTERM);
154 bytes = _dbus_string_get_length (&pid);
155 if (_dbus_write (print_pid_fd, &pid, 0, bytes) != bytes)
157 dbus_set_error (error, DBUS_ERROR_FAILED,
158 "Printing message bus PID: %s\n",
159 _dbus_strerror (errno));
160 _dbus_string_free (&pid);
161 kill (child_pid, SIGTERM);
165 _dbus_string_free (&pid);
167 _dbus_verbose ("parent exiting\n");
172 _dbus_verbose ("calling setsid()\n");
174 _dbus_assert_not_reached ("setsid() failed");
181 * Creates a file containing the process ID.
183 * @param filename the filename to write to
184 * @param pid our process ID
185 * @param error return location for errors
186 * @returns #FALSE on failure
189 _dbus_write_pid_file (const DBusString *filename,
193 const char *cfilename;
197 cfilename = _dbus_string_get_const_data (filename);
199 fd = open (cfilename, O_WRONLY|O_CREAT|O_EXCL|O_BINARY, 0644);
203 dbus_set_error (error, _dbus_error_from_errno (errno),
204 "Failed to open \"%s\": %s", cfilename,
205 _dbus_strerror (errno));
209 if ((f = fdopen (fd, "w")) == NULL)
211 dbus_set_error (error, _dbus_error_from_errno (errno),
212 "Failed to fdopen fd %d: %s", fd, _dbus_strerror (errno));
217 if (fprintf (f, "%lu\n", pid) < 0)
219 dbus_set_error (error, _dbus_error_from_errno (errno),
220 "Failed to write to \"%s\": %s", cfilename,
221 _dbus_strerror (errno));
227 if (fclose (f) == EOF)
229 dbus_set_error (error, _dbus_error_from_errno (errno),
230 "Failed to close \"%s\": %s", cfilename,
231 _dbus_strerror (errno));
240 * Changes the user and group the bus is running as.
242 * @param uid the new user ID
243 * @param gid the new group ID
244 * @param error return location for errors
245 * @returns #FALSE on failure
248 _dbus_change_identity (dbus_uid_t uid,
252 /* setgroups() only works if we are a privileged process,
253 * so we don't return error on failure; the only possible
254 * failure is that we don't have perms to do it.
255 * FIXME not sure this is right, maybe if setuid()
256 * is going to work then setgroups() should also work.
258 if (setgroups (0, NULL) < 0)
259 _dbus_warn ("Failed to drop supplementary groups: %s\n",
260 _dbus_strerror (errno));
262 /* Set GID first, or the setuid may remove our permission
265 if (setgid (gid) < 0)
267 dbus_set_error (error, _dbus_error_from_errno (errno),
268 "Failed to set GID to %lu: %s", gid,
269 _dbus_strerror (errno));
273 if (setuid (uid) < 0)
275 dbus_set_error (error, _dbus_error_from_errno (errno),
276 "Failed to set UID to %lu: %s", uid,
277 _dbus_strerror (errno));
284 /** Installs a UNIX signal handler
286 * @param sig the signal to handle
287 * @param handler the handler
290 _dbus_set_signal_handler (int sig,
291 DBusSignalHandler handler)
293 struct sigaction act;
296 sigemptyset (&empty_mask);
297 act.sa_handler = handler;
298 act.sa_mask = empty_mask;
300 sigaction (sig, &act, NULL);
305 * Removes a directory; Directory must be empty
307 * @param filename directory filename
308 * @param error initialized error object
309 * @returns #TRUE on success
312 _dbus_delete_directory (const DBusString *filename,
315 const char *filename_c;
317 _DBUS_ASSERT_ERROR_IS_CLEAR (error);
319 filename_c = _dbus_string_get_const_data (filename);
321 if (rmdir (filename_c) != 0)
323 dbus_set_error (error, DBUS_ERROR_FAILED,
324 "Failed to remove directory %s: %s\n",
325 filename_c, _dbus_strerror (errno));
332 /** Checks if a file exists
334 * @param file full path to the file
335 * @returns #TRUE if file exists
338 _dbus_file_exists (const char *file)
340 return (access (file, F_OK) == 0);
343 /** Checks if user is at the console
345 * @param username user to check
346 * @param error return location for errors
347 * @returns #TRUE is the user is at the consolei and there are no errors
350 _dbus_user_at_console (const char *username,
358 if (!_dbus_string_init (&f))
360 _DBUS_SET_OOM (error);
364 if (!_dbus_string_append (&f, DBUS_CONSOLE_AUTH_DIR))
366 _DBUS_SET_OOM (error);
371 if (!_dbus_string_append (&f, username))
373 _DBUS_SET_OOM (error);
377 result = _dbus_file_exists (_dbus_string_get_const_data (&f));
380 _dbus_string_free (&f);
387 * Checks whether the filename is an absolute path
389 * @param filename the filename
390 * @returns #TRUE if an absolute path
393 _dbus_path_is_absolute (const DBusString *filename)
395 if (_dbus_string_get_length (filename) > 0)
396 return _dbus_string_get_byte (filename, 0) == '/';
404 * @param filename the filename to stat
405 * @param statbuf the stat info to fill in
406 * @param error return location for error
407 * @returns #FALSE if error was set
410 _dbus_stat (const DBusString *filename,
414 const char *filename_c;
417 _DBUS_ASSERT_ERROR_IS_CLEAR (error);
419 filename_c = _dbus_string_get_const_data (filename);
421 if (stat (filename_c, &sb) < 0)
423 dbus_set_error (error, _dbus_error_from_errno (errno),
424 "%s", _dbus_strerror (errno));
428 statbuf->mode = sb.st_mode;
429 statbuf->nlink = sb.st_nlink;
430 statbuf->uid = sb.st_uid;
431 statbuf->gid = sb.st_gid;
432 statbuf->size = sb.st_size;
433 statbuf->atime = sb.st_atime;
434 statbuf->mtime = sb.st_mtime;
435 statbuf->ctime = sb.st_ctime;
442 * Internals of directory iterator
446 DIR *d; /**< The DIR* from opendir() */
451 * Open a directory to iterate over.
453 * @param filename the directory name
454 * @param error exception return object or #NULL
455 * @returns new iterator, or #NULL on error
458 _dbus_directory_open (const DBusString *filename,
463 const char *filename_c;
465 _DBUS_ASSERT_ERROR_IS_CLEAR (error);
467 filename_c = _dbus_string_get_const_data (filename);
469 d = opendir (filename_c);
472 dbus_set_error (error, _dbus_error_from_errno (errno),
473 "Failed to read directory \"%s\": %s",
475 _dbus_strerror (errno));
478 iter = dbus_new0 (DBusDirIter, 1);
482 dbus_set_error (error, DBUS_ERROR_NO_MEMORY,
483 "Could not allocate memory for directory iterator");
493 * Get next file in the directory. Will not return "." or ".." on
494 * UNIX. If an error occurs, the contents of "filename" are
495 * undefined. The error is never set if the function succeeds.
497 * @todo for thread safety, I think we have to use
498 * readdir_r(). (GLib has the same issue, should file a bug.)
500 * @param iter the iterator
501 * @param filename string to be set to the next file in the dir
502 * @param error return location for error
503 * @returns #TRUE if filename was filled in with a new filename
506 _dbus_directory_get_next_file (DBusDirIter *iter,
507 DBusString *filename,
512 _DBUS_ASSERT_ERROR_IS_CLEAR (error);
516 ent = readdir (iter->d);
520 dbus_set_error (error,
521 _dbus_error_from_errno (errno),
522 "%s", _dbus_strerror (errno));
525 else if (ent->d_name[0] == '.' &&
526 (ent->d_name[1] == '\0' ||
527 (ent->d_name[1] == '.' && ent->d_name[2] == '\0')))
531 _dbus_string_set_length (filename, 0);
532 if (!_dbus_string_append (filename, ent->d_name))
534 dbus_set_error (error, DBUS_ERROR_NO_MEMORY,
535 "No memory to read directory entry");
544 * Closes a directory iteration.
547 _dbus_directory_close (DBusDirIter *iter)
554 fill_user_info_from_group (struct group *g,
558 _dbus_assert (g->gr_name != NULL);
560 info->gid = g->gr_gid;
561 info->groupname = _dbus_strdup (g->gr_name);
563 /* info->members = dbus_strdupv (g->gr_mem) */
565 if (info->groupname == NULL)
567 dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
575 fill_group_info (DBusGroupInfo *info,
577 const DBusString *groupname,
580 const char *group_c_str;
582 _dbus_assert (groupname != NULL || gid != DBUS_GID_UNSET);
583 _dbus_assert (groupname == NULL || gid == DBUS_GID_UNSET);
586 group_c_str = _dbus_string_get_const_data (groupname);
590 /* For now assuming that the getgrnam() and getgrgid() flavors
591 * always correspond to the pwnam flavors, if not we have
592 * to add more configure checks.
595 #if defined (HAVE_POSIX_GETPWNAM_R) || defined (HAVE_NONPOSIX_GETPWNAM_R)
603 #ifdef HAVE_POSIX_GETPWNAM_R
606 result = getgrnam_r (group_c_str, &g_str, buf, sizeof (buf),
609 result = getgrgid_r (gid, &g_str, buf, sizeof (buf),
612 g = getgrnam_r (group_c_str, &g_str, buf, sizeof (buf));
614 #endif /* !HAVE_POSIX_GETPWNAM_R */
615 if (result == 0 && g == &g_str)
617 return fill_user_info_from_group (g, info, error);
621 dbus_set_error (error, _dbus_error_from_errno (errno),
622 "Group %s unknown or failed to look it up\n",
623 group_c_str ? group_c_str : "???");
627 #else /* ! HAVE_GETPWNAM_R */
629 /* I guess we're screwed on thread safety here */
632 g = getgrnam (group_c_str);
636 return fill_user_info_from_group (g, info, error);
640 dbus_set_error (error, _dbus_error_from_errno (errno),
641 "Group %s unknown or failed to look it up\n",
642 group_c_str ? group_c_str : "???");
646 #endif /* ! HAVE_GETPWNAM_R */
650 * Initializes the given DBusGroupInfo struct
651 * with information about the given group name.
653 * @param info the group info struct
654 * @param groupname name of group
655 * @param error the error return
656 * @returns #FALSE if error is set
659 _dbus_group_info_fill (DBusGroupInfo *info,
660 const DBusString *groupname,
663 return fill_group_info (info, DBUS_GID_UNSET,
669 * Initializes the given DBusGroupInfo struct
670 * with information about the given group ID.
672 * @param info the group info struct
673 * @param gid group ID
674 * @param error the error return
675 * @returns #FALSE if error is set
678 _dbus_group_info_fill_gid (DBusGroupInfo *info,
682 return fill_group_info (info, gid, NULL, error);
685 /** @} */ /* End of DBusInternalsUtils functions */
688 * @addtogroup DBusString
693 * Get the directory name from a complete filename
694 * @param filename the filename
695 * @param dirname string to append directory name to
696 * @returns #FALSE if no memory
699 _dbus_string_get_dirname (const DBusString *filename,
704 _dbus_assert (filename != dirname);
705 _dbus_assert (filename != NULL);
706 _dbus_assert (dirname != NULL);
708 /* Ignore any separators on the end */
709 sep = _dbus_string_get_length (filename);
711 return _dbus_string_append (dirname, "."); /* empty string passed in */
713 while (sep > 0 && _dbus_string_get_byte (filename, sep - 1) == '/')
716 _dbus_assert (sep >= 0);
719 return _dbus_string_append (dirname, "/");
721 /* Now find the previous separator */
722 _dbus_string_find_byte_backward (filename, sep, '/', &sep);
724 return _dbus_string_append (dirname, ".");
726 /* skip multiple separators */
727 while (sep > 0 && _dbus_string_get_byte (filename, sep - 1) == '/')
730 _dbus_assert (sep >= 0);
733 _dbus_string_get_byte (filename, 0) == '/')
734 return _dbus_string_append (dirname, "/");
736 return _dbus_string_copy_len (filename, 0, sep - 0,
737 dirname, _dbus_string_get_length (dirname));
739 /** @} */ /* DBusString stuff */
742 #ifdef DBUS_BUILD_TESTS
745 check_dirname (const char *filename,
750 _dbus_string_init_const (&f, filename);
752 if (!_dbus_string_init (&d))
753 _dbus_assert_not_reached ("no memory");
755 if (!_dbus_string_get_dirname (&f, &d))
756 _dbus_assert_not_reached ("no memory");
758 if (!_dbus_string_equal_c_str (&d, dirname))
760 _dbus_warn ("For filename \"%s\" got dirname \"%s\" and expected \"%s\"\n",
762 _dbus_string_get_const_data (&d),
767 _dbus_string_free (&d);
771 check_path_absolute (const char *path,
772 dbus_bool_t expected)
776 _dbus_string_init_const (&p, path);
778 if (_dbus_path_is_absolute (&p) != expected)
780 _dbus_warn ("For path \"%s\" expected absolute = %d got %d\n",
781 path, expected, _dbus_path_is_absolute (&p));
787 * Unit test for dbus-sysdeps.c.
789 * @returns #TRUE on success.
792 _dbus_sysdeps_test (void)
798 check_dirname ("foo", ".");
799 check_dirname ("foo/bar", "foo");
800 check_dirname ("foo//bar", "foo");
801 check_dirname ("foo///bar", "foo");
802 check_dirname ("foo/bar/", "foo");
803 check_dirname ("foo//bar/", "foo");
804 check_dirname ("foo///bar/", "foo");
805 check_dirname ("foo/bar//", "foo");
806 check_dirname ("foo//bar////", "foo");
807 check_dirname ("foo///bar///////", "foo");
808 check_dirname ("/foo", "/");
809 check_dirname ("////foo", "/");
810 check_dirname ("/foo/bar", "/foo");
811 check_dirname ("/foo//bar", "/foo");
812 check_dirname ("/foo///bar", "/foo");
813 check_dirname ("/", "/");
814 check_dirname ("///", "/");
815 check_dirname ("", ".");
818 _dbus_string_init_const (&str, "3.5");
819 if (!_dbus_string_parse_double (&str,
822 _dbus_warn ("Failed to parse double");
825 if (ABS(3.5 - val) > 1e-6)
827 _dbus_warn ("Failed to parse 3.5 correctly, got: %f", val);
832 _dbus_warn ("_dbus_string_parse_double of \"3.5\" returned wrong position %d", pos);
836 _dbus_string_init_const (&str, "0xff");
837 if (!_dbus_string_parse_double (&str,
840 _dbus_warn ("Failed to parse double");
843 if (ABS (0xff - val) > 1e-6)
845 _dbus_warn ("Failed to parse 0xff correctly, got: %f\n", val);
850 _dbus_warn ("_dbus_string_parse_double of \"0xff\" returned wrong position %d", pos);
854 check_path_absolute ("/", TRUE);
855 check_path_absolute ("/foo", TRUE);
856 check_path_absolute ("", FALSE);
857 check_path_absolute ("foo", FALSE);
858 check_path_absolute ("foo/bar", FALSE);
862 #endif /* DBUS_BUILD_TESTS */