/* Loop though files in a package and perform full file property checking. */ int check_pkg_full(alpm_pkg_t *pkg) { const char *root, *pkgname; size_t errors = 0; size_t rootlen; char filepath[PATH_MAX]; struct archive *mtree; struct archive_entry *entry = NULL; size_t file_count = 0; const alpm_list_t *lp; root = alpm_option_get_root(config->handle); rootlen = strlen(root); if(rootlen + 1 > PATH_MAX) { /* we are in trouble here */ pm_printf(ALPM_LOG_ERROR, _("path too long: %s%s\n"), root, ""); return 1; } strcpy(filepath, root); pkgname = alpm_pkg_get_name(pkg); mtree = alpm_pkg_mtree_open(pkg); if(mtree == NULL) { /* TODO: check error to confirm failure due to no mtree file */ if(!config->quiet) { printf(_("%s: no mtree file\n"), pkgname); } return 0; } 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; int backup = 0; /* strip leading "./" from path entries */ if(path[0] == '.' && path[1] == '/') { path += 2; } if(strcmp(path, ".INSTALL") == 0) { char filename[PATH_MAX]; snprintf(filename, PATH_MAX, "%slocal/%s-%s/install", alpm_option_get_dbpath(config->handle) + 1, pkgname, alpm_pkg_get_version(pkg)); archive_entry_set_pathname(entry, filename); path = archive_entry_pathname(entry); } else if(strcmp(path, ".CHANGELOG") == 0) { char filename[PATH_MAX]; snprintf(filename, PATH_MAX, "%slocal/%s-%s/changelog", alpm_option_get_dbpath(config->handle) + 1, pkgname, alpm_pkg_get_version(pkg)); archive_entry_set_pathname(entry, filename); path = archive_entry_pathname(entry); } else if(*path == '.') { continue; } file_count++; if(rootlen + 1 + strlen(path) > PATH_MAX) { pm_printf(ALPM_LOG_WARNING, _("path too long: %s%s\n"), root, path); continue; } strcpy(filepath + rootlen, path); if(check_file_exists(pkgname, filepath, &st) == 1) { errors++; continue; } 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; } if(check_file_type(pkgname, filepath, &st, entry) == 1) { errors++; continue; } file_errors += check_file_permissions(pkgname, filepath, &st, entry); if(type == AE_IFLNK) { file_errors += check_file_link(pkgname, filepath, &st, entry); } /* the following checks are expected to fail if a backup file has been modified */ for(lp = alpm_pkg_get_backup(pkg); lp; lp = lp->next) { alpm_backup_t *bl = lp->data; if(strcmp(path, bl->name) == 0) { backup = 1; break; } } if(type != AE_IFDIR) { /* file or symbolic link */ file_errors += check_file_time(pkgname, filepath, &st, entry, backup); } if(type == AE_IFREG) { /* TODO: these are expected to be changed with backup files */ file_errors += check_file_size(pkgname, filepath, &st, entry, backup); /* file_errors += check_file_md5sum(pkgname, filepath, &st, entry, backup); */ } if(config->quiet && file_errors) { printf("%s %s\n", pkgname, filepath); } errors += (file_errors != 0 ? 1 : 0); } alpm_pkg_mtree_close(pkg, mtree); if(!config->quiet) { printf(_n("%s: %jd total file, ", "%s: %jd total files, ", (unsigned long)file_count), pkgname, (intmax_t)file_count); printf(_n("%jd altered file\n", "%jd altered files\n", (unsigned long)errors), (intmax_t)errors); } return (errors != 0 ? 1 : 0); }
/* check filesystem against extra mtree data if available, * NOT guaranteed to catch db/filesystem discrepencies */ static int check_file_properties(alpm_pkg_t *pkg) { char path[PATH_MAX], *rel; int ret = 0; size_t space; struct archive *mtree = alpm_pkg_mtree_open(pkg); struct archive_entry *entry; if(!mtree) { pu_ui_warn("%s: mtree data not available (%s)", alpm_pkg_get_name(pkg), strerror(errno)); return require_mtree; } strncpy(path, alpm_option_get_root(handle), PATH_MAX); rel = path + strlen(path); space = PATH_MAX - (rel - path); while(alpm_pkg_mtree_next(pkg, mtree, &entry) == ARCHIVE_OK) { const char *ppath = archive_entry_pathname(entry); const char *fpath; struct stat buf; if(strncmp("./", ppath, 2) == 0) { ppath += 2; } if(strcmp(ppath, ".INSTALL") == 0) { if((fpath = get_db_path(pkg, "install")) == NULL) { continue; } } else if(strcmp(ppath, ".CHANGELOG") == 0) { if((fpath = get_db_path(pkg, "changelog")) == NULL) { continue; } } else if(ppath[0] == '.') { continue; } else if(skip_noextract && match_noextract(handle, ppath)) { continue; } else { strncpy(rel, ppath, space); fpath = path; } if(lstat(fpath, &buf) != 0) { if(errno == ENOENT) { eprintf("%s: '%s' missing file\n", alpm_pkg_get_name(pkg), fpath); } else { pu_ui_warn("%s: '%s' read error (%s)", alpm_pkg_get_name(pkg), fpath, strerror(errno)); } ret = 1; continue; } if(cmp_type(pkg, fpath, entry, &buf) != 0) { ret = 1; } if(skip_noupgrade && match_noupgrade(handle, ppath)) { continue; } if(cmp_mode(pkg, fpath, entry, &buf) != 0) { ret = 1; } if(cmp_uid(pkg, fpath, entry, &buf) != 0) { ret = 1; } if(cmp_gid(pkg, fpath, entry, &buf) != 0) { ret = 1; } if(skip_backups && match_backup(pkg, ppath)) { continue; } if(S_ISLNK(buf.st_mode) && S_ISLNK(archive_entry_mode(entry))) { if(cmp_target(pkg, fpath, entry) != 0) { ret = 1; } } if(!S_ISDIR(buf.st_mode)) { if(cmp_mtime(pkg, fpath, entry, &buf) != 0) { ret = 1; } if(!S_ISLNK(buf.st_mode)) { /* always fails for directories and symlinks */ if(cmp_size(pkg, fpath, entry, &buf) != 0) { ret = 1; } } } } alpm_pkg_mtree_close(pkg, mtree); if(!quiet && !ret) { eprintf("%s: all files match mtree\n", alpm_pkg_get_name(pkg)); } return ret; }