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

Contents of /pax-utils/scanmacho.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.24 - (show annotations) (download) (as text)
Mon Dec 16 20:30:38 2013 UTC (12 months, 1 week ago) by grobian
Branch: MAIN
CVS Tags: HEAD
Changes since 1.23: +50 -9 lines
File MIME type: text/x-csrc
scanmacho: add support to read LC_RPATH entries from Mach-O files

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

  ViewVC Help
Powered by ViewVC 1.1.20