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

Contents of /pax-utils/scanmacho.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.13 - (hide annotations) (download) (as text)
Tue Dec 30 13:34:46 2008 UTC (5 years, 8 months ago) by vapier
Branch: MAIN
Changes since 1.12: +3 -16 lines
File MIME type: text/x-csrc
convert getstr_perms() to strfileperms() and share it among all files

1 grobian 1.1 /*
2     * Copyright 2008 Gentoo Foundation
3     * Distributed under the terms of the GNU General Public License v2
4 vapier 1.13 * $Header: /var/cvsroot/gentoo-projects/pax-utils/scanmacho.c,v 1.12 2008/12/30 13:27:09 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.13 static const char *rcsid = "$Id: scanmacho.c,v 1.12 2008/12/30 13:27:09 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 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     #define prints(str) write(fileno(stdout), str, strlen(str))
156     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     "Scan archives (.a files)",
539     "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     "Print all scanned info (-F\"%o %O %D %b %F\")\n",
552     "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