static int create_dir(struct pkg *pkg, struct pkg_dir *d) { struct stat st; if (mkdirat(pkg->rootfd, RELATIVE_PATH(d->path), 0755) == -1) if (!mkdirat_p(pkg->rootfd, RELATIVE_PATH(d->path))) return (EPKG_FATAL); if (fstatat(pkg->rootfd, RELATIVE_PATH(d->path), &st, 0) == -1) { if (errno != ENOENT) { pkg_fatal_errno("Fail to stat directory %s", d->path); } if (fstatat(pkg->rootfd, RELATIVE_PATH(d->path), &st, AT_SYMLINK_NOFOLLOW) == 0) { unlinkat(pkg->rootfd, RELATIVE_PATH(d->path), 0); } if (mkdirat(pkg->rootfd, RELATIVE_PATH(d->path), 0755) == -1) { pkg_fatal_errno("Fail to create directory %s", d->path); } } if (st.st_uid == d->uid && st.st_gid == d->gid && (st.st_mode & ~S_IFMT) == (d->perm & ~S_IFMT)) { d->noattrs = true; } return (EPKG_OK); }
static int set_attrs(int fd, char *path, mode_t perm, uid_t uid, gid_t gid, const struct timespec *ats, const struct timespec *mts) { #ifdef HAVE_UTIMENSAT struct timespec times[2]; times[0] = *ats; times[1] = *mts; if (utimensat(fd, RELATIVE_PATH(path), times, AT_SYMLINK_NOFOLLOW) == -1){ pkg_emit_error("Fail to set time on %s: %s", path, strerror(errno)); return (EPKG_FATAL); } #else struct timeval tv[2]; char *saved_cwd[MAXPATHLEN]; tv[0].tv_sec = ats->tv_sec; tv[0].tv_usec = ats->tv_nsec / 1000; tv[1].tv_sec = mts->tv_sec; tv[1].tv_usec = mts->tv_nsec / 1000; memset(saved_cwd, 0, sizeof (saved_cwd)); if (getcwd(saved_cwd, sizeof(saved_cwd) - 1) == NULL) { pkg_emit_error("Fail to call getcwd: %s", strerror(errno)); return (EPKG_FATAL); } fchdir(fd); if (lutimes(RELATIVE_PATH(path), tv) == -1) { if (errno != ENOSYS) { pkg_emit_error("Fail to set time on %s: %s", path, strerror(errno)); return (EPKG_FATAL); } else { /* Fallback to utimes */ if (utimes(RELATIVE_PATH(path), tv) == -1) { pkg_emit_error("Fail to set time(fallback) on %s: %s", path, strerror(errno)); return (EPKG_FATAL); } } } chdir(saved_cwd); #endif if (getenv("INSTALL_AS_USER") == NULL) { if (fchownat(fd, RELATIVE_PATH(path), uid, gid, AT_SYMLINK_NOFOLLOW) == -1) { if (errno == ENOTSUP) { if (fchownat(fd, RELATIVE_PATH(path), uid, gid, 0) == -1) { pkg_emit_error("Fail to chown(fallback) %s: %s", path, strerror(errno)); return (EPKG_FATAL); } } else { pkg_emit_error("Fail to chown %s: %s", path, strerror(errno)); return (EPKG_FATAL); } } } /* zfs drops the setuid on fchownat */ if (fchmodat(fd, RELATIVE_PATH(path), perm, AT_SYMLINK_NOFOLLOW) == -1) { if (errno == ENOTSUP) { if (fchmodat(fd, RELATIVE_PATH(path), perm, 0) == -1) { pkg_emit_error("Fail to chmod(fallback) %s: %s", path, strerror(errno)); return (EPKG_FATAL); } } else { pkg_emit_error("Fail to chmod %s: %s", path, strerror(errno)); return (EPKG_FATAL); } } return (EPKG_OK); }
static void attempt_to_merge(int rootfd, struct pkg_config_file *rcf, struct pkg *local, bool merge) { const struct pkg_file *lf = NULL; struct sbuf *newconf; struct pkg_config_file *lcf = NULL; char *localconf = NULL; off_t sz; char *localsum; if (rcf == NULL) { pkg_debug(3, "No remote config file"); return; } if (local == NULL) { pkg_debug(3, "No local package"); return; } if (!pkg_is_config_file(local, rcf->path, &lf, &lcf)) { pkg_debug(3, "No local package"); return; } if (lcf->content == NULL) { pkg_debug(3, "Empty configuration content for local package"); return; } pkg_debug(1, "Config file found %s", rcf->path); if (file_to_bufferat(rootfd, RELATIVE_PATH(rcf->path), &localconf, &sz) != EPKG_OK) return; pkg_debug(2, "size: %d vs %d", sz, strlen(lcf->content)); if (sz == strlen(lcf->content)) { pkg_debug(2, "Ancient vanilla and deployed conf are the same size testing checksum"); localsum = pkg_checksum_data(localconf, sz, PKG_HASH_TYPE_SHA256_HEX); if (localsum && strcmp(localsum, lf->sum) == 0) { pkg_debug(2, "Checksum are the same %d", strlen(localconf)); free(localconf); free(localsum); return; } free(localsum); pkg_debug(2, "Checksum are different %d", strlen(localconf)); } rcf->status = MERGE_FAILED; if (!merge) { free(localconf); return; } pkg_debug(1, "Attempting to merge %s", rcf->path); newconf = sbuf_new_auto(); if (merge_3way(lcf->content, localconf, rcf->content, newconf) != 0) { pkg_emit_error("Impossible to merge configuration file"); } else { sbuf_finish(newconf); rcf->newcontent = strdup(sbuf_data(newconf)); rcf->status = MERGE_SUCCESS; } sbuf_delete(newconf); free(localconf); }
static int set_attrs(int fd, char *path, mode_t perm, uid_t uid, gid_t gid, const struct timespec *ats, const struct timespec *mts) { struct timeval tv[2]; struct stat st; int fdcwd; #ifdef HAVE_UTIMENSAT struct timespec times[2]; times[0] = *ats; times[1] = *mts; if (utimensat(fd, RELATIVE_PATH(path), times, AT_SYMLINK_NOFOLLOW) == -1 && errno != EOPNOTSUPP){ pkg_fatal_errno("Fail to set time on %s", path); } if (errno == EOPNOTSUPP) { #endif tv[0].tv_sec = ats->tv_sec; tv[0].tv_usec = ats->tv_nsec / 1000; tv[1].tv_sec = mts->tv_sec; tv[1].tv_usec = mts->tv_nsec / 1000; fdcwd = open(".", O_DIRECTORY|O_CLOEXEC); fchdir(fd); if (lutimes(RELATIVE_PATH(path), tv) == -1) { if (errno != ENOSYS) { pkg_fatal_errno("Fail to set time on %s", path); } else { /* Fallback to utimes */ if (utimes(RELATIVE_PATH(path), tv) == -1) { pkg_fatal_errno("Fail to set time(fallback) on " "%s", path); } } } fchdir(fdcwd); close(fdcwd); #ifdef HAVE_UTIMENSAT } #endif if (getenv("INSTALL_AS_USER") == NULL) { if (fchownat(fd, RELATIVE_PATH(path), uid, gid, AT_SYMLINK_NOFOLLOW) == -1) { if (errno == ENOTSUP) { if (fchownat(fd, RELATIVE_PATH(path), uid, gid, 0) == -1) { pkg_fatal_errno("Fail to chown(fallback) %s", path); } } else { pkg_fatal_errno("Fail to chown %s", path); } } } /* zfs drops the setuid on fchownat */ if (fchmodat(fd, RELATIVE_PATH(path), perm, AT_SYMLINK_NOFOLLOW) == -1) { if (errno == ENOTSUP) { /* * Executing fchmodat on a symbolic link results in * ENOENT (file not found) on platforms that do not * support AT_SYMLINK_NOFOLLOW. The file mode of * symlinks cannot be modified via file descriptor * reference on these systems. The lchmod function is * also not an option because it is not a posix * standard, nor is implemented everywhere. Since * symlink permissions have never been evaluated and * thus cosmetic, just skip them on these systems. */ if (fstatat(fd, RELATIVE_PATH(path), &st, AT_SYMLINK_NOFOLLOW) == -1) { pkg_fatal_errno("Fail to get file status %s", path); } if (!S_ISLNK(st.st_mode)) { if (fchmodat(fd, RELATIVE_PATH(path), perm, 0) == -1) { pkg_fatal_errno("Fail to chmod(fallback) %s", path); } } } else { pkg_fatal_errno("Fail to chmod %s", path); } } return (EPKG_OK); }