options.c revision 5b3ffdf2e696273d38434ff7b3c26349fff5a0ea
1#if HAVE_CONFIG_H 2#include "config.h" 3#endif 4 5#include <string.h> 6#include <stdlib.h> 7#include <unistd.h> 8#include <fcntl.h> 9#include <errno.h> 10#include <limits.h> 11 12#if HAVE_GETOPT_H 13#include <getopt.h> 14#endif 15 16#include "ltrace.h" 17#include "options.h" 18#include "defs.h" 19 20static char *progname; /* Program name (`ltrace') */ 21FILE * output; 22int opt_a = DEFAULT_ACOLUMN; /* default alignment column for results */ 23int opt_d = 0; /* debug */ 24int opt_i = 0; /* instruction pointer */ 25int opt_s = DEFAULT_STRLEN; /* default maximum # of bytes printed in strings */ 26int opt_S = 0; /* display syscalls */ 27int opt_L = 1; /* display library calls */ 28int opt_f = 0; /* trace child processes as they are created */ 29char * opt_u = NULL; /* username to run command as */ 30int opt_r = 0; /* print relative timestamp */ 31int opt_t = 0; /* print absolute timestamp */ 32#if HAVE_LIBIBERTY 33int opt_C = 0; /* Demangle low-level symbol names into user-level names */ 34#endif 35int opt_n = 0; /* indent trace output according to program flow */ 36 37/* List of pids given to option -p: */ 38struct opt_p_t * opt_p = NULL; /* attach to process with a given pid */ 39 40/* List of function names given to option -e: */ 41struct opt_e_t * opt_e = NULL; 42int opt_e_enable=1; 43 44static void usage(void) 45{ 46#if !(HAVE_GETOPT || HAVE_GETOPT_LONG) 47 fprintf(stdout, "Usage: %s [command [arg ...]]\n" 48"Trace library calls of a given program.\n\n", progname); 49#else 50 fprintf(stdout, "Usage: %s [option ...] [command [arg ...]]\n" 51"Trace library calls of a given program.\n\n" 52 53# if HAVE_GETOPT_LONG 54" -d, --debug print debugging info.\n" 55# else 56" -d print debugging info.\n" 57# endif 58" -f follow forks.\n" 59" -i print instruction pointer at time of library call.\n" 60" -L do NOT display library calls.\n" 61" -S display system calls.\n" 62" -r print relative timestamps.\n" 63" -t, -tt, -ttt print absolute timestamps.\n" 64# if HAVE_LIBIBERTY 65# if HAVE_GETOPT_LONG 66" -C, --demangle decode low-level symbol names into user-level names.\n" 67# else 68" -C decode low-level symbol names into user-level names.\n" 69# endif 70# endif 71# if HAVE_GETOPT_LONG 72" -a, --align=COLUMN align return values in a secific column.\n" 73# else 74" -a COLUMN align return values in a secific column.\n" 75# endif 76" -s STRLEN specify the maximum string size to print.\n" 77# if HAVE_GETOPT_LONG 78" -o, --output=FILE write the trace output to that file.\n" 79# else 80" -o FILE write the trace output to that file.\n" 81# endif 82" -u USERNAME run command with the userid, groupid of username.\n" 83" -p PID attach to the process with the process ID pid.\n" 84" -e expr modify which events to trace.\n" 85# if HAVE_GETOPT_LONG 86" -n, --indent=NR indent output by NR spaces for each call level nesting.\n" 87# else 88" -n NR indent output by NR spaces for each call level nesting.\n" 89# endif 90# if HAVE_GETOPT_LONG 91" -h, --help display this help and exit.\n" 92# else 93" -h display this help and exit.\n" 94# endif 95# if HAVE_GETOPT_LONG 96" -V, --version output version information and exit.\n" 97# else 98" -V output version information and exit.\n" 99# endif 100"\nReport bugs to Juan Cespedes <cespedes@debian.org>\n" 101 , progname); 102#endif 103} 104 105static char * search_for_command(char * filename) 106{ 107 static char pathname[1024]; 108 char *path; 109 int m, n; 110 111 if (strchr(filename, '/')) { 112 return filename; 113 } 114 for (path = getenv("PATH"); path && *path; path += m) { 115 if (strchr(path, ':')) { 116 n = strchr(path, ':') - path; 117 m = n + 1; 118 } else { 119 m = n = strlen(path); 120 } 121 strncpy(pathname, path, n); /* Possible buffer overrun */ 122 if (n && pathname[n - 1] != '/') { 123 pathname[n++] = '/'; 124 } 125 strcpy(pathname + n, filename); 126 if (!access(pathname, X_OK)) { 127 return pathname; 128 } 129 } 130 return filename; 131} 132 133char ** process_options(int argc, char **argv) 134{ 135 progname = argv[0]; 136 output = stderr; 137 138#if HAVE_GETOPT || HAVE_GETOPT_LONG 139 while(1) { 140 int c; 141#if HAVE_GETOPT_LONG 142 int option_index = 0; 143 static struct option long_options[] = { 144 { "align", 1, 0, 'a'}, 145 { "debug", 0, 0, 'd'}, 146# if HAVE_LIBIBERTY 147 { "demangle", 0, 0, 'C'}, 148#endif 149 { "indent", 0, 0, 'n'}, 150 { "help", 0, 0, 'h'}, 151 { "output", 1, 0, 'o'}, 152 { "version", 0, 0, 'V'}, 153 { 0, 0, 0, 0} 154 }; 155 c = getopt_long(argc, argv, "+dfiLSrthV" 156# if HAVE_LIBIBERTY 157 "C" 158# endif 159 "a:s:o:u:p:e:n:", long_options, &option_index); 160#else 161 c = getopt(argc, argv, "+dfiLSrthV" 162# if HAVE_LIBIBERTY 163 "C" 164# endif 165 "a:s:o:u:p:e:n:"); 166#endif 167 if (c==-1) { 168 break; 169 } 170 switch(c) { 171 case 'd': opt_d++; 172 break; 173 case 'f': opt_f = 1; 174 break; 175 case 'i': opt_i++; 176 break; 177 case 'L': opt_L = 0; 178 break; 179 case 'S': opt_S = 1; 180 break; 181 case 'r': opt_r++; 182 break; 183 case 't': opt_t++; 184 break; 185#if HAVE_LIBIBERTY 186 case 'C': opt_C++; 187 break; 188#endif 189 case 'a': opt_a = atoi(optarg); 190 break; 191 case 's': opt_s = atoi(optarg); 192 break; 193 case 'n': opt_n = atoi(optarg); 194 break; 195 case 'h': usage(); 196 exit(0); 197 case 'o': output = fopen(optarg, "w"); 198 if (!output) { 199 fprintf(stderr, "Can't open %s for output: %s\n", optarg, strerror(errno)); 200 exit(1); 201 } 202 setvbuf(output, (char *)NULL, _IOLBF, 0); 203 fcntl(fileno(output), F_SETFD, FD_CLOEXEC); 204 break; 205 case 'u': opt_u = optarg; 206 break; 207 case 'p': 208 { 209 struct opt_p_t * tmp = malloc(sizeof(struct opt_p_t)); 210 if (!tmp) { 211 perror("ltrace: malloc"); 212 exit(1); 213 } 214 tmp->pid = atoi(optarg); 215 tmp->next = opt_p; 216 opt_p = tmp; 217 break; 218 } 219 case 'e': 220 { 221 char * str_e = strdup(optarg); 222 if (!str_e) { 223 perror("ltrace: strdup"); 224 exit(1); 225 } 226 if (str_e[0]=='!') { 227 opt_e_enable=0; 228 str_e++; 229 } 230 while(*str_e) { 231 struct opt_e_t * tmp; 232 char *str2 = strchr(str_e,','); 233 if (str2) { 234 *str2 = '\0'; 235 } 236 tmp = malloc(sizeof(struct opt_e_t)); 237 if (!tmp) { 238 perror("ltrace: malloc"); 239 exit(1); 240 } 241 tmp->name = str_e; 242 tmp->next = opt_e; 243 opt_e = tmp; 244 if (str2) { 245 str_e = str2+1; 246 } else { 247 break; 248 } 249 } 250 break; 251 } 252 case 'V': printf("ltrace version " 253#ifdef VERSION 254 VERSION 255#else 256 "???" 257#endif 258 ".\n" 259"Copyright (C) 1997-1999 Juan Cespedes <cespedes@debian.org>.\n" 260"This is free software; see the GNU General Public Licence\n" 261"version 2 or later for copying conditions. There is NO warranty.\n"); 262 exit(0); 263 264 default: 265#if HAVE_GETOPT_LONG 266 fprintf(stderr, "Try `%s --help' for more information\n", progname); 267#else 268 fprintf(stderr, "Try `%s -h' for more information\n", progname); 269#endif 270 exit(1); 271 } 272 } 273 argc -= optind; argv += optind; 274#endif 275 276 if (!opt_p && argc<1) { 277 fprintf(stderr, "%s: too few arguments\n", progname); 278#if HAVE_GETOPT_LONG 279 fprintf(stderr, "Try `%s --help' for more information\n", progname); 280#elif HAVE_GETOPT 281 fprintf(stderr, "Try `%s -h' for more information\n", progname); 282#endif 283 exit(1); 284 } 285 if (opt_r && opt_t) { 286 fprintf(stderr, "%s: Incompatible options -r and -t\n", progname); 287 exit(1); 288 } 289 if (argc>0) { 290 command = search_for_command(argv[0]); 291 } 292 return &argv[0]; 293} 294