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

Contents of /pax-utils/scanelf.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.173 - (hide annotations) (download) (as text)
Thu Jan 18 00:26:34 2007 UTC (7 years, 6 months ago) by vapier
Branch: MAIN
Changes since 1.172: +3 -18 lines
File MIME type: text/x-csrc
move format/elf documentation out of usage() and into docbook

1 solar 1.1 /*
2 vapier 1.98 * Copyright 2003-2006 Gentoo Foundation
3 solar 1.1 * Distributed under the terms of the GNU General Public License v2
4 vapier 1.173 * $Header: /var/cvsroot/gentoo-projects/pax-utils/scanelf.c,v 1.172 2007/01/09 23:04:12 vapier Exp $
5 solar 1.1 *
6 vapier 1.98 * Copyright 2003-2006 Ned Ludd - <solar@gentoo.org>
7     * Copyright 2004-2006 Mike Frysinger - <vapier@gentoo.org>
8 solar 1.1 */
9    
10 vapier 1.89 #include "paxinc.h"
11 flameeyes 1.141
12 vapier 1.173 static const char *rcsid = "$Id: scanelf.c,v 1.172 2007/01/09 23:04:12 vapier Exp $";
13 vapier 1.36 #define argv0 "scanelf"
14 vapier 1.10
15 solar 1.132 #define IS_MODIFIER(c) (c == '%' || c == '#' || c == '+')
16 vapier 1.70
17 vapier 1.10 /* prototypes */
18 kevquinn 1.142 static int file_matches_list(const char *filename, char **matchlist);
19 vapier 1.106 static int scanelf_elfobj(elfobj *elf);
20     static int scanelf_elf(const char *filename, int fd, size_t len);
21     static int scanelf_archive(const char *filename, int fd, size_t len);
22 solar 1.164 static int scanelf_file(const char *filename, const struct stat *st_cache);
23     static int scanelf_dir(const char *path);
24 vapier 1.106 static void scanelf_ldpath(void);
25     static void scanelf_envpath(void);
26 vapier 1.10 static void usage(int status);
27 kevquinn 1.142 static char **get_split_env(const char *envvar);
28     static void parseenv(void);
29 solar 1.164 static int parseargs(int argc, char *argv[]);
30 vapier 1.60 static char *xstrdup(const char *s);
31 vapier 1.41 static void *xmalloc(size_t size);
32 kevquinn 1.142 static void *xrealloc(void *ptr, size_t size);
33 vapier 1.95 static void xstrncat(char **dst, const char *src, size_t *curr_len, size_t n);
34     #define xstrcat(dst,src,curr_len) xstrncat(dst,src,curr_len,0)
35 vapier 1.41 static inline void xchrcat(char **dst, const char append, size_t *curr_len);
36 vapier 1.10
37     /* variables to control behavior */
38 solar 1.119 static char match_etypes[126] = "";
39 vapier 1.48 static char *ldpaths[256];
40 vapier 1.10 static char scan_ldpath = 0;
41     static char scan_envpath = 0;
42 vapier 1.37 static char scan_symlink = 1;
43 vapier 1.105 static char scan_archives = 0;
44 vapier 1.10 static char dir_recurse = 0;
45 vapier 1.14 static char dir_crossmount = 1;
46 vapier 1.10 static char show_pax = 0;
47 solar 1.73 static char show_phdr = 0;
48 vapier 1.10 static char show_textrel = 0;
49     static char show_rpath = 0;
50 vapier 1.32 static char show_needed = 0;
51 vapier 1.38 static char show_interp = 0;
52 vapier 1.49 static char show_bind = 0;
53 vapier 1.84 static char show_soname = 0;
54 vapier 1.76 static char show_textrels = 0;
55 solar 1.16 static char show_banner = 1;
56 vapier 1.10 static char be_quiet = 0;
57 vapier 1.14 static char be_verbose = 0;
58 solar 1.127 static char be_wewy_wewy_quiet = 0;
59 solar 1.132 static char be_semi_verbose = 0;
60 vapier 1.39 static char *find_sym = NULL, *versioned_symname = NULL;
61 vapier 1.72 static char *find_lib = NULL;
62 solar 1.124 static char *find_section = NULL;
63 vapier 1.39 static char *out_format = NULL;
64 vapier 1.66 static char *search_path = NULL;
65 vapier 1.101 static char fix_elf = 0;
66 solar 1.86 static char gmatch = 0;
67 vapier 1.102 static char use_ldcache = 0;
68 solar 1.1
69 kevquinn 1.142 static char **qa_textrels = NULL;
70     static char **qa_execstack = NULL;
71 kevquinn 1.145 static char **qa_wx_load = NULL;
72 kevquinn 1.142
73 solar 1.120 int match_bits = 0;
74 solar 1.96 caddr_t ldcache = 0;
75     size_t ldcache_size = 0;
76 solar 1.127 unsigned long setpax = 0UL;
77 solar 1.96
78 solar 1.170 int has_objdump = 0;
79 vapier 1.152
80 solar 1.170 static char *which(const char *fname)
81     {
82     static char fullpath[BUFSIZ];
83 vapier 1.172 char *path, *p;
84 solar 1.170
85 vapier 1.172 path = getenv("PATH");
86     if (!path)
87 solar 1.170 return NULL;
88    
89 vapier 1.172 path = xstrdup(path);
90     while ((p = strrchr(path, ':')) != NULL) {
91 solar 1.170 snprintf(fullpath, sizeof(fullpath), "%s/%s", p + 1, fname);
92 vapier 1.172 *p = 0;
93 solar 1.170 if (access(fullpath, R_OK) != (-1)) {
94     free(path);
95     return (char *) fullpath;
96     }
97 vapier 1.172 }
98     free(path);
99 solar 1.170 return NULL;
100     }
101 vapier 1.152
102 vapier 1.39 /* sub-funcs for scanelf_file() */
103 vapier 1.77 static void scanelf_file_get_symtabs(elfobj *elf, void **sym, void **tab)
104     {
105     /* find the best SHT_DYNSYM and SHT_STRTAB sections */
106     #define GET_SYMTABS(B) \
107     if (elf->elf_class == ELFCLASS ## B) { \
108     Elf ## B ## _Shdr *symtab, *strtab, *dynsym, *dynstr; \
109     /* debug sections */ \
110     symtab = SHDR ## B (elf_findsecbyname(elf, ".symtab")); \
111     strtab = SHDR ## B (elf_findsecbyname(elf, ".strtab")); \
112     /* runtime sections */ \
113     dynsym = SHDR ## B (elf_findsecbyname(elf, ".dynsym")); \
114     dynstr = SHDR ## B (elf_findsecbyname(elf, ".dynstr")); \
115     if (symtab && dynsym) { \
116     *sym = (void*)((EGET(symtab->sh_size) > EGET(dynsym->sh_size)) ? symtab : dynsym); \
117     } else { \
118     *sym = (void*)(symtab ? symtab : dynsym); \
119     } \
120     if (strtab && dynstr) { \
121     *tab = (void*)((EGET(strtab->sh_size) > EGET(dynstr->sh_size)) ? strtab : dynstr); \
122     } else { \
123     *tab = (void*)(strtab ? strtab : dynstr); \
124     } \
125     }
126     GET_SYMTABS(32)
127     GET_SYMTABS(64)
128     }
129 solar 1.127
130 vapier 1.41 static char *scanelf_file_pax(elfobj *elf, char *found_pax)
131 solar 1.6 {
132 solar 1.61 static char ret[7];
133     unsigned long i, shown;
134    
135 vapier 1.41 if (!show_pax) return NULL;
136 vapier 1.10
137 solar 1.61 shown = 0;
138     memset(&ret, 0, sizeof(ret));
139    
140     if (elf->phdr) {
141     #define SHOW_PAX(B) \
142     if (elf->elf_class == ELFCLASS ## B) { \
143     Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \
144     Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \
145     for (i = 0; i < EGET(ehdr->e_phnum); i++) { \
146     if (EGET(phdr[i].p_type) != PT_PAX_FLAGS) \
147     continue; \
148 solar 1.127 if (fix_elf && setpax) { \
149     /* set the paxctl flags */ \
150     ESET(phdr[i].p_flags, setpax); \
151     } \
152 solar 1.129 if (be_quiet && (EGET(phdr[i].p_flags) == (PF_NOEMUTRAMP | PF_NORANDEXEC))) \
153 solar 1.61 continue; \
154     memcpy(ret, pax_short_pf_flags(EGET(phdr[i].p_flags)), 6); \
155     *found_pax = 1; \
156     ++shown; \
157     break; \
158     } \
159     }
160     SHOW_PAX(32)
161     SHOW_PAX(64)
162     }
163    
164 solar 1.128
165     if (fix_elf && setpax) {
166     /* set the chpax settings */
167 solar 1.129 if (elf->elf_class == ELFCLASS32) {
168     if (EHDR32(elf->ehdr)->e_type == ET_DYN || EHDR32(elf->ehdr)->e_type == ET_EXEC)
169     ESET(EHDR32(elf->ehdr)->e_ident[EI_PAX], pax_pf2hf_flags(setpax));
170     } else {
171     if (EHDR64(elf->ehdr)->e_type == ET_DYN || EHDR64(elf->ehdr)->e_type == ET_EXEC)
172     ESET(EHDR64(elf->ehdr)->e_ident[EI_PAX], pax_pf2hf_flags(setpax));
173     }
174 solar 1.128 }
175    
176 solar 1.61 /* fall back to EI_PAX if no PT_PAX was found */
177     if (!*ret) {
178 vapier 1.90 static char *paxflags;
179 solar 1.61 paxflags = pax_short_hf_flags(EI_PAX_FLAGS(elf));
180     if (!be_quiet || (be_quiet && EI_PAX_FLAGS(elf))) {
181     *found_pax = 1;
182 solar 1.127 return (be_wewy_wewy_quiet ? NULL : paxflags);
183 solar 1.61 }
184     strncpy(ret, paxflags, sizeof(ret));
185 vapier 1.14 }
186 vapier 1.41
187 solar 1.127 if (be_wewy_wewy_quiet || (be_quiet && !shown))
188 solar 1.61 return NULL;
189 vapier 1.90 else
190     return ret;
191     }
192 solar 1.61
193 solar 1.73 static char *scanelf_file_phdr(elfobj *elf, char *found_phdr, char *found_relro, char *found_load)
194 vapier 1.39 {
195 vapier 1.71 static char ret[12];
196 vapier 1.41 char *found;
197 vapier 1.99 unsigned long i, shown, multi_stack, multi_relro, multi_load;
198     int max_pt_load;
199 vapier 1.41
200 solar 1.73 if (!show_phdr) return NULL;
201 vapier 1.41
202 vapier 1.71 memcpy(ret, "--- --- ---\0", 12);
203    
204 vapier 1.41 shown = 0;
205 vapier 1.71 multi_stack = multi_relro = multi_load = 0;
206 vapier 1.99 max_pt_load = elf_max_pt_load(elf);
207 vapier 1.44
208 vapier 1.108 #define NOTE_GNU_STACK ".note.GNU-stack"
209 solar 1.73 #define SHOW_PHDR(B) \
210 vapier 1.39 if (elf->elf_class == ELFCLASS ## B) { \
211     Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \
212 vapier 1.91 Elf ## B ## _Off offset; \
213     uint32_t flags, check_flags; \
214     if (elf->phdr != NULL) { \
215     Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \
216     for (i = 0; i < EGET(ehdr->e_phnum); ++i) { \
217     if (EGET(phdr[i].p_type) == PT_GNU_STACK) { \
218 vapier 1.152 if (multi_stack++) \
219     warnf("%s: multiple PT_GNU_STACK's !?", elf->filename); \
220     if (file_matches_list(elf->filename, qa_execstack)) \
221     continue; \
222     found = found_phdr; \
223     offset = 0; \
224     check_flags = PF_X; \
225 vapier 1.91 } else if (EGET(phdr[i].p_type) == PT_GNU_RELRO) { \
226 vapier 1.152 if (multi_relro++) \
227     warnf("%s: multiple PT_GNU_RELRO's !?", elf->filename); \
228 vapier 1.91 found = found_relro; \
229     offset = 4; \
230     check_flags = PF_X; \
231     } else if (EGET(phdr[i].p_type) == PT_LOAD) { \
232 solar 1.117 if (ehdr->e_type == ET_DYN || ehdr->e_type == ET_EXEC) \
233 vapier 1.152 if (multi_load++ > max_pt_load) \
234     warnf("%s: more than %i PT_LOAD's !?", elf->filename, max_pt_load); \
235     if (file_matches_list(elf->filename, qa_wx_load)) \
236     continue; \
237     found = found_load; \
238     offset = 8; \
239     check_flags = PF_W|PF_X; \
240 vapier 1.91 } else \
241     continue; \
242     flags = EGET(phdr[i].p_flags); \
243     if (be_quiet && ((flags & check_flags) != check_flags)) \
244     continue; \
245 solar 1.130 if ((EGET(phdr[i].p_type) != PT_LOAD) && (fix_elf && ((flags & PF_X) != flags))) { \
246 vapier 1.101 ESET(phdr[i].p_flags, flags & (PF_X ^ (size_t)-1)); \
247     ret[3] = ret[7] = '!'; \
248     flags = EGET(phdr[i].p_flags); \
249     } \
250 vapier 1.91 memcpy(ret+offset, gnu_short_stack_flags(flags), 3); \
251     *found = 1; \
252     ++shown; \
253     } \
254     } else if (elf->shdr != NULL) { \
255     /* no program headers which means this is prob an object file */ \
256     Elf ## B ## _Shdr *shdr = SHDR ## B (elf->shdr); \
257     Elf ## B ## _Shdr *strtbl = shdr + EGET(ehdr->e_shstrndx); \
258 vapier 1.108 char *str; \
259 vapier 1.118 if ((void*)strtbl > (void*)elf->data_end) \
260 vapier 1.108 goto skip_this_shdr##B; \
261 vapier 1.91 check_flags = SHF_WRITE|SHF_EXECINSTR; \
262     for (i = 0; i < EGET(ehdr->e_shnum); ++i) { \
263     if (EGET(shdr[i].sh_type) != SHT_PROGBITS) continue; \
264     offset = EGET(strtbl->sh_offset) + EGET(shdr[i].sh_name); \
265 vapier 1.108 str = elf->data + offset; \
266     if (str > elf->data + offset + sizeof(NOTE_GNU_STACK)) continue; \
267     if (!strcmp(str, NOTE_GNU_STACK)) { \
268 vapier 1.91 if (multi_stack++) warnf("%s: multiple .note.GNU-stack's !?", elf->filename); \
269     flags = EGET(shdr[i].sh_flags); \
270     if (be_quiet && ((flags & check_flags) != check_flags)) \
271     continue; \
272     ++*found_phdr; \
273     shown = 1; \
274     if (flags & SHF_WRITE) ret[0] = 'W'; \
275     if (flags & SHF_ALLOC) ret[1] = 'A'; \
276     if (flags & SHF_EXECINSTR) ret[2] = 'X'; \
277     if (flags & 0xFFFFFFF8) warn("Invalid section flags for GNU-stack"); \
278     break; \
279     } \
280     } \
281 vapier 1.108 skip_this_shdr##B: \
282 vapier 1.91 if (!multi_stack) { \
283 vapier 1.158 if (file_matches_list(elf->filename, qa_execstack)) \
284     return NULL; \
285 vapier 1.91 *found_phdr = 1; \
286     shown = 1; \
287     memcpy(ret, "!WX", 3); \
288     } \
289 vapier 1.39 } \
290     }
291 solar 1.73 SHOW_PHDR(32)
292     SHOW_PHDR(64)
293 vapier 1.44
294 solar 1.127 if (be_wewy_wewy_quiet || (be_quiet && !shown))
295 vapier 1.41 return NULL;
296     else
297     return ret;
298 vapier 1.39 }
299 kevquinn 1.142
300 vapier 1.90 static const char *scanelf_file_textrel(elfobj *elf, char *found_textrel)
301 vapier 1.39 {
302 vapier 1.90 static const char *ret = "TEXTREL";
303 vapier 1.44 unsigned long i;
304 vapier 1.41
305 vapier 1.79 if (!show_textrel && !show_textrels) return NULL;
306 vapier 1.41
307 kevquinn 1.142 if (file_matches_list(elf->filename, qa_textrels)) return NULL;
308    
309 vapier 1.44 if (elf->phdr) {
310 vapier 1.39 #define SHOW_TEXTREL(B) \
311     if (elf->elf_class == ELFCLASS ## B) { \
312     Elf ## B ## _Dyn *dyn; \
313     Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \
314     Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \
315 vapier 1.44 Elf ## B ## _Off offset; \
316 vapier 1.39 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \
317 vapier 1.59 if (EGET(phdr[i].p_type) != PT_DYNAMIC) continue; \
318 vapier 1.44 offset = EGET(phdr[i].p_offset); \
319     if (offset >= elf->len - sizeof(Elf ## B ## _Dyn)) continue; \
320     dyn = DYN ## B (elf->data + offset); \
321 vapier 1.39 while (EGET(dyn->d_tag) != DT_NULL) { \
322     if (EGET(dyn->d_tag) == DT_TEXTREL) { /*dyn->d_tag != DT_FLAGS)*/ \
323     *found_textrel = 1; \
324     /*if (dyn->d_un.d_val & DF_TEXTREL)*/ \
325 solar 1.127 return (be_wewy_wewy_quiet ? NULL : ret); \
326 vapier 1.39 } \
327     ++dyn; \
328 vapier 1.26 } \
329 vapier 1.39 } }
330     SHOW_TEXTREL(32)
331     SHOW_TEXTREL(64)
332 vapier 1.44 }
333    
334 solar 1.127 if (be_quiet || be_wewy_wewy_quiet)
335 vapier 1.41 return NULL;
336     else
337 vapier 1.90 return " - ";
338 vapier 1.39 }
339 vapier 1.79 static char *scanelf_file_textrels(elfobj *elf, char *found_textrels, char *found_textrel)
340 vapier 1.76 {
341 vapier 1.82 unsigned long s, r, rmax;
342     void *symtab_void, *strtab_void, *text_void;
343 vapier 1.76
344     if (!show_textrels) return NULL;
345    
346 vapier 1.79 /* don't search for TEXTREL's if the ELF doesn't have any */
347     if (!*found_textrel) scanelf_file_textrel(elf, found_textrel);
348     if (!*found_textrel) return NULL;
349    
350 vapier 1.77 scanelf_file_get_symtabs(elf, &symtab_void, &strtab_void);
351 vapier 1.82 text_void = elf_findsecbyname(elf, ".text");
352 vapier 1.76
353 vapier 1.82 if (symtab_void && strtab_void && text_void && elf->shdr) {
354 vapier 1.76 #define SHOW_TEXTRELS(B) \
355     if (elf->elf_class == ELFCLASS ## B) { \
356     Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \
357     Elf ## B ## _Shdr *shdr = SHDR ## B (elf->shdr); \
358     Elf ## B ## _Shdr *symtab = SHDR ## B (symtab_void); \
359     Elf ## B ## _Shdr *strtab = SHDR ## B (strtab_void); \
360 vapier 1.82 Elf ## B ## _Shdr *text = SHDR ## B (text_void); \
361     Elf ## B ## _Addr vaddr = EGET(text->sh_addr); \
362     uint ## B ## _t memsz = EGET(text->sh_size); \
363 vapier 1.76 Elf ## B ## _Rel *rel; \
364     Elf ## B ## _Rela *rela; \
365     /* search the section headers for relocations */ \
366     for (s = 0; s < EGET(ehdr->e_shnum); ++s) { \
367     uint32_t sh_type = EGET(shdr[s].sh_type); \
368     if (sh_type == SHT_REL) { \
369     rel = REL ## B (elf->data + EGET(shdr[s].sh_offset)); \
370     rela = NULL; \
371     rmax = EGET(shdr[s].sh_size) / sizeof(*rel); \
372     } else if (sh_type == SHT_RELA) { \
373     rel = NULL; \
374     rela = RELA ## B (elf->data + EGET(shdr[s].sh_offset)); \
375     rmax = EGET(shdr[s].sh_size) / sizeof(*rela); \
376     } else \
377     continue; \
378 vapier 1.82 /* now see if any of the relocs are in the .text */ \
379     for (r = 0; r < rmax; ++r) { \
380     unsigned long sym_max; \
381     Elf ## B ## _Addr offset_tmp; \
382     Elf ## B ## _Sym *func; \
383     Elf ## B ## _Sym *sym; \
384     Elf ## B ## _Addr r_offset; \
385     uint ## B ## _t r_info; \
386     if (sh_type == SHT_REL) { \
387     r_offset = EGET(rel[r].r_offset); \
388     r_info = EGET(rel[r].r_info); \
389     } else { \
390     r_offset = EGET(rela[r].r_offset); \
391     r_info = EGET(rela[r].r_info); \
392     } \
393     /* make sure this relocation is inside of the .text */ \
394     if (r_offset < vaddr || r_offset >= vaddr + memsz) { \
395     if (be_verbose <= 2) continue; \
396     } else \
397 vapier 1.78 *found_textrels = 1; \
398 vapier 1.82 /* locate this relocation symbol name */ \
399     sym = SYM ## B (elf->data + EGET(symtab->sh_offset)); \
400 vapier 1.112 if ((void*)sym > (void*)elf->data_end) { \
401 vapier 1.111 warn("%s: corrupt ELF symbol", elf->filename); \
402 vapier 1.109 continue; \
403     } \
404 vapier 1.82 sym_max = ELF ## B ## _R_SYM(r_info); \
405     if (sym_max * EGET(symtab->sh_entsize) < symtab->sh_size) \
406     sym += sym_max; \
407     else \
408     sym = NULL; \
409     sym_max = EGET(symtab->sh_size) / EGET(symtab->sh_entsize); \
410     /* show the raw details about this reloc */ \
411 vapier 1.88 printf(" %s: ", elf->base_filename); \
412 vapier 1.82 if (sym && sym->st_name) \
413     printf("%s", (char*)(elf->data + EGET(strtab->sh_offset) + EGET(sym->st_name))); \
414     else \
415 vapier 1.169 printf("(memory/data?)"); \
416 vapier 1.82 printf(" [0x%lX]", (unsigned long)r_offset); \
417     /* now try to find the closest symbol that this rel is probably in */ \
418     sym = SYM ## B (elf->data + EGET(symtab->sh_offset)); \
419     func = NULL; \
420     offset_tmp = 0; \
421     while (sym_max--) { \
422     if (EGET(sym->st_value) < r_offset && EGET(sym->st_value) > offset_tmp) { \
423     func = sym; \
424     offset_tmp = EGET(sym->st_value); \
425 vapier 1.76 } \
426 vapier 1.82 ++sym; \
427 vapier 1.76 } \
428 vapier 1.82 printf(" in "); \
429 vapier 1.169 if (func && func->st_name) { \
430     const char *func_name = elf->data + EGET(strtab->sh_offset) + EGET(func->st_name); \
431     if (r_offset > EGET(func->st_size)) \
432     printf("(optimized out: previous %s)", func_name); \
433     else \
434     printf("%s", func_name); \
435     } else \
436     printf("(optimized out)"); \
437 vapier 1.82 printf(" [0x%lX]\n", (unsigned long)offset_tmp); \
438 solar 1.170 if (be_verbose && has_objdump) { \
439 vapier 1.167 char *sysbuf; \
440     size_t syslen; \
441     const char sysfmt[] = "objdump -r -R -d -w -l --start-address=0x%lX --stop-address=0x%lX %s | grep --color -i -C 3 '.*[[:space:]]%lX:[[:space:]]*R_.*'\n"; \
442     syslen = sizeof(sysfmt) + strlen(elf->filename) + 3 * sizeof(unsigned long) + 1; \
443     sysbuf = xmalloc(syslen); \
444     if (sysbuf) { \
445 vapier 1.169 Elf ## B ## _Addr end_addr = offset_tmp + EGET(func->st_size); \
446     if (end_addr < r_offset) \
447     /* not uncommon when things are optimized out */ \
448     end_addr = r_offset + 0x100; \
449 vapier 1.167 snprintf(sysbuf, syslen, sysfmt, \
450     (unsigned long)offset_tmp, \
451 vapier 1.169 (unsigned long)end_addr, \
452 vapier 1.167 elf->filename, \
453     (unsigned long)r_offset); \
454 vapier 1.168 fflush(stdout); \
455 vapier 1.167 system(sysbuf); \
456 vapier 1.168 fflush(stdout); \
457 vapier 1.167 free(sysbuf); \
458     } \
459     } \
460 vapier 1.76 } \
461     } }
462     SHOW_TEXTRELS(32)
463     SHOW_TEXTRELS(64)
464     }
465 vapier 1.82 if (!*found_textrels)
466     warnf("ELF %s has TEXTREL markings but doesnt appear to have any real TEXTREL's !?", elf->filename);
467 vapier 1.76
468     return NULL;
469     }
470 solar 1.83
471 vapier 1.102 static void rpath_security_checks(elfobj *, char *, const char *);
472     static void rpath_security_checks(elfobj *elf, char *item, const char *dt_type)
473 vapier 1.100 {
474 solar 1.83 struct stat st;
475 vapier 1.84 switch (*item) {
476 vapier 1.89 case '/': break;
477     case '.':
478 vapier 1.102 warnf("Security problem with relative %s '%s' in %s", dt_type, item, elf->filename);
479 vapier 1.89 break;
480 vapier 1.100 case ':':
481 vapier 1.89 case '\0':
482 vapier 1.102 warnf("Security problem NULL %s in %s", dt_type, elf->filename);
483 solar 1.83 break;
484     case '$':
485 vapier 1.84 if (fstat(elf->fd, &st) != -1)
486 solar 1.83 if ((st.st_mode & S_ISUID) || (st.st_mode & S_ISGID))
487 vapier 1.157 warnf("Security problem with %s='%s' in %s with mode set of %o",
488 vapier 1.102 dt_type, item, elf->filename, st.st_mode & 07777);
489 solar 1.83 break;
490     default:
491 vapier 1.102 warnf("Maybe? sec problem with %s='%s' in %s", dt_type, item, elf->filename);
492 solar 1.83 break;
493     }
494     }
495 vapier 1.41 static void scanelf_file_rpath(elfobj *elf, char *found_rpath, char **ret, size_t *ret_len)
496 vapier 1.39 {
497 vapier 1.48 unsigned long i, s;
498     char *rpath, *runpath, **r;
499 vapier 1.39 void *strtbl_void;
500 vapier 1.10
501 vapier 1.39 if (!show_rpath) return;
502 vapier 1.10
503 vapier 1.39 strtbl_void = elf_findsecbyname(elf, ".dynstr");
504     rpath = runpath = NULL;
505 vapier 1.10
506 vapier 1.44 if (elf->phdr && strtbl_void) {
507 vapier 1.26 #define SHOW_RPATH(B) \
508     if (elf->elf_class == ELFCLASS ## B) { \
509     Elf ## B ## _Dyn *dyn; \
510     Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \
511     Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \
512     Elf ## B ## _Shdr *strtbl = SHDR ## B (strtbl_void); \
513 vapier 1.44 Elf ## B ## _Off offset; \
514 vapier 1.60 Elf ## B ## _Xword word; \
515 vapier 1.48 /* Scan all the program headers */ \
516 vapier 1.26 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \
517 vapier 1.48 /* Just scan dynamic headers */ \
518 vapier 1.26 if (EGET(phdr[i].p_type) != PT_DYNAMIC) continue; \
519 vapier 1.44 offset = EGET(phdr[i].p_offset); \
520     if (offset >= elf->len - sizeof(Elf ## B ## _Dyn)) continue; \
521 vapier 1.48 /* Just scan dynamic RPATH/RUNPATH headers */ \
522 vapier 1.44 dyn = DYN ## B (elf->data + offset); \
523 vapier 1.48 while ((word=EGET(dyn->d_tag)) != DT_NULL) { \
524     if (word == DT_RPATH) { \
525     r = &rpath; \
526     } else if (word == DT_RUNPATH) { \
527     r = &runpath; \
528     } else { \
529     ++dyn; \
530     continue; \
531     } \
532     /* Verify the memory is somewhat sane */ \
533     offset = EGET(strtbl->sh_offset) + EGET(dyn->d_un.d_ptr); \
534 vapier 1.69 if (offset < (Elf ## B ## _Off)elf->len) { \
535 vapier 1.48 if (*r) warn("ELF has multiple %s's !?", get_elfdtype(word)); \
536     *r = (char*)(elf->data + offset); \
537 vapier 1.103 /* cache the length in case we need to nuke this section later on */ \
538     if (fix_elf) \
539     offset = strlen(*r); \
540 vapier 1.48 /* If quiet, don't output paths in ld.so.conf */ \
541 vapier 1.69 if (be_quiet) { \
542     size_t len; \
543     char *start, *end; \
544 vapier 1.75 /* note that we only 'chop' off leading known paths. */ \
545     /* since *r is read-only memory, we can only move the ptr forward. */ \
546     start = *r; \
547     /* scan each path in : delimited list */ \
548     while (start) { \
549 vapier 1.102 rpath_security_checks(elf, start, get_elfdtype(word)); \
550 vapier 1.69 end = strchr(start, ':'); \
551 vapier 1.75 len = (end ? abs(end - start) : strlen(start)); \
552 vapier 1.102 if (use_ldcache) \
553     for (s = 0; ldpaths[s]; ++s) \
554     if (!strncmp(ldpaths[s], start, len) && !ldpaths[s][len]) { \
555     *r = end; \
556     /* corner case ... if RPATH reads "/usr/lib:", we want \
557     * to show ':' rather than '' */ \
558     if (end && end[1] != '\0') \
559     (*r)++; \
560     break; \
561     } \
562 vapier 1.100 if (!*r || !end) \
563     break; \
564 vapier 1.75 else \
565     start = start + len + 1; \
566 vapier 1.69 } \
567     } \
568 vapier 1.101 if (*r) { \
569 solar 1.107 if (fix_elf > 2 || (fix_elf && **r == '\0')) { \
570 vapier 1.101 /* just nuke it */ \
571     nuke_it##B: \
572 vapier 1.103 memset(*r, 0x00, offset); \
573 vapier 1.102 *r = NULL; \
574 vapier 1.101 ESET(dyn->d_tag, DT_DEBUG); \
575 vapier 1.103 ESET(dyn->d_un.d_ptr, 0); \
576 vapier 1.101 } else if (fix_elf) { \
577     /* try to clean "bad" paths */ \
578     size_t len, tmpdir_len; \
579     char *start, *end; \
580     const char *tmpdir; \
581     start = *r; \
582     tmpdir = (getenv("TMPDIR") ? : "."); \
583     tmpdir_len = strlen(tmpdir); \
584     while (1) { \
585     end = strchr(start, ':'); \
586     if (start == end) { \
587     eat_this_path##B: \
588     len = strlen(end); \
589     memmove(start, end+1, len); \
590     start[len-1] = '\0'; \
591     end = start - 1; \
592     } else if (tmpdir && !strncmp(start, tmpdir, tmpdir_len)) { \
593     if (!end) { \
594     if (start == *r) \
595     goto nuke_it##B; \
596     *--start = '\0'; \
597     } else \
598     goto eat_this_path##B; \
599     } \
600     if (!end) \
601     break; \
602     start = end + 1; \
603     } \
604 vapier 1.102 if (**r == '\0') \
605     goto nuke_it##B; \
606 vapier 1.101 } \
607 vapier 1.102 if (*r) \
608     *found_rpath = 1; \
609 vapier 1.101 } \
610 vapier 1.26 } \
611     ++dyn; \
612     } \
613     } }
614     SHOW_RPATH(32)
615     SHOW_RPATH(64)
616 vapier 1.10 }
617 vapier 1.41
618 solar 1.127 if (be_wewy_wewy_quiet) return;
619 vapier 1.70
620 vapier 1.39 if (rpath && runpath) {
621 vapier 1.41 if (!strcmp(rpath, runpath)) {
622     xstrcat(ret, runpath, ret_len);
623     } else {
624 vapier 1.39 fprintf(stderr, "RPATH [%s] != RUNPATH [%s]\n", rpath, runpath);
625 vapier 1.41 xchrcat(ret, '{', ret_len);
626     xstrcat(ret, rpath, ret_len);
627     xchrcat(ret, ',', ret_len);
628     xstrcat(ret, runpath, ret_len);
629     xchrcat(ret, '}', ret_len);
630 vapier 1.39 }
631     } else if (rpath || runpath)
632 vapier 1.41 xstrcat(ret, (runpath ? runpath : rpath), ret_len);
633     else if (!be_quiet)
634     xstrcat(ret, " - ", ret_len);
635 vapier 1.39 }
636 solar 1.96
637     #define LDSO_CACHE_MAGIC "ld.so-"
638     #define LDSO_CACHE_MAGIC_LEN (sizeof LDSO_CACHE_MAGIC -1)
639     #define LDSO_CACHE_VER "1.7.0"
640     #define LDSO_CACHE_VER_LEN (sizeof LDSO_CACHE_VER -1)
641 vapier 1.97 #define FLAG_ANY -1
642     #define FLAG_TYPE_MASK 0x00ff
643     #define FLAG_LIBC4 0x0000
644     #define FLAG_ELF 0x0001
645     #define FLAG_ELF_LIBC5 0x0002
646     #define FLAG_ELF_LIBC6 0x0003
647     #define FLAG_REQUIRED_MASK 0xff00
648     #define FLAG_SPARC_LIB64 0x0100
649     #define FLAG_IA64_LIB64 0x0200
650     #define FLAG_X8664_LIB64 0x0300
651     #define FLAG_S390_LIB64 0x0400
652     #define FLAG_POWERPC_LIB64 0x0500
653     #define FLAG_MIPS64_LIBN32 0x0600
654     #define FLAG_MIPS64_LIBN64 0x0700
655 solar 1.96
656 vapier 1.97 static char *lookup_cache_lib(elfobj *, char *);
657 vapier 1.148
658 flameeyes 1.141 #if defined(__GLIBC__) || defined(__UCLIBC__)
659 vapier 1.148
660 vapier 1.97 static char *lookup_cache_lib(elfobj *elf, char *fname)
661 solar 1.96 {
662     int fd = 0;
663     char *strs;
664 vapier 1.104 static char buf[__PAX_UTILS_PATH_MAX] = "";
665 solar 1.96 const char *cachefile = "/etc/ld.so.cache";
666     struct stat st;
667    
668     typedef struct {
669     char magic[LDSO_CACHE_MAGIC_LEN];
670     char version[LDSO_CACHE_VER_LEN];
671     int nlibs;
672     } header_t;
673 vapier 1.97 header_t *header;
674 solar 1.96
675     typedef struct {
676     int flags;
677     int sooffset;
678     int liboffset;
679     } libentry_t;
680     libentry_t *libent;
681    
682     if (fname == NULL)
683     return NULL;
684    
685     if (ldcache == 0) {
686 vapier 1.97 if (stat(cachefile, &st) || (fd = open(cachefile, O_RDONLY)) == -1)
687 solar 1.96 return NULL;
688 vapier 1.97
689     /* cache these values so we only map/unmap the cache file once */
690 solar 1.96 ldcache_size = st.st_size;
691 vapier 1.97 ldcache = mmap(0, ldcache_size, PROT_READ, MAP_SHARED, fd, 0);
692    
693     close(fd);
694 solar 1.96
695 solar 1.116 if (ldcache == (caddr_t)-1) {
696     ldcache = 0;
697 solar 1.96 return NULL;
698 solar 1.116 }
699 solar 1.96
700     if (memcmp(((header_t *) ldcache)->magic, LDSO_CACHE_MAGIC, LDSO_CACHE_MAGIC_LEN))
701     return NULL;
702     if (memcmp (((header_t *) ldcache)->version, LDSO_CACHE_VER, LDSO_CACHE_VER_LEN))
703     return NULL;
704     }
705    
706     header = (header_t *) ldcache;
707     libent = (libentry_t *) (ldcache + sizeof(header_t));
708     strs = (char *) &libent[header->nlibs];
709    
710     for (fd = 0; fd < header->nlibs; fd++) {
711 vapier 1.97 /* this should be more fine grained, but for now we assume that
712     * diff arches will not be cached together. and we ignore the
713     * the different multilib mips cases. */
714     if (elf->elf_class == ELFCLASS64 && !(libent[fd].flags & FLAG_REQUIRED_MASK))
715     continue;
716     if (elf->elf_class == ELFCLASS32 && (libent[fd].flags & FLAG_REQUIRED_MASK))
717     continue;
718    
719 solar 1.96 if (strcmp(fname, strs + libent[fd].sooffset) != 0)
720     continue;
721     strncpy(buf, strs + libent[fd].liboffset, sizeof(buf));
722     }
723     return buf;
724     }
725 solar 1.154 #elif defined(__NetBSD__)
726     static char *lookup_cache_lib(elfobj *elf, char *fname)
727     {
728     static char buf[__PAX_UTILS_PATH_MAX] = "";
729     static struct stat st;
730    
731     char **ldpath;
732     for (ldpath = ldpaths; *ldpath != NULL; ldpath++) {
733     if ((unsigned) snprintf(buf, sizeof(buf), "%s/%s", *ldpath, fname) >= sizeof(buf))
734     continue; /* if the pathname is too long, or something went wrong, ignore */
735    
736     if (stat(buf, &st) != 0)
737     continue; /* if the lib doesn't exist in *ldpath, look further */
738    
739     /* NetBSD doesn't actually do sanity checks, it just loads the file
740     * and if that doesn't work, continues looking in other directories.
741     * This cannot easily be safely emulated, unfortunately. For now,
742     * just assume that if it exists, it's a valid library. */
743 vapier 1.148
744 solar 1.154 return buf;
745     }
746    
747     /* not found in any path */
748     return NULL;
749     }
750 flameeyes 1.141 #else
751 vapier 1.148 #warning Cache support not implemented for your target
752 flameeyes 1.141 static char *lookup_cache_lib(elfobj *elf, char *fname)
753     {
754     return NULL;
755     }
756     #endif
757 solar 1.96
758 vapier 1.84 static const char *scanelf_file_needed_lib(elfobj *elf, char *found_needed, char *found_lib, int op, char **ret, size_t *ret_len)
759 vapier 1.39 {
760 vapier 1.44 unsigned long i;
761 vapier 1.39 char *needed;
762     void *strtbl_void;
763 solar 1.96 char *p;
764 vapier 1.39
765 vapier 1.72 if ((op==0 && !show_needed) || (op==1 && !find_lib)) return NULL;
766 vapier 1.10
767 vapier 1.39 strtbl_void = elf_findsecbyname(elf, ".dynstr");
768 vapier 1.32
769 vapier 1.44 if (elf->phdr && strtbl_void) {
770 vapier 1.32 #define SHOW_NEEDED(B) \
771     if (elf->elf_class == ELFCLASS ## B) { \
772     Elf ## B ## _Dyn *dyn; \
773     Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \
774     Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \
775     Elf ## B ## _Shdr *strtbl = SHDR ## B (strtbl_void); \
776 vapier 1.44 Elf ## B ## _Off offset; \
777 vapier 1.32 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \
778     if (EGET(phdr[i].p_type) != PT_DYNAMIC) continue; \
779 vapier 1.44 offset = EGET(phdr[i].p_offset); \
780     if (offset >= elf->len - sizeof(Elf ## B ## _Dyn)) continue; \
781     dyn = DYN ## B (elf->data + offset); \
782 vapier 1.32 while (EGET(dyn->d_tag) != DT_NULL) { \
783     if (EGET(dyn->d_tag) == DT_NEEDED) { \
784 vapier 1.44 offset = EGET(strtbl->sh_offset) + EGET(dyn->d_un.d_ptr); \
785 vapier 1.69 if (offset >= (Elf ## B ## _Off)elf->len) { \
786 vapier 1.49 ++dyn; \
787     continue; \
788     } \
789 vapier 1.44 needed = (char*)(elf->data + offset); \
790 vapier 1.72 if (op == 0) { \
791 solar 1.127 if (!be_wewy_wewy_quiet) { \
792 vapier 1.72 if (*found_needed) xchrcat(ret, ',', ret_len); \
793 vapier 1.102 if (use_ldcache) \
794 vapier 1.97 if ((p = lookup_cache_lib(elf, needed)) != NULL) \
795 solar 1.96 needed = p; \
796 vapier 1.72 xstrcat(ret, needed, ret_len); \
797     } \
798     *found_needed = 1; \
799     } else { \
800 solar 1.86 if (!strncmp(find_lib, needed, strlen( !gmatch ? needed : find_lib))) { \
801 vapier 1.81 *found_lib = 1; \
802 solar 1.127 return (be_wewy_wewy_quiet ? NULL : needed); \
803 vapier 1.81 } \
804 vapier 1.72 } \
805 vapier 1.32 } \
806     ++dyn; \
807     } \
808     } }
809     SHOW_NEEDED(32)
810     SHOW_NEEDED(64)
811 vapier 1.85 if (op == 0 && !*found_needed && be_verbose)
812 vapier 1.84 warn("ELF lacks DT_NEEDED sections: %s", elf->filename);
813 vapier 1.32 }
814 vapier 1.72
815     return NULL;
816 vapier 1.39 }
817 vapier 1.41 static char *scanelf_file_interp(elfobj *elf, char *found_interp)
818 vapier 1.39 {
819     void *strtbl_void;
820    
821 vapier 1.41 if (!show_interp) return NULL;
822 vapier 1.32
823 vapier 1.39 strtbl_void = elf_findsecbyname(elf, ".interp");
824 vapier 1.38
825 vapier 1.39 if (strtbl_void) {
826 vapier 1.38 #define SHOW_INTERP(B) \
827     if (elf->elf_class == ELFCLASS ## B) { \
828 solar 1.40 Elf ## B ## _Shdr *strtbl = SHDR ## B (strtbl_void); \
829     *found_interp = 1; \
830 solar 1.127 return (be_wewy_wewy_quiet ? NULL : elf->data + EGET(strtbl->sh_offset)); \
831 vapier 1.38 }
832     SHOW_INTERP(32)
833     SHOW_INTERP(64)
834     }
835 vapier 1.41 return NULL;
836 vapier 1.39 }
837 vapier 1.49 static char *scanelf_file_bind(elfobj *elf, char *found_bind)
838     {
839     unsigned long i;
840     struct stat s;
841 solar 1.131 char dynamic = 0;
842 vapier 1.49
843     if (!show_bind) return NULL;
844 vapier 1.51 if (!elf->phdr) return NULL;
845 vapier 1.49
846     #define SHOW_BIND(B) \
847     if (elf->elf_class == ELFCLASS ## B) { \
848     Elf ## B ## _Dyn *dyn; \
849     Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \
850     Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \
851     Elf ## B ## _Off offset; \
852     for (i = 0; i < EGET(ehdr->e_phnum); i++) { \
853     if (EGET(phdr[i].p_type) != PT_DYNAMIC) continue; \
854 solar 1.131 dynamic = 1; \
855 vapier 1.49 offset = EGET(phdr[i].p_offset); \
856     if (offset >= elf->len - sizeof(Elf ## B ## _Dyn)) continue; \
857     dyn = DYN ## B (elf->data + offset); \
858     while (EGET(dyn->d_tag) != DT_NULL) { \
859     if (EGET(dyn->d_tag) == DT_BIND_NOW || \
860     (EGET(dyn->d_tag) == DT_FLAGS && EGET(dyn->d_un.d_val) & DF_BIND_NOW)) \
861     { \
862     if (be_quiet) return NULL; \
863     *found_bind = 1; \
864 solar 1.127 return (char *)(be_wewy_wewy_quiet ? NULL : "NOW"); \
865 vapier 1.49 } \
866     ++dyn; \
867     } \
868     } \
869     }
870     SHOW_BIND(32)
871     SHOW_BIND(64)
872    
873 solar 1.127 if (be_wewy_wewy_quiet) return NULL;
874 vapier 1.70
875 vapier 1.159 /* don't output anything if quiet mode and the ELF is static or not setuid */
876     if (be_quiet && (!dynamic || (!fstat(elf->fd, &s) && !(s.st_mode & (S_ISUID|S_ISGID))))) {
877 vapier 1.49 return NULL;
878     } else {
879     *found_bind = 1;
880 solar 1.131 return (char *) (dynamic ? "LAZY" : "STATIC");
881 vapier 1.49 }
882     }
883 vapier 1.84 static char *scanelf_file_soname(elfobj *elf, char *found_soname)
884     {
885     unsigned long i;
886     char *soname;
887     void *strtbl_void;
888    
889     if (!show_soname) return NULL;
890    
891     strtbl_void = elf_findsecbyname(elf, ".dynstr");
892    
893     if (elf->phdr && strtbl_void) {
894     #define SHOW_SONAME(B) \
895     if (elf->elf_class == ELFCLASS ## B) { \
896     Elf ## B ## _Dyn *dyn; \
897     Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \
898     Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \
899     Elf ## B ## _Shdr *strtbl = SHDR ## B (strtbl_void); \
900     Elf ## B ## _Off offset; \
901     /* only look for soname in shared objects */ \
902     if (ehdr->e_type != ET_DYN) \
903     return NULL; \
904     for (i = 0; i < EGET(ehdr->e_phnum); i++) { \
905     if (EGET(phdr[i].p_type) != PT_DYNAMIC) continue; \
906     offset = EGET(phdr[i].p_offset); \
907     if (offset >= elf->len - sizeof(Elf ## B ## _Dyn)) continue; \
908     dyn = DYN ## B (elf->data + offset); \
909     while (EGET(dyn->d_tag) != DT_NULL) { \
910     if (EGET(dyn->d_tag) == DT_SONAME) { \
911     offset = EGET(strtbl->sh_offset) + EGET(dyn->d_un.d_ptr); \
912     if (offset >= (Elf ## B ## _Off)elf->len) { \
913     ++dyn; \
914     continue; \
915     } \
916     soname = (char*)(elf->data + offset); \
917     *found_soname = 1; \
918 solar 1.127 return (be_wewy_wewy_quiet ? NULL : soname); \
919 vapier 1.84 } \
920     ++dyn; \
921     } \
922     } }
923     SHOW_SONAME(32)
924     SHOW_SONAME(64)
925     }
926    
927     return NULL;
928     }
929 vapier 1.72 static char *scanelf_file_sym(elfobj *elf, char *found_sym)
930 vapier 1.39 {
931 vapier 1.44 unsigned long i;
932 vapier 1.95 char *ret;
933 vapier 1.39 void *symtab_void, *strtab_void;
934 vapier 1.38
935 vapier 1.41 if (!find_sym) return NULL;
936 vapier 1.95 ret = find_sym;
937 vapier 1.32
938 vapier 1.77 scanelf_file_get_symtabs(elf, &symtab_void, &strtab_void);
939 vapier 1.27
940 vapier 1.39 if (symtab_void && strtab_void) {
941 vapier 1.27 #define FIND_SYM(B) \
942     if (elf->elf_class == ELFCLASS ## B) { \
943     Elf ## B ## _Shdr *symtab = SHDR ## B (symtab_void); \
944     Elf ## B ## _Shdr *strtab = SHDR ## B (strtab_void); \
945     Elf ## B ## _Sym *sym = SYM ## B (elf->data + EGET(symtab->sh_offset)); \
946 vapier 1.115 unsigned long cnt = EGET(symtab->sh_entsize); \
947 vapier 1.27 char *symname; \
948 vapier 1.115 if (cnt) \
949     cnt = EGET(symtab->sh_size) / cnt; \
950 vapier 1.27 for (i = 0; i < cnt; ++i) { \
951     if (sym->st_name) { \
952 vapier 1.134 /* make sure the symbol name is in acceptable memory range */ \
953 vapier 1.27 symname = (char *)(elf->data + EGET(strtab->sh_offset) + EGET(sym->st_name)); \
954 vapier 1.115 if ((void*)symname > (void*)elf->data_end) { \
955     warnf("%s: corrupt ELF symbols", elf->filename); \
956 vapier 1.134 ++sym; \
957 vapier 1.111 continue; \
958     } \
959 vapier 1.134 /* debug display ... show all symbols and some extra info */ \
960     if (*ret == '*') { \
961 vapier 1.32 printf("%s(%s) %5lX %15s %s\n", \
962 vapier 1.39 ((*found_sym == 0) ? "\n\t" : "\t"), \
963 vapier 1.76 elf->base_filename, \
964 vapier 1.94 (unsigned long)sym->st_size, \
965 vapier 1.95 get_elfstttype(sym->st_info), \
966 vapier 1.32 symname); \
967 vapier 1.39 *found_sym = 1; \
968 vapier 1.95 } else { \
969 vapier 1.134 /* allow the user to specify a comma delimited list of symbols to search for */ \
970 vapier 1.156 char *this_sym, *this_sym_ver, *next_sym; \
971 vapier 1.134 this_sym = ret; \
972 vapier 1.156 this_sym_ver = versioned_symname; \
973 vapier 1.95 do { \
974     next_sym = strchr(this_sym, ','); \
975     if (next_sym == NULL) \
976     next_sym = this_sym + strlen(this_sym); \
977 vapier 1.134 /* do we want a defined symbol ? */ \
978     if (*this_sym == '+') { \
979 vapier 1.140 if (sym->st_shndx == SHN_UNDEF) \
980 vapier 1.134 goto skip_this_sym##B; \
981     ++this_sym; \
982 vapier 1.156 ++this_sym_ver; \
983 vapier 1.134 /* do we want an undefined symbol ? */ \
984     } else if (*this_sym == '-') { \
985 vapier 1.140 if (sym->st_shndx != SHN_UNDEF) \
986 vapier 1.134 goto skip_this_sym##B; \
987     ++this_sym; \
988 vapier 1.156 ++this_sym_ver; \
989 vapier 1.134 } \
990     /* ok, lets compare the name now */ \
991 vapier 1.95 if ((strncmp(this_sym, symname, (next_sym-this_sym)) == 0 && symname[next_sym-this_sym] == '\0') || \
992 vapier 1.156 (strncmp(this_sym_ver, symname, strlen(this_sym_ver)) == 0)) { \
993 solar 1.132 if (be_semi_verbose) { \
994     char buf[126]; \
995     snprintf(buf, sizeof(buf), "%lX %s %s", \
996     (unsigned long)sym->st_size, get_elfstttype(sym->st_info), this_sym); \
997     ret = buf; \
998     } else \
999     ret = this_sym; \
1000 vapier 1.95 (*found_sym)++; \
1001     goto break_out; \
1002     } \
1003 vapier 1.134 skip_this_sym##B: this_sym = next_sym + 1; \
1004 vapier 1.95 } while (*next_sym != '\0'); \
1005     } \
1006 vapier 1.27 } \
1007     ++sym; \
1008     } }
1009     FIND_SYM(32)
1010     FIND_SYM(64)
1011 vapier 1.39 }
1012 vapier 1.70
1013 vapier 1.95 break_out:
1014 solar 1.127 if (be_wewy_wewy_quiet) return NULL;
1015 vapier 1.70
1016 vapier 1.41 if (*find_sym != '*' && *found_sym)
1017 vapier 1.95 return ret;
1018 vapier 1.41 if (be_quiet)
1019     return NULL;
1020     else
1021 solar 1.68 return (char *)" - ";
1022 vapier 1.39 }
1023 solar 1.119
1024    
1025 solar 1.124 static char *scanelf_file_sections(elfobj *elf, char *found_section)
1026     {
1027     if (!find_section)
1028     return NULL;
1029    
1030     #define FIND_SECTION(B) \
1031     if (elf->elf_class == ELFCLASS ## B) { \
1032 solar 1.136 int invert; \
1033 solar 1.124 Elf ## B ## _Shdr *section; \
1034 solar 1.136 invert = (*find_section == '!' ? 1 : 0); \
1035     section = SHDR ## B (elf_findsecbyname(elf, find_section+invert)); \
1036     if ((section == NULL && invert) || (section != NULL && !invert)) \
1037 solar 1.124 *found_section = 1; \
1038     }
1039     FIND_SECTION(32)
1040     FIND_SECTION(64)
1041    
1042 vapier 1.138 if (be_wewy_wewy_quiet)
1043     return NULL;
1044 solar 1.124
1045     if (*found_section)
1046     return find_section;
1047    
1048     if (be_quiet)
1049     return NULL;
1050     else
1051     return (char *)" - ";
1052     }
1053    
1054 vapier 1.39 /* scan an elf file and show all the fun stuff */
1055 solar 1.57 #define prints(str) write(fileno(stdout), str, strlen(str))
1056 vapier 1.106 static int scanelf_elfobj(elfobj *elf)
1057 vapier 1.39 {
1058 vapier 1.44 unsigned long i;
1059 vapier 1.162 char found_pax, found_phdr, found_relro, found_load, found_textrel,
1060     found_rpath, found_needed, found_interp, found_bind, found_soname,
1061 solar 1.124 found_sym, found_lib, found_file, found_textrels, found_section;
1062 vapier 1.41 static char *out_buffer = NULL;
1063     static size_t out_len;
1064 vapier 1.39
1065 vapier 1.76 found_pax = found_phdr = found_relro = found_load = found_textrel = \
1066 vapier 1.84 found_rpath = found_needed = found_interp = found_bind = found_soname = \
1067 solar 1.124 found_sym = found_lib = found_file = found_textrels = found_section = 0;
1068 vapier 1.39
1069 vapier 1.114 if (be_verbose > 2)
1070 vapier 1.106 printf("%s: scanning file {%s,%s}\n", elf->filename,
1071 vapier 1.69 get_elfeitype(EI_CLASS, elf->elf_class),
1072     get_elfeitype(EI_DATA, elf->data[EI_DATA]));
1073 vapier 1.114 else if (be_verbose > 1)
1074 vapier 1.106 printf("%s: scanning file\n", elf->filename);
1075 vapier 1.39
1076 vapier 1.41 /* init output buffer */
1077     if (!out_buffer) {
1078     out_len = sizeof(char) * 80;
1079     out_buffer = (char*)xmalloc(out_len);
1080     }
1081     *out_buffer = '\0';
1082    
1083 vapier 1.39 /* show the header */
1084     if (!be_quiet && show_banner) {
1085 vapier 1.49 for (i = 0; out_format[i]; ++i) {
1086 vapier 1.70 if (!IS_MODIFIER(out_format[i])) continue;
1087 vapier 1.41
1088     switch (out_format[++i]) {
1089 solar 1.132 case '+': break;
1090 vapier 1.41 case '%': break;
1091 vapier 1.70 case '#': break;
1092 vapier 1.66 case 'F':
1093     case 'p':
1094     case 'f': prints("FILE "); found_file = 1; break;
1095 vapier 1.41 case 'o': prints(" TYPE "); break;
1096     case 'x': prints(" PAX "); break;
1097 vapier 1.71 case 'e': prints("STK/REL/PTL "); break;
1098 vapier 1.41 case 't': prints("TEXTREL "); break;
1099     case 'r': prints("RPATH "); break;
1100 vapier 1.171 case 'M': prints("CLASS "); break;
1101 vapier 1.41 case 'n': prints("NEEDED "); break;
1102     case 'i': prints("INTERP "); break;
1103 vapier 1.49 case 'b': prints("BIND "); break;
1104 vapier 1.84 case 'S': prints("SONAME "); break;
1105 vapier 1.41 case 's': prints("SYM "); break;
1106 vapier 1.72 case 'N': prints("LIB "); break;
1107 vapier 1.76 case 'T': prints("TEXTRELS "); break;
1108 vapier 1.126 case 'k': prints("SECTION "); break;
1109 vapier 1.166 case 'a': prints("ARCH "); break;
1110 vapier 1.76 default: warnf("'%c' has no title ?", out_format[i]);
1111 vapier 1.39 }
1112 vapier 1.27 }
1113 vapier 1.49 if (!found_file) prints("FILE ");
1114 vapier 1.41 prints("\n");
1115 vapier 1.49 found_file = 0;
1116 vapier 1.39 show_banner = 0;
1117     }
1118    
1119     /* dump all the good stuff */
1120 vapier 1.49 for (i = 0; out_format[i]; ++i) {
1121 vapier 1.41 const char *out;
1122 vapier 1.66 const char *tmp;
1123 vapier 1.41
1124 vapier 1.70 if (!IS_MODIFIER(out_format[i])) {
1125 vapier 1.41 xchrcat(&out_buffer, out_format[i], &out_len);
1126     continue;
1127     }
1128 vapier 1.39
1129 vapier 1.41 out = NULL;
1130 solar 1.127 be_wewy_wewy_quiet = (out_format[i] == '#');
1131 solar 1.132 be_semi_verbose = (out_format[i] == '+');
1132 vapier 1.41 switch (out_format[++i]) {
1133 solar 1.132 case '+':
1134 vapier 1.70 case '%':
1135     case '#':
1136     xchrcat(&out_buffer, out_format[i], &out_len); break;
1137     case 'F':
1138 vapier 1.76 found_file = 1;
1139 solar 1.127 if (be_wewy_wewy_quiet) break;
1140 vapier 1.106 xstrcat(&out_buffer, elf->filename, &out_len);
1141 vapier 1.70 break;
1142 vapier 1.66 case 'p':
1143 vapier 1.76 found_file = 1;
1144 solar 1.127 if (be_wewy_wewy_quiet) break;
1145 vapier 1.106 tmp = elf->filename;
1146 vapier 1.66 if (search_path) {
1147     ssize_t len_search = strlen(search_path);
1148 vapier 1.106 ssize_t len_file = strlen(elf->filename);
1149     if (!strncmp(elf->filename, search_path, len_search) && \
1150 vapier 1.66 len_file > len_search)
1151     tmp += len_search;
1152     if (*tmp == '/' && search_path[len_search-1] == '/') tmp++;
1153     }
1154     xstrcat(&out_buffer, tmp, &out_len);
1155     break;
1156     case 'f':
1157 vapier 1.76 found_file = 1;
1158 solar 1.127 if (be_wewy_wewy_quiet) break;
1159 vapier 1.106 tmp = strrchr(elf->filename, '/');
1160     tmp = (tmp == NULL ? elf->filename : tmp+1);
1161 vapier 1.66 xstrcat(&out_buffer, tmp, &out_len);
1162     break;
1163 vapier 1.41 case 'o': out = get_elfetype(elf); break;
1164     case 'x': out = scanelf_file_pax(elf, &found_pax); break;
1165 solar 1.73 case 'e': out = scanelf_file_phdr(elf, &found_phdr, &found_relro, &found_load); break;
1166 vapier 1.41 case 't': out = scanelf_file_textrel(elf, &found_textrel); break;
1167 vapier 1.79 case 'T': out = scanelf_file_textrels(elf, &found_textrels, &found_textrel); break;
1168 vapier 1.41 case 'r': scanelf_file_rpath(elf, &found_rpath, &out_buffer, &out_len); break;
1169 vapier 1.171 case 'M': out = get_elfeitype(EI_CLASS, elf->data[EI_CLASS]); break;
1170 vapier 1.72 case 'n':
1171     case 'N': out = scanelf_file_needed_lib(elf, &found_needed, &found_lib, (out_format[i]=='N'), &out_buffer, &out_len); break;
1172 vapier 1.41 case 'i': out = scanelf_file_interp(elf, &found_interp); break;
1173 vapier 1.49 case 'b': out = scanelf_file_bind(elf, &found_bind); break;
1174 vapier 1.84 case 'S': out = scanelf_file_soname(elf, &found_soname); break;
1175 vapier 1.72 case 's': out = scanelf_file_sym(elf, &found_sym); break;
1176 solar 1.124 case 'k': out = scanelf_file_sections(elf, &found_section); break;
1177 vapier 1.166 case 'a': out = get_elfemtype(elf); break;
1178 vapier 1.76 default: warnf("'%c' has no scan code?", out_format[i]);
1179 vapier 1.29 }
1180 vapier 1.95 if (out) {
1181     /* hack for comma delimited output like `scanelf -s sym1,sym2,sym3` */
1182     if (out_format[i] == 's' && (tmp=strchr(out,',')) != NULL)
1183     xstrncat(&out_buffer, out, &out_len, (tmp-out));
1184     else
1185     xstrcat(&out_buffer, out, &out_len);
1186     }
1187 vapier 1.39 }
1188    
1189 vapier 1.54 #define FOUND_SOMETHING() \
1190 solar 1.73 (found_pax || found_phdr || found_relro || found_load || found_textrel || \
1191 vapier 1.76 found_rpath || found_needed || found_interp || found_bind || \
1192 solar 1.124 found_soname || found_sym || found_lib || found_textrels || found_section )
1193 vapier 1.54
1194     if (!found_file && (!be_quiet || (be_quiet && FOUND_SOMETHING()))) {
1195     xchrcat(&out_buffer, ' ', &out_len);
1196 vapier 1.106 xstrcat(&out_buffer, elf->filename, &out_len);
1197 vapier 1.27 }
1198 vapier 1.79 if (!be_quiet || (be_quiet && FOUND_SOMETHING())) {
1199 vapier 1.41 puts(out_buffer);
1200 vapier 1.79 fflush(stdout);
1201     }
1202 vapier 1.10
1203 vapier 1.105 return 0;
1204     }
1205    
1206 vapier 1.106 /* scan a single elf */
1207     static int scanelf_elf(const char *filename, int fd, size_t len)
1208     {
1209 solar 1.120 int ret = 1;
1210 vapier 1.106 elfobj *elf;
1211    
1212     /* verify this is real ELF */
1213     if ((elf = _readelf_fd(filename, fd, len, !fix_elf)) == NULL) {
1214     if (be_verbose > 2) printf("%s: not an ELF\n", filename);
1215 solar 1.120 return ret;
1216     }
1217     switch (match_bits) {
1218     case 32:
1219     if (elf->elf_class != ELFCLASS32)
1220     goto label_done;
1221     break;
1222     case 64:
1223     if (elf->elf_class != ELFCLASS64)
1224     goto label_done;
1225     break;
1226     default: break;
1227 vapier 1.106 }
1228 solar 1.119 if (strlen(match_etypes)) {
1229     char sbuf[126];
1230     strncpy(sbuf, match_etypes, sizeof(sbuf));
1231     if (strchr(match_etypes, ',') != NULL) {
1232     char *p;
1233     while((p = strrchr(sbuf, ',')) != NULL) {
1234     *p = 0;
1235 solar 1.129 if (etype_lookup(p+1) == get_etype(elf))
1236 solar 1.119 goto label_ret;
1237     }
1238     }
1239 solar 1.129 if (etype_lookup(sbuf) != get_etype(elf))
1240 solar 1.119 goto label_done;
1241     }
1242    
1243     label_ret:
1244 vapier 1.106 ret = scanelf_elfobj(elf);
1245 solar 1.119
1246     label_done:
1247 vapier 1.106 unreadelf(elf);
1248     return ret;
1249     }
1250 solar 1.119
1251 vapier 1.105 /* scan an archive of elfs */
1252 vapier 1.106 static int scanelf_archive(const char *filename, int fd, size_t len)
1253 vapier 1.105 {
1254 vapier 1.106 archive_handle *ar;
1255 vapier 1.105 archive_member *m;
1256 vapier 1.106 char *ar_buffer;
1257     elfobj *elf;
1258    
1259     ar = ar_open_fd(filename, fd);
1260     if (ar == NULL)
1261     return 1;
1262    
1263     ar_buffer = (char*)mmap(0, len, PROT_READ | (fix_elf ? PROT_WRITE : 0), (fix_elf ? MAP_SHARED : MAP_PRIVATE), fd, 0);
1264     while ((m=ar_next(ar)) != NULL) {
1265     elf = readelf_buffer(m->name, ar_buffer+lseek(fd,0,SEEK_CUR), m->size);
1266     if (elf) {
1267     scanelf_elfobj(elf);
1268     unreadelf(elf);
1269     }
1270     }
1271     munmap(ar_buffer, len);
1272    
1273 vapier 1.105 return 0;
1274     }
1275     /* scan a file which may be an elf or an archive or some other magical beast */
1276 solar 1.164 static int scanelf_file(const char *filename, const struct stat *st_cache)
1277 vapier 1.105 {
1278 vapier 1.161 const struct stat *st = st_cache;
1279     struct stat symlink_st;
1280 vapier 1.106 int fd;
1281 vapier 1.105
1282     /* always handle regular files and handle symlinked files if no -y */
1283 vapier 1.161 if (S_ISLNK(st->st_mode)) {
1284 solar 1.164 if (!scan_symlink) return 1;
1285 vapier 1.161 stat(filename, &symlink_st);
1286     st = &symlink_st;
1287 vapier 1.105 }
1288 vapier 1.161
1289     if (!S_ISREG(st->st_mode)) {
1290 vapier 1.105 if (be_verbose > 2) printf("%s: skipping non-file\n", filename);
1291 solar 1.164 return 1;
1292 vapier 1.105 }
1293    
1294 vapier 1.106 if ((fd=open(filename, (fix_elf ? O_RDWR : O_RDONLY))) == -1)
1295 solar 1.164 return 1;
1296 vapier 1.106
1297 vapier 1.161 if (scanelf_elf(filename, fd, st->st_size) == 1 && scan_archives)
1298 vapier 1.105 /* if it isn't an ELF, maybe it's an .a archive */
1299 vapier 1.161 scanelf_archive(filename, fd, st->st_size);
1300 vapier 1.106
1301     close(fd);
1302 solar 1.164 return 0;
1303 solar 1.6 }
1304    
1305 solar 1.1 /* scan a directory for ET_EXEC files and print when we find one */
1306 solar 1.164 static int scanelf_dir(const char *path)
1307 solar 1.1 {
1308 vapier 1.10 register DIR *dir;
1309     register struct dirent *dentry;
1310 vapier 1.14 struct stat st_top, st;
1311 vapier 1.104 char buf[__PAX_UTILS_PATH_MAX];
1312 vapier 1.32 size_t pathlen = 0, len = 0;
1313 solar 1.164 int ret = 0;
1314 vapier 1.10
1315     /* make sure path exists */
1316 vapier 1.39 if (lstat(path, &st_top) == -1) {
1317     if (be_verbose > 2) printf("%s: does not exist\n", path);
1318 solar 1.164 return 1;
1319 vapier 1.39 }
1320 solar 1.11
1321 vapier 1.10 /* ok, if it isn't a directory, assume we can open it */
1322 vapier 1.14 if (!S_ISDIR(st_top.st_mode)) {
1323 solar 1.164 return scanelf_file(path, &st_top);
1324 vapier 1.10 }
1325    
1326     /* now scan the dir looking for fun stuff */
1327     if ((dir = opendir(path)) == NULL) {
1328     warnf("could not opendir %s: %s", path, strerror(errno));
1329 solar 1.164 return 1;
1330 vapier 1.10 }
1331 vapier 1.114 if (be_verbose > 1) printf("%s: scanning dir\n", path);
1332 solar 1.11
1333 vapier 1.32 pathlen = strlen(path);
1334 vapier 1.10 while ((dentry = readdir(dir))) {
1335     if (!strcmp(dentry->d_name, ".") || !strcmp(dentry->d_name, ".."))
1336     continue;
1337 vapier 1.32 len = (pathlen + 1 + strlen(dentry->d_name) + 1);
1338     if (len >= sizeof(buf)) {
1339 vapier 1.76 warnf("Skipping '%s': len > sizeof(buf); %lu > %lu\n", path,
1340     (unsigned long)len, (unsigned long)sizeof(buf));
1341 vapier 1.32 continue;
1342     }
1343 solar 1.143 snprintf(buf, sizeof(buf), "%s%s%s", path, (path[pathlen-1] == '/') ? "" : "/", dentry->d_name);
1344 solar 1.20 if (lstat(buf, &st) != -1) {
1345 vapier 1.10 if (S_ISREG(st.st_mode))
1346 solar 1.164 ret = scanelf_file(buf, &st);
1347 vapier 1.10 else if (dir_recurse && S_ISDIR(st.st_mode)) {
1348 vapier 1.14 if (dir_crossmount || (st_top.st_dev == st.st_dev))
1349 solar 1.164 ret = scanelf_dir(buf);
1350 vapier 1.10 }
1351     }
1352     }
1353     closedir(dir);
1354 solar 1.164 return ret;
1355 solar 1.1 }
1356    
1357 vapier 1.133 static int scanelf_from_file(const char *filename)
1358 vapier 1.47 {
1359 solar 1.45 FILE *fp = NULL;
1360     char *p;
1361 vapier 1.104 char path[__PAX_UTILS_PATH_MAX];
1362 solar 1.164 int ret = 0;
1363 solar 1.45
1364 solar 1.132 if (strcmp(filename, "-") == 0)
1365 solar 1.45 fp = stdin;
1366     else if ((fp = fopen(filename, "r")) == NULL)
1367     return 1;
1368    
1369 vapier 1.104 while ((fgets(path, __PAX_UTILS_PATH_MAX, fp)) != NULL) {
1370 solar 1.45 if ((p = strchr(path, '\n')) != NULL)
1371     *p = 0;
1372 vapier 1.66 search_path = path;
1373 solar 1.164 ret = scanelf_dir(path);
1374 solar 1.45 }
1375     if (fp != stdin)
1376     fclose(fp);
1377 solar 1.164 return ret;
1378 solar 1.45 }
1379    
1380 solar 1.154 #if defined(__GLIBC__) || defined(__UCLIBC__) || defined(__NetBSD__)
1381 vapier 1.148
1382     static int load_ld_cache_config(int i, const char *fname)
1383 vapier 1.48 {
1384     FILE *fp = NULL;
1385     char *p;
1386 vapier 1.104 char path[__PAX_UTILS_PATH_MAX];
1387 vapier 1.48
1388 vapier 1.149 if (i + 1 == ARRAY_SIZE(ldpaths))
1389 solar 1.123 return i;
1390    
1391     if ((fp = fopen(fname, "r")) == NULL)
1392     return i;
1393 vapier 1.48
1394 vapier 1.104 while ((fgets(path, __PAX_UTILS_PATH_MAX, fp)) != NULL) {
1395 vapier 1.48 if ((p = strrchr(path, '\r')) != NULL)
1396     *p = 0;
1397     if ((p = strchr(path, '\n')) != NULL)
1398     *p = 0;
1399 solar 1.154 #ifdef __linux__
1400 solar 1.123 // recursive includes of the same file will make this segfault.
1401 solar 1.129 if ((memcmp(path, "include", 7) == 0) && isblank(path[7])) {
1402 solar 1.123 glob64_t gl;
1403     size_t x;
1404     char gpath[__PAX_UTILS_PATH_MAX];
1405    
1406 solar 1.129 memset(gpath, 0, sizeof(gpath));
1407 solar 1.123
1408     if (path[8] != '/')
1409 solar 1.129 snprintf(gpath, sizeof(gpath), "/etc/%s", &path[8]);
1410 solar 1.123 else
1411 solar 1.129 strncpy(gpath, &path[8], sizeof(gpath));
1412 solar 1.123
1413     if ((glob64(gpath, 0, NULL, &gl)) == 0) {
1414     for (x = 0; x < gl.gl_pathc; ++x) {
1415     /* try to avoid direct loops */
1416     if (strcmp(gl.gl_pathv[x], fname) == 0)
1417     continue;
1418 vapier 1.148 i = load_ld_cache_config(i, gl.gl_pathv[x]);
1419 vapier 1.149 if (i + 1 >= ARRAY_SIZE(ldpaths)) {
1420 solar 1.123 globfree64(&gl);
1421     return i;
1422     }
1423     }
1424     globfree64 (&gl);
1425     continue;
1426 solar 1.160 }
1427 solar 1.123 }
1428 solar 1.154 #endif
1429 solar 1.123 if (*path != '/')
1430     continue;
1431 vapier 1.48
1432     ldpaths[i++] = xstrdup(path);
1433    
1434 vapier 1.149 if (i + 1 == ARRAY_SIZE(ldpaths))
1435 vapier 1.48 break;
1436     }
1437     ldpaths[i] = NULL;
1438    
1439     fclose(fp);
1440 solar 1.123 return i;
1441 vapier 1.48 }
1442 flameeyes 1.141
1443 vapier 1.148 #elif defined(__FreeBSD__) || (__DragonFly__)
1444    
1445     static int load_ld_cache_config(int i, const char *fname)
1446 flameeyes 1.141 {
1447     FILE *fp = NULL;
1448     char *b = NULL, *p;
1449     struct elfhints_hdr hdr;
1450 vapier 1.152
1451 vapier 1.149 if (i + 1 == ARRAY_SIZE(ldpaths))
1452 flameeyes 1.141 return i;
1453    
1454     if ((fp = fopen(fname, "r")) == NULL)
1455     return i;
1456    
1457 vapier 1.152 if (fread(&hdr, 1, sizeof(hdr), fp) != sizeof(hdr) ||
1458     hdr.magic != ELFHINTS_MAGIC || hdr.version != 1 ||
1459     fseek(fp, hdr.strtab + hdr.dirlist, SEEK_SET) == -1)
1460     {
1461 flameeyes 1.141 fclose(fp);
1462     return i;
1463     }
1464 vapier 1.152
1465 flameeyes 1.141 b = (char*)malloc(hdr.dirlistlen+1);
1466 vapier 1.152 if (fread(b, 1, hdr.dirlistlen+1, fp) != hdr.dirlistlen+1) {
1467 flameeyes 1.141 fclose(fp);
1468     free(b);
1469     return i;
1470     }
1471 vapier 1.152
1472     while ((p = strsep(&b, ":"))) {
1473     if (*p == '\0') continue;
1474 flameeyes 1.141 ldpaths[i++] = xstrdup(p);
1475 vapier 1.152
1476 vapier 1.149 if (i + 1 == ARRAY_SIZE(ldpaths))
1477 flameeyes 1.141 break;
1478     }
1479     ldpaths[i] = NULL;
1480 vapier 1.157
1481 flameeyes 1.141 free(b);
1482     fclose(fp);
1483     return i;
1484     }
1485 vapier 1.148
1486     #else
1487    
1488     #warning Cache config support not implemented for your target
1489     static int load_ld_cache_config(int i, const char *fname)
1490     {
1491     memset(ldpaths, 0x00, sizeof(ldpaths));
1492     }
1493    
1494 flameeyes 1.141 #endif
1495 vapier 1.48
1496 vapier 1.10 /* scan /etc/ld.so.conf for paths */
1497     static void scanelf_ldpath()
1498     {
1499 vapier 1.17 char scan_l, scan_ul, scan_ull;
1500 vapier 1.48 int i = 0;
1501 vapier 1.10
1502 vapier 1.48 if (!ldpaths[0])
1503     err("Unable to load any paths from ld.so.conf");
1504 vapier 1.10
1505 vapier 1.17 scan_l = scan_ul = scan_ull = 0;
1506    
1507 vapier 1.48 while (ldpaths[i]) {
1508     if (!scan_l && !strcmp(ldpaths[i], "/lib")) scan_l = 1;
1509     if (!scan_ul && !strcmp(ldpaths[i], "/usr/lib")) scan_ul = 1;
1510     if (!scan_ull && !strcmp(ldpaths[i], "/usr/local/lib")) scan_ull = 1;
1511     scanelf_dir(ldpaths[i]);
1512     ++i;
1513     }
1514 vapier 1.10
1515 vapier 1.17 if (!scan_l) scanelf_dir("/lib");
1516     if (!scan_ul) scanelf_dir("/usr/lib");
1517     if (!scan_ull) scanelf_dir("/usr/local/lib");
1518 vapier 1.10 }
1519 solar 1.1
1520 vapier 1.10 /* scan env PATH for paths */
1521     static void scanelf_envpath()
1522 solar 1.1 {
1523 solar 1.34 char *path, *p;
1524 vapier 1.10
1525     path = getenv("PATH");
1526     if (!path)
1527     err("PATH is not set in your env !");
1528 vapier 1.41 path = xstrdup(path);
1529 vapier 1.10
1530     while ((p = strrchr(path, ':')) != NULL) {
1531     scanelf_dir(p + 1);
1532     *p = 0;
1533     }
1534 vapier 1.17
1535 solar 1.34 free(path);
1536 solar 1.1 }
1537    
1538 vapier 1.10 /* usage / invocation handling functions */
1539 solar 1.127 #define PARSE_FLAGS "plRmyAXz:xetrnLibSs:k:gN:TaqvF:f:o:E:M:BhV"
1540 vapier 1.27 #define a_argument required_argument
1541 vapier 1.10 static struct option const long_opts[] = {
1542     {"path", no_argument, NULL, 'p'},
1543     {"ldpath", no_argument, NULL, 'l'},
1544     {"recursive", no_argument, NULL, 'R'},
1545 vapier 1.14 {"mount", no_argument, NULL, 'm'},
1546 vapier 1.37 {"symlink", no_argument, NULL, 'y'},
1547 vapier 1.105 {"archives", no_argument, NULL, 'A'},
1548     {"ldcache", no_argument, NULL, 'L'},
1549 vapier 1.101 {"fix", no_argument, NULL, 'X'},
1550 solar 1.127 {"setpax", a_argument, NULL, 'z'},
1551 vapier 1.10 {"pax", no_argument, NULL, 'x'},
1552 solar 1.16 {"header", no_argument, NULL, 'e'},
1553 vapier 1.10 {"textrel", no_argument, NULL, 't'},
1554     {"rpath", no_argument, NULL, 'r'},
1555 vapier 1.32 {"needed", no_argument, NULL, 'n'},
1556 vapier 1.38 {"interp", no_argument, NULL, 'i'},
1557 vapier 1.49 {"bind", no_argument, NULL, 'b'},
1558 vapier 1.84 {"soname", no_argument, NULL, 'S'},
1559 vapier 1.76 {"symbol", a_argument, NULL, 's'},
1560 solar 1.124 {"section", a_argument, NULL, 'k'},
1561 vapier 1.76 {"lib", a_argument, NULL, 'N'},
1562 solar 1.86 {"gmatch", no_argument, NULL, 'g'},
1563 vapier 1.76 {"textrels", no_argument, NULL, 'T'},
1564 solar 1.119 {"etype", a_argument, NULL, 'E'},
1565 solar 1.120 {"bits", a_argument, NULL, 'M'},
1566 vapier 1.10 {"all", no_argument, NULL, 'a'},
1567     {"quiet", no_argument, NULL, 'q'},
1568 vapier 1.14 {"verbose", no_argument, NULL, 'v'},
1569 vapier 1.76 {"format", a_argument, NULL, 'F'},
1570     {"from", a_argument, NULL, 'f'},
1571     {"file", a_argument, NULL, 'o'},
1572 solar 1.16 {"nobanner", no_argument, NULL, 'B'},
1573 vapier 1.10 {"help", no_argument, NULL, 'h'},
1574     {"version", no_argument, NULL, 'V'},
1575     {NULL, no_argument, NULL, 0x0}
1576     };
1577 solar 1.57
1578 solar 1.68 static const char *opts_help[] = {
1579 vapier 1.10 "Scan all directories in PATH environment",
1580     "Scan all directories in /etc/ld.so.conf",
1581 vapier 1.14 "Scan directories recursively",
1582 vapier 1.37 "Don't recursively cross mount points",
1583 vapier 1.101 "Don't scan symlinks",
1584 vapier 1.105 "Scan archives (.a files)",
1585     "Utilize ld.so.cache information (use with -r/-n)",
1586 solar 1.127 "Try and 'fix' bad things (use with -r/-e)",
1587     "Sets EI_PAX/PT_PAX_FLAGS to <arg> (use with -Xx)\n",
1588 vapier 1.10 "Print PaX markings",
1589 vapier 1.71 "Print GNU_STACK/PT_LOAD markings",
1590 vapier 1.10 "Print TEXTREL information",
1591     "Print RPATH information",
1592 vapier 1.32 "Print NEEDED information",
1593 vapier 1.38 "Print INTERP information",
1594 vapier 1.49 "Print BIND information",
1595 vapier 1.84 "Print SONAME information",
1596 vapier 1.27 "Find a specified symbol",
1597 solar 1.124 "Find a specified section",
1598 vapier 1.72 "Find a specified library",
1599 solar 1.86 "Use strncmp to match libraries. (use with -N)",
1600 vapier 1.76 "Locate cause of TEXTREL",
1601 solar 1.129 "Print only ELF files matching etype ET_DYN,ET_EXEC ...",
1602 solar 1.120 "Print only ELF files matching numeric bits",
1603 vapier 1.82 "Print all scanned info (-x -e -t -r -b)\n",
1604 vapier 1.14 "Only output 'bad' things",
1605     "Be verbose (can be specified more than once)",
1606 vapier 1.39 "Use specified format for output",
1607 solar 1.45 "Read input stream from a filename",
1608 vapier 1.24 "Write output stream to a filename",
1609 vapier 1.14 "Don't display the header",
1610 vapier 1.10 "Print this help and exit",
1611     "Print version and exit",
1612     NULL
1613     };
1614    
1615     /* display usage and exit */
1616     static void usage(int status)
1617 solar 1.1 {
1618 vapier 1.44 unsigned long i;
1619 solar 1.52 printf("* Scan ELF binaries for stuff\n\n"
1620 vapier 1.105 "Usage: %s [options] <dir1/file1> [dir2 dirN file2 fileN ...]\n\n", argv0);
1621 solar 1.35 printf("Options: -[%s]\n", PARSE_FLAGS);
1622 vapier 1.10 for (i = 0; long_opts[i].name; ++i)
1623 vapier 1.27 if (long_opts[i].has_arg == no_argument)
1624 vapier 1.157 printf(" -%c, --%-14s* %s\n", long_opts[i].val,
1625 vapier 1.27 long_opts[i].name, opts_help[i]);
1626     else
1627 solar 1.124 printf(" -%c, --%-7s <arg> * %s\n", long_opts[i].val,
1628 vapier 1.27 long_opts[i].name, opts_help[i]);
1629 solar 1.45
1630 vapier 1.173 puts("\nFor more information, see the scanelf(1) manpage");
1631 vapier 1.10 exit(status);
1632 solar 1.1 }
1633    
1634     /* parse command line arguments and preform needed actions */
1635 vapier 1.165 #define do_pax_state(option, flag) \
1636     if (islower(option)) { \
1637     flags &= ~PF_##flag; \
1638     flags |= PF_NO##flag; \
1639     } else { \
1640     flags &= ~PF_NO##flag; \
1641     flags |= PF_##flag; \
1642     }
1643 solar 1.164 static int parseargs(int argc, char *argv[])
1644 vapier 1.10 {
1645 vapier 1.48 int i;
1646 vapier 1.133 const char *from_file = NULL;
1647 solar 1.164 int ret = 0;
1648 vapier 1.10
1649     opterr = 0;
1650 vapier 1.48 while ((i=getopt_long(argc, argv, PARSE_FLAGS, long_opts, NULL)) != -1) {
1651     switch (i) {
1652 vapier 1.10
1653 vapier 1.39 case 'V':
1654 vapier 1.80 printf("pax-utils-%s: %s compiled %s\n%s\n"
1655     "%s written for Gentoo by <solar and vapier @ gentoo.org>\n",
1656     VERSION, __FILE__, __DATE__, rcsid, argv0);
1657 vapier 1.10 exit(EXIT_SUCCESS);
1658     break;
1659     case 'h': usage(EXIT_SUCCESS); break;
1660 solar 1.45 case 'f':
1661 vapier 1.100 if (from_file) warn("You prob don't want to specify -f twice");
1662     from_file = optarg;
1663 solar 1.45 break;
1664 solar 1.119 case 'E':
1665     strncpy(match_etypes, optarg, sizeof(match_etypes));
1666     break;
1667 solar 1.120 case 'M':
1668     match_bits = atoi(optarg);
1669     break;
1670 vapier 1.24 case 'o': {
1671 vapier 1.146 if (freopen(optarg, "w", stdout) == NULL)
1672 vapier 1.24 err("Could not open output stream '%s': %s", optarg, strerror(errno));
1673 solar 1.21 break;
1674     }
1675 solar 1.124 case 'k':
1676 vapier 1.126 if (find_section) warn("You prob don't want to specify -k twice");
1677 solar 1.124 find_section = optarg;
1678     break;
1679 vapier 1.39 case 's': {
1680 vapier 1.93 if (find_sym) warn("You prob don't want to specify -s twice");
1681     find_sym = optarg;
1682     versioned_symname = (char*)xmalloc(sizeof(char) * (strlen(find_sym)+1+1));
1683 vapier 1.39 sprintf(versioned_symname, "%s@", find_sym);
1684     break;
1685     }
1686 vapier 1.72 case 'N': {
1687 vapier 1.93 if (find_lib) warn("You prob don't want to specify -N twice");
1688     find_lib = optarg;
1689 vapier 1.72 break;
1690     }
1691 vapier 1.39
1692     case 'F': {
1693 vapier 1.93 if (out_format) warn("You prob don't want to specify -F twice");
1694     out_format = optarg;
1695 vapier 1.39 break;
1696     }
1697 solar 1.127 case 'z': {
1698 solar 1.129 unsigned long flags = (PF_NOEMUTRAMP | PF_NORANDEXEC);
1699 solar 1.127 size_t x;
1700 vapier 1.27
1701 solar 1.127 for (x = 0 ; x < strlen(optarg); x++) {
1702     switch(optarg[x]) {
1703     case 'p':
1704     case 'P':
1705 vapier 1.165 do_pax_state(optarg[x], PAGEEXEC);
1706 solar 1.127 break;
1707     case 's':
1708     case 'S':
1709 vapier 1.165 do_pax_state(optarg[x], SEGMEXEC);
1710 solar 1.127 break;
1711     case 'm':
1712     case 'M':
1713 vapier 1.165 do_pax_state(optarg[x], MPROTECT);
1714 solar 1.127 break;
1715     case 'e':
1716     case 'E':
1717 vapier 1.165 do_pax_state(optarg[x], EMUTRAMP);
1718 solar 1.127 break;
1719     case 'r':
1720     case 'R':
1721 vapier 1.165 do_pax_state(optarg[x], RANDMMAP);
1722 solar 1.127 break;
1723     case 'x':
1724     case 'X':
1725 vapier 1.165 do_pax_state(optarg[x], RANDEXEC);
1726 solar 1.127 break;
1727     default:
1728     break;
1729     }
1730     }
1731     if (!(((flags & PF_PAGEEXEC) && (flags & PF_NOPAGEEXEC)) ||
1732     ((flags & PF_SEGMEXEC) && (flags & PF_NOSEGMEXEC)) ||
1733     ((flags & PF_RANDMMAP) && (flags & PF_NORANDMMAP)) ||
1734     ((flags & PF_RANDEXEC) && (flags & PF_NORANDEXEC)) ||
1735     ((flags & PF_EMUTRAMP) && (flags & PF_NOEMUTRAMP)) ||
1736     ((flags & PF_RANDMMAP) && (flags & PF_NORANDMMAP))))
1737     setpax = flags;
1738     break;
1739     }
1740 vapier 1.122 case 'g': gmatch = 1; break;
1741 vapier 1.102 case 'L': use_ldcache = 1; break;
1742 vapier 1.37 case 'y': scan_symlink = 0; break;
1743 vapier 1.105 case 'A': scan_archives = 1; break;
1744 solar 1.16 case 'B': show_banner = 0; break;
1745 vapier 1.10 case 'l': scan_ldpath = 1; break;
1746     case 'p': scan_envpath = 1; break;
1747     case 'R': dir_recurse = 1; break;
1748 vapier 1.14 case 'm': dir_crossmount = 0; break;
1749 vapier 1.101 case 'X': ++fix_elf; break;
1750 vapier 1.10 case 'x': show_pax = 1; break;
1751 solar 1.73 case 'e': show_phdr = 1; break;
1752 vapier 1.10 case 't': show_textrel = 1; break;
1753     case 'r': show_rpath = 1; break;
1754 vapier 1.32 case 'n': show_needed = 1; break;
1755 vapier 1.38 case 'i': show_interp = 1; break;
1756 vapier 1.49 case 'b': show_bind = 1; break;
1757 vapier 1.84 case 'S': show_soname = 1; break;
1758 vapier 1.76 case 'T': show_textrels = 1; break;
1759 vapier 1.10 case 'q': be_quiet = 1; break;
1760 vapier 1.14 case 'v': be_verbose = (be_verbose % 20) + 1; break;
1761 vapier 1.82 case 'a': show_pax = show_phdr = show_textrel = show_rpath = show_bind = 1; break;
1762 vapier 1.10
1763     case ':':
1764 vapier 1.113 err("Option '%c' is missing parameter", optopt);
1765 vapier 1.10 case '?':
1766 solar 1.119 err("Unknown option '%c' or argument missing", optopt);
1767 vapier 1.10 default:
1768 vapier 1.113 err("Unhandled option '%c'; please report this", i);
1769 vapier 1.10 }
1770     }
1771 solar 1.170 if (show_textrels && be_verbose) {
1772     if (which("objdump") != NULL)
1773     has_objdump = 1;
1774     }
1775 vapier 1.39 /* let the format option override all other options */
1776     if (out_format) {
1777 solar 1.73 show_pax = show_phdr = show_textrel = show_rpath = \
1778 vapier 1.84 show_needed = show_interp = show_bind = show_soname = \
1779     show_textrels = 0;
1780 vapier 1.48 for (i = 0; out_format[i]; ++i) {
1781 vapier 1.70 if (!IS_MODIFIER(out_format[i])) continue;
1782 vapier 1.39
1783 vapier 1.48 switch (out_format[++i]) {
1784 solar 1.132 case '+': break;
1785 vapier 1.39 case '%': break;
1786 vapier 1.70 case '#': break;
1787 vapier 1.39 case 'F': break;
1788 vapier 1.66 case 'p': break;
1789     case 'f': break;
1790 solar 1.124 case 'k': break;
1791 vapier 1.39 case 's': break;
1792 vapier 1.72 case 'N': break;
1793 vapier 1.41 case 'o': break;
1794 vapier 1.166 case 'a': break;
1795 vapier 1.171 case 'M': break;
1796 vapier 1.39 case 'x': show_pax = 1; break;
1797 solar 1.73 case 'e': show_phdr = 1; break;
1798 vapier 1.39 case 't': show_textrel = 1; break;
1799     case 'r': show_rpath = 1; break;
1800     case 'n': show_needed = 1; break;
1801     case 'i': show_interp = 1; break;
1802 vapier 1.49 case 'b': show_bind = 1; break;
1803 vapier 1.84 case 'S': show_soname = 1; break;
1804 vapier 1.76 case 'T': show_textrels = 1; break;
1805 vapier 1.39 default:
1806 vapier 1.162 err("Invalid format specifier '%c' (byte %i)",
1807 vapier 1.48 out_format[i], i+1);
1808 vapier 1.39 }
1809     }
1810 vapier 1.41
1811     /* construct our default format */
1812     } else {
1813     size_t fmt_len = 30;
1814     out_format = (char*)xmalloc(sizeof(char) * fmt_len);
1815 vapier 1.76 if (!be_quiet) xstrcat(&out_format, "%o ", &fmt_len);
1816     if (show_pax) xstrcat(&out_format, "%x ", &fmt_len);
1817     if (show_phdr) xstrcat(&out_format, "%e ", &fmt_len);
1818     if (show_textrel) xstrcat(&out_format, "%t ", &fmt_len);
1819     if (show_rpath) xstrcat(&out_format, "%r ", &fmt_len);
1820     if (show_needed) xstrcat(&out_format, "%n ", &fmt_len);
1821     if (show_interp) xstrcat(&out_format, "%i ", &fmt_len);
1822     if (show_bind) xstrcat(&out_format, "%b ", &fmt_len);
1823 vapier 1.84 if (show_soname) xstrcat(&out_format, "%S ", &fmt_len);
1824 vapier 1.76 if (show_textrels) xstrcat(&out_format, "%T ", &fmt_len);
1825     if (find_sym) xstrcat(&out_format, "%s ", &fmt_len);
1826 solar 1.124 if (find_section) xstrcat(&out_format, "%k ", &fmt_len);
1827 vapier 1.76 if (find_lib) xstrcat(&out_format, "%N ", &fmt_len);
1828     if (!be_quiet) xstrcat(&out_format, "%F ", &fmt_len);
1829 vapier 1.39 }
1830 vapier 1.41 if (be_verbose > 2) printf("Format: %s\n", out_format);
1831 vapier 1.39
1832     /* now lets actually do the scanning */
1833 vapier 1.102 if (scan_ldpath || use_ldcache)
1834 vapier 1.148 load_ld_cache_config(0, __PAX_UTILS_DEFAULT_LD_CACHE_CONFIG);
1835 vapier 1.10 if (scan_ldpath) scanelf_ldpath();
1836     if (scan_envpath) scanelf_envpath();
1837 solar 1.153 if (!from_file && optind == argc && ttyname(0) == NULL && !scan_ldpath && !scan_envpath)
1838 vapier 1.133 from_file = "-";
1839 solar 1.45 if (from_file) {
1840     scanelf_from_file(from_file);
1841     from_file = *argv;
1842     }
1843     if (optind == argc && !scan_ldpath && !scan_envpath && !from_file)
1844 vapier 1.25 err("Nothing to scan !?");
1845 vapier 1.66 while (optind < argc) {
1846     search_path = argv[optind++];
1847 solar 1.164 ret = scanelf_dir(search_path);
1848 vapier 1.66 }
1849 vapier 1.27
1850 vapier 1.39 /* clean up */
1851 vapier 1.152 free(versioned_symname);
1852 vapier 1.48 for (i = 0; ldpaths[i]; ++i)
1853     free(ldpaths[i]);
1854 solar 1.96
1855     if (ldcache != 0)
1856     munmap(ldcache, ldcache_size);
1857 solar 1.164 return ret;
1858 vapier 1.10 }
1859    
1860 vapier 1.150 static char **get_split_env(const char *envvar)
1861     {
1862 vapier 1.152 const char *delims = " \t\n";
1863 solar 1.143 char **envvals = NULL;
1864 vapier 1.152 char *env, *s;
1865 kevquinn 1.142 int nentry;
1866    
1867 solar 1.143 if ((env = getenv(envvar)) == NULL)
1868     return NULL;
1869 kevquinn 1.142
1870 solar 1.143 env = xstrdup(env);
1871     if (env == NULL)
1872     return NULL;
1873 kevquinn 1.142
1874 vapier 1.152 s = strtok(env, delims);
1875     if (s == NULL) {
1876     free(env);
1877     return NULL;
1878     }
1879    
1880 solar 1.143 nentry = 0;
1881 vapier 1.152 while (s != NULL) {
1882     ++nentry;
1883     envvals = xrealloc(envvals, sizeof(*envvals) * (nentry+1));
1884     envvals[nentry-1] = s;
1885     s = strtok(NULL, delims);
1886 kevquinn 1.142 }
1887 vapier 1.152 envvals[nentry] = NULL;
1888 kevquinn 1.142
1889 vapier 1.152 /* don't want to free(env) as it contains the memory that backs
1890     * the envvals array of strings */
1891 kevquinn 1.142 return envvals;
1892     }
1893 vapier 1.150 static void parseenv()
1894     {
1895     qa_textrels = get_split_env("QA_TEXTRELS");
1896     qa_execstack = get_split_env("QA_EXECSTACK");
1897     qa_wx_load = get_split_env("QA_WX_LOAD");
1898 vapier 1.41 }
1899 solar 1.163
1900 vapier 1.152 #ifdef __PAX_UTILS_CLEANUP
1901     static void cleanup()
1902     {
1903     free(out_format);
1904     free(qa_textrels);
1905     free(qa_execstack);
1906     free(qa_wx_load);
1907     }
1908     #endif
1909 vapier 1.41
1910    
1911 vapier 1.10 int main(int argc, char *argv[])
1912 solar 1.1 {
1913 solar 1.164 int ret;
1914 vapier 1.10 if (argc < 2)
1915     usage(EXIT_FAILURE);
1916 kevquinn 1.142 parseenv();
1917 solar 1.164 ret = parseargs(argc, argv);
1918 solar 1.21 fclose(stdout);
1919 vapier 1.152 #ifdef __PAX_UTILS_CLEANUP
1920     cleanup();
1921     warn("The calls to add/delete heap should be off:\n"
1922     "\t- 1 due to the out_buffer not being freed in scanelf_file()\n"
1923     "\t- 1 per QA_TEXTRELS/QA_EXECSTACK/QA_WX_LOAD");
1924 solar 1.61 #endif
1925 solar 1.164 return ret;
1926 solar 1.1 }
1927 vapier 1.155
1928    
1929    
1930     /* utility funcs */
1931     static char *xstrdup(const char *s)
1932     {
1933     char *ret = strdup(s);
1934     if (!ret) err("Could not strdup(): %s", strerror(errno));
1935     return ret;
1936     }
1937     static void *xmalloc(size_t size)
1938     {
1939     void *ret = malloc(size);
1940     if (!ret) err("Could not malloc() %li bytes", (unsigned long)size);
1941     return ret;
1942     }
1943     static void *xrealloc(void *ptr, size_t size)
1944     {
1945     void *ret = realloc(ptr, size);
1946     if (!ret) err("Could not realloc() %li bytes", (unsigned long)size);
1947     return ret;
1948     }
1949     static void xstrncat(char **dst, const char *src, size_t *curr_len, size_t n)
1950     {
1951     size_t new_len;
1952    
1953     new_len = strlen(*dst) + strlen(src);
1954     if (*curr_len <= new_len) {
1955     *curr_len = new_len + (*curr_len / 2);
1956     *dst = realloc(*dst, *curr_len);
1957     if (!*dst)
1958     err("could not realloc() %li bytes", (unsigned long)*curr_len);
1959     }
1960    
1961     if (n)
1962     strncat(*dst, src, n);
1963     else
1964     strcat(*dst, src);
1965     }
1966     static inline void xchrcat(char **dst, const char append, size_t *curr_len)
1967     {
1968     static char my_app[2];
1969     my_app[0] = append;
1970     my_app[1] = '\0';
1971     xstrcat(dst, my_app, curr_len);
1972     }
1973    
1974     /* Match filename against entries in matchlist, return TRUE
1975     * if the file is listed */
1976     static int file_matches_list(const char *filename, char **matchlist)
1977     {
1978     char **file;
1979     char *match;
1980     char buf[__PAX_UTILS_PATH_MAX];
1981    
1982     if (matchlist == NULL)
1983     return 0;
1984    
1985     for (file = matchlist; *file != NULL; file++) {
1986     if (search_path) {
1987     snprintf(buf, sizeof(buf), "%s%s", search_path, *file);
1988     match = buf;
1989     } else {
1990     match = *file;
1991     }
1992     if (fnmatch(match, filename, 0) == 0)
1993     return 1;
1994     }
1995     return 0;
1996     }

  ViewVC Help
Powered by ViewVC 1.1.20