1 /******************************************************************************
2  *  bwm-ng parsing and retrieve stuff                                         *
3  *                                                                            *
4  *  Copyright (C) 2004-2007 Volker Gropp (bwmng@gropp.org)                    *
5  *                                                                            *
6  *  for more info read README.                                                *
7  *                                                                            *
8  *  This program is free software; you can redistribute it and/or modify      *
9  *  it under the terms of the GNU General Public License as published by      *
10  *  the Free Software Foundation; either version 2 of the License, or         *
11  *  (at your option) any later version.                                       *
12  *                                                                            *
13  *  This program is distributed in the hope that it will be useful,           *
14  *  but WITHOUT ANY WARRANTY; without even the implied warranty of            *
15  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the             *
16  *  GNU General Public License for more details.                              *
17  *                                                                            *
18  *  You should have received a copy of the GNU General Public License         *
19  *  along with this program; if not, write to the Free Software               *
20  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA *
21  *                                                                            *
22  *****************************************************************************/
23 
24 #include "sysctl.h"
25 
26 #ifdef SYSCTL
27 /* do the actual work, get and print stats if verbose */
get_iface_stats_sysctl(char verbose)28 void get_iface_stats_sysctl (char verbose) {
29     size_t size;
30     int mib[] = {CTL_NET, PF_ROUTE, 0, 0, NET_RT_IFLIST, 0};
31     char *bsd_if_buf=NULL, *next=NULL, *lim=NULL;
32     char iface_is_up=0;
33     struct if_msghdr *ifmhdr, *nextifmhdr;
34     struct sockaddr_dl *saddr;
35 
36     char *name=NULL;
37 
38     int hidden_if=0,current_if_num=0,my_errno=0;
39     t_iface_speed_stats tmp_if_stats;
40     t_iface_speed_stats stats; /* local struct, used to calc total values */
41 
42     memset(&stats,0,(size_t)sizeof(t_iface_speed_stats)); /* init it */
43 
44     if (sysctl(mib, 6, NULL, &size, NULL, 0) < 0)
45 		 deinit(1, "sysctl failed: %s\n",strerror(errno));
46     if (!(bsd_if_buf = malloc(size))) deinit(1, "no memory: %s\n",strerror(errno));
47     memset(bsd_if_buf,0,size);
48     if (sysctl(mib, 6, bsd_if_buf, &size, NULL, 0) < 0) {
49         my_errno=errno;
50         free(bsd_if_buf);
51         deinit(1, "sysctl failed: %s\n",strerror(my_errno));
52     }
53 
54     lim = (bsd_if_buf + size);
55 
56     next = bsd_if_buf;
57     /* loop either while netstat enabled and still lines to read
58      * or still buffer (buf) left */
59     while (next < (bsd_if_buf + size)) {
60         /* BSD sysctl code */
61         ifmhdr = (struct if_msghdr *) next;
62         if (ifmhdr->ifm_type != RTM_IFINFO) break;
63         next += ifmhdr->ifm_msglen;
64         while (next < lim) {
65             nextifmhdr = (struct if_msghdr *) next;
66             if (nextifmhdr->ifm_type != RTM_NEWADDR) break;
67             next += nextifmhdr->ifm_msglen;
68         }
69         saddr = (struct sockaddr_dl *) (ifmhdr + 1);
70         if(saddr->sdl_family != AF_LINK) continue;
71 		iface_is_up= (show_all_if || (ifmhdr->ifm_flags & IFF_UP));
72         /* we have to copy here to use saddr->sdl_nlen */
73         name=(char *)malloc(saddr->sdl_nlen+1);
74 	     if (!name) {
75         	  deinit(1,"mem alloc failed: %s\n",strerror(errno));
76 	     }
77 
78 		strncpy(name,saddr->sdl_data,saddr->sdl_nlen);
79         name[saddr->sdl_nlen]='\0';
80         tmp_if_stats.bytes.in=ifmhdr->ifm_data.ifi_ibytes;
81         tmp_if_stats.bytes.out=ifmhdr->ifm_data.ifi_obytes;
82         tmp_if_stats.packets.in=ifmhdr->ifm_data.ifi_ipackets;
83         tmp_if_stats.packets.out=ifmhdr->ifm_data.ifi_opackets;
84 		tmp_if_stats.errors.in=ifmhdr->ifm_data.ifi_ierrors;
85         tmp_if_stats.errors.out=ifmhdr->ifm_data.ifi_oerrors;
86         /* init new interfaces and add fetched data to old or new one */
87         hidden_if = process_if_data (hidden_if, tmp_if_stats, &stats, name, current_if_num, verbose, iface_is_up);
88         free(name);
89         current_if_num++;
90     } /* fgets done (while) */
91     /* add to total stats and output current stats if verbose */
92     finish_iface_stats (verbose, stats, hidden_if,current_if_num);
93     /* close input stream */
94     free(bsd_if_buf);
95     return;
96 }
97 #endif
98 
99 #if SYSCTLDISK_IN
100 #ifdef HAVE_STRUCT_SYSCTL
101 #define MIBCOUNT 3
102 #else
103 #define MIBCOUNT 2
104 #endif
get_iface_stats_sysctldisk(char verbose)105 void get_iface_stats_sysctldisk (char verbose) {
106 	size_t size;
107 	int mib[MIBCOUNT];
108 #if defined(HW_DISKCOUNT) && !defined(HAVE_STRUCT_DISKSTATS_DS_NAME) && defined(HAVE_STRUCT_DISKSTATS)
109 	int diskcount = 0;
110 	char *name_str = NULL;
111 	char **name_arr = NULL;
112 	char *ptr = NULL;
113 #endif
114 #if defined(HAVE_STRUCT_DISKSTATS)
115 #define DISK_STRUCT struct diskstats
116 #elif defined(HAVE_STRUCT_DISK_SYSCTL)
117 #define DISK_STRUCT struct disk_sysctl
118 #endif
119 	DISK_STRUCT *dstats = NULL;
120 	int num,i;
121 	char *name=NULL;
122 	char free_name=0;
123 
124 	int hidden_if=0,current_if_num=0;
125 	t_iface_speed_stats tmp_if_stats;
126 	t_iface_speed_stats stats; /* local struct, used to calc total values */
127 
128 	memset(&stats,0,(size_t)sizeof(t_iface_speed_stats)); /* init it */
129 
130 	mib[0]=CTL_HW;
131 
132 /* get name list on systems without dk_name */
133 #if defined(HW_DISKCOUNT) && !defined(HAVE_STRUCT_DISKSTATS_DS_NAME) && defined(HAVE_STRUCT_DISKSTATS)
134 	mib[1]=HW_DISKCOUNT;
135 	if (sysctl(mib, 2, &diskcount, &size, NULL, 0) < 0)
136 		deinit(1, "sysctl failed: %s\n",strerror(errno));
137 
138 	mib[1]=HW_DISKNAMES;
139 	if (sysctl(mib, 2, NULL, &size, NULL, 0) < 0)
140 		deinit(1, "sysctl failed: %s\n",strerror(errno));
141 	if (!(name_str=(char *)malloc(size)))
142 		deinit(1, "malloc failed for name_str: %s\n",strerror(errno));
143 	if (sysctl(mib, 2, name_str, &size, NULL, 0) < 0) {
144 		free(name_str);
145 		deinit(1, "malloc failed for name_str: %s\n",strerror(errno));
146 	}
147 	/* assume comma seperated list as on OpenBSD */
148 	if (!(name_arr = (char **)malloc(diskcount * sizeof(char *)))) {
149 		free(name_str);
150 		deinit(1, "malloc failed for name_arr: %s\n",strerror(errno));
151 	}
152 	ptr = name_str;
153 	i = 0;
154 	while (i<diskcount-1 && (next = strchr(ptr,','))) {
155 		next[0]=0;
156 		next++;
157 		name_arr[i] = ptr;
158 		ptr = next;
159 		i++;
160 	}
161 	/* add last element aswell */
162 	name_arr[i] = ptr;
163 #endif
164 
165 /* get actual stats */
166 	mib[1] = HW_DISKSTATS;
167 #ifdef HAVE_STRUCT_SYSCTL
168 	mib[2] = sizeof(struct sysctl);
169 #endif
170 
171 	if (sysctl(mib, MIBCOUNT, NULL, &size, NULL, 0) < 0) {
172 #if HW_DISKCOUNT && !defined(HAVE_STRUCT_DISKSTATS_DS_NAME) && defined(HAVE_STRUCT_DISKSTATS)
173 		free(name_str);
174 		free(name_arr);
175 #endif
176 		deinit(1, "sysctl failed: %s\n",strerror(errno));
177 	}
178 
179 	num = size / sizeof(DISK_STRUCT);
180 	if (!(dstats = (DISK_STRUCT *)malloc(size))) {
181 #if HW_DISKCOUNT && !defined(HAVE_STRUCT_DISKSTATS_DS_NAME) && defined(HAVE_STRUCT_DISKSTATS)
182       free(name_str);
183       free(name_arr);
184 #endif
185       deinit(1, "malloc failed: %s\n",strerror(errno));
186 	}
187 
188 	if (sysctl(mib, MIBCOUNT, dstats, &size, NULL, 0) < 0) {
189 		free(dstats);
190 #if HW_DISKCOUNT && !defined(HAVE_STRUCT_DISKSTATS_DS_NAME) && defined(HAVE_STRUCT_DISKSTATS)
191       free(name_str);
192       free(name_arr);
193 #endif
194       deinit(1, "sysctl failed: %s\n",strerror(errno));
195 	}
196 	for (i = 0; i < num; i++) {
197 
198 #ifdef HAVE_STRUCT_DISKSTATS
199 #ifdef HAVE_STRUCT_DISKSTATS_DS_RBYTES
200 		tmp_if_stats.bytes.in = dstats[i].ds_rbytes;
201 		tmp_if_stats.bytes.out = dstats[i].ds_wbytes;
202 		tmp_if_stats.packets.in = dstats[i].ds_rxfer;
203 		tmp_if_stats.packets.out = dstats[i].ds_wxfer;
204 #else
205 		tmp_if_stats.bytes.in = tmp_if_stats.bytes.out = (ullong)(dstats[i].ds_bytes / 2);
206 		tmp_if_stats.packets.in = tmp_if_stats.packets.out = (ullong)(dstats[i].ds_xfer / 2);
207 #endif
208 #if !defined(HAVE_STRUCT_DISKSTATS_DS_NAME)
209 		name = name_arr[i];
210 #else
211 		name = dstats[i].ds_name;
212 #endif
213 #else
214 #ifdef HAVE_STRUCT_DISK_SYSCTL_DK_RBYTES
215 		tmp_if_stats.bytes.in = dstats[i].dk_rbytes;
216 		tmp_if_stats.bytes.out = dstats[i].dk_wbytes;
217       tmp_if_stats.packets.in = dstats[i].dk_rxfer;
218       tmp_if_stats.packets.out = dstats[i].dk_wxfer;
219 #else
220 		tmp_if_stats.bytes.in = tmp_if_stats.bytes.out = (ullong)(dstats[i].dk_bytes / 2);
221 		tmp_if_stats.packets.in = tmp_if_stats.packets.out = (ullong)(dstats[i].dk_xfer / 2);
222 #endif
223 		name = dstats[i].dk_name;
224 #endif
225 		tmp_if_stats.errors.in = tmp_if_stats.errors.out = 0;
226 
227 		if (!name || name[0]==0) {
228 			name=malloc(11);
229       	snprintf((char *)name,10,"unknown%i",current_if_num);
230          name[10]=0;
231 			free_name=1;
232 		}
233 
234 		hidden_if = process_if_data (hidden_if, tmp_if_stats, &stats, name, current_if_num, verbose, (tmp_if_stats.bytes.in != 0 || tmp_if_stats.bytes.out != 0));
235 
236 		if (free_name) free(name);
237 		current_if_num++;
238 	}
239 	/* add to total stats and output current stats if verbose */
240 	finish_iface_stats (verbose, stats, hidden_if,current_if_num);
241 	free(dstats);
242 #if HW_DISKCOUNT && !defined(HAVE_STRUCT_DISKSTATS_DS_NAME) && defined(HAVE_STRUCT_DISKSTATS)
243 	free(name_str);
244 	free(name_arr);
245 #endif
246 }
247 #endif
248 
249 
250