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