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

Contents of /pax-utils/scanmacho.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.19 - (hide annotations) (download) (as text)
Wed Dec 8 00:54:40 2010 UTC (3 years, 7 months ago) by vapier
Branch: MAIN
Changes since 1.18: +3 -3 lines
File MIME type: text/x-csrc
change to simpler const argv0 string

1 grobian 1.1 /*
2     * Copyright 2008 Gentoo Foundation
3     * Distributed under the terms of the GNU General Public License v2
4 vapier 1.19 * $Header: /var/cvsroot/gentoo-projects/pax-utils/scanmacho.c,v 1.18 2010/04/04 10:03:33 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 grobian 1.18 * 2008-2010 Fabian Groffen - <grobian@gentoo.org>
11 grobian 1.1 */
12    
13 vapier 1.19 static const char *rcsid = "$Id: scanmacho.c,v 1.18 2010/04/04 10:03:33 grobian Exp $";
14     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     /* 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 */
501     #define PARSE_FLAGS "pRmyAnibSN:gE:M:DO:ZaqvF:f:o:BhV"
502     #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     {"nobanner", no_argument, NULL, 'B'},
527     {"help", no_argument, NULL, 'h'},
528     {"version", no_argument, NULL, 'V'},
529     {NULL, no_argument, NULL, 0x0}
530     };
531    
532     static const char *opts_help[] = {
533     "Scan all directories in PATH environment",
534     "Scan directories recursively",
535     "Don't recursively cross mount points",
536     "Don't scan symlinks",
537 grobian 1.16 "Scan archives (.a files)\n",
538 grobian 1.1 "Print LC_LOAD_DYLIB information (ELF: NEEDED)",
539     "Print LC_LOAD_DYLINKER information (ELF: INTERP)",
540     "Print flags from mach_header (ELF: BIND)",
541     "Print LC_ID_DYLIB information (ELF: SONAME)",
542     "Find a specified library",
543     "Use strncmp to match libraries. (use with -N)",
544     "Print only Mach-O files matching mach_header\n"
545     " MH_OBJECT,MH_EXECUTE ... (ELF: etype)",
546     "Print only Mach-O files matching numeric bits",
547     "Print Endianness",
548     "Print only Mach-O files matching octal permissions",
549     "Print Mach-O file size",
550 grobian 1.16 "Print all useful/simple info\n",
551 grobian 1.1 "Only output 'bad' things",
552     "Be verbose (can be specified more than once)",
553     "Use specified format for output",
554     "Read input stream from a filename",
555     "Write output stream to a filename",
556     "Don't display the header",
557     "Print this help and exit",
558     "Print version and exit",
559     NULL
560     };
561    
562     /* display usage and exit */
563     static void usage(int status)
564     {
565     unsigned long i;
566     printf("* Scan Mach-O binaries for stuff\n\n"
567     "Usage: %s [options] <dir1/file1> [dir2 dirN file2 fileN ...]\n\n", argv0);
568     printf("Options: -[%s]\n", PARSE_FLAGS);
569     for (i = 0; long_opts[i].name; ++i)
570     if (long_opts[i].has_arg == no_argument)
571     printf(" -%c, --%-14s* %s\n", long_opts[i].val,
572     long_opts[i].name, opts_help[i]);
573     else
574     printf(" -%c, --%-7s <arg> * %s\n", long_opts[i].val,
575     long_opts[i].name, opts_help[i]);
576    
577     puts("\nFor more information, see the scanmacho(1) manpage");
578     exit(status);
579     }
580    
581     /* parse command line arguments and preform needed actions */
582     static int parseargs(int argc, char *argv[])
583     {
584     int i;
585     const char *from_file = NULL;
586     int ret = 0;
587    
588     opterr = 0;
589     while ((i = getopt_long(argc, argv, PARSE_FLAGS, long_opts, NULL)) != -1) {
590     switch (i) {
591    
592     case 'V':
593     printf("pax-utils-%s: %s compiled %s\n%s\n"
594     "%s written for Gentoo by <solar, vapier and grobian @ gentoo.org>\n",
595     VERSION, __FILE__, __DATE__, rcsid, argv0);
596     exit(EXIT_SUCCESS);
597     break;
598     case 'h': usage(EXIT_SUCCESS); break;
599     case 'f':
600     if (from_file) warn("You prob don't want to specify -f twice");
601     from_file = optarg;
602     break;
603     case 'E':
604     strncpy(match_etypes, optarg, sizeof(match_etypes));
605     break;
606     case 'M':
607     match_bits = atoi(optarg);
608     break;
609     case 'O':
610 vapier 1.11 if (sscanf(optarg, "%o", &match_perms) == -1)
611 grobian 1.1 match_bits = 0;
612     break;
613     case 'o': {
614     if (freopen(optarg, "w", stdout) == NULL)
615     err("Could not open output stream '%s': %s", optarg, strerror(errno));
616     break;
617     }
618     case 'N': {
619     if (find_lib) warn("You prob don't want to specify -N twice");
620     find_lib = optarg;
621     break;
622     }
623     case 'F': {
624     if (out_format) warn("You prob don't want to specify -F twice");
625     out_format = optarg;
626     break;
627     }
628     case 'Z': show_size = 1; break;
629     case 'g': g_match = 1; break;
630     case 'y': scan_symlink = 0; break;
631     case 'A': scan_archives = 1; break;
632     case 'B': show_banner = 0; break;
633     case 'p': scan_envpath = 1; break;
634     case 'R': dir_recurse = 1; break;
635     case 'm': dir_crossmount = 0; break;
636     case 'n': show_needed = 1; break;
637     case 'i': show_interp = 1; break;
638     case 'b': show_bind = 1; break;
639     case 'S': show_soname = 1; break;
640     case 'q': be_quiet = 1; break;
641     case 'v': be_verbose = (be_verbose % 20) + 1; break;
642     case 'a': show_perms = show_endian = show_bind = 1; break;
643     case 'D': show_endian = 1; break;
644     case ':':
645     err("Option '%c' is missing parameter", optopt);
646     case '?':
647     err("Unknown option '%c' or argument missing", optopt);
648     default:
649     err("Unhandled option '%c'; please report this", i);
650     }
651     }
652     /* let the format option override all other options */
653     if (out_format) {
654     show_needed = show_interp = show_bind = show_soname = \
655     show_perms = show_endian = show_size = 0;
656     for (i = 0; out_format[i]; ++i) {
657     if (!IS_MODIFIER(out_format[i])) continue;
658    
659     switch (out_format[++i]) {
660     case '+': break;
661     case '%': break;
662     case '#': break;
663     case 'F': break;
664     case 'p': break;
665     case 'f': break;
666     case 'k': break;
667     case 'N': break;
668     case 'o': break;
669     case 'a': break;
670     case 'M': break;
671     case 'Z': show_size = 1; break;
672     case 'D': show_endian = 1; break;
673     case 'O': show_perms = 1; break;
674     case 'n': show_needed = 1; break;
675     case 'i': show_interp = 1; break;
676     case 'b': show_bind = 1; break;
677     case 'S': show_soname = 1; break;
678     default:
679     err("Invalid format specifier '%c' (byte %i)",
680     out_format[i], i+1);
681     }
682     }
683    
684     /* construct our default format */
685     } else {
686     size_t fmt_len = 30;
687     out_format = xmalloc(sizeof(char) * fmt_len);
688     *out_format = '\0';
689 grobian 1.3 if (!be_quiet) xstrcat(&out_format, "%a ", &fmt_len);
690 grobian 1.1 if (!be_quiet) xstrcat(&out_format, "%o ", &fmt_len);
691     if (show_perms) xstrcat(&out_format, "%O ", &fmt_len);
692     if (show_size) xstrcat(&out_format, "%Z ", &fmt_len);
693     if (show_endian) xstrcat(&out_format, "%D ", &fmt_len);
694     if (show_needed) xstrcat(&out_format, "%n ", &fmt_len);
695     if (show_interp) xstrcat(&out_format, "%i ", &fmt_len);
696     if (show_bind) xstrcat(&out_format, "%b ", &fmt_len);
697     if (show_soname) xstrcat(&out_format, "%S ", &fmt_len);
698     if (find_lib) xstrcat(&out_format, "%N ", &fmt_len);
699     if (!be_quiet) xstrcat(&out_format, "%F ", &fmt_len);
700     }
701     if (be_verbose > 2) printf("Format: %s\n", out_format);
702    
703     /* now lets actually do the scanning */
704     if (scan_envpath)
705 vapier 1.12 scanmacho_envpath();
706 grobian 1.1 if (!from_file && optind == argc && ttyname(0) == NULL && !scan_envpath)
707     from_file = "-";
708     if (from_file) {
709     scanmacho_from_file(from_file);
710     from_file = *argv;
711     }
712     if (optind == argc && !scan_envpath && !from_file)
713     err("Nothing to scan !?");
714     while (optind < argc) {
715     search_path = argv[optind++];
716     ret = scanmacho_dir(search_path);
717     }
718    
719     return ret;
720     }
721    
722     int main(int argc, char *argv[])
723     {
724     int ret;
725     if (argc < 2)
726     usage(EXIT_FAILURE);
727     ret = parseargs(argc, argv);
728     fclose(stdout);
729     return ret;
730     }

  ViewVC Help
Powered by ViewVC 1.1.20