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