]>
Commit | Line | Data |
---|---|---|
2ed04863 | 1 | // systemtap debuginfo rpm finder |
ef36f781 | 2 | // Copyright (C) 2009-2014 Red Hat Inc. |
2ed04863 WC |
3 | // |
4 | // This file is part of systemtap, and is free software. You can | |
5 | // redistribute it and/or modify it under the terms of the GNU General | |
6 | // Public License (GPL); either version 2, or (at your option) any | |
7 | // later version. | |
8 | ||
9 | #include "config.h" | |
10 | #include "session.h" | |
11 | #include "rpm_finder.h" | |
12 | ||
13 | #include <iostream> | |
14 | #include <fstream> | |
15 | #include <sstream> | |
16 | #include <cerrno> | |
17 | #include <cstdlib> | |
18 | ||
19 | using namespace std; | |
20 | ||
21 | #ifdef HAVE_LIBRPM | |
22 | ||
23 | extern "C" { | |
24 | ||
25 | #define _RPM_4_4_COMPAT | |
26 | #include <string.h> | |
27 | #include <rpm/rpmlib.h> | |
28 | #include <rpm/rpmts.h> | |
29 | #include <rpm/rpmdb.h> | |
30 | #include <rpm/header.h> | |
31 | ||
32 | #ifndef xfree | |
33 | #define xfree free | |
34 | #endif | |
35 | ||
36 | } | |
37 | ||
d389518f DB |
38 | #if ! HAVE_LIBRPMIO && HAVE_NSS |
39 | extern "C" { | |
40 | #include <nss.h> | |
41 | } | |
9a0b2b7c | 42 | #include "nsscommon.h" |
d389518f DB |
43 | #endif |
44 | ||
2ed04863 WC |
45 | /* Returns the count of newly added rpms. */ |
46 | /* based on the code in F11 gdb-6.8.50.20090302 source rpm */ | |
76c87907 | 47 | /* Added in the rpm_type parameter to specify what rpm to look for */ |
2ed04863 WC |
48 | |
49 | static int | |
76c87907 | 50 | missing_rpm_enlist (systemtap_session& sess, const char *filename, const char *rpm_type) |
2ed04863 WC |
51 | { |
52 | static int rpm_init_done = 0; | |
53 | rpmts ts; | |
54 | rpmdbMatchIterator mi; | |
55 | int count = 0; | |
56 | ||
57 | if (filename == NULL) | |
58 | return 0; | |
59 | ||
60 | if (!rpm_init_done) | |
61 | { | |
62 | static int init_tried; | |
63 | ||
64 | /* Already failed the initialization before? */ | |
65 | if (init_tried) | |
66 | return 0; | |
67 | init_tried = 1; | |
68 | ||
69 | if (rpmReadConfigFiles(NULL, NULL) != 0) | |
70 | { | |
efee9a98 | 71 | cerr << _("Error reading the rpm configuration files") << endl; |
2ed04863 WC |
72 | return 0; |
73 | } | |
74 | ||
75 | rpm_init_done = 1; | |
76 | } | |
77 | ||
5f429a70 JS |
78 | /* If we've seen this combo before, don't check again... */ |
79 | if (!sess.rpms_checked.insert(string(filename) + rpm_type).second) | |
80 | return 0; | |
81 | ||
76c87907 | 82 | ts = rpmtsCreate(); |
2ed04863 WC |
83 | |
84 | mi = rpmtsInitIterator(ts, RPMTAG_BASENAMES, filename, 0); | |
85 | if (mi != NULL) | |
86 | { | |
87 | for (;;) | |
88 | { | |
89 | Header h; | |
76c87907 LB |
90 | char *rpminfo, *s, *s2; |
91 | char header[31] = {}; | |
92 | const char* arch = ".%{arch}"; | |
93 | sprintf(header, "%%{sourcerpm}%s%s", rpm_type, arch); | |
2ed04863 | 94 | errmsg_t err; |
76c87907 | 95 | size_t rpminfolen = strlen(rpm_type); |
2ed04863 | 96 | size_t srcrpmlen = sizeof (".src.rpm") - 1; |
76c87907 | 97 | rpmdbMatchIterator mi_rpminfo; |
2ed04863 WC |
98 | h = rpmdbNextIterator(mi); |
99 | if (h == NULL) | |
100 | break; | |
76c87907 | 101 | /* Verify the kernel file is not already installed. */ |
2ed04863 | 102 | |
76c87907 LB |
103 | rpminfo = headerSprintf(h, header, |
104 | rpmTagTable, rpmHeaderFormats, &err); | |
2ed04863 | 105 | |
76c87907 | 106 | if (!rpminfo) |
2ed04863 | 107 | { |
efee9a98 | 108 | cerr << _("Error querying the rpm file `") << filename << "': " |
2ed04863 WC |
109 | << err << endl; |
110 | continue; | |
111 | } | |
112 | /* s = `.src.rpm-debuginfo.%{arch}' */ | |
76c87907 | 113 | s = strrchr (rpminfo, '-') - srcrpmlen; |
2ed04863 | 114 | s2 = NULL; |
76c87907 | 115 | if (s > rpminfo && memcmp (s, ".src.rpm", srcrpmlen) == 0) |
2ed04863 WC |
116 | { |
117 | /* s2 = `-%{release}.src.rpm-debuginfo.%{arch}' */ | |
76c87907 | 118 | s2 = (char *) memrchr (rpminfo, '-', s - rpminfo); |
2ed04863 WC |
119 | } |
120 | if (s2) | |
121 | { | |
122 | /* s2 = `-%{version}-%{release}.src.rpm-debuginfo.%{arch}' */ | |
76c87907 | 123 | s2 = (char *) memrchr (rpminfo, '-', s2 - rpminfo); |
2ed04863 WC |
124 | } |
125 | if (!s2) | |
126 | { | |
efee9a98 | 127 | cerr << _("Error querying the rpm file `") << filename |
76c87907 LB |
128 | << "': " << rpminfo << endl; |
129 | xfree (rpminfo); | |
2ed04863 WC |
130 | continue; |
131 | } | |
132 | /* s = `.src.rpm-debuginfo.%{arch}' */ | |
133 | /* s2 = `-%{version}-%{release}.src.rpm-debuginfo.%{arch}' */ | |
76c87907 LB |
134 | memmove (s2 + rpminfolen, s2, s - s2); |
135 | memcpy (s2, rpm_type, rpminfolen); | |
2ed04863 WC |
136 | /* s = `XXXX.%{arch}' */ |
137 | /* strlen ("XXXX") == srcrpmlen + debuginfolen */ | |
138 | /* s2 = `-debuginfo-%{version}-%{release}XX.%{arch}' */ | |
139 | /* strlen ("XX") == srcrpmlen */ | |
76c87907 LB |
140 | memmove (s + rpminfolen, s + srcrpmlen + rpminfolen, |
141 | strlen (s + srcrpmlen + rpminfolen) + 1); | |
2ed04863 WC |
142 | /* s = `-debuginfo-%{version}-%{release}.%{arch}' */ |
143 | ||
144 | /* RPMDBI_PACKAGES requires keylen == sizeof (int). */ | |
145 | /* RPMDBI_LABEL is an interface for NVR-based dbiFindByLabel(). */ | |
76c87907 LB |
146 | mi_rpminfo = rpmtsInitIterator(ts, (rpmTag) RPMDBI_LABEL, |
147 | rpminfo, 0); | |
148 | if (mi_rpminfo) | |
2ed04863 | 149 | { |
76c87907 | 150 | rpmdbFreeIterator(mi_rpminfo); |
2ed04863 WC |
151 | count = 0; |
152 | break; | |
153 | } | |
2ed04863 | 154 | /* The allocated memory gets utilized below for MISSING_RPM_HASH. */ |
76c87907 LB |
155 | if(strcmp(rpm_type,"-debuginfo")==0){ |
156 | xfree(rpminfo); | |
157 | rpminfo = headerSprintf(h, | |
158 | "%{name}-%{version}-%{release}.%{arch}", | |
159 | rpmTagTable, rpmHeaderFormats, &err); | |
160 | } | |
161 | if (!rpminfo) | |
2ed04863 | 162 | { |
efee9a98 | 163 | cerr << _("Error querying the rpm file `") << filename |
2ed04863 WC |
164 | << "': " << err << endl; |
165 | continue; | |
166 | } | |
167 | ||
168 | /* Base package name for `debuginfo-install'. We do not use the | |
76c87907 LB |
169 | `yum' command directly as the line |
170 | yum --enablerepo='*-debuginfo' install NAME-debuginfo.ARCH | |
171 | would be more complicated than just: | |
172 | debuginfo-install NAME-VERSION-RELEASE.ARCH | |
173 | Do not supply the rpm base name (derived from .src.rpm name) as | |
174 | debuginfo-install is unable to install the debuginfo package if | |
175 | the base name PKG binary rpm is not installed while for example | |
176 | PKG-libs would be installed (RH Bug 467901). | |
177 | FUTURE: After multiple debuginfo versions simultaneously installed | |
178 | get supported the support for the VERSION-RELEASE tags handling | |
179 | may need an update. */ | |
180 | sess.rpms_to_install.insert(rpminfo); | |
181 | } | |
182 | count++; | |
2ed04863 WC |
183 | rpmdbFreeIterator(mi); |
184 | } | |
185 | ||
186 | rpmtsFree(ts); | |
d389518f DB |
187 | |
188 | #if HAVE_NSS | |
189 | // librpm uses NSS cryptography but doesn't shut down NSS when it is done. | |
190 | // If NSS is available, it will be used by the compile server client on | |
191 | // specific certificate databases and thus, it must be shut down first. | |
192 | // Get librpm to do it if we can. Otherwise do it ourselves. | |
193 | #if HAVE_LIBRPMIO | |
194 | rpmFreeCrypto (); // Shuts down NSS within librpm | |
195 | #else | |
aeb9cc10 | 196 | nssCleanup (NULL); // Shut down NSS ourselves |
d389518f DB |
197 | #endif |
198 | #endif | |
199 | ||
2ed04863 WC |
200 | return count; |
201 | } | |
2ed04863 WC |
202 | #endif /* HAVE_LIBRPM */ |
203 | ||
204 | void | |
76c87907 | 205 | missing_rpm_list_print (systemtap_session &sess, const char* rpm_type) |
2ed04863 WC |
206 | { |
207 | #ifdef HAVE_LIBRPM | |
c05365e6 | 208 | if (sess.rpms_to_install.size() > 0 && ! sess.suppress_warnings) { |
76c87907 LB |
209 | |
210 | if(strcmp(rpm_type,"-devel")==0) | |
efee9a98 | 211 | cerr << _("Incorrect version or missing kernel-devel package, use: yum install "); |
76c87907 LB |
212 | |
213 | else if(strcmp(rpm_type,"-debuginfo")==0) | |
efee9a98 | 214 | cerr << _("Missing separate debuginfos, use: debuginfo-install "); |
76c87907 LB |
215 | |
216 | else{ | |
efee9a98 | 217 | cerr << _("Incorrect parameter passed, please report this error.") << endl; |
76c87907 LB |
218 | _exit(1); |
219 | } | |
220 | ||
2ed04863 WC |
221 | for (set<std::string>::iterator it=sess.rpms_to_install.begin(); |
222 | it !=sess.rpms_to_install.end(); it++) | |
76c87907 | 223 | { |
2ed04863 | 224 | cerr << *it << " "; |
76c87907 | 225 | } |
2ed04863 WC |
226 | cerr << endl; |
227 | } | |
228 | #endif | |
229 | } | |
230 | ||
231 | int | |
232 | find_debug_rpms (systemtap_session &sess, const char * filename) | |
233 | { | |
234 | #ifdef HAVE_LIBRPM | |
76c87907 LB |
235 | const char *rpm_type = "-debuginfo"; |
236 | return missing_rpm_enlist(sess, filename, rpm_type); | |
237 | #else | |
238 | return 0; | |
239 | #endif | |
240 | } | |
241 | ||
242 | int find_devel_rpms(systemtap_session &sess, const char * filename) | |
243 | { | |
244 | #ifdef HAVE_LIBRPM | |
245 | const char *rpm_type = "-devel"; | |
246 | return missing_rpm_enlist(sess, filename, rpm_type); | |
2ed04863 WC |
247 | #else |
248 | return 0; | |
249 | #endif | |
250 | } |