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.
40 #include <sys/types.h>
43 #define printf_dbg(fmt, args...) printf(fmt, args)
45 #define printf_dbg(fmt, ...)
48 static char *trace_path
;
49 static char trace_path_pid
[PATH_MAX
];
50 static int autotrace
; /*
51 * Is the trace_path automatically chosen in /tmp ? Can
52 * we unlink if needed ?
54 static int sigfwd_pid
;
56 static int recunlink(const char *dirname
)
62 dir
= opendir(dirname
);
66 perror("Error opendir()");
70 while ((entry
= readdir(dir
)) != NULL
) {
71 if (strcmp(entry
->d_name
, ".") && strcmp(entry
->d_name
, "..")) {
72 snprintf(path
, (size_t) PATH_MAX
, "%s/%s", dirname
,
74 if (entry
->d_type
== DT_DIR
)
86 static int start_tracing(void)
89 char command
[PATH_MAX
];
92 ret
= recunlink(trace_path
);
98 * Create the directory in /tmp to deal with races (refuse if fail).
99 * Only allow user and group to read the trace data (to limit
100 * information disclosure).
102 ret
= mkdir(trace_path
, S_IRWXU
|S_IRWXG
);
104 perror("Trace directory creation error");
107 ret
= system("ltt-armall > /dev/null");
111 ret
= snprintf(command
, PATH_MAX
- 1,
112 "lttctl -C -w %s autotrace1 > /dev/null",
114 ret
= ret
< 0 ? ret
: 0;
117 ret
= system(command
);
122 static int stop_tracing(uid_t uid
, gid_t egid
)
126 ret
= system("lttctl -D autotrace1 > /dev/null");
129 ret
= system("ltt-disarmall > /dev/null");
132 /* Hand the trace back to the user after tracing is over */
133 ret
= chown(trace_path
, uid
, egid
);
135 perror("chown error");
140 static int write_child_pid(pid_t pid
, uid_t uid
, gid_t gid
)
146 /* Create the file as exclusive to deal with /tmp file creation races */
147 fd
= open(trace_path_pid
, O_WRONLY
| O_CREAT
| O_EXCL
| O_TRUNC
,
148 S_IRUSR
| S_IWUSR
| S_IRGRP
| S_IWGRP
);
149 fp
= fdopen(fd
, "w");
151 perror("Error writing child pid");
155 fprintf(fp
, "%u", (unsigned int) pid
);
158 perror("Error in fclose");
159 /* Hand pid information file back to user */
160 ret
= chown(trace_path_pid
, uid
, gid
);
162 perror("chown error");
166 static int parse_options(int argc
, char *argv
[], int *arg
)
172 || argv
[*arg
][0] != '-'
173 || argv
[*arg
][0] == '\0'
174 || argv
[*arg
][1] == '\0'
175 || !strcmp(argv
[*arg
], "--"))
177 switch (argv
[*arg
][1]) {
178 case 'o': if (*arg
+ 1 >= argc
) {
179 printf("Missing -o trace name\n");
183 trace_path
= argv
[*arg
+ 1];
186 default: printf("Unknown option -%c\n", argv
[*arg
][1]);
194 static int init_trace_path(void)
199 trace_path
= "/tmp/autotrace1";
202 ret
= snprintf(trace_path_pid
, PATH_MAX
- 1, "%s/%s",
204 ret
= ret
< 0 ? ret
: 0;
208 static void sighandler(int signo
, siginfo_t
*siginfo
, void *context
)
210 kill(sigfwd_pid
, signo
);
213 static int init_sighand(sigset_t
*saved_mask
)
215 sigset_t sig_all_mask
;
219 ret
= sigfillset(&sig_all_mask
);
221 perror("Error in sigfillset");
222 gret
= (gret
== 0) ? ret
: gret
;
223 ret
= sigprocmask(SIG_SETMASK
, &sig_all_mask
, saved_mask
);
225 perror("Error in sigprocmask");
226 gret
= (gret
== 0) ? ret
: gret
;
230 static int forward_signals(pid_t pid
, sigset_t
*saved_mask
)
232 struct sigaction act
;
235 /* Forward SIGINT and SIGTERM */
237 act
.sa_sigaction
= sighandler
;
238 act
.sa_flags
= SA_SIGINFO
| SA_RESTART
;
239 sigemptyset(&act
.sa_mask
);
240 ret
= sigaction(SIGINT
, &act
, NULL
);
242 perror("Error in sigaction");
243 gret
= (gret
== 0) ? ret
: gret
;
244 ret
= sigaction(SIGTERM
, &act
, NULL
);
246 perror("Error in sigaction");
247 gret
= (gret
== 0) ? ret
: gret
;
249 /* Reenable signals */
250 ret
= sigprocmask(SIG_SETMASK
, saved_mask
, NULL
);
252 perror("Error in sigprocmask");
253 gret
= (gret
== 0) ? ret
: gret
;
257 int main(int argc
, char *argv
[])
262 int gret
= 0, ret
= 0;
274 if (euid
!= 0 && uid
!= 0) {
275 printf("%s must be setuid root\n", argv
[0]);
279 printf_dbg("euid: %d\n", euid
);
280 printf_dbg("uid: %d\n", uid
);
281 printf_dbg("egid: %d\n", egid
);
282 printf_dbg("gid: %d\n", gid
);
285 ret
= parse_options(argc
, argv
, &arg
);
290 ret
= init_trace_path();
291 gret
= (gret
== 0) ? ret
: gret
;
293 ret
= init_sighand(&saved_mask
);
294 gret
= (gret
== 0) ? ret
: gret
;
296 ret
= start_tracing();
301 if (pid
> 0) { /* parent */
304 ret
= forward_signals(pid
, &saved_mask
);
305 gret
= (gret
== 0) ? ret
: gret
;
308 gret
= (gret
== 0) ? -errno
: gret
;
310 ret
= stop_tracing(uid
, egid
);
311 gret
= (gret
== 0) ? ret
: gret
;
312 ret
= write_child_pid(pid
, uid
, egid
);
313 gret
= (gret
== 0) ? ret
: gret
;
314 } else if (pid
== 0) { /* child */
315 /* Drop root euid before executing child program */
317 /* Reenable signals */
318 ret
= sigprocmask(SIG_SETMASK
, &saved_mask
, NULL
);
320 perror("Error in sigprocmask");
323 ret
= execvp(argv
[arg
], &argv
[arg
]);
325 perror("Execution error");
328 perror("Error in fork");
This page took 0.037707 seconds and 5 git commands to generate.