options.c 18.7 KB
Newer Older
1 2
/*
 * This file is part of ltrace.
3
 * Copyright (C) 2012, 2013, 2014 Petr Machata, Red Hat Inc.
4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
 * Copyright (C) 2009,2010 Joe Damato
 * Copyright (C) 1998,1999,2002,2003,2004,2007,2008,2009 Juan Cespedes
 * Copyright (C) 2006 Ian Wienand
 * Copyright (C) 2006 Steve Fink
 * Copyright (C) 2006 Paul Gilliam, IBM Corporation
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License as
 * published by the Free Software Foundation; either version 2 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
 * 02110-1301 USA
 */

Juan Cespedes's avatar
Juan Cespedes committed
26 27
#include "config.h"

28
#include <sys/ioctl.h>
29 30
#include <sys/stat.h>
#include <sys/types.h>
31
#include <assert.h>
32 33 34 35
#include <errno.h>
#include <fcntl.h>
#include <getopt.h>
#include <limits.h>
36
#include <stdio.h>
37 38 39
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
Juan Cespedes's avatar
Juan Cespedes committed
40

Juan Cespedes's avatar
Juan Cespedes committed
41
#include "common.h"
42 43
#include "filter.h"
#include "glob.h"
44
#include "demangle.h"
Juan Cespedes's avatar
Juan Cespedes committed
45

46
struct options_t options = {
47 48 49
	.align    = DEFAULT_ALIGN,    /* alignment column for results */
	.user     = NULL,             /* username to run command as */
	.syscalls = 0,                /* display syscalls */
50
#ifdef USE_DEMANGLE
51
	.demangle = 0,                /* Demangle low-level symbol names */
52
#endif
53 54
	.indent = 0,                  /* indent output according to program flow */
	.output = NULL,               /* output to a specific file */
55 56 57 58 59
	.summary = 0,                 /* Report a summary on program exit */
	.debug = 0,                   /* debug */
	.arraylen = DEFAULT_ARRAYLEN, /* maximum # array elements to print */
	.strlen = DEFAULT_STRLEN,     /* maximum # of bytes printed in strings */
	.follow = 0,                  /* trace child processes */
60 61
};

Juan Cespedes's avatar
Juan Cespedes committed
62
static char *progname;		/* Program name (`ltrace') */
Juan Cespedes's avatar
Juan Cespedes committed
63
int opt_i = 0;			/* instruction pointer */
Juan Cespedes's avatar
Juan Cespedes committed
64
int opt_r = 0;			/* print relative timestamp */
Juan Cespedes's avatar
Juan Cespedes committed
65
int opt_t = 0;			/* print absolute timestamp */
Juan Cespedes's avatar
Juan Cespedes committed
66
int opt_T = 0;			/* show the time spent inside each call */
Juan Cespedes's avatar
Juan Cespedes committed
67 68

/* List of pids given to option -p: */
69
struct opt_p_t *opt_p = NULL;	/* attach to process with a given pid */
Juan Cespedes's avatar
Juan Cespedes committed
70

71 72
/* Vector of struct opt_F_t.  */
struct vect opt_F;
73

74 75
static void
err_usage(void) {
Petr Machata's avatar
Petr Machata committed
76
	fprintf(stderr, "Try `%s --help' for more information.\n", progname);
77 78 79
	exit(1);
}

