// systemtap debuginfo rpm finder // Copyright (C) 2009-2014 Red Hat Inc. // // This file is part of systemtap, and is free software. You can // redistribute it and/or modify it under the terms of the GNU General // Public License (GPL); either version 2, or (at your option) any // later version. #include "config.h" #include "session.h" #include "rpm_finder.h" #include #include #include #include #include using namespace std; #ifdef HAVE_LIBRPM extern "C" { #include #include #include #include #include #ifndef xfree #define xfree free #endif } #if ! HAVE_LIBRPMIO && HAVE_NSS extern "C" { #include } #include "nsscommon.h" #endif /* Returns the count of newly added rpms. */ /* based on the code in F11 gdb-6.8.50.20090302 source rpm */ /* Added in the rpm_type parameter to specify what rpm to look for */ static int missing_rpm_enlist (systemtap_session& sess, const char *filename, const char *rpm_type) { static int rpm_init_done = 0; rpmts ts; rpmdbMatchIterator mi; int count = 0; if (filename == NULL) return 0; if (!rpm_init_done) { static int init_tried; /* Already failed the initialization before? */ if (init_tried) return 0; init_tried = 1; if (rpmReadConfigFiles(NULL, NULL) != 0) { cerr << _("Error reading the rpm configuration files") << endl; return 0; } rpm_init_done = 1; } /* If we've seen this combo before, don't check again... */ if (!sess.rpms_checked.insert(string(filename) + rpm_type).second) return 0; ts = rpmtsCreate(); mi = rpmtsInitIterator(ts, RPMTAG_BASENAMES, filename, 0); if (mi != NULL) { for (;;) { Header h; char *rpminfo, *s, *s2; char header[31] = {}; const char* arch = ".%{arch}"; sprintf(header, "%%{sourcerpm}%s%s", rpm_type, arch); errmsg_t err; size_t rpminfolen = strlen(rpm_type); size_t srcrpmlen = sizeof (".src.rpm") - 1; rpmdbMatchIterator mi_rpminfo; h = rpmdbNextIterator(mi); if (h == NULL) break; /* Verify the kernel file is not already installed. */ rpminfo = headerFormat(h, header, &err); if (!rpminfo) { cerr << _("Error querying the rpm file `") << filename << "': " << err << endl; continue; } /* s = `.src.rpm-debuginfo.%{arch}' */ s = strrchr (rpminfo, '-') - srcrpmlen; s2 = NULL; if (s > rpminfo && memcmp (s, ".src.rpm", srcrpmlen) == 0) { /* s2 = `-%{release}.src.rpm-debuginfo.%{arch}' */ s2 = (char *) memrchr (rpminfo, '-', s - rpminfo); } if (s2) { /* s2 = `-%{version}-%{release}.src.rpm-debuginfo.%{arch}' */ s2 = (char *) memrchr (rpminfo, '-', s2 - rpminfo); } if (!s2) { cerr << _("Error querying the rpm file `") << filename << "': " << rpminfo << endl; xfree (rpminfo); continue; } /* s = `.src.rpm-debuginfo.%{arch}' */ /* s2 = `-%{version}-%{release}.src.rpm-debuginfo.%{arch}' */ memmove (s2 + rpminfolen, s2, s - s2); memcpy (s2, rpm_type, rpminfolen); /* s = `XXXX.%{arch}' */ /* strlen ("XXXX") == srcrpmlen + debuginfolen */ /* s2 = `-debuginfo-%{version}-%{release}XX.%{arch}' */ /* strlen ("XX") == srcrpmlen */ memmove (s + rpminfolen, s + srcrpmlen + rpminfolen, strlen (s + srcrpmlen + rpminfolen) + 1); /* s = `-debuginfo-%{version}-%{release}.%{arch}' */ /* RPMDBI_PACKAGES requires keylen == sizeof (int). */ /* RPMDBI_LABEL is an interface for NVR-based dbiFindByLabel(). */ mi_rpminfo = rpmtsInitIterator(ts, (rpmTag) RPMDBI_LABEL, rpminfo, 0); if (mi_rpminfo) { rpmdbFreeIterator(mi_rpminfo); count = 0; break; } /* The allocated memory gets utilized below for MISSING_RPM_HASH. */ if(strcmp(rpm_type,"-debuginfo")==0){ xfree(rpminfo); rpminfo = headerFormat(h, "%{name}-%{version}-%{release}.%{arch}", &err); } if (!rpminfo) { cerr << _("Error querying the rpm file `") << filename << "': " << err << endl; continue; } /* Base package name for `debuginfo-install'. We do not use the `yum' command directly as the line yum --enablerepo='*-debuginfo' install NAME-debuginfo.ARCH would be more complicated than just: debuginfo-install NAME-VERSION-RELEASE.ARCH Do not supply the rpm base name (derived from .src.rpm name) as debuginfo-install is unable to install the debuginfo package if the base name PKG binary rpm is not installed while for example PKG-libs would be installed (RH Bug 467901). FUTURE: After multiple debuginfo versions simultaneously installed get supported the support for the VERSION-RELEASE tags handling may need an update. */ sess.rpms_to_install.insert(rpminfo); } count++; rpmdbFreeIterator(mi); } rpmtsFree(ts); #if HAVE_NSS // librpm uses NSS cryptography but doesn't shut down NSS when it is done. // If NSS is available, it will be used by the compile server client on // specific certificate databases and thus, it must be shut down first. // Get librpm to do it if we can. Otherwise do it ourselves. #if HAVE_LIBRPMIO rpmFreeCrypto (); // Shuts down NSS within librpm #else nssCleanup (NULL); // Shut down NSS ourselves #endif #endif return count; } #endif /* HAVE_LIBRPM */ #ifdef HAVE_LIBRPM void missing_rpm_list_print (systemtap_session &sess, const char* rpm_type) { if (sess.rpms_to_install.size() > 0 && ! sess.suppress_warnings) { if(strcmp(rpm_type,"-devel")==0) { // We default to using 'yum' as the package manager, unless we // can find 'dnf'. string pkg_mgr = "yum"; string dnf_path = find_executable("dnf"); if (is_fully_resolved(dnf_path, "", sess.sysenv)) pkg_mgr = "dnf"; cerr << sess.colorize(_F("Incorrect version or missing kernel-devel package, use: %s install ", pkg_mgr.c_str()), "error"); } else if(strcmp(rpm_type,"-debuginfo")==0) cerr << sess.colorize(_("Missing separate debuginfos, use: debuginfo-install "), "error"); else{ cerr << _("Incorrect parameter passed, please report this error.") << endl; _exit(1); } for (set::iterator it=sess.rpms_to_install.begin(); it !=sess.rpms_to_install.end(); it++) { cerr << sess.colorize(*it,"error") << " "; } cerr << endl; } } #else void missing_rpm_list_print (systemtap_session &, const char *) { } #endif #ifdef HAVE_LIBRPM int find_debug_rpms (systemtap_session &sess, const char * filename) { const char *rpm_type = "-debuginfo"; return missing_rpm_enlist(sess, filename, rpm_type); } #else int find_debug_rpms (systemtap_session &, const char *) { return 0; } #endif #ifdef HAVE_LIBRPM int find_devel_rpms(systemtap_session &sess, const char * filename) { const char *rpm_type = "-devel"; return missing_rpm_enlist(sess, filename, rpm_type); } #else int find_devel_rpms(systemtap_session &, const char *) { return 0; } #endif