153a5a1b3Sopenharmony_ci/*** 253a5a1b3Sopenharmony_ci This file is part of PulseAudio. 353a5a1b3Sopenharmony_ci 453a5a1b3Sopenharmony_ci Copyright 2004-2006 Lennart Poettering 553a5a1b3Sopenharmony_ci Copyright 2004 Joe Marcus Clarke 653a5a1b3Sopenharmony_ci Copyright 2006-2007 Pierre Ossman <ossman@cendio.se> for Cendio AB 753a5a1b3Sopenharmony_ci 853a5a1b3Sopenharmony_ci PulseAudio is free software; you can redistribute it and/or modify 953a5a1b3Sopenharmony_ci it under the terms of the GNU Lesser General Public License as 1053a5a1b3Sopenharmony_ci published by the Free Software Foundation; either version 2.1 of the 1153a5a1b3Sopenharmony_ci License, or (at your option) any later version. 1253a5a1b3Sopenharmony_ci 1353a5a1b3Sopenharmony_ci PulseAudio is distributed in the hope that it will be useful, but 1453a5a1b3Sopenharmony_ci WITHOUT ANY WARRANTY; without even the implied warranty of 1553a5a1b3Sopenharmony_ci MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 1653a5a1b3Sopenharmony_ci Lesser General Public License for more details. 1753a5a1b3Sopenharmony_ci 1853a5a1b3Sopenharmony_ci You should have received a copy of the GNU Lesser General Public 1953a5a1b3Sopenharmony_ci License along with PulseAudio; if not, see <http://www.gnu.org/licenses/>. 2053a5a1b3Sopenharmony_ci***/ 2153a5a1b3Sopenharmony_ci 2253a5a1b3Sopenharmony_ci#ifdef HAVE_CONFIG_H 2353a5a1b3Sopenharmony_ci#include <config.h> 2453a5a1b3Sopenharmony_ci#endif 2553a5a1b3Sopenharmony_ci 2653a5a1b3Sopenharmony_ci#ifndef LOG_TAG 2753a5a1b3Sopenharmony_ci#define LOG_TAG "CoreUtil" 2853a5a1b3Sopenharmony_ci#endif 2953a5a1b3Sopenharmony_ci 3053a5a1b3Sopenharmony_ci#include <math.h> 3153a5a1b3Sopenharmony_ci#include <stdarg.h> 3253a5a1b3Sopenharmony_ci#include <stdlib.h> 3353a5a1b3Sopenharmony_ci#include <signal.h> 3453a5a1b3Sopenharmony_ci#include <errno.h> 3553a5a1b3Sopenharmony_ci#include <string.h> 3653a5a1b3Sopenharmony_ci#include <stdio.h> 3753a5a1b3Sopenharmony_ci#include <fcntl.h> 3853a5a1b3Sopenharmony_ci#include <unistd.h> 3953a5a1b3Sopenharmony_ci#include <limits.h> 4053a5a1b3Sopenharmony_ci#include <ctype.h> 4153a5a1b3Sopenharmony_ci#include <sys/types.h> 4253a5a1b3Sopenharmony_ci#include <sys/stat.h> 4353a5a1b3Sopenharmony_ci#include <dirent.h> 4453a5a1b3Sopenharmony_ci 4553a5a1b3Sopenharmony_ci#ifdef HAVE_LANGINFO_H 4653a5a1b3Sopenharmony_ci#include <langinfo.h> 4753a5a1b3Sopenharmony_ci#endif 4853a5a1b3Sopenharmony_ci 4953a5a1b3Sopenharmony_ci#ifdef HAVE_UNAME 5053a5a1b3Sopenharmony_ci#include <sys/utsname.h> 5153a5a1b3Sopenharmony_ci#endif 5253a5a1b3Sopenharmony_ci 5353a5a1b3Sopenharmony_ci#if defined(HAVE_REGEX_H) 5453a5a1b3Sopenharmony_ci#include <regex.h> 5553a5a1b3Sopenharmony_ci#elif defined(HAVE_PCREPOSIX_H) 5653a5a1b3Sopenharmony_ci#include <pcreposix.h> 5753a5a1b3Sopenharmony_ci#endif 5853a5a1b3Sopenharmony_ci 5953a5a1b3Sopenharmony_ci#ifdef HAVE_STRTOD_L 6053a5a1b3Sopenharmony_ci#ifdef HAVE_LOCALE_H 6153a5a1b3Sopenharmony_ci#include <locale.h> 6253a5a1b3Sopenharmony_ci#endif 6353a5a1b3Sopenharmony_ci#ifdef HAVE_XLOCALE_H 6453a5a1b3Sopenharmony_ci#include <xlocale.h> 6553a5a1b3Sopenharmony_ci#endif 6653a5a1b3Sopenharmony_ci#endif 6753a5a1b3Sopenharmony_ci 6853a5a1b3Sopenharmony_ci#ifdef HAVE_SYS_RESOURCE_H 6953a5a1b3Sopenharmony_ci#include <sys/resource.h> 7053a5a1b3Sopenharmony_ci#endif 7153a5a1b3Sopenharmony_ci 7253a5a1b3Sopenharmony_ci#ifdef HAVE_SYS_CAPABILITY_H 7353a5a1b3Sopenharmony_ci#include <sys/capability.h> 7453a5a1b3Sopenharmony_ci#endif 7553a5a1b3Sopenharmony_ci 7653a5a1b3Sopenharmony_ci#ifdef HAVE_SYS_MMAN_H 7753a5a1b3Sopenharmony_ci#include <sys/mman.h> 7853a5a1b3Sopenharmony_ci#endif 7953a5a1b3Sopenharmony_ci 8053a5a1b3Sopenharmony_ci#ifdef HAVE_PTHREAD 8153a5a1b3Sopenharmony_ci#include <pthread.h> 8253a5a1b3Sopenharmony_ci#endif 8353a5a1b3Sopenharmony_ci 8453a5a1b3Sopenharmony_ci#ifdef HAVE_NETDB_H 8553a5a1b3Sopenharmony_ci#include <netdb.h> 8653a5a1b3Sopenharmony_ci#endif 8753a5a1b3Sopenharmony_ci 8853a5a1b3Sopenharmony_ci#ifdef HAVE_WINDOWS_H 8953a5a1b3Sopenharmony_ci#include <windows.h> 9053a5a1b3Sopenharmony_ci#include <shlobj.h> 9153a5a1b3Sopenharmony_ci#endif 9253a5a1b3Sopenharmony_ci 9353a5a1b3Sopenharmony_ci#ifndef ENOTSUP 9453a5a1b3Sopenharmony_ci#define ENOTSUP 135 9553a5a1b3Sopenharmony_ci#endif 9653a5a1b3Sopenharmony_ci 9753a5a1b3Sopenharmony_ci#ifdef HAVE_PWD_H 9853a5a1b3Sopenharmony_ci#include <pwd.h> 9953a5a1b3Sopenharmony_ci#endif 10053a5a1b3Sopenharmony_ci 10153a5a1b3Sopenharmony_ci#ifdef HAVE_GRP_H 10253a5a1b3Sopenharmony_ci#include <grp.h> 10353a5a1b3Sopenharmony_ci#endif 10453a5a1b3Sopenharmony_ci 10553a5a1b3Sopenharmony_ci#ifdef HAVE_LIBSAMPLERATE 10653a5a1b3Sopenharmony_ci#include <samplerate.h> 10753a5a1b3Sopenharmony_ci#endif 10853a5a1b3Sopenharmony_ci 10953a5a1b3Sopenharmony_ci#ifdef HAVE_DBUS 11053a5a1b3Sopenharmony_ci#include <pulsecore/rtkit.h> 11153a5a1b3Sopenharmony_ci#endif 11253a5a1b3Sopenharmony_ci 11353a5a1b3Sopenharmony_ci#if defined(__linux__) && !defined(__ANDROID__) 11453a5a1b3Sopenharmony_ci#include <sys/personality.h> 11553a5a1b3Sopenharmony_ci#endif 11653a5a1b3Sopenharmony_ci 11753a5a1b3Sopenharmony_ci#ifdef HAVE_CPUID_H 11853a5a1b3Sopenharmony_ci#include <cpuid.h> 11953a5a1b3Sopenharmony_ci#endif 12053a5a1b3Sopenharmony_ci 12153a5a1b3Sopenharmony_ci#include <pulse/xmalloc.h> 12253a5a1b3Sopenharmony_ci#include <pulse/util.h> 12353a5a1b3Sopenharmony_ci#include <pulse/utf8.h> 12453a5a1b3Sopenharmony_ci 12553a5a1b3Sopenharmony_ci#include <pulsecore/core-error.h> 12653a5a1b3Sopenharmony_ci#include <pulsecore/socket.h> 12753a5a1b3Sopenharmony_ci#include <pulsecore/log.h> 12853a5a1b3Sopenharmony_ci#include <pulsecore/macro.h> 12953a5a1b3Sopenharmony_ci#include <pulsecore/thread.h> 13053a5a1b3Sopenharmony_ci#include <pulsecore/strbuf.h> 13153a5a1b3Sopenharmony_ci#include <pulsecore/usergroup.h> 13253a5a1b3Sopenharmony_ci#include <pulsecore/strlist.h> 13353a5a1b3Sopenharmony_ci#include <pulsecore/pipe.h> 13453a5a1b3Sopenharmony_ci#include <pulsecore/once.h> 13553a5a1b3Sopenharmony_ci 13653a5a1b3Sopenharmony_ci#include "core-util.h" 13753a5a1b3Sopenharmony_ci 13853a5a1b3Sopenharmony_ci/* Not all platforms have this */ 13953a5a1b3Sopenharmony_ci#ifndef MSG_NOSIGNAL 14053a5a1b3Sopenharmony_ci#define MSG_NOSIGNAL 0 14153a5a1b3Sopenharmony_ci#endif 14253a5a1b3Sopenharmony_ci 14353a5a1b3Sopenharmony_ci#define NEWLINE "\r\n" 14453a5a1b3Sopenharmony_ci#define WHITESPACE "\n\r \t" 14553a5a1b3Sopenharmony_ci 14653a5a1b3Sopenharmony_cistatic pa_strlist *recorded_env = NULL; 14753a5a1b3Sopenharmony_ci 14853a5a1b3Sopenharmony_ci#ifdef OS_IS_WIN32 14953a5a1b3Sopenharmony_cistatic fd_set nonblocking_fds; 15053a5a1b3Sopenharmony_ci#endif 15153a5a1b3Sopenharmony_ci 15253a5a1b3Sopenharmony_ci#ifdef OS_IS_WIN32 15353a5a1b3Sopenharmony_ci 15453a5a1b3Sopenharmony_ci/* Returns the directory of the current DLL, with '/bin/' removed if it is the last component */ 15553a5a1b3Sopenharmony_cichar *pa_win32_get_toplevel(HANDLE handle) { 15653a5a1b3Sopenharmony_ci static char *toplevel = NULL; 15753a5a1b3Sopenharmony_ci 15853a5a1b3Sopenharmony_ci if (!toplevel) { 15953a5a1b3Sopenharmony_ci char library_path[MAX_PATH]; 16053a5a1b3Sopenharmony_ci char *p; 16153a5a1b3Sopenharmony_ci 16253a5a1b3Sopenharmony_ci if (!GetModuleFileName(handle, library_path, MAX_PATH)) 16353a5a1b3Sopenharmony_ci return NULL; 16453a5a1b3Sopenharmony_ci 16553a5a1b3Sopenharmony_ci toplevel = pa_xstrdup(library_path); 16653a5a1b3Sopenharmony_ci 16753a5a1b3Sopenharmony_ci p = strrchr(toplevel, PA_PATH_SEP_CHAR); 16853a5a1b3Sopenharmony_ci if (p) 16953a5a1b3Sopenharmony_ci *p = '\0'; 17053a5a1b3Sopenharmony_ci 17153a5a1b3Sopenharmony_ci p = strrchr(toplevel, PA_PATH_SEP_CHAR); 17253a5a1b3Sopenharmony_ci if (p && pa_streq(p + 1, "bin")) 17353a5a1b3Sopenharmony_ci *p = '\0'; 17453a5a1b3Sopenharmony_ci } 17553a5a1b3Sopenharmony_ci 17653a5a1b3Sopenharmony_ci return toplevel; 17753a5a1b3Sopenharmony_ci} 17853a5a1b3Sopenharmony_ci 17953a5a1b3Sopenharmony_cichar *pa_win32_get_system_appdata() { 18053a5a1b3Sopenharmony_ci static char appdata[MAX_PATH] = {0}; 18153a5a1b3Sopenharmony_ci 18253a5a1b3Sopenharmony_ci if (!*appdata && SHGetFolderPathAndSubDirA(NULL, CSIDL_COMMON_APPDATA|CSIDL_FLAG_CREATE, NULL, SHGFP_TYPE_CURRENT, "PulseAudio", appdata) != S_OK) 18353a5a1b3Sopenharmony_ci return NULL; 18453a5a1b3Sopenharmony_ci 18553a5a1b3Sopenharmony_ci return appdata; 18653a5a1b3Sopenharmony_ci} 18753a5a1b3Sopenharmony_ci 18853a5a1b3Sopenharmony_ci#endif 18953a5a1b3Sopenharmony_ci 19053a5a1b3Sopenharmony_cistatic void set_nonblock(int fd, bool nonblock) { 19153a5a1b3Sopenharmony_ci 19253a5a1b3Sopenharmony_ci#ifdef O_NONBLOCK 19353a5a1b3Sopenharmony_ci int v, nv; 19453a5a1b3Sopenharmony_ci pa_assert(fd >= 0); 19553a5a1b3Sopenharmony_ci 19653a5a1b3Sopenharmony_ci pa_assert_se((v = fcntl(fd, F_GETFL)) >= 0); 19753a5a1b3Sopenharmony_ci 19853a5a1b3Sopenharmony_ci if (nonblock) 19953a5a1b3Sopenharmony_ci nv = v | O_NONBLOCK; 20053a5a1b3Sopenharmony_ci else 20153a5a1b3Sopenharmony_ci nv = v & ~O_NONBLOCK; 20253a5a1b3Sopenharmony_ci 20353a5a1b3Sopenharmony_ci if (v != nv) 20453a5a1b3Sopenharmony_ci pa_assert_se(fcntl(fd, F_SETFL, nv) >= 0); 20553a5a1b3Sopenharmony_ci 20653a5a1b3Sopenharmony_ci#elif defined(OS_IS_WIN32) 20753a5a1b3Sopenharmony_ci u_long arg; 20853a5a1b3Sopenharmony_ci 20953a5a1b3Sopenharmony_ci if (nonblock) 21053a5a1b3Sopenharmony_ci arg = 1; 21153a5a1b3Sopenharmony_ci else 21253a5a1b3Sopenharmony_ci arg = 0; 21353a5a1b3Sopenharmony_ci 21453a5a1b3Sopenharmony_ci if (ioctlsocket(fd, FIONBIO, &arg) < 0) { 21553a5a1b3Sopenharmony_ci pa_assert_se(WSAGetLastError() == WSAENOTSOCK); 21653a5a1b3Sopenharmony_ci pa_log_warn("Only sockets can be made non-blocking!"); 21753a5a1b3Sopenharmony_ci return; 21853a5a1b3Sopenharmony_ci } 21953a5a1b3Sopenharmony_ci 22053a5a1b3Sopenharmony_ci /* There is no method to query status, so we remember all fds */ 22153a5a1b3Sopenharmony_ci if (nonblock) 22253a5a1b3Sopenharmony_ci FD_SET(fd, &nonblocking_fds); 22353a5a1b3Sopenharmony_ci else 22453a5a1b3Sopenharmony_ci FD_CLR(fd, &nonblocking_fds); 22553a5a1b3Sopenharmony_ci#else 22653a5a1b3Sopenharmony_ci pa_log_warn("Non-blocking I/O not supported.!"); 22753a5a1b3Sopenharmony_ci#endif 22853a5a1b3Sopenharmony_ci 22953a5a1b3Sopenharmony_ci} 23053a5a1b3Sopenharmony_ci 23153a5a1b3Sopenharmony_ci/** Make a file descriptor nonblock. Doesn't do any error checking */ 23253a5a1b3Sopenharmony_civoid pa_make_fd_nonblock(int fd) { 23353a5a1b3Sopenharmony_ci set_nonblock(fd, true); 23453a5a1b3Sopenharmony_ci} 23553a5a1b3Sopenharmony_ci 23653a5a1b3Sopenharmony_ci/** Make a file descriptor blocking. Doesn't do any error checking */ 23753a5a1b3Sopenharmony_civoid pa_make_fd_block(int fd) { 23853a5a1b3Sopenharmony_ci set_nonblock(fd, false); 23953a5a1b3Sopenharmony_ci} 24053a5a1b3Sopenharmony_ci 24153a5a1b3Sopenharmony_ci/** Query if a file descriptor is non-blocking */ 24253a5a1b3Sopenharmony_cibool pa_is_fd_nonblock(int fd) { 24353a5a1b3Sopenharmony_ci 24453a5a1b3Sopenharmony_ci#ifdef O_NONBLOCK 24553a5a1b3Sopenharmony_ci int v; 24653a5a1b3Sopenharmony_ci pa_assert(fd >= 0); 24753a5a1b3Sopenharmony_ci 24853a5a1b3Sopenharmony_ci pa_assert_se((v = fcntl(fd, F_GETFL)) >= 0); 24953a5a1b3Sopenharmony_ci 25053a5a1b3Sopenharmony_ci return !!(v & O_NONBLOCK); 25153a5a1b3Sopenharmony_ci 25253a5a1b3Sopenharmony_ci#elif defined(OS_IS_WIN32) 25353a5a1b3Sopenharmony_ci return !!FD_ISSET(fd, &nonblocking_fds); 25453a5a1b3Sopenharmony_ci#else 25553a5a1b3Sopenharmony_ci return false; 25653a5a1b3Sopenharmony_ci#endif 25753a5a1b3Sopenharmony_ci 25853a5a1b3Sopenharmony_ci} 25953a5a1b3Sopenharmony_ci 26053a5a1b3Sopenharmony_ci/* Set the FD_CLOEXEC flag for a fd */ 26153a5a1b3Sopenharmony_civoid pa_make_fd_cloexec(int fd) { 26253a5a1b3Sopenharmony_ci 26353a5a1b3Sopenharmony_ci#ifdef FD_CLOEXEC 26453a5a1b3Sopenharmony_ci int v; 26553a5a1b3Sopenharmony_ci pa_assert(fd >= 0); 26653a5a1b3Sopenharmony_ci 26753a5a1b3Sopenharmony_ci pa_assert_se((v = fcntl(fd, F_GETFD, 0)) >= 0); 26853a5a1b3Sopenharmony_ci 26953a5a1b3Sopenharmony_ci if (!(v & FD_CLOEXEC)) 27053a5a1b3Sopenharmony_ci pa_assert_se(fcntl(fd, F_SETFD, v|FD_CLOEXEC) >= 0); 27153a5a1b3Sopenharmony_ci#endif 27253a5a1b3Sopenharmony_ci 27353a5a1b3Sopenharmony_ci} 27453a5a1b3Sopenharmony_ci 27553a5a1b3Sopenharmony_ci/** Creates a directory securely. Will create parent directories recursively if 27653a5a1b3Sopenharmony_ci * required. This will not update permissions on parent directories if they 27753a5a1b3Sopenharmony_ci * already exist, however. */ 27853a5a1b3Sopenharmony_ciint pa_make_secure_dir(const char* dir, mode_t m, uid_t uid, gid_t gid, bool update_perms) { 27953a5a1b3Sopenharmony_ci struct stat st; 28053a5a1b3Sopenharmony_ci int r, saved_errno; 28153a5a1b3Sopenharmony_ci bool retry = true; 28253a5a1b3Sopenharmony_ci 28353a5a1b3Sopenharmony_ci pa_assert(dir); 28453a5a1b3Sopenharmony_ci 28553a5a1b3Sopenharmony_ciagain: 28653a5a1b3Sopenharmony_ci#ifdef OS_IS_WIN32 28753a5a1b3Sopenharmony_ci r = mkdir(dir); 28853a5a1b3Sopenharmony_ci#else 28953a5a1b3Sopenharmony_ci{ 29053a5a1b3Sopenharmony_ci mode_t u; 29153a5a1b3Sopenharmony_ci u = umask((~m) & 0777); 29253a5a1b3Sopenharmony_ci r = mkdir(dir, m); 29353a5a1b3Sopenharmony_ci umask(u); 29453a5a1b3Sopenharmony_ci} 29553a5a1b3Sopenharmony_ci#endif 29653a5a1b3Sopenharmony_ci 29753a5a1b3Sopenharmony_ci if (r < 0 && errno == ENOENT && retry) { 29853a5a1b3Sopenharmony_ci /* If a parent directory in the path doesn't exist, try to create that 29953a5a1b3Sopenharmony_ci * first, then try again. */ 30053a5a1b3Sopenharmony_ci pa_make_secure_parent_dir(dir, m, uid, gid, false); 30153a5a1b3Sopenharmony_ci retry = false; 30253a5a1b3Sopenharmony_ci goto again; 30353a5a1b3Sopenharmony_ci } 30453a5a1b3Sopenharmony_ci 30553a5a1b3Sopenharmony_ci if (r < 0 && errno != EEXIST) 30653a5a1b3Sopenharmony_ci return -1; 30753a5a1b3Sopenharmony_ci 30853a5a1b3Sopenharmony_ci#if defined(HAVE_FSTAT) && !defined(OS_IS_WIN32) 30953a5a1b3Sopenharmony_ci{ 31053a5a1b3Sopenharmony_ci int fd; 31153a5a1b3Sopenharmony_ci if ((fd = open(dir, 31253a5a1b3Sopenharmony_ci#ifdef O_CLOEXEC 31353a5a1b3Sopenharmony_ci O_CLOEXEC| 31453a5a1b3Sopenharmony_ci#endif 31553a5a1b3Sopenharmony_ci#ifdef O_NOCTTY 31653a5a1b3Sopenharmony_ci O_NOCTTY| 31753a5a1b3Sopenharmony_ci#endif 31853a5a1b3Sopenharmony_ci#ifdef O_NOFOLLOW 31953a5a1b3Sopenharmony_ci O_NOFOLLOW| 32053a5a1b3Sopenharmony_ci#endif 32153a5a1b3Sopenharmony_ci O_RDONLY)) < 0) 32253a5a1b3Sopenharmony_ci goto fail; 32353a5a1b3Sopenharmony_ci 32453a5a1b3Sopenharmony_ci if (fstat(fd, &st) < 0) { 32553a5a1b3Sopenharmony_ci pa_assert_se(pa_close(fd) >= 0); 32653a5a1b3Sopenharmony_ci goto fail; 32753a5a1b3Sopenharmony_ci } 32853a5a1b3Sopenharmony_ci 32953a5a1b3Sopenharmony_ci if (!S_ISDIR(st.st_mode)) { 33053a5a1b3Sopenharmony_ci pa_assert_se(pa_close(fd) >= 0); 33153a5a1b3Sopenharmony_ci errno = EEXIST; 33253a5a1b3Sopenharmony_ci goto fail; 33353a5a1b3Sopenharmony_ci } 33453a5a1b3Sopenharmony_ci 33553a5a1b3Sopenharmony_ci if (!update_perms) { 33653a5a1b3Sopenharmony_ci pa_assert_se(pa_close(fd) >= 0); 33753a5a1b3Sopenharmony_ci return 0; 33853a5a1b3Sopenharmony_ci } 33953a5a1b3Sopenharmony_ci 34053a5a1b3Sopenharmony_ci#ifdef HAVE_FCHOWN 34153a5a1b3Sopenharmony_ci if (uid == (uid_t) -1) 34253a5a1b3Sopenharmony_ci uid = getuid(); 34353a5a1b3Sopenharmony_ci if (gid == (gid_t) -1) 34453a5a1b3Sopenharmony_ci gid = getgid(); 34553a5a1b3Sopenharmony_ci if (((st.st_uid != uid) || (st.st_gid != gid)) && fchown(fd, uid, gid) < 0) { 34653a5a1b3Sopenharmony_ci pa_assert_se(pa_close(fd) >= 0); 34753a5a1b3Sopenharmony_ci goto fail; 34853a5a1b3Sopenharmony_ci } 34953a5a1b3Sopenharmony_ci#endif 35053a5a1b3Sopenharmony_ci 35153a5a1b3Sopenharmony_ci#ifdef HAVE_FCHMOD 35253a5a1b3Sopenharmony_ci if ((st.st_mode & 07777) != m && fchmod(fd, m) < 0) { 35353a5a1b3Sopenharmony_ci pa_assert_se(pa_close(fd) >= 0); 35453a5a1b3Sopenharmony_ci goto fail; 35553a5a1b3Sopenharmony_ci }; 35653a5a1b3Sopenharmony_ci#endif 35753a5a1b3Sopenharmony_ci 35853a5a1b3Sopenharmony_ci pa_assert_se(pa_close(fd) >= 0); 35953a5a1b3Sopenharmony_ci} 36053a5a1b3Sopenharmony_ci#else 36153a5a1b3Sopenharmony_ci pa_log_warn("Secure directory creation not supported on this platform."); 36253a5a1b3Sopenharmony_ci#endif 36353a5a1b3Sopenharmony_ci 36453a5a1b3Sopenharmony_ci return 0; 36553a5a1b3Sopenharmony_ci 36653a5a1b3Sopenharmony_cifail: 36753a5a1b3Sopenharmony_ci saved_errno = errno; 36853a5a1b3Sopenharmony_ci rmdir(dir); 36953a5a1b3Sopenharmony_ci errno = saved_errno; 37053a5a1b3Sopenharmony_ci 37153a5a1b3Sopenharmony_ci return -1; 37253a5a1b3Sopenharmony_ci} 37353a5a1b3Sopenharmony_ci 37453a5a1b3Sopenharmony_ci/* Return a newly allocated sting containing the parent directory of the specified file */ 37553a5a1b3Sopenharmony_cichar *pa_parent_dir(const char *fn) { 37653a5a1b3Sopenharmony_ci char *slash, *dir = pa_xstrdup(fn); 37753a5a1b3Sopenharmony_ci 37853a5a1b3Sopenharmony_ci if ((slash = (char*) pa_path_get_filename(dir)) == dir) { 37953a5a1b3Sopenharmony_ci pa_xfree(dir); 38053a5a1b3Sopenharmony_ci errno = ENOENT; 38153a5a1b3Sopenharmony_ci return NULL; 38253a5a1b3Sopenharmony_ci } 38353a5a1b3Sopenharmony_ci 38453a5a1b3Sopenharmony_ci *(slash-1) = 0; 38553a5a1b3Sopenharmony_ci return dir; 38653a5a1b3Sopenharmony_ci} 38753a5a1b3Sopenharmony_ci 38853a5a1b3Sopenharmony_ci/* Creates a the parent directory of the specified path securely */ 38953a5a1b3Sopenharmony_ciint pa_make_secure_parent_dir(const char *fn, mode_t m, uid_t uid, gid_t gid, bool update_perms) { 39053a5a1b3Sopenharmony_ci int ret = -1; 39153a5a1b3Sopenharmony_ci char *dir; 39253a5a1b3Sopenharmony_ci 39353a5a1b3Sopenharmony_ci if (!(dir = pa_parent_dir(fn))) 39453a5a1b3Sopenharmony_ci goto finish; 39553a5a1b3Sopenharmony_ci 39653a5a1b3Sopenharmony_ci if (pa_make_secure_dir(dir, m, uid, gid, update_perms) < 0) 39753a5a1b3Sopenharmony_ci goto finish; 39853a5a1b3Sopenharmony_ci 39953a5a1b3Sopenharmony_ci ret = 0; 40053a5a1b3Sopenharmony_ci 40153a5a1b3Sopenharmony_cifinish: 40253a5a1b3Sopenharmony_ci pa_xfree(dir); 40353a5a1b3Sopenharmony_ci return ret; 40453a5a1b3Sopenharmony_ci} 40553a5a1b3Sopenharmony_ci 40653a5a1b3Sopenharmony_ci/** Platform independent read function. Necessary since not all 40753a5a1b3Sopenharmony_ci * systems treat all file descriptors equal. If type is 40853a5a1b3Sopenharmony_ci * non-NULL it is used to cache the type of the fd. This is 40953a5a1b3Sopenharmony_ci * useful for making sure that only a single syscall is executed per 41053a5a1b3Sopenharmony_ci * function call. The variable pointed to should be initialized to 0 41153a5a1b3Sopenharmony_ci * by the caller. */ 41253a5a1b3Sopenharmony_cissize_t pa_read(int fd, void *buf, size_t count, int *type) { 41353a5a1b3Sopenharmony_ci 41453a5a1b3Sopenharmony_ci#ifdef OS_IS_WIN32 41553a5a1b3Sopenharmony_ci 41653a5a1b3Sopenharmony_ci if (!type || *type == 0) { 41753a5a1b3Sopenharmony_ci ssize_t r; 41853a5a1b3Sopenharmony_ci 41953a5a1b3Sopenharmony_ci if ((r = recv(fd, buf, count, 0)) >= 0) 42053a5a1b3Sopenharmony_ci return r; 42153a5a1b3Sopenharmony_ci 42253a5a1b3Sopenharmony_ci if (WSAGetLastError() != WSAENOTSOCK) { 42353a5a1b3Sopenharmony_ci errno = WSAGetLastError(); 42453a5a1b3Sopenharmony_ci if (errno == WSAEWOULDBLOCK) 42553a5a1b3Sopenharmony_ci errno = EAGAIN; 42653a5a1b3Sopenharmony_ci return r; 42753a5a1b3Sopenharmony_ci } 42853a5a1b3Sopenharmony_ci 42953a5a1b3Sopenharmony_ci if (type) 43053a5a1b3Sopenharmony_ci *type = 1; 43153a5a1b3Sopenharmony_ci } 43253a5a1b3Sopenharmony_ci 43353a5a1b3Sopenharmony_ci#endif 43453a5a1b3Sopenharmony_ci 43553a5a1b3Sopenharmony_ci for (;;) { 43653a5a1b3Sopenharmony_ci ssize_t r; 43753a5a1b3Sopenharmony_ci 43853a5a1b3Sopenharmony_ci if ((r = read(fd, buf, count)) < 0) 43953a5a1b3Sopenharmony_ci if (errno == EINTR) 44053a5a1b3Sopenharmony_ci continue; 44153a5a1b3Sopenharmony_ci 44253a5a1b3Sopenharmony_ci return r; 44353a5a1b3Sopenharmony_ci } 44453a5a1b3Sopenharmony_ci} 44553a5a1b3Sopenharmony_ci 44653a5a1b3Sopenharmony_ci/** Similar to pa_read(), but handles writes */ 44753a5a1b3Sopenharmony_cissize_t pa_write(int fd, const void *buf, size_t count, int *type) { 44853a5a1b3Sopenharmony_ci 44953a5a1b3Sopenharmony_ci if (!type || *type == 0) { 45053a5a1b3Sopenharmony_ci ssize_t r; 45153a5a1b3Sopenharmony_ci 45253a5a1b3Sopenharmony_ci for (;;) { 45353a5a1b3Sopenharmony_ci if ((r = send(fd, buf, count, MSG_NOSIGNAL)) < 0) { 45453a5a1b3Sopenharmony_ci 45553a5a1b3Sopenharmony_ci if (errno == EINTR) 45653a5a1b3Sopenharmony_ci continue; 45753a5a1b3Sopenharmony_ci 45853a5a1b3Sopenharmony_ci break; 45953a5a1b3Sopenharmony_ci } 46053a5a1b3Sopenharmony_ci 46153a5a1b3Sopenharmony_ci return r; 46253a5a1b3Sopenharmony_ci } 46353a5a1b3Sopenharmony_ci 46453a5a1b3Sopenharmony_ci#ifdef OS_IS_WIN32 46553a5a1b3Sopenharmony_ci if (WSAGetLastError() != WSAENOTSOCK) { 46653a5a1b3Sopenharmony_ci errno = WSAGetLastError(); 46753a5a1b3Sopenharmony_ci if (errno == WSAEWOULDBLOCK) 46853a5a1b3Sopenharmony_ci errno = EAGAIN; 46953a5a1b3Sopenharmony_ci return r; 47053a5a1b3Sopenharmony_ci } 47153a5a1b3Sopenharmony_ci#else 47253a5a1b3Sopenharmony_ci if (errno != ENOTSOCK) 47353a5a1b3Sopenharmony_ci return r; 47453a5a1b3Sopenharmony_ci#endif 47553a5a1b3Sopenharmony_ci 47653a5a1b3Sopenharmony_ci if (type) 47753a5a1b3Sopenharmony_ci *type = 1; 47853a5a1b3Sopenharmony_ci } 47953a5a1b3Sopenharmony_ci 48053a5a1b3Sopenharmony_ci for (;;) { 48153a5a1b3Sopenharmony_ci ssize_t r; 48253a5a1b3Sopenharmony_ci 48353a5a1b3Sopenharmony_ci if ((r = write(fd, buf, count)) < 0) 48453a5a1b3Sopenharmony_ci if (errno == EINTR) 48553a5a1b3Sopenharmony_ci continue; 48653a5a1b3Sopenharmony_ci 48753a5a1b3Sopenharmony_ci return r; 48853a5a1b3Sopenharmony_ci } 48953a5a1b3Sopenharmony_ci} 49053a5a1b3Sopenharmony_ci 49153a5a1b3Sopenharmony_ci/** Calls read() in a loop. Makes sure that as much as 'size' bytes, 49253a5a1b3Sopenharmony_ci * unless EOF is reached or an error occurred */ 49353a5a1b3Sopenharmony_cissize_t pa_loop_read(int fd, void*data, size_t size, int *type) { 49453a5a1b3Sopenharmony_ci ssize_t ret = 0; 49553a5a1b3Sopenharmony_ci int _type; 49653a5a1b3Sopenharmony_ci 49753a5a1b3Sopenharmony_ci pa_assert(fd >= 0); 49853a5a1b3Sopenharmony_ci pa_assert(data); 49953a5a1b3Sopenharmony_ci pa_assert(size); 50053a5a1b3Sopenharmony_ci 50153a5a1b3Sopenharmony_ci if (!type) { 50253a5a1b3Sopenharmony_ci _type = 0; 50353a5a1b3Sopenharmony_ci type = &_type; 50453a5a1b3Sopenharmony_ci } 50553a5a1b3Sopenharmony_ci 50653a5a1b3Sopenharmony_ci while (size > 0) { 50753a5a1b3Sopenharmony_ci ssize_t r; 50853a5a1b3Sopenharmony_ci 50953a5a1b3Sopenharmony_ci if ((r = pa_read(fd, data, size, type)) < 0) 51053a5a1b3Sopenharmony_ci return r; 51153a5a1b3Sopenharmony_ci 51253a5a1b3Sopenharmony_ci if (r == 0) 51353a5a1b3Sopenharmony_ci break; 51453a5a1b3Sopenharmony_ci 51553a5a1b3Sopenharmony_ci ret += r; 51653a5a1b3Sopenharmony_ci data = (uint8_t*) data + r; 51753a5a1b3Sopenharmony_ci size -= (size_t) r; 51853a5a1b3Sopenharmony_ci } 51953a5a1b3Sopenharmony_ci 52053a5a1b3Sopenharmony_ci return ret; 52153a5a1b3Sopenharmony_ci} 52253a5a1b3Sopenharmony_ci 52353a5a1b3Sopenharmony_ci/** Similar to pa_loop_read(), but wraps write() */ 52453a5a1b3Sopenharmony_cissize_t pa_loop_write(int fd, const void*data, size_t size, int *type) { 52553a5a1b3Sopenharmony_ci ssize_t ret = 0; 52653a5a1b3Sopenharmony_ci int _type; 52753a5a1b3Sopenharmony_ci 52853a5a1b3Sopenharmony_ci pa_assert(fd >= 0); 52953a5a1b3Sopenharmony_ci pa_assert(data); 53053a5a1b3Sopenharmony_ci pa_assert(size); 53153a5a1b3Sopenharmony_ci 53253a5a1b3Sopenharmony_ci if (!type) { 53353a5a1b3Sopenharmony_ci _type = 0; 53453a5a1b3Sopenharmony_ci type = &_type; 53553a5a1b3Sopenharmony_ci } 53653a5a1b3Sopenharmony_ci 53753a5a1b3Sopenharmony_ci while (size > 0) { 53853a5a1b3Sopenharmony_ci ssize_t r; 53953a5a1b3Sopenharmony_ci 54053a5a1b3Sopenharmony_ci if ((r = pa_write(fd, data, size, type)) < 0) 54153a5a1b3Sopenharmony_ci return r; 54253a5a1b3Sopenharmony_ci 54353a5a1b3Sopenharmony_ci if (r == 0) 54453a5a1b3Sopenharmony_ci break; 54553a5a1b3Sopenharmony_ci 54653a5a1b3Sopenharmony_ci ret += r; 54753a5a1b3Sopenharmony_ci data = (const uint8_t*) data + r; 54853a5a1b3Sopenharmony_ci size -= (size_t) r; 54953a5a1b3Sopenharmony_ci } 55053a5a1b3Sopenharmony_ci 55153a5a1b3Sopenharmony_ci return ret; 55253a5a1b3Sopenharmony_ci} 55353a5a1b3Sopenharmony_ci 55453a5a1b3Sopenharmony_ci/** Platform independent close function. Necessary since not all 55553a5a1b3Sopenharmony_ci * systems treat all file descriptors equal. */ 55653a5a1b3Sopenharmony_ciint pa_close(int fd) { 55753a5a1b3Sopenharmony_ci 55853a5a1b3Sopenharmony_ci#ifdef OS_IS_WIN32 55953a5a1b3Sopenharmony_ci int ret; 56053a5a1b3Sopenharmony_ci 56153a5a1b3Sopenharmony_ci FD_CLR(fd, &nonblocking_fds); 56253a5a1b3Sopenharmony_ci 56353a5a1b3Sopenharmony_ci if ((ret = closesocket(fd)) == 0) 56453a5a1b3Sopenharmony_ci return 0; 56553a5a1b3Sopenharmony_ci 56653a5a1b3Sopenharmony_ci if (WSAGetLastError() != WSAENOTSOCK) { 56753a5a1b3Sopenharmony_ci errno = WSAGetLastError(); 56853a5a1b3Sopenharmony_ci return ret; 56953a5a1b3Sopenharmony_ci } 57053a5a1b3Sopenharmony_ci#endif 57153a5a1b3Sopenharmony_ci 57253a5a1b3Sopenharmony_ci for (;;) { 57353a5a1b3Sopenharmony_ci int r; 57453a5a1b3Sopenharmony_ci 57553a5a1b3Sopenharmony_ci if ((r = close(fd)) < 0) { 57653a5a1b3Sopenharmony_ci if (errno == EINTR) 57753a5a1b3Sopenharmony_ci continue; 57853a5a1b3Sopenharmony_ci pa_log_error("Close fd failed, err code: %d", r); 57953a5a1b3Sopenharmony_ci } 58053a5a1b3Sopenharmony_ci return r; 58153a5a1b3Sopenharmony_ci } 58253a5a1b3Sopenharmony_ci} 58353a5a1b3Sopenharmony_ci 58453a5a1b3Sopenharmony_ci/* Print a warning messages in case that the given signal is not 58553a5a1b3Sopenharmony_ci * blocked or trapped */ 58653a5a1b3Sopenharmony_civoid pa_check_signal_is_blocked(int sig) { 58753a5a1b3Sopenharmony_ci#ifdef HAVE_SIGACTION 58853a5a1b3Sopenharmony_ci struct sigaction sa; 58953a5a1b3Sopenharmony_ci sigset_t set; 59053a5a1b3Sopenharmony_ci 59153a5a1b3Sopenharmony_ci /* If POSIX threads are supported use thread-aware 59253a5a1b3Sopenharmony_ci * pthread_sigmask() function, to check if the signal is 59353a5a1b3Sopenharmony_ci * blocked. Otherwise fall back to sigprocmask() */ 59453a5a1b3Sopenharmony_ci 59553a5a1b3Sopenharmony_ci#ifdef HAVE_PTHREAD 59653a5a1b3Sopenharmony_ci if (pthread_sigmask(SIG_SETMASK, NULL, &set) < 0) { 59753a5a1b3Sopenharmony_ci#endif 59853a5a1b3Sopenharmony_ci if (sigprocmask(SIG_SETMASK, NULL, &set) < 0) { 59953a5a1b3Sopenharmony_ci pa_log("sigprocmask(): %s", pa_cstrerror(errno)); 60053a5a1b3Sopenharmony_ci return; 60153a5a1b3Sopenharmony_ci } 60253a5a1b3Sopenharmony_ci#ifdef HAVE_PTHREAD 60353a5a1b3Sopenharmony_ci } 60453a5a1b3Sopenharmony_ci#endif 60553a5a1b3Sopenharmony_ci 60653a5a1b3Sopenharmony_ci if (sigismember(&set, sig)) 60753a5a1b3Sopenharmony_ci return; 60853a5a1b3Sopenharmony_ci 60953a5a1b3Sopenharmony_ci /* Check whether the signal is trapped */ 61053a5a1b3Sopenharmony_ci 61153a5a1b3Sopenharmony_ci if (sigaction(sig, NULL, &sa) < 0) { 61253a5a1b3Sopenharmony_ci pa_log("sigaction(): %s", pa_cstrerror(errno)); 61353a5a1b3Sopenharmony_ci return; 61453a5a1b3Sopenharmony_ci } 61553a5a1b3Sopenharmony_ci 61653a5a1b3Sopenharmony_ci if (sa.sa_handler != SIG_DFL) 61753a5a1b3Sopenharmony_ci return; 61853a5a1b3Sopenharmony_ci 61953a5a1b3Sopenharmony_ci pa_log_warn("%s is not trapped. This might cause malfunction!", pa_sig2str(sig)); 62053a5a1b3Sopenharmony_ci#else /* HAVE_SIGACTION */ 62153a5a1b3Sopenharmony_ci pa_log_warn("%s might not be trapped. This might cause malfunction!", pa_sig2str(sig)); 62253a5a1b3Sopenharmony_ci#endif 62353a5a1b3Sopenharmony_ci} 62453a5a1b3Sopenharmony_ci 62553a5a1b3Sopenharmony_ci/* The following function is based on an example from the GNU libc 62653a5a1b3Sopenharmony_ci * documentation. This function is similar to GNU's asprintf(). */ 62753a5a1b3Sopenharmony_cichar *pa_sprintf_malloc(const char *format, ...) { 62853a5a1b3Sopenharmony_ci size_t size = 100; 62953a5a1b3Sopenharmony_ci char *c = NULL; 63053a5a1b3Sopenharmony_ci 63153a5a1b3Sopenharmony_ci pa_assert(format); 63253a5a1b3Sopenharmony_ci 63353a5a1b3Sopenharmony_ci for(;;) { 63453a5a1b3Sopenharmony_ci int r; 63553a5a1b3Sopenharmony_ci va_list ap; 63653a5a1b3Sopenharmony_ci 63753a5a1b3Sopenharmony_ci c = pa_xrealloc(c, size); 63853a5a1b3Sopenharmony_ci 63953a5a1b3Sopenharmony_ci va_start(ap, format); 64053a5a1b3Sopenharmony_ci r = vsnprintf(c, size, format, ap); 64153a5a1b3Sopenharmony_ci va_end(ap); 64253a5a1b3Sopenharmony_ci 64353a5a1b3Sopenharmony_ci c[size-1] = 0; 64453a5a1b3Sopenharmony_ci 64553a5a1b3Sopenharmony_ci if (r > -1 && (size_t) r < size) 64653a5a1b3Sopenharmony_ci return c; 64753a5a1b3Sopenharmony_ci 64853a5a1b3Sopenharmony_ci if (r > -1) /* glibc 2.1 */ 64953a5a1b3Sopenharmony_ci size = (size_t) r+1; 65053a5a1b3Sopenharmony_ci else /* glibc 2.0 */ 65153a5a1b3Sopenharmony_ci size *= 2; 65253a5a1b3Sopenharmony_ci } 65353a5a1b3Sopenharmony_ci} 65453a5a1b3Sopenharmony_ci 65553a5a1b3Sopenharmony_ci/* Same as the previous function, but use a va_list instead of an 65653a5a1b3Sopenharmony_ci * ellipsis */ 65753a5a1b3Sopenharmony_cichar *pa_vsprintf_malloc(const char *format, va_list ap) { 65853a5a1b3Sopenharmony_ci size_t size = 100; 65953a5a1b3Sopenharmony_ci char *c = NULL; 66053a5a1b3Sopenharmony_ci 66153a5a1b3Sopenharmony_ci pa_assert(format); 66253a5a1b3Sopenharmony_ci 66353a5a1b3Sopenharmony_ci for(;;) { 66453a5a1b3Sopenharmony_ci int r; 66553a5a1b3Sopenharmony_ci va_list aq; 66653a5a1b3Sopenharmony_ci 66753a5a1b3Sopenharmony_ci c = pa_xrealloc(c, size); 66853a5a1b3Sopenharmony_ci 66953a5a1b3Sopenharmony_ci va_copy(aq, ap); 67053a5a1b3Sopenharmony_ci r = vsnprintf(c, size, format, aq); 67153a5a1b3Sopenharmony_ci va_end(aq); 67253a5a1b3Sopenharmony_ci 67353a5a1b3Sopenharmony_ci c[size-1] = 0; 67453a5a1b3Sopenharmony_ci 67553a5a1b3Sopenharmony_ci if (r > -1 && (size_t) r < size) 67653a5a1b3Sopenharmony_ci return c; 67753a5a1b3Sopenharmony_ci 67853a5a1b3Sopenharmony_ci if (r > -1) /* glibc 2.1 */ 67953a5a1b3Sopenharmony_ci size = (size_t) r+1; 68053a5a1b3Sopenharmony_ci else /* glibc 2.0 */ 68153a5a1b3Sopenharmony_ci size *= 2; 68253a5a1b3Sopenharmony_ci } 68353a5a1b3Sopenharmony_ci} 68453a5a1b3Sopenharmony_ci 68553a5a1b3Sopenharmony_ci/* Similar to OpenBSD's strlcpy() function */ 68653a5a1b3Sopenharmony_cichar *pa_strlcpy(char *b, const char *s, size_t l) { 68753a5a1b3Sopenharmony_ci size_t k; 68853a5a1b3Sopenharmony_ci 68953a5a1b3Sopenharmony_ci pa_assert(b); 69053a5a1b3Sopenharmony_ci pa_assert(s); 69153a5a1b3Sopenharmony_ci pa_assert(l > 0); 69253a5a1b3Sopenharmony_ci 69353a5a1b3Sopenharmony_ci k = strlen(s); 69453a5a1b3Sopenharmony_ci 69553a5a1b3Sopenharmony_ci if (k > l-1) 69653a5a1b3Sopenharmony_ci k = l-1; 69753a5a1b3Sopenharmony_ci 69853a5a1b3Sopenharmony_ci memcpy(b, s, k); 69953a5a1b3Sopenharmony_ci b[k] = 0; 70053a5a1b3Sopenharmony_ci 70153a5a1b3Sopenharmony_ci return b; 70253a5a1b3Sopenharmony_ci} 70353a5a1b3Sopenharmony_ci 70453a5a1b3Sopenharmony_ci#ifdef HAVE_SYS_RESOURCE_H 70553a5a1b3Sopenharmony_cistatic int set_nice(int nice_level) { 70653a5a1b3Sopenharmony_ci#ifdef HAVE_DBUS 70753a5a1b3Sopenharmony_ci DBusError error; 70853a5a1b3Sopenharmony_ci DBusConnection *bus; 70953a5a1b3Sopenharmony_ci int r; 71053a5a1b3Sopenharmony_ci 71153a5a1b3Sopenharmony_ci dbus_error_init(&error); 71253a5a1b3Sopenharmony_ci#endif 71353a5a1b3Sopenharmony_ci 71453a5a1b3Sopenharmony_ci#ifdef HAVE_SYS_RESOURCE_H 71553a5a1b3Sopenharmony_ci if (setpriority(PRIO_PROCESS, 0, nice_level) >= 0) { 71653a5a1b3Sopenharmony_ci pa_log_debug("setpriority() worked."); 71753a5a1b3Sopenharmony_ci return 0; 71853a5a1b3Sopenharmony_ci } 71953a5a1b3Sopenharmony_ci#endif 72053a5a1b3Sopenharmony_ci 72153a5a1b3Sopenharmony_ci#ifdef HAVE_DBUS 72253a5a1b3Sopenharmony_ci /* Try to talk to RealtimeKit */ 72353a5a1b3Sopenharmony_ci 72453a5a1b3Sopenharmony_ci if (!(bus = dbus_bus_get_private(DBUS_BUS_SYSTEM, &error))) { 72553a5a1b3Sopenharmony_ci pa_log("Failed to connect to system bus: %s", error.message); 72653a5a1b3Sopenharmony_ci dbus_error_free(&error); 72753a5a1b3Sopenharmony_ci errno = -EIO; 72853a5a1b3Sopenharmony_ci return -1; 72953a5a1b3Sopenharmony_ci } 73053a5a1b3Sopenharmony_ci 73153a5a1b3Sopenharmony_ci /* We need to disable exit on disconnect because otherwise 73253a5a1b3Sopenharmony_ci * dbus_shutdown will kill us. See 73353a5a1b3Sopenharmony_ci * https://bugs.freedesktop.org/show_bug.cgi?id=16924 */ 73453a5a1b3Sopenharmony_ci dbus_connection_set_exit_on_disconnect(bus, FALSE); 73553a5a1b3Sopenharmony_ci 73653a5a1b3Sopenharmony_ci r = rtkit_make_high_priority(bus, 0, nice_level); 73753a5a1b3Sopenharmony_ci dbus_connection_close(bus); 73853a5a1b3Sopenharmony_ci dbus_connection_unref(bus); 73953a5a1b3Sopenharmony_ci 74053a5a1b3Sopenharmony_ci if (r >= 0) { 74153a5a1b3Sopenharmony_ci pa_log_debug("RealtimeKit worked."); 74253a5a1b3Sopenharmony_ci return 0; 74353a5a1b3Sopenharmony_ci } 74453a5a1b3Sopenharmony_ci 74553a5a1b3Sopenharmony_ci errno = -r; 74653a5a1b3Sopenharmony_ci#endif 74753a5a1b3Sopenharmony_ci 74853a5a1b3Sopenharmony_ci return -1; 74953a5a1b3Sopenharmony_ci} 75053a5a1b3Sopenharmony_ci#endif 75153a5a1b3Sopenharmony_ci 75253a5a1b3Sopenharmony_ci/* Raise the priority of the current process as much as possible that 75353a5a1b3Sopenharmony_ci * is <= the specified nice level..*/ 75453a5a1b3Sopenharmony_ciint pa_raise_priority(int nice_level) { 75553a5a1b3Sopenharmony_ci 75653a5a1b3Sopenharmony_ci#ifdef HAVE_SYS_RESOURCE_H 75753a5a1b3Sopenharmony_ci int n; 75853a5a1b3Sopenharmony_ci 75953a5a1b3Sopenharmony_ci if (set_nice(nice_level) >= 0) { 76053a5a1b3Sopenharmony_ci pa_log_info("Successfully gained nice level %i.", nice_level); 76153a5a1b3Sopenharmony_ci return 0; 76253a5a1b3Sopenharmony_ci } 76353a5a1b3Sopenharmony_ci 76453a5a1b3Sopenharmony_ci for (n = nice_level+1; n < 0; n++) 76553a5a1b3Sopenharmony_ci if (set_nice(n) >= 0) { 76653a5a1b3Sopenharmony_ci pa_log_info("Successfully acquired nice level %i, which is lower than the requested %i.", n, nice_level); 76753a5a1b3Sopenharmony_ci return 0; 76853a5a1b3Sopenharmony_ci } 76953a5a1b3Sopenharmony_ci 77053a5a1b3Sopenharmony_ci pa_log_info("Failed to acquire high-priority scheduling: %s", pa_cstrerror(errno)); 77153a5a1b3Sopenharmony_ci return -1; 77253a5a1b3Sopenharmony_ci#endif 77353a5a1b3Sopenharmony_ci 77453a5a1b3Sopenharmony_ci#ifdef OS_IS_WIN32 77553a5a1b3Sopenharmony_ci if (nice_level < 0) { 77653a5a1b3Sopenharmony_ci if (!SetPriorityClass(GetCurrentProcess(), HIGH_PRIORITY_CLASS)) { 77753a5a1b3Sopenharmony_ci pa_log_warn("SetPriorityClass() failed: 0x%08lX", GetLastError()); 77853a5a1b3Sopenharmony_ci errno = EPERM; 77953a5a1b3Sopenharmony_ci return -1; 78053a5a1b3Sopenharmony_ci } 78153a5a1b3Sopenharmony_ci 78253a5a1b3Sopenharmony_ci pa_log_info("Successfully gained high priority class."); 78353a5a1b3Sopenharmony_ci } 78453a5a1b3Sopenharmony_ci#endif 78553a5a1b3Sopenharmony_ci 78653a5a1b3Sopenharmony_ci return 0; 78753a5a1b3Sopenharmony_ci} 78853a5a1b3Sopenharmony_ci 78953a5a1b3Sopenharmony_ci/* Reset the priority to normal, inverting the changes made by 79053a5a1b3Sopenharmony_ci * pa_raise_priority() and pa_thread_make_realtime()*/ 79153a5a1b3Sopenharmony_civoid pa_reset_priority(void) { 79253a5a1b3Sopenharmony_ci#ifdef HAVE_SYS_RESOURCE_H 79353a5a1b3Sopenharmony_ci struct sched_param sp; 79453a5a1b3Sopenharmony_ci 79553a5a1b3Sopenharmony_ci setpriority(PRIO_PROCESS, 0, 0); 79653a5a1b3Sopenharmony_ci 79753a5a1b3Sopenharmony_ci pa_zero(sp); 79853a5a1b3Sopenharmony_ci pthread_setschedparam(pthread_self(), SCHED_OTHER, &sp); 79953a5a1b3Sopenharmony_ci#endif 80053a5a1b3Sopenharmony_ci 80153a5a1b3Sopenharmony_ci#ifdef OS_IS_WIN32 80253a5a1b3Sopenharmony_ci SetPriorityClass(GetCurrentProcess(), NORMAL_PRIORITY_CLASS); 80353a5a1b3Sopenharmony_ci#endif 80453a5a1b3Sopenharmony_ci} 80553a5a1b3Sopenharmony_ci 80653a5a1b3Sopenharmony_ci/* Check whenever any substring in v matches the provided regex. */ 80753a5a1b3Sopenharmony_ciint pa_match(const char *expr, const char *v) { 80853a5a1b3Sopenharmony_ci#if defined(HAVE_REGEX_H) || defined(HAVE_PCREPOSIX_H) 80953a5a1b3Sopenharmony_ci int k; 81053a5a1b3Sopenharmony_ci regex_t re; 81153a5a1b3Sopenharmony_ci int r; 81253a5a1b3Sopenharmony_ci 81353a5a1b3Sopenharmony_ci pa_assert(expr); 81453a5a1b3Sopenharmony_ci pa_assert(v); 81553a5a1b3Sopenharmony_ci 81653a5a1b3Sopenharmony_ci if (regcomp(&re, expr, REG_NOSUB|REG_EXTENDED) != 0) { 81753a5a1b3Sopenharmony_ci errno = EINVAL; 81853a5a1b3Sopenharmony_ci return -1; 81953a5a1b3Sopenharmony_ci } 82053a5a1b3Sopenharmony_ci 82153a5a1b3Sopenharmony_ci if ((k = regexec(&re, v, 0, NULL, 0)) == 0) 82253a5a1b3Sopenharmony_ci r = 1; 82353a5a1b3Sopenharmony_ci else if (k == REG_NOMATCH) 82453a5a1b3Sopenharmony_ci r = 0; 82553a5a1b3Sopenharmony_ci else 82653a5a1b3Sopenharmony_ci r = -1; 82753a5a1b3Sopenharmony_ci 82853a5a1b3Sopenharmony_ci regfree(&re); 82953a5a1b3Sopenharmony_ci 83053a5a1b3Sopenharmony_ci if (r < 0) 83153a5a1b3Sopenharmony_ci errno = EINVAL; 83253a5a1b3Sopenharmony_ci 83353a5a1b3Sopenharmony_ci return r; 83453a5a1b3Sopenharmony_ci#else 83553a5a1b3Sopenharmony_ci errno = ENOSYS; 83653a5a1b3Sopenharmony_ci return -1; 83753a5a1b3Sopenharmony_ci#endif 83853a5a1b3Sopenharmony_ci} 83953a5a1b3Sopenharmony_ci 84053a5a1b3Sopenharmony_ci/* Check whenever the provided regex pattern is valid. */ 84153a5a1b3Sopenharmony_cibool pa_is_regex_valid(const char *expr) { 84253a5a1b3Sopenharmony_ci#if defined(HAVE_REGEX_H) || defined(HAVE_PCREPOSIX_H) 84353a5a1b3Sopenharmony_ci regex_t re; 84453a5a1b3Sopenharmony_ci 84553a5a1b3Sopenharmony_ci if (expr == NULL || regcomp(&re, expr, REG_NOSUB|REG_EXTENDED) != 0) { 84653a5a1b3Sopenharmony_ci return false; 84753a5a1b3Sopenharmony_ci } 84853a5a1b3Sopenharmony_ci 84953a5a1b3Sopenharmony_ci regfree(&re); 85053a5a1b3Sopenharmony_ci return true; 85153a5a1b3Sopenharmony_ci#else 85253a5a1b3Sopenharmony_ci return false; 85353a5a1b3Sopenharmony_ci#endif 85453a5a1b3Sopenharmony_ci} 85553a5a1b3Sopenharmony_ci 85653a5a1b3Sopenharmony_ci/* Try to parse a boolean string value.*/ 85753a5a1b3Sopenharmony_ciint pa_parse_boolean(const char *v) { 85853a5a1b3Sopenharmony_ci pa_assert(v); 85953a5a1b3Sopenharmony_ci 86053a5a1b3Sopenharmony_ci /* First we check language independent */ 86153a5a1b3Sopenharmony_ci if (pa_streq(v, "1") || !strcasecmp(v, "y") || !strcasecmp(v, "t") 86253a5a1b3Sopenharmony_ci || !strcasecmp(v, "yes") || !strcasecmp(v, "true") || !strcasecmp(v, "on")) 86353a5a1b3Sopenharmony_ci return 1; 86453a5a1b3Sopenharmony_ci else if (pa_streq(v, "0") || !strcasecmp(v, "n") || !strcasecmp(v, "f") 86553a5a1b3Sopenharmony_ci || !strcasecmp(v, "no") || !strcasecmp(v, "false") || !strcasecmp(v, "off")) 86653a5a1b3Sopenharmony_ci return 0; 86753a5a1b3Sopenharmony_ci 86853a5a1b3Sopenharmony_ci#ifdef HAVE_LANGINFO_H 86953a5a1b3Sopenharmony_ci{ 87053a5a1b3Sopenharmony_ci const char *expr; 87153a5a1b3Sopenharmony_ci /* And then we check language dependent */ 87253a5a1b3Sopenharmony_ci if ((expr = nl_langinfo(YESEXPR))) 87353a5a1b3Sopenharmony_ci if (expr[0]) 87453a5a1b3Sopenharmony_ci if (pa_match(expr, v) > 0) 87553a5a1b3Sopenharmony_ci return 1; 87653a5a1b3Sopenharmony_ci 87753a5a1b3Sopenharmony_ci if ((expr = nl_langinfo(NOEXPR))) 87853a5a1b3Sopenharmony_ci if (expr[0]) 87953a5a1b3Sopenharmony_ci if (pa_match(expr, v) > 0) 88053a5a1b3Sopenharmony_ci return 0; 88153a5a1b3Sopenharmony_ci} 88253a5a1b3Sopenharmony_ci#endif 88353a5a1b3Sopenharmony_ci 88453a5a1b3Sopenharmony_ci errno = EINVAL; 88553a5a1b3Sopenharmony_ci return -1; 88653a5a1b3Sopenharmony_ci} 88753a5a1b3Sopenharmony_ci 88853a5a1b3Sopenharmony_ci/* Try to parse a volume string to pa_volume_t. The allowed formats are: 88953a5a1b3Sopenharmony_ci * db, % and unsigned integer */ 89053a5a1b3Sopenharmony_ciint pa_parse_volume(const char *v, pa_volume_t *volume) { 89153a5a1b3Sopenharmony_ci int len; 89253a5a1b3Sopenharmony_ci uint32_t i; 89353a5a1b3Sopenharmony_ci double d; 89453a5a1b3Sopenharmony_ci char str[64]; 89553a5a1b3Sopenharmony_ci 89653a5a1b3Sopenharmony_ci pa_assert(v); 89753a5a1b3Sopenharmony_ci pa_assert(volume); 89853a5a1b3Sopenharmony_ci 89953a5a1b3Sopenharmony_ci len = strlen(v); 90053a5a1b3Sopenharmony_ci 90153a5a1b3Sopenharmony_ci if (len <= 0 || len >= 64) 90253a5a1b3Sopenharmony_ci return -1; 90353a5a1b3Sopenharmony_ci 90453a5a1b3Sopenharmony_ci memcpy(str, v, len + 1); 90553a5a1b3Sopenharmony_ci 90653a5a1b3Sopenharmony_ci if (str[len - 1] == '%') { 90753a5a1b3Sopenharmony_ci str[len - 1] = '\0'; 90853a5a1b3Sopenharmony_ci if (pa_atod(str, &d) < 0) 90953a5a1b3Sopenharmony_ci return -1; 91053a5a1b3Sopenharmony_ci 91153a5a1b3Sopenharmony_ci d = d / 100 * PA_VOLUME_NORM; 91253a5a1b3Sopenharmony_ci 91353a5a1b3Sopenharmony_ci if (d < 0 || d > PA_VOLUME_MAX) 91453a5a1b3Sopenharmony_ci return -1; 91553a5a1b3Sopenharmony_ci 91653a5a1b3Sopenharmony_ci *volume = d; 91753a5a1b3Sopenharmony_ci return 0; 91853a5a1b3Sopenharmony_ci } 91953a5a1b3Sopenharmony_ci 92053a5a1b3Sopenharmony_ci if (len > 2 && (str[len - 1] == 'b' || str[len - 1] == 'B') && 92153a5a1b3Sopenharmony_ci (str[len - 2] == 'd' || str[len - 2] == 'D')) { 92253a5a1b3Sopenharmony_ci str[len - 2] = '\0'; 92353a5a1b3Sopenharmony_ci if (pa_atod(str, &d) < 0) 92453a5a1b3Sopenharmony_ci return -1; 92553a5a1b3Sopenharmony_ci 92653a5a1b3Sopenharmony_ci if (d > pa_sw_volume_to_dB(PA_VOLUME_MAX)) 92753a5a1b3Sopenharmony_ci return -1; 92853a5a1b3Sopenharmony_ci 92953a5a1b3Sopenharmony_ci *volume = pa_sw_volume_from_dB(d); 93053a5a1b3Sopenharmony_ci return 0; 93153a5a1b3Sopenharmony_ci } 93253a5a1b3Sopenharmony_ci 93353a5a1b3Sopenharmony_ci if (pa_atou(v, &i) < 0 || !PA_VOLUME_IS_VALID(i)) 93453a5a1b3Sopenharmony_ci return -1; 93553a5a1b3Sopenharmony_ci 93653a5a1b3Sopenharmony_ci *volume = i; 93753a5a1b3Sopenharmony_ci return 0; 93853a5a1b3Sopenharmony_ci} 93953a5a1b3Sopenharmony_ci 94053a5a1b3Sopenharmony_ci/* Split the specified string wherever one of the characters in delimiter 94153a5a1b3Sopenharmony_ci * occurs. Each time it is called returns a newly allocated string 94253a5a1b3Sopenharmony_ci * with pa_xmalloc(). The variable state points to, should be 94353a5a1b3Sopenharmony_ci * initialized to NULL before the first call. */ 94453a5a1b3Sopenharmony_cichar *pa_split(const char *c, const char *delimiter, const char**state) { 94553a5a1b3Sopenharmony_ci const char *current = *state ? *state : c; 94653a5a1b3Sopenharmony_ci size_t l; 94753a5a1b3Sopenharmony_ci 94853a5a1b3Sopenharmony_ci if (!*current) 94953a5a1b3Sopenharmony_ci return NULL; 95053a5a1b3Sopenharmony_ci 95153a5a1b3Sopenharmony_ci l = strcspn(current, delimiter); 95253a5a1b3Sopenharmony_ci *state = current+l; 95353a5a1b3Sopenharmony_ci 95453a5a1b3Sopenharmony_ci if (**state) 95553a5a1b3Sopenharmony_ci (*state)++; 95653a5a1b3Sopenharmony_ci 95753a5a1b3Sopenharmony_ci return pa_xstrndup(current, l); 95853a5a1b3Sopenharmony_ci} 95953a5a1b3Sopenharmony_ci 96053a5a1b3Sopenharmony_ci/* Split the specified string wherever one of the characters in delimiter 96153a5a1b3Sopenharmony_ci * occurs. Each time it is called returns a pointer to the substring within the 96253a5a1b3Sopenharmony_ci * string and the length in 'n'. Note that the resultant string cannot be used 96353a5a1b3Sopenharmony_ci * as-is without the length parameter, since it is merely pointing to a point 96453a5a1b3Sopenharmony_ci * within the original string. The variable state points to, should be 96553a5a1b3Sopenharmony_ci * initialized to NULL before the first call. */ 96653a5a1b3Sopenharmony_ciconst char *pa_split_in_place(const char *c, const char *delimiter, size_t *n, const char**state) { 96753a5a1b3Sopenharmony_ci const char *current = *state ? *state : c; 96853a5a1b3Sopenharmony_ci size_t l; 96953a5a1b3Sopenharmony_ci 97053a5a1b3Sopenharmony_ci if (!*current) 97153a5a1b3Sopenharmony_ci return NULL; 97253a5a1b3Sopenharmony_ci 97353a5a1b3Sopenharmony_ci l = strcspn(current, delimiter); 97453a5a1b3Sopenharmony_ci *state = current+l; 97553a5a1b3Sopenharmony_ci 97653a5a1b3Sopenharmony_ci if (**state) 97753a5a1b3Sopenharmony_ci (*state)++; 97853a5a1b3Sopenharmony_ci 97953a5a1b3Sopenharmony_ci *n = l; 98053a5a1b3Sopenharmony_ci return current; 98153a5a1b3Sopenharmony_ci} 98253a5a1b3Sopenharmony_ci 98353a5a1b3Sopenharmony_ci/* Split a string into words. Otherwise similar to pa_split(). */ 98453a5a1b3Sopenharmony_cichar *pa_split_spaces(const char *c, const char **state) { 98553a5a1b3Sopenharmony_ci const char *current = *state ? *state : c; 98653a5a1b3Sopenharmony_ci size_t l; 98753a5a1b3Sopenharmony_ci 98853a5a1b3Sopenharmony_ci if (!*current || *c == 0) 98953a5a1b3Sopenharmony_ci return NULL; 99053a5a1b3Sopenharmony_ci 99153a5a1b3Sopenharmony_ci current += strspn(current, WHITESPACE); 99253a5a1b3Sopenharmony_ci l = strcspn(current, WHITESPACE); 99353a5a1b3Sopenharmony_ci 99453a5a1b3Sopenharmony_ci *state = current+l; 99553a5a1b3Sopenharmony_ci 99653a5a1b3Sopenharmony_ci return pa_xstrndup(current, l); 99753a5a1b3Sopenharmony_ci} 99853a5a1b3Sopenharmony_ci 99953a5a1b3Sopenharmony_ci/* Similar to pa_split_spaces, except this returns a string in-place. 100053a5a1b3Sopenharmony_ci Returned string is generally not NULL-terminated. 100153a5a1b3Sopenharmony_ci See pa_split_in_place(). */ 100253a5a1b3Sopenharmony_ciconst char *pa_split_spaces_in_place(const char *c, size_t *n, const char **state) { 100353a5a1b3Sopenharmony_ci const char *current = *state ? *state : c; 100453a5a1b3Sopenharmony_ci size_t l; 100553a5a1b3Sopenharmony_ci 100653a5a1b3Sopenharmony_ci if (!*current || *c == 0) 100753a5a1b3Sopenharmony_ci return NULL; 100853a5a1b3Sopenharmony_ci 100953a5a1b3Sopenharmony_ci current += strspn(current, WHITESPACE); 101053a5a1b3Sopenharmony_ci l = strcspn(current, WHITESPACE); 101153a5a1b3Sopenharmony_ci 101253a5a1b3Sopenharmony_ci *state = current+l; 101353a5a1b3Sopenharmony_ci 101453a5a1b3Sopenharmony_ci *n = l; 101553a5a1b3Sopenharmony_ci return current; 101653a5a1b3Sopenharmony_ci} 101753a5a1b3Sopenharmony_ci 101853a5a1b3Sopenharmony_ciPA_STATIC_TLS_DECLARE(signame, pa_xfree); 101953a5a1b3Sopenharmony_ci 102053a5a1b3Sopenharmony_ci/* Return the name of an UNIX signal. Similar to Solaris sig2str() */ 102153a5a1b3Sopenharmony_ciconst char *pa_sig2str(int sig) { 102253a5a1b3Sopenharmony_ci char *t; 102353a5a1b3Sopenharmony_ci 102453a5a1b3Sopenharmony_ci if (sig <= 0) 102553a5a1b3Sopenharmony_ci goto fail; 102653a5a1b3Sopenharmony_ci 102753a5a1b3Sopenharmony_ci#ifdef NSIG 102853a5a1b3Sopenharmony_ci if (sig >= NSIG) 102953a5a1b3Sopenharmony_ci goto fail; 103053a5a1b3Sopenharmony_ci#endif 103153a5a1b3Sopenharmony_ci 103253a5a1b3Sopenharmony_ci#ifdef HAVE_SIG2STR 103353a5a1b3Sopenharmony_ci { 103453a5a1b3Sopenharmony_ci char buf[SIG2STR_MAX]; 103553a5a1b3Sopenharmony_ci 103653a5a1b3Sopenharmony_ci if (sig2str(sig, buf) == 0) { 103753a5a1b3Sopenharmony_ci pa_xfree(PA_STATIC_TLS_GET(signame)); 103853a5a1b3Sopenharmony_ci t = pa_sprintf_malloc("SIG%s", buf); 103953a5a1b3Sopenharmony_ci PA_STATIC_TLS_SET(signame, t); 104053a5a1b3Sopenharmony_ci return t; 104153a5a1b3Sopenharmony_ci } 104253a5a1b3Sopenharmony_ci } 104353a5a1b3Sopenharmony_ci#else 104453a5a1b3Sopenharmony_ci 104553a5a1b3Sopenharmony_ci switch (sig) { 104653a5a1b3Sopenharmony_ci#ifdef SIGHUP 104753a5a1b3Sopenharmony_ci case SIGHUP: return "SIGHUP"; 104853a5a1b3Sopenharmony_ci#endif 104953a5a1b3Sopenharmony_ci case SIGINT: return "SIGINT"; 105053a5a1b3Sopenharmony_ci#ifdef SIGQUIT 105153a5a1b3Sopenharmony_ci case SIGQUIT: return "SIGQUIT"; 105253a5a1b3Sopenharmony_ci#endif 105353a5a1b3Sopenharmony_ci case SIGILL: return "SIGULL"; 105453a5a1b3Sopenharmony_ci#ifdef SIGTRAP 105553a5a1b3Sopenharmony_ci case SIGTRAP: return "SIGTRAP"; 105653a5a1b3Sopenharmony_ci#endif 105753a5a1b3Sopenharmony_ci case SIGABRT: return "SIGABRT"; 105853a5a1b3Sopenharmony_ci#ifdef SIGBUS 105953a5a1b3Sopenharmony_ci case SIGBUS: return "SIGBUS"; 106053a5a1b3Sopenharmony_ci#endif 106153a5a1b3Sopenharmony_ci case SIGFPE: return "SIGFPE"; 106253a5a1b3Sopenharmony_ci#ifdef SIGKILL 106353a5a1b3Sopenharmony_ci case SIGKILL: return "SIGKILL"; 106453a5a1b3Sopenharmony_ci#endif 106553a5a1b3Sopenharmony_ci#ifdef SIGUSR1 106653a5a1b3Sopenharmony_ci case SIGUSR1: return "SIGUSR1"; 106753a5a1b3Sopenharmony_ci#endif 106853a5a1b3Sopenharmony_ci case SIGSEGV: return "SIGSEGV"; 106953a5a1b3Sopenharmony_ci#ifdef SIGUSR2 107053a5a1b3Sopenharmony_ci case SIGUSR2: return "SIGUSR2"; 107153a5a1b3Sopenharmony_ci#endif 107253a5a1b3Sopenharmony_ci#ifdef SIGPIPE 107353a5a1b3Sopenharmony_ci case SIGPIPE: return "SIGPIPE"; 107453a5a1b3Sopenharmony_ci#endif 107553a5a1b3Sopenharmony_ci#ifdef SIGALRM 107653a5a1b3Sopenharmony_ci case SIGALRM: return "SIGALRM"; 107753a5a1b3Sopenharmony_ci#endif 107853a5a1b3Sopenharmony_ci case SIGTERM: return "SIGTERM"; 107953a5a1b3Sopenharmony_ci#ifdef SIGSTKFLT 108053a5a1b3Sopenharmony_ci case SIGSTKFLT: return "SIGSTKFLT"; 108153a5a1b3Sopenharmony_ci#endif 108253a5a1b3Sopenharmony_ci#ifdef SIGCHLD 108353a5a1b3Sopenharmony_ci case SIGCHLD: return "SIGCHLD"; 108453a5a1b3Sopenharmony_ci#endif 108553a5a1b3Sopenharmony_ci#ifdef SIGCONT 108653a5a1b3Sopenharmony_ci case SIGCONT: return "SIGCONT"; 108753a5a1b3Sopenharmony_ci#endif 108853a5a1b3Sopenharmony_ci#ifdef SIGSTOP 108953a5a1b3Sopenharmony_ci case SIGSTOP: return "SIGSTOP"; 109053a5a1b3Sopenharmony_ci#endif 109153a5a1b3Sopenharmony_ci#ifdef SIGTSTP 109253a5a1b3Sopenharmony_ci case SIGTSTP: return "SIGTSTP"; 109353a5a1b3Sopenharmony_ci#endif 109453a5a1b3Sopenharmony_ci#ifdef SIGTTIN 109553a5a1b3Sopenharmony_ci case SIGTTIN: return "SIGTTIN"; 109653a5a1b3Sopenharmony_ci#endif 109753a5a1b3Sopenharmony_ci#ifdef SIGTTOU 109853a5a1b3Sopenharmony_ci case SIGTTOU: return "SIGTTOU"; 109953a5a1b3Sopenharmony_ci#endif 110053a5a1b3Sopenharmony_ci#ifdef SIGURG 110153a5a1b3Sopenharmony_ci case SIGURG: return "SIGURG"; 110253a5a1b3Sopenharmony_ci#endif 110353a5a1b3Sopenharmony_ci#ifdef SIGXCPU 110453a5a1b3Sopenharmony_ci case SIGXCPU: return "SIGXCPU"; 110553a5a1b3Sopenharmony_ci#endif 110653a5a1b3Sopenharmony_ci#ifdef SIGXFSZ 110753a5a1b3Sopenharmony_ci case SIGXFSZ: return "SIGXFSZ"; 110853a5a1b3Sopenharmony_ci#endif 110953a5a1b3Sopenharmony_ci#ifdef SIGVTALRM 111053a5a1b3Sopenharmony_ci case SIGVTALRM: return "SIGVTALRM"; 111153a5a1b3Sopenharmony_ci#endif 111253a5a1b3Sopenharmony_ci#ifdef SIGPROF 111353a5a1b3Sopenharmony_ci case SIGPROF: return "SIGPROF"; 111453a5a1b3Sopenharmony_ci#endif 111553a5a1b3Sopenharmony_ci#ifdef SIGWINCH 111653a5a1b3Sopenharmony_ci case SIGWINCH: return "SIGWINCH"; 111753a5a1b3Sopenharmony_ci#endif 111853a5a1b3Sopenharmony_ci#ifdef SIGIO 111953a5a1b3Sopenharmony_ci case SIGIO: return "SIGIO"; 112053a5a1b3Sopenharmony_ci#endif 112153a5a1b3Sopenharmony_ci#ifdef SIGPWR 112253a5a1b3Sopenharmony_ci case SIGPWR: return "SIGPWR"; 112353a5a1b3Sopenharmony_ci#endif 112453a5a1b3Sopenharmony_ci#ifdef SIGSYS 112553a5a1b3Sopenharmony_ci case SIGSYS: return "SIGSYS"; 112653a5a1b3Sopenharmony_ci#endif 112753a5a1b3Sopenharmony_ci } 112853a5a1b3Sopenharmony_ci 112953a5a1b3Sopenharmony_ci#ifdef SIGRTMIN 113053a5a1b3Sopenharmony_ci if (sig >= SIGRTMIN && sig <= SIGRTMAX) { 113153a5a1b3Sopenharmony_ci pa_xfree(PA_STATIC_TLS_GET(signame)); 113253a5a1b3Sopenharmony_ci t = pa_sprintf_malloc("SIGRTMIN+%i", sig - SIGRTMIN); 113353a5a1b3Sopenharmony_ci PA_STATIC_TLS_SET(signame, t); 113453a5a1b3Sopenharmony_ci return t; 113553a5a1b3Sopenharmony_ci } 113653a5a1b3Sopenharmony_ci#endif 113753a5a1b3Sopenharmony_ci 113853a5a1b3Sopenharmony_ci#endif 113953a5a1b3Sopenharmony_ci 114053a5a1b3Sopenharmony_cifail: 114153a5a1b3Sopenharmony_ci 114253a5a1b3Sopenharmony_ci pa_xfree(PA_STATIC_TLS_GET(signame)); 114353a5a1b3Sopenharmony_ci t = pa_sprintf_malloc("SIG%i", sig); 114453a5a1b3Sopenharmony_ci PA_STATIC_TLS_SET(signame, t); 114553a5a1b3Sopenharmony_ci return t; 114653a5a1b3Sopenharmony_ci} 114753a5a1b3Sopenharmony_ci 114853a5a1b3Sopenharmony_ci#ifdef HAVE_GRP_H 114953a5a1b3Sopenharmony_ci 115053a5a1b3Sopenharmony_ci/* Check whether the specified GID and the group name match */ 115153a5a1b3Sopenharmony_cistatic int is_group(gid_t gid, const char *name) { 115253a5a1b3Sopenharmony_ci struct group *group = NULL; 115353a5a1b3Sopenharmony_ci int r = -1; 115453a5a1b3Sopenharmony_ci 115553a5a1b3Sopenharmony_ci errno = 0; 115653a5a1b3Sopenharmony_ci if (!(group = pa_getgrgid_malloc(gid))) { 115753a5a1b3Sopenharmony_ci if (!errno) 115853a5a1b3Sopenharmony_ci errno = ENOENT; 115953a5a1b3Sopenharmony_ci 116053a5a1b3Sopenharmony_ci pa_log("pa_getgrgid_malloc(%u): %s", gid, pa_cstrerror(errno)); 116153a5a1b3Sopenharmony_ci 116253a5a1b3Sopenharmony_ci goto finish; 116353a5a1b3Sopenharmony_ci } 116453a5a1b3Sopenharmony_ci 116553a5a1b3Sopenharmony_ci r = pa_streq(name, group->gr_name); 116653a5a1b3Sopenharmony_ci 116753a5a1b3Sopenharmony_cifinish: 116853a5a1b3Sopenharmony_ci pa_getgrgid_free(group); 116953a5a1b3Sopenharmony_ci 117053a5a1b3Sopenharmony_ci return r; 117153a5a1b3Sopenharmony_ci} 117253a5a1b3Sopenharmony_ci 117353a5a1b3Sopenharmony_ci/* Check the current user is member of the specified group */ 117453a5a1b3Sopenharmony_ciint pa_own_uid_in_group(const char *name, gid_t *gid) { 117553a5a1b3Sopenharmony_ci GETGROUPS_T *gids, tgid; 117653a5a1b3Sopenharmony_ci long n = sysconf(_SC_NGROUPS_MAX); 117753a5a1b3Sopenharmony_ci int r = -1, i, k; 117853a5a1b3Sopenharmony_ci 117953a5a1b3Sopenharmony_ci pa_assert(n > 0); 118053a5a1b3Sopenharmony_ci 118153a5a1b3Sopenharmony_ci gids = pa_xmalloc(sizeof(GETGROUPS_T) * (size_t) n); 118253a5a1b3Sopenharmony_ci 118353a5a1b3Sopenharmony_ci if ((n = getgroups((int) n, gids)) < 0) { 118453a5a1b3Sopenharmony_ci pa_log("getgroups(): %s", pa_cstrerror(errno)); 118553a5a1b3Sopenharmony_ci goto finish; 118653a5a1b3Sopenharmony_ci } 118753a5a1b3Sopenharmony_ci 118853a5a1b3Sopenharmony_ci for (i = 0; i < n; i++) { 118953a5a1b3Sopenharmony_ci 119053a5a1b3Sopenharmony_ci if ((k = is_group(gids[i], name)) < 0) 119153a5a1b3Sopenharmony_ci goto finish; 119253a5a1b3Sopenharmony_ci else if (k > 0) { 119353a5a1b3Sopenharmony_ci *gid = gids[i]; 119453a5a1b3Sopenharmony_ci r = 1; 119553a5a1b3Sopenharmony_ci goto finish; 119653a5a1b3Sopenharmony_ci } 119753a5a1b3Sopenharmony_ci } 119853a5a1b3Sopenharmony_ci 119953a5a1b3Sopenharmony_ci if ((k = is_group(tgid = getgid(), name)) < 0) 120053a5a1b3Sopenharmony_ci goto finish; 120153a5a1b3Sopenharmony_ci else if (k > 0) { 120253a5a1b3Sopenharmony_ci *gid = tgid; 120353a5a1b3Sopenharmony_ci r = 1; 120453a5a1b3Sopenharmony_ci goto finish; 120553a5a1b3Sopenharmony_ci } 120653a5a1b3Sopenharmony_ci 120753a5a1b3Sopenharmony_ci r = 0; 120853a5a1b3Sopenharmony_ci 120953a5a1b3Sopenharmony_cifinish: 121053a5a1b3Sopenharmony_ci 121153a5a1b3Sopenharmony_ci pa_xfree(gids); 121253a5a1b3Sopenharmony_ci return r; 121353a5a1b3Sopenharmony_ci} 121453a5a1b3Sopenharmony_ci 121553a5a1b3Sopenharmony_ci/* Check whether the specific user id is a member of the specified group */ 121653a5a1b3Sopenharmony_ciint pa_uid_in_group(uid_t uid, const char *name) { 121753a5a1b3Sopenharmony_ci struct group *group = NULL; 121853a5a1b3Sopenharmony_ci char **i; 121953a5a1b3Sopenharmony_ci int r = -1; 122053a5a1b3Sopenharmony_ci 122153a5a1b3Sopenharmony_ci errno = 0; 122253a5a1b3Sopenharmony_ci if (!(group = pa_getgrnam_malloc(name))) { 122353a5a1b3Sopenharmony_ci if (!errno) 122453a5a1b3Sopenharmony_ci errno = ENOENT; 122553a5a1b3Sopenharmony_ci goto finish; 122653a5a1b3Sopenharmony_ci } 122753a5a1b3Sopenharmony_ci 122853a5a1b3Sopenharmony_ci r = 0; 122953a5a1b3Sopenharmony_ci for (i = group->gr_mem; *i; i++) { 123053a5a1b3Sopenharmony_ci struct passwd *pw = NULL; 123153a5a1b3Sopenharmony_ci 123253a5a1b3Sopenharmony_ci errno = 0; 123353a5a1b3Sopenharmony_ci if (!(pw = pa_getpwnam_malloc(*i))) 123453a5a1b3Sopenharmony_ci continue; 123553a5a1b3Sopenharmony_ci 123653a5a1b3Sopenharmony_ci if (pw->pw_uid == uid) 123753a5a1b3Sopenharmony_ci r = 1; 123853a5a1b3Sopenharmony_ci 123953a5a1b3Sopenharmony_ci pa_getpwnam_free(pw); 124053a5a1b3Sopenharmony_ci 124153a5a1b3Sopenharmony_ci if (r == 1) 124253a5a1b3Sopenharmony_ci break; 124353a5a1b3Sopenharmony_ci } 124453a5a1b3Sopenharmony_ci 124553a5a1b3Sopenharmony_cifinish: 124653a5a1b3Sopenharmony_ci pa_getgrnam_free(group); 124753a5a1b3Sopenharmony_ci 124853a5a1b3Sopenharmony_ci return r; 124953a5a1b3Sopenharmony_ci} 125053a5a1b3Sopenharmony_ci 125153a5a1b3Sopenharmony_ci/* Get the GID of a given group, return (gid_t) -1 on failure. */ 125253a5a1b3Sopenharmony_cigid_t pa_get_gid_of_group(const char *name) { 125353a5a1b3Sopenharmony_ci gid_t ret = (gid_t) -1; 125453a5a1b3Sopenharmony_ci struct group *gr = NULL; 125553a5a1b3Sopenharmony_ci 125653a5a1b3Sopenharmony_ci errno = 0; 125753a5a1b3Sopenharmony_ci if (!(gr = pa_getgrnam_malloc(name))) { 125853a5a1b3Sopenharmony_ci if (!errno) 125953a5a1b3Sopenharmony_ci errno = ENOENT; 126053a5a1b3Sopenharmony_ci goto finish; 126153a5a1b3Sopenharmony_ci } 126253a5a1b3Sopenharmony_ci 126353a5a1b3Sopenharmony_ci ret = gr->gr_gid; 126453a5a1b3Sopenharmony_ci 126553a5a1b3Sopenharmony_cifinish: 126653a5a1b3Sopenharmony_ci pa_getgrnam_free(gr); 126753a5a1b3Sopenharmony_ci return ret; 126853a5a1b3Sopenharmony_ci} 126953a5a1b3Sopenharmony_ci 127053a5a1b3Sopenharmony_ciint pa_check_in_group(gid_t g) { 127153a5a1b3Sopenharmony_ci gid_t gids[NGROUPS_MAX]; 127253a5a1b3Sopenharmony_ci int r; 127353a5a1b3Sopenharmony_ci 127453a5a1b3Sopenharmony_ci if ((r = getgroups(NGROUPS_MAX, gids)) < 0) 127553a5a1b3Sopenharmony_ci return -1; 127653a5a1b3Sopenharmony_ci 127753a5a1b3Sopenharmony_ci for (; r > 0; r--) 127853a5a1b3Sopenharmony_ci if (gids[r-1] == g) 127953a5a1b3Sopenharmony_ci return 1; 128053a5a1b3Sopenharmony_ci 128153a5a1b3Sopenharmony_ci return 0; 128253a5a1b3Sopenharmony_ci} 128353a5a1b3Sopenharmony_ci 128453a5a1b3Sopenharmony_ci#else /* HAVE_GRP_H */ 128553a5a1b3Sopenharmony_ci 128653a5a1b3Sopenharmony_ciint pa_own_uid_in_group(const char *name, gid_t *gid) { 128753a5a1b3Sopenharmony_ci errno = ENOTSUP; 128853a5a1b3Sopenharmony_ci return -1; 128953a5a1b3Sopenharmony_ci 129053a5a1b3Sopenharmony_ci} 129153a5a1b3Sopenharmony_ci 129253a5a1b3Sopenharmony_ciint pa_uid_in_group(uid_t uid, const char *name) { 129353a5a1b3Sopenharmony_ci errno = ENOTSUP; 129453a5a1b3Sopenharmony_ci return -1; 129553a5a1b3Sopenharmony_ci} 129653a5a1b3Sopenharmony_ci 129753a5a1b3Sopenharmony_cigid_t pa_get_gid_of_group(const char *name) { 129853a5a1b3Sopenharmony_ci errno = ENOTSUP; 129953a5a1b3Sopenharmony_ci return (gid_t) -1; 130053a5a1b3Sopenharmony_ci} 130153a5a1b3Sopenharmony_ci 130253a5a1b3Sopenharmony_ciint pa_check_in_group(gid_t g) { 130353a5a1b3Sopenharmony_ci errno = ENOTSUP; 130453a5a1b3Sopenharmony_ci return -1; 130553a5a1b3Sopenharmony_ci} 130653a5a1b3Sopenharmony_ci 130753a5a1b3Sopenharmony_ci#endif 130853a5a1b3Sopenharmony_ci 130953a5a1b3Sopenharmony_ci/* Lock or unlock a file entirely. 131053a5a1b3Sopenharmony_ci (advisory on UNIX, mandatory on Windows) */ 131153a5a1b3Sopenharmony_ciint pa_lock_fd(int fd, int b) { 131253a5a1b3Sopenharmony_ci#ifdef F_SETLKW 131353a5a1b3Sopenharmony_ci struct flock f_lock; 131453a5a1b3Sopenharmony_ci 131553a5a1b3Sopenharmony_ci /* Try a R/W lock first */ 131653a5a1b3Sopenharmony_ci 131753a5a1b3Sopenharmony_ci f_lock.l_type = (short) (b ? F_WRLCK : F_UNLCK); 131853a5a1b3Sopenharmony_ci f_lock.l_whence = SEEK_SET; 131953a5a1b3Sopenharmony_ci f_lock.l_start = 0; 132053a5a1b3Sopenharmony_ci f_lock.l_len = 0; 132153a5a1b3Sopenharmony_ci 132253a5a1b3Sopenharmony_ci if (fcntl(fd, F_SETLKW, &f_lock) >= 0) 132353a5a1b3Sopenharmony_ci return 0; 132453a5a1b3Sopenharmony_ci 132553a5a1b3Sopenharmony_ci /* Perhaps the file descriptor was opened for read only, than try again with a read lock. */ 132653a5a1b3Sopenharmony_ci if (b && errno == EBADF) { 132753a5a1b3Sopenharmony_ci f_lock.l_type = F_RDLCK; 132853a5a1b3Sopenharmony_ci if (fcntl(fd, F_SETLKW, &f_lock) >= 0) 132953a5a1b3Sopenharmony_ci return 0; 133053a5a1b3Sopenharmony_ci } 133153a5a1b3Sopenharmony_ci 133253a5a1b3Sopenharmony_ci pa_log("%slock: %s", !b ? "un" : "", pa_cstrerror(errno)); 133353a5a1b3Sopenharmony_ci#endif 133453a5a1b3Sopenharmony_ci 133553a5a1b3Sopenharmony_ci#ifdef OS_IS_WIN32 133653a5a1b3Sopenharmony_ci HANDLE h = (HANDLE) _get_osfhandle(fd); 133753a5a1b3Sopenharmony_ci 133853a5a1b3Sopenharmony_ci if (b && LockFile(h, 0, 0, 0xFFFFFFFF, 0xFFFFFFFF)) 133953a5a1b3Sopenharmony_ci return 0; 134053a5a1b3Sopenharmony_ci if (!b && UnlockFile(h, 0, 0, 0xFFFFFFFF, 0xFFFFFFFF)) 134153a5a1b3Sopenharmony_ci return 0; 134253a5a1b3Sopenharmony_ci 134353a5a1b3Sopenharmony_ci pa_log("%slock failed: 0x%08lX", !b ? "un" : "", GetLastError()); 134453a5a1b3Sopenharmony_ci 134553a5a1b3Sopenharmony_ci /* FIXME: Needs to set errno! */ 134653a5a1b3Sopenharmony_ci#endif 134753a5a1b3Sopenharmony_ci 134853a5a1b3Sopenharmony_ci return -1; 134953a5a1b3Sopenharmony_ci} 135053a5a1b3Sopenharmony_ci 135153a5a1b3Sopenharmony_ci/* Remove trailing newlines from a string */ 135253a5a1b3Sopenharmony_cichar* pa_strip_nl(char *s) { 135353a5a1b3Sopenharmony_ci pa_assert(s); 135453a5a1b3Sopenharmony_ci 135553a5a1b3Sopenharmony_ci s[strcspn(s, NEWLINE)] = 0; 135653a5a1b3Sopenharmony_ci return s; 135753a5a1b3Sopenharmony_ci} 135853a5a1b3Sopenharmony_ci 135953a5a1b3Sopenharmony_cichar *pa_strip(char *s) { 136053a5a1b3Sopenharmony_ci char *e, *l = NULL; 136153a5a1b3Sopenharmony_ci 136253a5a1b3Sopenharmony_ci /* Drops trailing whitespace. Modifies the string in 136353a5a1b3Sopenharmony_ci * place. Returns pointer to first non-space character */ 136453a5a1b3Sopenharmony_ci 136553a5a1b3Sopenharmony_ci s += strspn(s, WHITESPACE); 136653a5a1b3Sopenharmony_ci 136753a5a1b3Sopenharmony_ci for (e = s; *e; e++) 136853a5a1b3Sopenharmony_ci if (!strchr(WHITESPACE, *e)) 136953a5a1b3Sopenharmony_ci l = e; 137053a5a1b3Sopenharmony_ci 137153a5a1b3Sopenharmony_ci if (l) 137253a5a1b3Sopenharmony_ci *(l+1) = 0; 137353a5a1b3Sopenharmony_ci else 137453a5a1b3Sopenharmony_ci *s = 0; 137553a5a1b3Sopenharmony_ci 137653a5a1b3Sopenharmony_ci return s; 137753a5a1b3Sopenharmony_ci} 137853a5a1b3Sopenharmony_ci 137953a5a1b3Sopenharmony_ci/* Create a temporary lock file and lock it. */ 138053a5a1b3Sopenharmony_ciint pa_lock_lockfile(const char *fn) { 138153a5a1b3Sopenharmony_ci int fd; 138253a5a1b3Sopenharmony_ci pa_assert(fn); 138353a5a1b3Sopenharmony_ci 138453a5a1b3Sopenharmony_ci for (;;) { 138553a5a1b3Sopenharmony_ci struct stat st; 138653a5a1b3Sopenharmony_ci 138753a5a1b3Sopenharmony_ci if ((fd = pa_open_cloexec(fn, O_CREAT|O_RDWR 138853a5a1b3Sopenharmony_ci#ifdef O_NOFOLLOW 138953a5a1b3Sopenharmony_ci |O_NOFOLLOW 139053a5a1b3Sopenharmony_ci#endif 139153a5a1b3Sopenharmony_ci , S_IRUSR|S_IWUSR)) < 0) { 139253a5a1b3Sopenharmony_ci pa_log_warn("Failed to create lock file '%s': %s", fn, pa_cstrerror(errno)); 139353a5a1b3Sopenharmony_ci goto fail; 139453a5a1b3Sopenharmony_ci } 139553a5a1b3Sopenharmony_ci 139653a5a1b3Sopenharmony_ci if (pa_lock_fd(fd, 1) < 0) { 139753a5a1b3Sopenharmony_ci pa_log_warn("Failed to lock file '%s'.", fn); 139853a5a1b3Sopenharmony_ci goto fail; 139953a5a1b3Sopenharmony_ci } 140053a5a1b3Sopenharmony_ci 140153a5a1b3Sopenharmony_ci if (fstat(fd, &st) < 0) { 140253a5a1b3Sopenharmony_ci pa_log_warn("Failed to fstat() file '%s': %s", fn, pa_cstrerror(errno)); 140353a5a1b3Sopenharmony_ci goto fail; 140453a5a1b3Sopenharmony_ci } 140553a5a1b3Sopenharmony_ci 140653a5a1b3Sopenharmony_ci /* Check whether the file has been removed meanwhile. When yes, 140753a5a1b3Sopenharmony_ci * restart this loop, otherwise, we're done */ 140853a5a1b3Sopenharmony_ci if (st.st_nlink >= 1) 140953a5a1b3Sopenharmony_ci break; 141053a5a1b3Sopenharmony_ci 141153a5a1b3Sopenharmony_ci if (pa_lock_fd(fd, 0) < 0) { 141253a5a1b3Sopenharmony_ci pa_log_warn("Failed to unlock file '%s'.", fn); 141353a5a1b3Sopenharmony_ci goto fail; 141453a5a1b3Sopenharmony_ci } 141553a5a1b3Sopenharmony_ci 141653a5a1b3Sopenharmony_ci if (pa_close(fd) < 0) { 141753a5a1b3Sopenharmony_ci pa_log_warn("Failed to close file '%s': %s", fn, pa_cstrerror(errno)); 141853a5a1b3Sopenharmony_ci fd = -1; 141953a5a1b3Sopenharmony_ci goto fail; 142053a5a1b3Sopenharmony_ci } 142153a5a1b3Sopenharmony_ci } 142253a5a1b3Sopenharmony_ci 142353a5a1b3Sopenharmony_ci return fd; 142453a5a1b3Sopenharmony_ci 142553a5a1b3Sopenharmony_cifail: 142653a5a1b3Sopenharmony_ci 142753a5a1b3Sopenharmony_ci if (fd >= 0) { 142853a5a1b3Sopenharmony_ci int saved_errno = errno; 142953a5a1b3Sopenharmony_ci pa_close(fd); 143053a5a1b3Sopenharmony_ci errno = saved_errno; 143153a5a1b3Sopenharmony_ci } 143253a5a1b3Sopenharmony_ci 143353a5a1b3Sopenharmony_ci return -1; 143453a5a1b3Sopenharmony_ci} 143553a5a1b3Sopenharmony_ci 143653a5a1b3Sopenharmony_ci/* Unlock a temporary lock file */ 143753a5a1b3Sopenharmony_ciint pa_unlock_lockfile(const char *fn, int fd) { 143853a5a1b3Sopenharmony_ci int r = 0; 143953a5a1b3Sopenharmony_ci pa_assert(fd >= 0); 144053a5a1b3Sopenharmony_ci 144153a5a1b3Sopenharmony_ci if (fn) { 144253a5a1b3Sopenharmony_ci if (unlink(fn) < 0) { 144353a5a1b3Sopenharmony_ci pa_log_warn("Unable to remove lock file '%s': %s", fn, pa_cstrerror(errno)); 144453a5a1b3Sopenharmony_ci r = -1; 144553a5a1b3Sopenharmony_ci } 144653a5a1b3Sopenharmony_ci } 144753a5a1b3Sopenharmony_ci 144853a5a1b3Sopenharmony_ci if (pa_lock_fd(fd, 0) < 0) { 144953a5a1b3Sopenharmony_ci pa_log_warn("Failed to unlock file '%s'.", fn); 145053a5a1b3Sopenharmony_ci r = -1; 145153a5a1b3Sopenharmony_ci } 145253a5a1b3Sopenharmony_ci 145353a5a1b3Sopenharmony_ci if (pa_close(fd) < 0) { 145453a5a1b3Sopenharmony_ci pa_log_warn("Failed to close '%s': %s", fn, pa_cstrerror(errno)); 145553a5a1b3Sopenharmony_ci r = -1; 145653a5a1b3Sopenharmony_ci } 145753a5a1b3Sopenharmony_ci 145853a5a1b3Sopenharmony_ci return r; 145953a5a1b3Sopenharmony_ci} 146053a5a1b3Sopenharmony_ci 146153a5a1b3Sopenharmony_cistatic int check_ours(const char *p) { 146253a5a1b3Sopenharmony_ci struct stat st; 146353a5a1b3Sopenharmony_ci 146453a5a1b3Sopenharmony_ci pa_assert(p); 146553a5a1b3Sopenharmony_ci 146653a5a1b3Sopenharmony_ci if (stat(p, &st) < 0) 146753a5a1b3Sopenharmony_ci return -errno; 146853a5a1b3Sopenharmony_ci 146953a5a1b3Sopenharmony_ci#ifdef HAVE_GETUID 147053a5a1b3Sopenharmony_ci if (st.st_uid != getuid() && st.st_uid != 0) 147153a5a1b3Sopenharmony_ci return -EACCES; 147253a5a1b3Sopenharmony_ci#endif 147353a5a1b3Sopenharmony_ci 147453a5a1b3Sopenharmony_ci return 0; 147553a5a1b3Sopenharmony_ci} 147653a5a1b3Sopenharmony_ci 147753a5a1b3Sopenharmony_cistatic char *get_pulse_home(void) { 147853a5a1b3Sopenharmony_ci char *h, *ret; 147953a5a1b3Sopenharmony_ci int t; 148053a5a1b3Sopenharmony_ci 148153a5a1b3Sopenharmony_ci h = pa_get_home_dir_malloc(); 148253a5a1b3Sopenharmony_ci if (!h) { 148353a5a1b3Sopenharmony_ci pa_log_error("Failed to get home directory."); 148453a5a1b3Sopenharmony_ci return NULL; 148553a5a1b3Sopenharmony_ci } 148653a5a1b3Sopenharmony_ci 148753a5a1b3Sopenharmony_ci t = check_ours(h); 148853a5a1b3Sopenharmony_ci if (t < 0 && t != -ENOENT) { 148953a5a1b3Sopenharmony_ci pa_log_error("Home directory not accessible: %s", pa_cstrerror(-t)); 149053a5a1b3Sopenharmony_ci pa_xfree(h); 149153a5a1b3Sopenharmony_ci return NULL; 149253a5a1b3Sopenharmony_ci } 149353a5a1b3Sopenharmony_ci 149453a5a1b3Sopenharmony_ci /* If the old directory exists, use it. */ 149553a5a1b3Sopenharmony_ci ret = pa_sprintf_malloc("%s" PA_PATH_SEP ".pulse", h); 149653a5a1b3Sopenharmony_ci pa_xfree(h); 149753a5a1b3Sopenharmony_ci if (access(ret, F_OK) >= 0) 149853a5a1b3Sopenharmony_ci return ret; 149953a5a1b3Sopenharmony_ci free(ret); 150053a5a1b3Sopenharmony_ci 150153a5a1b3Sopenharmony_ci /* Otherwise go for the XDG compliant directory. */ 150253a5a1b3Sopenharmony_ci if (pa_get_config_home_dir(&ret) < 0) 150353a5a1b3Sopenharmony_ci return NULL; 150453a5a1b3Sopenharmony_ci 150553a5a1b3Sopenharmony_ci return ret; 150653a5a1b3Sopenharmony_ci} 150753a5a1b3Sopenharmony_ci 150853a5a1b3Sopenharmony_cichar *pa_get_state_dir(void) { 150953a5a1b3Sopenharmony_ci char *d; 151053a5a1b3Sopenharmony_ci 151153a5a1b3Sopenharmony_ci /* The state directory shall contain dynamic data that should be 151253a5a1b3Sopenharmony_ci * kept across reboots, and is private to this user */ 151353a5a1b3Sopenharmony_ci 151453a5a1b3Sopenharmony_ci if (!(d = pa_xstrdup(getenv("PULSE_STATE_PATH")))) 151553a5a1b3Sopenharmony_ci if (!(d = get_pulse_home())) 151653a5a1b3Sopenharmony_ci return NULL; 151753a5a1b3Sopenharmony_ci 151853a5a1b3Sopenharmony_ci /* If PULSE_STATE_PATH and PULSE_RUNTIME_PATH point to the same 151953a5a1b3Sopenharmony_ci * dir then this will break. */ 152053a5a1b3Sopenharmony_ci 152153a5a1b3Sopenharmony_ci if (pa_make_secure_dir(d, 0700U, (uid_t) -1, (gid_t) -1, true) < 0) { 152253a5a1b3Sopenharmony_ci pa_log_error("Failed to create secure directory (%s): %s", d, pa_cstrerror(errno)); 152353a5a1b3Sopenharmony_ci pa_xfree(d); 152453a5a1b3Sopenharmony_ci return NULL; 152553a5a1b3Sopenharmony_ci } 152653a5a1b3Sopenharmony_ci 152753a5a1b3Sopenharmony_ci return d; 152853a5a1b3Sopenharmony_ci} 152953a5a1b3Sopenharmony_ci 153053a5a1b3Sopenharmony_cichar *pa_get_home_dir_malloc(void) { 153153a5a1b3Sopenharmony_ci char *homedir; 153253a5a1b3Sopenharmony_ci size_t allocated = 128; 153353a5a1b3Sopenharmony_ci 153453a5a1b3Sopenharmony_ci for (;;) { 153553a5a1b3Sopenharmony_ci homedir = pa_xmalloc(allocated); 153653a5a1b3Sopenharmony_ci 153753a5a1b3Sopenharmony_ci if (!pa_get_home_dir(homedir, allocated)) { 153853a5a1b3Sopenharmony_ci pa_xfree(homedir); 153953a5a1b3Sopenharmony_ci return NULL; 154053a5a1b3Sopenharmony_ci } 154153a5a1b3Sopenharmony_ci 154253a5a1b3Sopenharmony_ci if (strlen(homedir) < allocated - 1) 154353a5a1b3Sopenharmony_ci break; 154453a5a1b3Sopenharmony_ci 154553a5a1b3Sopenharmony_ci pa_xfree(homedir); 154653a5a1b3Sopenharmony_ci allocated *= 2; 154753a5a1b3Sopenharmony_ci } 154853a5a1b3Sopenharmony_ci 154953a5a1b3Sopenharmony_ci return homedir; 155053a5a1b3Sopenharmony_ci} 155153a5a1b3Sopenharmony_ci 155253a5a1b3Sopenharmony_ciint pa_append_to_home_dir(const char *path, char **_r) { 155353a5a1b3Sopenharmony_ci char *home_dir; 155453a5a1b3Sopenharmony_ci 155553a5a1b3Sopenharmony_ci pa_assert(path); 155653a5a1b3Sopenharmony_ci pa_assert(_r); 155753a5a1b3Sopenharmony_ci 155853a5a1b3Sopenharmony_ci home_dir = pa_get_home_dir_malloc(); 155953a5a1b3Sopenharmony_ci if (!home_dir) { 156053a5a1b3Sopenharmony_ci pa_log("Failed to get home directory."); 156153a5a1b3Sopenharmony_ci return -PA_ERR_NOENTITY; 156253a5a1b3Sopenharmony_ci } 156353a5a1b3Sopenharmony_ci 156453a5a1b3Sopenharmony_ci *_r = pa_sprintf_malloc("%s" PA_PATH_SEP "%s", home_dir, path); 156553a5a1b3Sopenharmony_ci pa_xfree(home_dir); 156653a5a1b3Sopenharmony_ci return 0; 156753a5a1b3Sopenharmony_ci} 156853a5a1b3Sopenharmony_ci 156953a5a1b3Sopenharmony_ciint pa_get_config_home_dir(char **_r) { 157053a5a1b3Sopenharmony_ci const char *e; 157153a5a1b3Sopenharmony_ci char *home_dir; 157253a5a1b3Sopenharmony_ci 157353a5a1b3Sopenharmony_ci pa_assert(_r); 157453a5a1b3Sopenharmony_ci 157553a5a1b3Sopenharmony_ci e = getenv("XDG_CONFIG_HOME"); 157653a5a1b3Sopenharmony_ci if (e && *e) { 157753a5a1b3Sopenharmony_ci *_r = pa_sprintf_malloc("%s" PA_PATH_SEP "pulse", e); 157853a5a1b3Sopenharmony_ci return 0; 157953a5a1b3Sopenharmony_ci } 158053a5a1b3Sopenharmony_ci 158153a5a1b3Sopenharmony_ci home_dir = pa_get_home_dir_malloc(); 158253a5a1b3Sopenharmony_ci if (!home_dir) 158353a5a1b3Sopenharmony_ci return -PA_ERR_NOENTITY; 158453a5a1b3Sopenharmony_ci 158553a5a1b3Sopenharmony_ci *_r = pa_sprintf_malloc("%s" PA_PATH_SEP ".config" PA_PATH_SEP "pulse", home_dir); 158653a5a1b3Sopenharmony_ci pa_xfree(home_dir); 158753a5a1b3Sopenharmony_ci return 0; 158853a5a1b3Sopenharmony_ci} 158953a5a1b3Sopenharmony_ci 159053a5a1b3Sopenharmony_ciint pa_get_data_home_dir(char **_r) { 159153a5a1b3Sopenharmony_ci const char *e; 159253a5a1b3Sopenharmony_ci char *home_dir; 159353a5a1b3Sopenharmony_ci 159453a5a1b3Sopenharmony_ci pa_assert(_r); 159553a5a1b3Sopenharmony_ci 159653a5a1b3Sopenharmony_ci e = getenv("XDG_DATA_HOME"); 159753a5a1b3Sopenharmony_ci if (e && *e) { 159853a5a1b3Sopenharmony_ci if (pa_is_path_absolute(e)) { 159953a5a1b3Sopenharmony_ci *_r = pa_sprintf_malloc("%s" PA_PATH_SEP "pulseaudio", e); 160053a5a1b3Sopenharmony_ci return 0; 160153a5a1b3Sopenharmony_ci } 160253a5a1b3Sopenharmony_ci else 160353a5a1b3Sopenharmony_ci pa_log_warn("Ignored non-absolute XDG_DATA_HOME value '%s'", e); 160453a5a1b3Sopenharmony_ci } 160553a5a1b3Sopenharmony_ci 160653a5a1b3Sopenharmony_ci home_dir = pa_get_home_dir_malloc(); 160753a5a1b3Sopenharmony_ci if (!home_dir) 160853a5a1b3Sopenharmony_ci return -PA_ERR_NOENTITY; 160953a5a1b3Sopenharmony_ci 161053a5a1b3Sopenharmony_ci *_r = pa_sprintf_malloc("%s" PA_PATH_SEP ".local" PA_PATH_SEP "share" PA_PATH_SEP "pulseaudio", home_dir); 161153a5a1b3Sopenharmony_ci pa_xfree(home_dir); 161253a5a1b3Sopenharmony_ci return 0; 161353a5a1b3Sopenharmony_ci} 161453a5a1b3Sopenharmony_ci 161553a5a1b3Sopenharmony_ciint pa_get_data_dirs(pa_dynarray **_r) { 161653a5a1b3Sopenharmony_ci const char *e; 161753a5a1b3Sopenharmony_ci const char *def = "/usr/local/share/:/usr/share/"; 161853a5a1b3Sopenharmony_ci const char *p; 161953a5a1b3Sopenharmony_ci const char *split_state = NULL; 162053a5a1b3Sopenharmony_ci char *n; 162153a5a1b3Sopenharmony_ci pa_dynarray *paths; 162253a5a1b3Sopenharmony_ci 162353a5a1b3Sopenharmony_ci pa_assert(_r); 162453a5a1b3Sopenharmony_ci 162553a5a1b3Sopenharmony_ci e = getenv("XDG_DATA_DIRS"); 162653a5a1b3Sopenharmony_ci p = e && *e ? e : def; 162753a5a1b3Sopenharmony_ci 162853a5a1b3Sopenharmony_ci paths = pa_dynarray_new((pa_free_cb_t) pa_xfree); 162953a5a1b3Sopenharmony_ci 163053a5a1b3Sopenharmony_ci while ((n = pa_split(p, ":", &split_state))) { 163153a5a1b3Sopenharmony_ci char *path; 163253a5a1b3Sopenharmony_ci 163353a5a1b3Sopenharmony_ci if (!pa_is_path_absolute(n)) { 163453a5a1b3Sopenharmony_ci pa_log_warn("Ignored non-absolute path '%s' in XDG_DATA_DIRS", n); 163553a5a1b3Sopenharmony_ci pa_xfree(n); 163653a5a1b3Sopenharmony_ci continue; 163753a5a1b3Sopenharmony_ci } 163853a5a1b3Sopenharmony_ci 163953a5a1b3Sopenharmony_ci path = pa_sprintf_malloc("%s" PA_PATH_SEP "pulseaudio", n); 164053a5a1b3Sopenharmony_ci pa_xfree(n); 164153a5a1b3Sopenharmony_ci pa_dynarray_append(paths, path); 164253a5a1b3Sopenharmony_ci } 164353a5a1b3Sopenharmony_ci 164453a5a1b3Sopenharmony_ci if (pa_dynarray_size(paths) == 0) { 164553a5a1b3Sopenharmony_ci pa_log_warn("XDG_DATA_DIRS contains no valid paths"); 164653a5a1b3Sopenharmony_ci pa_dynarray_free(paths); 164753a5a1b3Sopenharmony_ci return -PA_ERR_INVALID; 164853a5a1b3Sopenharmony_ci } 164953a5a1b3Sopenharmony_ci 165053a5a1b3Sopenharmony_ci *_r = paths; 165153a5a1b3Sopenharmony_ci return 0; 165253a5a1b3Sopenharmony_ci} 165353a5a1b3Sopenharmony_ci 165453a5a1b3Sopenharmony_ciint pa_append_to_config_home_dir(const char *path, char **_r) { 165553a5a1b3Sopenharmony_ci int r; 165653a5a1b3Sopenharmony_ci char *config_home_dir; 165753a5a1b3Sopenharmony_ci 165853a5a1b3Sopenharmony_ci pa_assert(path); 165953a5a1b3Sopenharmony_ci pa_assert(_r); 166053a5a1b3Sopenharmony_ci 166153a5a1b3Sopenharmony_ci r = pa_get_config_home_dir(&config_home_dir); 166253a5a1b3Sopenharmony_ci if (r < 0) 166353a5a1b3Sopenharmony_ci return r; 166453a5a1b3Sopenharmony_ci 166553a5a1b3Sopenharmony_ci *_r = pa_sprintf_malloc("%s" PA_PATH_SEP "%s", config_home_dir, path); 166653a5a1b3Sopenharmony_ci pa_xfree(config_home_dir); 166753a5a1b3Sopenharmony_ci return 0; 166853a5a1b3Sopenharmony_ci} 166953a5a1b3Sopenharmony_ci 167053a5a1b3Sopenharmony_cichar *pa_get_binary_name_malloc(void) { 167153a5a1b3Sopenharmony_ci char *t; 167253a5a1b3Sopenharmony_ci size_t allocated = 128; 167353a5a1b3Sopenharmony_ci 167453a5a1b3Sopenharmony_ci for (;;) { 167553a5a1b3Sopenharmony_ci t = pa_xmalloc(allocated); 167653a5a1b3Sopenharmony_ci 167753a5a1b3Sopenharmony_ci if (!pa_get_binary_name(t, allocated)) { 167853a5a1b3Sopenharmony_ci pa_xfree(t); 167953a5a1b3Sopenharmony_ci return NULL; 168053a5a1b3Sopenharmony_ci } 168153a5a1b3Sopenharmony_ci 168253a5a1b3Sopenharmony_ci if (strlen(t) < allocated - 1) 168353a5a1b3Sopenharmony_ci break; 168453a5a1b3Sopenharmony_ci 168553a5a1b3Sopenharmony_ci pa_xfree(t); 168653a5a1b3Sopenharmony_ci allocated *= 2; 168753a5a1b3Sopenharmony_ci } 168853a5a1b3Sopenharmony_ci 168953a5a1b3Sopenharmony_ci return t; 169053a5a1b3Sopenharmony_ci} 169153a5a1b3Sopenharmony_ci 169253a5a1b3Sopenharmony_cistatic char* make_random_dir(mode_t m) { 169353a5a1b3Sopenharmony_ci static const char table[] = 169453a5a1b3Sopenharmony_ci "abcdefghijklmnopqrstuvwxyz" 169553a5a1b3Sopenharmony_ci "ABCDEFGHIJKLMNOPQRSTUVWXYZ" 169653a5a1b3Sopenharmony_ci "0123456789"; 169753a5a1b3Sopenharmony_ci 169853a5a1b3Sopenharmony_ci char *fn; 169953a5a1b3Sopenharmony_ci size_t pathlen; 170053a5a1b3Sopenharmony_ci 170153a5a1b3Sopenharmony_ci fn = pa_sprintf_malloc("%s" PA_PATH_SEP "pulse-XXXXXXXXXXXX", pa_get_temp_dir()); 170253a5a1b3Sopenharmony_ci pathlen = strlen(fn); 170353a5a1b3Sopenharmony_ci 170453a5a1b3Sopenharmony_ci for (;;) { 170553a5a1b3Sopenharmony_ci size_t i; 170653a5a1b3Sopenharmony_ci int r; 170753a5a1b3Sopenharmony_ci mode_t u; 170853a5a1b3Sopenharmony_ci int saved_errno; 170953a5a1b3Sopenharmony_ci 171053a5a1b3Sopenharmony_ci for (i = pathlen - 12; i < pathlen; i++) 171153a5a1b3Sopenharmony_ci fn[i] = table[rand() % (sizeof(table)-1)]; 171253a5a1b3Sopenharmony_ci 171353a5a1b3Sopenharmony_ci u = umask((~m) & 0777); 171453a5a1b3Sopenharmony_ci#ifndef OS_IS_WIN32 171553a5a1b3Sopenharmony_ci r = mkdir(fn, m); 171653a5a1b3Sopenharmony_ci#else 171753a5a1b3Sopenharmony_ci r = mkdir(fn); 171853a5a1b3Sopenharmony_ci#endif 171953a5a1b3Sopenharmony_ci 172053a5a1b3Sopenharmony_ci saved_errno = errno; 172153a5a1b3Sopenharmony_ci umask(u); 172253a5a1b3Sopenharmony_ci errno = saved_errno; 172353a5a1b3Sopenharmony_ci 172453a5a1b3Sopenharmony_ci if (r >= 0) 172553a5a1b3Sopenharmony_ci return fn; 172653a5a1b3Sopenharmony_ci 172753a5a1b3Sopenharmony_ci if (errno != EEXIST) { 172853a5a1b3Sopenharmony_ci pa_log_error("Failed to create random directory %s: %s", fn, pa_cstrerror(errno)); 172953a5a1b3Sopenharmony_ci pa_xfree(fn); 173053a5a1b3Sopenharmony_ci return NULL; 173153a5a1b3Sopenharmony_ci } 173253a5a1b3Sopenharmony_ci } 173353a5a1b3Sopenharmony_ci} 173453a5a1b3Sopenharmony_ci 173553a5a1b3Sopenharmony_cistatic int make_random_dir_and_link(mode_t m, const char *k) { 173653a5a1b3Sopenharmony_ci char *p; 173753a5a1b3Sopenharmony_ci 173853a5a1b3Sopenharmony_ci if (!(p = make_random_dir(m))) 173953a5a1b3Sopenharmony_ci return -1; 174053a5a1b3Sopenharmony_ci 174153a5a1b3Sopenharmony_ci#ifdef HAVE_SYMLINK 174253a5a1b3Sopenharmony_ci if (symlink(p, k) < 0) { 174353a5a1b3Sopenharmony_ci int saved_errno = errno; 174453a5a1b3Sopenharmony_ci 174553a5a1b3Sopenharmony_ci if (errno != EEXIST) 174653a5a1b3Sopenharmony_ci pa_log_error("Failed to symlink %s to %s: %s", k, p, pa_cstrerror(errno)); 174753a5a1b3Sopenharmony_ci 174853a5a1b3Sopenharmony_ci rmdir(p); 174953a5a1b3Sopenharmony_ci pa_xfree(p); 175053a5a1b3Sopenharmony_ci 175153a5a1b3Sopenharmony_ci errno = saved_errno; 175253a5a1b3Sopenharmony_ci return -1; 175353a5a1b3Sopenharmony_ci } 175453a5a1b3Sopenharmony_ci#else 175553a5a1b3Sopenharmony_ci pa_xfree(p); 175653a5a1b3Sopenharmony_ci return -1; 175753a5a1b3Sopenharmony_ci#endif 175853a5a1b3Sopenharmony_ci 175953a5a1b3Sopenharmony_ci pa_xfree(p); 176053a5a1b3Sopenharmony_ci return 0; 176153a5a1b3Sopenharmony_ci} 176253a5a1b3Sopenharmony_ci 176353a5a1b3Sopenharmony_cichar *pa_get_runtime_dir(void) { 176453a5a1b3Sopenharmony_ci char *d, *k = NULL, *p = NULL, *t = NULL, *mid; 176553a5a1b3Sopenharmony_ci mode_t m; 176653a5a1b3Sopenharmony_ci 176753a5a1b3Sopenharmony_ci /* The runtime directory shall contain dynamic data that needs NOT 176853a5a1b3Sopenharmony_ci * to be kept across reboots and is usually private to the user, 176953a5a1b3Sopenharmony_ci * except in system mode, where it might be accessible by other 177053a5a1b3Sopenharmony_ci * users, too. Since we need POSIX locking and UNIX sockets in 177153a5a1b3Sopenharmony_ci * this directory, we try XDG_RUNTIME_DIR first, and if that isn't 177253a5a1b3Sopenharmony_ci * set create a directory in $HOME and link it to a random subdir 177353a5a1b3Sopenharmony_ci * in /tmp, if it was not explicitly configured. */ 177453a5a1b3Sopenharmony_ci 177553a5a1b3Sopenharmony_ci m = pa_in_system_mode() ? 0755U : 0755U; 177653a5a1b3Sopenharmony_ci 177753a5a1b3Sopenharmony_ci /* Use the explicitly configured value if it is set */ 177853a5a1b3Sopenharmony_ci d = getenv("PULSE_RUNTIME_PATH"); 177953a5a1b3Sopenharmony_ci if (d) { 178053a5a1b3Sopenharmony_ci 178153a5a1b3Sopenharmony_ci if (pa_make_secure_dir(d, m, (uid_t) -1, (gid_t) -1, true) < 0) { 178253a5a1b3Sopenharmony_ci pa_log_error("Failed to create secure directory (%s): %s", d, pa_cstrerror(errno)); 178353a5a1b3Sopenharmony_ci goto fail; 178453a5a1b3Sopenharmony_ci } 178553a5a1b3Sopenharmony_ci 178653a5a1b3Sopenharmony_ci return pa_xstrdup(d); 178753a5a1b3Sopenharmony_ci } 178853a5a1b3Sopenharmony_ci 178953a5a1b3Sopenharmony_ci /* Use the XDG standard for the runtime directory. */ 179053a5a1b3Sopenharmony_ci d = getenv("XDG_RUNTIME_DIR"); 179153a5a1b3Sopenharmony_ci if (d) { 179253a5a1b3Sopenharmony_ci#ifdef HAVE_GETUID 179353a5a1b3Sopenharmony_ci struct stat st; 179453a5a1b3Sopenharmony_ci if (stat(d, &st) == 0 && st.st_uid != getuid()) { 179553a5a1b3Sopenharmony_ci pa_log(_("XDG_RUNTIME_DIR (%s) is not owned by us (uid %d), but by uid %d! " 179653a5a1b3Sopenharmony_ci "(This could e.g. happen if you try to connect to a non-root PulseAudio as a root user, over the native protocol. Don't do that.)"), 179753a5a1b3Sopenharmony_ci d, getuid(), st.st_uid); 179853a5a1b3Sopenharmony_ci goto fail; 179953a5a1b3Sopenharmony_ci } 180053a5a1b3Sopenharmony_ci#endif 180153a5a1b3Sopenharmony_ci 180253a5a1b3Sopenharmony_ci k = pa_sprintf_malloc("%s" PA_PATH_SEP "pulse", d); 180353a5a1b3Sopenharmony_ci 180453a5a1b3Sopenharmony_ci if (pa_make_secure_dir(k, m, (uid_t) -1, (gid_t) -1, true) < 0) { 180553a5a1b3Sopenharmony_ci pa_log_error("Failed to create secure directory (%s): %s", k, pa_cstrerror(errno)); 180653a5a1b3Sopenharmony_ci goto fail; 180753a5a1b3Sopenharmony_ci } 180853a5a1b3Sopenharmony_ci 180953a5a1b3Sopenharmony_ci return k; 181053a5a1b3Sopenharmony_ci } 181153a5a1b3Sopenharmony_ci 181253a5a1b3Sopenharmony_ci /* XDG_RUNTIME_DIR wasn't set, use the old legacy fallback */ 181353a5a1b3Sopenharmony_ci d = get_pulse_home(); 181453a5a1b3Sopenharmony_ci if (!d) 181553a5a1b3Sopenharmony_ci goto fail; 181653a5a1b3Sopenharmony_ci 181753a5a1b3Sopenharmony_ci if (pa_make_secure_dir(d, m, (uid_t) -1, (gid_t) -1, true) < 0) { 181853a5a1b3Sopenharmony_ci pa_log_error("Failed to create secure directory (%s): %s", d, pa_cstrerror(errno)); 181953a5a1b3Sopenharmony_ci pa_xfree(d); 182053a5a1b3Sopenharmony_ci goto fail; 182153a5a1b3Sopenharmony_ci } 182253a5a1b3Sopenharmony_ci 182353a5a1b3Sopenharmony_ci mid = pa_machine_id(); 182453a5a1b3Sopenharmony_ci if (!mid) { 182553a5a1b3Sopenharmony_ci pa_xfree(d); 182653a5a1b3Sopenharmony_ci goto fail; 182753a5a1b3Sopenharmony_ci } 182853a5a1b3Sopenharmony_ci 182953a5a1b3Sopenharmony_ci k = pa_sprintf_malloc("%s" PA_PATH_SEP "%s-runtime", d, mid); 183053a5a1b3Sopenharmony_ci pa_xfree(d); 183153a5a1b3Sopenharmony_ci pa_xfree(mid); 183253a5a1b3Sopenharmony_ci 183353a5a1b3Sopenharmony_ci for (;;) { 183453a5a1b3Sopenharmony_ci /* OK, first let's check if the "runtime" symlink already exists */ 183553a5a1b3Sopenharmony_ci 183653a5a1b3Sopenharmony_ci p = pa_readlink(k); 183753a5a1b3Sopenharmony_ci if (!p) { 183853a5a1b3Sopenharmony_ci 183953a5a1b3Sopenharmony_ci if (errno != ENOENT) { 184053a5a1b3Sopenharmony_ci pa_log_error("Failed to stat runtime directory %s: %s", k, pa_cstrerror(errno)); 184153a5a1b3Sopenharmony_ci goto fail; 184253a5a1b3Sopenharmony_ci } 184353a5a1b3Sopenharmony_ci 184453a5a1b3Sopenharmony_ci#ifdef HAVE_SYMLINK 184553a5a1b3Sopenharmony_ci /* Hmm, so the runtime directory didn't exist yet, so let's 184653a5a1b3Sopenharmony_ci * create one in /tmp and symlink that to it */ 184753a5a1b3Sopenharmony_ci 184853a5a1b3Sopenharmony_ci if (make_random_dir_and_link(0700, k) < 0) { 184953a5a1b3Sopenharmony_ci 185053a5a1b3Sopenharmony_ci /* Mhmm, maybe another process was quicker than us, 185153a5a1b3Sopenharmony_ci * let's check if that was valid */ 185253a5a1b3Sopenharmony_ci if (errno == EEXIST) 185353a5a1b3Sopenharmony_ci continue; 185453a5a1b3Sopenharmony_ci 185553a5a1b3Sopenharmony_ci goto fail; 185653a5a1b3Sopenharmony_ci } 185753a5a1b3Sopenharmony_ci#else 185853a5a1b3Sopenharmony_ci /* No symlink possible, so let's just create the runtime directly 185953a5a1b3Sopenharmony_ci * Do not check again if it exists since it cannot be a symlink */ 186053a5a1b3Sopenharmony_ci if (mkdir(k) < 0 && errno != EEXIST) 186153a5a1b3Sopenharmony_ci goto fail; 186253a5a1b3Sopenharmony_ci#endif 186353a5a1b3Sopenharmony_ci 186453a5a1b3Sopenharmony_ci return k; 186553a5a1b3Sopenharmony_ci } 186653a5a1b3Sopenharmony_ci 186753a5a1b3Sopenharmony_ci /* Make sure that this actually makes sense */ 186853a5a1b3Sopenharmony_ci if (!pa_is_path_absolute(p)) { 186953a5a1b3Sopenharmony_ci pa_log_error("Path %s in link %s is not absolute.", p, k); 187053a5a1b3Sopenharmony_ci errno = ENOENT; 187153a5a1b3Sopenharmony_ci goto fail; 187253a5a1b3Sopenharmony_ci } 187353a5a1b3Sopenharmony_ci 187453a5a1b3Sopenharmony_ci /* Hmm, so this symlink is still around, make sure nobody fools us */ 187553a5a1b3Sopenharmony_ci#ifdef HAVE_LSTAT 187653a5a1b3Sopenharmony_ci{ 187753a5a1b3Sopenharmony_ci struct stat st; 187853a5a1b3Sopenharmony_ci if (lstat(p, &st) < 0) { 187953a5a1b3Sopenharmony_ci 188053a5a1b3Sopenharmony_ci if (errno != ENOENT) { 188153a5a1b3Sopenharmony_ci pa_log_error("Failed to stat runtime directory %s: %s", p, pa_cstrerror(errno)); 188253a5a1b3Sopenharmony_ci goto fail; 188353a5a1b3Sopenharmony_ci } 188453a5a1b3Sopenharmony_ci 188553a5a1b3Sopenharmony_ci } else { 188653a5a1b3Sopenharmony_ci 188753a5a1b3Sopenharmony_ci if (S_ISDIR(st.st_mode) && 188853a5a1b3Sopenharmony_ci (st.st_uid == getuid()) && 188953a5a1b3Sopenharmony_ci ((st.st_mode & 0777) == 0700)) { 189053a5a1b3Sopenharmony_ci 189153a5a1b3Sopenharmony_ci pa_xfree(p); 189253a5a1b3Sopenharmony_ci return k; 189353a5a1b3Sopenharmony_ci } 189453a5a1b3Sopenharmony_ci 189553a5a1b3Sopenharmony_ci pa_log_info("Hmm, runtime path exists, but points to an invalid directory. Changing runtime directory."); 189653a5a1b3Sopenharmony_ci } 189753a5a1b3Sopenharmony_ci} 189853a5a1b3Sopenharmony_ci#endif 189953a5a1b3Sopenharmony_ci 190053a5a1b3Sopenharmony_ci pa_xfree(p); 190153a5a1b3Sopenharmony_ci p = NULL; 190253a5a1b3Sopenharmony_ci 190353a5a1b3Sopenharmony_ci /* Hmm, so the link points to some nonexisting or invalid 190453a5a1b3Sopenharmony_ci * dir. Let's replace it by a new link. We first create a 190553a5a1b3Sopenharmony_ci * temporary link and then rename that to allow concurrent 190653a5a1b3Sopenharmony_ci * execution of this function. */ 190753a5a1b3Sopenharmony_ci 190853a5a1b3Sopenharmony_ci t = pa_sprintf_malloc("%s.tmp", k); 190953a5a1b3Sopenharmony_ci 191053a5a1b3Sopenharmony_ci if (make_random_dir_and_link(0700, t) < 0) { 191153a5a1b3Sopenharmony_ci 191253a5a1b3Sopenharmony_ci if (errno != EEXIST) { 191353a5a1b3Sopenharmony_ci pa_log_error("Failed to symlink %s: %s", t, pa_cstrerror(errno)); 191453a5a1b3Sopenharmony_ci goto fail; 191553a5a1b3Sopenharmony_ci } 191653a5a1b3Sopenharmony_ci 191753a5a1b3Sopenharmony_ci pa_xfree(t); 191853a5a1b3Sopenharmony_ci t = NULL; 191953a5a1b3Sopenharmony_ci 192053a5a1b3Sopenharmony_ci /* Hmm, someone else was quicker then us. Let's give 192153a5a1b3Sopenharmony_ci * him some time to finish, and retry. */ 192253a5a1b3Sopenharmony_ci pa_msleep(10); 192353a5a1b3Sopenharmony_ci continue; 192453a5a1b3Sopenharmony_ci } 192553a5a1b3Sopenharmony_ci 192653a5a1b3Sopenharmony_ci /* OK, we succeeded in creating the temporary symlink, so 192753a5a1b3Sopenharmony_ci * let's rename it */ 192853a5a1b3Sopenharmony_ci if (rename(t, k) < 0) { 192953a5a1b3Sopenharmony_ci pa_log_error("Failed to rename %s to %s: %s", t, k, pa_cstrerror(errno)); 193053a5a1b3Sopenharmony_ci goto fail; 193153a5a1b3Sopenharmony_ci } 193253a5a1b3Sopenharmony_ci 193353a5a1b3Sopenharmony_ci pa_xfree(t); 193453a5a1b3Sopenharmony_ci return k; 193553a5a1b3Sopenharmony_ci } 193653a5a1b3Sopenharmony_ci 193753a5a1b3Sopenharmony_cifail: 193853a5a1b3Sopenharmony_ci pa_xfree(p); 193953a5a1b3Sopenharmony_ci pa_xfree(k); 194053a5a1b3Sopenharmony_ci pa_xfree(t); 194153a5a1b3Sopenharmony_ci 194253a5a1b3Sopenharmony_ci return NULL; 194353a5a1b3Sopenharmony_ci} 194453a5a1b3Sopenharmony_ci 194553a5a1b3Sopenharmony_ci/* Try to open a configuration file. If "env" is specified, open the 194653a5a1b3Sopenharmony_ci * value of the specified environment variable. Otherwise look for a 194753a5a1b3Sopenharmony_ci * file "local" in the home directory or a file "global" in global 194853a5a1b3Sopenharmony_ci * file system. If "result" is non-NULL, a pointer to a newly 194953a5a1b3Sopenharmony_ci * allocated buffer containing the used configuration file is 195053a5a1b3Sopenharmony_ci * stored there.*/ 195153a5a1b3Sopenharmony_ciFILE *pa_open_config_file(const char *global, const char *local, const char *env, char **result) { 195253a5a1b3Sopenharmony_ci const char *fn; 195353a5a1b3Sopenharmony_ci FILE *f; 195453a5a1b3Sopenharmony_ci 195553a5a1b3Sopenharmony_ci if (env && (fn = getenv(env))) { 195653a5a1b3Sopenharmony_ci if ((f = pa_fopen_cloexec(fn, "r"))) { 195753a5a1b3Sopenharmony_ci if (result) 195853a5a1b3Sopenharmony_ci *result = pa_xstrdup(fn); 195953a5a1b3Sopenharmony_ci 196053a5a1b3Sopenharmony_ci return f; 196153a5a1b3Sopenharmony_ci } 196253a5a1b3Sopenharmony_ci 196353a5a1b3Sopenharmony_ci pa_log_warn("Failed to open configuration file '%s': %s", fn, pa_cstrerror(errno)); 196453a5a1b3Sopenharmony_ci return NULL; 196553a5a1b3Sopenharmony_ci } 196653a5a1b3Sopenharmony_ci 196753a5a1b3Sopenharmony_ci if (local) { 196853a5a1b3Sopenharmony_ci const char *e; 196953a5a1b3Sopenharmony_ci char *lfn; 197053a5a1b3Sopenharmony_ci char *h; 197153a5a1b3Sopenharmony_ci 197253a5a1b3Sopenharmony_ci if ((e = getenv("PULSE_CONFIG_PATH"))) { 197353a5a1b3Sopenharmony_ci fn = lfn = pa_sprintf_malloc("%s" PA_PATH_SEP "%s", e, local); 197453a5a1b3Sopenharmony_ci f = pa_fopen_cloexec(fn, "r"); 197553a5a1b3Sopenharmony_ci } else if ((h = pa_get_home_dir_malloc())) { 197653a5a1b3Sopenharmony_ci fn = lfn = pa_sprintf_malloc("%s" PA_PATH_SEP ".pulse" PA_PATH_SEP "%s", h, local); 197753a5a1b3Sopenharmony_ci f = pa_fopen_cloexec(fn, "r"); 197853a5a1b3Sopenharmony_ci if (!f) { 197953a5a1b3Sopenharmony_ci free(lfn); 198053a5a1b3Sopenharmony_ci fn = lfn = pa_sprintf_malloc("%s" PA_PATH_SEP ".config/pulse" PA_PATH_SEP "%s", h, local); 198153a5a1b3Sopenharmony_ci f = pa_fopen_cloexec(fn, "r"); 198253a5a1b3Sopenharmony_ci } 198353a5a1b3Sopenharmony_ci pa_xfree(h); 198453a5a1b3Sopenharmony_ci } else 198553a5a1b3Sopenharmony_ci return NULL; 198653a5a1b3Sopenharmony_ci 198753a5a1b3Sopenharmony_ci if (f) { 198853a5a1b3Sopenharmony_ci if (result) 198953a5a1b3Sopenharmony_ci *result = pa_xstrdup(fn); 199053a5a1b3Sopenharmony_ci 199153a5a1b3Sopenharmony_ci pa_xfree(lfn); 199253a5a1b3Sopenharmony_ci return f; 199353a5a1b3Sopenharmony_ci } 199453a5a1b3Sopenharmony_ci 199553a5a1b3Sopenharmony_ci if (errno != ENOENT) { 199653a5a1b3Sopenharmony_ci pa_log_warn("Failed to open configuration file '%s': %s", fn, pa_cstrerror(errno)); 199753a5a1b3Sopenharmony_ci pa_xfree(lfn); 199853a5a1b3Sopenharmony_ci return NULL; 199953a5a1b3Sopenharmony_ci } 200053a5a1b3Sopenharmony_ci 200153a5a1b3Sopenharmony_ci pa_xfree(lfn); 200253a5a1b3Sopenharmony_ci } 200353a5a1b3Sopenharmony_ci 200453a5a1b3Sopenharmony_ci if (global) { 200553a5a1b3Sopenharmony_ci char *gfn; 200653a5a1b3Sopenharmony_ci 200753a5a1b3Sopenharmony_ci#ifdef OS_IS_WIN32 200853a5a1b3Sopenharmony_ci if (strncmp(global, PA_DEFAULT_CONFIG_DIR, strlen(PA_DEFAULT_CONFIG_DIR)) == 0) 200953a5a1b3Sopenharmony_ci gfn = pa_sprintf_malloc("%s" PA_PATH_SEP "etc" PA_PATH_SEP "pulse%s", 201053a5a1b3Sopenharmony_ci pa_win32_get_toplevel(NULL), 201153a5a1b3Sopenharmony_ci global + strlen(PA_DEFAULT_CONFIG_DIR)); 201253a5a1b3Sopenharmony_ci else 201353a5a1b3Sopenharmony_ci#endif 201453a5a1b3Sopenharmony_ci gfn = pa_xstrdup(global); 201553a5a1b3Sopenharmony_ci 201653a5a1b3Sopenharmony_ci if ((f = pa_fopen_cloexec(gfn, "r"))) { 201753a5a1b3Sopenharmony_ci if (result) 201853a5a1b3Sopenharmony_ci *result = gfn; 201953a5a1b3Sopenharmony_ci else 202053a5a1b3Sopenharmony_ci pa_xfree(gfn); 202153a5a1b3Sopenharmony_ci 202253a5a1b3Sopenharmony_ci return f; 202353a5a1b3Sopenharmony_ci } 202453a5a1b3Sopenharmony_ci pa_xfree(gfn); 202553a5a1b3Sopenharmony_ci } 202653a5a1b3Sopenharmony_ci 202753a5a1b3Sopenharmony_ci errno = ENOENT; 202853a5a1b3Sopenharmony_ci return NULL; 202953a5a1b3Sopenharmony_ci} 203053a5a1b3Sopenharmony_ci 203153a5a1b3Sopenharmony_cichar *pa_find_config_file(const char *global, const char *local, const char *env) { 203253a5a1b3Sopenharmony_ci const char *fn; 203353a5a1b3Sopenharmony_ci 203453a5a1b3Sopenharmony_ci if (env && (fn = getenv(env))) { 203553a5a1b3Sopenharmony_ci if (access(fn, R_OK) == 0) 203653a5a1b3Sopenharmony_ci return pa_xstrdup(fn); 203753a5a1b3Sopenharmony_ci 203853a5a1b3Sopenharmony_ci pa_log_warn("Failed to access configuration file '%s': %s", fn, pa_cstrerror(errno)); 203953a5a1b3Sopenharmony_ci return NULL; 204053a5a1b3Sopenharmony_ci } 204153a5a1b3Sopenharmony_ci 204253a5a1b3Sopenharmony_ci if (local) { 204353a5a1b3Sopenharmony_ci const char *e; 204453a5a1b3Sopenharmony_ci char *lfn; 204553a5a1b3Sopenharmony_ci char *h; 204653a5a1b3Sopenharmony_ci 204753a5a1b3Sopenharmony_ci if ((e = getenv("PULSE_CONFIG_PATH"))) 204853a5a1b3Sopenharmony_ci fn = lfn = pa_sprintf_malloc("%s" PA_PATH_SEP "%s", e, local); 204953a5a1b3Sopenharmony_ci else if ((h = pa_get_home_dir_malloc())) { 205053a5a1b3Sopenharmony_ci fn = lfn = pa_sprintf_malloc("%s" PA_PATH_SEP ".pulse" PA_PATH_SEP "%s", h, local); 205153a5a1b3Sopenharmony_ci pa_xfree(h); 205253a5a1b3Sopenharmony_ci } else 205353a5a1b3Sopenharmony_ci return NULL; 205453a5a1b3Sopenharmony_ci 205553a5a1b3Sopenharmony_ci if (access(fn, R_OK) == 0) { 205653a5a1b3Sopenharmony_ci char *r = pa_xstrdup(fn); 205753a5a1b3Sopenharmony_ci pa_xfree(lfn); 205853a5a1b3Sopenharmony_ci return r; 205953a5a1b3Sopenharmony_ci } 206053a5a1b3Sopenharmony_ci 206153a5a1b3Sopenharmony_ci if (errno != ENOENT) { 206253a5a1b3Sopenharmony_ci pa_log_warn("Failed to access configuration file '%s': %s", fn, pa_cstrerror(errno)); 206353a5a1b3Sopenharmony_ci pa_xfree(lfn); 206453a5a1b3Sopenharmony_ci return NULL; 206553a5a1b3Sopenharmony_ci } 206653a5a1b3Sopenharmony_ci 206753a5a1b3Sopenharmony_ci pa_xfree(lfn); 206853a5a1b3Sopenharmony_ci } 206953a5a1b3Sopenharmony_ci 207053a5a1b3Sopenharmony_ci if (global) { 207153a5a1b3Sopenharmony_ci char *gfn; 207253a5a1b3Sopenharmony_ci 207353a5a1b3Sopenharmony_ci#ifdef OS_IS_WIN32 207453a5a1b3Sopenharmony_ci if (strncmp(global, PA_DEFAULT_CONFIG_DIR, strlen(PA_DEFAULT_CONFIG_DIR)) == 0) 207553a5a1b3Sopenharmony_ci gfn = pa_sprintf_malloc("%s" PA_PATH_SEP "etc" PA_PATH_SEP "pulse%s", 207653a5a1b3Sopenharmony_ci pa_win32_get_toplevel(NULL), 207753a5a1b3Sopenharmony_ci global + strlen(PA_DEFAULT_CONFIG_DIR)); 207853a5a1b3Sopenharmony_ci else 207953a5a1b3Sopenharmony_ci#endif 208053a5a1b3Sopenharmony_ci gfn = pa_xstrdup(global); 208153a5a1b3Sopenharmony_ci 208253a5a1b3Sopenharmony_ci if (access(gfn, R_OK) == 0) 208353a5a1b3Sopenharmony_ci return gfn; 208453a5a1b3Sopenharmony_ci pa_xfree(gfn); 208553a5a1b3Sopenharmony_ci } 208653a5a1b3Sopenharmony_ci 208753a5a1b3Sopenharmony_ci errno = ENOENT; 208853a5a1b3Sopenharmony_ci 208953a5a1b3Sopenharmony_ci return NULL; 209053a5a1b3Sopenharmony_ci} 209153a5a1b3Sopenharmony_ci 209253a5a1b3Sopenharmony_ci/* Format the specified data as a hexademical string */ 209353a5a1b3Sopenharmony_cichar *pa_hexstr(const uint8_t* d, size_t dlength, char *s, size_t slength) { 209453a5a1b3Sopenharmony_ci size_t i = 0, j = 0; 209553a5a1b3Sopenharmony_ci const char hex[] = "0123456789abcdef"; 209653a5a1b3Sopenharmony_ci 209753a5a1b3Sopenharmony_ci pa_assert(d); 209853a5a1b3Sopenharmony_ci pa_assert(s); 209953a5a1b3Sopenharmony_ci pa_assert(slength > 0); 210053a5a1b3Sopenharmony_ci 210153a5a1b3Sopenharmony_ci while (j+2 < slength && i < dlength) { 210253a5a1b3Sopenharmony_ci s[j++] = hex[*d >> 4]; 210353a5a1b3Sopenharmony_ci s[j++] = hex[*d & 0xF]; 210453a5a1b3Sopenharmony_ci 210553a5a1b3Sopenharmony_ci d++; 210653a5a1b3Sopenharmony_ci i++; 210753a5a1b3Sopenharmony_ci } 210853a5a1b3Sopenharmony_ci 210953a5a1b3Sopenharmony_ci s[j < slength ? j : slength] = 0; 211053a5a1b3Sopenharmony_ci return s; 211153a5a1b3Sopenharmony_ci} 211253a5a1b3Sopenharmony_ci 211353a5a1b3Sopenharmony_ci/* Convert a hexadecimal digit to a number or -1 if invalid */ 211453a5a1b3Sopenharmony_cistatic int hexc(char c) { 211553a5a1b3Sopenharmony_ci if (c >= '0' && c <= '9') 211653a5a1b3Sopenharmony_ci return c - '0'; 211753a5a1b3Sopenharmony_ci 211853a5a1b3Sopenharmony_ci if (c >= 'A' && c <= 'F') 211953a5a1b3Sopenharmony_ci return c - 'A' + 10; 212053a5a1b3Sopenharmony_ci 212153a5a1b3Sopenharmony_ci if (c >= 'a' && c <= 'f') 212253a5a1b3Sopenharmony_ci return c - 'a' + 10; 212353a5a1b3Sopenharmony_ci 212453a5a1b3Sopenharmony_ci errno = EINVAL; 212553a5a1b3Sopenharmony_ci return -1; 212653a5a1b3Sopenharmony_ci} 212753a5a1b3Sopenharmony_ci 212853a5a1b3Sopenharmony_ci/* Parse a hexadecimal string as created by pa_hexstr() to a BLOB */ 212953a5a1b3Sopenharmony_cisize_t pa_parsehex(const char *p, uint8_t *d, size_t dlength) { 213053a5a1b3Sopenharmony_ci size_t j = 0; 213153a5a1b3Sopenharmony_ci 213253a5a1b3Sopenharmony_ci pa_assert(p); 213353a5a1b3Sopenharmony_ci pa_assert(d); 213453a5a1b3Sopenharmony_ci 213553a5a1b3Sopenharmony_ci while (j < dlength && *p) { 213653a5a1b3Sopenharmony_ci int b; 213753a5a1b3Sopenharmony_ci 213853a5a1b3Sopenharmony_ci if ((b = hexc(*(p++))) < 0) 213953a5a1b3Sopenharmony_ci return (size_t) -1; 214053a5a1b3Sopenharmony_ci 214153a5a1b3Sopenharmony_ci d[j] = (uint8_t) (b << 4); 214253a5a1b3Sopenharmony_ci 214353a5a1b3Sopenharmony_ci if (!*p) 214453a5a1b3Sopenharmony_ci return (size_t) -1; 214553a5a1b3Sopenharmony_ci 214653a5a1b3Sopenharmony_ci if ((b = hexc(*(p++))) < 0) 214753a5a1b3Sopenharmony_ci return (size_t) -1; 214853a5a1b3Sopenharmony_ci 214953a5a1b3Sopenharmony_ci d[j] |= (uint8_t) b; 215053a5a1b3Sopenharmony_ci j++; 215153a5a1b3Sopenharmony_ci } 215253a5a1b3Sopenharmony_ci 215353a5a1b3Sopenharmony_ci return j; 215453a5a1b3Sopenharmony_ci} 215553a5a1b3Sopenharmony_ci 215653a5a1b3Sopenharmony_ci/* Returns nonzero when *s starts with *pfx */ 215753a5a1b3Sopenharmony_cibool pa_startswith(const char *s, const char *pfx) { 215853a5a1b3Sopenharmony_ci size_t l; 215953a5a1b3Sopenharmony_ci 216053a5a1b3Sopenharmony_ci pa_assert(s); 216153a5a1b3Sopenharmony_ci pa_assert(pfx); 216253a5a1b3Sopenharmony_ci 216353a5a1b3Sopenharmony_ci l = strlen(pfx); 216453a5a1b3Sopenharmony_ci 216553a5a1b3Sopenharmony_ci return strlen(s) >= l && strncmp(s, pfx, l) == 0; 216653a5a1b3Sopenharmony_ci} 216753a5a1b3Sopenharmony_ci 216853a5a1b3Sopenharmony_ci/* Returns nonzero when *s ends with *sfx */ 216953a5a1b3Sopenharmony_cibool pa_endswith(const char *s, const char *sfx) { 217053a5a1b3Sopenharmony_ci size_t l1, l2; 217153a5a1b3Sopenharmony_ci 217253a5a1b3Sopenharmony_ci pa_assert(s); 217353a5a1b3Sopenharmony_ci pa_assert(sfx); 217453a5a1b3Sopenharmony_ci 217553a5a1b3Sopenharmony_ci l1 = strlen(s); 217653a5a1b3Sopenharmony_ci l2 = strlen(sfx); 217753a5a1b3Sopenharmony_ci 217853a5a1b3Sopenharmony_ci return l1 >= l2 && pa_streq(s + l1 - l2, sfx); 217953a5a1b3Sopenharmony_ci} 218053a5a1b3Sopenharmony_ci 218153a5a1b3Sopenharmony_cibool pa_is_path_absolute(const char *fn) { 218253a5a1b3Sopenharmony_ci pa_assert(fn); 218353a5a1b3Sopenharmony_ci 218453a5a1b3Sopenharmony_ci#ifndef OS_IS_WIN32 218553a5a1b3Sopenharmony_ci return *fn == '/'; 218653a5a1b3Sopenharmony_ci#else 218753a5a1b3Sopenharmony_ci return strlen(fn) >= 3 && isalpha(fn[0]) && fn[1] == ':' && fn[2] == '\\'; 218853a5a1b3Sopenharmony_ci#endif 218953a5a1b3Sopenharmony_ci} 219053a5a1b3Sopenharmony_ci 219153a5a1b3Sopenharmony_cichar *pa_make_path_absolute(const char *p) { 219253a5a1b3Sopenharmony_ci char *r; 219353a5a1b3Sopenharmony_ci char *cwd; 219453a5a1b3Sopenharmony_ci 219553a5a1b3Sopenharmony_ci pa_assert(p); 219653a5a1b3Sopenharmony_ci 219753a5a1b3Sopenharmony_ci if (pa_is_path_absolute(p)) 219853a5a1b3Sopenharmony_ci return pa_xstrdup(p); 219953a5a1b3Sopenharmony_ci 220053a5a1b3Sopenharmony_ci if (!(cwd = pa_getcwd())) 220153a5a1b3Sopenharmony_ci return pa_xstrdup(p); 220253a5a1b3Sopenharmony_ci 220353a5a1b3Sopenharmony_ci r = pa_sprintf_malloc("%s" PA_PATH_SEP "%s", cwd, p); 220453a5a1b3Sopenharmony_ci pa_xfree(cwd); 220553a5a1b3Sopenharmony_ci return r; 220653a5a1b3Sopenharmony_ci} 220753a5a1b3Sopenharmony_ci 220853a5a1b3Sopenharmony_ci/* If fn is NULL, return the PulseAudio runtime or state dir (depending on the 220953a5a1b3Sopenharmony_ci * rt parameter). If fn is non-NULL and starts with /, return fn. Otherwise, 221053a5a1b3Sopenharmony_ci * append fn to the runtime/state dir and return it. */ 221153a5a1b3Sopenharmony_cistatic char *get_path(const char *fn, bool prependmid, bool rt) { 221253a5a1b3Sopenharmony_ci char *rtp; 221353a5a1b3Sopenharmony_ci 221453a5a1b3Sopenharmony_ci rtp = rt ? pa_get_runtime_dir() : pa_get_state_dir(); 221553a5a1b3Sopenharmony_ci 221653a5a1b3Sopenharmony_ci if (fn) { 221753a5a1b3Sopenharmony_ci char *r, *canonical_rtp; 221853a5a1b3Sopenharmony_ci 221953a5a1b3Sopenharmony_ci if (pa_is_path_absolute(fn)) { 222053a5a1b3Sopenharmony_ci pa_xfree(rtp); 222153a5a1b3Sopenharmony_ci return pa_xstrdup(fn); 222253a5a1b3Sopenharmony_ci } 222353a5a1b3Sopenharmony_ci 222453a5a1b3Sopenharmony_ci if (!rtp) 222553a5a1b3Sopenharmony_ci return NULL; 222653a5a1b3Sopenharmony_ci 222753a5a1b3Sopenharmony_ci /* Hopefully make the path smaller to avoid 108 char limit (fdo#44680) */ 222853a5a1b3Sopenharmony_ci if ((canonical_rtp = pa_realpath(rtp))) { 222953a5a1b3Sopenharmony_ci if (strlen(rtp) >= strlen(canonical_rtp)) 223053a5a1b3Sopenharmony_ci pa_xfree(rtp); 223153a5a1b3Sopenharmony_ci else { 223253a5a1b3Sopenharmony_ci pa_xfree(canonical_rtp); 223353a5a1b3Sopenharmony_ci canonical_rtp = rtp; 223453a5a1b3Sopenharmony_ci } 223553a5a1b3Sopenharmony_ci } else 223653a5a1b3Sopenharmony_ci canonical_rtp = rtp; 223753a5a1b3Sopenharmony_ci 223853a5a1b3Sopenharmony_ci if (prependmid) { 223953a5a1b3Sopenharmony_ci char *mid; 224053a5a1b3Sopenharmony_ci 224153a5a1b3Sopenharmony_ci if (!(mid = pa_machine_id())) { 224253a5a1b3Sopenharmony_ci pa_xfree(canonical_rtp); 224353a5a1b3Sopenharmony_ci return NULL; 224453a5a1b3Sopenharmony_ci } 224553a5a1b3Sopenharmony_ci 224653a5a1b3Sopenharmony_ci r = pa_sprintf_malloc("%s" PA_PATH_SEP "%s-%s", canonical_rtp, mid, fn); 224753a5a1b3Sopenharmony_ci pa_xfree(mid); 224853a5a1b3Sopenharmony_ci } else 224953a5a1b3Sopenharmony_ci r = pa_sprintf_malloc("%s" PA_PATH_SEP "%s", canonical_rtp, fn); 225053a5a1b3Sopenharmony_ci 225153a5a1b3Sopenharmony_ci pa_xfree(canonical_rtp); 225253a5a1b3Sopenharmony_ci return r; 225353a5a1b3Sopenharmony_ci } else 225453a5a1b3Sopenharmony_ci return rtp; 225553a5a1b3Sopenharmony_ci} 225653a5a1b3Sopenharmony_ci 225753a5a1b3Sopenharmony_cichar *pa_runtime_path(const char *fn) { 225853a5a1b3Sopenharmony_ci return get_path(fn, false, true); 225953a5a1b3Sopenharmony_ci} 226053a5a1b3Sopenharmony_ci 226153a5a1b3Sopenharmony_cichar *pa_state_path(const char *fn, bool appendmid) { 226253a5a1b3Sopenharmony_ci return get_path(fn, appendmid, false); 226353a5a1b3Sopenharmony_ci} 226453a5a1b3Sopenharmony_ci 226553a5a1b3Sopenharmony_ci/* Convert the string s to a signed integer in *ret_i */ 226653a5a1b3Sopenharmony_ciint pa_atoi(const char *s, int32_t *ret_i) { 226753a5a1b3Sopenharmony_ci long l; 226853a5a1b3Sopenharmony_ci 226953a5a1b3Sopenharmony_ci pa_assert(s); 227053a5a1b3Sopenharmony_ci pa_assert(ret_i); 227153a5a1b3Sopenharmony_ci 227253a5a1b3Sopenharmony_ci if (pa_atol(s, &l) < 0) 227353a5a1b3Sopenharmony_ci return -1; 227453a5a1b3Sopenharmony_ci 227553a5a1b3Sopenharmony_ci if (l < INT32_MIN || l > INT32_MAX) { 227653a5a1b3Sopenharmony_ci errno = ERANGE; 227753a5a1b3Sopenharmony_ci return -1; 227853a5a1b3Sopenharmony_ci } 227953a5a1b3Sopenharmony_ci 228053a5a1b3Sopenharmony_ci *ret_i = (int32_t) l; 228153a5a1b3Sopenharmony_ci 228253a5a1b3Sopenharmony_ci return 0; 228353a5a1b3Sopenharmony_ci} 228453a5a1b3Sopenharmony_ci 228553a5a1b3Sopenharmony_cienum numtype { 228653a5a1b3Sopenharmony_ci NUMTYPE_UINT, 228753a5a1b3Sopenharmony_ci NUMTYPE_INT, 228853a5a1b3Sopenharmony_ci NUMTYPE_DOUBLE, 228953a5a1b3Sopenharmony_ci}; 229053a5a1b3Sopenharmony_ci 229153a5a1b3Sopenharmony_ci/* A helper function for pa_atou() and friends. This does some common checks, 229253a5a1b3Sopenharmony_ci * because our number parsing is more strict than the strtoX functions. 229353a5a1b3Sopenharmony_ci * 229453a5a1b3Sopenharmony_ci * Leading zeros are stripped from integers so that they don't get parsed as 229553a5a1b3Sopenharmony_ci * octal (but "0x" is preserved for hexadecimal numbers). For NUMTYPE_INT the 229653a5a1b3Sopenharmony_ci * zero stripping may involve allocating a new string, in which case it's 229753a5a1b3Sopenharmony_ci * stored in tmp. Otherwise tmp is set to NULL. The caller needs to free tmp 229853a5a1b3Sopenharmony_ci * after they're done with ret. When parsing other types than NUMTYPE_INT the 229953a5a1b3Sopenharmony_ci * caller can pass NULL as tmp. 230053a5a1b3Sopenharmony_ci * 230153a5a1b3Sopenharmony_ci * The final string to parse is returned in ret. ret will point either inside 230253a5a1b3Sopenharmony_ci * s or to tmp. */ 230353a5a1b3Sopenharmony_cistatic int prepare_number_string(const char *s, enum numtype type, char **tmp, const char **ret) { 230453a5a1b3Sopenharmony_ci const char *original = s; 230553a5a1b3Sopenharmony_ci bool negative = false; 230653a5a1b3Sopenharmony_ci 230753a5a1b3Sopenharmony_ci pa_assert(s); 230853a5a1b3Sopenharmony_ci pa_assert(type != NUMTYPE_INT || tmp); 230953a5a1b3Sopenharmony_ci pa_assert(ret); 231053a5a1b3Sopenharmony_ci 231153a5a1b3Sopenharmony_ci if (tmp) 231253a5a1b3Sopenharmony_ci *tmp = NULL; 231353a5a1b3Sopenharmony_ci 231453a5a1b3Sopenharmony_ci /* The strtoX functions accept leading spaces, we don't. */ 231553a5a1b3Sopenharmony_ci if (isspace((unsigned char) s[0])) 231653a5a1b3Sopenharmony_ci return -1; 231753a5a1b3Sopenharmony_ci 231853a5a1b3Sopenharmony_ci /* The strtoX functions accept a plus sign, we don't. */ 231953a5a1b3Sopenharmony_ci if (s[0] == '+') 232053a5a1b3Sopenharmony_ci return -1; 232153a5a1b3Sopenharmony_ci 232253a5a1b3Sopenharmony_ci /* The strtoul and strtoull functions allow a minus sign even though they 232353a5a1b3Sopenharmony_ci * parse an unsigned number. In case of a minus sign the original negative 232453a5a1b3Sopenharmony_ci * number gets negated. We don't want that kind of behviour. */ 232553a5a1b3Sopenharmony_ci if (type == NUMTYPE_UINT && s[0] == '-') 232653a5a1b3Sopenharmony_ci return -1; 232753a5a1b3Sopenharmony_ci 232853a5a1b3Sopenharmony_ci /* The strtoX functions interpret the number as octal if it starts with 232953a5a1b3Sopenharmony_ci * a zero. We prefer to use base 10, so we strip all leading zeros (if the 233053a5a1b3Sopenharmony_ci * string starts with "0x", strtoul() interprets it as hexadecimal, which 233153a5a1b3Sopenharmony_ci * is fine, because it's unambiguous unlike octal). 233253a5a1b3Sopenharmony_ci * 233353a5a1b3Sopenharmony_ci * While stripping the leading zeros, we have to remember to also handle 233453a5a1b3Sopenharmony_ci * the case where the number is negative, which makes the zero skipping 233553a5a1b3Sopenharmony_ci * code somewhat complex. */ 233653a5a1b3Sopenharmony_ci 233753a5a1b3Sopenharmony_ci /* Doubles don't need zero stripping, we can finish now. */ 233853a5a1b3Sopenharmony_ci if (type == NUMTYPE_DOUBLE) 233953a5a1b3Sopenharmony_ci goto finish; 234053a5a1b3Sopenharmony_ci 234153a5a1b3Sopenharmony_ci if (s[0] == '-') { 234253a5a1b3Sopenharmony_ci negative = true; 234353a5a1b3Sopenharmony_ci s++; /* Skip the minus sign. */ 234453a5a1b3Sopenharmony_ci } 234553a5a1b3Sopenharmony_ci 234653a5a1b3Sopenharmony_ci /* Don't skip zeros if the string starts with "0x". */ 234753a5a1b3Sopenharmony_ci if (s[0] == '0' && s[1] != 'x') { 234853a5a1b3Sopenharmony_ci while (s[0] == '0' && s[1]) 234953a5a1b3Sopenharmony_ci s++; /* Skip zeros. */ 235053a5a1b3Sopenharmony_ci } 235153a5a1b3Sopenharmony_ci 235253a5a1b3Sopenharmony_ci if (negative) { 235353a5a1b3Sopenharmony_ci s--; /* Go back one step, we need the minus sign back. */ 235453a5a1b3Sopenharmony_ci 235553a5a1b3Sopenharmony_ci /* If s != original, then we have skipped some zeros and we need to replace 235653a5a1b3Sopenharmony_ci * the last skipped zero with a minus sign. */ 235753a5a1b3Sopenharmony_ci if (s != original) { 235853a5a1b3Sopenharmony_ci *tmp = pa_xstrdup(s); 235953a5a1b3Sopenharmony_ci *tmp[0] = '-'; 236053a5a1b3Sopenharmony_ci s = *tmp; 236153a5a1b3Sopenharmony_ci } 236253a5a1b3Sopenharmony_ci } 236353a5a1b3Sopenharmony_ci 236453a5a1b3Sopenharmony_cifinish: 236553a5a1b3Sopenharmony_ci *ret = s; 236653a5a1b3Sopenharmony_ci return 0; 236753a5a1b3Sopenharmony_ci} 236853a5a1b3Sopenharmony_ci 236953a5a1b3Sopenharmony_ci/* Convert the string s to an unsigned integer in *ret_u */ 237053a5a1b3Sopenharmony_ciint pa_atou(const char *s, uint32_t *ret_u) { 237153a5a1b3Sopenharmony_ci char *x = NULL; 237253a5a1b3Sopenharmony_ci unsigned long l; 237353a5a1b3Sopenharmony_ci 237453a5a1b3Sopenharmony_ci pa_assert(s); 237553a5a1b3Sopenharmony_ci pa_assert(ret_u); 237653a5a1b3Sopenharmony_ci 237753a5a1b3Sopenharmony_ci if (prepare_number_string(s, NUMTYPE_UINT, NULL, &s) < 0) { 237853a5a1b3Sopenharmony_ci errno = EINVAL; 237953a5a1b3Sopenharmony_ci return -1; 238053a5a1b3Sopenharmony_ci } 238153a5a1b3Sopenharmony_ci 238253a5a1b3Sopenharmony_ci errno = 0; 238353a5a1b3Sopenharmony_ci l = strtoul(s, &x, 0); 238453a5a1b3Sopenharmony_ci 238553a5a1b3Sopenharmony_ci /* If x doesn't point to the end of s, there was some trailing garbage in 238653a5a1b3Sopenharmony_ci * the string. If x points to s, no conversion was done (empty string). */ 238753a5a1b3Sopenharmony_ci if (!x || *x || x == s || errno) { 238853a5a1b3Sopenharmony_ci if (!errno) 238953a5a1b3Sopenharmony_ci errno = EINVAL; 239053a5a1b3Sopenharmony_ci return -1; 239153a5a1b3Sopenharmony_ci } 239253a5a1b3Sopenharmony_ci 239353a5a1b3Sopenharmony_ci if (l > UINT32_MAX) { 239453a5a1b3Sopenharmony_ci errno = ERANGE; 239553a5a1b3Sopenharmony_ci return -1; 239653a5a1b3Sopenharmony_ci } 239753a5a1b3Sopenharmony_ci 239853a5a1b3Sopenharmony_ci *ret_u = (uint32_t) l; 239953a5a1b3Sopenharmony_ci 240053a5a1b3Sopenharmony_ci return 0; 240153a5a1b3Sopenharmony_ci} 240253a5a1b3Sopenharmony_ci 240353a5a1b3Sopenharmony_ci/* Convert the string s to an unsigned 64 bit integer in *ret_u */ 240453a5a1b3Sopenharmony_ciint pa_atou64(const char *s, uint64_t *ret_u) { 240553a5a1b3Sopenharmony_ci char *x = NULL; 240653a5a1b3Sopenharmony_ci unsigned long long l; 240753a5a1b3Sopenharmony_ci 240853a5a1b3Sopenharmony_ci pa_assert(s); 240953a5a1b3Sopenharmony_ci pa_assert(ret_u); 241053a5a1b3Sopenharmony_ci 241153a5a1b3Sopenharmony_ci if (prepare_number_string(s, NUMTYPE_UINT, NULL, &s) < 0) { 241253a5a1b3Sopenharmony_ci errno = EINVAL; 241353a5a1b3Sopenharmony_ci return -1; 241453a5a1b3Sopenharmony_ci } 241553a5a1b3Sopenharmony_ci 241653a5a1b3Sopenharmony_ci errno = 0; 241753a5a1b3Sopenharmony_ci l = strtoull(s, &x, 0); 241853a5a1b3Sopenharmony_ci 241953a5a1b3Sopenharmony_ci /* If x doesn't point to the end of s, there was some trailing garbage in 242053a5a1b3Sopenharmony_ci * the string. If x points to s, no conversion was done (empty string). */ 242153a5a1b3Sopenharmony_ci if (!x || *x || x == s || errno) { 242253a5a1b3Sopenharmony_ci if (!errno) 242353a5a1b3Sopenharmony_ci errno = EINVAL; 242453a5a1b3Sopenharmony_ci return -1; 242553a5a1b3Sopenharmony_ci } 242653a5a1b3Sopenharmony_ci 242753a5a1b3Sopenharmony_ci if (l > UINT64_MAX) { 242853a5a1b3Sopenharmony_ci errno = ERANGE; 242953a5a1b3Sopenharmony_ci return -1; 243053a5a1b3Sopenharmony_ci } 243153a5a1b3Sopenharmony_ci 243253a5a1b3Sopenharmony_ci *ret_u = (uint64_t) l; 243353a5a1b3Sopenharmony_ci 243453a5a1b3Sopenharmony_ci return 0; 243553a5a1b3Sopenharmony_ci} 243653a5a1b3Sopenharmony_ci 243753a5a1b3Sopenharmony_ci/* Convert the string s to a signed long integer in *ret_l. */ 243853a5a1b3Sopenharmony_ciint pa_atol(const char *s, long *ret_l) { 243953a5a1b3Sopenharmony_ci char *tmp; 244053a5a1b3Sopenharmony_ci char *x = NULL; 244153a5a1b3Sopenharmony_ci long l; 244253a5a1b3Sopenharmony_ci 244353a5a1b3Sopenharmony_ci pa_assert(s); 244453a5a1b3Sopenharmony_ci pa_assert(ret_l); 244553a5a1b3Sopenharmony_ci 244653a5a1b3Sopenharmony_ci if (prepare_number_string(s, NUMTYPE_INT, &tmp, &s) < 0) { 244753a5a1b3Sopenharmony_ci errno = EINVAL; 244853a5a1b3Sopenharmony_ci return -1; 244953a5a1b3Sopenharmony_ci } 245053a5a1b3Sopenharmony_ci 245153a5a1b3Sopenharmony_ci errno = 0; 245253a5a1b3Sopenharmony_ci l = strtol(s, &x, 0); 245353a5a1b3Sopenharmony_ci 245453a5a1b3Sopenharmony_ci /* If x doesn't point to the end of s, there was some trailing garbage in 245553a5a1b3Sopenharmony_ci * the string. If x points to s, no conversion was done (at least an empty 245653a5a1b3Sopenharmony_ci * string can trigger this). */ 245753a5a1b3Sopenharmony_ci if (!x || *x || x == s || errno) { 245853a5a1b3Sopenharmony_ci if (!errno) 245953a5a1b3Sopenharmony_ci errno = EINVAL; 246053a5a1b3Sopenharmony_ci pa_xfree(tmp); 246153a5a1b3Sopenharmony_ci return -1; 246253a5a1b3Sopenharmony_ci } 246353a5a1b3Sopenharmony_ci 246453a5a1b3Sopenharmony_ci pa_xfree(tmp); 246553a5a1b3Sopenharmony_ci 246653a5a1b3Sopenharmony_ci *ret_l = l; 246753a5a1b3Sopenharmony_ci 246853a5a1b3Sopenharmony_ci return 0; 246953a5a1b3Sopenharmony_ci} 247053a5a1b3Sopenharmony_ci 247153a5a1b3Sopenharmony_ci/* Convert the string s to a signed 64 bit integer in *ret_l. */ 247253a5a1b3Sopenharmony_ciint pa_atoi64(const char *s, int64_t *ret_l) { 247353a5a1b3Sopenharmony_ci char *tmp; 247453a5a1b3Sopenharmony_ci char *x = NULL; 247553a5a1b3Sopenharmony_ci long long l; 247653a5a1b3Sopenharmony_ci 247753a5a1b3Sopenharmony_ci pa_assert(s); 247853a5a1b3Sopenharmony_ci pa_assert(ret_l); 247953a5a1b3Sopenharmony_ci 248053a5a1b3Sopenharmony_ci if (prepare_number_string(s, NUMTYPE_INT, &tmp, &s) < 0) { 248153a5a1b3Sopenharmony_ci errno = EINVAL; 248253a5a1b3Sopenharmony_ci return -1; 248353a5a1b3Sopenharmony_ci } 248453a5a1b3Sopenharmony_ci 248553a5a1b3Sopenharmony_ci errno = 0; 248653a5a1b3Sopenharmony_ci l = strtoll(s, &x, 0); 248753a5a1b3Sopenharmony_ci 248853a5a1b3Sopenharmony_ci /* If x doesn't point to the end of s, there was some trailing garbage in 248953a5a1b3Sopenharmony_ci * the string. If x points to s, no conversion was done (at least an empty 249053a5a1b3Sopenharmony_ci * string can trigger this). */ 249153a5a1b3Sopenharmony_ci if (!x || *x || x == s || errno) { 249253a5a1b3Sopenharmony_ci if (!errno) 249353a5a1b3Sopenharmony_ci errno = EINVAL; 249453a5a1b3Sopenharmony_ci pa_xfree(tmp); 249553a5a1b3Sopenharmony_ci return -1; 249653a5a1b3Sopenharmony_ci } 249753a5a1b3Sopenharmony_ci 249853a5a1b3Sopenharmony_ci pa_xfree(tmp); 249953a5a1b3Sopenharmony_ci 250053a5a1b3Sopenharmony_ci *ret_l = l; 250153a5a1b3Sopenharmony_ci 250253a5a1b3Sopenharmony_ci if (l < INT64_MIN || l > INT64_MAX) { 250353a5a1b3Sopenharmony_ci errno = ERANGE; 250453a5a1b3Sopenharmony_ci return -1; 250553a5a1b3Sopenharmony_ci } 250653a5a1b3Sopenharmony_ci 250753a5a1b3Sopenharmony_ci return 0; 250853a5a1b3Sopenharmony_ci} 250953a5a1b3Sopenharmony_ci 251053a5a1b3Sopenharmony_ci#ifdef HAVE_STRTOD_L 251153a5a1b3Sopenharmony_cistatic locale_t c_locale = NULL; 251253a5a1b3Sopenharmony_ci 251353a5a1b3Sopenharmony_cistatic void c_locale_destroy(void) { 251453a5a1b3Sopenharmony_ci freelocale(c_locale); 251553a5a1b3Sopenharmony_ci} 251653a5a1b3Sopenharmony_ci#endif 251753a5a1b3Sopenharmony_ci 251853a5a1b3Sopenharmony_ciint pa_atod(const char *s, double *ret_d) { 251953a5a1b3Sopenharmony_ci char *x = NULL; 252053a5a1b3Sopenharmony_ci double f; 252153a5a1b3Sopenharmony_ci 252253a5a1b3Sopenharmony_ci pa_assert(s); 252353a5a1b3Sopenharmony_ci pa_assert(ret_d); 252453a5a1b3Sopenharmony_ci 252553a5a1b3Sopenharmony_ci if (prepare_number_string(s, NUMTYPE_DOUBLE, NULL, &s) < 0) { 252653a5a1b3Sopenharmony_ci errno = EINVAL; 252753a5a1b3Sopenharmony_ci return -1; 252853a5a1b3Sopenharmony_ci } 252953a5a1b3Sopenharmony_ci 253053a5a1b3Sopenharmony_ci /* This should be locale independent */ 253153a5a1b3Sopenharmony_ci 253253a5a1b3Sopenharmony_ci#ifdef HAVE_STRTOD_L 253353a5a1b3Sopenharmony_ci 253453a5a1b3Sopenharmony_ci PA_ONCE_BEGIN { 253553a5a1b3Sopenharmony_ci 253653a5a1b3Sopenharmony_ci if ((c_locale = newlocale(LC_ALL_MASK, "C", NULL))) 253753a5a1b3Sopenharmony_ci atexit(c_locale_destroy); 253853a5a1b3Sopenharmony_ci 253953a5a1b3Sopenharmony_ci } PA_ONCE_END; 254053a5a1b3Sopenharmony_ci 254153a5a1b3Sopenharmony_ci if (c_locale) { 254253a5a1b3Sopenharmony_ci errno = 0; 254353a5a1b3Sopenharmony_ci f = strtod_l(s, &x, c_locale); 254453a5a1b3Sopenharmony_ci } else 254553a5a1b3Sopenharmony_ci#endif 254653a5a1b3Sopenharmony_ci { 254753a5a1b3Sopenharmony_ci errno = 0; 254853a5a1b3Sopenharmony_ci f = strtod(s, &x); 254953a5a1b3Sopenharmony_ci } 255053a5a1b3Sopenharmony_ci 255153a5a1b3Sopenharmony_ci /* If x doesn't point to the end of s, there was some trailing garbage in 255253a5a1b3Sopenharmony_ci * the string. If x points to s, no conversion was done (at least an empty 255353a5a1b3Sopenharmony_ci * string can trigger this). */ 255453a5a1b3Sopenharmony_ci if (!x || *x || x == s || errno) { 255553a5a1b3Sopenharmony_ci if (!errno) 255653a5a1b3Sopenharmony_ci errno = EINVAL; 255753a5a1b3Sopenharmony_ci return -1; 255853a5a1b3Sopenharmony_ci } 255953a5a1b3Sopenharmony_ci 256053a5a1b3Sopenharmony_ci if (isnan(f)) { 256153a5a1b3Sopenharmony_ci errno = EINVAL; 256253a5a1b3Sopenharmony_ci return -1; 256353a5a1b3Sopenharmony_ci } 256453a5a1b3Sopenharmony_ci 256553a5a1b3Sopenharmony_ci *ret_d = f; 256653a5a1b3Sopenharmony_ci 256753a5a1b3Sopenharmony_ci return 0; 256853a5a1b3Sopenharmony_ci} 256953a5a1b3Sopenharmony_ci 257053a5a1b3Sopenharmony_ci/* Same as snprintf, but guarantees NUL-termination on every platform */ 257153a5a1b3Sopenharmony_cisize_t pa_snprintf(char *str, size_t size, const char *format, ...) { 257253a5a1b3Sopenharmony_ci size_t ret; 257353a5a1b3Sopenharmony_ci va_list ap; 257453a5a1b3Sopenharmony_ci 257553a5a1b3Sopenharmony_ci pa_assert(str); 257653a5a1b3Sopenharmony_ci pa_assert(size > 0); 257753a5a1b3Sopenharmony_ci pa_assert(format); 257853a5a1b3Sopenharmony_ci 257953a5a1b3Sopenharmony_ci va_start(ap, format); 258053a5a1b3Sopenharmony_ci ret = pa_vsnprintf(str, size, format, ap); 258153a5a1b3Sopenharmony_ci va_end(ap); 258253a5a1b3Sopenharmony_ci 258353a5a1b3Sopenharmony_ci return ret; 258453a5a1b3Sopenharmony_ci} 258553a5a1b3Sopenharmony_ci 258653a5a1b3Sopenharmony_ci/* Same as vsnprintf, but guarantees NUL-termination on every platform */ 258753a5a1b3Sopenharmony_cisize_t pa_vsnprintf(char *str, size_t size, const char *format, va_list ap) { 258853a5a1b3Sopenharmony_ci int ret; 258953a5a1b3Sopenharmony_ci 259053a5a1b3Sopenharmony_ci pa_assert(str); 259153a5a1b3Sopenharmony_ci pa_assert(size > 0); 259253a5a1b3Sopenharmony_ci pa_assert(format); 259353a5a1b3Sopenharmony_ci 259453a5a1b3Sopenharmony_ci ret = vsnprintf(str, size, format, ap); 259553a5a1b3Sopenharmony_ci 259653a5a1b3Sopenharmony_ci str[size-1] = 0; 259753a5a1b3Sopenharmony_ci 259853a5a1b3Sopenharmony_ci if (ret < 0) 259953a5a1b3Sopenharmony_ci return strlen(str); 260053a5a1b3Sopenharmony_ci 260153a5a1b3Sopenharmony_ci if ((size_t) ret > size-1) 260253a5a1b3Sopenharmony_ci return size-1; 260353a5a1b3Sopenharmony_ci 260453a5a1b3Sopenharmony_ci return (size_t) ret; 260553a5a1b3Sopenharmony_ci} 260653a5a1b3Sopenharmony_ci 260753a5a1b3Sopenharmony_ci/* Truncate the specified string, but guarantee that the string 260853a5a1b3Sopenharmony_ci * returned still validates as UTF8 */ 260953a5a1b3Sopenharmony_cichar *pa_truncate_utf8(char *c, size_t l) { 261053a5a1b3Sopenharmony_ci pa_assert(c); 261153a5a1b3Sopenharmony_ci pa_assert(pa_utf8_valid(c)); 261253a5a1b3Sopenharmony_ci 261353a5a1b3Sopenharmony_ci if (strlen(c) <= l) 261453a5a1b3Sopenharmony_ci return c; 261553a5a1b3Sopenharmony_ci 261653a5a1b3Sopenharmony_ci c[l] = 0; 261753a5a1b3Sopenharmony_ci 261853a5a1b3Sopenharmony_ci while (l > 0 && !pa_utf8_valid(c)) 261953a5a1b3Sopenharmony_ci c[--l] = 0; 262053a5a1b3Sopenharmony_ci 262153a5a1b3Sopenharmony_ci return c; 262253a5a1b3Sopenharmony_ci} 262353a5a1b3Sopenharmony_ci 262453a5a1b3Sopenharmony_cichar *pa_getcwd(void) { 262553a5a1b3Sopenharmony_ci size_t l = 128; 262653a5a1b3Sopenharmony_ci 262753a5a1b3Sopenharmony_ci for (;;) { 262853a5a1b3Sopenharmony_ci char *p = pa_xmalloc(l); 262953a5a1b3Sopenharmony_ci if (getcwd(p, l)) 263053a5a1b3Sopenharmony_ci return p; 263153a5a1b3Sopenharmony_ci 263253a5a1b3Sopenharmony_ci if (errno != ERANGE) { 263353a5a1b3Sopenharmony_ci pa_xfree(p); 263453a5a1b3Sopenharmony_ci return NULL; 263553a5a1b3Sopenharmony_ci } 263653a5a1b3Sopenharmony_ci 263753a5a1b3Sopenharmony_ci pa_xfree(p); 263853a5a1b3Sopenharmony_ci l *= 2; 263953a5a1b3Sopenharmony_ci } 264053a5a1b3Sopenharmony_ci} 264153a5a1b3Sopenharmony_ci 264253a5a1b3Sopenharmony_civoid *pa_will_need(const void *p, size_t l) { 264353a5a1b3Sopenharmony_ci#ifdef RLIMIT_MEMLOCK 264453a5a1b3Sopenharmony_ci struct rlimit rlim; 264553a5a1b3Sopenharmony_ci#endif 264653a5a1b3Sopenharmony_ci const void *a; 264753a5a1b3Sopenharmony_ci size_t size; 264853a5a1b3Sopenharmony_ci int r = ENOTSUP; 264953a5a1b3Sopenharmony_ci size_t bs; 265053a5a1b3Sopenharmony_ci const size_t page_size = pa_page_size(); 265153a5a1b3Sopenharmony_ci 265253a5a1b3Sopenharmony_ci pa_assert(p); 265353a5a1b3Sopenharmony_ci pa_assert(l > 0); 265453a5a1b3Sopenharmony_ci 265553a5a1b3Sopenharmony_ci a = PA_PAGE_ALIGN_PTR(p); 265653a5a1b3Sopenharmony_ci size = (size_t) ((const uint8_t*) p + l - (const uint8_t*) a); 265753a5a1b3Sopenharmony_ci 265853a5a1b3Sopenharmony_ci#ifdef HAVE_POSIX_MADVISE 265953a5a1b3Sopenharmony_ci if ((r = posix_madvise((void*) a, size, POSIX_MADV_WILLNEED)) == 0) { 266053a5a1b3Sopenharmony_ci pa_log_debug("posix_madvise() worked fine!"); 266153a5a1b3Sopenharmony_ci return (void*) p; 266253a5a1b3Sopenharmony_ci } 266353a5a1b3Sopenharmony_ci#endif 266453a5a1b3Sopenharmony_ci 266553a5a1b3Sopenharmony_ci /* Most likely the memory was not mmap()ed from a file and thus 266653a5a1b3Sopenharmony_ci * madvise() didn't work, so let's misuse mlock() do page this 266753a5a1b3Sopenharmony_ci * stuff back into RAM. Yeah, let's fuck with the MM! It's so 266853a5a1b3Sopenharmony_ci * inviting, the man page of mlock() tells us: "All pages that 266953a5a1b3Sopenharmony_ci * contain a part of the specified address range are guaranteed to 267053a5a1b3Sopenharmony_ci * be resident in RAM when the call returns successfully." */ 267153a5a1b3Sopenharmony_ci 267253a5a1b3Sopenharmony_ci#ifdef RLIMIT_MEMLOCK 267353a5a1b3Sopenharmony_ci pa_assert_se(getrlimit(RLIMIT_MEMLOCK, &rlim) == 0); 267453a5a1b3Sopenharmony_ci 267553a5a1b3Sopenharmony_ci if (rlim.rlim_cur < page_size) { 267653a5a1b3Sopenharmony_ci pa_log_debug("posix_madvise() failed (or doesn't exist), resource limits don't allow mlock(), can't page in data: %s", pa_cstrerror(r)); 267753a5a1b3Sopenharmony_ci errno = EPERM; 267853a5a1b3Sopenharmony_ci return (void*) p; 267953a5a1b3Sopenharmony_ci } 268053a5a1b3Sopenharmony_ci 268153a5a1b3Sopenharmony_ci bs = PA_PAGE_ALIGN((size_t) rlim.rlim_cur); 268253a5a1b3Sopenharmony_ci#else 268353a5a1b3Sopenharmony_ci bs = page_size*4; 268453a5a1b3Sopenharmony_ci#endif 268553a5a1b3Sopenharmony_ci 268653a5a1b3Sopenharmony_ci pa_log_debug("posix_madvise() failed (or doesn't exist), trying mlock(): %s", pa_cstrerror(r)); 268753a5a1b3Sopenharmony_ci 268853a5a1b3Sopenharmony_ci#ifdef HAVE_MLOCK 268953a5a1b3Sopenharmony_ci while (size > 0 && bs > 0) { 269053a5a1b3Sopenharmony_ci 269153a5a1b3Sopenharmony_ci if (bs > size) 269253a5a1b3Sopenharmony_ci bs = size; 269353a5a1b3Sopenharmony_ci 269453a5a1b3Sopenharmony_ci if (mlock(a, bs) < 0) { 269553a5a1b3Sopenharmony_ci bs = PA_PAGE_ALIGN(bs / 2); 269653a5a1b3Sopenharmony_ci continue; 269753a5a1b3Sopenharmony_ci } 269853a5a1b3Sopenharmony_ci 269953a5a1b3Sopenharmony_ci pa_assert_se(munlock(a, bs) == 0); 270053a5a1b3Sopenharmony_ci 270153a5a1b3Sopenharmony_ci a = (const uint8_t*) a + bs; 270253a5a1b3Sopenharmony_ci size -= bs; 270353a5a1b3Sopenharmony_ci } 270453a5a1b3Sopenharmony_ci#endif 270553a5a1b3Sopenharmony_ci 270653a5a1b3Sopenharmony_ci if (bs <= 0) 270753a5a1b3Sopenharmony_ci pa_log_debug("mlock() failed too (or doesn't exist), giving up: %s", pa_cstrerror(errno)); 270853a5a1b3Sopenharmony_ci else 270953a5a1b3Sopenharmony_ci pa_log_debug("mlock() worked fine!"); 271053a5a1b3Sopenharmony_ci 271153a5a1b3Sopenharmony_ci return (void*) p; 271253a5a1b3Sopenharmony_ci} 271353a5a1b3Sopenharmony_ci 271453a5a1b3Sopenharmony_civoid pa_close_pipe(int fds[2]) { 271553a5a1b3Sopenharmony_ci pa_assert(fds); 271653a5a1b3Sopenharmony_ci 271753a5a1b3Sopenharmony_ci if (fds[0] >= 0) 271853a5a1b3Sopenharmony_ci pa_assert_se(pa_close(fds[0]) == 0); 271953a5a1b3Sopenharmony_ci 272053a5a1b3Sopenharmony_ci if (fds[1] >= 0) 272153a5a1b3Sopenharmony_ci pa_assert_se(pa_close(fds[1]) == 0); 272253a5a1b3Sopenharmony_ci 272353a5a1b3Sopenharmony_ci fds[0] = fds[1] = -1; 272453a5a1b3Sopenharmony_ci} 272553a5a1b3Sopenharmony_ci 272653a5a1b3Sopenharmony_cichar *pa_readlink(const char *p) { 272753a5a1b3Sopenharmony_ci#ifdef HAVE_READLINK 272853a5a1b3Sopenharmony_ci size_t l = 100; 272953a5a1b3Sopenharmony_ci 273053a5a1b3Sopenharmony_ci for (;;) { 273153a5a1b3Sopenharmony_ci char *c; 273253a5a1b3Sopenharmony_ci ssize_t n; 273353a5a1b3Sopenharmony_ci 273453a5a1b3Sopenharmony_ci c = pa_xmalloc(l); 273553a5a1b3Sopenharmony_ci 273653a5a1b3Sopenharmony_ci if ((n = readlink(p, c, l-1)) < 0) { 273753a5a1b3Sopenharmony_ci pa_xfree(c); 273853a5a1b3Sopenharmony_ci return NULL; 273953a5a1b3Sopenharmony_ci } 274053a5a1b3Sopenharmony_ci 274153a5a1b3Sopenharmony_ci if ((size_t) n < l-1) { 274253a5a1b3Sopenharmony_ci c[n] = 0; 274353a5a1b3Sopenharmony_ci return c; 274453a5a1b3Sopenharmony_ci } 274553a5a1b3Sopenharmony_ci 274653a5a1b3Sopenharmony_ci pa_xfree(c); 274753a5a1b3Sopenharmony_ci l *= 2; 274853a5a1b3Sopenharmony_ci } 274953a5a1b3Sopenharmony_ci#else 275053a5a1b3Sopenharmony_ci return NULL; 275153a5a1b3Sopenharmony_ci#endif 275253a5a1b3Sopenharmony_ci} 275353a5a1b3Sopenharmony_ci 275453a5a1b3Sopenharmony_ciint pa_close_all(int except_fd, ...) { 275553a5a1b3Sopenharmony_ci va_list ap; 275653a5a1b3Sopenharmony_ci unsigned n = 0, i; 275753a5a1b3Sopenharmony_ci int r, *p; 275853a5a1b3Sopenharmony_ci 275953a5a1b3Sopenharmony_ci va_start(ap, except_fd); 276053a5a1b3Sopenharmony_ci 276153a5a1b3Sopenharmony_ci if (except_fd >= 0) 276253a5a1b3Sopenharmony_ci for (n = 1; va_arg(ap, int) >= 0; n++) 276353a5a1b3Sopenharmony_ci ; 276453a5a1b3Sopenharmony_ci 276553a5a1b3Sopenharmony_ci va_end(ap); 276653a5a1b3Sopenharmony_ci 276753a5a1b3Sopenharmony_ci p = pa_xnew(int, n+1); 276853a5a1b3Sopenharmony_ci 276953a5a1b3Sopenharmony_ci va_start(ap, except_fd); 277053a5a1b3Sopenharmony_ci 277153a5a1b3Sopenharmony_ci i = 0; 277253a5a1b3Sopenharmony_ci if (except_fd >= 0) { 277353a5a1b3Sopenharmony_ci int fd; 277453a5a1b3Sopenharmony_ci p[i++] = except_fd; 277553a5a1b3Sopenharmony_ci 277653a5a1b3Sopenharmony_ci while ((fd = va_arg(ap, int)) >= 0) 277753a5a1b3Sopenharmony_ci p[i++] = fd; 277853a5a1b3Sopenharmony_ci } 277953a5a1b3Sopenharmony_ci p[i] = -1; 278053a5a1b3Sopenharmony_ci 278153a5a1b3Sopenharmony_ci va_end(ap); 278253a5a1b3Sopenharmony_ci 278353a5a1b3Sopenharmony_ci r = pa_close_allv(p); 278453a5a1b3Sopenharmony_ci pa_xfree(p); 278553a5a1b3Sopenharmony_ci 278653a5a1b3Sopenharmony_ci return r; 278753a5a1b3Sopenharmony_ci} 278853a5a1b3Sopenharmony_ci 278953a5a1b3Sopenharmony_ciint pa_close_allv(const int except_fds[]) { 279053a5a1b3Sopenharmony_ci#ifndef OS_IS_WIN32 279153a5a1b3Sopenharmony_ci struct rlimit rl; 279253a5a1b3Sopenharmony_ci int maxfd, fd; 279353a5a1b3Sopenharmony_ci 279453a5a1b3Sopenharmony_ci#if defined(__linux__) || defined(__sun) 279553a5a1b3Sopenharmony_ci int saved_errno; 279653a5a1b3Sopenharmony_ci DIR *d; 279753a5a1b3Sopenharmony_ci 279853a5a1b3Sopenharmony_ci if ((d = opendir("/proc/self/fd"))) { 279953a5a1b3Sopenharmony_ci 280053a5a1b3Sopenharmony_ci struct dirent *de; 280153a5a1b3Sopenharmony_ci 280253a5a1b3Sopenharmony_ci while ((de = readdir(d))) { 280353a5a1b3Sopenharmony_ci bool found; 280453a5a1b3Sopenharmony_ci long l; 280553a5a1b3Sopenharmony_ci char *e = NULL; 280653a5a1b3Sopenharmony_ci int i; 280753a5a1b3Sopenharmony_ci 280853a5a1b3Sopenharmony_ci if (de->d_name[0] == '.') 280953a5a1b3Sopenharmony_ci continue; 281053a5a1b3Sopenharmony_ci 281153a5a1b3Sopenharmony_ci errno = 0; 281253a5a1b3Sopenharmony_ci l = strtol(de->d_name, &e, 10); 281353a5a1b3Sopenharmony_ci if (errno != 0 || !e || *e) { 281453a5a1b3Sopenharmony_ci closedir(d); 281553a5a1b3Sopenharmony_ci errno = EINVAL; 281653a5a1b3Sopenharmony_ci return -1; 281753a5a1b3Sopenharmony_ci } 281853a5a1b3Sopenharmony_ci 281953a5a1b3Sopenharmony_ci fd = (int) l; 282053a5a1b3Sopenharmony_ci 282153a5a1b3Sopenharmony_ci if ((long) fd != l) { 282253a5a1b3Sopenharmony_ci closedir(d); 282353a5a1b3Sopenharmony_ci errno = EINVAL; 282453a5a1b3Sopenharmony_ci return -1; 282553a5a1b3Sopenharmony_ci } 282653a5a1b3Sopenharmony_ci 282753a5a1b3Sopenharmony_ci if (fd < 3) 282853a5a1b3Sopenharmony_ci continue; 282953a5a1b3Sopenharmony_ci 283053a5a1b3Sopenharmony_ci if (fd == dirfd(d)) 283153a5a1b3Sopenharmony_ci continue; 283253a5a1b3Sopenharmony_ci 283353a5a1b3Sopenharmony_ci found = false; 283453a5a1b3Sopenharmony_ci for (i = 0; except_fds[i] >= 0; i++) 283553a5a1b3Sopenharmony_ci if (except_fds[i] == fd) { 283653a5a1b3Sopenharmony_ci found = true; 283753a5a1b3Sopenharmony_ci break; 283853a5a1b3Sopenharmony_ci } 283953a5a1b3Sopenharmony_ci 284053a5a1b3Sopenharmony_ci if (found) 284153a5a1b3Sopenharmony_ci continue; 284253a5a1b3Sopenharmony_ci 284353a5a1b3Sopenharmony_ci if (pa_close(fd) < 0) { 284453a5a1b3Sopenharmony_ci saved_errno = errno; 284553a5a1b3Sopenharmony_ci closedir(d); 284653a5a1b3Sopenharmony_ci errno = saved_errno; 284753a5a1b3Sopenharmony_ci 284853a5a1b3Sopenharmony_ci return -1; 284953a5a1b3Sopenharmony_ci } 285053a5a1b3Sopenharmony_ci } 285153a5a1b3Sopenharmony_ci 285253a5a1b3Sopenharmony_ci closedir(d); 285353a5a1b3Sopenharmony_ci return 0; 285453a5a1b3Sopenharmony_ci } 285553a5a1b3Sopenharmony_ci 285653a5a1b3Sopenharmony_ci#endif 285753a5a1b3Sopenharmony_ci 285853a5a1b3Sopenharmony_ci if (getrlimit(RLIMIT_NOFILE, &rl) >= 0) 285953a5a1b3Sopenharmony_ci maxfd = (int) rl.rlim_max; 286053a5a1b3Sopenharmony_ci else 286153a5a1b3Sopenharmony_ci maxfd = sysconf(_SC_OPEN_MAX); 286253a5a1b3Sopenharmony_ci 286353a5a1b3Sopenharmony_ci for (fd = 3; fd < maxfd; fd++) { 286453a5a1b3Sopenharmony_ci int i; 286553a5a1b3Sopenharmony_ci bool found; 286653a5a1b3Sopenharmony_ci 286753a5a1b3Sopenharmony_ci found = false; 286853a5a1b3Sopenharmony_ci for (i = 0; except_fds[i] >= 0; i++) 286953a5a1b3Sopenharmony_ci if (except_fds[i] == fd) { 287053a5a1b3Sopenharmony_ci found = true; 287153a5a1b3Sopenharmony_ci break; 287253a5a1b3Sopenharmony_ci } 287353a5a1b3Sopenharmony_ci 287453a5a1b3Sopenharmony_ci if (found) 287553a5a1b3Sopenharmony_ci continue; 287653a5a1b3Sopenharmony_ci 287753a5a1b3Sopenharmony_ci if (pa_close(fd) < 0 && errno != EBADF) 287853a5a1b3Sopenharmony_ci return -1; 287953a5a1b3Sopenharmony_ci } 288053a5a1b3Sopenharmony_ci#endif /* !OS_IS_WIN32 */ 288153a5a1b3Sopenharmony_ci 288253a5a1b3Sopenharmony_ci return 0; 288353a5a1b3Sopenharmony_ci} 288453a5a1b3Sopenharmony_ci 288553a5a1b3Sopenharmony_ciint pa_unblock_sigs(int except, ...) { 288653a5a1b3Sopenharmony_ci va_list ap; 288753a5a1b3Sopenharmony_ci unsigned n = 0, i; 288853a5a1b3Sopenharmony_ci int r, *p; 288953a5a1b3Sopenharmony_ci 289053a5a1b3Sopenharmony_ci va_start(ap, except); 289153a5a1b3Sopenharmony_ci 289253a5a1b3Sopenharmony_ci if (except >= 1) 289353a5a1b3Sopenharmony_ci for (n = 1; va_arg(ap, int) >= 0; n++) 289453a5a1b3Sopenharmony_ci ; 289553a5a1b3Sopenharmony_ci 289653a5a1b3Sopenharmony_ci va_end(ap); 289753a5a1b3Sopenharmony_ci 289853a5a1b3Sopenharmony_ci p = pa_xnew(int, n+1); 289953a5a1b3Sopenharmony_ci 290053a5a1b3Sopenharmony_ci va_start(ap, except); 290153a5a1b3Sopenharmony_ci 290253a5a1b3Sopenharmony_ci i = 0; 290353a5a1b3Sopenharmony_ci if (except >= 1) { 290453a5a1b3Sopenharmony_ci int sig; 290553a5a1b3Sopenharmony_ci p[i++] = except; 290653a5a1b3Sopenharmony_ci 290753a5a1b3Sopenharmony_ci while ((sig = va_arg(ap, int)) >= 0) 290853a5a1b3Sopenharmony_ci p[i++] = sig; 290953a5a1b3Sopenharmony_ci } 291053a5a1b3Sopenharmony_ci p[i] = -1; 291153a5a1b3Sopenharmony_ci 291253a5a1b3Sopenharmony_ci va_end(ap); 291353a5a1b3Sopenharmony_ci 291453a5a1b3Sopenharmony_ci r = pa_unblock_sigsv(p); 291553a5a1b3Sopenharmony_ci pa_xfree(p); 291653a5a1b3Sopenharmony_ci 291753a5a1b3Sopenharmony_ci return r; 291853a5a1b3Sopenharmony_ci} 291953a5a1b3Sopenharmony_ci 292053a5a1b3Sopenharmony_ciint pa_unblock_sigsv(const int except[]) { 292153a5a1b3Sopenharmony_ci#ifndef OS_IS_WIN32 292253a5a1b3Sopenharmony_ci int i; 292353a5a1b3Sopenharmony_ci sigset_t ss; 292453a5a1b3Sopenharmony_ci 292553a5a1b3Sopenharmony_ci if (sigemptyset(&ss) < 0) 292653a5a1b3Sopenharmony_ci return -1; 292753a5a1b3Sopenharmony_ci 292853a5a1b3Sopenharmony_ci for (i = 0; except[i] > 0; i++) 292953a5a1b3Sopenharmony_ci if (sigaddset(&ss, except[i]) < 0) 293053a5a1b3Sopenharmony_ci return -1; 293153a5a1b3Sopenharmony_ci 293253a5a1b3Sopenharmony_ci return sigprocmask(SIG_SETMASK, &ss, NULL); 293353a5a1b3Sopenharmony_ci#else 293453a5a1b3Sopenharmony_ci return 0; 293553a5a1b3Sopenharmony_ci#endif 293653a5a1b3Sopenharmony_ci} 293753a5a1b3Sopenharmony_ci 293853a5a1b3Sopenharmony_ciint pa_reset_sigs(int except, ...) { 293953a5a1b3Sopenharmony_ci va_list ap; 294053a5a1b3Sopenharmony_ci unsigned n = 0, i; 294153a5a1b3Sopenharmony_ci int *p, r; 294253a5a1b3Sopenharmony_ci 294353a5a1b3Sopenharmony_ci va_start(ap, except); 294453a5a1b3Sopenharmony_ci 294553a5a1b3Sopenharmony_ci if (except >= 1) 294653a5a1b3Sopenharmony_ci for (n = 1; va_arg(ap, int) >= 0; n++) 294753a5a1b3Sopenharmony_ci ; 294853a5a1b3Sopenharmony_ci 294953a5a1b3Sopenharmony_ci va_end(ap); 295053a5a1b3Sopenharmony_ci 295153a5a1b3Sopenharmony_ci p = pa_xnew(int, n+1); 295253a5a1b3Sopenharmony_ci 295353a5a1b3Sopenharmony_ci va_start(ap, except); 295453a5a1b3Sopenharmony_ci 295553a5a1b3Sopenharmony_ci i = 0; 295653a5a1b3Sopenharmony_ci if (except >= 1) { 295753a5a1b3Sopenharmony_ci int sig; 295853a5a1b3Sopenharmony_ci p[i++] = except; 295953a5a1b3Sopenharmony_ci 296053a5a1b3Sopenharmony_ci while ((sig = va_arg(ap, int)) >= 0) 296153a5a1b3Sopenharmony_ci p[i++] = sig; 296253a5a1b3Sopenharmony_ci } 296353a5a1b3Sopenharmony_ci p[i] = -1; 296453a5a1b3Sopenharmony_ci 296553a5a1b3Sopenharmony_ci va_end(ap); 296653a5a1b3Sopenharmony_ci 296753a5a1b3Sopenharmony_ci r = pa_reset_sigsv(p); 296853a5a1b3Sopenharmony_ci pa_xfree(p); 296953a5a1b3Sopenharmony_ci 297053a5a1b3Sopenharmony_ci return r; 297153a5a1b3Sopenharmony_ci} 297253a5a1b3Sopenharmony_ci 297353a5a1b3Sopenharmony_ciint pa_reset_sigsv(const int except[]) { 297453a5a1b3Sopenharmony_ci#ifndef OS_IS_WIN32 297553a5a1b3Sopenharmony_ci int sig; 297653a5a1b3Sopenharmony_ci 297753a5a1b3Sopenharmony_ci for (sig = 1; sig < NSIG; sig++) { 297853a5a1b3Sopenharmony_ci bool reset = true; 297953a5a1b3Sopenharmony_ci 298053a5a1b3Sopenharmony_ci switch (sig) { 298153a5a1b3Sopenharmony_ci case SIGKILL: 298253a5a1b3Sopenharmony_ci case SIGSTOP: 298353a5a1b3Sopenharmony_ci reset = false; 298453a5a1b3Sopenharmony_ci break; 298553a5a1b3Sopenharmony_ci 298653a5a1b3Sopenharmony_ci default: { 298753a5a1b3Sopenharmony_ci int i; 298853a5a1b3Sopenharmony_ci 298953a5a1b3Sopenharmony_ci for (i = 0; except[i] > 0; i++) { 299053a5a1b3Sopenharmony_ci if (sig == except[i]) { 299153a5a1b3Sopenharmony_ci reset = false; 299253a5a1b3Sopenharmony_ci break; 299353a5a1b3Sopenharmony_ci } 299453a5a1b3Sopenharmony_ci } 299553a5a1b3Sopenharmony_ci } 299653a5a1b3Sopenharmony_ci } 299753a5a1b3Sopenharmony_ci 299853a5a1b3Sopenharmony_ci if (reset) { 299953a5a1b3Sopenharmony_ci struct sigaction sa; 300053a5a1b3Sopenharmony_ci 300153a5a1b3Sopenharmony_ci memset(&sa, 0, sizeof(sa)); 300253a5a1b3Sopenharmony_ci sa.sa_handler = SIG_DFL; 300353a5a1b3Sopenharmony_ci 300453a5a1b3Sopenharmony_ci /* On Linux the first two RT signals are reserved by 300553a5a1b3Sopenharmony_ci * glibc, and sigaction() will return EINVAL for them. */ 300653a5a1b3Sopenharmony_ci if ((sigaction(sig, &sa, NULL) < 0)) 300753a5a1b3Sopenharmony_ci if (errno != EINVAL) 300853a5a1b3Sopenharmony_ci return -1; 300953a5a1b3Sopenharmony_ci } 301053a5a1b3Sopenharmony_ci } 301153a5a1b3Sopenharmony_ci#endif 301253a5a1b3Sopenharmony_ci 301353a5a1b3Sopenharmony_ci return 0; 301453a5a1b3Sopenharmony_ci} 301553a5a1b3Sopenharmony_ci 301653a5a1b3Sopenharmony_civoid pa_set_env(const char *key, const char *value) { 301753a5a1b3Sopenharmony_ci pa_assert(key); 301853a5a1b3Sopenharmony_ci pa_assert(value); 301953a5a1b3Sopenharmony_ci 302053a5a1b3Sopenharmony_ci /* This is not thread-safe */ 302153a5a1b3Sopenharmony_ci 302253a5a1b3Sopenharmony_ci#ifdef OS_IS_WIN32 302353a5a1b3Sopenharmony_ci int kl = strlen(key); 302453a5a1b3Sopenharmony_ci int vl = strlen(value); 302553a5a1b3Sopenharmony_ci char *tmp = pa_xmalloc(kl+vl+2); 302653a5a1b3Sopenharmony_ci memcpy(tmp, key, kl); 302753a5a1b3Sopenharmony_ci memcpy(tmp+kl+1, value, vl); 302853a5a1b3Sopenharmony_ci tmp[kl] = '='; 302953a5a1b3Sopenharmony_ci tmp[kl+1+vl] = '\0'; 303053a5a1b3Sopenharmony_ci putenv(tmp); 303153a5a1b3Sopenharmony_ci /* Even though it should be safe to free it on Windows, we don't want to 303253a5a1b3Sopenharmony_ci * rely on undocumented behaviour. */ 303353a5a1b3Sopenharmony_ci#else 303453a5a1b3Sopenharmony_ci setenv(key, value, 1); 303553a5a1b3Sopenharmony_ci#endif 303653a5a1b3Sopenharmony_ci} 303753a5a1b3Sopenharmony_ci 303853a5a1b3Sopenharmony_civoid pa_unset_env(const char *key) { 303953a5a1b3Sopenharmony_ci pa_assert(key); 304053a5a1b3Sopenharmony_ci 304153a5a1b3Sopenharmony_ci /* This is not thread-safe */ 304253a5a1b3Sopenharmony_ci 304353a5a1b3Sopenharmony_ci#ifdef OS_IS_WIN32 304453a5a1b3Sopenharmony_ci int kl = strlen(key); 304553a5a1b3Sopenharmony_ci char *tmp = pa_xmalloc(kl+2); 304653a5a1b3Sopenharmony_ci memcpy(tmp, key, kl); 304753a5a1b3Sopenharmony_ci tmp[kl] = '='; 304853a5a1b3Sopenharmony_ci tmp[kl+1] = '\0'; 304953a5a1b3Sopenharmony_ci putenv(tmp); 305053a5a1b3Sopenharmony_ci /* Even though it should be safe to free it on Windows, we don't want to 305153a5a1b3Sopenharmony_ci * rely on undocumented behaviour. */ 305253a5a1b3Sopenharmony_ci#else 305353a5a1b3Sopenharmony_ci unsetenv(key); 305453a5a1b3Sopenharmony_ci#endif 305553a5a1b3Sopenharmony_ci} 305653a5a1b3Sopenharmony_ci 305753a5a1b3Sopenharmony_civoid pa_set_env_and_record(const char *key, const char *value) { 305853a5a1b3Sopenharmony_ci pa_assert(key); 305953a5a1b3Sopenharmony_ci pa_assert(value); 306053a5a1b3Sopenharmony_ci 306153a5a1b3Sopenharmony_ci /* This is not thread-safe */ 306253a5a1b3Sopenharmony_ci 306353a5a1b3Sopenharmony_ci pa_set_env(key, value); 306453a5a1b3Sopenharmony_ci recorded_env = pa_strlist_prepend(recorded_env, key); 306553a5a1b3Sopenharmony_ci} 306653a5a1b3Sopenharmony_ci 306753a5a1b3Sopenharmony_civoid pa_unset_env_recorded(void) { 306853a5a1b3Sopenharmony_ci 306953a5a1b3Sopenharmony_ci /* This is not thread-safe */ 307053a5a1b3Sopenharmony_ci 307153a5a1b3Sopenharmony_ci for (;;) { 307253a5a1b3Sopenharmony_ci char *s; 307353a5a1b3Sopenharmony_ci 307453a5a1b3Sopenharmony_ci recorded_env = pa_strlist_pop(recorded_env, &s); 307553a5a1b3Sopenharmony_ci 307653a5a1b3Sopenharmony_ci if (!s) 307753a5a1b3Sopenharmony_ci break; 307853a5a1b3Sopenharmony_ci 307953a5a1b3Sopenharmony_ci pa_unset_env(s); 308053a5a1b3Sopenharmony_ci pa_xfree(s); 308153a5a1b3Sopenharmony_ci } 308253a5a1b3Sopenharmony_ci} 308353a5a1b3Sopenharmony_ci 308453a5a1b3Sopenharmony_cibool pa_in_system_mode(void) { 308553a5a1b3Sopenharmony_ci const char *e; 308653a5a1b3Sopenharmony_ci 308753a5a1b3Sopenharmony_ci if (!(e = getenv("PULSE_SYSTEM"))) 308853a5a1b3Sopenharmony_ci return false; 308953a5a1b3Sopenharmony_ci 309053a5a1b3Sopenharmony_ci return !!atoi(e); 309153a5a1b3Sopenharmony_ci} 309253a5a1b3Sopenharmony_ci 309353a5a1b3Sopenharmony_ci/* Checks a delimiters-separated list of words in haystack for needle */ 309453a5a1b3Sopenharmony_cibool pa_str_in_list(const char *haystack, const char *delimiters, const char *needle) { 309553a5a1b3Sopenharmony_ci char *s; 309653a5a1b3Sopenharmony_ci const char *state = NULL; 309753a5a1b3Sopenharmony_ci 309853a5a1b3Sopenharmony_ci if (!haystack || !needle) 309953a5a1b3Sopenharmony_ci return false; 310053a5a1b3Sopenharmony_ci 310153a5a1b3Sopenharmony_ci while ((s = pa_split(haystack, delimiters, &state))) { 310253a5a1b3Sopenharmony_ci if (pa_streq(needle, s)) { 310353a5a1b3Sopenharmony_ci pa_xfree(s); 310453a5a1b3Sopenharmony_ci return true; 310553a5a1b3Sopenharmony_ci } 310653a5a1b3Sopenharmony_ci 310753a5a1b3Sopenharmony_ci pa_xfree(s); 310853a5a1b3Sopenharmony_ci } 310953a5a1b3Sopenharmony_ci 311053a5a1b3Sopenharmony_ci return false; 311153a5a1b3Sopenharmony_ci} 311253a5a1b3Sopenharmony_ci 311353a5a1b3Sopenharmony_ci/* Checks a whitespace-separated list of words in haystack for needle */ 311453a5a1b3Sopenharmony_cibool pa_str_in_list_spaces(const char *haystack, const char *needle) { 311553a5a1b3Sopenharmony_ci const char *s; 311653a5a1b3Sopenharmony_ci size_t n; 311753a5a1b3Sopenharmony_ci const char *state = NULL; 311853a5a1b3Sopenharmony_ci 311953a5a1b3Sopenharmony_ci if (!haystack || !needle) 312053a5a1b3Sopenharmony_ci return false; 312153a5a1b3Sopenharmony_ci 312253a5a1b3Sopenharmony_ci while ((s = pa_split_spaces_in_place(haystack, &n, &state))) { 312353a5a1b3Sopenharmony_ci if (pa_strneq(needle, s, n)) 312453a5a1b3Sopenharmony_ci return true; 312553a5a1b3Sopenharmony_ci } 312653a5a1b3Sopenharmony_ci 312753a5a1b3Sopenharmony_ci return false; 312853a5a1b3Sopenharmony_ci} 312953a5a1b3Sopenharmony_ci 313053a5a1b3Sopenharmony_cichar* pa_str_strip_suffix(const char *str, const char *suffix) { 313153a5a1b3Sopenharmony_ci size_t str_l, suf_l, prefix; 313253a5a1b3Sopenharmony_ci char *ret; 313353a5a1b3Sopenharmony_ci 313453a5a1b3Sopenharmony_ci pa_assert(str); 313553a5a1b3Sopenharmony_ci pa_assert(suffix); 313653a5a1b3Sopenharmony_ci 313753a5a1b3Sopenharmony_ci str_l = strlen(str); 313853a5a1b3Sopenharmony_ci suf_l = strlen(suffix); 313953a5a1b3Sopenharmony_ci 314053a5a1b3Sopenharmony_ci if (str_l < suf_l) 314153a5a1b3Sopenharmony_ci return NULL; 314253a5a1b3Sopenharmony_ci 314353a5a1b3Sopenharmony_ci prefix = str_l - suf_l; 314453a5a1b3Sopenharmony_ci 314553a5a1b3Sopenharmony_ci if (!pa_streq(&str[prefix], suffix)) 314653a5a1b3Sopenharmony_ci return NULL; 314753a5a1b3Sopenharmony_ci 314853a5a1b3Sopenharmony_ci ret = pa_xmalloc(prefix + 1); 314953a5a1b3Sopenharmony_ci 315053a5a1b3Sopenharmony_ci strncpy(ret, str, prefix); 315153a5a1b3Sopenharmony_ci ret[prefix] = '\0'; 315253a5a1b3Sopenharmony_ci 315353a5a1b3Sopenharmony_ci return ret; 315453a5a1b3Sopenharmony_ci} 315553a5a1b3Sopenharmony_ci 315653a5a1b3Sopenharmony_cichar *pa_get_user_name_malloc(void) { 315753a5a1b3Sopenharmony_ci ssize_t k; 315853a5a1b3Sopenharmony_ci char *u; 315953a5a1b3Sopenharmony_ci 316053a5a1b3Sopenharmony_ci#ifdef _SC_LOGIN_NAME_MAX 316153a5a1b3Sopenharmony_ci k = (ssize_t) sysconf(_SC_LOGIN_NAME_MAX); 316253a5a1b3Sopenharmony_ci 316353a5a1b3Sopenharmony_ci if (k <= 0) 316453a5a1b3Sopenharmony_ci#endif 316553a5a1b3Sopenharmony_ci k = 32; 316653a5a1b3Sopenharmony_ci 316753a5a1b3Sopenharmony_ci u = pa_xnew(char, k+1); 316853a5a1b3Sopenharmony_ci 316953a5a1b3Sopenharmony_ci if (!(pa_get_user_name(u, k))) { 317053a5a1b3Sopenharmony_ci pa_xfree(u); 317153a5a1b3Sopenharmony_ci return NULL; 317253a5a1b3Sopenharmony_ci } 317353a5a1b3Sopenharmony_ci 317453a5a1b3Sopenharmony_ci return u; 317553a5a1b3Sopenharmony_ci} 317653a5a1b3Sopenharmony_ci 317753a5a1b3Sopenharmony_cichar *pa_get_host_name_malloc(void) { 317853a5a1b3Sopenharmony_ci size_t l; 317953a5a1b3Sopenharmony_ci 318053a5a1b3Sopenharmony_ci l = 100; 318153a5a1b3Sopenharmony_ci for (;;) { 318253a5a1b3Sopenharmony_ci char *c; 318353a5a1b3Sopenharmony_ci 318453a5a1b3Sopenharmony_ci c = pa_xmalloc(l); 318553a5a1b3Sopenharmony_ci 318653a5a1b3Sopenharmony_ci if (!pa_get_host_name(c, l)) { 318753a5a1b3Sopenharmony_ci 318853a5a1b3Sopenharmony_ci if (errno != EINVAL && errno != ENAMETOOLONG) 318953a5a1b3Sopenharmony_ci break; 319053a5a1b3Sopenharmony_ci 319153a5a1b3Sopenharmony_ci } else if (strlen(c) < l-1) { 319253a5a1b3Sopenharmony_ci char *u; 319353a5a1b3Sopenharmony_ci 319453a5a1b3Sopenharmony_ci if (*c == 0) { 319553a5a1b3Sopenharmony_ci pa_xfree(c); 319653a5a1b3Sopenharmony_ci break; 319753a5a1b3Sopenharmony_ci } 319853a5a1b3Sopenharmony_ci 319953a5a1b3Sopenharmony_ci u = pa_utf8_filter(c); 320053a5a1b3Sopenharmony_ci pa_xfree(c); 320153a5a1b3Sopenharmony_ci return u; 320253a5a1b3Sopenharmony_ci } 320353a5a1b3Sopenharmony_ci 320453a5a1b3Sopenharmony_ci /* Hmm, the hostname is as long the space we offered the 320553a5a1b3Sopenharmony_ci * function, we cannot know if it fully fit in, so let's play 320653a5a1b3Sopenharmony_ci * safe and retry. */ 320753a5a1b3Sopenharmony_ci 320853a5a1b3Sopenharmony_ci pa_xfree(c); 320953a5a1b3Sopenharmony_ci l *= 2; 321053a5a1b3Sopenharmony_ci } 321153a5a1b3Sopenharmony_ci 321253a5a1b3Sopenharmony_ci return NULL; 321353a5a1b3Sopenharmony_ci} 321453a5a1b3Sopenharmony_ci 321553a5a1b3Sopenharmony_cichar *pa_machine_id(void) { 321653a5a1b3Sopenharmony_ci FILE *f; 321753a5a1b3Sopenharmony_ci char *h; 321853a5a1b3Sopenharmony_ci 321953a5a1b3Sopenharmony_ci /* The returned value is supposed be some kind of ascii identifier 322053a5a1b3Sopenharmony_ci * that is unique and stable across reboots. First we try if the machine-id 322153a5a1b3Sopenharmony_ci * file is available. If it's available, that's great, since it provides an 322253a5a1b3Sopenharmony_ci * identifier that suits our needs perfectly. If it's not, we fall back to 322353a5a1b3Sopenharmony_ci * the hostname, which is not as good, since it can change over time. */ 322453a5a1b3Sopenharmony_ci 322553a5a1b3Sopenharmony_ci /* We search for the machine-id file from four locations. The first two are 322653a5a1b3Sopenharmony_ci * relative to the configured installation prefix, but if we're installed 322753a5a1b3Sopenharmony_ci * under /usr/local, for example, it's likely that the machine-id won't be 322853a5a1b3Sopenharmony_ci * found there, so we also try the hardcoded paths. 322953a5a1b3Sopenharmony_ci * 323053a5a1b3Sopenharmony_ci * PA_MACHINE_ID or PA_MACHINE_ID_FALLBACK might exist on a Windows system, 323153a5a1b3Sopenharmony_ci * but the last two hardcoded paths certainly don't, hence we don't try 323253a5a1b3Sopenharmony_ci * them on Windows. */ 323353a5a1b3Sopenharmony_ci if ((f = pa_fopen_cloexec(PA_MACHINE_ID, "r")) || 323453a5a1b3Sopenharmony_ci (f = pa_fopen_cloexec(PA_MACHINE_ID_FALLBACK, "r")) || 323553a5a1b3Sopenharmony_ci#if !defined(OS_IS_WIN32) 323653a5a1b3Sopenharmony_ci (f = pa_fopen_cloexec("/etc/machine-id", "r")) || 323753a5a1b3Sopenharmony_ci (f = pa_fopen_cloexec("/var/lib/dbus/machine-id", "r")) 323853a5a1b3Sopenharmony_ci#else 323953a5a1b3Sopenharmony_ci false 324053a5a1b3Sopenharmony_ci#endif 324153a5a1b3Sopenharmony_ci ) { 324253a5a1b3Sopenharmony_ci char ln[34] = "", *r; 324353a5a1b3Sopenharmony_ci 324453a5a1b3Sopenharmony_ci r = fgets(ln, sizeof(ln)-1, f); 324553a5a1b3Sopenharmony_ci fclose(f); 324653a5a1b3Sopenharmony_ci 324753a5a1b3Sopenharmony_ci pa_strip_nl(ln); 324853a5a1b3Sopenharmony_ci 324953a5a1b3Sopenharmony_ci if (r && ln[0]) 325053a5a1b3Sopenharmony_ci return pa_utf8_filter(ln); 325153a5a1b3Sopenharmony_ci } 325253a5a1b3Sopenharmony_ci 325353a5a1b3Sopenharmony_ci if ((h = pa_get_host_name_malloc())) 325453a5a1b3Sopenharmony_ci return h; 325553a5a1b3Sopenharmony_ci 325653a5a1b3Sopenharmony_ci#if !defined(OS_IS_WIN32) && !defined(__ANDROID__) 325753a5a1b3Sopenharmony_ci /* If no hostname was set we use the POSIX hostid. It's usually 325853a5a1b3Sopenharmony_ci * the IPv4 address. Might not be that stable. */ 325953a5a1b3Sopenharmony_ci return pa_sprintf_malloc("%08lx", (unsigned long) gethostid()); 326053a5a1b3Sopenharmony_ci#else 326153a5a1b3Sopenharmony_ci return NULL; 326253a5a1b3Sopenharmony_ci#endif 326353a5a1b3Sopenharmony_ci} 326453a5a1b3Sopenharmony_ci 326553a5a1b3Sopenharmony_cichar *pa_session_id(void) { 326653a5a1b3Sopenharmony_ci const char *e; 326753a5a1b3Sopenharmony_ci 326853a5a1b3Sopenharmony_ci e = getenv("XDG_SESSION_ID"); 326953a5a1b3Sopenharmony_ci if (!e) 327053a5a1b3Sopenharmony_ci return NULL; 327153a5a1b3Sopenharmony_ci 327253a5a1b3Sopenharmony_ci return pa_utf8_filter(e); 327353a5a1b3Sopenharmony_ci} 327453a5a1b3Sopenharmony_ci 327553a5a1b3Sopenharmony_cichar *pa_uname_string(void) { 327653a5a1b3Sopenharmony_ci#ifdef HAVE_UNAME 327753a5a1b3Sopenharmony_ci struct utsname u; 327853a5a1b3Sopenharmony_ci 327953a5a1b3Sopenharmony_ci pa_assert_se(uname(&u) >= 0); 328053a5a1b3Sopenharmony_ci 328153a5a1b3Sopenharmony_ci return pa_sprintf_malloc("%s %s %s %s", u.sysname, u.machine, u.release, u.version); 328253a5a1b3Sopenharmony_ci#endif 328353a5a1b3Sopenharmony_ci#ifdef OS_IS_WIN32 328453a5a1b3Sopenharmony_ci OSVERSIONINFO i; 328553a5a1b3Sopenharmony_ci 328653a5a1b3Sopenharmony_ci pa_zero(i); 328753a5a1b3Sopenharmony_ci i.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); 328853a5a1b3Sopenharmony_ci pa_assert_se(GetVersionEx(&i)); 328953a5a1b3Sopenharmony_ci 329053a5a1b3Sopenharmony_ci return pa_sprintf_malloc("Windows %lu.%lu (%lu) %s", i.dwMajorVersion, i.dwMinorVersion, i.dwBuildNumber, i.szCSDVersion); 329153a5a1b3Sopenharmony_ci#endif 329253a5a1b3Sopenharmony_ci} 329353a5a1b3Sopenharmony_ci 329453a5a1b3Sopenharmony_ci#ifdef HAVE_VALGRIND_MEMCHECK_H 329553a5a1b3Sopenharmony_cibool pa_in_valgrind(void) { 329653a5a1b3Sopenharmony_ci static int b = 0; 329753a5a1b3Sopenharmony_ci 329853a5a1b3Sopenharmony_ci /* To make heisenbugs a bit simpler to find we check for $VALGRIND 329953a5a1b3Sopenharmony_ci * here instead of really checking whether we run in valgrind or 330053a5a1b3Sopenharmony_ci * not. */ 330153a5a1b3Sopenharmony_ci 330253a5a1b3Sopenharmony_ci if (b < 1) 330353a5a1b3Sopenharmony_ci b = getenv("VALGRIND") ? 2 : 1; 330453a5a1b3Sopenharmony_ci 330553a5a1b3Sopenharmony_ci return b > 1; 330653a5a1b3Sopenharmony_ci} 330753a5a1b3Sopenharmony_ci#endif 330853a5a1b3Sopenharmony_ci 330953a5a1b3Sopenharmony_ciunsigned pa_gcd(unsigned a, unsigned b) { 331053a5a1b3Sopenharmony_ci 331153a5a1b3Sopenharmony_ci while (b > 0) { 331253a5a1b3Sopenharmony_ci unsigned t = b; 331353a5a1b3Sopenharmony_ci b = a % b; 331453a5a1b3Sopenharmony_ci a = t; 331553a5a1b3Sopenharmony_ci } 331653a5a1b3Sopenharmony_ci 331753a5a1b3Sopenharmony_ci return a; 331853a5a1b3Sopenharmony_ci} 331953a5a1b3Sopenharmony_ci 332053a5a1b3Sopenharmony_civoid pa_reduce(unsigned *num, unsigned *den) { 332153a5a1b3Sopenharmony_ci 332253a5a1b3Sopenharmony_ci unsigned gcd = pa_gcd(*num, *den); 332353a5a1b3Sopenharmony_ci 332453a5a1b3Sopenharmony_ci if (gcd <= 0) 332553a5a1b3Sopenharmony_ci return; 332653a5a1b3Sopenharmony_ci 332753a5a1b3Sopenharmony_ci *num /= gcd; 332853a5a1b3Sopenharmony_ci *den /= gcd; 332953a5a1b3Sopenharmony_ci 333053a5a1b3Sopenharmony_ci pa_assert(pa_gcd(*num, *den) == 1); 333153a5a1b3Sopenharmony_ci} 333253a5a1b3Sopenharmony_ci 333353a5a1b3Sopenharmony_ciunsigned pa_ncpus(void) { 333453a5a1b3Sopenharmony_ci long ncpus; 333553a5a1b3Sopenharmony_ci 333653a5a1b3Sopenharmony_ci#ifdef _SC_NPROCESSORS_ONLN 333753a5a1b3Sopenharmony_ci ncpus = sysconf(_SC_NPROCESSORS_ONLN); 333853a5a1b3Sopenharmony_ci#else 333953a5a1b3Sopenharmony_ci ncpus = 1; 334053a5a1b3Sopenharmony_ci#endif 334153a5a1b3Sopenharmony_ci 334253a5a1b3Sopenharmony_ci return ncpus <= 0 ? 1 : (unsigned) ncpus; 334353a5a1b3Sopenharmony_ci} 334453a5a1b3Sopenharmony_ci 334553a5a1b3Sopenharmony_cichar *pa_replace(const char*s, const char*a, const char *b) { 334653a5a1b3Sopenharmony_ci pa_strbuf *sb; 334753a5a1b3Sopenharmony_ci size_t an; 334853a5a1b3Sopenharmony_ci 334953a5a1b3Sopenharmony_ci pa_assert(s); 335053a5a1b3Sopenharmony_ci pa_assert(a); 335153a5a1b3Sopenharmony_ci pa_assert(*a); 335253a5a1b3Sopenharmony_ci pa_assert(b); 335353a5a1b3Sopenharmony_ci 335453a5a1b3Sopenharmony_ci an = strlen(a); 335553a5a1b3Sopenharmony_ci sb = pa_strbuf_new(); 335653a5a1b3Sopenharmony_ci 335753a5a1b3Sopenharmony_ci for (;;) { 335853a5a1b3Sopenharmony_ci const char *p; 335953a5a1b3Sopenharmony_ci 336053a5a1b3Sopenharmony_ci if (!(p = strstr(s, a))) 336153a5a1b3Sopenharmony_ci break; 336253a5a1b3Sopenharmony_ci 336353a5a1b3Sopenharmony_ci pa_strbuf_putsn(sb, s, p-s); 336453a5a1b3Sopenharmony_ci pa_strbuf_puts(sb, b); 336553a5a1b3Sopenharmony_ci s = p + an; 336653a5a1b3Sopenharmony_ci } 336753a5a1b3Sopenharmony_ci 336853a5a1b3Sopenharmony_ci pa_strbuf_puts(sb, s); 336953a5a1b3Sopenharmony_ci 337053a5a1b3Sopenharmony_ci return pa_strbuf_to_string_free(sb); 337153a5a1b3Sopenharmony_ci} 337253a5a1b3Sopenharmony_ci 337353a5a1b3Sopenharmony_cichar *pa_escape(const char *p, const char *chars) { 337453a5a1b3Sopenharmony_ci const char *s; 337553a5a1b3Sopenharmony_ci const char *c; 337653a5a1b3Sopenharmony_ci char *out_string, *output; 337753a5a1b3Sopenharmony_ci int char_count = strlen(p); 337853a5a1b3Sopenharmony_ci 337953a5a1b3Sopenharmony_ci /* Maximum number of characters in output string 338053a5a1b3Sopenharmony_ci * including trailing 0. */ 338153a5a1b3Sopenharmony_ci char_count = 2 * char_count + 1; 338253a5a1b3Sopenharmony_ci 338353a5a1b3Sopenharmony_ci /* allocate output string */ 338453a5a1b3Sopenharmony_ci out_string = pa_xmalloc(char_count); 338553a5a1b3Sopenharmony_ci output = out_string; 338653a5a1b3Sopenharmony_ci 338753a5a1b3Sopenharmony_ci /* write output string */ 338853a5a1b3Sopenharmony_ci for (s = p; *s; ++s) { 338953a5a1b3Sopenharmony_ci if (*s == '\\') 339053a5a1b3Sopenharmony_ci *output++ = '\\'; 339153a5a1b3Sopenharmony_ci else if (chars) { 339253a5a1b3Sopenharmony_ci for (c = chars; *c; ++c) { 339353a5a1b3Sopenharmony_ci if (*s == *c) { 339453a5a1b3Sopenharmony_ci *output++ = '\\'; 339553a5a1b3Sopenharmony_ci break; 339653a5a1b3Sopenharmony_ci } 339753a5a1b3Sopenharmony_ci } 339853a5a1b3Sopenharmony_ci } 339953a5a1b3Sopenharmony_ci *output++ = *s; 340053a5a1b3Sopenharmony_ci } 340153a5a1b3Sopenharmony_ci 340253a5a1b3Sopenharmony_ci *output = 0; 340353a5a1b3Sopenharmony_ci 340453a5a1b3Sopenharmony_ci /* Remove trailing garbage */ 340553a5a1b3Sopenharmony_ci output = pa_xstrdup(out_string); 340653a5a1b3Sopenharmony_ci 340753a5a1b3Sopenharmony_ci pa_xfree(out_string); 340853a5a1b3Sopenharmony_ci return output; 340953a5a1b3Sopenharmony_ci} 341053a5a1b3Sopenharmony_ci 341153a5a1b3Sopenharmony_cichar *pa_unescape(char *p) { 341253a5a1b3Sopenharmony_ci char *s, *d; 341353a5a1b3Sopenharmony_ci bool escaped = false; 341453a5a1b3Sopenharmony_ci 341553a5a1b3Sopenharmony_ci for (s = p, d = p; *s; s++) { 341653a5a1b3Sopenharmony_ci if (!escaped && *s == '\\') { 341753a5a1b3Sopenharmony_ci escaped = true; 341853a5a1b3Sopenharmony_ci continue; 341953a5a1b3Sopenharmony_ci } 342053a5a1b3Sopenharmony_ci 342153a5a1b3Sopenharmony_ci *(d++) = *s; 342253a5a1b3Sopenharmony_ci escaped = false; 342353a5a1b3Sopenharmony_ci } 342453a5a1b3Sopenharmony_ci 342553a5a1b3Sopenharmony_ci *d = 0; 342653a5a1b3Sopenharmony_ci 342753a5a1b3Sopenharmony_ci return p; 342853a5a1b3Sopenharmony_ci} 342953a5a1b3Sopenharmony_ci 343053a5a1b3Sopenharmony_cichar *pa_realpath(const char *path) { 343153a5a1b3Sopenharmony_ci char *t; 343253a5a1b3Sopenharmony_ci pa_assert(path); 343353a5a1b3Sopenharmony_ci 343453a5a1b3Sopenharmony_ci /* We want only absolute paths */ 343553a5a1b3Sopenharmony_ci if (path[0] != '/') { 343653a5a1b3Sopenharmony_ci errno = EINVAL; 343753a5a1b3Sopenharmony_ci return NULL; 343853a5a1b3Sopenharmony_ci } 343953a5a1b3Sopenharmony_ci 344053a5a1b3Sopenharmony_ci#if defined(__GLIBC__) 344153a5a1b3Sopenharmony_ci { 344253a5a1b3Sopenharmony_ci char *r; 344353a5a1b3Sopenharmony_ci 344453a5a1b3Sopenharmony_ci if (!(r = realpath(path, NULL))) 344553a5a1b3Sopenharmony_ci return NULL; 344653a5a1b3Sopenharmony_ci 344753a5a1b3Sopenharmony_ci /* We copy this here in case our pa_xmalloc() is not 344853a5a1b3Sopenharmony_ci * implemented on top of libc malloc() */ 344953a5a1b3Sopenharmony_ci t = pa_xstrdup(r); 345053a5a1b3Sopenharmony_ci pa_xfree(r); 345153a5a1b3Sopenharmony_ci } 345253a5a1b3Sopenharmony_ci#elif defined(PATH_MAX) 345353a5a1b3Sopenharmony_ci { 345453a5a1b3Sopenharmony_ci char *path_buf; 345553a5a1b3Sopenharmony_ci path_buf = pa_xmalloc(PATH_MAX); 345653a5a1b3Sopenharmony_ci 345753a5a1b3Sopenharmony_ci#if defined(OS_IS_WIN32) 345853a5a1b3Sopenharmony_ci if (!(t = _fullpath(path_buf, path, _MAX_PATH))) { 345953a5a1b3Sopenharmony_ci pa_xfree(path_buf); 346053a5a1b3Sopenharmony_ci return NULL; 346153a5a1b3Sopenharmony_ci } 346253a5a1b3Sopenharmony_ci#else 346353a5a1b3Sopenharmony_ci if (!(t = realpath(path, path_buf))) { 346453a5a1b3Sopenharmony_ci pa_xfree(path_buf); 346553a5a1b3Sopenharmony_ci return NULL; 346653a5a1b3Sopenharmony_ci } 346753a5a1b3Sopenharmony_ci#endif 346853a5a1b3Sopenharmony_ci } 346953a5a1b3Sopenharmony_ci#else 347053a5a1b3Sopenharmony_ci#error "It's not clear whether this system supports realpath(..., NULL) like GNU libc does. If it doesn't we need a private version of realpath() here." 347153a5a1b3Sopenharmony_ci#endif 347253a5a1b3Sopenharmony_ci 347353a5a1b3Sopenharmony_ci return t; 347453a5a1b3Sopenharmony_ci} 347553a5a1b3Sopenharmony_ci 347653a5a1b3Sopenharmony_civoid pa_disable_sigpipe(void) { 347753a5a1b3Sopenharmony_ci 347853a5a1b3Sopenharmony_ci#ifdef SIGPIPE 347953a5a1b3Sopenharmony_ci struct sigaction sa; 348053a5a1b3Sopenharmony_ci 348153a5a1b3Sopenharmony_ci pa_zero(sa); 348253a5a1b3Sopenharmony_ci 348353a5a1b3Sopenharmony_ci if (sigaction(SIGPIPE, NULL, &sa) < 0) { 348453a5a1b3Sopenharmony_ci pa_log("sigaction(): %s", pa_cstrerror(errno)); 348553a5a1b3Sopenharmony_ci return; 348653a5a1b3Sopenharmony_ci } 348753a5a1b3Sopenharmony_ci 348853a5a1b3Sopenharmony_ci sa.sa_handler = SIG_IGN; 348953a5a1b3Sopenharmony_ci 349053a5a1b3Sopenharmony_ci if (sigaction(SIGPIPE, &sa, NULL) < 0) { 349153a5a1b3Sopenharmony_ci pa_log("sigaction(): %s", pa_cstrerror(errno)); 349253a5a1b3Sopenharmony_ci return; 349353a5a1b3Sopenharmony_ci } 349453a5a1b3Sopenharmony_ci#endif 349553a5a1b3Sopenharmony_ci} 349653a5a1b3Sopenharmony_ci 349753a5a1b3Sopenharmony_civoid pa_xfreev(void**a) { 349853a5a1b3Sopenharmony_ci void **p; 349953a5a1b3Sopenharmony_ci 350053a5a1b3Sopenharmony_ci if (!a) 350153a5a1b3Sopenharmony_ci return; 350253a5a1b3Sopenharmony_ci 350353a5a1b3Sopenharmony_ci for (p = a; *p; p++) 350453a5a1b3Sopenharmony_ci pa_xfree(*p); 350553a5a1b3Sopenharmony_ci 350653a5a1b3Sopenharmony_ci pa_xfree(a); 350753a5a1b3Sopenharmony_ci} 350853a5a1b3Sopenharmony_ci 350953a5a1b3Sopenharmony_cichar **pa_split_spaces_strv(const char *s) { 351053a5a1b3Sopenharmony_ci char **t, *e; 351153a5a1b3Sopenharmony_ci unsigned i = 0, n = 8; 351253a5a1b3Sopenharmony_ci const char *state = NULL; 351353a5a1b3Sopenharmony_ci 351453a5a1b3Sopenharmony_ci t = pa_xnew(char*, n); 351553a5a1b3Sopenharmony_ci while ((e = pa_split_spaces(s, &state))) { 351653a5a1b3Sopenharmony_ci t[i++] = e; 351753a5a1b3Sopenharmony_ci 351853a5a1b3Sopenharmony_ci if (i >= n) { 351953a5a1b3Sopenharmony_ci n *= 2; 352053a5a1b3Sopenharmony_ci t = pa_xrenew(char*, t, n); 352153a5a1b3Sopenharmony_ci } 352253a5a1b3Sopenharmony_ci } 352353a5a1b3Sopenharmony_ci 352453a5a1b3Sopenharmony_ci if (i <= 0) { 352553a5a1b3Sopenharmony_ci pa_xfree(t); 352653a5a1b3Sopenharmony_ci return NULL; 352753a5a1b3Sopenharmony_ci } 352853a5a1b3Sopenharmony_ci 352953a5a1b3Sopenharmony_ci t[i] = NULL; 353053a5a1b3Sopenharmony_ci return t; 353153a5a1b3Sopenharmony_ci} 353253a5a1b3Sopenharmony_ci 353353a5a1b3Sopenharmony_cichar* pa_maybe_prefix_path(const char *path, const char *prefix) { 353453a5a1b3Sopenharmony_ci pa_assert(path); 353553a5a1b3Sopenharmony_ci 353653a5a1b3Sopenharmony_ci if (pa_is_path_absolute(path)) 353753a5a1b3Sopenharmony_ci return pa_xstrdup(path); 353853a5a1b3Sopenharmony_ci 353953a5a1b3Sopenharmony_ci return pa_sprintf_malloc("%s" PA_PATH_SEP "%s", prefix, path); 354053a5a1b3Sopenharmony_ci} 354153a5a1b3Sopenharmony_ci 354253a5a1b3Sopenharmony_cisize_t pa_pipe_buf(int fd) { 354353a5a1b3Sopenharmony_ci 354453a5a1b3Sopenharmony_ci#ifdef _PC_PIPE_BUF 354553a5a1b3Sopenharmony_ci long n; 354653a5a1b3Sopenharmony_ci 354753a5a1b3Sopenharmony_ci if ((n = fpathconf(fd, _PC_PIPE_BUF)) >= 0) 354853a5a1b3Sopenharmony_ci return (size_t) n; 354953a5a1b3Sopenharmony_ci#endif 355053a5a1b3Sopenharmony_ci 355153a5a1b3Sopenharmony_ci#ifdef PIPE_BUF 355253a5a1b3Sopenharmony_ci return PIPE_BUF; 355353a5a1b3Sopenharmony_ci#else 355453a5a1b3Sopenharmony_ci return 4096; 355553a5a1b3Sopenharmony_ci#endif 355653a5a1b3Sopenharmony_ci} 355753a5a1b3Sopenharmony_ci 355853a5a1b3Sopenharmony_civoid pa_reset_personality(void) { 355953a5a1b3Sopenharmony_ci 356053a5a1b3Sopenharmony_ci#if defined(__linux__) && !defined(__ANDROID__) 356153a5a1b3Sopenharmony_ci if (personality(PER_LINUX) < 0) 356253a5a1b3Sopenharmony_ci pa_log_warn("Uh, personality() failed: %s", pa_cstrerror(errno)); 356353a5a1b3Sopenharmony_ci#endif 356453a5a1b3Sopenharmony_ci 356553a5a1b3Sopenharmony_ci} 356653a5a1b3Sopenharmony_ci 356753a5a1b3Sopenharmony_cibool pa_run_from_build_tree(void) { 356853a5a1b3Sopenharmony_ci static bool b = false; 356953a5a1b3Sopenharmony_ci 357053a5a1b3Sopenharmony_ci#ifdef HAVE_RUNNING_FROM_BUILD_TREE 357153a5a1b3Sopenharmony_ci char *rp; 357253a5a1b3Sopenharmony_ci PA_ONCE_BEGIN { 357353a5a1b3Sopenharmony_ci if ((rp = pa_readlink("/proc/self/exe"))) { 357453a5a1b3Sopenharmony_ci b = pa_startswith(rp, PA_BUILDDIR); 357553a5a1b3Sopenharmony_ci pa_xfree(rp); 357653a5a1b3Sopenharmony_ci } 357753a5a1b3Sopenharmony_ci } PA_ONCE_END; 357853a5a1b3Sopenharmony_ci#endif 357953a5a1b3Sopenharmony_ci 358053a5a1b3Sopenharmony_ci return b; 358153a5a1b3Sopenharmony_ci} 358253a5a1b3Sopenharmony_ci 358353a5a1b3Sopenharmony_ciconst char *pa_get_temp_dir(void) { 358453a5a1b3Sopenharmony_ci const char *t; 358553a5a1b3Sopenharmony_ci 358653a5a1b3Sopenharmony_ci if ((t = getenv("TMPDIR")) && 358753a5a1b3Sopenharmony_ci pa_is_path_absolute(t)) 358853a5a1b3Sopenharmony_ci return t; 358953a5a1b3Sopenharmony_ci 359053a5a1b3Sopenharmony_ci if ((t = getenv("TMP")) && 359153a5a1b3Sopenharmony_ci pa_is_path_absolute(t)) 359253a5a1b3Sopenharmony_ci return t; 359353a5a1b3Sopenharmony_ci 359453a5a1b3Sopenharmony_ci if ((t = getenv("TEMP")) && 359553a5a1b3Sopenharmony_ci pa_is_path_absolute(t)) 359653a5a1b3Sopenharmony_ci return t; 359753a5a1b3Sopenharmony_ci 359853a5a1b3Sopenharmony_ci if ((t = getenv("TEMPDIR")) && 359953a5a1b3Sopenharmony_ci pa_is_path_absolute(t)) 360053a5a1b3Sopenharmony_ci return t; 360153a5a1b3Sopenharmony_ci 360253a5a1b3Sopenharmony_ci return "/tmp"; 360353a5a1b3Sopenharmony_ci} 360453a5a1b3Sopenharmony_ci 360553a5a1b3Sopenharmony_ciint pa_open_cloexec(const char *fn, int flags, mode_t mode) { 360653a5a1b3Sopenharmony_ci int fd; 360753a5a1b3Sopenharmony_ci 360853a5a1b3Sopenharmony_ci#ifdef O_NOCTTY 360953a5a1b3Sopenharmony_ci flags |= O_NOCTTY; 361053a5a1b3Sopenharmony_ci#endif 361153a5a1b3Sopenharmony_ci 361253a5a1b3Sopenharmony_ci#ifdef O_CLOEXEC 361353a5a1b3Sopenharmony_ci if ((fd = open(fn, flags|O_CLOEXEC, mode)) >= 0) 361453a5a1b3Sopenharmony_ci goto finish; 361553a5a1b3Sopenharmony_ci 361653a5a1b3Sopenharmony_ci if (errno != EINVAL) 361753a5a1b3Sopenharmony_ci return fd; 361853a5a1b3Sopenharmony_ci#endif 361953a5a1b3Sopenharmony_ci 362053a5a1b3Sopenharmony_ci if ((fd = open(fn, flags, mode)) >= 0) 362153a5a1b3Sopenharmony_ci goto finish; 362253a5a1b3Sopenharmony_ci 362353a5a1b3Sopenharmony_ci /* return error */ 362453a5a1b3Sopenharmony_ci return fd; 362553a5a1b3Sopenharmony_ci 362653a5a1b3Sopenharmony_cifinish: 362753a5a1b3Sopenharmony_ci /* Some implementations might simply ignore O_CLOEXEC if it is not 362853a5a1b3Sopenharmony_ci * understood, make sure FD_CLOEXEC is enabled anyway */ 362953a5a1b3Sopenharmony_ci 363053a5a1b3Sopenharmony_ci pa_make_fd_cloexec(fd); 363153a5a1b3Sopenharmony_ci return fd; 363253a5a1b3Sopenharmony_ci} 363353a5a1b3Sopenharmony_ci 363453a5a1b3Sopenharmony_ciint pa_socket_cloexec(int domain, int type, int protocol) { 363553a5a1b3Sopenharmony_ci int fd; 363653a5a1b3Sopenharmony_ci 363753a5a1b3Sopenharmony_ci#ifdef SOCK_CLOEXEC 363853a5a1b3Sopenharmony_ci if ((fd = socket(domain, type | SOCK_CLOEXEC, protocol)) >= 0) 363953a5a1b3Sopenharmony_ci goto finish; 364053a5a1b3Sopenharmony_ci 364153a5a1b3Sopenharmony_ci if (errno != EINVAL) 364253a5a1b3Sopenharmony_ci return fd; 364353a5a1b3Sopenharmony_ci#endif 364453a5a1b3Sopenharmony_ci 364553a5a1b3Sopenharmony_ci if ((fd = socket(domain, type, protocol)) >= 0) 364653a5a1b3Sopenharmony_ci goto finish; 364753a5a1b3Sopenharmony_ci 364853a5a1b3Sopenharmony_ci /* return error */ 364953a5a1b3Sopenharmony_ci return fd; 365053a5a1b3Sopenharmony_ci 365153a5a1b3Sopenharmony_cifinish: 365253a5a1b3Sopenharmony_ci /* Some implementations might simply ignore SOCK_CLOEXEC if it is 365353a5a1b3Sopenharmony_ci * not understood, make sure FD_CLOEXEC is enabled anyway */ 365453a5a1b3Sopenharmony_ci 365553a5a1b3Sopenharmony_ci pa_make_fd_cloexec(fd); 365653a5a1b3Sopenharmony_ci return fd; 365753a5a1b3Sopenharmony_ci} 365853a5a1b3Sopenharmony_ci 365953a5a1b3Sopenharmony_ciint pa_pipe_cloexec(int pipefd[2]) { 366053a5a1b3Sopenharmony_ci int r; 366153a5a1b3Sopenharmony_ci 366253a5a1b3Sopenharmony_ci#ifdef HAVE_PIPE2 366353a5a1b3Sopenharmony_ci if ((r = pipe2(pipefd, O_CLOEXEC)) >= 0) 366453a5a1b3Sopenharmony_ci goto finish; 366553a5a1b3Sopenharmony_ci 366653a5a1b3Sopenharmony_ci if (errno == EMFILE) { 366753a5a1b3Sopenharmony_ci pa_log_error("The per-process limit on the number of open file descriptors has been reached."); 366853a5a1b3Sopenharmony_ci return r; 366953a5a1b3Sopenharmony_ci } 367053a5a1b3Sopenharmony_ci 367153a5a1b3Sopenharmony_ci if (errno == ENFILE) { 367253a5a1b3Sopenharmony_ci pa_log_error("The system-wide limit on the total number of open files has been reached."); 367353a5a1b3Sopenharmony_ci return r; 367453a5a1b3Sopenharmony_ci } 367553a5a1b3Sopenharmony_ci 367653a5a1b3Sopenharmony_ci if (errno != EINVAL && errno != ENOSYS) 367753a5a1b3Sopenharmony_ci return r; 367853a5a1b3Sopenharmony_ci 367953a5a1b3Sopenharmony_ci#endif 368053a5a1b3Sopenharmony_ci 368153a5a1b3Sopenharmony_ci if ((r = pipe(pipefd)) >= 0) 368253a5a1b3Sopenharmony_ci goto finish; 368353a5a1b3Sopenharmony_ci 368453a5a1b3Sopenharmony_ci if (errno == EMFILE) { 368553a5a1b3Sopenharmony_ci pa_log_error("The per-process limit on the number of open file descriptors has been reached."); 368653a5a1b3Sopenharmony_ci return r; 368753a5a1b3Sopenharmony_ci } 368853a5a1b3Sopenharmony_ci 368953a5a1b3Sopenharmony_ci if (errno == ENFILE) { 369053a5a1b3Sopenharmony_ci pa_log_error("The system-wide limit on the total number of open files has been reached."); 369153a5a1b3Sopenharmony_ci return r; 369253a5a1b3Sopenharmony_ci } 369353a5a1b3Sopenharmony_ci 369453a5a1b3Sopenharmony_ci /* return error */ 369553a5a1b3Sopenharmony_ci return r; 369653a5a1b3Sopenharmony_ci 369753a5a1b3Sopenharmony_cifinish: 369853a5a1b3Sopenharmony_ci pa_make_fd_cloexec(pipefd[0]); 369953a5a1b3Sopenharmony_ci pa_make_fd_cloexec(pipefd[1]); 370053a5a1b3Sopenharmony_ci 370153a5a1b3Sopenharmony_ci return 0; 370253a5a1b3Sopenharmony_ci} 370353a5a1b3Sopenharmony_ci 370453a5a1b3Sopenharmony_ciint pa_accept_cloexec(int sockfd, struct sockaddr *addr, socklen_t *addrlen) { 370553a5a1b3Sopenharmony_ci int fd; 370653a5a1b3Sopenharmony_ci 370753a5a1b3Sopenharmony_ci errno = 0; 370853a5a1b3Sopenharmony_ci 370953a5a1b3Sopenharmony_ci#ifdef HAVE_ACCEPT4 371053a5a1b3Sopenharmony_ci if ((fd = accept4(sockfd, addr, addrlen, SOCK_CLOEXEC)) >= 0) 371153a5a1b3Sopenharmony_ci goto finish; 371253a5a1b3Sopenharmony_ci 371353a5a1b3Sopenharmony_ci if (errno != EINVAL && errno != ENOSYS) 371453a5a1b3Sopenharmony_ci return fd; 371553a5a1b3Sopenharmony_ci 371653a5a1b3Sopenharmony_ci#endif 371753a5a1b3Sopenharmony_ci 371853a5a1b3Sopenharmony_ci#ifdef HAVE_PACCEPT 371953a5a1b3Sopenharmony_ci if ((fd = paccept(sockfd, addr, addrlen, NULL, SOCK_CLOEXEC)) >= 0) 372053a5a1b3Sopenharmony_ci goto finish; 372153a5a1b3Sopenharmony_ci#endif 372253a5a1b3Sopenharmony_ci 372353a5a1b3Sopenharmony_ci if ((fd = accept(sockfd, addr, addrlen)) >= 0) 372453a5a1b3Sopenharmony_ci goto finish; 372553a5a1b3Sopenharmony_ci 372653a5a1b3Sopenharmony_ci /* return error */ 372753a5a1b3Sopenharmony_ci return fd; 372853a5a1b3Sopenharmony_ci 372953a5a1b3Sopenharmony_cifinish: 373053a5a1b3Sopenharmony_ci pa_make_fd_cloexec(fd); 373153a5a1b3Sopenharmony_ci return fd; 373253a5a1b3Sopenharmony_ci} 373353a5a1b3Sopenharmony_ci 373453a5a1b3Sopenharmony_ciFILE* pa_fopen_cloexec(const char *path, const char *mode) { 373553a5a1b3Sopenharmony_ci FILE *f; 373653a5a1b3Sopenharmony_ci char *m; 373753a5a1b3Sopenharmony_ci 373853a5a1b3Sopenharmony_ci m = pa_sprintf_malloc("%se", mode); 373953a5a1b3Sopenharmony_ci 374053a5a1b3Sopenharmony_ci errno = 0; 374153a5a1b3Sopenharmony_ci if ((f = fopen(path, m))) { 374253a5a1b3Sopenharmony_ci pa_xfree(m); 374353a5a1b3Sopenharmony_ci goto finish; 374453a5a1b3Sopenharmony_ci } 374553a5a1b3Sopenharmony_ci 374653a5a1b3Sopenharmony_ci pa_xfree(m); 374753a5a1b3Sopenharmony_ci 374853a5a1b3Sopenharmony_ci if (errno != EINVAL) 374953a5a1b3Sopenharmony_ci return NULL; 375053a5a1b3Sopenharmony_ci 375153a5a1b3Sopenharmony_ci if (!(f = fopen(path, mode))) 375253a5a1b3Sopenharmony_ci return NULL; 375353a5a1b3Sopenharmony_ci 375453a5a1b3Sopenharmony_cifinish: 375553a5a1b3Sopenharmony_ci pa_make_fd_cloexec(fileno(f)); 375653a5a1b3Sopenharmony_ci return f; 375753a5a1b3Sopenharmony_ci} 375853a5a1b3Sopenharmony_ci 375953a5a1b3Sopenharmony_civoid pa_nullify_stdfds(void) { 376053a5a1b3Sopenharmony_ci 376153a5a1b3Sopenharmony_ci#ifndef OS_IS_WIN32 376253a5a1b3Sopenharmony_ci pa_close(STDIN_FILENO); 376353a5a1b3Sopenharmony_ci pa_close(STDOUT_FILENO); 376453a5a1b3Sopenharmony_ci pa_close(STDERR_FILENO); 376553a5a1b3Sopenharmony_ci 376653a5a1b3Sopenharmony_ci pa_assert_se(open("/dev/null", O_RDONLY) == STDIN_FILENO); 376753a5a1b3Sopenharmony_ci pa_assert_se(open("/dev/null", O_WRONLY) == STDOUT_FILENO); 376853a5a1b3Sopenharmony_ci pa_assert_se(open("/dev/null", O_WRONLY) == STDERR_FILENO); 376953a5a1b3Sopenharmony_ci#else 377053a5a1b3Sopenharmony_ci FreeConsole(); 377153a5a1b3Sopenharmony_ci#endif 377253a5a1b3Sopenharmony_ci 377353a5a1b3Sopenharmony_ci} 377453a5a1b3Sopenharmony_ci 377553a5a1b3Sopenharmony_cichar *pa_read_line_from_file(const char *fn) { 377653a5a1b3Sopenharmony_ci FILE *f; 377753a5a1b3Sopenharmony_ci char ln[256] = "", *r; 377853a5a1b3Sopenharmony_ci 377953a5a1b3Sopenharmony_ci if (!(f = pa_fopen_cloexec(fn, "r"))) 378053a5a1b3Sopenharmony_ci return NULL; 378153a5a1b3Sopenharmony_ci 378253a5a1b3Sopenharmony_ci r = fgets(ln, sizeof(ln)-1, f); 378353a5a1b3Sopenharmony_ci fclose(f); 378453a5a1b3Sopenharmony_ci 378553a5a1b3Sopenharmony_ci if (!r) { 378653a5a1b3Sopenharmony_ci errno = EIO; 378753a5a1b3Sopenharmony_ci return NULL; 378853a5a1b3Sopenharmony_ci } 378953a5a1b3Sopenharmony_ci 379053a5a1b3Sopenharmony_ci pa_strip_nl(ln); 379153a5a1b3Sopenharmony_ci return pa_xstrdup(ln); 379253a5a1b3Sopenharmony_ci} 379353a5a1b3Sopenharmony_ci 379453a5a1b3Sopenharmony_cibool pa_running_in_vm(void) { 379553a5a1b3Sopenharmony_ci 379653a5a1b3Sopenharmony_ci#if defined(__i386__) || defined(__x86_64__) 379753a5a1b3Sopenharmony_ci 379853a5a1b3Sopenharmony_ci /* Both CPUID and DMI are x86 specific interfaces... */ 379953a5a1b3Sopenharmony_ci 380053a5a1b3Sopenharmony_ci#ifdef HAVE_CPUID_H 380153a5a1b3Sopenharmony_ci unsigned int eax, ebx, ecx, edx; 380253a5a1b3Sopenharmony_ci#endif 380353a5a1b3Sopenharmony_ci 380453a5a1b3Sopenharmony_ci#ifdef __linux__ 380553a5a1b3Sopenharmony_ci const char *const dmi_vendors[] = { 380653a5a1b3Sopenharmony_ci "/sys/class/dmi/id/sys_vendor", 380753a5a1b3Sopenharmony_ci "/sys/class/dmi/id/board_vendor", 380853a5a1b3Sopenharmony_ci "/sys/class/dmi/id/bios_vendor" 380953a5a1b3Sopenharmony_ci }; 381053a5a1b3Sopenharmony_ci 381153a5a1b3Sopenharmony_ci unsigned i; 381253a5a1b3Sopenharmony_ci 381353a5a1b3Sopenharmony_ci for (i = 0; i < PA_ELEMENTSOF(dmi_vendors); i++) { 381453a5a1b3Sopenharmony_ci char *s; 381553a5a1b3Sopenharmony_ci 381653a5a1b3Sopenharmony_ci if ((s = pa_read_line_from_file(dmi_vendors[i]))) { 381753a5a1b3Sopenharmony_ci 381853a5a1b3Sopenharmony_ci if (pa_startswith(s, "QEMU") || 381953a5a1b3Sopenharmony_ci /* http://kb.vmware.com/selfservice/microsites/search.do?language=en_US&cmd=displayKC&externalId=1009458 */ 382053a5a1b3Sopenharmony_ci pa_startswith(s, "VMware") || 382153a5a1b3Sopenharmony_ci pa_startswith(s, "VMW") || 382253a5a1b3Sopenharmony_ci pa_startswith(s, "Microsoft Corporation") || 382353a5a1b3Sopenharmony_ci pa_startswith(s, "innotek GmbH") || 382453a5a1b3Sopenharmony_ci pa_startswith(s, "Xen")) { 382553a5a1b3Sopenharmony_ci 382653a5a1b3Sopenharmony_ci pa_xfree(s); 382753a5a1b3Sopenharmony_ci return true; 382853a5a1b3Sopenharmony_ci } 382953a5a1b3Sopenharmony_ci 383053a5a1b3Sopenharmony_ci pa_xfree(s); 383153a5a1b3Sopenharmony_ci } 383253a5a1b3Sopenharmony_ci } 383353a5a1b3Sopenharmony_ci 383453a5a1b3Sopenharmony_ci#endif 383553a5a1b3Sopenharmony_ci 383653a5a1b3Sopenharmony_ci#ifdef HAVE_CPUID_H 383753a5a1b3Sopenharmony_ci 383853a5a1b3Sopenharmony_ci /* Hypervisors provide presence on 0x1 cpuid leaf. 383953a5a1b3Sopenharmony_ci * http://lwn.net/Articles/301888/ */ 384053a5a1b3Sopenharmony_ci if (__get_cpuid(1, &eax, &ebx, &ecx, &edx) == 0) 384153a5a1b3Sopenharmony_ci return false; 384253a5a1b3Sopenharmony_ci 384353a5a1b3Sopenharmony_ci if (ecx & 0x80000000) 384453a5a1b3Sopenharmony_ci return true; 384553a5a1b3Sopenharmony_ci 384653a5a1b3Sopenharmony_ci#endif /* HAVE_CPUID_H */ 384753a5a1b3Sopenharmony_ci 384853a5a1b3Sopenharmony_ci#endif /* defined(__i386__) || defined(__x86_64__) */ 384953a5a1b3Sopenharmony_ci 385053a5a1b3Sopenharmony_ci return false; 385153a5a1b3Sopenharmony_ci} 385253a5a1b3Sopenharmony_ci 385353a5a1b3Sopenharmony_cisize_t pa_page_size(void) { 385453a5a1b3Sopenharmony_ci#if defined(PAGE_SIZE) 385553a5a1b3Sopenharmony_ci return PAGE_SIZE; 385653a5a1b3Sopenharmony_ci#elif defined(PAGESIZE) 385753a5a1b3Sopenharmony_ci return PAGESIZE; 385853a5a1b3Sopenharmony_ci#elif defined(HAVE_SYSCONF) 385953a5a1b3Sopenharmony_ci static size_t page_size = 4096; /* Let's hope it's like x86. */ 386053a5a1b3Sopenharmony_ci 386153a5a1b3Sopenharmony_ci PA_ONCE_BEGIN { 386253a5a1b3Sopenharmony_ci long ret = sysconf(_SC_PAGE_SIZE); 386353a5a1b3Sopenharmony_ci if (ret > 0) 386453a5a1b3Sopenharmony_ci page_size = ret; 386553a5a1b3Sopenharmony_ci } PA_ONCE_END; 386653a5a1b3Sopenharmony_ci 386753a5a1b3Sopenharmony_ci return page_size; 386853a5a1b3Sopenharmony_ci#else 386953a5a1b3Sopenharmony_ci return 4096; 387053a5a1b3Sopenharmony_ci#endif 387153a5a1b3Sopenharmony_ci} 3872