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

Contents of /pax-utils/scanmacho.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.14 - (show annotations) (download) (as text)
Sun Mar 15 08:56:14 2009 UTC (5 years, 7 months ago) by vapier
Branch: MAIN
Changes since 1.13: +3 -3 lines
File MIME type: text/x-csrc
trick gcc into not warning about write() when outputting the banner -- we dont care if this fails

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

  ViewVC Help
Powered by ViewVC 1.1.20