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 /*
23  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #pragma ident	"%Z%%M%	%I%	%E% SMI"
28 
29 /*
30  * smbstat: Server Message Block File System statistics
31  */
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <kstat.h>
35 #include <stdarg.h>
36 #include <errno.h>
37 #include <inttypes.h>
38 #include <strings.h>
39 #include <utility.h>
40 #include <libintl.h>
41 #include <zone.h>
42 
43 static kstat_ctl_t *kc;		/* libkstat cookie */
44 static kstat_t *smb_info;
45 static kstat_t *smb_dispatch;
46 static kstat_t *ksmb_kstat;
47 
48 static int get_smbinfo_stat(void);
49 static int get_smbdispatch_stat(void);
50 static void smbstat_setup(void);
51 static void smbstat_smb_info_print();
52 static void smbstat_smb_dispatch_print();
53 static void smbstat_print(const char *, kstat_t *, int);
54 static int smbstat_width(kstat_t *, int);
55 static void smbstat_fail(int, char *, ...);
56 static kid_t smbstat_kstat_read(kstat_ctl_t *, kstat_t *, void *);
57 static void smbstat_usage(void);
58 
59 #define	MAX_COLUMNS	80
60 
61 int
62 main(int argc, char *argv[])
63 {
64 	int c;
65 	int iflag = 0;		/* smb_info stats */
66 	int dflag = 0;		/* smb_dispatch_all stats */
67 
68 	if (getzoneid() != GLOBAL_ZONEID) {
69 		(void) fprintf(stderr,
70 		    gettext("%s: Cannot execute in non-global zone.\n"),
71 		    argv[0]);
72 		return (0);
73 	}
74 
75 	if (is_system_labeled()) {
76 		(void) fprintf(stderr,
77 		    gettext("%s: Trusted Extensions not supported.\n"),
78 		    argv[0]);
79 		return (0);
80 	}
81 
82 	while ((c = getopt(argc, argv, "id")) != EOF) {
83 		switch (c) {
84 		case 'i':
85 			iflag++;
86 			break;
87 		case 'd':
88 			dflag++;
89 			break;
90 		case '?':
91 		default:
92 			smbstat_usage();
93 		}
94 	}
95 
96 	if ((argc - optind) > 0) {
97 		smbstat_usage();
98 	}
99 
100 	smbstat_setup();
101 
102 	if (iflag) {
103 		smbstat_smb_info_print();
104 	} else if (dflag) {
105 		smbstat_smb_dispatch_print();
106 	} else {
107 		smbstat_smb_info_print();
108 		smbstat_smb_dispatch_print();
109 	}
110 
111 	(void) kstat_close(kc);
112 	free(ksmb_kstat);
113 	return (0);
114 }
115 
116 
117 static int
118 get_smbinfo_stat(void)
119 {
120 	(void) smbstat_kstat_read(kc, smb_info, NULL);
121 	return (smbstat_width(smb_info, 0));
122 }
123 
124 static int
125 get_smbdispatch_stat(void)
126 {
127 	(void) smbstat_kstat_read(kc, smb_dispatch, NULL);
128 	return (smbstat_width(smb_dispatch, 0));
129 }
130 
131 static void
132 smbstat_smb_info_print()
133 {
134 	int field_width;
135 
136 	field_width = get_smbinfo_stat();
137 	if (field_width == 0)
138 		return;
139 
140 	smbstat_print(gettext("\nSMB Info:\n"), smb_info, field_width);
141 }
142 
143 static void
144 smbstat_smb_dispatch_print()
145 {
146 	int field_width;
147 
148 	field_width = get_smbdispatch_stat();
149 	if (field_width == 0)
150 		return;
151 
152 	smbstat_print(gettext("\nAll dispatched SMB requests statistics:\n"),
153 	    smb_dispatch, field_width);
154 }
155 
156 static void
157 smbstat_setup(void)
158 {
159 	if ((kc = kstat_open()) == NULL)
160 		smbstat_fail(1, gettext("kstat_open(): can't open /dev/kstat"));
161 
162 	if ((ksmb_kstat = malloc(sizeof (kstat_t))) == NULL) {
163 		(void) kstat_close(kc);
164 		smbstat_fail(1, gettext("Out of memory"));
165 	}
166 
167 	smb_info = kstat_lookup(kc, "smb", 0, "smb_info");
168 	smb_dispatch = kstat_lookup(kc, "smb", 0, "smb_dispatch_all");
169 	if ((smb_info == NULL) || (smb_dispatch == NULL))
170 		smbstat_fail(0, gettext("kstat lookups failed for smb. "
171 		    "Your kernel module may not be loaded\n"));
172 }
173 
174 static int
175 smbstat_width(kstat_t *req, int field_width)
176 {
177 	int i, nreq, len;
178 	char fixlen[128];
179 	kstat_named_t *knp;
180 
181 	knp = KSTAT_NAMED_PTR(req);
182 	nreq = req->ks_ndata;
183 
184 	for (i = 0; i < nreq; i++) {
185 		len = strlen(knp[i].name) + 1;
186 		if (field_width < len)
187 			field_width = len;
188 		(void) sprintf(fixlen, "%" PRIu64, knp[i].value.ui64);
189 		len = strlen(fixlen) + 1;
190 		if (field_width < len)
191 			field_width = len;
192 	}
193 	return (field_width);
194 }
195 
196 static void
197 smbstat_print(const char *title_string, kstat_t *req, int field_width)
198 {
199 	int i, j, nreq, ncolumns;
200 	char fixlen[128];
201 	kstat_named_t *knp;
202 
203 	if (req == NULL)
204 		return;
205 
206 	if (field_width == 0)
207 		return;
208 
209 	(void) printf("%s\n", title_string);
210 	ncolumns = (MAX_COLUMNS -1)/field_width;
211 
212 	knp = KSTAT_NAMED_PTR(req);
213 	nreq = req->ks_ndata;
214 
215 	for (i = 0; i < nreq; i += ncolumns) {
216 		/* prints out the titles of the columns */
217 		for (j = i; j < MIN(i + ncolumns, nreq); j++) {
218 			(void) printf("%-*s", field_width, knp[j].name);
219 		}
220 		(void) printf("\n");
221 		/* prints out the stat numbers */
222 		for (j = i; j < MIN(i + ncolumns, nreq); j++) {
223 			(void) sprintf(fixlen, "%" PRIu64 " ",
224 			    knp[j].value.ui64);
225 			(void) printf("%-*s", field_width, fixlen);
226 		}
227 		(void) printf("\n");
228 
229 	}
230 }
231 
232 static void
233 smbstat_usage(void)
234 {
235 	(void) fprintf(stderr, gettext("Usage: smbstat [-id]\n"));
236 	exit(1);
237 }
238 
239 static void
240 smbstat_fail(int do_perror, char *message, ...)
241 {
242 	va_list args;
243 
244 	va_start(args, message);
245 	(void) fprintf(stderr, gettext("smbstat: "));
246 	/* LINTED E_SEC_PRINTF_VAR_FMT */
247 	(void) vfprintf(stderr, message, args);
248 	va_end(args);
249 	if (do_perror)
250 		(void) fprintf(stderr, ": %s", strerror(errno));
251 	(void) fprintf(stderr, "\n");
252 	exit(1);
253 }
254 
255 static kid_t
256 smbstat_kstat_read(kstat_ctl_t *kc, kstat_t *ksp, void *data)
257 {
258 	kid_t kstat_chain_id = kstat_read(kc, ksp, data);
259 
260 	if (kstat_chain_id == -1)
261 		smbstat_fail(1, gettext("kstat_read('%s') failed"),
262 		    ksp->ks_name);
263 	return (kstat_chain_id);
264 }
265 
266 /*
267  * Enable libumem debugging by default on DEBUG builds.
268  */
269 #ifdef DEBUG
270 /* LINTED - external libumem symbol */
271 const char *
272 _umem_debug_init(void)
273 {
274 	return ("default,verbose"); /* $UMEM_DEBUG setting */
275 }
276 
277 /* LINTED - external libumem symbol */
278 const char *
279 _umem_logging_init(void)
280 {
281 	return ("fail,contents"); /* $UMEM_LOGGING setting */
282 }
283 #endif
284