/[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.35 Revision 1.71
1/* 1/*
2 * Copyright 2003 Ned Ludd <solar@gentoo.org>
3 * Copyright 1999-2005 Gentoo Foundation 2 * Copyright 2003-2005 Gentoo Foundation
4 * Distributed under the terms of the GNU General Public License v2 3 * Distributed under the terms of the GNU General Public License v2
5 * $Header: /var/cvsroot/gentoo-projects/pax-utils/Attic/scanelf.c,v 1.35 2005/04/14 00:17:30 solar Exp $ 4 * $Header: /var/cvsroot/gentoo-projects/pax-utils/Attic/scanelf.c,v 1.71 2005/06/04 02:50:50 vapier Exp $
6 * 5 *
7 ******************************************************************** 6 ********************************************************************
8 * This program is free software; you can redistribute it and/or 7 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License as 8 * modify it under the terms of the GNU General Public License as
10 * published by the Free Software Foundation; either version 2 of the 9 * published by the Free Software Foundation; either version 2 of the
22 */ 21 */
23 22
24#include <stdio.h> 23#include <stdio.h>
25#include <stdlib.h> 24#include <stdlib.h>
26#include <sys/types.h> 25#include <sys/types.h>
26#include <libgen.h>
27#include <limits.h>
27#define __USE_GNU 28#define __USE_GNU
28#include <string.h> 29#include <string.h>
29#include <errno.h> 30#include <errno.h>
30#include <unistd.h> 31#include <unistd.h>
31#include <sys/stat.h> 32#include <sys/stat.h>
32#include <dirent.h> 33#include <dirent.h>
33#include <getopt.h> 34#include <getopt.h>
34#include <assert.h> 35#include <assert.h>
35
36#include "paxelf.h" 36#include "paxelf.h"
37 37
38static const char *rcsid = "$Id: scanelf.c,v 1.35 2005/04/14 00:17:30 solar Exp $"; 38static const char *rcsid = "$Id: scanelf.c,v 1.71 2005/06/04 02:50:50 vapier Exp $";
39#define argv0 "scanelf"
39 40
40 41#define IS_MODIFIER(c) (c == '%' || c == '#')
41/* helper functions for showing errors */
42#define argv0 "scanelf" /*((*argv != NULL) ? argv[0] : __FILE__ "\b\b")*/
43#define warn(fmt, args...) \
44 fprintf(stderr, "%s: " fmt "\n", argv0, ## args)
45#define warnf(fmt, args...) warn("%s(): " fmt, __FUNCTION__, ## args)
46#define err(fmt, args...) \
47 do { \
48 warn(fmt, ## args); \
49 exit(EXIT_FAILURE); \
50 } while (0)
51 42
52 43
53 44
54/* prototypes */ 45/* prototypes */
55static void scanelf_file(const char *filename); 46static void scanelf_file(const char *filename);
56static void scanelf_dir(const char *path); 47static void scanelf_dir(const char *path);
57static void scanelf_ldpath(); 48static void scanelf_ldpath();
58static void scanelf_envpath(); 49static void scanelf_envpath();
59static void usage(int status); 50static void usage(int status);
60static void parseargs(int argc, char *argv[]); 51static void parseargs(int argc, char *argv[]);
52static char *xstrdup(const char *s);
53static void *xmalloc(size_t size);
54static void xstrcat(char **dst, const char *src, size_t *curr_len);
55static inline void xchrcat(char **dst, const char append, size_t *curr_len);
61 56
62/* variables to control behavior */ 57/* variables to control behavior */
58static char *ldpaths[256];
63static char scan_ldpath = 0; 59static char scan_ldpath = 0;
64static char scan_envpath = 0; 60static char scan_envpath = 0;
61static char scan_symlink = 1;
65static char dir_recurse = 0; 62static char dir_recurse = 0;
66static char dir_crossmount = 1; 63static char dir_crossmount = 1;
67static char show_pax = 0; 64static char show_pax = 0;
68static char show_stack = 0; 65static char show_stack = 0;
69static char show_textrel = 0; 66static char show_textrel = 0;
70static char show_rpath = 0; 67static char show_rpath = 0;
71static char show_needed = 0; 68static char show_needed = 0;
69static char show_interp = 0;
70static char show_bind = 0;
72static char show_banner = 1; 71static char show_banner = 1;
73static char be_quiet = 0; 72static char be_quiet = 0;
74static char be_verbose = 0; 73static char be_verbose = 0;
74static char be_wewy_wewy_quiet = 0;
75static char *find_sym = NULL, *versioned_symname = NULL;
75static char *find_sym = NULL; 76static char *out_format = NULL;
77static char *search_path = NULL;
76 78
77 79
78 80
79/* scan an elf file and show all the fun stuff */ 81/* sub-funcs for scanelf_file() */
80static void scanelf_file(const char *filename) 82static char *scanelf_file_pax(elfobj *elf, char *found_pax)
81{ 83{
82 int i; 84 static char *paxflags;
83 char found_pax, found_stack, found_relro, found_textrel, 85 static char ret[7];
84 found_rpath, found_needed, found_sym; 86 unsigned long i, shown;
85 elfobj *elf;
86 struct stat st;
87 87
88 /* make sure path exists */
89 if (lstat(filename, &st) == -1)
90 return;
91 if (!S_ISREG(st.st_mode))
92 return;
93 found_pax = found_stack = found_relro = found_textrel = \
94 found_rpath = found_needed = found_sym = 0;
95 88
96 /* verify this is real ELF */ 89 if (!show_pax) return NULL;
97 if ((elf = readelf(filename)) == NULL) {
98 if (be_verbose > 2) printf("%s: not an ELF\n", filename);
99 return;
100 }
101 90
102 if (be_verbose > 1)
103 printf("%s: {%s,%s} scanning file\n", filename,
104 get_elfeitype(elf, EI_CLASS, elf->elf_class),
105 get_elfeitype(elf, EI_DATA, elf->data[EI_DATA]));
106 else if (be_verbose)
107 printf("%s: scanning file\n", filename);
108
109 /* show the header */
110 if (!be_quiet && show_banner) {
111 printf(" TYPE ");
112 if (show_pax) printf(" PAX ");
113 if (show_stack) printf("STK/REL ");
114 if (show_textrel) printf("TEXTREL ");
115 if (show_rpath) printf("RPATH ");
116 if (show_needed) printf("NEEDED ");
117 printf(" FILE\n");
118 show_banner = 0; 91 shown = 0;
119 } 92 memset(&ret, 0, sizeof(ret));
120 93
121 /* dump all the good stuff */ 94 if (elf->phdr) {
122 if (!be_quiet) 95#define SHOW_PAX(B) \
123 printf("%-7s ", get_elfetype(elf)); 96 if (elf->elf_class == ELFCLASS ## B) { \
97 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \
98 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \
99 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \
100 if (EGET(phdr[i].p_type) != PT_PAX_FLAGS) \
101 continue; \
102 if (be_quiet && (EGET(phdr[i].p_flags) == 10240)) \
103 continue; \
104 memcpy(ret, pax_short_pf_flags(EGET(phdr[i].p_flags)), 6); \
105 *found_pax = 1; \
106 ++shown; \
107 break; \
108 } \
109 }
110 SHOW_PAX(32)
111 SHOW_PAX(64)
112 }
124 113
125 if (show_pax) { 114 /* fall back to EI_PAX if no PT_PAX was found */
115 if (!*ret) {
126 char *paxflags = pax_short_hf_flags(PAX_FLAGS(elf)); 116 paxflags = pax_short_hf_flags(EI_PAX_FLAGS(elf));
127 if (!be_quiet || (be_quiet && strncmp(paxflags, "PeMRxS", 6))) { 117 if (!be_quiet || (be_quiet && EI_PAX_FLAGS(elf))) {
128 found_pax = 1; 118 *found_pax = 1;
129 printf("%s ", pax_short_hf_flags(PAX_FLAGS(elf))); 119 return paxflags;
130 }
131 } 120 }
121 strncpy(ret, paxflags, sizeof(ret));
122 // ++shown;
123 }
132 124
133 /* stack fun */ 125 if (be_quiet && !shown)
134 if (show_stack) { 126 return NULL;
127 return ret;
128
129}
130static char *scanelf_file_stack(elfobj *elf, char *found_stack, char *found_relro, char *found_load)
131{
132 static char ret[12];
133 char *found;
134 unsigned long i, off, shown, check_flags;
135 unsigned char multi_stack, multi_relro, multi_load;
136
137 if (!show_stack) return NULL;
138
139 memcpy(ret, "--- --- ---\0", 12);
140
141 shown = 0;
142 multi_stack = multi_relro = multi_load = 0;
143
144 if (elf->phdr) {
135#define SHOW_STACK(B) \ 145#define SHOW_STACK(B) \
136 if (elf->elf_class == ELFCLASS ## B) { \ 146 if (elf->elf_class == ELFCLASS ## B) { \
137 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \ 147 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \
138 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \ 148 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \
149 uint32_t flags; \
139 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \ 150 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \
140 if (EGET(phdr[i].p_type) != PT_GNU_STACK && \
141 EGET(phdr[i].p_type) != PT_GNU_RELRO) continue; \
142 if (be_quiet && !(EGET(phdr[i].p_flags) & PF_X)) \
143 continue; \
144 if (EGET(phdr[i].p_type) == PT_GNU_STACK) \ 151 if (EGET(phdr[i].p_type) == PT_GNU_STACK) { \
145 found_stack = 1; \ 152 if (multi_stack++) warnf("%s: multiple PT_GNU_STACK's !?", elf->filename); \
153 found = found_stack; \
154 off = 0; \
155 check_flags = PF_X; \
146 if (EGET(phdr[i].p_type) == PT_GNU_RELRO) \ 156 } else if (EGET(phdr[i].p_type) == PT_GNU_RELRO) { \
157 if (multi_relro++) warnf("%s: multiple PT_GNU_RELRO's !?", elf->filename); \
158 found = found_relro; \
159 off = 4; \
160 check_flags = PF_X; \
161 } else if (EGET(phdr[i].p_type) == PT_LOAD) { \
162 if (multi_load++ > 2) warnf("%s: more than 2 PT_LOAD's !?", elf->filename); \
163 found = found_load; \
164 off = 8; \
165 check_flags = PF_W|PF_X; \
166 } else \
167 continue; \
168 flags = EGET(phdr[i].p_flags); \
169 if (be_quiet && ((flags & check_flags) != check_flags)) \
170 continue; \
171 memcpy(ret+off, gnu_short_stack_flags(flags), 3); \
172 *found = 1; \
173 ++shown; \
174 } \
175 }
176 SHOW_STACK(32)
177 SHOW_STACK(64)
178 }
179
180 if (be_quiet && !shown)
181 return NULL;
182 else
183 return ret;
184}
185static char *scanelf_file_textrel(elfobj *elf, char *found_textrel)
186{
187 static char ret[] = "TEXTREL";
188 unsigned long i;
189
190 if (!show_textrel) return NULL;
191
192 if (elf->phdr) {
193#define SHOW_TEXTREL(B) \
194 if (elf->elf_class == ELFCLASS ## B) { \
195 Elf ## B ## _Dyn *dyn; \
196 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \
197 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \
198 Elf ## B ## _Off offset; \
199 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \
200 if (EGET(phdr[i].p_type) != PT_DYNAMIC) continue; \
201 offset = EGET(phdr[i].p_offset); \
202 if (offset >= elf->len - sizeof(Elf ## B ## _Dyn)) continue; \
203 dyn = DYN ## B (elf->data + offset); \
204 while (EGET(dyn->d_tag) != DT_NULL) { \
205 if (EGET(dyn->d_tag) == DT_TEXTREL) { /*dyn->d_tag != DT_FLAGS)*/ \
147 found_relro = 1; \ 206 *found_textrel = 1; \
148 printf("%s ", gnu_short_stack_flags(EGET(phdr[i].p_flags))); \ 207 /*if (dyn->d_un.d_val & DF_TEXTREL)*/ \
208 return (be_wewy_wewy_quiet ? NULL : ret); \
209 } \
210 ++dyn; \
149 } \ 211 } \
150 }
151 SHOW_STACK(32)
152 SHOW_STACK(64)
153 if (!be_quiet && !found_stack) printf("--- ");
154 if (!be_quiet && !found_relro) printf("--- ");
155 }
156
157 /* textrel fun */
158 if (show_textrel) {
159#define SHOW_TEXTREL(B) \
160 if (elf->elf_class == ELFCLASS ## B) { \
161 Elf ## B ## _Dyn *dyn; \
162 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \
163 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \
164 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \
165 if (phdr[i].p_type != PT_DYNAMIC) continue; \
166 dyn = DYN ## B (elf->data + EGET(phdr[i].p_offset)); \
167 while (EGET(dyn->d_tag) != DT_NULL) { \
168 if (EGET(dyn->d_tag) == DT_TEXTREL) { /*dyn->d_tag != DT_FLAGS)*/ \
169 found_textrel = 1; \
170 /*if (dyn->d_un.d_val & DF_TEXTREL)*/ \
171 fputs("TEXTREL ", stdout); \
172 } \
173 ++dyn; \
174 } \
175 } } 212 } }
176 SHOW_TEXTREL(32) 213 SHOW_TEXTREL(32)
177 SHOW_TEXTREL(64) 214 SHOW_TEXTREL(64)
178 if (!be_quiet && !found_textrel) fputs("------- ", stdout);
179 } 215 }
180 216
181 /* rpath fun */ 217 if (be_quiet || be_wewy_wewy_quiet)
182 /* TODO: if be_quiet, only output RPATH's which aren't in /etc/ld.so.conf */ 218 return NULL;
183 if (show_rpath) { 219 else
220 return (char *)" - ";
221}
222static void scanelf_file_rpath(elfobj *elf, char *found_rpath, char **ret, size_t *ret_len)
223{
224 unsigned long i, s;
184 char *rpath, *runpath; 225 char *rpath, *runpath, **r;
226 void *strtbl_void;
227
228 if (!show_rpath) return;
229
185 void *strtbl_void = elf_findsecbyname(elf, ".dynstr"); 230 strtbl_void = elf_findsecbyname(elf, ".dynstr");
186 rpath = runpath = NULL; 231 rpath = runpath = NULL;
187 232
188 if (strtbl_void) { 233 if (elf->phdr && strtbl_void) {
189#define SHOW_RPATH(B) \ 234#define SHOW_RPATH(B) \
190 if (elf->elf_class == ELFCLASS ## B) { \ 235 if (elf->elf_class == ELFCLASS ## B) { \
191 Elf ## B ## _Dyn *dyn; \ 236 Elf ## B ## _Dyn *dyn; \
192 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \ 237 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \
193 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \ 238 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \
194 Elf ## B ## _Shdr *strtbl = SHDR ## B (strtbl_void); \ 239 Elf ## B ## _Shdr *strtbl = SHDR ## B (strtbl_void); \
240 Elf ## B ## _Off offset; \
241 Elf ## B ## _Xword word; \
242 /* Scan all the program headers */ \
195 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \ 243 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \
244 /* Just scan dynamic headers */ \
196 if (EGET(phdr[i].p_type) != PT_DYNAMIC) continue; \ 245 if (EGET(phdr[i].p_type) != PT_DYNAMIC) continue; \
246 offset = EGET(phdr[i].p_offset); \
247 if (offset >= elf->len - sizeof(Elf ## B ## _Dyn)) continue; \
248 /* Just scan dynamic RPATH/RUNPATH headers */ \
197 dyn = DYN ## B (elf->data + EGET(phdr[i].p_offset)); \ 249 dyn = DYN ## B (elf->data + offset); \
198 while (EGET(dyn->d_tag) != DT_NULL) { \ 250 while ((word=EGET(dyn->d_tag)) != DT_NULL) { \
199 if (EGET(dyn->d_tag) == DT_RPATH) { \ 251 if (word == DT_RPATH) { \
252 r = &rpath; \
253 } else if (word == DT_RUNPATH) { \
254 r = &runpath; \
255 } else { \
256 ++dyn; \
257 continue; \
258 } \
259 /* Verify the memory is somewhat sane */ \
200 rpath = elf->data + EGET(strtbl->sh_offset) + EGET(dyn->d_un.d_ptr); \ 260 offset = EGET(strtbl->sh_offset) + EGET(dyn->d_un.d_ptr); \
261 if (offset < (Elf ## B ## _Off)elf->len) { \
262 if (*r) warn("ELF has multiple %s's !?", get_elfdtype(word)); \
263 *r = (char*)(elf->data + offset); \
264 /* If quiet, don't output paths in ld.so.conf */ \
265 if (be_quiet) { \
266 size_t len; \
267 char *start, *end; \
268 for (s = 0; *r && ldpaths[s]; ++s) { \
269 /* scan each path in : delimited list */ \
270 start = *r; \
271 end = strchr(start, ':'); \
272 while ((start && ((end = strchr(start, ':')) != NULL)) || start) { \
273 len = (end ? abs(end - start) : strlen(start)); \
274 if (!strncmp(ldpaths[s], start, len) && !ldpaths[s][len]) { \
275 *r = (end ? end + 1 : NULL); \
276 break; \
277 } \
278 start = (end ? start + len + 1 : NULL); \
279 } \
280 } \
281 } \
201 found_rpath = 1; \ 282 if (*r) *found_rpath = 1; \
202 } else if (EGET(dyn->d_tag) == DT_RUNPATH) { \
203 runpath = elf->data + EGET(strtbl->sh_offset) + EGET(dyn->d_un.d_ptr); \
204 found_rpath = 1; \
205 } \ 283 } \
206 ++dyn; \ 284 ++dyn; \
207 } \ 285 } \
208 } } 286 } }
209 SHOW_RPATH(32) 287 SHOW_RPATH(32)
210 SHOW_RPATH(64) 288 SHOW_RPATH(64)
211 } 289 }
290
291 if (be_wewy_wewy_quiet) return;
292
212 if (rpath && runpath) { 293 if (rpath && runpath) {
213 if (!strcmp(rpath, runpath)) 294 if (!strcmp(rpath, runpath)) {
214 printf("%-5s ", runpath); 295 xstrcat(ret, runpath, ret_len);
215 else { 296 } else {
216 fprintf(stderr, "%s's RPATH [%s] != RUNPATH [%s]\n", filename, rpath, runpath); 297 fprintf(stderr, "RPATH [%s] != RUNPATH [%s]\n", rpath, runpath);
217 printf("{%s,%s} ", rpath, runpath); 298 xchrcat(ret, '{', ret_len);
299 xstrcat(ret, rpath, ret_len);
300 xchrcat(ret, ',', ret_len);
301 xstrcat(ret, runpath, ret_len);
302 xchrcat(ret, '}', ret_len);
218 } 303 }
219 } else if (rpath || runpath) 304 } else if (rpath || runpath)
220 printf("%-5s ", (runpath ? runpath : rpath)); 305 xstrcat(ret, (runpath ? runpath : rpath), ret_len);
221 else if (!be_quiet && !found_rpath) 306 else if (!be_quiet)
222 printf(" - "); 307 xstrcat(ret, " - ", ret_len);
223 } 308}
224 309static void scanelf_file_needed(elfobj *elf, char *found_needed, char **ret, size_t *ret_len)
225 /* print out all the NEEDED entries */ 310{
226 if (show_needed) { 311 unsigned long i;
227 char *needed; 312 char *needed;
313 void *strtbl_void;
314
315 if (!show_needed) return;
316
228 void *strtbl_void = elf_findsecbyname(elf, ".dynstr"); 317 strtbl_void = elf_findsecbyname(elf, ".dynstr");
229 318
230 if (strtbl_void) { 319 if (elf->phdr && strtbl_void) {
231#define SHOW_NEEDED(B) \ 320#define SHOW_NEEDED(B) \
232 if (elf->elf_class == ELFCLASS ## B) { \ 321 if (elf->elf_class == ELFCLASS ## B) { \
233 Elf ## B ## _Dyn *dyn; \ 322 Elf ## B ## _Dyn *dyn; \
234 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \ 323 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \
235 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \ 324 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \
236 Elf ## B ## _Shdr *strtbl = SHDR ## B (strtbl_void); \ 325 Elf ## B ## _Shdr *strtbl = SHDR ## B (strtbl_void); \
326 Elf ## B ## _Off offset; \
237 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \ 327 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \
238 if (be_verbose && EGET(phdr[i].p_type) == PT_INTERP) { \
239 dyn = DYN ## B (elf->data + EGET(phdr[i].p_offset)); \
240 printf("%s\n", elf->data + EGET(strtbl->sh_offset) + EGET(dyn->d_un.d_ptr)); \
241 exit(0); \
242 } \
243 if (EGET(phdr[i].p_type) != PT_DYNAMIC) continue; \ 328 if (EGET(phdr[i].p_type) != PT_DYNAMIC) continue; \
329 offset = EGET(phdr[i].p_offset); \
330 if (offset >= elf->len - sizeof(Elf ## B ## _Dyn)) continue; \
244 dyn = DYN ## B (elf->data + EGET(phdr[i].p_offset)); \ 331 dyn = DYN ## B (elf->data + offset); \
245 while (EGET(dyn->d_tag) != DT_NULL) { \ 332 while (EGET(dyn->d_tag) != DT_NULL) { \
246 if (EGET(dyn->d_tag) == DT_NEEDED) { \ 333 if (EGET(dyn->d_tag) == DT_NEEDED) { \
247 needed = elf->data + EGET(strtbl->sh_offset) + EGET(dyn->d_un.d_ptr); \ 334 offset = EGET(strtbl->sh_offset) + EGET(dyn->d_un.d_ptr); \
248 if (found_needed) printf(","); \ 335 if (offset >= (Elf ## B ## _Off)elf->len) { \
249 printf("%s", needed); \ 336 ++dyn; \
337 continue; \
338 } \
339 needed = (char*)(elf->data + offset); \
340 if (*found_needed) xchrcat(ret, ',', ret_len); \
341 if (!be_wewy_wewy_quiet) xstrcat(ret, needed, ret_len); \
250 found_needed = 1; \ 342 *found_needed = 1; \
251 } \ 343 } \
252 ++dyn; \ 344 ++dyn; \
253 } \ 345 } \
254 } } 346 } }
255 SHOW_NEEDED(32) 347 SHOW_NEEDED(32)
256 SHOW_NEEDED(64) 348 SHOW_NEEDED(64)
257 } 349 }
258 if (!be_quiet && !found_needed) 350}
259 printf(" - "); 351static char *scanelf_file_interp(elfobj *elf, char *found_interp)
260 else if (found_needed) 352{
261 printf(" "); 353 void *strtbl_void;
354
355 if (!show_interp) return NULL;
356
357 strtbl_void = elf_findsecbyname(elf, ".interp");
358
359 if (strtbl_void) {
360#define SHOW_INTERP(B) \
361 if (elf->elf_class == ELFCLASS ## B) { \
362 Elf ## B ## _Shdr *strtbl = SHDR ## B (strtbl_void); \
363 *found_interp = 1; \
364 return (be_wewy_wewy_quiet ? NULL : elf->data + EGET(strtbl->sh_offset)); \
262 } 365 }
366 SHOW_INTERP(32)
367 SHOW_INTERP(64)
368 }
369 return NULL;
370}
371static char *scanelf_file_bind(elfobj *elf, char *found_bind)
372{
373 unsigned long i;
374 struct stat s;
263 375
264 /* search the symbol table for a specified symbol */ 376 if (!show_bind) return NULL;
265 if (find_sym) { 377 if (!elf->phdr) return NULL;
378
379#define SHOW_BIND(B) \
380 if (elf->elf_class == ELFCLASS ## B) { \
381 Elf ## B ## _Dyn *dyn; \
382 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \
383 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \
384 Elf ## B ## _Off offset; \
385 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \
386 if (EGET(phdr[i].p_type) != PT_DYNAMIC) continue; \
387 offset = EGET(phdr[i].p_offset); \
388 if (offset >= elf->len - sizeof(Elf ## B ## _Dyn)) continue; \
389 dyn = DYN ## B (elf->data + offset); \
390 while (EGET(dyn->d_tag) != DT_NULL) { \
391 if (EGET(dyn->d_tag) == DT_BIND_NOW || \
392 (EGET(dyn->d_tag) == DT_FLAGS && EGET(dyn->d_un.d_val) & DF_BIND_NOW)) \
393 { \
394 if (be_quiet) return NULL; \
395 *found_bind = 1; \
396 return (char *)(be_wewy_wewy_quiet ? NULL : "NOW"); \
397 } \
398 ++dyn; \
399 } \
400 } \
401 }
402 SHOW_BIND(32)
403 SHOW_BIND(64)
404
405 if (be_wewy_wewy_quiet) return NULL;
406
407 if (be_quiet && !fstat(elf->fd, &s) && !(s.st_mode & S_ISUID || s.st_mode & S_ISGID)) {
408 return NULL;
409 } else {
410 *found_bind = 1;
411 return (char *) "LAZY";
412 }
413}
414static char *scanelf_file_sym(elfobj *elf, char *found_sym, const char *filename)
415{
416 unsigned long i;
266 void *symtab_void, *strtab_void; 417 void *symtab_void, *strtab_void;
267 char *versioned_symname;
268 size_t len;
269 418
270 len = strlen(find_sym) + 1; 419 if (!find_sym) return NULL;
271 versioned_symname = (char *)malloc(sizeof(char) * (len+1));
272 if (!versioned_symname) {
273 warnf("Could not malloc() mem for sym scan");
274 return;
275 }
276 sprintf(versioned_symname, "%s@", find_sym);
277 420
421 /* debug sections */
278 symtab_void = elf_findsecbyname(elf, ".symtab"); 422 symtab_void = elf_findsecbyname(elf, ".symtab");
279 strtab_void = elf_findsecbyname(elf, ".strtab"); 423 strtab_void = elf_findsecbyname(elf, ".strtab");
424 /* fall back to runtime sections */
425 if (!symtab_void || !strtab_void) {
426 symtab_void = elf_findsecbyname(elf, ".dynsym");
427 strtab_void = elf_findsecbyname(elf, ".dynstr");
428 }
280 429
281 if (symtab_void && strtab_void) { 430 if (symtab_void && strtab_void) {
431 char *base, *basemem;
432 basemem = xstrdup(filename);
433 base = basename(basemem);
282#define FIND_SYM(B) \ 434#define FIND_SYM(B) \
283 if (elf->elf_class == ELFCLASS ## B) { \ 435 if (elf->elf_class == ELFCLASS ## B) { \
284 Elf ## B ## _Shdr *symtab = SHDR ## B (symtab_void); \ 436 Elf ## B ## _Shdr *symtab = SHDR ## B (symtab_void); \
285 Elf ## B ## _Shdr *strtab = SHDR ## B (strtab_void); \ 437 Elf ## B ## _Shdr *strtab = SHDR ## B (strtab_void); \
286 Elf ## B ## _Sym *sym = SYM ## B (elf->data + EGET(symtab->sh_offset)); \ 438 Elf ## B ## _Sym *sym = SYM ## B (elf->data + EGET(symtab->sh_offset)); \
287 int cnt = EGET(symtab->sh_size) / EGET(symtab->sh_entsize); \ 439 unsigned long cnt = EGET(symtab->sh_size) / EGET(symtab->sh_entsize); \
288 char *symname; \ 440 char *symname; \
289 for (i = 0; i < cnt; ++i) { \ 441 for (i = 0; i < cnt; ++i) { \
290 if (sym->st_name) { \ 442 if (sym->st_name) { \
291 symname = (char *)(elf->data + EGET(strtab->sh_offset) + EGET(sym->st_name)); \ 443 symname = (char *)(elf->data + EGET(strtab->sh_offset) + EGET(sym->st_name)); \
292 if (*find_sym == '*') { \ 444 if (*find_sym == '*') { \
293 printf("%s(%s) %5lX %15s %s\n", \ 445 printf("%s(%s) %5lX %15s %s\n", \
294 ((found_sym == 0) ? "\n\t" : "\t"), \ 446 ((*found_sym == 0) ? "\n\t" : "\t"), \
295 (char *)basename(filename), \ 447 base, \
296 (long)sym->st_size, \ 448 (long)sym->st_size, \
297 (char *)get_elfstttype(sym->st_info), \ 449 (char *)get_elfstttype(sym->st_info), \
298 symname); \ 450 symname); \
299 found_sym = 1; \ 451 *found_sym = 1; \
300 } else if ((strcmp(find_sym, symname) == 0) || \ 452 } else if ((strcmp(find_sym, symname) == 0) || \
301 (strncmp(symname, versioned_symname, len) == 0)) \ 453 (strcmp(symname, versioned_symname) == 0)) \
302 found_sym++; \ 454 (*found_sym)++; \
303 } \ 455 } \
304 ++sym; \ 456 ++sym; \
305 } } 457 } }
306 FIND_SYM(32) 458 FIND_SYM(32)
307 FIND_SYM(64) 459 FIND_SYM(64)
460 free(basemem);
461 }
462
463 if (be_wewy_wewy_quiet) return NULL;
464
465 if (*find_sym != '*' && *found_sym)
466 return find_sym;
467 if (be_quiet)
468 return NULL;
469 else
470 return (char *)" - ";
471}
472/* scan an elf file and show all the fun stuff */
473#define prints(str) write(fileno(stdout), str, strlen(str))
474static void scanelf_file(const char *filename)
475{
476 unsigned long i;
477 char found_pax, found_stack, found_relro, found_load, found_textrel,
478 found_rpath, found_needed, found_interp, found_bind,
479 found_sym, found_file;
480 elfobj *elf;
481 struct stat st;
482 static char *out_buffer = NULL;
483 static size_t out_len;
484
485 /* make sure 'filename' exists */
486 if (lstat(filename, &st) == -1) {
487 if (be_verbose > 2) printf("%s: does not exist\n", filename);
488 return;
489 }
490 /* always handle regular files and handle symlinked files if no -y */
491 if (S_ISLNK(st.st_mode)) {
492 if (!scan_symlink) return;
493 stat(filename, &st);
494 }
495 if (!S_ISREG(st.st_mode)) {
496 if (be_verbose > 2) printf("%s: skipping non-file\n", filename);
497 return;
498 }
499
500 found_pax = found_stack = found_relro = found_load = \
501 found_textrel = found_rpath = found_needed = found_interp = \
502 found_bind = found_sym = found_file = 0;
503
504 /* verify this is real ELF */
505 if ((elf = readelf(filename)) == NULL) {
506 if (be_verbose > 2) printf("%s: not an ELF\n", filename);
507 return;
508 }
509
510 if (be_verbose > 1)
511 printf("%s: scanning file {%s,%s}\n", filename,
512 get_elfeitype(EI_CLASS, elf->elf_class),
513 get_elfeitype(EI_DATA, elf->data[EI_DATA]));
514 else if (be_verbose)
515 printf("%s: scanning file\n", filename);
516
517 /* init output buffer */
518 if (!out_buffer) {
519 out_len = sizeof(char) * 80;
520 out_buffer = (char*)xmalloc(out_len);
521 }
522 *out_buffer = '\0';
523
524 /* show the header */
525 if (!be_quiet && show_banner) {
526 for (i = 0; out_format[i]; ++i) {
527 if (!IS_MODIFIER(out_format[i])) continue;
528
529 switch (out_format[++i]) {
530 case '%': break;
531 case '#': break;
532 case 'F':
533 case 'p':
534 case 'f': prints("FILE "); found_file = 1; break;
535 case 'o': prints(" TYPE "); break;
536 case 'x': prints(" PAX "); break;
537 case 'e': prints("STK/REL/PTL "); break;
538 case 't': prints("TEXTREL "); break;
539 case 'r': prints("RPATH "); break;
540 case 'n': prints("NEEDED "); break;
541 case 'i': prints("INTERP "); break;
542 case 'b': prints("BIND "); break;
543 case 's': prints("SYM "); break;
308 } 544 }
309 free(versioned_symname); 545 }
310 if (*find_sym != '*') { 546 if (!found_file) prints("FILE ");
311 if (found_sym) 547 prints("\n");
312 printf(" %s ", find_sym); 548 found_file = 0;
313 else if (!be_quiet) 549 show_banner = 0;
314 fputs(" - ", stdout); 550 }
551
552 /* dump all the good stuff */
553 for (i = 0; out_format[i]; ++i) {
554 const char *out;
555 const char *tmp;
556
557 /* make sure we trim leading spaces in quiet mode */
558 if (be_quiet && *out_buffer == ' ' && !out_buffer[1])
559 *out_buffer = '\0';
560
561 if (!IS_MODIFIER(out_format[i])) {
562 xchrcat(&out_buffer, out_format[i], &out_len);
563 continue;
564 }
565
566 out = NULL;
567 be_wewy_wewy_quiet = (out_format[i] == '#');
568 switch (out_format[++i]) {
569 case '%':
570 case '#':
571 xchrcat(&out_buffer, out_format[i], &out_len); break;
572 case 'F':
573 if (be_wewy_wewy_quiet) break;
574 found_file = 1;
575 xstrcat(&out_buffer, filename, &out_len);
576 break;
577 case 'p':
578 if (be_wewy_wewy_quiet) break;
579 found_file = 1;
580 tmp = filename;
581 if (search_path) {
582 ssize_t len_search = strlen(search_path);
583 ssize_t len_file = strlen(filename);
584 if (!strncmp(filename, search_path, len_search) && \
585 len_file > len_search)
586 tmp += len_search;
587 if (*tmp == '/' && search_path[len_search-1] == '/') tmp++;
315 } 588 }
589 xstrcat(&out_buffer, tmp, &out_len);
590 break;
591 case 'f':
592 if (be_wewy_wewy_quiet) break;
593 found_file = 1;
594 tmp = strrchr(filename, '/');
595 tmp = (tmp == NULL ? filename : tmp+1);
596 xstrcat(&out_buffer, tmp, &out_len);
597 break;
598 case 'o': out = get_elfetype(elf); break;
599 case 'x': out = scanelf_file_pax(elf, &found_pax); break;
600 case 'e': out = scanelf_file_stack(elf, &found_stack, &found_relro, &found_load); break;
601 case 't': out = scanelf_file_textrel(elf, &found_textrel); break;
602 case 'r': scanelf_file_rpath(elf, &found_rpath, &out_buffer, &out_len); break;
603 case 'n': scanelf_file_needed(elf, &found_needed, &out_buffer, &out_len); break;
604 case 'i': out = scanelf_file_interp(elf, &found_interp); break;
605 case 'b': out = scanelf_file_bind(elf, &found_bind); break;
606 case 's': out = scanelf_file_sym(elf, &found_sym, filename); break;
316 } 607 }
608 if (out) xstrcat(&out_buffer, out, &out_len);
609 }
317 610
318 if (!be_quiet || found_pax || found_stack || found_textrel || \ 611#define FOUND_SOMETHING() \
319 found_rpath || found_needed || found_sym) 612 (found_pax || found_stack || found_relro || found_load || found_textrel || \
320 puts(filename); 613 found_rpath || found_needed || found_interp || found_bind || found_sym)
614
615 if (!found_file && (!be_quiet || (be_quiet && FOUND_SOMETHING()))) {
616 xchrcat(&out_buffer, ' ', &out_len);
617 xstrcat(&out_buffer, filename, &out_len);
618 }
619 if (!be_quiet || (be_quiet && FOUND_SOMETHING()))
620 puts(out_buffer);
321 621
322 unreadelf(elf); 622 unreadelf(elf);
323} 623}
324 624
325/* scan a directory for ET_EXEC files and print when we find one */ 625/* scan a directory for ET_EXEC files and print when we find one */
330 struct stat st_top, st; 630 struct stat st_top, st;
331 char buf[_POSIX_PATH_MAX]; 631 char buf[_POSIX_PATH_MAX];
332 size_t pathlen = 0, len = 0; 632 size_t pathlen = 0, len = 0;
333 633
334 /* make sure path exists */ 634 /* make sure path exists */
335 if (lstat(path, &st_top) == -1) 635 if (lstat(path, &st_top) == -1) {
636 if (be_verbose > 2) printf("%s: does not exist\n", path);
336 return; 637 return;
638 }
337 639
338 /* ok, if it isn't a directory, assume we can open it */ 640 /* ok, if it isn't a directory, assume we can open it */
339 if (!S_ISDIR(st_top.st_mode)) { 641 if (!S_ISDIR(st_top.st_mode)) {
340 scanelf_file(path); 642 scanelf_file(path);
341 return; 643 return;
368 } 670 }
369 } 671 }
370 closedir(dir); 672 closedir(dir);
371} 673}
372 674
675static int scanelf_from_file(char *filename)
676{
677 FILE *fp = NULL;
678 char *p;
679 char path[_POSIX_PATH_MAX];
680
681 if (((strcmp(filename, "-")) == 0) && (ttyname(0) == NULL))
682 fp = stdin;
683 else if ((fp = fopen(filename, "r")) == NULL)
684 return 1;
685
686 while ((fgets(path, _POSIX_PATH_MAX, fp)) != NULL) {
687 if ((p = strchr(path, '\n')) != NULL)
688 *p = 0;
689 search_path = path;
690 scanelf_dir(path);
691 }
692 if (fp != stdin)
693 fclose(fp);
694 return 0;
695}
696
697static void load_ld_so_conf()
698{
699 FILE *fp = NULL;
700 char *p;
701 char path[_POSIX_PATH_MAX];
702 int i = 0;
703
704 if ((fp = fopen("/etc/ld.so.conf", "r")) == NULL)
705 return;
706
707 while ((fgets(path, _POSIX_PATH_MAX, fp)) != NULL) {
708 if (*path != '/')
709 continue;
710
711 if ((p = strrchr(path, '\r')) != NULL)
712 *p = 0;
713 if ((p = strchr(path, '\n')) != NULL)
714 *p = 0;
715
716 ldpaths[i++] = xstrdup(path);
717
718 if (i + 1 == sizeof(ldpaths) / sizeof(*ldpaths))
719 break;
720 }
721 ldpaths[i] = NULL;
722
723 fclose(fp);
724}
725
373/* scan /etc/ld.so.conf for paths */ 726/* scan /etc/ld.so.conf for paths */
374static void scanelf_ldpath() 727static void scanelf_ldpath()
375{ 728{
376 char scan_l, scan_ul, scan_ull; 729 char scan_l, scan_ul, scan_ull;
377 char *path, *p; 730 int i = 0;
378 FILE *fp;
379 731
380 if ((fp = fopen("/etc/ld.so.conf", "r")) == NULL) 732 if (!ldpaths[0])
381 err("Unable to open ld.so.conf: %s", strerror(errno)); 733 err("Unable to load any paths from ld.so.conf");
382 734
383 scan_l = scan_ul = scan_ull = 0; 735 scan_l = scan_ul = scan_ull = 0;
384 736
385 if ((path = malloc(_POSIX_PATH_MAX)) == NULL) { 737 while (ldpaths[i]) {
386 warn("Can not malloc() memory for ldpath scanning");
387 return;
388 }
389 while ((fgets(path, _POSIX_PATH_MAX, fp)) != NULL)
390 if (*path == '/') {
391 if ((p = strrchr(path, '\r')) != NULL)
392 *p = 0;
393 if ((p = strrchr(path, '\n')) != NULL)
394 *p = 0;
395 if (!scan_l && !strcmp(path, "/lib")) scan_l = 1; 738 if (!scan_l && !strcmp(ldpaths[i], "/lib")) scan_l = 1;
396 if (!scan_ul && !strcmp(path, "/usr/lib")) scan_ul = 1; 739 if (!scan_ul && !strcmp(ldpaths[i], "/usr/lib")) scan_ul = 1;
397 if (!scan_ull && !strcmp(path, "/usr/local/lib")) scan_ull = 1; 740 if (!scan_ull && !strcmp(ldpaths[i], "/usr/local/lib")) scan_ull = 1;
398 scanelf_dir(path); 741 scanelf_dir(ldpaths[i]);
742 ++i;
399 } 743 }
400 free(path);
401 fclose(fp);
402 744
403 if (!scan_l) scanelf_dir("/lib"); 745 if (!scan_l) scanelf_dir("/lib");
404 if (!scan_ul) scanelf_dir("/usr/lib"); 746 if (!scan_ul) scanelf_dir("/usr/lib");
405 if (!scan_ull) scanelf_dir("/usr/local/lib"); 747 if (!scan_ull) scanelf_dir("/usr/local/lib");
406} 748}
411 char *path, *p; 753 char *path, *p;
412 754
413 path = getenv("PATH"); 755 path = getenv("PATH");
414 if (!path) 756 if (!path)
415 err("PATH is not set in your env !"); 757 err("PATH is not set in your env !");
416 758 path = xstrdup(path);
417 if ((path = strdup(path)) == NULL)
418 err("strdup failed: %s", strerror(errno));
419 759
420 while ((p = strrchr(path, ':')) != NULL) { 760 while ((p = strrchr(path, ':')) != NULL) {
421 scanelf_dir(p + 1); 761 scanelf_dir(p + 1);
422 *p = 0; 762 *p = 0;
423 } 763 }
426} 766}
427 767
428 768
429 769
430/* usage / invocation handling functions */ 770/* usage / invocation handling functions */
431#define PARSE_FLAGS "plRmxetrns:aqvo:BhV" 771#define PARSE_FLAGS "plRmyxetrnibs:aqvF:f:o:BhV"
432#define a_argument required_argument 772#define a_argument required_argument
433static struct option const long_opts[] = { 773static struct option const long_opts[] = {
434 {"path", no_argument, NULL, 'p'}, 774 {"path", no_argument, NULL, 'p'},
435 {"ldpath", no_argument, NULL, 'l'}, 775 {"ldpath", no_argument, NULL, 'l'},
436 {"recursive", no_argument, NULL, 'R'}, 776 {"recursive", no_argument, NULL, 'R'},
437 {"mount", no_argument, NULL, 'm'}, 777 {"mount", no_argument, NULL, 'm'},
778 {"symlink", no_argument, NULL, 'y'},
438 {"pax", no_argument, NULL, 'x'}, 779 {"pax", no_argument, NULL, 'x'},
439 {"header", no_argument, NULL, 'e'}, 780 {"header", no_argument, NULL, 'e'},
440 {"textrel", no_argument, NULL, 't'}, 781 {"textrel", no_argument, NULL, 't'},
441 {"rpath", no_argument, NULL, 'r'}, 782 {"rpath", no_argument, NULL, 'r'},
442 {"needed", no_argument, NULL, 'n'}, 783 {"needed", no_argument, NULL, 'n'},
784 {"interp", no_argument, NULL, 'i'},
785 {"bind", no_argument, NULL, 'b'},
443 {"symbol", a_argument, NULL, 's'}, 786 {"symbol", a_argument, NULL, 's'},
444 {"all", no_argument, NULL, 'a'}, 787 {"all", no_argument, NULL, 'a'},
445 {"quiet", no_argument, NULL, 'q'}, 788 {"quiet", no_argument, NULL, 'q'},
446 {"verbose", no_argument, NULL, 'v'}, 789 {"verbose", no_argument, NULL, 'v'},
790 {"format", a_argument, NULL, 'F'},
791 {"from", a_argument, NULL, 'f'},
447 {"file", a_argument, NULL, 'o'}, 792 {"file", a_argument, NULL, 'o'},
448 {"nobanner", no_argument, NULL, 'B'}, 793 {"nobanner", no_argument, NULL, 'B'},
449 {"help", no_argument, NULL, 'h'}, 794 {"help", no_argument, NULL, 'h'},
450 {"version", no_argument, NULL, 'V'}, 795 {"version", no_argument, NULL, 'V'},
451 {NULL, no_argument, NULL, 0x0} 796 {NULL, no_argument, NULL, 0x0}
452}; 797};
798
453static char *opts_help[] = { 799static const char *opts_help[] = {
454 "Scan all directories in PATH environment", 800 "Scan all directories in PATH environment",
455 "Scan all directories in /etc/ld.so.conf", 801 "Scan all directories in /etc/ld.so.conf",
456 "Scan directories recursively", 802 "Scan directories recursively",
457 "Don't recursively cross mount points\n", 803 "Don't recursively cross mount points",
804 "Don't scan symlinks\n",
458 "Print PaX markings", 805 "Print PaX markings",
459 "Print GNU_STACK markings", 806 "Print GNU_STACK/PT_LOAD markings",
460 "Print TEXTREL information", 807 "Print TEXTREL information",
461 "Print RPATH information", 808 "Print RPATH information",
462 "Print NEEDED information", 809 "Print NEEDED information",
810 "Print INTERP information",
811 "Print BIND information",
463 "Find a specified symbol", 812 "Find a specified symbol",
464 "Print all scanned info (-x -e -t -r)\n", 813 "Print all scanned info (-x -e -t -r -n -i -b)\n",
465 "Only output 'bad' things", 814 "Only output 'bad' things",
466 "Be verbose (can be specified more than once)", 815 "Be verbose (can be specified more than once)",
816 "Use specified format for output",
817 "Read input stream from a filename",
467 "Write output stream to a filename", 818 "Write output stream to a filename",
468 "Don't display the header", 819 "Don't display the header",
469 "Print this help and exit", 820 "Print this help and exit",
470 "Print version and exit", 821 "Print version and exit",
471 NULL 822 NULL
472}; 823};
473 824
474/* display usage and exit */ 825/* display usage and exit */
475static void usage(int status) 826static void usage(int status)
476{ 827{
477 int i; 828 unsigned long i;
478 printf(" Scan ELF binaries for stuff\n" 829 printf("* Scan ELF binaries for stuff\n\n"
479 "Usage: %s [options] <dir1/file1> [dir2 dirN fileN ...]\n\n", argv0); 830 "Usage: %s [options] <dir1/file1> [dir2 dirN fileN ...]\n\n", argv0);
480 printf("Options: -[%s]\n", PARSE_FLAGS); 831 printf("Options: -[%s]\n", PARSE_FLAGS);
481 for (i = 0; long_opts[i].name; ++i) 832 for (i = 0; long_opts[i].name; ++i)
482 if (long_opts[i].has_arg == no_argument) 833 if (long_opts[i].has_arg == no_argument)
483 printf(" -%c, --%-13s %s\n", long_opts[i].val, 834 printf(" -%c, --%-13s* %s\n", long_opts[i].val,
484 long_opts[i].name, opts_help[i]); 835 long_opts[i].name, opts_help[i]);
485 else 836 else
486 printf(" -%c, --%-6s <arg> %s\n", long_opts[i].val, 837 printf(" -%c, --%-6s <arg> * %s\n", long_opts[i].val,
487 long_opts[i].name, opts_help[i]); 838 long_opts[i].name, opts_help[i]);
839
840 if (status != EXIT_SUCCESS)
841 exit(status);
842
843 puts("\nThe format modifiers for the -F option are:");
844 puts(" F Filename \tx PaX Flags \te STACK/RELRO");
845 puts(" t TEXTREL \tr RPATH \tn NEEDED");
846 puts(" i INTERP \tb BIND \ts symbol");
847 puts(" p filename (with search path removed)");
848 puts(" f base filename");
849 puts("Prefix each modifier with '%' (verbose) or '#' (silent)");
850
488 exit(status); 851 exit(status);
489} 852}
490 853
491/* parse command line arguments and preform needed actions */ 854/* parse command line arguments and preform needed actions */
492static void parseargs(int argc, char *argv[]) 855static void parseargs(int argc, char *argv[])
493{ 856{
494 int flag; 857 int i;
858 char *from_file = NULL;
495 859
496 opterr = 0; 860 opterr = 0;
497 while ((flag=getopt_long(argc, argv, PARSE_FLAGS, long_opts, NULL)) != -1) { 861 while ((i=getopt_long(argc, argv, PARSE_FLAGS, long_opts, NULL)) != -1) {
498 switch (flag) { 862 switch (i) {
499 863
500 case 'V': /* version info */ 864 case 'V':
501 printf("%s compiled %s\n%s\n" 865 printf("%s compiled %s\n%s\n"
502 "%s written for Gentoo Linux by <solar and vapier @ gentoo.org>\n", 866 "%s written for Gentoo Linux by <solar and vapier @ gentoo.org>\n",
503 __FILE__, __DATE__, rcsid, argv0); 867 __FILE__, __DATE__, rcsid, argv0);
504 exit(EXIT_SUCCESS); 868 exit(EXIT_SUCCESS);
505 break; 869 break;
506 case 'h': usage(EXIT_SUCCESS); break; 870 case 'h': usage(EXIT_SUCCESS); break;
507 871 case 'f':
872 if (from_file) err("Don't specify -f twice");
873 from_file = xstrdup(optarg);
874 break;
508 case 'o': { 875 case 'o': {
509 FILE *fp = NULL; 876 FILE *fp = NULL;
510 fp = freopen(optarg, "w", stdout); 877 if ((fp = freopen(optarg, "w", stdout)) == NULL)
511 if (fp == NULL)
512 err("Could not open output stream '%s': %s", optarg, strerror(errno)); 878 err("Could not open output stream '%s': %s", optarg, strerror(errno));
513 stdout = fp; 879 SET_STDOUT(fp);
514 break; 880 break;
515 } 881 }
516 882
517 case 's': find_sym = strdup(optarg); break; 883 case 's': {
884 size_t len;
885 if (find_sym) err("Don't specify -s twice");
886 find_sym = xstrdup(optarg);
887 len = strlen(find_sym) + 1;
888 versioned_symname = (char*)xmalloc(sizeof(char) * (len+1));
889 sprintf(versioned_symname, "%s@", find_sym);
890 break;
891 }
518 892
893 case 'F': {
894 if (out_format) err("Don't specify -F twice");
895 out_format = xstrdup(optarg);
896 break;
897 }
898
899 case 'y': scan_symlink = 0; break;
519 case 'B': show_banner = 0; break; 900 case 'B': show_banner = 0; break;
520 case 'l': scan_ldpath = 1; break; 901 case 'l': scan_ldpath = 1; break;
521 case 'p': scan_envpath = 1; break; 902 case 'p': scan_envpath = 1; break;
522 case 'R': dir_recurse = 1; break; 903 case 'R': dir_recurse = 1; break;
523 case 'm': dir_crossmount = 0; break; 904 case 'm': dir_crossmount = 0; break;
524 case 'x': show_pax = 1; break; 905 case 'x': show_pax = 1; break;
525 case 'e': show_stack = 1; break; 906 case 'e': show_stack = 1; break;
526 case 't': show_textrel = 1; break; 907 case 't': show_textrel = 1; break;
527 case 'r': show_rpath = 1; break; 908 case 'r': show_rpath = 1; break;
528 case 'n': show_needed = 1; break; 909 case 'n': show_needed = 1; break;
910 case 'i': show_interp = 1; break;
911 case 'b': show_bind = 1; break;
529 case 'q': be_quiet = 1; break; 912 case 'q': be_quiet = 1; break;
530 case 'v': be_verbose = (be_verbose % 20) + 1; break; 913 case 'v': be_verbose = (be_verbose % 20) + 1; break;
531 case 'a': show_pax = show_stack = show_textrel = show_needed = show_rpath = 1; break; 914 case 'a': show_pax = show_stack = show_textrel = show_rpath = \
915 show_needed = show_interp = show_bind = 1; break;
532 916
533 case ':': 917 case ':':
534 warn("Option missing parameter"); 918 err("Option missing parameter\n");
535 usage(EXIT_FAILURE);
536 break;
537 case '?': 919 case '?':
538 warn("Unknown option"); 920 err("Unknown option\n");
539 usage(EXIT_FAILURE);
540 break;
541 default: 921 default:
542 err("Unhandled option '%c'", flag); 922 err("Unhandled option '%c'", i);
543 break; 923 }
924 }
925
926 /* let the format option override all other options */
927 if (out_format) {
928 show_pax = show_stack = show_textrel = show_rpath = \
929 show_needed = show_interp = show_bind = 0;
930 for (i = 0; out_format[i]; ++i) {
931 if (!IS_MODIFIER(out_format[i])) continue;
932
933 switch (out_format[++i]) {
934 case '%': break;
935 case '#': break;
936 case 'F': break;
937 case 'p': break;
938 case 'f': break;
939 case 's': break;
940 case 'o': break;
941 case 'x': show_pax = 1; break;
942 case 'e': show_stack = 1; break;
943 case 't': show_textrel = 1; break;
944 case 'r': show_rpath = 1; break;
945 case 'n': show_needed = 1; break;
946 case 'i': show_interp = 1; break;
947 case 'b': show_bind = 1; break;
948 default:
949 err("Invalid format specifier '%c' (byte %i)",
950 out_format[i], i+1);
544 } 951 }
545 } 952 }
546 953
547 if (be_quiet && be_verbose) 954 /* construct our default format */
548 err("You can be quiet or you can be verbose, not both, stupid"); 955 } else {
956 size_t fmt_len = 30;
957 out_format = (char*)xmalloc(sizeof(char) * fmt_len);
958 if (!be_quiet) xstrcat(&out_format, "%o ", &fmt_len);
959 if (show_pax) xstrcat(&out_format, "%x ", &fmt_len);
960 if (show_stack) xstrcat(&out_format, "%e ", &fmt_len);
961 if (show_textrel) xstrcat(&out_format, "%t ", &fmt_len);
962 if (show_rpath) xstrcat(&out_format, "%r ", &fmt_len);
963 if (show_needed) xstrcat(&out_format, "%n ", &fmt_len);
964 if (show_interp) xstrcat(&out_format, "%i ", &fmt_len);
965 if (show_bind) xstrcat(&out_format, "%b ", &fmt_len);
966 if (find_sym) xstrcat(&out_format, "%s ", &fmt_len);
967 if (!be_quiet) xstrcat(&out_format, "%F ", &fmt_len);
968 }
969 if (be_verbose > 2) printf("Format: %s\n", out_format);
549 970
971 /* now lets actually do the scanning */
972 if (scan_ldpath || (show_rpath && be_quiet))
973 load_ld_so_conf();
550 if (scan_ldpath) scanelf_ldpath(); 974 if (scan_ldpath) scanelf_ldpath();
551 if (scan_envpath) scanelf_envpath(); 975 if (scan_envpath) scanelf_envpath();
976 if (from_file) {
977 scanelf_from_file(from_file);
978 free(from_file);
979 from_file = *argv;
980 }
552 if (optind == argc && !scan_ldpath && !scan_envpath) 981 if (optind == argc && !scan_ldpath && !scan_envpath && !from_file)
553 err("Nothing to scan !?"); 982 err("Nothing to scan !?");
554 while (optind < argc) 983 while (optind < argc) {
555 scanelf_dir(argv[optind++]); 984 search_path = argv[optind++];
985 scanelf_dir(search_path);
986 }
556 987
557 if (find_sym) free(find_sym); 988 /* clean up */
989 if (find_sym) {
990 free(find_sym);
991 free(versioned_symname);
992 }
993 if (out_format) free(out_format);
994 for (i = 0; ldpaths[i]; ++i)
995 free(ldpaths[i]);
558} 996}
559 997
998
999
1000/* utility funcs */
1001static char *xstrdup(const char *s)
1002{
1003 char *ret = strdup(s);
1004 if (!ret) err("Could not strdup(): %s", strerror(errno));
1005 return ret;
1006}
1007
1008static void *xmalloc(size_t size)
1009{
1010 void *ret = malloc(size);
1011 if (!ret) err("Could not malloc() %li bytes", (unsigned long)size);
1012 return ret;
1013}
1014
1015static void xstrcat(char **dst, const char *src, size_t *curr_len)
1016{
1017 size_t new_len;
1018
1019 new_len = strlen(*dst) + strlen(src);
1020 if (*curr_len <= new_len) {
1021 *curr_len = new_len + (*curr_len / 2);
1022 *dst = realloc(*dst, *curr_len);
1023 if (!*dst)
1024 err("could not realloc %li bytes", (unsigned long)*curr_len);
1025 }
1026
1027 strcat(*dst, src);
1028}
1029
1030static inline void xchrcat(char **dst, const char append, size_t *curr_len)
1031{
1032 static char my_app[2];
1033 my_app[0] = append;
1034 my_app[1] = '\0';
1035 xstrcat(dst, my_app, curr_len);
1036}
560 1037
561 1038
562int main(int argc, char *argv[]) 1039int main(int argc, char *argv[])
563{ 1040{
564 if (argc < 2) 1041 if (argc < 2)
565 usage(EXIT_FAILURE); 1042 usage(EXIT_FAILURE);
566 parseargs(argc, argv); 1043 parseargs(argc, argv);
567 fclose(stdout); 1044 fclose(stdout);
1045#ifdef __BOUNDS_CHECKING_ON
1046 warn("The calls to add/delete heap should be off by 1 due to the out_buffer not being freed in scanelf_file()");
1047#endif
568 return EXIT_SUCCESS; 1048 return EXIT_SUCCESS;
569} 1049}

Legend:
Removed from v.1.35  
changed lines
  Added in v.1.71

  ViewVC Help
Powered by ViewVC 1.1.20