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

Contents of /pax-utils/scanmacho.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.12 - (hide annotations) (download) (as text)
Tue Dec 30 13:27:09 2008 UTC (5 years, 6 months ago) by vapier
Branch: MAIN
Changes since 1.11: +18 -41 lines
File MIME type: text/x-csrc
cleanup code style a bit and simplify a bunch of places -- hopefully i didnt break anything

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

  ViewVC Help
Powered by ViewVC 1.1.20