summaryrefslogtreecommitdiff
path: root/src/strauss.c
blob: 1b6d8d419993ffdf83167b55086ac6531c32e7b7 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
/*
 * Strauss awareness implementation.
 *
 * Copyright (c) 2018-2022 The strace developers.
 * All rights reserved.
 *
 * SPDX-License-Identifier: LGPL-2.1-or-later
 */

#include "defs.h"

#include <stdio.h>
#include <stdlib.h>
#include <sys/time.h>

#include "strauss.h"

static const char *strauss[] = {
	"",
	"     ____",
	"    /    \\",
	"   |-. .-.|",
	"   (_@)(_@)",
	"   .---_  \\",
	"  /..   \\_/",
	"  |__.-^ /",
	"      }  |",
	"     |   [",
	"     [  ]",
	"    ]   |",
	"    |   [",
	"    [  ]",
	"   /   |        __",
	"  \\|   |/     _/ /_",
	" \\ |   |//___/__/__/_",
	"\\\\  \\ /  //    -____/_",
	"//   \"   \\\\      \\___.-",
	" //     \\\\  __.----._/_",
	"/ '/|||\\` .-         __>",
	"[        /         __.-",
	"[        [           }",
	"\\        \\          /",
	" \"-._____ \\.____.--\"",
	"    |  | |  |",
	"    |  | |  |",
	"    |  | |  |",
	"    |  | |  |",
	"    {  } {  }",
	"    |  | |  |",
	"    |  | |  |",
	"    |  | |  |",
	"    /  { |  |",
	" .-\"   / [   -._",
	"/___/ /   \\ \\___\"-.",
	"    -\"     \"-",
	};

const size_t strauss_lines = ARRAY_SIZE(strauss);

enum { MAX_TIP_LINES = 14 };

