]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/shared/import-util.c
logind: Don't match non-leader processes for utmp TTY determination (#38027)
[thirdparty/systemd.git] / src / shared / import-util.c
CommitLineData
db9ecf05 1/* SPDX-License-Identifier: LGPL-2.1-or-later */
3d7415f4 2
b5efdb8a 3#include "alloc-util.h"
8c9cfc28 4#include "btrfs-util.h"
137c6c6b
LP
5#include "chattr-util.h"
6#include "errno-util.h"
bb15fafe 7#include "import-util.h"
a8fbdf54 8#include "log.h"
d8b4d14d 9#include "nulstr-util.h"
8b43440b 10#include "string-table.h"
07630cea 11#include "string-util.h"
3d7415f4 12
56ce4ada
LP
13static const char *skip_protocol_and_hostname(const char *url) {
14 const char *d;
15 size_t n;
16
17 /* A very very lenient implementation of RFC3986 Section 3.2 */
18
19 /* Find colon separating protocol and hostname */
20 d = strchr(url, ':');
21 if (!d || url == d)
22 return NULL;
23 d++;
24
25 /* Skip slashes after colon */
26 d += strspn(d, "/");
27
28 /* Skip everything till next slash or end */
29 n = strcspn(d, "/?#");
30 if (n == 0)
31 return NULL;
32
33 return d + n;
34}
3d7415f4 35
56ce4ada
LP
36int import_url_last_component(
37 const char *url,
38 char **ret) {
3d7415f4 39
56ce4ada
LP
40 const char *e, *p, *h;
41
42 /* This extracts the last path component of the specified URI, i.e. the last non-empty substrings
43 * between two "/" characters. This ignores "Query" and "Fragment" suffixes (as per RFC3986). */
44
45 h = skip_protocol_and_hostname(url);
46 if (!h)
47 return -EINVAL;
48
49 e = h + strcspn(h, "?#"); /* Cut off "Query" and "Fragment" */
50
51 while (e > h && e[-1] == '/') /* Eat trailing slashes */
3d7415f4
LP
52 e--;
53
54 p = e;
56ce4ada 55 while (p > h && p[-1] != '/') /* Find component before that */
3d7415f4
LP
56 p--;
57
56ce4ada
LP
58 if (e <= p) /* Empty component? */
59 return -EADDRNOTAVAIL;
3d7415f4 60
56ce4ada
LP
61 if (ret) {
62 char *s;
63
64 s = strndup(p, e - p);
65 if (!s)
66 return -ENOMEM;
67
68 *ret = s;
69 }
3d7415f4 70
3d7415f4
LP
71 return 0;
72}
73
56ce4ada
LP
74int import_url_change_suffix(
75 const char *url,
76 size_t n_drop_components,
77 const char *suffix,
78 char **ret) {
79
80 const char *e, *h;
3d7415f4
LP
81 char *s;
82
83 assert(url);
84 assert(ret);
85
56ce4ada
LP
86 /* This drops the specified number of path components of the specified URI, i.e. the specified number
87 * of non-empty substring between two "/" characters from the end of the string, and then append the
88 * specified suffix instead. Before doing all this it chops off the "Query" and "Fragment" suffixes
ba669952 89 * (they are *not* re-added to the final URL). Note that n_drop_components may be 0 (in which case the
56ce4ada
LP
90 * component are simply added to the end). The suffix may be specified as NULL or empty string in
91 * which case nothing is appended, only the specified number of components chopped off. Note that the
92 * function may be called with n_drop_components == 0 and suffix == NULL, in which case the "Query"
93 * and "Fragment" is chopped off, and ensured the URL ends in a single "/", and that's it. */
94
95 h = skip_protocol_and_hostname(url);
96 if (!h)
97 return -EINVAL;
3d7415f4 98
56ce4ada 99 e = h + strcspn(h, "?#"); /* Cut off "Query" and "Fragment" */
3d7415f4 100
56ce4ada 101 while (e > h && e[-1] == '/') /* Eat trailing slashes */
3d7415f4
LP
102 e--;
103
56ce4ada
LP
104 /* Drop the specified number of components from the end. Note that this is pretty lenient: if there
105 * are less component we silently drop those and then append the suffix to the top. */
106 while (n_drop_components > 0) {
107 while (e > h && e[-1] != '/') /* Eat last word (we don't mind if empty) */
108 e--;
109
110 while (e > h && e[-1] == '/') /* Eat slashes before the last word */
111 e--;
112
113 n_drop_components--;
114 }
3d7415f4 115
56ce4ada 116 s = new(char, (e - url) + 1 + strlen_ptr(suffix) + 1);
3d7415f4
LP
117 if (!s)
118 return -ENOMEM;
119
56ce4ada 120 strcpy(stpcpy(mempcpy(s, url, e - url), "/"), strempty(suffix));
3d7415f4
LP
121 *ret = s;
122 return 0;
123}
124
71613cd5
LP
125static const char* const import_type_table[_IMPORT_TYPE_MAX] = {
126 [IMPORT_RAW] = "raw",
127 [IMPORT_TAR] = "tar",
128};
129
130DEFINE_STRING_TABLE_LOOKUP(import_type, ImportType);
131
3d7415f4 132static const char* const import_verify_table[_IMPORT_VERIFY_MAX] = {
71613cd5
LP
133 [IMPORT_VERIFY_NO] = "no",
134 [IMPORT_VERIFY_CHECKSUM] = "checksum",
3d7415f4
LP
135 [IMPORT_VERIFY_SIGNATURE] = "signature",
136};
137
138DEFINE_STRING_TABLE_LOOKUP(import_verify, ImportVerify);
139
140int tar_strip_suffixes(const char *name, char **ret) {
141 const char *e;
142 char *s;
143
144 e = endswith(name, ".tar");
145 if (!e)
146 e = endswith(name, ".tar.xz");
147 if (!e)
148 e = endswith(name, ".tar.gz");
149 if (!e)
150 e = endswith(name, ".tar.bz2");
bd9c55eb
LB
151 if (!e)
152 e = endswith(name, ".tar.zst");
3d7415f4
LP
153 if (!e)
154 e = endswith(name, ".tgz");
155 if (!e)
156 e = strchr(name, 0);
157
158 if (e <= name)
159 return -EINVAL;
160
161 s = strndup(name, e - name);
162 if (!s)
163 return -ENOMEM;
164
165 *ret = s;
166 return 0;
167}
168
169int raw_strip_suffixes(const char *p, char **ret) {
170
171 static const char suffixes[] =
172 ".xz\0"
173 ".gz\0"
174 ".bz2\0"
bd9c55eb 175 ".zst\0"
a747994b
LP
176 ".sysext.raw\0"
177 ".confext.raw\0"
3d7415f4
LP
178 ".raw\0"
179 ".qcow2\0"
180 ".img\0"
181 ".bin\0";
182
183 _cleanup_free_ char *q = NULL;
184
185 q = strdup(p);
186 if (!q)
187 return -ENOMEM;
188
189 for (;;) {
3d7415f4
LP
190 bool changed = false;
191
192 NULSTR_FOREACH(sfx, suffixes) {
193 char *e;
194
195 e = endswith(q, sfx);
196 if (e) {
197 *e = 0;
198 changed = true;
199 }
200 }
201
202 if (!changed)
203 break;
204 }
205
ae2a15bc 206 *ret = TAKE_PTR(q);
3d7415f4
LP
207
208 return 0;
209}
210
8c9cfc28
LP
211int import_assign_pool_quota_and_warn(const char *path) {
212 int r;
213
052ba0eb 214 assert(path);
8c9cfc28
LP
215
216 r = btrfs_subvol_auto_qgroup(path, 0, true);
217 if (r == -ENOTTY) {
218 log_debug_errno(r, "Failed to set up quota hierarchy for %s, as directory is not on btrfs or not a subvolume. Ignoring.", path);
219 return 0;
220 }
221 if (r < 0)
222 return log_error_errno(r, "Failed to set up default quota hierarchy for %s: %m", path);
223 if (r > 0)
b11591af 224 log_debug("Set up default quota hierarchy for %s.", path);
8c9cfc28
LP
225
226 return 0;
227}
137c6c6b
LP
228
229int import_set_nocow_and_log(int fd, const char *path) {
230 int r;
231
a997f338 232 r = chattr_fd(fd, FS_NOCOW_FL, FS_NOCOW_FL);
137c6c6b
LP
233 if (r < 0)
234 return log_full_errno(
f1ee656d 235 ERRNO_IS_IOCTL_NOT_SUPPORTED(r) ? LOG_DEBUG : LOG_WARNING,
137c6c6b
LP
236 r, "Failed to set file attributes on %s: %m", path);
237
238 return 0;
239}