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, c_charv_t *symlinks_allowed)
425 : : {
426 : 144 : struct tempdir *tmpdir = NULL;
427 : :
428 [ + + ]: 144 : for (size_t i = 0; i < tempdirs->len; i++) {
429 : 17 : tmpdir = tempdirs->d[i];
430 [ + - + - ]: 17 : if (strncmp(tmpdir->name, path, tmpdir->len) == 0 && path[tmpdir->len] == '/') {
431 : 17 : reopen_tempdir(rootfd, tmpdir);
432 : 17 : return (tmpdir);
433 : : }
434 : 0 : }
435 : :
436 : 127 : tmpdir = open_tempdir(rootfd, path, symlinks_allowed);
437 [ + + ]: 127 : if (tmpdir != NULL)
438 [ - + - + : 32 : pkgvec_push(tempdirs, tmpdir);
+ - ]
439 : :
440 : 127 : return (tmpdir);
441 : 144 : }
442 : :
443 : : static void
444 : 149 : close_tempdir(struct tempdir *t)
445 : : {
446 [ + + ]: 149 : if (t == NULL)
447 : 98 : return;
448 [ + + ]: 51 : if (t->fd != -1)
449 : 49 : close(t->fd);
450 : 51 : t->fd = -1;
451 : 149 : }
452 : :
453 : : static int
454 : 6 : create_dir(struct pkg *pkg, struct pkg_dir *d, tempdirs_t *tempdirs, c_charv_t *symlinks_allowed)
455 : : {
456 : : struct stat st;
457 : 6 : struct tempdir *tmpdir = NULL;
458 : : int fd;
459 : : const char *path;
460 : :
461 : 6 : tmpdir = get_tempdir(pkg->rootfd, d->path, tempdirs, symlinks_allowed);
462 [ + + ]: 6 : if (tmpdir == NULL) {
463 : 5 : fd = pkg->rootfd;
464 : 5 : path = d->path;
465 : 5 : } else {
466 : 1 : fd = tmpdir->fd;
467 : 1 : path = d->path + tmpdir->len;
468 : : }
469 : :
470 [ + + ]: 6 : if (mkdirat(fd, RELATIVE_PATH(path), 0755) == -1)
471 [ + - ]: 4 : if (!mkdirat_p(fd, RELATIVE_PATH(path))) {
472 : 0 : close_tempdir(tmpdir);
473 : 0 : return (EPKG_FATAL);
474 : : }
475 [ + + ]: 6 : if (fstatat(fd, RELATIVE_PATH(path), &st, 0) == -1) {
476 [ + - ]: 1 : if (errno != ENOENT) {
477 : 0 : close_tempdir(tmpdir);
478 : 0 : pkg_fatal_errno("Fail to stat directory %s", path);
479 : 0 : }
480 [ - + ]: 1 : if (fstatat(fd, RELATIVE_PATH(path), &st, AT_SYMLINK_NOFOLLOW) == 0) {
481 : 1 : unlinkat(fd, RELATIVE_PATH(path), 0);
482 : 1 : }
483 [ + - ]: 1 : if (mkdirat(fd, RELATIVE_PATH(path), 0755) == -1) {
484 [ # # ]: 0 : if (tmpdir != NULL) {
485 : 0 : close_tempdir(tmpdir);
486 : 0 : pkg_fatal_errno("Fail to create directory '%s/%s'", tmpdir->temp, path);
487 : 0 : }
488 : 0 : pkg_fatal_errno("Fail to create directory %s", path);
489 : 0 : }
490 : 1 : }
491 : :
492 [ + + - + : 6 : if (st.st_uid == d->uid && st.st_gid == d->gid &&
- + ]
493 : 3 : (st.st_mode & ~S_IFMT) == (d->perm & ~S_IFMT)) {
494 : 3 : d->noattrs = true;
495 : 3 : }
496 : :
497 : 6 : close_tempdir(tmpdir);
498 : 6 : return (EPKG_OK);
499 : 6 : }
500 : :
501 : : /* In case of directories create the dir and extract the creds */
502 : : static int
503 : 6 : do_extract_dir(struct pkg* pkg, struct archive *a __unused, struct archive_entry *ae,
504 : : const char *path, struct pkg *local __unused, tempdirs_t *tempdirs, c_charv_t *symlinks_allowed)
505 : : {
506 : : struct pkg_dir *d;
507 : : const struct stat *aest;
508 : : unsigned long clear;
509 : :
510 : 6 : d = pkg_get_dir(pkg, path);
511 [ + - ]: 6 : if (d == NULL) {
512 : 0 : pkg_emit_error("Directory %s not specified in the manifest, skipping",
513 : 0 : path);
514 : 0 : return (EPKG_OK);
515 : : }
516 : 6 : aest = archive_entry_stat(ae);
517 : 6 : d->perm = aest->st_mode;
518 : 6 : d->uid = get_uid_from_archive(ae);
519 : 6 : d->gid = get_gid_from_archive(ae);
520 : 6 : fill_timespec_buf(aest, d->time);
521 : 6 : archive_entry_fflags(ae, &d->fflags, &clear);
522 : :
523 [ - + ]: 6 : if (create_dir(pkg, d, tempdirs, symlinks_allowed) == EPKG_FATAL) {
524 : 0 : return (EPKG_FATAL);
525 : : }
526 : :
527 : 12 : metalog_add(PKG_METALOG_DIR, RELATIVE_PATH(path),
528 : 6 : archive_entry_uname(ae), archive_entry_gname(ae),
529 : 6 : aest->st_mode & ~S_IFDIR, d->fflags, NULL);
530 : :
531 : 6 : return (EPKG_OK);
532 : 6 : }
533 : :
534 : :
535 : : static bool
536 : 29 : try_mkdir(int fd, const char *path)
537 : : {
538 : 29 : char *p = get_dirname(xstrdup(path));
539 : :
540 [ - + ]: 29 : if (!mkdirat_p(fd, RELATIVE_PATH(p))) {
541 : 0 : free(p);
542 : 0 : return (false);
543 : : }
544 : 29 : free(p);
545 : 29 : return (true);
546 : 29 : }
547 : :
548 : : static int
549 : 13 : create_symlinks(struct pkg *pkg, struct pkg_file *f, const char *target, tempdirs_t *tempdirs,
550 : : c_charv_t *symlinks_allowed)
551 : : {
552 : 13 : struct tempdir *tmpdir = NULL;
553 : : int fd;
554 : : const char *path;
555 : 13 : bool tried_mkdir = false;
556 : :
557 : 13 : tmpdir = get_tempdir(pkg->rootfd, f->path, tempdirs, symlinks_allowed);
558 [ + + - + ]: 13 : if (tmpdir == NULL && errno == 0)
559 : 2 : hidden_tempfile(f->temppath, sizeof(f->temppath), f->path);
560 [ + + ]: 26 : if (tmpdir == NULL) {
561 : 2 : fd = pkg->rootfd;
562 : 2 : path = f->temppath;
563 : 2 : } else {
564 : 11 : fd = tmpdir->fd;
565 : 11 : path = f->path + tmpdir->len;
566 : : }
567 : : retry:
568 [ + + ]: 16 : if (symlinkat(target, fd, RELATIVE_PATH(path)) == -1) {
569 [ - + ]: 3 : if (!tried_mkdir) {
570 [ - + ]: 3 : if (!try_mkdir(fd, path)) {
571 : 0 : close_tempdir(tmpdir);
572 : 0 : return (EPKG_FATAL);
573 : : }
574 : 3 : tried_mkdir = true;
575 : 3 : goto retry;
576 : : }
577 : :
578 : 0 : pkg_fatal_errno("Fail to create symlink: %s", path);
579 : 0 : }
580 : :
581 [ - + - + : 39 : if (set_attrsat(fd, path, f->perm, f->uid, f->gid,
- + ]
582 : 26 : &f->time[0], &f->time[1]) != EPKG_OK) {
583 : 0 : close_tempdir(tmpdir);
584 : 0 : return (EPKG_FATAL);
585 : : }
586 [ + + ]: 13 : if (tmpdir != NULL)
587 : 11 : set_chflags(fd, path, f->fflags);
588 : 13 : close_tempdir(tmpdir);
589 : :
590 : 13 : return (EPKG_OK);
591 : 13 : }
592 : :
593 : : /* In case of a symlink create it directly with a random name */
594 : : static int
595 : 10 : do_extract_symlink(struct pkg *pkg, struct archive *a __unused, struct archive_entry *ae,
596 : : const char *path, struct pkg *local __unused, tempdirs_t *tempdirs,
597 : : c_charv_t *symlinks_allowed)
598 : : {
599 : : struct pkg_file *f;
600 : : const struct stat *aest;
601 : : unsigned long clear;
602 : :
603 : 10 : f = pkg_get_file(pkg, path);
604 [ + - ]: 10 : if (f == NULL) {
605 : 0 : pkg_emit_error("Symlink %s not specified in the manifest", path);
606 : 0 : return (EPKG_FATAL);
607 : : }
608 : :
609 : 10 : aest = archive_entry_stat(ae);
610 : 10 : archive_entry_fflags(ae, &f->fflags, &clear);
611 : 10 : f->uid = get_uid_from_archive(ae);
612 : 10 : f->gid = get_gid_from_archive(ae);
613 : 10 : f->perm = aest->st_mode;
614 : 10 : fill_timespec_buf(aest, f->time);
615 : 10 : archive_entry_fflags(ae, &f->fflags, &clear);
616 : :
617 [ - + ]: 10 : if (create_symlinks(pkg, f, archive_entry_symlink(ae), tempdirs, symlinks_allowed) == EPKG_FATAL)
618 : 0 : return (EPKG_FATAL);
619 : :
620 : 20 : metalog_add(PKG_METALOG_LINK, RELATIVE_PATH(path),
621 : 10 : archive_entry_uname(ae), archive_entry_gname(ae),
622 : 10 : aest->st_mode & ~S_IFLNK, f->fflags, archive_entry_symlink(ae));
623 : :
624 : 10 : return (EPKG_OK);
625 : 10 : }
626 : :
627 : : static int
628 : 5 : create_hardlink(struct pkg *pkg, struct pkg_file *f, const char *path, tempdirs_t *tempdirs,
629 : : c_charv_t *symlinks_allowed)
630 : : {
631 : 5 : bool tried_mkdir = false;
632 : : struct pkg_file *fh;
633 : : int fd, fdh;
634 : : const char *pathfrom, *pathto;
635 : 5 : struct tempdir *tmpdir = NULL;
636 : 5 : struct tempdir *tmphdir = NULL;
637 : :
638 : 5 : tmpdir = get_tempdir(pkg->rootfd, f->path, tempdirs, symlinks_allowed);
639 [ + + - + ]: 5 : if (tmpdir == NULL && errno == 0)
640 : 3 : hidden_tempfile(f->temppath, sizeof(f->temppath), f->path);
641 [ + + ]: 5 : if (tmpdir != NULL) {
642 : 2 : fd = tmpdir->fd;
643 : 2 : } else {
644 : 3 : fd = pkg->rootfd;
645 : : }
646 : 5 : fh = pkg_get_file(pkg, path);
647 [ + - ]: 5 : if (fh == NULL) {
648 : 0 : close_tempdir(tmpdir);
649 : 0 : pkg_emit_error("Can't find the file %s is supposed to be"
650 : 0 : " hardlinked to %s", f->path, path);
651 : 0 : return (EPKG_FATAL);
652 : : }
653 [ + + ]: 5 : if (fh->temppath[0] == '\0') {
654 [ - + ]: 2 : for (size_t i = 0; i < tempdirs->len; i++) {
655 [ + - + - ]: 2 : if (strncmp(tempdirs->d[i]->name, fh->path, tempdirs->d[i]->len) == 0 &&
656 : 2 : fh->path[tempdirs->d[i]->len] == '/' ) {
657 : 2 : tmphdir = tempdirs->d[i];
658 : 2 : reopen_tempdir(pkg->rootfd, tmphdir);
659 : 2 : break;
660 : : }
661 : 0 : }
662 : 2 : }
663 [ + + ]: 5 : if (tmpdir == NULL) {
664 : 3 : pathto = f->temppath;
665 : 3 : fd = pkg->rootfd;
666 : 3 : } else {
667 : 2 : pathto = f->path + tmpdir->len;
668 : 2 : fd = tmpdir->fd;
669 : : }
670 : :
671 [ + + ]: 10 : if (tmphdir == NULL) {
672 : 3 : pathfrom = fh->temppath;
673 : 3 : fdh = pkg->rootfd;
674 : 3 : } else {
675 : 2 : pathfrom = fh->path + tmphdir->len;
676 : 2 : fdh = tmphdir->fd;
677 : : }
678 : :
679 : : retry:
680 [ + - + - : 15 : if (linkat(fdh, RELATIVE_PATH(pathfrom),
+ - ]
681 : 10 : fd, RELATIVE_PATH(pathto), 0) == -1) {
682 [ # # ]: 0 : if (!tried_mkdir) {
683 [ # # ]: 0 : if (!try_mkdir(fd, pathto)) {
684 : 0 : close_tempdir(tmpdir);
685 : 0 : close_tempdir(tmphdir);
686 : 0 : return (EPKG_FATAL);
687 : : }
688 : 0 : tried_mkdir = true;
689 : 0 : goto retry;
690 : : }
691 : :
692 : 0 : close_tempdir(tmpdir);
693 : 0 : close_tempdir(tmphdir);
694 : 0 : pkg_fatal_errno("Fail to create hardlink: %s <-> %s", pathfrom, pathto);
695 : 0 : }
696 : 5 : close_tempdir(tmpdir);
697 : 5 : close_tempdir(tmphdir);
698 : :
699 : 5 : return (EPKG_OK);
700 : 5 : }
701 : :
702 : : static int
703 : 4 : do_extract_hardlink(struct pkg *pkg, struct archive *a __unused, struct archive_entry *ae,
704 : : const char *path, struct pkg *local __unused, tempdirs_t *tempdirs,
705 : : c_charv_t *symlinks_allowed)
706 : : {
707 : : struct pkg_file *f;
708 : : const struct stat *aest;
709 : : const char *lp;
710 : :
711 : 4 : f = pkg_get_file(pkg, path);
712 [ + - ]: 4 : if (f == NULL) {
713 : 0 : pkg_emit_error("Hardlink %s not specified in the manifest", path);
714 : 0 : return (EPKG_FATAL);
715 : : }
716 : 4 : lp = archive_entry_hardlink(ae);
717 : 4 : aest = archive_entry_stat(ae);
718 : :
719 [ - + ]: 4 : if (create_hardlink(pkg, f, lp, tempdirs, symlinks_allowed) == EPKG_FATAL)
720 : 0 : return (EPKG_FATAL);
721 : :
722 : 8 : metalog_add(PKG_METALOG_FILE, RELATIVE_PATH(path),
723 : 4 : archive_entry_uname(ae), archive_entry_gname(ae),
724 : 4 : aest->st_mode & ~S_IFREG, 0, NULL);
725 : :
726 : 4 : return (EPKG_OK);
727 : 4 : }
728 : :
729 : : static int
730 : 120 : open_tempfile(int rootfd, const char *path, int perm)
731 : : {
732 : : int fd;
733 : 120 : bool tried_mkdir = false;
734 : :
735 : : retry:
736 : 146 : fd = openat(rootfd, RELATIVE_PATH(path), O_CREAT|O_WRONLY|O_EXCL, perm);
737 [ + + ]: 146 : if (fd == -1) {
738 [ - + ]: 26 : if (!tried_mkdir) {
739 [ - + ]: 26 : if (!try_mkdir(rootfd, path))
740 : 0 : return (-2);
741 : 26 : tried_mkdir = true;
742 : 26 : goto retry;
743 : : }
744 : 0 : return (-1);
745 : : }
746 : 120 : return (fd);
747 : 120 : }
748 : :
749 : : static int
750 : 120 : create_regfile(struct pkg *pkg, struct pkg_file *f, struct archive *a,
751 : : struct archive_entry *ae, int fromfd, struct pkg *local, tempdirs_t *tempdirs,
752 : : c_charv_t *symlinks_allowed)
753 : : {
754 : 120 : int fd = -1;
755 : : size_t len;
756 : : char buf[32768];
757 : : char *path;
758 : 120 : struct tempdir *tmpdir = NULL;
759 : :
760 : 120 : tmpdir = get_tempdir(pkg->rootfd, f->path, tempdirs, symlinks_allowed);
761 [ + + - + ]: 120 : if (tmpdir == NULL && errno == 0)
762 : 85 : hidden_tempfile(f->temppath, sizeof(f->temppath), f->path);
763 : :
764 [ + + ]: 120 : if (tmpdir != NULL) {
765 : 35 : fd = open_tempfile(tmpdir->fd, f->path + tmpdir->len, f->perm);
766 : 35 : } else {
767 : 85 : fd = open_tempfile(pkg->rootfd, f->temppath, f->perm);
768 : : }
769 [ - + ]: 120 : if (fd == -2) {
770 : 0 : close_tempdir(tmpdir);
771 : 0 : return (EPKG_FATAL);
772 : : }
773 : :
774 [ + - ]: 120 : if (fd == -1) {
775 [ # # ]: 0 : if (tmpdir != NULL) {
776 : 0 : close_tempdir(tmpdir);
777 : 0 : pkg_fatal_errno("Fail to create temporary file '%s/%s' for %s", tmpdir->name, f->path + tmpdir->len, f->path);
778 : 0 : }
779 : 0 : pkg_fatal_errno("Fail to create temporary file for %s", f->path);
780 : 0 : }
781 : :
782 [ + + ]: 120 : if (fromfd == -1) {
783 : : /* check if this is a config file */
784 : 117 : f->config = pkghash_get_value(pkg->config_files_hash, f->path);
785 [ + + ]: 117 : if (f->config) {
786 : : const char *cfdata;
787 : 11 : bool merge = pkg_object_bool(pkg_config_get("AUTOMERGE"));
788 : 11 : const char *merge_tool = pkg_object_string(pkg_config_get("MERGETOOL"));
789 : :
790 : 11 : pkg_debug(1, "Populating config_file %s", f->path);
791 : 11 : len = archive_entry_size(ae);
792 : 11 : f->config->content = xmalloc(len + 1);
793 : 11 : archive_read_data(a, f->config->content, len);
794 : 11 : f->config->content[len] = '\0';
795 : 11 : cfdata = f->config->content;
796 : 11 : attempt_to_merge(pkg->rootfd, f->config, local, merge, merge_tool);
797 [ + + ]: 11 : if (f->config->status == MERGE_SUCCESS)
798 : 4 : cfdata = f->config->newcontent;
799 : 11 : dprintf(fd, "%s", cfdata);
800 [ + + ]: 11 : if (f->config->newcontent != NULL)
801 : 4 : free(f->config->newcontent);
802 : 11 : } else {
803 [ + - ]: 106 : if (ftruncate(fd, archive_entry_size(ae)) == -1) {
804 : 0 : close_tempdir(tmpdir);
805 : 0 : pkg_errno("Fail to truncate file: %s", f->temppath);
806 : 0 : }
807 : : }
808 : :
809 [ + + - + ]: 117 : if (!f->config && archive_read_data_into_fd(a, fd) != ARCHIVE_OK) {
810 : 0 : close_tempdir(tmpdir);
811 : 0 : pkg_emit_error("Fail to extract %s from package: %s",
812 : 0 : f->path, archive_error_string(a));
813 : 0 : return (EPKG_FATAL);
814 : : }
815 : 117 : } else {
816 [ + + ]: 5 : while ((len = read(fromfd, buf, sizeof(buf))) > 0)
817 [ + - ]: 2 : if (write(fd, buf, len) == -1) {
818 : 0 : pkg_errno("Fail to write file: %s", f->temppath);
819 : 0 : }
820 : : }
821 [ + - ]: 120 : if (fd != -1)
822 : 120 : close(fd);
823 [ + + ]: 120 : if (tmpdir == NULL) {
824 : 85 : fd = pkg->rootfd;
825 : 85 : path = f->temppath;
826 : 85 : } else {
827 : 35 : fd = tmpdir->fd;
828 : 35 : path = f->path + tmpdir->len;
829 : : }
830 : :
831 [ - + - + : 360 : if (set_attrsat(fd, path, f->perm, f->uid, f->gid,
- + ]
832 : 240 : &f->time[0], &f->time[1]) != EPKG_OK) {
833 : 0 : close_tempdir(tmpdir);
834 : 0 : return (EPKG_FATAL);
835 : : }
836 [ + + ]: 120 : if (tmpdir != NULL)
837 : 35 : set_chflags(fd, path, f->fflags);
838 : :
839 : 120 : close_tempdir(tmpdir);
840 : 120 : return (EPKG_OK);
841 : 120 : }
842 : :
843 : : static int
844 : 117 : do_extract_regfile(struct pkg *pkg, struct archive *a, struct archive_entry *ae,
845 : : const char *path, struct pkg *local, tempdirs_t *tempdirs, c_charv_t *symlinks_allowed)
846 : : {
847 : : struct pkg_file *f;
848 : : const struct stat *aest;
849 : : unsigned long clear;
850 : :
851 : 117 : f = pkg_get_file(pkg, path);
852 [ + - ]: 117 : if (f == NULL) {
853 : 0 : pkg_emit_error("File %s not specified in the manifest", path);
854 : 0 : return (EPKG_FATAL);
855 : : }
856 : :
857 : 117 : aest = archive_entry_stat(ae);
858 : 117 : archive_entry_fflags(ae, &f->fflags, &clear);
859 : 117 : f->perm = aest->st_mode;
860 : 117 : f->uid = get_uid_from_archive(ae);
861 : 117 : f->gid = get_gid_from_archive(ae);
862 : 117 : fill_timespec_buf(aest, f->time);
863 : 117 : archive_entry_fflags(ae, &f->fflags, &clear);
864 : :
865 [ - + ]: 117 : if (create_regfile(pkg, f, a, ae, -1, local, tempdirs, symlinks_allowed) == EPKG_FATAL)
866 : 0 : return (EPKG_FATAL);
867 : :
868 : 234 : metalog_add(PKG_METALOG_FILE, RELATIVE_PATH(path),
869 : 117 : archive_entry_uname(ae), archive_entry_gname(ae),
870 : 117 : aest->st_mode & ~S_IFREG, f->fflags, NULL);
871 : :
872 : 117 : return (EPKG_OK);
873 : 117 : }
874 : :
875 : : static int
876 : 110 : do_extract(struct archive *a, struct archive_entry *ae,
877 : : int nfiles, struct pkg *pkg, struct pkg *local, tempdirs_t *tempdirs,
878 : : c_charv_t *symlinks_allowed)
879 : : {
880 : 110 : int retcode = EPKG_OK;
881 : 110 : int ret = 0, cur_file = 0;
882 : : char path[MAXPATHLEN];
883 : : int (*extract_cb)(struct pkg *pkg, struct archive *a,
884 : : struct archive_entry *ae, const char *path, struct pkg *local,
885 : : tempdirs_t *tempdirs, c_charv_t *sa);
886 : :
887 : : #ifndef HAVE_ARC4RANDOM
888 : : srand(time(NULL));
889 : : #endif
890 : :
891 [ + - ]: 110 : if (nfiles == 0)
892 : 0 : return (EPKG_OK);
893 : :
894 : 110 : pkg_emit_extract_begin(pkg);
895 : 110 : pkg_emit_progress_start(NULL);
896 : :
897 : 137 : do {
898 : 137 : pkg_absolutepath(archive_entry_pathname(ae), path, sizeof(path), true);
899 [ - + - + ]: 274 : if (match_ucl_lists(path,
900 : 137 : pkg_config_get("FILES_IGNORE_GLOB"),
901 : 137 : pkg_config_get("FILES_IGNORE_REGEX")))
902 : 0 : continue;
903 [ - - + + : 137 : switch (archive_entry_filetype(ae)) {
+ + - - -
- ]
904 : : case AE_IFDIR:
905 : 6 : extract_cb = do_extract_dir;
906 : 6 : break;
907 : : case AE_IFLNK:
908 : 10 : extract_cb = do_extract_symlink;
909 : 10 : break;
910 : : case 0: /* HARDLINKS */
911 : 4 : extract_cb = do_extract_hardlink;
912 : 4 : break;
913 : : case AE_IFREG:
914 : 117 : extract_cb = do_extract_regfile;
915 : 117 : break;
916 : : case AE_IFMT:
917 : 0 : pkg_emit_error("Archive contains an unsupported filetype (AE_IFMT): %s", path);
918 : 0 : retcode = EPKG_FATAL;
919 : 0 : goto cleanup;
920 : : break;
921 : : case AE_IFSOCK:
922 : 0 : pkg_emit_error("Archive contains an unsupported filetype (AE_IFSOCK): %s", path);
923 : 0 : retcode = EPKG_FATAL;
924 : 0 : goto cleanup;
925 : : break;
926 : : case AE_IFCHR:
927 : 0 : pkg_emit_error("Archive contains an unsupported filetype (AE_IFCHR): %s", path);
928 : 0 : retcode = EPKG_FATAL;
929 : 0 : goto cleanup;
930 : : break;
931 : : case AE_IFIFO:
932 : 0 : pkg_emit_error("Archive contains an unsupported filetype (AE_IFIFO): %s", path);
933 : 0 : retcode = EPKG_FATAL;
934 : 0 : goto cleanup;
935 : : break;
936 : : case AE_IFBLK:
937 : 0 : pkg_emit_error("Archive contains an unsupported filetype (AE_IFBLK): %s", path);
938 : 0 : retcode = EPKG_FATAL;
939 : 0 : goto cleanup;
940 : : break;
941 : : default:
942 : 0 : pkg_emit_error("Archive contains an unsupported filetype (%d): %s", archive_entry_filetype(ae), path);
943 : 0 : retcode = EPKG_FATAL;
944 : 0 : goto cleanup;
945 : : break;
946 : : }
947 : :
948 [ + - ]: 137 : if (extract_cb(pkg, a, ae, path, local, tempdirs, symlinks_allowed) != EPKG_OK) {
949 : 0 : retcode = EPKG_FATAL;
950 : 0 : goto cleanup;
951 : : }
952 [ + + ]: 137 : if (archive_entry_filetype(ae) != AE_IFDIR) {
953 : 131 : pkg_emit_progress_tick(cur_file++, nfiles);
954 : 131 : }
955 [ + + ]: 137 : } while ((ret = archive_read_next_header(a, &ae)) == ARCHIVE_OK);
956 : 110 : pkg_emit_progress_tick(cur_file++, nfiles);
957 : :
958 [ + - ]: 110 : if (ret != ARCHIVE_EOF) {
959 : 0 : pkg_emit_error("archive_read_next_header(): %s",
960 : 0 : archive_error_string(a));
961 : 0 : retcode = EPKG_FATAL;
962 : 0 : }
963 : :
964 : : cleanup:
965 : 110 : pkg_emit_progress_tick(nfiles, nfiles);
966 : 110 : pkg_emit_extract_finished(pkg);
967 : :
968 : 110 : return (retcode);
969 : 110 : }
970 : :
971 : : static void
972 : 44 : backup_file_if_needed(struct pkg *p, struct pkg_file *f)
973 : : {
974 : : char path[MAXPATHLEN];
975 : : struct stat st;
976 : : char *sum;
977 : : pkg_checksum_type_t t;
978 : :
979 [ + - + - ]: 88 : if (fstatat(p->rootfd, RELATIVE_PATH(f->path), &st,
980 : 44 : AT_SYMLINK_NOFOLLOW) == -1)
981 : 0 : return;
982 : :
983 [ - + ]: 44 : if (S_ISLNK(st.st_mode))
984 : 0 : return;
985 : :
986 [ + + ]: 44 : if (S_ISREG(st.st_mode)) {
987 : 43 : t = pkg_checksum_file_get_type(f->sum, -1);
988 : 86 : sum = pkg_checksum_generate_fileat(p->rootfd,
989 : 43 : RELATIVE_PATH(f->path), t);
990 [ + - ]: 43 : if (sum == NULL)
991 : 0 : return;
992 : :
993 [ + + ]: 43 : if (STREQ(sum, f->sum)) {
994 : 41 : free(sum);
995 : 41 : return;
996 : : }
997 : 2 : free(sum);
998 : 2 : }
999 : :
1000 : 3 : snprintf(path, sizeof(path), "%s.pkgsave", f->path);
1001 : 6 : renameat(p->rootfd, RELATIVE_PATH(f->path),
1002 : 3 : p->rootfd, RELATIVE_PATH(path));
1003 : 44 : }
1004 : :
1005 : : static int
1006 : 171 : pkg_extract_finalize(struct pkg *pkg, tempdirs_t *tempdirs)
1007 : : {
1008 : : struct stat st;
1009 : 171 : struct pkg_file *f = NULL;
1010 : 171 : struct pkg_dir *d = NULL;
1011 : : char path[MAXPATHLEN + 8];
1012 : : const char *fto;
1013 : : #ifdef HAVE_CHFLAGSAT
1014 : : bool install_as_user;
1015 : :
1016 : 171 : install_as_user = (getenv("INSTALL_AS_USER") != NULL);
1017 : : #endif
1018 : :
1019 : :
1020 [ - + ]: 171 : if (tempdirs != NULL) {
1021 [ + + ]: 203 : for (size_t i = 0; i < tempdirs->len; i++) {
1022 : 32 : struct tempdir *t = tempdirs->d[i];
1023 [ - + - + : 96 : if (renameat(pkg->rootfd, RELATIVE_PATH(t->temp),
- + ]
1024 : 64 : pkg->rootfd, RELATIVE_PATH(t->name)) != 0) {
1025 : 0 : pkg_fatal_errno("Fail to rename %s -> %s",
1026 : : t->temp, t->name);
1027 : 0 : }
1028 : 32 : free(t);
1029 : 32 : }
1030 : 171 : }
1031 [ + + ]: 309 : while (pkg_files(pkg, &f) == EPKG_OK) {
1032 : :
1033 [ - + - + ]: 276 : if (match_ucl_lists(f->path,
1034 : 138 : pkg_config_get("FILES_IGNORE_GLOB"),
1035 : 138 : pkg_config_get("FILES_IGNORE_REGEX")))
1036 : 0 : continue;
1037 : 138 : append_touched_file(f->path);
1038 [ + + ]: 138 : if (*f->temppath == '\0')
1039 : 48 : continue;
1040 : 90 : fto = f->path;
1041 [ + + + + : 90 : if (f->config && f->config->status == MERGE_FAILED &&
+ + ]
1042 : 2 : f->previous != PKG_FILE_NONE) {
1043 : 1 : snprintf(path, sizeof(path), "%s.pkgnew", f->path);
1044 : 1 : fto = path;
1045 : 1 : }
1046 : :
1047 [ + + + + ]: 90 : if (f->config && f->config->status == MERGE_NOT_LOCAL) {
1048 : 1 : backup_file_if_needed(pkg, f);
1049 : 1 : }
1050 : :
1051 : : /*
1052 : : * enforce an unlink of the file to workaround a bug that
1053 : : * results in renameat returning 0 of the from file is hardlink
1054 : : * on the to file, but the to file is not removed
1055 : : */
1056 [ + + + + ]: 90 : if (f->previous != PKG_FILE_NONE &&
1057 : 60 : fstatat(pkg->rootfd, RELATIVE_PATH(fto), &st,
1058 : 60 : AT_SYMLINK_NOFOLLOW) != -1) {
1059 : : #ifdef HAVE_CHFLAGSAT
1060 [ - + # # ]: 58 : if (!install_as_user && st.st_flags & NOCHANGESFLAGS) {
1061 : 0 : chflagsat(pkg->rootfd, RELATIVE_PATH(fto), 0,
1062 : : AT_SYMLINK_NOFOLLOW);
1063 : 0 : }
1064 : : #endif
1065 : : /* if the files does not belong to any package, we do save it */
1066 [ + + ]: 58 : if (f->previous == PKG_FILE_SAVE) {
1067 : 43 : backup_file_if_needed(pkg, f);
1068 : 43 : }
1069 : 58 : unlinkat(pkg->rootfd, RELATIVE_PATH(fto), 0);
1070 : 58 : }
1071 [ + - + - : 270 : if (renameat(pkg->rootfd, RELATIVE_PATH(f->temppath),
+ - ]
1072 : 180 : pkg->rootfd, RELATIVE_PATH(fto)) == -1) {
1073 : 0 : pkg_fatal_errno("Fail to rename %s -> %s",
1074 : : f->temppath, fto);
1075 : 0 : }
1076 : :
1077 [ + - ]: 90 : if (set_chflags(pkg->rootfd, fto, f->fflags) != EPKG_OK)
1078 : 0 : return (EPKG_FATAL);
1079 : : }
1080 : :
1081 [ + + ]: 177 : while (pkg_dirs(pkg, &d) == EPKG_OK) {
1082 : 6 : append_touched_dir(d->path);
1083 [ + + ]: 6 : if (d->noattrs)
1084 : 3 : continue;
1085 [ + - + - : 9 : if (set_attrsat(pkg->rootfd, d->path, d->perm,
+ - ]
1086 : 6 : d->uid, d->gid, &d->time[0], &d->time[1]) != EPKG_OK)
1087 : 0 : return (EPKG_FATAL);
1088 [ + - ]: 3 : if (set_chflags(pkg->rootfd, d->path, d->fflags) != EPKG_OK)
1089 : 0 : return (EPKG_FATAL);
1090 : : }
1091 [ - + ]: 171 : if (tempdirs != NULL)
1092 : 171 : pkgvec_free(tempdirs);
1093 : :
1094 : 171 : return (EPKG_OK);
1095 : 171 : }
1096 : :
1097 : : static char *
1098 : 6 : pkg_globmatch(char *pattern, const char *name)
1099 : : {
1100 : : glob_t g;
1101 : : int i;
1102 : : char *buf, *buf2;
1103 : 6 : char *path = NULL;
1104 : :
1105 [ + + ]: 6 : if (glob(pattern, 0, NULL, &g) == GLOB_NOMATCH) {
1106 : 3 : globfree(&g);
1107 : :
1108 : 3 : return (NULL);
1109 : : }
1110 : :
1111 [ + + ]: 6 : for (i = 0; i < g.gl_pathc; i++) {
1112 : : /* the version starts here */
1113 : 3 : buf = strrchr(g.gl_pathv[i], '-');
1114 [ + - ]: 3 : if (buf == NULL)
1115 : 0 : continue;
1116 : 3 : buf2 = strrchr(g.gl_pathv[i], '/');
1117 [ + - ]: 3 : if (buf2 == NULL)
1118 : 0 : buf2 = g.gl_pathv[i];
1119 : : else
1120 : 3 : buf2++;
1121 : : /* ensure we have match the proper name */
1122 [ - + ]: 3 : if (strncmp(buf2, name, buf - buf2) != 0)
1123 : 0 : continue;
1124 [ - + ]: 3 : if (path == NULL) {
1125 : 3 : path = g.gl_pathv[i];
1126 : 3 : continue;
1127 : : }
1128 [ # # ]: 0 : if (pkg_version_cmp(path, g.gl_pathv[i]) == 1)
1129 : 0 : path = g.gl_pathv[i];
1130 : 0 : }
1131 [ - + ]: 3 : if (path)
1132 : 3 : path = xstrdup(path);
1133 : 3 : globfree(&g);
1134 : :
1135 : 3 : return (path);
1136 : 6 : }
1137 : :
1138 : : static int
1139 : 17 : pkg_add_check_pkg_archive(struct pkgdb *db, struct pkg *pkg,
1140 : : const char *path, int flags, const char *location)
1141 : : {
1142 : : const char *arch;
1143 : : int ret, retcode;
1144 : 17 : struct pkg_dep *dep = NULL;
1145 : : char bd[MAXPATHLEN];
1146 : : char dpath[MAXPATHLEN], *ppath;
1147 : 17 : const char *ext = NULL;
1148 : 17 : struct pkg *pkg_inst = NULL;
1149 : : bool fromstdin;
1150 : :
1151 [ + - ]: 17 : arch = pkg->abi != NULL ? pkg->abi : pkg->altabi;
1152 : :
1153 [ - + # # ]: 17 : if (!is_valid_abi(arch, true) && (flags & PKG_ADD_FORCE) == 0) {
1154 : 0 : return (EPKG_FATAL);
1155 : : }
1156 : :
1157 [ - + # # ]: 17 : if (!is_valid_os_version(pkg) && (flags & PKG_ADD_FORCE) == 0) {
1158 : 0 : return (EPKG_FATAL);
1159 : : }
1160 : :
1161 : : /* XX check */
1162 : 17 : ret = pkg_try_installed(db, pkg->name, &pkg_inst, PKG_LOAD_BASIC);
1163 [ + - ]: 17 : if (ret == EPKG_OK) {
1164 [ # # ]: 0 : if ((flags & PKG_ADD_FORCE) == 0) {
1165 : 0 : pkg_emit_already_installed(pkg_inst);
1166 : 0 : pkg_free(pkg_inst);
1167 : 0 : pkg_inst = NULL;
1168 : 0 : return (EPKG_INSTALLED);
1169 : : }
1170 [ # # ]: 0 : if (pkg_inst->locked) {
1171 : 0 : pkg_emit_locked(pkg_inst);
1172 : 0 : pkg_free(pkg_inst);
1173 : 0 : pkg_inst = NULL;
1174 : 0 : return (EPKG_LOCKED);
1175 : : }
1176 : 0 : pkg_emit_notice("package %s is already installed, forced "
1177 : 0 : "install", pkg->name);
1178 : 0 : pkg_free(pkg_inst);
1179 : 0 : pkg_inst = NULL;
1180 [ - + ]: 17 : } else if (ret != EPKG_END) {
1181 : 0 : return (ret);
1182 : : }
1183 : :
1184 : : /*
1185 : : * Check for dependencies by searching the same directory as
1186 : : * the package archive we're reading. Of course, if we're
1187 : : * reading from a file descriptor or a unix domain socket or
1188 : : * whatever, there's no valid directory to search.
1189 : : */
1190 : 17 : fromstdin = STREQ(path, "-");
1191 : 17 : strlcpy(bd, path, sizeof(bd));
1192 [ + + ]: 17 : if (!fromstdin) {
1193 : : /* In-place truncate bd to the directory components. */
1194 : 14 : char *basedir = strrchr(bd, '/');
1195 [ + + ]: 14 : if (NULL == basedir) {
1196 : 9 : bd[0]='.';
1197 : 9 : bd[1]='\0';
1198 : 9 : } else {
1199 : 5 : *basedir = '\0';
1200 : : }
1201 [ - + ]: 14 : if ((ext = strrchr(path, '.')) == NULL) {
1202 : 0 : pkg_emit_error("%s has no extension", path);
1203 : 0 : return (EPKG_FATAL);
1204 : : }
1205 : 14 : }
1206 : :
1207 : 17 : retcode = EPKG_FATAL;
1208 : 17 : pkg_emit_add_deps_begin(pkg);
1209 : :
1210 [ + + ]: 23 : while (pkg_deps(pkg, &dep) == EPKG_OK) {
1211 : 9 : dpath[0] = '\0';
1212 : :
1213 [ + - ]: 9 : if (pkg_is_installed(db, dep->name) == EPKG_OK)
1214 : 0 : continue;
1215 : :
1216 [ + + ]: 9 : if (fromstdin) {
1217 : 2 : pkg_emit_missing_dep(pkg, dep);
1218 [ + + ]: 2 : if ((flags & PKG_ADD_FORCE_MISSING) == 0)
1219 : 1 : goto cleanup;
1220 : 1 : continue;
1221 : : }
1222 : :
1223 [ + + - + ]: 7 : if (dep->version != NULL && dep->version[0] != '\0') {
1224 : 8 : snprintf(dpath, sizeof(dpath), "%s/%s-%s%s", bd,
1225 : 4 : dep->name, dep->version, ext);
1226 : 4 : }
1227 : :
1228 [ + + + + ]: 7 : if (strlen(dpath) == 0 || access(dpath, F_OK) != 0) {
1229 : 12 : snprintf(dpath, sizeof(dpath), "%s/%s-*%s", bd,
1230 : 6 : dep->name, ext);
1231 : 6 : ppath = pkg_globmatch(dpath, dep->name);
1232 [ + + ]: 6 : if (ppath == NULL) {
1233 : 3 : pkg_emit_missing_dep(pkg, dep);
1234 [ + + ]: 3 : if ((flags & PKG_ADD_FORCE_MISSING) == 0)
1235 : 2 : goto cleanup;
1236 : 1 : continue;
1237 : : }
1238 : 3 : strlcpy(dpath, ppath, sizeof(dpath));
1239 : 3 : free(ppath);
1240 : 3 : }
1241 : :
1242 [ + - - + ]: 4 : if ((flags & PKG_ADD_UPGRADE) == 0 &&
1243 : 4 : access(dpath, F_OK) == 0) {
1244 : 4 : ret = pkg_add(db, dpath, PKG_ADD_AUTOMATIC, location);
1245 : :
1246 [ + - ]: 4 : if (ret != EPKG_OK)
1247 : 0 : goto cleanup;
1248 : 4 : } else {
1249 : 0 : pkg_emit_missing_dep(pkg, dep);
1250 [ # # ]: 0 : if ((flags & PKG_ADD_FORCE_MISSING) == 0)
1251 : 0 : goto cleanup;
1252 : : }
1253 : : }
1254 : :
1255 : 14 : retcode = EPKG_OK;
1256 : : cleanup:
1257 : 17 : pkg_emit_add_deps_finished(pkg);
1258 : :
1259 : 17 : return (retcode);
1260 : 17 : }
1261 : :
1262 : : static int
1263 : 33 : pkg_add_cleanup_old(struct pkgdb *db, struct pkg *old, struct pkg *new, struct triggers *t, int flags)
1264 : : {
1265 : : struct pkg_file *f;
1266 : 33 : int ret = EPKG_OK;
1267 : :
1268 : 33 : pkg_start_stop_rc_scripts(old, PKG_RC_STOP);
1269 : :
1270 : : /*
1271 : : * Execute pre deinstall scripts
1272 : : */
1273 [ - + ]: 33 : if ((flags & PKG_ADD_NOSCRIPT) == 0) {
1274 : 33 : ret = pkg_lua_script_run(old, PKG_LUA_PRE_DEINSTALL, (old != NULL));
1275 [ - + # # ]: 33 : if (ret != EPKG_OK && ctx.developer_mode) {
1276 : 0 : return (ret);
1277 : : } else {
1278 : 33 : ret = pkg_script_run(old, PKG_SCRIPT_PRE_DEINSTALL, (old != NULL));
1279 [ - + # # ]: 33 : if (ret != EPKG_OK && ctx.developer_mode) {
1280 : 0 : return (ret);
1281 : : } else {
1282 : 33 : ret = EPKG_OK;
1283 : : }
1284 : : }
1285 : 33 : }
1286 : :
1287 : : /* Now remove files that no longer exist in the new package */
1288 [ + - ]: 33 : if (new != NULL) {
1289 : 33 : f = NULL;
1290 [ + + ]: 57 : while (pkg_files(old, &f) == EPKG_OK) {
1291 [ + + - + : 24 : if (!pkg_has_file(new, f->path) || match_ucl_lists(f->path,
- + ]
1292 : 16 : pkg_config_get("FILES_IGNORE_GLOB"),
1293 : 16 : pkg_config_get("FILES_IGNORE_REGEX"))) {
1294 : 8 : pkg_debug(2, "File %s is not in the new package", f->path);
1295 [ + + ]: 8 : if (ctx.backup_libraries) {
1296 : : const char *libname;
1297 : 3 : libname = strrchr(f->path, '/');
1298 [ + - + + ]: 3 : if (libname != NULL &&
1299 : 3 : stringlist_contains(&old->shlibs_provided, libname+1)) {
1300 : 2 : backup_library(db, old, f->path);
1301 : 2 : }
1302 : 3 : }
1303 : :
1304 : 8 : trigger_is_it_a_cleanup(t, f->path);
1305 : 8 : pkg_delete_file(old, f);
1306 : 8 : }
1307 : : }
1308 : :
1309 : 33 : pkg_delete_dirs(db, old, new);
1310 : 33 : }
1311 : :
1312 : 33 : return (ret);
1313 : 33 : }
1314 : :
1315 : : void
1316 : 0 : pkg_rollback_pkg(struct pkg *p)
1317 : : {
1318 : 0 : struct pkg_file *f = NULL;
1319 : :
1320 [ # # ]: 0 : while (pkg_files(p, &f) == EPKG_OK) {
1321 [ # # # # ]: 0 : if (match_ucl_lists(f->path,
1322 : 0 : pkg_config_get("FILES_IGNORE_GLOB"),
1323 : 0 : pkg_config_get("FILES_IGNORE_REGEX")))
1324 : 0 : continue;
1325 [ # # ]: 0 : if (*f->temppath != '\0') {
1326 : 0 : unlinkat(p->rootfd, f->temppath, 0);
1327 : 0 : }
1328 : : }
1329 : 0 : }
1330 : :
1331 : : void
1332 : 0 : pkg_rollback_cb(void *data)
1333 : : {
1334 : 0 : pkg_rollback_pkg((struct pkg *)data);
1335 : 0 : }
1336 : :
1337 : : int
1338 : 13 : pkg_add_triggers(void)
1339 : : {
1340 : 13 : return (triggers_execute(NULL));
1341 : : }
1342 : :
1343 : : static int
1344 : 172 : pkg_add_common(struct pkgdb *db, const char *path, unsigned flags,
1345 : : const char *reloc, struct pkg *remote,
1346 : : struct pkg *local, struct triggers *t)
1347 : : {
1348 : : struct archive *a;
1349 : : struct archive_entry *ae;
1350 : 172 : struct pkg *pkg = NULL;
1351 : 172 : xstring *message = NULL;
1352 : : struct pkg_message *msg;
1353 : : struct pkg_file *f;
1354 : : const char *msgstr;
1355 : 172 : bool extract = true, openxact = false;
1356 : 172 : int retcode = EPKG_OK;
1357 : : int ret;
1358 : : int nfiles;
1359 : : tempdirs_t tempdirs;
1360 : : c_charv_t symlinks_allowed;
1361 : :
1362 [ + - ]: 172 : assert(path != NULL);
1363 : :
1364 : 172 : pkgvec_init(&tempdirs);
1365 : 172 : pkgvec_init(&symlinks_allowed);
1366 : :
1367 : : /*
1368 : : * Open the package archive file, read all the meta files and set the
1369 : : * current archive_entry to the first non-meta file.
1370 : : * If there is no non-meta files, EPKG_END is returned.
1371 : : */
1372 : 172 : ret = pkg_open2(&pkg, &a, &ae, path, 0, -1);
1373 [ + + ]: 172 : if (ret == EPKG_END)
1374 : 60 : extract = false;
1375 [ - + ]: 112 : else if (ret != EPKG_OK) {
1376 : 0 : retcode = ret;
1377 : 0 : goto cleanup;
1378 : : }
1379 [ + + ]: 172 : if ((flags & PKG_ADD_SPLITTED_UPGRADE) == 0)
1380 : 163 : pkg_emit_new_action();
1381 [ + + ]: 172 : if ((flags & (PKG_ADD_UPGRADE | PKG_ADD_SPLITTED_UPGRADE)) !=
1382 : : PKG_ADD_UPGRADE)
1383 : 139 : pkg_emit_install_begin(pkg);
1384 : : else
1385 : 33 : pkg_emit_upgrade_begin(pkg, local);
1386 : :
1387 [ - + ]: 172 : if (pkg_is_valid(pkg) != EPKG_OK) {
1388 : 0 : pkg_emit_error("the package is not valid");
1389 : 0 : return (EPKG_FATAL);
1390 : : }
1391 : :
1392 [ + + ]: 172 : if (flags & PKG_ADD_AUTOMATIC)
1393 : 34 : pkg->automatic = true;
1394 : :
1395 : : /*
1396 : : * Additional checks for non-remote package
1397 : : */
1398 [ + + ]: 172 : if (remote == NULL) {
1399 : 17 : ret = pkg_add_check_pkg_archive(db, pkg, path, flags, reloc);
1400 [ + + ]: 17 : if (ret != EPKG_OK) {
1401 : : /* Do not return error on installed package */
1402 [ - + ]: 3 : retcode = (ret == EPKG_INSTALLED ? EPKG_OK : ret);
1403 : 3 : goto cleanup;
1404 : : }
1405 : 14 : }
1406 : : else {
1407 [ + + ]: 155 : if (remote->repo != NULL) {
1408 : : /* Save reponame */
1409 : 93 : pkg_kv_add(&pkg->annotations, "repository", remote->repo->name, "annotation");
1410 : 93 : pkg_kv_add(&pkg->annotations, "repo_type", remote->repo->ops->type, "annotation");
1411 : 93 : }
1412 : :
1413 : 155 : free(pkg->digest);
1414 : 155 : pkg->digest = xstrdup(remote->digest);
1415 : : /* only preserve flags if -A has not been passed */
1416 [ + + ]: 155 : if ((flags & PKG_ADD_AUTOMATIC) == 0)
1417 : 126 : pkg->automatic = remote->automatic;
1418 : : }
1419 : :
1420 [ + - ]: 169 : if (reloc != NULL)
1421 : 0 : pkg_kv_add(&pkg->annotations, "relocated", reloc, "annotation");
1422 : :
1423 : 169 : pkg_open_root_fd(pkg);
1424 : : /* analyse previous files */
1425 : 169 : f = NULL;
1426 [ + + ]: 300 : while (pkg_files(pkg, &f) == EPKG_OK) {
1427 [ - + - + ]: 262 : if (match_ucl_lists(f->path,
1428 : 131 : pkg_config_get("FILES_IGNORE_GLOB"),
1429 : 131 : pkg_config_get("FILES_IGNORE_REGEX"))) {
1430 : 0 : continue;
1431 : : }
1432 [ + + ]: 131 : if (faccessat(pkg->rootfd, RELATIVE_PATH(f->path), F_OK, 0) == 0) {
1433 : 61 : f->previous = PKG_FILE_EXIST;
1434 [ + + ]: 61 : if (!pkgdb_file_exists(db, f->path)) {
1435 : 45 : f->previous = PKG_FILE_SAVE;
1436 : 45 : }
1437 : 61 : }
1438 : : }
1439 : :
1440 : : /*
1441 : : * Register the package before installing it in case there are problems
1442 : : * that could be caught here.
1443 : : */
1444 : 169 : retcode = pkgdb_register_pkg(db, pkg, flags & PKG_ADD_FORCE, NULL);
1445 [ - + ]: 169 : if (retcode != EPKG_OK)
1446 : 0 : goto cleanup;
1447 : 169 : openxact = true;
1448 : :
1449 : : /*
1450 : : * Execute pre-install scripts
1451 : : */
1452 [ + + ]: 169 : if ((flags & PKG_ADD_NOSCRIPT) == 0) {
1453 [ - + ]: 168 : if ((retcode = pkg_lua_script_run(pkg, PKG_LUA_PRE_INSTALL, (local != NULL))) != EPKG_OK)
1454 : 0 : goto cleanup;
1455 [ + + ]: 168 : if ((retcode = pkg_script_run(pkg, PKG_SCRIPT_PRE_INSTALL, (local != NULL))) != EPKG_OK)
1456 : 1 : goto cleanup;
1457 : 167 : }
1458 : :
1459 : :
1460 : : /* add the user and group if necessary */
1461 : :
1462 : 168 : nfiles = pkghash_count(pkg->filehash) + pkghash_count(pkg->dirhash);
1463 : : /*
1464 : : * Extract the files on disk.
1465 : : */
1466 [ + + ]: 168 : if (extract) {
1467 : 110 : pkg_register_cleanup_callback(pkg_rollback_cb, pkg);
1468 [ - + - + : 110 : pkgvec_push(&symlinks_allowed, pkg->prefix);
+ - ]
1469 : 110 : retcode = do_extract(a, ae, nfiles, pkg, local, &tempdirs, &symlinks_allowed);
1470 : 110 : pkg_unregister_cleanup_callback(pkg_rollback_cb, pkg);
1471 [ - + ]: 110 : if (retcode != EPKG_OK) {
1472 : : /* If the add failed, clean up (silently) */
1473 : 0 : pkg_rollback_pkg(pkg);
1474 : 0 : pkg_delete_dirs(db, pkg, NULL);
1475 : 0 : goto cleanup;
1476 : : }
1477 : 110 : }
1478 : :
1479 : : /*
1480 : : * If this was a split upgrade, the old package has been entirely
1481 : : * removed already.
1482 : : */
1483 [ + + + + ]: 168 : if (local != NULL && (flags & PKG_ADD_SPLITTED_UPGRADE) == 0) {
1484 : 33 : pkg_open_root_fd(local);
1485 : 33 : pkg_debug(1, "Cleaning up old version");
1486 [ - + ]: 33 : if (pkg_add_cleanup_old(db, local, pkg, t, flags) != EPKG_OK) {
1487 : 0 : retcode = EPKG_FATAL;
1488 : 0 : goto cleanup;
1489 : : }
1490 : 33 : }
1491 : :
1492 : :
1493 : : /* Update configuration file content with db with newer versions */
1494 : 168 : pkgdb_update_config_file_content(pkg, db->sqlite);
1495 : :
1496 : 168 : retcode = pkg_extract_finalize(pkg, &tempdirs);
1497 : :
1498 : 168 : pkgdb_register_finale(db, retcode, NULL);
1499 : 168 : openxact = false;
1500 : :
1501 : : /*
1502 : : * Execute post install scripts
1503 : : */
1504 : :
1505 [ - + ]: 168 : if (retcode != EPKG_OK)
1506 : 0 : goto cleanup;
1507 [ + + ]: 168 : if ((flags & PKG_ADD_NOSCRIPT) == 0) {
1508 : 167 : pkg_lua_script_run(pkg, PKG_LUA_POST_INSTALL, (local != NULL));
1509 : 167 : pkg_script_run(pkg, PKG_SCRIPT_POST_INSTALL, (local != NULL));
1510 : 167 : }
1511 : :
1512 : : /*
1513 : : * start the different related services if the users do want that
1514 : : * and that the service is running
1515 : : */
1516 : :
1517 : 168 : pkg_start_stop_rc_scripts(pkg, PKG_RC_START);
1518 : :
1519 [ + + ]: 168 : if ((flags & (PKG_ADD_UPGRADE | PKG_ADD_SPLITTED_UPGRADE)) !=
1520 : : PKG_ADD_UPGRADE)
1521 : 135 : pkg_emit_install_finished(pkg, local);
1522 : : else
1523 : 33 : pkg_emit_upgrade_finished(pkg, local);
1524 : :
1525 [ + + + + : 189 : tll_foreach(pkg->message, m) {
+ + ]
1526 : 21 : msg = m->item;
1527 : 21 : msgstr = NULL;
1528 [ + + ]: 21 : if (msg->type == PKG_MESSAGE_ALWAYS) {
1529 : 3 : msgstr = msg->str;
1530 [ + - + + ]: 21 : } else if (local != NULL &&
1531 : 18 : msg->type == PKG_MESSAGE_UPGRADE) {
1532 [ + + + + ]: 12 : if (msg->maximum_version == NULL &&
1533 : 6 : msg->minimum_version == NULL) {
1534 : 3 : msgstr = msg->str;
1535 [ + + ]: 12 : } else if (msg->maximum_version == NULL) {
1536 [ + + ]: 3 : if (pkg_version_cmp(local->version, msg->minimum_version) == 1) {
1537 : 2 : msgstr = msg->str;
1538 : 2 : }
1539 [ + + ]: 9 : } else if (msg->minimum_version == NULL) {
1540 [ + + ]: 3 : if (pkg_version_cmp(local->version, msg->maximum_version) == -1) {
1541 : 1 : msgstr = msg->str;
1542 : 1 : }
1543 [ + + + + ]: 6 : } else if (pkg_version_cmp(local->version, msg->maximum_version) == -1 &&
1544 : 2 : pkg_version_cmp(local->version, msg->minimum_version) == 1) {
1545 : 1 : msgstr = msg->str;
1546 : 1 : }
1547 [ - + # # ]: 18 : } else if (local == NULL &&
1548 : 0 : msg->type == PKG_MESSAGE_INSTALL) {
1549 : 0 : msgstr = msg->str;
1550 : 0 : }
1551 [ + + ]: 21 : if (msgstr != NULL) {
1552 [ + + ]: 10 : if (message == NULL) {
1553 : 3 : message = xstring_new();
1554 : 6 : pkg_fprintf(message->fp, "=====\nMessage from "
1555 : 3 : "%n-%v:\n\n", pkg, pkg);
1556 : 3 : }
1557 : 10 : fprintf(message->fp, "--\n%s\n", msgstr);
1558 : 10 : }
1559 : 21 : }
1560 [ + + - + ]: 171 : if (pkg_has_message(pkg) && message != NULL) {
1561 : 3 : fflush(message->fp);
1562 : 3 : pkg_emit_message(message->buf);
1563 : 3 : xstring_free(message);
1564 : 3 : }
1565 : :
1566 : : cleanup:
1567 : 172 : pkgvec_free(&symlinks_allowed);
1568 : :
1569 [ + + ]: 172 : if (openxact)
1570 : 1 : pkgdb_register_finale(db, retcode, NULL);
1571 [ - + ]: 172 : if (a != NULL) {
1572 : 172 : archive_read_close(a);
1573 : 172 : archive_read_free(a);
1574 : 172 : }
1575 : :
1576 : 172 : pkg_free(pkg);
1577 : :
1578 : 172 : return (retcode);
1579 : 172 : }
1580 : :
1581 : : int
1582 : 17 : pkg_add(struct pkgdb *db, const char *path, unsigned flags,
1583 : : const char *location)
1584 : : {
1585 : 17 : return pkg_add_common(db, path, flags, location, NULL, NULL, NULL);
1586 : : }
1587 : :
1588 : : int
1589 : 113 : pkg_add_from_remote(struct pkgdb *db, const char *path, unsigned flags,
1590 : : const char *location, struct pkg *rp, struct triggers *t)
1591 : : {
1592 : 113 : return pkg_add_common(db, path, flags, location, rp, NULL, t);
1593 : : }
1594 : :
1595 : : int
1596 : 42 : pkg_add_upgrade(struct pkgdb *db, const char *path, unsigned flags,
1597 : : const char *location,
1598 : : struct pkg *rp, struct pkg *lp, struct triggers *t)
1599 : : {
1600 [ - + - + ]: 84 : if (pkgdb_ensure_loaded(db, lp,
1601 : 42 : PKG_LOAD_FILES|PKG_LOAD_SCRIPTS|PKG_LOAD_DIRS|PKG_LOAD_LUA_SCRIPTS) != EPKG_OK)
1602 : 0 : return (EPKG_FATAL);
1603 : :
1604 : 42 : return pkg_add_common(db, path, flags, location, rp, lp, t);
1605 : 42 : }
1606 : :
1607 : : static int
1608 : 0 : pkg_group_dump(int fd, struct pkg *pkg)
1609 : : {
1610 : : ucl_object_t *o, *seq;
1611 : 0 : struct pkg_dep *dep = NULL;
1612 : :
1613 [ # # ]: 0 : if (pkg->type != PKG_GROUP_REMOTE)
1614 : 0 : return (EPKG_FATAL);
1615 : 0 : o = ucl_object_typed_new(UCL_OBJECT);
1616 : 0 : ucl_object_insert_key(o, ucl_object_fromstring(pkg->name), "name", 0, false);
1617 : 0 : ucl_object_insert_key(o, ucl_object_fromstring(pkg->comment), "comment", 0, false);
1618 : 0 : seq = ucl_object_typed_new(UCL_ARRAY);
1619 [ # # ]: 0 : while (pkg_deps(pkg, &dep) == EPKG_OK)
1620 : 0 : ucl_array_append(seq, ucl_object_fromstring(dep->name));
1621 : 0 : ucl_object_insert_key(o, seq, "depends", 0, false);
1622 : 0 : ucl_object_emit_fd(o, UCL_EMIT_CONFIG, fd);
1623 : 0 : return (EPKG_OK);
1624 : 0 : }
1625 : :
1626 : : int
1627 : 0 : pkg_add_group(struct pkg *pkg)
1628 : : {
1629 : : char temp[MAXPATHLEN];
1630 : 0 : int dfd = pkg_get_dbdirfd();
1631 : 0 : mkdirat(dfd, "groups", 0755);
1632 : 0 : int gfd = openat(dfd, "groups", O_DIRECTORY|O_CLOEXEC);
1633 : 0 : hidden_tempfile(temp, MAXPATHLEN, pkg->name);
1634 : 0 : int fd = openat(gfd, temp, O_CREAT|O_EXCL|O_WRONLY, 0644);
1635 [ # # ]: 0 : if (fd == -1) {
1636 : 0 : pkg_emit_errno("impossible to create group file %s", pkg->name);
1637 : 0 : return (EPKG_FATAL);
1638 : : }
1639 : 0 : pkg_group_dump(fd, pkg);
1640 : 0 : close(fd);
1641 [ # # ]: 0 : if (renameat(gfd, temp, gfd, pkg->name) == -1) {
1642 : 0 : unlinkat(gfd, temp, 0);
1643 : 0 : pkg_emit_errno("impossible to create group file %s", pkg->name);
1644 : 0 : return (EPKG_FATAL);
1645 : : }
1646 : 0 : return (EPKG_OK);
1647 : 0 : }
1648 : :
1649 : : int
1650 : 3 : pkg_add_fromdir(struct pkg *pkg, const char *src)
1651 : : {
1652 : : struct stat st;
1653 : 3 : struct pkg_dir *d = NULL;
1654 : 3 : struct pkg_file *f = NULL;
1655 : : char target[MAXPATHLEN];
1656 : : struct passwd *pw, pwent;
1657 : : struct group *gr, grent;
1658 : : int err, fd, fromfd;
1659 : : int retcode;
1660 : : hardlinks_t hardlinks;
1661 : : const char *path;
1662 : : char buffer[1024];
1663 : : size_t link_len;
1664 : : bool install_as_user;
1665 : : tempdirs_t tempdirs;
1666 : : c_charv_t symlinks_allowed;
1667 : :
1668 : 3 : pkgvec_init(&symlinks_allowed);
1669 [ - + + - : 3 : pkgvec_push(&symlinks_allowed, pkg->prefix);
+ - ]
1670 : 3 : pkgvec_init(&hardlinks);
1671 : 3 : pkgvec_init(&tempdirs);
1672 : 3 : install_as_user = (getenv("INSTALL_AS_USER") != NULL);
1673 : :
1674 : 3 : fromfd = open(src, O_DIRECTORY);
1675 [ + - ]: 3 : if (fromfd == -1) {
1676 : 0 : pkg_fatal_errno("Unable to open source directory '%s'", src);
1677 : 0 : }
1678 : 3 : pkg_open_root_fd(pkg);
1679 : :
1680 [ - + ]: 3 : while (pkg_dirs(pkg, &d) == EPKG_OK) {
1681 [ # # ]: 0 : if (fstatat(fromfd, RELATIVE_PATH(d->path), &st, 0) == -1) {
1682 : 0 : close(fromfd);
1683 : 0 : pkg_fatal_errno("%s%s", src, d->path);
1684 : 0 : }
1685 [ # # ]: 0 : if (d->perm == 0)
1686 : 0 : d->perm = st.st_mode & ~S_IFMT;
1687 [ # # ]: 0 : if (d->uname[0] != '\0') {
1688 : 0 : err = getpwnam_r(d->uname, &pwent, buffer,
1689 : : sizeof(buffer), &pw);
1690 [ # # ]: 0 : if (err != 0) {
1691 : 0 : pkg_emit_errno("getpwnam_r", d->uname);
1692 : 0 : retcode = EPKG_FATAL;
1693 : 0 : goto cleanup;
1694 : : }
1695 : 0 : d->uid = pwent.pw_uid;
1696 : 0 : } else {
1697 [ # # ]: 0 : d->uid = install_as_user ? st.st_uid : 0;
1698 : : }
1699 [ # # ]: 0 : if (d->gname[0] != '\0') {
1700 : 0 : err = getgrnam_r(d->gname, &grent, buffer,
1701 : : sizeof(buffer), &gr);
1702 [ # # ]: 0 : if (err != 0) {
1703 : 0 : pkg_emit_errno("getgrnam_r", d->gname);
1704 : 0 : retcode = EPKG_FATAL;
1705 : 0 : goto cleanup;
1706 : : }
1707 : 0 : d->gid = grent.gr_gid;
1708 : 0 : } else {
1709 : 0 : d->gid = st.st_gid;
1710 : : }
1711 : : #ifdef HAVE_STRUCT_STAT_ST_MTIM
1712 : 0 : d->time[0] = st.st_atim;
1713 : 0 : d->time[1] = st.st_mtim;
1714 : : #else
1715 : : #if defined(_DARWIN_C_SOURCE) || defined(__APPLE__)
1716 : : d->time[0] = st.st_atimespec;
1717 : : d->time[1] = st.st_mtimespec;
1718 : : #else
1719 : : d->time[0].tv_sec = st.st_atime;
1720 : : d->time[0].tv_nsec = 0;
1721 : : d->time[1].tv_sec = st.st_mtime;
1722 : : d->time[1].tv_nsec = 0;
1723 : : #endif
1724 : : #endif
1725 : :
1726 [ # # ]: 0 : if (create_dir(pkg, d, &tempdirs, &symlinks_allowed) == EPKG_FATAL) {
1727 : 0 : retcode = EPKG_FATAL;
1728 : 0 : goto cleanup;
1729 : : }
1730 : : }
1731 : :
1732 [ + + ]: 10 : while (pkg_files(pkg, &f) == EPKG_OK) {
1733 [ - + - + ]: 14 : if (match_ucl_lists(f->path,
1734 : 7 : pkg_config_get("FILES_IGNORE_GLOB"),
1735 : 7 : pkg_config_get("FILES_IGNORE_REGEX")))
1736 : 0 : continue;
1737 [ - + - + ]: 14 : if (fstatat(fromfd, RELATIVE_PATH(f->path), &st,
1738 : 7 : AT_SYMLINK_NOFOLLOW) == -1) {
1739 [ # # ]: 0 : pkgvec_free_and_free(&hardlinks, free);
1740 : 0 : close(fromfd);
1741 : 0 : pkg_fatal_errno("%s%s", src, f->path);
1742 : 0 : }
1743 [ + + ]: 7 : if (f->uname[0] != '\0') {
1744 : 6 : err = getpwnam_r(f->uname, &pwent, buffer,
1745 : : sizeof(buffer), &pw);
1746 [ + - ]: 6 : if (err != 0) {
1747 : 0 : pkg_emit_errno("getpwnam_r", f->uname);
1748 : 0 : retcode = EPKG_FATAL;
1749 : 0 : goto cleanup;
1750 : : }
1751 : 6 : f->uid = pwent.pw_uid;
1752 : 6 : } else {
1753 [ + - ]: 1 : f->uid = install_as_user ? st.st_uid : 0;
1754 : : }
1755 : :
1756 [ + + ]: 7 : if (f->gname[0] != '\0') {
1757 : 6 : err = getgrnam_r(f->gname, &grent, buffer,
1758 : : sizeof(buffer), &gr);
1759 [ - + ]: 6 : if (err != 0) {
1760 : 0 : pkg_emit_errno("getgrnam_r", f->gname);
1761 : 0 : retcode = EPKG_FATAL;
1762 : 0 : goto cleanup;
1763 : : }
1764 : 6 : f->gid = grent.gr_gid;
1765 : 6 : } else {
1766 : 1 : f->gid = st.st_gid;
1767 : : }
1768 : :
1769 [ - + ]: 7 : if (f->perm == 0)
1770 : 7 : f->perm = st.st_mode & ~S_IFMT;
1771 [ + + - + ]: 7 : if (f->uid == 0 && install_as_user)
1772 : 6 : f->uid = st.st_uid;
1773 : : #ifdef HAVE_STRUCT_STAT_ST_MTIM
1774 : 7 : f->time[0] = st.st_atim;
1775 : 7 : f->time[1] = st.st_mtim;
1776 : : #else
1777 : : #if defined(_DARWIN_C_SOURCE) || defined(__APPLE__)
1778 : : f->time[0] = st.st_atimespec;
1779 : : f->time[1] = st.st_mtimespec;
1780 : : #else
1781 : : f->time[0].tv_sec = st.st_atime;
1782 : : f->time[0].tv_nsec = 0;
1783 : : f->time[1].tv_sec = st.st_mtime;
1784 : : f->time[1].tv_nsec = 0;
1785 : : #endif
1786 : : #endif
1787 : :
1788 [ + + ]: 7 : if (S_ISLNK(st.st_mode)) {
1789 [ + - + - : 9 : if ((link_len = readlinkat(fromfd,
+ - ]
1790 : 3 : RELATIVE_PATH(f->path), target,
1791 : 3 : sizeof(target))) == -1) {
1792 [ # # ]: 0 : pkgvec_free_and_free(&hardlinks, free);
1793 : 0 : close(fromfd);
1794 : 0 : pkg_fatal_errno("Impossible to read symlinks "
1795 : : "'%s'", f->path);
1796 : 0 : }
1797 : 3 : target[link_len] = '\0';
1798 [ + - ]: 3 : if (create_symlinks(pkg, f, target, &tempdirs, &symlinks_allowed) == EPKG_FATAL) {
1799 : 0 : retcode = EPKG_FATAL;
1800 : 0 : goto cleanup;
1801 : : }
1802 [ - + ]: 7 : } else if (S_ISREG(st.st_mode)) {
1803 [ + - + - ]: 8 : if ((fd = openat(fromfd, RELATIVE_PATH(f->path),
1804 : 4 : O_RDONLY)) == -1) {
1805 [ # # ]: 0 : pkgvec_free_and_free(&hardlinks, free);
1806 : 0 : close(fromfd);
1807 : 0 : pkg_fatal_errno("Impossible to open source file"
1808 : : " '%s'", RELATIVE_PATH(f->path));
1809 : 0 : }
1810 : 4 : path = NULL;
1811 [ + + ]: 4 : for (size_t i = 0; i < hardlinks.len; i++) {
1812 : 1 : struct hardlink *hit = hardlinks.d[i];
1813 [ + - + - ]: 1 : if (hit->ino == st.st_ino &&
1814 : 1 : hit->dev == st.st_dev) {
1815 : 1 : path = hit->path;
1816 : 1 : break;
1817 : : }
1818 : 0 : }
1819 [ + + ]: 4 : if (path != NULL) {
1820 [ + - ]: 1 : if (create_hardlink(pkg, f, path, &tempdirs, &symlinks_allowed) == EPKG_FATAL) {
1821 : 0 : close(fd);
1822 : 0 : retcode = EPKG_FATAL;
1823 : 0 : goto cleanup;
1824 : : }
1825 : 1 : } else {
1826 [ + - ]: 3 : if (create_regfile(pkg, f, NULL, NULL, fd, NULL, &tempdirs, &symlinks_allowed) == EPKG_FATAL) {
1827 : 0 : close(fd);
1828 : 0 : retcode = EPKG_FATAL;
1829 : 0 : goto cleanup;
1830 : : }
1831 : 3 : struct hardlink *h = xcalloc(1, sizeof(*h));
1832 : 3 : h->ino = st.st_ino;
1833 : 3 : h->dev = st.st_dev;
1834 : 3 : h->path = f->path;
1835 [ - + - + : 3 : pkgvec_push(&hardlinks, h);
+ - ]
1836 : : }
1837 : 4 : close(fd);
1838 : 4 : } else {
1839 : 0 : pkg_emit_error("Invalid file type");
1840 : 0 : retcode = EPKG_FATAL;
1841 : 0 : goto cleanup;
1842 : : }
1843 : : }
1844 : :
1845 : 3 : retcode = pkg_extract_finalize(pkg, &tempdirs);
1846 : :
1847 : : cleanup:
1848 : 3 : pkgvec_free(&symlinks_allowed);
1849 [ + + ]: 6 : pkgvec_free_and_free(&hardlinks, free);
1850 : 3 : close(fromfd);
1851 : 3 : return (retcode);
1852 : 3 : }
1853 : :
|