/src/systemd/src/basic/path-util.h
Line | Count | Source (jump to first uncovered line) |
1 | | /* SPDX-License-Identifier: LGPL-2.1-or-later */ |
2 | | #pragma once |
3 | | |
4 | | #include <alloca.h> |
5 | | #include <stdbool.h> |
6 | | #include <stddef.h> |
7 | | |
8 | | #include "macro.h" |
9 | | #include "string-util.h" |
10 | | #include "strv.h" |
11 | | #include "time-util.h" |
12 | | |
13 | | #define PATH_SPLIT_SBIN_BIN(x) x "sbin:" x "bin" |
14 | | #define PATH_SPLIT_SBIN_BIN_NULSTR(x) x "sbin\0" x "bin\0" |
15 | | |
16 | | #define PATH_NORMAL_SBIN_BIN(x) x "bin" |
17 | | #define PATH_NORMAL_SBIN_BIN_NULSTR(x) x "bin\0" |
18 | | |
19 | | #if HAVE_SPLIT_BIN |
20 | | # define PATH_SBIN_BIN(x) PATH_SPLIT_SBIN_BIN(x) |
21 | | # define PATH_SBIN_BIN_NULSTR(x) PATH_SPLIT_SBIN_BIN_NULSTR(x) |
22 | | #else |
23 | | # define PATH_SBIN_BIN(x) PATH_NORMAL_SBIN_BIN(x) |
24 | | # define PATH_SBIN_BIN_NULSTR(x) PATH_NORMAL_SBIN_BIN_NULSTR(x) |
25 | | #endif |
26 | | |
27 | | #define DEFAULT_PATH_NORMAL PATH_SBIN_BIN("/usr/local/") ":" PATH_SBIN_BIN("/usr/") |
28 | | #define DEFAULT_PATH_NORMAL_NULSTR PATH_SBIN_BIN_NULSTR("/usr/local/") PATH_SBIN_BIN_NULSTR("/usr/") |
29 | | #define DEFAULT_PATH_SPLIT_USR DEFAULT_PATH_NORMAL ":" PATH_SBIN_BIN("/") |
30 | | #define DEFAULT_PATH_SPLIT_USR_NULSTR DEFAULT_PATH_NORMAL_NULSTR PATH_SBIN_BIN_NULSTR("/") |
31 | | #define DEFAULT_PATH_COMPAT PATH_SPLIT_SBIN_BIN("/usr/local/") ":" PATH_SPLIT_SBIN_BIN("/usr/") ":" PATH_SPLIT_SBIN_BIN("/") |
32 | | |
33 | | #if HAVE_SPLIT_USR |
34 | | # define DEFAULT_PATH DEFAULT_PATH_SPLIT_USR |
35 | | # define DEFAULT_PATH_NULSTR DEFAULT_PATH_SPLIT_USR_NULSTR |
36 | | #else |
37 | | # define DEFAULT_PATH DEFAULT_PATH_NORMAL |
38 | | # define DEFAULT_PATH_NULSTR DEFAULT_PATH_NORMAL_NULSTR |
39 | | #endif |
40 | | |
41 | | #ifndef DEFAULT_USER_PATH |
42 | | # define DEFAULT_USER_PATH DEFAULT_PATH |
43 | | #endif |
44 | | |
45 | 0 | static inline bool is_path(const char *p) { |
46 | 0 | if (!p) /* A NULL pointer is definitely not a path */ |
47 | 0 | return false; |
48 | 0 |
|
49 | 0 | return strchr(p, '/'); |
50 | 0 | } |
51 | | |
52 | 6.01k | static inline bool path_is_absolute(const char *p) { |
53 | 6.01k | if (!p) /* A NULL pointer is definitely not an absolute path */ |
54 | 0 | return false; |
55 | | |
56 | 6.01k | return p[0] == '/'; |
57 | 6.01k | } |
58 | | |
59 | | int path_split_and_make_absolute(const char *p, char ***ret); |
60 | | char* path_make_absolute(const char *p, const char *prefix); |
61 | | int safe_getcwd(char **ret); |
62 | | int path_make_absolute_cwd(const char *p, char **ret); |
63 | | int path_make_relative(const char *from, const char *to, char **ret); |
64 | | int path_make_relative_parent(const char *from_child, const char *to, char **ret); |
65 | | char *path_startswith_full(const char *path, const char *prefix, bool accept_dot_dot) _pure_; |
66 | 0 | static inline char* path_startswith(const char *path, const char *prefix) { |
67 | 0 | return path_startswith_full(path, prefix, true); |
68 | 0 | } |
69 | | int path_compare(const char *a, const char *b) _pure_; |
70 | | |
71 | 0 | static inline bool path_equal(const char *a, const char *b) { |
72 | 0 | return path_compare(a, b) == 0; |
73 | 0 | } |
74 | | |
75 | | bool path_equal_or_files_same(const char *a, const char *b, int flags); |
76 | | /* Compares only the last portion of the input paths, ie: the filenames */ |
77 | | bool path_equal_filename(const char *a, const char *b); |
78 | | |
79 | | char* path_extend_internal(char **x, ...); |
80 | | #define path_extend(x, ...) path_extend_internal(x, __VA_ARGS__, POINTER_MAX) |
81 | | #define path_join(...) path_extend_internal(NULL, __VA_ARGS__, POINTER_MAX) |
82 | | |
83 | | char* path_simplify(char *path); |
84 | | |
85 | 0 | static inline bool path_equal_ptr(const char *a, const char *b) { |
86 | 0 | return !!a == !!b && (!a || path_equal(a, b)); |
87 | 0 | } |
88 | | |
89 | | /* Note: the search terminates on the first NULL item. */ |
90 | | #define PATH_IN_SET(p, ...) path_strv_contains(STRV_MAKE(__VA_ARGS__), p) |
91 | | |
92 | | char* path_startswith_strv(const char *p, char **set); |
93 | | #define PATH_STARTSWITH_SET(p, ...) path_startswith_strv(p, STRV_MAKE(__VA_ARGS__)) |
94 | | |
95 | | int path_strv_make_absolute_cwd(char **l); |
96 | | char** path_strv_resolve(char **l, const char *root); |
97 | | char** path_strv_resolve_uniq(char **l, const char *root); |
98 | | |
99 | | int find_executable_full(const char *name, const char *root, char **exec_search_path, bool use_path_envvar, char **ret_filename, int *ret_fd); |
100 | 0 | static inline int find_executable(const char *name, char **ret_filename) { |
101 | 0 | return find_executable_full(name, /* root= */ NULL, NULL, true, ret_filename, NULL); |
102 | 0 | } |
103 | | |
104 | | bool paths_check_timestamp(const char* const* paths, usec_t *paths_ts_usec, bool update); |
105 | | |
106 | | int fsck_exists(const char *fstype); |
107 | | |
108 | | /* Iterates through the path prefixes of the specified path, going up |
109 | | * the tree, to root. Also returns "" (and not "/"!) for the root |
110 | | * directory. Excludes the specified directory itself */ |
111 | | #define PATH_FOREACH_PREFIX(prefix, path) \ |
112 | | for (char *_slash = ({ \ |
113 | | path_simplify(strcpy(prefix, path)); \ |
114 | | streq(prefix, "/") ? NULL : strrchr(prefix, '/'); \ |
115 | | }); \ |
116 | | _slash && ((*_slash = 0), true); \ |
117 | | _slash = strrchr((prefix), '/')) |
118 | | |
119 | | /* Same as PATH_FOREACH_PREFIX but also includes the specified path itself */ |
120 | | #define PATH_FOREACH_PREFIX_MORE(prefix, path) \ |
121 | | for (char *_slash = ({ \ |
122 | | path_simplify(strcpy(prefix, path)); \ |
123 | | if (streq(prefix, "/")) \ |
124 | | prefix[0] = 0; \ |
125 | | strrchr(prefix, 0); \ |
126 | | }); \ |
127 | | _slash && ((*_slash = 0), true); \ |
128 | | _slash = strrchr((prefix), '/')) |
129 | | |
130 | | /* Similar to path_join(), but only works for two components, and only the first one may be NULL and returns |
131 | | * an alloca() buffer, or possibly a const pointer into the path parameter. */ |
132 | | #define prefix_roota(root, path) \ |
133 | | ({ \ |
134 | | const char* _path = (path), *_root = (root), *_ret; \ |
135 | | char *_p, *_n; \ |
136 | | size_t _l; \ |
137 | | while (_path[0] == '/' && _path[1] == '/') \ |
138 | | _path ++; \ |
139 | | if (isempty(_root)) \ |
140 | | _ret = _path; \ |
141 | | else { \ |
142 | | _l = strlen(_root) + 1 + strlen(_path) + 1; \ |
143 | | _n = newa(char, _l); \ |
144 | | _p = stpcpy(_n, _root); \ |
145 | | while (_p > _n && _p[-1] == '/') \ |
146 | | _p--; \ |
147 | | if (_path[0] != '/') \ |
148 | | *(_p++) = '/'; \ |
149 | | strcpy(_p, _path); \ |
150 | | _ret = _n; \ |
151 | | } \ |
152 | | _ret; \ |
153 | | }) |
154 | | |
155 | | int path_find_first_component(const char **p, bool accept_dot_dot, const char **ret); |
156 | | int path_find_last_component(const char *path, bool accept_dot_dot, const char **next, const char **ret); |
157 | | const char *last_path_component(const char *path); |
158 | | int path_extract_filename(const char *path, char **ret); |
159 | | int path_extract_directory(const char *path, char **ret); |
160 | | |
161 | | bool filename_is_valid(const char *p) _pure_; |
162 | | bool path_is_valid_full(const char *p, bool accept_dot_dot) _pure_; |
163 | 0 | static inline bool path_is_valid(const char *p) { |
164 | 0 | return path_is_valid_full(p, /* accept_dot_dot= */ true); |
165 | 0 | } |
166 | 4.55k | static inline bool path_is_safe(const char *p) { |
167 | 4.55k | return path_is_valid_full(p, /* accept_dot_dot= */ false); |
168 | 4.55k | } |
169 | | bool path_is_normalized(const char *p) _pure_; |
170 | | |
171 | | char *file_in_same_dir(const char *path, const char *filename); |
172 | | |
173 | | bool hidden_or_backup_file(const char *filename) _pure_; |
174 | | |
175 | | bool is_device_path(const char *path); |
176 | | |
177 | | bool valid_device_node_path(const char *path); |
178 | | bool valid_device_allow_pattern(const char *path); |
179 | | |
180 | | bool dot_or_dot_dot(const char *path); |
181 | | |
182 | 0 | static inline const char *skip_dev_prefix(const char *p) { |
183 | 0 | const char *e; |
184 | 0 |
|
185 | 0 | /* Drop any /dev prefix if there is any */ |
186 | 0 |
|
187 | 0 | e = path_startswith(p, "/dev/"); |
188 | 0 |
|
189 | 0 | return e ?: p; |
190 | 0 | } |
191 | | |
192 | | bool empty_or_root(const char *path); |
193 | 0 | static inline const char *empty_to_root(const char *path) { |
194 | 0 | return isempty(path) ? "/" : path; |
195 | 0 | } |
196 | | |
197 | | bool path_strv_contains(char **l, const char *path); |
198 | | bool prefixed_path_strv_contains(char **l, const char *path); |
199 | | |
200 | | int path_glob_can_match(const char *pattern, const char *prefix, char **ret); |