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
|
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License, Version 1.0 only
* (the "License"). You may not use this file except in compliance
* with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* or http://www.opensolaris.org/os/licensing.
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright (c) 1994, by Sun Microsytems, Inc.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h> /* for strerror() */
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/tnf.h>
#include <fcntl.h>
#include <errno.h>
#include <locale.h>
#include "prbk.h"
#include <tnf/tnfctl.h>
extern tnfctl_handle_t *g_hndl;
typedef struct _pidlist {
pid_t pid;
struct _pidlist *next;
} pidlist_t;
static boolean_t check_kernelmode(tnfctl_trace_attrs_t *attrs_p);
static boolean_t
check_kernelmode(tnfctl_trace_attrs_t *attrs_p)
{
extern int g_kernelmode;
tnfctl_errcode_t err;
if (!g_kernelmode) {
(void) fprintf(stderr, gettext(
"This command is only available "
"in kernel mode (prex invoked with the -k flag)\n"));
return (B_TRUE);
}
if (attrs_p) {
err = tnfctl_trace_attrs_get(g_hndl, attrs_p);
if (err) {
(void) fprintf(stderr, gettext(
"error on checking trace attributes : %s\n"),
tnfctl_strerror(err));
return (B_TRUE);
}
}
return (B_FALSE);
}
/*
* Print trace buffer status (is one allocated, and if so, how big is it.
*/
void
prbk_buffer_list()
{
tnfctl_trace_attrs_t attrs;
if (check_kernelmode(&attrs))
return;
if (attrs.trace_buf_state == TNFCTL_BUF_NONE) {
(void) printf(gettext("No trace buffer allocated\n"));
} else {
(void) printf(gettext("Trace buffer size is %d bytes\n"),
attrs.trace_buf_size);
if (attrs.trace_buf_state == TNFCTL_BUF_BROKEN) {
(void) printf(gettext("Tracing system has failed -- "
"tracing suspended\n"));
}
}
}
/*
* Allocate a trace buffer. Check for reasonable size; reject if there's
* already a buffer.
*/
void
prbk_buffer_alloc(int size)
{
tnfctl_errcode_t err;
tnfctl_trace_attrs_t attrs;
if (check_kernelmode(&attrs))
return;
if (attrs.trace_buf_state != TNFCTL_BUF_NONE) {
(void) fprintf(stderr,
gettext("There is already a buffer allocated\n"));
return;
}
if (size < attrs.trace_min_size) {
(void) fprintf(stderr, gettext(
"Size %d is less than the minimum buffer size of %d -- "
"buffer size set to %d bytes\n"),
size, attrs.trace_min_size, attrs.trace_min_size);
size = attrs.trace_min_size;
}
err = tnfctl_buffer_alloc(g_hndl, NULL, size);
if (err) {
(void) fprintf(stderr,
gettext("error in allocating buffer: %s\n"),
tnfctl_strerror(err));
return;
}
/* get the trace attributes again */
if (check_kernelmode(&attrs))
return;
(void) printf(gettext("Buffer of size %d bytes allocated\n"),
attrs.trace_buf_size);
}
/*
* Deallocate the kernel's trace buffer.
*/
void
prbk_buffer_dealloc()
{
tnfctl_errcode_t err;
if (check_kernelmode(NULL))
return;
err = tnfctl_buffer_dealloc(g_hndl);
switch (err) {
case (TNFCTL_ERR_NONE):
(void) printf(gettext("buffer deallocated\n"));
break;
case (TNFCTL_ERR_NOBUF):
(void) fprintf(stderr,
gettext("There is no buffer to deallocate\n"));
break;
case (TNFCTL_ERR_BADDEALLOC):
(void) fprintf(stderr,
gettext("Can't deallocate the buffer when "
"tracing is active\n"));
break;
default:
(void) fprintf(stderr,
gettext("error in deleting buffer: %s\n"),
tnfctl_strerror(err));
break;
}
}
/*
* Process filter routines.
*
* Process id sets are encoded as "pidlists": a linked list of pids.
* In a feeble attempt at encapsulation, the pidlist_t type is private
* to this file; prexgram.y manipulates pidlists only as opaque handles.
*/
/*
* Add the given pid (new) to the pidlist (pl).
*/
void *
prbk_pidlist_add(void *pl, int new)
{
pidlist_t *npl = (pidlist_t *) malloc(sizeof (*npl));
if (npl == NULL) {
(void) fprintf(stderr,
gettext("Out of memory -- can't process pid %d\n"),
new);
return (pl);
}
npl->next = pl;
npl->pid = new;
return (npl);
}
/*
* Add the pids in the given pidlist to the process filter list.
* For each pid, check whether it's already in the filter list,
* and whether the process exists.
*/
void
prbk_pfilter_add(void *pl)
{
pidlist_t *ppl = (pidlist_t *) pl;
pidlist_t *tmp;
tnfctl_errcode_t err;
if (check_kernelmode(NULL))
return;
while (ppl != NULL) {
err = tnfctl_filter_list_add(g_hndl, ppl->pid);
if (err) {
(void) fprintf(stderr, gettext("Process %ld: %s\n"),
ppl->pid, tnfctl_strerror(err));
}
tmp = ppl;
ppl = ppl->next;
free(tmp);
}
}
/*
* Drop the pids in the given pidlist from the process filter list.
* For each pid, complain if it's not in the process filter list;
* and if the process no longer exists (and hence has already implicitly
* been dropped from the process filter list), say so.
*/
void
prbk_pfilter_drop(void *pl)
{
pidlist_t *ppl = (pidlist_t *) pl;
pidlist_t *tmp;
tnfctl_errcode_t err;
if (check_kernelmode(NULL))
return;
while (ppl != NULL) {
tmp = ppl;
err = tnfctl_filter_list_delete(g_hndl, tmp->pid);
switch (err) {
case (TNFCTL_ERR_NONE):
break;
case (TNFCTL_ERR_BADARG):
(void) fprintf(stderr,
gettext("Process %ld is not being traced\n"),
tmp->pid);
break;
case (TNFCTL_ERR_NOPROCESS):
(void) printf(gettext("Process %ld has exited\n"),
tmp->pid);
break;
default:
(void) fprintf(stderr, gettext("Process %ld: %s\n"),
tmp->pid, tnfctl_strerror(err));
break;
}
ppl = ppl->next;
free(tmp);
}
}
/*
* Turn process filter mode on or off. The process filter is maintained
* even when process filtering is off, but has no effect: all processes
* are traced.
*/
void
prbk_set_pfilter_mode(boolean_t onoff)
{
tnfctl_errcode_t err;
if (check_kernelmode(NULL))
return;
err = tnfctl_filter_state_set(g_hndl, onoff);
if (err) {
(void) fprintf(stderr, gettext("pfilter: %s\n"),
tnfctl_strerror(err));
}
}
/*
* Report whether process filter mode is currently on or off, and
* dump the current process filter set.
*/
void
prbk_show_pfilter_mode()
{
tnfctl_errcode_t err;
tnfctl_trace_attrs_t attrs;
pid_t *pids_p;
int i, pid_count;
pid_t *cur_pid;
if (check_kernelmode(&attrs))
return;
(void) printf(gettext("Process filtering is %s\n"),
attrs.filter_state ? "on" : "off");
err = tnfctl_filter_list_get(g_hndl, &pids_p, &pid_count);
if (err) {
(void) fprintf(stderr,
gettext("error in getting process filter list: %s\n"),
tnfctl_strerror(err));
return;
}
(void) printf(gettext("Process filter set is "));
if (pid_count == 0)
(void) printf("empty.\n");
else {
(void) printf("{");
cur_pid = pids_p;
for (i = 0; i < pid_count; i++, cur_pid++) {
(void) printf("%ld%s", *cur_pid,
(i != (pid_count - 1)) ? ", " : "}\n");
}
}
}
/*
* Check for process filtering on with empty pid filter.
*/
void
prbk_warn_pfilter_empty(void)
{
tnfctl_errcode_t err;
pid_t *pids_p;
int pid_count;
tnfctl_trace_attrs_t attrs;
if (check_kernelmode(&attrs))
return;
if (attrs.filter_state) {
err = tnfctl_filter_list_get(g_hndl, &pids_p, &pid_count);
if (err) {
(void) fprintf(stderr,
gettext("error in getting process filter list: %s\n"),
tnfctl_strerror(err));
return;
}
if (!pid_count)
(void) fprintf(stderr,
gettext("Warning: Process filtering on, \
but pid filter list is empty\n"));
}
}
/*
* Turn kernel tracing on or off.
*/
void
prbk_set_tracing(boolean_t onoff)
{
tnfctl_errcode_t err;
if (check_kernelmode(NULL))
return;
err = tnfctl_trace_state_set(g_hndl, onoff);
if (err) {
(void) fprintf(stderr,
gettext("error in setting tracing state: %s\n"),
tnfctl_strerror(err));
}
}
/*
* Show whether kernel tracing is currently on or off.
*/
void
prbk_show_tracing()
{
tnfctl_trace_attrs_t attrs;
if (check_kernelmode(&attrs))
return;
(void) printf(gettext("Tracing is %s\n"),
attrs.trace_state ? "on" : "off");
}
|