4 * lttngtrace starts/stop system wide tracing around program execution.
6 * Copyright (c) 2010 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License along
19 * with this program; if not, write to the Free Software Foundation, Inc.,
20 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
22 * This file should be setuid root, and belong to a "tracing" group. Only users
23 * part of the tracing group can trace and view the traces gathered.
25 * TODO: LTTng should support per-session tracepoint activation.
26 * TODO: use mkstemp() and save last trace name in user's home directory.
27 * TODO: drop priv + reenable standard signal handlers + call lttv at the end.
28 * TODO: -o option should be limited to creation of files in locations that the
29 * calling user has file creation access.
43 #include <sys/types.h>
46 #define printf_dbg(fmt, args...) printf(fmt, args)
48 #define printf_dbg(fmt, ...)
51 static char *trace_path
;
52 static char trace_path_pid
[PATH_MAX
];
53 static int autotrace
; /*
54 * Is the trace_path automatically chosen in /tmp ? Can
55 * we unlink if needed ?
57 static int sigfwd_pid
;
58 static char *progname
= NULL
;
61 fprintf(stderr
, "usage : %s [-o trace_name] command\n", progname
);
62 fprintf(stderr
, "\nTracing tool for LTTng and UST\n\
65 -o trace_name\t\tOutput file of the trace\n\
69 static int recunlink(const char *dirname
)
75 dir
= opendir(dirname
);
79 perror("Error opendir()");
83 while ((entry
= readdir(dir
)) != NULL
) {
84 if (strcmp(entry
->d_name
, ".") && strcmp(entry
->d_name
, "..")) {
85 snprintf(path
, (size_t) PATH_MAX
, "%s/%s", dirname
,
87 if (entry
->d_type
== DT_DIR
)
99 static int start_tracing(void)
102 char command
[PATH_MAX
];
105 ret
= recunlink(trace_path
);
111 * Create the directory in /tmp to deal with races (refuse if fail).
112 * Only allow user and group to read the trace data (to limit
113 * information disclosure).
115 ret
= mkdir(trace_path
, S_IRWXU
|S_IRWXG
);
117 perror("Trace directory creation error");
120 ret
= system("ltt-armall > /dev/null");
124 ret
= snprintf(command
, PATH_MAX
- 1,
125 "lttctl -C -w %s autotrace1 > /dev/null",
127 ret
= ret
< 0 ? ret
: 0;
130 ret
= system(command
);
135 static int stop_tracing(uid_t uid
, gid_t egid
)
139 ret
= system("lttctl -D autotrace1 > /dev/null");
142 ret
= system("ltt-disarmall > /dev/null");
145 /* Hand the trace back to the user after tracing is over */
146 ret
= chown(trace_path
, uid
, egid
);
148 perror("chown error");
153 static int write_child_pid(pid_t pid
, uid_t uid
, gid_t gid
)
159 /* Create the file as exclusive to deal with /tmp file creation races */
160 fd
= open(trace_path_pid
, O_WRONLY
| O_CREAT
| O_EXCL
| O_TRUNC
,
161 S_IRUSR
| S_IWUSR
| S_IRGRP
| S_IWGRP
);
162 fp
= fdopen(fd
, "w");
164 perror("Error writing child pid");
168 fprintf(fp
, "%u", (unsigned int) pid
);
171 perror("Error in fclose");
172 /* Hand pid information file back to user */
173 ret
= chown(trace_path_pid
, uid
, gid
);
175 perror("chown error");
179 static int parse_options(int argc
, char **argv
, int *arg
)
183 while ((c
= getopt(argc
, argv
, "ho:")) != -1) {
186 trace_path
= strdup(optarg
);
199 if (argc
- optind
> 0) {
200 for (i
= optind
+ 1; i
< argc
; i
++) {
201 printf ("Non-option argument %s\n", argv
[i
]);
213 static int init_trace_path(void)
218 trace_path
= "/tmp/autotrace1";
221 ret
= snprintf(trace_path_pid
, PATH_MAX
- 1, "%s/%s",
223 ret
= ret
< 0 ? ret
: 0;
227 static void sighandler(int signo
, siginfo_t
*siginfo
, void *context
)
229 kill(sigfwd_pid
, signo
);
232 static int init_sighand(sigset_t
*saved_mask
)
234 sigset_t sig_all_mask
;
238 ret
= sigfillset(&sig_all_mask
);
240 perror("Error in sigfillset");
241 gret
= (gret
== 0) ? ret
: gret
;
242 ret
= sigprocmask(SIG_SETMASK
, &sig_all_mask
, saved_mask
);
244 perror("Error in sigprocmask");
245 gret
= (gret
== 0) ? ret
: gret
;
249 static int forward_signals(pid_t pid
, sigset_t
*saved_mask
)
251 struct sigaction act
;
254 /* Forward SIGINT and SIGTERM */
256 act
.sa_sigaction
= sighandler
;
257 act
.sa_flags
= SA_SIGINFO
| SA_RESTART
;
258 sigemptyset(&act
.sa_mask
);
259 ret
= sigaction(SIGINT
, &act
, NULL
);
261 perror("Error in sigaction");
262 gret
= (gret
== 0) ? ret
: gret
;
263 ret
= sigaction(SIGTERM
, &act
, NULL
);
265 perror("Error in sigaction");
266 gret
= (gret
== 0) ? ret
: gret
;
268 /* Reenable signals */
269 ret
= sigprocmask(SIG_SETMASK
, saved_mask
, NULL
);
271 perror("Error in sigprocmask");
272 gret
= (gret
== 0) ? ret
: gret
;
276 int main(int argc
, char *argv
[])
281 int gret
= 0, ret
= 0;
297 if (euid
!= 0 && uid
!= 0) {
298 printf("%s must be setuid root\n", progname
);
302 printf_dbg("euid: %d\n", euid
);
303 printf_dbg("uid: %d\n", uid
);
304 printf_dbg("egid: %d\n", egid
);
305 printf_dbg("gid: %d\n", gid
);
307 ret
= parse_options(argc
, argv
, &arg
);
311 ret
= init_trace_path();
312 gret
= (gret
== 0) ? ret
: gret
;
314 ret
= init_sighand(&saved_mask
);
315 gret
= (gret
== 0) ? ret
: gret
;
317 ret
= start_tracing();
322 if (pid
> 0) { /* parent */
325 ret
= forward_signals(pid
, &saved_mask
);
326 gret
= (gret
== 0) ? ret
: gret
;
329 gret
= (gret
== 0) ? -errno
: gret
;
331 ret
= stop_tracing(uid
, egid
);
332 gret
= (gret
== 0) ? ret
: gret
;
333 ret
= write_child_pid(pid
, uid
, egid
);
334 gret
= (gret
== 0) ? ret
: gret
;
335 } else if (pid
== 0) { /* child */
336 /* Drop root euid before executing child program */
338 /* Reenable signals */
339 ret
= sigprocmask(SIG_SETMASK
, &saved_mask
, NULL
);
341 perror("Error in sigprocmask");
344 ret
= execvp(argv
[arg
], &argv
[arg
]);
346 perror("Execution error");
349 perror("Error in fork");
This page took 0.039663 seconds and 4 git commands to generate.