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

Contents of /pax-utils/scanelf.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.41 - (hide annotations) (download) (as text)
Fri May 6 01:01:42 2005 UTC (9 years, 4 months ago) by vapier
Branch: MAIN
Changes since 1.40: +196 -132 lines
File MIME type: text/x-csrc
buffer output so quiet + format works

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

  ViewVC Help
Powered by ViewVC 1.1.20