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

Contents of /pax-utils/scanmacho.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.11 - (hide annotations) (download) (as text)
Tue Dec 30 13:13:15 2008 UTC (5 years, 8 months ago) by vapier
Branch: MAIN
Changes since 1.10: +3 -3 lines
File MIME type: text/x-csrc
drop excessive parenthesis

1 grobian 1.1 /*
2     * Copyright 2008 Gentoo Foundation
3     * Distributed under the terms of the GNU General Public License v2
4 vapier 1.11 * $Header: /var/cvsroot/gentoo-projects/pax-utils/scanmacho.c,v 1.10 2008/12/30 13:09:20 vapier 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 vapier 1.11 static const char *rcsid = "$Id: scanmacho.c,v 1.10 2008/12/30 13:09:20 vapier 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 vapier 1.9 static int match_bits = 0;
54     static unsigned int match_perms = 0;
55 grobian 1.1
56 vapier 1.10 static const char *getstr_perms(const char *fname)
57 grobian 1.1 {
58     struct stat st;
59     static char buf[8];
60    
61 vapier 1.10 if (stat(fname, &st) == -1)
62     return "";
63 grobian 1.1
64     snprintf(buf, sizeof(buf), "%o", st.st_mode);
65    
66 vapier 1.10 return buf + 2;
67 grobian 1.1 }
68    
69     static const char *macho_file_needed_lib(
70     fatobj *fobj,
71     char *found_needed,
72     char *found_lib,
73     int op,
74     char **ret,
75     size_t *ret_len
76     ) {
77     char *needed;
78     loadcmd *lcmd;
79     struct dylib_command *dlcmd;
80     uint32_t lc_load_dylib = LC_LOAD_DYLIB;
81    
82     if ((op == 0 && !show_needed) || (op == 1 && !find_lib))
83     return NULL;
84    
85     lcmd = firstloadcmd(fobj);
86    
87     if (fobj->swapped)
88     lc_load_dylib = bswap_32(lc_load_dylib);
89    
90     do {
91     if (lcmd->lcmd->cmd == lc_load_dylib) {
92     dlcmd = (struct dylib_command*)lcmd->data;
93     if (fobj->swapped) {
94     needed = (char *)(lcmd->data +
95     bswap_32(dlcmd->dylib.name.offset));
96     } else {
97     needed = (char *)(lcmd->data + dlcmd->dylib.name.offset);
98     }
99     if (op == 0) {
100     if (!be_wewy_wewy_quiet) {
101     if (*found_needed)
102     xchrcat(ret, ',', ret_len);
103     xstrcat(ret, needed, ret_len);
104     }
105     *found_needed = 1;
106     } else {
107     if (!strncmp(find_lib, needed,
108     strlen(!g_match ? needed : find_lib)))
109     {
110     *found_lib = 1;
111     free(lcmd);
112     return (be_wewy_wewy_quiet ? NULL : needed);
113     }
114     }
115     }
116     } while (nextloadcmd(lcmd));
117    
118     if (op == 0 && !*found_needed && be_verbose)
119     warn("Mach-O lacks LC_LOAD_DYLIB commands: %s", fobj->filename);
120    
121     return NULL;
122     }
123    
124     static char *macho_file_interp(fatobj *fobj, char *found_interp)
125     {
126     loadcmd *lcmd;
127     uint32_t lc_load_dylinker = LC_LOAD_DYLINKER;
128    
129     if (!show_interp)
130     return NULL;
131    
132     lcmd = firstloadcmd(fobj);
133    
134     if (fobj->swapped)
135     lc_load_dylinker = bswap_32(lc_load_dylinker);
136    
137     do {
138     if (lcmd->lcmd->cmd == lc_load_dylinker) {
139     struct dylinker_command *dlcmd =
140     (struct dylinker_command*)lcmd->data;
141     char *dylinker;
142     if (fobj->swapped) {
143     dylinker = (char *)(lcmd->data +
144     bswap_32(dlcmd->name.offset));
145     } else {
146     dylinker = (char *)(lcmd->data + dlcmd->name.offset);
147     }
148     *found_interp = 1;
149     free(lcmd);
150     return (be_wewy_wewy_quiet ? NULL : dylinker);
151     }
152     } while (nextloadcmd(lcmd));
153 vapier 1.7
154 grobian 1.1 return NULL;
155     }
156    
157     static char *macho_file_soname(fatobj *fobj, char *found_soname)
158     {
159     loadcmd *lcmd;
160     char *soname;
161     uint32_t lc_id_dylib = LC_ID_DYLIB;
162    
163     if (!show_soname)
164     return NULL;
165    
166     lcmd = firstloadcmd(fobj);
167    
168     if (fobj->swapped)
169     lc_id_dylib = bswap_32(lc_id_dylib);
170    
171     do {
172     if (lcmd->lcmd->cmd == lc_id_dylib) {
173     struct dylib_command *dlcmd = (struct dylib_command*)lcmd->data;
174     if (fobj->swapped) {
175     soname = (char *)(lcmd->data +
176     bswap_32(dlcmd->dylib.name.offset));
177     } else {
178     soname = (char *)(lcmd->data + dlcmd->dylib.name.offset);
179     }
180     *found_soname = 1;
181     free(lcmd);
182     return (be_wewy_wewy_quiet ? NULL : soname);
183     }
184     } while (nextloadcmd(lcmd));
185 vapier 1.7
186 grobian 1.1 return NULL;
187     }
188    
189     /* scan a macho file and show all the fun stuff */
190     #define prints(str) write(fileno(stdout), str, strlen(str))
191     static int scanmacho_fatobj(fatobj *fobj)
192     {
193     unsigned long i;
194     char found_needed, found_interp, found_soname, found_lib, found_file;
195     static char *out_buffer = NULL;
196     static size_t out_len;
197    
198     found_needed = found_interp = found_soname = \
199     found_lib = found_file = 0;
200    
201     if (be_verbose > 2)
202     printf("%s: scanning file {%s,%s}\n", fobj->filename,
203     get_machocputype(fobj),
204     get_machosubcputype(fobj));
205     else if (be_verbose > 1)
206     printf("%s: scanning file\n", fobj->filename);
207    
208     /* init output buffer */
209     if (!out_buffer) {
210     out_len = sizeof(char) * 80;
211     out_buffer = xmalloc(out_len);
212     }
213     *out_buffer = '\0';
214    
215     /* show the header */
216     if (!be_quiet && show_banner) {
217     for (i = 0; out_format[i]; ++i) {
218     if (!IS_MODIFIER(out_format[i])) continue;
219    
220     switch (out_format[++i]) {
221     case '+': break;
222     case '%': break;
223     case '#': break;
224     case 'F':
225     case 'p':
226     case 'f': prints("FILE "); found_file = 1; break;
227     case 'o': prints(" TYPE "); break;
228     case 'M': prints("CPU "); break;
229     case 'n': prints("NEEDED "); break;
230     case 'i': prints("DYLINKER "); break;
231     case 'b': prints("FLAGS "); break;
232     case 'Z': prints("SIZE "); break;
233     case 'S': prints("INSTALLNAME "); break;
234     case 'N': prints("LIB "); break;
235     case 'a': prints("ARCH "); break;
236     case 'O': prints("PERM "); break;
237     case 'D': prints("ENDIAN "); break;
238     default: warnf("'%c' has no title ?", out_format[i]);
239     }
240     }
241     if (!found_file) prints("FILE ");
242     prints("\n");
243     found_file = 0;
244     show_banner = 0;
245     }
246    
247     /* dump all the good stuff */
248     for (i = 0; out_format[i]; ++i) {
249     const char *out;
250     const char *tmp;
251     static char ubuf[sizeof(unsigned long)*2];
252     if (!IS_MODIFIER(out_format[i])) {
253     xchrcat(&out_buffer, out_format[i], &out_len);
254     continue;
255     }
256    
257     out = NULL;
258     be_wewy_wewy_quiet = (out_format[i] == '#');
259     be_semi_verbose = (out_format[i] == '+');
260     switch (out_format[++i]) {
261     case '+':
262     case '%':
263     case '#':
264     xchrcat(&out_buffer, out_format[i], &out_len); break;
265     case 'F':
266     found_file = 1;
267     if (be_wewy_wewy_quiet) break;
268     xstrcat(&out_buffer, fobj->filename, &out_len);
269     break;
270     case 'p':
271     found_file = 1;
272     if (be_wewy_wewy_quiet) break;
273     tmp = fobj->filename;
274     if (search_path) {
275     ssize_t len_search = strlen(search_path);
276     ssize_t len_file = strlen(fobj->filename);
277     if (!strncmp(fobj->filename, search_path, len_search) && \
278     len_file > len_search)
279     tmp += len_search;
280     if (*tmp == '/' && search_path[len_search-1] == '/') tmp++;
281     }
282     xstrcat(&out_buffer, tmp, &out_len);
283     break;
284     case 'f':
285     found_file = 1;
286     if (be_wewy_wewy_quiet) break;
287     xstrcat(&out_buffer, fobj->base_filename, &out_len);
288     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 = getstr_perms(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_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 grobian 1.2 /* scan a single Mach-O */
327 grobian 1.1 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 grobian 1.2 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 grobian 1.1 }
365 grobian 1.2 } while (walk->next != NULL && (walk = walk->next));
366     goto label_done;
367 grobian 1.1 }
368 grobian 1.2
369 grobian 1.1 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 vapier 1.6 ar_buffer = mmap(0, len, PROT_READ, MAP_PRIVATE, fd, 0);
393 grobian 1.1 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 grobian 1.5 fobj->data = NULL;
401 grobian 1.1 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 grobian 1.4 /* scan a directory for Mach-O files and print when we find one */
445 grobian 1.1 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    
465     /* now scan the dir looking for fun stuff */
466     if ((dir = opendir(path)) == NULL) {
467     warnf("could not opendir %s: %s", path, strerror(errno));
468     return 1;
469     }
470     if (be_verbose > 1) printf("%s: scanning dir\n", path);
471    
472     pathlen = strlen(path);
473     while ((dentry = readdir(dir))) {
474     if (!strcmp(dentry->d_name, ".") || !strcmp(dentry->d_name, ".."))
475     continue;
476     len = (pathlen + 1 + strlen(dentry->d_name) + 1);
477     if (len >= sizeof(buf)) {
478     warnf("Skipping '%s': len > sizeof(buf); %lu > %lu\n", path,
479     (unsigned long)len, (unsigned long)sizeof(buf));
480     continue;
481     }
482     snprintf(buf, sizeof(buf), "%s%s%s", path, (path[pathlen-1] == '/') ? "" : "/", dentry->d_name);
483     if (lstat(buf, &st) != -1) {
484     if (S_ISREG(st.st_mode))
485     ret = scanmacho_file(buf, &st);
486     else if (dir_recurse && S_ISDIR(st.st_mode)) {
487     if (dir_crossmount || (st_top.st_dev == st.st_dev))
488     ret = scanmacho_dir(buf);
489     }
490     }
491     }
492     closedir(dir);
493     return ret;
494     }
495    
496     static int scanmacho_from_file(const char *filename)
497     {
498     FILE *fp = NULL;
499     char *p;
500     char path[__PAX_UTILS_PATH_MAX];
501     int ret = 0;
502    
503     if (strcmp(filename, "-") == 0)
504     fp = stdin;
505     else if ((fp = fopen(filename, "r")) == NULL)
506     return 1;
507    
508     while ((fgets(path, __PAX_UTILS_PATH_MAX, fp)) != NULL) {
509     if ((p = strchr(path, '\n')) != NULL)
510     *p = 0;
511     search_path = path;
512     ret = scanmacho_dir(path);
513     }
514     if (fp != stdin)
515     fclose(fp);
516     return ret;
517     }
518    
519     /* scan env PATH for paths */
520     static void scanelf_envpath(void)
521     {
522     char *path, *p;
523    
524     path = getenv("PATH");
525     if (!path)
526     err("PATH is not set in your env !");
527     path = xstrdup(path);
528    
529     while ((p = strrchr(path, ':')) != NULL) {
530     scanmacho_dir(p + 1);
531     *p = 0;
532     }
533    
534     free(path);
535     }
536    
537     /* 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 */
538     #define PARSE_FLAGS "pRmyAnibSN:gE:M:DO:ZaqvF:f:o:BhV"
539     #define a_argument required_argument
540     static struct option const long_opts[] = {
541     {"path", no_argument, NULL, 'p'},
542     {"recursive", no_argument, NULL, 'R'},
543     {"mount", no_argument, NULL, 'm'},
544     {"symlink", no_argument, NULL, 'y'},
545     {"archives", no_argument, NULL, 'A'},
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     {"nobanner", no_argument, NULL, 'B'},
564     {"help", no_argument, NULL, 'h'},
565     {"version", no_argument, NULL, 'V'},
566     {NULL, no_argument, NULL, 0x0}
567     };
568    
569     static const char *opts_help[] = {
570     "Scan all directories in PATH environment",
571     "Scan directories recursively",
572     "Don't recursively cross mount points",
573     "Don't scan symlinks",
574     "Scan archives (.a files)",
575     "Print LC_LOAD_DYLIB information (ELF: NEEDED)",
576     "Print LC_LOAD_DYLINKER information (ELF: INTERP)",
577     "Print flags from mach_header (ELF: BIND)",
578     "Print LC_ID_DYLIB information (ELF: SONAME)",
579     "Find a specified library",
580     "Use strncmp to match libraries. (use with -N)",
581     "Print only Mach-O files matching mach_header\n"
582     " MH_OBJECT,MH_EXECUTE ... (ELF: etype)",
583     "Print only Mach-O files matching numeric bits",
584     "Print Endianness",
585     "Print only Mach-O files matching octal permissions",
586     "Print Mach-O file size",
587     "Print all scanned info (-F\"%o %O %D %b %F\")\n",
588     "Only output 'bad' things",
589     "Be verbose (can be specified more than once)",
590     "Use specified format for output",
591     "Read input stream from a filename",
592     "Write output stream to a filename",
593     "Don't display the header",
594     "Print this help and exit",
595     "Print version and exit",
596     NULL
597     };
598    
599     /* display usage and exit */
600     static void usage(int status)
601     {
602     unsigned long i;
603     printf("* Scan Mach-O binaries for stuff\n\n"
604     "Usage: %s [options] <dir1/file1> [dir2 dirN file2 fileN ...]\n\n", argv0);
605     printf("Options: -[%s]\n", PARSE_FLAGS);
606     for (i = 0; long_opts[i].name; ++i)
607     if (long_opts[i].has_arg == no_argument)
608     printf(" -%c, --%-14s* %s\n", long_opts[i].val,
609     long_opts[i].name, opts_help[i]);
610     else
611     printf(" -%c, --%-7s <arg> * %s\n", long_opts[i].val,
612     long_opts[i].name, opts_help[i]);
613    
614     puts("\nFor more information, see the scanmacho(1) manpage");
615     exit(status);
616     }
617    
618     /* parse command line arguments and preform needed actions */
619     static int parseargs(int argc, char *argv[])
620     {
621     int i;
622     const char *from_file = NULL;
623     int ret = 0;
624    
625     opterr = 0;
626     while ((i = getopt_long(argc, argv, PARSE_FLAGS, long_opts, NULL)) != -1) {
627     switch (i) {
628    
629     case 'V':
630     printf("pax-utils-%s: %s compiled %s\n%s\n"
631     "%s written for Gentoo by <solar, vapier and grobian @ gentoo.org>\n",
632     VERSION, __FILE__, __DATE__, rcsid, argv0);
633     exit(EXIT_SUCCESS);
634     break;
635     case 'h': usage(EXIT_SUCCESS); break;
636     case 'f':
637     if (from_file) warn("You prob don't want to specify -f twice");
638     from_file = optarg;
639     break;
640     case 'E':
641     strncpy(match_etypes, optarg, sizeof(match_etypes));
642     break;
643     case 'M':
644     match_bits = atoi(optarg);
645     break;
646     case 'O':
647 vapier 1.11 if (sscanf(optarg, "%o", &match_perms) == -1)
648 grobian 1.1 match_bits = 0;
649     break;
650     case 'o': {
651     if (freopen(optarg, "w", stdout) == NULL)
652     err("Could not open output stream '%s': %s", optarg, strerror(errno));
653     break;
654     }
655     case 'N': {
656     if (find_lib) warn("You prob don't want to specify -N twice");
657     find_lib = optarg;
658     break;
659     }
660     case 'F': {
661     if (out_format) warn("You prob don't want to specify -F twice");
662     out_format = optarg;
663     break;
664     }
665     case 'Z': show_size = 1; break;
666     case 'g': g_match = 1; break;
667     case 'y': scan_symlink = 0; break;
668     case 'A': scan_archives = 1; break;
669     case 'B': show_banner = 0; break;
670     case 'p': scan_envpath = 1; break;
671     case 'R': dir_recurse = 1; break;
672     case 'm': dir_crossmount = 0; break;
673     case 'n': show_needed = 1; break;
674     case 'i': show_interp = 1; break;
675     case 'b': show_bind = 1; break;
676     case 'S': show_soname = 1; break;
677     case 'q': be_quiet = 1; break;
678     case 'v': be_verbose = (be_verbose % 20) + 1; break;
679     case 'a': show_perms = show_endian = show_bind = 1; break;
680     case 'D': show_endian = 1; break;
681     case ':':
682     err("Option '%c' is missing parameter", optopt);
683     case '?':
684     err("Unknown option '%c' or argument missing", optopt);
685     default:
686     err("Unhandled option '%c'; please report this", i);
687     }
688     }
689     /* let the format option override all other options */
690     if (out_format) {
691     show_needed = show_interp = show_bind = show_soname = \
692     show_perms = show_endian = show_size = 0;
693     for (i = 0; out_format[i]; ++i) {
694     if (!IS_MODIFIER(out_format[i])) continue;
695    
696     switch (out_format[++i]) {
697     case '+': break;
698     case '%': break;
699     case '#': break;
700     case 'F': break;
701     case 'p': break;
702     case 'f': break;
703     case 'k': break;
704     case 'N': break;
705     case 'o': break;
706     case 'a': break;
707     case 'M': break;
708     case 'Z': show_size = 1; break;
709     case 'D': show_endian = 1; break;
710     case 'O': show_perms = 1; break;
711     case 'n': show_needed = 1; break;
712     case 'i': show_interp = 1; break;
713     case 'b': show_bind = 1; break;
714     case 'S': show_soname = 1; break;
715     default:
716     err("Invalid format specifier '%c' (byte %i)",
717     out_format[i], i+1);
718     }
719     }
720    
721     /* construct our default format */
722     } else {
723     size_t fmt_len = 30;
724     out_format = xmalloc(sizeof(char) * fmt_len);
725     *out_format = '\0';
726 grobian 1.3 if (!be_quiet) xstrcat(&out_format, "%a ", &fmt_len);
727 grobian 1.1 if (!be_quiet) xstrcat(&out_format, "%o ", &fmt_len);
728     if (show_perms) xstrcat(&out_format, "%O ", &fmt_len);
729     if (show_size) xstrcat(&out_format, "%Z ", &fmt_len);
730     if (show_endian) xstrcat(&out_format, "%D ", &fmt_len);
731     if (show_needed) xstrcat(&out_format, "%n ", &fmt_len);
732     if (show_interp) xstrcat(&out_format, "%i ", &fmt_len);
733     if (show_bind) xstrcat(&out_format, "%b ", &fmt_len);
734     if (show_soname) xstrcat(&out_format, "%S ", &fmt_len);
735     if (find_lib) xstrcat(&out_format, "%N ", &fmt_len);
736     if (!be_quiet) xstrcat(&out_format, "%F ", &fmt_len);
737     }
738     if (be_verbose > 2) printf("Format: %s\n", out_format);
739    
740     /* now lets actually do the scanning */
741     if (scan_envpath)
742     scanelf_envpath();
743     if (!from_file && optind == argc && ttyname(0) == NULL && !scan_envpath)
744     from_file = "-";
745     if (from_file) {
746     scanmacho_from_file(from_file);
747     from_file = *argv;
748     }
749     if (optind == argc && !scan_envpath && !from_file)
750     err("Nothing to scan !?");
751     while (optind < argc) {
752     search_path = argv[optind++];
753     ret = scanmacho_dir(search_path);
754     }
755    
756     return ret;
757     }
758    
759     int main(int argc, char *argv[])
760     {
761     int ret;
762     if (argc < 2)
763     usage(EXIT_FAILURE);
764     ret = parseargs(argc, argv);
765     fclose(stdout);
766     return ret;
767     }

  ViewVC Help
Powered by ViewVC 1.1.20