chiark / gitweb /
systemd: do not require absolute paths in ExecStart
[elogind.git] / src / basic / path-util.h
1 /* SPDX-License-Identifier: LGPL-2.1+ */
2 #pragma once
3
4 /***
5   This file is part of systemd.
6
7   Copyright 2010-2012 Lennart Poettering
8
9   elogind is free software; you can redistribute it and/or modify it
10   under the terms of the GNU Lesser General Public License as published by
11   the Free Software Foundation; either version 2.1 of the License, or
12   (at your option) any later version.
13
14   elogind is distributed in the hope that it will be useful, but
15   WITHOUT ANY WARRANTY; without even the implied warranty of
16   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17   Lesser General Public License for more details.
18
19   You should have received a copy of the GNU Lesser General Public License
20   along with elogind; If not, see <http://www.gnu.org/licenses/>.
21 ***/
22
23 #include <alloca.h>
24 #include <stdbool.h>
25 #include <stddef.h>
26
27 #include "macro.h"
28 #include "string-util.h"
29 #include "time-util.h"
30
31 #if HAVE_SPLIT_BIN
32 #  define PATH_SBIN_BIN(x) x "sbin:" x "bin"
33 #  define PATH0_SBIN_BIN(x) x "sbin\0" x "bin"
34 #else
35 #  define PATH0_SBIN_BIN(x) x "bin"
36 #  define PATH_SBIN_BIN(x) x "bin"
37 #endif
38
39 #define DEFAULT_PATH_NORMAL PATH_SBIN_BIN("/usr/local/") ":" PATH_SBIN_BIN("/usr/")
40 #define DEFAULT_PATH0_NORMAL PATH0_SBIN_BIN("/usr/local/") "\0" PATH0_SBIN_BIN("/usr/")
41 #define DEFAULT_PATH_SPLIT_USR DEFAULT_PATH_NORMAL ":" PATH_SBIN_BIN("/")
42 #define DEFAULT_PATH0_SPLIT_USR DEFAULT_PATH0_NORMAL "\0" PATH0_SBIN_BIN("/")
43
44 #if HAVE_SPLIT_USR
45 #  define DEFAULT_PATH DEFAULT_PATH_SPLIT_USR
46 #  define DEFAULT_PATH_NULSTR DEFAULT_PATH0_SPLIT_USR
47 #else
48 #  define DEFAULT_PATH DEFAULT_PATH_NORMAL
49 #  define DEFAULT_PATH_NULSTR DEFAULT_PATH0_NORMAL
50 #endif
51
52 bool is_path(const char *p) _pure_;
53 #if 0 /// UNNEEDED by elogind
54 int path_split_and_make_absolute(const char *p, char ***ret);
55 #endif // 0
56 bool path_is_absolute(const char *p) _pure_;
57 #if 0 /// UNNEEDED by elogind
58 char* path_make_absolute(const char *p, const char *prefix);
59 #endif // 0
60 int safe_getcwd(char **ret);
61 int path_make_absolute_cwd(const char *p, char **ret);
62 #if 0 /// UNNEEDED by elogind
63 int path_make_relative(const char *from_dir, const char *to_path, char **_r);
64 #endif // 0
65 char* path_kill_slashes(char *path);
66 char* path_startswith(const char *path, const char *prefix) _pure_;
67 int path_compare(const char *a, const char *b) _pure_;
68 bool path_equal(const char *a, const char *b) _pure_;
69 bool path_equal_or_files_same(const char *a, const char *b, int flags);
70 char* path_join(const char *root, const char *path, const char *rest);
71
72 static inline bool path_equal_ptr(const char *a, const char *b) {
73         return !!a == !!b && (!a || path_equal(a, b));
74 }
75
76 /* Note: the search terminates on the first NULL item. */
77 #define PATH_IN_SET(p, ...)                                     \
78         ({                                                      \
79                 char **s;                                       \
80                 bool _found = false;                            \
81                 STRV_FOREACH(s, STRV_MAKE(__VA_ARGS__))         \
82                         if (path_equal(p, *s)) {                \
83                                _found = true;                   \
84                                break;                           \
85                         }                                       \
86                 _found;                                         \
87         })
88
89 #if 0 /// UNNEEDED by elogind
90 #define PATH_STARTSWITH_SET(p, ...)                             \
91         ({                                                      \
92                 char **s;                                       \
93                 bool _found = false;                            \
94                 STRV_FOREACH(s, STRV_MAKE(__VA_ARGS__))         \
95                         if (path_startswith(p, *s)) {           \
96                                _found = true;                   \
97                                break;                           \
98                         }                                       \
99                 _found;                                         \
100         })
101
102 int path_strv_make_absolute_cwd(char **l);
103 #endif // 0
104 char** path_strv_resolve(char **l, const char *root);
105 char** path_strv_resolve_uniq(char **l, const char *root);
106
107 int find_binary(const char *name, char **filename);
108
109 #if 0 /// UNNEEDED by elogind
110 bool paths_check_timestamp(const char* const* paths, usec_t *paths_ts_usec, bool update);
111
112 int fsck_exists(const char *fstype);
113 int mkfs_exists(const char *fstype);
114 #endif // 0
115
116 /* Iterates through the path prefixes of the specified path, going up
117  * the tree, to root. Also returns "" (and not "/"!) for the root
118  * directory. Excludes the specified directory itself */
119 #define PATH_FOREACH_PREFIX(prefix, path) \
120         for (char *_slash = ({ path_kill_slashes(strcpy(prefix, path)); streq(prefix, "/") ? NULL : strrchr(prefix, '/'); }); _slash && ((*_slash = 0), true); _slash = strrchr((prefix), '/'))
121
122 /* Same as PATH_FOREACH_PREFIX but also includes the specified path itself */
123 #define PATH_FOREACH_PREFIX_MORE(prefix, path) \
124         for (char *_slash = ({ path_kill_slashes(strcpy(prefix, path)); if (streq(prefix, "/")) prefix[0] = 0; strrchr(prefix, 0); }); _slash && ((*_slash = 0), true); _slash = strrchr((prefix), '/'))
125
126 char *prefix_root(const char *root, const char *path);
127
128 /* Similar to prefix_root(), but returns an alloca() buffer, or
129  * possibly a const pointer into the path parameter */
130 #define prefix_roota(root, path)                                        \
131         ({                                                              \
132                 const char* _path = (path), *_root = (root), *_ret;     \
133                 char *_p, *_n;                                          \
134                 size_t _l;                                              \
135                 while (_path[0] == '/' && _path[1] == '/')              \
136                         _path ++;                                       \
137                 if (isempty(_root) || path_equal(_root, "/"))           \
138                         _ret = _path;                                   \
139                 else {                                                  \
140                         _l = strlen(_root) + 1 + strlen(_path) + 1;     \
141                         _n = alloca(_l);                                \
142                         _p = stpcpy(_n, _root);                         \
143                         while (_p > _n && _p[-1] == '/')                \
144                                 _p--;                                   \
145                         if (_path[0] != '/')                            \
146                                 *(_p++) = '/';                          \
147                         strcpy(_p, _path);                              \
148                         _ret = _n;                                      \
149                 }                                                       \
150                 _ret;                                                   \
151         })
152
153 #if 0 /// UNNEEDED by elogind
154 int parse_path_argument_and_warn(const char *path, bool suppress_root, char **arg);
155 #endif // 0
156
157 char* dirname_malloc(const char *path);
158 const char *last_path_component(const char *path);
159
160 bool filename_is_valid(const char *p) _pure_;
161 bool path_is_normalized(const char *p) _pure_;
162
163 char *file_in_same_dir(const char *path, const char *filename);
164
165 bool hidden_or_backup_file(const char *filename) _pure_;
166
167 #if 0 /// UNNEEDED by elogind
168 bool is_device_path(const char *path);
169 bool is_deviceallow_pattern(const char *path);
170
171 int systemd_installation_has_version(const char *root, unsigned minimal_version);
172 #endif // 0
173
174 bool dot_or_dot_dot(const char *path);
175
176 static inline const char *skip_dev_prefix(const char *p) {
177         const char *e;
178
179         /* Drop any /dev prefix if there is any */
180
181         e = path_startswith(p, "/dev/");
182
183         return e ?: p;
184 }