X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=dbus%2Fdbus-sysdeps-unix.c;h=1cb4a58be902986452d1f2fe9bc85ad7b05a2b99;hb=7d9239c9c78cb6d0b9c282376fcf3cda1de23209;hp=1c72327f2ee66a8c1fa3b1468b1dbd3db1c9243e;hpb=19d48c3344fa0b43d960c2f0b8b5fbb2f9f8cb86;p=platform%2Fupstream%2Fdbus.git diff --git a/dbus/dbus-sysdeps-unix.c b/dbus/dbus-sysdeps-unix.c index 1c72327..1cb4a58 100644 --- a/dbus/dbus-sysdeps-unix.c +++ b/dbus/dbus-sysdeps-unix.c @@ -1,11 +1,11 @@ /* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ /* dbus-sysdeps-unix.c Wrappers around UNIX system/libc features (internal to D-Bus implementation) - * + * * Copyright (C) 2002, 2003, 2006 Red Hat, Inc. * Copyright (C) 2003 CodeFactory AB * * Licensed under the Academic Free License version 2.1 - * + * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -15,7 +15,7 @@ * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * + * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA @@ -55,6 +55,7 @@ #include #include #include +#include #ifdef HAVE_ERRNO_H #include @@ -71,11 +72,20 @@ #ifdef HAVE_GETPEERUCRED #include #endif +#ifdef HAVE_ALLOCA_H +#include +#endif #ifdef HAVE_ADT #include #endif +#include "sd-daemon.h" + +#if !DBUS_USE_SYNC +#include +#endif + #ifndef O_BINARY #define O_BINARY 0 #endif @@ -88,6 +98,38 @@ #define socklen_t int #endif +#if defined (__sun) || defined (__sun__) +/* + * CMS_SPACE etc. definitions for Solaris < 10, based on + * http://mailman.videolan.org/pipermail/vlc-devel/2006-May/024402.html + * via + * http://wiki.opencsw.org/porting-faq#toc10 + * + * These are only redefined for Solaris, for now: if your OS needs these too, + * please file a bug. (Or preferably, improve your OS so they're not needed.) + */ + +# ifndef CMSG_ALIGN +# ifdef __sun__ +# define CMSG_ALIGN(len) _CMSG_DATA_ALIGN (len) +# else + /* aligning to sizeof (long) is assumed to be portable (fd.o#40235) */ +# define CMSG_ALIGN(len) (((len) + sizeof (long) - 1) & \ + ~(sizeof (long) - 1)) +# endif +# endif + +# ifndef CMSG_SPACE +# define CMSG_SPACE(len) (CMSG_ALIGN (sizeof (struct cmsghdr)) + \ + CMSG_ALIGN (len)) +# endif + +# ifndef CMSG_LEN +# define CMSG_LEN(len) (CMSG_ALIGN (sizeof (struct cmsghdr)) + (len)) +# endif + +#endif /* Solaris */ + static dbus_bool_t _dbus_open_socket (int *fd_p, int domain, @@ -130,13 +172,6 @@ _dbus_open_socket (int *fd_p, } } -dbus_bool_t -_dbus_open_tcp_socket (int *fd, - DBusError *error) -{ - return _dbus_open_socket(fd, AF_INET, SOCK_STREAM, 0, error); -} - /** * Opens a UNIX domain socket (as in the socket() call). * Does not bind the socket. @@ -147,7 +182,7 @@ _dbus_open_tcp_socket (int *fd, * @param error return location for an error * @returns #FALSE if error is set */ -dbus_bool_t +static dbus_bool_t _dbus_open_unix_socket (int *fd, DBusError *error) { @@ -162,7 +197,7 @@ _dbus_open_unix_socket (int *fd, * @param error return location for an error * @returns #FALSE if error is set */ -dbus_bool_t +dbus_bool_t _dbus_close_socket (int fd, DBusError *error) { @@ -202,7 +237,7 @@ _dbus_write_socket (int fd, int start, int len) { -#ifdef MSG_NOSIGNAL +#if HAVE_DECL_MSG_NOSIGNAL const char *data; int bytes_written; @@ -440,7 +475,7 @@ _dbus_write_socket_with_unix_fds_two(int fd, again: bytes_written = sendmsg (fd, &m, 0 -#ifdef MSG_NOSIGNAL +#if HAVE_DECL_MSG_NOSIGNAL |MSG_NOSIGNAL #endif ); @@ -460,7 +495,7 @@ _dbus_write_socket_with_unix_fds_two(int fd, /** * Like _dbus_write_two() but only works on sockets and is thus * available on Windows. - * + * * @param fd the file descriptor * @param buffer1 first buffer * @param start1 first byte to write in first buffer @@ -479,7 +514,7 @@ _dbus_write_socket_two (int fd, int start2, int len2) { -#ifdef MSG_NOSIGNAL +#if HAVE_DECL_MSG_NOSIGNAL struct iovec vectors[2]; const char *data1; const char *data2; @@ -543,7 +578,7 @@ _dbus_socket_is_invalid (int fd) * * Unlike _dbus_read_socket(), _dbus_read() is not available * on Windows. - * + * * @param fd the file descriptor to read from * @param buffer the buffer to append data to * @param count the amount of data to read @@ -559,7 +594,7 @@ _dbus_read (int fd, char *data; _dbus_assert (count >= 0); - + start = _dbus_string_get_length (buffer); if (!_dbus_string_lengthen (buffer, count)) @@ -571,7 +606,7 @@ _dbus_read (int fd, data = _dbus_string_get_data_len (buffer, start, count); again: - + bytes_read = read (fd, data, count); if (bytes_read < 0) @@ -594,7 +629,7 @@ _dbus_read (int fd, if (bytes_read > 0) _dbus_verbose_bytes_of_string (buffer, start, bytes_read); #endif - + return bytes_read; } } @@ -602,7 +637,7 @@ _dbus_read (int fd, /** * Thin wrapper around the write() system call that writes a part of a * DBusString and handles EINTR for you. - * + * * @param fd the file descriptor to write * @param buffer the buffer to write data from * @param start the first byte in the buffer to write @@ -617,9 +652,9 @@ _dbus_write (int fd, { const char *data; int bytes_written; - + data = _dbus_string_get_const_data_len (buffer, start, len); - + again: bytes_written = write (fd, data, len); @@ -631,7 +666,7 @@ _dbus_write (int fd, if (bytes_written > 0) _dbus_verbose_bytes_of_string (buffer, start, bytes_written); #endif - + return bytes_written; } @@ -669,7 +704,7 @@ _dbus_write_two (int fd, _dbus_assert (start2 >= 0); _dbus_assert (len1 >= 0); _dbus_assert (len2 >= 0); - + #ifdef HAVE_WRITEV { struct iovec vectors[2]; @@ -687,40 +722,40 @@ _dbus_write_two (int fd, start2 = 0; len2 = 0; } - + vectors[0].iov_base = (char*) data1; vectors[0].iov_len = len1; vectors[1].iov_base = (char*) data2; vectors[1].iov_len = len2; again: - + bytes_written = writev (fd, vectors, data2 ? 2 : 1); if (bytes_written < 0 && errno == EINTR) goto again; - + return bytes_written; } #else /* HAVE_WRITEV */ { int ret1; - + ret1 = _dbus_write (fd, buffer1, start1, len1); if (ret1 == len1 && buffer2 != NULL) { ret2 = _dbus_write (fd, buffer2, start2, len2); if (ret2 < 0) ret2 = 0; /* we can't report an error as the first write was OK */ - + return ret1 + ret2; } else return ret1; } -#endif /* !HAVE_WRITEV */ +#endif /* !HAVE_WRITEV */ } #define _DBUS_MAX_SUN_PATH_LENGTH 99 @@ -742,7 +777,7 @@ _dbus_write_two (int fd, * Creates a socket and connects it to the UNIX domain socket at the * given path. The connection fd is returned, and is set up as * nonblocking. - * + * * Uses abstract sockets instead of filesystem-linked sockets if * requested (it's possible only on Linux; see "man 7 unix" on Linux). * On non-Linux abstract socket usage always fails. @@ -761,14 +796,14 @@ _dbus_connect_unix_socket (const char *path, { int fd; size_t path_len; - struct sockaddr_un addr; + struct sockaddr_un addr; _DBUS_ASSERT_ERROR_IS_CLEAR (error); _dbus_verbose ("connecting to unix socket %s abstract=%d\n", path, abstract); - - + + if (!_dbus_open_unix_socket (&fd, error)) { _DBUS_ASSERT_ERROR_IS_SET(error); @@ -793,7 +828,7 @@ _dbus_connect_unix_socket (const char *path, _dbus_close (fd, NULL); return -1; } - + strncpy (&addr.sun_path[1], path, path_len); /* _dbus_verbose_bytes (addr.sun_path, sizeof (addr.sun_path)); */ #else /* HAVE_ABSTRACT_SOCKETS */ @@ -815,27 +850,23 @@ _dbus_connect_unix_socket (const char *path, strncpy (addr.sun_path, path, path_len); } - + if (connect (fd, (struct sockaddr*) &addr, _DBUS_STRUCT_OFFSET (struct sockaddr_un, sun_path) + path_len) < 0) - { + { dbus_set_error (error, _dbus_error_from_errno (errno), "Failed to connect to socket %s: %s", path, _dbus_strerror (errno)); _dbus_close (fd, NULL); - fd = -1; - return -1; } if (!_dbus_set_fd_nonblocking (fd, error)) { _DBUS_ASSERT_ERROR_IS_SET (error); - - _dbus_close (fd, NULL); - fd = -1; + _dbus_close (fd, NULL); return -1; } @@ -843,6 +874,96 @@ _dbus_connect_unix_socket (const char *path, } /** + * Creates a UNIX domain socket and connects it to the specified + * process to execute. + * + * This will set FD_CLOEXEC for the socket returned. + * + * @param path the path to the executable + * @param argv the argument list for the process to execute. + * argv[0] typically is identical to the path of the executable + * @param error return location for error code + * @returns connection file descriptor or -1 on error + */ +int +_dbus_connect_exec (const char *path, + char *const argv[], + DBusError *error) +{ + int fds[2]; + pid_t pid; + + _DBUS_ASSERT_ERROR_IS_CLEAR (error); + + _dbus_verbose ("connecting to process %s\n", path); + + if (socketpair (AF_UNIX, SOCK_STREAM +#ifdef SOCK_CLOEXEC + |SOCK_CLOEXEC +#endif + , 0, fds) < 0) + { + dbus_set_error (error, + _dbus_error_from_errno (errno), + "Failed to create socket pair: %s", + _dbus_strerror (errno)); + return -1; + } + + _dbus_fd_set_close_on_exec (fds[0]); + _dbus_fd_set_close_on_exec (fds[1]); + + pid = fork (); + if (pid < 0) + { + dbus_set_error (error, + _dbus_error_from_errno (errno), + "Failed to fork() to call %s: %s", + path, _dbus_strerror (errno)); + close (fds[0]); + close (fds[1]); + return -1; + } + + if (pid == 0) + { + /* child */ + close (fds[0]); + + dup2 (fds[1], STDIN_FILENO); + dup2 (fds[1], STDOUT_FILENO); + + if (fds[1] != STDIN_FILENO && + fds[1] != STDOUT_FILENO) + close (fds[1]); + + /* Inherit STDERR and the controlling terminal from the + parent */ + + _dbus_close_all (); + + execvp (path, argv); + + fprintf (stderr, "Failed to execute process %s: %s\n", path, _dbus_strerror (errno)); + + _exit(1); + } + + /* parent */ + close (fds[1]); + + if (!_dbus_set_fd_nonblocking (fds[0], error)) + { + _DBUS_ASSERT_ERROR_IS_SET (error); + + close (fds[0]); + return -1; + } + + return fds[0]; +} + +/** * Enables or disables the reception of credentials on the given socket during * the next message transmission. This is only effective if the #LOCAL_CREDS * system feature exists, in which case the other side of the connection does @@ -857,10 +978,10 @@ _dbus_set_local_creds (int fd, dbus_bool_t on) dbus_bool_t retval = TRUE; #if defined(HAVE_CMSGCRED) - /* NOOP just to make sure only one codepath is used + /* NOOP just to make sure only one codepath is used * and to prefer CMSGCRED */ -#elif defined(LOCAL_CREDS) +#elif defined(LOCAL_CREDS) int val = on ? 1 : 0; if (setsockopt (fd, 0, LOCAL_CREDS, &val, sizeof (val)) < 0) { @@ -900,12 +1021,13 @@ _dbus_listen_unix_socket (const char *path, int listen_fd; struct sockaddr_un addr; size_t path_len; + unsigned int reuseaddr; _DBUS_ASSERT_ERROR_IS_CLEAR (error); _dbus_verbose ("listening on unix socket %s abstract=%d\n", path, abstract); - + if (!_dbus_open_unix_socket (&listen_fd, error)) { _DBUS_ASSERT_ERROR_IS_SET(error); @@ -916,7 +1038,7 @@ _dbus_listen_unix_socket (const char *path, _DBUS_ZERO (addr); addr.sun_family = AF_UNIX; path_len = strlen (path); - + if (abstract) { #ifdef HAVE_ABSTRACT_SOCKETS @@ -933,7 +1055,7 @@ _dbus_listen_unix_socket (const char *path, _dbus_close (listen_fd, NULL); return -1; } - + strncpy (&addr.sun_path[1], path, path_len); /* _dbus_verbose_bytes (addr.sun_path, sizeof (addr.sun_path)); */ #else /* HAVE_ABSTRACT_SOCKETS */ @@ -970,10 +1092,17 @@ _dbus_listen_unix_socket (const char *path, _dbus_close (listen_fd, NULL); return -1; } - + strncpy (addr.sun_path, path, path_len); } - + + reuseaddr = 1; + if (setsockopt (listen_fd, SOL_SOCKET, SO_REUSEADDR, &reuseaddr, sizeof(reuseaddr))==-1) + { + _dbus_warn ("Failed to set socket option\"%s\": %s", + path, _dbus_strerror (errno)); + } + if (bind (listen_fd, (struct sockaddr*) &addr, _DBUS_STRUCT_OFFSET (struct sockaddr_un, sun_path) + path_len) < 0) { dbus_set_error (error, _dbus_error_from_errno (errno), @@ -1007,19 +1136,118 @@ _dbus_listen_unix_socket (const char *path, _dbus_close (listen_fd, NULL); return -1; } - + /* Try opening up the permissions, but if we can't, just go ahead * and continue, maybe it will be good enough. */ if (!abstract && chmod (path, 0777) < 0) _dbus_warn ("Could not set mode 0777 on socket %s\n", path); - + return listen_fd; } /** - * Creates a socket and connects to a socket at the given host + * Acquires one or more sockets passed in from systemd. The sockets + * are set to be nonblocking. + * + * This will set FD_CLOEXEC for the sockets returned. + * + * @param fds the file descriptors + * @param error return location for errors + * @returns the number of file descriptors + */ +int +_dbus_listen_systemd_sockets (int **fds, + DBusError *error) +{ + int r, n; + unsigned fd; + int *new_fds; + + _DBUS_ASSERT_ERROR_IS_CLEAR (error); + + n = sd_listen_fds (TRUE); + if (n < 0) + { + dbus_set_error (error, _dbus_error_from_errno (-n), + "Failed to acquire systemd socket: %s", + _dbus_strerror (-n)); + return -1; + } + + if (n <= 0) + { + dbus_set_error (error, DBUS_ERROR_BAD_ADDRESS, + "No socket received."); + return -1; + } + + for (fd = SD_LISTEN_FDS_START; fd < SD_LISTEN_FDS_START + n; fd ++) + { + r = sd_is_socket (fd, AF_UNSPEC, SOCK_STREAM, 1); + if (r < 0) + { + dbus_set_error (error, _dbus_error_from_errno (-r), + "Failed to verify systemd socket type: %s", + _dbus_strerror (-r)); + return -1; + } + + if (!r) + { + dbus_set_error (error, DBUS_ERROR_BAD_ADDRESS, + "Passed socket has wrong type."); + return -1; + } + } + + /* OK, the file descriptors are all good, so let's take posession of + them then. */ + + new_fds = dbus_new (int, n); + if (!new_fds) + { + dbus_set_error (error, DBUS_ERROR_NO_MEMORY, + "Failed to allocate file handle array."); + goto fail; + } + + for (fd = SD_LISTEN_FDS_START; fd < SD_LISTEN_FDS_START + n; fd ++) + { + if (!_dbus_set_local_creds (fd, TRUE)) + { + dbus_set_error (error, _dbus_error_from_errno (errno), + "Failed to enable LOCAL_CREDS on systemd socket: %s", + _dbus_strerror (errno)); + goto fail; + } + + if (!_dbus_set_fd_nonblocking (fd, error)) + { + _DBUS_ASSERT_ERROR_IS_SET (error); + goto fail; + } + + new_fds[fd - SD_LISTEN_FDS_START] = fd; + } + + *fds = new_fds; + return n; + + fail: + + for (fd = SD_LISTEN_FDS_START; fd < SD_LISTEN_FDS_START + n; fd ++) + { + _dbus_close (fd, NULL); + } + + dbus_free (new_fds); + return -1; +} + +/** + * Creates a socket and connects to a socket at the given host * and port. The connection fd is returned, and is set up as * nonblocking. * @@ -1052,14 +1280,6 @@ _dbus_connect_tcp_socket_with_nonce (const char *host, struct addrinfo hints; struct addrinfo *ai, *tmp; - _DBUS_ASSERT_ERROR_IS_CLEAR (error); - - if (!_dbus_open_tcp_socket (&fd, error)) - { - _DBUS_ASSERT_ERROR_IS_SET(error); - return -1; - } - _DBUS_ASSERT_ERROR_IS_CLEAR(error); _DBUS_ZERO (hints); @@ -1087,7 +1307,6 @@ _dbus_connect_tcp_socket_with_nonce (const char *host, _dbus_error_from_errno (errno), "Failed to lookup host/port: \"%s:%s\": %s (%d)", host, port, gai_strerror(res), res); - _dbus_close (fd, NULL); return -1; } @@ -1176,6 +1395,7 @@ _dbus_listen_tcp_socket (const char *host, int nlisten_fd = 0, *listen_fd = NULL, res, i; struct addrinfo hints; struct addrinfo *ai, *tmp; + unsigned int reuseaddr; *fds_p = NULL; _DBUS_ASSERT_ERROR_IS_CLEAR (error); @@ -1201,13 +1421,14 @@ _dbus_listen_tcp_socket (const char *host, hints.ai_flags = AI_ADDRCONFIG | AI_PASSIVE; redo_lookup_with_port: + ai = NULL; if ((res = getaddrinfo(host, port, &hints, &ai)) != 0 || !ai) { dbus_set_error (error, _dbus_error_from_errno (errno), "Failed to lookup host/port: \"%s:%s\": %s (%d)", host ? host : "*", port, gai_strerror(res), res); - return -1; + goto failed; } tmp = ai; @@ -1221,6 +1442,13 @@ _dbus_listen_tcp_socket (const char *host, } _DBUS_ASSERT_ERROR_IS_CLEAR(error); + reuseaddr = 1; + if (setsockopt (fd, SOL_SOCKET, SO_REUSEADDR, &reuseaddr, sizeof(reuseaddr))==-1) + { + _dbus_warn ("Failed to set socket option \"%s:%s\": %s", + host ? host : "*", port, _dbus_strerror (errno)); + } + if (bind (fd, (struct sockaddr*) tmp->ai_addr, tmp->ai_addrlen) < 0) { saved_errno = errno; @@ -1271,16 +1499,18 @@ _dbus_listen_tcp_socket (const char *host, to use the same port */ if (!port || !strcmp(port, "0")) { + int result; struct sockaddr_storage addr; socklen_t addrlen; char portbuf[50]; addrlen = sizeof(addr); - getsockname(fd, (struct sockaddr*) &addr, &addrlen); + result = getsockname(fd, (struct sockaddr*) &addr, &addrlen); - if ((res = getnameinfo((struct sockaddr*)&addr, addrlen, NULL, 0, - portbuf, sizeof(portbuf), - NI_NUMERICHOST)) != 0) + if (result == -1 || + (res = getnameinfo ((struct sockaddr*)&addr, addrlen, NULL, 0, + portbuf, sizeof(portbuf), + NI_NUMERICHOST)) != 0) { dbus_set_error (error, _dbus_error_from_errno (errno), "Failed to resolve port \"%s:%s\": %s (%s)", @@ -1319,7 +1549,7 @@ _dbus_listen_tcp_socket (const char *host, dbus_set_error (error, _dbus_error_from_errno (errno), "Failed to bind socket \"%s:%s\": %s", host ? host : "*", port, _dbus_strerror (errno)); - return -1; + goto failed; } for (i = 0 ; i < nlisten_fd ; i++) @@ -1349,7 +1579,7 @@ write_credentials_byte (int server_fd, { int bytes_written; char buf[1] = { '\0' }; -#if defined(HAVE_CMSGCRED) +#if defined(HAVE_CMSGCRED) union { struct cmsghdr hdr; char cred[CMSG_SPACE (sizeof (struct cmsgcred))]; @@ -1372,13 +1602,21 @@ write_credentials_byte (int server_fd, #endif _DBUS_ASSERT_ERROR_IS_CLEAR (error); - + again: -#if defined(HAVE_CMSGCRED) - bytes_written = sendmsg (server_fd, &msg, 0); +#if defined(HAVE_CMSGCRED) + bytes_written = sendmsg (server_fd, &msg, 0 +#if HAVE_DECL_MSG_NOSIGNAL + |MSG_NOSIGNAL +#endif + ); #else - bytes_written = write (server_fd, buf, 1); + bytes_written = send (server_fd, buf, 1, 0 +#if HAVE_DECL_MSG_NOSIGNAL + |MSG_NOSIGNAL +#endif + ); #endif if (bytes_written < 0 && errno == EINTR) @@ -1415,7 +1653,7 @@ write_credentials_byte (int server_fd, * we got valid credentials. On some systems, such as Linux, * reading/writing the byte isn't actually required, but we do it * anyway just to avoid multiple codepaths. - * + * * Fails if no byte is available, so you must select() first. * * The point of the byte is that on some systems we have to @@ -1437,8 +1675,8 @@ _dbus_read_credentials_socket (int client_fd, dbus_uid_t uid_read; dbus_pid_t pid_read; int bytes_read; - -#ifdef HAVE_CMSGCRED + +#ifdef HAVE_CMSGCRED union { struct cmsghdr hdr; char cred[CMSG_SPACE (sizeof (struct cmsgcred))]; @@ -1455,7 +1693,7 @@ _dbus_read_credentials_socket (int client_fd, pid_read = DBUS_PID_UNSET; _DBUS_ASSERT_ERROR_IS_CLEAR (error); - + /* The POSIX spec certainly doesn't promise this, but * we need these assertions to fail as soon as we're wrong about * it so we can do the porting fixups @@ -1497,7 +1735,7 @@ _dbus_read_credentials_socket (int client_fd, * normally only call read_credentials if the socket was ready * for reading */ - + dbus_set_error (error, _dbus_error_from_errno (errno), "Failed to read credentials byte: %s", _dbus_strerror (errno)); @@ -1533,9 +1771,13 @@ _dbus_read_credentials_socket (int client_fd, { #ifdef SO_PEERCRED - struct ucred cr; +#ifdef __OpenBSD__ + struct sockpeercred cr; +#else + struct ucred cr; +#endif int cr_len = sizeof (cr); - + if (getsockopt (client_fd, SOL_SOCKET, SO_PEERCRED, &cr, &cr_len) == 0 && cr_len == sizeof (cr)) { @@ -1585,9 +1827,9 @@ _dbus_read_credentials_socket (int client_fd, { _dbus_verbose ("Failed to adt_start_session(): %s\n", _dbus_strerror (errno)); } - else + else { - if (adt_set_from_ucred (adth, ucred, ADT_NEW)) + if (adt_set_from_ucred (adth, ucred, ADT_NEW)) { _dbus_verbose ("Failed to adt_set_from_ucred(): %s\n", _dbus_strerror (errno)); } @@ -1628,7 +1870,7 @@ _dbus_read_credentials_socket (int client_fd, if (pid_read != DBUS_PID_UNSET) { - if (!_dbus_credentials_add_unix_pid (credentials, pid_read)) + if (!_dbus_credentials_add_pid (credentials, pid_read)) { _DBUS_SET_OOM (error); return FALSE; @@ -1643,7 +1885,7 @@ _dbus_read_credentials_socket (int client_fd, return FALSE; } } - + return TRUE; } @@ -1669,7 +1911,7 @@ _dbus_send_credentials_socket (int server_fd, DBusError *error) { _DBUS_ASSERT_ERROR_IS_CLEAR (error); - + if (write_credentials_byte (server_fd, error)) return TRUE; else @@ -1729,8 +1971,8 @@ _dbus_accept (int listen_fd) } /** - * Checks to make sure the given directory is - * private to the user + * Checks to make sure the given directory is + * private to the user * * @param dir the name of the directory * @param error error return @@ -1741,19 +1983,19 @@ _dbus_check_dir_is_private_to_user (DBusString *dir, DBusError *error) { const char *directory; struct stat sb; - + _DBUS_ASSERT_ERROR_IS_CLEAR (error); - + directory = _dbus_string_get_const_data (dir); - + if (stat (directory, &sb) < 0) { dbus_set_error (error, _dbus_error_from_errno (errno), "%s", _dbus_strerror (errno)); - + return FALSE; } - + if ((S_IROTH & sb.st_mode) || (S_IWOTH & sb.st_mode) || (S_IRGRP & sb.st_mode) || (S_IWGRP & sb.st_mode)) { @@ -1761,7 +2003,7 @@ _dbus_check_dir_is_private_to_user (DBusString *dir, DBusError *error) "%s directory is not private to the user", directory); return FALSE; } - + return TRUE; } @@ -1772,12 +2014,12 @@ fill_user_info_from_passwd (struct passwd *p, { _dbus_assert (p->pw_name != NULL); _dbus_assert (p->pw_dir != NULL); - + info->uid = p->pw_uid; info->primary_gid = p->pw_gid; info->username = _dbus_strdup (p->pw_name); info->homedir = _dbus_strdup (p->pw_dir); - + if (info->username == NULL || info->homedir == NULL) { @@ -1795,7 +2037,7 @@ fill_user_info (DBusUserInfo *info, DBusError *error) { const char *username_c; - + /* exactly one of username/uid provided */ _dbus_assert (username != NULL || uid != DBUS_UID_UNSET); _dbus_assert (username == NULL || uid == DBUS_UID_UNSET); @@ -1806,7 +2048,7 @@ fill_user_info (DBusUserInfo *info, info->n_group_ids = 0; info->username = NULL; info->homedir = NULL; - + if (username != NULL) username_c = _dbus_string_get_const_data (username); else @@ -1816,7 +2058,7 @@ fill_user_info (DBusUserInfo *info, * are always symmetrical, if not we have to add more configure * checks */ - + #if defined (HAVE_POSIX_GETPWNAM_R) || defined (HAVE_NONPOSIX_GETPWNAM_R) { struct passwd *p; @@ -1920,7 +2162,7 @@ fill_user_info (DBusUserInfo *info, /* Fill this in so we can use it to get groups */ username_c = info->username; - + #ifdef HAVE_GETGROUPLIST { gid_t *buf; @@ -1936,7 +2178,7 @@ fill_user_info (DBusUserInfo *info, dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); goto failed; } - + if (getgrouplist (username_c, info->primary_gid, buf, &buf_count) < 0) @@ -1953,10 +2195,10 @@ fill_user_info (DBusUserInfo *info, for the "id" command, and it turns out that they use an undocumented library function getgrouplist_2 (!) which is not declared in any header in /usr/include (!!). That did not seem - like the way to go here. + like the way to go here. */ - if (buf_count == initial_buf_count) - { + if (buf_count == initial_buf_count) + { buf_count *= 16; /* Retry with an arbitrarily scaled-up array */ } new = dbus_realloc (buf, buf_count * sizeof (buf[0])); @@ -1966,7 +2208,7 @@ fill_user_info (DBusUserInfo *info, dbus_free (buf); goto failed; } - + buf = new; errno = 0; @@ -1976,7 +2218,7 @@ fill_user_info (DBusUserInfo *info, { _dbus_warn ("It appears that username \"%s\" is in more than %d groups.\nProceeding with just the first %d groups.", username_c, buf_count, buf_count); - } + } else { dbus_set_error (error, @@ -1998,12 +2240,12 @@ fill_user_info (DBusUserInfo *info, dbus_free (buf); goto failed; } - + for (i = 0; i < buf_count; ++i) info->group_ids[i] = buf[i]; info->n_group_ids = buf_count; - + dbus_free (buf); } #else /* HAVE_GETGROUPLIST */ @@ -2023,9 +2265,9 @@ fill_user_info (DBusUserInfo *info, #endif /* HAVE_GETGROUPLIST */ _DBUS_ASSERT_ERROR_IS_CLEAR (error); - + return TRUE; - + failed: _DBUS_ASSERT_ERROR_IS_SET (error); return FALSE; @@ -2083,7 +2325,7 @@ _dbus_credentials_add_from_current_process (DBusCredentials *credentials) _dbus_assert (sizeof (uid_t) <= sizeof (dbus_uid_t)); _dbus_assert (sizeof (gid_t) <= sizeof (dbus_gid_t)); - if (!_dbus_credentials_add_unix_pid(credentials, _dbus_getpid())) + if (!_dbus_credentials_add_pid(credentials, _dbus_getpid())) return FALSE; if (!_dbus_credentials_add_unix_uid(credentials, _dbus_geteuid())) return FALSE; @@ -2098,7 +2340,7 @@ _dbus_credentials_add_from_current_process (DBusCredentials *credentials) * is required, that is done in dbus-auth.c. The username here * need not be anything human-readable, it can be the machine-readable * form i.e. a user id. - * + * * @param str the string to append to * @returns #FALSE on no memory */ @@ -2140,7 +2382,7 @@ _dbus_geteuid (void) /** * The only reason this is separate from _dbus_getpid() is to allow it * on Windows for logging but not for other purposes. - * + * * @returns process ID to put in log messages */ unsigned long @@ -2162,7 +2404,7 @@ _dbus_parse_uid (const DBusString *uid_str, { int end; long val; - + if (_dbus_string_get_length (uid_str) == 0) { _dbus_verbose ("UID string was zero length\n"); @@ -2177,7 +2419,7 @@ _dbus_parse_uid (const DBusString *uid_str, _dbus_verbose ("could not parse string as a UID\n"); return FALSE; } - + if (end != _dbus_string_get_length (uid_str)) { _dbus_verbose ("string contained trailing stuff after UID\n"); @@ -2190,7 +2432,12 @@ _dbus_parse_uid (const DBusString *uid_str, } #if !DBUS_USE_SYNC -_DBUS_DEFINE_GLOBAL_LOCK (atomic); +/* To be thread-safe by default on platforms that don't necessarily have + * atomic operations (notably Debian armel, which is armv4t), we must + * use a mutex that can be initialized statically, like this. + * GLib >= 2.32 uses a similar system. + */ +static pthread_mutex_t atomic_mutex = PTHREAD_MUTEX_INITIALIZER; #endif /** @@ -2206,10 +2453,12 @@ _dbus_atomic_inc (DBusAtomic *atomic) return __sync_add_and_fetch(&atomic->value, 1)-1; #else dbus_int32_t res; - _DBUS_LOCK (atomic); + + pthread_mutex_lock (&atomic_mutex); res = atomic->value; atomic->value += 1; - _DBUS_UNLOCK (atomic); + pthread_mutex_unlock (&atomic_mutex); + return res; #endif } @@ -2227,25 +2476,39 @@ _dbus_atomic_dec (DBusAtomic *atomic) return __sync_sub_and_fetch(&atomic->value, 1)+1; #else dbus_int32_t res; - - _DBUS_LOCK (atomic); + + pthread_mutex_lock (&atomic_mutex); res = atomic->value; atomic->value -= 1; - _DBUS_UNLOCK (atomic); + pthread_mutex_unlock (&atomic_mutex); + return res; #endif } -#ifdef DBUS_BUILD_TESTS -/** Gets our GID - * @returns process GID +/** + * Atomically get the value of an integer. It may change at any time + * thereafter, so this is mostly only useful for assertions. + * + * @param atomic pointer to the integer to get + * @returns the value at this moment */ -dbus_gid_t -_dbus_getgid (void) +dbus_int32_t +_dbus_atomic_get (DBusAtomic *atomic) { - return getgid (); -} +#if DBUS_USE_SYNC + __sync_synchronize (); + return atomic->value; +#else + dbus_int32_t res; + + pthread_mutex_lock (&atomic_mutex); + res = atomic->value; + pthread_mutex_unlock (&atomic_mutex); + + return res; #endif +} /** * Wrapper for poll(). @@ -2280,7 +2543,7 @@ _dbus_poll (DBusPollFD *fds, _DBUS_STRUCT_OFFSET (struct pollfd, revents)) { return poll ((struct pollfd*) fds, - n_fds, + n_fds, timeout_milliseconds); } else @@ -2298,7 +2561,7 @@ _dbus_poll (DBusPollFD *fds, int i; struct timeval tv; int ready; - + FD_ZERO (&read_set); FD_ZERO (&write_set); FD_ZERO (&err_set); @@ -2317,7 +2580,7 @@ _dbus_poll (DBusPollFD *fds, max_fd = MAX (max_fd, fdp->fd); } - + tv.tv_sec = timeout_milliseconds / 1000; tv.tv_usec = (timeout_milliseconds % 1000) * 1000; @@ -2352,14 +2615,12 @@ _dbus_poll (DBusPollFD *fds, * available, to avoid problems when the system time changes. * * @param tv_sec return location for number of seconds - * @param tv_usec return location for number of microseconds (thousandths) + * @param tv_usec return location for number of microseconds */ void -_dbus_get_current_time (long *tv_sec, - long *tv_usec) +_dbus_get_monotonic_time (long *tv_sec, + long *tv_usec) { - struct timeval t; - #ifdef HAVE_MONOTONIC_CLOCK struct timespec ts; clock_gettime (CLOCK_MONOTONIC, &ts); @@ -2369,6 +2630,8 @@ _dbus_get_current_time (long *tv_sec, if (tv_usec) *tv_usec = ts.tv_nsec / 1000; #else + struct timeval t; + gettimeofday (&t, NULL); if (tv_sec) @@ -2379,362 +2642,24 @@ _dbus_get_current_time (long *tv_sec, } /** - * Appends the contents of the given file to the string, - * returning error code. At the moment, won't open a file - * more than a megabyte in size. + * Get current time, as in gettimeofday(). Never uses the monotonic + * clock. * - * @param str the string to append to - * @param filename filename to load - * @param error place to set an error - * @returns #FALSE if error was set + * @param tv_sec return location for number of seconds + * @param tv_usec return location for number of microseconds */ -dbus_bool_t -_dbus_file_get_contents (DBusString *str, - const DBusString *filename, - DBusError *error) +void +_dbus_get_real_time (long *tv_sec, + long *tv_usec) { - int fd; - struct stat sb; - int orig_len; - int total; - const char *filename_c; + struct timeval t; - _DBUS_ASSERT_ERROR_IS_CLEAR (error); - - filename_c = _dbus_string_get_const_data (filename); - - /* O_BINARY useful on Cygwin */ - fd = open (filename_c, O_RDONLY | O_BINARY); - if (fd < 0) - { - dbus_set_error (error, _dbus_error_from_errno (errno), - "Failed to open \"%s\": %s", - filename_c, - _dbus_strerror (errno)); - return FALSE; - } - - _dbus_verbose ("file fd %d opened\n", fd); - - if (fstat (fd, &sb) < 0) - { - dbus_set_error (error, _dbus_error_from_errno (errno), - "Failed to stat \"%s\": %s", - filename_c, - _dbus_strerror (errno)); - - _dbus_verbose ("fstat() failed: %s", - _dbus_strerror (errno)); - - _dbus_close (fd, NULL); - - return FALSE; - } - - if (sb.st_size > _DBUS_ONE_MEGABYTE) - { - dbus_set_error (error, DBUS_ERROR_FAILED, - "File size %lu of \"%s\" is too large.", - (unsigned long) sb.st_size, filename_c); - _dbus_close (fd, NULL); - return FALSE; - } - - total = 0; - orig_len = _dbus_string_get_length (str); - if (sb.st_size > 0 && S_ISREG (sb.st_mode)) - { - int bytes_read; - - while (total < (int) sb.st_size) - { - bytes_read = _dbus_read (fd, str, - sb.st_size - total); - if (bytes_read <= 0) - { - dbus_set_error (error, _dbus_error_from_errno (errno), - "Error reading \"%s\": %s", - filename_c, - _dbus_strerror (errno)); - - _dbus_verbose ("read() failed: %s", - _dbus_strerror (errno)); - - _dbus_close (fd, NULL); - _dbus_string_set_length (str, orig_len); - return FALSE; - } - else - total += bytes_read; - } - - _dbus_close (fd, NULL); - return TRUE; - } - else if (sb.st_size != 0) - { - _dbus_verbose ("Can only open regular files at the moment.\n"); - dbus_set_error (error, DBUS_ERROR_FAILED, - "\"%s\" is not a regular file", - filename_c); - _dbus_close (fd, NULL); - return FALSE; - } - else - { - _dbus_close (fd, NULL); - return TRUE; - } -} - -/** - * Writes a string out to a file. If the file exists, - * it will be atomically overwritten by the new data. - * - * @param str the string to write out - * @param filename the file to save string to - * @param error error to be filled in on failure - * @returns #FALSE on failure - */ -dbus_bool_t -_dbus_string_save_to_file (const DBusString *str, - const DBusString *filename, - DBusError *error) -{ - int fd; - int bytes_to_write; - const char *filename_c; - DBusString tmp_filename; - const char *tmp_filename_c; - int total; - dbus_bool_t need_unlink; - dbus_bool_t retval; - - _DBUS_ASSERT_ERROR_IS_CLEAR (error); - - fd = -1; - retval = FALSE; - need_unlink = FALSE; - - if (!_dbus_string_init (&tmp_filename)) - { - dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); - return FALSE; - } - - if (!_dbus_string_copy (filename, 0, &tmp_filename, 0)) - { - dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); - _dbus_string_free (&tmp_filename); - return FALSE; - } - - if (!_dbus_string_append (&tmp_filename, ".")) - { - dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); - _dbus_string_free (&tmp_filename); - return FALSE; - } - -#define N_TMP_FILENAME_RANDOM_BYTES 8 - if (!_dbus_generate_random_ascii (&tmp_filename, N_TMP_FILENAME_RANDOM_BYTES)) - { - dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL); - _dbus_string_free (&tmp_filename); - return FALSE; - } - - filename_c = _dbus_string_get_const_data (filename); - tmp_filename_c = _dbus_string_get_const_data (&tmp_filename); - - fd = open (tmp_filename_c, O_WRONLY | O_BINARY | O_EXCL | O_CREAT, - 0600); - if (fd < 0) - { - dbus_set_error (error, _dbus_error_from_errno (errno), - "Could not create %s: %s", tmp_filename_c, - _dbus_strerror (errno)); - goto out; - } - - _dbus_verbose ("tmp file fd %d opened\n", fd); - - need_unlink = TRUE; - - total = 0; - bytes_to_write = _dbus_string_get_length (str); - - while (total < bytes_to_write) - { - int bytes_written; - - bytes_written = _dbus_write (fd, str, total, - bytes_to_write - total); - - if (bytes_written <= 0) - { - dbus_set_error (error, _dbus_error_from_errno (errno), - "Could not write to %s: %s", tmp_filename_c, - _dbus_strerror (errno)); - - goto out; - } - - total += bytes_written; - } - - if (fsync(fd)) - { - dbus_set_error (error, _dbus_error_from_errno (errno), - "Could not synchronize file %s: %s", - tmp_filename_c, _dbus_strerror (errno)); - - goto out; - } - - if (!_dbus_close (fd, NULL)) - { - dbus_set_error (error, _dbus_error_from_errno (errno), - "Could not close file %s: %s", - tmp_filename_c, _dbus_strerror (errno)); - - goto out; - } - - fd = -1; - - if (rename (tmp_filename_c, filename_c) < 0) - { - dbus_set_error (error, _dbus_error_from_errno (errno), - "Could not rename %s to %s: %s", - tmp_filename_c, filename_c, - _dbus_strerror (errno)); - - goto out; - } - - need_unlink = FALSE; - - retval = TRUE; - - out: - /* close first, then unlink, to prevent ".nfs34234235" garbage - * files - */ - - if (fd >= 0) - _dbus_close (fd, NULL); - - if (need_unlink && unlink (tmp_filename_c) < 0) - _dbus_verbose ("Failed to unlink temp file %s: %s\n", - tmp_filename_c, _dbus_strerror (errno)); - - _dbus_string_free (&tmp_filename); - - if (!retval) - _DBUS_ASSERT_ERROR_IS_SET (error); - - return retval; -} - -/** Makes the file readable by every user in the system. - * - * @param filename the filename - * @param error error location - * @returns #TRUE if the file's permissions could be changed. - */ -dbus_bool_t -_dbus_make_file_world_readable(const DBusString *filename, - DBusError *error) -{ - const char *filename_c; - - _DBUS_ASSERT_ERROR_IS_CLEAR (error); - - filename_c = _dbus_string_get_const_data (filename); - if (chmod (filename_c, 0644) == -1) - { - dbus_set_error (error, - DBUS_ERROR_FAILED, - "Could not change permissions of file %s: %s\n", - filename_c, - _dbus_strerror (errno)); - return FALSE; - } - return TRUE; -} - -/** Creates the given file, failing if the file already exists. - * - * @param filename the filename - * @param error error location - * @returns #TRUE if we created the file and it didn't exist - */ -dbus_bool_t -_dbus_create_file_exclusively (const DBusString *filename, - DBusError *error) -{ - int fd; - const char *filename_c; - - _DBUS_ASSERT_ERROR_IS_CLEAR (error); - - filename_c = _dbus_string_get_const_data (filename); - - fd = open (filename_c, O_WRONLY | O_BINARY | O_EXCL | O_CREAT, - 0600); - if (fd < 0) - { - dbus_set_error (error, - DBUS_ERROR_FAILED, - "Could not create file %s: %s\n", - filename_c, - _dbus_strerror (errno)); - return FALSE; - } - - _dbus_verbose ("exclusive file fd %d opened\n", fd); - - if (!_dbus_close (fd, NULL)) - { - dbus_set_error (error, - DBUS_ERROR_FAILED, - "Could not close file %s: %s\n", - filename_c, - _dbus_strerror (errno)); - return FALSE; - } - - return TRUE; -} - -/** - * Deletes the given file. - * - * @param filename the filename - * @param error error location - * - * @returns #TRUE if unlink() succeeded - */ -dbus_bool_t -_dbus_delete_file (const DBusString *filename, - DBusError *error) -{ - const char *filename_c; - - _DBUS_ASSERT_ERROR_IS_CLEAR (error); - - filename_c = _dbus_string_get_const_data (filename); + gettimeofday (&t, NULL); - if (unlink (filename_c) < 0) - { - dbus_set_error (error, DBUS_ERROR_FAILED, - "Failed to delete file %s: %s\n", - filename_c, _dbus_strerror (errno)); - return FALSE; - } - else - return TRUE; + if (tv_sec) + *tv_sec = t.tv_sec; + if (tv_usec) + *tv_usec = t.tv_usec; } /** @@ -2752,14 +2677,14 @@ _dbus_create_directory (const DBusString *filename, const char *filename_c; _DBUS_ASSERT_ERROR_IS_CLEAR (error); - + filename_c = _dbus_string_get_const_data (filename); if (mkdir (filename_c, 0700) < 0) { if (errno == EEXIST) return TRUE; - + dbus_set_error (error, DBUS_ERROR_FAILED, "Failed to create directory %s: %s\n", filename_c, _dbus_strerror (errno)); @@ -2789,7 +2714,7 @@ _dbus_concat_dir_and_file (DBusString *dir, if (_dbus_string_get_length (dir) == 0 || _dbus_string_get_length (next_component) == 0) return TRUE; - + dir_ends_in_slash = '/' == _dbus_string_get_byte (dir, _dbus_string_get_length (dir) - 1); @@ -2851,7 +2776,7 @@ _dbus_generate_pseudorandom_bytes (DBusString *str, { int old_len; char *p; - + old_len = _dbus_string_get_length (str); if (!_dbus_string_lengthen (str, n_bytes)) @@ -2884,7 +2809,7 @@ _dbus_generate_random_bytes (DBusString *str, * a DBusError. So we always fall back to pseudorandom * if the I/O fails. */ - + old_len = _dbus_string_get_length (str); fd = -1; @@ -2894,7 +2819,7 @@ _dbus_generate_random_bytes (DBusString *str, return _dbus_generate_pseudorandom_bytes (str, n_bytes); _dbus_verbose ("/dev/urandom fd %d opened\n", fd); - + if (_dbus_read (fd, str, n_bytes) != n_bytes) { _dbus_close (fd, NULL); @@ -2904,9 +2829,9 @@ _dbus_generate_random_bytes (DBusString *str, _dbus_verbose ("Read %d bytes from /dev/urandom\n", n_bytes); - + _dbus_close (fd, NULL); - + return TRUE; } @@ -2933,7 +2858,7 @@ const char* _dbus_strerror (int error_number) { const char *msg; - + msg = strerror (error_number); if (msg == NULL) msg = "unknown"; @@ -2958,17 +2883,17 @@ _dbus_disable_sigpipe (void) * @param fd the file descriptor */ void -_dbus_fd_set_close_on_exec (int fd) +_dbus_fd_set_close_on_exec (intptr_t fd) { int val; - + val = fcntl (fd, F_GETFD, 0); - + if (val < 0) return; val |= FD_CLOEXEC; - + fcntl (fd, F_SETFD, val); } @@ -2984,7 +2909,7 @@ _dbus_close (int fd, DBusError *error) { _DBUS_ASSERT_ERROR_IS_CLEAR (error); - + again: if (close (fd) < 0) { @@ -3004,6 +2929,7 @@ _dbus_close (int fd, * (i.e. avoids stdin/stdout/stderr). Sets O_CLOEXEC. * * @param fd the file descriptor to duplicate + * @param error address of error location. * @returns duplicated file descriptor * */ int @@ -3055,7 +2981,7 @@ _dbus_set_fd_nonblocking (int fd, int val; _DBUS_ASSERT_ERROR_IS_CLEAR (error); - + val = fcntl (fd, F_GETFL, 0); if (val < 0) { @@ -3088,17 +3014,17 @@ _dbus_set_fd_nonblocking (int fd, */ void _dbus_print_backtrace (void) -{ +{ #if defined (HAVE_BACKTRACE) && defined (DBUS_BUILT_R_DYNAMIC) void *bt[500]; int bt_size; int i; char **syms; - + bt_size = backtrace (bt, 500); syms = backtrace_symbols (bt, bt_size); - + i = 0; while (i < bt_size) { @@ -3122,11 +3048,6 @@ _dbus_print_backtrace (void) * * Marks both file descriptors as close-on-exec * - * @todo libdbus only uses this for the debug-pipe server, so in - * principle it could be in dbus-sysdeps-util.c, except that - * dbus-sysdeps-util.c isn't in libdbus when tests are enabled and the - * debug-pipe server is used. - * * @param fd1 return location for one end * @param fd2 return location for the other end * @param blocking #TRUE if pipe should be blocking @@ -3178,20 +3099,20 @@ _dbus_full_duplex_pipe (int *fd1, { dbus_set_error (error, _dbus_error_from_errno (errno), "Could not set full-duplex pipe nonblocking"); - + _dbus_close (fds[0], NULL); _dbus_close (fds[1], NULL); - + return FALSE; } - + *fd1 = fds[0]; *fd2 = fds[1]; _dbus_verbose ("full-duplex pipe %d <-> %d\n", *fd1, *fd2); - - return TRUE; + + return TRUE; #else _dbus_warn ("_dbus_full_duplex_pipe() not implemented on this OS\n"); dbus_set_error (error, DBUS_ERROR_FAILED, @@ -3206,27 +3127,87 @@ _dbus_full_duplex_pipe (int *fd1, * * @param format a printf-style format string * @param args arguments for the format string - * @returns length of the given format string and args + * @returns length of the given format string and args, or -1 if no memory */ int _dbus_printf_string_upper_bound (const char *format, va_list args) { - char c; - return vsnprintf (&c, 1, format, args); + char static_buf[1024]; + int bufsize = sizeof (static_buf); + int len; + va_list args_copy; + + DBUS_VA_COPY (args_copy, args); + len = vsnprintf (static_buf, bufsize, format, args_copy); + va_end (args_copy); + + /* If vsnprintf() returned non-negative, then either the string fits in + * static_buf, or this OS has the POSIX and C99 behaviour where vsnprintf + * returns the number of characters that were needed, or this OS returns the + * truncated length. + * + * We ignore the possibility that snprintf might just ignore the length and + * overrun the buffer (64-bit Solaris 7), because that's pathological. + * If your libc is really that bad, come back when you have a better one. */ + if (len == bufsize) + { + /* This could be the truncated length (Tru64 and IRIX have this bug), + * or the real length could be coincidentally the same. Which is it? + * If vsnprintf returns the truncated length, we'll go to the slow + * path. */ + DBUS_VA_COPY (args_copy, args); + + if (vsnprintf (static_buf, 1, format, args_copy) == 1) + len = -1; + + va_end (args_copy); + } + + /* If vsnprintf() returned negative, we have to do more work. + * HP-UX returns negative. */ + while (len < 0) + { + char *buf; + + bufsize *= 2; + + buf = dbus_malloc (bufsize); + + if (buf == NULL) + return -1; + + DBUS_VA_COPY (args_copy, args); + len = vsnprintf (buf, bufsize, format, args_copy); + va_end (args_copy); + + dbus_free (buf); + + /* If the reported length is exactly the buffer size, round up to the + * next size, in case vsnprintf has been returning the truncated + * length */ + if (len == bufsize) + len = -1; + } + + return len; } /** - * Gets the temporary files directory by inspecting the environment variables + * Gets the temporary files directory by inspecting the environment variables * TMPDIR, TMP, and TEMP in that order. If none of those are set "/tmp" is returned * - * @returns location of temp directory + * @returns location of temp directory, or #NULL if no memory for locking */ const char* _dbus_get_tmpdir(void) { + /* Protected by _DBUS_LOCK_sysdeps */ static const char* tmpdir = NULL; + if (!_DBUS_LOCK (sysdeps)) + return NULL; + if (tmpdir == NULL) { /* TMPDIR is what glibc uses, then @@ -3248,12 +3229,15 @@ _dbus_get_tmpdir(void) if (tmpdir == NULL) tmpdir = "/tmp"; } - + + _DBUS_UNLOCK (sysdeps); + _dbus_assert(tmpdir != NULL); - + return tmpdir; } +#if defined(DBUS_ENABLE_X11_AUTOLAUNCH) || defined(DBUS_ENABLE_LAUNCHD) /** * Execute a subprocess, returning up to 1024 bytes of output * into @p result. @@ -3286,11 +3270,10 @@ _read_subprocess_line_argv (const char *progpath, int ret; int status; int orig_len; - int i; dbus_bool_t retval; sigset_t new_set, old_set; - + _DBUS_ASSERT_ERROR_IS_CLEAR (error); retval = FALSE; @@ -3301,9 +3284,9 @@ _read_subprocess_line_argv (const char *progpath, sigemptyset (&new_set); sigaddset (&new_set, SIGCHLD); sigprocmask (SIG_BLOCK, &new_set, &old_set); - + orig_len = _dbus_string_get_length (result); - + #define READ_END 0 #define WRITE_END 1 if (pipe (result_pipe) < 0) @@ -3339,7 +3322,6 @@ _read_subprocess_line_argv (const char *progpath, if (pid == 0) { /* child process */ - int maxfds; int fd; fd = open ("/dev/null", O_RDWR); @@ -3348,30 +3330,19 @@ _read_subprocess_line_argv (const char *progpath, _exit (1); _dbus_verbose ("/dev/null fd %d opened\n", fd); - + /* set-up stdXXX */ close (result_pipe[READ_END]); close (errors_pipe[READ_END]); - close (0); /* close stdin */ - close (1); /* close stdout */ - close (2); /* close stderr */ - if (dup2 (fd, 0) == -1) + if (dup2 (fd, 0) == -1) /* setup stdin */ _exit (1); - if (dup2 (result_pipe[WRITE_END], 1) == -1) + if (dup2 (result_pipe[WRITE_END], 1) == -1) /* setup stdout */ _exit (1); - if (dup2 (errors_pipe[WRITE_END], 2) == -1) + if (dup2 (errors_pipe[WRITE_END], 2) == -1) /* setup stderr */ _exit (1); - maxfds = sysconf (_SC_OPEN_MAX); - /* Pick something reasonable if for some reason sysconf - * says unlimited. - */ - if (maxfds < 0) - maxfds = 1024; - /* close all inherited fds */ - for (i = 3; i < maxfds; i++) - close (i); + _dbus_close_all (); sigprocmask (SIG_SETMASK, &old_set, NULL); @@ -3403,7 +3374,7 @@ _read_subprocess_line_argv (const char *progpath, errors_pipe[WRITE_END] = -1; ret = 0; - do + do { ret = _dbus_read (result_pipe[READ_END], result, 1024); } @@ -3422,7 +3393,12 @@ _read_subprocess_line_argv (const char *progpath, { /* The process ended with error */ DBusString error_message; - _dbus_string_init (&error_message); + if (!_dbus_string_init (&error_message)) + { + _DBUS_SET_OOM (error); + goto out; + } + ret = 0; do { @@ -3443,7 +3419,7 @@ _read_subprocess_line_argv (const char *progpath, } retval = TRUE; - + out: sigprocmask (SIG_SETMASK, &old_set, NULL); @@ -3461,8 +3437,9 @@ _read_subprocess_line_argv (const char *progpath, if (errors_pipe[1] != -1) close (errors_pipe[1]); - return retval; + return retval; } +#endif /** * Returns the address of a new session bus. @@ -3471,34 +3448,60 @@ _read_subprocess_line_argv (const char *progpath, * address. If a failure happens, returns #FALSE and * sets an error in @p error. * + * @param scope scope of autolaunch (Windows only) * @param address a DBusString where the address can be stored * @param error a DBusError to store the error in case of failure * @returns #TRUE on success, #FALSE if an error happened */ dbus_bool_t -_dbus_get_autolaunch_address (DBusString *address, +_dbus_get_autolaunch_address (const char *scope, + DBusString *address, DBusError *error) { - static char *argv[6]; +#ifdef DBUS_ENABLE_X11_AUTOLAUNCH + /* Perform X11-based autolaunch. (We also support launchd-based autolaunch, + * but that's done elsewhere, and if it worked, this function wouldn't + * be called.) */ + const char *display; + char *argv[6]; int i; DBusString uuid; dbus_bool_t retval; - + + if (_dbus_check_setuid ()) + { + dbus_set_error_const (error, DBUS_ERROR_NOT_SUPPORTED, + "Unable to autolaunch when setuid"); + return FALSE; + } + _DBUS_ASSERT_ERROR_IS_CLEAR (error); retval = FALSE; + /* fd.o #19997: if $DISPLAY isn't set to something useful, then + * dbus-launch-x11 is just going to fail. Rather than trying to + * run it, we might as well bail out early with a nice error. */ + display = _dbus_getenv ("DISPLAY"); + + if (display == NULL || display[0] == '\0') + { + dbus_set_error_const (error, DBUS_ERROR_NOT_SUPPORTED, + "Unable to autolaunch a dbus-daemon without a $DISPLAY for X11"); + return FALSE; + } + if (!_dbus_string_init (&uuid)) { _DBUS_SET_OOM (error); return FALSE; } - + if (!_dbus_get_local_machine_uuid_encoded (&uuid)) { _DBUS_SET_OOM (error); goto out; } - + i = 0; argv[i] = "dbus-launch"; ++i; @@ -3522,6 +3525,12 @@ _dbus_get_autolaunch_address (DBusString *address, out: _dbus_string_free (&uuid); return retval; +#else + dbus_set_error_const (error, DBUS_ERROR_NOT_SUPPORTED, + "Using X11 for dbus-daemon autolaunch was disabled at compile time, " + "set your DBUS_SESSION_BUS_ADDRESS instead"); + return FALSE; +#endif } /** @@ -3548,222 +3557,169 @@ _dbus_read_local_machine_uuid (DBusGUID *machine_id, DBusError *error) { DBusString filename; + dbus_bool_t b; + _dbus_string_init_const (&filename, DBUS_MACHINE_UUID_FILE); - return _dbus_read_uuid_file (&filename, machine_id, create_if_not_found, error); -} -#define DBUS_UNIX_STANDARD_SESSION_SERVICEDIR "/dbus-1/services" -#define DBUS_UNIX_STANDARD_SYSTEM_SERVICEDIR "/dbus-1/system-services" + b = _dbus_read_uuid_file (&filename, machine_id, create_if_not_found, error); + if (b) + return TRUE; -/** - * Determines the address of the session bus by querying a - * platform-specific method. - * - * The first parameter will be a boolean specifying whether - * or not a dynamic session lookup is supported on this platform. - * - * If supported is TRUE and the return value is #TRUE, the - * address will be appended to @p address. - * If a failure happens, returns #FALSE and sets an error in - * @p error. - * - * If supported is FALSE, ignore the return value. - * - * @param supported returns whether this method is supported - * @param address a DBusString where the address can be stored - * @param error a DBusError to store the error in case of failure - * @returns #TRUE on success, #FALSE if an error happened - */ -dbus_bool_t -_dbus_lookup_session_address (dbus_bool_t *supported, - DBusString *address, - DBusError *error) -{ - /* On non-Mac Unix platforms, if the session address isn't already - * set in DBUS_SESSION_BUS_ADDRESS environment variable, we punt and - * fall back to the autolaunch: global default; see - * init_session_address in dbus/dbus-bus.c. */ - *supported = FALSE; - return TRUE; + dbus_error_free (error); + + /* Fallback to the system machine ID */ + _dbus_string_init_const (&filename, "/etc/machine-id"); + return _dbus_read_uuid_file (&filename, machine_id, FALSE, error); } /** - * Returns the standard directories for a session bus to look for service - * activation files - * - * On UNIX this should be the standard xdg freedesktop.org data directories: - * - * XDG_DATA_HOME=${XDG_DATA_HOME-$HOME/.local/share} - * XDG_DATA_DIRS=${XDG_DATA_DIRS-/usr/local/share:/usr/share} - * - * and - * - * DBUS_DATADIR - * - * @param dirs the directory list we are returning - * @returns #FALSE on OOM + * quries launchd for a specific env var which holds the socket path. + * @param socket_path append the socket path to this DBusString + * @param launchd_env_var the env var to look up + * @param error a DBusError to store the error in case of failure + * @return the value of the env var */ - -dbus_bool_t -_dbus_get_standard_session_servicedirs (DBusList **dirs) +dbus_bool_t +_dbus_lookup_launchd_socket (DBusString *socket_path, + const char *launchd_env_var, + DBusError *error) { - const char *xdg_data_home; - const char *xdg_data_dirs; - DBusString servicedir_path; - - if (!_dbus_string_init (&servicedir_path)) - return FALSE; - - xdg_data_home = _dbus_getenv ("XDG_DATA_HOME"); - xdg_data_dirs = _dbus_getenv ("XDG_DATA_DIRS"); +#ifdef DBUS_ENABLE_LAUNCHD + char *argv[4]; + int i; - if (xdg_data_dirs != NULL) - { - if (!_dbus_string_append (&servicedir_path, xdg_data_dirs)) - goto oom; + _DBUS_ASSERT_ERROR_IS_CLEAR (error); - if (!_dbus_string_append (&servicedir_path, ":")) - goto oom; - } - else + if (_dbus_check_setuid ()) { - if (!_dbus_string_append (&servicedir_path, "/usr/local/share:/usr/share:")) - goto oom; + dbus_set_error_const (error, DBUS_ERROR_NOT_SUPPORTED, + "Unable to find launchd socket when setuid"); + return FALSE; } - /* - * add configured datadir to defaults - * this may be the same as an xdg dir - * however the config parser should take - * care of duplicates - */ - if (!_dbus_string_append (&servicedir_path, DBUS_DATADIR":")) - goto oom; + i = 0; + argv[i] = "launchctl"; + ++i; + argv[i] = "getenv"; + ++i; + argv[i] = (char*)launchd_env_var; + ++i; + argv[i] = NULL; + ++i; - if (xdg_data_home != NULL) + _dbus_assert (i == _DBUS_N_ELEMENTS (argv)); + + if (!_read_subprocess_line_argv(argv[0], TRUE, argv, socket_path, error)) { - if (!_dbus_string_append (&servicedir_path, xdg_data_home)) - goto oom; + return FALSE; } - else - { - const DBusString *homedir; - DBusString local_share; - - if (!_dbus_homedir_from_current_process (&homedir)) - goto oom; - - if (!_dbus_string_append (&servicedir_path, _dbus_string_get_const_data (homedir))) - goto oom; - _dbus_string_init_const (&local_share, "/.local/share"); - if (!_dbus_concat_dir_and_file (&servicedir_path, &local_share)) - goto oom; + /* no error, but no result either */ + if (_dbus_string_get_length(socket_path) == 0) + { + return FALSE; } - if (!_dbus_split_paths_and_append (&servicedir_path, - DBUS_UNIX_STANDARD_SESSION_SERVICEDIR, - dirs)) - goto oom; - - _dbus_string_free (&servicedir_path); + /* strip the carriage-return */ + _dbus_string_shorten(socket_path, 1); return TRUE; - - oom: - _dbus_string_free (&servicedir_path); +#else /* DBUS_ENABLE_LAUNCHD */ + dbus_set_error(error, DBUS_ERROR_NOT_SUPPORTED, + "can't lookup socket from launchd; launchd support not compiled in"); return FALSE; +#endif } - -/** - * Returns the standard directories for a system bus to look for service - * activation files - * - * On UNIX this should be the standard xdg freedesktop.org data directories: - * - * XDG_DATA_DIRS=${XDG_DATA_DIRS-/usr/local/share:/usr/share} - * - * and - * - * DBUS_DATADIR - * - * On Windows there is no system bus and this function can return nothing. - * - * @param dirs the directory list we are returning - * @returns #FALSE on OOM - */ - -dbus_bool_t -_dbus_get_standard_system_servicedirs (DBusList **dirs) +#ifdef DBUS_ENABLE_LAUNCHD +static dbus_bool_t +_dbus_lookup_session_address_launchd (DBusString *address, DBusError *error) { - const char *xdg_data_dirs; - DBusString servicedir_path; + dbus_bool_t valid_socket; + DBusString socket_path; - if (!_dbus_string_init (&servicedir_path)) - return FALSE; + if (_dbus_check_setuid ()) + { + dbus_set_error_const (error, DBUS_ERROR_NOT_SUPPORTED, + "Unable to find launchd socket when setuid"); + return FALSE; + } + + if (!_dbus_string_init (&socket_path)) + { + _DBUS_SET_OOM (error); + return FALSE; + } - xdg_data_dirs = _dbus_getenv ("XDG_DATA_DIRS"); + valid_socket = _dbus_lookup_launchd_socket (&socket_path, "DBUS_LAUNCHD_SESSION_BUS_SOCKET", error); - if (xdg_data_dirs != NULL) + if (dbus_error_is_set(error)) { - if (!_dbus_string_append (&servicedir_path, xdg_data_dirs)) - goto oom; + _dbus_string_free(&socket_path); + return FALSE; + } - if (!_dbus_string_append (&servicedir_path, ":")) - goto oom; + if (!valid_socket) + { + dbus_set_error(error, "no socket path", + "launchd did not provide a socket path, " + "verify that org.freedesktop.dbus-session.plist is loaded!"); + _dbus_string_free(&socket_path); + return FALSE; } - else + if (!_dbus_string_append (address, "unix:path=")) { - if (!_dbus_string_append (&servicedir_path, "/usr/local/share:/usr/share:")) - goto oom; + _DBUS_SET_OOM (error); + _dbus_string_free(&socket_path); + return FALSE; + } + if (!_dbus_string_copy (&socket_path, 0, address, + _dbus_string_get_length (address))) + { + _DBUS_SET_OOM (error); + _dbus_string_free(&socket_path); + return FALSE; } - /* - * add configured datadir to defaults - * this may be the same as an xdg dir - * however the config parser should take - * care of duplicates - */ - if (!_dbus_string_append (&servicedir_path, DBUS_DATADIR":")) - goto oom; - - if (!_dbus_split_paths_and_append (&servicedir_path, - DBUS_UNIX_STANDARD_SYSTEM_SERVICEDIR, - dirs)) - goto oom; - - _dbus_string_free (&servicedir_path); + _dbus_string_free(&socket_path); return TRUE; - - oom: - _dbus_string_free (&servicedir_path); - return FALSE; -} - -/** - * Append the absolute path of the system.conf file - * (there is no system bus on Windows so this can just - * return FALSE and print a warning or something) - * - * @param str the string to append to - * @returns #FALSE if no memory - */ -dbus_bool_t -_dbus_append_system_config_file (DBusString *str) -{ - return _dbus_string_append (str, DBUS_SYSTEM_CONFIG_FILE); } +#endif /** - * Append the absolute path of the session.conf file. - * - * @param str the string to append to - * @returns #FALSE if no memory + * Determines the address of the session bus by querying a + * platform-specific method. + * + * The first parameter will be a boolean specifying whether + * or not a dynamic session lookup is supported on this platform. + * + * If supported is TRUE and the return value is #TRUE, the + * address will be appended to @p address. + * If a failure happens, returns #FALSE and sets an error in + * @p error. + * + * If supported is FALSE, ignore the return value. + * + * @param supported returns whether this method is supported + * @param address a DBusString where the address can be stored + * @param error a DBusError to store the error in case of failure + * @returns #TRUE on success, #FALSE if an error happened */ dbus_bool_t -_dbus_append_session_config_file (DBusString *str) +_dbus_lookup_session_address (dbus_bool_t *supported, + DBusString *address, + DBusError *error) { - return _dbus_string_append (str, DBUS_SESSION_CONFIG_FILE); +#ifdef DBUS_ENABLE_LAUNCHD + *supported = TRUE; + return _dbus_lookup_session_address_launchd (address, error); +#else + /* On non-Mac Unix platforms, if the session address isn't already + * set in DBUS_SESSION_BUS_ADDRESS environment variable, we punt and + * fall back to the autolaunch: global default; see + * init_session_address in dbus/dbus-bus.c. */ + *supported = FALSE; + return TRUE; +#endif } /** @@ -3771,7 +3727,7 @@ _dbus_append_session_config_file (DBusString *str) * caches should be nuked. Of course any caches that need explicit reload * are probably broken, but c'est la vie. * - * + * */ void _dbus_flush_caches (void) @@ -3786,10 +3742,10 @@ _dbus_flush_caches (void) * * On UNIX the directory is ~/.dbus-keyrings while on Windows it should probably * be something else, since the dotfile convention is not normal on Windows. - * + * * @param directory string to append directory to * @param credentials credentials the directory should be for - * + * * @returns #FALSE on no memory */ dbus_bool_t @@ -3799,10 +3755,10 @@ _dbus_append_keyring_directory_for_credentials (DBusString *directory, DBusString homedir; DBusString dotdir; dbus_uid_t uid; - + _dbus_assert (credentials != NULL); _dbus_assert (!_dbus_credentials_are_anonymous (credentials)); - + if (!_dbus_string_init (&homedir)) return FALSE; @@ -3811,11 +3767,11 @@ _dbus_append_keyring_directory_for_credentials (DBusString *directory, if (!_dbus_homedir_from_uid (uid, &homedir)) goto failed; - -#ifdef DBUS_BUILD_TESTS + +#ifdef DBUS_ENABLE_EMBEDDED_TESTS { const char *override; - + override = _dbus_getenv ("DBUS_TEST_HOMEDIR"); if (override != NULL && *override != '\0') { @@ -3828,6 +3784,8 @@ _dbus_append_keyring_directory_for_credentials (DBusString *directory, } else { + /* Not strictly thread-safe, but if we fail at thread-safety here, + * the worst that will happen is some extra warnings. */ static dbus_bool_t already_warned = FALSE; if (!already_warned) { @@ -3842,7 +3800,7 @@ _dbus_append_keyring_directory_for_credentials (DBusString *directory, if (!_dbus_concat_dir_and_file (&homedir, &dotdir)) goto failed; - + if (!_dbus_string_copy (&homedir, 0, directory, _dbus_string_get_length (directory))) { goto failed; @@ -3850,17 +3808,18 @@ _dbus_append_keyring_directory_for_credentials (DBusString *directory, _dbus_string_free (&homedir); return TRUE; - - failed: + + failed: _dbus_string_free (&homedir); return FALSE; } //PENDING(kdab) docs -void -_dbus_daemon_publish_session_bus_address (const char* addr) +dbus_bool_t +_dbus_daemon_publish_session_bus_address (const char* addr, + const char *scope) { - + return TRUE; } //PENDING(kdab) docs @@ -3942,4 +3901,191 @@ _dbus_socket_can_pass_unix_fd(int fd) { #endif } +/** + * Closes all file descriptors except the first three (i.e. stdin, + * stdout, stderr). + */ +void +_dbus_close_all (void) +{ + int maxfds, i; + +#ifdef __linux__ + DIR *d; + + /* On Linux we can optimize this a bit if /proc is available. If it + isn't available, fall back to the brute force way. */ + + d = opendir ("/proc/self/fd"); + if (d) + { + for (;;) + { + struct dirent buf, *de; + int k, fd; + long l; + char *e = NULL; + + k = readdir_r (d, &buf, &de); + if (k != 0 || !de) + break; + + if (de->d_name[0] == '.') + continue; + + errno = 0; + l = strtol (de->d_name, &e, 10); + if (errno != 0 || e == NULL || *e != '\0') + continue; + + fd = (int) l; + if (fd < 3) + continue; + + if (fd == dirfd (d)) + continue; + + close (fd); + } + + closedir (d); + return; + } +#endif + + maxfds = sysconf (_SC_OPEN_MAX); + + /* Pick something reasonable if for some reason sysconf says + * unlimited. + */ + if (maxfds < 0) + maxfds = 1024; + + /* close all inherited fds */ + for (i = 3; i < maxfds; i++) + close (i); +} + +/** + * **NOTE**: If you modify this function, please also consider making + * the corresponding change in GLib. See + * glib/gutils.c:g_check_setuid(). + * + * Returns TRUE if the current process was executed as setuid (or an + * equivalent __libc_enable_secure is available). See: + * http://osdir.com/ml/linux.lfs.hardened/2007-04/msg00032.html + */ +dbus_bool_t +_dbus_check_setuid (void) +{ + /* TODO: get __libc_enable_secure exported from glibc. + * See http://www.openwall.com/lists/owl-dev/2012/08/14/1 + */ +#if 0 && defined(HAVE_LIBC_ENABLE_SECURE) + { + /* See glibc/include/unistd.h */ + extern int __libc_enable_secure; + return __libc_enable_secure; + } +#elif defined(HAVE_ISSETUGID) + /* BSD: http://www.freebsd.org/cgi/man.cgi?query=issetugid&sektion=2 */ + return issetugid (); +#else + uid_t ruid, euid, suid; /* Real, effective and saved user ID's */ + gid_t rgid, egid, sgid; /* Real, effective and saved group ID's */ + + /* We call into this function from _dbus_threads_init_platform_specific() + * to make sure these are initialized before we start threading. */ + static dbus_bool_t check_setuid_initialised; + static dbus_bool_t is_setuid; + + if (_DBUS_UNLIKELY (!check_setuid_initialised)) + { +#ifdef HAVE_GETRESUID + if (getresuid (&ruid, &euid, &suid) != 0 || + getresgid (&rgid, &egid, &sgid) != 0) +#endif /* HAVE_GETRESUID */ + { + suid = ruid = getuid (); + sgid = rgid = getgid (); + euid = geteuid (); + egid = getegid (); + } + + check_setuid_initialised = TRUE; + is_setuid = (ruid != euid || ruid != suid || + rgid != egid || rgid != sgid); + + } + return is_setuid; +#endif +} + +/** + * Read the address from the socket and append it to the string + * + * @param fd the socket + * @param address + * @param error return location for error code + */ +dbus_bool_t +_dbus_append_address_from_socket (int fd, + DBusString *address, + DBusError *error) +{ + union { + struct sockaddr sa; + struct sockaddr_storage storage; + struct sockaddr_un un; + struct sockaddr_in ipv4; + struct sockaddr_in6 ipv6; + } socket; + char hostip[INET6_ADDRSTRLEN]; + int size = sizeof (socket); + + if (getsockname (fd, &socket.sa, &size)) + goto err; + + switch (socket.sa.sa_family) + { + case AF_UNIX: + if (socket.un.sun_path[0]=='\0') + { + if (_dbus_string_append_printf (address, "unix:abstract=%s", &(socket.un.sun_path[1]))) + return TRUE; + } + else + { + if (_dbus_string_append_printf (address, "unix:path=%s", socket.un.sun_path)) + return TRUE; + } + break; + case AF_INET: + if (inet_ntop (AF_INET, &socket.ipv4.sin_addr, hostip, sizeof (hostip))) + if (_dbus_string_append_printf (address, "tcp:family=ipv4,host=%s,port=%u", + hostip, ntohs (socket.ipv4.sin_port))) + return TRUE; + break; +#ifdef AF_INET6 + case AF_INET6: + if (inet_ntop (AF_INET6, &socket.ipv6.sin6_addr, hostip, sizeof (hostip))) + if (_dbus_string_append_printf (address, "tcp:family=ipv6,host=%s,port=%u", + hostip, ntohs (socket.ipv6.sin6_port))) + return TRUE; + break; +#endif + default: + dbus_set_error (error, + _dbus_error_from_errno (EINVAL), + "Failed to read address from socket: Unknown socket type."); + return FALSE; + } + err: + dbus_set_error (error, + _dbus_error_from_errno (errno), + "Failed to open socket: %s", + _dbus_strerror (errno)); + return FALSE; +} + /* tests in dbus-sysdeps-util.c */