/[gentoo-projects]/pax-utils/scanelf.c
Gentoo

Diff of /pax-utils/scanelf.c

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

Revision 1.27 Revision 1.40
1/* 1/*
2 * Copyright 2003 Ned Ludd <solar@gentoo.org> 2 * Copyright 2003 Ned Ludd <solar@gentoo.org>
3 * Copyright 1999-2005 Gentoo Foundation 3 * Copyright 1999-2005 Gentoo Foundation
4 * Distributed under the terms of the GNU General Public License v2 4 * Distributed under the terms of the GNU General Public License v2
5 * $Header: /var/cvsroot/gentoo-projects/pax-utils/Attic/scanelf.c,v 1.27 2005/04/05 01:44:08 vapier Exp $ 5 * $Header: /var/cvsroot/gentoo-projects/pax-utils/Attic/scanelf.c,v 1.40 2005/04/21 00:13:03 solar Exp $
6 * 6 *
7 ******************************************************************** 7 ********************************************************************
8 * This program is free software; you can redistribute it and/or 8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License as 9 * modify it under the terms of the GNU General Public License as
10 * published by the Free Software Foundation; either version 2 of the 10 * published by the Free Software Foundation; either version 2 of the
22 */ 22 */
23 23
24#include <stdio.h> 24#include <stdio.h>
25#include <stdlib.h> 25#include <stdlib.h>
26#include <sys/types.h> 26#include <sys/types.h>
27#define __USE_GNU
27#include <string.h> 28#include <string.h>
28#include <errno.h> 29#include <errno.h>
29#include <unistd.h> 30#include <unistd.h>
30#include <sys/stat.h> 31#include <sys/stat.h>
31#include <dirent.h> 32#include <dirent.h>
32#include <getopt.h> 33#include <getopt.h>
33#include <assert.h> 34#include <assert.h>
34 35
35#include "paxelf.h" 36#include "paxelf.h"
36 37
37static const char *rcsid = "$Id: scanelf.c,v 1.27 2005/04/05 01:44:08 vapier Exp $"; 38static const char *rcsid = "$Id: scanelf.c,v 1.40 2005/04/21 00:13:03 solar Exp $";
38 39#define argv0 "scanelf"
39
40/* helper functions for showing errors */
41#define argv0 "scanelf" /*((*argv != NULL) ? argv[0] : __FILE__ "\b\b")*/
42#define warn(fmt, args...) \
43 fprintf(stderr, "%s: " fmt "\n", argv0, ## args)
44#define warnf(fmt, args...) warn("%s(): " fmt, __FUNCTION__, ## args)
45#define err(fmt, args...) \
46 do { \
47 warn(fmt, ## args); \
48 exit(EXIT_FAILURE); \
49 } while (0)
50 40
51 41
52 42
53/* prototypes */ 43/* prototypes */
54static void scanelf_file(const char *filename); 44static void scanelf_file(const char *filename);
59static void parseargs(int argc, char *argv[]); 49static void parseargs(int argc, char *argv[]);
60 50
61/* variables to control behavior */ 51/* variables to control behavior */
62static char scan_ldpath = 0; 52static char scan_ldpath = 0;
63static char scan_envpath = 0; 53static char scan_envpath = 0;
54static char scan_symlink = 1;
64static char dir_recurse = 0; 55static char dir_recurse = 0;
65static char dir_crossmount = 1; 56static char dir_crossmount = 1;
66static char show_pax = 0; 57static char show_pax = 0;
67static char show_stack = 0; 58static char show_stack = 0;
68static char show_textrel = 0; 59static char show_textrel = 0;
69static char show_rpath = 0; 60static char show_rpath = 0;
61static char show_needed = 0;
62static char show_interp = 0;
70static char show_banner = 1; 63static char show_banner = 1;
71static char be_quiet = 0; 64static char be_quiet = 0;
72static char be_verbose = 0; 65static char be_verbose = 0;
66static char *find_sym = NULL, *versioned_symname = NULL;
73static char *find_sym = NULL; 67static char *out_format = NULL;
74 68
75 69
76 70
77/* scan an elf file and show all the fun stuff */ 71/* sub-funcs for scanelf_file() */
78static void scanelf_file(const char *filename) 72static void scanelf_file_pax(elfobj *elf, char *found_pax)
73{
74 char *paxflags;
75 if (!show_pax) return;
76
77 paxflags = pax_short_hf_flags(PAX_FLAGS(elf));
78 if (!be_quiet || (be_quiet && strncmp(paxflags, "PeMRxS", 6))) {
79 *found_pax = 1;
80 printf("%s ", pax_short_hf_flags(PAX_FLAGS(elf)));
81 }
82}
83static void scanelf_file_stack(elfobj *elf, char *found_stack, char *found_relro)
79{ 84{
80 int i; 85 int i;
81 char found_pax, found_stack, found_relro, found_textrel, found_rpath, found_sym;
82 elfobj *elf;
83
84 found_pax = found_stack = found_relro = found_textrel = found_rpath = found_sym = 0;
85
86 /* verify this is real ELF */
87 if ((elf = readelf(filename)) == NULL) {
88 if (be_verbose > 2) printf("%s: not an ELF\n", filename);
89 return;
90 }
91
92 if (be_verbose > 1)
93 printf("%s: {%s,%s} scanning file\n", filename,
94 get_elfeitype(elf, EI_CLASS, elf->elf_class),
95 get_elfeitype(elf, EI_DATA, elf->data[EI_DATA]));
96 else if (be_verbose)
97 printf("%s: scanning file\n", filename);
98
99 /* show the header */
100 if (!be_quiet && show_banner) {
101 printf(" TYPE ");
102 if (show_pax) printf(" PAX ");
103 if (show_stack) printf(" STK/REL ");
104 if (show_textrel) printf("TEXTREL ");
105 if (show_rpath) printf("RPATH ");
106 printf(" FILE\n");
107 show_banner = 0;
108 }
109
110 /* dump all the good stuff */
111 if (!be_quiet)
112 printf("%-7s ", get_elfetype(elf));
113
114 if (show_pax) {
115 char *paxflags = pax_short_hf_flags(PAX_FLAGS(elf));
116 if (!be_quiet || (be_quiet && strncmp(paxflags, "PeMRxS", 6))) {
117 found_pax = 1;
118 printf("%s ", pax_short_hf_flags(PAX_FLAGS(elf)));
119 }
120 }
121
122 /* stack fun */
123 if (show_stack) { 86 if (!show_stack) return;
124#define SHOW_STACK(B) \ 87#define SHOW_STACK(B) \
125 if (elf->elf_class == ELFCLASS ## B) { \ 88 if (elf->elf_class == ELFCLASS ## B) { \
126 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \ 89 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \
127 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \ 90 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \
128 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \ 91 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \
129 if (EGET(phdr[i].p_type) != PT_GNU_STACK && \ 92 if (EGET(phdr[i].p_type) != PT_GNU_STACK && \
130 EGET(phdr[i].p_type) != PT_GNU_RELRO) continue; \ 93 EGET(phdr[i].p_type) != PT_GNU_RELRO) continue; \
131 if (be_quiet && !(EGET(phdr[i].p_flags) & PF_X)) \ 94 if (be_quiet && !(EGET(phdr[i].p_flags) & PF_X)) \
132 continue; \ 95 continue; \
133 if (EGET(phdr[i].p_type) == PT_GNU_STACK) \ 96 if (EGET(phdr[i].p_type) == PT_GNU_STACK) \
134 found_stack = 1; \ 97 *found_stack = 1; \
135 if (EGET(phdr[i].p_type) == PT_GNU_RELRO) \ 98 if (EGET(phdr[i].p_type) == PT_GNU_RELRO) \
136 found_relro = 1; \ 99 *found_relro = 1; \
137 printf("%s ", gnu_short_stack_flags(EGET(phdr[i].p_flags))); \ 100 printf("%s ", gnu_short_stack_flags(EGET(phdr[i].p_flags))); \
101 } \
102 }
103 SHOW_STACK(32)
104 SHOW_STACK(64)
105 if (!be_quiet && !*found_stack) printf("--- ");
106 if (!be_quiet && !*found_relro) printf("--- ");
107}
108static void scanelf_file_textrel(elfobj *elf, char *found_textrel)
109{
110 int i;
111 if (!show_textrel) return;
112#define SHOW_TEXTREL(B) \
113 if (elf->elf_class == ELFCLASS ## B) { \
114 Elf ## B ## _Dyn *dyn; \
115 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \
116 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \
117 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \
118 if (phdr[i].p_type != PT_DYNAMIC) continue; \
119 dyn = DYN ## B (elf->data + EGET(phdr[i].p_offset)); \
120 while (EGET(dyn->d_tag) != DT_NULL) { \
121 if (EGET(dyn->d_tag) == DT_TEXTREL) { /*dyn->d_tag != DT_FLAGS)*/ \
122 *found_textrel = 1; \
123 /*if (dyn->d_un.d_val & DF_TEXTREL)*/ \
124 printf("TEXTREL "); \
125 } \
126 ++dyn; \
138 } \ 127 } \
139 }
140 SHOW_STACK(32)
141 SHOW_STACK(64)
142 if (!be_quiet && !found_stack) printf("--- ");
143 if (!be_quiet && !found_relro) printf("--- ");
144 }
145
146 /* textrel fun */
147 if (show_textrel) {
148#define SHOW_TEXTREL(B) \
149 if (elf->elf_class == ELFCLASS ## B) { \
150 Elf ## B ## _Dyn *dyn; \
151 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \
152 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \
153 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \
154 if (phdr[i].p_type != PT_DYNAMIC) continue; \
155 dyn = DYN ## B (elf->data + EGET(phdr[i].p_offset)); \
156 while (EGET(dyn->d_tag) != DT_NULL) { \
157 if (EGET(dyn->d_tag) == DT_TEXTREL) { /*dyn->d_tag != DT_FLAGS)*/ \
158 found_textrel = 1; \
159 /*if (dyn->d_un.d_val & DF_TEXTREL)*/ \
160 printf("TEXTREL "); \
161 } \
162 ++dyn; \
163 } \
164 } } 128 } }
165 SHOW_TEXTREL(32) 129 SHOW_TEXTREL(32)
166 SHOW_TEXTREL(64) 130 SHOW_TEXTREL(64)
167 if (!be_quiet && !found_textrel) printf("------- "); 131 if (!be_quiet && !*found_textrel) printf("------- ");
168 } 132}
169 133static void scanelf_file_rpath(elfobj *elf, char *found_rpath)
170 /* rpath fun */ 134{
171 /* TODO: if be_quiet, only output RPATH's which aren't in /etc/ld.so.conf */ 135 /* TODO: if be_quiet, only output RPATH's which aren't in /etc/ld.so.conf */
172 if (show_rpath) { 136 int i;
173 char *rpath, *runpath; 137 char *rpath, *runpath;
138 void *strtbl_void;
139
140 if (!show_rpath) return;
141
174 void *strtbl_void = elf_findsecbyname(elf, ".dynstr"); 142 strtbl_void = elf_findsecbyname(elf, ".dynstr");
175 rpath = runpath = NULL; 143 rpath = runpath = NULL;
176 144
177 if (strtbl_void) { 145 if (strtbl_void) {
178#define SHOW_RPATH(B) \ 146#define SHOW_RPATH(B) \
179 if (elf->elf_class == ELFCLASS ## B) { \ 147 if (elf->elf_class == ELFCLASS ## B) { \
180 Elf ## B ## _Dyn *dyn; \ 148 Elf ## B ## _Dyn *dyn; \
181 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \ 149 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \
182 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \ 150 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \
185 if (EGET(phdr[i].p_type) != PT_DYNAMIC) continue; \ 153 if (EGET(phdr[i].p_type) != PT_DYNAMIC) continue; \
186 dyn = DYN ## B (elf->data + EGET(phdr[i].p_offset)); \ 154 dyn = DYN ## B (elf->data + EGET(phdr[i].p_offset)); \
187 while (EGET(dyn->d_tag) != DT_NULL) { \ 155 while (EGET(dyn->d_tag) != DT_NULL) { \
188 if (EGET(dyn->d_tag) == DT_RPATH) { \ 156 if (EGET(dyn->d_tag) == DT_RPATH) { \
189 rpath = elf->data + EGET(strtbl->sh_offset) + EGET(dyn->d_un.d_ptr); \ 157 rpath = elf->data + EGET(strtbl->sh_offset) + EGET(dyn->d_un.d_ptr); \
190 found_rpath = 1; \ 158 *found_rpath = 1; \
191 } else if (EGET(dyn->d_tag) == DT_RUNPATH) { \ 159 } else if (EGET(dyn->d_tag) == DT_RUNPATH) { \
192 runpath = elf->data + EGET(strtbl->sh_offset) + EGET(dyn->d_un.d_ptr); \ 160 runpath = elf->data + EGET(strtbl->sh_offset) + EGET(dyn->d_un.d_ptr); \
193 found_rpath = 1; \ 161 *found_rpath = 1; \
194 } \ 162 } \
195 ++dyn; \ 163 ++dyn; \
196 } \ 164 } \
197 } } 165 } }
198 SHOW_RPATH(32) 166 SHOW_RPATH(32)
199 SHOW_RPATH(64) 167 SHOW_RPATH(64)
200 } 168 }
201 if (rpath && runpath) { 169 if (rpath && runpath) {
202 if (!strcmp(rpath, runpath)) 170 if (!strcmp(rpath, runpath))
203 printf("%-5s ", runpath); 171 printf("%-5s ", runpath);
204 else { 172 else {
205 fprintf(stderr, "%s's RPATH [%s] != RUNPATH [%s]\n", filename, rpath, runpath); 173 fprintf(stderr, "RPATH [%s] != RUNPATH [%s]\n", rpath, runpath);
206 printf("{%s,%s} ", rpath, runpath); 174 printf("{%s,%s} ", rpath, runpath);
207 } 175 }
208 } else if (rpath || runpath) 176 } else if (rpath || runpath)
209 printf("%-5s ", (runpath ? runpath : rpath)); 177 printf("%-5s ", (runpath ? runpath : rpath));
210 else if (!be_quiet && !found_rpath) 178 else if (!be_quiet && !*found_rpath)
211 printf(" - "); 179 printf(" - ");
180}
181static void scanelf_file_needed(elfobj *elf, char *found_needed)
182{
183 int i;
184 char *needed;
185 void *strtbl_void;
186
187 if (!show_needed) return;
188
189 strtbl_void = elf_findsecbyname(elf, ".dynstr");
190
191 if (strtbl_void) {
192#define SHOW_NEEDED(B) \
193 if (elf->elf_class == ELFCLASS ## B) { \
194 Elf ## B ## _Dyn *dyn; \
195 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \
196 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \
197 Elf ## B ## _Shdr *strtbl = SHDR ## B (strtbl_void); \
198 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \
199 if (EGET(phdr[i].p_type) != PT_DYNAMIC) continue; \
200 dyn = DYN ## B (elf->data + EGET(phdr[i].p_offset)); \
201 while (EGET(dyn->d_tag) != DT_NULL) { \
202 if (EGET(dyn->d_tag) == DT_NEEDED) { \
203 needed = elf->data + EGET(strtbl->sh_offset) + EGET(dyn->d_un.d_ptr); \
204 if (*found_needed) printf(","); \
205 printf("%s", needed); \
206 *found_needed = 1; \
207 } \
208 ++dyn; \
209 } \
210 } }
211 SHOW_NEEDED(32)
212 SHOW_NEEDED(64)
213 }
214 if (!be_quiet && !*found_needed)
215 printf(" - ");
216 else if (*found_needed)
217 printf(" ");
218}
219static void scanelf_file_interp(elfobj *elf, char *found_interp)
220{
221 void *strtbl_void;
222
223 if (!show_interp) return;
224
225 strtbl_void = elf_findsecbyname(elf, ".interp");
226
227 if (strtbl_void) {
228#define SHOW_INTERP(B) \
229 if (elf->elf_class == ELFCLASS ## B) { \
230 Elf ## B ## _Shdr *strtbl = SHDR ## B (strtbl_void); \
231 printf("%s ", elf->data + EGET(strtbl->sh_offset)); \
232 *found_interp = 1; \
212 } 233 }
213 234 SHOW_INTERP(32)
214 if (!be_quiet || found_pax || found_stack || found_textrel || found_rpath) 235 SHOW_INTERP(64)
215 printf("%s\n", filename); 236 }
216 237 if (!be_quiet && !*found_interp)
217 if (find_sym) { 238 printf(" - ");
239 else if (*found_interp)
240 printf(" ");
241}
242static void scanelf_file_sym(elfobj *elf, char *found_sym, const char *filename)
243{
244 int i;
218 void *symtab_void, *strtab_void; 245 void *symtab_void, *strtab_void;
246
247 if (!find_sym) return;
248
219 symtab_void = elf_findsecbyname(elf, ".symtab"); 249 symtab_void = elf_findsecbyname(elf, ".symtab");
220 strtab_void = elf_findsecbyname(elf, ".strtab"); 250 strtab_void = elf_findsecbyname(elf, ".strtab");
221 251
222 if (symtab_void && strtab_void) { 252 if (symtab_void && strtab_void) {
223#define FIND_SYM(B) \ 253#define FIND_SYM(B) \
224 if (elf->elf_class == ELFCLASS ## B) { \ 254 if (elf->elf_class == ELFCLASS ## B) { \
225 Elf ## B ## _Shdr *symtab = SHDR ## B (symtab_void); \ 255 Elf ## B ## _Shdr *symtab = SHDR ## B (symtab_void); \
226 Elf ## B ## _Shdr *strtab = SHDR ## B (strtab_void); \ 256 Elf ## B ## _Shdr *strtab = SHDR ## B (strtab_void); \
227 Elf ## B ## _Sym *sym = SYM ## B (elf->data + EGET(symtab->sh_offset)); \ 257 Elf ## B ## _Sym *sym = SYM ## B (elf->data + EGET(symtab->sh_offset)); \
228 int cnt = EGET(symtab->sh_size) / EGET(symtab->sh_entsize); \ 258 int cnt = EGET(symtab->sh_size) / EGET(symtab->sh_entsize); \
229 char *symname; \ 259 char *symname; \
230 if (be_verbose > 1) \
231 printf("%s: .symtab has %i entries\n", filename, cnt); \
232 for (i = 0; i < cnt; ++i) { \ 260 for (i = 0; i < cnt; ++i) { \
233 if (sym->st_name) { \ 261 if (sym->st_name) { \
234 symname = (char *)(elf->data + EGET(strtab->sh_offset) + EGET(sym->st_name)); \ 262 symname = (char *)(elf->data + EGET(strtab->sh_offset) + EGET(sym->st_name)); \
235 if (*find_sym == '*' || !strcmp(find_sym, symname)) \ 263 if (*find_sym == '*') { \
236 printf("%s: %5lX %15s %s\n", \ 264 printf("%s(%s) %5lX %15s %s\n", \
237 filename, \ 265 ((*found_sym == 0) ? "\n\t" : "\t"), \
266 (char *)basename(filename), \
238 (long)sym->st_size, \ 267 (long)sym->st_size, \
239 (char *)get_elfstttype(sym->st_info & 0xF), \ 268 (char *)get_elfstttype(sym->st_info), \
240 symname); \ 269 symname); \
270 *found_sym = 1; \
271 } else if ((strcmp(find_sym, symname) == 0) || \
272 (strcmp(symname, versioned_symname) == 0)) \
273 (*found_sym)++; \
241 } \ 274 } \
242 ++sym; \ 275 ++sym; \
243 } } 276 } }
244 FIND_SYM(32) 277 FIND_SYM(32)
245 FIND_SYM(64) 278 FIND_SYM(64)
279 }
280 if (*find_sym != '*') {
281 if (*found_sym)
282 printf(" %s ", find_sym);
283 else if (!be_quiet)
284 printf(" - ");
285 }
286}
287/* scan an elf file and show all the fun stuff */
288static void scanelf_file(const char *filename)
289{
290 int i;
291 char found_pax, found_stack, found_relro, found_textrel,
292 found_rpath, found_needed, found_interp, found_sym,
293 found_file;
294 elfobj *elf;
295 struct stat st;
296
297 /* make sure 'filename' exists */
298 if (lstat(filename, &st) == -1) {
299 if (be_verbose > 2) printf("%s: does not exist\n", filename);
300 return;
301 }
302 /* always handle regular files and handle symlinked files if no -y */
303 if (!(S_ISREG(st.st_mode) || (S_ISLNK(st.st_mode) && scan_symlink))) {
304 if (be_verbose > 2) printf("%s: skipping non-file\n", filename);
305 return;
306 }
307
308 found_pax = found_stack = found_relro = found_textrel = \
309 found_rpath = found_needed = found_interp = found_sym = \
310 found_file = 0;
311
312 /* verify this is real ELF */
313 if ((elf = readelf(filename)) == NULL) {
314 if (be_verbose > 2) printf("%s: not an ELF\n", filename);
315 return;
316 }
317
318 if (be_verbose > 1)
319 printf("%s: {%s,%s} scanning file\n", filename,
320 get_elfeitype(elf, EI_CLASS, elf->elf_class),
321 get_elfeitype(elf, EI_DATA, elf->data[EI_DATA]));
322 else if (be_verbose)
323 printf("%s: scanning file\n", filename);
324
325 /* show the header */
326 if (!be_quiet && show_banner) {
327 if (out_format) {
328 for (i=0; out_format[i]; ++i) {
329 if (out_format[i] != '%') continue;
330
331 switch (out_format[++i]) {
332 case '%': break;
333 case 'F': printf("FILE "); break;
334 case 'x': printf(" PAX "); break;
335 case 'e': printf("STK/REL "); break;
336 case 't': printf("TEXTREL "); break;
337 case 'r': printf("RPATH "); break;
338 case 'n': printf("NEEDED "); break;
339 case 'i': printf("INTERP "); break;
340 case 's': printf("SYM "); break;
341 }
246 } 342 }
343 } else {
344 printf(" TYPE ");
345 if (show_pax) printf(" PAX ");
346 if (show_stack) printf("STK/REL ");
347 if (show_textrel) printf("TEXTREL ");
348 if (show_rpath) printf("RPATH ");
349 if (show_needed) printf("NEEDED ");
350 if (show_interp) printf("INTERP ");
351 if (find_sym) printf("SYM ");
352 }
353 if (!found_file) printf(" FILE");
354 printf("\n");
355 show_banner = 0;
356 }
357
358 /* dump all the good stuff */
359 if (!be_quiet && !out_format)
360 printf("%-7s ", get_elfetype(elf));
361
362 if (out_format) {
363 for (i=0; out_format[i]; ++i) {
364 if (out_format[i] != '%') {
365 printf("%c", out_format[i]);
366 continue;
367 }
368
369 switch (out_format[++i]) {
370 case '%': printf("%%"); break;
371 case 'F': found_file = 1; printf("%s ", filename); break;
372 case 'x': scanelf_file_pax(elf, &found_pax); break;
373 case 'e': scanelf_file_stack(elf, &found_stack, &found_relro); break;
374 case 't': scanelf_file_textrel(elf, &found_textrel); break;
375 case 'r': scanelf_file_rpath(elf, &found_rpath); break;
376 case 'n': scanelf_file_needed(elf, &found_needed); break;
377 case 'i': scanelf_file_interp(elf, &found_interp); break;
378 case 's': scanelf_file_sym(elf, &found_sym, filename); break;
379 }
380 }
381 } else {
382 scanelf_file_pax(elf, &found_pax);
383 scanelf_file_stack(elf, &found_stack, &found_relro);
384 scanelf_file_textrel(elf, &found_textrel);
385 scanelf_file_rpath(elf, &found_rpath);
386 scanelf_file_needed(elf, &found_needed);
387 scanelf_file_interp(elf, &found_interp);
388 scanelf_file_sym(elf, &found_sym, filename);
389 }
390
391 if (!found_file) {
392 if (!be_quiet || found_pax || found_stack || found_textrel || \
393 found_rpath || found_needed || found_sym)
394 puts(filename);
395 } else {
396 printf("\n");
247 } 397 }
248 398
249 unreadelf(elf); 399 unreadelf(elf);
250} 400}
251 401
254{ 404{
255 register DIR *dir; 405 register DIR *dir;
256 register struct dirent *dentry; 406 register struct dirent *dentry;
257 struct stat st_top, st; 407 struct stat st_top, st;
258 char buf[_POSIX_PATH_MAX]; 408 char buf[_POSIX_PATH_MAX];
259 size_t len = 0; 409 size_t pathlen = 0, len = 0;
260 410
261 /* make sure path exists */ 411 /* make sure path exists */
262 if (lstat(path, &st_top) == -1) 412 if (lstat(path, &st_top) == -1) {
413 if (be_verbose > 2) printf("%s: does not exist\n", path);
263 return; 414 return;
415 }
264 416
265 /* ok, if it isn't a directory, assume we can open it */ 417 /* ok, if it isn't a directory, assume we can open it */
266 if (!S_ISDIR(st_top.st_mode)) { 418 if (!S_ISDIR(st_top.st_mode)) {
267 scanelf_file(path); 419 scanelf_file(path);
268 return; 420 return;
273 warnf("could not opendir %s: %s", path, strerror(errno)); 425 warnf("could not opendir %s: %s", path, strerror(errno));
274 return; 426 return;
275 } 427 }
276 if (be_verbose) printf("%s: scanning dir\n", path); 428 if (be_verbose) printf("%s: scanning dir\n", path);
277 429
430 pathlen = strlen(path);
278 while ((dentry = readdir(dir))) { 431 while ((dentry = readdir(dir))) {
279 if (!strcmp(dentry->d_name, ".") || !strcmp(dentry->d_name, "..")) 432 if (!strcmp(dentry->d_name, ".") || !strcmp(dentry->d_name, ".."))
280 continue; 433 continue;
281 len = (strlen(path) + 2 + strlen(dentry->d_name)); 434 len = (pathlen + 1 + strlen(dentry->d_name) + 1);
282 assert(len < sizeof(buf)); 435 if (len >= sizeof(buf)) {
283 strncpy(buf, path, len); 436 warnf("Skipping '%s': len > sizeof(buf); %d > %d\n", path, (int)len, (int)sizeof(buf));
284 strncat(buf, "/", len); 437 continue;
285 strncat(buf, dentry->d_name, len); 438 }
286 buf[sizeof(buf)] = 0; 439 sprintf(buf, "%s/%s", path, dentry->d_name);
287 if (lstat(buf, &st) != -1) { 440 if (lstat(buf, &st) != -1) {
288 if (S_ISREG(st.st_mode)) 441 if (S_ISREG(st.st_mode))
289 scanelf_file(buf); 442 scanelf_file(buf);
290 else if (dir_recurse && S_ISDIR(st.st_mode)) { 443 else if (dir_recurse && S_ISDIR(st.st_mode)) {
291 if (dir_crossmount || (st_top.st_dev == st.st_dev)) 444 if (dir_crossmount || (st_top.st_dev == st.st_dev))
306 if ((fp = fopen("/etc/ld.so.conf", "r")) == NULL) 459 if ((fp = fopen("/etc/ld.so.conf", "r")) == NULL)
307 err("Unable to open ld.so.conf: %s", strerror(errno)); 460 err("Unable to open ld.so.conf: %s", strerror(errno));
308 461
309 scan_l = scan_ul = scan_ull = 0; 462 scan_l = scan_ul = scan_ull = 0;
310 463
311 path = malloc(_POSIX_PATH_MAX); 464 if ((path = malloc(_POSIX_PATH_MAX)) == NULL) {
465 warn("Can not malloc() memory for ldpath scanning");
466 return;
467 }
312 while ((fgets(path, _POSIX_PATH_MAX, fp)) != NULL) 468 while ((fgets(path, _POSIX_PATH_MAX, fp)) != NULL)
313 if (*path == '/') { 469 if (*path == '/') {
314 if ((p = strrchr(path, '\r')) != NULL) 470 if ((p = strrchr(path, '\r')) != NULL)
315 *p = 0; 471 *p = 0;
316 if ((p = strrchr(path, '\n')) != NULL) 472 if ((p = strrchr(path, '\n')) != NULL)
319 if (!scan_ul && !strcmp(path, "/usr/lib")) scan_ul = 1; 475 if (!scan_ul && !strcmp(path, "/usr/lib")) scan_ul = 1;
320 if (!scan_ull && !strcmp(path, "/usr/local/lib")) scan_ull = 1; 476 if (!scan_ull && !strcmp(path, "/usr/local/lib")) scan_ull = 1;
321 scanelf_dir(path); 477 scanelf_dir(path);
322 } 478 }
323 free(path); 479 free(path);
480 fclose(fp);
324 481
325 if (!scan_l) scanelf_dir("/lib"); 482 if (!scan_l) scanelf_dir("/lib");
326 if (!scan_ul) scanelf_dir("/usr/lib"); 483 if (!scan_ul) scanelf_dir("/usr/lib");
327 if (!scan_ull) scanelf_dir("/usr/local/lib"); 484 if (!scan_ull) scanelf_dir("/usr/local/lib");
328
329 fclose(fp);
330} 485}
331 486
332/* scan env PATH for paths */ 487/* scan env PATH for paths */
333static void scanelf_envpath() 488static void scanelf_envpath()
334{ 489{
337 path = getenv("PATH"); 492 path = getenv("PATH");
338 if (!path) 493 if (!path)
339 err("PATH is not set in your env !"); 494 err("PATH is not set in your env !");
340 495
341 if ((path = strdup(path)) == NULL) 496 if ((path = strdup(path)) == NULL)
342 err("stdup failed: %s", strerror(errno)); 497 err("strdup failed: %s", strerror(errno));
343 498
344 while ((p = strrchr(path, ':')) != NULL) { 499 while ((p = strrchr(path, ':')) != NULL) {
345 scanelf_dir(p + 1); 500 scanelf_dir(p + 1);
346 *p = 0; 501 *p = 0;
347 } 502 }
350} 505}
351 506
352 507
353 508
354/* usage / invocation handling functions */ 509/* usage / invocation handling functions */
355#define PARSE_FLAGS "plRmxetrs:aqvo:BhV" 510#define PARSE_FLAGS "plRmyxetrnis:aqvF:o:BhV"
356#define a_argument required_argument 511#define a_argument required_argument
357static struct option const long_opts[] = { 512static struct option const long_opts[] = {
358 {"path", no_argument, NULL, 'p'}, 513 {"path", no_argument, NULL, 'p'},
359 {"ldpath", no_argument, NULL, 'l'}, 514 {"ldpath", no_argument, NULL, 'l'},
360 {"recursive", no_argument, NULL, 'R'}, 515 {"recursive", no_argument, NULL, 'R'},
361 {"mount", no_argument, NULL, 'm'}, 516 {"mount", no_argument, NULL, 'm'},
517 {"symlink", no_argument, NULL, 'y'},
362 {"pax", no_argument, NULL, 'x'}, 518 {"pax", no_argument, NULL, 'x'},
363 {"header", no_argument, NULL, 'e'}, 519 {"header", no_argument, NULL, 'e'},
364 {"textrel", no_argument, NULL, 't'}, 520 {"textrel", no_argument, NULL, 't'},
365 {"rpath", no_argument, NULL, 'r'}, 521 {"rpath", no_argument, NULL, 'r'},
522 {"needed", no_argument, NULL, 'n'},
523 {"interp", no_argument, NULL, 'i'},
366 {"symbol", a_argument, NULL, 's'}, 524 {"symbol", a_argument, NULL, 's'},
367 {"all", no_argument, NULL, 'a'}, 525 {"all", no_argument, NULL, 'a'},
368 {"quiet", no_argument, NULL, 'q'}, 526 {"quiet", no_argument, NULL, 'q'},
369 {"verbose", no_argument, NULL, 'v'}, 527 {"verbose", no_argument, NULL, 'v'},
528 {"format", a_argument, NULL, 'F'},
370 {"file", a_argument, NULL, 'o'}, 529 {"file", a_argument, NULL, 'o'},
371 {"nobanner", no_argument, NULL, 'B'}, 530 {"nobanner", no_argument, NULL, 'B'},
372 {"help", no_argument, NULL, 'h'}, 531 {"help", no_argument, NULL, 'h'},
373 {"version", no_argument, NULL, 'V'}, 532 {"version", no_argument, NULL, 'V'},
374 {NULL, no_argument, NULL, 0x0} 533 {NULL, no_argument, NULL, 0x0}
375}; 534};
376static char *opts_help[] = { 535static char *opts_help[] = {
377 "Scan all directories in PATH environment", 536 "Scan all directories in PATH environment",
378 "Scan all directories in /etc/ld.so.conf", 537 "Scan all directories in /etc/ld.so.conf",
379 "Scan directories recursively", 538 "Scan directories recursively",
380 "Don't recursively cross mount points\n", 539 "Don't recursively cross mount points",
540 "Don't scan symlinks\n",
381 "Print PaX markings", 541 "Print PaX markings",
382 "Print GNU_STACK markings", 542 "Print GNU_STACK markings",
383 "Print TEXTREL information", 543 "Print TEXTREL information",
384 "Print RPATH information", 544 "Print RPATH information",
545 "Print NEEDED information",
546 "Print INTERP information",
385 "Find a specified symbol", 547 "Find a specified symbol",
386 "Print all scanned info (-x -e -t -r)\n", 548 "Print all scanned info (-x -e -t -r)\n",
387 "Only output 'bad' things", 549 "Only output 'bad' things",
388 "Be verbose (can be specified more than once)", 550 "Be verbose (can be specified more than once)",
551 "Use specified format for output",
389 "Write output stream to a filename", 552 "Write output stream to a filename",
390 "Don't display the header", 553 "Don't display the header",
391 "Print this help and exit", 554 "Print this help and exit",
392 "Print version and exit", 555 "Print version and exit",
393 NULL 556 NULL
395 558
396/* display usage and exit */ 559/* display usage and exit */
397static void usage(int status) 560static void usage(int status)
398{ 561{
399 int i; 562 int i;
400 printf(" Scan ELF binaries for stuff\n" 563 printf(" Scan ELF binaries for stuff\n\n"
401 "Usage: %s [options] <dir1> [dir2 dirN ...]\n\n", argv0); 564 "Usage: %s [options] <dir1/file1> [dir2 dirN fileN ...]\n\n", argv0);
402 printf("Options:\n"); 565 printf("Options: -[%s]\n", PARSE_FLAGS);
403 for (i = 0; long_opts[i].name; ++i) 566 for (i = 0; long_opts[i].name; ++i)
404 if (long_opts[i].has_arg == no_argument) 567 if (long_opts[i].has_arg == no_argument)
405 printf(" -%c, --%-13s %s\n", long_opts[i].val, 568 printf(" -%c, --%-13s %s\n", long_opts[i].val,
406 long_opts[i].name, opts_help[i]); 569 long_opts[i].name, opts_help[i]);
407 else 570 else
417 580
418 opterr = 0; 581 opterr = 0;
419 while ((flag=getopt_long(argc, argv, PARSE_FLAGS, long_opts, NULL)) != -1) { 582 while ((flag=getopt_long(argc, argv, PARSE_FLAGS, long_opts, NULL)) != -1) {
420 switch (flag) { 583 switch (flag) {
421 584
422 case 'V': /* version info */ 585 case 'V':
423 printf("%s compiled %s\n%s\n" 586 printf("%s compiled %s\n%s\n"
424 "%s written for Gentoo Linux by <solar and vapier @ gentoo.org>\n", 587 "%s written for Gentoo Linux by <solar and vapier @ gentoo.org>\n",
425 __FILE__, __DATE__, rcsid, argv0); 588 __FILE__, __DATE__, rcsid, argv0);
426 exit(EXIT_SUCCESS); 589 exit(EXIT_SUCCESS);
427 break; 590 break;
434 err("Could not open output stream '%s': %s", optarg, strerror(errno)); 597 err("Could not open output stream '%s': %s", optarg, strerror(errno));
435 stdout = fp; 598 stdout = fp;
436 break; 599 break;
437 } 600 }
438 601
602 case 's': {
603 size_t len;
439 case 's': find_sym = strdup(optarg); break; 604 find_sym = strdup(optarg);
605 if (!find_sym) {
606 warnf("Could not malloc() mem for sym scan");
607 find_sym = NULL;
608 break;
609 }
610 len = strlen(find_sym) + 1;
611 versioned_symname = (char *)malloc(sizeof(char) * (len+1));
612 if (!versioned_symname) {
613 free(find_sym);
614 find_sym = NULL;
615 warnf("Could not malloc() mem for sym scan");
616 break;
617 }
618 sprintf(versioned_symname, "%s@", find_sym);
619 break;
620 }
440 621
622 case 'F': {
623 out_format = strdup(optarg);
624 if (!out_format)
625 err("Could not malloc() mem for output format");
626 break;
627 }
628
629 case 'y': scan_symlink = 0; break;
441 case 'B': show_banner = 0; break; 630 case 'B': show_banner = 0; break;
442 case 'l': scan_ldpath = 1; break; 631 case 'l': scan_ldpath = 1; break;
443 case 'p': scan_envpath = 1; break; 632 case 'p': scan_envpath = 1; break;
444 case 'R': dir_recurse = 1; break; 633 case 'R': dir_recurse = 1; break;
445 case 'm': dir_crossmount = 0; break; 634 case 'm': dir_crossmount = 0; break;
446 case 'x': show_pax = 1; break; 635 case 'x': show_pax = 1; break;
447 case 'e': show_stack = 1; break; 636 case 'e': show_stack = 1; break;
448 case 't': show_textrel = 1; break; 637 case 't': show_textrel = 1; break;
449 case 'r': show_rpath = 1; break; 638 case 'r': show_rpath = 1; break;
639 case 'n': show_needed = 1; break;
640 case 'i': show_interp = 1; break;
450 case 'q': be_quiet = 1; break; 641 case 'q': be_quiet = 1; break;
451 case 'v': be_verbose = (be_verbose % 20) + 1; break; 642 case 'v': be_verbose = (be_verbose % 20) + 1; break;
452 case 'a': show_pax = show_stack = show_textrel = show_rpath = 1; break; 643 case 'a': show_pax = show_stack = show_textrel = show_rpath = show_needed = show_interp = 1; break;
453 644
454 case ':': 645 case ':':
455 warn("Option missing parameter"); 646 warn("Option missing parameter\n");
456 usage(EXIT_FAILURE); 647 usage(EXIT_FAILURE);
457 break; 648 break;
458 case '?': 649 case '?':
459 warn("Unknown option"); 650 warn("Unknown option\n");
460 usage(EXIT_FAILURE); 651 usage(EXIT_FAILURE);
461 break; 652 break;
462 default: 653 default:
463 err("Unhandled option '%c'", flag); 654 err("Unhandled option '%c'", flag);
464 break; 655 break;
466 } 657 }
467 658
468 if (be_quiet && be_verbose) 659 if (be_quiet && be_verbose)
469 err("You can be quiet or you can be verbose, not both, stupid"); 660 err("You can be quiet or you can be verbose, not both, stupid");
470 661
662 /* let the format option override all other options */
663 if (out_format) {
664 show_pax = show_stack = show_textrel = show_rpath = show_needed = show_interp = 0;
665 for (flag=0; out_format[flag]; ++flag) {
666 if (out_format[flag] != '%') continue;
667
668 switch (out_format[++flag]) {
669 case '%': break;
670 case 'F': break;
671 case 's': break;
672 case 'x': show_pax = 1; break;
673 case 'e': show_stack = 1; break;
674 case 't': show_textrel = 1; break;
675 case 'r': show_rpath = 1; break;
676 case 'n': show_needed = 1; break;
677 case 'i': show_interp = 1; break;
678 default:
679 err("Invalid format specifier '%c' (byte %i)",
680 out_format[flag], flag+1);
681 }
682 }
683 }
684
685 /* now lets actually do the scanning */
471 if (scan_ldpath) scanelf_ldpath(); 686 if (scan_ldpath) scanelf_ldpath();
472 if (scan_envpath) scanelf_envpath(); 687 if (scan_envpath) scanelf_envpath();
473 if (optind == argc && !scan_ldpath && !scan_envpath) 688 if (optind == argc && !scan_ldpath && !scan_envpath)
474 err("Nothing to scan !?"); 689 err("Nothing to scan !?");
475 while (optind < argc) 690 while (optind < argc)
476 scanelf_dir(argv[optind++]); 691 scanelf_dir(argv[optind++]);
477 692
478 if (find_sym) free(find_sym); 693 /* clean up */
694 if (find_sym) {
695 free(find_sym);
696 free(versioned_symname);
697 }
698 if (out_format) free(out_format);
479} 699}
480 700
481 701
482 702
483int main(int argc, char *argv[]) 703int main(int argc, char *argv[])

Legend:
Removed from v.1.27  
changed lines
  Added in v.1.40

  ViewVC Help
Powered by ViewVC 1.1.20