/[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.43 Revision 1.60
1/* 1/*
2 * Copyright 2003 Ned Ludd <solar@gentoo.org> 2 * Copyright 2003 Ned Ludd <solar@gentoo.org>
3 * Copyright 1999-2005 Gentoo Foundation 3 * Copyright 1999-2005 Gentoo Foundation
4 * Distributed under the terms of the GNU General Public License v2 4 * Distributed under the terms of the GNU General Public License v2
5 * $Header: /var/cvsroot/gentoo-projects/pax-utils/Attic/scanelf.c,v 1.43 2005/05/06 02:55:27 vapier Exp $ 5 * $Header: /var/cvsroot/gentoo-projects/pax-utils/Attic/scanelf.c,v 1.60 2005/05/27 02:58:39 vapier Exp $
6 * 6 *
7 ******************************************************************** 7 ********************************************************************
8 * This program is free software; you can redistribute it and/or 8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License as 9 * modify it under the terms of the GNU General Public License as
10 * published by the Free Software Foundation; either version 2 of the 10 * published by the Free Software Foundation; either version 2 of the
22 */ 22 */
23 23
24#include <stdio.h> 24#include <stdio.h>
25#include <stdlib.h> 25#include <stdlib.h>
26#include <sys/types.h> 26#include <sys/types.h>
27#include <libgen.h>
28#include <limits.h>
27#define __USE_GNU 29#define __USE_GNU
28#include <string.h> 30#include <string.h>
29#include <errno.h> 31#include <errno.h>
30#include <unistd.h> 32#include <unistd.h>
31#include <sys/stat.h> 33#include <sys/stat.h>
33#include <getopt.h> 35#include <getopt.h>
34#include <assert.h> 36#include <assert.h>
35 37
36#include "paxelf.h" 38#include "paxelf.h"
37 39
38static const char *rcsid = "$Id: scanelf.c,v 1.43 2005/05/06 02:55:27 vapier Exp $"; 40static const char *rcsid = "$Id: scanelf.c,v 1.60 2005/05/27 02:58:39 vapier Exp $";
39#define argv0 "scanelf" 41#define argv0 "scanelf"
40 42
41 43
42 44
43/* prototypes */ 45/* prototypes */
45static void scanelf_dir(const char *path); 47static void scanelf_dir(const char *path);
46static void scanelf_ldpath(); 48static void scanelf_ldpath();
47static void scanelf_envpath(); 49static void scanelf_envpath();
48static void usage(int status); 50static void usage(int status);
49static void parseargs(int argc, char *argv[]); 51static void parseargs(int argc, char *argv[]);
50static char *xstrdup(char *s); 52static char *xstrdup(const char *s);
51static void *xmalloc(size_t size); 53static void *xmalloc(size_t size);
52static void xstrcat(char **dst, const char *src, size_t *curr_len); 54static void xstrcat(char **dst, const char *src, size_t *curr_len);
53static inline void xchrcat(char **dst, const char append, size_t *curr_len); 55static inline void xchrcat(char **dst, const char append, size_t *curr_len);
54static int xemptybuffer(const char *buff);
55 56
56/* variables to control behavior */ 57/* variables to control behavior */
58static char *ldpaths[256];
57static char scan_ldpath = 0; 59static char scan_ldpath = 0;
58static char scan_envpath = 0; 60static char scan_envpath = 0;
59static char scan_symlink = 1; 61static char scan_symlink = 1;
60static char dir_recurse = 0; 62static char dir_recurse = 0;
61static char dir_crossmount = 1; 63static char dir_crossmount = 1;
63static char show_stack = 0; 65static char show_stack = 0;
64static char show_textrel = 0; 66static char show_textrel = 0;
65static char show_rpath = 0; 67static char show_rpath = 0;
66static char show_needed = 0; 68static char show_needed = 0;
67static char show_interp = 0; 69static char show_interp = 0;
70static char show_bind = 0;
68static char show_banner = 1; 71static char show_banner = 1;
69static char be_quiet = 0; 72static char be_quiet = 0;
70static char be_verbose = 0; 73static char be_verbose = 0;
71static char *find_sym = NULL, *versioned_symname = NULL; 74static char *find_sym = NULL, *versioned_symname = NULL;
72static char *out_format = NULL; 75static char *out_format = NULL;
88 91
89 return NULL; 92 return NULL;
90} 93}
91static char *scanelf_file_stack(elfobj *elf, char *found_stack, char *found_relro) 94static char *scanelf_file_stack(elfobj *elf, char *found_stack, char *found_relro)
92{ 95{
93 static char ret[8]; 96 static char ret[8] = "--- ---";
94 char *found; 97 char *found;
95 int i, off, shown; 98 unsigned long i, off, shown;
96 99
97 if (!show_stack) return NULL; 100 if (!show_stack) return NULL;
98 101
99 shown = 0; 102 shown = 0;
100 strcpy(ret, "--- ---"); 103
104 if (elf->phdr) {
101#define SHOW_STACK(B) \ 105#define SHOW_STACK(B) \
102 if (elf->elf_class == ELFCLASS ## B) { \ 106 if (elf->elf_class == ELFCLASS ## B) { \
103 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \ 107 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \
104 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \ 108 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \
105 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \ 109 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \
106 if (EGET(phdr[i].p_type) == PT_GNU_STACK) { \ 110 if (EGET(phdr[i].p_type) == PT_GNU_STACK) { \
107 found = found_stack; \ 111 found = found_stack; \
108 off = 0; \ 112 off = 0; \
109 } else if (EGET(phdr[i].p_type) == PT_GNU_RELRO) { \ 113 } else if (EGET(phdr[i].p_type) == PT_GNU_RELRO) { \
110 found = found_relro; \ 114 found = found_relro; \
111 off = 3; \ 115 off = 4; \
112 } else \ 116 } else \
113 continue; \ 117 continue; \
114 if (be_quiet && !(EGET(phdr[i].p_flags) & PF_X)) \ 118 if (be_quiet && !(EGET(phdr[i].p_flags) & PF_X)) \
115 continue; \ 119 continue; \
116 memcpy(ret+off, gnu_short_stack_flags(EGET(phdr[i].p_flags)), 3); \ 120 memcpy(ret+off, gnu_short_stack_flags(EGET(phdr[i].p_flags)), 3); \
118 ++shown; \ 122 ++shown; \
119 } \ 123 } \
120 } 124 }
121 SHOW_STACK(32) 125 SHOW_STACK(32)
122 SHOW_STACK(64) 126 SHOW_STACK(64)
127 }
128
123 if (be_quiet && !shown) 129 if (be_quiet && !shown)
124 return NULL; 130 return NULL;
125 else 131 else
126 return ret; 132 return ret;
127} 133}
128static char *scanelf_file_textrel(elfobj *elf, char *found_textrel) 134static char *scanelf_file_textrel(elfobj *elf, char *found_textrel)
129{ 135{
130 static char *ret = "TEXTREL"; 136 static char *ret = "TEXTREL";
131 int i; 137 unsigned long i;
132 138
133 if (!show_textrel) return NULL; 139 if (!show_textrel) return NULL;
134 140
141 if (elf->phdr) {
135#define SHOW_TEXTREL(B) \ 142#define SHOW_TEXTREL(B) \
136 if (elf->elf_class == ELFCLASS ## B) { \ 143 if (elf->elf_class == ELFCLASS ## B) { \
137 Elf ## B ## _Dyn *dyn; \ 144 Elf ## B ## _Dyn *dyn; \
138 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \ 145 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \
139 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \ 146 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \
147 Elf ## B ## _Off offset; \
140 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \ 148 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \
141 if (phdr[i].p_type != PT_DYNAMIC) continue; \ 149 if (EGET(phdr[i].p_type) != PT_DYNAMIC) continue; \
150 offset = EGET(phdr[i].p_offset); \
151 if (offset >= elf->len - sizeof(Elf ## B ## _Dyn)) continue; \
142 dyn = DYN ## B (elf->data + EGET(phdr[i].p_offset)); \ 152 dyn = DYN ## B (elf->data + offset); \
143 while (EGET(dyn->d_tag) != DT_NULL) { \ 153 while (EGET(dyn->d_tag) != DT_NULL) { \
144 if (EGET(dyn->d_tag) == DT_TEXTREL) { /*dyn->d_tag != DT_FLAGS)*/ \ 154 if (EGET(dyn->d_tag) == DT_TEXTREL) { /*dyn->d_tag != DT_FLAGS)*/ \
145 *found_textrel = 1; \ 155 *found_textrel = 1; \
146 /*if (dyn->d_un.d_val & DF_TEXTREL)*/ \ 156 /*if (dyn->d_un.d_val & DF_TEXTREL)*/ \
147 return ret; \ 157 return ret; \
149 ++dyn; \ 159 ++dyn; \
150 } \ 160 } \
151 } } 161 } }
152 SHOW_TEXTREL(32) 162 SHOW_TEXTREL(32)
153 SHOW_TEXTREL(64) 163 SHOW_TEXTREL(64)
164 }
165
154 if (be_quiet) 166 if (be_quiet)
155 return NULL; 167 return NULL;
156 else 168 else
157 return " - "; 169 return " - ";
158} 170}
159static void scanelf_file_rpath(elfobj *elf, char *found_rpath, char **ret, size_t *ret_len) 171static void scanelf_file_rpath(elfobj *elf, char *found_rpath, char **ret, size_t *ret_len)
160{ 172{
161 /* TODO: if be_quiet, only output RPATH's which aren't in /etc/ld.so.conf */ 173 /* TODO: when checking RPATH entries, check each subpath (between :) in ld.so.conf */
162 int i; 174 unsigned long i, s;
163 char *rpath, *runpath; 175 char *rpath, *runpath, **r;
164 void *strtbl_void; 176 void *strtbl_void;
165 177
166 if (!show_rpath) return; 178 if (!show_rpath) return;
167 179
168 strtbl_void = elf_findsecbyname(elf, ".dynstr"); 180 strtbl_void = elf_findsecbyname(elf, ".dynstr");
169 rpath = runpath = NULL; 181 rpath = runpath = NULL;
170 182
171 if (strtbl_void) { 183 if (elf->phdr && strtbl_void) {
172#define SHOW_RPATH(B) \ 184#define SHOW_RPATH(B) \
173 if (elf->elf_class == ELFCLASS ## B) { \ 185 if (elf->elf_class == ELFCLASS ## B) { \
174 Elf ## B ## _Dyn *dyn; \ 186 Elf ## B ## _Dyn *dyn; \
175 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \ 187 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \
176 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \ 188 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \
177 Elf ## B ## _Shdr *strtbl = SHDR ## B (strtbl_void); \ 189 Elf ## B ## _Shdr *strtbl = SHDR ## B (strtbl_void); \
190 Elf ## B ## _Off offset; \
191 Elf ## B ## _Xword word; \
192 /* Scan all the program headers */ \
178 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \ 193 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \
194 /* Just scan dynamic headers */ \
179 if (EGET(phdr[i].p_type) != PT_DYNAMIC) continue; \ 195 if (EGET(phdr[i].p_type) != PT_DYNAMIC) continue; \
196 offset = EGET(phdr[i].p_offset); \
197 if (offset >= elf->len - sizeof(Elf ## B ## _Dyn)) continue; \
198 /* Just scan dynamic RPATH/RUNPATH headers */ \
180 dyn = DYN ## B (elf->data + EGET(phdr[i].p_offset)); \ 199 dyn = DYN ## B (elf->data + offset); \
181 while (EGET(dyn->d_tag) != DT_NULL) { \ 200 while ((word=EGET(dyn->d_tag)) != DT_NULL) { \
182 if (EGET(dyn->d_tag) == DT_RPATH) { \ 201 if (word == DT_RPATH) { \
183 if (rpath) warn("ELF has multiple DT_RPATH's !?"); \ 202 r = &rpath; \
203 } else if (word == DT_RUNPATH) { \
204 r = &runpath; \
205 } else { \
206 ++dyn; \
207 continue; \
208 } \
209 /* Verify the memory is somewhat sane */ \
184 rpath = elf->data + EGET(strtbl->sh_offset) + EGET(dyn->d_un.d_ptr); \ 210 offset = EGET(strtbl->sh_offset) + EGET(dyn->d_un.d_ptr); \
211 if (offset < elf->len) { \
212 if (*r) warn("ELF has multiple %s's !?", get_elfdtype(word)); \
213 *r = (char*)(elf->data + offset); \
214 /* If quiet, don't output paths in ld.so.conf */ \
215 if (be_quiet) \
216 for (s = 0; ldpaths[s]; ++s) \
217 if (!strcmp(ldpaths[s], *r)) { \
218 *r = NULL; \
219 break; \
220 } \
185 *found_rpath = 1; \ 221 if (*r) *found_rpath = 1; \
186 } else if (EGET(dyn->d_tag) == DT_RUNPATH) { \
187 if (runpath) warn("ELF has multiple DT_RUNPATH's !?"); \
188 runpath = elf->data + EGET(strtbl->sh_offset) + EGET(dyn->d_un.d_ptr); \
189 *found_rpath = 1; \
190 } \ 222 } \
191 ++dyn; \ 223 ++dyn; \
192 } \ 224 } \
193 } } 225 } }
194 SHOW_RPATH(32) 226 SHOW_RPATH(32)
211 else if (!be_quiet) 243 else if (!be_quiet)
212 xstrcat(ret, " - ", ret_len); 244 xstrcat(ret, " - ", ret_len);
213} 245}
214static void scanelf_file_needed(elfobj *elf, char *found_needed, char **ret, size_t *ret_len) 246static void scanelf_file_needed(elfobj *elf, char *found_needed, char **ret, size_t *ret_len)
215{ 247{
216 int i; 248 unsigned long i;
217 char *needed; 249 char *needed;
218 void *strtbl_void; 250 void *strtbl_void;
219 251
220 if (!show_needed) return; 252 if (!show_needed) return;
221 253
222 strtbl_void = elf_findsecbyname(elf, ".dynstr"); 254 strtbl_void = elf_findsecbyname(elf, ".dynstr");
223 255
224 if (strtbl_void) { 256 if (elf->phdr && strtbl_void) {
225#define SHOW_NEEDED(B) \ 257#define SHOW_NEEDED(B) \
226 if (elf->elf_class == ELFCLASS ## B) { \ 258 if (elf->elf_class == ELFCLASS ## B) { \
227 Elf ## B ## _Dyn *dyn; \ 259 Elf ## B ## _Dyn *dyn; \
228 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \ 260 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \
229 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \ 261 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \
230 Elf ## B ## _Shdr *strtbl = SHDR ## B (strtbl_void); \ 262 Elf ## B ## _Shdr *strtbl = SHDR ## B (strtbl_void); \
263 Elf ## B ## _Off offset; \
231 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \ 264 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \
232 if (EGET(phdr[i].p_type) != PT_DYNAMIC) continue; \ 265 if (EGET(phdr[i].p_type) != PT_DYNAMIC) continue; \
266 offset = EGET(phdr[i].p_offset); \
267 if (offset >= elf->len - sizeof(Elf ## B ## _Dyn)) continue; \
233 dyn = DYN ## B (elf->data + EGET(phdr[i].p_offset)); \ 268 dyn = DYN ## B (elf->data + offset); \
234 while (EGET(dyn->d_tag) != DT_NULL) { \ 269 while (EGET(dyn->d_tag) != DT_NULL) { \
235 if (EGET(dyn->d_tag) == DT_NEEDED) { \ 270 if (EGET(dyn->d_tag) == DT_NEEDED) { \
236 needed = elf->data + EGET(strtbl->sh_offset) + EGET(dyn->d_un.d_ptr); \ 271 offset = EGET(strtbl->sh_offset) + EGET(dyn->d_un.d_ptr); \
272 if (offset >= elf->len) { \
273 ++dyn; \
274 continue; \
275 } \
276 needed = (char*)(elf->data + offset); \
237 if (*found_needed) xchrcat(ret, ',', ret_len); \ 277 if (*found_needed) xchrcat(ret, ',', ret_len); \
238 xstrcat(ret, needed, ret_len); \ 278 xstrcat(ret, needed, ret_len); \
239 *found_needed = 1; \ 279 *found_needed = 1; \
240 } \ 280 } \
241 ++dyn; \ 281 ++dyn; \
263 SHOW_INTERP(32) 303 SHOW_INTERP(32)
264 SHOW_INTERP(64) 304 SHOW_INTERP(64)
265 } 305 }
266 return NULL; 306 return NULL;
267} 307}
308static char *scanelf_file_bind(elfobj *elf, char *found_bind)
309{
310 unsigned long i;
311 struct stat s;
312
313 if (!show_bind) return NULL;
314 if (!elf->phdr) return NULL;
315
316#define SHOW_BIND(B) \
317 if (elf->elf_class == ELFCLASS ## B) { \
318 Elf ## B ## _Dyn *dyn; \
319 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \
320 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \
321 Elf ## B ## _Off offset; \
322 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \
323 if (EGET(phdr[i].p_type) != PT_DYNAMIC) continue; \
324 offset = EGET(phdr[i].p_offset); \
325 if (offset >= elf->len - sizeof(Elf ## B ## _Dyn)) continue; \
326 dyn = DYN ## B (elf->data + offset); \
327 while (EGET(dyn->d_tag) != DT_NULL) { \
328 if (EGET(dyn->d_tag) == DT_BIND_NOW || \
329 (EGET(dyn->d_tag) == DT_FLAGS && EGET(dyn->d_un.d_val) & DF_BIND_NOW)) \
330 { \
331 if (be_quiet) return NULL; \
332 *found_bind = 1; \
333 return "NOW"; \
334 } \
335 ++dyn; \
336 } \
337 } \
338 }
339 SHOW_BIND(32)
340 SHOW_BIND(64)
341
342 if (be_quiet && !fstat(elf->fd, &s) && !(s.st_mode & S_ISUID || s.st_mode & S_ISGID)) {
343 return NULL;
344 } else {
345 *found_bind = 1;
346 return "LAZY";
347 }
348}
268static char *scanelf_file_sym(elfobj *elf, char *found_sym, const char *filename) 349static char *scanelf_file_sym(elfobj *elf, char *found_sym, const char *filename)
269{ 350{
270 int i; 351 unsigned long i;
271 void *symtab_void, *strtab_void; 352 void *symtab_void, *strtab_void;
272 353
273 if (!find_sym) return NULL; 354 if (!find_sym) return NULL;
274 355
275 symtab_void = elf_findsecbyname(elf, ".symtab"); 356 symtab_void = elf_findsecbyname(elf, ".symtab");
276 strtab_void = elf_findsecbyname(elf, ".strtab"); 357 strtab_void = elf_findsecbyname(elf, ".strtab");
277 358
278 if (symtab_void && strtab_void) { 359 if (symtab_void && strtab_void) {
360 char *base, *basemem;
361 basemem = xstrdup(filename);
362 base = basename(basemem);
279#define FIND_SYM(B) \ 363#define FIND_SYM(B) \
280 if (elf->elf_class == ELFCLASS ## B) { \ 364 if (elf->elf_class == ELFCLASS ## B) { \
281 Elf ## B ## _Shdr *symtab = SHDR ## B (symtab_void); \ 365 Elf ## B ## _Shdr *symtab = SHDR ## B (symtab_void); \
282 Elf ## B ## _Shdr *strtab = SHDR ## B (strtab_void); \ 366 Elf ## B ## _Shdr *strtab = SHDR ## B (strtab_void); \
283 Elf ## B ## _Sym *sym = SYM ## B (elf->data + EGET(symtab->sh_offset)); \ 367 Elf ## B ## _Sym *sym = SYM ## B (elf->data + EGET(symtab->sh_offset)); \
284 int cnt = EGET(symtab->sh_size) / EGET(symtab->sh_entsize); \ 368 unsigned long cnt = EGET(symtab->sh_size) / EGET(symtab->sh_entsize); \
285 char *symname; \ 369 char *symname; \
286 for (i = 0; i < cnt; ++i) { \ 370 for (i = 0; i < cnt; ++i) { \
287 if (sym->st_name) { \ 371 if (sym->st_name) { \
288 symname = (char *)(elf->data + EGET(strtab->sh_offset) + EGET(sym->st_name)); \ 372 symname = (char *)(elf->data + EGET(strtab->sh_offset) + EGET(sym->st_name)); \
289 if (*find_sym == '*') { \ 373 if (*find_sym == '*') { \
290 printf("%s(%s) %5lX %15s %s\n", \ 374 printf("%s(%s) %5lX %15s %s\n", \
291 ((*found_sym == 0) ? "\n\t" : "\t"), \ 375 ((*found_sym == 0) ? "\n\t" : "\t"), \
292 (char *)basename(filename), \ 376 base, \
293 (long)sym->st_size, \ 377 (long)sym->st_size, \
294 (char *)get_elfstttype(sym->st_info), \ 378 (char *)get_elfstttype(sym->st_info), \
295 symname); \ 379 symname); \
296 *found_sym = 1; \ 380 *found_sym = 1; \
297 } else if ((strcmp(find_sym, symname) == 0) || \ 381 } else if ((strcmp(find_sym, symname) == 0) || \
300 } \ 384 } \
301 ++sym; \ 385 ++sym; \
302 } } 386 } }
303 FIND_SYM(32) 387 FIND_SYM(32)
304 FIND_SYM(64) 388 FIND_SYM(64)
389 free(basemem);
305 } 390 }
306 if (*find_sym != '*' && *found_sym) 391 if (*find_sym != '*' && *found_sym)
307 return find_sym; 392 return find_sym;
308 if (be_quiet) 393 if (be_quiet)
309 return NULL; 394 return NULL;
310 else 395 else
311 return " - "; 396 return " - ";
312} 397}
313/* scan an elf file and show all the fun stuff */ 398/* scan an elf file and show all the fun stuff */
314#define prints(str) fputs(str, stdout) 399// #define prints(str) fputs(str, stdout)
400#define prints(str) write(fileno(stdout), str, strlen(str))
315static void scanelf_file(const char *filename) 401static void scanelf_file(const char *filename)
316{ 402{
317 int i; 403 unsigned long i;
318 char found_pax, found_stack, found_relro, found_textrel, 404 char found_pax, found_stack, found_relro, found_textrel,
319 found_rpath, found_needed, found_interp, found_sym, 405 found_rpath, found_needed, found_interp, found_bind,
320 found_file; 406 found_sym, found_file;
321 elfobj *elf; 407 elfobj *elf;
322 struct stat st; 408 struct stat st;
323 static char *out_buffer = NULL; 409 static char *out_buffer = NULL;
324 static size_t out_len; 410 static size_t out_len;
325 411
327 if (lstat(filename, &st) == -1) { 413 if (lstat(filename, &st) == -1) {
328 if (be_verbose > 2) printf("%s: does not exist\n", filename); 414 if (be_verbose > 2) printf("%s: does not exist\n", filename);
329 return; 415 return;
330 } 416 }
331 /* always handle regular files and handle symlinked files if no -y */ 417 /* always handle regular files and handle symlinked files if no -y */
332 if (!(S_ISREG(st.st_mode) || (S_ISLNK(st.st_mode) && scan_symlink))) { 418 if (S_ISLNK(st.st_mode)) {
419 if (!scan_symlink) return;
420 stat(filename, &st);
421 }
422 if (!S_ISREG(st.st_mode)) {
333 if (be_verbose > 2) printf("%s: skipping non-file\n", filename); 423 if (be_verbose > 2) printf("%s: skipping non-file\n", filename);
334 return; 424 return;
335 } 425 }
336 426
337 found_pax = found_stack = found_relro = found_textrel = \ 427 found_pax = found_stack = found_relro = found_textrel = \
338 found_rpath = found_needed = found_interp = found_sym = \ 428 found_rpath = found_needed = found_interp = found_bind = \
339 found_file = 0; 429 found_sym = found_file = 0;
340 430
341 /* verify this is real ELF */ 431 /* verify this is real ELF */
342 if ((elf = readelf(filename)) == NULL) { 432 if ((elf = readelf(filename)) == NULL) {
343 if (be_verbose > 2) printf("%s: not an ELF\n", filename); 433 if (be_verbose > 2) printf("%s: not an ELF\n", filename);
344 return; 434 return;
358 } 448 }
359 *out_buffer = '\0'; 449 *out_buffer = '\0';
360 450
361 /* show the header */ 451 /* show the header */
362 if (!be_quiet && show_banner) { 452 if (!be_quiet && show_banner) {
363 for (i=0; out_format[i]; ++i) { 453 for (i = 0; out_format[i]; ++i) {
364 if (out_format[i] != '%') continue; 454 if (out_format[i] != '%') continue;
365 455
366 switch (out_format[++i]) { 456 switch (out_format[++i]) {
367 case '%': break; 457 case '%': break;
368 case 'F': prints("FILE "); break; 458 case 'F': prints("FILE "); found_file = 1; break;
369 case 'o': prints(" TYPE "); break; 459 case 'o': prints(" TYPE "); break;
370 case 'x': prints(" PAX "); break; 460 case 'x': prints(" PAX "); break;
371 case 'e': prints("STK/REL "); break; 461 case 'e': prints("STK/REL "); break;
372 case 't': prints("TEXTREL "); break; 462 case 't': prints("TEXTREL "); break;
373 case 'r': prints("RPATH "); break; 463 case 'r': prints("RPATH "); break;
374 case 'n': prints("NEEDED "); break; 464 case 'n': prints("NEEDED "); break;
375 case 'i': prints("INTERP "); break; 465 case 'i': prints("INTERP "); break;
466 case 'b': prints("BIND "); break;
376 case 's': prints("SYM "); break; 467 case 's': prints("SYM "); break;
377 } 468 }
378 } 469 }
470 if (!found_file) prints("FILE ");
379 prints("\n"); 471 prints("\n");
472 found_file = 0;
380 show_banner = 0; 473 show_banner = 0;
381 } 474 }
382 475
383 /* dump all the good stuff */ 476 /* dump all the good stuff */
384 for (i=0; out_format[i]; ++i) { 477 for (i = 0; out_format[i]; ++i) {
385 const char *out; 478 const char *out;
386 479
387 /* make sure we trim leading spaces in quiet mode */ 480 /* make sure we trim leading spaces in quiet mode */
388 if (be_quiet && *out_buffer == ' ' && !out_buffer[1]) 481 if (be_quiet && *out_buffer == ' ' && !out_buffer[1])
389 *out_buffer = '\0'; 482 *out_buffer = '\0';
402 case 'e': out = scanelf_file_stack(elf, &found_stack, &found_relro); break; 495 case 'e': out = scanelf_file_stack(elf, &found_stack, &found_relro); break;
403 case 't': out = scanelf_file_textrel(elf, &found_textrel); break; 496 case 't': out = scanelf_file_textrel(elf, &found_textrel); break;
404 case 'r': scanelf_file_rpath(elf, &found_rpath, &out_buffer, &out_len); break; 497 case 'r': scanelf_file_rpath(elf, &found_rpath, &out_buffer, &out_len); break;
405 case 'n': scanelf_file_needed(elf, &found_needed, &out_buffer, &out_len); break; 498 case 'n': scanelf_file_needed(elf, &found_needed, &out_buffer, &out_len); break;
406 case 'i': out = scanelf_file_interp(elf, &found_interp); break; 499 case 'i': out = scanelf_file_interp(elf, &found_interp); break;
500 case 'b': out = scanelf_file_bind(elf, &found_bind); break;
407 case 's': out = scanelf_file_sym(elf, &found_sym, filename); break; 501 case 's': out = scanelf_file_sym(elf, &found_sym, filename); break;
408 } 502 }
409 if (out) xstrcat(&out_buffer, out, &out_len); 503 if (out) xstrcat(&out_buffer, out, &out_len);
410 } 504 }
411 505
412 if (!found_file) { 506#define FOUND_SOMETHING() \
413 if (!be_quiet || found_pax || found_stack || found_textrel || \ 507 (found_pax || found_stack || found_textrel || found_rpath || \
414 found_rpath || found_needed || found_interp || found_sym) 508 found_needed || found_interp || found_bind || found_sym)
509
510 if (!found_file && (!be_quiet || (be_quiet && FOUND_SOMETHING()))) {
511 xchrcat(&out_buffer, ' ', &out_len);
415 xstrcat(&out_buffer, filename, &out_len); 512 xstrcat(&out_buffer, filename, &out_len);
416 } 513 }
417 if (!(be_quiet && xemptybuffer(out_buffer))) 514 if (!be_quiet || (be_quiet && FOUND_SOMETHING()))
418 puts(out_buffer); 515 puts(out_buffer);
419 516
420 unreadelf(elf); 517 unreadelf(elf);
421} 518}
422 519
468 } 565 }
469 } 566 }
470 closedir(dir); 567 closedir(dir);
471} 568}
472 569
570static int scanelf_from_file(char *filename)
571{
572 FILE *fp = NULL;
573 char *p;
574 char path[_POSIX_PATH_MAX];
575
576 if (((strcmp(filename, "-")) == 0) && (ttyname(0) == NULL))
577 fp = stdin;
578 else if ((fp = fopen(filename, "r")) == NULL)
579 return 1;
580
581 while ((fgets(path, _POSIX_PATH_MAX, fp)) != NULL) {
582 if ((p = strchr(path, '\n')) != NULL)
583 *p = 0;
584 scanelf_dir(path);
585 }
586 if (fp != stdin)
587 fclose(fp);
588 return 0;
589}
590
591static void load_ld_so_conf()
592{
593 FILE *fp = NULL;
594 char *p;
595 char path[_POSIX_PATH_MAX];
596 int i = 0;
597
598 if ((fp = fopen("/etc/ld.so.conf", "r")) == NULL)
599 return;
600
601 while ((fgets(path, _POSIX_PATH_MAX, fp)) != NULL) {
602 if (*path != '/')
603 continue;
604
605 if ((p = strrchr(path, '\r')) != NULL)
606 *p = 0;
607 if ((p = strchr(path, '\n')) != NULL)
608 *p = 0;
609
610 ldpaths[i++] = xstrdup(path);
611
612 if (i + 1 == sizeof(ldpaths) / sizeof(*ldpaths))
613 break;
614 }
615 ldpaths[i] = NULL;
616
617 fclose(fp);
618}
619
473/* scan /etc/ld.so.conf for paths */ 620/* scan /etc/ld.so.conf for paths */
474static void scanelf_ldpath() 621static void scanelf_ldpath()
475{ 622{
476 char scan_l, scan_ul, scan_ull; 623 char scan_l, scan_ul, scan_ull;
477 char *path, *p; 624 int i = 0;
478 FILE *fp;
479 625
480 if ((fp = fopen("/etc/ld.so.conf", "r")) == NULL) 626 if (!ldpaths[0])
481 err("Unable to open ld.so.conf: %s", strerror(errno)); 627 err("Unable to load any paths from ld.so.conf");
482 628
483 scan_l = scan_ul = scan_ull = 0; 629 scan_l = scan_ul = scan_ull = 0;
484 630
485 path = (char*)xmalloc(_POSIX_PATH_MAX); 631 while (ldpaths[i]) {
486 while ((fgets(path, _POSIX_PATH_MAX, fp)) != NULL)
487 if (*path == '/') {
488 if ((p = strrchr(path, '\r')) != NULL)
489 *p = 0;
490 if ((p = strrchr(path, '\n')) != NULL)
491 *p = 0;
492 if (!scan_l && !strcmp(path, "/lib")) scan_l = 1; 632 if (!scan_l && !strcmp(ldpaths[i], "/lib")) scan_l = 1;
493 if (!scan_ul && !strcmp(path, "/usr/lib")) scan_ul = 1; 633 if (!scan_ul && !strcmp(ldpaths[i], "/usr/lib")) scan_ul = 1;
494 if (!scan_ull && !strcmp(path, "/usr/local/lib")) scan_ull = 1; 634 if (!scan_ull && !strcmp(ldpaths[i], "/usr/local/lib")) scan_ull = 1;
495 scanelf_dir(path); 635 scanelf_dir(ldpaths[i]);
636 ++i;
496 } 637 }
497 free(path);
498 fclose(fp);
499 638
500 if (!scan_l) scanelf_dir("/lib"); 639 if (!scan_l) scanelf_dir("/lib");
501 if (!scan_ul) scanelf_dir("/usr/lib"); 640 if (!scan_ul) scanelf_dir("/usr/lib");
502 if (!scan_ull) scanelf_dir("/usr/local/lib"); 641 if (!scan_ull) scanelf_dir("/usr/local/lib");
503} 642}
521} 660}
522 661
523 662
524 663
525/* usage / invocation handling functions */ 664/* usage / invocation handling functions */
526#define PARSE_FLAGS "plRmyxetrnis:aqvF:o:BhV" 665#define PARSE_FLAGS "plRmyxetrnibs:aqvF:f:o:BhV"
527#define a_argument required_argument 666#define a_argument required_argument
528static struct option const long_opts[] = { 667static struct option const long_opts[] = {
529 {"path", no_argument, NULL, 'p'}, 668 {"path", no_argument, NULL, 'p'},
530 {"ldpath", no_argument, NULL, 'l'}, 669 {"ldpath", no_argument, NULL, 'l'},
531 {"recursive", no_argument, NULL, 'R'}, 670 {"recursive", no_argument, NULL, 'R'},
535 {"header", no_argument, NULL, 'e'}, 674 {"header", no_argument, NULL, 'e'},
536 {"textrel", no_argument, NULL, 't'}, 675 {"textrel", no_argument, NULL, 't'},
537 {"rpath", no_argument, NULL, 'r'}, 676 {"rpath", no_argument, NULL, 'r'},
538 {"needed", no_argument, NULL, 'n'}, 677 {"needed", no_argument, NULL, 'n'},
539 {"interp", no_argument, NULL, 'i'}, 678 {"interp", no_argument, NULL, 'i'},
679 {"bind", no_argument, NULL, 'b'},
540 {"symbol", a_argument, NULL, 's'}, 680 {"symbol", a_argument, NULL, 's'},
541 {"all", no_argument, NULL, 'a'}, 681 {"all", no_argument, NULL, 'a'},
542 {"quiet", no_argument, NULL, 'q'}, 682 {"quiet", no_argument, NULL, 'q'},
543 {"verbose", no_argument, NULL, 'v'}, 683 {"verbose", no_argument, NULL, 'v'},
544 {"format", a_argument, NULL, 'F'}, 684 {"format", a_argument, NULL, 'F'},
685 {"from", a_argument, NULL, 'f'},
545 {"file", a_argument, NULL, 'o'}, 686 {"file", a_argument, NULL, 'o'},
546 {"nobanner", no_argument, NULL, 'B'}, 687 {"nobanner", no_argument, NULL, 'B'},
547 {"help", no_argument, NULL, 'h'}, 688 {"help", no_argument, NULL, 'h'},
548 {"version", no_argument, NULL, 'V'}, 689 {"version", no_argument, NULL, 'V'},
549 {NULL, no_argument, NULL, 0x0} 690 {NULL, no_argument, NULL, 0x0}
550}; 691};
692
551static char *opts_help[] = { 693static char *opts_help[] = {
552 "Scan all directories in PATH environment", 694 "Scan all directories in PATH environment",
553 "Scan all directories in /etc/ld.so.conf", 695 "Scan all directories in /etc/ld.so.conf",
554 "Scan directories recursively", 696 "Scan directories recursively",
555 "Don't recursively cross mount points", 697 "Don't recursively cross mount points",
558 "Print GNU_STACK markings", 700 "Print GNU_STACK markings",
559 "Print TEXTREL information", 701 "Print TEXTREL information",
560 "Print RPATH information", 702 "Print RPATH information",
561 "Print NEEDED information", 703 "Print NEEDED information",
562 "Print INTERP information", 704 "Print INTERP information",
705 "Print BIND information",
563 "Find a specified symbol", 706 "Find a specified symbol",
564 "Print all scanned info (-x -e -t -r)\n", 707 "Print all scanned info (-x -e -t -r -n -i -b)\n",
565 "Only output 'bad' things", 708 "Only output 'bad' things",
566 "Be verbose (can be specified more than once)", 709 "Be verbose (can be specified more than once)",
567 "Use specified format for output", 710 "Use specified format for output",
711 "Read input stream from a filename",
568 "Write output stream to a filename", 712 "Write output stream to a filename",
569 "Don't display the header", 713 "Don't display the header",
570 "Print this help and exit", 714 "Print this help and exit",
571 "Print version and exit", 715 "Print version and exit",
572 NULL 716 NULL
573}; 717};
574 718
575/* display usage and exit */ 719/* display usage and exit */
576static void usage(int status) 720static void usage(int status)
577{ 721{
578 int i; 722 unsigned long i;
579 printf(" Scan ELF binaries for stuff\n\n" 723 printf("* Scan ELF binaries for stuff\n\n"
580 "Usage: %s [options] <dir1/file1> [dir2 dirN fileN ...]\n\n", argv0); 724 "Usage: %s [options] <dir1/file1> [dir2 dirN fileN ...]\n\n", argv0);
581 printf("Options: -[%s]\n", PARSE_FLAGS); 725 printf("Options: -[%s]\n", PARSE_FLAGS);
582 for (i = 0; long_opts[i].name; ++i) 726 for (i = 0; long_opts[i].name; ++i)
583 if (long_opts[i].has_arg == no_argument) 727 if (long_opts[i].has_arg == no_argument)
584 printf(" -%c, --%-13s %s\n", long_opts[i].val, 728 printf(" -%c, --%-13s* %s\n", long_opts[i].val,
585 long_opts[i].name, opts_help[i]); 729 long_opts[i].name, opts_help[i]);
586 else 730 else
587 printf(" -%c, --%-6s <arg> %s\n", long_opts[i].val, 731 printf(" -%c, --%-6s <arg> * %s\n", long_opts[i].val,
588 long_opts[i].name, opts_help[i]); 732 long_opts[i].name, opts_help[i]);
733
734 if (status != EXIT_SUCCESS)
735 exit(status);
736
737 puts("\nThe format modifiers for the -F option are:");
738 puts(" %F Filename \t%x PaX Flags \t%e STACK/RELRO");
739 puts(" %t TEXTREL \t%r RPATH \t%n NEEDED");
740 puts(" %i INTERP \t%b BIND \t%s symbol");
741
589 exit(status); 742 exit(status);
590} 743}
591 744
592/* parse command line arguments and preform needed actions */ 745/* parse command line arguments and preform needed actions */
593static void parseargs(int argc, char *argv[]) 746static void parseargs(int argc, char *argv[])
594{ 747{
595 int flag; 748 int i;
749 char *from_file = NULL;
596 750
597 opterr = 0; 751 opterr = 0;
598 while ((flag=getopt_long(argc, argv, PARSE_FLAGS, long_opts, NULL)) != -1) { 752 while ((i=getopt_long(argc, argv, PARSE_FLAGS, long_opts, NULL)) != -1) {
599 switch (flag) { 753 switch (i) {
600 754
601 case 'V': 755 case 'V':
602 printf("%s compiled %s\n%s\n" 756 printf("%s compiled %s\n%s\n"
603 "%s written for Gentoo Linux by <solar and vapier @ gentoo.org>\n", 757 "%s written for Gentoo Linux by <solar and vapier @ gentoo.org>\n",
604 __FILE__, __DATE__, rcsid, argv0); 758 __FILE__, __DATE__, rcsid, argv0);
605 exit(EXIT_SUCCESS); 759 exit(EXIT_SUCCESS);
606 break; 760 break;
607 case 'h': usage(EXIT_SUCCESS); break; 761 case 'h': usage(EXIT_SUCCESS); break;
608 762 case 'f':
763 if (from_file == NULL)
764 from_file = xstrdup(optarg);
765 break;
609 case 'o': { 766 case 'o': {
610 FILE *fp = NULL; 767 FILE *fp = NULL;
611 fp = freopen(optarg, "w", stdout); 768 fp = freopen(optarg, "w", stdout);
612 if (fp == NULL) 769 if (fp == NULL)
613 err("Could not open output stream '%s': %s", optarg, strerror(errno)); 770 err("Could not open output stream '%s': %s", optarg, strerror(errno));
623 sprintf(versioned_symname, "%s@", find_sym); 780 sprintf(versioned_symname, "%s@", find_sym);
624 break; 781 break;
625 } 782 }
626 783
627 case 'F': { 784 case 'F': {
628 out_format = strdup(optarg); 785 out_format = xstrdup(optarg);
629 break; 786 break;
630 } 787 }
631 788
632 case 'y': scan_symlink = 0; break; 789 case 'y': scan_symlink = 0; break;
633 case 'B': show_banner = 0; break; 790 case 'B': show_banner = 0; break;
639 case 'e': show_stack = 1; break; 796 case 'e': show_stack = 1; break;
640 case 't': show_textrel = 1; break; 797 case 't': show_textrel = 1; break;
641 case 'r': show_rpath = 1; break; 798 case 'r': show_rpath = 1; break;
642 case 'n': show_needed = 1; break; 799 case 'n': show_needed = 1; break;
643 case 'i': show_interp = 1; break; 800 case 'i': show_interp = 1; break;
801 case 'b': show_bind = 1; break;
644 case 'q': be_quiet = 1; break; 802 case 'q': be_quiet = 1; break;
645 case 'v': be_verbose = (be_verbose % 20) + 1; break; 803 case 'v': be_verbose = (be_verbose % 20) + 1; break;
646 case 'a': show_pax = show_stack = show_textrel = show_rpath = show_needed = show_interp = 1; break; 804 case 'a': show_pax = show_stack = show_textrel = show_rpath = \
805 show_needed = show_interp = show_bind = 1; break;
647 806
648 case ':': 807 case ':':
649 warn("Option missing parameter\n"); 808 err("Option missing parameter\n");
650 usage(EXIT_FAILURE);
651 break;
652 case '?': 809 case '?':
653 warn("Unknown option\n"); 810 err("Unknown option\n");
654 usage(EXIT_FAILURE);
655 break;
656 default: 811 default:
657 err("Unhandled option '%c'", flag); 812 err("Unhandled option '%c'", i);
658 break;
659 }
660 } 813 }
661 814 }
662 if (be_quiet && be_verbose)
663 err("You can be quiet or you can be verbose, not both, stupid");
664 815
665 /* let the format option override all other options */ 816 /* let the format option override all other options */
666 if (out_format) { 817 if (out_format) {
667 show_pax = show_stack = show_textrel = show_rpath = show_needed = show_interp = 0; 818 show_pax = show_stack = show_textrel = show_rpath = \
819 show_needed = show_interp = show_bind = 0;
668 for (flag=0; out_format[flag]; ++flag) { 820 for (i = 0; out_format[i]; ++i) {
669 if (out_format[flag] != '%') continue; 821 if (out_format[i] != '%') continue;
670 822
671 switch (out_format[++flag]) { 823 switch (out_format[++i]) {
672 case '%': break; 824 case '%': break;
673 case 'F': break; 825 case 'F': break;
674 case 's': break; 826 case 's': break;
675 case 'o': break; 827 case 'o': break;
676 case 'x': show_pax = 1; break; 828 case 'x': show_pax = 1; break;
677 case 'e': show_stack = 1; break; 829 case 'e': show_stack = 1; break;
678 case 't': show_textrel = 1; break; 830 case 't': show_textrel = 1; break;
679 case 'r': show_rpath = 1; break; 831 case 'r': show_rpath = 1; break;
680 case 'n': show_needed = 1; break; 832 case 'n': show_needed = 1; break;
681 case 'i': show_interp = 1; break; 833 case 'i': show_interp = 1; break;
834 case 'b': show_bind = 1; break;
682 default: 835 default:
683 err("Invalid format specifier '%c' (byte %i)", 836 err("Invalid format specifier '%c' (byte %i)",
684 out_format[flag], flag+1); 837 out_format[i], i+1);
685 } 838 }
686 } 839 }
687 840
688 /* construct our default format */ 841 /* construct our default format */
689 } else { 842 } else {
694 if (show_stack) xstrcat(&out_format, "%e ", &fmt_len); 847 if (show_stack) xstrcat(&out_format, "%e ", &fmt_len);
695 if (show_textrel) xstrcat(&out_format, "%t ", &fmt_len); 848 if (show_textrel) xstrcat(&out_format, "%t ", &fmt_len);
696 if (show_rpath) xstrcat(&out_format, "%r ", &fmt_len); 849 if (show_rpath) xstrcat(&out_format, "%r ", &fmt_len);
697 if (show_needed) xstrcat(&out_format, "%n ", &fmt_len); 850 if (show_needed) xstrcat(&out_format, "%n ", &fmt_len);
698 if (show_interp) xstrcat(&out_format, "%i ", &fmt_len); 851 if (show_interp) xstrcat(&out_format, "%i ", &fmt_len);
852 if (show_bind) xstrcat(&out_format, "%b ", &fmt_len);
699 if (find_sym) xstrcat(&out_format, "%s ", &fmt_len); 853 if (find_sym) xstrcat(&out_format, "%s ", &fmt_len);
700 if (!be_quiet) xstrcat(&out_format, "%F ", &fmt_len); 854 if (!be_quiet) xstrcat(&out_format, "%F ", &fmt_len);
701 } 855 }
702 if (be_verbose > 2) printf("Format: %s\n", out_format); 856 if (be_verbose > 2) printf("Format: %s\n", out_format);
703 857
704 /* now lets actually do the scanning */ 858 /* now lets actually do the scanning */
859 if (scan_ldpath || (show_rpath && be_quiet))
860 load_ld_so_conf();
705 if (scan_ldpath) scanelf_ldpath(); 861 if (scan_ldpath) scanelf_ldpath();
706 if (scan_envpath) scanelf_envpath(); 862 if (scan_envpath) scanelf_envpath();
863 if (from_file) {
864 scanelf_from_file(from_file);
865 free(from_file);
866 from_file = *argv;
867 }
707 if (optind == argc && !scan_ldpath && !scan_envpath) 868 if (optind == argc && !scan_ldpath && !scan_envpath && !from_file)
708 err("Nothing to scan !?"); 869 err("Nothing to scan !?");
709 while (optind < argc) 870 while (optind < argc)
710 scanelf_dir(argv[optind++]); 871 scanelf_dir(argv[optind++]);
711 872
712 /* clean up */ 873 /* clean up */
713 if (find_sym) { 874 if (find_sym) {
714 free(find_sym); 875 free(find_sym);
715 free(versioned_symname); 876 free(versioned_symname);
716 } 877 }
717 if (out_format) free(out_format); 878 if (out_format) free(out_format);
879 for (i = 0; ldpaths[i]; ++i)
880 free(ldpaths[i]);
718} 881}
719 882
720 883
721 884
722/* utility funcs */ 885/* utility funcs */
723static char *xstrdup(char *s) 886static char *xstrdup(const char *s)
724{ 887{
725 char *ret = strdup(s); 888 char *ret = strdup(s);
726 if (!ret) err("Could not strdup(): %s", strerror(errno)); 889 if (!ret) err("Could not strdup(): %s", strerror(errno));
727 return ret; 890 return ret;
728} 891}
892
729static void *xmalloc(size_t size) 893static void *xmalloc(size_t size)
730{ 894{
731 void *ret = malloc(size); 895 void *ret = malloc(size);
732 if (!ret) err("Could not malloc() %li bytes", (unsigned long)size); 896 if (!ret) err("Could not malloc() %li bytes", (unsigned long)size);
733 return ret; 897 return ret;
734} 898}
899
735static void xstrcat(char **dst, const char *src, size_t *curr_len) 900static void xstrcat(char **dst, const char *src, size_t *curr_len)
736{ 901{
737 long new_len; 902 long new_len;
738 903
739 new_len = strlen(*dst) + strlen(src); 904 new_len = strlen(*dst) + strlen(src);
744 err("could not realloc %li bytes", (unsigned long)*curr_len); 909 err("could not realloc %li bytes", (unsigned long)*curr_len);
745 } 910 }
746 911
747 strcat(*dst, src); 912 strcat(*dst, src);
748} 913}
914
749static inline void xchrcat(char **dst, const char append, size_t *curr_len) 915static inline void xchrcat(char **dst, const char append, size_t *curr_len)
750{ 916{
751 static char my_app[2]; 917 static char my_app[2];
752 my_app[0] = append; 918 my_app[0] = append;
753 my_app[1] = '\0'; 919 my_app[1] = '\0';
754 xstrcat(dst, my_app, curr_len); 920 xstrcat(dst, my_app, curr_len);
755} 921}
756static int xemptybuffer(const char *buff)
757{
758 long i;
759 for (i=0; buff[i]; ++i)
760 if (buff[i] != ' ')
761 return 0;
762 return 1;
763}
764
765 922
766 923
767int main(int argc, char *argv[]) 924int main(int argc, char *argv[])
768{ 925{
769 if (argc < 2) 926 if (argc < 2)

Legend:
Removed from v.1.43  
changed lines
  Added in v.1.60

  ViewVC Help
Powered by ViewVC 1.1.20