static const char *tips_tricks_tweaks[][MAX_TIP_LINES] = {
	{ "strace has an extensive manual page",
	  "that covers all the possible options",
	  "and contains several useful invocation",
	  "examples." },
	{ "You can use -o|COMMAND to redirect strace's",
	  "output to COMMAND.  This may be useful",
	  "in cases when there is a redirection",
	  "in place for the traced program.  Don't",
	  "forget to escape the pipe character, though,",
	  "as it is usually interpreted by the shell." },
	{ "It's possible to display timestamps",
	  " produced by -r, -t, and -T options",
	  "with nanosecond precision using their",
	  "long variants: --relative-timestamps=ns,",
	  "--absolute-timestamps=ns, and",
	  "--syscall-times=ns, respectively.", "",
	  "Why microsecond precision is the default?",
	  "To preserve the historic output format",
	  "which was limited by struct timeval",
	  "precision." },
	{ "A particular quote from a particular novel",
	  "by Arthur C. Clarke is printed if an attempt",
	  "is made to attach to a particular process." },
	{ "It's possible to tune the environment",
	  "of the traced process using the -E/--env",
	  "option:", "",
	  "    strace -E REMOVE_VAR -E VAR=new_val" },
#ifdef ENABLE_STACKTRACE
	{ "You can print a stack trace for each traced",
	  "call by specifying -k/--stack-traces option.",
# ifdef USE_DEMANGLE
	  "It can even demangle symbol names.",
# endif
	  },
#else
	{ "We wish we could tell you that you can",
	  "specify -k/--stack-traces option to print",
	  "stack traces for each traced system call,",
	  "but, unfortunately, you can't: this strace",
	  "binary is built without stack tracing",
	  "support." },
#endif
#ifdef ENABLE_SECONTEXT
	{ "You can print SELinux contexts associated",
	  "with PIDs, FDs, and paths by specifying",
	  "--secontext option.  Unless provided",
	  "with the \"full\" parameter, it prints only",
	  "SELinux context type, and the \"mismatch\"",
	  "parameter enables printing of the expected",
	  "context in case of mismatch, so", "",
	  "    strace --secontext=full,mismatch", "",
	  "will show all gory SELinux details." },
#else
	{ "We wish we could tell you that you can",
	  "specify --secontext option to print SELinux",
	  "context for each PID, FD, and path occurred",
	  "in the trace, but, unfortunately, you can't:",
	  "this strace binary is built without SELinux",
	  "support." },
#endif
	{ "Have you ever been bitten by an accidental",
	  "overwrite of the output file specified",
	  "in the -o option?  Specify",
	  "-A/--output-append-mode as well,",
	  "and this problem will never bite you again!" },
	{ "strace is about as old as the Linux kernel.",
	  "It has been originally written for SunOS",
	  "by Paul Kranenburg in 1991.  The support",
	  "for all OSes except Linux was dropped",
	  "in 2012, though, in strace 4.7." },
	{ "strace is able to decode netlink messages.",
	  "It does so automatically for I/O performed",
	  "on netlink sockets.  Try it yourself:", "",
	  "    strace -e%network ip a" },
	{ "Filtered syscalls, errors, and signals can",
	  "be specified either by name or by number,",
	  "for example:", "",
	  "    strace --trace=0,1,2 --signal=2,15 true" },
	{ "It is possible to specify -r and -t options",
	  "simultaneously since strace 4.22." },
	{ "Strace can print only successful syscall",
	  "invocations when supplied with",
	  "-z/--successful-only option.  There's also",
	  "a possibility to filter calls with other",
	  "statuses, please refer to -e status option",
	  "documentation." },
	{ "If you trace a process that uses KVM",
	  "subsystem, --kvm=vcpu option may be of use:",
	  "it prints KVM VCPU exit reason.  It requires",
	  "Linux 4.16+, however." },
	{ "It is possible to get strace out of your way",
	  "(in terms of parent/child relationships and",
	  "signal communication) with -D/--daemonize",
	  "option.  Another option that may be of use",
	  "in this case is -I/--interruptible, it",
	  "restricts the set of signals that interrupt",
	  "strace." },
	{ "If strace is too chatty to your taste, you",
	  "can silence it with -qqq option." },
	{ "strace prints file paths along with file",
	  "descriptor numbers when it is invoked with",
	  "-y/--decode-fds option.",
	  "When -yy (or --decode-fds=all) is provided,",
	  "it also prints protocol-specific information",
	  "for sockets and device numbers for character",
	  "and block device files." },
	{ "You can control what columns are shown",
	  "in the call summary table produced by -c/-C",
	  "options with -U/--summary-columns option.",
	  "It is a way to get minimum/maximum call",
	  "duration printed, for example:", "",
	  "    strace -c -U name,min-time,max-time ls" },
	{ "If you feel that syscall duration shown",
	  "in the call summary table (-c/-C option)",
	  "is not right, you can try to use -w option",
	  "(that collects wall clock time,",
	  "instead of system time), maybe that is what",
	  "you are looking for." },
	{ "strace understands -z option since 2002,",
	  "but it wasn't documented because its",
	  "implementation was broken.  Only 17 years",
	  "later, in strace 5.2, it was properly",
	  "implemented and documented." },
	{ "If you feel that strace is too slow, you may",
	  "want to try --seccomp-bpf option, maybe you",
	  "will feel better." },
	{ "-v is a shorthand for -e abbrev=none and not",
	  "for -e verbose=all.  It is idiosyncratic,",
	  "but it is the historic behaviour." },
	{ "strace uses netlink for printing",
	  "protocol-specific information about socket",
	  "descriptors (-yy option)." },
	{ "strace is able to tamper with tracees'",
	  "execution by injecting an arbitrary return",
	  "or error value instead of syscall execution,",
	  "for example:", "",
	  "    strace --inject=unlink:retval=0", "",
	  "will prevent execution of unlink calls, but",
	  "the traced process will think that the calls",
	  "have succeeded." },
	{ "strace's tampering capabilities include",
	  "injection of arbitrary return/error values,",
	  "injection of a signal, injection of a delay",
	  "or data before or after syscall execution." },
	{ "If you want to see numerical values of named",
	  "constants, there is an option for that:",
	  "-X/--const-print-style.  When -Xraw",
	  "(or --const-print-style=raw) is provided,",
	  "strace prints just the numerical value",
	  "of an argument; with -Xverbose, it prints",
	  "values in both numerical and symbolic form." },
	{ "getpid syscall is present on all",
	  "architectures except on Alpha, where getxpid",
	  "syscall (that returns a pair of PID and PPID",
	  "in a pair of registers) is used instead.",
	  "Other two examples of syscalls that utilise",
	  "two registers for their return values are",
	  "getxuid and getxgid: they return a pair",
	  "of real and effective UIDs/GIDs." },
	{ "There are three syscalls that implement",
	  "generic \"open file\" task: open, openat,",
	  "and openat2.  On some (newly supported)",
	  "architectures, open syscall is not even",
	  "present.  How to write a robust filtering",
	  "expression in this case?",
	  "With the conditional syntax, for example:", "",
	  "    strace --trace=?open,?openat,?openat2", "",
	  "You may want to escape question marks, since",
	  "your shell may interpret them as a path glob",
	  "expression." },
	{ "It is possible to use regular expressions",
	  "for syscall names in the -e trace",
	  "expression, for example:", "",
	  "    strace -e trace=/^sched_.*", "",
	  "will trace all scheduling-related syscalls." },
	{ "IA-64 (Itanium) uses syscall numbers",
	  "beginning from 1024, because numbers",
	  "beginning from 0 were designated for i386",
	  "compat layer (that has never been",
	  "upstreamed).  Another example",
	  "of an architecture with sparse syscall table",
	  "is MIPS, with parts of it beginning at index",
	  "0 (SVR4 ABI), 1000 (SysV ABI), 2000",
	  "(BSD 4.3 ABI), 3000 (POSIX ABI), 4000 (Linux",
	  "O32 ABI), 5000 (Linux N64 ABI), and 6000",
	  "(Linux N32 ABI)." },
	{ "Der Strauss, the strace's project mascot,",
	  "was conceived in 2017.  It is a brainchild",
	  "of Vitaly Chaykovsky." },
	/* https://github.com/strace/strace/issues/14 */
	{ "Medicinal effects of strace can be achieved",
	  "by invoking it with the following options:", "",
	  "    strace -DDDqqq -enone --signal=none" },
	{ "Historically, supplying -o option to strace",
	  "leads to silencing of messages about tracee",
	  "attach/detach and personality changes.",
	  "It can be now overridden with --quiet=none",
	  "option." },
	{ "You can avoid tracing of \"other programs\"",
	  "that are executed by the traced program",
	  "with -b execve option." },
	{ "-F option used to be a separate option",
	  "for following vfork calls." },
	{ "It is possible to provide multiple PIDs",
	  "to a single -p option with white space",
	  "or comma as accepted delimiter, in order",
	  "to support usage like", "",
	  "    strace -p \"`pidof PROG`\"",
	  "or",
	  "    strace -p \"`pgrep PROG`\"", "",
	  "pidof uses space as a delimiter, pgrep uses",
	  "newline." },
	{ "-n option, that prints syscall numbers,",
	  "while seemingly quite obvious functionality,",
	  "was added to strace only in version 5.9,",
	  "in the year 2020." },
	{ "Instead of tirelessly specifying",
	  "architecture- and libc-specific sets",
	  "of syscalls pertaining specific task each",
	  "time, one can try to use pre-defined syscall",
	  "classes.  For example,", "",
	  "    strace -e%creds", "",
	  "will trace all syscalls related to accessing",
	  "and modifying process's user/group IDs",
	  "and capability sets.  Other pre-defined",
	  "syscall classes include %clock, %desc,",
	  "%file, %ipc, %memory, %net, %process,",
	  "and %signal." },
	{ "Trying to figure out communication between",
	  "tracees inside a different PID namespace",
	  "(in so-called \"containers\", for example)?",
	  "Try out the --pidns-translation option,",
	  "it prints PIDs in strace's PID NS when a PID",
	  "reference from a different PID NS occurs",
	  "in trace.  It is not enabled by default",
	  "because there is no sane kernel API",
	  "to perform PID translation between",
	  "namespaces, so each such translation",
	  "requires many reads and ioctls in procfs,",
	  "which may incur severe performance penalty." },
	{ "If you don't like the way strace escapes",
	  "non-printable characters using octal",
	  "numbers, and don't want to sacrifice",
	  "readability of the ASCII output with -x/-xx",
	  "options, you might want to try", "",
	  "    strace --strings-in-hex=non-ascii-chars", "",
	  "that will change escape sequences",
	  "to hexadecimal numbers usage." },
	{ "-Y option (an alias to --decode-pids=comm)",
	  "shows comm string associated with the PID." },
};

