First buildable version.
[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 STRINGIFY(lit) #lit
14 #define _(x) gettext (x)
15
16 static int opt_d, opt_f, opt_q, opt_p;
17
18 /* Script filename.  */
19 static char *opt_Z = STRINGIFY (STAP_SCRIPT_FILENAME);
20
21 static void *
22 xmalloc (size_t size)
23 {
24   void *retval = malloc (size);
25
26   if (retval == NULL)
27     error (EXIT_FAILURE, errno, _("memory allocation of %zu bytes"), size);
28
29   return retval;
30 }
31
32 static void
33 usage (int status)
34 {
35   printf ("\
36 usage: staptrace [-dfq] [-o file] [-p pid] [command [arg ...]]\n\
37                  [-Z <stap script>]\n\
38 \n\
39 Default -Z is: %s\n\
40 ",
41           opt_Z);
42   exit (status);
43 }
44
45 static void
46 dump_args (char **args)
47 {
48   char **argp;
49
50   for (argp = args; *argp; argp++)
51     {
52       if (argp > args)
53         fputs (", ", stderr);
54       fprintf (stderr, "'%s'", *argp);
55     }
56   fputc ('\n', stderr);
57 }
58
59 int
60 main (int argc, char **argv)
61 {
62   char **args, **argp;
63
64   args = xmalloc (sizeof (*args) * argc * 2);
65   argp = args;
66   *argp++ = argv[0];
67
68   for (;;)
69     {
70       int i;
71
72       i = getopt (argc, argv, "+dfqo:p:hZ:");
73       if (i == EOF)
74         break;
75       switch (i)
76         {
77         case 'd':
78           opt_d = 1;
79           break;
80         case 'f':
81           if (opt_f)
82             error (EXIT_FAILURE, 0, _("-ff is unsupported"));
83           *argp++ = "-G";
84           *argp++ = "opt_f=1";
85           opt_f = 1;
86           break;
87         case 'q':
88           *argp++ = "-G";
89           *argp++ = "opt_q=1";
90           opt_q = 1;
91           break;
92         case 'o':
93           *argp++ = "-o";
94           *argp++ = optarg;
95           break;
96         case 'p':
97           *argp++ = "-x";
98           *argp++ = optarg;
99           opt_p = 1;
100           break;
101         case 'Z':
102           opt_Z = optarg;
103           break;
104         case 'h':
105           usage (EXIT_SUCCESS);
106         default:
107           error (0, 0, _("Invalid option '%c'"), i);
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++ = 0;
149     }
150   *argp++ = opt_Z;
151   *argp = NULL;
152
153   if (opt_d)
154     dump_args (args);
155   execvp ("stap", args);
156
157   if (!opt_d)
158     dump_args (args);
159   error (EXIT_FAILURE, errno, "Error executing stap");
160 }