40 #include "xbps_api_impl.h"
43 set_extract_flags(uid_t euid)
48 flags = FEXTRACT_FLAGS;
50 flags = EXTRACT_FLAGS;
56 find_pkg_symlink_target(prop_dictionary_t d,
const char *file)
61 const char *pkgfile, *tgt = NULL;
66 links = prop_dictionary_get(d,
"links");
69 for (i = 0; i < prop_array_count(links); i++) {
70 rfile = strchr(file,
'.') + 1;
71 obj = prop_array_get(links, i);
72 prop_dictionary_get_cstring_nocopy(obj,
"file", &pkgfile);
73 if (strcmp(rfile, pkgfile) == 0) {
74 prop_dictionary_get_cstring_nocopy(obj,
"target", &tgt);
84 prop_dictionary_t pkg_repod,
87 prop_dictionary_t pkg_metad = NULL, filesd = NULL, old_filesd = NULL;
88 prop_array_t array, obsoletes;
91 void *instbuf = NULL, *rembuf = NULL;
92 const struct stat *entry_statp;
95 struct archive_entry *entry;
96 size_t i, entry_idx = 0;
97 size_t instbufsiz, rembufsiz;
99 const char *file, *entry_pname, *transact, *pkgname;
100 const char *version, *pkgver, *fname, *tgtlnk;
101 char *dname, *buf, *buf2, *p, *p2;
102 int ar_rv, rv, rv_stat, flags;
103 bool preserve, update, conf_file, file_exists, skip_obsoletes;
104 bool softreplace, skip_extract, force;
107 assert(prop_object_type(pkg_repod) == PROP_TYPE_DICTIONARY);
110 force = preserve = update = conf_file = file_exists =
false;
111 skip_obsoletes = softreplace =
false;
113 prop_dictionary_get_bool(pkg_repod,
"preserve", &preserve);
114 prop_dictionary_get_bool(pkg_repod,
"skip-obsoletes", &skip_obsoletes);
115 prop_dictionary_get_bool(pkg_repod,
"softreplace", &softreplace);
116 prop_dictionary_get_cstring_nocopy(pkg_repod,
117 "transaction", &transact);
118 prop_dictionary_get_cstring_nocopy(pkg_repod,
"pkgname", &pkgname);
119 prop_dictionary_get_cstring_nocopy(pkg_repod,
"version", &version);
120 prop_dictionary_get_cstring_nocopy(pkg_repod,
"pkgver", &pkgver);
121 prop_dictionary_get_cstring_nocopy(pkg_repod,
"filename", &fname);
125 if (xhp->
flags & XBPS_FLAG_FORCE_INSTALL)
130 memset(&xucd, 0,
sizeof(xucd));
132 if (access(xhp->
rootdir, R_OK) == -1) {
133 if (errno != ENOENT) {
142 if (chdir(xhp->
rootdir) == -1) {
143 xbps_set_cb_state(xhp, XBPS_STATE_UNPACK_FAIL,
144 errno, pkgname, version,
145 "%s: [unpack] failed to chdir to rootdir `%s': %s",
146 pkgver, xhp->
rootdir, strerror(errno));
150 if (strcmp(transact,
"update") == 0)
156 ar_rv = archive_read_next_header(ar, &entry);
157 if (ar_rv == ARCHIVE_EOF || ar_rv == ARCHIVE_FATAL)
159 else if (ar_rv == ARCHIVE_RETRY)
162 entry_statp = archive_entry_stat(entry);
163 entry_pname = archive_entry_pathname(entry);
164 entry_size = archive_entry_size(entry);
165 flags = set_extract_flags(euid);
169 if (S_ISDIR(entry_statp->st_mode)) {
170 archive_read_data_skip(ar);
178 xucd.pkgver = pkgver;
179 xucd.entry = entry_pname;
180 xucd.entry_size = entry_size;
181 xucd.entry_is_conf =
false;
183 if (strcmp(
"./INSTALL", entry_pname) == 0) {
188 instbufsiz = entry_size;
189 instbuf = malloc(entry_size);
192 if (archive_read_data(ar, instbuf, entry_size) !=
200 pkgname, version,
"pre", update);
202 xbps_set_cb_state(xhp,
203 XBPS_STATE_UNPACK_FAIL,
204 rv, pkgname, version,
205 "%s: [unpack] INSTALL script failed "
206 "to execute pre ACTION: %s",
207 pkgver, strerror(rv));
213 }
else if (strcmp(
"./REMOVE", entry_pname) == 0) {
215 rembufsiz = entry_size;
216 rembuf = malloc(entry_size);
218 if (archive_read_data(ar, rembuf, entry_size) !=
226 }
else if (strcmp(
"./files.plist", entry_pname) == 0) {
232 filesd = xbps_dictionary_from_archive_entry(ar, entry);
233 if (filesd == NULL) {
238 }
else if (strcmp(
"./props.plist", entry_pname) == 0) {
240 archive_read_data_skip(ar);
247 if (filesd == NULL) {
248 archive_read_data_skip(ar);
254 if (entry_idx >= 3) {
255 xbps_set_cb_state(xhp,
256 XBPS_STATE_UNPACK_FAIL,
257 ENODEV, pkgname, version,
258 "%s: [unpack] invalid binary package `%s'.",
272 xucd.entry_total_count = 0;
273 array = prop_dictionary_get(filesd,
"files");
274 xucd.entry_total_count +=
275 (ssize_t)prop_array_count(array);
276 array = prop_dictionary_get(filesd,
"conf_files");
277 xucd.entry_total_count +=
278 (ssize_t)prop_array_count(array);
279 array = prop_dictionary_get(filesd,
"links");
280 xucd.entry_total_count +=
281 (ssize_t)prop_array_count(array);
288 conf_file = skip_extract = file_exists =
false;
289 rv_stat = lstat(entry_pname, &st);
293 if (!force && S_ISREG(entry_statp->st_mode)) {
294 buf = strchr(entry_pname,
'.') + 1;
304 if (xbps_entry_is_a_conf_file(pkg_repod, buf)) {
307 xucd.entry_is_conf =
true;
309 rv = xbps_entry_install_conf_file(xhp,
310 filesd, entry, entry_pname,
315 }
else if (rv == 0) {
322 rv = xbps_file_hash_check_dictionary(
323 xhp, filesd,
"files", buf);
327 "%s-%s: failed to check"
328 " hash for `%s': %s\n",
333 }
else if (rv == 0) {
339 "matches existing SHA256, "
340 "skipping...\n", pkgname,
341 version, entry_pname);
346 }
else if (!force && S_ISLNK(entry_statp->st_mode)) {
351 buf = realpath(entry_pname, NULL);
353 if (strcmp(xhp->
rootdir,
"/")) {
358 tgtlnk = find_pkg_symlink_target(filesd,
361 if (strncmp(tgtlnk,
"./", 2) == 0) {
362 buf2 = strdup(entry_pname);
364 dname = dirname(buf2);
371 xbps_dbg_printf(xhp,
"%s: symlink %s cur: %s "
372 "new: %s\n", pkgver, entry_pname, p, p2);
374 if (strcmp(p, p2) == 0) {
375 xbps_dbg_printf(xhp,
"%s-%s: symlink "
376 "%s matched, skipping...\n",
377 pkgname, version, entry_pname);
387 if (!force && file_exists && skip_extract &&
388 (entry_statp->st_mode != st.st_mode)) {
389 if (chmod(entry_pname,
390 entry_statp->st_mode) != 0) {
393 "to set perms %s to %s: %s\n",
395 archive_entry_strmode(entry),
401 xbps_dbg_printf(xhp,
"%s-%s: entry %s changed file "
402 "mode to %s.\n", pkgname, version, entry_pname,
403 archive_entry_strmode(entry));
409 if ((!force && file_exists && skip_extract && (euid == 0)) &&
410 (((entry_statp->st_uid != st.st_uid)) ||
411 ((entry_statp->st_gid != st.st_gid)))) {
412 if (chown(entry_pname,
413 entry_statp->st_uid, entry_statp->st_gid) != 0) {
416 "to set uid/gid to %u:%u (%s)\n",
418 entry_statp->st_uid, entry_statp->st_gid,
421 xbps_dbg_printf(xhp,
"%s-%s: entry %s changed "
422 "uid/gid to %u:%u.\n", pkgname, version,
424 entry_statp->st_uid, entry_statp->st_gid);
428 if (!update && conf_file && file_exists && !skip_extract) {
434 (void)rename(entry_pname, buf);
437 xbps_set_cb_state(xhp,
438 XBPS_STATE_CONFIG_FILE, 0,
440 "Renamed old configuration file "
441 "`%s' to `%s.old'.", entry_pname, entry_pname);
444 if (!force && skip_extract) {
445 archive_read_data_skip(ar);
452 entry_pname = archive_entry_pathname(entry);
456 if (archive_read_extract(ar, entry, flags) != 0) {
457 rv = archive_errno(ar);
458 xbps_set_cb_state(xhp, XBPS_STATE_UNPACK_FAIL,
459 rv, pkgname, version,
460 "%s: [unpack] failed to extract file `%s': %s",
461 pkgver, entry_pname, strerror(rv));
464 xucd.entry_extract_count++;
472 if ((rv = archive_errno(ar)) != 0) {
473 xbps_set_cb_state(xhp, XBPS_STATE_UNPACK_FAIL,
474 rv, pkgname, version,
475 "%s: [unpack] failed to extract files: %s",
476 pkgver, fname, archive_error_string(ar));
486 if (skip_obsoletes || preserve || (!softreplace && !update))
494 assert(prop_object_type(old_filesd) == PROP_TYPE_DICTIONARY);
496 obsoletes = xbps_find_pkg_obsoletes(xhp, old_filesd, filesd);
497 for (i = 0; i < prop_array_count(obsoletes); i++) {
498 obj = prop_array_get(obsoletes, i);
499 file = prop_string_cstring_nocopy(obj);
500 if (
remove(file) == -1) {
501 xbps_set_cb_state(xhp,
502 XBPS_STATE_REMOVE_FILE_OBSOLETE_FAIL,
503 errno, pkgname, version,
504 "%s: failed to remove obsolete entry `%s': %s",
505 pkgver, file, strerror(errno));
508 xbps_set_cb_state(xhp,
509 XBPS_STATE_REMOVE_FILE_OBSOLETE,
511 "%s: removed obsolete entry: %s", pkgver, file);
512 prop_object_release(obj);
516 prop_dictionary_make_immutable(pkg_repod);
517 pkg_metad = prop_dictionary_copy_mutable(pkg_repod);
520 array = prop_dictionary_get(filesd,
"files");
521 if (array && prop_array_count(array))
522 prop_dictionary_set(pkg_metad,
"files", array);
523 array = prop_dictionary_get(filesd,
"conf_files");
524 if (array && prop_array_count(array))
525 prop_dictionary_set(pkg_metad,
"conf_files", array);
526 array = prop_dictionary_get(filesd,
"links");
527 if (array && prop_array_count(array))
528 prop_dictionary_set(pkg_metad,
"links", array);
529 array = prop_dictionary_get(filesd,
"dirs");
530 if (array && prop_array_count(array))
531 prop_dictionary_set(pkg_metad,
"dirs", array);
534 if (instbuf != NULL) {
535 data = prop_data_create_data(instbuf, instbufsiz);
537 prop_dictionary_set(pkg_metad,
"install-script", data);
538 prop_object_release(data);
541 if (rembuf != NULL) {
542 data = prop_data_create_data(rembuf, rembufsiz);
544 prop_dictionary_set(pkg_metad,
"remove-script", data);
545 prop_object_release(data);
549 prop_dictionary_remove(pkg_metad,
"remove-and-update");
550 prop_dictionary_remove(pkg_metad,
"transaction");
551 prop_dictionary_remove(pkg_metad,
"state");
556 if (access(xhp->
metadir, R_OK|X_OK) == -1) {
557 if (errno == ENOENT) {
565 if (!prop_dictionary_externalize_to_file(pkg_metad, buf)) {
567 xbps_set_cb_state(xhp, XBPS_STATE_UNPACK_FAIL,
568 errno, pkgname, version,
569 "%s: [unpack] failed to extract metadata file `%s': %s",
570 pkgver, buf, strerror(errno));
576 if (prop_object_type(pkg_metad) == PROP_TYPE_DICTIONARY)
577 prop_object_release(pkg_metad);
578 if (prop_object_type(filesd) == PROP_TYPE_DICTIONARY)
579 prop_object_release(filesd);
585 xbps_unpack_binary_pkg(
struct xbps_handle *xhp, prop_dictionary_t pkg_repod)
587 struct archive *ar = NULL;
588 struct stat pkg_stat;
589 const char *pkgname, *version, *pkgver;
593 assert(prop_object_type(pkg_repod) == PROP_TYPE_DICTIONARY);
595 prop_dictionary_get_cstring_nocopy(pkg_repod,
"pkgname", &pkgname);
596 prop_dictionary_get_cstring_nocopy(pkg_repod,
"version", &version);
597 prop_dictionary_get_cstring_nocopy(pkg_repod,
"pkgver", &pkgver);
599 xbps_set_cb_state(xhp, XBPS_STATE_UNPACK, 0, pkgname, version, NULL);
601 bpkg = xbps_repository_pkg_path(xhp, pkg_repod);
603 xbps_set_cb_state(xhp, XBPS_STATE_UNPACK_FAIL,
604 errno, pkgname, version,
605 "%s: [unpack] cannot determine binary package "
606 "file for `%s': %s", pkgver, bpkg, strerror(errno));
610 if ((ar = archive_read_new()) == NULL) {
617 archive_read_support_compression_gzip(ar);
618 archive_read_support_compression_bzip2(ar);
619 archive_read_support_compression_xz(ar);
620 archive_read_support_format_tar(ar);
622 pkg_fd = open(bpkg, O_RDONLY|O_CLOEXEC);
624 rv = archive_errno(ar);
625 xbps_set_cb_state(xhp, XBPS_STATE_UNPACK_FAIL,
626 rv, pkgname, version,
627 "%s: [unpack] failed to open binary package `%s': %s",
628 pkgver, bpkg, strerror(rv));
630 archive_read_free(ar);
633 archive_read_open_fd(ar, pkg_fd, ARCHIVE_READ_BLOCKSIZE);
636 #ifdef HAVE_POSIX_FADVISE
637 fstat(pkg_fd, &pkg_stat);
638 posix_fadvise(pkg_fd, 0, pkg_stat.st_size, POSIX_FADV_SEQUENTIAL);
643 if ((rv = unpack_archive(xhp, pkg_repod, ar)) != 0) {
644 xbps_set_cb_state(xhp, XBPS_STATE_UNPACK_FAIL,
645 rv, pkgname, version,
646 "%s: [unpack] failed to unpack files from archive: %s",
647 pkgver, strerror(rv));
650 #ifdef HAVE_POSIX_FADVISE
651 posix_fadvise(pkg_fd, 0, pkg_stat.st_size, POSIX_FADV_DONTNEED);
657 XBPS_PKG_STATE_UNPACKED)) != 0) {
658 xbps_set_cb_state(xhp, XBPS_STATE_UNPACK_FAIL,
659 rv, pkgname, version,
660 "%s: [unpack] failed to set state to unpacked: %s",
661 pkgver, strerror(rv));
666 archive_read_free(ar);