xref: /minix/minix/usr.bin/trace/output.c (revision 045e0ed3)
1 
2 #include "inc.h"
3 
4 #include <fcntl.h>
5 #include <unistd.h>
6 
7 /*
8  * The maximum number of bytes that may be buffered before writing the buffered
9  * output to the underlying file.  This is a performance optimization only.
10  * Writing more than this number of bytes at once will be handled correctly.
11  */
12 #define OUTPUT_BUFSZ	512
13 
14 static int out_fd;
15 static char out_buf[OUTPUT_BUFSZ];
16 static int out_len;
17 static int out_err;
18 
19 static pid_t last_pid; /* not a trace_proc pointer; it could become invalid! */
20 static unsigned int line_off;
21 static unsigned int prefix_off;
22 static int print_pid;
23 static int print_susp;
24 static int add_space;
25 
26 /*
27  * Initialize the output channel.  Called before any other output functions,
28  * but after a child process (to be traced) has already been spawned.  If the
29  * given file string is not NULL, it is the path to a file that is to be used
30  * to write output to.  If it is NULL, output is written to standard error.
31  */
32 int
33 output_init(const char * file)
34 {
35 
36 	/* Initialize state. */
37 	out_len = 0;
38 	out_err = FALSE;
39 
40 	last_pid = 0;
41 	line_off = 0;
42 	prefix_off = 0;
43 	print_pid = FALSE;
44 	print_susp = FALSE;
45 	add_space = FALSE;
46 
47 	/*
48 	 * Ignore signals resulting from writing to a closed pipe.  We can
49 	 * handle write errors properly ourselves.  Setting O_NOSIGPIPE is an
50 	 * alternative, but that would affect other processes writing to the
51 	 * same file object, even after we have terminated.
52 	 */
53 	signal(SIGPIPE, SIG_IGN);
54 
55 	/* Initialize the output file descriptor. */
56 	if (file == NULL) {
57 		/* No output file given?  Use standard error. */
58 		out_fd = STDERR_FILENO;
59 
60 		return 0;
61 	} else {
62 		/*
63 		 * Use a restrictive mask for the output file.  Traces may
64 		 * contain sensitive information (for security and otherwise),
65 		 * and the user might not always be careful about the location
66 		 * of the file.
67 		 */
68 		/* The file descriptor is not closed explicitly. */
69 		out_fd = open(file, O_WRONLY | O_CREAT | O_TRUNC | O_APPEND,
70 		    0600);
71 
72 		return (out_fd < 0) ? -1 : 0;
73 	}
74 }
75 
76 /*
77  * Write the given data to the given file descriptor, taking into account the
78  * possibility of partial writes and write errors.
79  */
80 static void
81 write_fd(int fd, const char *buf, size_t len)
82 {
83 	ssize_t r;
84 
85 	/* If we got a write error before, do not try to write more. */
86 	if (out_err)
87 		return;
88 
89 	/* Write all output, in chunks if we have to. */
90 	while (len > 0) {
91 		r = write(fd, buf, len);
92 
93 		/*
94 		 * A write error (and that includes EOF) causes the program to
95 		 * terminate with an error code.  For obvious reasons we cannot
96 		 * print an error about this.  Do not even report to standard
97 		 * error if the output was redirected, because that may mess
98 		 * with the actual programs being run right now.
99 		 */
100 		if (r <= 0) {
101 			out_err = TRUE;
102 
103 			break;
104 		}
105 
106 		len -= r;
107 	}
108 }
109 
110 /*
111  * Return TRUE iff an output error occurred and the program should terminate.
112  */
113 int
114 output_error(void)
115 {
116 
117 	return out_err;
118 }
119 
120 /*
121  * Print the given null-terminated string to the output channel.  Return the
122  * number of characters printed, for alignment purposes.  In the future, this
123  * number may end up being different from the number of bytes given to print,
124  * due to multibyte encoding or colors or whatnot.
125  */
126 static unsigned int
127 output_write(const char * text)
128 {
129 	size_t len;
130 
131 	len = strlen(text);
132 
133 	if (out_len + len > sizeof(out_buf)) {
134 		write_fd(out_fd, out_buf, out_len);
135 
136 		out_len = 0;
137 
138 		/* Write large buffers right away. */
139 		if (len > sizeof(out_buf)) {
140 			write_fd(out_fd, text, len);
141 
142 			return len;
143 		}
144 	}
145 
146 	memcpy(&out_buf[out_len], text, len);
147 
148 	out_len += len;
149 
150 	return len;
151 }
152 
153 /*
154  * Flush any pending output to the output channel.
155  */
156 void
157 output_flush(void)
158 {
159 
160 	if (out_len > 0) {
161 		write_fd(out_fd, out_buf, out_len);
162 
163 		out_len = 0;
164 	}
165 }
166 
167 /*
168  * Print a prefix for a line of output.  Possibly print a timestamp first.
169  * Then, if applicable, print a PID prefix for the given process, or an info
170  * prefix if no process (NULL) is given.
171  *
172  * PIDs are relevant only when multiple processes are traced.  As long as there
173  * are multiple processes, each line is prefixed with the PID of the process.
174  * As soon as the number of processes has been reduced back to one, one more
175  * line is prefixed with the PID of the remaining process (with a "'" instead
176  * of a "|") to help the user identify which process remains.  In addition,
177  * whenever a preempted call is about to be resumed, a "*" is printed instead
178  * of a space, so as to show that it is a continuation of a previous line.  An
179  * example of all these cases:
180  *
181  *   fork() = 3
182  *       3| Tracing test (pid 3)
183  *       3| fork() = 0
184  *       3| read(0, <..>
185  *       2| waitpid(-1, <..>
186  *    INFO| This is an example info line.
187  *       3|*read(0, "", 1024) = 0
188  *       3| exit(1)
189  *       3| Process exited normally with code 1
190  *       2'*waitpid(-1, W_EXITED(1), 0) = 3
191  *   exit(0)
192  *   Process exited normally with code 0
193  */
194 static void
195 put_prefix(struct trace_proc * proc, int resuming)
196 {
197 	struct timeval tv;
198 	struct tm *tm;
199 	char prefix[32];
200 	unsigned int off, count;
201 
202 	assert(line_off == 0);
203 
204 	off = 0;
205 
206 	if (timestamps > 0) {
207 		gettimeofday(&tv, NULL);
208 
209 		tm = gmtime(&tv.tv_sec);
210 
211 		off = strftime(prefix, sizeof(prefix), "%T", tm);
212 
213 		if (timestamps > 1)
214 			off += snprintf(&prefix[off], sizeof(prefix) - off,
215 			    ".%06u", tv.tv_usec);
216 
217 		assert(off < sizeof(prefix) - 2);
218 		prefix[off++] = ' ';
219 		prefix[off] = '\0';
220 
221 		off = output_write(prefix);
222 	}
223 
224 	count = proc_count();
225 
226 	/* TODO: add a command line option for always printing the pid. */
227 	if (print_pid || count > 1 || proc == NULL) {
228 		/*
229 		 * TODO: we currently rely on the highest PID having at most
230 		 * five digits, but this will eventually change.  There are
231 		 * several ways to deal with that, but none are great.
232 		 */
233 		if (proc == NULL)
234 			snprintf(prefix, sizeof(prefix), "%5s| ", "INFO");
235 		else
236 			snprintf(prefix, sizeof(prefix), "%5d%c%c",
237 			    proc->pid, (count > 1) ? '|' : '\'',
238 			    resuming ? '*' : ' ');
239 
240 		off += output_write(prefix);
241 
242 		last_pid = (proc != NULL ? proc->pid : 0);
243 	} else
244 		assert(!resuming);
245 
246 	prefix_off = off;
247 	line_off += off;
248 
249 	/* Remember whether the next line should get prefixed regardless. */
250 	print_pid = (count > 1 || proc == NULL);
251 }
252 
253 /*
254  * Add a string to the end of the text recording for the given process.
255  * This is used only to record the call-enter output of system calls.
256  */
257 static void
258 record_add(struct trace_proc * proc, const char * text)
259 {
260 	size_t len;
261 
262 	assert(proc->recording);
263 
264 	/* If the recording buffer is already full, do not record more. */
265 	if (proc->outlen == sizeof(proc->outbuf))
266 		return;
267 
268 	len = strlen(text);
269 
270 	/* If nonempty, the recording buffer is always null terminated. */
271 	if (len < sizeof(proc->outbuf) - proc->outlen - 1) {
272 		strcpy(&proc->outbuf[proc->outlen], text);
273 
274 		proc->outlen += len;
275 	} else
276 		proc->outlen = sizeof(proc->outbuf); /* buffer exhausted */
277 }
278 
279 /*
280  * Start recording text for the given process.  Since this marks the start of
281  * a call, remember to print a preemption marker when the call gets preempted.
282  */
283 void
284 record_start(struct trace_proc * proc)
285 {
286 
287 	proc->recording = TRUE;
288 
289 	print_susp = TRUE;
290 }
291 
292 /*
293  * Stop recording text for the given process.
294  */
295 void
296 record_stop(struct trace_proc * proc)
297 {
298 
299 	proc->recording = FALSE;
300 }
301 
302 /*
303  * Clear recorded text for the given process.  Since this also marks the end of
304  * the entire call, no longer print a supension marker before the next newline.
305  */
306 void
307 record_clear(struct trace_proc * proc)
308 {
309 
310 	assert(!proc->recording);
311 	proc->outlen = 0;
312 
313 	if (proc->pid == last_pid)
314 		print_susp = FALSE;
315 }
316 
317 /*
318  * Replay the record for the given process on a new line, if the current line
319  * does not already have output for this process.  If it does, do nothing.
320  * If the process has no recorded output, just start a new line.  Return TRUE
321  * iff the caller must print its own replay text due to a recording overflow.
322  */
323 int
324 record_replay(struct trace_proc * proc)
325 {
326 	int space;
327 
328 	assert(!proc->recording);
329 
330 	/*
331 	 * If there is output on the current line, and it is for the current
332 	 * process, we must assume that it is the original, recorded text, and
333 	 * thus, we should do nothing.  If output on the current line is for
334 	 * another process, we must force a new line before replaying.
335 	 */
336 	if (line_off > 0) {
337 		if (proc->pid == last_pid)
338 			return FALSE;
339 
340 		put_newline();
341 	}
342 
343 	/*
344 	 * If there is nothing to replay, do nothing further.  This case may
345 	 * occur when printing signals, in which case the caller still expects
346 	 * a new line to be started.  This line must not be prefixed with a
347 	 * "resuming" marker though--after all, nothing is being resumed here.
348 	 */
349 	if (proc->outlen == 0)
350 		return FALSE;
351 
352 	/*
353 	 * If there is text to replay, then this does mean we are in effect
354 	 * resuming the recorded call, even if it is just to print a signal.
355 	 * Thus, we must print a prefix that shows the call is being resumed.
356 	 * Similarly, unless the recording is cleared before a newline, we must
357 	 * suspend the line again, too.
358 	 */
359 	put_prefix(proc, TRUE /*resuming*/);
360 
361 	print_susp = TRUE;
362 
363 	/*
364 	 * If the recording buffer was exhausted during recording, the caller
365 	 * must generate the replay text instead.
366 	 */
367 	if (proc->outlen == sizeof(proc->outbuf))
368 		return TRUE;
369 
370 	/*
371 	 * Replay the recording.  If it ends with a space, turn it into a soft
372 	 * space, because the recording may be followed immediately by a
373 	 * newline; an example of this is the exit() exception.
374 	 */
375 	space = proc->outbuf[proc->outlen - 1] == ' ';
376 	if (space)
377 		proc->outbuf[proc->outlen - 1] = 0;
378 
379 	put_text(proc, proc->outbuf);
380 
381 	if (space) {
382 		put_space(proc);
383 
384 		/* Restore the space, in case another replay takes place. */
385 		proc->outbuf[proc->outlen - 1] = ' ';
386 	}
387 
388 	return FALSE;
389 }
390 
391 /*
392  * Start a new line, and adjust the local state accordingly.  If nothing has
393  * been printed on the current line yet, this function is a no-op.  Otherwise,
394  * the output so far may have to be marked as preempted with the "<..>"
395  * preemption marker.
396  */
397 void
398 put_newline(void)
399 {
400 
401 	if (line_off == 0)
402 		return;
403 
404 	if (print_susp) {
405 		if (add_space)
406 			(void)output_write(" ");
407 
408 		(void)output_write("<..>");
409 	}
410 
411 #if DEBUG
412 	(void)output_write("|");
413 #endif
414 
415 	(void)output_write("\n");
416 	output_flush();
417 
418 	line_off = 0;
419 	add_space = FALSE;
420 	print_susp = FALSE;
421 	last_pid = 0;
422 }
423 
424 /*
425  * Print a string as part of the output associated with a process.  If the
426  * current line contains output for another process, a newline will be printed
427  * first.  If the current line contains output for the same process, then the
428  * text will simply continue on the same line.  If the current line is empty,
429  * a process PID prefix may have to be printed first.  Either way, after this
430  * operation, the current line will contain text for the given process.  If
431  * requested, the text may also be recorded for the process, for later replay.
432  * As an exception, proc may be NULL when printing general information lines.
433  */
434 void
435 put_text(struct trace_proc * proc, const char * text)
436 {
437 
438 	if (line_off > 0 && (proc == NULL || proc->pid != last_pid)) {
439 		/*
440 		 * The current line has not been terminated with a newline yet.
441 		 * Start a new line.  Note that this means that for lines not
442 		 * associated to a process, the whole line must be printed at
443 		 * once.  This can be fixed but is currently not an issue.
444 		 */
445 		put_newline();
446 	}
447 
448 	/* See if we must add a prefix at the start of the line. */
449 	if (line_off == 0)
450 		put_prefix(proc, FALSE /*resuming*/);
451 
452 	/* If needed, record the given text. */
453 	if (proc != NULL && proc->recording)
454 		record_add(proc, text);
455 
456 	/*
457 	 * If we delayed printing a space, print one now.  This is never part
458 	 * of text that must be saved.  In fact, we support these soft spaces
459 	 * for exactly one case; see put_space() for details.
460 	 */
461 	if (add_space) {
462 		line_off += output_write(" ");
463 
464 		add_space = FALSE;
465 	}
466 
467 	/* Finally, print the actual text. */
468 	line_off += output_write(text);
469 
470 	last_pid = (proc != NULL) ? proc->pid : 0;
471 }
472 
473 /*
474  * Add a space to the output for the given process, but only if and once more
475  * text is printed for the process afterwards.  The aim is to ensure that no
476  * lines ever end with a space, to prevent needless line wrapping on terminals.
477  * The space may have to be remembered for the current line (for preemption,
478  * which does not have a process pointer to work with) as well as recorded for
479  * later replay, if recording is enabled.  Consider the following example:
480  *
481  * [A]   3| execve(..) <..>
482  *       2| getpid(0) = 2 (ppid=1)
483  * [B]   3| execve(..) = -1 [ENOENT]
484  * [A]   3| exit(1) <..>
485  *       2| getpid(0) = 2 (ppid=1)
486  *       3| exit(1)
487  *       3| Process exited normally with code 1
488  *
489  * On the [A] lines, the space between the call's closing parenthesis and the
490  * "<..>" preemption marker is the result of add_space being set to TRUE; on
491  * the [B] line, the space between the closing parenthesis and the equals sign
492  * is the result of the space being recorded.
493  */
494 void
495 put_space(struct trace_proc * proc)
496 {
497 
498 	/* This call must only be used after output for the given process. */
499 	assert(last_pid == proc->pid);
500 
501 	/* In case the call does not get preempted. */
502 	add_space = TRUE;
503 
504 	/* In case the call does get preempted. */
505 	if (proc->recording)
506 		record_add(proc, " ");
507 }
508 
509 /*
510  * Indent the remainders of the text on the line for this process, such that
511  * similar remainders are similarly aligned.  In particular, the remainder is
512  * the equals sign of a call, and everything after it.  Of course, alignment
513  * can only be used if the call has not already printed beyond the alignment
514  * position.  Also, the prefix must not be counted toward the alignment, as it
515  * is possible that a line without prefix may be preempted and later continued
516  * with prefix.  All things considered, the result would look like this:
517  *
518  *   getuid()                      = 1 (euid=1)
519  *   setuid(0)                     = -1 [EPERM]
520  *   write(2, "Permission denied\n", 18) = 18
521  *   fork()                        = 3
522  *       3| Tracing test (pid 3)
523  *       3| fork()                        = 0
524  *       3| exit(0)
525  *       3| Process exited normally with code 0
526  *       2' waitpid(-1, W_EXITED(0), 0)   = 3
527  *
528  */
529 void put_align(struct trace_proc * __unused proc)
530 {
531 
532 	/*
533 	 * TODO: add actual support for this.  The following code works,
534 	 * although not so efficiently.  The difficulty is the default
535 	 * configuration and corresponding options.
536 
537 	while (line_off - prefix_off < 20)
538 		put_text(proc, " ");
539 
540 	 */
541 }
542