util.c revision f67cc036ba92a3c71acb664ed2d548de5827cf1f
6c03089c32c251d823173bda4d809a9e643219f0Lennart Poettering/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
6c03089c32c251d823173bda4d809a9e643219f0Lennart Poettering This file is part of systemd.
6c03089c32c251d823173bda4d809a9e643219f0Lennart Poettering Copyright 2010 Lennart Poettering
6c03089c32c251d823173bda4d809a9e643219f0Lennart Poettering systemd is free software; you can redistribute it and/or modify it
6c03089c32c251d823173bda4d809a9e643219f0Lennart Poettering under the terms of the GNU Lesser General Public License as published by
6c03089c32c251d823173bda4d809a9e643219f0Lennart Poettering the Free Software Foundation; either version 2.1 of the License, or
6c03089c32c251d823173bda4d809a9e643219f0Lennart Poettering (at your option) any later version.
6c03089c32c251d823173bda4d809a9e643219f0Lennart Poettering systemd is distributed in the hope that it will be useful, but
6c03089c32c251d823173bda4d809a9e643219f0Lennart Poettering WITHOUT ANY WARRANTY; without even the implied warranty of
6c03089c32c251d823173bda4d809a9e643219f0Lennart Poettering MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
6c03089c32c251d823173bda4d809a9e643219f0Lennart Poettering Lesser General Public License for more details.
6c03089c32c251d823173bda4d809a9e643219f0Lennart Poettering You should have received a copy of the GNU Lesser General Public License
6c03089c32c251d823173bda4d809a9e643219f0Lennart Poettering along with systemd; If not, see <http://www.gnu.org/licenses/>.
96cde13ace6406582688028f3df5668a172ba628Zbigniew Jędrzejewski-Szmek static __thread size_t pgsz = 0;
7027ff61a34a12487712b382a061c654acc3a679Lennart Poettering assert_se((r = sysconf(_SC_PAGESIZE)) > 0);
7027ff61a34a12487712b382a061c654acc3a679Lennart Poetteringbool streq_ptr(const char *a, const char *b) {
7027ff61a34a12487712b382a061c654acc3a679Lennart Poettering /* Like streq(), but tries to make sense of NULL pointers */
ae018d9bc900d6355dea4af05119b49c67945184Lennart Poettering assert_se(clock_gettime(clock_id, &ts) == 0);
aff38e74bd776471f15ba54b305a24b0251eb865Lennart Poetteringdual_timestamp* dual_timestamp_get(dual_timestamp *ts) {
aff38e74bd776471f15ba54b305a24b0251eb865Lennart Poetteringdual_timestamp* dual_timestamp_from_realtime(dual_timestamp *ts, usec_t u) {
aff38e74bd776471f15ba54b305a24b0251eb865Lennart Poettering delta = (int64_t) now(CLOCK_REALTIME) - (int64_t) u;
ae018d9bc900d6355dea4af05119b49c67945184Lennart Poetteringusec_t timespec_load(const struct timespec *ts) {
ae018d9bc900d6355dea4af05119b49c67945184Lennart Poetteringstruct timespec *timespec_store(struct timespec *ts, usec_t u) {
ae018d9bc900d6355dea4af05119b49c67945184Lennart Poettering ts->tv_sec = (time_t) (u / USEC_PER_SEC);
ae018d9bc900d6355dea4af05119b49c67945184Lennart Poettering ts->tv_nsec = (long int) ((u % USEC_PER_SEC) * NSEC_PER_USEC);
a0ab566574303be1ca12cdb334f284cfd407caa5Lennart Poetteringusec_t timeval_load(const struct timeval *tv) {
78edb35ab4f4227485cb9ec816b43c37e0d5e62aLennart Poetteringstruct timeval *timeval_store(struct timeval *tv, usec_t u) {
78edb35ab4f4227485cb9ec816b43c37e0d5e62aLennart Poettering tv->tv_sec = (time_t) (u / USEC_PER_SEC);
78edb35ab4f4227485cb9ec816b43c37e0d5e62aLennart Poettering tv->tv_usec = (suseconds_t) (u % USEC_PER_SEC);
96cde13ace6406582688028f3df5668a172ba628Zbigniew Jędrzejewski-Szmekbool endswith(const char *s, const char *postfix) {
assert(s);
if (pl == 0)
assert(s);
if (pl == 0)
for(i = 0; i < pl; ++i) {
assert(s);
if (wl == 0)
return s[wl] == 0 ||
return -errno;
for (i = 0; i < n_fd; i++)
int parse_boolean(const char *v) {
assert(v);
if (streq(v, "1") || v[0] == 'y' || v[0] == 'Y' || v[0] == 't' || v[0] == 'T' || !strcasecmp(v, "on"))
else if (streq(v, "0") || v[0] == 'n' || v[0] == 'N' || v[0] == 'f' || v[0] == 'F' || !strcasecmp(v, "off"))
return -EINVAL;
unsigned long ul = 0;
assert(s);
return -ERANGE;
if (pid <= 0)
return -ERANGE;
unsigned long ul = 0;
assert(s);
return -ERANGE;
char *x = NULL;
assert(s);
errno = 0;
l = strtoul(s, &x, 0);
if (!x || *x || errno)
return -ERANGE;
*ret_u = (unsigned) l;
char *x = NULL;
assert(s);
errno = 0;
l = strtol(s, &x, 0);
if (!x || *x || errno)
return -ERANGE;
*ret_i = (int) l;
char *x = NULL;
assert(s);
errno = 0;
l = strtoull(s, &x, 0);
if (!x || *x || errno)
*ret_llu = l;
char *x = NULL;
assert(s);
errno = 0;
l = strtoll(s, &x, 0);
if (!x || *x || errno)
*ret_lli = l;
char *current;
if (!*current || *c == 0)
return NULL;
return (char*) current;
char *current, *e;
bool escaped = false;
if (!*current || *c == 0)
return NULL;
current ++;
for (e = current; *e; e++) {
if (escaped)
escaped = false;
escaped = true;
*l = e-current;
current ++;
for (e = current; *e; e++) {
if (escaped)
escaped = false;
escaped = true;
*l = e-current;
for (e = current; *e; e++) {
if (escaped)
escaped = false;
escaped = true;
*l = e-current;
*state = e;
return (char*) current;
FILE *f;
long unsigned ppid;
assert_se(snprintf(fn, sizeof(fn)-1, "/proc/%lu/stat", (unsigned long) pid) < (int) (sizeof(fn)-1));
return -errno;
fclose(f);
fclose(f);
return -EIO;
return -EIO;
return -ERANGE;
FILE *f;
assert_se(snprintf(fn, sizeof(fn)-1, "/proc/%lu/stat", (unsigned long) pid) < (int) (sizeof(fn)-1));
return -errno;
fclose(f);
fclose(f);
return -EIO;
return -EIO;
FILE *f;
return -errno;
errno = 0;
r = -errno;
goto finish;
fflush(f);
if (ferror(f)) {
if (errno != 0)
r = -errno;
r = -EIO;
fclose(f);
mode_t u;
umask(u);
FILE *f;
errno = 0;
r = -errno;
goto finish;
fflush(f);
if (ferror(f)) {
if (errno != 0)
r = -errno;
r = -EIO;
r = -errno;
unlink(p);
fclose(f);
free(p);
FILE *f;
char t[LINE_MAX], *c;
return -errno;
if (!fgets(t, sizeof(t), f)) {
if (ferror(f)) {
r = -errno;
goto finish;
c = strdup(t);
r = -ENOMEM;
goto finish;
truncate_nl(c);
*line = c;
fclose(f);
FILE *f;
size_t n, l;
return -errno;
r = -errno;
goto finish;
r = -E2BIG;
goto finish;
size_t k;
r = -ENOMEM;
goto finish;
buf = t;
if (ferror(f)) {
r = -errno;
goto finish;
r = -E2BIG;
goto finish;
buf[l] = 0;
if (size)
*size = l;
fclose(f);
int parse_env_file(
const char *fname,
const char *separator, ...) {
p = contents;
char **value;
size_t n;
v = strndup(p, n);
r = -ENOMEM;
goto fail;
free(v);
v = NULL;
*value = v;
if (!key)
fail:
int load_env_file(
const char *fname,
char ***rl) {
FILE *f;
char **m = NULL;
return -errno;
while (!feof(f)) {
char l[LINE_MAX], *p, *u;
if (!fgets(l, sizeof(l), f)) {
if (feof(f))
r = -errno;
goto finish;
p = strstrip(l);
if (!(u = normalize_env_assignment(p))) {
r = -ENOMEM;
goto finish;
t = strv_append(m, u);
free(u);
r = -ENOMEM;
goto finish;
strv_free(m);
*rl = m;
m = NULL;
fclose(f);
strv_free(m);
FILE *f;
errno = 0;
STRV_FOREACH(i, l) {
fputs(*i, f);
fflush(f);
if (ferror(f)) {
if (errno != 0)
r = -errno;
r = -EIO;
r = -errno;
unlink(p);
fclose(f);
free(p);
char *truncate_nl(char *s) {
assert(s);
if (pid == 0)
return -ENOMEM;
free(p);
bool space = false;
FILE *f;
if (pid == 0)
return -ENOMEM;
free(p);
return -errno;
fclose(f);
return -ENOMEM;
if (isprint(c)) {
if (space) {
left--;
space = false;
left--;
space = true;
fclose(f);
free(r);
if (!comm_fallback)
return -ENOENT;
free(t);
return -ENOMEM;
*line = r;
bool eof;
FILE *f;
if (pid == 0)
return -ENOMEM;
free(p);
return -errno;
fclose(f);
if (count <= 0)
if (pid == 0)
return -ENOMEM;
free(p);
FILE *f;
if (pid == 0)
return getuid();
return -ENOMEM;
free(p);
return -errno;
while (!feof(f)) {
if (feof(f))
r = -errno;
goto finish;
goto finish;
r = -EIO;
fclose(f);
size_t a;
if (!s && !suffix)
if (!suffix)
return strdup(s);
assert(s);
a = strlen(s);
return NULL;
memcpy(r, s, a);
int readlink_malloc(const char *p, char **r) {
assert(p);
assert(r);
ssize_t n;
if (!(c = new(char, l)))
return -ENOMEM;
free(c);
return ret;
free(c);
int readlink_and_make_absolute(const char *p, char **r) {
char *target, *k;
assert(p);
assert(r);
return -ENOMEM;
int readlink_and_canonicalize(const char *p, char **r) {
assert(p);
assert(r);
j = readlink_and_make_absolute(p, &t);
s = canonicalize_file_name(t);
free(t);
path_kill_slashes(*r);
int reset_all_signal_handlers(void) {
int sig;
return -errno;
char *strstrip(char *s) {
for (e = strchr(s, 0); e > s; e --)
assert(s);
size_t k;
return NULL;
size_t l;
return -ENOMEM;
free(t);
r = rmdir(t);
free(t);
return -errno;
char hexchar(int x) {
int unhexchar(char c) {
char octchar(int x) {
int unoctchar(char c) {
char decchar(int x) {
int undecchar(char c) {
char *cescape(const char *s) {
assert(s);
return NULL;
*(t++) = octchar((unsigned char) *f);
assert(s);
for (f = s, t = r; f < s + length; f++) {
a = unoctchar(f[0]);
goto finish;
char *cunescape(const char *s) {
return NULL;
*(t++) = hexchar(*f);
char *bus_path_escape(const char *s) {
assert(s);
return NULL;
*(t++) = hexchar(*f);
char *bus_path_unescape(const char *f) {
assert(f);
if (!(r = strdup(f)))
return NULL;
char *ascii_strlower(char *t) {
assert(t);
int flags;
return -errno;
if (nonblock)
return -errno;
int flags;
return -errno;
if (cloexec)
return -errno;
for (i = 0; i < n_fdset; i++)
DIR *d;
int fd;
r = -errno;
r = -errno;
closedir(d);
bool chars_intersect(const char *a, const char *b) {
if (strchr(b, *p))
assert(l > 0);
return NULL;
return NULL;
return buf;
usec_t n, d;
return NULL;
if (d >= USEC_PER_YEAR)
(unsigned long long) (d / USEC_PER_YEAR),
else if (d >= USEC_PER_MONTH)
(unsigned long long) (d / USEC_PER_MONTH),
else if (d >= USEC_PER_WEEK)
(unsigned long long) (d / USEC_PER_WEEK),
(unsigned long long) (d / USEC_PER_HOUR));
else if (d >= USEC_PER_HOUR)
(unsigned long long) (d / USEC_PER_HOUR),
(unsigned long long) (d / USEC_PER_MINUTE));
else if (d >= USEC_PER_MINUTE)
(unsigned long long) (d / USEC_PER_MINUTE),
else if (d >= USEC_PER_SEC)
(unsigned long long) (d / USEC_PER_SEC));
else if (d >= USEC_PER_MSEC)
(unsigned long long) (d / USEC_PER_MSEC));
return buf;
const char *suffix;
} table[] = {
char *p = buf;
assert(l > 0);
return NULL;
size_t n;
k = snprintf(p, l, "%s%llu%s", p > buf ? " " : "", (unsigned long long) (t / table[i].usec), table[i].suffix);
return buf;
static const char * const table[] = {
int fd, r = 0;
return -errno;
if (vt < 0) {
r = -errno;
goto fail;
r = -errno;
fail:
assert(f);
size_t k;
return -ETIMEDOUT;
return -EIO;
if (need_nl)
*ret = c;
return -ETIMEDOUT;
return -EIO;
return -EBADMSG;
if (need_nl)
*need_nl = false;
bool on_tty;
bool need_nl = true;
if (on_tty)
if (on_tty)
if (r == -EBADMSG) {
if (need_nl)
*ret = c;
if (switch_to_text)
r = -errno;
goto finish;
r = -errno;
int fd, r;
if (fd < 0)
return fd;
int fd, r;
return -errno;
return -errno;
if (fd < 0)
return -errno;
return -errno;
return -ENOTTY;
return fd;
ssize_t l;
return -errno;
return -errno;
r = -errno;
goto fail;
r = -errno;
goto fail;
if (notify >= 0)
goto fail;
return fd;
r = -errno;
goto fail;
ssize_t l;
struct inotify_event *e;
r = -errno;
goto fail;
r = -EIO;
goto fail;
l -= step;
if (notify >= 0)
return fd;
fail:
if (fd >= 0)
if (notify >= 0)
int release_terminal(void) {
int r = 0, fd;
return -errno;
r = -errno;
int r = 0, sig;
r = -errno;
r = -errno;
r = -errno;
r = -errno;
r = -errno;
int close_pipe(int p[]) {
assert(p);
a = close_nointr(p[0]);
uint8_t *p;
ssize_t n = 0;
p = buf;
while (nbytes > 0) {
ssize_t k;
return n > 0 ? n : -errno;
return n > 0 ? n : -EIO;
return n > 0 ? n : (k < 0 ? -errno : 0);
nbytes -= k;
const uint8_t *p;
ssize_t n = 0;
p = buf;
while (nbytes > 0) {
ssize_t k;
return n > 0 ? n : -errno;
return n > 0 ? n : -EIO;
return n > 0 ? n : (k < 0 ? -errno : 0);
nbytes -= k;
const char *suffix;
} table[] = {
usec_t r = 0;
assert(t);
errno = 0;
if (errno != 0)
return -errno;
return -ERANGE;
return -EINVAL;
return -EINVAL;
*usec = r;
const char *suffix;
} table[] = {
off_t r = 0;
assert(t);
errno = 0;
if (errno != 0)
return -errno;
return -ERANGE;
return -EINVAL;
return -EINVAL;
*bytes = r;
return -errno;
int make_null_stdio(void) {
int null_fd;
return -errno;
DIR *d;
return -errno;
if (!de) {
closedir(d);
unsigned long long random_ull(void) {
int fd;
ssize_t r;
goto fallback;
if (r != sizeof(ull))
goto fallback;
return ull;
if (saved_argc > 0) {
if (saved_argv[0])
if (!saved_argv[i])
int sig;
char* gethostname_malloc(void) {
struct utsname u;
bool hostname_is_set(void) {
struct utsname u;
char* getlogname_malloc(void) {
long bufsize;
if (uid == 0)
return NULL;
return name;
return NULL;
return name;
assert(r);
return -ENOMEM;
free(s);
unsigned long ttynr;
FILE *f;
return -ENOMEM;
return -errno;
fclose(f);
fclose(f);
return -EIO;
return -EIO;
assert(r);
if (k != -ENOENT)
return -ENOMEM;
if (_devnr)
return -ENOMEM;
if (_devnr)
b = strdup(p);
free(s);
return -ENOMEM;
if (_devnr)
DIR *d;
int ret = 0;
if (r != 0 && ret == 0) {
ret = -r;
if (!de)
if (honour_sticky)
if (honour_sticky) {
if (is_dir) {
int subdir_fd;
if (subdir_fd < 0) {
if (r < 0 && ret == 0)
ret = r;
if (!keep_around)
closedir(d);
return ret;
int fd;
if (fd < 0) {
return -errno;
return -errno;
if (delete_root) {
r = -errno;
return -errno;
return -errno;
return -errno;
return -errno;
cpu_set_t *r;
if (!(r = CPU_ALLOC(n)))
return NULL;
if (ncpus)
*ncpus = n;
CPU_FREE(r);
return NULL;
char *s = NULL;
goto finish;
if (fd < 0)
goto finish;
if (ellipse) {
free(s);
if (status) {
free(s);
if (fd >= 0)
void status_welcome(void) {
NULL)) < 0) {
if (r != -ENOENT)
WORD,
char *r = NULL, *k;
for (e = format; *e; e ++) {
switch (state) {
case WORD:
case CURLY:
goto fail;
free(r);
goto fail;
free(r);
case VARIABLE:
if (!(k = strappend(r, t)))
goto fail;
free(r);
goto fail;
free(r);
fail:
free(r);
return NULL;
return NULL;
if (!(m = strv_split_quoted(e))) {
r[k] = NULL;
strv_free(r);
return NULL;
m = NULL;
q = strv_length(m);
r[k] = NULL;
strv_free(r);
strv_free(m);
return NULL;
memcpy(r + k, m, q * sizeof(char*));
free(m);
strv_free(r);
return NULL;
r[k] = NULL;
return -errno;
return -EIO;
unsigned columns(void) {
return parsed_columns;
if (parsed_columns <= 0)
if (parsed_columns <= 0)
return parsed_columns;
return -errno;
return -EIO;
unsigned lines(void) {
return parsed_lines;
if (parsed_lines <= 0)
if (parsed_lines <= 0)
return parsed_lines;
int running_in_chroot(void) {
struct stat a, b;
zero(a);
zero(b);
return -errno;
return -errno;
size_t x;
assert(s);
memcpy(r, s, x);
int fd;
return -errno;
size_t l;
assert(s);
l = strlen(s);
return strdup(s);
return strdup(s);
char *normalize_env_assignment(const char *s) {
if (!(r = strdup(s)))
return NULL;
return strstrip(r);
return NULL;
return NULL;
free(p);
if (!value) {
return NULL;
r = NULL;
if (!status)
return -errno;
return -EPROTO;
return -EPROTO;
sync();
pause();
return -errno;
int nfd;
DIR *d;
return NULL;
return NULL;
int signal_from_string_try_harder(const char *s) {
int signo;
assert(s);
return signo;
assert(f);
assert(t);
if (!dual_timestamp_is_set(t))
name,
(unsigned long long) t->realtime,
(unsigned long long) t->monotonic);
assert(t);
t->realtime = a;
t->monotonic = b;
char *fstab_node_to_udev_node(const char *p) {
char *dn, *t, *u;
return NULL;
free(u);
return NULL;
free(t);
return NULL;
return dn;
return NULL;
free(u);
return NULL;
free(t);
return NULL;
return dn;
return strdup(p);
return -EINVAL;
return -EINVAL;
return -EINVAL;
if (tty)
tty++;
d = _d;
goto finish;
char *path;
if (pid == 0) {
if (!argv) {
char *path;
goto finish;
if (_d)
if (pids)
if (!nulstr)
bool plymouth_running(void) {
assert(p);
assert(*p);
p = *buf;
*buf = p;
} sequence[] = {
p = *buf;
switch (sequence[i]) {
case SPACE:
case SPACE_OR_NUMBER:
case NUMBER:
case LETTER:
case COLON:
*buf = p;
assert(s);
if (l < strlen(s))
static bool hostname_valid_char(char c) {
bool hostname_is_valid(const char *s) {
if (isempty(s))
if (!hostname_valid_char(*p))
if (p-s > HOST_NAME_MAX)
char* hostname_cleanup(char *s) {
return -errno;
return -errno;
FILE *f;
const char *fn;
size_t k;
int fd;
return -ENOMEM;
if (fd < 0) {
free(t);
return -errno;
unlink(t);
free(t);
return -errno;
*_f = f;
*_temp_path = t;
return -errno;
int fd, r;
if (fd < 0)
return fd;
int fd, r;
return -EINVAL;
if (fd < 0)
return fd;
return -EINVAL;
return -EINVAL;
if (fd < 0)
return fd;
return -errno;
if (fd < 0)
return fd;
if (fdf < 0)
return -errno;
if (fdt < 0) {
return -errno;
ssize_t n, k;
r = -errno;
errno = 0;
struct stat a, b;
r = -ENOMEM;
goto finish;
r = -errno;
goto finish;
r = -errno;
goto finish;
const char *fn;
size_t k;
unsigned long long ull;
return -ENOMEM;
unlink(t);
free(t);
r = -errno;
unlink(t);
free(t);
free(t);
size_t k;
return -EINVAL;
return -ENOMEM;
*path = f;
struct passwd *p;
uid_t u;
if (uid)
*uid = 0;
if (gid)
*gid = 0;
if (home)
errno = 0;
p = getpwuid(u);
errno = 0;
if (uid)
if (gid)
if (home)
struct group *g;
if (gid)
*gid = 0;
errno = 0;
errno = 0;
if (gid)
int ngroups_max, r, i;
return -errno;
glob_t g;
zero(g);
errno = 0;
if (k == GLOB_NOMATCH)
else if (k == GLOB_NOSPACE)
r = -ENOMEM;
globfree(&g);
assert(d);
return -errno;
char **i, *parent;
DIR *d;
char **l = NULL;
return -errno;
goto finish;
if (!de)
if (list) {
t = realloc(l, sizeof(char*) * n);
r = -ENOMEM;
goto finish;
assert((unsigned) r < n);
r = -ENOMEM;
goto finish;
l[++r] = NULL;
closedir(d);
if (list)
*list = l;
strv_free(l);
char *join(const char *x, ...) {
size_t l;
l = strlen(x);
l += strlen(t);
return NULL;
p = stpcpy(r, x);
p = stpcpy(p, t);
bool is_main_thread(void) {
return cached > 0;
return -ENOMEM;
free(p);
*ret = d;
return -ENOMEM;
free(p);
return -ENOENT;
return -ENOMEM;
r = read_one_line_file(p, &s);
free(p);
free(s);
return -EINVAL;
return -ENOMEM;
free(p);
return -ENOENT;
int file_is_priv_sticky(const char *p) {
assert(p);
return -errno;
static const char *const ioprio_class_table[] = {
static const char *const sigchld_code_table[] = {
static const char *const log_level_table[] = {
static const char* const sched_policy_table[] = {
static const char* const rlimit_table[] = {
static const char* const ip_tos_table[] = {
static const char *const __signal_table[] = {
#ifdef SIGSTKFLT
const char *name;
if (name)
return name;
return buf;
int signal_from_string(const char *s) {
int signo;
int offset = 0;
if (signo > 0)
return signo;
if (safe_atou(s, &u) >= 0) {
return signo;
bool kexec_loaded(void) {
bool loaded = false;
loaded = true;
free(s);
return loaded;
int strdup_or_null(const char *a, char **b) {
assert(b);
*b = NULL;
c = strdup(a);
return -ENOMEM;
case O_RDONLY:
return PROT_READ;
case O_WRONLY:
return PROT_WRITE;
case O_RDWR:
return -EINVAL;
const char *suffix;
} table[] = {
goto finish;
return buf;
assert(p);
r = malloc(l);
return NULL;
memcpy(r, p, l);
int r, value;
l == sizeof(value) &&
value = (int) n;
return -errno;
int r, value;
l == sizeof(value) &&
value = (int) n;
return -errno;
int fd;
if (agent_pid < 0)
return -errno;
if (agent_pid != 0) {
if (fd < 0) {
if (!stdout_is_tty)
if (!stderr_is_tty)
return -errno;
return -errno;
FILE *f;
bool done = false;
size_t l;
if (pid == 0)
return -errno;
c = getc(f);
done = true;
line[i] = c;
line[i] = 0;
if (!value) {
r = -ENOMEM;
} while (!done);
fclose(f);
char *p, *w, *state;
size_t l, k;
bool found = false;
return r == -ENOENT ? 0 : r;
found = true;
free(p);
return found;