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

Contents of /pax-utils/scanmacho.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.1 - (show annotations) (download) (as text)
Mon Sep 8 07:02:56 2008 UTC (5 years, 7 months ago) by grobian
Branch: MAIN
File MIME type: text/x-csrc
Initial commit of Mach-O related files.  (bug #236512)
- added macho.h (Mach-O definitions) and scanmacho.c (the scanelf
  equivalent for Mach-O files)
- changed the Makefile to compile scanmacho (tested compilation on
  Darwin and Solaris)
- changed paxinc.h to include macho.h and paxmacho.h
- extended paxmacho.[ch] with relevant code to read meta information
  from Mach-O files

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

  ViewVC Help
Powered by ViewVC 1.1.20