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

Contents of /pax-utils/scanelf.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.39 - (hide annotations) (download) (as text)
Wed Apr 20 22:06:08 2005 UTC (9 years, 4 months ago) by vapier
Branch: MAIN
Changes since 1.38: +307 -186 lines
File MIME type: text/x-csrc
break scanelf_file() up into smaller functions to easily support custom --format output

1 solar 1.1 /*
2     * Copyright 2003 Ned Ludd <solar@gentoo.org>
3 vapier 1.8 * Copyright 1999-2005 Gentoo Foundation
4 solar 1.1 * Distributed under the terms of the GNU General Public License v2
5 vapier 1.39 * $Header: /var/cvsroot/gentoo-projects/pax-utils/scanelf.c,v 1.38 2005/04/19 22:19:26 vapier Exp $
6 solar 1.1 *
7     ********************************************************************
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
10     * published by the Free Software Foundation; either version 2 of the
11     * License, or (at your option) any later version.
12     *
13     * This program is distributed in the hope that it will be useful, but
14     * WITHOUT ANY WARRANTY; without even the implied warranty of
15     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16     * General Public License for more details.
17     *
18     * You should have received a copy of the GNU General Public License
19     * along with this program; if not, write to the Free Software
20     * Foundation, Inc., 59 Temple Place - Suite 330, Boston,
21     * MA 02111-1307, USA.
22     */
23    
24     #include <stdio.h>
25     #include <stdlib.h>
26     #include <sys/types.h>
27 solar 1.28 #define __USE_GNU
28 solar 1.1 #include <string.h>
29 vapier 1.10 #include <errno.h>
30 solar 1.1 #include <unistd.h>
31     #include <sys/stat.h>
32     #include <dirent.h>
33     #include <getopt.h>
34 solar 1.20 #include <assert.h>
35 solar 1.21
36 solar 1.1 #include "paxelf.h"
37    
38 vapier 1.39 static const char *rcsid = "$Id: scanelf.c,v 1.38 2005/04/19 22:19:26 vapier Exp $";
39 vapier 1.36 #define argv0 "scanelf"
40 vapier 1.10
41    
42    
43     /* prototypes */
44     static void scanelf_file(const char *filename);
45     static void scanelf_dir(const char *path);
46     static void scanelf_ldpath();
47     static void scanelf_envpath();
48     static void usage(int status);
49     static void parseargs(int argc, char *argv[]);
50    
51     /* variables to control behavior */
52     static char scan_ldpath = 0;
53     static char scan_envpath = 0;
54 vapier 1.37 static char scan_symlink = 1;
55 vapier 1.10 static char dir_recurse = 0;
56 vapier 1.14 static char dir_crossmount = 1;
57 vapier 1.10 static char show_pax = 0;
58     static char show_stack = 0;
59     static char show_textrel = 0;
60     static char show_rpath = 0;
61 vapier 1.32 static char show_needed = 0;
62 vapier 1.38 static char show_interp = 0;
63 solar 1.16 static char show_banner = 1;
64 vapier 1.10 static char be_quiet = 0;
65 vapier 1.14 static char be_verbose = 0;
66 vapier 1.39 static char *find_sym = NULL, *versioned_symname = NULL;
67     static char *out_format = NULL;
68 vapier 1.10
69 solar 1.1
70    
71 vapier 1.39 /* sub-funcs for scanelf_file() */
72     static void scanelf_file_pax(elfobj *elf, char *found_pax)
73 solar 1.6 {
74 vapier 1.39 char *paxflags;
75     if (!show_pax) return;
76 vapier 1.10
77 vapier 1.39 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 vapier 1.14 }
82 vapier 1.39 }
83     static void scanelf_file_stack(elfobj *elf, char *found_stack, char *found_relro)
84     {
85     int i;
86     if (!show_stack) return;
87 vapier 1.26 #define SHOW_STACK(B) \
88 vapier 1.39 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     }
108     static 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 vapier 1.26 } \
128 vapier 1.39 } }
129     SHOW_TEXTREL(32)
130     SHOW_TEXTREL(64)
131     if (!be_quiet && !*found_textrel) printf("------- ");
132     }
133     static 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 vapier 1.10
140 vapier 1.39 if (!show_rpath) return;
141 vapier 1.10
142 vapier 1.39 strtbl_void = elf_findsecbyname(elf, ".dynstr");
143     rpath = runpath = NULL;
144 vapier 1.10
145 vapier 1.39 if (strtbl_void) {
146 vapier 1.26 #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 vapier 1.39 *found_rpath = 1; \
159 vapier 1.26 } else if (EGET(dyn->d_tag) == DT_RUNPATH) { \
160     runpath = elf->data + EGET(strtbl->sh_offset) + EGET(dyn->d_un.d_ptr); \
161 vapier 1.39 *found_rpath = 1; \
162 vapier 1.26 } \
163     ++dyn; \
164     } \
165     } }
166     SHOW_RPATH(32)
167     SHOW_RPATH(64)
168 vapier 1.10 }
169 vapier 1.39 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     }
181     static 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 vapier 1.10
189 vapier 1.39 strtbl_void = elf_findsecbyname(elf, ".dynstr");
190 vapier 1.32
191 vapier 1.39 if (strtbl_void) {
192 vapier 1.32 #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 vapier 1.39 if (*found_needed) printf(","); \
205 vapier 1.32 printf("%s", needed); \
206 vapier 1.39 *found_needed = 1; \
207 vapier 1.32 } \
208     ++dyn; \
209     } \
210     } }
211     SHOW_NEEDED(32)
212     SHOW_NEEDED(64)
213     }
214 vapier 1.39 if (!be_quiet && !*found_needed)
215     printf(" - ");
216     else if (*found_needed)
217     printf(" ");
218     }
219     static void scanelf_file_interp(elfobj *elf, char *found_interp)
220     {
221     void *strtbl_void;
222    
223     if (!show_interp) return;
224 vapier 1.32
225 vapier 1.39 strtbl_void = elf_findsecbyname(elf, ".interp");
226 vapier 1.38
227 vapier 1.39 if (strtbl_void) {
228 vapier 1.38 #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 vapier 1.39 *found_interp = 1; \
233 vapier 1.38 }
234     SHOW_INTERP(32)
235     SHOW_INTERP(64)
236     }
237 vapier 1.39 if (!be_quiet && !*found_interp)
238     printf(" - ");
239     else if (*found_interp)
240     printf(" ");
241     }
242     static void scanelf_file_sym(elfobj *elf, char *found_sym, const char *filename)
243     {
244     int i;
245     void *symtab_void, *strtab_void;
246 vapier 1.38
247 vapier 1.39 if (!find_sym) return;
248 vapier 1.32
249 vapier 1.39 symtab_void = elf_findsecbyname(elf, ".symtab");
250     strtab_void = elf_findsecbyname(elf, ".strtab");
251 vapier 1.27
252 vapier 1.39 if (symtab_void && strtab_void) {
253 vapier 1.27 #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 solar 1.28 if (*find_sym == '*') { \
264 vapier 1.32 printf("%s(%s) %5lX %15s %s\n", \
265 vapier 1.39 ((*found_sym == 0) ? "\n\t" : "\t"), \
266 vapier 1.32 (char *)basename(filename), \
267     (long)sym->st_size, \
268     (char *)get_elfstttype(sym->st_info), \
269     symname); \
270 vapier 1.39 *found_sym = 1; \
271 vapier 1.32 } else if ((strcmp(find_sym, symname) == 0) || \
272 vapier 1.39 (strcmp(symname, versioned_symname) == 0)) \
273     (*found_sym)++; \
274 vapier 1.27 } \
275     ++sym; \
276     } }
277     FIND_SYM(32)
278     FIND_SYM(64)
279 vapier 1.39 }
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 */
288     static 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     }
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 vapier 1.27 }
353 vapier 1.39 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 vapier 1.29 }
381 vapier 1.39 } 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");
397 vapier 1.27 }
398 vapier 1.10
399     unreadelf(elf);
400 solar 1.6 }
401    
402 solar 1.1 /* scan a directory for ET_EXEC files and print when we find one */
403 vapier 1.10 static void scanelf_dir(const char *path)
404 solar 1.1 {
405 vapier 1.10 register DIR *dir;
406     register struct dirent *dentry;
407 vapier 1.14 struct stat st_top, st;
408 solar 1.21 char buf[_POSIX_PATH_MAX];
409 vapier 1.32 size_t pathlen = 0, len = 0;
410 vapier 1.10
411     /* make sure path exists */
412 vapier 1.39 if (lstat(path, &st_top) == -1) {
413     if (be_verbose > 2) printf("%s: does not exist\n", path);
414 vapier 1.10 return;
415 vapier 1.39 }
416 solar 1.11
417 vapier 1.10 /* ok, if it isn't a directory, assume we can open it */
418 vapier 1.14 if (!S_ISDIR(st_top.st_mode)) {
419 vapier 1.10 scanelf_file(path);
420     return;
421     }
422    
423     /* now scan the dir looking for fun stuff */
424     if ((dir = opendir(path)) == NULL) {
425     warnf("could not opendir %s: %s", path, strerror(errno));
426     return;
427     }
428 vapier 1.15 if (be_verbose) printf("%s: scanning dir\n", path);
429 solar 1.11
430 vapier 1.32 pathlen = strlen(path);
431 vapier 1.10 while ((dentry = readdir(dir))) {
432     if (!strcmp(dentry->d_name, ".") || !strcmp(dentry->d_name, ".."))
433     continue;
434 vapier 1.32 len = (pathlen + 1 + strlen(dentry->d_name) + 1);
435     if (len >= sizeof(buf)) {
436     warnf("Skipping '%s': len > sizeof(buf); %d > %d\n", path, (int)len, (int)sizeof(buf));
437     continue;
438     }
439 solar 1.31 sprintf(buf, "%s/%s", path, dentry->d_name);
440 solar 1.20 if (lstat(buf, &st) != -1) {
441 vapier 1.10 if (S_ISREG(st.st_mode))
442 solar 1.20 scanelf_file(buf);
443 vapier 1.10 else if (dir_recurse && S_ISDIR(st.st_mode)) {
444 vapier 1.14 if (dir_crossmount || (st_top.st_dev == st.st_dev))
445 solar 1.20 scanelf_dir(buf);
446 vapier 1.10 }
447     }
448     }
449     closedir(dir);
450 solar 1.1 }
451    
452 vapier 1.10 /* scan /etc/ld.so.conf for paths */
453     static void scanelf_ldpath()
454     {
455 vapier 1.17 char scan_l, scan_ul, scan_ull;
456 vapier 1.10 char *path, *p;
457     FILE *fp;
458    
459     if ((fp = fopen("/etc/ld.so.conf", "r")) == NULL)
460     err("Unable to open ld.so.conf: %s", strerror(errno));
461    
462 vapier 1.17 scan_l = scan_ul = scan_ull = 0;
463    
464 solar 1.30 if ((path = malloc(_POSIX_PATH_MAX)) == NULL) {
465     warn("Can not malloc() memory for ldpath scanning");
466     return;
467     }
468 vapier 1.10 while ((fgets(path, _POSIX_PATH_MAX, fp)) != NULL)
469     if (*path == '/') {
470     if ((p = strrchr(path, '\r')) != NULL)
471     *p = 0;
472     if ((p = strrchr(path, '\n')) != NULL)
473     *p = 0;
474 vapier 1.17 if (!scan_l && !strcmp(path, "/lib")) scan_l = 1;
475     if (!scan_ul && !strcmp(path, "/usr/lib")) scan_ul = 1;
476     if (!scan_ull && !strcmp(path, "/usr/local/lib")) scan_ull = 1;
477 vapier 1.10 scanelf_dir(path);
478     }
479     free(path);
480 vapier 1.32 fclose(fp);
481 vapier 1.10
482 vapier 1.17 if (!scan_l) scanelf_dir("/lib");
483     if (!scan_ul) scanelf_dir("/usr/lib");
484     if (!scan_ull) scanelf_dir("/usr/local/lib");
485 vapier 1.10 }
486 solar 1.1
487 vapier 1.10 /* scan env PATH for paths */
488     static void scanelf_envpath()
489 solar 1.1 {
490 solar 1.34 char *path, *p;
491 vapier 1.10
492     path = getenv("PATH");
493     if (!path)
494     err("PATH is not set in your env !");
495    
496 solar 1.34 if ((path = strdup(path)) == NULL)
497 vapier 1.32 err("strdup failed: %s", strerror(errno));
498 vapier 1.10
499     while ((p = strrchr(path, ':')) != NULL) {
500     scanelf_dir(p + 1);
501     *p = 0;
502     }
503 vapier 1.17
504 solar 1.34 free(path);
505 solar 1.1 }
506    
507    
508 vapier 1.10
509     /* usage / invocation handling functions */
510 vapier 1.39 #define PARSE_FLAGS "plRmyxetrnis:aqvF:o:BhV"
511 vapier 1.27 #define a_argument required_argument
512 vapier 1.10 static struct option const long_opts[] = {
513     {"path", no_argument, NULL, 'p'},
514     {"ldpath", no_argument, NULL, 'l'},
515     {"recursive", no_argument, NULL, 'R'},
516 vapier 1.14 {"mount", no_argument, NULL, 'm'},
517 vapier 1.37 {"symlink", no_argument, NULL, 'y'},
518 vapier 1.10 {"pax", no_argument, NULL, 'x'},
519 solar 1.16 {"header", no_argument, NULL, 'e'},
520 vapier 1.10 {"textrel", no_argument, NULL, 't'},
521     {"rpath", no_argument, NULL, 'r'},
522 vapier 1.32 {"needed", no_argument, NULL, 'n'},
523 vapier 1.38 {"interp", no_argument, NULL, 'i'},
524 vapier 1.27 {"symbol", a_argument, NULL, 's'},
525 vapier 1.10 {"all", no_argument, NULL, 'a'},
526     {"quiet", no_argument, NULL, 'q'},
527 vapier 1.14 {"verbose", no_argument, NULL, 'v'},
528 vapier 1.39 {"format", a_argument, NULL, 'F'},
529 vapier 1.27 {"file", a_argument, NULL, 'o'},
530 solar 1.16 {"nobanner", no_argument, NULL, 'B'},
531 vapier 1.10 {"help", no_argument, NULL, 'h'},
532     {"version", no_argument, NULL, 'V'},
533     {NULL, no_argument, NULL, 0x0}
534     };
535     static char *opts_help[] = {
536     "Scan all directories in PATH environment",
537     "Scan all directories in /etc/ld.so.conf",
538 vapier 1.14 "Scan directories recursively",
539 vapier 1.37 "Don't recursively cross mount points",
540     "Don't scan symlinks\n",
541 vapier 1.10 "Print PaX markings",
542     "Print GNU_STACK markings",
543     "Print TEXTREL information",
544     "Print RPATH information",
545 vapier 1.32 "Print NEEDED information",
546 vapier 1.38 "Print INTERP information",
547 vapier 1.27 "Find a specified symbol",
548 solar 1.16 "Print all scanned info (-x -e -t -r)\n",
549 vapier 1.14 "Only output 'bad' things",
550     "Be verbose (can be specified more than once)",
551 vapier 1.39 "Use specified format for output",
552 vapier 1.24 "Write output stream to a filename",
553 vapier 1.14 "Don't display the header",
554 vapier 1.10 "Print this help and exit",
555     "Print version and exit",
556     NULL
557     };
558    
559     /* display usage and exit */
560     static void usage(int status)
561 solar 1.1 {
562 vapier 1.10 int i;
563 vapier 1.37 printf(" Scan ELF binaries for stuff\n\n"
564 solar 1.35 "Usage: %s [options] <dir1/file1> [dir2 dirN fileN ...]\n\n", argv0);
565     printf("Options: -[%s]\n", PARSE_FLAGS);
566 vapier 1.10 for (i = 0; long_opts[i].name; ++i)
567 vapier 1.27 if (long_opts[i].has_arg == no_argument)
568     printf(" -%c, --%-13s %s\n", long_opts[i].val,
569     long_opts[i].name, opts_help[i]);
570     else
571     printf(" -%c, --%-6s <arg> %s\n", long_opts[i].val,
572     long_opts[i].name, opts_help[i]);
573 vapier 1.10 exit(status);
574 solar 1.1 }
575    
576     /* parse command line arguments and preform needed actions */
577 vapier 1.10 static void parseargs(int argc, char *argv[])
578     {
579     int flag;
580    
581     opterr = 0;
582     while ((flag=getopt_long(argc, argv, PARSE_FLAGS, long_opts, NULL)) != -1) {
583     switch (flag) {
584    
585 vapier 1.39 case 'V':
586 solar 1.19 printf("%s compiled %s\n%s\n"
587     "%s written for Gentoo Linux by <solar and vapier @ gentoo.org>\n",
588     __FILE__, __DATE__, rcsid, argv0);
589 vapier 1.10 exit(EXIT_SUCCESS);
590     break;
591     case 'h': usage(EXIT_SUCCESS); break;
592    
593 vapier 1.24 case 'o': {
594 solar 1.21 FILE *fp = NULL;
595     fp = freopen(optarg, "w", stdout);
596 vapier 1.24 if (fp == NULL)
597     err("Could not open output stream '%s': %s", optarg, strerror(errno));
598     stdout = fp;
599 solar 1.21 break;
600     }
601 vapier 1.24
602 vapier 1.39 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 vapier 1.27
629 vapier 1.37 case 'y': scan_symlink = 0; break;
630 solar 1.16 case 'B': show_banner = 0; break;
631 vapier 1.10 case 'l': scan_ldpath = 1; break;
632     case 'p': scan_envpath = 1; break;
633     case 'R': dir_recurse = 1; break;
634 vapier 1.14 case 'm': dir_crossmount = 0; break;
635 vapier 1.10 case 'x': show_pax = 1; break;
636 solar 1.16 case 'e': show_stack = 1; break;
637 vapier 1.10 case 't': show_textrel = 1; break;
638     case 'r': show_rpath = 1; break;
639 vapier 1.32 case 'n': show_needed = 1; break;
640 vapier 1.38 case 'i': show_interp = 1; break;
641 vapier 1.10 case 'q': be_quiet = 1; break;
642 vapier 1.14 case 'v': be_verbose = (be_verbose % 20) + 1; break;
643 vapier 1.38 case 'a': show_pax = show_stack = show_textrel = show_rpath = show_needed = show_interp = 1; break;
644 vapier 1.10
645     case ':':
646 vapier 1.39 warn("Option missing parameter\n");
647 vapier 1.10 usage(EXIT_FAILURE);
648     break;
649     case '?':
650 vapier 1.39 warn("Unknown option\n");
651 vapier 1.10 usage(EXIT_FAILURE);
652     break;
653     default:
654     err("Unhandled option '%c'", flag);
655     break;
656     }
657     }
658    
659 vapier 1.14 if (be_quiet && be_verbose)
660     err("You can be quiet or you can be verbose, not both, stupid");
661    
662 vapier 1.39 /* 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 */
686 vapier 1.10 if (scan_ldpath) scanelf_ldpath();
687     if (scan_envpath) scanelf_envpath();
688 vapier 1.25 if (optind == argc && !scan_ldpath && !scan_envpath)
689     err("Nothing to scan !?");
690 vapier 1.10 while (optind < argc)
691     scanelf_dir(argv[optind++]);
692 vapier 1.27
693 vapier 1.39 /* clean up */
694     if (find_sym) {
695     free(find_sym);
696     free(versioned_symname);
697     }
698     if (out_format) free(out_format);
699 vapier 1.10 }
700    
701    
702    
703     int main(int argc, char *argv[])
704 solar 1.1 {
705 vapier 1.10 if (argc < 2)
706     usage(EXIT_FAILURE);
707     parseargs(argc, argv);
708 solar 1.21 fclose(stdout);
709 vapier 1.10 return EXIT_SUCCESS;
710 solar 1.1 }

  ViewVC Help
Powered by ViewVC 1.1.20