80 81
static void
usage(void) {
Juan Cespedes's avatar
Juan Cespedes committed
82
	fprintf(stdout, "Usage: %s [option ...] [command [arg ...]]\n"
83 84
		"Trace library calls of a given program.\n\n"
		"  -a, --align=COLUMN  align return values in a secific column.\n"
Petr Machata's avatar
Petr Machata committed
85
		"  -A MAXELTS          maximum number of array elements to print.\n"
86
		"  -b, --no-signals    don't print signals.\n"
87
		"  -c                  count time and calls, and report a summary on exit.\n"
Juan Cespedes's avatar
Juan Cespedes committed
88
# ifdef USE_DEMANGLE
89
		"  -C, --demangle      decode low-level symbol names into user-level names.\n"
Juan Cespedes's avatar
Juan Cespedes committed
90
# endif
Petr Machata's avatar
Petr Machata committed
91
		"  -D, --debug=MASK    enable debugging (see -Dh or --debug=help).\n"
92
		"  -Dh, --debug=help   show help on debugging.\n"
Petr Machata's avatar
Petr Machata committed
93
		"  -e FILTER           modify which library calls to trace.\n"
Juan Cespedes's avatar
Juan Cespedes committed
94
		"  -f                  trace children (fork() and clone()).\n"
95
		"  -F, --config=FILE   load alternate configuration file (may be repeated).\n"
96 97
		"  -h, --help          display this help and exit.\n"
		"  -i                  print instruction pointer at time of library call.\n"
Petr Machata's avatar
Petr Machata committed
98
		"  -l, --library=LIBRARY_PATTERN only trace symbols implemented by this library.\n"
99 100
		"  -L                  do NOT display library calls.\n"
		"  -n, --indent=NR     indent output by NR spaces for each call level nesting.\n"
Petr Machata's avatar
Petr Machata committed
101
		"  -o, --output=FILENAME write the trace output to file with given name.\n"
102 103
		"  -p PID              attach to the process with the process ID pid.\n"
		"  -r                  print relative timestamps.\n"
Petr Machata's avatar
Petr Machata committed
104 105
		"  -s STRSIZE          specify the maximum string size to print.\n"
		"  -S                  trace system calls as well as library calls.\n"
106 107 108 109
		"  -t, -tt, -ttt       print absolute timestamps.\n"
		"  -T                  show the time spent inside each call.\n"
		"  -u USERNAME         run command with the userid, groupid of username.\n"
		"  -V, --version       output version information and exit.\n"
110
#if defined(HAVE_UNWINDER)
111
		"  -w, --where=NR      print backtrace showing NR stack frames at most.\n"
112
#endif /* defined(HAVE_UNWINDER) */
Petr Machata's avatar
Petr Machata committed
113
		"  -x FILTER           modify which static functions to trace.\n"
114
		"\nReport bugs to [email protected]\n",
115
		progname);
Juan Cespedes's avatar
Juan Cespedes committed
116 117
}

118 119 120 121 122 123 124 125 126 127 128 129 130
static void
usage_debug(void) {
	fprintf(stdout, "%s debugging option, --debug=<octal> or -D<octal>:\n", progname);
	fprintf(stdout, 
			"\n"
			" number  ref. in source   description\n"
			"      1   general           Generally helpful progress information\n"
			"     10   event             Shows every event received by a traced process\n"
			"     20   process           Shows actions carried upon a traced processes\n"
			"     40   function          Shows every entry to internal functions\n"
			"\n"
			"Debugging options are mixed using bitwise-or.\n"
			"Note that the meanings and values are subject to change.\n"
131 132
			"Also note that these values are used inconsistently in ltrace, and the\n"
			"only debuglevel that you can rely on is -D77 that will show everything.\n"
133 134 135
		   );
}

136 137
static char *
search_for_command(char *filename) {
Juan Cespedes's avatar
Juan Cespedes committed
138
	static char pathname[PATH_MAX];
Juan Cespedes's avatar
Juan Cespedes committed
139 140 141 142 143 144 145 146 147 148 149 150 151
	char *path;
	int m, n;

	if (strchr(filename, '/')) {
		return filename;
	}
	for (path = getenv("PATH"); path && *path; path += m) {
		if (strchr(path, ':')) {
			n = strchr(path, ':') - path;
			m = n + 1;
		} else {
			m = n = strlen(path);
		}
Juan Cespedes's avatar
Juan Cespedes committed
152
		if (n + strlen(filename) + 1 >= PATH_MAX) {
Petr Machata's avatar
Petr Machata committed
153
			fprintf(stderr, "Error: filename too long.\n");
Juan Cespedes's avatar
Juan Cespedes committed
154 155 156
			exit(1);
		}
		strncpy(pathname, path, n);
Juan Cespedes's avatar
Juan Cespedes committed
157 158 159 160 161 162 163 164 165 166 167
		if (n && pathname[n - 1] != '/') {
			pathname[n++] = '/';
		}
		strcpy(pathname + n, filename);
		if (!access(pathname, X_OK)) {
			return pathname;
		}
	}
	return filename;
}

