diff options
-rw-r--r-- | src/apk_package.h | 1 | ||||
-rw-r--r-- | src/archive.c | 111 | ||||
-rw-r--r-- | src/audit.c | 3 | ||||
-rw-r--r-- | src/database.c | 69 | ||||
-rw-r--r-- | src/fix.c | 8 |
5 files changed, 109 insertions, 83 deletions
diff --git a/src/apk_package.h b/src/apk_package.h index 77b66c0..1b0e2cf 100644 --- a/src/apk_package.h +++ b/src/apk_package.h @@ -91,6 +91,7 @@ struct apk_installed_package { unsigned run_all_triggers : 1; unsigned broken_files : 1; unsigned broken_script : 1; + unsigned broken_xattr : 1; }; struct apk_package { diff --git a/src/archive.c b/src/archive.c index 3062c43..63eb48f 100644 --- a/src/archive.c +++ b/src/archive.c @@ -397,7 +397,7 @@ int apk_archive_entry_extract(int atfd, const struct apk_file_info *ae, { struct apk_xattr *xattr; char *fn = ae->name; - int fd, r = -1, atflags = 0; + int fd, r = -1, atflags = 0, ret = 0; if (suffix != NULL) { fn = alloca(PATH_MAX); @@ -413,8 +413,8 @@ int apk_archive_entry_extract(int atfd, const struct apk_file_info *ae, switch (ae->mode & S_IFMT) { case S_IFDIR: r = mkdirat(atfd, fn, ae->mode & 07777); - if (r < 0 && errno == EEXIST) - r = 0; + if (r < 0 && errno != EEXIST) + ret = -errno; break; case S_IFREG: if (ae->link_target == NULL) { @@ -422,11 +422,11 @@ int apk_archive_entry_extract(int atfd, const struct apk_file_info *ae, fd = openat(atfd, fn, flags, ae->mode & 07777); if (fd < 0) { - r = -1; + ret = -errno; break; } - if (apk_istream_splice(is, fd, ae->size, cb, cb_ctx) == ae->size) - r = 0; + r = apk_istream_splice(is, fd, ae->size, cb, cb_ctx); + if (r != ae->size) ret = r < 0 ? r : -ENOSPC; close(fd); } else { char *link_target = ae->link_target; @@ -436,10 +436,12 @@ int apk_archive_entry_extract(int atfd, const struct apk_file_info *ae, ae->link_target, suffix); } r = linkat(atfd, link_target, atfd, fn, 0); + if (r < 0) ret = -errno; } break; case S_IFLNK: r = symlinkat(ae->link_target, atfd, fn); + if (r < 0) ret = -errno; atflags |= AT_SYMLINK_NOFOLLOW; break; case S_IFSOCK: @@ -447,65 +449,68 @@ int apk_archive_entry_extract(int atfd, const struct apk_file_info *ae, case S_IFCHR: case S_IFIFO: r = mknodat(atfd, fn, ae->mode & 07777, ae->device); + if (r < 0) ret = -errno; break; } - if (r == 0) { - r = fchownat(atfd, fn, ae->uid, ae->gid, atflags); + if (ret) { + apk_error("Failed to create %s: %s", ae->name, strerror(-ret)); + return ret; + } + + r = fchownat(atfd, fn, ae->uid, ae->gid, atflags); + if (r < 0) { + apk_error("Failed to set ownership on %s: %s", + fn, strerror(errno)); + if (!ret) ret = -errno; + } + + /* chown resets suid bit so we need set it again */ + if (ae->mode & 07000) { + r = fchmodat(atfd, fn, ae->mode & 07777, atflags); if (r < 0) { - apk_error("Failed to set ownership on %s: %s", + apk_error("Failed to set file permissions " + "on %s: %s", fn, strerror(errno)); - return -errno; - } - - /* chown resets suid bit so we need set it again */ - if (ae->mode & 07000) { - r = fchmodat(atfd, fn, ae->mode & 07777, atflags); - if (r < 0) { - apk_error("Failed to set file permissions " - "on %s: %s", - fn, strerror(errno)); - return -errno; - } + if (!ret) ret = -errno; } + } - /* extract xattrs */ - if (ae->xattrs && ae->xattrs->num) { - r = 0; - fd = openat(atfd, fn, O_RDWR); - if (fd >= 0) { - foreach_array_item(xattr, ae->xattrs) { - if (fsetxattr(fd, xattr->name, xattr->value.ptr, xattr->value.len, 0) < 0) { - r = errno; - break; - } + /* extract xattrs */ + if (ae->xattrs && ae->xattrs->num) { + r = 0; + fd = openat(atfd, fn, O_RDWR); + if (fd >= 0) { + foreach_array_item(xattr, ae->xattrs) { + if (fsetxattr(fd, xattr->name, xattr->value.ptr, xattr->value.len, 0) < 0) { + r = -errno; + if (r != -ENOTSUP) break; } - close(fd); - } else { - r = errno; } - if (r) { + close(fd); + } else { + r = -errno; + } + if (r) { + if (r != -ENOTSUP) apk_error("Failed to set xattrs on %s: %s", - fn, strerror(r)); - return -r; - } + fn, strerror(-r)); + if (!ret) ret = -errno; } + } - if (!S_ISLNK(ae->mode)) { - /* preserve modification time */ - struct timespec times[2]; - - times[0].tv_sec = times[1].tv_sec = ae->mtime; - times[0].tv_nsec = times[1].tv_nsec = 0; - r = utimensat(atfd, fn, times, atflags); - if (r < 0) { - apk_error("Failed to preserve modification time on %s: %s", - fn, strerror(errno)); - return -errno; - } + if (!S_ISLNK(ae->mode)) { + /* preserve modification time */ + struct timespec times[2]; + + times[0].tv_sec = times[1].tv_sec = ae->mtime; + times[0].tv_nsec = times[1].tv_nsec = 0; + r = utimensat(atfd, fn, times, atflags); + if (r < 0) { + apk_error("Failed to preserve modification time on %s: %s", + fn, strerror(errno)); + if (!ret || ret == -ENOTSUP) ret = -errno; } - } else { - apk_error("Failed to extract %s: %s", ae->name, strerror(errno)); - return -errno; } + return 0; } diff --git a/src/audit.c b/src/audit.c index c09f994..6655cb3 100644 --- a/src/audit.c +++ b/src/audit.c @@ -110,7 +110,8 @@ static int audit_file(struct audit_ctx *actx, if (dbf->csum.type != APK_CHECKSUM_NONE && apk_checksum_compare(&fi.csum, &dbf->csum) != 0) rv = 'U'; - else if (apk_checksum_compare(&fi.xattr_csum, &dbf->acl->xattr_csum) != 0) + else if (!dbf->diri->pkg->ipkg->broken_xattr && + apk_checksum_compare(&fi.xattr_csum, &dbf->acl->xattr_csum) != 0) rv = 'x'; else if (S_ISLNK(fi.mode) && dbf->csum.type == APK_CHECKSUM_NONE) rv = 'U'; diff --git a/src/database.c b/src/database.c index 364b4df..0b26bb2 100644 --- a/src/database.c +++ b/src/database.c @@ -852,6 +852,7 @@ int apk_db_index_read(struct apk_database *db, struct apk_bstream *bs, int repo) switch (l.ptr[r]) { case 'f': ipkg->broken_files = 1; break; case 's': ipkg->broken_script = 1; break; + case 'x': ipkg->broken_xattr = 1; break; default: if (!(apk_flags & APK_FORCE)) goto old_apk_tools; @@ -926,12 +927,14 @@ static int apk_db_write_fdb(struct apk_database *db, struct apk_ostream *os) apk_blob_push_blob(&bbuf, db->repo_tags[ipkg->repository_tag].plain_name); apk_blob_push_blob(&bbuf, APK_BLOB_STR("\n")); } - if (ipkg->broken_files || ipkg->broken_script) { + if (ipkg->broken_files || ipkg->broken_script || ipkg->broken_xattr) { apk_blob_push_blob(&bbuf, APK_BLOB_STR("f:")); if (ipkg->broken_files) apk_blob_push_blob(&bbuf, APK_BLOB_STR("f")); if (ipkg->broken_script) apk_blob_push_blob(&bbuf, APK_BLOB_STR("s")); + if (ipkg->broken_xattr) + apk_blob_push_blob(&bbuf, APK_BLOB_STR("x")); apk_blob_push_blob(&bbuf, APK_BLOB_STR("\n")); } hlist_for_each_entry(diri, c1, &ipkg->owned_dirs, pkg_dirs_list) { @@ -2366,35 +2369,44 @@ static int apk_db_install_archive_entry(void *_ctx, r = apk_archive_entry_extract(db->root_fd, ae, ".apk-new", is, extract_cb, ctx); - /* Hardlinks need special care for checksum */ - if (ae->csum.type == APK_CHECKSUM_NONE && - ae->link_target != NULL) { - do { - struct apk_db_file *lfile; - struct apk_db_dir_instance *ldiri; - struct hlist_node *n; - - if (!apk_blob_rsplit(APK_BLOB_STR(ae->link_target), - '/', &bdir, &bfile)) - break; - - ldiri = find_diri(ipkg, bdir, diri, NULL); - if (ldiri == NULL) - break; + switch (r) { + case 0: + /* Hardlinks need special care for checksum */ + if (ae->csum.type == APK_CHECKSUM_NONE && + ae->link_target != NULL) { + do { + struct apk_db_file *lfile; + struct apk_db_dir_instance *ldiri; + struct hlist_node *n; + + if (!apk_blob_rsplit(APK_BLOB_STR(ae->link_target), + '/', &bdir, &bfile)) + break; - hlist_for_each_entry(lfile, n, &ldiri->owned_files, - diri_files_list) { - if (apk_blob_compare(APK_BLOB_PTR_LEN(lfile->name, lfile->namelen), - bfile) == 0) { - memcpy(&file->csum, &lfile->csum, - sizeof(file->csum)); + ldiri = find_diri(ipkg, bdir, diri, NULL); + if (ldiri == NULL) break; - } - } - } while (0); - } else - memcpy(&file->csum, &ae->csum, sizeof(file->csum)); + hlist_for_each_entry(lfile, n, &ldiri->owned_files, + diri_files_list) { + if (apk_blob_compare(APK_BLOB_PTR_LEN(lfile->name, lfile->namelen), + bfile) == 0) { + memcpy(&file->csum, &lfile->csum, + sizeof(file->csum)); + break; + } + } + } while (0); + } else + memcpy(&file->csum, &ae->csum, sizeof(file->csum)); + break; + case -ENOTSUP: + ipkg->broken_xattr = 1; + break; + default: + ipkg->broken_files = 1; + break; + } } else { if (apk_verbosity >= 3) apk_message("%s (dir)", ae->name); @@ -2408,7 +2420,7 @@ static int apk_db_install_archive_entry(void *_ctx, } ctx->installed_size += ctx->current_file_size; - return r; + return 0; } static void apk_db_purge_pkg(struct apk_database *db, @@ -2659,6 +2671,7 @@ int apk_db_install_pkg(struct apk_database *db, struct apk_package *oldpkg, ipkg->run_all_triggers = 1; ipkg->broken_script = 0; ipkg->broken_files = 0; + ipkg->broken_xattr = 0; if (ipkg->triggers->num != 0) { list_del(&ipkg->trigger_pkgs_list); list_init(&ipkg->trigger_pkgs_list); @@ -19,6 +19,7 @@ struct fix_ctx { unsigned short solver_flags; int fix_depends : 1; + int fix_xattrs : 1; int fix_directory_permissions : 1; int errors; }; @@ -30,6 +31,9 @@ static int option_parse_applet(void *pctx, struct apk_db_options *dbopts, int op case 'd': ctx->fix_depends = 1; break; + case 'x': + ctx->fix_xattrs = 1; + break; case 'u': ctx->solver_flags |= APK_SOLVERF_UPGRADE; break; @@ -49,6 +53,7 @@ static const struct apk_option options_applet[] = { { 'd', "depends", "Fix all dependencies too" }, { 'r', "reinstall", "Reinstall the package (default)" }, { 'u', "upgrade", "Prefer to upgrade package" }, + { 'x', "xattr", "Fix packages with broken xattrs" }, { 0x10000, "directory-permissions", "Reset all directory permissions" }, }; @@ -95,7 +100,8 @@ static int fix_main(void *pctx, struct apk_database *db, struct apk_string_array if (args->num == 0) { list_for_each_entry(ipkg, &db->installed.packages, installed_pkgs_list) { - if (ipkg->broken_files || ipkg->broken_script) + if (ipkg->broken_files || ipkg->broken_script || + (ipkg->broken_xattr && ctx->fix_xattrs)) mark_fix(ctx, ipkg->pkg->name); } } else |