9
9
#include <popt.h>
10
10
#include <gelf.h>
11
11
12
+ #include <link.h>
13
+ #include <dlfcn.h>
14
+
12
15
#include <rpm/rpmstring.h>
13
16
#include <rpm/argv.h>
14
17
18
+ int libtool_version_fallback = 0 ;
15
19
int soname_only = 0 ;
16
20
int fake_soname = 1 ;
17
21
int filter_soname = 1 ;
@@ -33,6 +37,53 @@ typedef struct elfInfo_s {
33
37
ARGV_t provides ;
34
38
} elfInfo ;
35
39
40
+ /*
41
+ * If filename contains ".so" followed by a version number, return
42
+ * a copy of the version number.
43
+ */
44
+ static char * getLibtoolVer (const char * filename )
45
+ {
46
+ const char * so ;
47
+ int found_digit , found_dot = 0 ;
48
+ // Start from the end of the string. Verify that it ends with
49
+ // numbers and dots, preceded by ".so.".
50
+ so = filename + strlen (filename );
51
+ while (so > filename + 2 ) {
52
+ if (* so == '.' ) {
53
+ found_dot ++ ;
54
+ so -- ;
55
+ continue ;
56
+ } else if (strchr ("0123456789" , * so )) {
57
+ found_digit ++ ;
58
+ so -- ;
59
+ continue ;
60
+ } else if (strncmp (so - 2 , ".so." , 4 ) == 0 ) {
61
+ so += 2 ;
62
+ if (found_digit && found_dot > 1 ) {
63
+ return strdup (so );
64
+ }
65
+ break ;
66
+ } else {
67
+ return NULL ;
68
+ }
69
+ }
70
+ return NULL ;
71
+ }
72
+
73
+ static char * getLibtoolVerFromShLink (const char * filename )
74
+ {
75
+ void * dl_handle ;
76
+ struct link_map * linkmap ;
77
+ char * version = NULL ;
78
+ dl_handle = dlmopen (LM_ID_NEWLM , filename , RTLD_LAZY );
79
+ if (dl_handle == NULL ) return NULL ;
80
+ if (dlinfo (dl_handle , RTLD_DI_LINKMAP , & linkmap ) != -1 ) {
81
+ version = getLibtoolVer (linkmap -> l_name );
82
+ }
83
+ dlclose (dl_handle );
84
+ return version ;
85
+ }
86
+
36
87
/*
37
88
* Rough soname sanity filtering: all sane soname's dependencies need to
38
89
* contain ".so", and normal linkable libraries start with "lib",
@@ -96,14 +147,21 @@ static const char *mkmarker(GElf_Ehdr *ehdr)
96
147
}
97
148
98
149
static void addDep (ARGV_t * deps ,
99
- const char * soname , const char * ver , const char * marker )
150
+ const char * soname , const char * ver , const char * marker ,
151
+ const char * compare_op , const char * fallback_ver )
100
152
{
101
153
char * dep = NULL ;
102
154
103
155
if (skipSoname (soname ))
104
156
return ;
105
157
106
- if (ver || marker ) {
158
+ if (compare_op && fallback_ver ) {
159
+ // when versioned symbols aren't available, the libtool version
160
+ // might be used to generate a minimum dependency version.
161
+ rasprintf (& dep ,
162
+ "%s()%s %s %s" , soname , marker ? marker : "" ,
163
+ compare_op , fallback_ver );
164
+ } else if (ver || marker ) {
107
165
rasprintf (& dep ,
108
166
"%s(%s)%s" , soname , ver ? ver : "" , marker ? marker : "" );
109
167
}
@@ -143,10 +201,10 @@ static void processVerDef(Elf_Scn *scn, GElf_Shdr *shdr, elfInfo *ei)
143
201
auxoffset += aux -> vda_next ;
144
202
continue ;
145
203
} else if (soname && !soname_only ) {
146
- addDep (& ei -> provides , soname , s , ei -> marker );
204
+ addDep (& ei -> provides , soname , s , ei -> marker , NULL , NULL );
147
205
}
148
206
}
149
-
207
+
150
208
}
151
209
}
152
210
rfree (soname );
@@ -182,7 +240,7 @@ static void processVerNeed(Elf_Scn *scn, GElf_Shdr *shdr, elfInfo *ei)
182
240
break ;
183
241
184
242
if (genRequires (ei ) && soname && !soname_only ) {
185
- addDep (& ei -> requires , soname , s , ei -> marker );
243
+ addDep (& ei -> requires , soname , s , ei -> marker , NULL , NULL );
186
244
}
187
245
auxoffset += aux -> vna_next ;
188
246
}
@@ -222,8 +280,14 @@ static void processDynamic(Elf_Scn *scn, GElf_Shdr *shdr, elfInfo *ei)
222
280
case DT_NEEDED :
223
281
if (genRequires (ei )) {
224
282
s = elf_strptr (ei -> elf , shdr -> sh_link , dyn -> d_un .d_val );
225
- if (s )
226
- addDep (& ei -> requires , s , NULL , ei -> marker );
283
+ if (s ) {
284
+ char * libtool_ver = NULL ;
285
+ if (libtool_version_fallback ) {
286
+ libtool_ver = getLibtoolVerFromShLink (s );
287
+ }
288
+ addDep (& ei -> requires , s , NULL , ei -> marker , ">=" , libtool_ver );
289
+ free (libtool_ver );
290
+ }
227
291
}
228
292
break ;
229
293
}
@@ -322,8 +386,14 @@ static int processFile(const char *fn, int dtype)
322
386
const char * bn = strrchr (fn , '/' );
323
387
ei -> soname = rstrdup (bn ? bn + 1 : fn );
324
388
}
325
- if (ei -> soname )
326
- addDep (& ei -> provides , ei -> soname , NULL , ei -> marker );
389
+ if (ei -> soname ) {
390
+ char * libtool_ver = NULL ;
391
+ if (libtool_version_fallback ) {
392
+ libtool_ver = getLibtoolVer (fn );
393
+ }
394
+ addDep (& ei -> provides , ei -> soname , NULL , ei -> marker , "=" , libtool_ver );
395
+ free (libtool_ver );
396
+ }
327
397
}
328
398
329
399
/* If requested and present, add dep for interpreter (ie dynamic linker) */
@@ -359,11 +429,12 @@ int main(int argc, char *argv[])
359
429
struct poptOption opts [] = {
360
430
{ "provides" , 'P' , POPT_ARG_VAL , & provides , -1 , NULL , NULL },
361
431
{ "requires" , 'R' , POPT_ARG_VAL , & requires , -1 , NULL , NULL },
432
+ { "libtool-version-fallback" , 0 , POPT_ARG_VAL , & libtool_version_fallback , -1 , NULL , NULL },
362
433
{ "soname-only" , 0 , POPT_ARG_VAL , & soname_only , -1 , NULL , NULL },
363
434
{ "no-fake-soname" , 0 , POPT_ARG_VAL , & fake_soname , 0 , NULL , NULL },
364
435
{ "no-filter-soname" , 0 , POPT_ARG_VAL , & filter_soname , 0 , NULL , NULL },
365
436
{ "require-interp" , 0 , POPT_ARG_VAL , & require_interp , -1 , NULL , NULL },
366
- POPT_AUTOHELP
437
+ POPT_AUTOHELP
367
438
POPT_TABLEEND
368
439
};
369
440
0 commit comments