168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183
static void
guess_cols(void) {
	struct winsize ws;
	char *c;

	options.align = DEFAULT_ALIGN;
	c = getenv("COLUMNS");
	if (c && *c) {
		char *endptr;
		int cols;
		cols = strtol(c, &endptr, 0);
		if (cols > 0 && !*endptr) {
			options.align = cols * 5 / 8;
		}
	} else if (ioctl(1, TIOCGWINSZ, &ws) != -1 && ws.ws_col > 0) {
		options.align = ws.ws_col * 5 / 8;
Juan Cespedes's avatar
Juan Cespedes committed
184 185
	} else if (ioctl(2, TIOCGWINSZ, &ws) != -1 && ws.ws_col > 0) {
		options.align = ws.ws_col * 5 / 8;
186 187 188
	}
}

189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204
static int
compile_libname(const char *expr, const char *a_lib, int lib_re_p,
		struct filter_lib_matcher *matcher)
{
	if (strcmp(a_lib, "MAIN") == 0) {
		filter_lib_matcher_main_init(matcher);
	} else {
		/* Add ^ and $ to the library expression as well.  */
		char lib[strlen(a_lib) + 3];
		sprintf(lib, "^%s$", a_lib);

		enum filter_lib_matcher_type type
			= lib[0] == '/' ? FLM_PATHNAME : FLM_SONAME;

		regex_t lib_re;
		int status = (lib_re_p ? regcomp : globcomp)(&lib_re, lib, 0);
Petr Machata's avatar
Petr Machata committed
205
		if (status != 0) {
206 207
			char buf[100];
			regerror(status, &lib_re, buf, sizeof buf);
208
			fprintf(stderr, "Couldn't compile '%s': %s.\n",
209 210 211 212 213 214 215 216
				expr, buf);
			return -1;
		}
		filter_lib_matcher_name_init(matcher, type, lib_re);
	}
	return 0;
}

217
static int
218 219
add_filter_rule(struct filter *filt, const char *expr,
		enum filter_rule_type type,
220 221
		const char *a_sym, int sym_re_p,
		const char *a_lib, int lib_re_p)
222 223 224 225 226 227 228 229
{
	struct filter_rule *rule = malloc(sizeof(*rule));
	struct filter_lib_matcher *matcher = malloc(sizeof(*matcher));

	if (rule == NULL || matcher == NULL) {
	fail:
		free(rule);
		free(matcher);
230
		return -1;
231 232 233
	}

	regex_t symbol_re;
234 235 236 237 238 239
	{
		/* Add ^ to the start of expression and $ to the end, so that
		 * we match the whole symbol name.  Let the user write the "*"
		 * explicitly if they wish.  */
		char sym[strlen(a_sym) + 3];
		sprintf(sym, "^%s$", a_sym);
240 241
		int status = (sym_re_p ? regcomp : globcomp)
			(&symbol_re, sym, 0);
242 243 244
		if (status != 0) {
			char buf[100];
			regerror(status, &symbol_re, buf, sizeof buf);
245
			fprintf(stderr, "Couldn't compile '%s': %s.\n",
246
				expr, buf);
247 248
			goto fail;
		}
249 250
	}

251 252 253
	if (compile_libname(expr, a_lib, lib_re_p, matcher) < 0) {
		regfree(&symbol_re);
		goto fail;
254 255 256
	}

	filter_rule_init(rule, type, matcher, symbol_re);
257
	filter_add_rule(filt, rule);
258
	return 0;
259 260
}

261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280
static int
grok_libname_pattern(char **libnamep, char **libendp)
{
	char *libname = *libnamep;
	char *libend = *libendp;

	if (libend[0] != '/')
		return 0;

	*libend-- = 0;
	if (libname != libend && libname[0] == '/')
		++libname;
	else
		fprintf(stderr, "Unmatched '/' in library name.\n");

	*libendp = libend;
	*libnamep = libname;
	return 1;
}

