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

Contents of /pax-utils/scanmacho.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.16 - (hide annotations) (download) (as text)
Sun Dec 20 20:37:09 2009 UTC (4 years, 8 months ago) by grobian
Branch: MAIN
Changes since 1.15: +4 -4 lines
File MIME type: text/x-csrc
introduce gaps to create groupings of options, like scanelf does

1 grobian 1.1 /*
2     * Copyright 2008 Gentoo Foundation
3     * Distributed under the terms of the GNU General Public License v2
4 grobian 1.16 * $Header: /var/cvsroot/gentoo-projects/pax-utils/scanmacho.c,v 1.15 2009/12/20 20:33:31 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.16 static const char *rcsid = "$Id: scanmacho.c,v 1.15 2009/12/20 20:33:31 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 vapier 1.12 static void scanmacho_envpath(void);
26 grobian 1.1 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     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 vapier 1.12 uint32_t lc_load_dylib;
66 grobian 1.1
67     if ((op == 0 && !show_needed) || (op == 1 && !find_lib))
68     return NULL;
69    
70     lcmd = firstloadcmd(fobj);
71 vapier 1.12 lc_load_dylib = MGET(fobj->swapped, LC_LOAD_DYLIB);
72 grobian 1.1
73     do {
74     if (lcmd->lcmd->cmd == lc_load_dylib) {
75 vapier 1.12 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 grobian 1.1 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 vapier 1.12 uint32_t lc_load_dylinker;
107 grobian 1.1
108     if (!show_interp)
109     return NULL;
110    
111     lcmd = firstloadcmd(fobj);
112 vapier 1.12 lc_load_dylinker = MGET(fobj->swapped, LC_LOAD_DYLINKER);
113 grobian 1.1
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 vapier 1.12 dylinker = (char *)(lcmd->data + MGET(fobj->swapped, dlcmd->name.offset));
120 grobian 1.1 *found_interp = 1;
121     free(lcmd);
122     return (be_wewy_wewy_quiet ? NULL : dylinker);
123     }
124     } while (nextloadcmd(lcmd));
125 vapier 1.7
126 grobian 1.1 return NULL;
127     }
128    
129     static char *macho_file_soname(fatobj *fobj, char *found_soname)
130     {
131     loadcmd *lcmd;
132 vapier 1.12 uint32_t lc_id_dylib;
133 grobian 1.1
134     if (!show_soname)
135     return NULL;
136    
137     lcmd = firstloadcmd(fobj);
138 vapier 1.12 lc_id_dylib = MGET(fobj->swapped, LC_ID_DYLIB);
139 grobian 1.1
140     do {
141     if (lcmd->lcmd->cmd == lc_id_dylib) {
142     struct dylib_command *dlcmd = (struct dylib_command*)lcmd->data;
143 vapier 1.12 char *soname;
144     soname = (char *)(lcmd->data + MGET(fobj->swapped, dlcmd->dylib.name.offset));
145 grobian 1.1 *found_soname = 1;
146     free(lcmd);
147     return (be_wewy_wewy_quiet ? NULL : soname);
148     }
149     } while (nextloadcmd(lcmd));
150 vapier 1.7
151 grobian 1.1 return NULL;
152     }
153    
154     /* scan a macho file and show all the fun stuff */
155 vapier 1.14 #define prints(str) ({ ssize_t ret = write(fileno(stdout), str, strlen(str)); ret; })
156 grobian 1.1 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 vapier 1.13 case 'O': out = strfileperms(fobj->filename); break;
258 grobian 1.1 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 grobian 1.2 /* scan a single Mach-O */
292 grobian 1.1 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 grobian 1.2 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 grobian 1.1 }
330 grobian 1.2 } while (walk->next != NULL && (walk = walk->next));
331     goto label_done;
332 grobian 1.1 }
333 grobian 1.2
334 grobian 1.1 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 vapier 1.6 ar_buffer = mmap(0, len, PROT_READ, MAP_PRIVATE, fd, 0);
358 grobian 1.1 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 grobian 1.5 fobj->data = NULL;
366 grobian 1.1 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 grobian 1.4 /* scan a directory for Mach-O files and print when we find one */
410 grobian 1.1 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 vapier 1.12 if (!S_ISDIR(st_top.st_mode))
427 grobian 1.1 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 vapier 1.12 static void scanmacho_envpath(void)
485 grobian 1.1 {
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 grobian 1.16 "Scan archives (.a files)\n",
539 grobian 1.1 "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 grobian 1.16 "Print all useful/simple info\n",
552 grobian 1.1 "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 vapier 1.11 if (sscanf(optarg, "%o", &match_perms) == -1)
612 grobian 1.1 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 grobian 1.3 if (!be_quiet) xstrcat(&out_format, "%a ", &fmt_len);
691 grobian 1.1 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 vapier 1.12 scanmacho_envpath();
707 grobian 1.1 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