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