The follow fields are checked: Directory: uid, gid, mode File: uid, gid, mode, size, time Symbolic Link: uid, gid, mode, link, time Signed-off-by: Allan McRae <allan@archlinux.org> --- src/pacman/check.c | 137 ++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 133 insertions(+), 4 deletions(-) diff --git a/src/pacman/check.c b/src/pacman/check.c index ba9036a..be84dd6 100644 --- a/src/pacman/check.c +++ b/src/pacman/check.c @@ -43,6 +43,104 @@ static int check_file_exists(const char *pkgname, const char * filepath, return 0; } +static int check_file_permissions(const char *pkgname, const char *filepath, + struct stat *st, struct archive_entry *entry) +{ + int errors = 0; + mode_t fsmode; + + /* uid */ + if(st->st_uid != archive_entry_uid(entry)) { + errors++; + if(!config->quiet) { + pm_printf(ALPM_LOG_WARNING, "%s: %s (UID mismatch)\n", + pkgname, filepath); + } + } + + /* gid */ + if(st->st_gid != archive_entry_gid(entry)) { + errors++; + if(!config->quiet) { + pm_printf(ALPM_LOG_WARNING, "%s: %s (GID mismatch)\n", + pkgname, filepath); + } + } + + /* mode */ + fsmode = st->st_mode & (S_ISUID | S_ISGID | S_ISVTX | S_IRWXU | S_IRWXG | S_IRWXO); + if(fsmode != archive_entry_perm(entry)) { + errors++; + if(!config->quiet) { + pm_printf(ALPM_LOG_WARNING, "%s: %s (Permissions mismatch)\n", + pkgname, filepath); + } + } + + return (errors != 0 ? 1 : 0); +} + +static int check_file_time(const char *pkgname, const char *filepath, + struct stat *st, struct archive_entry *entry) +{ + if(st->st_mtime != archive_entry_mtime(entry)) { + if(!config->quiet) { + pm_printf(ALPM_LOG_WARNING, "%s: %s (Modification time mismatch)\n", + pkgname, filepath); + } + return 1; + } + + return 0; +} + +static int check_file_link(const char *pkgname, const char *filepath, + struct stat *st, struct archive_entry *entry) +{ + /* TODO - fail early if file is not a symlink */ + size_t length = st->st_size + 1; + char link[length]; + + if(readlink(filepath, link, length) != st->st_size) { + /* this should not happen */ + pm_printf(ALPM_LOG_ERROR, _("unable to read symlink contents: %s\n"), filepath); + return 1; + } + link[length - 1] = '\0'; + + if(strcmp(link, archive_entry_symlink(entry)) != 0) { + if(!config->quiet) { + pm_printf(ALPM_LOG_WARNING, "%s: %s (Symlink path mismatch)\n", + pkgname, filepath); + } + return 1; + } + + return 0; +} + +static int check_file_size(const char *pkgname, const char *filepath, + struct stat *st, struct archive_entry *entry) +{ + if(st->st_size != archive_entry_size(entry)) { + if(!config->quiet) { + pm_printf(ALPM_LOG_WARNING, "%s: %s (Size mismatch)\n", + pkgname, filepath); + } + return 1; + } + + return 0; +} + +/* placeholder - libarchive currently does not read checksums from mtree files +static int check_file_md5sum(const char *pkgname, const char *filepath, + struct stat *st, struct archive_entry *entry) +{ + return 0; +} +*/ + /* Loop through the files of the package to check if they exist. */ int check_pkg_fast(alpm_pkg_t *pkg) { @@ -120,8 +218,10 @@ int check_pkg_full(alpm_pkg_t *pkg) while(alpm_pkg_mtree_next(pkg, mtree, &entry) == ARCHIVE_OK) { struct stat st; const char *path = archive_entry_pathname(entry); + mode_t type; + size_t file_errors = 0; - /* ignore special files for the moment */ + /* TODO: ignoring special files for the moment */ if(*path == '.') { continue; } @@ -134,13 +234,40 @@ int check_pkg_full(alpm_pkg_t *pkg) } strcpy(filepath + rootlen, path); - if(check_file_exists(pkgname, filepath, &st) == 1) - { + if(check_file_exists(pkgname, filepath, &st) == 1) { errors++; continue; } - /* TODO: check file properties */ + type = archive_entry_filetype(entry); + + if(type != AE_IFDIR && type != AE_IFREG && type != AE_IFLNK) { + pm_printf(ALPM_LOG_WARNING, _("file type not recognized: %s%s\n"), root, path); + continue; + } + + file_errors += check_file_permissions(pkgname, filepath, &st, entry); + + if(type != AE_IFDIR) { + /* file or symbolic link */ + file_errors += check_file_time(pkgname, filepath, &st, entry); + } + + if(type == AE_IFLNK) { + file_errors += check_file_link(pkgname, filepath, &st, entry); + } + + if(type == AE_IFREG) { + /* TODO: these are expected to be changed with backup files */ + file_errors += check_file_size(pkgname, filepath, &st, entry); + //file_errors += check_file_md5sum(pkgname, filepath, &st, entry); + } + + if(config->quiet && file_errors) { + printf("%s %s\n", pkgname, filepath); + } + + errors += (file_errors != 0 ? 1 : 0); } alpm_pkg_mtree_close(pkg, mtree); @@ -154,3 +281,5 @@ int check_pkg_full(alpm_pkg_t *pkg) return (errors != 0 ? 1 : 0); } + +/* vim: set ts=2 sw=2 noet: */ -- 1.7.10.1