/* SPDX-License-Identifier: LGPL-2.1-or-later */
#include <errno.h>
+#include <fnmatch.h>
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
-/* When we include libgen.h because we need dirname() we immediately
- * undefine basename() since libgen.h defines it as a macro to the
- * POSIX version which is really broken. We prefer GNU basename(). */
-#include <libgen.h>
-#undef basename
-
#include "alloc-util.h"
#include "chase-symlinks.h"
#include "extract-word.h"
#include "glob-util.h"
#include "log.h"
#include "macro.h"
-#include "nulstr-util.h"
-#include "parse-util.h"
#include "path-util.h"
#include "stat-util.h"
#include "string-util.h"
#include "strv.h"
#include "time-util.h"
-#include "utf8.h"
int path_split_and_make_absolute(const char *p, char ***ret) {
char **l;
}
int safe_getcwd(char **ret) {
- char *cwd;
+ _cleanup_free_ char *cwd = NULL;
cwd = get_current_dir_name();
if (!cwd)
/* Let's make sure the directory is really absolute, to protect us from the logic behind
* CVE-2018-1000001 */
- if (cwd[0] != '/') {
- free(cwd);
+ if (cwd[0] != '/')
return -ENOMEDIUM;
- }
- *ret = cwd;
+ if (ret)
+ *ret = TAKE_PTR(cwd);
+
return 0;
}
return 0;
}
+int path_make_relative_parent(const char *from_child, const char *to, char **ret) {
+ _cleanup_free_ char *from = NULL;
+ int r;
+
+ assert(from_child);
+ assert(to);
+ assert(ret);
+
+ /* Similar to path_make_relative(), but provides the relative path from the parent directory of
+ * 'from_child'. This may be useful when creating relative symlink. */
+
+ r = path_extract_directory(from_child, &from);
+ if (r < 0)
+ return r;
+
+ return path_make_relative(from, to, ret);
+}
+
char* path_startswith_strv(const char *p, char **set) {
STRV_FOREACH(s, set) {
char *t;
char *path_simplify(char *path) {
bool add_slash = false;
- char *f = path;
+ char *f = ASSERT_PTR(path);
int r;
- assert(path);
-
/* Removes redundant inner and trailing slashes. Also removes unnecessary dots.
* Modifies the passed string in-place.
*
return path;
}
-int path_simplify_and_warn(
- char *path,
- unsigned flag,
- const char *unit,
- const char *filename,
- unsigned line,
- const char *lvalue) {
-
- bool fatal = flag & PATH_CHECK_FATAL;
-
- assert(!FLAGS_SET(flag, PATH_CHECK_ABSOLUTE | PATH_CHECK_RELATIVE));
-
- if (!utf8_is_valid(path))
- return log_syntax_invalid_utf8(unit, LOG_ERR, filename, line, path);
-
- if (flag & (PATH_CHECK_ABSOLUTE | PATH_CHECK_RELATIVE)) {
- bool absolute;
-
- absolute = path_is_absolute(path);
-
- if (!absolute && (flag & PATH_CHECK_ABSOLUTE))
- return log_syntax(unit, LOG_ERR, filename, line, SYNTHETIC_ERRNO(EINVAL),
- "%s= path is not absolute%s: %s",
- lvalue, fatal ? "" : ", ignoring", path);
-
- if (absolute && (flag & PATH_CHECK_RELATIVE))
- return log_syntax(unit, LOG_ERR, filename, line, SYNTHETIC_ERRNO(EINVAL),
- "%s= path is absolute%s: %s",
- lvalue, fatal ? "" : ", ignoring", path);
- }
-
- path_simplify(path);
-
- if (!path_is_valid(path))
- return log_syntax(unit, LOG_ERR, filename, line, SYNTHETIC_ERRNO(EINVAL),
- "%s= path has invalid length (%zu bytes)%s.",
- lvalue, strlen(path), fatal ? "" : ", ignoring");
-
- if (!path_is_normalized(path))
- return log_syntax(unit, LOG_ERR, filename, line, SYNTHETIC_ERRNO(EINVAL),
- "%s= path is not normalized%s: %s",
- lvalue, fatal ? "" : ", ignoring", path);
-
- return 0;
-}
-
char *path_startswith_full(const char *path, const char *prefix, bool accept_dot_dot) {
assert(path);
assert(prefix);
return executable_is_good(checker);
}
-char* dirname_malloc(const char *path) {
- char *d, *dir, *dir2;
-
- assert(path);
-
- d = strdup(path);
- if (!d)
- return NULL;
-
- dir = dirname(d);
- assert(dir);
-
- if (dir == d)
- return d;
-
- dir2 = strdup(dir);
- free(d);
-
- return dir2;
-}
-
static const char *skip_slash_or_dot(const char *p) {
for (; !isempty(p); p++) {
if (*p == '/')
return -ENOMEM;
*ret = TAKE_PTR(a);
- return strlen(c) > (size_t)r ? O_DIRECTORY : 0;
+ return strlen(c) > (size_t) r ? O_DIRECTORY : 0;
}
int path_extract_directory(const char *path, char **ret) {
if (isempty(p))
return false;
- if (dot_or_dot_dot(p))
+ if (dot_or_dot_dot(p)) /* Yes, in this context we consider "." and ".." invalid */
return false;
e = strchrnul(p, '/');
assert(filename);
if (filename[0] == '.' ||
- streq(filename, "lost+found") ||
- streq(filename, "aquota.user") ||
- streq(filename, "aquota.group") ||
+ STR_IN_SET(filename,
+ "lost+found",
+ "aquota.user",
+ "aquota.group") ||
endswith(filename, "~"))
return true;
return valid_device_node_path(path);
}
-int systemd_installation_has_version(const char *root, unsigned minimal_version) {
- const char *pattern;
- int r;
-
- /* Try to guess if systemd installation is later than the specified version. This
- * is hacky and likely to yield false negatives, particularly if the installation
- * is non-standard. False positives should be relatively rare.
- */
-
- NULSTR_FOREACH(pattern,
- /* /lib works for systems without usr-merge, and for systems with a sane
- * usr-merge, where /lib is a symlink to /usr/lib. /usr/lib is necessary
- * for Gentoo which does a merge without making /lib a symlink.
- */
- "lib/systemd/libsystemd-shared-*.so\0"
- "lib64/systemd/libsystemd-shared-*.so\0"
- "usr/lib/systemd/libsystemd-shared-*.so\0"
- "usr/lib64/systemd/libsystemd-shared-*.so\0") {
-
- _cleanup_strv_free_ char **names = NULL;
- _cleanup_free_ char *path = NULL;
- char *c;
-
- path = path_join(root, pattern);
- if (!path)
- return -ENOMEM;
-
- r = glob_extend(&names, path, 0);
- if (r == -ENOENT)
- continue;
- if (r < 0)
- return r;
-
- assert_se(c = endswith(path, "*.so"));
- *c = '\0'; /* truncate the glob part */
-
- STRV_FOREACH(name, names) {
- /* This is most likely to run only once, hence let's not optimize anything. */
- char *t, *t2;
- unsigned version;
-
- t = startswith(*name, path);
- if (!t)
- continue;
-
- t2 = endswith(t, ".so");
- if (!t2)
- continue;
-
- t2[0] = '\0'; /* truncate the suffix */
-
- r = safe_atou(t, &version);
- if (r < 0) {
- log_debug_errno(r, "Found libsystemd shared at \"%s.so\", but failed to parse version: %m", *name);
- continue;
- }
-
- log_debug("Found libsystemd shared at \"%s.so\", version %u (%s).",
- *name, version,
- version >= minimal_version ? "OK" : "too old");
- if (version >= minimal_version)
- return true;
- }
- }
-
- return false;
-}
-
bool dot_or_dot_dot(const char *path) {
if (!path)
return false;
return false;
}
+
+int path_glob_can_match(const char *pattern, const char *prefix, char **ret) {
+ assert(pattern);
+ assert(prefix);
+
+ for (const char *a = pattern, *b = prefix;;) {
+ _cleanup_free_ char *g = NULL, *h = NULL;
+ const char *p, *q;
+ int r, s;
+
+ r = path_find_first_component(&a, /* accept_dot_dot = */ false, &p);
+ if (r < 0)
+ return r;
+
+ s = path_find_first_component(&b, /* accept_dot_dot = */ false, &q);
+ if (s < 0)
+ return s;
+
+ if (s == 0) {
+ /* The pattern matches the prefix. */
+ if (ret) {
+ char *t;
+
+ t = path_join(prefix, p);
+ if (!t)
+ return -ENOMEM;
+
+ *ret = t;
+ }
+ return true;
+ }
+
+ if (r == 0)
+ break;
+
+ if (r == s && strneq(p, q, r))
+ continue; /* common component. Check next. */
+
+ g = strndup(p, r);
+ if (!g)
+ return -ENOMEM;
+
+ if (!string_is_glob(g))
+ break;
+
+ /* We found a glob component. Check if the glob pattern matches the prefix component. */
+
+ h = strndup(q, s);
+ if (!h)
+ return -ENOMEM;
+
+ r = fnmatch(g, h, 0);
+ if (r == FNM_NOMATCH)
+ break;
+ if (r != 0) /* Failure to process pattern? */
+ return -EINVAL;
+ }
+
+ /* The pattern does not match the prefix. */
+ if (ret)
+ *ret = NULL;
+ return false;
+}