static const char tip_top[] =
	"  ______________________________________________    ";
static const char tip_bottom[] =
	" \\______________________________________________/   ";
static const char *tip_left[] = { " / ", " | "};
static const char *tip_right[] = {
	" \\   ",
	" |   ",
	" \\   ",
	"  \\  ",
	"  _\\ ",
	" /   ",
	" |   ", };

enum tips_fmt show_tips = TIPS_NONE;
int tip_id = TIP_ID_RANDOM;

void
print_strauss(size_t verbosity)
{
	if (verbosity < STRAUSS_START_VERBOSITY)
		return;

	verbosity = MIN(verbosity - STRAUSS_START_VERBOSITY, strauss_lines);

	for (size_t i = 0; i < verbosity; i++)
		puts(strauss[i]);
}

void
print_totd(void)
{
	static bool printed = false;
	const int w = (int) (sizeof(tip_top) - 1 - strlen(tip_left[0])
				- strlen(tip_right[0]));
	struct timeval tv;
	size_t id;
	size_t i;

	if (printed || show_tips == TIPS_NONE)
		return;

	if (tip_id == TIP_ID_RANDOM) {
		gettimeofday(&tv, NULL);
		srand(tv.tv_sec ^ tv.tv_usec);
		id = rand();
	} else {
		id = tip_id;
	}
	id %= ARRAY_SIZE(tips_tricks_tweaks);

	fprintf(stderr, "%s%s\n", tip_top, strauss[1]);
	fprintf(stderr, "%s%-*s%s%s\n",
		tip_left[0], w, "", tip_right[0], strauss[2]);
	for (i = 0; (i < MAX_TIP_LINES) && (tips_tricks_tweaks[id][i] ||
					    (i < (ARRAY_SIZE(tip_right) - 1)));
	     i++) {
		fprintf(stderr, "%s%-*.*s%s%s\n",
			tip_left[MIN(i + 1, ARRAY_SIZE(tip_left) - 1)],
			w, w, tips_tricks_tweaks[id][i] ?: "",
			tip_right[MIN(i + 1, ARRAY_SIZE(tip_right) - 1)],
			strauss[MIN(3 + i, strauss_lines - 1)]);
	}
	fprintf(stderr, "%s%s\n",
		tip_bottom, strauss[MIN(3 + i, strauss_lines - 1)]);
	do {
		fprintf(stderr, "%*s%*s%*s%s\n",
			(int) strlen(tip_left[0]), "",
			w, "",
			(int) strlen(tip_right[0]), "",
			strauss[MIN(4 + i, strauss_lines - 1)]);
	} while ((show_tips == TIPS_FULL) && (4 + ++i < strauss_lines));

	printed = true;
}