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 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 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