xref: /illumos-gate/usr/src/cmd/mdb/common/modules/svc.startd/startd.c (revision 581cede61ac9c14d8d4ea452562a567189eead78)
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 (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 #pragma ident	"%Z%%M%	%I%	%E% SMI"
27 
28 #include <mdb/mdb_modapi.h>
29 
30 #include <libuutil.h>
31 #include <libuutil_impl.h>
32 
33 #include <librestart_priv.h>		/* instance_data_t */
34 #include <startd.h>
35 
36 
37 /*
38  * To count the elements of a uu_list_t without knowing its implementation, we
39  * must walk & count them.
40  */
41 /* ARGSUSED */
42 static int
43 inc_sz(uintptr_t addr, const void *unknown, void *data)
44 {
45 	size_t *sz = data;
46 
47 	++(*sz);
48 
49 	return (WALK_NEXT);
50 }
51 
52 /*ARGSUSED*/
53 static int
54 startd_status(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
55 {
56 	uu_list_t *dgraphp;
57 	restarter_instance_list_t ril;
58 	u_longlong_t ns_total;
59 	u_longlong_t lookups;
60 	u_longlong_t dep_inserts, dep_cycle_ns, dep_insert_ns;
61 	size_t graph_num, restarter_num;
62 
63 	if (mdb_readvar(&lookups, "dictionary_lookups") == -1) {
64 		mdb_warn("failed to read 'dictionary_lookups' value\n");
65 		return (DCMD_ERR);
66 	}
67 
68 	if (mdb_readvar(&ns_total, "dictionary_ns_total") == -1) {
69 		mdb_warn("failed to read 'dictionary_ns_total' value\n");
70 		return (DCMD_ERR);
71 	}
72 
73 	if (mdb_readvar(&dep_inserts, "dep_inserts") == -1) {
74 		mdb_warn("failed to read 'dep_inserts' value\n");
75 		return (DCMD_ERR);
76 	}
77 
78 	if (mdb_readvar(&dep_cycle_ns, "dep_cycle_ns") == -1) {
79 		mdb_warn("failed to read 'dep_cycle_ns' value\n");
80 		return (DCMD_ERR);
81 	}
82 
83 	if (mdb_readvar(&dep_insert_ns, "dep_insert_ns") == -1) {
84 		mdb_warn("failed to read 'dep_insert_ns' value\n");
85 		return (DCMD_ERR);
86 	}
87 
88 	if (mdb_readvar(&dgraphp, "dgraph") == -1) {
89 		mdb_warn("failed to read 'dgraph' value\n");
90 		return (DCMD_ERR);
91 	}
92 
93 	graph_num = 0;
94 	if (mdb_pwalk("uu_list_node", inc_sz, &graph_num,
95 	    (uintptr_t)dgraphp) == -1) {
96 		mdb_warn("failed to read uu_list\n");
97 		return (DCMD_ERR);
98 	}
99 
100 	if (mdb_readvar(&ril, "instance_list") == -1) {
101 		mdb_warn("failed to read 'instance_list' value\n");
102 		return (DCMD_ERR);
103 	}
104 
105 	restarter_num = 0;
106 	if (mdb_pwalk("uu_list_node", inc_sz, &restarter_num,
107 	    (uintptr_t)ril.ril_instance_list) == -1) {
108 		mdb_warn("failed to read uu_list\n");
109 		return (DCMD_ERR);
110 	}
111 
112 	mdb_printf(
113 	    "         dictionary lookups: %llu\n"
114 	    "        average lookup time: %llu us\n"
115 	    "graph dependency insertions: %llu\n"
116 	    "   average cycle-check time: %llu us\n"
117 	    " avg dependency insert time: %llu us\n"
118 	    "number of nodes in dgraph: %llu\n"
119 	    "number of nodes in instance_list: %llu\n", lookups,
120 	    lookups ? ns_total / (1000 * lookups) : 0, dep_inserts,
121 	    dep_inserts ? dep_cycle_ns / (1000 * dep_inserts) : 0,
122 	    dep_inserts ? dep_insert_ns / (1000 * dep_inserts) : 0,
123 	    (u_longlong_t)graph_num, (u_longlong_t)restarter_num);
124 
125 	return (DCMD_OK);
126 }
127 
128 static char
129 xstate2chr(restarter_instance_state_t s)
130 {
131 	switch (s) {
132 	case RESTARTER_STATE_UNINIT:	return ('u');
133 	case RESTARTER_STATE_DISABLED:	return ('d');
134 	case RESTARTER_STATE_OFFLINE:	return ('0');
135 	case RESTARTER_STATE_DEGRADED:	return ('D');
136 	case RESTARTER_STATE_ONLINE:	return ('1');
137 	case RESTARTER_STATE_MAINT:	return ('m');
138 	case RESTARTER_STATE_NONE:	return ('n');
139 	default:			return ('?');
140 	}
141 }
142 
143 /*ARGSUSED*/
144 static int
145 pr_instance(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
146 {
147 	restarter_instance_list_t ril;
148 	restarter_inst_t ri;
149 	char *iname;
150 	char statechr = '-';
151 	char typechr;
152 
153 	if ((flags & DCMD_ADDRSPEC) == 0) {
154 		if (mdb_readvar(&ril, "instance_list") == -1) {
155 			mdb_warn("failed to read 'instance_list' value\n");
156 			return (DCMD_ERR);
157 		}
158 
159 		if (mdb_pwalk_dcmd("uu_list_node", "instance", 0, NULL,
160 		    (uintptr_t)ril.ril_instance_list) == -1) {
161 			mdb_warn("can't walk instances\n");
162 			return (DCMD_ERR);
163 		}
164 
165 		return (DCMD_OK);
166 	}
167 
168 	if (mdb_vread(&ri, sizeof (restarter_inst_t), addr) == -1) {
169 		mdb_warn("couldn't read instance at %a\n");
170 		return (DCMD_ERR);
171 	}
172 
173 	if (DCMD_HDRSPEC(flags))
174 		mdb_printf("%-10s %-3s %1s %1s %4s\n", "ADDR", "ID", "T", "S",
175 		    "FMRI");
176 
177 	iname = mdb_alloc(1024, UM_SLEEP | UM_GC);
178 
179 	if (mdb_readstr(iname, 1024, (uintptr_t)ri.ri_i.i_fmri) == -1) {
180 		mdb_warn("couldn't read instance name\n");
181 		strcpy(iname, "-");
182 	}
183 
184 	statechr = xstate2chr(ri.ri_i.i_state);
185 	typechr = (ri.ri_i.i_enabled) ? 'I' : 'i';
186 
187 	mdb_printf("%-10a %3x %c %c %s\n", addr, ri.ri_id, typechr, statechr,
188 	    iname);
189 
190 	return (DCMD_OK);
191 }
192 
193 /*ARGSUSED*/
194 static int
195 pr_vertex(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
196 {
197 	uu_list_t *dgraphp;
198 	graph_vertex_t gv;
199 	char *vname;
200 	int id;
201 	char typechr;
202 	char statechr = '-';
203 
204 	if ((flags & DCMD_ADDRSPEC) == 0) {
205 		if (mdb_readvar(&dgraphp, "dgraph") == -1) {
206 			mdb_warn("failed to read 'dgraph' value\n");
207 			return (DCMD_ERR);
208 		}
209 
210 		if (mdb_pwalk_dcmd("uu_list_node", "vertex", 0, NULL,
211 		    (uintptr_t)dgraphp) == -1) {
212 			mdb_warn("can't walk vertices");
213 			return (DCMD_ERR);
214 		}
215 
216 		return (DCMD_OK);
217 	}
218 
219 	if (mdb_vread(&gv, sizeof (graph_vertex_t), addr) == -1) {
220 		mdb_warn("couldn't read vertex at %a\n");
221 		return (DCMD_ERR);
222 	}
223 
224 	if (DCMD_HDRSPEC(flags))
225 		mdb_printf("%-10s %-3s %1s %1s %4s\n", "ADDR", "ID", "T", "S",
226 		    "FMRI");
227 
228 	vname = mdb_alloc(1024, UM_SLEEP | UM_GC);
229 
230 	if (mdb_readstr(vname, 1024, (uintptr_t)gv.gv_name) == -1) {
231 		mdb_warn("couldn't read vertex name\n");
232 		strcpy(vname, "-");
233 	}
234 
235 	id = gv.gv_id;
236 
237 	switch (gv.gv_type) {
238 	case GVT_FILE:
239 		typechr = 'f';
240 		break;
241 	case GVT_GROUP:
242 		switch (gv.gv_depgroup) {
243 		case DEPGRP_REQUIRE_ANY:
244 			typechr = 'r';
245 			break;
246 		case DEPGRP_REQUIRE_ALL:
247 			typechr = 'R';
248 			break;
249 		case DEPGRP_EXCLUDE_ALL:
250 			typechr = 'X';
251 			break;
252 		case DEPGRP_OPTIONAL_ALL:
253 			typechr = 'o';
254 			break;
255 		default:
256 			typechr = '?';
257 			break;
258 		}
259 		break;
260 	case GVT_INST:
261 		typechr = (gv.gv_flags & GV_ENABLED) ? 'I' : 'i';
262 		statechr = xstate2chr(gv.gv_state);
263 		break;
264 	case GVT_SVC:
265 		typechr = 's';
266 		break;
267 	default:
268 		typechr = '?';
269 		break;
270 	}
271 
272 	mdb_printf("%-10a %3x %c %c %s\n", addr, id, typechr, statechr, vname);
273 
274 	return (DCMD_OK);
275 }
276 
277 /* ARGSUSED */
278 static int
279 logbuf(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
280 {
281 	GElf_Sym sym;
282 	char *buf;
283 	char *cp;
284 
285 	if (mdb_lookup_by_name("logbuf", &sym) == -1) {
286 		mdb_warn("The 'logbuf' symbol is missing.\n");
287 		return (DCMD_ERR);
288 	}
289 
290 	buf = mdb_alloc(sym.st_size, UM_SLEEP | UM_GC);
291 
292 	if (mdb_vread(buf, sym.st_size, sym.st_value) == -1) {
293 		mdb_warn("failed to read 'logbuf'\n");
294 		return (DCMD_ERR);
295 	}
296 
297 	cp = strchr(buf, '\0');
298 
299 	if (cp == buf)
300 		/* Empty */
301 		return (DCMD_OK);
302 
303 	if (cp >= buf + sym.st_size ||
304 	    strchr(cp + 1, '\0') >= buf + sym.st_size) {
305 		mdb_warn("'logbuf' is corrupt\n");
306 		return (DCMD_ERR);
307 	}
308 
309 	mdb_printf("%s", cp + 1);
310 	mdb_printf("%s", buf);
311 
312 	return (DCMD_OK);
313 }
314 
315 static const mdb_dcmd_t dcmds[] = {
316 	{ "instance", NULL, "display svc.startd restarter instance",
317 	    pr_instance },
318 	{ "startd_log", NULL, "display svc.startd debug message buffer",
319 	    logbuf },
320 	{ "startd_status", NULL, "svc.startd status summary", startd_status },
321 	{ "vertex", NULL, "display svc.startd dependency graph vertex",
322 	    pr_vertex },
323 	{ NULL }
324 };
325 
326 static const mdb_walker_t walkers[] = {
327 	{ NULL }
328 };
329 
330 static const mdb_modinfo_t modinfo = {
331 	MDB_API_VERSION, dcmds, walkers
332 };
333 
334 const mdb_modinfo_t *
335 _mdb_init(void)
336 {
337 	return (&modinfo);
338 }
339