/* * 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 #include #include #include /* for strerror() */ #include #include #include #include #include #include #include "prbk.h" #include 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"); }