4 This file is part of PulseAudio.
6 Copyright 2004-2006 Lennart Poettering
7 Copyright 2004 Joe Marcus Clarke
8 Copyright 2006-2007 Pierre Ossman <ossman@cendio.se> for Cendio AB
10 PulseAudio is free software; you can redistribute it and/or modify
11 it under the terms of the GNU Lesser General Public License as
12 published by the Free Software Foundation; either version 2.1 of the
13 License, or (at your option) any later version.
15 PulseAudio is distributed in the hope that it will be useful, but
16 WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 Lesser General Public License for more details.
20 You should have received a copy of the GNU Lesser General Public
21 License along with PulseAudio; if not, write to the Free Software
22 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
41 #include <sys/types.h>
49 #ifdef HAVE_SYS_RESOURCE_H
50 #include <sys/resource.h>
53 #ifdef HAVE_SYS_CAPABILITY_H
54 #include <sys/capability.h>
57 #ifdef HAVE_SYS_MMAN_H
81 #ifdef HAVE_LIBSAMPLERATE
82 #include <samplerate.h>
85 #include <pulse/xmalloc.h>
86 #include <pulse/util.h>
87 #include <pulse/utf8.h>
89 #include <pulsecore/core-error.h>
90 #include <pulsecore/winsock.h>
91 #include <pulsecore/log.h>
92 #include <pulsecore/macro.h>
94 #include "core-util.h"
96 /* Not all platforms have this */
98 #define MSG_NOSIGNAL 0
102 #define PA_USER_RUNTIME_PATH_PREFIX "/tmp/pulse-"
104 #define PA_USER_RUNTIME_PATH_PREFIX "%TEMP%\\pulse-"
109 #define PULSE_ROOTENV "PULSE_ROOT"
111 int pa_set_root(HANDLE handle
) {
112 char library_path
[MAX_PATH
+ sizeof(PULSE_ROOTENV
) + 1], *sep
;
114 strcpy(library_path
, PULSE_ROOTENV
"=");
116 if (!GetModuleFileName(handle
, library_path
+ sizeof(PULSE_ROOTENV
), MAX_PATH
))
119 sep
= strrchr(library_path
, PA_PATH_SEP_CHAR
);
123 if (_putenv(library_path
) < 0)
131 /** Make a file descriptor nonblock. Doesn't do any error checking */
132 void pa_make_nonblock_fd(int fd
) {
137 if ((v
= fcntl(fd
, F_GETFL
)) >= 0)
138 if (!(v
& O_NONBLOCK
))
139 fcntl(fd
, F_SETFL
, v
|O_NONBLOCK
);
140 #elif defined(OS_IS_WIN32)
142 if (ioctlsocket(fd
, FIONBIO
, &arg
) < 0) {
143 if (WSAGetLastError() == WSAENOTSOCK
)
144 pa_log_warn("WARNING: Only sockets can be made non-blocking!");
147 pa_log_warn("WARNING: Non-blocking I/O not supported.!");
151 /** Creates a directory securely */
152 int pa_make_secure_dir(const char* dir
, mode_t m
, uid_t uid
, gid_t gid
) {
169 if (r
< 0 && errno
!= EEXIST
)
173 if (uid
== (uid_t
)-1)
175 if (gid
== (gid_t
)-1)
177 (void) chown(dir
, uid
, gid
);
185 if (lstat(dir
, &st
) < 0)
187 if (stat(dir
, &st
) < 0)
192 if (!S_ISDIR(st
.st_mode
) ||
193 (st
.st_uid
!= uid
) ||
194 (st
.st_gid
!= gid
) ||
195 ((st
.st_mode
& 0777) != m
)) {
200 pa_log_warn("secure directory creation not supported on Win32.");
210 /* Return a newly allocated sting containing the parent directory of the specified file */
211 char *pa_parent_dir(const char *fn
) {
212 char *slash
, *dir
= pa_xstrdup(fn
);
214 if ((slash
= (char*) pa_path_get_filename(dir
)) == dir
) {
223 /* Creates a the parent directory of the specified path securely */
224 int pa_make_secure_parent_dir(const char *fn
, mode_t m
, uid_t uid
, gid_t gid
) {
228 if (!(dir
= pa_parent_dir(fn
)))
231 if (pa_make_secure_dir(dir
, m
, uid
, gid
) < 0)
241 /** Platform independent read function. Necessary since not all
242 * systems treat all file descriptors equal. If type is
243 * non-NULL it is used to cache the type of the fd. This is
244 * useful for making sure that only a single syscall is executed per
245 * function call. The variable pointed to should be initialized to 0
247 ssize_t
pa_read(int fd
, void *buf
, size_t count
, int *type
) {
251 if (!type
|| *type
== 0) {
254 if ((r
= recv(fd
, buf
, count
, 0)) >= 0)
257 if (WSAGetLastError() != WSAENOTSOCK
) {
258 errno
= WSAGetLastError();
268 return read(fd
, buf
, count
);
271 /** Similar to pa_read(), but handles writes */
272 ssize_t
pa_write(int fd
, const void *buf
, size_t count
, int *type
) {
274 if (!type
|| *type
== 0) {
277 if ((r
= send(fd
, buf
, count
, MSG_NOSIGNAL
)) >= 0)
281 if (WSAGetLastError() != WSAENOTSOCK
) {
282 errno
= WSAGetLastError();
286 if (errno
!= ENOTSOCK
)
294 return write(fd
, buf
, count
);
297 /** Calls read() in a loop. Makes sure that as much as 'size' bytes,
298 * unless EOF is reached or an error occured */
299 ssize_t
pa_loop_read(int fd
, void*data
, size_t size
, int *type
) {
315 if ((r
= pa_read(fd
, data
, size
, type
)) < 0)
322 data
= (uint8_t*) data
+ r
;
329 /** Similar to pa_loop_read(), but wraps write() */
330 ssize_t
pa_loop_write(int fd
, const void*data
, size_t size
, int *type
) {
346 if ((r
= pa_write(fd
, data
, size
, type
)) < 0)
353 data
= (const uint8_t*) data
+ r
;
360 /** Platform independent read function. Necessary since not all
361 * systems treat all file descriptors equal. */
362 int pa_close(int fd
) {
367 if ((ret
= closesocket(fd
)) == 0)
370 if (WSAGetLastError() != WSAENOTSOCK
) {
371 errno
= WSAGetLastError();
379 /* Print a warning messages in case that the given signal is not
380 * blocked or trapped */
381 void pa_check_signal_is_blocked(int sig
) {
382 #ifdef HAVE_SIGACTION
386 /* If POSIX threads are supported use thread-aware
387 * pthread_sigmask() function, to check if the signal is
388 * blocked. Otherwise fall back to sigprocmask() */
391 if (pthread_sigmask(SIG_SETMASK
, NULL
, &set
) < 0) {
393 if (sigprocmask(SIG_SETMASK
, NULL
, &set
) < 0) {
394 pa_log("sigprocmask(): %s", pa_cstrerror(errno
));
401 if (sigismember(&set
, sig
))
404 /* Check whether the signal is trapped */
406 if (sigaction(sig
, NULL
, &sa
) < 0) {
407 pa_log("sigaction(): %s", pa_cstrerror(errno
));
411 if (sa
.sa_handler
!= SIG_DFL
)
414 pa_log("WARNING: %s is not trapped. This might cause malfunction!", pa_strsignal(sig
));
415 #else /* HAVE_SIGACTION */
416 pa_log("WARNING: %s might not be trapped. This might cause malfunction!", pa_strsignal(sig
));
420 /* The following function is based on an example from the GNU libc
421 * documentation. This function is similar to GNU's asprintf(). */
422 char *pa_sprintf_malloc(const char *format
, ...) {
432 c
= pa_xrealloc(c
, size
);
434 va_start(ap
, format
);
435 r
= vsnprintf(c
, size
, format
, ap
);
440 if (r
> -1 && r
< size
)
443 if (r
> -1) /* glibc 2.1 */
450 /* Same as the previous function, but use a va_list instead of an
452 char *pa_vsprintf_malloc(const char *format
, va_list ap
) {
462 c
= pa_xrealloc(c
, size
);
465 r
= vsnprintf(c
, size
, format
, aq
);
470 if (r
> -1 && r
< size
)
473 if (r
> -1) /* glibc 2.1 */
480 /* Similar to OpenBSD's strlcpy() function */
481 char *pa_strlcpy(char *b
, const char *s
, size_t l
) {
491 /* Make the current thread a realtime thread*/
492 void pa_make_realtime(void) {
494 #ifdef _POSIX_PRIORITY_SCHEDULING
495 struct sched_param sp
;
498 memset(&sp
, 0, sizeof(sp
));
501 if ((r
= pthread_getschedparam(pthread_self(), &policy
, &sp
)) != 0) {
502 pa_log("pthread_getschedgetparam(): %s", pa_cstrerror(r
));
506 sp
.sched_priority
= 1;
507 if ((r
= pthread_setschedparam(pthread_self(), SCHED_FIFO
, &sp
)) != 0) {
508 pa_log_warn("pthread_setschedparam(): %s", pa_cstrerror(r
));
512 pa_log_info("Successfully enabled SCHED_FIFO scheduling for thread.");
517 #define NICE_LEVEL (-11)
519 /* Raise the priority of the current process as much as possible and
520 sensible: set the nice level to -15.*/
521 void pa_raise_priority(void) {
523 #ifdef HAVE_SYS_RESOURCE_H
524 if (setpriority(PRIO_PROCESS
, 0, NICE_LEVEL
) < 0)
525 pa_log_warn("setpriority(): %s", pa_cstrerror(errno
));
527 pa_log_info("Successfully gained nice level %i.", NICE_LEVEL
);
531 if (!SetPriorityClass(GetCurrentProcess(), HIGH_PRIORITY_CLASS
))
532 pa_log_warn("SetPriorityClass() failed: 0x%08X", GetLastError());
534 pa_log_info("Successfully gained high priority class.");
538 /* Reset the priority to normal, inverting the changes made by
539 * pa_raise_priority() */
540 void pa_reset_priority(void) {
542 SetPriorityClass(GetCurrentProcess(), NORMAL_PRIORITY_CLASS
);
545 #ifdef HAVE_SYS_RESOURCE_H
546 setpriority(PRIO_PROCESS
, 0, 0);
550 /* Set the FD_CLOEXEC flag for a fd */
551 int pa_fd_set_cloexec(int fd
, int b
) {
557 if ((v
= fcntl(fd
, F_GETFD
, 0)) < 0)
560 v
= (v
& ~FD_CLOEXEC
) | (b
? FD_CLOEXEC
: 0);
562 if (fcntl(fd
, F_SETFD
, v
) < 0)
569 /* Try to parse a boolean string value.*/
570 int pa_parse_boolean(const char *v
) {
572 if (!strcmp(v
, "1") || v
[0] == 'y' || v
[0] == 'Y' || v
[0] == 't' || v
[0] == 'T' || !strcasecmp(v
, "on"))
574 else if (!strcmp(v
, "0") || v
[0] == 'n' || v
[0] == 'N' || v
[0] == 'f' || v
[0] == 'F' || !strcasecmp(v
, "off"))
580 /* Split the specified string wherever one of the strings in delimiter
581 * occurs. Each time it is called returns a newly allocated string
582 * with pa_xmalloc(). The variable state points to, should be
583 * initiallized to NULL before the first call. */
584 char *pa_split(const char *c
, const char *delimiter
, const char**state
) {
585 const char *current
= *state
? *state
: c
;
591 l
= strcspn(current
, delimiter
);
597 return pa_xstrndup(current
, l
);
600 /* What is interpreted as whitespace? */
601 #define WHITESPACE " \t\n"
603 /* Split a string into words. Otherwise similar to pa_split(). */
604 char *pa_split_spaces(const char *c
, const char **state
) {
605 const char *current
= *state
? *state
: c
;
608 if (!*current
|| *c
== 0)
611 current
+= strspn(current
, WHITESPACE
);
612 l
= strcspn(current
, WHITESPACE
);
616 return pa_xstrndup(current
, l
);
619 /* Return the name of an UNIX signal. Similar to GNU's strsignal() */
620 const char *pa_strsignal(int sig
) {
622 case SIGINT
: return "SIGINT";
623 case SIGTERM
: return "SIGTERM";
625 case SIGUSR1
: return "SIGUSR1";
628 case SIGUSR2
: return "SIGUSR2";
631 case SIGXCPU
: return "SIGXCPU";
634 case SIGPIPE
: return "SIGPIPE";
637 case SIGCHLD
: return "SIGCHLD";
640 case SIGHUP
: return "SIGHUP";
642 default: return "UNKNOWN SIGNAL";
648 /* Check whether the specified GID and the group name match */
649 static int is_group(gid_t gid
, const char *name
) {
650 struct group group
, *result
= NULL
;
655 #ifdef HAVE_GETGRGID_R
656 #ifdef _SC_GETGR_R_SIZE_MAX
657 n
= sysconf(_SC_GETGR_R_SIZE_MAX
);
662 data
= pa_xmalloc(n
);
664 if (getgrgid_r(gid
, &group
, data
, n
, &result
) < 0 || !result
) {
665 pa_log("getgrgid_r(%u): %s", (unsigned)gid
, pa_cstrerror(errno
));
669 r
= strcmp(name
, result
->gr_name
) == 0;
674 /* XXX Not thread-safe, but needed on OSes (e.g. FreeBSD 4.X) that do not
675 * support getgrgid_r. */
676 if ((result
= getgrgid(gid
)) == NULL
) {
677 pa_log("getgrgid(%u): %s", gid
, pa_cstrerror(errno
));
681 r
= strcmp(name
, result
->gr_name
) == 0;
689 /* Check the current user is member of the specified group */
690 int pa_own_uid_in_group(const char *name
, gid_t
*gid
) {
691 GETGROUPS_T
*gids
, tgid
;
692 int n
= sysconf(_SC_NGROUPS_MAX
);
697 gids
= pa_xmalloc(sizeof(GETGROUPS_T
)*n
);
699 if ((n
= getgroups(n
, gids
)) < 0) {
700 pa_log("getgroups(): %s", pa_cstrerror(errno
));
704 for (i
= 0; i
< n
; i
++) {
705 if (is_group(gids
[i
], name
) > 0) {
712 if (is_group(tgid
= getgid(), name
) > 0) {
726 /* Check whether the specifc user id is a member of the specified group */
727 int pa_uid_in_group(uid_t uid
, const char *name
) {
730 struct group grbuf
, *gr
;
734 g_n
= sysconf(_SC_GETGR_R_SIZE_MAX
);
735 g_buf
= pa_xmalloc(g_n
);
737 p_n
= sysconf(_SC_GETPW_R_SIZE_MAX
);
738 p_buf
= pa_xmalloc(p_n
);
740 if (getgrnam_r(name
, &grbuf
, g_buf
, (size_t) g_n
, &gr
) != 0 || !gr
)
744 for (i
= gr
->gr_mem
; *i
; i
++) {
745 struct passwd pwbuf
, *pw
;
747 if (getpwnam_r(*i
, &pwbuf
, p_buf
, (size_t) p_n
, &pw
) != 0 || !pw
)
750 if (pw
->pw_uid
== uid
) {
763 /* Get the GID of a gfiven group, return (gid_t) -1 on failure. */
764 gid_t
pa_get_gid_of_group(const char *name
) {
765 gid_t ret
= (gid_t
) -1;
768 struct group grbuf
, *gr
;
770 g_n
= sysconf(_SC_GETGR_R_SIZE_MAX
);
771 g_buf
= pa_xmalloc(g_n
);
773 if (getgrnam_r(name
, &grbuf
, g_buf
, (size_t) g_n
, &gr
) != 0 || !gr
)
783 int pa_check_in_group(gid_t g
) {
784 gid_t gids
[NGROUPS_MAX
];
787 if ((r
= getgroups(NGROUPS_MAX
, gids
)) < 0)
797 #else /* HAVE_GRP_H */
799 int pa_own_uid_in_group(const char *name
, gid_t
*gid
) {
804 int pa_uid_in_group(uid_t uid
, const char *name
) {
808 gid_t
pa_get_gid_of_group(const char *name
) {
812 int pa_check_in_group(gid_t g
) {
818 /* Lock or unlock a file entirely.
819 (advisory on UNIX, mandatory on Windows) */
820 int pa_lock_fd(int fd
, int b
) {
824 /* Try a R/W lock first */
826 flock
.l_type
= b
? F_WRLCK
: F_UNLCK
;
827 flock
.l_whence
= SEEK_SET
;
831 if (fcntl(fd
, F_SETLKW
, &flock
) >= 0)
834 /* Perhaps the file descriptor qas opened for read only, than try again with a read lock. */
835 if (b
&& errno
== EBADF
) {
836 flock
.l_type
= F_RDLCK
;
837 if (fcntl(fd
, F_SETLKW
, &flock
) >= 0)
841 pa_log("%slock: %s", !b
? "un" : "", pa_cstrerror(errno
));
845 HANDLE h
= (HANDLE
)_get_osfhandle(fd
);
847 if (b
&& LockFile(h
, 0, 0, 0xFFFFFFFF, 0xFFFFFFFF))
849 if (!b
&& UnlockFile(h
, 0, 0, 0xFFFFFFFF, 0xFFFFFFFF))
852 pa_log("%slock failed: 0x%08X", !b
? "un" : "", GetLastError());
858 /* Remove trailing newlines from a string */
859 char* pa_strip_nl(char *s
) {
862 s
[strcspn(s
, "\r\n")] = 0;
866 /* Create a temporary lock file and lock it. */
867 int pa_lock_lockfile(const char *fn
) {
874 if ((fd
= open(fn
, O_CREAT
|O_RDWR
, S_IRUSR
|S_IWUSR
)) < 0) {
875 pa_log_warn("Failed to create lock file '%s': %s", fn
, pa_cstrerror(errno
));
879 if (pa_lock_fd(fd
, 1) < 0) {
880 pa_log_warn("Failed to lock file '%s'.", fn
);
884 if (fstat(fd
, &st
) < 0) {
885 pa_log_warn("Failed to fstat() file '%s': %s", fn
, pa_cstrerror(errno
));
889 /* Check wheter the file has been removed meanwhile. When yes,
890 * restart this loop, otherwise, we're done */
891 if (st
.st_nlink
>= 1)
894 if (pa_lock_fd(fd
, 0) < 0) {
895 pa_log_warn("Failed to unlock file '%s'.", fn
);
899 if (pa_close(fd
) < 0) {
900 pa_log_warn("Failed to close file '%s': %s", fn
, pa_cstrerror(errno
));
918 /* Unlock a temporary lcok file */
919 int pa_unlock_lockfile(const char *fn
, int fd
) {
924 if (unlink(fn
) < 0) {
925 pa_log_warn("Unable to remove lock file '%s': %s", fn
, pa_cstrerror(errno
));
929 if (pa_lock_fd(fd
, 0) < 0) {
930 pa_log_warn("Failed to unlock file '%s'.", fn
);
934 if (pa_close(fd
) < 0) {
935 pa_log_warn("Failed to close '%s': %s", fn
, pa_cstrerror(errno
));
942 /* Try to open a configuration file. If "env" is specified, open the
943 * value of the specified environment variable. Otherwise look for a
944 * file "local" in the home directory or a file "global" in global
945 * file system. If "result" is non-NULL, a pointer to a newly
946 * allocated buffer containing the used configuration file is
948 FILE *pa_open_config_file(const char *global
, const char *local
, const char *env
, char **result
, const char *mode
) {
955 if (!getenv(PULSE_ROOTENV
))
959 if (env
&& (fn
= getenv(env
))) {
961 if (!ExpandEnvironmentStrings(fn
, buf
, PATH_MAX
))
967 *result
= pa_xstrdup(fn
);
969 return fopen(fn
, mode
);
976 if ((e
= getenv("PULSE_CONFIG_PATH")))
977 fn
= lfn
= pa_sprintf_malloc("%s/%s", e
, local
);
978 else if (pa_get_home_dir(h
, sizeof(h
)))
979 fn
= lfn
= pa_sprintf_malloc("%s/.pulse/%s", h
, local
);
985 if (!ExpandEnvironmentStrings(lfn
, buf
, PATH_MAX
))
993 *result
= pa_xstrdup(fn
);
998 if (errno
!= ENOENT
) {
999 pa_log_warn("WARNING: failed to open configuration file '%s': %s",
1000 lfn
, pa_cstrerror(errno
));
1015 if (!ExpandEnvironmentStrings(global
, buf
, PATH_MAX
))
1021 *result
= pa_xstrdup(global
);
1023 return fopen(global
, mode
);
1026 /* Format the specified data as a hexademical string */
1027 char *pa_hexstr(const uint8_t* d
, size_t dlength
, char *s
, size_t slength
) {
1028 size_t i
= 0, j
= 0;
1029 const char hex
[] = "0123456789abcdef";
1033 pa_assert(slength
> 0);
1035 while (i
< dlength
&& j
+3 <= slength
) {
1036 s
[j
++] = hex
[*d
>> 4];
1037 s
[j
++] = hex
[*d
& 0xF];
1043 s
[j
< slength
? j
: slength
] = 0;
1047 /* Convert a hexadecimal digit to a number or -1 if invalid */
1048 static int hexc(char c
) {
1049 if (c
>= '0' && c
<= '9')
1052 if (c
>= 'A' && c
<= 'F')
1053 return c
- 'A' + 10;
1055 if (c
>= 'a' && c
<= 'f')
1056 return c
- 'a' + 10;
1061 /* Parse a hexadecimal string as created by pa_hexstr() to a BLOB */
1062 size_t pa_parsehex(const char *p
, uint8_t *d
, size_t dlength
) {
1068 while (j
< dlength
&& *p
) {
1071 if ((b
= hexc(*(p
++))) < 0)
1074 d
[j
] = (uint8_t) (b
<< 4);
1079 if ((b
= hexc(*(p
++))) < 0)
1082 d
[j
] |= (uint8_t) b
;
1089 /* Returns nonzero when *s starts with *pfx */
1090 int pa_startswith(const char *s
, const char *pfx
) {
1098 return strlen(s
) >= l
&& strncmp(s
, pfx
, l
) == 0;
1101 /* Returns nonzero when *s ends with *sfx */
1102 int pa_endswith(const char *s
, const char *sfx
) {
1111 return l1
>= l2
&& strcmp(s
+l1
-l2
, sfx
) == 0;
1114 /* if fn is null return the PulseAudio run time path in s (/tmp/pulse)
1115 * if fn is non-null and starts with / return fn in s
1116 * otherwise append fn to the run time path and return it in s */
1117 char *pa_runtime_path(const char *fn
, char *s
, size_t l
) {
1121 if (fn
&& *fn
== '/')
1123 if (fn
&& strlen(fn
) >= 3 && isalpha(fn
[0]) && fn
[1] == ':' && fn
[2] == '\\')
1125 return pa_strlcpy(s
, fn
, l
);
1127 if ((e
= getenv("PULSE_RUNTIME_PATH"))) {
1130 pa_snprintf(s
, l
, "%s%c%s", e
, PA_PATH_SEP_CHAR
, fn
);
1132 pa_snprintf(s
, l
, "%s", e
);
1138 pa_snprintf(s
, l
, "%s%s%c%s", PA_USER_RUNTIME_PATH_PREFIX
, pa_get_user_name(u
, sizeof(u
)), PA_PATH_SEP_CHAR
, fn
);
1140 pa_snprintf(s
, l
, "%s%s", PA_USER_RUNTIME_PATH_PREFIX
, pa_get_user_name(u
, sizeof(u
)));
1148 ExpandEnvironmentStrings(buf
, s
, l
);
1155 /* Convert the string s to a signed integer in *ret_i */
1156 int pa_atoi(const char *s
, int32_t *ret_i
) {
1163 l
= strtol(s
, &x
, 0);
1168 *ret_i
= (int32_t) l
;
1173 /* Convert the string s to an unsigned integer in *ret_u */
1174 int pa_atou(const char *s
, uint32_t *ret_u
) {
1181 l
= strtoul(s
, &x
, 0);
1186 *ret_u
= (uint32_t) l
;
1191 /* Same as snprintf, but guarantees NUL-termination on every platform */
1192 int pa_snprintf(char *str
, size_t size
, const char *format
, ...) {
1197 pa_assert(size
> 0);
1200 va_start(ap
, format
);
1201 ret
= vsnprintf(str
, size
, format
, ap
);
1209 /* Truncate the specified string, but guarantee that the string
1210 * returned still validates as UTF8 */
1211 char *pa_truncate_utf8(char *c
, size_t l
) {
1213 pa_assert(pa_utf8_valid(c
));
1220 while (l
> 0 && !pa_utf8_valid(c
))
1226 char *pa_getcwd(void) {
1230 char *p
= pa_xnew(char, l
);
1234 if (errno
!= ERANGE
)
1242 char *pa_make_path_absolute(const char *p
) {
1249 return pa_xstrdup(p
);
1251 if (!(cwd
= pa_getcwd()))
1252 return pa_xstrdup(p
);
1254 r
= pa_sprintf_malloc("%s/%s", cwd
, p
);
1259 void *pa_will_need(const void *p
, size_t l
) {
1260 #ifdef RLIMIT_MEMLOCK
1271 a
= PA_PAGE_ALIGN_PTR(p
);
1272 size
= (const uint8_t*) p
+ l
- (const uint8_t*) a
;
1274 #ifdef HAVE_POSIX_MADVISE
1275 if ((r
= posix_madvise((void*) a
, size
, POSIX_MADV_WILLNEED
)) == 0) {
1276 pa_log_debug("posix_madvise() worked fine!");
1281 /* Most likely the memory was not mmap()ed from a file and thus
1282 * madvise() didn't work, so let's misuse mlock() do page this
1283 * stuff back into RAM. Yeah, let's fuck with the MM! It's so
1284 * inviting, the man page of mlock() tells us: "All pages that
1285 * contain a part of the specified address range are guaranteed to
1286 * be resident in RAM when the call returns successfully." */
1288 #ifdef RLIMIT_MEMLOCK
1289 pa_assert_se(getrlimit(RLIMIT_MEMLOCK
, &rlim
) == 0);
1291 if (rlim
.rlim_cur
< PA_PAGE_SIZE
) {
1292 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
));
1296 bs
= PA_PAGE_ALIGN(rlim
.rlim_cur
);
1298 bs
= PA_PAGE_SIZE
*4;
1301 pa_log_debug("posix_madvise() failed (or doesn't exist), trying mlock(): %s", pa_cstrerror(r
));
1303 while (size
> 0 && bs
> 0) {
1308 if (mlock(a
, bs
) < 0) {
1309 bs
= PA_PAGE_ALIGN(bs
/ 2);
1313 pa_assert_se(munlock(a
, bs
) == 0);
1315 a
= (const uint8_t*) a
+ bs
;
1320 pa_log_debug("mlock() failed too, giving up: %s", pa_cstrerror(errno
));
1322 pa_log_debug("mlock() worked fine!");
1327 void pa_close_pipe(int fds
[2]) {
1331 pa_assert_se(pa_close(fds
[0]) == 0);
1334 pa_assert_se(pa_close(fds
[1]) == 0);
1336 fds
[0] = fds
[1] = -1;