281
static int
Petr Machata's avatar
Petr Machata committed
282
parse_filter(struct filter *filt, char *expr, int operators)
283
{
284 285 286
	/* Filter is a chain of [email protected] rules separated by '-' or '+'.
	 * If the filter expression starts with '-', the missing
	 * initial rule is implicitly *@*.  */
287 288 289 290

	enum filter_rule_type type = FR_ADD;

	while (*expr != 0) {
291
		size_t s = strcspn(expr, &"[email protected]"[operators ? 0 : 2]);
292 293 294 295 296 297 298 299 300
		char *symname = expr;
		char *libname;
		char *next = expr + s + 1;
		enum filter_rule_type this_type = type;

		if (expr[s] == 0) {
			libname = "*";
			expr = next - 1;

301 302 303
		} else if (expr[s] == '-' || expr[s] == '+') {
			type = expr[s] == '-' ? FR_SUBTRACT : FR_ADD;
			expr[s] = 0;
304 305 306 307 308 309
			libname = "*";
			expr = next;

		} else {
			assert(expr[s] == '@');
			expr[s] = 0;
310
			s = strcspn(next, &"-+"[operators ? 0 : 2]);
311 312 313 314 315 316 317
			if (s == 0) {
				libname = "*";
				expr = next;
			} else if (next[s] == 0) {
				expr = next + s;
				libname = next;
			} else {
318 319
				assert(next[s] == '-' || next[s] == '+');
				type = next[s] == '-' ? FR_SUBTRACT : FR_ADD;
320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354
				next[s] = 0;
				expr = next + s + 1;
				libname = next;
			}
		}

		assert(*libname != 0);
		char *symend = symname + strlen(symname) - 1;
		char *libend = libname + strlen(libname) - 1;
		int sym_is_re = 0;
		int lib_is_re = 0;

		/*
		 * /xxx/@... and [email protected]/xxx/ means that xxx are regular
		 * expressions.  They are globs otherwise.
		 *
		 * /[email protected]/ is the same as /xxx/@/yyy/
		 *
		 * @/xxx matches library path name
		 * @.xxx matches library relative path name
		 */
		if (symname[0] == '/') {
			if (symname != symend && symend[0] == '/') {
				++symname;
				*symend-- = 0;
				sym_is_re = 1;

			} else {
				sym_is_re = 1;
				lib_is_re = 1;
				++symname;

				/* /[email protected]/ is the same as
				 * /XXX/@/YYY/.  */
				if (libend[0] != '/')
Petr Machata's avatar
Petr Machata committed
355 356
					fprintf(stderr, "Unmatched '/'"
						" in symbol name.\n");
357 358 359 360 361 362 363 364
				else
					*libend-- = 0;
			}
		}

		/* If libname ends in '/', then we expect '/' in the
		 * beginning too.  Otherwise the initial '/' is part
		 * of absolute file name.  */
365 366
		if (!lib_is_re)
			lib_is_re = grok_libname_pattern(&libname, &libend);
367 368 369 370 371 372

		if (*symname == 0) /* /@AA/ */
			symname = "*";
		if (*libname == 0) /* /[email protected]/ */
			libname = "*";

Petr Machata's avatar
Petr Machata committed
373 374 375
		add_filter_rule(filt, expr, this_type,
				symname, sym_is_re,
				libname, lib_is_re);
376 377 378 379 380 381
	}

	return 0;
}

static struct filter *
382
recursive_parse_chain(const char *orig, char *expr, int operators)
383 384 385
{
	struct filter *filt = malloc(sizeof(*filt));
	if (filt == NULL) {
Petr Machata's avatar
Petr Machata committed
386
		fprintf(stderr, "(Part of) filter will be ignored: '%s': %s.\n",
387
			expr, strerror(errno));
388 389 390
		return NULL;
	}

Petr Machata's avatar
Petr Machata committed
391
	filter_init(filt);
Petr Machata's avatar
Petr Machata committed
392
	if (parse_filter(filt, expr, operators) < 0) {
393
		fprintf(stderr, "Filter '%s' will be ignored.\n", orig);
394 395
		free(filt);
		filt = NULL;
396
	}
397 398

	return filt;
399 400
}

Petr Machata's avatar
Petr Machata committed
401 402 403 404 405 406 407 408
static struct filter **
slist_chase_end(struct filter **begin)
{
	for (; *begin != NULL; begin = &(*begin)->next)
		;
	return begin;
}

