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

Contents of /pax-utils/scanelf.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.44 - (hide annotations) (download) (as text)
Tue May 10 22:54:25 2005 UTC (9 years, 7 months ago) by vapier
Branch: MAIN
Changes since 1.43: +40 -18 lines
File MIME type: text/x-csrc
make sure we verify pointers before using them and use variables with larger sizes than just int

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

  ViewVC Help
Powered by ViewVC 1.1.20