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

Contents of /pax-utils/scanmacho.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.20 - (hide annotations) (download) (as text)
Wed Dec 8 01:16:01 2010 UTC (3 years, 9 months ago) by vapier
Branch: MAIN
Changes since 1.19: +8 -4 lines
File MIME type: text/x-csrc
add a -C/--nocolor option and respect env $NOCOLOR #332289

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

  ViewVC Help
Powered by ViewVC 1.1.20