1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License, Version 1.0 only
6 * (the "License"). You may not use this file except in compliance
7 * with the License.
8 *
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
13 *
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
19 *
20 * CDDL HEADER END
21 */
22 /*
23 * Copyright (c) 1994, by Sun Microsytems, Inc.
24 */
25
26 #pragma ident "%Z%%M% %I% %E% SMI"
27
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <unistd.h>
31 #include <string.h> /* for strerror() */
32 #include <sys/types.h>
33 #include <sys/stat.h>
34 #include <sys/tnf.h>
35 #include <fcntl.h>
36 #include <errno.h>
37 #include <locale.h>
38
39 #include "prbk.h"
40
41 #include <tnf/tnfctl.h>
42
43 extern tnfctl_handle_t *g_hndl;
44
45 typedef struct _pidlist {
46 pid_t pid;
47 struct _pidlist *next;
48 } pidlist_t;
49
50 static boolean_t check_kernelmode(tnfctl_trace_attrs_t *attrs_p);
51
52 static boolean_t
check_kernelmode(tnfctl_trace_attrs_t * attrs_p)53 check_kernelmode(tnfctl_trace_attrs_t *attrs_p)
54 {
55 extern int g_kernelmode;
56 tnfctl_errcode_t err;
57
58 if (!g_kernelmode) {
59 (void) fprintf(stderr, gettext(
60 "This command is only available "
61 "in kernel mode (prex invoked with the -k flag)\n"));
62 return (B_TRUE);
63 }
64 if (attrs_p) {
65 err = tnfctl_trace_attrs_get(g_hndl, attrs_p);
66 if (err) {
67 (void) fprintf(stderr, gettext(
68 "error on checking trace attributes : %s\n"),
69 tnfctl_strerror(err));
70 return (B_TRUE);
71 }
72 }
73 return (B_FALSE);
74 }
75
76 /*
77 * Print trace buffer status (is one allocated, and if so, how big is it.
78 */
79 void
prbk_buffer_list()80 prbk_buffer_list()
81 {
82 tnfctl_trace_attrs_t attrs;
83
84 if (check_kernelmode(&attrs))
85 return;
86 if (attrs.trace_buf_state == TNFCTL_BUF_NONE) {
87 (void) printf(gettext("No trace buffer allocated\n"));
88 } else {
89 (void) printf(gettext("Trace buffer size is %d bytes\n"),
90 attrs.trace_buf_size);
91 if (attrs.trace_buf_state == TNFCTL_BUF_BROKEN) {
92 (void) printf(gettext("Tracing system has failed -- "
93 "tracing suspended\n"));
94 }
95 }
96 }
97
98
99 /*
100 * Allocate a trace buffer. Check for reasonable size; reject if there's
101 * already a buffer.
102 */
103 void
prbk_buffer_alloc(int size)104 prbk_buffer_alloc(int size)
105 {
106 tnfctl_errcode_t err;
107 tnfctl_trace_attrs_t attrs;
108
109 if (check_kernelmode(&attrs))
110 return;
111
112 if (attrs.trace_buf_state != TNFCTL_BUF_NONE) {
113 (void) fprintf(stderr,
114 gettext("There is already a buffer allocated\n"));
115 return;
116 }
117 if (size < attrs.trace_min_size) {
118 (void) fprintf(stderr, gettext(
119 "Size %d is less than the minimum buffer size of %d -- "
120 "buffer size set to %d bytes\n"),
121 size, attrs.trace_min_size, attrs.trace_min_size);
122 size = attrs.trace_min_size;
123 }
124
125 err = tnfctl_buffer_alloc(g_hndl, NULL, size);
126 if (err) {
127 (void) fprintf(stderr,
128 gettext("error in allocating buffer: %s\n"),
129 tnfctl_strerror(err));
130 return;
131 }
132
133 /* get the trace attributes again */
134 if (check_kernelmode(&attrs))
135 return;
136 (void) printf(gettext("Buffer of size %d bytes allocated\n"),
137 attrs.trace_buf_size);
138 }
139
140
141 /*
142 * Deallocate the kernel's trace buffer.
143 */
144 void
prbk_buffer_dealloc()145 prbk_buffer_dealloc()
146 {
147 tnfctl_errcode_t err;
148
149 if (check_kernelmode(NULL))
150 return;
151
152 err = tnfctl_buffer_dealloc(g_hndl);
153 switch (err) {
154 case (TNFCTL_ERR_NONE):
155 (void) printf(gettext("buffer deallocated\n"));
156 break;
157 case (TNFCTL_ERR_NOBUF):
158 (void) fprintf(stderr,
159 gettext("There is no buffer to deallocate\n"));
160 break;
161 case (TNFCTL_ERR_BADDEALLOC):
162 (void) fprintf(stderr,
163 gettext("Can't deallocate the buffer when "
164 "tracing is active\n"));
165 break;
166 default:
167 (void) fprintf(stderr,
168 gettext("error in deleting buffer: %s\n"),
169 tnfctl_strerror(err));
170 break;
171 }
172 }
173
174
175 /*
176 * Process filter routines.
177 *
178 * Process id sets are encoded as "pidlists": a linked list of pids.
179 * In a feeble attempt at encapsulation, the pidlist_t type is private
180 * to this file; prexgram.y manipulates pidlists only as opaque handles.
181 */
182
183 /*
184 * Add the given pid (new) to the pidlist (pl).
185 */
186 void *
prbk_pidlist_add(void * pl,int new)187 prbk_pidlist_add(void *pl, int new)
188
189 {
190 pidlist_t *npl = (pidlist_t *) malloc(sizeof (*npl));
191
192 if (npl == NULL) {
193 (void) fprintf(stderr,
194 gettext("Out of memory -- can't process pid %d\n"),
195 new);
196 return (pl);
197 }
198 npl->next = pl;
199 npl->pid = new;
200 return (npl);
201 }
202
203 /*
204 * Add the pids in the given pidlist to the process filter list.
205 * For each pid, check whether it's already in the filter list,
206 * and whether the process exists.
207 */
208 void
prbk_pfilter_add(void * pl)209 prbk_pfilter_add(void *pl)
210 {
211 pidlist_t *ppl = (pidlist_t *) pl;
212 pidlist_t *tmp;
213 tnfctl_errcode_t err;
214
215 if (check_kernelmode(NULL))
216 return;
217 while (ppl != NULL) {
218 err = tnfctl_filter_list_add(g_hndl, ppl->pid);
219 if (err) {
220 (void) fprintf(stderr, gettext("Process %ld: %s\n"),
221 ppl->pid, tnfctl_strerror(err));
222 }
223 tmp = ppl;
224 ppl = ppl->next;
225 free(tmp);
226 }
227 }
228
229 /*
230 * Drop the pids in the given pidlist from the process filter list.
231 * For each pid, complain if it's not in the process filter list;
232 * and if the process no longer exists (and hence has already implicitly
233 * been dropped from the process filter list), say so.
234 */
235 void
prbk_pfilter_drop(void * pl)236 prbk_pfilter_drop(void *pl)
237 {
238 pidlist_t *ppl = (pidlist_t *) pl;
239 pidlist_t *tmp;
240 tnfctl_errcode_t err;
241
242 if (check_kernelmode(NULL))
243 return;
244
245 while (ppl != NULL) {
246 tmp = ppl;
247 err = tnfctl_filter_list_delete(g_hndl, tmp->pid);
248 switch (err) {
249 case (TNFCTL_ERR_NONE):
250 break;
251 case (TNFCTL_ERR_BADARG):
252 (void) fprintf(stderr,
253 gettext("Process %ld is not being traced\n"),
254 tmp->pid);
255 break;
256 case (TNFCTL_ERR_NOPROCESS):
257 (void) printf(gettext("Process %ld has exited\n"),
258 tmp->pid);
259 break;
260 default:
261 (void) fprintf(stderr, gettext("Process %ld: %s\n"),
262 tmp->pid, tnfctl_strerror(err));
263 break;
264 }
265 ppl = ppl->next;
266 free(tmp);
267 }
268 }
269
270 /*
271 * Turn process filter mode on or off. The process filter is maintained
272 * even when process filtering is off, but has no effect: all processes
273 * are traced.
274 */
275 void
prbk_set_pfilter_mode(boolean_t onoff)276 prbk_set_pfilter_mode(boolean_t onoff)
277 {
278 tnfctl_errcode_t err;
279
280 if (check_kernelmode(NULL))
281 return;
282 err = tnfctl_filter_state_set(g_hndl, onoff);
283 if (err) {
284 (void) fprintf(stderr, gettext("pfilter: %s\n"),
285 tnfctl_strerror(err));
286 }
287 }
288
289
290 /*
291 * Report whether process filter mode is currently on or off, and
292 * dump the current process filter set.
293 */
294 void
prbk_show_pfilter_mode()295 prbk_show_pfilter_mode()
296 {
297 tnfctl_errcode_t err;
298 tnfctl_trace_attrs_t attrs;
299 pid_t *pids_p;
300 int i, pid_count;
301 pid_t *cur_pid;
302
303 if (check_kernelmode(&attrs))
304 return;
305 (void) printf(gettext("Process filtering is %s\n"),
306 attrs.filter_state ? "on" : "off");
307 err = tnfctl_filter_list_get(g_hndl, &pids_p, &pid_count);
308 if (err) {
309 (void) fprintf(stderr,
310 gettext("error in getting process filter list: %s\n"),
311 tnfctl_strerror(err));
312 return;
313 }
314 (void) printf(gettext("Process filter set is "));
315 if (pid_count == 0)
316 (void) printf("empty.\n");
317 else {
318 (void) printf("{");
319 cur_pid = pids_p;
320 for (i = 0; i < pid_count; i++, cur_pid++) {
321 (void) printf("%ld%s", *cur_pid,
322 (i != (pid_count - 1)) ? ", " : "}\n");
323 }
324 }
325 }
326
327 /*
328 * Check for process filtering on with empty pid filter.
329 */
330 void
prbk_warn_pfilter_empty(void)331 prbk_warn_pfilter_empty(void)
332 {
333 tnfctl_errcode_t err;
334 pid_t *pids_p;
335 int pid_count;
336 tnfctl_trace_attrs_t attrs;
337
338 if (check_kernelmode(&attrs))
339 return;
340 if (attrs.filter_state) {
341 err = tnfctl_filter_list_get(g_hndl, &pids_p, &pid_count);
342 if (err) {
343 (void) fprintf(stderr,
344 gettext("error in getting process filter list: %s\n"),
345 tnfctl_strerror(err));
346 return;
347 }
348 if (!pid_count)
349 (void) fprintf(stderr,
350 gettext("Warning: Process filtering on, \
351 but pid filter list is empty\n"));
352 }
353 }
354
355
356 /*
357 * Turn kernel tracing on or off.
358 */
359 void
prbk_set_tracing(boolean_t onoff)360 prbk_set_tracing(boolean_t onoff)
361 {
362 tnfctl_errcode_t err;
363
364 if (check_kernelmode(NULL))
365 return;
366
367 err = tnfctl_trace_state_set(g_hndl, onoff);
368 if (err) {
369 (void) fprintf(stderr,
370 gettext("error in setting tracing state: %s\n"),
371 tnfctl_strerror(err));
372 }
373 }
374
375 /*
376 * Show whether kernel tracing is currently on or off.
377 */
378 void
prbk_show_tracing()379 prbk_show_tracing()
380 {
381 tnfctl_trace_attrs_t attrs;
382
383 if (check_kernelmode(&attrs))
384 return;
385 (void) printf(gettext("Tracing is %s\n"),
386 attrs.trace_state ? "on" : "off");
387 }
388