1 #include <debug.h>
2 #include <cmdline.h>
3 #include <stdio.h>
4 #include <stdlib.h>
5 #include <getopt.h>
6 #include <string.h>
7 #include <ctype.h>
8
9 extern char *optarg;
10 extern int optind, opterr, optopt;
11
12 static struct option long_options[] = {
13 {"start-address", required_argument, 0, 's'},
14 {"inc-address", required_argument, 0, 'i'},
15 {"locals-only", no_argument, 0, 'l'},
16 {"quiet", no_argument, 0, 'Q'},
17 {"noupdate", no_argument, 0, 'n'},
18 {"lookup", required_argument, 0, 'L'},
19 {"default", required_argument, 0, 'D'},
20 {"verbose", no_argument, 0, 'V'},
21 {"help", no_argument, 0, 'h'},
22 {"mapfile", required_argument, 0, 'M'},
23 {"output", required_argument, 0, 'o'},
24 {"prelinkmap", required_argument, 0, 'p'},
25 {0, 0, 0, 0},
26 };
27
28 /* This array must parallel long_options[] */
29 static const char *descriptions[] = {
30 "start address to prelink libraries to",
31 "address increment for each library",
32 "prelink local relocations only",
33 "suppress informational and non-fatal error messages",
34 "do a dry run--calculate the prelink info but do not update any files",
35 "provide a directory for library lookup",
36 "provide a default library or executable for symbol lookup",
37 "print verbose output",
38 "print help screen",
39 "print a list of prelink addresses to file (prefix filename with + to append instead of overwrite)",
40 "specify an output directory (if multiple inputs) or file (is single input)",
41 "specify a file with prelink addresses instead of a --start-address/--inc-address combination",
42 };
43
print_help(const char * name)44 void print_help(const char *name) {
45 fprintf(stdout,
46 "invokation:\n"
47 "\t%s file1 [file2 file3 ...] -Ldir1 [-Ldir2 ...] -saddr -iinc [-Vqn] [-M<logfile>]\n"
48 "\t%s -l file [-Vqn] [-M<logfile>]\n"
49 "\t%s -h\n\n", name, name, name);
50 fprintf(stdout, "options:\n");
51 struct option *opt = long_options;
52 const char **desc = descriptions;
53 while (opt->name) {
54 fprintf(stdout, "\t-%c/--%s%s: %s\n",
55 opt->val,
56 opt->name,
57 (opt->has_arg ? " (argument)" : ""),
58 *desc);
59 opt++;
60 desc++;
61 }
62 }
63
get_options(int argc,char ** argv,int * start_addr,int * inc_addr,int * locals_only,int * quiet,int * dry_run,char *** dirs,int * num_dirs,char *** defaults,int * num_defaults,int * verbose,char ** mapfile,char ** output,char ** prelinkmap)64 int get_options(int argc, char **argv,
65 int *start_addr,
66 int *inc_addr,
67 int *locals_only,
68 int *quiet,
69 int *dry_run,
70 char ***dirs,
71 int *num_dirs,
72 char ***defaults,
73 int *num_defaults,
74 int *verbose,
75 char **mapfile,
76 char **output,
77 char **prelinkmap) {
78 int c;
79
80 ASSERT(dry_run); *dry_run = 0;
81 ASSERT(quiet); *quiet = 0;
82 ASSERT(verbose); *verbose = 0;
83 ASSERT(dirs); *dirs = NULL;
84 ASSERT(num_dirs); *num_dirs = 0;
85 ASSERT(defaults); *defaults = NULL;
86 ASSERT(num_defaults); *num_defaults = 0;
87 ASSERT(start_addr); *start_addr = -1;
88 ASSERT(inc_addr); *inc_addr = -1;
89 ASSERT(locals_only); *locals_only = 0;
90 ASSERT(mapfile); *mapfile = NULL;
91 ASSERT(output); *output = NULL;
92 ASSERT(prelinkmap); *prelinkmap = NULL;
93 int dirs_size = 0;
94 int defaults_size = 0;
95
96 while (1) {
97 /* getopt_long stores the option index here. */
98 int option_index = 0;
99
100 c = getopt_long (argc, argv,
101 "VhnQlL:D:s:i:M:o:p:",
102 long_options,
103 &option_index);
104 /* Detect the end of the options. */
105 if (c == -1) break;
106
107 if (isgraph(c)) {
108 INFO ("option -%c with value `%s'\n", c, (optarg ?: "(null)"));
109 }
110
111 #define SET_STRING_OPTION(name) do { \
112 ASSERT(optarg); \
113 (*name) = strdup(optarg); \
114 } while(0)
115
116 #define SET_REPEATED_STRING_OPTION(arr, num, size) do { \
117 if (*num == size) { \
118 size += 10; \
119 *arr = (char **)REALLOC(*arr, size * sizeof(char *)); \
120 } \
121 SET_STRING_OPTION(((*arr) + *num)); \
122 (*num)++; \
123 } while(0)
124
125 #define SET_INT_OPTION(val) do { \
126 ASSERT(optarg); \
127 if (strlen(optarg) >= 2 && optarg[0] == '0' && optarg[1] == 'x') { \
128 FAILIF(1 != sscanf(optarg+2, "%x", val), \
129 "Expecting a hexadecimal argument!\n"); \
130 } else { \
131 FAILIF(1 != sscanf(optarg, "%d", val), \
132 "Expecting a decimal argument!\n"); \
133 } \
134 } while(0)
135
136 switch (c) {
137 case 0:
138 /* If this option set a flag, do nothing else now. */
139 if (long_options[option_index].flag != 0)
140 break;
141 INFO ("option %s", long_options[option_index].name);
142 if (optarg)
143 INFO (" with arg %s", optarg);
144 INFO ("\n");
145 break;
146 case 'Q': *quiet = 1; break;
147 case 'n': *dry_run = 1; break;
148 case 'M':
149 SET_STRING_OPTION(mapfile);
150 break;
151 case 'o':
152 SET_STRING_OPTION(output);
153 break;
154 case 'p':
155 SET_STRING_OPTION(prelinkmap);
156 break;
157 case 's':
158 SET_INT_OPTION(start_addr);
159 break;
160 case 'i':
161 SET_INT_OPTION(inc_addr);
162 break;
163 case 'L':
164 SET_REPEATED_STRING_OPTION(dirs, num_dirs, dirs_size);
165 break;
166 case 'D':
167 SET_REPEATED_STRING_OPTION(defaults, num_defaults, defaults_size);
168 break;
169 case 'l': *locals_only = 1; break;
170 case 'h': print_help(argv[0]); exit(1); break;
171 case 'V': *verbose = 1; break;
172 case '?':
173 /* getopt_long already printed an error message. */
174 break;
175
176 #undef SET_STRING_OPTION
177 #undef SET_REPEATED_STRING_OPTION
178 #undef SET_INT_OPTION
179
180 default:
181 FAILIF(1, "Unknown option");
182 }
183 }
184
185 return optind;
186 }
187