2f6f328c86f6b6b54f546f8b46cd11f051eca826
[staptrace.git] / src / staptrace.c
1 #include <error.h>
2 #include <errno.h>
3 #include <stdlib.h>
4 #include <unistd.h>
5 #include <libintl.h>
6 #include <stdio.h>
7 #include <string.h>
8
9 #ifndef STAP_SCRIPT_FILENAME
10 #error "STAP_SCRIPT_FILENAME is required"
11 #endif
12
13 #define STRINGIFY1(lit) #lit
14 #define STRINGIFY(lit) STRINGIFY1 (lit)
15 #define _(x) gettext (x)
16
17 static int opt_d, opt_f, opt_q, opt_p;
18
19 /* Script filename.  */
20 static char *opt_Z = STRINGIFY (STAP_SCRIPT_FILENAME);
21
22 static void *
23 xmalloc (size_t size)
24 {
25   void *retval = malloc (size);
26
27   if (retval == NULL)
28     error (EXIT_FAILURE, errno, _("memory allocation of %zu bytes"), size);
29
30   return retval;
31 }
32
33 static void
34 usage (int status)
35 {
36   printf ("\
37 usage: staptrace [-dfq] [-o file] [-p pid] [command [arg ...]]\n\
38                  [-Z <stap script>]\n\
39 \n\
40 Default -Z is: %s\n\
41 ",
42           opt_Z);
43   exit (status);
44 }
45
46 static void
47 dump_args (char **args)
48 {
49   char **argp;
50
51   for (argp = args; *argp; argp++)
52     {
53       if (argp > args)
54         fputs (", ", stderr);
55       fprintf (stderr, "'%s'", *argp);
56     }
57   fputc ('\n', stderr);
58 }
59
60 int
61 main (int argc, char **argv)
62 {
63   char **args, **argp;
64
65   args = xmalloc (sizeof (*args) * argc * 2);
66   argp = args;
67   *argp++ = argv[0];
68
69   for (;;)
70     {
71       int i;
72
73       i = getopt (argc, argv, "+dfqo:p:hZ:");
74       if (i == EOF)
75         break;
76       switch (i)
77         {
78         case 'd':
79           opt_d = 1;
80           break;
81         case 'f':
82           if (opt_f)
83             error (EXIT_FAILURE, 0, _("-ff is unsupported"));
84           *argp++ = "-G";
85           *argp++ = "opt_f=1";
86           opt_f = 1;
87           break;
88         case 'q':
89           *argp++ = "-G";
90           *argp++ = "opt_q=1";
91           opt_q = 1;
92           break;
93         case 'o':
94           *argp++ = "-o";
95           *argp++ = optarg;
96           break;
97         case 'p':
98           *argp++ = "-x";
99           *argp++ = optarg;
100           opt_p = 1;
101           break;
102         case 'Z':
103           opt_Z = optarg;
104           break;
105         case 'h':
106           usage (EXIT_SUCCESS);
107         default:
108           usage (EXIT_FAILURE);
109         }
110     }
111
112   if ((optind == argc) == !opt_p)
113     usage (EXIT_FAILURE);
114
115   if (optind < argc)
116     {
117       size_t len;
118       int i;
119       char *d;
120       const char *s;
121
122       *argp++ = "-c";
123
124       len = 32;
125       for (i = optind; i < argc; i++)
126         len += 3 + strlen (argv[i]) * 4;
127
128       d = *argp++ = xmalloc (len);
129       d = stpcpy (d, "(exec");
130       for (i = optind; i < argc; i++)
131         {
132           *d++ = ' ';
133           *d++ = '\'';
134           for (s = argv[optind]; *s; s++)
135             switch (*s)
136               {
137               case '\'':
138                 d = stpcpy (d, "'\\''");
139                 break;
140               case '\\':
141                 *d++ = '\\';
142                 /* FALLTHRU */
143               default:
144                 *d++ = *s;
145               }
146           *d++ = '\'';
147         }
148       *d++ = ')';
149       *d++ = 0;
150     }
151   *argp++ = opt_Z;
152   *argp = NULL;
153
154   if (opt_d)
155     dump_args (args);
156   execvp ("stap", args);
157
158   if (!opt_d)
159     dump_args (args);
160   error (EXIT_FAILURE, errno, "Error executing stap");
161 }