/[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.17 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.17 2005/04/02 00:11:01 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>
34#include <assert.h>
33 35
34#include "paxelf.h" 36#include "paxelf.h"
35 37
36static const char *rcsid = "$Id: scanelf.c,v 1.17 2005/04/02 00:11:01 vapier Exp $"; 38static const char *rcsid = "$Id: scanelf.c,v 1.40 2005/04/21 00:13:03 solar Exp $";
37 39#define argv0 "scanelf"
38
39/* helper functions for showing errors */
40#define argv0 "scanelf\0" /*((*argv != NULL) ? argv[0] : __FILE__ "\b\b")*/
41#define warn(fmt, args...) \
42 fprintf(stderr, "%s: " fmt "\n", argv0, ## args)
43#define warnf(fmt, args...) warn("%s(): " fmt, __FUNCTION__, ## args)
44#define err(fmt, args...) \
45 do { \
46 warn(fmt, ## args); \
47 exit(EXIT_FAILURE); \
48 } while (0)
49 40
50 41
51 42
52/* prototypes */ 43/* prototypes */
53static void scanelf_file(const char *filename); 44static void scanelf_file(const char *filename);
58static void parseargs(int argc, char *argv[]); 49static void parseargs(int argc, char *argv[]);
59 50
60/* variables to control behavior */ 51/* variables to control behavior */
61static char scan_ldpath = 0; 52static char scan_ldpath = 0;
62static char scan_envpath = 0; 53static char scan_envpath = 0;
54static char scan_symlink = 1;
63static char dir_recurse = 0; 55static char dir_recurse = 0;
64static char dir_crossmount = 1; 56static char dir_crossmount = 1;
65static char show_pax = 0; 57static char show_pax = 0;
66static char show_stack = 0; 58static char show_stack = 0;
67static char show_textrel = 0; 59static char show_textrel = 0;
68static char show_rpath = 0; 60static char show_rpath = 0;
61static char show_needed = 0;
62static char show_interp = 0;
69static char show_banner = 1; 63static char show_banner = 1;
70static char be_quiet = 0; 64static char be_quiet = 0;
71static char be_verbose = 0; 65static char be_verbose = 0;
66static char *find_sym = NULL, *versioned_symname = NULL;
67static char *out_format = NULL;
72 68
73 69
74 70
71/* sub-funcs for scanelf_file() */
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)
84{
85 int i;
86 if (!show_stack) return;
87#define SHOW_STACK(B) \
88 if (elf->elf_class == ELFCLASS ## B) { \
89 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \
90 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \
91 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \
92 if (EGET(phdr[i].p_type) != PT_GNU_STACK && \
93 EGET(phdr[i].p_type) != PT_GNU_RELRO) continue; \
94 if (be_quiet && !(EGET(phdr[i].p_flags) & PF_X)) \
95 continue; \
96 if (EGET(phdr[i].p_type) == PT_GNU_STACK) \
97 *found_stack = 1; \
98 if (EGET(phdr[i].p_type) == PT_GNU_RELRO) \
99 *found_relro = 1; \
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; \
127 } \
128 } }
129 SHOW_TEXTREL(32)
130 SHOW_TEXTREL(64)
131 if (!be_quiet && !*found_textrel) printf("------- ");
132}
133static void scanelf_file_rpath(elfobj *elf, char *found_rpath)
134{
135 /* TODO: if be_quiet, only output RPATH's which aren't in /etc/ld.so.conf */
136 int i;
137 char *rpath, *runpath;
138 void *strtbl_void;
139
140 if (!show_rpath) return;
141
142 strtbl_void = elf_findsecbyname(elf, ".dynstr");
143 rpath = runpath = NULL;
144
145 if (strtbl_void) {
146#define SHOW_RPATH(B) \
147 if (elf->elf_class == ELFCLASS ## B) { \
148 Elf ## B ## _Dyn *dyn; \
149 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \
150 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \
151 Elf ## B ## _Shdr *strtbl = SHDR ## B (strtbl_void); \
152 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \
153 if (EGET(phdr[i].p_type) != PT_DYNAMIC) continue; \
154 dyn = DYN ## B (elf->data + EGET(phdr[i].p_offset)); \
155 while (EGET(dyn->d_tag) != DT_NULL) { \
156 if (EGET(dyn->d_tag) == DT_RPATH) { \
157 rpath = elf->data + EGET(strtbl->sh_offset) + EGET(dyn->d_un.d_ptr); \
158 *found_rpath = 1; \
159 } else if (EGET(dyn->d_tag) == DT_RUNPATH) { \
160 runpath = elf->data + EGET(strtbl->sh_offset) + EGET(dyn->d_un.d_ptr); \
161 *found_rpath = 1; \
162 } \
163 ++dyn; \
164 } \
165 } }
166 SHOW_RPATH(32)
167 SHOW_RPATH(64)
168 }
169 if (rpath && runpath) {
170 if (!strcmp(rpath, runpath))
171 printf("%-5s ", runpath);
172 else {
173 fprintf(stderr, "RPATH [%s] != RUNPATH [%s]\n", rpath, runpath);
174 printf("{%s,%s} ", rpath, runpath);
175 }
176 } else if (rpath || runpath)
177 printf("%-5s ", (runpath ? runpath : rpath));
178 else if (!be_quiet && !*found_rpath)
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; \
233 }
234 SHOW_INTERP(32)
235 SHOW_INTERP(64)
236 }
237 if (!be_quiet && !*found_interp)
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;
245 void *symtab_void, *strtab_void;
246
247 if (!find_sym) return;
248
249 symtab_void = elf_findsecbyname(elf, ".symtab");
250 strtab_void = elf_findsecbyname(elf, ".strtab");
251
252 if (symtab_void && strtab_void) {
253#define FIND_SYM(B) \
254 if (elf->elf_class == ELFCLASS ## B) { \
255 Elf ## B ## _Shdr *symtab = SHDR ## B (symtab_void); \
256 Elf ## B ## _Shdr *strtab = SHDR ## B (strtab_void); \
257 Elf ## B ## _Sym *sym = SYM ## B (elf->data + EGET(symtab->sh_offset)); \
258 int cnt = EGET(symtab->sh_size) / EGET(symtab->sh_entsize); \
259 char *symname; \
260 for (i = 0; i < cnt; ++i) { \
261 if (sym->st_name) { \
262 symname = (char *)(elf->data + EGET(strtab->sh_offset) + EGET(sym->st_name)); \
263 if (*find_sym == '*') { \
264 printf("%s(%s) %5lX %15s %s\n", \
265 ((*found_sym == 0) ? "\n\t" : "\t"), \
266 (char *)basename(filename), \
267 (long)sym->st_size, \
268 (char *)get_elfstttype(sym->st_info), \
269 symname); \
270 *found_sym = 1; \
271 } else if ((strcmp(find_sym, symname) == 0) || \
272 (strcmp(symname, versioned_symname) == 0)) \
273 (*found_sym)++; \
274 } \
275 ++sym; \
276 } }
277 FIND_SYM(32)
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}
75/* scan an elf file and show all the fun stuff */ 287/* scan an elf file and show all the fun stuff */
76static void scanelf_file(const char *filename) 288static void scanelf_file(const char *filename)
77{ 289{
78 int i; 290 int i;
79 char found_pax, found_stack, found_relro, found_textrel, found_rpath; 291 char found_pax, found_stack, found_relro, found_textrel,
80 Elf_Dyn *dyn; 292 found_rpath, found_needed, found_interp, found_sym,
293 found_file;
81 elfobj *elf = NULL; 294 elfobj *elf;
295 struct stat st;
82 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
83 found_pax = found_stack = found_relro = found_textrel = found_rpath = 0; 308 found_pax = found_stack = found_relro = found_textrel = \
309 found_rpath = found_needed = found_interp = found_sym = \
310 found_file = 0;
84 311
85 /* verify this is real ELF */ 312 /* verify this is real ELF */
86 if ((elf = readelf(filename)) == NULL) { 313 if ((elf = readelf(filename)) == NULL) {
87 if (be_verbose > 1) printf("%s: not an ELF\n", filename); 314 if (be_verbose > 2) printf("%s: not an ELF\n", filename);
88 return; 315 return;
89 } 316 }
90 if (check_elf_header(elf->ehdr) || !IS_ELF(elf)) {
91 if (be_verbose > 1) printf("%s: cannot handle ELF :(\n", filename);
92 goto bail;
93 }
94 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)
95 if (be_verbose) printf("%s: scanning file\n", filename); 323 printf("%s: scanning file\n", filename);
96 324
97 /* show the header */ 325 /* show the header */
98 if (!be_quiet && show_banner) { 326 if (!be_quiet && show_banner) {
99 fputs(" TYPE ", stdout); 327 if (out_format) {
100 if (show_pax) fputs(" PAX ", stdout); 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 }
342 }
343 } else {
344 printf(" TYPE ");
345 if (show_pax) printf(" PAX ");
101 if (show_stack) fputs(" STK/REL ", stdout); 346 if (show_stack) printf("STK/REL ");
102 if (show_textrel) fputs("TEXTREL ", stdout); 347 if (show_textrel) printf("TEXTREL ");
103 if (show_rpath) fputs("RPATH ", stdout); 348 if (show_rpath) printf("RPATH ");
104 fputs(" FILE\n", stdout); 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");
105 show_banner = 0; 355 show_banner = 0;
106 } 356 }
107 357
108 /* dump all the good stuff */ 358 /* dump all the good stuff */
109 if (!be_quiet) 359 if (!be_quiet && !out_format)
110 printf("%-7s ", get_elfetype(elf->ehdr->e_type)); 360 printf("%-7s ", get_elfetype(elf));
111 361
112 if (show_pax) { 362 if (out_format) {
113 char *paxflags = pax_short_hf_flags(PAX_FLAGS(elf)); 363 for (i=0; out_format[i]; ++i) {
114 if (!be_quiet || (be_quiet && strncmp(paxflags, "PeMRxS", 6))) { 364 if (out_format[i] != '%') {
115 found_pax = 1; 365 printf("%c", out_format[i]);
116 printf("%s ", pax_short_hf_flags(PAX_FLAGS(elf)));
117 }
118 }
119
120 /* stack fun */
121 if (show_stack) {
122 for (i = 0; i < elf->ehdr->e_phnum; i++) {
123 if (elf->phdr[i].p_type != PT_GNU_STACK && \
124 elf->phdr[i].p_type != PT_GNU_RELRO) continue;
125
126 if (be_quiet && !(elf->phdr[i].p_flags & PF_X))
127 continue; 366 continue;
128
129 if (elf->phdr[i].p_type == PT_GNU_STACK)
130 found_stack = 1;
131 if (elf->phdr[i].p_type == PT_GNU_RELRO)
132 found_relro = 1;
133
134 printf("%s ", gnu_short_stack_flags(elf->phdr[i].p_flags));
135 }
136 if (!be_quiet && !found_stack) fputs("--- ", stdout);
137 if (!be_quiet && !found_relro) fputs("--- ", stdout);
138 }
139
140 /* textrel fun */
141 if (show_textrel) {
142 for (i = 0; i < elf->ehdr->e_phnum; i++) {
143 if (elf->phdr[i].p_type != PT_DYNAMIC) continue;
144
145 dyn = (Elf_Dyn *)(elf->data + elf->phdr[i].p_offset);
146 while (dyn->d_tag != DT_NULL) {
147 if (dyn->d_tag == DT_TEXTREL) { //dyn->d_tag != DT_FLAGS)
148 found_textrel = 1;
149// if (dyn->d_un.d_val & DF_TEXTREL)
150 fputs("TEXTREL ", stdout);
151 }
152 ++dyn;
153 } 367 }
154 }
155 if (!be_quiet && !found_textrel) fputs("------- ", stdout);
156 }
157 368
158 /* rpath fun */ 369 switch (out_format[++i]) {
159 /* TODO: if be_quiet, only output RPATH's which aren't in /etc/ld.so.conf */ 370 case '%': printf("%%"); break;
160 if (show_rpath) { 371 case 'F': found_file = 1; printf("%s ", filename); break;
161 Elf_Shdr *strtbl = elf_findsecbyname(elf, ".dynstr"); 372 case 'x': scanelf_file_pax(elf, &found_pax); break;
162 373 case 'e': scanelf_file_stack(elf, &found_stack, &found_relro); break;
163 if (strtbl) 374 case 't': scanelf_file_textrel(elf, &found_textrel); break;
164 for (i = 0; i < elf->ehdr->e_phnum; i++) { 375 case 'r': scanelf_file_rpath(elf, &found_rpath); break;
165 if (elf->phdr[i].p_type != PT_DYNAMIC) continue; 376 case 'n': scanelf_file_needed(elf, &found_needed); break;
166 377 case 'i': scanelf_file_interp(elf, &found_interp); break;
167 dyn = (Elf_Dyn *)(elf->data + elf->phdr[i].p_offset); 378 case 's': scanelf_file_sym(elf, &found_sym, filename); break;
168 while (dyn->d_tag != DT_NULL) {
169 if (dyn->d_tag == DT_RPATH) { //|| dyn->d_tag != DT_RUNPATH)
170 char *rpath = elf->data + strtbl->sh_offset + dyn->d_un.d_ptr;
171 found_rpath = 1;
172 printf("%s ", rpath);
173 }
174 ++dyn;
175 } 379 }
176 } 380 }
177 if (!be_quiet && !found_rpath) fputs(" - ", stdout); 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);
178 } 389 }
179 390
391 if (!found_file) {
180 if (!be_quiet || found_pax || found_stack || found_textrel || found_rpath) 392 if (!be_quiet || found_pax || found_stack || found_textrel || \
393 found_rpath || found_needed || found_sym)
181 puts(filename); 394 puts(filename);
395 } else {
396 printf("\n");
397 }
182 398
183bail:
184 unreadelf(elf); 399 unreadelf(elf);
185} 400}
186 401
187/* scan a directory for ET_EXEC files and print when we find one */ 402/* scan a directory for ET_EXEC files and print when we find one */
188static void scanelf_dir(const char *path) 403static void scanelf_dir(const char *path)
189{ 404{
190 register DIR *dir; 405 register DIR *dir;
191 register struct dirent *dentry; 406 register struct dirent *dentry;
192 struct stat st_top, st; 407 struct stat st_top, st;
193 char *p; 408 char buf[_POSIX_PATH_MAX];
194 int len = 0; 409 size_t pathlen = 0, len = 0;
195 410
196 /* make sure path exists */ 411 /* make sure path exists */
197 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);
198 return; 414 return;
415 }
199 416
200 /* 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 */
201 if (!S_ISDIR(st_top.st_mode)) { 418 if (!S_ISDIR(st_top.st_mode)) {
202 scanelf_file(path); 419 scanelf_file(path);
203 return; 420 return;
208 warnf("could not opendir %s: %s", path, strerror(errno)); 425 warnf("could not opendir %s: %s", path, strerror(errno));
209 return; 426 return;
210 } 427 }
211 if (be_verbose) printf("%s: scanning dir\n", path); 428 if (be_verbose) printf("%s: scanning dir\n", path);
212 429
430 pathlen = strlen(path);
213 while ((dentry = readdir(dir))) { 431 while ((dentry = readdir(dir))) {
214 if (!strcmp(dentry->d_name, ".") || !strcmp(dentry->d_name, "..")) 432 if (!strcmp(dentry->d_name, ".") || !strcmp(dentry->d_name, ".."))
215 continue; 433 continue;
216 len = (strlen(path) + 2 + strlen(dentry->d_name)); 434 len = (pathlen + 1 + strlen(dentry->d_name) + 1);
217 p = malloc(len); 435 if (len >= sizeof(buf)) {
218 if (!p) 436 warnf("Skipping '%s': len > sizeof(buf); %d > %d\n", path, (int)len, (int)sizeof(buf));
219 err("scanelf_dir(): Could not malloc: %s", strerror(errno)); 437 continue;
220 strncpy(p, path, len); 438 }
221 strncat(p, "/", len); 439 sprintf(buf, "%s/%s", path, dentry->d_name);
222 strncat(p, dentry->d_name, len);
223 if (lstat(p, &st) != -1) { 440 if (lstat(buf, &st) != -1) {
224 if (S_ISREG(st.st_mode)) 441 if (S_ISREG(st.st_mode))
225 scanelf_file(p); 442 scanelf_file(buf);
226 else if (dir_recurse && S_ISDIR(st.st_mode)) { 443 else if (dir_recurse && S_ISDIR(st.st_mode)) {
227 if (dir_crossmount || (st_top.st_dev == st.st_dev)) 444 if (dir_crossmount || (st_top.st_dev == st.st_dev))
228 scanelf_dir(p); 445 scanelf_dir(buf);
229 } 446 }
230 } 447 }
231 free(p);
232 } 448 }
233 closedir(dir); 449 closedir(dir);
234} 450}
235 451
236/* scan /etc/ld.so.conf for paths */ 452/* scan /etc/ld.so.conf for paths */
243 if ((fp = fopen("/etc/ld.so.conf", "r")) == NULL) 459 if ((fp = fopen("/etc/ld.so.conf", "r")) == NULL)
244 err("Unable to open ld.so.conf: %s", strerror(errno)); 460 err("Unable to open ld.so.conf: %s", strerror(errno));
245 461
246 scan_l = scan_ul = scan_ull = 0; 462 scan_l = scan_ul = scan_ull = 0;
247 463
248 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 }
249 while ((fgets(path, _POSIX_PATH_MAX, fp)) != NULL) 468 while ((fgets(path, _POSIX_PATH_MAX, fp)) != NULL)
250 if (*path == '/') { 469 if (*path == '/') {
251 if ((p = strrchr(path, '\r')) != NULL) 470 if ((p = strrchr(path, '\r')) != NULL)
252 *p = 0; 471 *p = 0;
253 if ((p = strrchr(path, '\n')) != NULL) 472 if ((p = strrchr(path, '\n')) != NULL)
256 if (!scan_ul && !strcmp(path, "/usr/lib")) scan_ul = 1; 475 if (!scan_ul && !strcmp(path, "/usr/lib")) scan_ul = 1;
257 if (!scan_ull && !strcmp(path, "/usr/local/lib")) scan_ull = 1; 476 if (!scan_ull && !strcmp(path, "/usr/local/lib")) scan_ull = 1;
258 scanelf_dir(path); 477 scanelf_dir(path);
259 } 478 }
260 free(path); 479 free(path);
480 fclose(fp);
261 481
262 if (!scan_l) scanelf_dir("/lib"); 482 if (!scan_l) scanelf_dir("/lib");
263 if (!scan_ul) scanelf_dir("/usr/lib"); 483 if (!scan_ul) scanelf_dir("/usr/lib");
264 if (!scan_ull) scanelf_dir("/usr/local/lib"); 484 if (!scan_ull) scanelf_dir("/usr/local/lib");
265
266 fclose(fp);
267} 485}
268 486
269/* scan env PATH for paths */ 487/* scan env PATH for paths */
270static void scanelf_envpath() 488static void scanelf_envpath()
271{ 489{
274 path = getenv("PATH"); 492 path = getenv("PATH");
275 if (!path) 493 if (!path)
276 err("PATH is not set in your env !"); 494 err("PATH is not set in your env !");
277 495
278 if ((path = strdup(path)) == NULL) 496 if ((path = strdup(path)) == NULL)
279 err("stdup failed: %s", strerror(errno)); 497 err("strdup failed: %s", strerror(errno));
280 498
281 while ((p = strrchr(path, ':')) != NULL) { 499 while ((p = strrchr(path, ':')) != NULL) {
282 scanelf_dir(p + 1); 500 scanelf_dir(p + 1);
283 *p = 0; 501 *p = 0;
284 } 502 }
287} 505}
288 506
289 507
290 508
291/* usage / invocation handling functions */ 509/* usage / invocation handling functions */
292#define PARSE_FLAGS "plRmxetraqvBhV" 510#define PARSE_FLAGS "plRmyxetrnis:aqvF:o:BhV"
511#define a_argument required_argument
293static struct option const long_opts[] = { 512static struct option const long_opts[] = {
294 {"path", no_argument, NULL, 'p'}, 513 {"path", no_argument, NULL, 'p'},
295 {"ldpath", no_argument, NULL, 'l'}, 514 {"ldpath", no_argument, NULL, 'l'},
296 {"recursive", no_argument, NULL, 'R'}, 515 {"recursive", no_argument, NULL, 'R'},
297 {"mount", no_argument, NULL, 'm'}, 516 {"mount", no_argument, NULL, 'm'},
517 {"symlink", no_argument, NULL, 'y'},
298 {"pax", no_argument, NULL, 'x'}, 518 {"pax", no_argument, NULL, 'x'},
299 {"header", no_argument, NULL, 'e'}, 519 {"header", no_argument, NULL, 'e'},
300 {"textrel", no_argument, NULL, 't'}, 520 {"textrel", no_argument, NULL, 't'},
301 {"rpath", no_argument, NULL, 'r'}, 521 {"rpath", no_argument, NULL, 'r'},
522 {"needed", no_argument, NULL, 'n'},
523 {"interp", no_argument, NULL, 'i'},
524 {"symbol", a_argument, NULL, 's'},
302 {"all", no_argument, NULL, 'a'}, 525 {"all", no_argument, NULL, 'a'},
303 {"quiet", no_argument, NULL, 'q'}, 526 {"quiet", no_argument, NULL, 'q'},
304 {"verbose", no_argument, NULL, 'v'}, 527 {"verbose", no_argument, NULL, 'v'},
528 {"format", a_argument, NULL, 'F'},
529 {"file", a_argument, NULL, 'o'},
305 {"nobanner", no_argument, NULL, 'B'}, 530 {"nobanner", no_argument, NULL, 'B'},
306 {"help", no_argument, NULL, 'h'}, 531 {"help", no_argument, NULL, 'h'},
307 {"version", no_argument, NULL, 'V'}, 532 {"version", no_argument, NULL, 'V'},
308 {NULL, no_argument, NULL, 0x0} 533 {NULL, no_argument, NULL, 0x0}
309}; 534};
310static char *opts_help[] = { 535static char *opts_help[] = {
311 "Scan all directories in PATH environment", 536 "Scan all directories in PATH environment",
312 "Scan all directories in /etc/ld.so.conf", 537 "Scan all directories in /etc/ld.so.conf",
313 "Scan directories recursively", 538 "Scan directories recursively",
314 "Don't recursively cross mount points\n", 539 "Don't recursively cross mount points",
540 "Don't scan symlinks\n",
315 "Print PaX markings", 541 "Print PaX markings",
316 "Print GNU_STACK markings", 542 "Print GNU_STACK markings",
317 "Print TEXTREL information", 543 "Print TEXTREL information",
318 "Print RPATH information", 544 "Print RPATH information",
545 "Print NEEDED information",
546 "Print INTERP information",
547 "Find a specified symbol",
319 "Print all scanned info (-x -e -t -r)\n", 548 "Print all scanned info (-x -e -t -r)\n",
320 "Only output 'bad' things", 549 "Only output 'bad' things",
321 "Be verbose (can be specified more than once)", 550 "Be verbose (can be specified more than once)",
551 "Use specified format for output",
552 "Write output stream to a filename",
322 "Don't display the header", 553 "Don't display the header",
323 "Print this help and exit", 554 "Print this help and exit",
324 "Print version and exit", 555 "Print version and exit",
325 NULL 556 NULL
326}; 557};
328/* display usage and exit */ 559/* display usage and exit */
329static void usage(int status) 560static void usage(int status)
330{ 561{
331 int i; 562 int i;
332 printf(" Scan ELF binaries for stuff\n\n" 563 printf(" Scan ELF binaries for stuff\n\n"
333 "Usage: %s [options] <dir1> [dir2 dirN ...]\n\n", argv0); 564 "Usage: %s [options] <dir1/file1> [dir2 dirN fileN ...]\n\n", argv0);
334 fputs("Options:\n", stdout); 565 printf("Options: -[%s]\n", PARSE_FLAGS);
335 for (i = 0; long_opts[i].name; ++i) 566 for (i = 0; long_opts[i].name; ++i)
567 if (long_opts[i].has_arg == no_argument)
336 printf(" -%c, --%-12s %s\n", long_opts[i].val, 568 printf(" -%c, --%-13s %s\n", long_opts[i].val,
337 long_opts[i].name, opts_help[i]); 569 long_opts[i].name, opts_help[i]);
338#ifdef MANLYPAGE 570 else
339 for (i = 0; long_opts[i].name; ++i) 571 printf(" -%c, --%-6s <arg> %s\n", long_opts[i].val,
340 printf(".TP\n\\fB\\-%c, \\-\\-%s\\fR\n%s\n", long_opts[i].val,
341 long_opts[i].name, opts_help[i]); 572 long_opts[i].name, opts_help[i]);
342#endif
343 exit(status); 573 exit(status);
344} 574}
345 575
346/* parse command line arguments and preform needed actions */ 576/* parse command line arguments and preform needed actions */
347static void parseargs(int argc, char *argv[]) 577static void parseargs(int argc, char *argv[])
350 580
351 opterr = 0; 581 opterr = 0;
352 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) {
353 switch (flag) { 583 switch (flag) {
354 584
355 case 'V': /* version info */ 585 case 'V':
356 printf("%s compiled %s\n" 586 printf("%s compiled %s\n%s\n"
357 "%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",
358 "%s\n",
359 __FILE__, __DATE__, argv0, rcsid); 588 __FILE__, __DATE__, rcsid, argv0);
360 exit(EXIT_SUCCESS); 589 exit(EXIT_SUCCESS);
361 break; 590 break;
362 case 's': /* reserved for -s, --symbol= */
363 case 'h': usage(EXIT_SUCCESS); break; 591 case 'h': usage(EXIT_SUCCESS); break;
364 592
593 case 'o': {
594 FILE *fp = NULL;
595 fp = freopen(optarg, "w", stdout);
596 if (fp == NULL)
597 err("Could not open output stream '%s': %s", optarg, strerror(errno));
598 stdout = fp;
599 break;
600 }
601
602 case 's': {
603 size_t len;
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 }
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;
365 case 'B': show_banner = 0; break; 630 case 'B': show_banner = 0; break;
366 case 'l': scan_ldpath = 1; break; 631 case 'l': scan_ldpath = 1; break;
367 case 'p': scan_envpath = 1; break; 632 case 'p': scan_envpath = 1; break;
368 case 'R': dir_recurse = 1; break; 633 case 'R': dir_recurse = 1; break;
369 case 'm': dir_crossmount = 0; break; 634 case 'm': dir_crossmount = 0; break;
370 case 'x': show_pax = 1; break; 635 case 'x': show_pax = 1; break;
371 case 'e': show_stack = 1; break; 636 case 'e': show_stack = 1; break;
372 case 't': show_textrel = 1; break; 637 case 't': show_textrel = 1; break;
373 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;
374 case 'q': be_quiet = 1; break; 641 case 'q': be_quiet = 1; break;
375 case 'v': be_verbose = (be_verbose % 20) + 1; break; 642 case 'v': be_verbose = (be_verbose % 20) + 1; break;
376 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;
377 644
378 case ':': 645 case ':':
379 warn("Option missing parameter"); 646 warn("Option missing parameter\n");
380 usage(EXIT_FAILURE); 647 usage(EXIT_FAILURE);
381 break; 648 break;
382 case '?': 649 case '?':
383 warn("Unknown option"); 650 warn("Unknown option\n");
384 usage(EXIT_FAILURE); 651 usage(EXIT_FAILURE);
385 break; 652 break;
386 default: 653 default:
387 err("Unhandled option '%c'", flag); 654 err("Unhandled option '%c'", flag);
388 break; 655 break;
390 } 657 }
391 658
392 if (be_quiet && be_verbose) 659 if (be_quiet && be_verbose)
393 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");
394 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 */
395 if (scan_ldpath) scanelf_ldpath(); 686 if (scan_ldpath) scanelf_ldpath();
396 if (scan_envpath) scanelf_envpath(); 687 if (scan_envpath) scanelf_envpath();
688 if (optind == argc && !scan_ldpath && !scan_envpath)
689 err("Nothing to scan !?");
397 while (optind < argc) 690 while (optind < argc)
398 scanelf_dir(argv[optind++]); 691 scanelf_dir(argv[optind++]);
692
693 /* clean up */
694 if (find_sym) {
695 free(find_sym);
696 free(versioned_symname);
697 }
698 if (out_format) free(out_format);
399} 699}
400 700
401 701
402 702
403int main(int argc, char *argv[]) 703int main(int argc, char *argv[])
404{ 704{
405 if (argc < 2) 705 if (argc < 2)
406 usage(EXIT_FAILURE); 706 usage(EXIT_FAILURE);
407 parseargs(argc, argv); 707 parseargs(argc, argv);
708 fclose(stdout);
408 return EXIT_SUCCESS; 709 return EXIT_SUCCESS;
409} 710}

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

  ViewVC Help
Powered by ViewVC 1.1.20