From fa6f20ec4f65e6a51534f9a6b0baa880a6565e03 Mon Sep 17 00:00:00 2001 From: Juan RP Date: Sat, 25 Oct 2014 10:11:46 +0200 Subject: [PATCH] xbps-pkgdb: rework symlinks checks to avoid false positives with -r. --- bin/xbps-pkgdb/check_pkg_symlinks.c | 125 ++++++++++++++++------------ 1 file changed, 73 insertions(+), 52 deletions(-) diff --git a/bin/xbps-pkgdb/check_pkg_symlinks.c b/bin/xbps-pkgdb/check_pkg_symlinks.c index a7c1fe8b..c5cb089b 100644 --- a/bin/xbps-pkgdb/check_pkg_symlinks.c +++ b/bin/xbps-pkgdb/check_pkg_symlinks.c @@ -45,30 +45,52 @@ * * returns 0 if test ran successfully, 1 otherwise and -1 on error. */ + static char * -symlink_target(const char *pkgname, const char *path) +symlink_target(struct xbps_handle *xhp, const char *path) { struct stat sb; - char *lnk; + char *lnk, *res; ssize_t r; - if (lstat(path, &sb) == -1) { - xbps_error_printf("%s: lstat failed for %s\n", pkgname, path); + if (lstat(path, &sb) == -1) return NULL; - } lnk = malloc(sb.st_size + 1); assert(lnk); r = readlink(path, lnk, sb.st_size + 1); if (r < 0 || r > sb.st_size) { - xbps_error_printf("%s: readlink failed for %s\n", pkgname, path); free(lnk); return NULL; } lnk[sb.st_size] = '\0'; + if (lnk[0] != '/') { + char tpath[PATH_MAX], *p, *dname; - return lnk; + /* relative */ + p = strdup(path); + assert(p); + dname = dirname(p); + assert(dname); + snprintf(tpath, sizeof(tpath), "%s/%s", dname, lnk); + free(p); + if ((res = realpath(tpath, NULL)) == NULL) { + free(lnk); + return NULL; + } + if (strcmp(xhp->rootdir, "/") == 0) + p = strdup(res); + else + p = strdup(res + strlen(xhp->rootdir)); + free(res); + res = p; + free(lnk); + } else { + /* absolute */ + res = lnk; + } + return res; } int @@ -77,9 +99,6 @@ check_pkg_symlinks(struct xbps_handle *xhp, const char *pkgname, void *arg) xbps_array_t array; xbps_object_t obj; xbps_dictionary_t filesd = arg; - const char *file, *tgt = NULL; - char path[PATH_MAX], tgt_path[PATH_MAX], *p, *buf, *buf2, *lnk, *dname; - int rv; bool broken = false; array = xbps_dictionary_get(filesd, "links"); @@ -87,6 +106,9 @@ check_pkg_symlinks(struct xbps_handle *xhp, const char *pkgname, void *arg) return false; for (unsigned int i = 0; i < xbps_array_count(array); i++) { + const char *file = NULL, *tgt = NULL; + char path[PATH_MAX], *lnk = NULL, *tlnk = NULL; + obj = xbps_array_get(array, i); if (!xbps_dictionary_get_cstring_nocopy(obj, "file", &file)) continue; @@ -96,62 +118,61 @@ check_pkg_symlinks(struct xbps_handle *xhp, const char *pkgname, void *arg) "empty target object!\n", pkgname, file); continue; } - if (strcmp(tgt, "") == 0) { + if (tgt[0] == '\0') { xbps_warn_printf("%s: `%s' symlink with " "empty target object!\n", pkgname, file); continue; } - - if (strcmp(xhp->rootdir, "/")) { - snprintf(path, sizeof(path), "%s%s", xhp->rootdir, file); - snprintf(tgt_path, sizeof(tgt_path), "%s%s", xhp->rootdir, tgt); - - strncpy(tgt_path, tgt, sizeof(tgt_path)-1); - } else { - strncpy(path, file, sizeof(path)-1); - strncpy(tgt_path, tgt, sizeof(tgt_path)-1); - } - - if ((lnk = symlink_target(pkgname, path)) == NULL) - continue; - - p = strdup(path); - assert(p); - dname = dirname(p); - buf = xbps_xasprintf("%s/%s", dname, lnk); - free(p); - - buf2 = realpath(path, NULL); - if (buf2 == NULL) { - xbps_warn_printf("%s: broken symlink %s (target: %s)\n", - pkgname, file, tgt); - free(buf); - free(lnk); + snprintf(path, sizeof(path), "%s/%s", xhp->rootdir, file); + if ((lnk = symlink_target(xhp, path)) == NULL) { + xbps_error_printf("%s: broken symlink %s (target: %s)\n", pkgname, file, tgt); + broken = true; continue; } + if (tgt[0] != '/') { + char *p, *p1, *dname; - rv = 1; - if (lnk[0] != '/') { - /* relative symlink */ - if ((strcmp(lnk, tgt) == 0) || - (strcmp(buf, tgt_path) == 0) || - (strcmp(buf2, tgt_path) == 0)) - rv = 0; + p = strdup(file); + assert(p); + dname = dirname(p); + assert(dname); + snprintf(path, sizeof(path), "%s/%s", dname, tgt); + p1 = realpath(path, NULL); + free(p); + if (p1 == NULL) { + xbps_error_printf("%s: failed to realpath %s: %s\n", + pkgname, file, strerror(errno)); + free(lnk); + continue; + } + if (strcmp(xhp->rootdir, "/") == 0) + tlnk = strdup(p1); + else + tlnk = strdup(p1 + strlen(xhp->rootdir)); + free(p1); } else { - /* absolute symlink */ - if (strcmp(lnk, tgt) == 0) - rv = 0; - } + char *p; - if (rv) { + snprintf(path, sizeof(path), "%s/%s", xhp->rootdir, tgt); + if ((p = realpath(path, NULL))) { + if (strcmp(xhp->rootdir, "/") == 0) + tlnk = strdup(p); + else + tlnk = strdup(p + strlen(xhp->rootdir)); + free(p); + } else { + tlnk = strdup(tgt); + } + } + /* absolute */ + if (strcmp(lnk, tlnk)) { xbps_warn_printf("%s: modified symlink %s " "points to %s (shall be %s)\n", - pkgname, file, lnk, tgt); + pkgname, file, lnk, tlnk); broken = true; } - free(buf); - free(buf2); free(lnk); + free(tlnk); } return broken; }