summaryrefslogtreecommitdiff
path: root/src/systemd/src/basic/util.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/systemd/src/basic/util.c')
-rw-r--r--src/systemd/src/basic/util.c364
1 files changed, 235 insertions, 129 deletions
diff --git a/src/systemd/src/basic/util.c b/src/systemd/src/basic/util.c
index 4293268857..3b41adad8d 100644
--- a/src/systemd/src/basic/util.c
+++ b/src/systemd/src/basic/util.c
@@ -339,6 +339,33 @@ void close_many(const int fds[], unsigned n_fd) {
}
#endif /* NM_IGNORED */
+int fclose_nointr(FILE *f) {
+ assert(f);
+
+ /* Same as close_nointr(), but for fclose() */
+
+ if (fclose(f) == 0)
+ return 0;
+
+ if (errno == EINTR)
+ return 0;
+
+ return -errno;
+}
+
+FILE* safe_fclose(FILE *f) {
+
+ /* Same as safe_close(), but for fclose() */
+
+ if (f) {
+ PROTECT_ERRNO;
+
+ assert_se(fclose_nointr(f) != EBADF);
+ }
+
+ return NULL;
+}
+
int unlink_noerrno(const char *path) {
PROTECT_ERRNO;
int r;
@@ -386,6 +413,19 @@ int parse_pid(const char *s, pid_t* ret_pid) {
return 0;
}
+bool uid_is_valid(uid_t uid) {
+
+ /* Some libc APIs use UID_INVALID as special placeholder */
+ if (uid == (uid_t) 0xFFFFFFFF)
+ return false;
+
+ /* A long time ago UIDs where 16bit, hence explicitly avoid the 16bit -1 too */
+ if (uid == (uid_t) 0xFFFF)
+ return false;
+
+ return true;
+}
+
int parse_uid(const char *s, uid_t* ret_uid) {
unsigned long ul = 0;
uid_t uid;
@@ -402,13 +442,11 @@ int parse_uid(const char *s, uid_t* ret_uid) {
if ((unsigned long) uid != ul)
return -ERANGE;
- /* Some libc APIs use UID_INVALID as special placeholder */
- if (uid == (uid_t) 0xFFFFFFFF)
- return -ENXIO;
-
- /* A long time ago UIDs where 16bit, hence explicitly avoid the 16bit -1 too */
- if (uid == (uid_t) 0xFFFF)
- return -ENXIO;
+ if (!uid_is_valid(uid))
+ return -ENXIO; /* we return ENXIO instead of EINVAL
+ * here, to make it easy to distuingish
+ * invalid numeric uids invalid
+ * strings. */
if (ret_uid)
*ret_uid = uid;
@@ -477,6 +515,7 @@ int safe_atou8(const char *s, uint8_t *ret) {
*ret = (uint8_t) l;
return 0;
}
+#endif /* NM_IGNORED */
int safe_atou16(const char *s, uint16_t *ret) {
char *x = NULL;
@@ -498,6 +537,7 @@ int safe_atou16(const char *s, uint16_t *ret) {
return 0;
}
+#if 0 /* NM_IGNORED */
int safe_atoi16(const char *s, int16_t *ret) {
char *x = NULL;
long l;
@@ -2201,7 +2241,7 @@ int loop_write(int fd, const void *buf, size_t nbytes, bool do_poll) {
return 0;
}
-int parse_size(const char *t, off_t base, off_t *size) {
+int parse_size(const char *t, uint64_t base, uint64_t *size) {
/* Soo, sometimes we want to parse IEC binary suffixes, and
* sometimes SI decimal suffixes. This function can parse
@@ -2229,8 +2269,8 @@ int parse_size(const char *t, off_t base, off_t *size) {
{ "G", 1024ULL*1024ULL*1024ULL },
{ "M", 1024ULL*1024ULL },
{ "K", 1024ULL },
- { "B", 1 },
- { "", 1 },
+ { "B", 1ULL },
+ { "", 1ULL },
};
static const struct table si[] = {
@@ -2240,8 +2280,8 @@ int parse_size(const char *t, off_t base, off_t *size) {
{ "G", 1000ULL*1000ULL*1000ULL },
{ "M", 1000ULL*1000ULL },
{ "K", 1000ULL },
- { "B", 1 },
- { "", 1 },
+ { "B", 1ULL },
+ { "", 1ULL },
};
const struct table *table;
@@ -2263,33 +2303,32 @@ int parse_size(const char *t, off_t base, off_t *size) {
p = t;
do {
- long long l;
- unsigned long long l2;
+ unsigned long long l, tmp;
double frac = 0;
char *e;
unsigned i;
- errno = 0;
- l = strtoll(p, &e, 10);
+ p += strspn(p, WHITESPACE);
+ if (*p == '-')
+ return -ERANGE;
+ errno = 0;
+ l = strtoull(p, &e, 10);
if (errno > 0)
return -errno;
-
- if (l < 0)
- return -ERANGE;
-
if (e == p)
return -EINVAL;
if (*e == '.') {
e++;
+
+ /* strtoull() itself would accept space/+/- */
if (*e >= '0' && *e <= '9') {
+ unsigned long long l2;
char *e2;
- /* strotoull itself would accept space/+/- */
l2 = strtoull(e, &e2, 10);
-
- if (errno == ERANGE)
+ if (errno > 0)
return -errno;
/* Ignore failure. E.g. 10.M is valid */
@@ -2302,27 +2341,27 @@ int parse_size(const char *t, off_t base, off_t *size) {
e += strspn(e, WHITESPACE);
for (i = start_pos; i < n_entries; i++)
- if (startswith(e, table[i].suffix)) {
- unsigned long long tmp;
- if ((unsigned long long) l + (frac > 0) > ULLONG_MAX / table[i].factor)
- return -ERANGE;
- tmp = l * table[i].factor + (unsigned long long) (frac * table[i].factor);
- if (tmp > ULLONG_MAX - r)
- return -ERANGE;
-
- r += tmp;
- if ((unsigned long long) (off_t) r != r)
- return -ERANGE;
-
- p = e + strlen(table[i].suffix);
-
- start_pos = i + 1;
+ if (startswith(e, table[i].suffix))
break;
- }
if (i >= n_entries)
return -EINVAL;
+ if (l + (frac > 0) > ULLONG_MAX / table[i].factor)
+ return -ERANGE;
+
+ tmp = l * table[i].factor + (unsigned long long) (frac * table[i].factor);
+ if (tmp > ULLONG_MAX - r)
+ return -ERANGE;
+
+ r += tmp;
+ if ((unsigned long long) (uint64_t) r != r)
+ return -ERANGE;
+
+ p = e + strlen(table[i].suffix);
+
+ start_pos = i + 1;
+
} while (*p);
*size = r;
@@ -3033,21 +3072,6 @@ char* strshorten(char *s, size_t l) {
}
#if 0 /* NM_IGNORED */
-bool machine_name_is_valid(const char *s) {
-
- if (!hostname_is_valid(s, false))
- return false;
-
- /* Machine names should be useful hostnames, but also be
- * useful in unit names, hence we enforce a stricter length
- * limitation. */
-
- if (strlen(s) > 64)
- return false;
-
- return true;
-}
-
int pipe_eof(int fd) {
struct pollfd pollfd = {
.fd = fd,
@@ -3793,38 +3817,38 @@ int prot_from_flags(int flags) {
}
}
-char *format_bytes(char *buf, size_t l, off_t t) {
+char *format_bytes(char *buf, size_t l, uint64_t t) {
unsigned i;
static const struct {
const char *suffix;
- off_t factor;
+ uint64_t factor;
} table[] = {
- { "E", 1024ULL*1024ULL*1024ULL*1024ULL*1024ULL*1024ULL },
- { "P", 1024ULL*1024ULL*1024ULL*1024ULL*1024ULL },
- { "T", 1024ULL*1024ULL*1024ULL*1024ULL },
- { "G", 1024ULL*1024ULL*1024ULL },
- { "M", 1024ULL*1024ULL },
- { "K", 1024ULL },
+ { "E", UINT64_C(1024)*UINT64_C(1024)*UINT64_C(1024)*UINT64_C(1024)*UINT64_C(1024)*UINT64_C(1024) },
+ { "P", UINT64_C(1024)*UINT64_C(1024)*UINT64_C(1024)*UINT64_C(1024)*UINT64_C(1024) },
+ { "T", UINT64_C(1024)*UINT64_C(1024)*UINT64_C(1024)*UINT64_C(1024) },
+ { "G", UINT64_C(1024)*UINT64_C(1024)*UINT64_C(1024) },
+ { "M", UINT64_C(1024)*UINT64_C(1024) },
+ { "K", UINT64_C(1024) },
};
- if (t == (off_t) -1)
+ if (t == (uint64_t) -1)
return NULL;
for (i = 0; i < ELEMENTSOF(table); i++) {
if (t >= table[i].factor) {
snprintf(buf, l,
- "%llu.%llu%s",
- (unsigned long long) (t / table[i].factor),
- (unsigned long long) (((t*10ULL) / table[i].factor) % 10ULL),
+ "%" PRIu64 ".%" PRIu64 "%s",
+ t / table[i].factor,
+ ((t*UINT64_C(10)) / table[i].factor) % UINT64_C(10),
table[i].suffix);
goto finish;
}
}
- snprintf(buf, l, "%lluB", (unsigned long long) t);
+ snprintf(buf, l, "%" PRIu64 "B", t);
finish:
buf[l-1] = 0;
@@ -4325,7 +4349,7 @@ bool is_locale_utf8(void) {
/* Check result, but ignore the result if C was set
* explicitly. */
cached_answer =
- streq(set, "C") &&
+ STR_IN_SET(set, "C", "POSIX") &&
!getenv("LC_ALL") &&
!getenv("LC_CTYPE") &&
!getenv("LANG");
@@ -4752,7 +4776,6 @@ void* greedy_realloc(void **p, size_t *allocated, size_t need, size_t size) {
return q;
}
-#if 0 /* NM_IGNORED */
void* greedy_realloc0(void **p, size_t *allocated, size_t need, size_t size) {
size_t prev;
uint8_t *q;
@@ -4772,6 +4795,7 @@ void* greedy_realloc0(void **p, size_t *allocated, size_t need, size_t size) {
return q;
}
+#if 0 /* NM_IGNORED */
bool id128_is_valid(const char *s) {
size_t i, l;
@@ -4860,7 +4884,7 @@ int shall_restore_state(void) {
int proc_cmdline(char **ret) {
assert(ret);
- if (detect_container(NULL) > 0)
+ if (detect_container() > 0)
return get_process_cmdline(1, 0, false, ret);
else
return read_one_line_file("/proc/cmdline", ret);
@@ -4882,7 +4906,7 @@ int parse_proc_cmdline(int (*parse_item)(const char *key, const char *value)) {
_cleanup_free_ char *word = NULL;
char *value = NULL;
- r = unquote_first_word(&p, &word, UNQUOTE_RELAX);
+ r = extract_first_word(&p, &word, NULL, EXTRACT_QUOTES|EXTRACT_RELAX);
if (r < 0)
return r;
if (r == 0)
@@ -4922,7 +4946,7 @@ int get_proc_cmdline_key(const char *key, char **value) {
_cleanup_free_ char *word = NULL;
const char *e;
- r = unquote_first_word(&p, &word, UNQUOTE_RELAX);
+ r = extract_first_word(&p, &word, NULL, EXTRACT_QUOTES|EXTRACT_RELAX);
if (r < 0)
return r;
if (r == 0)
@@ -4967,6 +4991,9 @@ int container_get_leader(const char *machine, pid_t *pid) {
assert(machine);
assert(pid);
+ if (!machine_name_is_valid(machine))
+ return -EINVAL;
+
p = strjoina("/run/systemd/machines/", machine);
r = parse_env_file(p, NEWLINE, "LEADER", &s, "CLASS", &class, NULL);
if (r == -ENOENT)
@@ -4989,8 +5016,8 @@ int container_get_leader(const char *machine, pid_t *pid) {
return 0;
}
-int namespace_open(pid_t pid, int *pidns_fd, int *mntns_fd, int *netns_fd, int *root_fd) {
- _cleanup_close_ int pidnsfd = -1, mntnsfd = -1, netnsfd = -1;
+int namespace_open(pid_t pid, int *pidns_fd, int *mntns_fd, int *netns_fd, int *userns_fd, int *root_fd) {
+ _cleanup_close_ int pidnsfd = -1, mntnsfd = -1, netnsfd = -1, usernsfd = -1;
int rfd = -1;
assert(pid >= 0);
@@ -5022,6 +5049,15 @@ int namespace_open(pid_t pid, int *pidns_fd, int *mntns_fd, int *netns_fd, int *
return -errno;
}
+ if (userns_fd) {
+ const char *userns;
+
+ userns = procfs_file_alloca(pid, "ns/user");
+ usernsfd = open(userns, O_RDONLY|O_NOCTTY|O_CLOEXEC);
+ if (usernsfd < 0 && errno != ENOENT)
+ return -errno;
+ }
+
if (root_fd) {
const char *root;
@@ -5040,15 +5076,33 @@ int namespace_open(pid_t pid, int *pidns_fd, int *mntns_fd, int *netns_fd, int *
if (netns_fd)
*netns_fd = netnsfd;
+ if (userns_fd)
+ *userns_fd = usernsfd;
+
if (root_fd)
*root_fd = rfd;
- pidnsfd = mntnsfd = netnsfd = -1;
+ pidnsfd = mntnsfd = netnsfd = usernsfd = -1;
return 0;
}
-int namespace_enter(int pidns_fd, int mntns_fd, int netns_fd, int root_fd) {
+int namespace_enter(int pidns_fd, int mntns_fd, int netns_fd, int userns_fd, int root_fd) {
+ if (userns_fd >= 0) {
+ /* Can't setns to your own userns, since then you could
+ * escalate from non-root to root in your own namespace, so
+ * check if namespaces equal before attempting to enter. */
+ _cleanup_free_ char *userns_fd_path = NULL;
+ int r;
+ if (asprintf(&userns_fd_path, "/proc/self/fd/%d", userns_fd) < 0)
+ return -ENOMEM;
+
+ r = files_same(userns_fd_path, "/proc/self/ns/user");
+ if (r < 0)
+ return r;
+ if (r)
+ userns_fd = -1;
+ }
if (pidns_fd >= 0)
if (setns(pidns_fd, CLONE_NEWPID) < 0)
@@ -5062,6 +5116,10 @@ int namespace_enter(int pidns_fd, int mntns_fd, int netns_fd, int root_fd) {
if (setns(netns_fd, CLONE_NEWNET) < 0)
return -errno;
+ if (userns_fd >= 0)
+ if (setns(userns_fd, CLONE_NEWUSER) < 0)
+ return -errno;
+
if (root_fd >= 0) {
if (fchdir(root_fd) < 0)
return -errno;
@@ -5741,7 +5799,7 @@ int is_device_node(const char *path) {
return !!(S_ISBLK(info.st_mode) || S_ISCHR(info.st_mode));
}
-int unquote_first_word(const char **p, char **ret, UnquoteFlags flags) {
+int extract_first_word(const char **p, char **ret, const char *separators, ExtractFlags flags) {
_cleanup_free_ char *s = NULL;
size_t allocated = 0, sz = 0;
int r;
@@ -5754,13 +5812,19 @@ int unquote_first_word(const char **p, char **ret, UnquoteFlags flags) {
SINGLE_QUOTE_ESCAPE,
DOUBLE_QUOTE,
DOUBLE_QUOTE_ESCAPE,
- SPACE,
+ SEPARATOR,
} state = START;
assert(p);
- assert(*p);
assert(ret);
+ if (!separators)
+ separators = WHITESPACE;
+
+ /* Bail early if called after last value or with no input */
+ if (!*p)
+ goto finish_force_terminate;
+
/* Parses the first word of a string, and returns it in
* *ret. Removes all quotes in the process. When parsing fails
* (because of an uneven number of quotes or similar), leaves
@@ -5772,32 +5836,45 @@ int unquote_first_word(const char **p, char **ret, UnquoteFlags flags) {
switch (state) {
case START:
+ if (flags & EXTRACT_DONT_COALESCE_SEPARATORS)
+ if (!GREEDY_REALLOC(s, allocated, sz+1))
+ return -ENOMEM;
+
if (c == 0)
- goto finish;
- else if (strchr(WHITESPACE, c))
+ goto finish_force_terminate;
+ else if (strchr(separators, c)) {
+ if (flags & EXTRACT_DONT_COALESCE_SEPARATORS) {
+ (*p) ++;
+ goto finish_force_next;
+ }
break;
+ }
+
+ /* We found a non-blank character, so we will always
+ * want to return a string (even if it is empty),
+ * allocate it here. */
+ if (!GREEDY_REALLOC(s, allocated, sz+1))
+ return -ENOMEM;
state = VALUE;
/* fallthrough */
case VALUE:
if (c == 0)
- goto finish;
- else if (c == '\'') {
- if (!GREEDY_REALLOC(s, allocated, sz+1))
- return -ENOMEM;
-
+ goto finish_force_terminate;
+ else if (c == '\'' && (flags & EXTRACT_QUOTES))
state = SINGLE_QUOTE;
- } else if (c == '\\')
+ else if (c == '\\')
state = VALUE_ESCAPE;
- else if (c == '\"') {
- if (!GREEDY_REALLOC(s, allocated, sz+1))
- return -ENOMEM;
-
+ else if (c == '\"' && (flags & EXTRACT_QUOTES))
state = DOUBLE_QUOTE;
- } else if (strchr(WHITESPACE, c))
- state = SPACE;
- else {
+ else if (strchr(separators, c)) {
+ if (flags & EXTRACT_DONT_COALESCE_SEPARATORS) {
+ (*p) ++;
+ goto finish_force_next;
+ }
+ state = SEPARATOR;
+ } else {
if (!GREEDY_REALLOC(s, allocated, sz+2))
return -ENOMEM;
@@ -5808,8 +5885,8 @@ int unquote_first_word(const char **p, char **ret, UnquoteFlags flags) {
case SINGLE_QUOTE:
if (c == 0) {
- if (flags & UNQUOTE_RELAX)
- goto finish;
+ if (flags & EXTRACT_RELAX)
+ goto finish_force_terminate;
return -EINVAL;
} else if (c == '\'')
state = VALUE;
@@ -5847,29 +5924,29 @@ int unquote_first_word(const char **p, char **ret, UnquoteFlags flags) {
return -ENOMEM;
if (c == 0) {
- if ((flags & UNQUOTE_CUNESCAPE_RELAX) &&
- (state == VALUE_ESCAPE || flags & UNQUOTE_RELAX)) {
+ if ((flags & EXTRACT_CUNESCAPE_RELAX) &&
+ (state == VALUE_ESCAPE || flags & EXTRACT_RELAX)) {
/* If we find an unquoted trailing backslash and we're in
- * UNQUOTE_CUNESCAPE_RELAX mode, keep it verbatim in the
+ * EXTRACT_CUNESCAPE_RELAX mode, keep it verbatim in the
* output.
*
- * Unbalanced quotes will only be allowed in UNQUOTE_RELAX
- * mode, UNQUOTE_CUNESCAP_RELAX mode does not allow them.
+ * Unbalanced quotes will only be allowed in EXTRACT_RELAX
+ * mode, EXTRACT_CUNESCAPE_RELAX mode does not allow them.
*/
s[sz++] = '\\';
- goto finish;
+ goto finish_force_terminate;
}
- if (flags & UNQUOTE_RELAX)
- goto finish;
+ if (flags & EXTRACT_RELAX)
+ goto finish_force_terminate;
return -EINVAL;
}
- if (flags & UNQUOTE_CUNESCAPE) {
+ if (flags & EXTRACT_CUNESCAPE) {
uint32_t u;
r = cunescape_one(*p, (size_t) -1, &c, &u);
if (r < 0) {
- if (flags & UNQUOTE_CUNESCAPE_RELAX) {
+ if (flags & EXTRACT_CUNESCAPE_RELAX) {
s[sz++] = '\\';
s[sz++] = c;
goto end_escape;
@@ -5892,24 +5969,27 @@ end_escape:
VALUE;
break;
- case SPACE:
+ case SEPARATOR:
if (c == 0)
+ goto finish_force_terminate;
+ if (!strchr(separators, c))
goto finish;
- if (!strchr(WHITESPACE, c))
- goto finish;
-
break;
}
(*p) ++;
}
+finish_force_terminate:
+ *p = NULL;
finish:
if (!s) {
+ *p = NULL;
*ret = NULL;
return 0;
}
+finish_force_next:
s[sz] = 0;
*ret = s;
s = NULL;
@@ -5917,26 +5997,27 @@ finish:
return 1;
}
-int unquote_first_word_and_warn(
+int extract_first_word_and_warn(
const char **p,
char **ret,
- UnquoteFlags flags,
+ const char *separators,
+ ExtractFlags flags,
const char *unit,
const char *filename,
unsigned line,
const char *rvalue) {
/* Try to unquote it, if it fails, warn about it and try again but this
- * time using UNQUOTE_CUNESCAPE_RELAX to keep the backslashes verbatim
+ * time using EXTRACT_CUNESCAPE_RELAX to keep the backslashes verbatim
* in invalid escape sequences. */
const char *save;
int r;
save = *p;
- r = unquote_first_word(p, ret, flags);
- if (r < 0 && !(flags&UNQUOTE_CUNESCAPE_RELAX)) {
- /* Retry it with UNQUOTE_CUNESCAPE_RELAX. */
+ r = extract_first_word(p, ret, separators, flags);
+ if (r < 0 && !(flags&EXTRACT_CUNESCAPE_RELAX)) {
+ /* Retry it with EXTRACT_CUNESCAPE_RELAX. */
*p = save;
- r = unquote_first_word(p, ret, flags|UNQUOTE_CUNESCAPE_RELAX);
+ r = extract_first_word(p, ret, separators, flags|EXTRACT_CUNESCAPE_RELAX);
if (r < 0)
log_syntax(unit, LOG_ERR, filename, line, EINVAL,
"Unbalanced quoting in command line, ignoring: \"%s\"", rvalue);
@@ -5947,7 +6028,7 @@ int unquote_first_word_and_warn(
return r;
}
-int unquote_many_words(const char **p, UnquoteFlags flags, ...) {
+int extract_many_words(const char **p, const char *separators, ExtractFlags flags, ...) {
va_list ap;
char **l;
int n = 0, i, c, r;
@@ -5973,7 +6054,7 @@ int unquote_many_words(const char **p, UnquoteFlags flags, ...) {
l = newa0(char*, n);
for (c = 0; c < n; c++) {
- r = unquote_first_word(p, &l[c], flags);
+ r = extract_first_word(p, &l[c], separators, flags);
if (r < 0) {
int j;
@@ -6055,7 +6136,7 @@ int ptsname_malloc(int fd, char **ret) {
}
int openpt_in_namespace(pid_t pid, int flags) {
- _cleanup_close_ int pidnsfd = -1, mntnsfd = -1, rootfd = -1;
+ _cleanup_close_ int pidnsfd = -1, mntnsfd = -1, usernsfd = -1, rootfd = -1;
_cleanup_close_pair_ int pair[2] = { -1, -1 };
union {
struct cmsghdr cmsghdr;
@@ -6072,7 +6153,7 @@ int openpt_in_namespace(pid_t pid, int flags) {
assert(pid > 0);
- r = namespace_open(pid, &pidnsfd, &mntnsfd, NULL, &rootfd);
+ r = namespace_open(pid, &pidnsfd, &mntnsfd, NULL, &usernsfd, &rootfd);
if (r < 0)
return r;
@@ -6088,7 +6169,7 @@ int openpt_in_namespace(pid_t pid, int flags) {
pair[0] = safe_close(pair[0]);
- r = namespace_enter(pidnsfd, mntnsfd, -1, rootfd);
+ r = namespace_enter(pidnsfd, mntnsfd, -1, usernsfd, rootfd);
if (r < 0)
_exit(EXIT_FAILURE);
@@ -6096,6 +6177,9 @@ int openpt_in_namespace(pid_t pid, int flags) {
if (master < 0)
_exit(EXIT_FAILURE);
+ if (unlockpt(master) < 0)
+ _exit(EXIT_FAILURE);
+
cmsg = CMSG_FIRSTHDR(&mh);
cmsg->cmsg_level = SOL_SOCKET;
cmsg->cmsg_type = SCM_RIGHTS;
@@ -6555,7 +6639,35 @@ int rename_noreplace(int olddirfd, const char *oldpath, int newdirfd, const char
return 0;
}
+#endif /* NM_IGNORED */
+static char *strcpy_backslash_escaped(char *t, const char *s, const char *bad) {
+ assert(bad);
+
+ for (; *s; s++) {
+ if (*s == '\\' || strchr(bad, *s))
+ *(t++) = '\\';
+
+ *(t++) = *s;
+ }
+
+ return t;
+}
+
+char *shell_escape(const char *s, const char *bad) {
+ char *r, *t;
+
+ r = new(char, strlen(s)*2+1);
+ if (!r)
+ return NULL;
+
+ t = strcpy_backslash_escaped(r, s, bad);
+ *t = 0;
+
+ return r;
+}
+
+#if 0 /* NM_IGNORED */
char *shell_maybe_quote(const char *s) {
const char *p;
char *r, *t;
@@ -6582,13 +6694,7 @@ char *shell_maybe_quote(const char *s) {
*(t++) = '"';
t = mempcpy(t, s, p - s);
- for (; *p; p++) {
-
- if (strchr(SHELL_NEED_ESCAPE, *p))
- *(t++) = '\\';
-
- *(t++) = *p;
- }
+ t = strcpy_backslash_escaped(t, p, SHELL_NEED_ESCAPE);
*(t++)= '"';
*t = 0;