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

Contents of /pax-utils/scanmacho.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.24 - (hide annotations) (download) (as text)
Mon Dec 16 20:30:38 2013 UTC (12 months ago) by grobian
Branch: MAIN
CVS Tags: HEAD
Changes since 1.23: +50 -9 lines
File MIME type: text/x-csrc
scanmacho: add support to read LC_RPATH entries from Mach-O files

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

  ViewVC Help
Powered by ViewVC 1.1.20