xref: /titanic_50/usr/src/cmd/tnf/prex/prbk.c (revision b86efd96f8acd85ddaa930a2f0c1d664237e4aaf)
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
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
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
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
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 *
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
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
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
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
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
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
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
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