xref: /titanic_52/usr/src/cmd/cmd-inet/usr.bin/netstat/unix.c (revision cc7a88b54b4969574f03e1a1225bb13be487f5db)
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 2001 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 /*	Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T	*/
28 /*	  All Rights Reserved  	*/
29 
30 /*
31  * University Copyright- Copyright (c) 1982, 1986, 1988
32  * The Regents of the University of California
33  * All Rights Reserved
34  *
35  * University Acknowledgment- Portions of this document are derived from
36  * software developed by the University of California, Berkeley, and its
37  * contributors.
38  */
39 
40 #pragma ident	"%Z%%M%	%I%	%E% SMI"
41 
42 /*
43  * code for netstat's -k option
44  *
45  * NOTES:
46  * 1. A comment "LINTED: (note 1)" appears before certain lines where
47  *    lint would have complained, "pointer cast may result in improper
48  *    alignment". These are lines where lint had suspected potential
49  *    improper alignment of a data structure; in each such situation
50  *    we have relied on the kernel guaranteeing proper alignment.
51  */
52 
53 #include <stdio.h>
54 #include <stdlib.h>
55 #include <unistd.h>
56 #include <strings.h>
57 #include <string.h>
58 #include <kstat.h>
59 
60 #include <sys/types.h>
61 #include <sys/socket.h>
62 #include <sys/stream.h>
63 #include <sys/tiuser.h>
64 #include <sys/socketvar.h>
65 #include <sys/sysmacros.h>
66 
67 static char		*typetoname(t_scalar_t);
68 static void		print_kn(kstat_t *);
69 static char		*nextstr(char *);
70 extern void		fail(int, char *, ...);
71 
72 #define	NALEN	8			/* nulladdress string length	*/
73 
74 /*
75  * Print a summary of connections related to a unix protocol.
76  */
77 void
78 unixpr(kstat_ctl_t 	*kc)
79 {
80 	kstat_t		*ksp;
81 
82 	if (kc == NULL) {	/* sanity check.			*/
83 		fail(0, "unixpr: No kstat");
84 		exit(3);
85 	}
86 
87 	/* find the sockfs kstat:					*/
88 	if ((ksp = kstat_lookup(kc, "sockfs", 0, "sock_unix_list")) ==
89 	    (kstat_t *)NULL) {
90 		fail(0, "kstat_data_lookup failed\n");
91 	}
92 
93 	if (kstat_read(kc, ksp, NULL) == -1) {
94 		fail(0, "kstat_read failed for sock_unix_list\n");
95 	}
96 
97 	print_kn(ksp);
98 }
99 
100 static void
101 print_kn(kstat_t *ksp)
102 {
103 	int		i;
104 	struct sockinfo	*psi;		/* ptr to current sockinfo	*/
105 	char		*pas;		/* ptr to string-format addrs	*/
106 	char		*nullstr;	/* ptr to null string		*/
107 	char		*conn_vp;
108 	char		*local_vp;
109 
110 	if (ksp->ks_ndata == 0) {
111 		return;			/* no AF_UNIX sockets found	*/
112 	}
113 
114 	/*
115 	 * Having ks_data set with ks_data == NULL shouldn't happen;
116 	 * If it does, the sockfs kstat is seriously broken.
117 	 */
118 	if ((psi = ksp->ks_data) == NULL) {
119 		fail(0, "print_kn: no kstat data\n");
120 	}
121 
122 	/* set pas to the address strings which are after the sockinfo	*/
123 	pas = &((char *)psi)[sizeof (struct sockinfo)];
124 
125 	/* Create a string of NALEN "0"'s for NULL addresses.		*/
126 	if ((nullstr = calloc(1, NALEN)) == NULL) {
127 		fail(0, "print_kn: out of memory\n");
128 	}
129 	(void) memset((void *)nullstr, '0', NALEN);
130 
131 	(void) printf("\nActive UNIX domain sockets\n");
132 	(void) printf("%-8.8s %-10.10s %8.8s %8.8s  "
133 			"Local Addr      Remote Addr\n",
134 			"Address", "Type", "Vnode", "Conn");
135 
136 	/* for each sockinfo structure, display what we need:		*/
137 	for (i = 0; i < ksp->ks_ndata; i++) {
138 		/* display sonode's address. 1st string after sockinfo:	*/
139 		pas = &(((char *)psi)[sizeof (struct sockinfo)]);
140 		(void) printf("%s ", pas);
141 
142 		(void) printf("%-10.10s ", typetoname(psi->si_serv_type));
143 
144 		/* laddr.sou_vp: 2nd string after sockinfo:		*/
145 		pas = nextstr(pas);
146 
147 		local_vp = conn_vp = nullstr;
148 
149 		if ((psi->si_state & SS_ISBOUND) &&
150 		    (psi->si_ux_laddr_sou_magic == SOU_MAGIC_EXPLICIT)) {
151 			local_vp = pas;
152 		}
153 
154 		/* faddr.sou_vp: 3rd string after sockinfo:		*/
155 		pas = nextstr(pas);
156 		if ((psi->si_state & SS_ISCONNECTED) &&
157 		    (psi->si_ux_faddr_sou_magic == SOU_MAGIC_EXPLICIT)) {
158 			conn_vp = pas;
159 		}
160 
161 		(void) printf("%s %s ", local_vp, conn_vp);
162 
163 		/* laddr.soa_sa: 					*/
164 		if ((psi->si_state & SS_ISBOUND) &&
165 		    strlen(psi->si_laddr_sun_path) != 0 &&
166 		    psi->si_laddr_soa_len != 0) {
167 			if (psi->si_state & SS_FADDR_NOXLATE) {
168 				(void) printf(" (socketpair)  ");
169 			} else {
170 				if (psi->si_laddr_soa_len >
171 					sizeof (psi->si_laddr_family))
172 					(void) printf("%s ",
173 						psi->si_laddr_sun_path);
174 				else
175 					(void) printf("               ");
176 			}
177 		} else
178 			(void) printf("               ");
179 
180 		/* faddr.soa_sa:					*/
181 		if ((psi->si_state & SS_ISCONNECTED) &&
182 		    strlen(psi->si_faddr_sun_path) != 0 &&
183 		    psi->si_faddr_soa_len != 0) {
184 
185 			if (psi->si_state & SS_FADDR_NOXLATE) {
186 				(void) printf(" (socketpair)  ");
187 			} else {
188 				if (psi->si_faddr_soa_len >
189 					sizeof (psi->si_faddr_family))
190 					(void) printf("%s ",
191 							psi->si_faddr_sun_path);
192 				else
193 					(void) printf("               ");
194 			}
195 		} else
196 			(void) printf("               ");
197 
198 		(void) printf("\n");
199 
200 		/* if si_size didn't get filled in, then we're done	*/
201 		if (psi->si_size == 0 ||
202 		    !IS_P2ALIGNED(psi->si_size, sizeof (psi))) {
203 			break;
204 		}
205 
206 		/* LINTED: (note 1) */
207 		psi = (struct sockinfo *)&(((char *)psi)[psi->si_size]);
208 	}
209 }
210 
211 static char *
212 typetoname(t_scalar_t type)
213 {
214 	switch (type) {
215 	case T_CLTS:
216 		return ("dgram");
217 
218 	case T_COTS:
219 		return ("stream");
220 
221 	case T_COTS_ORD:
222 		return ("stream-ord");
223 
224 	default:
225 		return ("");
226 	}
227 }
228 
229 /*
230  * nextstr():	find the beginning of a next string.
231  *	The sockfs kstat left-justifies each address string, leaving
232  *	null's between the strings. Since we don't necessarily know
233  *	the sizes of pointers in the kernel, we need to skip over these
234  *	nulls in order to get to the start of the next string.
235  */
236 static char *
237 nextstr(char *pas)
238 {
239 	char *next;
240 
241 	for (next = &pas[strlen(pas) + 1]; *next == NULL; ) {
242 		next++;
243 	}
244 
245 	return (next);
246 }
247