Branch data Line data Source code
1 : : /*-
2 : : * Copyright (c) 2011-2022 Baptiste Daroussin <bapt@FreeBSD.org>
3 : : * Copyright (c) 2011-2012 Julien Laffaye <jlaffaye@FreeBSD.org>
4 : : * Copyright (c) 2016, Vsevolod Stakhov
5 : : * Copyright (c) 2024, Future Crew, LLC
6 : : * Author: Gleb Popov <arrowd@FreeBSD.org>
7 : : *
8 : : * Redistribution and use in source and binary forms, with or without
9 : : * modification, are permitted provided that the following conditions
10 : : * are met:
11 : : * 1. Redistributions of source code must retain the above copyright
12 : : * notice, this list of conditions and the following disclaimer
13 : : * in this position and unchanged.
14 : : * 2. Redistributions in binary form must reproduce the above copyright
15 : : * notice, this list of conditions and the following disclaimer in the
16 : : * documentation and/or other materials provided with the distribution.
17 : : *
18 : : * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
19 : : * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20 : : * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21 : : * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
22 : : * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23 : : * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 : : * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 : : * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 : : * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27 : : * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 : : */
29 : :
30 : : #ifdef HAVE_CONFIG_H
31 : : #include "pkg_config.h"
32 : : #endif
33 : :
34 : : #include <archive.h>
35 : : #include <archive_entry.h>
36 : : #include <assert.h>
37 : : #include <libgen.h>
38 : : #include <string.h>
39 : : #include <errno.h>
40 : : #include <fcntl.h>
41 : : #include <glob.h>
42 : : #include <pwd.h>
43 : : #include <grp.h>
44 : : #include <sys/time.h>
45 : : #include <sys/wait.h>
46 : : #include <time.h>
47 : : #include <xstring.h>
48 : : #include <tllist.h>
49 : :
50 : : #include "pkg.h"
51 : : #include "private/event.h"
52 : : #include "private/utils.h"
53 : : #include "private/pkg.h"
54 : : #include "private/pkgdb.h"
55 : :
56 : : #if defined(UF_NOUNLINK)
57 : : #define NOCHANGESFLAGS (UF_IMMUTABLE | UF_APPEND | UF_NOUNLINK | SF_IMMUTABLE | SF_APPEND | SF_NOUNLINK)
58 : : #else
59 : : #define NOCHANGESFLAGS (UF_IMMUTABLE | UF_APPEND | SF_IMMUTABLE | SF_APPEND)
60 : : #endif
61 : :
62 : : struct external_merge_tmp_file {
63 : : int fd;
64 : : const char *template;
65 : : char path[MAXPATHLEN];
66 : : const char *content;
67 : : size_t content_len;
68 : : };
69 : :
70 : : static merge_status
71 : 0 : merge_with_external_tool(const char *merge_tool, struct pkg_config_file *lcf,
72 : : size_t lcf_len, struct pkg_config_file *rcf, char *localconf, char **mergedconf)
73 : : {
74 : : pid_t wait_res;
75 : : int status;
76 : : FILE *inout[2];
77 : :
78 : 0 : char *tmpdir = getenv("TMPDIR");
79 [ # # ]: 0 : if (tmpdir == NULL)
80 : 0 : tmpdir = "/tmp";
81 : :
82 : : int output_fd;
83 : : char output_path[MAXPATHLEN];
84 : : off_t output_sz;
85 : :
86 : 0 : strlcpy(output_path, tmpdir, sizeof(output_path));
87 : 0 : strlcat(output_path, "/OUTPUT.XXXXXXXXXX", sizeof(output_path));
88 : 0 : output_fd = mkstemp(output_path);
89 [ # # ]: 0 : if (output_fd == -1) {
90 : 0 : pkg_emit_error("Can't create %s", output_path);
91 : 0 : return MERGE_FAILED;
92 : : }
93 : 0 : close(output_fd);
94 : :
95 : 0 : struct external_merge_tmp_file tmp_files[] = {
96 : 0 : {-1, "/BASE.XXXXXXXXXX", {0}, lcf->content, lcf_len},
97 : 0 : {-1, "/LOCAL.XXXXXXXXXX", {0}, localconf, strlen(localconf)},
98 : 0 : {-1, "/REMOTE.XXXXXXXXXX", {0}, rcf->content, strlen(rcf->content)}
99 : : };
100 : 0 : bool tmp_files_ok = true;
101 [ # # ]: 0 : for (int i = 0; i < NELEM(tmp_files); i++) {
102 : 0 : int copied = strlcpy(tmp_files[i].path, tmpdir, sizeof(tmp_files[i].path));
103 [ # # ]: 0 : if (copied >= sizeof(tmp_files[i].path)) {
104 : 0 : pkg_emit_error("Temporary path too long: %s", tmp_files[i].path);
105 : 0 : return MERGE_FAILED;
106 : : }
107 : 0 : copied = strlcat(tmp_files[i].path, tmp_files[i].template, sizeof(tmp_files[i].path));
108 [ # # ]: 0 : if (copied >= sizeof(tmp_files[i].path)) {
109 : 0 : pkg_emit_error("Temporary path too long: %s", tmp_files[i].path);
110 : 0 : return MERGE_FAILED;
111 : : }
112 : :
113 : 0 : tmp_files[i].fd = mkstemp(tmp_files[i].path);
114 [ # # ]: 0 : if (tmp_files[i].fd == -1) {
115 : 0 : pkg_emit_error("Can't create %s", tmp_files[i].path);
116 : 0 : tmp_files_ok = false;
117 : 0 : break;
118 : : }
119 [ # # ]: 0 : if (write(tmp_files[i].fd, tmp_files[i].content, tmp_files[i].content_len) == -1) {
120 : 0 : pkg_emit_error("Failed to write %s", tmp_files[i].path);
121 : 0 : tmp_files_ok = false;
122 : 0 : break;
123 : : }
124 : 0 : close(tmp_files[i].fd);
125 : 0 : tmp_files[i].fd = -1;
126 : 0 : }
127 [ # # ]: 0 : if (!tmp_files_ok) {
128 [ # # ]: 0 : for (int i = 0; i < NELEM(tmp_files); i++) {
129 [ # # ]: 0 : if (tmp_files[i].fd != -1)
130 : 0 : close(tmp_files[i].fd);
131 [ # # ]: 0 : if (strlen(tmp_files[i].path))
132 : 0 : unlink(tmp_files[i].path);
133 : 0 : }
134 : 0 : return MERGE_FAILED;
135 : : }
136 : :
137 : : char command[MAXPATHLEN];
138 [ # # ]: 0 : for (int i = 0; *merge_tool != '\0'; i++, merge_tool++) {
139 [ # # ]: 0 : if (*merge_tool != '%') {
140 : 0 : command[i] = *merge_tool;
141 : 0 : continue;
142 : : }
143 : 0 : merge_tool++;
144 : : int tmp_files_index;
145 [ # # # # : 0 : switch (*merge_tool) {
# # ]
146 : : case 'b':
147 : 0 : tmp_files_index = 0;
148 : 0 : break;
149 : : case 'l':
150 : 0 : tmp_files_index = 1;
151 : 0 : break;
152 : : case 'r':
153 : 0 : tmp_files_index = 2;
154 : 0 : break;
155 : : case 'n':
156 : 0 : i += strlcpy(&command[i], RELATIVE_PATH(rcf->path), sizeof(command) - i) - 1;
157 : 0 : continue;
158 : : case 'o':
159 : 0 : i += strlcpy(&command[i], output_path, sizeof(command) - i) - 1;
160 : 0 : continue;
161 : : default:
162 : 0 : pkg_emit_error("Unknown format string in the MERGETOOL command");
163 : 0 : merge_tool--;
164 : 0 : continue;
165 : : }
166 : 0 : i += strlcpy(&command[i], tmp_files[tmp_files_index].path, sizeof(command) - i) - 1;
167 : 0 : }
168 : :
169 : 0 : pid_t pid = process_spawn_pipe(inout, command);
170 : 0 : wait_res = waitpid(pid, &status, 0);
171 : :
172 : 0 : fclose(inout[0]);
173 : 0 : fclose(inout[1]);
174 [ # # ]: 0 : for (int i = 0; i < sizeof(tmp_files); i++) {
175 : 0 : unlink(tmp_files[i].path);
176 : 0 : }
177 : :
178 [ # # # # : 0 : if (wait_res == -1 || WIFSIGNALED(status) || WEXITSTATUS(status)) {
# # # # #
# ]
179 : 0 : unlink(output_path);
180 : 0 : pkg_emit_error("External merge tool failed, retrying with builtin algorithm");
181 : 0 : return MERGE_FAILED;
182 : : }
183 : :
184 : 0 : file_to_bufferat(AT_FDCWD, output_path, mergedconf, &output_sz);
185 : 0 : unlink(output_path);
186 : :
187 : 0 : return MERGE_SUCCESS;
188 : 0 : }
189 : :
190 : : static void
191 : 11 : attempt_to_merge(int rootfd, struct pkg_config_file *rcf, struct pkg *local,
192 : : bool merge, const char *merge_tool)
193 : : {
194 : 11 : const struct pkg_file *lf = NULL;
195 : : struct stat st;
196 : : xstring *newconf;
197 : 11 : struct pkg_config_file *lcf = NULL;
198 : : size_t lcf_len;
199 : :
200 : 11 : char *localconf = NULL;
201 : : off_t sz;
202 : : char *localsum;
203 : :
204 [ + + ]: 11 : if (local == NULL) {
205 : 5 : pkg_debug(3, "No local package");
206 [ + + ]: 5 : if (fstatat(rootfd, RELATIVE_PATH(rcf->path), &st, 0) == 0) {
207 : 1 : rcf->status = MERGE_NOT_LOCAL;
208 : 1 : }
209 : 5 : return;
210 : : }
211 : :
212 [ + + ]: 6 : if (!pkg_is_config_file(local, rcf->path, &lf, &lcf)) {
213 : 2 : pkg_debug(3, "No local package");
214 : 2 : rcf->status = MERGE_FAILED;
215 : 2 : return;
216 : : }
217 : :
218 [ + - ]: 4 : if (lcf->content == NULL) {
219 : 0 : pkg_debug(3, "Empty configuration content for local package");
220 : 0 : return;
221 : : }
222 : :
223 : 4 : pkg_debug(1, "Config file found %s", rcf->path);
224 [ - + ]: 4 : if (file_to_bufferat(rootfd, RELATIVE_PATH(rcf->path), &localconf, &sz) != EPKG_OK)
225 : 0 : return;
226 : :
227 : 4 : pkg_debug(2, "size: %jd vs %jd", (intmax_t)sz, (intmax_t)strlen(lcf->content));
228 : :
229 : 4 : lcf_len = strlen(lcf->content);
230 [ + - ]: 4 : if (sz == lcf_len) {
231 : 0 : pkg_debug(2, "Ancient vanilla and deployed conf are the same size testing checksum");
232 : 0 : localsum = pkg_checksum_data(localconf, sz,
233 : : PKG_HASH_TYPE_SHA256_HEX);
234 [ # # # # ]: 0 : if (localsum && STREQ(localsum, lf->sum)) {
235 : 0 : pkg_debug(2, "Checksum are the same %jd", (intmax_t)strlen(localconf));
236 : 0 : free(localsum);
237 : 0 : goto ret;
238 : : }
239 : 0 : free(localsum);
240 : 0 : pkg_debug(2, "Checksum are different %jd", (intmax_t)strlen(localconf));
241 : 0 : }
242 : 4 : rcf->status = MERGE_FAILED;
243 [ + - ]: 4 : if (!merge) {
244 : 0 : goto ret;
245 : : }
246 : :
247 : 4 : pkg_debug(1, "Attempting to merge %s", rcf->path);
248 [ + - ]: 4 : if (merge_tool) {
249 : 0 : char* mergedconf = NULL;
250 : 0 : rcf->status = merge_with_external_tool(merge_tool, lcf, lcf_len, rcf, localconf, &mergedconf);
251 : 0 : rcf->newcontent = mergedconf;
252 [ # # ]: 0 : if (rcf->status == MERGE_SUCCESS)
253 : 0 : goto ret;
254 : 0 : }
255 : 4 : newconf = xstring_new();
256 [ - + ]: 8 : if (merge_3way(lcf->content, localconf, rcf->content, newconf) != 0) {
257 : 0 : xstring_free(newconf);
258 : 0 : pkg_emit_error("Impossible to merge configuration file");
259 : 0 : } else {
260 : 4 : char *conf = xstring_get(newconf);
261 : 4 : rcf->newcontent = conf;
262 : 4 : rcf->status = MERGE_SUCCESS;
263 : : }
264 : : ret:
265 : 4 : free(localconf);
266 : 11 : }
267 : :
268 : : static uid_t
269 : 133 : get_uid_from_archive(struct archive_entry *ae)
270 : : {
271 : : static char user_buffer[1024];
272 : : const char *user;
273 : : static struct passwd pwent;
274 : : struct passwd *result;
275 : : int err;
276 : :
277 : 133 : user = archive_entry_uname(ae);
278 [ + + + + ]: 133 : if (pwent.pw_name != NULL && STREQ(user, pwent.pw_name))
279 : 47 : goto out;
280 : 86 : pwent.pw_name = NULL;
281 : 86 : err = getpwnam_r(user, &pwent, user_buffer, sizeof(user_buffer),
282 : : &result);
283 [ - + ]: 86 : if (err != 0) {
284 : 0 : pkg_emit_errno("getpwnam_r", user );
285 : 0 : return (0);
286 : : }
287 [ + - ]: 86 : if (result == NULL)
288 : 0 : return (0);
289 : : out:
290 : 133 : return (pwent.pw_uid);
291 : 133 : }
292 : :
293 : : static gid_t
294 : 133 : get_gid_from_archive(struct archive_entry *ae)
295 : : {
296 : : static char group_buffer[1024];
297 : : static struct group grent;
298 : : struct group *result;
299 : : const char *group;
300 : : int err;
301 : :
302 : 133 : group = archive_entry_gname(ae);
303 [ + + + + ]: 133 : if (grent.gr_name != NULL && STREQ(group, grent.gr_name))
304 : 48 : goto out;
305 : 85 : grent.gr_name = NULL;
306 : 85 : err = getgrnam_r(group, &grent, group_buffer, sizeof(group_buffer),
307 : : &result);
308 [ - + ]: 85 : if (err != 0) {
309 : 0 : pkg_emit_errno("getgrnam_r", group );
310 : 0 : return (0);
311 : : }
312 [ + - ]: 85 : if (result == NULL)
313 : 0 : return (0);
314 : : out:
315 : 133 : return (grent.gr_gid);
316 : 133 : }
317 : :
318 : : static int
319 : 139 : set_chflags(int fd, const char *path, u_long fflags)
320 : : {
321 : : #ifdef HAVE_CHFLAGSAT
322 [ + - ]: 139 : if (getenv("INSTALL_AS_USER"))
323 : 139 : return (EPKG_OK);
324 [ # # ]: 0 : if (fflags == 0)
325 : 0 : return (EPKG_OK);
326 [ # # ]: 0 : if (chflagsat(fd, RELATIVE_PATH(path), fflags, AT_SYMLINK_NOFOLLOW) == -1) {
327 : 0 : pkg_fatal_errno("Fail to chflags %s", path);
328 : 0 : }
329 : : #endif
330 : 0 : return (EPKG_OK);
331 : 139 : }
332 : : int
333 : 137 : set_attrsat(int fd, const char *path, mode_t perm, uid_t uid, gid_t gid,
334 : : const struct timespec *ats, const struct timespec *mts)
335 : : {
336 : : struct stat st;
337 : : struct timespec times[2];
338 : :
339 : 137 : times[0] = *ats;
340 : 137 : times[1] = *mts;
341 [ # # ]: 137 : if (utimensat(fd, RELATIVE_PATH(path), times,
342 [ - + ]: 137 : AT_SYMLINK_NOFOLLOW) == -1 && errno != EOPNOTSUPP){
343 : 0 : pkg_fatal_errno("Fail to set time on %s", path);
344 : 0 : }
345 : :
346 [ + + ]: 137 : if (getenv("INSTALL_AS_USER") == NULL) {
347 [ + - + - ]: 2 : if (fchownat(fd, RELATIVE_PATH(path), uid, gid,
348 : 1 : AT_SYMLINK_NOFOLLOW) == -1) {
349 [ # # ]: 0 : if (errno == ENOTSUP) {
350 [ # # ]: 0 : if (fchownat(fd, RELATIVE_PATH(path), uid, gid, 0) == -1) {
351 : 0 : pkg_fatal_errno("Fail to chown(fallback) %s", path);
352 : 0 : }
353 : 0 : }
354 : : else {
355 : 0 : pkg_fatal_errno("Fail to chown %s", path);
356 : : }
357 : 0 : }
358 : 1 : }
359 : :
360 : : /* zfs drops the setuid on fchownat */
361 [ + - ]: 137 : if (fchmodat(fd, RELATIVE_PATH(path), perm, AT_SYMLINK_NOFOLLOW) == -1) {
362 [ # # ]: 0 : if (errno == ENOTSUP) {
363 : : /*
364 : : * Executing fchmodat on a symbolic link results in
365 : : * ENOENT (file not found) on platforms that do not
366 : : * support AT_SYMLINK_NOFOLLOW. The file mode of
367 : : * symlinks cannot be modified via file descriptor
368 : : * reference on these systems. The lchmod function is
369 : : * also not an option because it is not a posix
370 : : * standard, nor is implemented everywhere. Since
371 : : * symlink permissions have never been evaluated and
372 : : * thus cosmetic, just skip them on these systems.
373 : : */
374 [ # # ]: 0 : if (fstatat(fd, RELATIVE_PATH(path), &st, AT_SYMLINK_NOFOLLOW) == -1) {
375 : 0 : pkg_fatal_errno("Fail to get file status %s", path);
376 : 0 : }
377 [ # # ]: 0 : if (!S_ISLNK(st.st_mode)) {
378 [ # # ]: 0 : if (fchmodat(fd, RELATIVE_PATH(path), perm, 0) == -1) {
379 : 0 : pkg_fatal_errno("Fail to chmod(fallback) %s", path);
380 : 0 : }
381 : 0 : }
382 : 0 : }
383 : : else {
384 : 0 : pkg_fatal_errno("Fail to chmod %s", path);
385 : : }
386 : 0 : }
387 : :
388 : 137 : return (EPKG_OK);
389 : 137 : }
390 : :
391 : : static void
392 : 133 : fill_timespec_buf(const struct stat *aest, struct timespec tspec[2])
393 : : {
394 : : #ifdef HAVE_STRUCT_STAT_ST_MTIM
395 : 133 : tspec[0].tv_sec = aest->st_atim.tv_sec;
396 : 133 : tspec[0].tv_nsec = aest->st_atim.tv_nsec;
397 : 133 : tspec[1].tv_sec = aest->st_mtim.tv_sec;
398 : 133 : tspec[1].tv_nsec = aest->st_mtim.tv_nsec;
399 : : #else
400 : : # if defined(_DARWIN_C_SOURCE) || defined(__APPLE__)
401 : : tspec[0].tv_sec = aest->st_atimespec.tv_sec;
402 : : tspec[0].tv_nsec = aest->st_atimespec.tv_nsec;
403 : : tspec[1].tv_sec = aest->st_mtimespec.tv_sec;
404 : : tspec[1].tv_nsec = aest->st_mtimespec.tv_nsec;
405 : : # else
406 : : /* Portable unix version */
407 : : tspec[0].tv_sec = aest->st_atime;
408 : : tspec[0].tv_nsec = 0;
409 : : tspec[1].tv_sec = aest->st_mtime;
410 : : tspec[1].tv_nsec = 0;
411 : : # endif
412 : : #endif
413 : 133 : }
414 : :
415 : : static void
416 : 19 : reopen_tempdir(int rootfd, struct tempdir *t)
417 : : {
418 [ + + ]: 19 : if (t->fd != -1)
419 : 2 : return;
420 : 17 : t->fd = openat(rootfd, RELATIVE_PATH(t->temp), O_DIRECTORY|O_CLOEXEC);
421 : 19 : }
422 : :
423 : : static struct tempdir *
424 : 144 : get_tempdir(int rootfd, const char *path, tempdirs_t *tempdirs, stringlist_t *symlinks_allowed)
425 : : {
426 : 144 : struct tempdir *tmpdir = NULL;
427 : :
428 [ + + + + : 144 : tll_foreach(*tempdirs, t) {
# # ]
429 [ + - + - ]: 17 : if (strncmp(t->item->name, path, t->item->len) == 0 && path[t->item->len] == '/') {
430 : 17 : reopen_tempdir(rootfd, t->item);
431 : 17 : return (t->item);
432 : : }
433 : 0 : }
434 : :
435 : 127 : tmpdir = open_tempdir(rootfd, path, symlinks_allowed);
436 [ + + ]: 127 : if (tmpdir != NULL)
437 [ - + + - : 32 : tll_push_back(*tempdirs, tmpdir);
# # - + -
+ ]
438 : :
439 : 127 : return (tmpdir);
440 : 144 : }
441 : :
442 : : static void
443 : 149 : close_tempdir(struct tempdir *t)
444 : : {
445 [ + + ]: 149 : if (t == NULL)
446 : 98 : return;
447 [ + + ]: 51 : if (t->fd != -1)
448 : 49 : close(t->fd);
449 : 51 : t->fd = -1;
450 : 149 : }
451 : :
452 : : static int
453 : 6 : create_dir(struct pkg *pkg, struct pkg_dir *d, tempdirs_t *tempdirs, stringlist_t *symlinks_allowed)
454 : : {
455 : : struct stat st;
456 : 6 : struct tempdir *tmpdir = NULL;
457 : : int fd;
458 : : const char *path;
459 : :
460 : 6 : tmpdir = get_tempdir(pkg->rootfd, d->path, tempdirs, symlinks_allowed);
461 [ + + ]: 6 : if (tmpdir == NULL) {
462 : 5 : fd = pkg->rootfd;
463 : 5 : path = d->path;
464 : 5 : } else {
465 : 1 : fd = tmpdir->fd;
466 : 1 : path = d->path + tmpdir->len;
467 : : }
468 : :
469 [ + + ]: 6 : if (mkdirat(fd, RELATIVE_PATH(path), 0755) == -1)
470 [ + - ]: 4 : if (!mkdirat_p(fd, RELATIVE_PATH(path))) {
471 : 0 : close_tempdir(tmpdir);
472 : 0 : return (EPKG_FATAL);
473 : : }
474 [ + + ]: 6 : if (fstatat(fd, RELATIVE_PATH(path), &st, 0) == -1) {
475 [ + - ]: 1 : if (errno != ENOENT) {
476 : 0 : close_tempdir(tmpdir);
477 : 0 : pkg_fatal_errno("Fail to stat directory %s", path);
478 : 0 : }
479 [ - + ]: 1 : if (fstatat(fd, RELATIVE_PATH(path), &st, AT_SYMLINK_NOFOLLOW) == 0) {
480 : 1 : unlinkat(fd, RELATIVE_PATH(path), 0);
481 : 1 : }
482 [ + - ]: 1 : if (mkdirat(fd, RELATIVE_PATH(path), 0755) == -1) {
483 [ # # ]: 0 : if (tmpdir != NULL) {
484 : 0 : close_tempdir(tmpdir);
485 : 0 : pkg_fatal_errno("Fail to create directory '%s/%s'", tmpdir->temp, path);
486 : 0 : }
487 : 0 : pkg_fatal_errno("Fail to create directory %s", path);
488 : 0 : }
489 : 1 : }
490 : :
491 [ + + - + : 6 : if (st.st_uid == d->uid && st.st_gid == d->gid &&
- + ]
492 : 3 : (st.st_mode & ~S_IFMT) == (d->perm & ~S_IFMT)) {
493 : 3 : d->noattrs = true;
494 : 3 : }
495 : :
496 : 6 : close_tempdir(tmpdir);
497 : 6 : return (EPKG_OK);
498 : 6 : }
499 : :
500 : : /* In case of directories create the dir and extract the creds */
501 : : static int
502 : 6 : do_extract_dir(struct pkg* pkg, struct archive *a __unused, struct archive_entry *ae,
503 : : const char *path, struct pkg *local __unused, tempdirs_t *tempdirs, stringlist_t *symlinks_allowed)
504 : : {
505 : : struct pkg_dir *d;
506 : : const struct stat *aest;
507 : : unsigned long clear;
508 : :
509 : 6 : d = pkg_get_dir(pkg, path);
510 [ + - ]: 6 : if (d == NULL) {
511 : 0 : pkg_emit_error("Directory %s not specified in the manifest, skipping",
512 : 0 : path);
513 : 0 : return (EPKG_OK);
514 : : }
515 : 6 : aest = archive_entry_stat(ae);
516 : 6 : d->perm = aest->st_mode;
517 : 6 : d->uid = get_uid_from_archive(ae);
518 : 6 : d->gid = get_gid_from_archive(ae);
519 : 6 : fill_timespec_buf(aest, d->time);
520 : 6 : archive_entry_fflags(ae, &d->fflags, &clear);
521 : :
522 [ - + ]: 6 : if (create_dir(pkg, d, tempdirs, symlinks_allowed) == EPKG_FATAL) {
523 : 0 : return (EPKG_FATAL);
524 : : }
525 : :
526 : 12 : metalog_add(PKG_METALOG_DIR, RELATIVE_PATH(path),
527 : 6 : archive_entry_uname(ae), archive_entry_gname(ae),
528 : 6 : aest->st_mode & ~S_IFDIR, d->fflags, NULL);
529 : :
530 : 6 : return (EPKG_OK);
531 : 6 : }
532 : :
533 : :
534 : : static bool
535 : 29 : try_mkdir(int fd, const char *path)
536 : : {
537 : 29 : char *p = get_dirname(xstrdup(path));
538 : :
539 [ - + ]: 29 : if (!mkdirat_p(fd, RELATIVE_PATH(p))) {
540 : 0 : free(p);
541 : 0 : return (false);
542 : : }
543 : 29 : free(p);
544 : 29 : return (true);
545 : 29 : }
546 : :
547 : : static int
548 : 13 : create_symlinks(struct pkg *pkg, struct pkg_file *f, const char *target, tempdirs_t *tempdirs,
549 : : stringlist_t *symlinks_allowed)
550 : : {
551 : 13 : struct tempdir *tmpdir = NULL;
552 : : int fd;
553 : : const char *path;
554 : 13 : bool tried_mkdir = false;
555 : :
556 : 13 : tmpdir = get_tempdir(pkg->rootfd, f->path, tempdirs, symlinks_allowed);
557 [ + + - + ]: 13 : if (tmpdir == NULL && errno == 0)
558 : 2 : hidden_tempfile(f->temppath, sizeof(f->temppath), f->path);
559 [ + + ]: 26 : if (tmpdir == NULL) {
560 : 2 : fd = pkg->rootfd;
561 : 2 : path = f->temppath;
562 : 2 : } else {
563 : 11 : fd = tmpdir->fd;
564 : 11 : path = f->path + tmpdir->len;
565 : : }
566 : : retry:
567 [ + + ]: 16 : if (symlinkat(target, fd, RELATIVE_PATH(path)) == -1) {
568 [ - + ]: 3 : if (!tried_mkdir) {
569 [ - + ]: 3 : if (!try_mkdir(fd, path)) {
570 : 0 : close_tempdir(tmpdir);
571 : 0 : return (EPKG_FATAL);
572 : : }
573 : 3 : tried_mkdir = true;
574 : 3 : goto retry;
575 : : }
576 : :
577 : 0 : pkg_fatal_errno("Fail to create symlink: %s", path);
578 : 0 : }
579 : :
580 [ - + - + : 39 : if (set_attrsat(fd, path, f->perm, f->uid, f->gid,
- + ]
581 : 26 : &f->time[0], &f->time[1]) != EPKG_OK) {
582 : 0 : close_tempdir(tmpdir);
583 : 0 : return (EPKG_FATAL);
584 : : }
585 [ + + ]: 13 : if (tmpdir != NULL)
586 : 11 : set_chflags(fd, path, f->fflags);
587 : 13 : close_tempdir(tmpdir);
588 : :
589 : 13 : return (EPKG_OK);
590 : 13 : }
591 : :
592 : : /* In case of a symlink create it directly with a random name */
593 : : static int
594 : 10 : do_extract_symlink(struct pkg *pkg, struct archive *a __unused, struct archive_entry *ae,
595 : : const char *path, struct pkg *local __unused, tempdirs_t *tempdirs,
596 : : stringlist_t *symlinks_allowed)
597 : : {
598 : : struct pkg_file *f;
599 : : const struct stat *aest;
600 : : unsigned long clear;
601 : :
602 : 10 : f = pkg_get_file(pkg, path);
603 [ + - ]: 10 : if (f == NULL) {
604 : 0 : pkg_emit_error("Symlink %s not specified in the manifest", path);
605 : 0 : return (EPKG_FATAL);
606 : : }
607 : :
608 : 10 : aest = archive_entry_stat(ae);
609 : 10 : archive_entry_fflags(ae, &f->fflags, &clear);
610 : 10 : f->uid = get_uid_from_archive(ae);
611 : 10 : f->gid = get_gid_from_archive(ae);
612 : 10 : f->perm = aest->st_mode;
613 : 10 : fill_timespec_buf(aest, f->time);
614 : 10 : archive_entry_fflags(ae, &f->fflags, &clear);
615 : :
616 [ - + ]: 10 : if (create_symlinks(pkg, f, archive_entry_symlink(ae), tempdirs, symlinks_allowed) == EPKG_FATAL)
617 : 0 : return (EPKG_FATAL);
618 : :
619 : 20 : metalog_add(PKG_METALOG_LINK, RELATIVE_PATH(path),
620 : 10 : archive_entry_uname(ae), archive_entry_gname(ae),
621 : 10 : aest->st_mode & ~S_IFLNK, f->fflags, archive_entry_symlink(ae));
622 : :
623 : 10 : return (EPKG_OK);
624 : 10 : }
625 : :
626 : : static int
627 : 5 : create_hardlink(struct pkg *pkg, struct pkg_file *f, const char *path, tempdirs_t *tempdirs,
628 : : stringlist_t *symlinks_allowed)
629 : : {
630 : 5 : bool tried_mkdir = false;
631 : : struct pkg_file *fh;
632 : : int fd, fdh;
633 : : const char *pathfrom, *pathto;
634 : 5 : struct tempdir *tmpdir = NULL;
635 : 5 : struct tempdir *tmphdir = NULL;
636 : :
637 : 5 : tmpdir = get_tempdir(pkg->rootfd, f->path, tempdirs, symlinks_allowed);
638 [ + + - + ]: 5 : if (tmpdir == NULL && errno == 0)
639 : 3 : hidden_tempfile(f->temppath, sizeof(f->temppath), f->path);
640 [ + + ]: 5 : if (tmpdir != NULL) {
641 : 2 : fd = tmpdir->fd;
642 : 2 : } else {
643 : 3 : fd = pkg->rootfd;
644 : : }
645 : 5 : fh = pkg_get_file(pkg, path);
646 [ + - ]: 5 : if (fh == NULL) {
647 : 0 : close_tempdir(tmpdir);
648 : 0 : pkg_emit_error("Can't find the file %s is supposed to be"
649 : 0 : " hardlinked to %s", f->path, path);
650 : 0 : return (EPKG_FATAL);
651 : : }
652 [ + + ]: 5 : if (fh->temppath[0] == '\0') {
653 [ + - - + : 2 : tll_foreach(*tempdirs, t) {
# # ]
654 [ + - + - ]: 2 : if (strncmp(t->item->name, fh->path, t->item->len) == 0 &&
655 : 2 : fh->path[t->item->len] == '/' ) {
656 : 2 : tmphdir = t->item;
657 : 2 : reopen_tempdir(pkg->rootfd, tmphdir);
658 : 2 : break;
659 : : }
660 : 0 : }
661 : 2 : }
662 [ + + ]: 5 : if (tmpdir == NULL) {
663 : 3 : pathto = f->temppath;
664 : 3 : fd = pkg->rootfd;
665 : 3 : } else {
666 : 2 : pathto = f->path + tmpdir->len;
667 : 2 : fd = tmpdir->fd;
668 : : }
669 : :
670 [ + + ]: 10 : if (tmphdir == NULL) {
671 : 3 : pathfrom = fh->temppath;
672 : 3 : fdh = pkg->rootfd;
673 : 3 : } else {
674 : 2 : pathfrom = fh->path + tmphdir->len;
675 : 2 : fdh = tmphdir->fd;
676 : : }
677 : :
678 : : retry:
679 [ + - + - : 15 : if (linkat(fdh, RELATIVE_PATH(pathfrom),
+ - ]
680 : 10 : fd, RELATIVE_PATH(pathto), 0) == -1) {
681 [ # # ]: 0 : if (!tried_mkdir) {
682 [ # # ]: 0 : if (!try_mkdir(fd, pathto)) {
683 : 0 : close_tempdir(tmpdir);
684 : 0 : close_tempdir(tmphdir);
685 : 0 : return (EPKG_FATAL);
686 : : }
687 : 0 : tried_mkdir = true;
688 : 0 : goto retry;
689 : : }
690 : :
691 : 0 : close_tempdir(tmpdir);
692 : 0 : close_tempdir(tmphdir);
693 : 0 : pkg_fatal_errno("Fail to create hardlink: %s <-> %s", pathfrom, pathto);
694 : 0 : }
695 : 5 : close_tempdir(tmpdir);
696 : 5 : close_tempdir(tmphdir);
697 : :
698 : 5 : return (EPKG_OK);
699 : 5 : }
700 : :
701 : : static int
702 : 4 : do_extract_hardlink(struct pkg *pkg, struct archive *a __unused, struct archive_entry *ae,
703 : : const char *path, struct pkg *local __unused, tempdirs_t *tempdirs,
704 : : stringlist_t *symlinks_allowed)
705 : : {
706 : : struct pkg_file *f;
707 : : const struct stat *aest;
708 : : const char *lp;
709 : :
710 : 4 : f = pkg_get_file(pkg, path);
711 [ + - ]: 4 : if (f == NULL) {
712 : 0 : pkg_emit_error("Hardlink %s not specified in the manifest", path);
713 : 0 : return (EPKG_FATAL);
714 : : }
715 : 4 : lp = archive_entry_hardlink(ae);
716 : 4 : aest = archive_entry_stat(ae);
717 : :
718 [ - + ]: 4 : if (create_hardlink(pkg, f, lp, tempdirs, symlinks_allowed) == EPKG_FATAL)
719 : 0 : return (EPKG_FATAL);
720 : :
721 : 8 : metalog_add(PKG_METALOG_FILE, RELATIVE_PATH(path),
722 : 4 : archive_entry_uname(ae), archive_entry_gname(ae),
723 : 4 : aest->st_mode & ~S_IFREG, 0, NULL);
724 : :
725 : 4 : return (EPKG_OK);
726 : 4 : }
727 : :
728 : : static int
729 : 120 : open_tempfile(int rootfd, const char *path, int perm)
730 : : {
731 : : int fd;
732 : 120 : bool tried_mkdir = false;
733 : :
734 : : retry:
735 : 146 : fd = openat(rootfd, RELATIVE_PATH(path), O_CREAT|O_WRONLY|O_EXCL, perm);
736 [ + + ]: 146 : if (fd == -1) {
737 [ - + ]: 26 : if (!tried_mkdir) {
738 [ - + ]: 26 : if (!try_mkdir(rootfd, path))
739 : 0 : return (-2);
740 : 26 : tried_mkdir = true;
741 : 26 : goto retry;
742 : : }
743 : 0 : return (-1);
744 : : }
745 : 120 : return (fd);
746 : 120 : }
747 : :
748 : : static int
749 : 120 : create_regfile(struct pkg *pkg, struct pkg_file *f, struct archive *a,
750 : : struct archive_entry *ae, int fromfd, struct pkg *local, tempdirs_t *tempdirs,
751 : : stringlist_t *symlinks_allowed)
752 : : {
753 : 120 : int fd = -1;
754 : : size_t len;
755 : : char buf[32768];
756 : : char *path;
757 : 120 : struct tempdir *tmpdir = NULL;
758 : :
759 : 120 : tmpdir = get_tempdir(pkg->rootfd, f->path, tempdirs, symlinks_allowed);
760 [ + + - + ]: 120 : if (tmpdir == NULL && errno == 0)
761 : 85 : hidden_tempfile(f->temppath, sizeof(f->temppath), f->path);
762 : :
763 [ + + ]: 120 : if (tmpdir != NULL) {
764 : 35 : fd = open_tempfile(tmpdir->fd, f->path + tmpdir->len, f->perm);
765 : 35 : } else {
766 : 85 : fd = open_tempfile(pkg->rootfd, f->temppath, f->perm);
767 : : }
768 [ - + ]: 120 : if (fd == -2) {
769 : 0 : close_tempdir(tmpdir);
770 : 0 : return (EPKG_FATAL);
771 : : }
772 : :
773 [ + - ]: 120 : if (fd == -1) {
774 [ # # ]: 0 : if (tmpdir != NULL) {
775 : 0 : close_tempdir(tmpdir);
776 : 0 : pkg_fatal_errno("Fail to create temporary file '%s/%s' for %s", tmpdir->name, f->path + tmpdir->len, f->path);
777 : 0 : }
778 : 0 : pkg_fatal_errno("Fail to create temporary file for %s", f->path);
779 : 0 : }
780 : :
781 [ + + ]: 120 : if (fromfd == -1) {
782 : : /* check if this is a config file */
783 : 117 : f->config = pkghash_get_value(pkg->config_files_hash, f->path);
784 [ + + ]: 117 : if (f->config) {
785 : : const char *cfdata;
786 : 11 : bool merge = pkg_object_bool(pkg_config_get("AUTOMERGE"));
787 : 11 : const char *merge_tool = pkg_object_string(pkg_config_get("MERGETOOL"));
788 : :
789 : 11 : pkg_debug(1, "Populating config_file %s", f->path);
790 : 11 : len = archive_entry_size(ae);
791 : 11 : f->config->content = xmalloc(len + 1);
792 : 11 : archive_read_data(a, f->config->content, len);
793 : 11 : f->config->content[len] = '\0';
794 : 11 : cfdata = f->config->content;
795 : 11 : attempt_to_merge(pkg->rootfd, f->config, local, merge, merge_tool);
796 [ + + ]: 11 : if (f->config->status == MERGE_SUCCESS)
797 : 4 : cfdata = f->config->newcontent;
798 : 11 : dprintf(fd, "%s", cfdata);
799 [ + + ]: 11 : if (f->config->newcontent != NULL)
800 : 4 : free(f->config->newcontent);
801 : 11 : } else {
802 [ + - ]: 106 : if (ftruncate(fd, archive_entry_size(ae)) == -1) {
803 : 0 : close_tempdir(tmpdir);
804 : 0 : pkg_errno("Fail to truncate file: %s", f->temppath);
805 : 0 : }
806 : : }
807 : :
808 [ + + - + ]: 117 : if (!f->config && archive_read_data_into_fd(a, fd) != ARCHIVE_OK) {
809 : 0 : close_tempdir(tmpdir);
810 : 0 : pkg_emit_error("Fail to extract %s from package: %s",
811 : 0 : f->path, archive_error_string(a));
812 : 0 : return (EPKG_FATAL);
813 : : }
814 : 117 : } else {
815 [ + + ]: 5 : while ((len = read(fromfd, buf, sizeof(buf))) > 0)
816 [ + - ]: 2 : if (write(fd, buf, len) == -1) {
817 : 0 : pkg_errno("Fail to write file: %s", f->temppath);
818 : 0 : }
819 : : }
820 [ + - ]: 120 : if (fd != -1)
821 : 120 : close(fd);
822 [ + + ]: 120 : if (tmpdir == NULL) {
823 : 85 : fd = pkg->rootfd;
824 : 85 : path = f->temppath;
825 : 85 : } else {
826 : 35 : fd = tmpdir->fd;
827 : 35 : path = f->path + tmpdir->len;
828 : : }
829 : :
830 [ - + - + : 360 : if (set_attrsat(fd, path, f->perm, f->uid, f->gid,
- + ]
831 : 240 : &f->time[0], &f->time[1]) != EPKG_OK) {
832 : 0 : close_tempdir(tmpdir);
833 : 0 : return (EPKG_FATAL);
834 : : }
835 [ + + ]: 120 : if (tmpdir != NULL)
836 : 35 : set_chflags(fd, path, f->fflags);
837 : :
838 : 120 : close_tempdir(tmpdir);
839 : 120 : return (EPKG_OK);
840 : 120 : }
841 : :
842 : : static int
843 : 117 : do_extract_regfile(struct pkg *pkg, struct archive *a, struct archive_entry *ae,
844 : : const char *path, struct pkg *local, tempdirs_t *tempdirs, stringlist_t *symlinks_allowed)
845 : : {
846 : : struct pkg_file *f;
847 : : const struct stat *aest;
848 : : unsigned long clear;
849 : :
850 : 117 : f = pkg_get_file(pkg, path);
851 [ + - ]: 117 : if (f == NULL) {
852 : 0 : pkg_emit_error("File %s not specified in the manifest", path);
853 : 0 : return (EPKG_FATAL);
854 : : }
855 : :
856 : 117 : aest = archive_entry_stat(ae);
857 : 117 : archive_entry_fflags(ae, &f->fflags, &clear);
858 : 117 : f->perm = aest->st_mode;
859 : 117 : f->uid = get_uid_from_archive(ae);
860 : 117 : f->gid = get_gid_from_archive(ae);
861 : 117 : fill_timespec_buf(aest, f->time);
862 : 117 : archive_entry_fflags(ae, &f->fflags, &clear);
863 : :
864 [ - + ]: 117 : if (create_regfile(pkg, f, a, ae, -1, local, tempdirs, symlinks_allowed) == EPKG_FATAL)
865 : 0 : return (EPKG_FATAL);
866 : :
867 : 234 : metalog_add(PKG_METALOG_FILE, RELATIVE_PATH(path),
868 : 117 : archive_entry_uname(ae), archive_entry_gname(ae),
869 : 117 : aest->st_mode & ~S_IFREG, f->fflags, NULL);
870 : :
871 : 117 : return (EPKG_OK);
872 : 117 : }
873 : :
874 : : static int
875 : 110 : do_extract(struct archive *a, struct archive_entry *ae,
876 : : int nfiles, struct pkg *pkg, struct pkg *local, tempdirs_t *tempdirs,
877 : : stringlist_t *symlinks_allowed)
878 : : {
879 : 110 : int retcode = EPKG_OK;
880 : 110 : int ret = 0, cur_file = 0;
881 : : char path[MAXPATHLEN];
882 : : int (*extract_cb)(struct pkg *pkg, struct archive *a,
883 : : struct archive_entry *ae, const char *path, struct pkg *local,
884 : : tempdirs_t *tempdirs, stringlist_t *sa);
885 : :
886 : : #ifndef HAVE_ARC4RANDOM
887 : : srand(time(NULL));
888 : : #endif
889 : :
890 [ + - ]: 110 : if (nfiles == 0)
891 : 0 : return (EPKG_OK);
892 : :
893 : 110 : pkg_emit_extract_begin(pkg);
894 : 110 : pkg_emit_progress_start(NULL);
895 : :
896 : 137 : do {
897 : 137 : pkg_absolutepath(archive_entry_pathname(ae), path, sizeof(path), true);
898 [ - + - + ]: 274 : if (match_ucl_lists(path,
899 : 137 : pkg_config_get("FILES_IGNORE_GLOB"),
900 : 137 : pkg_config_get("FILES_IGNORE_REGEX")))
901 : 0 : continue;
902 [ - - + + : 137 : switch (archive_entry_filetype(ae)) {
+ + - - -
- ]
903 : : case AE_IFDIR:
904 : 6 : extract_cb = do_extract_dir;
905 : 6 : break;
906 : : case AE_IFLNK:
907 : 10 : extract_cb = do_extract_symlink;
908 : 10 : break;
909 : : case 0: /* HARDLINKS */
910 : 4 : extract_cb = do_extract_hardlink;
911 : 4 : break;
912 : : case AE_IFREG:
913 : 117 : extract_cb = do_extract_regfile;
914 : 117 : break;
915 : : case AE_IFMT:
916 : 0 : pkg_emit_error("Archive contains an unsupported filetype (AE_IFMT): %s", path);
917 : 0 : retcode = EPKG_FATAL;
918 : 0 : goto cleanup;
919 : : break;
920 : : case AE_IFSOCK:
921 : 0 : pkg_emit_error("Archive contains an unsupported filetype (AE_IFSOCK): %s", path);
922 : 0 : retcode = EPKG_FATAL;
923 : 0 : goto cleanup;
924 : : break;
925 : : case AE_IFCHR:
926 : 0 : pkg_emit_error("Archive contains an unsupported filetype (AE_IFCHR): %s", path);
927 : 0 : retcode = EPKG_FATAL;
928 : 0 : goto cleanup;
929 : : break;
930 : : case AE_IFIFO:
931 : 0 : pkg_emit_error("Archive contains an unsupported filetype (AE_IFIFO): %s", path);
932 : 0 : retcode = EPKG_FATAL;
933 : 0 : goto cleanup;
934 : : break;
935 : : case AE_IFBLK:
936 : 0 : pkg_emit_error("Archive contains an unsupported filetype (AE_IFBLK): %s", path);
937 : 0 : retcode = EPKG_FATAL;
938 : 0 : goto cleanup;
939 : : break;
940 : : default:
941 : 0 : pkg_emit_error("Archive contains an unsupported filetype (%d): %s", archive_entry_filetype(ae), path);
942 : 0 : retcode = EPKG_FATAL;
943 : 0 : goto cleanup;
944 : : break;
945 : : }
946 : :
947 [ + - ]: 137 : if (extract_cb(pkg, a, ae, path, local, tempdirs, symlinks_allowed) != EPKG_OK) {
948 : 0 : retcode = EPKG_FATAL;
949 : 0 : goto cleanup;
950 : : }
951 [ + + ]: 137 : if (archive_entry_filetype(ae) != AE_IFDIR) {
952 : 131 : pkg_emit_progress_tick(cur_file++, nfiles);
953 : 131 : }
954 [ + + ]: 137 : } while ((ret = archive_read_next_header(a, &ae)) == ARCHIVE_OK);
955 : 110 : pkg_emit_progress_tick(cur_file++, nfiles);
956 : :
957 [ + - ]: 110 : if (ret != ARCHIVE_EOF) {
958 : 0 : pkg_emit_error("archive_read_next_header(): %s",
959 : 0 : archive_error_string(a));
960 : 0 : retcode = EPKG_FATAL;
961 : 0 : }
962 : :
963 : : cleanup:
964 : 110 : pkg_emit_progress_tick(nfiles, nfiles);
965 : 110 : pkg_emit_extract_finished(pkg);
966 : :
967 : 110 : return (retcode);
968 : 110 : }
969 : :
970 : : static void
971 : 44 : backup_file_if_needed(struct pkg *p, struct pkg_file *f)
972 : : {
973 : : char path[MAXPATHLEN];
974 : : struct stat st;
975 : : char *sum;
976 : : pkg_checksum_type_t t;
977 : :
978 [ + - + - ]: 88 : if (fstatat(p->rootfd, RELATIVE_PATH(f->path), &st,
979 : 44 : AT_SYMLINK_NOFOLLOW) == -1)
980 : 0 : return;
981 : :
982 [ - + ]: 44 : if (S_ISLNK(st.st_mode))
983 : 0 : return;
984 : :
985 [ + + ]: 44 : if (S_ISREG(st.st_mode)) {
986 : 43 : t = pkg_checksum_file_get_type(f->sum, -1);
987 : 86 : sum = pkg_checksum_generate_fileat(p->rootfd,
988 : 43 : RELATIVE_PATH(f->path), t);
989 [ + - ]: 43 : if (sum == NULL)
990 : 0 : return;
991 : :
992 [ + + ]: 43 : if (STREQ(sum, f->sum)) {
993 : 41 : free(sum);
994 : 41 : return;
995 : : }
996 : 2 : free(sum);
997 : 2 : }
998 : :
999 : 3 : snprintf(path, sizeof(path), "%s.pkgsave", f->path);
1000 : 6 : renameat(p->rootfd, RELATIVE_PATH(f->path),
1001 : 3 : p->rootfd, RELATIVE_PATH(path));
1002 : 44 : }
1003 : :
1004 : : static int
1005 : 171 : pkg_extract_finalize(struct pkg *pkg, tempdirs_t *tempdirs)
1006 : : {
1007 : : struct stat st;
1008 : 171 : struct pkg_file *f = NULL;
1009 : 171 : struct pkg_dir *d = NULL;
1010 : : char path[MAXPATHLEN + 8];
1011 : : const char *fto;
1012 : : #ifdef HAVE_CHFLAGSAT
1013 : : bool install_as_user;
1014 : :
1015 : 171 : install_as_user = (getenv("INSTALL_AS_USER") != NULL);
1016 : : #endif
1017 : :
1018 : :
1019 [ - + ]: 171 : if (tempdirs != NULL) {
1020 [ + + + + : 203 : tll_foreach(*tempdirs, t) {
- + ]
1021 [ - + - + : 96 : if (renameat(pkg->rootfd, RELATIVE_PATH(t->item->temp),
- + ]
1022 : 64 : pkg->rootfd, RELATIVE_PATH(t->item->name)) != 0) {
1023 : 0 : pkg_fatal_errno("Fail to rename %s -> %s",
1024 : : t->item->temp, t->item->name);
1025 : 0 : }
1026 : 32 : free(t->item);
1027 : 32 : }
1028 : 171 : }
1029 [ + + ]: 309 : while (pkg_files(pkg, &f) == EPKG_OK) {
1030 : :
1031 [ - + - + ]: 276 : if (match_ucl_lists(f->path,
1032 : 138 : pkg_config_get("FILES_IGNORE_GLOB"),
1033 : 138 : pkg_config_get("FILES_IGNORE_REGEX")))
1034 : 0 : continue;
1035 : 138 : append_touched_file(f->path);
1036 [ + + ]: 138 : if (*f->temppath == '\0')
1037 : 48 : continue;
1038 : 90 : fto = f->path;
1039 [ + + + + : 90 : if (f->config && f->config->status == MERGE_FAILED &&
+ + ]
1040 : 2 : f->previous != PKG_FILE_NONE) {
1041 : 1 : snprintf(path, sizeof(path), "%s.pkgnew", f->path);
1042 : 1 : fto = path;
1043 : 1 : }
1044 : :
1045 [ + + + + ]: 90 : if (f->config && f->config->status == MERGE_NOT_LOCAL) {
1046 : 1 : backup_file_if_needed(pkg, f);
1047 : 1 : }
1048 : :
1049 : : /*
1050 : : * enforce an unlink of the file to workaround a bug that
1051 : : * results in renameat returning 0 of the from file is hardlink
1052 : : * on the to file, but the to file is not removed
1053 : : */
1054 [ + + + + ]: 90 : if (f->previous != PKG_FILE_NONE &&
1055 : 60 : fstatat(pkg->rootfd, RELATIVE_PATH(fto), &st,
1056 : 60 : AT_SYMLINK_NOFOLLOW) != -1) {
1057 : : #ifdef HAVE_CHFLAGSAT
1058 [ - + # # ]: 58 : if (!install_as_user && st.st_flags & NOCHANGESFLAGS) {
1059 : 0 : chflagsat(pkg->rootfd, RELATIVE_PATH(fto), 0,
1060 : : AT_SYMLINK_NOFOLLOW);
1061 : 0 : }
1062 : : #endif
1063 : : /* if the files does not belong to any package, we do save it */
1064 [ + + ]: 58 : if (f->previous == PKG_FILE_SAVE) {
1065 : 43 : backup_file_if_needed(pkg, f);
1066 : 43 : }
1067 : 58 : unlinkat(pkg->rootfd, RELATIVE_PATH(fto), 0);
1068 : 58 : }
1069 [ + - + - : 270 : if (renameat(pkg->rootfd, RELATIVE_PATH(f->temppath),
+ - ]
1070 : 180 : pkg->rootfd, RELATIVE_PATH(fto)) == -1) {
1071 : 0 : pkg_fatal_errno("Fail to rename %s -> %s",
1072 : : f->temppath, fto);
1073 : 0 : }
1074 : :
1075 [ + - ]: 90 : if (set_chflags(pkg->rootfd, fto, f->fflags) != EPKG_OK)
1076 : 0 : return (EPKG_FATAL);
1077 : : }
1078 : :
1079 [ + + ]: 177 : while (pkg_dirs(pkg, &d) == EPKG_OK) {
1080 : 6 : append_touched_dir(d->path);
1081 [ + + ]: 6 : if (d->noattrs)
1082 : 3 : continue;
1083 [ + - + - : 9 : if (set_attrsat(pkg->rootfd, d->path, d->perm,
+ - ]
1084 : 6 : d->uid, d->gid, &d->time[0], &d->time[1]) != EPKG_OK)
1085 : 0 : return (EPKG_FATAL);
1086 [ + - ]: 3 : if (set_chflags(pkg->rootfd, d->path, d->fflags) != EPKG_OK)
1087 : 0 : return (EPKG_FATAL);
1088 : : }
1089 [ - + ]: 171 : if (tempdirs != NULL)
1090 [ + + + + : 203 : tll_free(*tempdirs);
- + ]
1091 : :
1092 : 171 : return (EPKG_OK);
1093 : 171 : }
1094 : :
1095 : : static char *
1096 : 6 : pkg_globmatch(char *pattern, const char *name)
1097 : : {
1098 : : glob_t g;
1099 : : int i;
1100 : : char *buf, *buf2;
1101 : 6 : char *path = NULL;
1102 : :
1103 [ + + ]: 6 : if (glob(pattern, 0, NULL, &g) == GLOB_NOMATCH) {
1104 : 3 : globfree(&g);
1105 : :
1106 : 3 : return (NULL);
1107 : : }
1108 : :
1109 [ + + ]: 6 : for (i = 0; i < g.gl_pathc; i++) {
1110 : : /* the version starts here */
1111 : 3 : buf = strrchr(g.gl_pathv[i], '-');
1112 [ + - ]: 3 : if (buf == NULL)
1113 : 0 : continue;
1114 : 3 : buf2 = strrchr(g.gl_pathv[i], '/');
1115 [ + - ]: 3 : if (buf2 == NULL)
1116 : 0 : buf2 = g.gl_pathv[i];
1117 : : else
1118 : 3 : buf2++;
1119 : : /* ensure we have match the proper name */
1120 [ - + ]: 3 : if (strncmp(buf2, name, buf - buf2) != 0)
1121 : 0 : continue;
1122 [ - + ]: 3 : if (path == NULL) {
1123 : 3 : path = g.gl_pathv[i];
1124 : 3 : continue;
1125 : : }
1126 [ # # ]: 0 : if (pkg_version_cmp(path, g.gl_pathv[i]) == 1)
1127 : 0 : path = g.gl_pathv[i];
1128 : 0 : }
1129 [ - + ]: 3 : if (path)
1130 : 3 : path = xstrdup(path);
1131 : 3 : globfree(&g);
1132 : :
1133 : 3 : return (path);
1134 : 6 : }
1135 : :
1136 : : static int
1137 : 17 : pkg_add_check_pkg_archive(struct pkgdb *db, struct pkg *pkg,
1138 : : const char *path, int flags, const char *location)
1139 : : {
1140 : : const char *arch;
1141 : : int ret, retcode;
1142 : 17 : struct pkg_dep *dep = NULL;
1143 : : char bd[MAXPATHLEN];
1144 : : char dpath[MAXPATHLEN], *ppath;
1145 : 17 : const char *ext = NULL;
1146 : 17 : struct pkg *pkg_inst = NULL;
1147 : : bool fromstdin;
1148 : :
1149 [ + - ]: 17 : arch = pkg->abi != NULL ? pkg->abi : pkg->altabi;
1150 : :
1151 [ - + # # ]: 17 : if (!is_valid_abi(arch, true) && (flags & PKG_ADD_FORCE) == 0) {
1152 : 0 : return (EPKG_FATAL);
1153 : : }
1154 : :
1155 [ - + # # ]: 17 : if (!is_valid_os_version(pkg) && (flags & PKG_ADD_FORCE) == 0) {
1156 : 0 : return (EPKG_FATAL);
1157 : : }
1158 : :
1159 : : /* XX check */
1160 : 17 : ret = pkg_try_installed(db, pkg->name, &pkg_inst, PKG_LOAD_BASIC);
1161 [ + - ]: 17 : if (ret == EPKG_OK) {
1162 [ # # ]: 0 : if ((flags & PKG_ADD_FORCE) == 0) {
1163 : 0 : pkg_emit_already_installed(pkg_inst);
1164 : 0 : pkg_free(pkg_inst);
1165 : 0 : pkg_inst = NULL;
1166 : 0 : return (EPKG_INSTALLED);
1167 : : }
1168 [ # # ]: 0 : if (pkg_inst->locked) {
1169 : 0 : pkg_emit_locked(pkg_inst);
1170 : 0 : pkg_free(pkg_inst);
1171 : 0 : pkg_inst = NULL;
1172 : 0 : return (EPKG_LOCKED);
1173 : : }
1174 : 0 : pkg_emit_notice("package %s is already installed, forced "
1175 : 0 : "install", pkg->name);
1176 : 0 : pkg_free(pkg_inst);
1177 : 0 : pkg_inst = NULL;
1178 [ - + ]: 17 : } else if (ret != EPKG_END) {
1179 : 0 : return (ret);
1180 : : }
1181 : :
1182 : : /*
1183 : : * Check for dependencies by searching the same directory as
1184 : : * the package archive we're reading. Of course, if we're
1185 : : * reading from a file descriptor or a unix domain socket or
1186 : : * whatever, there's no valid directory to search.
1187 : : */
1188 : 17 : fromstdin = STREQ(path, "-");
1189 : 17 : strlcpy(bd, path, sizeof(bd));
1190 [ + + ]: 17 : if (!fromstdin) {
1191 : : /* In-place truncate bd to the directory components. */
1192 : 14 : char *basedir = strrchr(bd, '/');
1193 [ + + ]: 14 : if (NULL == basedir) {
1194 : 9 : bd[0]='.';
1195 : 9 : bd[1]='\0';
1196 : 9 : } else {
1197 : 5 : *basedir = '\0';
1198 : : }
1199 [ - + ]: 14 : if ((ext = strrchr(path, '.')) == NULL) {
1200 : 0 : pkg_emit_error("%s has no extension", path);
1201 : 0 : return (EPKG_FATAL);
1202 : : }
1203 : 14 : }
1204 : :
1205 : 17 : retcode = EPKG_FATAL;
1206 : 17 : pkg_emit_add_deps_begin(pkg);
1207 : :
1208 [ + + ]: 23 : while (pkg_deps(pkg, &dep) == EPKG_OK) {
1209 : 9 : dpath[0] = '\0';
1210 : :
1211 [ + - ]: 9 : if (pkg_is_installed(db, dep->name) == EPKG_OK)
1212 : 0 : continue;
1213 : :
1214 [ + + ]: 9 : if (fromstdin) {
1215 : 2 : pkg_emit_missing_dep(pkg, dep);
1216 [ + + ]: 2 : if ((flags & PKG_ADD_FORCE_MISSING) == 0)
1217 : 1 : goto cleanup;
1218 : 1 : continue;
1219 : : }
1220 : :
1221 [ + + - + ]: 7 : if (dep->version != NULL && dep->version[0] != '\0') {
1222 : 8 : snprintf(dpath, sizeof(dpath), "%s/%s-%s%s", bd,
1223 : 4 : dep->name, dep->version, ext);
1224 : 4 : }
1225 : :
1226 [ + + + + ]: 7 : if (strlen(dpath) == 0 || access(dpath, F_OK) != 0) {
1227 : 12 : snprintf(dpath, sizeof(dpath), "%s/%s-*%s", bd,
1228 : 6 : dep->name, ext);
1229 : 6 : ppath = pkg_globmatch(dpath, dep->name);
1230 [ + + ]: 6 : if (ppath == NULL) {
1231 : 3 : pkg_emit_missing_dep(pkg, dep);
1232 [ + + ]: 3 : if ((flags & PKG_ADD_FORCE_MISSING) == 0)
1233 : 2 : goto cleanup;
1234 : 1 : continue;
1235 : : }
1236 : 3 : strlcpy(dpath, ppath, sizeof(dpath));
1237 : 3 : free(ppath);
1238 : 3 : }
1239 : :
1240 [ + - - + ]: 4 : if ((flags & PKG_ADD_UPGRADE) == 0 &&
1241 : 4 : access(dpath, F_OK) == 0) {
1242 : 4 : ret = pkg_add(db, dpath, PKG_ADD_AUTOMATIC, location);
1243 : :
1244 [ + - ]: 4 : if (ret != EPKG_OK)
1245 : 0 : goto cleanup;
1246 : 4 : } else {
1247 : 0 : pkg_emit_missing_dep(pkg, dep);
1248 [ # # ]: 0 : if ((flags & PKG_ADD_FORCE_MISSING) == 0)
1249 : 0 : goto cleanup;
1250 : : }
1251 : : }
1252 : :
1253 : 14 : retcode = EPKG_OK;
1254 : : cleanup:
1255 : 17 : pkg_emit_add_deps_finished(pkg);
1256 : :
1257 : 17 : return (retcode);
1258 : 17 : }
1259 : :
1260 : : static int
1261 : 33 : pkg_add_cleanup_old(struct pkgdb *db, struct pkg *old, struct pkg *new, struct triggers *t, int flags)
1262 : : {
1263 : : struct pkg_file *f;
1264 : 33 : int ret = EPKG_OK;
1265 : :
1266 : 33 : pkg_start_stop_rc_scripts(old, PKG_RC_STOP);
1267 : :
1268 : : /*
1269 : : * Execute pre deinstall scripts
1270 : : */
1271 [ - + ]: 33 : if ((flags & PKG_ADD_NOSCRIPT) == 0) {
1272 : 33 : ret = pkg_lua_script_run(old, PKG_LUA_PRE_DEINSTALL, (old != NULL));
1273 [ - + # # ]: 33 : if (ret != EPKG_OK && ctx.developer_mode) {
1274 : 0 : return (ret);
1275 : : } else {
1276 : 33 : ret = pkg_script_run(old, PKG_SCRIPT_PRE_DEINSTALL, (old != NULL));
1277 [ - + # # ]: 33 : if (ret != EPKG_OK && ctx.developer_mode) {
1278 : 0 : return (ret);
1279 : : } else {
1280 : 33 : ret = EPKG_OK;
1281 : : }
1282 : : }
1283 : 33 : }
1284 : :
1285 : : /* Now remove files that no longer exist in the new package */
1286 [ + - ]: 33 : if (new != NULL) {
1287 : 33 : f = NULL;
1288 [ + + ]: 57 : while (pkg_files(old, &f) == EPKG_OK) {
1289 [ + + - + : 24 : if (!pkg_has_file(new, f->path) || match_ucl_lists(f->path,
- + ]
1290 : 16 : pkg_config_get("FILES_IGNORE_GLOB"),
1291 : 16 : pkg_config_get("FILES_IGNORE_REGEX"))) {
1292 : 8 : pkg_debug(2, "File %s is not in the new package", f->path);
1293 [ + + ]: 8 : if (ctx.backup_libraries) {
1294 : : const char *libname;
1295 : 3 : libname = strrchr(f->path, '/');
1296 [ + - + + ]: 3 : if (libname != NULL &&
1297 : 3 : stringlist_contains(&old->shlibs_provided, libname+1)) {
1298 : 2 : backup_library(db, old, f->path);
1299 : 2 : }
1300 : 3 : }
1301 : :
1302 : 8 : trigger_is_it_a_cleanup(t, f->path);
1303 : 8 : pkg_delete_file(old, f);
1304 : 8 : }
1305 : : }
1306 : :
1307 : 33 : pkg_delete_dirs(db, old, new);
1308 : 33 : }
1309 : :
1310 : 33 : return (ret);
1311 : 33 : }
1312 : :
1313 : : void
1314 : 0 : pkg_rollback_pkg(struct pkg *p)
1315 : : {
1316 : 0 : struct pkg_file *f = NULL;
1317 : :
1318 [ # # ]: 0 : while (pkg_files(p, &f) == EPKG_OK) {
1319 [ # # # # ]: 0 : if (match_ucl_lists(f->path,
1320 : 0 : pkg_config_get("FILES_IGNORE_GLOB"),
1321 : 0 : pkg_config_get("FILES_IGNORE_REGEX")))
1322 : 0 : continue;
1323 [ # # ]: 0 : if (*f->temppath != '\0') {
1324 : 0 : unlinkat(p->rootfd, f->temppath, 0);
1325 : 0 : }
1326 : : }
1327 : 0 : }
1328 : :
1329 : : void
1330 : 0 : pkg_rollback_cb(void *data)
1331 : : {
1332 : 0 : pkg_rollback_pkg((struct pkg *)data);
1333 : 0 : }
1334 : :
1335 : : int
1336 : 13 : pkg_add_triggers(void)
1337 : : {
1338 : 13 : return (triggers_execute(NULL));
1339 : : }
1340 : :
1341 : : static int
1342 : 172 : pkg_add_common(struct pkgdb *db, const char *path, unsigned flags,
1343 : : const char *reloc, struct pkg *remote,
1344 : : struct pkg *local, struct triggers *t)
1345 : : {
1346 : : struct archive *a;
1347 : : struct archive_entry *ae;
1348 : 172 : struct pkg *pkg = NULL;
1349 : 172 : xstring *message = NULL;
1350 : : struct pkg_message *msg;
1351 : : struct pkg_file *f;
1352 : : const char *msgstr;
1353 : 172 : bool extract = true, openxact = false;
1354 : 172 : int retcode = EPKG_OK;
1355 : : int ret;
1356 : : int nfiles;
1357 : 172 : tempdirs_t tempdirs = tll_init();
1358 : 172 : stringlist_t symlinks_allowed = tll_init();
1359 : :
1360 [ + - ]: 172 : assert(path != NULL);
1361 : :
1362 : : /*
1363 : : * Open the package archive file, read all the meta files and set the
1364 : : * current archive_entry to the first non-meta file.
1365 : : * If there is no non-meta files, EPKG_END is returned.
1366 : : */
1367 : 172 : ret = pkg_open2(&pkg, &a, &ae, path, 0, -1);
1368 [ + + ]: 172 : if (ret == EPKG_END)
1369 : 60 : extract = false;
1370 [ - + ]: 112 : else if (ret != EPKG_OK) {
1371 : 0 : retcode = ret;
1372 : 0 : goto cleanup;
1373 : : }
1374 [ + + ]: 172 : if ((flags & PKG_ADD_SPLITTED_UPGRADE) == 0)
1375 : 163 : pkg_emit_new_action();
1376 [ + + ]: 172 : if ((flags & (PKG_ADD_UPGRADE | PKG_ADD_SPLITTED_UPGRADE)) !=
1377 : : PKG_ADD_UPGRADE)
1378 : 139 : pkg_emit_install_begin(pkg);
1379 : : else
1380 : 33 : pkg_emit_upgrade_begin(pkg, local);
1381 : :
1382 [ - + ]: 172 : if (pkg_is_valid(pkg) != EPKG_OK) {
1383 : 0 : pkg_emit_error("the package is not valid");
1384 : 0 : return (EPKG_FATAL);
1385 : : }
1386 : :
1387 [ + + ]: 172 : if (flags & PKG_ADD_AUTOMATIC)
1388 : 34 : pkg->automatic = true;
1389 : :
1390 : : /*
1391 : : * Additional checks for non-remote package
1392 : : */
1393 [ + + ]: 172 : if (remote == NULL) {
1394 : 17 : ret = pkg_add_check_pkg_archive(db, pkg, path, flags, reloc);
1395 [ + + ]: 17 : if (ret != EPKG_OK) {
1396 : : /* Do not return error on installed package */
1397 [ - + ]: 3 : retcode = (ret == EPKG_INSTALLED ? EPKG_OK : ret);
1398 : 3 : goto cleanup;
1399 : : }
1400 : 14 : }
1401 : : else {
1402 [ + + ]: 155 : if (remote->repo != NULL) {
1403 : : /* Save reponame */
1404 : 93 : pkg_kv_add(&pkg->annotations, "repository", remote->repo->name, "annotation");
1405 : 93 : pkg_kv_add(&pkg->annotations, "repo_type", remote->repo->ops->type, "annotation");
1406 : 93 : }
1407 : :
1408 : 155 : free(pkg->digest);
1409 : 155 : pkg->digest = xstrdup(remote->digest);
1410 : : /* only preserve flags if -A has not been passed */
1411 [ + + ]: 155 : if ((flags & PKG_ADD_AUTOMATIC) == 0)
1412 : 126 : pkg->automatic = remote->automatic;
1413 : : }
1414 : :
1415 [ - + ]: 169 : if (reloc != NULL)
1416 : 0 : pkg_kv_add(&pkg->annotations, "relocated", reloc, "annotation");
1417 : :
1418 : 169 : pkg_open_root_fd(pkg);
1419 : : /* analyse previous files */
1420 : 169 : f = NULL;
1421 [ + + ]: 300 : while (pkg_files(pkg, &f) == EPKG_OK) {
1422 [ - + - + ]: 262 : if (match_ucl_lists(f->path,
1423 : 131 : pkg_config_get("FILES_IGNORE_GLOB"),
1424 : 131 : pkg_config_get("FILES_IGNORE_REGEX"))) {
1425 : 0 : continue;
1426 : : }
1427 [ + + ]: 131 : if (faccessat(pkg->rootfd, RELATIVE_PATH(f->path), F_OK, 0) == 0) {
1428 : 61 : f->previous = PKG_FILE_EXIST;
1429 [ + + ]: 61 : if (!pkgdb_file_exists(db, f->path)) {
1430 : 45 : f->previous = PKG_FILE_SAVE;
1431 : 45 : }
1432 : 61 : }
1433 : : }
1434 : :
1435 : : /*
1436 : : * Register the package before installing it in case there are problems
1437 : : * that could be caught here.
1438 : : */
1439 : 169 : retcode = pkgdb_register_pkg(db, pkg, flags & PKG_ADD_FORCE, NULL);
1440 [ - + ]: 169 : if (retcode != EPKG_OK)
1441 : 0 : goto cleanup;
1442 : 169 : openxact = true;
1443 : :
1444 : : /*
1445 : : * Execute pre-install scripts
1446 : : */
1447 [ + + ]: 169 : if ((flags & PKG_ADD_NOSCRIPT) == 0) {
1448 [ - + ]: 168 : if ((retcode = pkg_lua_script_run(pkg, PKG_LUA_PRE_INSTALL, (local != NULL))) != EPKG_OK)
1449 : 0 : goto cleanup;
1450 [ + + ]: 168 : if ((retcode = pkg_script_run(pkg, PKG_SCRIPT_PRE_INSTALL, (local != NULL))) != EPKG_OK)
1451 : 1 : goto cleanup;
1452 : 167 : }
1453 : :
1454 : :
1455 : : /* add the user and group if necessary */
1456 : :
1457 : 168 : nfiles = pkghash_count(pkg->filehash) + pkghash_count(pkg->dirhash);
1458 : : /*
1459 : : * Extract the files on disk.
1460 : : */
1461 [ + + ]: 168 : if (extract) {
1462 : 110 : pkg_register_cleanup_callback(pkg_rollback_cb, pkg);
1463 [ - + + - : 110 : tll_push_back(symlinks_allowed, pkg->prefix);
# # - + -
+ ]
1464 : 110 : retcode = do_extract(a, ae, nfiles, pkg, local, &tempdirs, &symlinks_allowed);
1465 : 110 : pkg_unregister_cleanup_callback(pkg_rollback_cb, pkg);
1466 [ - + ]: 110 : if (retcode != EPKG_OK) {
1467 : : /* If the add failed, clean up (silently) */
1468 : 0 : pkg_rollback_pkg(pkg);
1469 : 0 : pkg_delete_dirs(db, pkg, NULL);
1470 : 0 : goto cleanup;
1471 : : }
1472 : 110 : }
1473 : :
1474 : : /*
1475 : : * If this was a split upgrade, the old package has been entirely
1476 : : * removed already.
1477 : : */
1478 [ + + + + ]: 168 : if (local != NULL && (flags & PKG_ADD_SPLITTED_UPGRADE) == 0) {
1479 : 33 : pkg_open_root_fd(local);
1480 : 33 : pkg_debug(1, "Cleaning up old version");
1481 [ - + ]: 33 : if (pkg_add_cleanup_old(db, local, pkg, t, flags) != EPKG_OK) {
1482 : 0 : retcode = EPKG_FATAL;
1483 : 0 : goto cleanup;
1484 : : }
1485 : 33 : }
1486 : :
1487 : :
1488 : : /* Update configuration file content with db with newer versions */
1489 : 168 : pkgdb_update_config_file_content(pkg, db->sqlite);
1490 : :
1491 : 168 : retcode = pkg_extract_finalize(pkg, &tempdirs);
1492 : :
1493 : 168 : pkgdb_register_finale(db, retcode, NULL);
1494 : 168 : openxact = false;
1495 : :
1496 : : /*
1497 : : * Execute post install scripts
1498 : : */
1499 : :
1500 [ - + ]: 168 : if (retcode != EPKG_OK)
1501 : 0 : goto cleanup;
1502 [ + + ]: 168 : if ((flags & PKG_ADD_NOSCRIPT) == 0) {
1503 : 167 : pkg_lua_script_run(pkg, PKG_LUA_POST_INSTALL, (local != NULL));
1504 : 167 : pkg_script_run(pkg, PKG_SCRIPT_POST_INSTALL, (local != NULL));
1505 : 167 : }
1506 : :
1507 : : /*
1508 : : * start the different related services if the users do want that
1509 : : * and that the service is running
1510 : : */
1511 : :
1512 : 168 : pkg_start_stop_rc_scripts(pkg, PKG_RC_START);
1513 : :
1514 [ + + ]: 168 : if ((flags & (PKG_ADD_UPGRADE | PKG_ADD_SPLITTED_UPGRADE)) !=
1515 : : PKG_ADD_UPGRADE)
1516 : 135 : pkg_emit_install_finished(pkg, local);
1517 : : else
1518 : 33 : pkg_emit_upgrade_finished(pkg, local);
1519 : :
1520 [ + + + + : 189 : tll_foreach(pkg->message, m) {
+ + ]
1521 : 21 : msg = m->item;
1522 : 21 : msgstr = NULL;
1523 [ + + ]: 21 : if (msg->type == PKG_MESSAGE_ALWAYS) {
1524 : 3 : msgstr = msg->str;
1525 [ + - + + ]: 21 : } else if (local != NULL &&
1526 : 18 : msg->type == PKG_MESSAGE_UPGRADE) {
1527 [ + + + + ]: 12 : if (msg->maximum_version == NULL &&
1528 : 6 : msg->minimum_version == NULL) {
1529 : 3 : msgstr = msg->str;
1530 [ + + ]: 12 : } else if (msg->maximum_version == NULL) {
1531 [ + + ]: 3 : if (pkg_version_cmp(local->version, msg->minimum_version) == 1) {
1532 : 2 : msgstr = msg->str;
1533 : 2 : }
1534 [ + + ]: 9 : } else if (msg->minimum_version == NULL) {
1535 [ + + ]: 3 : if (pkg_version_cmp(local->version, msg->maximum_version) == -1) {
1536 : 1 : msgstr = msg->str;
1537 : 1 : }
1538 [ + + + + ]: 6 : } else if (pkg_version_cmp(local->version, msg->maximum_version) == -1 &&
1539 : 2 : pkg_version_cmp(local->version, msg->minimum_version) == 1) {
1540 : 1 : msgstr = msg->str;
1541 : 1 : }
1542 [ - + # # ]: 18 : } else if (local == NULL &&
1543 : 0 : msg->type == PKG_MESSAGE_INSTALL) {
1544 : 0 : msgstr = msg->str;
1545 : 0 : }
1546 [ + + ]: 21 : if (msgstr != NULL) {
1547 [ + + ]: 10 : if (message == NULL) {
1548 : 3 : message = xstring_new();
1549 : 6 : pkg_fprintf(message->fp, "=====\nMessage from "
1550 : 3 : "%n-%v:\n\n", pkg, pkg);
1551 : 3 : }
1552 : 10 : fprintf(message->fp, "--\n%s\n", msgstr);
1553 : 10 : }
1554 : 21 : }
1555 [ + + - + ]: 171 : if (pkg_has_message(pkg) && message != NULL) {
1556 : 3 : fflush(message->fp);
1557 : 3 : pkg_emit_message(message->buf);
1558 : 3 : xstring_free(message);
1559 : 3 : }
1560 : :
1561 : : cleanup:
1562 [ + + + + : 282 : tll_free(symlinks_allowed);
- + ]
1563 : :
1564 [ + + ]: 172 : if (openxact)
1565 : 1 : pkgdb_register_finale(db, retcode, NULL);
1566 [ - + ]: 172 : if (a != NULL) {
1567 : 172 : archive_read_close(a);
1568 : 172 : archive_read_free(a);
1569 : 172 : }
1570 : :
1571 : 172 : pkg_free(pkg);
1572 : :
1573 : 172 : return (retcode);
1574 : 172 : }
1575 : :
1576 : : int
1577 : 17 : pkg_add(struct pkgdb *db, const char *path, unsigned flags,
1578 : : const char *location)
1579 : : {
1580 : 17 : return pkg_add_common(db, path, flags, location, NULL, NULL, NULL);
1581 : : }
1582 : :
1583 : : int
1584 : 113 : pkg_add_from_remote(struct pkgdb *db, const char *path, unsigned flags,
1585 : : const char *location, struct pkg *rp, struct triggers *t)
1586 : : {
1587 : 113 : return pkg_add_common(db, path, flags, location, rp, NULL, t);
1588 : : }
1589 : :
1590 : : int
1591 : 42 : pkg_add_upgrade(struct pkgdb *db, const char *path, unsigned flags,
1592 : : const char *location,
1593 : : struct pkg *rp, struct pkg *lp, struct triggers *t)
1594 : : {
1595 [ - + - + ]: 84 : if (pkgdb_ensure_loaded(db, lp,
1596 : 42 : PKG_LOAD_FILES|PKG_LOAD_SCRIPTS|PKG_LOAD_DIRS|PKG_LOAD_LUA_SCRIPTS) != EPKG_OK)
1597 : 0 : return (EPKG_FATAL);
1598 : :
1599 : 42 : return pkg_add_common(db, path, flags, location, rp, lp, t);
1600 : 42 : }
1601 : :
1602 : : static int
1603 : 0 : pkg_group_dump(int fd, struct pkg *pkg)
1604 : : {
1605 : : ucl_object_t *o, *seq;
1606 : 0 : struct pkg_dep *dep = NULL;
1607 : :
1608 [ # # ]: 0 : if (pkg->type != PKG_GROUP_REMOTE)
1609 : 0 : return (EPKG_FATAL);
1610 : 0 : o = ucl_object_typed_new(UCL_OBJECT);
1611 : 0 : ucl_object_insert_key(o, ucl_object_fromstring(pkg->name), "name", 0, false);
1612 : 0 : ucl_object_insert_key(o, ucl_object_fromstring(pkg->comment), "comment", 0, false);
1613 : 0 : seq = ucl_object_typed_new(UCL_ARRAY);
1614 [ # # ]: 0 : while (pkg_deps(pkg, &dep) == EPKG_OK)
1615 : 0 : ucl_array_append(seq, ucl_object_fromstring(dep->name));
1616 : 0 : ucl_object_insert_key(o, seq, "depends", 0, false);
1617 : 0 : ucl_object_emit_fd(o, UCL_EMIT_CONFIG, fd);
1618 : 0 : return (EPKG_OK);
1619 : 0 : }
1620 : :
1621 : : int
1622 : 0 : pkg_add_group(struct pkg *pkg)
1623 : : {
1624 : : char temp[MAXPATHLEN];
1625 : 0 : int dfd = pkg_get_dbdirfd();
1626 : 0 : mkdirat(dfd, "groups", 0755);
1627 : 0 : int gfd = openat(dfd, "groups", O_DIRECTORY|O_CLOEXEC);
1628 : 0 : hidden_tempfile(temp, MAXPATHLEN, pkg->name);
1629 : 0 : int fd = openat(gfd, temp, O_CREAT|O_EXCL|O_WRONLY, 0644);
1630 [ # # ]: 0 : if (fd == -1) {
1631 : 0 : pkg_emit_errno("impossible to create group file %s", pkg->name);
1632 : 0 : return (EPKG_FATAL);
1633 : : }
1634 : 0 : pkg_group_dump(fd, pkg);
1635 : 0 : close(fd);
1636 [ # # ]: 0 : if (renameat(gfd, temp, gfd, pkg->name) == -1) {
1637 : 0 : unlinkat(gfd, temp, 0);
1638 : 0 : pkg_emit_errno("impossible to create group file %s", pkg->name);
1639 : 0 : return (EPKG_FATAL);
1640 : : }
1641 : 0 : return (EPKG_OK);
1642 : 0 : }
1643 : :
1644 : : int
1645 : 3 : pkg_add_fromdir(struct pkg *pkg, const char *src)
1646 : : {
1647 : : struct stat st;
1648 : 3 : struct pkg_dir *d = NULL;
1649 : 3 : struct pkg_file *f = NULL;
1650 : : char target[MAXPATHLEN];
1651 : : struct passwd *pw, pwent;
1652 : : struct group *gr, grent;
1653 : : int err, fd, fromfd;
1654 : : int retcode;
1655 : 3 : hardlinks_t hardlinks = tll_init();
1656 : : const char *path;
1657 : : char buffer[1024];
1658 : : size_t link_len;
1659 : : bool install_as_user;
1660 : 3 : tempdirs_t tempdirs = tll_init();
1661 : 3 : stringlist_t symlinks_allowed = tll_init();
1662 [ - + + - : 3 : tll_push_back(symlinks_allowed, pkg->prefix);
# # - + -
+ ]
1663 : :
1664 : 3 : install_as_user = (getenv("INSTALL_AS_USER") != NULL);
1665 : :
1666 : 3 : fromfd = open(src, O_DIRECTORY);
1667 [ + - ]: 3 : if (fromfd == -1) {
1668 : 0 : pkg_fatal_errno("Unable to open source directory '%s'", src);
1669 : 0 : }
1670 : 3 : pkg_open_root_fd(pkg);
1671 : :
1672 [ - + ]: 3 : while (pkg_dirs(pkg, &d) == EPKG_OK) {
1673 [ # # ]: 0 : if (fstatat(fromfd, RELATIVE_PATH(d->path), &st, 0) == -1) {
1674 : 0 : close(fromfd);
1675 : 0 : pkg_fatal_errno("%s%s", src, d->path);
1676 : 0 : }
1677 [ # # ]: 0 : if (d->perm == 0)
1678 : 0 : d->perm = st.st_mode & ~S_IFMT;
1679 [ # # ]: 0 : if (d->uname[0] != '\0') {
1680 : 0 : err = getpwnam_r(d->uname, &pwent, buffer,
1681 : : sizeof(buffer), &pw);
1682 [ # # ]: 0 : if (err != 0) {
1683 : 0 : pkg_emit_errno("getpwnam_r", d->uname);
1684 : 0 : retcode = EPKG_FATAL;
1685 : 0 : goto cleanup;
1686 : : }
1687 : 0 : d->uid = pwent.pw_uid;
1688 : 0 : } else {
1689 [ # # ]: 0 : d->uid = install_as_user ? st.st_uid : 0;
1690 : : }
1691 [ # # ]: 0 : if (d->gname[0] != '\0') {
1692 : 0 : err = getgrnam_r(d->gname, &grent, buffer,
1693 : : sizeof(buffer), &gr);
1694 [ # # ]: 0 : if (err != 0) {
1695 : 0 : pkg_emit_errno("getgrnam_r", d->gname);
1696 : 0 : retcode = EPKG_FATAL;
1697 : 0 : goto cleanup;
1698 : : }
1699 : 0 : d->gid = grent.gr_gid;
1700 : 0 : } else {
1701 : 0 : d->gid = st.st_gid;
1702 : : }
1703 : : #ifdef HAVE_STRUCT_STAT_ST_MTIM
1704 : 0 : d->time[0] = st.st_atim;
1705 : 0 : d->time[1] = st.st_mtim;
1706 : : #else
1707 : : #if defined(_DARWIN_C_SOURCE) || defined(__APPLE__)
1708 : : d->time[0] = st.st_atimespec;
1709 : : d->time[1] = st.st_mtimespec;
1710 : : #else
1711 : : d->time[0].tv_sec = st.st_atime;
1712 : : d->time[0].tv_nsec = 0;
1713 : : d->time[1].tv_sec = st.st_mtime;
1714 : : d->time[1].tv_nsec = 0;
1715 : : #endif
1716 : : #endif
1717 : :
1718 [ # # ]: 0 : if (create_dir(pkg, d, &tempdirs, &symlinks_allowed) == EPKG_FATAL) {
1719 : 0 : retcode = EPKG_FATAL;
1720 : 0 : goto cleanup;
1721 : : }
1722 : : }
1723 : :
1724 [ + + ]: 10 : while (pkg_files(pkg, &f) == EPKG_OK) {
1725 [ - + - + ]: 14 : if (match_ucl_lists(f->path,
1726 : 7 : pkg_config_get("FILES_IGNORE_GLOB"),
1727 : 7 : pkg_config_get("FILES_IGNORE_REGEX")))
1728 : 0 : continue;
1729 [ + - + - ]: 14 : if (fstatat(fromfd, RELATIVE_PATH(f->path), &st,
1730 : 7 : AT_SYMLINK_NOFOLLOW) == -1) {
1731 [ # # # # : 0 : tll_free_and_free(hardlinks, free);
# # ]
1732 : 0 : close(fromfd);
1733 : 0 : pkg_fatal_errno("%s%s", src, f->path);
1734 : 0 : }
1735 [ + + ]: 7 : if (f->uname[0] != '\0') {
1736 : 6 : err = getpwnam_r(f->uname, &pwent, buffer,
1737 : : sizeof(buffer), &pw);
1738 [ - + ]: 6 : if (err != 0) {
1739 : 0 : pkg_emit_errno("getpwnam_r", f->uname);
1740 : 0 : retcode = EPKG_FATAL;
1741 : 0 : goto cleanup;
1742 : : }
1743 : 6 : f->uid = pwent.pw_uid;
1744 : 6 : } else {
1745 [ + - ]: 1 : f->uid = install_as_user ? st.st_uid : 0;
1746 : : }
1747 : :
1748 [ + + ]: 7 : if (f->gname[0] != '\0') {
1749 : 6 : err = getgrnam_r(f->gname, &grent, buffer,
1750 : : sizeof(buffer), &gr);
1751 [ - + ]: 6 : if (err != 0) {
1752 : 0 : pkg_emit_errno("getgrnam_r", f->gname);
1753 : 0 : retcode = EPKG_FATAL;
1754 : 0 : goto cleanup;
1755 : : }
1756 : 6 : f->gid = grent.gr_gid;
1757 : 6 : } else {
1758 : 1 : f->gid = st.st_gid;
1759 : : }
1760 : :
1761 [ - + ]: 7 : if (f->perm == 0)
1762 : 7 : f->perm = st.st_mode & ~S_IFMT;
1763 [ + + - + ]: 7 : if (f->uid == 0 && install_as_user)
1764 : 6 : f->uid = st.st_uid;
1765 : : #ifdef HAVE_STRUCT_STAT_ST_MTIM
1766 : 7 : f->time[0] = st.st_atim;
1767 : 7 : f->time[1] = st.st_mtim;
1768 : : #else
1769 : : #if defined(_DARWIN_C_SOURCE) || defined(__APPLE__)
1770 : : f->time[0] = st.st_atimespec;
1771 : : f->time[1] = st.st_mtimespec;
1772 : : #else
1773 : : f->time[0].tv_sec = st.st_atime;
1774 : : f->time[0].tv_nsec = 0;
1775 : : f->time[1].tv_sec = st.st_mtime;
1776 : : f->time[1].tv_nsec = 0;
1777 : : #endif
1778 : : #endif
1779 : :
1780 [ + + ]: 7 : if (S_ISLNK(st.st_mode)) {
1781 [ + - + - : 9 : if ((link_len = readlinkat(fromfd,
+ - ]
1782 : 3 : RELATIVE_PATH(f->path), target,
1783 : 3 : sizeof(target))) == -1) {
1784 [ # # # # : 0 : tll_free_and_free(hardlinks, free);
# # ]
1785 : 0 : close(fromfd);
1786 : 0 : pkg_fatal_errno("Impossible to read symlinks "
1787 : : "'%s'", f->path);
1788 : 0 : }
1789 : 3 : target[link_len] = '\0';
1790 [ + - ]: 3 : if (create_symlinks(pkg, f, target, &tempdirs, &symlinks_allowed) == EPKG_FATAL) {
1791 : 0 : retcode = EPKG_FATAL;
1792 : 0 : goto cleanup;
1793 : : }
1794 [ - + ]: 7 : } else if (S_ISREG(st.st_mode)) {
1795 [ + - + - ]: 8 : if ((fd = openat(fromfd, RELATIVE_PATH(f->path),
1796 : 4 : O_RDONLY)) == -1) {
1797 [ # # # # : 0 : tll_free_and_free(hardlinks, free);
# # ]
1798 : 0 : close(fromfd);
1799 : 0 : pkg_fatal_errno("Impossible to open source file"
1800 : : " '%s'", RELATIVE_PATH(f->path));
1801 : 0 : }
1802 : 4 : path = NULL;
1803 [ + + + + : 4 : tll_foreach(hardlinks, hit) {
# # ]
1804 [ + - + - ]: 1 : if (hit->item->ino == st.st_ino &&
1805 : 1 : hit->item->dev == st.st_dev) {
1806 : 1 : path = hit->item->path;
1807 : 1 : break;
1808 : : }
1809 : 0 : }
1810 [ + + ]: 4 : if (path != NULL) {
1811 [ + - ]: 1 : if (create_hardlink(pkg, f, path, &tempdirs, &symlinks_allowed) == EPKG_FATAL) {
1812 : 0 : close(fd);
1813 : 0 : retcode = EPKG_FATAL;
1814 : 0 : goto cleanup;
1815 : : }
1816 : 1 : } else {
1817 [ + - ]: 3 : if (create_regfile(pkg, f, NULL, NULL, fd, NULL, &tempdirs, &symlinks_allowed) == EPKG_FATAL) {
1818 : 0 : close(fd);
1819 : 0 : retcode = EPKG_FATAL;
1820 : 0 : goto cleanup;
1821 : : }
1822 : 3 : struct hardlink *h = xcalloc(1, sizeof(*h));
1823 : 3 : h->ino = st.st_ino;
1824 : 3 : h->dev = st.st_dev;
1825 : 3 : h->path = f->path;
1826 [ - + + - : 3 : tll_push_back(hardlinks, h);
# # - + -
+ ]
1827 : : }
1828 : 4 : close(fd);
1829 : 4 : } else {
1830 : 0 : pkg_emit_error("Invalid file type");
1831 : 0 : retcode = EPKG_FATAL;
1832 : 0 : goto cleanup;
1833 : : }
1834 : : }
1835 : :
1836 : 3 : retcode = pkg_extract_finalize(pkg, &tempdirs);
1837 : :
1838 : : cleanup:
1839 [ - + + + : 6 : tll_free(symlinks_allowed);
- + ]
1840 [ - + + + : 6 : tll_free_and_free(hardlinks, free);
- + ]
1841 : 3 : close(fromfd);
1842 : 3 : return (retcode);
1843 : 3 : }
1844 : :
|