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
) {
366 ret
= closesocket(fd
);
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
) {
482 assert(b
&& s
&& l
> 0);
489 /* Make the current thread a realtime thread*/
490 void pa_make_realtime(void) {
492 #ifdef _POSIX_PRIORITY_SCHEDULING
493 struct sched_param sp
;
496 memset(&sp
, 0, sizeof(sp
));
499 if ((r
= pthread_getschedparam(pthread_self(), &policy
, &sp
)) != 0) {
500 pa_log("pthread_getschedgetparam(): %s", pa_cstrerror(r
));
504 sp
.sched_priority
= 1;
505 if ((r
= pthread_setschedparam(pthread_self(), SCHED_FIFO
, &sp
)) != 0) {
506 pa_log_warn("pthread_setschedparam(): %s", pa_cstrerror(r
));
510 pa_log_info("Successfully enabled SCHED_FIFO scheduling for thread.");
515 #define NICE_LEVEL (-11)
517 /* Raise the priority of the current process as much as possible and
518 sensible: set the nice level to -15.*/
519 void pa_raise_priority(void) {
521 #ifdef HAVE_SYS_RESOURCE_H
522 if (setpriority(PRIO_PROCESS
, 0, NICE_LEVEL
) < 0)
523 pa_log_warn("setpriority(): %s", pa_cstrerror(errno
));
525 pa_log_info("Successfully gained nice level %i.", NICE_LEVEL
);
529 if (!SetPriorityClass(GetCurrentProcess(), HIGH_PRIORITY_CLASS
))
530 pa_log_warn("SetPriorityClass() failed: 0x%08X", GetLastError());
532 pa_log_info("Successfully gained high priority class.");
536 /* Reset the priority to normal, inverting the changes made by
537 * pa_raise_priority() */
538 void pa_reset_priority(void) {
540 SetPriorityClass(GetCurrentProcess(), NORMAL_PRIORITY_CLASS
);
543 #ifdef HAVE_SYS_RESOURCE_H
544 setpriority(PRIO_PROCESS
, 0, 0);
548 /* Set the FD_CLOEXEC flag for a fd */
549 int pa_fd_set_cloexec(int fd
, int b
) {
555 if ((v
= fcntl(fd
, F_GETFD
, 0)) < 0)
558 v
= (v
& ~FD_CLOEXEC
) | (b
? FD_CLOEXEC
: 0);
560 if (fcntl(fd
, F_SETFD
, v
) < 0)
567 /* Try to parse a boolean string value.*/
568 int pa_parse_boolean(const char *v
) {
570 if (!strcmp(v
, "1") || v
[0] == 'y' || v
[0] == 'Y' || v
[0] == 't' || v
[0] == 'T' || !strcasecmp(v
, "on"))
572 else if (!strcmp(v
, "0") || v
[0] == 'n' || v
[0] == 'N' || v
[0] == 'f' || v
[0] == 'F' || !strcasecmp(v
, "off"))
578 /* Split the specified string wherever one of the strings in delimiter
579 * occurs. Each time it is called returns a newly allocated string
580 * with pa_xmalloc(). The variable state points to, should be
581 * initiallized to NULL before the first call. */
582 char *pa_split(const char *c
, const char *delimiter
, const char**state
) {
583 const char *current
= *state
? *state
: c
;
589 l
= strcspn(current
, delimiter
);
595 return pa_xstrndup(current
, l
);
598 /* What is interpreted as whitespace? */
599 #define WHITESPACE " \t\n"
601 /* Split a string into words. Otherwise similar to pa_split(). */
602 char *pa_split_spaces(const char *c
, const char **state
) {
603 const char *current
= *state
? *state
: c
;
606 if (!*current
|| *c
== 0)
609 current
+= strspn(current
, WHITESPACE
);
610 l
= strcspn(current
, WHITESPACE
);
614 return pa_xstrndup(current
, l
);
617 /* Return the name of an UNIX signal. Similar to GNU's strsignal() */
618 const char *pa_strsignal(int sig
) {
620 case SIGINT
: return "SIGINT";
621 case SIGTERM
: return "SIGTERM";
623 case SIGUSR1
: return "SIGUSR1";
626 case SIGUSR2
: return "SIGUSR2";
629 case SIGXCPU
: return "SIGXCPU";
632 case SIGPIPE
: return "SIGPIPE";
635 case SIGCHLD
: return "SIGCHLD";
638 case SIGHUP
: return "SIGHUP";
640 default: return "UNKNOWN SIGNAL";
646 /* Check whether the specified GID and the group name match */
647 static int is_group(gid_t gid
, const char *name
) {
648 struct group group
, *result
= NULL
;
653 #ifdef HAVE_GETGRGID_R
654 #ifdef _SC_GETGR_R_SIZE_MAX
655 n
= sysconf(_SC_GETGR_R_SIZE_MAX
);
660 data
= pa_xmalloc(n
);
662 if (getgrgid_r(gid
, &group
, data
, n
, &result
) < 0 || !result
) {
663 pa_log("getgrgid_r(%u): %s", (unsigned)gid
, pa_cstrerror(errno
));
667 r
= strcmp(name
, result
->gr_name
) == 0;
672 /* XXX Not thread-safe, but needed on OSes (e.g. FreeBSD 4.X) that do not
673 * support getgrgid_r. */
674 if ((result
= getgrgid(gid
)) == NULL
) {
675 pa_log("getgrgid(%u): %s", gid
, pa_cstrerror(errno
));
679 r
= strcmp(name
, result
->gr_name
) == 0;
687 /* Check the current user is member of the specified group */
688 int pa_own_uid_in_group(const char *name
, gid_t
*gid
) {
689 GETGROUPS_T
*gids
, tgid
;
690 int n
= sysconf(_SC_NGROUPS_MAX
);
695 gids
= pa_xmalloc(sizeof(GETGROUPS_T
)*n
);
697 if ((n
= getgroups(n
, gids
)) < 0) {
698 pa_log("getgroups(): %s", pa_cstrerror(errno
));
702 for (i
= 0; i
< n
; i
++) {
703 if (is_group(gids
[i
], name
) > 0) {
710 if (is_group(tgid
= getgid(), name
) > 0) {
724 /* Check whether the specifc user id is a member of the specified group */
725 int pa_uid_in_group(uid_t uid
, const char *name
) {
728 struct group grbuf
, *gr
;
732 g_n
= sysconf(_SC_GETGR_R_SIZE_MAX
);
733 g_buf
= pa_xmalloc(g_n
);
735 p_n
= sysconf(_SC_GETPW_R_SIZE_MAX
);
736 p_buf
= pa_xmalloc(p_n
);
738 if (getgrnam_r(name
, &grbuf
, g_buf
, (size_t) g_n
, &gr
) != 0 || !gr
)
742 for (i
= gr
->gr_mem
; *i
; i
++) {
743 struct passwd pwbuf
, *pw
;
745 if (getpwnam_r(*i
, &pwbuf
, p_buf
, (size_t) p_n
, &pw
) != 0 || !pw
)
748 if (pw
->pw_uid
== uid
) {
761 /* Get the GID of a gfiven group, return (gid_t) -1 on failure. */
762 gid_t
pa_get_gid_of_group(const char *name
) {
763 gid_t ret
= (gid_t
) -1;
766 struct group grbuf
, *gr
;
768 g_n
= sysconf(_SC_GETGR_R_SIZE_MAX
);
769 g_buf
= pa_xmalloc(g_n
);
771 if (getgrnam_r(name
, &grbuf
, g_buf
, (size_t) g_n
, &gr
) != 0 || !gr
)
781 int pa_check_in_group(gid_t g
) {
782 gid_t gids
[NGROUPS_MAX
];
785 if ((r
= getgroups(NGROUPS_MAX
, gids
)) < 0)
795 #else /* HAVE_GRP_H */
797 int pa_own_uid_in_group(const char *name
, gid_t
*gid
) {
802 int pa_uid_in_group(uid_t uid
, const char *name
) {
806 gid_t
pa_get_gid_of_group(const char *name
) {
810 int pa_check_in_group(gid_t g
) {
816 /* Lock or unlock a file entirely.
817 (advisory on UNIX, mandatory on Windows) */
818 int pa_lock_fd(int fd
, int b
) {
822 /* Try a R/W lock first */
824 flock
.l_type
= b
? F_WRLCK
: F_UNLCK
;
825 flock
.l_whence
= SEEK_SET
;
829 if (fcntl(fd
, F_SETLKW
, &flock
) >= 0)
832 /* Perhaps the file descriptor qas opened for read only, than try again with a read lock. */
833 if (b
&& errno
== EBADF
) {
834 flock
.l_type
= F_RDLCK
;
835 if (fcntl(fd
, F_SETLKW
, &flock
) >= 0)
839 pa_log("%slock: %s", !b
? "un" : "",
840 pa_cstrerror(errno
));
844 HANDLE h
= (HANDLE
)_get_osfhandle(fd
);
846 if (b
&& LockFile(h
, 0, 0, 0xFFFFFFFF, 0xFFFFFFFF))
848 if (!b
&& UnlockFile(h
, 0, 0, 0xFFFFFFFF, 0xFFFFFFFF))
851 pa_log("%slock failed: 0x%08X", !b
? "un" : "", GetLastError());
857 /* Remove trailing newlines from a string */
858 char* pa_strip_nl(char *s
) {
861 s
[strcspn(s
, "\r\n")] = 0;
865 /* Create a temporary lock file and lock it. */
866 int pa_lock_lockfile(const char *fn
) {
873 if ((fd
= open(fn
, O_CREAT
|O_RDWR
, S_IRUSR
|S_IWUSR
)) < 0) {
874 pa_log("failed to create lock file '%s': %s", fn
,
875 pa_cstrerror(errno
));
879 if (pa_lock_fd(fd
, 1) < 0) {
880 pa_log("failed to lock file '%s'.", fn
);
884 if (fstat(fd
, &st
) < 0) {
885 pa_log("failed to fstat() file '%s'.", fn
);
889 /* Check wheter the file has been removed meanwhile. When yes, restart this loop, otherwise, we're done */
890 if (st
.st_nlink
>= 1)
893 if (pa_lock_fd(fd
, 0) < 0) {
894 pa_log("failed to unlock file '%s'.", fn
);
899 pa_log("failed to close file '%s'.", fn
);
916 /* Unlock a temporary lcok file */
917 int pa_unlock_lockfile(const char *fn
, int fd
) {
919 assert(fn
&& fd
>= 0);
921 if (unlink(fn
) < 0) {
922 pa_log_warn("WARNING: unable to remove lock file '%s': %s",
923 fn
, pa_cstrerror(errno
));
927 if (pa_lock_fd(fd
, 0) < 0) {
928 pa_log_warn("WARNING: failed to unlock file '%s'.", fn
);
933 pa_log_warn("WARNING: failed to close lock file '%s': %s",
934 fn
, pa_cstrerror(errno
));
941 /* Try to open a configuration file. If "env" is specified, open the
942 * value of the specified environment variable. Otherwise look for a
943 * file "local" in the home directory or a file "global" in global
944 * file system. If "result" is non-NULL, a pointer to a newly
945 * allocated buffer containing the used configuration file is
947 FILE *pa_open_config_file(const char *global
, const char *local
, const char *env
, char **result
, const char *mode
) {
954 if (!getenv(PULSE_ROOTENV
))
958 if (env
&& (fn
= getenv(env
))) {
960 if (!ExpandEnvironmentStrings(fn
, buf
, PATH_MAX
))
966 *result
= pa_xstrdup(fn
);
968 return fopen(fn
, mode
);
975 if ((e
= getenv("PULSE_CONFIG_PATH")))
976 fn
= lfn
= pa_sprintf_malloc("%s/%s", e
, local
);
977 else if (pa_get_home_dir(h
, sizeof(h
)))
978 fn
= lfn
= pa_sprintf_malloc("%s/.pulse/%s", h
, local
);
984 if (!ExpandEnvironmentStrings(lfn
, buf
, PATH_MAX
))
992 *result
= pa_xstrdup(fn
);
997 if (errno
!= ENOENT
) {
998 pa_log_warn("WARNING: failed to open configuration file '%s': %s",
999 lfn
, pa_cstrerror(errno
));
1014 if (!ExpandEnvironmentStrings(global
, buf
, PATH_MAX
))
1020 *result
= pa_xstrdup(global
);
1022 return fopen(global
, mode
);
1025 /* Format the specified data as a hexademical string */
1026 char *pa_hexstr(const uint8_t* d
, size_t dlength
, char *s
, size_t slength
) {
1027 size_t i
= 0, j
= 0;
1028 const char hex
[] = "0123456789abcdef";
1029 assert(d
&& s
&& slength
> 0);
1031 while (i
< dlength
&& j
+3 <= slength
) {
1032 s
[j
++] = hex
[*d
>> 4];
1033 s
[j
++] = hex
[*d
& 0xF];
1039 s
[j
< slength
? j
: slength
] = 0;
1043 /* Convert a hexadecimal digit to a number or -1 if invalid */
1044 static int hexc(char c
) {
1045 if (c
>= '0' && c
<= '9')
1048 if (c
>= 'A' && c
<= 'F')
1049 return c
- 'A' + 10;
1051 if (c
>= 'a' && c
<= 'f')
1052 return c
- 'a' + 10;
1057 /* Parse a hexadecimal string as created by pa_hexstr() to a BLOB */
1058 size_t pa_parsehex(const char *p
, uint8_t *d
, size_t dlength
) {
1062 while (j
< dlength
&& *p
) {
1065 if ((b
= hexc(*(p
++))) < 0)
1068 d
[j
] = (uint8_t) (b
<< 4);
1073 if ((b
= hexc(*(p
++))) < 0)
1076 d
[j
] |= (uint8_t) b
;
1083 /* Returns nonzero when *s starts with *pfx */
1084 int pa_startswith(const char *s
, const char *pfx
) {
1092 return strlen(s
) >= l
&& strncmp(s
, pfx
, l
) == 0;
1095 /* Returns nonzero when *s ends with *sfx */
1096 int pa_endswith(const char *s
, const char *sfx
) {
1105 return l1
>= l2
&& strcmp(s
+l1
-l2
, sfx
) == 0;
1108 /* if fn is null return the PulseAudio run time path in s (/tmp/pulse)
1109 * if fn is non-null and starts with / return fn in s
1110 * otherwise append fn to the run time path and return it in s */
1111 char *pa_runtime_path(const char *fn
, char *s
, size_t l
) {
1115 if (fn
&& *fn
== '/')
1117 if (fn
&& strlen(fn
) >= 3 && isalpha(fn
[0]) && fn
[1] == ':' && fn
[2] == '\\')
1119 return pa_strlcpy(s
, fn
, l
);
1121 if ((e
= getenv("PULSE_RUNTIME_PATH"))) {
1124 pa_snprintf(s
, l
, "%s%c%s", e
, PA_PATH_SEP_CHAR
, fn
);
1126 pa_snprintf(s
, l
, "%s", e
);
1132 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
);
1134 pa_snprintf(s
, l
, "%s%s", PA_USER_RUNTIME_PATH_PREFIX
, pa_get_user_name(u
, sizeof(u
)));
1142 ExpandEnvironmentStrings(buf
, s
, l
);
1149 /* Convert the string s to a signed integer in *ret_i */
1150 int pa_atoi(const char *s
, int32_t *ret_i
) {
1155 l
= strtol(s
, &x
, 0);
1160 *ret_i
= (int32_t) l
;
1165 /* Convert the string s to an unsigned integer in *ret_u */
1166 int pa_atou(const char *s
, uint32_t *ret_u
) {
1171 l
= strtoul(s
, &x
, 0);
1176 *ret_u
= (uint32_t) l
;
1181 /* Same as snprintf, but guarantees NUL-termination on every platform */
1182 int pa_snprintf(char *str
, size_t size
, const char *format
, ...) {
1187 pa_assert(size
> 0);
1190 va_start(ap
, format
);
1191 ret
= vsnprintf(str
, size
, format
, ap
);
1199 /* Truncate the specified string, but guarantee that the string
1200 * returned still validates as UTF8 */
1201 char *pa_truncate_utf8(char *c
, size_t l
) {
1203 pa_assert(pa_utf8_valid(c
));
1210 while (l
> 0 && !pa_utf8_valid(c
))
1216 char *pa_getcwd(void) {
1220 char *p
= pa_xnew(char, l
);
1224 if (errno
!= ERANGE
)
1232 char *pa_make_path_absolute(const char *p
) {
1239 return pa_xstrdup(p
);
1241 if (!(cwd
= pa_getcwd()))
1242 return pa_xstrdup(p
);
1244 r
= pa_sprintf_malloc("%s/%s", cwd
, p
);
1249 void *pa_will_need(const void *p
, size_t l
) {
1250 #ifdef RLIMIT_MEMLOCK
1261 a
= PA_PAGE_ALIGN_PTR(p
);
1262 size
= (const uint8_t*) p
+ l
- (const uint8_t*) a
;
1264 #ifdef HAVE_POSIX_MADVISE
1265 if ((r
= posix_madvise((void*) a
, size
, POSIX_MADV_WILLNEED
)) == 0) {
1266 pa_log_debug("posix_madvise() worked fine!");
1271 /* Most likely the memory was not mmap()ed from a file and thus
1272 * madvise() didn't work, so let's misuse mlock() do page this
1273 * stuff back into RAM. Yeah, let's fuck with the MM! It's so
1274 * inviting, the man page of mlock() tells us: "All pages that
1275 * contain a part of the specified address range are guaranteed to
1276 * be resident in RAM when the call returns successfully." */
1278 #ifdef RLIMIT_MEMLOCK
1279 pa_assert_se(getrlimit(RLIMIT_MEMLOCK
, &rlim
) == 0);
1281 if (rlim
.rlim_cur
< PA_PAGE_SIZE
) {
1282 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
));
1286 bs
= PA_PAGE_ALIGN(rlim
.rlim_cur
);
1288 bs
= PA_PAGE_SIZE
*4;
1291 pa_log_debug("posix_madvise() failed (or doesn't exist), trying mlock(): %s", pa_cstrerror(r
));
1293 while (size
> 0 && bs
> 0) {
1298 if (mlock(a
, bs
) < 0) {
1299 bs
= PA_PAGE_ALIGN(bs
/ 2);
1303 pa_assert_se(munlock(a
, bs
) == 0);
1305 a
= (const uint8_t*) a
+ bs
;
1310 pa_log_debug("mlock() failed too, giving up: %s", pa_cstrerror(errno
));
1312 pa_log_debug("mlock() worked fine!");