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/*
29 * Interface to close a tnfctl handle
30 */
31
32#include "tnfctl_int.h"
33#include "kernel_int.h"
34#include "dbg.h"
35
36#include <stdlib.h>
37#include <signal.h>
38#include <errno.h>
39
40/* for bug 1253419 - guard against multiple tracing */
41
42extern mutex_t		_tnfctl_internalguard_lock;
43
44/*
45 * Close a tnfctl handle - close any open fds and free up any memory
46 * that was allocated.
47 */
48tnfctl_errcode_t
49tnfctl_close(tnfctl_handle_t *hdl, tnfctl_targ_op_t action)
50{
51	tnfctl_errcode_t	prexstat;
52	prb_status_t	prbstat;
53	prb_proc_ctl_t	*proc_p;
54	tnfctl_probe_t	*probe_hdl, *tmp_hdl;
55
56	if (hdl == NULL)
57		return (TNFCTL_ERR_NONE);
58
59	if (hdl->mode == KERNEL_MODE) {
60		prexstat = _tnfctl_prbk_close(hdl);
61		if (prexstat)
62			return (prexstat);
63	}
64
65	if (hdl->mode == INTERNAL_MODE) {
66		_tnfctl_internal_releaselock();
67	} else if (hdl->mode != KERNEL_MODE) {
68		_tnfctl_external_releaselock(hdl);
69	}
70
71	_tnfctl_free_objs_and_probes(hdl);
72
73	/* free probe handles */
74	probe_hdl = hdl->probe_handle_list_head;
75	while (probe_hdl != NULL) {
76		/* call the destructor function for client probe data */
77		if (hdl->destroy_func)
78			hdl->destroy_func(probe_hdl->client_registered_data);
79		tmp_hdl = probe_hdl;
80		probe_hdl = probe_hdl->next;
81		free(tmp_hdl);
82	}
83	hdl->probe_handle_list_head = NULL;
84
85	if (hdl->mode != DIRECT_MODE) {
86		/* indirect, internal, or kernel mode */
87		free(hdl);
88		return (TNFCTL_ERR_NONE);
89	}
90
91	/* DIRECT_MODE */
92
93	proc_p = hdl->proc_p;
94	if (proc_p == NULL) {
95		free(hdl);
96		return (TNFCTL_ERR_NONE);
97	}
98
99	switch (action) {
100	case TNFCTL_TARG_DEFAULT:
101		break;
102	case TNFCTL_TARG_KILL:
103		prbstat = prb_proc_setklc(proc_p, B_TRUE);
104		if (prbstat)
105			return (_tnfctl_map_to_errcode(prbstat));
106		prbstat = prb_proc_setrlc(proc_p, B_FALSE);
107		if (prbstat)
108			return (_tnfctl_map_to_errcode(prbstat));
109		break;
110	case TNFCTL_TARG_RESUME:
111		prbstat = prb_proc_setklc(proc_p, B_FALSE);
112		if (prbstat)
113			return (_tnfctl_map_to_errcode(prbstat));
114		prbstat = prb_proc_setrlc(proc_p, B_TRUE);
115		if (prbstat)
116			return (_tnfctl_map_to_errcode(prbstat));
117		break;
118	case TNFCTL_TARG_SUSPEND:
119		prbstat = prb_proc_setklc(proc_p, B_FALSE);
120		if (prbstat)
121			return (_tnfctl_map_to_errcode(prbstat));
122		prbstat = prb_proc_setrlc(proc_p, B_FALSE);
123		if (prbstat)
124			return (_tnfctl_map_to_errcode(prbstat));
125		break;
126	default:
127		return (TNFCTL_ERR_BADARG);
128	}
129	prbstat = prb_proc_close(proc_p);
130	free(hdl);
131	return (_tnfctl_map_to_errcode(prbstat));
132}
133
134tnfctl_errcode_t
135_tnfctl_internal_releaselock()
136{
137	mutex_lock(&_tnfctl_internalguard_lock);
138	_tnfctl_internal_tracing_flag = 0;
139	mutex_unlock(&_tnfctl_internalguard_lock);
140	return (TNFCTL_ERR_NONE);
141}
142
143tnfctl_errcode_t
144_tnfctl_external_releaselock(tnfctl_handle_t *hdl)
145{
146	tnfctl_errcode_t	prexstat;
147	prb_status_t		prbstat;
148	uintptr_t		targ_symbol_ptr;
149	pid_t			pidzero = 0;
150
151	prexstat = _tnfctl_sym_find(hdl, TNFCTL_EXTERNAL_TRACEDPID,
152	    &targ_symbol_ptr);
153	if (prexstat) {
154	return (prexstat);
155	}
156	prbstat = hdl->p_write(hdl->proc_p, targ_symbol_ptr,
157	&pidzero, sizeof (pidzero));
158	if (prbstat) {
159	return (_tnfctl_map_to_errcode(prbstat));
160	}
161	return (TNFCTL_ERR_NONE);
162}
163