409
static void
410
parse_filter_chain(const char *expr, struct filter **retp)
411 412 413
{
	char *str = strdup(expr);
	if (str == NULL) {
Petr Machata's avatar
Petr Machata committed
414
		fprintf(stderr, "Filter '%s' will be ignored: %s.\n",
415
			expr, strerror(errno));
416 417
		return;
	}
418 419 420 421
	/* Support initial '!' for backward compatibility.  */
	if (str[0] == '!')
		str[0] = '-';

422
	*slist_chase_end(retp) = recursive_parse_chain(expr, str, 1);
423
	free(str);
424 425
}

426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441
static int
parse_int(const char *optarg, char opt, int min, int max)
{
	char *endptr;
	long int l = strtol(optarg, &endptr, 0);
	if (l < min || (max != 0 && l > max)
	    || *optarg == 0 || *endptr != 0) {
		const char *fmt = max != 0
			? "Invalid argument to -%c: '%s'.  Use integer %d..%d.\n"
			: "Invalid argument to -%c: '%s'.  Use integer >=%d.\n";
		fprintf(stderr, fmt, opt, optarg, min, max);
		exit(1);
	}
	return (int)l;
}

442
int
443 444
parse_colon_separated_list(const char *paths, struct vect *vec,
			   enum opt_F_origin origin)
445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470
{
	/* PATHS contains a colon-separated list of directories and
	 * files to load.  It's modeled after shell PATH variable,
	 * which doesn't allow escapes.  PYTHONPATH in CPython behaves
	 * the same way.  So let's follow suit, it makes things easier
	 * to us.  */

	char *clone = strdup(paths);
	if (clone == NULL) {
		fprintf(stderr, "Couldn't parse argument %s: %s.\n",
			paths, strerror(errno));
		return -1;
	}

	/* It's undesirable to use strtok, because we want the string
	 * "a::b" to have three elements.  */
	char *tok = clone - 1;
	char *end = clone + strlen(clone);
	while (tok < end) {
		++tok;
		size_t len = strcspn(tok, ":");
		tok[len] = 0;

		struct opt_F_t arg = {
			.pathname = tok,
			.own_pathname = tok == clone,
471
			.origin = origin,
472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498
		};
		if (VECT_PUSHBACK(vec, &arg) < 0)
			/* Presumably this is not a deal-breaker.  */
			fprintf(stderr, "Couldn't store component of %s: %s.\n",
				paths, strerror(errno));

		tok += len;
	}

	return 0;
}

void
opt_F_destroy(struct opt_F_t *entry)
{
	if (entry == NULL)
		return;
	if (entry->own_pathname)
		free(entry->pathname);
}

enum opt_F_kind
opt_F_get_kind(struct opt_F_t *entry)
{
	if (entry->kind == OPT_F_UNKNOWN) {
		struct stat st;
		if (lstat(entry->pathname, &st) < 0) {
499 500 501
			if (entry->origin == OPT_F_CMDLINE)
				fprintf(stderr, "Couldn't stat %s: %s\n",
					entry->pathname, strerror(errno));
502 503 504
			entry->kind = OPT_F_BROKEN;
		} else if (S_ISDIR(st.st_mode)) {
			entry->kind = OPT_F_DIR;
505
		} else if (S_ISREG(st.st_mode) || S_ISLNK(st.st_mode)) {
506 507
			entry->kind = OPT_F_FILE;
		} else {
508 509 510
			if (entry->origin == OPT_F_CMDLINE)
				fprintf(stderr, "%s is neither a regular file, "
					"nor a directory.\n", entry->pathname);
511 512 513 514 515 516 517
			entry->kind = OPT_F_BROKEN;
		}
	}
	assert(entry->kind != OPT_F_UNKNOWN);
	return entry->kind;
}

