Version: 0.3.0
* Preliminary autoconf support
* Switched to getopt()
* New option: -C (demangle C++ names)
* New options: --help, --version
* Display "format" (printf-like) argument types
* Updated manual page
* New option: -e
diff --git a/options.c b/options.c
index 0b556d8..fcec2a8 100644
--- a/options.c
+++ b/options.c
@@ -1,13 +1,22 @@
+#if HAVE_CONFIG_H
+#include "config.h"
+#endif
+
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <limits.h>
+#if HAVE_GETOPT_H
+#include <getopt.h>
+#endif
+
#include "ltrace.h"
#include "options.h"
#include "defs.h"
+static char *progname; /* Program name (`ltrace') */
FILE * output;
int opt_a = DEFAULT_ACOLUMN; /* default alignment column for results */
int opt_d = 0; /* debug */
@@ -18,14 +27,70 @@
int opt_f = 0; /* trace child processes as they are created */
char * opt_u = NULL; /* username to run command as */
int opt_t = 0; /* print absolute timestamp */
+#if HAVE_LIBIBERTY
+int opt_C = 0; /* Demangle low-level symbol names into user-level names */
+#endif
/* List of pids given to option -p: */
struct opt_p_t * opt_p = NULL; /* attach to process with a given pid */
+/* List of function names given to option -e: */
+struct opt_e_t * opt_e = NULL;
+int opt_e_enable=1;
+
static void usage(void)
{
- fprintf(stderr, "Usage: ltrace [-dfiLSttt] [-a column] [-s strlen] [-o filename]\n"
- " [-u username] [-p pid] ... [command [arg ...]]\n\n");
+#if !(HAVE_GETOPT || HAVE_GETOPT_LONG)
+ fprintf(stdout, "Usage: %s [command [arg ...]]\n"
+"Trace library calls of a given program.\n\n", progname);
+#else
+ fprintf(stdout, "Usage: %s [option ...] [command [arg ...]]\n"
+"Trace library calls of a given program.\n\n"
+
+# if HAVE_GETOPT_LONG
+" -d, --debug print debugging info.\n"
+# else
+" -d print debugging info.\n"
+# endif
+" -f follow forks.\n"
+" -i print instruction pointer at time of library call.\n"
+" -L do NOT display library calls.\n"
+" -S display system calls.\n"
+" -t, -tt, -ttt print absolute timestamps.\n"
+# if HAVE_LIBIBERTY
+# if HAVE_GETOPT_LONG
+" -C, --demangle decode low-level symbol names into user-level names.\n"
+# else
+" -C decode low-level symbol names into user-level names.\n"
+# endif
+# endif
+# if HAVE_GETOPT_LONG
+" -a, --align=COLUMN align return values in a secific column.\n"
+# else
+" -a COLUMN align return values in a secific column.\n"
+# endif
+" -s STRLEN specify the maximum string size to print.\n"
+# if HAVE_GETOPT_LONG
+" -o, --output=FILE write the trace output to that file.\n"
+# else
+" -o FILE write the trace output to that file.\n"
+# endif
+" -u USERNAME run command with the userid, groupid of username.\n"
+" -p PID attach to the process with the process ID pid.\n"
+" -e expr modify which events to trace.\n"
+# if HAVE_GETOPT_LONG
+" -h, --help display this help and exit.\n"
+# else
+" -h display this help and exit.\n"
+# endif
+# if HAVE_GETOPT_LONG
+" -V, --version output version information and exit.\n"
+# else
+" -V output version information and exit.\n"
+# endif
+"\nReport bugs to Juan Cespedes <cespedes@debian.org>\n"
+ , progname);
+#endif
}
static char * search_for_command(char * filename)
@@ -58,19 +123,39 @@
char ** process_options(int argc, char **argv)
{
- char *nextchar = NULL;
-
+ progname = argv[0];
output = stderr;
+#if HAVE_GETOPT || HAVE_GETOPT_LONG
while(1) {
- if (!nextchar || !(*nextchar)) {
- if (!argv[1] || argv[1][0] != '-' || !argv[1][1]) {
- break;
- }
- nextchar = &argv[1][1];
- argc--; argv++;
+ int c;
+#if HAVE_GETOPT_LONG
+ int option_index = 0;
+ static struct option long_options[] = {
+ { "align", 1, 0, 'a'},
+ { "debug", 0, 0, 'd'},
+ { "demangle", 0, 0, 'C'},
+ { "help", 0, 0, 'h'},
+ { "output", 1, 0, 'o'},
+ { "version", 0, 0, 'V'},
+ { 0, 0, 0, 0}
+ };
+ c = getopt_long(argc, argv, "+dfiLSthV"
+# if HAVE_LIBIBERTY
+ "C"
+# endif
+ "a:s:o:u:p:e:", long_options, &option_index);
+#else
+ c = getopt(argc, argv, "+dfiLSth"
+# if HAVE_LIBIBERTY
+ "C"
+# endif
+ "a:s:o:u:p:e:");
+#endif
+ if (c==-1) {
+ break;
}
- switch (*nextchar++) {
+ switch(c) {
case 'd': opt_d++;
break;
case 'f': opt_f = 1;
@@ -83,51 +168,104 @@
break;
case 't': opt_t++;
break;
- case 'a': if (!argv[1]) { usage(); exit(1); }
- opt_a = atoi(argv[1]);
- argc--; argv++;
+#if HAVE_LIBIBERTY
+ case 'C': opt_C++;
break;
- case 's': if (!argv[1]) { usage(); exit(1); }
- opt_s = atoi(argv[1]);
- argc--; argv++;
+#endif
+ case 'a': opt_a = atoi(optarg);
break;
- case 'o': if (!argv[1]) { usage(); exit(1); }
- output = fopen(argv[1], "w");
+ case 's': opt_s = atoi(optarg);
+ break;
+ case 'h': usage();
+ exit(0);
+ case 'o': output = fopen(optarg, "w");
if (!output) {
- fprintf(stderr, "Can't open %s for output: %s\n", argv[1], strerror(errno));
+ fprintf(stderr, "Can't open %s for output: %s\n", optarg, strerror(errno));
exit(1);
}
- argc--; argv++;
break;
- case 'u': if (!argv[1]) { usage(); exit(1); }
- opt_u = argv[1];
- argc--; argv++;
+ case 'u': opt_u = optarg;
break;
- case 'p': if (!argv[1]) { usage(); exit(1); }
+ case 'p':
{
struct opt_p_t * tmp = malloc(sizeof(struct opt_p_t));
if (!tmp) {
perror("malloc");
exit(1);
}
- tmp->pid = atoi(argv[1]);
+ tmp->pid = atoi(optarg);
tmp->next = opt_p;
opt_p = tmp;
- argc--; argv++;
break;
}
- default: fprintf(stderr, "Unknown option '%c'\n", *(nextchar-1));
- usage();
+ case 'e':
+ {
+ char * str_e = strdup(optarg);
+ if (!str_e) {
+ perror("strdup");
+ exit(1);
+ }
+ if (str_e[0]=='!') {
+ opt_e_enable=0;
+ str_e++;
+ }
+ while(*str_e) {
+ struct opt_e_t * tmp;
+ char *str2 = strchr(str_e,',');
+ if (str2) {
+ *str2 = '\0';
+ }
+ tmp = malloc(sizeof(struct opt_e_t));
+ if (!tmp) {
+ perror("malloc");
+ exit(1);
+ }
+ tmp->name = str_e;
+ tmp->next = opt_e;
+ opt_e = tmp;
+ if (str2) {
+ str_e = str2+1;
+ } else {
+ break;
+ }
+ }
+ break;
+ }
+ case 'V': printf("ltrace version "
+#ifdef VERSION
+ VERSION
+#else
+ "???"
+#endif
+ ".\n"
+"Copyright (C) 1997-1998 Juan Cespedes <cespedes@debian.org>.\n"
+"This is free software; see the GNU General Public Licence\n"
+"version 2 or later for copying conditions. There is NO warranty.\n");
+ exit(0);
+
+ default:
+#if HAVE_GETOPT_LONG
+ fprintf(stderr, "Try `%s --help' for more information\n", progname);
+#else
+ fprintf(stderr, "Try `%s -h' for more information\n", progname);
+#endif
exit(1);
}
}
+ argc -= optind; argv += optind;
+#endif
- if (!opt_p && argc<2) {
- usage();
+ if (!opt_p && argc<1) {
+ fprintf(stderr, "%s: too few arguments\n", progname);
+#if HAVE_GETOPT_LONG
+ fprintf(stderr, "Try `%s --help' for more information\n", progname);
+#elif HAVE_GETOPT
+ fprintf(stderr, "Try `%s -h' for more information\n", progname);
+#endif
exit(1);
}
- if (argc>1) {
- command = search_for_command(argv[1]);
+ if (argc>0) {
+ command = search_for_command(argv[0]);
}
- return &argv[1];
+ return &argv[0];
}