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

Contents of /pax-utils/scanmacho.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.5 - (hide annotations) (download) (as text)
Sun Oct 19 18:11:59 2008 UTC (5 years, 5 months ago) by grobian
Branch: MAIN
Changes since 1.4: +3 -2 lines
File MIME type: text/x-csrc
Made reading archives work.

The Darwin linker creates BSD ar archives, which (stupidly) always use
the "extended filename" method to store filenames.  For this reason I
implemented the BSD extended filename method in paxinc's ar_next.
Next to some fixes in the macho code not to free and unmap when this is
not desired, this yields in a working scanmacho on static archives.

The change has been checked with scanelf against a GNU ELF static
archive not to break anything.

1 grobian 1.1 /*
2     * Copyright 2008 Gentoo Foundation
3     * Distributed under the terms of the GNU General Public License v2
4 grobian 1.5 * $Header: /var/cvsroot/gentoo-projects/pax-utils/scanmacho.c,v 1.4 2008/09/12 19:59:26 grobian Exp $
5 grobian 1.1 *
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 grobian 1.5 static const char *rcsid = "$Id: scanmacho.c,v 1.4 2008/09/12 19:59:26 grobian Exp $";
14 grobian 1.1 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 grobian 1.2 /* scan a single Mach-O */
334 grobian 1.1 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     if (strlen(match_etypes)) {
361 grobian 1.2 char sbuf[128];
362     char ftype[32];
363    
364     snprintf(sbuf, 128, ",%s,", match_etypes);
365    
366     walk = fobj;
367     do {
368     snprintf(ftype, 32, ",%s,", get_machomhtype(walk));
369     if (strstr(sbuf, ftype) != NULL) {
370     ret = scanmacho_fatobj(walk);
371 grobian 1.1 }
372 grobian 1.2 } while (walk->next != NULL && (walk = walk->next));
373     goto label_done;
374 grobian 1.1 }
375 grobian 1.2
376 grobian 1.1 walk = fobj;
377     do {
378     ret = scanmacho_fatobj(walk);
379     } while (walk->next != NULL && (walk = walk->next));
380    
381     label_done:
382     unreadmacho(fobj);
383     return ret;
384     }
385    
386     /* scan an archive of Mach-Os */
387     static int scanmacho_archive(const char *filename, int fd, size_t len)
388     {
389     archive_handle *ar;
390     archive_member *m;
391     char *ar_buffer;
392     fatobj *fobj;
393     fatobj *walk;
394    
395     ar = ar_open_fd(filename, fd);
396     if (ar == NULL)
397     return 1;
398    
399     ar_buffer = (char*)mmap(0, len, PROT_READ, MAP_PRIVATE, fd, 0);
400     while ((m = ar_next(ar)) != NULL) {
401     fobj = readmacho_buffer(m->name, ar_buffer + lseek(fd, 0, SEEK_CUR), m->size);
402     if (fobj) {
403     walk = fobj;
404     do {
405     scanmacho_fatobj(walk);
406     } while (walk->next != NULL && (walk = walk->next));
407 grobian 1.5 fobj->data = NULL;
408 grobian 1.1 unreadmacho(fobj);
409     }
410     }
411     munmap(ar_buffer, len);
412    
413     return 0;
414     }
415     /* scan a file which may be an Mach-O or an archive or some other
416     * magical beast */
417     static int scanmacho_file(const char *filename, const struct stat *st_cache)
418     {
419     const struct stat *st = st_cache;
420     struct stat symlink_st;
421     int fd;
422    
423     /* always handle regular files and handle symlinked files if no -y */
424     if (S_ISLNK(st->st_mode)) {
425     if (!scan_symlink)
426     return 1;
427     stat(filename, &symlink_st);
428     st = &symlink_st;
429     }
430    
431     if (!S_ISREG(st->st_mode)) {
432     if (be_verbose > 2) printf("%s: skipping non-file\n", filename);
433     return 1;
434     }
435    
436     if (match_perms) {
437     if ((st->st_mode | match_perms) != st->st_mode)
438     return 1;
439     }
440     if ((fd = open(filename, O_RDONLY)) == -1)
441     return 1;
442    
443     if (scanmacho_fat(filename, fd, st->st_size) == 1 && scan_archives)
444     /* if it isn't an Mach-O, maybe it's an .a archive */
445     scanmacho_archive(filename, fd, st->st_size);
446    
447     close(fd);
448     return 0;
449     }
450    
451 grobian 1.4 /* scan a directory for Mach-O files and print when we find one */
452 grobian 1.1 static int scanmacho_dir(const char *path)
453     {
454     register DIR *dir;
455     register struct dirent *dentry;
456     struct stat st_top, st;
457     char buf[__PAX_UTILS_PATH_MAX];
458     size_t pathlen = 0, len = 0;
459     int ret = 0;
460    
461     /* make sure path exists */
462     if (lstat(path, &st_top) == -1) {
463     if (be_verbose > 2) printf("%s: does not exist\n", path);
464     return 1;
465     }
466    
467     /* ok, if it isn't a directory, assume we can open it */
468     if (!S_ISDIR(st_top.st_mode)) {
469     return scanmacho_file(path, &st_top);
470     }
471    
472     /* now scan the dir looking for fun stuff */
473     if ((dir = opendir(path)) == NULL) {
474     warnf("could not opendir %s: %s", path, strerror(errno));
475     return 1;
476     }
477     if (be_verbose > 1) printf("%s: scanning dir\n", path);
478    
479     pathlen = strlen(path);
480     while ((dentry = readdir(dir))) {
481     if (!strcmp(dentry->d_name, ".") || !strcmp(dentry->d_name, ".."))
482     continue;
483     len = (pathlen + 1 + strlen(dentry->d_name) + 1);
484     if (len >= sizeof(buf)) {
485     warnf("Skipping '%s': len > sizeof(buf); %lu > %lu\n", path,
486     (unsigned long)len, (unsigned long)sizeof(buf));
487     continue;
488     }
489     snprintf(buf, sizeof(buf), "%s%s%s", path, (path[pathlen-1] == '/') ? "" : "/", dentry->d_name);
490     if (lstat(buf, &st) != -1) {
491     if (S_ISREG(st.st_mode))
492     ret = scanmacho_file(buf, &st);
493     else if (dir_recurse && S_ISDIR(st.st_mode)) {
494     if (dir_crossmount || (st_top.st_dev == st.st_dev))
495     ret = scanmacho_dir(buf);
496     }
497     }
498     }
499     closedir(dir);
500     return ret;
501     }
502    
503     static int scanmacho_from_file(const char *filename)
504     {
505     FILE *fp = NULL;
506     char *p;
507     char path[__PAX_UTILS_PATH_MAX];
508     int ret = 0;
509    
510     if (strcmp(filename, "-") == 0)
511     fp = stdin;
512     else if ((fp = fopen(filename, "r")) == NULL)
513     return 1;
514    
515     while ((fgets(path, __PAX_UTILS_PATH_MAX, fp)) != NULL) {
516     if ((p = strchr(path, '\n')) != NULL)
517     *p = 0;
518     search_path = path;
519     ret = scanmacho_dir(path);
520     }
521     if (fp != stdin)
522     fclose(fp);
523     return ret;
524     }
525    
526    
527     /* scan env PATH for paths */
528     static void scanelf_envpath(void)
529     {
530     char *path, *p;
531    
532     path = getenv("PATH");
533     if (!path)
534     err("PATH is not set in your env !");
535     path = xstrdup(path);
536    
537     while ((p = strrchr(path, ':')) != NULL) {
538     scanmacho_dir(p + 1);
539     *p = 0;
540     }
541    
542     free(path);
543     }
544    
545     /* 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 */
546     #define PARSE_FLAGS "pRmyAnibSN:gE:M:DO:ZaqvF:f:o:BhV"
547     #define a_argument required_argument
548     static struct option const long_opts[] = {
549     {"path", no_argument, NULL, 'p'},
550     {"recursive", no_argument, NULL, 'R'},
551     {"mount", no_argument, NULL, 'm'},
552     {"symlink", no_argument, NULL, 'y'},
553     {"archives", no_argument, NULL, 'A'},
554     {"needed", no_argument, NULL, 'n'},
555     {"interp", no_argument, NULL, 'i'},
556     {"bind", no_argument, NULL, 'b'},
557     {"soname", no_argument, NULL, 'S'},
558     {"lib", a_argument, NULL, 'N'},
559     {"gmatch", no_argument, NULL, 'g'},
560     {"etype", a_argument, NULL, 'E'},
561     {"bits", a_argument, NULL, 'M'},
562     {"endian", no_argument, NULL, 'D'},
563     {"perms", a_argument, NULL, 'O'},
564     {"size", no_argument, NULL, 'Z'},
565     {"all", no_argument, NULL, 'a'},
566     {"quiet", no_argument, NULL, 'q'},
567     {"verbose", no_argument, NULL, 'v'},
568     {"format", a_argument, NULL, 'F'},
569     {"from", a_argument, NULL, 'f'},
570     {"file", a_argument, NULL, 'o'},
571     {"nobanner", no_argument, NULL, 'B'},
572     {"help", no_argument, NULL, 'h'},
573     {"version", no_argument, NULL, 'V'},
574     {NULL, no_argument, NULL, 0x0}
575     };
576    
577     static const char *opts_help[] = {
578     "Scan all directories in PATH environment",
579     "Scan directories recursively",
580     "Don't recursively cross mount points",
581     "Don't scan symlinks",
582     "Scan archives (.a files)",
583     "Print LC_LOAD_DYLIB information (ELF: NEEDED)",
584     "Print LC_LOAD_DYLINKER information (ELF: INTERP)",
585     "Print flags from mach_header (ELF: BIND)",
586     "Print LC_ID_DYLIB information (ELF: SONAME)",
587     "Find a specified library",
588     "Use strncmp to match libraries. (use with -N)",
589     "Print only Mach-O files matching mach_header\n"
590     " MH_OBJECT,MH_EXECUTE ... (ELF: etype)",
591     "Print only Mach-O files matching numeric bits",
592     "Print Endianness",
593     "Print only Mach-O files matching octal permissions",
594     "Print Mach-O file size",
595     "Print all scanned info (-F\"%o %O %D %b %F\")\n",
596     "Only output 'bad' things",
597     "Be verbose (can be specified more than once)",
598     "Use specified format for output",
599     "Read input stream from a filename",
600     "Write output stream to a filename",
601     "Don't display the header",
602     "Print this help and exit",
603     "Print version and exit",
604     NULL
605     };
606    
607     /* display usage and exit */
608     static void usage(int status)
609     {
610     unsigned long i;
611     printf("* Scan Mach-O binaries for stuff\n\n"
612     "Usage: %s [options] <dir1/file1> [dir2 dirN file2 fileN ...]\n\n", argv0);
613     printf("Options: -[%s]\n", PARSE_FLAGS);
614     for (i = 0; long_opts[i].name; ++i)
615     if (long_opts[i].has_arg == no_argument)
616     printf(" -%c, --%-14s* %s\n", long_opts[i].val,
617     long_opts[i].name, opts_help[i]);
618     else
619     printf(" -%c, --%-7s <arg> * %s\n", long_opts[i].val,
620     long_opts[i].name, opts_help[i]);
621    
622     puts("\nFor more information, see the scanmacho(1) manpage");
623     exit(status);
624     }
625    
626     /* parse command line arguments and preform needed actions */
627     static int parseargs(int argc, char *argv[])
628     {
629     int i;
630     const char *from_file = NULL;
631     int ret = 0;
632    
633     opterr = 0;
634     while ((i = getopt_long(argc, argv, PARSE_FLAGS, long_opts, NULL)) != -1) {
635     switch (i) {
636    
637     case 'V':
638     printf("pax-utils-%s: %s compiled %s\n%s\n"
639     "%s written for Gentoo by <solar, vapier and grobian @ gentoo.org>\n",
640     VERSION, __FILE__, __DATE__, rcsid, argv0);
641     exit(EXIT_SUCCESS);
642     break;
643     case 'h': usage(EXIT_SUCCESS); break;
644     case 'f':
645     if (from_file) warn("You prob don't want to specify -f twice");
646     from_file = optarg;
647     break;
648     case 'E':
649     strncpy(match_etypes, optarg, sizeof(match_etypes));
650     break;
651     case 'M':
652     match_bits = atoi(optarg);
653     break;
654     case 'O':
655     if (sscanf(optarg, "%o", &match_perms) == (-1))
656     match_bits = 0;
657     break;
658     case 'o': {
659     if (freopen(optarg, "w", stdout) == NULL)
660     err("Could not open output stream '%s': %s", optarg, strerror(errno));
661     break;
662     }
663     case 'N': {
664     if (find_lib) warn("You prob don't want to specify -N twice");
665     find_lib = optarg;
666     break;
667     }
668     case 'F': {
669     if (out_format) warn("You prob don't want to specify -F twice");
670     out_format = optarg;
671     break;
672     }
673     case 'Z': show_size = 1; break;
674     case 'g': g_match = 1; break;
675     case 'y': scan_symlink = 0; break;
676     case 'A': scan_archives = 1; break;
677     case 'B': show_banner = 0; break;
678     case 'p': scan_envpath = 1; break;
679     case 'R': dir_recurse = 1; break;
680     case 'm': dir_crossmount = 0; break;
681     case 'n': show_needed = 1; break;
682     case 'i': show_interp = 1; break;
683     case 'b': show_bind = 1; break;
684     case 'S': show_soname = 1; break;
685     case 'q': be_quiet = 1; break;
686     case 'v': be_verbose = (be_verbose % 20) + 1; break;
687     case 'a': show_perms = show_endian = show_bind = 1; break;
688     case 'D': show_endian = 1; break;
689     case ':':
690     err("Option '%c' is missing parameter", optopt);
691     case '?':
692     err("Unknown option '%c' or argument missing", optopt);
693     default:
694     err("Unhandled option '%c'; please report this", i);
695     }
696     }
697     /* let the format option override all other options */
698     if (out_format) {
699     show_needed = show_interp = show_bind = show_soname = \
700     show_perms = show_endian = show_size = 0;
701     for (i = 0; out_format[i]; ++i) {
702     if (!IS_MODIFIER(out_format[i])) continue;
703    
704     switch (out_format[++i]) {
705     case '+': break;
706     case '%': break;
707     case '#': break;
708     case 'F': break;
709     case 'p': break;
710     case 'f': break;
711     case 'k': break;
712     case 'N': break;
713     case 'o': break;
714     case 'a': break;
715     case 'M': break;
716     case 'Z': show_size = 1; break;
717     case 'D': show_endian = 1; break;
718     case 'O': show_perms = 1; break;
719     case 'n': show_needed = 1; break;
720     case 'i': show_interp = 1; break;
721     case 'b': show_bind = 1; break;
722     case 'S': show_soname = 1; break;
723     default:
724     err("Invalid format specifier '%c' (byte %i)",
725     out_format[i], i+1);
726     }
727     }
728    
729     /* construct our default format */
730     } else {
731     size_t fmt_len = 30;
732     out_format = xmalloc(sizeof(char) * fmt_len);
733     *out_format = '\0';
734 grobian 1.3 if (!be_quiet) xstrcat(&out_format, "%a ", &fmt_len);
735 grobian 1.1 if (!be_quiet) xstrcat(&out_format, "%o ", &fmt_len);
736     if (show_perms) xstrcat(&out_format, "%O ", &fmt_len);
737     if (show_size) xstrcat(&out_format, "%Z ", &fmt_len);
738     if (show_endian) xstrcat(&out_format, "%D ", &fmt_len);
739     if (show_needed) xstrcat(&out_format, "%n ", &fmt_len);
740     if (show_interp) xstrcat(&out_format, "%i ", &fmt_len);
741     if (show_bind) xstrcat(&out_format, "%b ", &fmt_len);
742     if (show_soname) xstrcat(&out_format, "%S ", &fmt_len);
743     if (find_lib) xstrcat(&out_format, "%N ", &fmt_len);
744     if (!be_quiet) xstrcat(&out_format, "%F ", &fmt_len);
745     }
746     if (be_verbose > 2) printf("Format: %s\n", out_format);
747    
748     /* now lets actually do the scanning */
749     if (scan_envpath)
750     scanelf_envpath();
751     if (!from_file && optind == argc && ttyname(0) == NULL && !scan_envpath)
752     from_file = "-";
753     if (from_file) {
754     scanmacho_from_file(from_file);
755     from_file = *argv;
756     }
757     if (optind == argc && !scan_envpath && !from_file)
758     err("Nothing to scan !?");
759     while (optind < argc) {
760     search_path = argv[optind++];
761     ret = scanmacho_dir(search_path);
762     }
763    
764     return ret;
765     }
766    
767     int main(int argc, char *argv[])
768     {
769     int ret;
770     if (argc < 2)
771     usage(EXIT_FAILURE);
772     ret = parseargs(argc, argv);
773     fclose(stdout);
774     return ret;
775     }

  ViewVC Help
Powered by ViewVC 1.1.20