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