199ca880aSopenharmony_ci/***
299ca880aSopenharmony_ci  This file is part of eudev, forked from systemd.
399ca880aSopenharmony_ci
499ca880aSopenharmony_ci  Copyright 2010 Lennart Poettering
599ca880aSopenharmony_ci
699ca880aSopenharmony_ci  systemd is free software; you can redistribute it and/or modify it
799ca880aSopenharmony_ci  under the terms of the GNU Lesser General Public License as published by
899ca880aSopenharmony_ci  the Free Software Foundation; either version 2.1 of the License, or
999ca880aSopenharmony_ci  (at your option) any later version.
1099ca880aSopenharmony_ci
1199ca880aSopenharmony_ci  systemd is distributed in the hope that it will be useful, but
1299ca880aSopenharmony_ci  WITHOUT ANY WARRANTY; without even the implied warranty of
1399ca880aSopenharmony_ci  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
1499ca880aSopenharmony_ci  Lesser General Public License for more details.
1599ca880aSopenharmony_ci
1699ca880aSopenharmony_ci  You should have received a copy of the GNU Lesser General Public License
1799ca880aSopenharmony_ci  along with systemd; If not, see <http://www.gnu.org/licenses/>.
1899ca880aSopenharmony_ci***/
1999ca880aSopenharmony_ci
2099ca880aSopenharmony_ci#include <assert.h>
2199ca880aSopenharmony_ci#include <string.h>
2299ca880aSopenharmony_ci#include <unistd.h>
2399ca880aSopenharmony_ci#include <errno.h>
2499ca880aSopenharmony_ci#include <stdlib.h>
2599ca880aSopenharmony_ci#include <signal.h>
2699ca880aSopenharmony_ci#include <stdio.h>
2799ca880aSopenharmony_ci#include <syslog.h>
2899ca880aSopenharmony_ci#include <sched.h>
2999ca880aSopenharmony_ci#include <sys/resource.h>
3099ca880aSopenharmony_ci#include <linux/sched.h>
3199ca880aSopenharmony_ci#include <sys/types.h>
3299ca880aSopenharmony_ci#include <sys/stat.h>
3399ca880aSopenharmony_ci#include <fcntl.h>
3499ca880aSopenharmony_ci#include <dirent.h>
3599ca880aSopenharmony_ci#include <sys/ioctl.h>
3699ca880aSopenharmony_ci#include <stdarg.h>
3799ca880aSopenharmony_ci#include <poll.h>
3899ca880aSopenharmony_ci#include <ctype.h>
3999ca880aSopenharmony_ci#include <sys/prctl.h>
4099ca880aSopenharmony_ci#include <sys/utsname.h>
4199ca880aSopenharmony_ci#include <pwd.h>
4299ca880aSopenharmony_ci#include <netinet/ip.h>
4399ca880aSopenharmony_ci#include <linux/kd.h>
4499ca880aSopenharmony_ci#include <dlfcn.h>
4599ca880aSopenharmony_ci#include <sys/wait.h>
4699ca880aSopenharmony_ci#include <sys/time.h>
4799ca880aSopenharmony_ci#include <glob.h>
4899ca880aSopenharmony_ci#include <grp.h>
4999ca880aSopenharmony_ci#include <sys/mman.h>
5099ca880aSopenharmony_ci#include <sys/vfs.h>
5199ca880aSopenharmony_ci#include <linux/magic.h>
5299ca880aSopenharmony_ci#include <limits.h>
5399ca880aSopenharmony_ci#include <locale.h>
5499ca880aSopenharmony_ci#include <libgen.h>
5599ca880aSopenharmony_ci
5699ca880aSopenharmony_ci#include "macro.h"
5799ca880aSopenharmony_ci#include "util.h"
5899ca880aSopenharmony_ci#include "ioprio.h"
5999ca880aSopenharmony_ci#include "missing.h"
6099ca880aSopenharmony_ci#include "log.h"
6199ca880aSopenharmony_ci#include "strv.h"
6299ca880aSopenharmony_ci#include "mkdir.h"
6399ca880aSopenharmony_ci#include "path-util.h"
6499ca880aSopenharmony_ci#include "hashmap.h"
6599ca880aSopenharmony_ci#include "fileio.h"
6699ca880aSopenharmony_ci#include "utf8.h"
6799ca880aSopenharmony_ci#include "virt.h"
6899ca880aSopenharmony_ci#include "process-util.h"
6999ca880aSopenharmony_ci#include "random-util.h"
7099ca880aSopenharmony_ci#include "terminal-util.h"
7199ca880aSopenharmony_ci
7299ca880aSopenharmony_ci/* Put this test here for a lack of better place */
7399ca880aSopenharmony_ciassert_cc(EAGAIN == EWOULDBLOCK);
7499ca880aSopenharmony_ci
7599ca880aSopenharmony_ciint saved_argc = 0;
7699ca880aSopenharmony_cichar **saved_argv = NULL;
7799ca880aSopenharmony_ci
7899ca880aSopenharmony_cisize_t page_size(void) {
7999ca880aSopenharmony_ci        static thread_local size_t pgsz = 0;
8099ca880aSopenharmony_ci        long r;
8199ca880aSopenharmony_ci
8299ca880aSopenharmony_ci        if (_likely_(pgsz > 0))
8399ca880aSopenharmony_ci                return pgsz;
8499ca880aSopenharmony_ci
8599ca880aSopenharmony_ci        r = sysconf(_SC_PAGESIZE);
8699ca880aSopenharmony_ci        assert(r > 0);
8799ca880aSopenharmony_ci
8899ca880aSopenharmony_ci        pgsz = (size_t) r;
8999ca880aSopenharmony_ci        return pgsz;
9099ca880aSopenharmony_ci}
9199ca880aSopenharmony_ci
9299ca880aSopenharmony_cibool streq_ptr(const char *a, const char *b) {
9399ca880aSopenharmony_ci
9499ca880aSopenharmony_ci        /* Like streq(), but tries to make sense of NULL pointers */
9599ca880aSopenharmony_ci
9699ca880aSopenharmony_ci        if (a && b)
9799ca880aSopenharmony_ci                return streq(a, b);
9899ca880aSopenharmony_ci
9999ca880aSopenharmony_ci        if (!a && !b)
10099ca880aSopenharmony_ci                return true;
10199ca880aSopenharmony_ci
10299ca880aSopenharmony_ci        return false;
10399ca880aSopenharmony_ci}
10499ca880aSopenharmony_ci
10599ca880aSopenharmony_cichar* endswith(const char *s, const char *postfix) {
10699ca880aSopenharmony_ci        size_t sl, pl;
10799ca880aSopenharmony_ci
10899ca880aSopenharmony_ci        assert(s);
10999ca880aSopenharmony_ci        assert(postfix);
11099ca880aSopenharmony_ci
11199ca880aSopenharmony_ci        sl = strlen(s);
11299ca880aSopenharmony_ci        pl = strlen(postfix);
11399ca880aSopenharmony_ci
11499ca880aSopenharmony_ci        if (pl == 0)
11599ca880aSopenharmony_ci                return (char*) s + sl;
11699ca880aSopenharmony_ci
11799ca880aSopenharmony_ci        if (sl < pl)
11899ca880aSopenharmony_ci                return NULL;
11999ca880aSopenharmony_ci
12099ca880aSopenharmony_ci        if (memcmp(s + sl - pl, postfix, pl) != 0)
12199ca880aSopenharmony_ci                return NULL;
12299ca880aSopenharmony_ci
12399ca880aSopenharmony_ci        return (char*) s + sl - pl;
12499ca880aSopenharmony_ci}
12599ca880aSopenharmony_ci
12699ca880aSopenharmony_cisize_t cescape_char(char c, char *buf) {
12799ca880aSopenharmony_ci        char * buf_old = buf;
12899ca880aSopenharmony_ci
12999ca880aSopenharmony_ci        switch (c) {
13099ca880aSopenharmony_ci
13199ca880aSopenharmony_ci                case '\a':
13299ca880aSopenharmony_ci                        *(buf++) = '\\';
13399ca880aSopenharmony_ci                        *(buf++) = 'a';
13499ca880aSopenharmony_ci                        break;
13599ca880aSopenharmony_ci                case '\b':
13699ca880aSopenharmony_ci                        *(buf++) = '\\';
13799ca880aSopenharmony_ci                        *(buf++) = 'b';
13899ca880aSopenharmony_ci                        break;
13999ca880aSopenharmony_ci                case '\f':
14099ca880aSopenharmony_ci                        *(buf++) = '\\';
14199ca880aSopenharmony_ci                        *(buf++) = 'f';
14299ca880aSopenharmony_ci                        break;
14399ca880aSopenharmony_ci                case '\n':
14499ca880aSopenharmony_ci                        *(buf++) = '\\';
14599ca880aSopenharmony_ci                        *(buf++) = 'n';
14699ca880aSopenharmony_ci                        break;
14799ca880aSopenharmony_ci                case '\r':
14899ca880aSopenharmony_ci                        *(buf++) = '\\';
14999ca880aSopenharmony_ci                        *(buf++) = 'r';
15099ca880aSopenharmony_ci                        break;
15199ca880aSopenharmony_ci                case '\t':
15299ca880aSopenharmony_ci                        *(buf++) = '\\';
15399ca880aSopenharmony_ci                        *(buf++) = 't';
15499ca880aSopenharmony_ci                        break;
15599ca880aSopenharmony_ci                case '\v':
15699ca880aSopenharmony_ci                        *(buf++) = '\\';
15799ca880aSopenharmony_ci                        *(buf++) = 'v';
15899ca880aSopenharmony_ci                        break;
15999ca880aSopenharmony_ci                case '\\':
16099ca880aSopenharmony_ci                        *(buf++) = '\\';
16199ca880aSopenharmony_ci                        *(buf++) = '\\';
16299ca880aSopenharmony_ci                        break;
16399ca880aSopenharmony_ci                case '"':
16499ca880aSopenharmony_ci                        *(buf++) = '\\';
16599ca880aSopenharmony_ci                        *(buf++) = '"';
16699ca880aSopenharmony_ci                        break;
16799ca880aSopenharmony_ci                case '\'':
16899ca880aSopenharmony_ci                        *(buf++) = '\\';
16999ca880aSopenharmony_ci                        *(buf++) = '\'';
17099ca880aSopenharmony_ci                        break;
17199ca880aSopenharmony_ci
17299ca880aSopenharmony_ci                default:
17399ca880aSopenharmony_ci                        /* For special chars we prefer octal over
17499ca880aSopenharmony_ci                         * hexadecimal encoding, simply because glib's
17599ca880aSopenharmony_ci                         * g_strescape() does the same */
17699ca880aSopenharmony_ci                        if ((c < ' ') || (c >= 127)) {
17799ca880aSopenharmony_ci                                *(buf++) = '\\';
17899ca880aSopenharmony_ci                                *(buf++) = octchar((unsigned char) c >> 6);
17999ca880aSopenharmony_ci                                *(buf++) = octchar((unsigned char) c >> 3);
18099ca880aSopenharmony_ci                                *(buf++) = octchar((unsigned char) c);
18199ca880aSopenharmony_ci                        } else
18299ca880aSopenharmony_ci                                *(buf++) = c;
18399ca880aSopenharmony_ci                        break;
18499ca880aSopenharmony_ci        }
18599ca880aSopenharmony_ci
18699ca880aSopenharmony_ci        return buf - buf_old;
18799ca880aSopenharmony_ci}
18899ca880aSopenharmony_ci
18999ca880aSopenharmony_ciint close_nointr(int fd) {
19099ca880aSopenharmony_ci        assert(fd >= 0);
19199ca880aSopenharmony_ci
19299ca880aSopenharmony_ci        if (close(fd) >= 0)
19399ca880aSopenharmony_ci                return 0;
19499ca880aSopenharmony_ci
19599ca880aSopenharmony_ci        /*
19699ca880aSopenharmony_ci         * Just ignore EINTR; a retry loop is the wrong thing to do on
19799ca880aSopenharmony_ci         * Linux.
19899ca880aSopenharmony_ci         *
19999ca880aSopenharmony_ci         * http://lkml.indiana.edu/hypermail/linux/kernel/0509.1/0877.html
20099ca880aSopenharmony_ci         * https://bugzilla.gnome.org/show_bug.cgi?id=682819
20199ca880aSopenharmony_ci         * http://utcc.utoronto.ca/~cks/space/blog/unix/CloseEINTR
20299ca880aSopenharmony_ci         * https://sites.google.com/site/michaelsafyan/software-engineering/checkforeintrwheninvokingclosethinkagain
20399ca880aSopenharmony_ci         */
20499ca880aSopenharmony_ci        if (errno == EINTR)
20599ca880aSopenharmony_ci                return 0;
20699ca880aSopenharmony_ci
20799ca880aSopenharmony_ci        return -errno;
20899ca880aSopenharmony_ci}
20999ca880aSopenharmony_ci
21099ca880aSopenharmony_ciint safe_close(int fd) {
21199ca880aSopenharmony_ci
21299ca880aSopenharmony_ci        /*
21399ca880aSopenharmony_ci         * Like close_nointr() but cannot fail. Guarantees errno is
21499ca880aSopenharmony_ci         * unchanged. Is a NOP with negative fds passed, and returns
21599ca880aSopenharmony_ci         * -1, so that it can be used in this syntax:
21699ca880aSopenharmony_ci         *
21799ca880aSopenharmony_ci         * fd = safe_close(fd);
21899ca880aSopenharmony_ci         */
21999ca880aSopenharmony_ci
22099ca880aSopenharmony_ci        if (fd >= 0) {
22199ca880aSopenharmony_ci                PROTECT_ERRNO;
22299ca880aSopenharmony_ci
22399ca880aSopenharmony_ci                /* The kernel might return pretty much any error code
22499ca880aSopenharmony_ci                 * via close(), but the fd will be closed anyway. The
22599ca880aSopenharmony_ci                 * only condition we want to check for here is whether
22699ca880aSopenharmony_ci                 * the fd was invalid at all... */
22799ca880aSopenharmony_ci
22899ca880aSopenharmony_ci                assert_se(close_nointr(fd) != -EBADF);
22999ca880aSopenharmony_ci        }
23099ca880aSopenharmony_ci
23199ca880aSopenharmony_ci        return -1;
23299ca880aSopenharmony_ci}
23399ca880aSopenharmony_ci
23499ca880aSopenharmony_civoid close_many(const int fds[], unsigned n_fd) {
23599ca880aSopenharmony_ci        unsigned i;
23699ca880aSopenharmony_ci
23799ca880aSopenharmony_ci        assert(fds || n_fd <= 0);
23899ca880aSopenharmony_ci
23999ca880aSopenharmony_ci        for (i = 0; i < n_fd; i++)
24099ca880aSopenharmony_ci                safe_close(fds[i]);
24199ca880aSopenharmony_ci}
24299ca880aSopenharmony_ci
24399ca880aSopenharmony_ciint unlink_noerrno(const char *path) {
24499ca880aSopenharmony_ci        PROTECT_ERRNO;
24599ca880aSopenharmony_ci        int r;
24699ca880aSopenharmony_ci
24799ca880aSopenharmony_ci        r = unlink(path);
24899ca880aSopenharmony_ci        if (r < 0)
24999ca880aSopenharmony_ci                return -errno;
25099ca880aSopenharmony_ci
25199ca880aSopenharmony_ci        return 0;
25299ca880aSopenharmony_ci}
25399ca880aSopenharmony_ci
25499ca880aSopenharmony_ciint parse_uid(const char *s, uid_t* ret_uid) {
25599ca880aSopenharmony_ci        unsigned long ul = 0;
25699ca880aSopenharmony_ci        uid_t uid;
25799ca880aSopenharmony_ci        int r;
25899ca880aSopenharmony_ci
25999ca880aSopenharmony_ci        assert(s);
26099ca880aSopenharmony_ci
26199ca880aSopenharmony_ci        r = safe_atolu(s, &ul);
26299ca880aSopenharmony_ci        if (r < 0)
26399ca880aSopenharmony_ci                return r;
26499ca880aSopenharmony_ci
26599ca880aSopenharmony_ci        uid = (uid_t) ul;
26699ca880aSopenharmony_ci
26799ca880aSopenharmony_ci        if ((unsigned long) uid != ul)
26899ca880aSopenharmony_ci                return -ERANGE;
26999ca880aSopenharmony_ci
27099ca880aSopenharmony_ci        /* Some libc APIs use UID_INVALID as special placeholder */
27199ca880aSopenharmony_ci        if (uid == (uid_t) 0xFFFFFFFF)
27299ca880aSopenharmony_ci                return -ENXIO;
27399ca880aSopenharmony_ci
27499ca880aSopenharmony_ci        /* A long time ago UIDs where 16bit, hence explicitly avoid the 16bit -1 too */
27599ca880aSopenharmony_ci        if (uid == (uid_t) 0xFFFF)
27699ca880aSopenharmony_ci                return -ENXIO;
27799ca880aSopenharmony_ci
27899ca880aSopenharmony_ci        if (ret_uid)
27999ca880aSopenharmony_ci                *ret_uid = uid;
28099ca880aSopenharmony_ci
28199ca880aSopenharmony_ci        return 0;
28299ca880aSopenharmony_ci}
28399ca880aSopenharmony_ci
28499ca880aSopenharmony_ciint safe_atou(const char *s, unsigned *ret_u) {
28599ca880aSopenharmony_ci        char *x = NULL;
28699ca880aSopenharmony_ci        unsigned long l;
28799ca880aSopenharmony_ci
28899ca880aSopenharmony_ci        assert(s);
28999ca880aSopenharmony_ci        assert(ret_u);
29099ca880aSopenharmony_ci
29199ca880aSopenharmony_ci        errno = 0;
29299ca880aSopenharmony_ci        l = strtoul(s, &x, 0);
29399ca880aSopenharmony_ci
29499ca880aSopenharmony_ci        if (!x || x == s || *x || errno)
29599ca880aSopenharmony_ci                return errno > 0 ? -errno : -EINVAL;
29699ca880aSopenharmony_ci
29799ca880aSopenharmony_ci        if ((unsigned long) (unsigned) l != l)
29899ca880aSopenharmony_ci                return -ERANGE;
29999ca880aSopenharmony_ci
30099ca880aSopenharmony_ci        *ret_u = (unsigned) l;
30199ca880aSopenharmony_ci        return 0;
30299ca880aSopenharmony_ci}
30399ca880aSopenharmony_ci
30499ca880aSopenharmony_ciint safe_atoi(const char *s, int *ret_i) {
30599ca880aSopenharmony_ci        char *x = NULL;
30699ca880aSopenharmony_ci        long l;
30799ca880aSopenharmony_ci
30899ca880aSopenharmony_ci        assert(s);
30999ca880aSopenharmony_ci        assert(ret_i);
31099ca880aSopenharmony_ci
31199ca880aSopenharmony_ci        errno = 0;
31299ca880aSopenharmony_ci        l = strtol(s, &x, 0);
31399ca880aSopenharmony_ci
31499ca880aSopenharmony_ci        if (!x || x == s || *x || errno)
31599ca880aSopenharmony_ci                return errno > 0 ? -errno : -EINVAL;
31699ca880aSopenharmony_ci
31799ca880aSopenharmony_ci        if ((long) (int) l != l)
31899ca880aSopenharmony_ci                return -ERANGE;
31999ca880aSopenharmony_ci
32099ca880aSopenharmony_ci        *ret_i = (int) l;
32199ca880aSopenharmony_ci        return 0;
32299ca880aSopenharmony_ci}
32399ca880aSopenharmony_ci
32499ca880aSopenharmony_ciint safe_atollu(const char *s, long long unsigned *ret_llu) {
32599ca880aSopenharmony_ci        char *x = NULL;
32699ca880aSopenharmony_ci        unsigned long long l;
32799ca880aSopenharmony_ci
32899ca880aSopenharmony_ci        assert(s);
32999ca880aSopenharmony_ci        assert(ret_llu);
33099ca880aSopenharmony_ci
33199ca880aSopenharmony_ci        errno = 0;
33299ca880aSopenharmony_ci        l = strtoull(s, &x, 0);
33399ca880aSopenharmony_ci
33499ca880aSopenharmony_ci        if (!x || x == s || *x || errno)
33599ca880aSopenharmony_ci                return errno ? -errno : -EINVAL;
33699ca880aSopenharmony_ci
33799ca880aSopenharmony_ci        *ret_llu = l;
33899ca880aSopenharmony_ci        return 0;
33999ca880aSopenharmony_ci}
34099ca880aSopenharmony_ci
34199ca880aSopenharmony_ciint safe_atolli(const char *s, long long int *ret_lli) {
34299ca880aSopenharmony_ci        char *x = NULL;
34399ca880aSopenharmony_ci        long long l;
34499ca880aSopenharmony_ci
34599ca880aSopenharmony_ci        assert(s);
34699ca880aSopenharmony_ci        assert(ret_lli);
34799ca880aSopenharmony_ci
34899ca880aSopenharmony_ci        errno = 0;
34999ca880aSopenharmony_ci        l = strtoll(s, &x, 0);
35099ca880aSopenharmony_ci
35199ca880aSopenharmony_ci        if (!x || x == s || *x || errno)
35299ca880aSopenharmony_ci                return errno ? -errno : -EINVAL;
35399ca880aSopenharmony_ci
35499ca880aSopenharmony_ci        *ret_lli = l;
35599ca880aSopenharmony_ci        return 0;
35699ca880aSopenharmony_ci}
35799ca880aSopenharmony_ci
35899ca880aSopenharmony_cistatic size_t strcspn_escaped(const char *s, const char *reject) {
35999ca880aSopenharmony_ci        bool escaped = false;
36099ca880aSopenharmony_ci        int n;
36199ca880aSopenharmony_ci
36299ca880aSopenharmony_ci        for (n=0; s[n]; n++) {
36399ca880aSopenharmony_ci                if (escaped)
36499ca880aSopenharmony_ci                        escaped = false;
36599ca880aSopenharmony_ci                else if (s[n] == '\\')
36699ca880aSopenharmony_ci                        escaped = true;
36799ca880aSopenharmony_ci                else if (strchr(reject, s[n]))
36899ca880aSopenharmony_ci                        break;
36999ca880aSopenharmony_ci        }
37099ca880aSopenharmony_ci
37199ca880aSopenharmony_ci        /* if s ends in \, return index of previous char */
37299ca880aSopenharmony_ci        return n - escaped;
37399ca880aSopenharmony_ci}
37499ca880aSopenharmony_ci
37599ca880aSopenharmony_ci/* Split a string into words. */
37699ca880aSopenharmony_ciconst char* split(const char **state, size_t *l, const char *separator, bool quoted) {
37799ca880aSopenharmony_ci        const char *current;
37899ca880aSopenharmony_ci
37999ca880aSopenharmony_ci        current = *state;
38099ca880aSopenharmony_ci
38199ca880aSopenharmony_ci        if (!*current) {
38299ca880aSopenharmony_ci                assert(**state == '\0');
38399ca880aSopenharmony_ci                return NULL;
38499ca880aSopenharmony_ci        }
38599ca880aSopenharmony_ci
38699ca880aSopenharmony_ci        current += strspn(current, separator);
38799ca880aSopenharmony_ci        if (!*current) {
38899ca880aSopenharmony_ci                *state = current;
38999ca880aSopenharmony_ci                return NULL;
39099ca880aSopenharmony_ci        }
39199ca880aSopenharmony_ci
39299ca880aSopenharmony_ci        if (quoted && strchr("\'\"", *current)) {
39399ca880aSopenharmony_ci                char quotechars[2] = {*current, '\0'};
39499ca880aSopenharmony_ci
39599ca880aSopenharmony_ci                *l = strcspn_escaped(current + 1, quotechars);
39699ca880aSopenharmony_ci                if (current[*l + 1] == '\0' || current[*l + 1] != quotechars[0] ||
39799ca880aSopenharmony_ci                    (current[*l + 2] && !strchr(separator, current[*l + 2]))) {
39899ca880aSopenharmony_ci                        /* right quote missing or garbage at the end */
39999ca880aSopenharmony_ci                        *state = current;
40099ca880aSopenharmony_ci                        return NULL;
40199ca880aSopenharmony_ci                }
40299ca880aSopenharmony_ci                *state = current++ + *l + 2;
40399ca880aSopenharmony_ci        } else if (quoted) {
40499ca880aSopenharmony_ci                *l = strcspn_escaped(current, separator);
40599ca880aSopenharmony_ci                if (current[*l] && !strchr(separator, current[*l])) {
40699ca880aSopenharmony_ci                        /* unfinished escape */
40799ca880aSopenharmony_ci                        *state = current;
40899ca880aSopenharmony_ci                        return NULL;
40999ca880aSopenharmony_ci                }
41099ca880aSopenharmony_ci                *state = current + *l;
41199ca880aSopenharmony_ci        } else {
41299ca880aSopenharmony_ci                *l = strcspn(current, separator);
41399ca880aSopenharmony_ci                *state = current + *l;
41499ca880aSopenharmony_ci        }
41599ca880aSopenharmony_ci
41699ca880aSopenharmony_ci        return current;
41799ca880aSopenharmony_ci}
41899ca880aSopenharmony_ci
41999ca880aSopenharmony_cichar *truncate_nl(char *s) {
42099ca880aSopenharmony_ci        assert(s);
42199ca880aSopenharmony_ci
42299ca880aSopenharmony_ci        s[strcspn(s, NEWLINE)] = 0;
42399ca880aSopenharmony_ci        return s;
42499ca880aSopenharmony_ci}
42599ca880aSopenharmony_ci
42699ca880aSopenharmony_cichar *strnappend(const char *s, const char *suffix, size_t b) {
42799ca880aSopenharmony_ci        size_t a;
42899ca880aSopenharmony_ci        char *r;
42999ca880aSopenharmony_ci
43099ca880aSopenharmony_ci        if (!s && !suffix)
43199ca880aSopenharmony_ci                return strdup("");
43299ca880aSopenharmony_ci
43399ca880aSopenharmony_ci        if (!s)
43499ca880aSopenharmony_ci                return strndup(suffix, b);
43599ca880aSopenharmony_ci
43699ca880aSopenharmony_ci        if (!suffix)
43799ca880aSopenharmony_ci                return strdup(s);
43899ca880aSopenharmony_ci
43999ca880aSopenharmony_ci        assert(s);
44099ca880aSopenharmony_ci        assert(suffix);
44199ca880aSopenharmony_ci
44299ca880aSopenharmony_ci        a = strlen(s);
44399ca880aSopenharmony_ci        if (b > ((size_t) -1) - a)
44499ca880aSopenharmony_ci                return NULL;
44599ca880aSopenharmony_ci
44699ca880aSopenharmony_ci        r = new(char, a+b+1);
44799ca880aSopenharmony_ci        if (!r)
44899ca880aSopenharmony_ci                return NULL;
44999ca880aSopenharmony_ci
45099ca880aSopenharmony_ci        memcpy(r, s, a);
45199ca880aSopenharmony_ci        memcpy(r+a, suffix, b);
45299ca880aSopenharmony_ci        r[a+b] = 0;
45399ca880aSopenharmony_ci
45499ca880aSopenharmony_ci        return r;
45599ca880aSopenharmony_ci}
45699ca880aSopenharmony_ci
45799ca880aSopenharmony_cichar *strappend(const char *s, const char *suffix) {
45899ca880aSopenharmony_ci        return strnappend(s, suffix, suffix ? strlen(suffix) : 0);
45999ca880aSopenharmony_ci}
46099ca880aSopenharmony_ci
46199ca880aSopenharmony_ciint rmdir_parents(const char *path, const char *stop) {
46299ca880aSopenharmony_ci        size_t l;
46399ca880aSopenharmony_ci        int r = 0;
46499ca880aSopenharmony_ci
46599ca880aSopenharmony_ci        assert(path);
46699ca880aSopenharmony_ci        assert(stop);
46799ca880aSopenharmony_ci
46899ca880aSopenharmony_ci        l = strlen(path);
46999ca880aSopenharmony_ci
47099ca880aSopenharmony_ci        /* Skip trailing slashes */
47199ca880aSopenharmony_ci        while (l > 0 && path[l-1] == '/')
47299ca880aSopenharmony_ci                l--;
47399ca880aSopenharmony_ci
47499ca880aSopenharmony_ci        while (l > 0) {
47599ca880aSopenharmony_ci                char *t;
47699ca880aSopenharmony_ci
47799ca880aSopenharmony_ci                /* Skip last component */
47899ca880aSopenharmony_ci                while (l > 0 && path[l-1] != '/')
47999ca880aSopenharmony_ci                        l--;
48099ca880aSopenharmony_ci
48199ca880aSopenharmony_ci                /* Skip trailing slashes */
48299ca880aSopenharmony_ci                while (l > 0 && path[l-1] == '/')
48399ca880aSopenharmony_ci                        l--;
48499ca880aSopenharmony_ci
48599ca880aSopenharmony_ci                if (l <= 0)
48699ca880aSopenharmony_ci                        break;
48799ca880aSopenharmony_ci
48899ca880aSopenharmony_ci                if (!(t = strndup(path, l)))
48999ca880aSopenharmony_ci                        return -ENOMEM;
49099ca880aSopenharmony_ci
49199ca880aSopenharmony_ci                if (path_startswith(stop, t)) {
49299ca880aSopenharmony_ci                        free(t);
49399ca880aSopenharmony_ci                        return 0;
49499ca880aSopenharmony_ci                }
49599ca880aSopenharmony_ci
49699ca880aSopenharmony_ci                r = rmdir(t);
49799ca880aSopenharmony_ci                free(t);
49899ca880aSopenharmony_ci
49999ca880aSopenharmony_ci                if (r < 0)
50099ca880aSopenharmony_ci                        if (errno != ENOENT)
50199ca880aSopenharmony_ci                                return -errno;
50299ca880aSopenharmony_ci        }
50399ca880aSopenharmony_ci
50499ca880aSopenharmony_ci        return 0;
50599ca880aSopenharmony_ci}
50699ca880aSopenharmony_ci
50799ca880aSopenharmony_cichar hexchar(int x) {
50899ca880aSopenharmony_ci        static const char table[16] = "0123456789abcdef";
50999ca880aSopenharmony_ci
51099ca880aSopenharmony_ci        return table[x & 15];
51199ca880aSopenharmony_ci}
51299ca880aSopenharmony_ci
51399ca880aSopenharmony_ciint unhexchar(char c) {
51499ca880aSopenharmony_ci
51599ca880aSopenharmony_ci        if (c >= '0' && c <= '9')
51699ca880aSopenharmony_ci                return c - '0';
51799ca880aSopenharmony_ci
51899ca880aSopenharmony_ci        if (c >= 'a' && c <= 'f')
51999ca880aSopenharmony_ci                return c - 'a' + 10;
52099ca880aSopenharmony_ci
52199ca880aSopenharmony_ci        if (c >= 'A' && c <= 'F')
52299ca880aSopenharmony_ci                return c - 'A' + 10;
52399ca880aSopenharmony_ci
52499ca880aSopenharmony_ci        return -EINVAL;
52599ca880aSopenharmony_ci}
52699ca880aSopenharmony_ci
52799ca880aSopenharmony_cichar octchar(int x) {
52899ca880aSopenharmony_ci        return '0' + (x & 7);
52999ca880aSopenharmony_ci}
53099ca880aSopenharmony_ci
53199ca880aSopenharmony_ciint unoctchar(char c) {
53299ca880aSopenharmony_ci
53399ca880aSopenharmony_ci        if (c >= '0' && c <= '7')
53499ca880aSopenharmony_ci                return c - '0';
53599ca880aSopenharmony_ci
53699ca880aSopenharmony_ci        return -EINVAL;
53799ca880aSopenharmony_ci}
53899ca880aSopenharmony_ci
53999ca880aSopenharmony_cichar *cescape(const char *s) {
54099ca880aSopenharmony_ci        char *r, *t;
54199ca880aSopenharmony_ci        const char *f;
54299ca880aSopenharmony_ci
54399ca880aSopenharmony_ci        assert(s);
54499ca880aSopenharmony_ci
54599ca880aSopenharmony_ci        /* Does C style string escaping. May be reversed with
54699ca880aSopenharmony_ci         * cunescape(). */
54799ca880aSopenharmony_ci
54899ca880aSopenharmony_ci        r = new(char, strlen(s)*4 + 1);
54999ca880aSopenharmony_ci        if (!r)
55099ca880aSopenharmony_ci                return NULL;
55199ca880aSopenharmony_ci
55299ca880aSopenharmony_ci        for (f = s, t = r; *f; f++)
55399ca880aSopenharmony_ci                t += cescape_char(*f, t);
55499ca880aSopenharmony_ci
55599ca880aSopenharmony_ci        *t = 0;
55699ca880aSopenharmony_ci
55799ca880aSopenharmony_ci        return r;
55899ca880aSopenharmony_ci}
55999ca880aSopenharmony_ci
56099ca880aSopenharmony_ci
56199ca880aSopenharmony_cistatic int cunescape_one(const char *p, size_t length, char *ret, uint32_t *ret_unicode) {
56299ca880aSopenharmony_ci        int r = 1;
56399ca880aSopenharmony_ci
56499ca880aSopenharmony_ci        assert(p);
56599ca880aSopenharmony_ci        assert(*p);
56699ca880aSopenharmony_ci        assert(ret);
56799ca880aSopenharmony_ci
56899ca880aSopenharmony_ci        /* Unescapes C style. Returns the unescaped character in ret,
56999ca880aSopenharmony_ci         * unless we encountered a \u sequence in which case the full
57099ca880aSopenharmony_ci         * unicode character is returned in ret_unicode, instead. */
57199ca880aSopenharmony_ci
57299ca880aSopenharmony_ci        if (length != (size_t) -1 && length < 1)
57399ca880aSopenharmony_ci                return -EINVAL;
57499ca880aSopenharmony_ci
57599ca880aSopenharmony_ci        switch (p[0]) {
57699ca880aSopenharmony_ci
57799ca880aSopenharmony_ci        case 'a':
57899ca880aSopenharmony_ci                *ret = '\a';
57999ca880aSopenharmony_ci                break;
58099ca880aSopenharmony_ci        case 'b':
58199ca880aSopenharmony_ci                *ret = '\b';
58299ca880aSopenharmony_ci                break;
58399ca880aSopenharmony_ci        case 'f':
58499ca880aSopenharmony_ci                *ret = '\f';
58599ca880aSopenharmony_ci                break;
58699ca880aSopenharmony_ci        case 'n':
58799ca880aSopenharmony_ci                *ret = '\n';
58899ca880aSopenharmony_ci                break;
58999ca880aSopenharmony_ci        case 'r':
59099ca880aSopenharmony_ci                *ret = '\r';
59199ca880aSopenharmony_ci                break;
59299ca880aSopenharmony_ci        case 't':
59399ca880aSopenharmony_ci                *ret = '\t';
59499ca880aSopenharmony_ci                break;
59599ca880aSopenharmony_ci        case 'v':
59699ca880aSopenharmony_ci                *ret = '\v';
59799ca880aSopenharmony_ci                break;
59899ca880aSopenharmony_ci        case '\\':
59999ca880aSopenharmony_ci                *ret = '\\';
60099ca880aSopenharmony_ci                break;
60199ca880aSopenharmony_ci        case '"':
60299ca880aSopenharmony_ci                *ret = '"';
60399ca880aSopenharmony_ci                break;
60499ca880aSopenharmony_ci        case '\'':
60599ca880aSopenharmony_ci                *ret = '\'';
60699ca880aSopenharmony_ci                break;
60799ca880aSopenharmony_ci
60899ca880aSopenharmony_ci        case 's':
60999ca880aSopenharmony_ci                /* This is an extension of the XDG syntax files */
61099ca880aSopenharmony_ci                *ret = ' ';
61199ca880aSopenharmony_ci                break;
61299ca880aSopenharmony_ci
61399ca880aSopenharmony_ci        case 'x': {
61499ca880aSopenharmony_ci                /* hexadecimal encoding */
61599ca880aSopenharmony_ci                int a, b;
61699ca880aSopenharmony_ci
61799ca880aSopenharmony_ci                if (length != (size_t) -1 && length < 3)
61899ca880aSopenharmony_ci                        return -EINVAL;
61999ca880aSopenharmony_ci
62099ca880aSopenharmony_ci                a = unhexchar(p[1]);
62199ca880aSopenharmony_ci                if (a < 0)
62299ca880aSopenharmony_ci                        return -EINVAL;
62399ca880aSopenharmony_ci
62499ca880aSopenharmony_ci                b = unhexchar(p[2]);
62599ca880aSopenharmony_ci                if (b < 0)
62699ca880aSopenharmony_ci                        return -EINVAL;
62799ca880aSopenharmony_ci
62899ca880aSopenharmony_ci                /* Don't allow NUL bytes */
62999ca880aSopenharmony_ci                if (a == 0 && b == 0)
63099ca880aSopenharmony_ci                        return -EINVAL;
63199ca880aSopenharmony_ci
63299ca880aSopenharmony_ci                *ret = (char) ((a << 4U) | b);
63399ca880aSopenharmony_ci                r = 3;
63499ca880aSopenharmony_ci                break;
63599ca880aSopenharmony_ci        }
63699ca880aSopenharmony_ci
63799ca880aSopenharmony_ci        case 'u': {
63899ca880aSopenharmony_ci                /* C++11 style 16bit unicode */
63999ca880aSopenharmony_ci
64099ca880aSopenharmony_ci                int a[4];
64199ca880aSopenharmony_ci                unsigned i;
64299ca880aSopenharmony_ci                uint32_t c;
64399ca880aSopenharmony_ci
64499ca880aSopenharmony_ci                if (length != (size_t) -1 && length < 5)
64599ca880aSopenharmony_ci                        return -EINVAL;
64699ca880aSopenharmony_ci
64799ca880aSopenharmony_ci                for (i = 0; i < 4; i++) {
64899ca880aSopenharmony_ci                        a[i] = unhexchar(p[1 + i]);
64999ca880aSopenharmony_ci                        if (a[i] < 0)
65099ca880aSopenharmony_ci                                return a[i];
65199ca880aSopenharmony_ci                }
65299ca880aSopenharmony_ci
65399ca880aSopenharmony_ci                c = ((uint32_t) a[0] << 12U) | ((uint32_t) a[1] << 8U) | ((uint32_t) a[2] << 4U) | (uint32_t) a[3];
65499ca880aSopenharmony_ci
65599ca880aSopenharmony_ci                /* Don't allow 0 chars */
65699ca880aSopenharmony_ci                if (c == 0)
65799ca880aSopenharmony_ci                        return -EINVAL;
65899ca880aSopenharmony_ci
65999ca880aSopenharmony_ci                if (c < 128)
66099ca880aSopenharmony_ci                        *ret = c;
66199ca880aSopenharmony_ci                else {
66299ca880aSopenharmony_ci                        if (!ret_unicode)
66399ca880aSopenharmony_ci                                return -EINVAL;
66499ca880aSopenharmony_ci
66599ca880aSopenharmony_ci                        *ret = 0;
66699ca880aSopenharmony_ci                        *ret_unicode = c;
66799ca880aSopenharmony_ci                }
66899ca880aSopenharmony_ci
66999ca880aSopenharmony_ci                r = 5;
67099ca880aSopenharmony_ci                break;
67199ca880aSopenharmony_ci        }
67299ca880aSopenharmony_ci
67399ca880aSopenharmony_ci        case 'U': {
67499ca880aSopenharmony_ci                /* C++11 style 32bit unicode */
67599ca880aSopenharmony_ci
67699ca880aSopenharmony_ci                int a[8];
67799ca880aSopenharmony_ci                unsigned i;
67899ca880aSopenharmony_ci                uint32_t c;
67999ca880aSopenharmony_ci
68099ca880aSopenharmony_ci                if (length != (size_t) -1 && length < 9)
68199ca880aSopenharmony_ci                        return -EINVAL;
68299ca880aSopenharmony_ci
68399ca880aSopenharmony_ci                for (i = 0; i < 8; i++) {
68499ca880aSopenharmony_ci                        a[i] = unhexchar(p[1 + i]);
68599ca880aSopenharmony_ci                        if (a[i] < 0)
68699ca880aSopenharmony_ci                                return a[i];
68799ca880aSopenharmony_ci                }
68899ca880aSopenharmony_ci
68999ca880aSopenharmony_ci                c = ((uint32_t) a[0] << 28U) | ((uint32_t) a[1] << 24U) | ((uint32_t) a[2] << 20U) | ((uint32_t) a[3] << 16U) |
69099ca880aSopenharmony_ci                    ((uint32_t) a[4] << 12U) | ((uint32_t) a[5] <<  8U) | ((uint32_t) a[6] <<  4U) |  (uint32_t) a[7];
69199ca880aSopenharmony_ci
69299ca880aSopenharmony_ci                /* Don't allow 0 chars */
69399ca880aSopenharmony_ci                if (c == 0)
69499ca880aSopenharmony_ci                        return -EINVAL;
69599ca880aSopenharmony_ci
69699ca880aSopenharmony_ci                /* Don't allow invalid code points */
69799ca880aSopenharmony_ci                if (!unichar_is_valid(c))
69899ca880aSopenharmony_ci                        return -EINVAL;
69999ca880aSopenharmony_ci
70099ca880aSopenharmony_ci                if (c < 128)
70199ca880aSopenharmony_ci                        *ret = c;
70299ca880aSopenharmony_ci                else {
70399ca880aSopenharmony_ci                        if (!ret_unicode)
70499ca880aSopenharmony_ci                                return -EINVAL;
70599ca880aSopenharmony_ci
70699ca880aSopenharmony_ci                        *ret = 0;
70799ca880aSopenharmony_ci                        *ret_unicode = c;
70899ca880aSopenharmony_ci                }
70999ca880aSopenharmony_ci
71099ca880aSopenharmony_ci                r = 9;
71199ca880aSopenharmony_ci                break;
71299ca880aSopenharmony_ci        }
71399ca880aSopenharmony_ci
71499ca880aSopenharmony_ci        case '0':
71599ca880aSopenharmony_ci        case '1':
71699ca880aSopenharmony_ci        case '2':
71799ca880aSopenharmony_ci        case '3':
71899ca880aSopenharmony_ci        case '4':
71999ca880aSopenharmony_ci        case '5':
72099ca880aSopenharmony_ci        case '6':
72199ca880aSopenharmony_ci        case '7': {
72299ca880aSopenharmony_ci                /* octal encoding */
72399ca880aSopenharmony_ci                int a, b, c;
72499ca880aSopenharmony_ci                uint32_t m;
72599ca880aSopenharmony_ci
72699ca880aSopenharmony_ci                if (length != (size_t) -1 && length < 4)
72799ca880aSopenharmony_ci                        return -EINVAL;
72899ca880aSopenharmony_ci
72999ca880aSopenharmony_ci                a = unoctchar(p[0]);
73099ca880aSopenharmony_ci                if (a < 0)
73199ca880aSopenharmony_ci                        return -EINVAL;
73299ca880aSopenharmony_ci
73399ca880aSopenharmony_ci                b = unoctchar(p[1]);
73499ca880aSopenharmony_ci                if (b < 0)
73599ca880aSopenharmony_ci                        return -EINVAL;
73699ca880aSopenharmony_ci
73799ca880aSopenharmony_ci                c = unoctchar(p[2]);
73899ca880aSopenharmony_ci                if (c < 0)
73999ca880aSopenharmony_ci                        return -EINVAL;
74099ca880aSopenharmony_ci
74199ca880aSopenharmony_ci                /* don't allow NUL bytes */
74299ca880aSopenharmony_ci                if (a == 0 && b == 0 && c == 0)
74399ca880aSopenharmony_ci                        return -EINVAL;
74499ca880aSopenharmony_ci
74599ca880aSopenharmony_ci                /* Don't allow bytes above 255 */
74699ca880aSopenharmony_ci                m = ((uint32_t) a << 6U) | ((uint32_t) b << 3U) | (uint32_t) c;
74799ca880aSopenharmony_ci                if (m > 255)
74899ca880aSopenharmony_ci                        return -EINVAL;
74999ca880aSopenharmony_ci
75099ca880aSopenharmony_ci                *ret = m;
75199ca880aSopenharmony_ci                r = 3;
75299ca880aSopenharmony_ci                break;
75399ca880aSopenharmony_ci        }
75499ca880aSopenharmony_ci
75599ca880aSopenharmony_ci        default:
75699ca880aSopenharmony_ci                return -EINVAL;
75799ca880aSopenharmony_ci        }
75899ca880aSopenharmony_ci
75999ca880aSopenharmony_ci        return r;
76099ca880aSopenharmony_ci}
76199ca880aSopenharmony_ci
76299ca880aSopenharmony_cichar *xescape(const char *s, const char *bad) {
76399ca880aSopenharmony_ci        char *r, *t;
76499ca880aSopenharmony_ci        const char *f;
76599ca880aSopenharmony_ci
76699ca880aSopenharmony_ci        /* Escapes all chars in bad, in addition to \ and all special
76799ca880aSopenharmony_ci         * chars, in \xFF style escaping. May be reversed with
76899ca880aSopenharmony_ci         * cunescape(). */
76999ca880aSopenharmony_ci
77099ca880aSopenharmony_ci        r = new(char, strlen(s) * 4 + 1);
77199ca880aSopenharmony_ci        if (!r)
77299ca880aSopenharmony_ci                return NULL;
77399ca880aSopenharmony_ci
77499ca880aSopenharmony_ci        for (f = s, t = r; *f; f++) {
77599ca880aSopenharmony_ci
77699ca880aSopenharmony_ci                if ((*f < ' ') || (*f >= 127) ||
77799ca880aSopenharmony_ci                    (*f == '\\') || strchr(bad, *f)) {
77899ca880aSopenharmony_ci                        *(t++) = '\\';
77999ca880aSopenharmony_ci                        *(t++) = 'x';
78099ca880aSopenharmony_ci                        *(t++) = hexchar(*f >> 4);
78199ca880aSopenharmony_ci                        *(t++) = hexchar(*f);
78299ca880aSopenharmony_ci                } else
78399ca880aSopenharmony_ci                        *(t++) = *f;
78499ca880aSopenharmony_ci        }
78599ca880aSopenharmony_ci
78699ca880aSopenharmony_ci        *t = 0;
78799ca880aSopenharmony_ci
78899ca880aSopenharmony_ci        return r;
78999ca880aSopenharmony_ci}
79099ca880aSopenharmony_ci
79199ca880aSopenharmony_ci_pure_ static bool hidden_file_allow_backup(const char *filename) {
79299ca880aSopenharmony_ci        assert(filename);
79399ca880aSopenharmony_ci
79499ca880aSopenharmony_ci        return
79599ca880aSopenharmony_ci                filename[0] == '.' ||
79699ca880aSopenharmony_ci                streq(filename, "lost+found") ||
79799ca880aSopenharmony_ci                streq(filename, "aquota.user") ||
79899ca880aSopenharmony_ci                streq(filename, "aquota.group") ||
79999ca880aSopenharmony_ci                endswith(filename, ".rpmnew") ||
80099ca880aSopenharmony_ci                endswith(filename, ".rpmsave") ||
80199ca880aSopenharmony_ci                endswith(filename, ".rpmorig") ||
80299ca880aSopenharmony_ci                endswith(filename, ".dpkg-old") ||
80399ca880aSopenharmony_ci                endswith(filename, ".dpkg-new") ||
80499ca880aSopenharmony_ci                endswith(filename, ".dpkg-tmp") ||
80599ca880aSopenharmony_ci                endswith(filename, ".dpkg-dist") ||
80699ca880aSopenharmony_ci                endswith(filename, ".dpkg-bak") ||
80799ca880aSopenharmony_ci                endswith(filename, ".dpkg-backup") ||
80899ca880aSopenharmony_ci                endswith(filename, ".dpkg-remove") ||
80999ca880aSopenharmony_ci                endswith(filename, ".swp");
81099ca880aSopenharmony_ci}
81199ca880aSopenharmony_ci
81299ca880aSopenharmony_cibool hidden_file(const char *filename) {
81399ca880aSopenharmony_ci        assert(filename);
81499ca880aSopenharmony_ci
81599ca880aSopenharmony_ci        if (endswith(filename, "~"))
81699ca880aSopenharmony_ci                return true;
81799ca880aSopenharmony_ci
81899ca880aSopenharmony_ci        return hidden_file_allow_backup(filename);
81999ca880aSopenharmony_ci}
82099ca880aSopenharmony_ci
82199ca880aSopenharmony_ciint flush_fd(int fd) {
82299ca880aSopenharmony_ci        struct pollfd pollfd = {
82399ca880aSopenharmony_ci                .fd = fd,
82499ca880aSopenharmony_ci                .events = POLLIN,
82599ca880aSopenharmony_ci        };
82699ca880aSopenharmony_ci
82799ca880aSopenharmony_ci        for (;;) {
82899ca880aSopenharmony_ci                char buf[LINE_MAX];
82999ca880aSopenharmony_ci                ssize_t l;
83099ca880aSopenharmony_ci                int r;
83199ca880aSopenharmony_ci
83299ca880aSopenharmony_ci                r = poll(&pollfd, 1, 0);
83399ca880aSopenharmony_ci                if (r < 0) {
83499ca880aSopenharmony_ci                        if (errno == EINTR)
83599ca880aSopenharmony_ci                                continue;
83699ca880aSopenharmony_ci
83799ca880aSopenharmony_ci                        return -errno;
83899ca880aSopenharmony_ci
83999ca880aSopenharmony_ci                } else if (r == 0)
84099ca880aSopenharmony_ci                        return 0;
84199ca880aSopenharmony_ci
84299ca880aSopenharmony_ci                l = read(fd, buf, sizeof(buf));
84399ca880aSopenharmony_ci                if (l < 0) {
84499ca880aSopenharmony_ci
84599ca880aSopenharmony_ci                        if (errno == EINTR)
84699ca880aSopenharmony_ci                                continue;
84799ca880aSopenharmony_ci
84899ca880aSopenharmony_ci                        if (errno == EAGAIN)
84999ca880aSopenharmony_ci                                return 0;
85099ca880aSopenharmony_ci
85199ca880aSopenharmony_ci                        return -errno;
85299ca880aSopenharmony_ci                } else if (l == 0)
85399ca880aSopenharmony_ci                        return 0;
85499ca880aSopenharmony_ci        }
85599ca880aSopenharmony_ci}
85699ca880aSopenharmony_ci
85799ca880aSopenharmony_cissize_t loop_read(int fd, void *buf, size_t nbytes, bool do_poll) {
85899ca880aSopenharmony_ci        uint8_t *p = buf;
85999ca880aSopenharmony_ci        ssize_t n = 0;
86099ca880aSopenharmony_ci
86199ca880aSopenharmony_ci        assert(fd >= 0);
86299ca880aSopenharmony_ci        assert(buf);
86399ca880aSopenharmony_ci
86499ca880aSopenharmony_ci        while (nbytes > 0) {
86599ca880aSopenharmony_ci                ssize_t k;
86699ca880aSopenharmony_ci
86799ca880aSopenharmony_ci                k = read(fd, p, nbytes);
86899ca880aSopenharmony_ci                if (k < 0) {
86999ca880aSopenharmony_ci                        if (errno == EINTR)
87099ca880aSopenharmony_ci                                continue;
87199ca880aSopenharmony_ci
87299ca880aSopenharmony_ci                        if (errno == EAGAIN && do_poll) {
87399ca880aSopenharmony_ci
87499ca880aSopenharmony_ci                                /* We knowingly ignore any return value here,
87599ca880aSopenharmony_ci                                 * and expect that any error/EOF is reported
87699ca880aSopenharmony_ci                                 * via read() */
87799ca880aSopenharmony_ci
87899ca880aSopenharmony_ci                                fd_wait_for_event(fd, POLLIN, USEC_INFINITY);
87999ca880aSopenharmony_ci                                continue;
88099ca880aSopenharmony_ci                        }
88199ca880aSopenharmony_ci
88299ca880aSopenharmony_ci                        return n > 0 ? n : -errno;
88399ca880aSopenharmony_ci                }
88499ca880aSopenharmony_ci
88599ca880aSopenharmony_ci                if (k == 0)
88699ca880aSopenharmony_ci                        return n;
88799ca880aSopenharmony_ci
88899ca880aSopenharmony_ci                p += k;
88999ca880aSopenharmony_ci                nbytes -= k;
89099ca880aSopenharmony_ci                n += k;
89199ca880aSopenharmony_ci        }
89299ca880aSopenharmony_ci
89399ca880aSopenharmony_ci        return n;
89499ca880aSopenharmony_ci}
89599ca880aSopenharmony_ci
89699ca880aSopenharmony_ciint loop_read_exact(int fd, void *buf, size_t nbytes, bool do_poll) {
89799ca880aSopenharmony_ci        ssize_t n;
89899ca880aSopenharmony_ci
89999ca880aSopenharmony_ci        n = loop_read(fd, buf, nbytes, do_poll);
90099ca880aSopenharmony_ci        if (n < 0)
90199ca880aSopenharmony_ci                return n;
90299ca880aSopenharmony_ci        if ((size_t) n != nbytes)
90399ca880aSopenharmony_ci                return -EIO;
90499ca880aSopenharmony_ci        return 0;
90599ca880aSopenharmony_ci}
90699ca880aSopenharmony_ci
90799ca880aSopenharmony_ciint loop_write(int fd, const void *buf, size_t nbytes, bool do_poll) {
90899ca880aSopenharmony_ci        const uint8_t *p = buf;
90999ca880aSopenharmony_ci
91099ca880aSopenharmony_ci        assert(fd >= 0);
91199ca880aSopenharmony_ci        assert(buf);
91299ca880aSopenharmony_ci
91399ca880aSopenharmony_ci        errno = 0;
91499ca880aSopenharmony_ci
91599ca880aSopenharmony_ci        do {
91699ca880aSopenharmony_ci                ssize_t k;
91799ca880aSopenharmony_ci
91899ca880aSopenharmony_ci                k = write(fd, p, nbytes);
91999ca880aSopenharmony_ci                if (k < 0) {
92099ca880aSopenharmony_ci                        if (errno == EINTR)
92199ca880aSopenharmony_ci                                continue;
92299ca880aSopenharmony_ci
92399ca880aSopenharmony_ci                        if (errno == EAGAIN && do_poll) {
92499ca880aSopenharmony_ci                                /* We knowingly ignore any return value here,
92599ca880aSopenharmony_ci                                 * and expect that any error/EOF is reported
92699ca880aSopenharmony_ci                                 * via write() */
92799ca880aSopenharmony_ci
92899ca880aSopenharmony_ci                                fd_wait_for_event(fd, POLLOUT, USEC_INFINITY);
92999ca880aSopenharmony_ci                                continue;
93099ca880aSopenharmony_ci                        }
93199ca880aSopenharmony_ci
93299ca880aSopenharmony_ci                        return -errno;
93399ca880aSopenharmony_ci                }
93499ca880aSopenharmony_ci
93599ca880aSopenharmony_ci                if (nbytes > 0 && k == 0) /* Can't really happen */
93699ca880aSopenharmony_ci                        return -EIO;
93799ca880aSopenharmony_ci
93899ca880aSopenharmony_ci                p += k;
93999ca880aSopenharmony_ci                nbytes -= k;
94099ca880aSopenharmony_ci        } while (nbytes > 0);
94199ca880aSopenharmony_ci
94299ca880aSopenharmony_ci        return 0;
94399ca880aSopenharmony_ci}
94499ca880aSopenharmony_ci
94599ca880aSopenharmony_cichar* dirname_malloc(const char *path) {
94699ca880aSopenharmony_ci        char *d, *dir, *dir2;
94799ca880aSopenharmony_ci
94899ca880aSopenharmony_ci        d = strdup(path);
94999ca880aSopenharmony_ci        if (!d)
95099ca880aSopenharmony_ci                return NULL;
95199ca880aSopenharmony_ci        dir = dirname(d);
95299ca880aSopenharmony_ci        assert(dir);
95399ca880aSopenharmony_ci
95499ca880aSopenharmony_ci        if (dir != d) {
95599ca880aSopenharmony_ci                dir2 = strdup(dir);
95699ca880aSopenharmony_ci                free(d);
95799ca880aSopenharmony_ci                return dir2;
95899ca880aSopenharmony_ci        }
95999ca880aSopenharmony_ci
96099ca880aSopenharmony_ci        return dir;
96199ca880aSopenharmony_ci}
96299ca880aSopenharmony_ci
96399ca880aSopenharmony_ci_pure_ static int is_temporary_fs(struct statfs *s) {
96499ca880aSopenharmony_ci        assert(s);
96599ca880aSopenharmony_ci
96699ca880aSopenharmony_ci        return F_TYPE_EQUAL(s->f_type, TMPFS_MAGIC) ||
96799ca880aSopenharmony_ci               F_TYPE_EQUAL(s->f_type, RAMFS_MAGIC);
96899ca880aSopenharmony_ci}
96999ca880aSopenharmony_ci
97099ca880aSopenharmony_ciint chmod_and_chown(const char *path, mode_t mode, uid_t uid, gid_t gid) {
97199ca880aSopenharmony_ci        assert(path);
97299ca880aSopenharmony_ci
97399ca880aSopenharmony_ci        /* Under the assumption that we are running privileged we
97499ca880aSopenharmony_ci         * first change the access mode and only then hand out
97599ca880aSopenharmony_ci         * ownership to avoid a window where access is too open. */
97699ca880aSopenharmony_ci
97799ca880aSopenharmony_ci        if (mode != MODE_INVALID)
97899ca880aSopenharmony_ci                if (chmod(path, mode) < 0)
97999ca880aSopenharmony_ci                        return -errno;
98099ca880aSopenharmony_ci
98199ca880aSopenharmony_ci        if (uid != UID_INVALID || gid != GID_INVALID)
98299ca880aSopenharmony_ci                if (chown(path, uid, gid) < 0)
98399ca880aSopenharmony_ci                        return -errno;
98499ca880aSopenharmony_ci
98599ca880aSopenharmony_ci        return 0;
98699ca880aSopenharmony_ci}
98799ca880aSopenharmony_ci
98899ca880aSopenharmony_ciint touch_file(const char *path, bool parents, usec_t stamp, uid_t uid, gid_t gid, mode_t mode) {
98999ca880aSopenharmony_ci        _cleanup_close_ int fd;
99099ca880aSopenharmony_ci        int r;
99199ca880aSopenharmony_ci
99299ca880aSopenharmony_ci        assert(path);
99399ca880aSopenharmony_ci
99499ca880aSopenharmony_ci        if (parents)
99599ca880aSopenharmony_ci                mkdir_parents(path, 0755);
99699ca880aSopenharmony_ci
99799ca880aSopenharmony_ci        fd = open(path, O_WRONLY|O_CREAT|O_CLOEXEC|O_NOCTTY, mode > 0 ? mode : 0644);
99899ca880aSopenharmony_ci        if (fd < 0)
99999ca880aSopenharmony_ci                return -errno;
100099ca880aSopenharmony_ci
100199ca880aSopenharmony_ci        if (mode > 0) {
100299ca880aSopenharmony_ci                r = fchmod(fd, mode);
100399ca880aSopenharmony_ci                if (r < 0)
100499ca880aSopenharmony_ci                        return -errno;
100599ca880aSopenharmony_ci        }
100699ca880aSopenharmony_ci
100799ca880aSopenharmony_ci        if (uid != UID_INVALID || gid != GID_INVALID) {
100899ca880aSopenharmony_ci                r = fchown(fd, uid, gid);
100999ca880aSopenharmony_ci                if (r < 0)
101099ca880aSopenharmony_ci                        return -errno;
101199ca880aSopenharmony_ci        }
101299ca880aSopenharmony_ci
101399ca880aSopenharmony_ci        if (stamp != USEC_INFINITY) {
101499ca880aSopenharmony_ci                struct timespec ts[2];
101599ca880aSopenharmony_ci
101699ca880aSopenharmony_ci                timespec_store(&ts[0], stamp);
101799ca880aSopenharmony_ci                ts[1] = ts[0];
101899ca880aSopenharmony_ci                r = futimens(fd, ts);
101999ca880aSopenharmony_ci        } else
102099ca880aSopenharmony_ci                r = futimens(fd, NULL);
102199ca880aSopenharmony_ci        if (r < 0)
102299ca880aSopenharmony_ci                return -errno;
102399ca880aSopenharmony_ci
102499ca880aSopenharmony_ci        return 0;
102599ca880aSopenharmony_ci}
102699ca880aSopenharmony_ci
102799ca880aSopenharmony_ciint touch(const char *path) {
102899ca880aSopenharmony_ci        return touch_file(path, false, USEC_INFINITY, UID_INVALID, GID_INVALID, 0);
102999ca880aSopenharmony_ci}
103099ca880aSopenharmony_ci
103199ca880aSopenharmony_cibool null_or_empty(struct stat *st) {
103299ca880aSopenharmony_ci        assert(st);
103399ca880aSopenharmony_ci
103499ca880aSopenharmony_ci        if (S_ISREG(st->st_mode) && st->st_size <= 0)
103599ca880aSopenharmony_ci                return true;
103699ca880aSopenharmony_ci
103799ca880aSopenharmony_ci        if (S_ISCHR(st->st_mode) || S_ISBLK(st->st_mode))
103899ca880aSopenharmony_ci                return true;
103999ca880aSopenharmony_ci
104099ca880aSopenharmony_ci        return false;
104199ca880aSopenharmony_ci}
104299ca880aSopenharmony_ci
104399ca880aSopenharmony_ciint null_or_empty_path(const char *fn) {
104499ca880aSopenharmony_ci        struct stat st;
104599ca880aSopenharmony_ci
104699ca880aSopenharmony_ci        assert(fn);
104799ca880aSopenharmony_ci
104899ca880aSopenharmony_ci        if (stat(fn, &st) < 0)
104999ca880aSopenharmony_ci                return -errno;
105099ca880aSopenharmony_ci
105199ca880aSopenharmony_ci        return null_or_empty(&st);
105299ca880aSopenharmony_ci}
105399ca880aSopenharmony_ci
105499ca880aSopenharmony_ciint null_or_empty_fd(int fd) {
105599ca880aSopenharmony_ci        struct stat st;
105699ca880aSopenharmony_ci
105799ca880aSopenharmony_ci        assert(fd >= 0);
105899ca880aSopenharmony_ci
105999ca880aSopenharmony_ci        if (fstat(fd, &st) < 0)
106099ca880aSopenharmony_ci                return -errno;
106199ca880aSopenharmony_ci
106299ca880aSopenharmony_ci        return null_or_empty(&st);
106399ca880aSopenharmony_ci}
106499ca880aSopenharmony_ci
106599ca880aSopenharmony_cibool dirent_is_file_with_suffix(const struct dirent *de, const char *suffix) {
106699ca880aSopenharmony_ci        assert(de);
106799ca880aSopenharmony_ci
106899ca880aSopenharmony_ci        if (de->d_type != DT_REG &&
106999ca880aSopenharmony_ci            de->d_type != DT_LNK &&
107099ca880aSopenharmony_ci            de->d_type != DT_UNKNOWN)
107199ca880aSopenharmony_ci                return false;
107299ca880aSopenharmony_ci
107399ca880aSopenharmony_ci        if (hidden_file_allow_backup(de->d_name))
107499ca880aSopenharmony_ci                return false;
107599ca880aSopenharmony_ci
107699ca880aSopenharmony_ci        return endswith(de->d_name, suffix);
107799ca880aSopenharmony_ci}
107899ca880aSopenharmony_ci
107999ca880aSopenharmony_cibool nulstr_contains(const char*nulstr, const char *needle) {
108099ca880aSopenharmony_ci        const char *i;
108199ca880aSopenharmony_ci
108299ca880aSopenharmony_ci        if (!nulstr)
108399ca880aSopenharmony_ci                return false;
108499ca880aSopenharmony_ci
108599ca880aSopenharmony_ci        NULSTR_FOREACH(i, nulstr)
108699ca880aSopenharmony_ci                if (streq(i, needle))
108799ca880aSopenharmony_ci                        return true;
108899ca880aSopenharmony_ci
108999ca880aSopenharmony_ci        return false;
109099ca880aSopenharmony_ci}
109199ca880aSopenharmony_ci
109299ca880aSopenharmony_ci
109399ca880aSopenharmony_cistatic inline int ppoll_fallback(struct pollfd *fds, nfds_t nfds, const struct timespec *timeout_ts, const sigset_t *sigmask) {
109499ca880aSopenharmony_ci        int ready, timeout;
109599ca880aSopenharmony_ci        sigset_t origmask;
109699ca880aSopenharmony_ci
109799ca880aSopenharmony_ci        timeout = (timeout_ts == NULL) ? -1 : (timeout_ts->tv_sec * 1000 + timeout_ts->tv_nsec / 1000000);
109899ca880aSopenharmony_ci
109999ca880aSopenharmony_ci        /* This is racey, but what can we do without ppoll? */
110099ca880aSopenharmony_ci        sigprocmask(SIG_SETMASK, sigmask, &origmask);
110199ca880aSopenharmony_ci        ready = poll(fds, nfds, timeout);
110299ca880aSopenharmony_ci        sigprocmask(SIG_SETMASK, &origmask, NULL);
110399ca880aSopenharmony_ci
110499ca880aSopenharmony_ci	return ready;
110599ca880aSopenharmony_ci}
110699ca880aSopenharmony_ci
110799ca880aSopenharmony_ciint fd_wait_for_event(int fd, int event, usec_t t) {
110899ca880aSopenharmony_ci
110999ca880aSopenharmony_ci        struct pollfd pollfd = {
111099ca880aSopenharmony_ci                .fd = fd,
111199ca880aSopenharmony_ci                .events = event,
111299ca880aSopenharmony_ci        };
111399ca880aSopenharmony_ci
111499ca880aSopenharmony_ci        struct timespec ts;
111599ca880aSopenharmony_ci        int r;
111699ca880aSopenharmony_ci
111799ca880aSopenharmony_ci#if HAVE_DECL_PPOLL
111899ca880aSopenharmony_ci        r = ppoll(&pollfd, 1, t == USEC_INFINITY ? NULL : timespec_store(&ts, t), NULL);
111999ca880aSopenharmony_ci#else
112099ca880aSopenharmony_ci        /* Fallback path when ppoll() is unavailable */
112199ca880aSopenharmony_ci        r = ppoll_fallback(&pollfd, 1, t == USEC_INFINITY ? NULL : timespec_store(&ts, t), NULL);
112299ca880aSopenharmony_ci#endif
112399ca880aSopenharmony_ci        if (r < 0)
112499ca880aSopenharmony_ci                return -errno;
112599ca880aSopenharmony_ci
112699ca880aSopenharmony_ci        if (r == 0)
112799ca880aSopenharmony_ci                return 0;
112899ca880aSopenharmony_ci
112999ca880aSopenharmony_ci        return pollfd.revents;
113099ca880aSopenharmony_ci}
113199ca880aSopenharmony_ci
113299ca880aSopenharmony_ciint fopen_temporary(const char *path, FILE **_f, char **_temp_path) {
113399ca880aSopenharmony_ci        FILE *f;
113499ca880aSopenharmony_ci        char *t;
113599ca880aSopenharmony_ci        int r, fd;
113699ca880aSopenharmony_ci
113799ca880aSopenharmony_ci        assert(path);
113899ca880aSopenharmony_ci        assert(_f);
113999ca880aSopenharmony_ci        assert(_temp_path);
114099ca880aSopenharmony_ci
114199ca880aSopenharmony_ci        r = tempfn_xxxxxx(path, &t);
114299ca880aSopenharmony_ci        if (r < 0)
114399ca880aSopenharmony_ci                return r;
114499ca880aSopenharmony_ci
114599ca880aSopenharmony_ci#if HAVE_DECL_MKOSTEMP
114699ca880aSopenharmony_ci        fd = mkostemp_safe(t, O_WRONLY|O_CLOEXEC);
114799ca880aSopenharmony_ci#else
114899ca880aSopenharmony_ci        fd = mkstemp_safe(t);
114999ca880aSopenharmony_ci        fcntl(fd, F_SETFD, FD_CLOEXEC);
115099ca880aSopenharmony_ci#endif
115199ca880aSopenharmony_ci        if (fd < 0) {
115299ca880aSopenharmony_ci                free(t);
115399ca880aSopenharmony_ci                return -errno;
115499ca880aSopenharmony_ci        }
115599ca880aSopenharmony_ci
115699ca880aSopenharmony_ci        f = fdopen(fd, "we");
115799ca880aSopenharmony_ci        if (!f) {
115899ca880aSopenharmony_ci                unlink(t);
115999ca880aSopenharmony_ci                free(t);
116099ca880aSopenharmony_ci                return -errno;
116199ca880aSopenharmony_ci        }
116299ca880aSopenharmony_ci
116399ca880aSopenharmony_ci        *_f = f;
116499ca880aSopenharmony_ci        *_temp_path = t;
116599ca880aSopenharmony_ci
116699ca880aSopenharmony_ci        return 0;
116799ca880aSopenharmony_ci}
116899ca880aSopenharmony_ci
116999ca880aSopenharmony_ciint get_user_creds(
117099ca880aSopenharmony_ci                const char **username,
117199ca880aSopenharmony_ci                uid_t *uid, gid_t *gid,
117299ca880aSopenharmony_ci                const char **home,
117399ca880aSopenharmony_ci                const char **shell) {
117499ca880aSopenharmony_ci
117599ca880aSopenharmony_ci        struct passwd *p;
117699ca880aSopenharmony_ci        uid_t u;
117799ca880aSopenharmony_ci
117899ca880aSopenharmony_ci        assert(username);
117999ca880aSopenharmony_ci        assert(*username);
118099ca880aSopenharmony_ci
118199ca880aSopenharmony_ci        /* We enforce some special rules for uid=0: in order to avoid
118299ca880aSopenharmony_ci         * NSS lookups for root we hardcode its data. */
118399ca880aSopenharmony_ci
118499ca880aSopenharmony_ci        if (streq(*username, "root") || streq(*username, "0")) {
118599ca880aSopenharmony_ci                *username = "root";
118699ca880aSopenharmony_ci
118799ca880aSopenharmony_ci                if (uid)
118899ca880aSopenharmony_ci                        *uid = 0;
118999ca880aSopenharmony_ci
119099ca880aSopenharmony_ci                if (gid)
119199ca880aSopenharmony_ci                        *gid = 0;
119299ca880aSopenharmony_ci
119399ca880aSopenharmony_ci                if (home)
119499ca880aSopenharmony_ci                        *home = "/root";
119599ca880aSopenharmony_ci
119699ca880aSopenharmony_ci                if (shell)
119799ca880aSopenharmony_ci                        *shell = "/bin/sh";
119899ca880aSopenharmony_ci
119999ca880aSopenharmony_ci                return 0;
120099ca880aSopenharmony_ci        }
120199ca880aSopenharmony_ci
120299ca880aSopenharmony_ci        if (parse_uid(*username, &u) >= 0) {
120399ca880aSopenharmony_ci                errno = 0;
120499ca880aSopenharmony_ci                p = getpwuid(u);
120599ca880aSopenharmony_ci
120699ca880aSopenharmony_ci                /* If there are multiple users with the same id, make
120799ca880aSopenharmony_ci                 * sure to leave $USER to the configured value instead
120899ca880aSopenharmony_ci                 * of the first occurrence in the database. However if
120999ca880aSopenharmony_ci                 * the uid was configured by a numeric uid, then let's
121099ca880aSopenharmony_ci                 * pick the real username from /etc/passwd. */
121199ca880aSopenharmony_ci                if (p)
121299ca880aSopenharmony_ci                        *username = p->pw_name;
121399ca880aSopenharmony_ci        } else {
121499ca880aSopenharmony_ci                errno = 0;
121599ca880aSopenharmony_ci                p = getpwnam(*username);
121699ca880aSopenharmony_ci        }
121799ca880aSopenharmony_ci
121899ca880aSopenharmony_ci        if (!p)
121999ca880aSopenharmony_ci                return errno > 0 ? -errno : -ESRCH;
122099ca880aSopenharmony_ci
122199ca880aSopenharmony_ci        if (uid)
122299ca880aSopenharmony_ci                *uid = p->pw_uid;
122399ca880aSopenharmony_ci
122499ca880aSopenharmony_ci        if (gid)
122599ca880aSopenharmony_ci                *gid = p->pw_gid;
122699ca880aSopenharmony_ci
122799ca880aSopenharmony_ci        if (home)
122899ca880aSopenharmony_ci                *home = p->pw_dir;
122999ca880aSopenharmony_ci
123099ca880aSopenharmony_ci        if (shell)
123199ca880aSopenharmony_ci                *shell = p->pw_shell;
123299ca880aSopenharmony_ci
123399ca880aSopenharmony_ci        return 0;
123499ca880aSopenharmony_ci}
123599ca880aSopenharmony_ci
123699ca880aSopenharmony_ciint get_group_creds(const char **groupname, gid_t *gid) {
123799ca880aSopenharmony_ci        struct group *g;
123899ca880aSopenharmony_ci        gid_t id;
123999ca880aSopenharmony_ci
124099ca880aSopenharmony_ci        assert(groupname);
124199ca880aSopenharmony_ci
124299ca880aSopenharmony_ci        /* We enforce some special rules for gid=0: in order to avoid
124399ca880aSopenharmony_ci         * NSS lookups for root we hardcode its data. */
124499ca880aSopenharmony_ci
124599ca880aSopenharmony_ci        if (streq(*groupname, "root") || streq(*groupname, "0")) {
124699ca880aSopenharmony_ci                *groupname = "root";
124799ca880aSopenharmony_ci
124899ca880aSopenharmony_ci                if (gid)
124999ca880aSopenharmony_ci                        *gid = 0;
125099ca880aSopenharmony_ci
125199ca880aSopenharmony_ci                return 0;
125299ca880aSopenharmony_ci        }
125399ca880aSopenharmony_ci
125499ca880aSopenharmony_ci        if (parse_gid(*groupname, &id) >= 0) {
125599ca880aSopenharmony_ci                errno = 0;
125699ca880aSopenharmony_ci                g = getgrgid(id);
125799ca880aSopenharmony_ci
125899ca880aSopenharmony_ci                if (g)
125999ca880aSopenharmony_ci                        *groupname = g->gr_name;
126099ca880aSopenharmony_ci        } else {
126199ca880aSopenharmony_ci                errno = 0;
126299ca880aSopenharmony_ci                g = getgrnam(*groupname);
126399ca880aSopenharmony_ci        }
126499ca880aSopenharmony_ci
126599ca880aSopenharmony_ci        if (!g)
126699ca880aSopenharmony_ci                return errno > 0 ? -errno : -ESRCH;
126799ca880aSopenharmony_ci
126899ca880aSopenharmony_ci        if (gid)
126999ca880aSopenharmony_ci                *gid = g->gr_gid;
127099ca880aSopenharmony_ci
127199ca880aSopenharmony_ci        return 0;
127299ca880aSopenharmony_ci}
127399ca880aSopenharmony_ci
127499ca880aSopenharmony_cichar *strjoin(const char *x, ...) {
127599ca880aSopenharmony_ci        va_list ap;
127699ca880aSopenharmony_ci        size_t l;
127799ca880aSopenharmony_ci        char *r, *p;
127899ca880aSopenharmony_ci
127999ca880aSopenharmony_ci        va_start(ap, x);
128099ca880aSopenharmony_ci
128199ca880aSopenharmony_ci        if (x) {
128299ca880aSopenharmony_ci                l = strlen(x);
128399ca880aSopenharmony_ci
128499ca880aSopenharmony_ci                for (;;) {
128599ca880aSopenharmony_ci                        const char *t;
128699ca880aSopenharmony_ci                        size_t n;
128799ca880aSopenharmony_ci
128899ca880aSopenharmony_ci                        t = va_arg(ap, const char *);
128999ca880aSopenharmony_ci                        if (!t)
129099ca880aSopenharmony_ci                                break;
129199ca880aSopenharmony_ci
129299ca880aSopenharmony_ci                        n = strlen(t);
129399ca880aSopenharmony_ci                        if (n > ((size_t) -1) - l) {
129499ca880aSopenharmony_ci                                va_end(ap);
129599ca880aSopenharmony_ci                                return NULL;
129699ca880aSopenharmony_ci                        }
129799ca880aSopenharmony_ci
129899ca880aSopenharmony_ci                        l += n;
129999ca880aSopenharmony_ci                }
130099ca880aSopenharmony_ci        } else
130199ca880aSopenharmony_ci                l = 0;
130299ca880aSopenharmony_ci
130399ca880aSopenharmony_ci        va_end(ap);
130499ca880aSopenharmony_ci
130599ca880aSopenharmony_ci        r = new(char, l+1);
130699ca880aSopenharmony_ci        if (!r)
130799ca880aSopenharmony_ci                return NULL;
130899ca880aSopenharmony_ci
130999ca880aSopenharmony_ci        if (x) {
131099ca880aSopenharmony_ci                p = stpcpy(r, x);
131199ca880aSopenharmony_ci
131299ca880aSopenharmony_ci                va_start(ap, x);
131399ca880aSopenharmony_ci
131499ca880aSopenharmony_ci                for (;;) {
131599ca880aSopenharmony_ci                        const char *t;
131699ca880aSopenharmony_ci
131799ca880aSopenharmony_ci                        t = va_arg(ap, const char *);
131899ca880aSopenharmony_ci                        if (!t)
131999ca880aSopenharmony_ci                                break;
132099ca880aSopenharmony_ci
132199ca880aSopenharmony_ci                        p = stpcpy(p, t);
132299ca880aSopenharmony_ci                }
132399ca880aSopenharmony_ci
132499ca880aSopenharmony_ci                va_end(ap);
132599ca880aSopenharmony_ci        } else
132699ca880aSopenharmony_ci                r[0] = 0;
132799ca880aSopenharmony_ci
132899ca880aSopenharmony_ci        return r;
132999ca880aSopenharmony_ci}
133099ca880aSopenharmony_ci
133199ca880aSopenharmony_cibool is_main_thread(void) {
133299ca880aSopenharmony_ci        static thread_local int cached = 0;
133399ca880aSopenharmony_ci
133499ca880aSopenharmony_ci        if (_unlikely_(cached == 0))
133599ca880aSopenharmony_ci                cached = getpid() == gettid() ? 1 : -1;
133699ca880aSopenharmony_ci
133799ca880aSopenharmony_ci        return cached > 0;
133899ca880aSopenharmony_ci}
133999ca880aSopenharmony_ci
134099ca880aSopenharmony_cistatic const char *const ioprio_class_table[] = {
134199ca880aSopenharmony_ci        [IOPRIO_CLASS_NONE] = "none",
134299ca880aSopenharmony_ci        [IOPRIO_CLASS_RT] = "realtime",
134399ca880aSopenharmony_ci        [IOPRIO_CLASS_BE] = "best-effort",
134499ca880aSopenharmony_ci        [IOPRIO_CLASS_IDLE] = "idle"
134599ca880aSopenharmony_ci};
134699ca880aSopenharmony_ci
134799ca880aSopenharmony_ciDEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(ioprio_class, int, INT_MAX);
134899ca880aSopenharmony_ci
134999ca880aSopenharmony_cistatic const char *const sigchld_code_table[] = {
135099ca880aSopenharmony_ci        [CLD_EXITED] = "exited",
135199ca880aSopenharmony_ci        [CLD_KILLED] = "killed",
135299ca880aSopenharmony_ci        [CLD_DUMPED] = "dumped",
135399ca880aSopenharmony_ci        [CLD_TRAPPED] = "trapped",
135499ca880aSopenharmony_ci        [CLD_STOPPED] = "stopped",
135599ca880aSopenharmony_ci        [CLD_CONTINUED] = "continued",
135699ca880aSopenharmony_ci};
135799ca880aSopenharmony_ci
135899ca880aSopenharmony_ciDEFINE_STRING_TABLE_LOOKUP(sigchld_code, int);
135999ca880aSopenharmony_ci
136099ca880aSopenharmony_cistatic const char *const log_facility_unshifted_table[LOG_NFACILITIES] = {
136199ca880aSopenharmony_ci        [LOG_FAC(LOG_KERN)] = "kern",
136299ca880aSopenharmony_ci        [LOG_FAC(LOG_USER)] = "user",
136399ca880aSopenharmony_ci        [LOG_FAC(LOG_MAIL)] = "mail",
136499ca880aSopenharmony_ci        [LOG_FAC(LOG_DAEMON)] = "daemon",
136599ca880aSopenharmony_ci        [LOG_FAC(LOG_AUTH)] = "auth",
136699ca880aSopenharmony_ci        [LOG_FAC(LOG_SYSLOG)] = "syslog",
136799ca880aSopenharmony_ci        [LOG_FAC(LOG_LPR)] = "lpr",
136899ca880aSopenharmony_ci        [LOG_FAC(LOG_NEWS)] = "news",
136999ca880aSopenharmony_ci        [LOG_FAC(LOG_UUCP)] = "uucp",
137099ca880aSopenharmony_ci        [LOG_FAC(LOG_CRON)] = "cron",
137199ca880aSopenharmony_ci        [LOG_FAC(LOG_AUTHPRIV)] = "authpriv",
137299ca880aSopenharmony_ci        [LOG_FAC(LOG_FTP)] = "ftp",
137399ca880aSopenharmony_ci        [LOG_FAC(LOG_LOCAL0)] = "local0",
137499ca880aSopenharmony_ci        [LOG_FAC(LOG_LOCAL1)] = "local1",
137599ca880aSopenharmony_ci        [LOG_FAC(LOG_LOCAL2)] = "local2",
137699ca880aSopenharmony_ci        [LOG_FAC(LOG_LOCAL3)] = "local3",
137799ca880aSopenharmony_ci        [LOG_FAC(LOG_LOCAL4)] = "local4",
137899ca880aSopenharmony_ci        [LOG_FAC(LOG_LOCAL5)] = "local5",
137999ca880aSopenharmony_ci        [LOG_FAC(LOG_LOCAL6)] = "local6",
138099ca880aSopenharmony_ci        [LOG_FAC(LOG_LOCAL7)] = "local7"
138199ca880aSopenharmony_ci};
138299ca880aSopenharmony_ci
138399ca880aSopenharmony_ciDEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(log_facility_unshifted, int, LOG_FAC(~0));
138499ca880aSopenharmony_ci
138599ca880aSopenharmony_cistatic const char *const log_level_table[] = {
138699ca880aSopenharmony_ci        [LOG_EMERG] = "emerg",
138799ca880aSopenharmony_ci        [LOG_ALERT] = "alert",
138899ca880aSopenharmony_ci        [LOG_CRIT] = "crit",
138999ca880aSopenharmony_ci        [LOG_ERR] = "err",
139099ca880aSopenharmony_ci        [LOG_WARNING] = "warning",
139199ca880aSopenharmony_ci        [LOG_NOTICE] = "notice",
139299ca880aSopenharmony_ci        [LOG_INFO] = "info",
139399ca880aSopenharmony_ci        [LOG_DEBUG] = "debug"
139499ca880aSopenharmony_ci};
139599ca880aSopenharmony_ci
139699ca880aSopenharmony_ciDEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(log_level, int, LOG_DEBUG);
139799ca880aSopenharmony_ci
139899ca880aSopenharmony_cistatic const char* const sched_policy_table[] = {
139999ca880aSopenharmony_ci        [SCHED_OTHER] = "other",
140099ca880aSopenharmony_ci        [SCHED_BATCH] = "batch",
140199ca880aSopenharmony_ci        [SCHED_IDLE] = "idle",
140299ca880aSopenharmony_ci        [SCHED_FIFO] = "fifo",
140399ca880aSopenharmony_ci        [SCHED_RR] = "rr"
140499ca880aSopenharmony_ci};
140599ca880aSopenharmony_ci
140699ca880aSopenharmony_ciDEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(sched_policy, int, INT_MAX);
140799ca880aSopenharmony_ci
140899ca880aSopenharmony_cistatic const char* const rlimit_table[_RLIMIT_MAX] = {
140999ca880aSopenharmony_ci        [RLIMIT_CPU] = "LimitCPU",
141099ca880aSopenharmony_ci        [RLIMIT_FSIZE] = "LimitFSIZE",
141199ca880aSopenharmony_ci        [RLIMIT_DATA] = "LimitDATA",
141299ca880aSopenharmony_ci        [RLIMIT_STACK] = "LimitSTACK",
141399ca880aSopenharmony_ci        [RLIMIT_CORE] = "LimitCORE",
141499ca880aSopenharmony_ci        [RLIMIT_RSS] = "LimitRSS",
141599ca880aSopenharmony_ci        [RLIMIT_NOFILE] = "LimitNOFILE",
141699ca880aSopenharmony_ci        [RLIMIT_AS] = "LimitAS",
141799ca880aSopenharmony_ci        [RLIMIT_NPROC] = "LimitNPROC",
141899ca880aSopenharmony_ci        [RLIMIT_MEMLOCK] = "LimitMEMLOCK",
141999ca880aSopenharmony_ci        [RLIMIT_LOCKS] = "LimitLOCKS",
142099ca880aSopenharmony_ci        [RLIMIT_SIGPENDING] = "LimitSIGPENDING",
142199ca880aSopenharmony_ci        [RLIMIT_MSGQUEUE] = "LimitMSGQUEUE",
142299ca880aSopenharmony_ci        [RLIMIT_NICE] = "LimitNICE",
142399ca880aSopenharmony_ci        [RLIMIT_RTPRIO] = "LimitRTPRIO",
142499ca880aSopenharmony_ci        [RLIMIT_RTTIME] = "LimitRTTIME"
142599ca880aSopenharmony_ci};
142699ca880aSopenharmony_ci
142799ca880aSopenharmony_ciDEFINE_STRING_TABLE_LOOKUP(rlimit, int);
142899ca880aSopenharmony_ci
142999ca880aSopenharmony_cistatic const char* const ip_tos_table[] = {
143099ca880aSopenharmony_ci        [IPTOS_LOWDELAY] = "low-delay",
143199ca880aSopenharmony_ci        [IPTOS_THROUGHPUT] = "throughput",
143299ca880aSopenharmony_ci        [IPTOS_RELIABILITY] = "reliability",
143399ca880aSopenharmony_ci        [IPTOS_LOWCOST] = "low-cost",
143499ca880aSopenharmony_ci};
143599ca880aSopenharmony_ci
143699ca880aSopenharmony_ciDEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(ip_tos, int, 0xff);
143799ca880aSopenharmony_ci
143899ca880aSopenharmony_cistatic const char *const __signal_table[] = {
143999ca880aSopenharmony_ci        [SIGHUP] = "HUP",
144099ca880aSopenharmony_ci        [SIGINT] = "INT",
144199ca880aSopenharmony_ci        [SIGQUIT] = "QUIT",
144299ca880aSopenharmony_ci        [SIGILL] = "ILL",
144399ca880aSopenharmony_ci        [SIGTRAP] = "TRAP",
144499ca880aSopenharmony_ci        [SIGABRT] = "ABRT",
144599ca880aSopenharmony_ci        [SIGBUS] = "BUS",
144699ca880aSopenharmony_ci        [SIGFPE] = "FPE",
144799ca880aSopenharmony_ci        [SIGKILL] = "KILL",
144899ca880aSopenharmony_ci        [SIGUSR1] = "USR1",
144999ca880aSopenharmony_ci        [SIGSEGV] = "SEGV",
145099ca880aSopenharmony_ci        [SIGUSR2] = "USR2",
145199ca880aSopenharmony_ci        [SIGPIPE] = "PIPE",
145299ca880aSopenharmony_ci        [SIGALRM] = "ALRM",
145399ca880aSopenharmony_ci        [SIGTERM] = "TERM",
145499ca880aSopenharmony_ci#ifdef SIGSTKFLT
145599ca880aSopenharmony_ci        [SIGSTKFLT] = "STKFLT",  /* Linux on SPARC doesn't know SIGSTKFLT */
145699ca880aSopenharmony_ci#endif
145799ca880aSopenharmony_ci        [SIGCHLD] = "CHLD",
145899ca880aSopenharmony_ci        [SIGCONT] = "CONT",
145999ca880aSopenharmony_ci        [SIGSTOP] = "STOP",
146099ca880aSopenharmony_ci        [SIGTSTP] = "TSTP",
146199ca880aSopenharmony_ci        [SIGTTIN] = "TTIN",
146299ca880aSopenharmony_ci        [SIGTTOU] = "TTOU",
146399ca880aSopenharmony_ci        [SIGURG] = "URG",
146499ca880aSopenharmony_ci        [SIGXCPU] = "XCPU",
146599ca880aSopenharmony_ci        [SIGXFSZ] = "XFSZ",
146699ca880aSopenharmony_ci        [SIGVTALRM] = "VTALRM",
146799ca880aSopenharmony_ci        [SIGPROF] = "PROF",
146899ca880aSopenharmony_ci        [SIGWINCH] = "WINCH",
146999ca880aSopenharmony_ci        [SIGIO] = "IO",
147099ca880aSopenharmony_ci        [SIGPWR] = "PWR",
147199ca880aSopenharmony_ci        [SIGSYS] = "SYS"
147299ca880aSopenharmony_ci};
147399ca880aSopenharmony_ci
147499ca880aSopenharmony_ciDEFINE_PRIVATE_STRING_TABLE_LOOKUP(__signal, int);
147599ca880aSopenharmony_ci
147699ca880aSopenharmony_ciconst char *signal_to_string(int signo) {
147799ca880aSopenharmony_ci        static thread_local char buf[sizeof("RTMIN+")-1 + DECIMAL_STR_MAX(int) + 1];
147899ca880aSopenharmony_ci        const char *name;
147999ca880aSopenharmony_ci
148099ca880aSopenharmony_ci        name = __signal_to_string(signo);
148199ca880aSopenharmony_ci        if (name)
148299ca880aSopenharmony_ci                return name;
148399ca880aSopenharmony_ci
148499ca880aSopenharmony_ci        if (signo >= SIGRTMIN && signo <= SIGRTMAX)
148599ca880aSopenharmony_ci                snprintf(buf, sizeof(buf), "RTMIN+%d", signo - SIGRTMIN);
148699ca880aSopenharmony_ci        else
148799ca880aSopenharmony_ci                snprintf(buf, sizeof(buf), "%d", signo);
148899ca880aSopenharmony_ci
148999ca880aSopenharmony_ci        return buf;
149099ca880aSopenharmony_ci}
149199ca880aSopenharmony_ci
149299ca880aSopenharmony_ciint fd_inc_sndbuf(int fd, size_t n) {
149399ca880aSopenharmony_ci        int r, value;
149499ca880aSopenharmony_ci        socklen_t l = sizeof(value);
149599ca880aSopenharmony_ci
149699ca880aSopenharmony_ci        r = getsockopt(fd, SOL_SOCKET, SO_SNDBUF, &value, &l);
149799ca880aSopenharmony_ci        if (r >= 0 && l == sizeof(value) && (size_t) value >= n*2)
149899ca880aSopenharmony_ci                return 0;
149999ca880aSopenharmony_ci
150099ca880aSopenharmony_ci        /* If we have the privileges we will ignore the kernel limit. */
150199ca880aSopenharmony_ci
150299ca880aSopenharmony_ci        value = (int) n;
150399ca880aSopenharmony_ci        if (setsockopt(fd, SOL_SOCKET, SO_SNDBUFFORCE, &value, sizeof(value)) < 0)
150499ca880aSopenharmony_ci                if (setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &value, sizeof(value)) < 0)
150599ca880aSopenharmony_ci                        return -errno;
150699ca880aSopenharmony_ci
150799ca880aSopenharmony_ci        return 1;
150899ca880aSopenharmony_ci}
150999ca880aSopenharmony_ci
151099ca880aSopenharmony_cibool in_initrd(void) {
151199ca880aSopenharmony_ci        static int saved = -1;
151299ca880aSopenharmony_ci        struct statfs s;
151399ca880aSopenharmony_ci
151499ca880aSopenharmony_ci        if (saved >= 0)
151599ca880aSopenharmony_ci                return saved;
151699ca880aSopenharmony_ci
151799ca880aSopenharmony_ci        /* We make two checks here:
151899ca880aSopenharmony_ci         *
151999ca880aSopenharmony_ci         * 1. the flag file /etc/initrd-release must exist
152099ca880aSopenharmony_ci         * 2. the root file system must be a memory file system
152199ca880aSopenharmony_ci         *
152299ca880aSopenharmony_ci         * The second check is extra paranoia, since misdetecting an
152399ca880aSopenharmony_ci         * initrd can have bad bad consequences due the initrd
152499ca880aSopenharmony_ci         * emptying when transititioning to the main systemd.
152599ca880aSopenharmony_ci         */
152699ca880aSopenharmony_ci
152799ca880aSopenharmony_ci        saved = access("/etc/initrd-release", F_OK) >= 0 &&
152899ca880aSopenharmony_ci                statfs("/", &s) >= 0 &&
152999ca880aSopenharmony_ci                is_temporary_fs(&s);
153099ca880aSopenharmony_ci
153199ca880aSopenharmony_ci        return saved;
153299ca880aSopenharmony_ci}
153399ca880aSopenharmony_ci
153499ca880aSopenharmony_cibool filename_is_valid(const char *p) {
153599ca880aSopenharmony_ci
153699ca880aSopenharmony_ci        if (isempty(p))
153799ca880aSopenharmony_ci                return false;
153899ca880aSopenharmony_ci
153999ca880aSopenharmony_ci        if (strchr(p, '/'))
154099ca880aSopenharmony_ci                return false;
154199ca880aSopenharmony_ci
154299ca880aSopenharmony_ci        if (streq(p, "."))
154399ca880aSopenharmony_ci                return false;
154499ca880aSopenharmony_ci
154599ca880aSopenharmony_ci        if (streq(p, ".."))
154699ca880aSopenharmony_ci                return false;
154799ca880aSopenharmony_ci
154899ca880aSopenharmony_ci        if (strlen(p) > FILENAME_MAX)
154999ca880aSopenharmony_ci                return false;
155099ca880aSopenharmony_ci
155199ca880aSopenharmony_ci        return true;
155299ca880aSopenharmony_ci}
155399ca880aSopenharmony_ci
155499ca880aSopenharmony_ci/* hey glibc, APIs with callbacks without a user pointer are so useless */
155599ca880aSopenharmony_civoid *xbsearch_r(const void *key, const void *base, size_t nmemb, size_t size,
155699ca880aSopenharmony_ci                 int (*compar) (const void *, const void *, void *), void *arg) {
155799ca880aSopenharmony_ci        size_t l, u, idx;
155899ca880aSopenharmony_ci        const void *p;
155999ca880aSopenharmony_ci        int comparison;
156099ca880aSopenharmony_ci
156199ca880aSopenharmony_ci        l = 0;
156299ca880aSopenharmony_ci        u = nmemb;
156399ca880aSopenharmony_ci        while (l < u) {
156499ca880aSopenharmony_ci                idx = (l + u) / 2;
156599ca880aSopenharmony_ci                p = (void *)(((const char *) base) + (idx * size));
156699ca880aSopenharmony_ci                comparison = compar(key, p, arg);
156799ca880aSopenharmony_ci                if (comparison < 0)
156899ca880aSopenharmony_ci                        u = idx;
156999ca880aSopenharmony_ci                else if (comparison > 0)
157099ca880aSopenharmony_ci                        l = idx + 1;
157199ca880aSopenharmony_ci                else
157299ca880aSopenharmony_ci                        return (void *)p;
157399ca880aSopenharmony_ci        }
157499ca880aSopenharmony_ci        return NULL;
157599ca880aSopenharmony_ci}
157699ca880aSopenharmony_ci
157799ca880aSopenharmony_civoid* greedy_realloc(void **p, size_t *allocated, size_t need, size_t size) {
157899ca880aSopenharmony_ci        size_t a, newalloc;
157999ca880aSopenharmony_ci        void *q;
158099ca880aSopenharmony_ci
158199ca880aSopenharmony_ci        assert(p);
158299ca880aSopenharmony_ci        assert(allocated);
158399ca880aSopenharmony_ci
158499ca880aSopenharmony_ci        if (*allocated >= need)
158599ca880aSopenharmony_ci                return *p;
158699ca880aSopenharmony_ci
158799ca880aSopenharmony_ci        newalloc = MAX(need * 2, 64u / size);
158899ca880aSopenharmony_ci        a = newalloc * size;
158999ca880aSopenharmony_ci
159099ca880aSopenharmony_ci        /* check for overflows */
159199ca880aSopenharmony_ci        if (a < size * need)
159299ca880aSopenharmony_ci                return NULL;
159399ca880aSopenharmony_ci
159499ca880aSopenharmony_ci        q = realloc(*p, a);
159599ca880aSopenharmony_ci        if (!q)
159699ca880aSopenharmony_ci                return NULL;
159799ca880aSopenharmony_ci
159899ca880aSopenharmony_ci        *p = q;
159999ca880aSopenharmony_ci        *allocated = newalloc;
160099ca880aSopenharmony_ci        return q;
160199ca880aSopenharmony_ci}
160299ca880aSopenharmony_ci
160399ca880aSopenharmony_ciint proc_cmdline(char **ret) {
160499ca880aSopenharmony_ci        assert(ret);
160599ca880aSopenharmony_ci
160699ca880aSopenharmony_ci        if (detect_container(NULL) > 0)
160799ca880aSopenharmony_ci                return get_process_cmdline(1, 0, false, ret);
160899ca880aSopenharmony_ci        else
160999ca880aSopenharmony_ci                return read_one_line_file("/proc/cmdline", ret);
161099ca880aSopenharmony_ci}
161199ca880aSopenharmony_ci
161299ca880aSopenharmony_ciint parse_proc_cmdline(int (*parse_item)(const char *key, const char *value)) {
161399ca880aSopenharmony_ci        _cleanup_free_ char *line = NULL;
161499ca880aSopenharmony_ci        const char *p;
161599ca880aSopenharmony_ci        int r;
161699ca880aSopenharmony_ci
161799ca880aSopenharmony_ci        assert(parse_item);
161899ca880aSopenharmony_ci
161999ca880aSopenharmony_ci        r = proc_cmdline(&line);
162099ca880aSopenharmony_ci        if (r < 0)
162199ca880aSopenharmony_ci                return r;
162299ca880aSopenharmony_ci
162399ca880aSopenharmony_ci        p = line;
162499ca880aSopenharmony_ci        for (;;) {
162599ca880aSopenharmony_ci                _cleanup_free_ char *word = NULL;
162699ca880aSopenharmony_ci                char *value = NULL;
162799ca880aSopenharmony_ci
162899ca880aSopenharmony_ci                r = unquote_first_word(&p, &word, UNQUOTE_RELAX);
162999ca880aSopenharmony_ci                if (r < 0)
163099ca880aSopenharmony_ci                        return r;
163199ca880aSopenharmony_ci                if (r == 0)
163299ca880aSopenharmony_ci                        break;
163399ca880aSopenharmony_ci
163499ca880aSopenharmony_ci                /* Filter out arguments that are intended only for the
163599ca880aSopenharmony_ci                 * initrd */
163699ca880aSopenharmony_ci                if (!in_initrd() && startswith(word, "rd."))
163799ca880aSopenharmony_ci                        continue;
163899ca880aSopenharmony_ci
163999ca880aSopenharmony_ci                value = strchr(word, '=');
164099ca880aSopenharmony_ci                if (value)
164199ca880aSopenharmony_ci                        *(value++) = 0;
164299ca880aSopenharmony_ci
164399ca880aSopenharmony_ci                r = parse_item(word, value);
164499ca880aSopenharmony_ci                if (r < 0)
164599ca880aSopenharmony_ci                        return r;
164699ca880aSopenharmony_ci        }
164799ca880aSopenharmony_ci
164899ca880aSopenharmony_ci        return 0;
164999ca880aSopenharmony_ci}
165099ca880aSopenharmony_ci
165199ca880aSopenharmony_ciint getpeercred(int fd, struct ucred *ucred) {
165299ca880aSopenharmony_ci        socklen_t n = sizeof(struct ucred);
165399ca880aSopenharmony_ci        struct ucred u;
165499ca880aSopenharmony_ci        int r;
165599ca880aSopenharmony_ci
165699ca880aSopenharmony_ci        assert(fd >= 0);
165799ca880aSopenharmony_ci        assert(ucred);
165899ca880aSopenharmony_ci
165999ca880aSopenharmony_ci        r = getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &u, &n);
166099ca880aSopenharmony_ci        if (r < 0)
166199ca880aSopenharmony_ci                return -errno;
166299ca880aSopenharmony_ci
166399ca880aSopenharmony_ci        if (n != sizeof(struct ucred))
166499ca880aSopenharmony_ci                return -EIO;
166599ca880aSopenharmony_ci
166699ca880aSopenharmony_ci        /* Check if the data is actually useful and not suppressed due
166799ca880aSopenharmony_ci         * to namespacing issues */
166899ca880aSopenharmony_ci        if (u.pid <= 0)
166999ca880aSopenharmony_ci                return -ENODATA;
167099ca880aSopenharmony_ci        if (u.uid == UID_INVALID)
167199ca880aSopenharmony_ci                return -ENODATA;
167299ca880aSopenharmony_ci        if (u.gid == GID_INVALID)
167399ca880aSopenharmony_ci                return -ENODATA;
167499ca880aSopenharmony_ci
167599ca880aSopenharmony_ci        *ucred = u;
167699ca880aSopenharmony_ci        return 0;
167799ca880aSopenharmony_ci}
167899ca880aSopenharmony_ci
167999ca880aSopenharmony_ci#if HAVE_DECL_MKOSTEMP
168099ca880aSopenharmony_ci/* This is much like like mkostemp() but is subject to umask(). */
168199ca880aSopenharmony_ciint mkostemp_safe(char *pattern, int flags) {
168299ca880aSopenharmony_ci        _cleanup_umask_ mode_t u;
168399ca880aSopenharmony_ci        int fd;
168499ca880aSopenharmony_ci
168599ca880aSopenharmony_ci        assert(pattern);
168699ca880aSopenharmony_ci
168799ca880aSopenharmony_ci        u = umask(077);
168899ca880aSopenharmony_ci
168999ca880aSopenharmony_ci        fd = mkostemp(pattern, flags);
169099ca880aSopenharmony_ci        if (fd < 0)
169199ca880aSopenharmony_ci                return -errno;
169299ca880aSopenharmony_ci
169399ca880aSopenharmony_ci        return fd;
169499ca880aSopenharmony_ci}
169599ca880aSopenharmony_ci#else
169699ca880aSopenharmony_ci/* This is much like like mkstemp() but is subject to umask(). */
169799ca880aSopenharmony_ciint mkstemp_safe(char *pattern) {
169899ca880aSopenharmony_ci        _cleanup_umask_ mode_t u;
169999ca880aSopenharmony_ci        int fd;
170099ca880aSopenharmony_ci
170199ca880aSopenharmony_ci        assert(pattern);
170299ca880aSopenharmony_ci
170399ca880aSopenharmony_ci        u = umask(077);
170499ca880aSopenharmony_ci
170599ca880aSopenharmony_ci        fd = mkstemp(pattern);
170699ca880aSopenharmony_ci        if (fd < 0)
170799ca880aSopenharmony_ci                return -errno;
170899ca880aSopenharmony_ci
170999ca880aSopenharmony_ci        return fd;
171099ca880aSopenharmony_ci}
171199ca880aSopenharmony_ci#endif
171299ca880aSopenharmony_ci
171399ca880aSopenharmony_ciint tempfn_xxxxxx(const char *p, char **ret) {
171499ca880aSopenharmony_ci        const char *fn;
171599ca880aSopenharmony_ci        char *t;
171699ca880aSopenharmony_ci
171799ca880aSopenharmony_ci        assert(p);
171899ca880aSopenharmony_ci        assert(ret);
171999ca880aSopenharmony_ci
172099ca880aSopenharmony_ci        /*
172199ca880aSopenharmony_ci         * Turns this:
172299ca880aSopenharmony_ci         *         /foo/bar/waldo
172399ca880aSopenharmony_ci         *
172499ca880aSopenharmony_ci         * Into this:
172599ca880aSopenharmony_ci         *         /foo/bar/.#waldoXXXXXX
172699ca880aSopenharmony_ci         */
172799ca880aSopenharmony_ci
172899ca880aSopenharmony_ci        fn = basename((char*)p);
172999ca880aSopenharmony_ci        if (!filename_is_valid(fn))
173099ca880aSopenharmony_ci                return -EINVAL;
173199ca880aSopenharmony_ci
173299ca880aSopenharmony_ci        t = new(char, strlen(p) + 2 + 6 + 1);
173399ca880aSopenharmony_ci        if (!t)
173499ca880aSopenharmony_ci                return -ENOMEM;
173599ca880aSopenharmony_ci
173699ca880aSopenharmony_ci        strcpy(stpcpy(stpcpy(mempcpy(t, p, fn - p), ".#"), fn), "XXXXXX");
173799ca880aSopenharmony_ci
173899ca880aSopenharmony_ci        *ret = path_kill_slashes(t);
173999ca880aSopenharmony_ci        return 0;
174099ca880aSopenharmony_ci}
174199ca880aSopenharmony_ci
174299ca880aSopenharmony_ciint is_dir(const char* path, bool follow) {
174399ca880aSopenharmony_ci        struct stat st;
174499ca880aSopenharmony_ci        int r;
174599ca880aSopenharmony_ci
174699ca880aSopenharmony_ci        if (follow)
174799ca880aSopenharmony_ci                r = stat(path, &st);
174899ca880aSopenharmony_ci        else
174999ca880aSopenharmony_ci                r = lstat(path, &st);
175099ca880aSopenharmony_ci        if (r < 0)
175199ca880aSopenharmony_ci                return -errno;
175299ca880aSopenharmony_ci
175399ca880aSopenharmony_ci        return !!S_ISDIR(st.st_mode);
175499ca880aSopenharmony_ci}
175599ca880aSopenharmony_ci
175699ca880aSopenharmony_ciint unquote_first_word(const char **p, char **ret, UnquoteFlags flags) {
175799ca880aSopenharmony_ci        _cleanup_free_ char *s = NULL;
175899ca880aSopenharmony_ci        size_t allocated = 0, sz = 0;
175999ca880aSopenharmony_ci        int r;
176099ca880aSopenharmony_ci
176199ca880aSopenharmony_ci        enum {
176299ca880aSopenharmony_ci                START,
176399ca880aSopenharmony_ci                VALUE,
176499ca880aSopenharmony_ci                VALUE_ESCAPE,
176599ca880aSopenharmony_ci                SINGLE_QUOTE,
176699ca880aSopenharmony_ci                SINGLE_QUOTE_ESCAPE,
176799ca880aSopenharmony_ci                DOUBLE_QUOTE,
176899ca880aSopenharmony_ci                DOUBLE_QUOTE_ESCAPE,
176999ca880aSopenharmony_ci                SPACE,
177099ca880aSopenharmony_ci        } state = START;
177199ca880aSopenharmony_ci
177299ca880aSopenharmony_ci        assert(p);
177399ca880aSopenharmony_ci        assert(*p);
177499ca880aSopenharmony_ci        assert(ret);
177599ca880aSopenharmony_ci
177699ca880aSopenharmony_ci        /* Parses the first word of a string, and returns it in
177799ca880aSopenharmony_ci         * *ret. Removes all quotes in the process. When parsing fails
177899ca880aSopenharmony_ci         * (because of an uneven number of quotes or similar), leaves
177999ca880aSopenharmony_ci         * the pointer *p at the first invalid character. */
178099ca880aSopenharmony_ci
178199ca880aSopenharmony_ci        for (;;) {
178299ca880aSopenharmony_ci                char c = **p;
178399ca880aSopenharmony_ci
178499ca880aSopenharmony_ci                switch (state) {
178599ca880aSopenharmony_ci
178699ca880aSopenharmony_ci                case START:
178799ca880aSopenharmony_ci                        if (c == 0)
178899ca880aSopenharmony_ci                                goto finish;
178999ca880aSopenharmony_ci                        else if (strchr(WHITESPACE, c))
179099ca880aSopenharmony_ci                                break;
179199ca880aSopenharmony_ci
179299ca880aSopenharmony_ci                        state = VALUE;
179399ca880aSopenharmony_ci                        /* fallthrough */
179499ca880aSopenharmony_ci
179599ca880aSopenharmony_ci                case VALUE:
179699ca880aSopenharmony_ci                        if (c == 0)
179799ca880aSopenharmony_ci                                goto finish;
179899ca880aSopenharmony_ci                        else if (c == '\'')
179999ca880aSopenharmony_ci                                state = SINGLE_QUOTE;
180099ca880aSopenharmony_ci                        else if (c == '\\')
180199ca880aSopenharmony_ci                                state = VALUE_ESCAPE;
180299ca880aSopenharmony_ci                        else if (c == '\"')
180399ca880aSopenharmony_ci                                state = DOUBLE_QUOTE;
180499ca880aSopenharmony_ci                        else if (strchr(WHITESPACE, c))
180599ca880aSopenharmony_ci                                state = SPACE;
180699ca880aSopenharmony_ci                        else {
180799ca880aSopenharmony_ci                                if (!GREEDY_REALLOC(s, allocated, sz+2))
180899ca880aSopenharmony_ci                                        return -ENOMEM;
180999ca880aSopenharmony_ci
181099ca880aSopenharmony_ci                                s[sz++] = c;
181199ca880aSopenharmony_ci                        }
181299ca880aSopenharmony_ci
181399ca880aSopenharmony_ci                        break;
181499ca880aSopenharmony_ci
181599ca880aSopenharmony_ci                case VALUE_ESCAPE:
181699ca880aSopenharmony_ci                        if (c == 0) {
181799ca880aSopenharmony_ci                                if (flags & UNQUOTE_RELAX)
181899ca880aSopenharmony_ci                                        goto finish;
181999ca880aSopenharmony_ci                                return -EINVAL;
182099ca880aSopenharmony_ci                        }
182199ca880aSopenharmony_ci
182299ca880aSopenharmony_ci                        if (!GREEDY_REALLOC(s, allocated, sz+7))
182399ca880aSopenharmony_ci                                return -ENOMEM;
182499ca880aSopenharmony_ci
182599ca880aSopenharmony_ci                        if (flags & UNQUOTE_CUNESCAPE) {
182699ca880aSopenharmony_ci                                uint32_t u;
182799ca880aSopenharmony_ci
182899ca880aSopenharmony_ci                                r = cunescape_one(*p, (size_t) -1, &c, &u);
182999ca880aSopenharmony_ci                                if (r < 0)
183099ca880aSopenharmony_ci                                        return -EINVAL;
183199ca880aSopenharmony_ci
183299ca880aSopenharmony_ci                                (*p) += r - 1;
183399ca880aSopenharmony_ci
183499ca880aSopenharmony_ci                                if (c != 0)
183599ca880aSopenharmony_ci                                        s[sz++] = c; /* normal explicit char */
183699ca880aSopenharmony_ci                                else
183799ca880aSopenharmony_ci                                        sz += utf8_encode_unichar(s + sz, u); /* unicode chars we'll encode as utf8 */
183899ca880aSopenharmony_ci                        } else
183999ca880aSopenharmony_ci                                s[sz++] = c;
184099ca880aSopenharmony_ci
184199ca880aSopenharmony_ci                        state = VALUE;
184299ca880aSopenharmony_ci                        break;
184399ca880aSopenharmony_ci
184499ca880aSopenharmony_ci                case SINGLE_QUOTE:
184599ca880aSopenharmony_ci                        if (c == 0) {
184699ca880aSopenharmony_ci                                if (flags & UNQUOTE_RELAX)
184799ca880aSopenharmony_ci                                        goto finish;
184899ca880aSopenharmony_ci                                return -EINVAL;
184999ca880aSopenharmony_ci                        } else if (c == '\'')
185099ca880aSopenharmony_ci                                state = VALUE;
185199ca880aSopenharmony_ci                        else if (c == '\\')
185299ca880aSopenharmony_ci                                state = SINGLE_QUOTE_ESCAPE;
185399ca880aSopenharmony_ci                        else {
185499ca880aSopenharmony_ci                                if (!GREEDY_REALLOC(s, allocated, sz+2))
185599ca880aSopenharmony_ci                                        return -ENOMEM;
185699ca880aSopenharmony_ci
185799ca880aSopenharmony_ci                                s[sz++] = c;
185899ca880aSopenharmony_ci                        }
185999ca880aSopenharmony_ci
186099ca880aSopenharmony_ci                        break;
186199ca880aSopenharmony_ci
186299ca880aSopenharmony_ci                case SINGLE_QUOTE_ESCAPE:
186399ca880aSopenharmony_ci                        if (c == 0) {
186499ca880aSopenharmony_ci                                if (flags & UNQUOTE_RELAX)
186599ca880aSopenharmony_ci                                        goto finish;
186699ca880aSopenharmony_ci                                return -EINVAL;
186799ca880aSopenharmony_ci                        }
186899ca880aSopenharmony_ci
186999ca880aSopenharmony_ci                        if (!GREEDY_REALLOC(s, allocated, sz+7))
187099ca880aSopenharmony_ci                                return -ENOMEM;
187199ca880aSopenharmony_ci
187299ca880aSopenharmony_ci                        if (flags & UNQUOTE_CUNESCAPE) {
187399ca880aSopenharmony_ci                                uint32_t u;
187499ca880aSopenharmony_ci
187599ca880aSopenharmony_ci                                r = cunescape_one(*p, (size_t) -1, &c, &u);
187699ca880aSopenharmony_ci                                if (r < 0)
187799ca880aSopenharmony_ci                                        return -EINVAL;
187899ca880aSopenharmony_ci
187999ca880aSopenharmony_ci                                (*p) += r - 1;
188099ca880aSopenharmony_ci
188199ca880aSopenharmony_ci                                if (c != 0)
188299ca880aSopenharmony_ci                                        s[sz++] = c;
188399ca880aSopenharmony_ci                                else
188499ca880aSopenharmony_ci                                        sz += utf8_encode_unichar(s + sz, u);
188599ca880aSopenharmony_ci                        } else
188699ca880aSopenharmony_ci                                s[sz++] = c;
188799ca880aSopenharmony_ci
188899ca880aSopenharmony_ci                        state = SINGLE_QUOTE;
188999ca880aSopenharmony_ci                        break;
189099ca880aSopenharmony_ci
189199ca880aSopenharmony_ci                case DOUBLE_QUOTE:
189299ca880aSopenharmony_ci                        if (c == 0)
189399ca880aSopenharmony_ci                                return -EINVAL;
189499ca880aSopenharmony_ci                        else if (c == '\"')
189599ca880aSopenharmony_ci                                state = VALUE;
189699ca880aSopenharmony_ci                        else if (c == '\\')
189799ca880aSopenharmony_ci                                state = DOUBLE_QUOTE_ESCAPE;
189899ca880aSopenharmony_ci                        else {
189999ca880aSopenharmony_ci                                if (!GREEDY_REALLOC(s, allocated, sz+2))
190099ca880aSopenharmony_ci                                        return -ENOMEM;
190199ca880aSopenharmony_ci
190299ca880aSopenharmony_ci                                s[sz++] = c;
190399ca880aSopenharmony_ci                        }
190499ca880aSopenharmony_ci
190599ca880aSopenharmony_ci                        break;
190699ca880aSopenharmony_ci
190799ca880aSopenharmony_ci                case DOUBLE_QUOTE_ESCAPE:
190899ca880aSopenharmony_ci                        if (c == 0) {
190999ca880aSopenharmony_ci                                if (flags & UNQUOTE_RELAX)
191099ca880aSopenharmony_ci                                        goto finish;
191199ca880aSopenharmony_ci                                return -EINVAL;
191299ca880aSopenharmony_ci                        }
191399ca880aSopenharmony_ci
191499ca880aSopenharmony_ci                        if (!GREEDY_REALLOC(s, allocated, sz+7))
191599ca880aSopenharmony_ci                                return -ENOMEM;
191699ca880aSopenharmony_ci
191799ca880aSopenharmony_ci                        if (flags & UNQUOTE_CUNESCAPE) {
191899ca880aSopenharmony_ci                                uint32_t u;
191999ca880aSopenharmony_ci
192099ca880aSopenharmony_ci                                r = cunescape_one(*p, (size_t) -1, &c, &u);
192199ca880aSopenharmony_ci                                if (r < 0)
192299ca880aSopenharmony_ci                                        return -EINVAL;
192399ca880aSopenharmony_ci
192499ca880aSopenharmony_ci                                (*p) += r - 1;
192599ca880aSopenharmony_ci
192699ca880aSopenharmony_ci                                if (c != 0)
192799ca880aSopenharmony_ci                                        s[sz++] = c;
192899ca880aSopenharmony_ci                                else
192999ca880aSopenharmony_ci                                        sz += utf8_encode_unichar(s + sz, u);
193099ca880aSopenharmony_ci                        } else
193199ca880aSopenharmony_ci                                s[sz++] = c;
193299ca880aSopenharmony_ci
193399ca880aSopenharmony_ci                        state = DOUBLE_QUOTE;
193499ca880aSopenharmony_ci                        break;
193599ca880aSopenharmony_ci
193699ca880aSopenharmony_ci                case SPACE:
193799ca880aSopenharmony_ci                        if (c == 0)
193899ca880aSopenharmony_ci                                goto finish;
193999ca880aSopenharmony_ci                        if (!strchr(WHITESPACE, c))
194099ca880aSopenharmony_ci                                goto finish;
194199ca880aSopenharmony_ci
194299ca880aSopenharmony_ci                        break;
194399ca880aSopenharmony_ci                }
194499ca880aSopenharmony_ci
194599ca880aSopenharmony_ci                (*p) ++;
194699ca880aSopenharmony_ci        }
194799ca880aSopenharmony_ci
194899ca880aSopenharmony_cifinish:
194999ca880aSopenharmony_ci        if (!s) {
195099ca880aSopenharmony_ci                *ret = NULL;
195199ca880aSopenharmony_ci                return 0;
195299ca880aSopenharmony_ci        }
195399ca880aSopenharmony_ci
195499ca880aSopenharmony_ci        s[sz] = 0;
195599ca880aSopenharmony_ci        *ret = s;
195699ca880aSopenharmony_ci        s = NULL;
195799ca880aSopenharmony_ci
195899ca880aSopenharmony_ci        return 1;
195999ca880aSopenharmony_ci}
196099ca880aSopenharmony_ci
196199ca880aSopenharmony_civoid cmsg_close_all(struct msghdr *mh) {
196299ca880aSopenharmony_ci        struct cmsghdr *cmsg;
196399ca880aSopenharmony_ci
196499ca880aSopenharmony_ci        assert(mh);
196599ca880aSopenharmony_ci
196699ca880aSopenharmony_ci        for (cmsg = CMSG_FIRSTHDR(mh); cmsg; cmsg = CMSG_NXTHDR(mh, cmsg))
196799ca880aSopenharmony_ci                if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_RIGHTS)
196899ca880aSopenharmony_ci                        close_many((int*) CMSG_DATA(cmsg), (cmsg->cmsg_len - CMSG_LEN(0)) / sizeof(int));
196999ca880aSopenharmony_ci}
1970