518
char **
519 520
process_options(int argc, char **argv)
{
521 522
	VECT_INIT(&opt_F, struct opt_F_t);

Juan Cespedes's avatar
Juan Cespedes committed
523
	progname = argv[0];
524
	options.output = stderr;
525
	options.no_signals = 0;
526
#if defined(HAVE_UNWINDER)
527
	options.bt_depth = -1;
528
#endif /* defined(HAVE_UNWINDER) */
Juan Cespedes's avatar
Juan Cespedes committed
529

530 531
	guess_cols();

532 533
	int libcalls = 1;

534
	while (1) {
Juan Cespedes's avatar
Juan Cespedes committed
535
		int c;
536
		char *p;
537
#ifdef HAVE_GETOPT_LONG
Juan Cespedes's avatar
Juan Cespedes committed
538 539
		int option_index = 0;
		static struct option long_options[] = {
540
			{"align", 1, 0, 'a'},
Juan Cespedes's avatar
Juan Cespedes committed
541
			{"config", 1, 0, 'F'},
542
			{"debug", 1, 0, 'D'},
Juan Cespedes's avatar
Juan Cespedes committed
543
# ifdef USE_DEMANGLE
544
			{"demangle", 0, 0, 'C'},
545
# endif
546 547 548 549 550
			{"indent", 1, 0, 'n'},
			{"help", 0, 0, 'h'},
			{"library", 1, 0, 'l'},
			{"output", 1, 0, 'o'},
			{"version", 0, 0, 'V'},
551
			{"no-signals", 0, 0, 'b'},
552
# if defined(HAVE_UNWINDER)
553
			{"where", 1, 0, 'w'},
554
# endif /* defined(HAVE_UNWINDER) */
555
			{0, 0, 0, 0}
Juan Cespedes's avatar
Juan Cespedes committed
556
		};
557 558 559 560 561 562
#endif

		const char *opts = "+"
#ifdef USE_DEMANGLE
			"C"
#endif
563
#if defined(HAVE_UNWINDER)
564 565
			"w:"
#endif
566
			"cfhiLrStTVba:A:D:e:F:l:n:o:p:s:u:x:";
567 568 569 570 571

#ifdef HAVE_GETOPT_LONG
		c = getopt_long(argc, argv, opts, long_options, &option_index);
#else
		c = getopt(argc, argv, opts);
572
#endif
573
		if (c == -1) {
Juan Cespedes's avatar
Juan Cespedes committed
574
			break;
Juan Cespedes's avatar
Juan Cespedes committed
575
		}
576 577
		switch (c) {
		case 'a':
578
			options.align = parse_int(optarg, 'a', 0, 0);
579
			break;
Juan Cespedes's avatar
Juan Cespedes committed
580
		case 'A':
581
			options.arraylen = parse_int(optarg, 'A', 0, 0);
Steve Fink's avatar
Steve Fink committed
582
			break;
Joe Damato's avatar
Joe Damato committed
583 584 585
		case 'b':
			options.no_signals = 1;
			break;
586
		case 'c':
587
			options.summary++;
588
			break;
Juan Cespedes's avatar
Juan Cespedes committed
589
#ifdef USE_DEMANGLE
590
		case 'C':
591
			options.demangle++;
592
			break;
Juan Cespedes's avatar
Juan Cespedes committed
593
#endif
594 595 596 597 598 599 600 601 602 603
		case 'D':
			if (optarg[0]=='h') {
				usage_debug();
				exit(0);
			}
			options.debug = strtoul(optarg,&p,8);
			if (*p) {
				fprintf(stderr, "%s: --debug requires an octal argument\n", progname);
				err_usage();
			}
604
			break;
605

606
		case 'e':
607
			parse_filter_chain(optarg, &options.plt_filter);
608 609
			break;

610
		case 'f':
611
			options.follow = 1;
612
			break;
Juan Cespedes's avatar
Juan Cespedes committed
613
		case 'F':
614 615
			parse_colon_separated_list(optarg, &opt_F,
						   OPT_F_CMDLINE);
616
			break;
617 618 619 620 621 622
		case 'h':
			usage();
			exit(0);
		case 'i':
			opt_i++;
			break;
Petr Machata's avatar
Petr Machata committed
623 624 625 626 627 628

		case 'l': {
			size_t patlen = strlen(optarg);
			char buf[patlen + 2];
			sprintf(buf, "@%s", optarg);
			*slist_chase_end(&options.export_filter)
629
				= recursive_parse_chain(buf, buf, 0);
630
			break;
Petr Machata's avatar
Petr Machata committed
631 632
		}

633
		case 'L':
634
			libcalls = 0;
635
			break;
636 637
		case 'n':
			options.indent = parse_int(optarg, 'n', 0, 20);
638 639
			break;
		case 'o':
640 641
			options.output = fopen(optarg, "w");
			if (!options.output) {
642 643 644
				fprintf(stderr,
					"can't open %s for writing: %s\n",
					optarg, strerror(errno));
645 646
				exit(1);
			}
647 648
			setvbuf(options.output, (char *)NULL, _IOLBF, 0);
			fcntl(fileno(options.output), F_SETFD, FD_CLOEXEC);
649 650 651
			break;
		case 'p':
			{
Juan Cespedes's avatar
Juan Cespedes committed
652
				struct opt_p_t *tmp = malloc(sizeof(struct opt_p_t));
653 654 655 656
				if (!tmp) {
					perror("ltrace: malloc");
					exit(1);
				}
657
				tmp->pid = parse_int(optarg, 'p', 1, 0);
658 659 660 661 662 663 664 665
				tmp->next = opt_p;
				opt_p = tmp;
				break;
			}
		case 'r':
			opt_r++;
			break;
		case 's':
666
			options.strlen = parse_int(optarg, 's', 0, 0);
667 668
			break;
		case 'S':
669
			options.syscalls = 1;
670 671 672 673 674 675 676 677
			break;
		case 't':
			opt_t++;
			break;
		case 'T':
			opt_T++;
			break;
		case 'u':
678
			options.user = optarg;
679 680
			break;
		case 'V':
681
			printf("ltrace " PACKAGE_VERSION "\n"
682
			       "Copyright (C) 2010-2013 Petr Machata, Red Hat Inc.\n"
683 684 685 686
			       "Copyright (C) 1997-2009 Juan Cespedes <[email protected]>.\n"
			       "License GPLv2+: GNU GPL version 2 or later <http://gnu.org/licenses/gpl.html>\n"
			       "This is free software: you are free to change and redistribute it.\n"
			       "There is NO WARRANTY, to the extent permitted by law.\n");
687
			exit(0);
688
			break;
689
#if defined(HAVE_UNWINDER)
Joe Damato's avatar
Joe Damato committed
690
		case 'w':
691
			options.bt_depth = parse_int(optarg, 'w', 1, 0);
692
			break;
693
#endif /* defined(HAVE_UNWINDER) */
694

695
		case 'x':
Petr Machata's avatar
Petr Machata committed
696 697
			parse_filter_chain(optarg, &options.static_filter);
			break;
698

699
		default:
700
			err_usage();
Juan Cespedes's avatar
Juan Cespedes committed
701 702
		}
	}
703 704
	argc -= optind;
	argv += optind;
Juan Cespedes's avatar
Juan Cespedes committed
705

Petr Machata's avatar
Petr Machata committed
706 707 708 709 710 711
	/* If neither -e, nor -l, nor -L are used, set default -e.
	 * Use @MAIN for now, as that's what ltrace used to have in
	 * the past.  XXX Maybe we should make this "*" instead.  */
	if (libcalls
	    && options.plt_filter == NULL
	    && options.export_filter == NULL) {
712
		parse_filter_chain("@MAIN", &options.plt_filter);
713 714
		options.hide_caller = 1;
	}
Petr Machata's avatar
Petr Machata committed
715 716 717 718 719 720
	if (!libcalls && options.plt_filter != NULL) {
		fprintf(stderr,
			"%s: Option -L can't be used with -e or -l.\n",
			progname);
		err_usage();
	}
721

722
	if (!opt_p && argc < 1) {
Juan Cespedes's avatar
Juan Cespedes committed
723
		fprintf(stderr, "%s: too few arguments\n", progname);
724
		err_usage();
Juan Cespedes's avatar
Juan Cespedes committed
725
	}
Juan Cespedes's avatar
Juan Cespedes committed
726
	if (opt_r && opt_t) {
Petr Machata's avatar
Petr Machata committed
727 728
		fprintf(stderr,
			"%s: Options -r and -t can't be used together\n",
729
			progname);
730
		err_usage();
Juan Cespedes's avatar
Juan Cespedes committed
731
	}
732
	if (argc > 0) {
Juan Cespedes's avatar
Juan Cespedes committed
733
		command = search_for_command(argv[0]);
Juan Cespedes's avatar
Juan Cespedes committed
734
	}
Juan Cespedes's avatar
Juan Cespedes committed
735
	return &argv[0];
Juan Cespedes's avatar
Juan Cespedes committed
736
}