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

Contents of /pax-utils/scanmacho.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.9 - (show annotations) (download) (as text)
Tue Dec 30 12:39:53 2008 UTC (5 years, 6 months ago) by vapier
Branch: MAIN
Changes since 1.8: +4 -9 lines
File MIME type: text/x-csrc
mark local state vars as static and drop unused ones

1 /*
2 * Copyright 2008 Gentoo Foundation
3 * Distributed under the terms of the GNU General Public License v2
4 * $Header: /var/cvsroot/gentoo-projects/pax-utils/scanmacho.c,v 1.8 2008/12/30 12:34:28 vapier Exp $
5 *
6 * based on scanelf by:
7 * Copyright 2003-2007 Ned Ludd - <solar@gentoo.org>
8 * Copyright 2004-2007 Mike Frysinger - <vapier@gentoo.org>
9 * for Darwin specific fun:
10 * 2008 Fabian Groffen - <grobian@gentoo.org>
11 */
12
13 static const char *rcsid = "$Id: scanmacho.c,v 1.8 2008/12/30 12:34:28 vapier Exp $";
14 const char * const argv0 = "scanmacho";
15
16 #include "paxinc.h"
17
18 #define IS_MODIFIER(c) (c == '%' || c == '#' || c == '+')
19
20 /* prototypes */
21 static int scanmacho_fatobj(fatobj *fobj);
22 static int scanmacho_file(const char *filename, const struct stat *st_cache);
23 static int scanmacho_from_file(const char *filename);
24 static int scanmacho_dir(const char *path);
25 static void scanelf_envpath(void);
26 static void usage(int status);
27 static int parseargs(int argc, char *argv[]);
28
29 /* variables to control behavior */
30 static char match_etypes[126] = "";
31 static char scan_envpath = 0;
32 static char scan_symlink = 1;
33 static char scan_archives = 0;
34 static char dir_recurse = 0;
35 static char dir_crossmount = 1;
36 static char show_perms = 0;
37 static char show_size = 0;
38 static char show_needed = 0;
39 static char show_interp = 0;
40 static char show_bind = 0;
41 static char show_soname = 0;
42 static char show_banner = 1;
43 static char show_endian = 0;
44 static char be_quiet = 0;
45 static char be_verbose = 0;
46 static char be_wewy_wewy_quiet = 0;
47 static char be_semi_verbose = 0;
48 static char *find_lib = NULL;
49 static char *out_format = NULL;
50 static char *search_path = NULL;
51 static char g_match = 0;
52
53 static int match_bits = 0;
54 static unsigned int match_perms = 0;
55
56 static char *getstr_perms(const char *fname);
57 static char *getstr_perms(const char *fname)
58 {
59 struct stat st;
60 static char buf[8];
61
62 if ((stat(fname, &st)) == (-1))
63 return (char *) "";
64
65 snprintf(buf, sizeof(buf), "%o", st.st_mode);
66
67 return (char *) buf + 2;
68 }
69
70 static const char *macho_file_needed_lib(
71 fatobj *fobj,
72 char *found_needed,
73 char *found_lib,
74 int op,
75 char **ret,
76 size_t *ret_len
77 ) {
78 char *needed;
79 loadcmd *lcmd;
80 struct dylib_command *dlcmd;
81 uint32_t lc_load_dylib = LC_LOAD_DYLIB;
82
83 if ((op == 0 && !show_needed) || (op == 1 && !find_lib))
84 return NULL;
85
86 lcmd = firstloadcmd(fobj);
87
88 if (fobj->swapped)
89 lc_load_dylib = bswap_32(lc_load_dylib);
90
91 do {
92 if (lcmd->lcmd->cmd == lc_load_dylib) {
93 dlcmd = (struct dylib_command*)lcmd->data;
94 if (fobj->swapped) {
95 needed = (char *)(lcmd->data +
96 bswap_32(dlcmd->dylib.name.offset));
97 } else {
98 needed = (char *)(lcmd->data + dlcmd->dylib.name.offset);
99 }
100 if (op == 0) {
101 if (!be_wewy_wewy_quiet) {
102 if (*found_needed)
103 xchrcat(ret, ',', ret_len);
104 xstrcat(ret, needed, ret_len);
105 }
106 *found_needed = 1;
107 } else {
108 if (!strncmp(find_lib, needed,
109 strlen(!g_match ? needed : find_lib)))
110 {
111 *found_lib = 1;
112 free(lcmd);
113 return (be_wewy_wewy_quiet ? NULL : needed);
114 }
115 }
116 }
117 } while (nextloadcmd(lcmd));
118
119 if (op == 0 && !*found_needed && be_verbose)
120 warn("Mach-O lacks LC_LOAD_DYLIB commands: %s", fobj->filename);
121
122 return NULL;
123 }
124
125 static char *macho_file_interp(fatobj *fobj, char *found_interp)
126 {
127 loadcmd *lcmd;
128 uint32_t lc_load_dylinker = LC_LOAD_DYLINKER;
129
130 if (!show_interp)
131 return NULL;
132
133 lcmd = firstloadcmd(fobj);
134
135 if (fobj->swapped)
136 lc_load_dylinker = bswap_32(lc_load_dylinker);
137
138 do {
139 if (lcmd->lcmd->cmd == lc_load_dylinker) {
140 struct dylinker_command *dlcmd =
141 (struct dylinker_command*)lcmd->data;
142 char *dylinker;
143 if (fobj->swapped) {
144 dylinker = (char *)(lcmd->data +
145 bswap_32(dlcmd->name.offset));
146 } else {
147 dylinker = (char *)(lcmd->data + dlcmd->name.offset);
148 }
149 *found_interp = 1;
150 free(lcmd);
151 return (be_wewy_wewy_quiet ? NULL : dylinker);
152 }
153 } while (nextloadcmd(lcmd));
154
155 return NULL;
156 }
157
158 static char *macho_file_soname(fatobj *fobj, char *found_soname)
159 {
160 loadcmd *lcmd;
161 char *soname;
162 uint32_t lc_id_dylib = LC_ID_DYLIB;
163
164 if (!show_soname)
165 return NULL;
166
167 lcmd = firstloadcmd(fobj);
168
169 if (fobj->swapped)
170 lc_id_dylib = bswap_32(lc_id_dylib);
171
172 do {
173 if (lcmd->lcmd->cmd == lc_id_dylib) {
174 struct dylib_command *dlcmd = (struct dylib_command*)lcmd->data;
175 if (fobj->swapped) {
176 soname = (char *)(lcmd->data +
177 bswap_32(dlcmd->dylib.name.offset));
178 } else {
179 soname = (char *)(lcmd->data + dlcmd->dylib.name.offset);
180 }
181 *found_soname = 1;
182 free(lcmd);
183 return (be_wewy_wewy_quiet ? NULL : soname);
184 }
185 } while (nextloadcmd(lcmd));
186
187 return NULL;
188 }
189
190 /* scan a macho file and show all the fun stuff */
191 #define prints(str) write(fileno(stdout), str, strlen(str))
192 static int scanmacho_fatobj(fatobj *fobj)
193 {
194 unsigned long i;
195 char found_needed, found_interp, found_soname, found_lib, found_file;
196 static char *out_buffer = NULL;
197 static size_t out_len;
198
199 found_needed = found_interp = found_soname = \
200 found_lib = found_file = 0;
201
202 if (be_verbose > 2)
203 printf("%s: scanning file {%s,%s}\n", fobj->filename,
204 get_machocputype(fobj),
205 get_machosubcputype(fobj));
206 else if (be_verbose > 1)
207 printf("%s: scanning file\n", fobj->filename);
208
209 /* init output buffer */
210 if (!out_buffer) {
211 out_len = sizeof(char) * 80;
212 out_buffer = xmalloc(out_len);
213 }
214 *out_buffer = '\0';
215
216 /* show the header */
217 if (!be_quiet && show_banner) {
218 for (i = 0; out_format[i]; ++i) {
219 if (!IS_MODIFIER(out_format[i])) continue;
220
221 switch (out_format[++i]) {
222 case '+': break;
223 case '%': break;
224 case '#': break;
225 case 'F':
226 case 'p':
227 case 'f': prints("FILE "); found_file = 1; break;
228 case 'o': prints(" TYPE "); break;
229 case 'M': prints("CPU "); break;
230 case 'n': prints("NEEDED "); break;
231 case 'i': prints("DYLINKER "); break;
232 case 'b': prints("FLAGS "); break;
233 case 'Z': prints("SIZE "); break;
234 case 'S': prints("INSTALLNAME "); break;
235 case 'N': prints("LIB "); break;
236 case 'a': prints("ARCH "); break;
237 case 'O': prints("PERM "); break;
238 case 'D': prints("ENDIAN "); break;
239 default: warnf("'%c' has no title ?", out_format[i]);
240 }
241 }
242 if (!found_file) prints("FILE ");
243 prints("\n");
244 found_file = 0;
245 show_banner = 0;
246 }
247
248 /* dump all the good stuff */
249 for (i = 0; out_format[i]; ++i) {
250 const char *out;
251 const char *tmp;
252 static char ubuf[sizeof(unsigned long)*2];
253 if (!IS_MODIFIER(out_format[i])) {
254 xchrcat(&out_buffer, out_format[i], &out_len);
255 continue;
256 }
257
258 out = NULL;
259 be_wewy_wewy_quiet = (out_format[i] == '#');
260 be_semi_verbose = (out_format[i] == '+');
261 switch (out_format[++i]) {
262 case '+':
263 case '%':
264 case '#':
265 xchrcat(&out_buffer, out_format[i], &out_len); break;
266 case 'F':
267 found_file = 1;
268 if (be_wewy_wewy_quiet) break;
269 xstrcat(&out_buffer, fobj->filename, &out_len);
270 break;
271 case 'p':
272 found_file = 1;
273 if (be_wewy_wewy_quiet) break;
274 tmp = fobj->filename;
275 if (search_path) {
276 ssize_t len_search = strlen(search_path);
277 ssize_t len_file = strlen(fobj->filename);
278 if (!strncmp(fobj->filename, search_path, len_search) && \
279 len_file > len_search)
280 tmp += len_search;
281 if (*tmp == '/' && search_path[len_search-1] == '/') tmp++;
282 }
283 xstrcat(&out_buffer, tmp, &out_len);
284 break;
285 case 'f':
286 found_file = 1;
287 if (be_wewy_wewy_quiet) break;
288 xstrcat(&out_buffer, fobj->base_filename, &out_len);
289 break;
290 case 'o': out = get_machomhtype(fobj); break;
291 case 'M': out = get_machocputype(fobj); break;
292 case 'D': out = get_machoendian(fobj); break;
293 case 'O': out = getstr_perms(fobj->filename); break;
294 case 'n':
295 case 'N': out = macho_file_needed_lib(fobj, &found_needed, &found_lib, (out_format[i]=='N'), &out_buffer, &out_len); break;
296 case 'i': out = macho_file_interp(fobj, &found_interp); break;
297 case 'b': get_machomhflags(fobj, &out_buffer, &out_len); break;
298 case 'S': out = macho_file_soname(fobj, &found_soname); break;
299 case 'a': out = get_machomtype(fobj); break;
300 case 'Z': snprintf(ubuf, sizeof(ubuf), "%llu", (unsigned long long int)fobj->len); out = ubuf; break;;
301 default: warnf("'%c' has no scan code?", out_format[i]);
302 }
303 if (out) {
304 /* hack for comma delimited output like `scanelf -s sym1,sym2,sym3` */
305 if (out_format[i] == 's' && (tmp=strchr(out,',')) != NULL)
306 xstrncat(&out_buffer, out, &out_len, (tmp-out));
307 else
308 xstrcat(&out_buffer, out, &out_len);
309 }
310 }
311
312 #define FOUND_SOMETHING() \
313 ( found_needed || found_interp || found_soname || found_lib )
314
315 if (!found_file && (!be_quiet || (be_quiet && FOUND_SOMETHING()))) {
316 xchrcat(&out_buffer, ' ', &out_len);
317 xstrcat(&out_buffer, fobj->filename, &out_len);
318 }
319 if (!be_quiet || (be_quiet && FOUND_SOMETHING())) {
320 puts(out_buffer);
321 fflush(stdout);
322 }
323
324 return 0;
325 }
326
327 /* scan a single Mach-O */
328 static int scanmacho_fat(const char *filename, int fd, size_t len)
329 {
330 int ret = 1;
331 fatobj *fobj;
332 fatobj *walk;
333
334 /* verify this is real Mach-O */
335 if ((fobj = readmacho_fd(filename, fd, len)) == NULL) {
336 if (be_verbose > 2) printf("%s: not a Mach-O object\n", filename);
337 return ret;
338 }
339 switch (match_bits) {
340 case 32:
341 case 64:
342 walk = fobj;
343 do {
344 if ((walk->ismach64 && match_bits == 64) ||
345 (!walk->ismach64 && match_bits == 32))
346 {
347 ret = scanmacho_fatobj(walk);
348 }
349 } while (walk->next != NULL && (walk = walk->next));
350 goto label_done;
351 default:
352 break;
353 }
354 if (strlen(match_etypes)) {
355 char sbuf[128];
356 char ftype[32];
357
358 snprintf(sbuf, 128, ",%s,", match_etypes);
359
360 walk = fobj;
361 do {
362 snprintf(ftype, 32, ",%s,", get_machomhtype(walk));
363 if (strstr(sbuf, ftype) != NULL) {
364 ret = scanmacho_fatobj(walk);
365 }
366 } while (walk->next != NULL && (walk = walk->next));
367 goto label_done;
368 }
369
370 walk = fobj;
371 do {
372 ret = scanmacho_fatobj(walk);
373 } while (walk->next != NULL && (walk = walk->next));
374
375 label_done:
376 unreadmacho(fobj);
377 return ret;
378 }
379
380 /* scan an archive of Mach-Os */
381 static int scanmacho_archive(const char *filename, int fd, size_t len)
382 {
383 archive_handle *ar;
384 archive_member *m;
385 char *ar_buffer;
386 fatobj *fobj;
387 fatobj *walk;
388
389 ar = ar_open_fd(filename, fd);
390 if (ar == NULL)
391 return 1;
392
393 ar_buffer = mmap(0, len, PROT_READ, MAP_PRIVATE, fd, 0);
394 while ((m = ar_next(ar)) != NULL) {
395 fobj = readmacho_buffer(m->name, ar_buffer + lseek(fd, 0, SEEK_CUR), m->size);
396 if (fobj) {
397 walk = fobj;
398 do {
399 scanmacho_fatobj(walk);
400 } while (walk->next != NULL && (walk = walk->next));
401 fobj->data = NULL;
402 unreadmacho(fobj);
403 }
404 }
405 munmap(ar_buffer, len);
406
407 return 0;
408 }
409 /* scan a file which may be an Mach-O or an archive or some other
410 * magical beast */
411 static int scanmacho_file(const char *filename, const struct stat *st_cache)
412 {
413 const struct stat *st = st_cache;
414 struct stat symlink_st;
415 int fd;
416
417 /* always handle regular files and handle symlinked files if no -y */
418 if (S_ISLNK(st->st_mode)) {
419 if (!scan_symlink)
420 return 1;
421 stat(filename, &symlink_st);
422 st = &symlink_st;
423 }
424
425 if (!S_ISREG(st->st_mode)) {
426 if (be_verbose > 2) printf("%s: skipping non-file\n", filename);
427 return 1;
428 }
429
430 if (match_perms) {
431 if ((st->st_mode | match_perms) != st->st_mode)
432 return 1;
433 }
434 if ((fd = open(filename, O_RDONLY)) == -1)
435 return 1;
436
437 if (scanmacho_fat(filename, fd, st->st_size) == 1 && scan_archives)
438 /* if it isn't an Mach-O, maybe it's an .a archive */
439 scanmacho_archive(filename, fd, st->st_size);
440
441 close(fd);
442 return 0;
443 }
444
445 /* scan a directory for Mach-O files and print when we find one */
446 static int scanmacho_dir(const char *path)
447 {
448 register DIR *dir;
449 register struct dirent *dentry;
450 struct stat st_top, st;
451 char buf[__PAX_UTILS_PATH_MAX];
452 size_t pathlen = 0, len = 0;
453 int ret = 0;
454
455 /* make sure path exists */
456 if (lstat(path, &st_top) == -1) {
457 if (be_verbose > 2) printf("%s: does not exist\n", path);
458 return 1;
459 }
460
461 /* ok, if it isn't a directory, assume we can open it */
462 if (!S_ISDIR(st_top.st_mode)) {
463 return scanmacho_file(path, &st_top);
464 }
465
466 /* now scan the dir looking for fun stuff */
467 if ((dir = opendir(path)) == NULL) {
468 warnf("could not opendir %s: %s", path, strerror(errno));
469 return 1;
470 }
471 if (be_verbose > 1) printf("%s: scanning dir\n", path);
472
473 pathlen = strlen(path);
474 while ((dentry = readdir(dir))) {
475 if (!strcmp(dentry->d_name, ".") || !strcmp(dentry->d_name, ".."))
476 continue;
477 len = (pathlen + 1 + strlen(dentry->d_name) + 1);
478 if (len >= sizeof(buf)) {
479 warnf("Skipping '%s': len > sizeof(buf); %lu > %lu\n", path,
480 (unsigned long)len, (unsigned long)sizeof(buf));
481 continue;
482 }
483 snprintf(buf, sizeof(buf), "%s%s%s", path, (path[pathlen-1] == '/') ? "" : "/", dentry->d_name);
484 if (lstat(buf, &st) != -1) {
485 if (S_ISREG(st.st_mode))
486 ret = scanmacho_file(buf, &st);
487 else if (dir_recurse && S_ISDIR(st.st_mode)) {
488 if (dir_crossmount || (st_top.st_dev == st.st_dev))
489 ret = scanmacho_dir(buf);
490 }
491 }
492 }
493 closedir(dir);
494 return ret;
495 }
496
497 static int scanmacho_from_file(const char *filename)
498 {
499 FILE *fp = NULL;
500 char *p;
501 char path[__PAX_UTILS_PATH_MAX];
502 int ret = 0;
503
504 if (strcmp(filename, "-") == 0)
505 fp = stdin;
506 else if ((fp = fopen(filename, "r")) == NULL)
507 return 1;
508
509 while ((fgets(path, __PAX_UTILS_PATH_MAX, fp)) != NULL) {
510 if ((p = strchr(path, '\n')) != NULL)
511 *p = 0;
512 search_path = path;
513 ret = scanmacho_dir(path);
514 }
515 if (fp != stdin)
516 fclose(fp);
517 return ret;
518 }
519
520 /* scan env PATH for paths */
521 static void scanelf_envpath(void)
522 {
523 char *path, *p;
524
525 path = getenv("PATH");
526 if (!path)
527 err("PATH is not set in your env !");
528 path = xstrdup(path);
529
530 while ((p = strrchr(path, ':')) != NULL) {
531 scanmacho_dir(p + 1);
532 *p = 0;
533 }
534
535 free(path);
536 }
537
538 /* usage / invocation handling functions */ /* Free Flags: c d e j k l r s t u w x z C G H I J K L P Q T U W X Y */
539 #define PARSE_FLAGS "pRmyAnibSN:gE:M:DO:ZaqvF:f:o:BhV"
540 #define a_argument required_argument
541 static struct option const long_opts[] = {
542 {"path", no_argument, NULL, 'p'},
543 {"recursive", no_argument, NULL, 'R'},
544 {"mount", no_argument, NULL, 'm'},
545 {"symlink", no_argument, NULL, 'y'},
546 {"archives", no_argument, NULL, 'A'},
547 {"needed", no_argument, NULL, 'n'},
548 {"interp", no_argument, NULL, 'i'},
549 {"bind", no_argument, NULL, 'b'},
550 {"soname", no_argument, NULL, 'S'},
551 {"lib", a_argument, NULL, 'N'},
552 {"gmatch", no_argument, NULL, 'g'},
553 {"etype", a_argument, NULL, 'E'},
554 {"bits", a_argument, NULL, 'M'},
555 {"endian", no_argument, NULL, 'D'},
556 {"perms", a_argument, NULL, 'O'},
557 {"size", no_argument, NULL, 'Z'},
558 {"all", no_argument, NULL, 'a'},
559 {"quiet", no_argument, NULL, 'q'},
560 {"verbose", no_argument, NULL, 'v'},
561 {"format", a_argument, NULL, 'F'},
562 {"from", a_argument, NULL, 'f'},
563 {"file", a_argument, NULL, 'o'},
564 {"nobanner", no_argument, NULL, 'B'},
565 {"help", no_argument, NULL, 'h'},
566 {"version", no_argument, NULL, 'V'},
567 {NULL, no_argument, NULL, 0x0}
568 };
569
570 static const char *opts_help[] = {
571 "Scan all directories in PATH environment",
572 "Scan directories recursively",
573 "Don't recursively cross mount points",
574 "Don't scan symlinks",
575 "Scan archives (.a files)",
576 "Print LC_LOAD_DYLIB information (ELF: NEEDED)",
577 "Print LC_LOAD_DYLINKER information (ELF: INTERP)",
578 "Print flags from mach_header (ELF: BIND)",
579 "Print LC_ID_DYLIB information (ELF: SONAME)",
580 "Find a specified library",
581 "Use strncmp to match libraries. (use with -N)",
582 "Print only Mach-O files matching mach_header\n"
583 " MH_OBJECT,MH_EXECUTE ... (ELF: etype)",
584 "Print only Mach-O files matching numeric bits",
585 "Print Endianness",
586 "Print only Mach-O files matching octal permissions",
587 "Print Mach-O file size",
588 "Print all scanned info (-F\"%o %O %D %b %F\")\n",
589 "Only output 'bad' things",
590 "Be verbose (can be specified more than once)",
591 "Use specified format for output",
592 "Read input stream from a filename",
593 "Write output stream to a filename",
594 "Don't display the header",
595 "Print this help and exit",
596 "Print version and exit",
597 NULL
598 };
599
600 /* display usage and exit */
601 static void usage(int status)
602 {
603 unsigned long i;
604 printf("* Scan Mach-O binaries for stuff\n\n"
605 "Usage: %s [options] <dir1/file1> [dir2 dirN file2 fileN ...]\n\n", argv0);
606 printf("Options: -[%s]\n", PARSE_FLAGS);
607 for (i = 0; long_opts[i].name; ++i)
608 if (long_opts[i].has_arg == no_argument)
609 printf(" -%c, --%-14s* %s\n", long_opts[i].val,
610 long_opts[i].name, opts_help[i]);
611 else
612 printf(" -%c, --%-7s <arg> * %s\n", long_opts[i].val,
613 long_opts[i].name, opts_help[i]);
614
615 puts("\nFor more information, see the scanmacho(1) manpage");
616 exit(status);
617 }
618
619 /* parse command line arguments and preform needed actions */
620 static int parseargs(int argc, char *argv[])
621 {
622 int i;
623 const char *from_file = NULL;
624 int ret = 0;
625
626 opterr = 0;
627 while ((i = getopt_long(argc, argv, PARSE_FLAGS, long_opts, NULL)) != -1) {
628 switch (i) {
629
630 case 'V':
631 printf("pax-utils-%s: %s compiled %s\n%s\n"
632 "%s written for Gentoo by <solar, vapier and grobian @ gentoo.org>\n",
633 VERSION, __FILE__, __DATE__, rcsid, argv0);
634 exit(EXIT_SUCCESS);
635 break;
636 case 'h': usage(EXIT_SUCCESS); break;
637 case 'f':
638 if (from_file) warn("You prob don't want to specify -f twice");
639 from_file = optarg;
640 break;
641 case 'E':
642 strncpy(match_etypes, optarg, sizeof(match_etypes));
643 break;
644 case 'M':
645 match_bits = atoi(optarg);
646 break;
647 case 'O':
648 if (sscanf(optarg, "%o", &match_perms) == (-1))
649 match_bits = 0;
650 break;
651 case 'o': {
652 if (freopen(optarg, "w", stdout) == NULL)
653 err("Could not open output stream '%s': %s", optarg, strerror(errno));
654 break;
655 }
656 case 'N': {
657 if (find_lib) warn("You prob don't want to specify -N twice");
658 find_lib = optarg;
659 break;
660 }
661 case 'F': {
662 if (out_format) warn("You prob don't want to specify -F twice");
663 out_format = optarg;
664 break;
665 }
666 case 'Z': show_size = 1; break;
667 case 'g': g_match = 1; break;
668 case 'y': scan_symlink = 0; break;
669 case 'A': scan_archives = 1; break;
670 case 'B': show_banner = 0; break;
671 case 'p': scan_envpath = 1; break;
672 case 'R': dir_recurse = 1; break;
673 case 'm': dir_crossmount = 0; break;
674 case 'n': show_needed = 1; break;
675 case 'i': show_interp = 1; break;
676 case 'b': show_bind = 1; break;
677 case 'S': show_soname = 1; break;
678 case 'q': be_quiet = 1; break;
679 case 'v': be_verbose = (be_verbose % 20) + 1; break;
680 case 'a': show_perms = show_endian = show_bind = 1; break;
681 case 'D': show_endian = 1; break;
682 case ':':
683 err("Option '%c' is missing parameter", optopt);
684 case '?':
685 err("Unknown option '%c' or argument missing", optopt);
686 default:
687 err("Unhandled option '%c'; please report this", i);
688 }
689 }
690 /* let the format option override all other options */
691 if (out_format) {
692 show_needed = show_interp = show_bind = show_soname = \
693 show_perms = show_endian = show_size = 0;
694 for (i = 0; out_format[i]; ++i) {
695 if (!IS_MODIFIER(out_format[i])) continue;
696
697 switch (out_format[++i]) {
698 case '+': break;
699 case '%': break;
700 case '#': break;
701 case 'F': break;
702 case 'p': break;
703 case 'f': break;
704 case 'k': break;
705 case 'N': break;
706 case 'o': break;
707 case 'a': break;
708 case 'M': break;
709 case 'Z': show_size = 1; break;
710 case 'D': show_endian = 1; break;
711 case 'O': show_perms = 1; break;
712 case 'n': show_needed = 1; break;
713 case 'i': show_interp = 1; break;
714 case 'b': show_bind = 1; break;
715 case 'S': show_soname = 1; break;
716 default:
717 err("Invalid format specifier '%c' (byte %i)",
718 out_format[i], i+1);
719 }
720 }
721
722 /* construct our default format */
723 } else {
724 size_t fmt_len = 30;
725 out_format = xmalloc(sizeof(char) * fmt_len);
726 *out_format = '\0';
727 if (!be_quiet) xstrcat(&out_format, "%a ", &fmt_len);
728 if (!be_quiet) xstrcat(&out_format, "%o ", &fmt_len);
729 if (show_perms) xstrcat(&out_format, "%O ", &fmt_len);
730 if (show_size) xstrcat(&out_format, "%Z ", &fmt_len);
731 if (show_endian) xstrcat(&out_format, "%D ", &fmt_len);
732 if (show_needed) xstrcat(&out_format, "%n ", &fmt_len);
733 if (show_interp) xstrcat(&out_format, "%i ", &fmt_len);
734 if (show_bind) xstrcat(&out_format, "%b ", &fmt_len);
735 if (show_soname) xstrcat(&out_format, "%S ", &fmt_len);
736 if (find_lib) xstrcat(&out_format, "%N ", &fmt_len);
737 if (!be_quiet) xstrcat(&out_format, "%F ", &fmt_len);
738 }
739 if (be_verbose > 2) printf("Format: %s\n", out_format);
740
741 /* now lets actually do the scanning */
742 if (scan_envpath)
743 scanelf_envpath();
744 if (!from_file && optind == argc && ttyname(0) == NULL && !scan_envpath)
745 from_file = "-";
746 if (from_file) {
747 scanmacho_from_file(from_file);
748 from_file = *argv;
749 }
750 if (optind == argc && !scan_envpath && !from_file)
751 err("Nothing to scan !?");
752 while (optind < argc) {
753 search_path = argv[optind++];
754 ret = scanmacho_dir(search_path);
755 }
756
757 return ret;
758 }
759
760 int main(int argc, char *argv[])
761 {
762 int ret;
763 if (argc < 2)
764 usage(EXIT_FAILURE);
765 ret = parseargs(argc, argv);
766 fclose(stdout);
767 return ret;
768 }

  ViewVC Help
Powered by ViewVC 1.1.20