1 /* GKrellM
2 |  Copyright (C) 1999-2019 Bill Wilson
3 |
4 |  Author:  Bill Wilson    billw@gkrellm.net
5 |  Latest versions might be found at:  http://gkrellm.net
6 |
7 |  darwin.c code is Copyright (c) Ben Hines <bhines@alumni.ucsd.edu>
8 |
9 |
10 |  GKrellM is free software: you can redistribute it and/or modify it
11 |  under the terms of the GNU General Public License as published by
12 |  the Free Software Foundation, either version 3 of the License, or
13 |  (at your option) any later version.
14 |
15 |  GKrellM is distributed in the hope that it will be useful, but WITHOUT
16 |  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
17 |  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
18 |  License for more details.
19 |
20 |  You should have received a copy of the GNU General Public License
21 |  along with this program. If not, see http://www.gnu.org/licenses/
22 |
23 |
24 |  Additional permission under GNU GPL version 3 section 7
25 |
26 |  If you modify this program, or any covered work, by linking or
27 |  combining it with the OpenSSL project's OpenSSL library (or a
28 |  modified version of that library), containing parts covered by
29 |  the terms of the OpenSSL or SSLeay licenses, you are granted
30 |  additional permission to convey the resulting work.
31 |  Corresponding Source for a non-source form of such a combination
32 |  shall include the source code for the parts of OpenSSL used as well
33 |  as that of the covered work.
34 */
35 
36 #ifdef HAVE_KVM_H
37 #include <kvm.h>
38 #endif
39 
40 #include <mach/mach_init.h>
41 #include <mach/mach_host.h>
42 #include <mach/vm_map.h>
43 
44 #ifdef HAVE_KVM_H
45 kvm_t	*kvmd = NULL;
46 char	errbuf[_POSIX2_LINE_MAX];
47 #endif
48 
49 static void gkrellm_sys_disk_cleanup(void);
50 
51 
52 void
gkrellm_sys_main_init(void)53 gkrellm_sys_main_init(void)
54 	{
55 #ifdef HAVE_KVM_H
56 	/* We just ignore error, here.  Even if GKrellM doesn't have
57 	|  kmem privilege, it runs with available information.
58 	*/
59 	kvmd = kvm_openfiles(NULL, NULL, NULL, O_RDONLY, errbuf);
60 	if (setgid(getgid()) != 0)
61 		{
62 		fprintf(stderr, "Can't drop setgid privileges.");
63 		exit(1);
64 		}
65 #endif
66 	}
67 
68 void
gkrellm_sys_main_cleanup(void)69 gkrellm_sys_main_cleanup(void)
70 	{
71     gkrellm_sys_disk_cleanup();
72 	}
73 
74 /* ===================================================================== */
75 /* CPU monitor interface */
76 
77 static guint		n_cpus;
78 
79 void
gkrellm_sys_cpu_read_data(void)80 gkrellm_sys_cpu_read_data(void)
81 	{
82 		processor_cpu_load_info_data_t *pinfo;
83 		mach_msg_type_number_t info_count;
84 		int i;
85 
86 		if (host_processor_info (mach_host_self (),
87 						   PROCESSOR_CPU_LOAD_INFO,
88 						   &n_cpus,
89 						   (processor_info_array_t*)&pinfo,
90 						   &info_count) != KERN_SUCCESS) {
91 			return;
92 		}
93 
94         for (i = 0; i < n_cpus; i++) {
95 			gkrellm_cpu_assign_data(i,
96 					pinfo[i].cpu_ticks [CPU_STATE_USER],
97 					pinfo[i].cpu_ticks [CPU_STATE_NICE],
98 					pinfo[i].cpu_ticks [CPU_STATE_SYSTEM],
99 					pinfo[i].cpu_ticks [CPU_STATE_IDLE]);
100 		}
101 		vm_deallocate (mach_task_self (), (vm_address_t) pinfo, info_count);
102 	}
103 
104 gboolean
gkrellm_sys_cpu_init(void)105 gkrellm_sys_cpu_init(void)
106 	{
107 	processor_cpu_load_info_data_t *pinfo;
108 	mach_msg_type_number_t info_count;
109 
110 	n_cpus = 0;
111 
112 	if (host_processor_info (mach_host_self (),
113 						  PROCESSOR_CPU_LOAD_INFO,
114 						  &n_cpus,
115 						  (processor_info_array_t*)&pinfo,
116 						  &info_count) != KERN_SUCCESS) {
117 		return FALSE;
118 	}
119 	vm_deallocate (mach_task_self (), (vm_address_t) pinfo, info_count);
120 	gkrellm_cpu_set_number_of_cpus(n_cpus);
121 	return TRUE;
122 	}
123 
124 
125 /* ===================================================================== */
126 /* Proc monitor interface */
127 
128 #include <sys/sysctl.h>
129 #include <sys/user.h>
130 
131 #ifdef HAVE_KVM_H
132 #define	PID_MAX		30000
133 #include <kvm.h>
134 #endif
135 #include <limits.h>
136 #include <paths.h>
137 #include <utmpx.h>
138 
139 static int	oid_v_forks[CTL_MAXNAME + 2];
140 static int	oid_v_vforks[CTL_MAXNAME + 2];
141 static int	oid_v_rforks[CTL_MAXNAME + 2];
142 static size_t	oid_v_forks_len = sizeof(oid_v_forks);
143 static size_t	oid_v_vforks_len = sizeof(oid_v_vforks);
144 static size_t	oid_v_rforks_len = sizeof(oid_v_rforks);
145 static int	have_v_forks = 0;
146 
147 gboolean
gkrellm_sys_proc_init(void)148 gkrellm_sys_proc_init(void)
149 	{
150 	static int	oid_name2oid[2] = { 0, 3 };
151 	static char	*name = "vm.stats.vm.v_forks";
152 	static char	*vname = "vm.stats.vm.v_vforks";
153 	static char	*rname = "vm.stats.vm.v_rforks";
154 
155 	/* check if vm.stats.vm.v_forks is available */
156 	if (sysctl(oid_name2oid, 2, oid_v_forks, &oid_v_forks_len,
157 		   (void *)name, strlen(name)) < 0)
158 		return TRUE;
159 	if (sysctl(oid_name2oid, 2, oid_v_vforks, &oid_v_vforks_len,
160 		   (void *)vname, strlen(vname)) < 0)
161 		return TRUE;
162 	if (sysctl(oid_name2oid, 2, oid_v_rforks, &oid_v_rforks_len,
163 		   (void *)rname, strlen(rname)) < 0)
164 		return TRUE;
165 	oid_v_forks_len /= sizeof(int);
166 	oid_v_vforks_len /= sizeof(int);
167 	oid_v_rforks_len /= sizeof(int);
168 	++have_v_forks;
169 	return TRUE;
170 	}
171 
172 void
gkrellm_sys_proc_read_data(void)173 gkrellm_sys_proc_read_data(void)
174 	{
175 	static int	oid_proc[] = { CTL_KERN, KERN_PROC, KERN_PROC_ALL };
176 	double		avenrun;
177 	static u_int	n_processes, n_forks = 0;
178 #ifdef HAVE_KVM_H
179 	static u_int	curpid = -1;
180 #endif
181 	u_int		n_vforks, n_rforks;
182 	gint		r_forks, r_vforks, r_rforks;
183 	size_t		len;
184 #ifdef HAVE_KVM_H
185 	gint		nextpid, nforked;
186 	static struct nlist nl[] = {
187 #define N_NEXTPID	0
188 		{ "_nextpid" },
189 		{ "" }
190 	};
191 #endif
192 
193 	if (getloadavg(&avenrun, 1) <= 0)
194 		avenrun = 0;
195 
196 	if (have_v_forks)
197 		{
198 		/* We don't want to just use sysctlbyname().  Because,
199                  * we call it so often. */
200 		len = sizeof(n_forks);
201 		r_forks = sysctl(oid_v_forks, oid_v_forks_len,
202 				 &n_forks, &len, NULL, 0);
203 		len = sizeof(n_vforks);
204 		r_vforks = sysctl(oid_v_vforks, oid_v_vforks_len,
205 				  &n_vforks, &len, NULL, 0);
206 		len = sizeof(n_rforks);
207 		r_rforks = sysctl(oid_v_rforks, oid_v_rforks_len,
208 				  &n_rforks, &len, NULL, 0);
209 		if (r_forks >= 0 && r_vforks >= 0 && r_rforks >= 0)
210 			n_forks = n_forks + n_vforks + n_rforks;
211 		}
212 #ifdef HAVE_KVM_H
213 	else
214 		{
215 		/* workaround: Can I get total number of processes? */
216 		if (kvmd != NULL)
217 			{
218 			if (nl[0].n_type == 0)
219 				kvm_nlist(kvmd, nl);
220 			if (nl[0].n_type != 0 &&
221 			    kvm_read(kvmd, nl[N_NEXTPID].n_value,
222 				     (char *)&nextpid,
223 				     sizeof(nextpid)) == sizeof(nextpid))
224 				{
225 				if (curpid < 0)
226 					curpid = nextpid;
227 				if ((nforked = nextpid - curpid) < 0)
228 					n_forks += PID_MAX - 100;
229 				n_forks += nforked;
230 				curpid = nextpid;
231 				n_forks = n_forks;
232 				}
233 			}
234 		}
235 #endif
236 
237 	if (sysctl(oid_proc, 3, NULL, &len, NULL, 0) >= 0)
238 		n_processes = len / sizeof(struct kinfo_proc);
239 
240 	gkrellm_proc_assign_data(n_processes, 0, n_forks, avenrun);
241 	}
242 
243 void
gkrellm_sys_proc_read_users(void)244 gkrellm_sys_proc_read_users(void)
245 	{
246     struct utmpx  *utmpx_entry;
247 	gchar          ttybuf[MAXPATHLEN];
248 	struct stat    sb;
249     gint           n_users;
250 
251     n_users = 0;
252     setutxent();
253     while((utmpx_entry = getutxent()))
254         {
255         if (utmpx_entry->ut_type != USER_PROCESS)
256             continue; // skip other entries (reboot, runlevel changes etc.)
257 
258         (void)snprintf(ttybuf, sizeof(ttybuf), "%s/%s",
259             _PATH_DEV, utmpx_entry->ut_line);
260 
261         if (stat(ttybuf, &sb))
262             continue; // tty of entry missing, no real user
263 
264         ++n_users;
265 
266         }
267     endutxent();
268 	gkrellm_proc_assign_users(n_users);
269 	}
270 
271 
272 /* ===================================================================== */
273 /* Disk monitor interface */
274 
275 #include <CoreFoundation/CoreFoundation.h>
276 #include <IOKit/IOKitLib.h>
277 #include <IOKit/storage/IOBlockStorageDevice.h>
278 #include <IOKit/storage/IOBlockStorageDriver.h>
279 #include <IOKit/storage/IOStorageDeviceCharacteristics.h>
280 
281 
282 typedef struct _GK_DISK
283 	{
284     io_service_t  service;
285     io_string_t   path;
286 	} GK_DARWIN_DISK;
287 
288 static GPtrArray *s_disk_ptr_array = NULL;
289 
290 
291 static GK_DARWIN_DISK *
gk_darwin_disk_new()292 gk_darwin_disk_new()
293 {
294 	return g_new0(GK_DARWIN_DISK, 1);
295 }
296 
297 static void
gk_darwin_disk_free(GK_DARWIN_DISK * disk)298 gk_darwin_disk_free(GK_DARWIN_DISK *disk)
299 {
300     if (disk->service != MACH_PORT_NULL)
301         IOObjectRelease(disk->service);
302 	g_free(disk);
303 }
304 
305 static gboolean
dict_get_int64(CFDictionaryRef dict,CFStringRef key,gint64 * value)306 dict_get_int64(CFDictionaryRef dict, CFStringRef key, gint64 *value)
307 {
308     CFNumberRef number_ref;
309 
310     number_ref = (CFNumberRef) CFDictionaryGetValue(dict, key);
311     if ((NULL == number_ref) ||
312         !CFNumberGetValue(number_ref, kCFNumberSInt64Type, value))
313     {
314         *value = 0;
315         return FALSE;
316     }
317     return TRUE;
318 }
319 
320 static gboolean
dict_get_string(CFDictionaryRef dict,CFStringRef key,char * buf,size_t buf_len)321 dict_get_string(CFDictionaryRef dict, CFStringRef key, char *buf, size_t buf_len)
322 {
323     CFStringRef string_ref;
324 
325     string_ref = (CFStringRef)CFDictionaryGetValue(dict, key);
326     if ((NULL == string_ref) ||
327         !CFStringGetCString(string_ref, buf, buf_len, kCFStringEncodingUTF8))
328     {
329         buf[0] = '\0';
330         return FALSE;
331     }
332     return TRUE;
333 }
334 
335 static gboolean
add_storage_device(io_registry_entry_t service)336 add_storage_device(io_registry_entry_t service)
337 {
338     GK_DARWIN_DISK *disk;
339     CFMutableDictionaryRef chars_dict; /* needs release */
340     gchar vendor_str[128];
341     gchar product_str[128];
342     gchar *disk_label;
343 
344     gkrellm_debug(DEBUG_SYSDEP, "add_storage_device(); START\n");
345 
346     disk = gk_darwin_disk_new();
347     disk->service = service;
348 
349     if (IORegistryEntryGetPath(service, kIOServicePlane, disk->path)
350         != kIOReturnSuccess)
351     {
352         g_warning("Could not fetch io registry path for disk\n");
353         gk_darwin_disk_free(disk);
354         return FALSE;
355     }
356 
357     chars_dict = (CFMutableDictionaryRef)IORegistryEntryCreateCFProperty(
358         service, CFSTR(kIOPropertyDeviceCharacteristicsKey),
359         kCFAllocatorDefault, 0);
360 
361     if (NULL == chars_dict)
362     {
363         g_warning("Could not fetch properties for disk\n");
364         gk_darwin_disk_free(disk);
365         return FALSE;
366     }
367 
368     gkrellm_debug(DEBUG_SYSDEP, "Getting vendor name\n");
369     dict_get_string(chars_dict, CFSTR(kIOPropertyVendorNameKey),
370         vendor_str, sizeof(vendor_str));
371     g_strstrip(vendor_str); // remove leading/trailing whitespace
372 
373     gkrellm_debug(DEBUG_SYSDEP, "Getting product name\n");
374     dict_get_string(chars_dict, CFSTR(kIOPropertyProductNameKey),
375         product_str, sizeof(product_str));
376     g_strstrip(product_str); // remove leading/trailing whitespace
377 
378     if (strlen(vendor_str) > 0)
379         disk_label = g_strdup_printf("%s %s", vendor_str, product_str);
380     else
381         disk_label = g_strdup(product_str);
382 
383     gkrellm_debug(DEBUG_SYSDEP, "Adding disk '%s' with fancy label '%s'\n",
384         disk->path, disk_label);
385 
386     // Add disk to internal list
387     g_ptr_array_add(s_disk_ptr_array, disk);
388 
389     // Add disk to gkrellm list
390     gkrellm_disk_add_by_name(disk->path, disk_label);
391 
392     /* we don't need to store the label, it is only for GUI display */
393     g_free(disk_label);
394     CFRelease(chars_dict);
395 
396     gkrellm_debug(DEBUG_SYSDEP, "add_storage_device(); END\n");
397     return TRUE;
398 }
399 
400 
401 gchar *
gkrellm_sys_disk_name_from_device(gint device_number,gint unit_number,gint * order)402 gkrellm_sys_disk_name_from_device(gint device_number, gint unit_number,
403 			gint *order)
404 	{
405 	return NULL;	/* Not implemented */
406 	}
407 
408 gint
gkrellm_sys_disk_order_from_name(const gchar * name)409 gkrellm_sys_disk_order_from_name(const gchar *name)
410 	{
411 	/* implement this if you want disk charts to show up in a particular
412 	|  order in gkrellm.
413 	*/
414 	return -1;	/* Not implemented, disks show up in same order as disk_list */
415 	}
416 
417 void
gkrellm_sys_disk_read_data(void)418 gkrellm_sys_disk_read_data(void)
419 {
420     int i;
421     GK_DARWIN_DISK *disk;
422 
423 	for (i = 0; i < s_disk_ptr_array->len; i++)
424         {
425         io_registry_entry_t storage_driver; /* needs release */
426         CFDictionaryRef storage_driver_stats; /* needs release */
427         gint64 bytes_read;
428         gint64 bytes_written;
429 
430 		disk = (GK_DARWIN_DISK *)g_ptr_array_index(s_disk_ptr_array, i);
431 
432         //gkrellm_debug(DEBUG_SYSDEP, "Fetching disk stats for '%s'\n", disk->path);
433 
434         /* get subitem of device, has to be some kind of IOStorageDriver */
435         if (IORegistryEntryGetChildEntry(disk->service, kIOServicePlane,
436             &storage_driver) != kIOReturnSuccess)
437         {
438             gkrellm_debug(DEBUG_SYSDEP,
439                 "No driver child found in storage device, skipping disk '%s'\n",
440                 disk->path);
441             // skip devices that have no driver child
442             continue;
443         }
444 
445         storage_driver_stats = IORegistryEntryCreateCFProperty(storage_driver,
446             CFSTR(kIOBlockStorageDriverStatisticsKey), kCFAllocatorDefault, 0);
447 
448         if (NULL == storage_driver_stats)
449         {
450             gkrellm_debug(DEBUG_SYSDEP,
451                 "No statistics dict found in storage driver, skipping disk '%s'\n",
452                 disk->path);
453             IOObjectRelease(storage_driver);
454             continue;
455         }
456 
457         /* Obtain the number of bytes read/written from the drive statistics */
458         if (dict_get_int64(storage_driver_stats,
459                 CFSTR(kIOBlockStorageDriverStatisticsBytesReadKey), &bytes_read)
460             &&
461             dict_get_int64(storage_driver_stats,
462                 CFSTR(kIOBlockStorageDriverStatisticsBytesWrittenKey), &bytes_written)
463            )
464         {
465             gkrellm_disk_assign_data_by_name(disk->path, bytes_read,
466                 bytes_written, FALSE);
467         }
468         else
469         {
470             gkrellm_debug(DEBUG_SYSDEP,
471                 "could not fetch read/write stats for disk '%s'\n",
472                 disk->path);
473         }
474 
475         CFRelease(storage_driver_stats);
476         IOObjectRelease(storage_driver);
477     } // for()
478 }
479 
480 gboolean
gkrellm_sys_disk_init(void)481 gkrellm_sys_disk_init(void)
482     {
483     /* needs release */
484     io_iterator_t iter = MACH_PORT_NULL;
485 
486     /* needs release (if add_storage_device() failed) */
487     io_service_t service = MACH_PORT_NULL;
488 
489     gkrellm_debug(DEBUG_SYSDEP, "gkrellm_sys_disk_init();\n");
490 
491     s_disk_ptr_array = g_ptr_array_new();
492 
493     if (IOServiceGetMatchingServices(kIOMasterPortDefault,
494         IOServiceMatching(kIOBlockStorageDeviceClass),
495         &iter) == kIOReturnSuccess)
496         {
497         while ((service = IOIteratorNext(iter)) != MACH_PORT_NULL)
498             {
499             if (!add_storage_device(service))
500                 IOObjectRelease(service);
501             }
502         IOObjectRelease(iter);
503         }
504 
505 	gkrellm_debug(DEBUG_SYSDEP,
506         "gkrellm_sys_disk_init(); Found %u disk(s) for monitoring.\n",
507 		s_disk_ptr_array->len);
508 
509 	return (s_disk_ptr_array->len == 0 ? FALSE : TRUE);
510     }
511 
512 static void
gkrellm_sys_disk_cleanup(void)513 gkrellm_sys_disk_cleanup(void)
514 {
515 	guint i;
516 
517     if (NULL == s_disk_ptr_array)
518 		return;
519     gkrellm_debug(DEBUG_SYSDEP,
520         "gkrellm_sys_disk_cleanup() Freeing counters for %u disk(s)\n",
521 		s_disk_ptr_array->len);
522 	for (i = 0; i < s_disk_ptr_array->len; i++)
523 		gk_darwin_disk_free(g_ptr_array_index(s_disk_ptr_array, i));
524 	g_ptr_array_free(s_disk_ptr_array, TRUE);
525 }
526 
527 /* ===================================================================== */
528 /* Inet monitor interface */
529 
530 #include "../inet.h"
531 
532 #include <net/route.h>
533 #include <netinet/in.h>
534 #include <netinet/in_systm.h>
535 #include <netinet/ip.h>
536 #ifdef INET6
537 #include <netinet/ip6.h>
538 #endif /* INET6 */
539 #include <netinet/in_pcb.h>
540 #include <netinet/ip_icmp.h>
541 #include <netinet/icmp_var.h>
542 #include <netinet/igmp_var.h>
543 #include <netinet/ip_var.h>
544 #include <netinet/tcp.h>
545 #include <netinet/tcpip.h>
546 #include <netinet/tcp_seq.h>
547 #define TCPSTATES
548 #include <netinet/tcp_fsm.h>
549 #include <netinet/tcp_var.h>
550 #include <netinet/udp.h>
551 #include <netinet/udp_var.h>
552 #include <sys/types.h>
553 
554  void
gkrellm_sys_inet_read_tcp_data(void)555  gkrellm_sys_inet_read_tcp_data(void)
556 {
557 	ActiveTCP	tcp;
558     const char *mibvar="net.inet.tcp.pcblist";
559 	char *buf;
560 	struct tcpcb *tp = NULL;
561 	struct inpcb *inp;
562 	struct xinpgen *xig, *oxig;
563 	struct xsocket *so;
564 	size_t len=0;
565 	if (sysctlbyname(mibvar, 0, &len, 0, 0) < 0) {
566 		if (errno != ENOENT)
567 			g_warning("sysctl: %s\n", mibvar);
568 		return;
569 	}
570 	if ((buf = malloc(len)) == 0) {
571 		g_warning("malloc %lu bytes\n", (u_long)len);
572 		return;
573  	}
574 	if (sysctlbyname(mibvar, buf, &len, 0, 0) < 0) {
575 		g_warning("sysctl: %s\n", mibvar);
576 		free(buf);
577 		return;
578 	}
579      /*
580          * Bail-out to avoid logic error in the loop below when
581          * there is in fact no more control block to process
582          */
583         if (len <= sizeof(struct xinpgen)) {
584             free(buf);
585             return;
586         }
587  	oxig = xig = (struct xinpgen *)buf;
588 	for (xig = (struct xinpgen *)((char *)xig + xig->xig_len);
589 	     xig->xig_len > sizeof(struct xinpgen);
590 	     xig = (struct xinpgen *)((char *)xig + xig->xig_len)) {
591     	tp = &((struct xtcpcb *)xig)->xt_tp;
592 	   	inp = &((struct xtcpcb *)xig)->xt_inp;
593 		so = &((struct xtcpcb *)xig)->xt_socket;
594     if (so->xso_protocol != IPPROTO_TCP)
595  			continue;
596 		/* Ignore PCBs which were freed during copyout. */
597 		if (inp->inp_gencnt > oxig->xig_gen)
598 			continue;
599 	if ((inp->inp_vflag & INP_IPV4) == 0
600 #ifdef INET6
601 		    && (inp->inp_vflag & INP_IPV6) == 0
602 #endif /* INET6 */
603 			)
604 			continue;
605                 /*
606                  * Local address is not an indication of listening socket or
607                  * server sockey but just rather the socket has been bound.
608                  * That why many UDP sockets were not displayed in the original code.
609                  */
610                 if (tp->t_state <= TCPS_LISTEN){
611                     continue;
612                     }
613 			if (inp->inp_vflag & INP_IPV4) {
614 			     tcp.local_port=ntohs(inp->inp_lport);
615 			     tcp.remote_addr.s_addr=(uint32_t)inp->inp_faddr.s_addr;
616 			     tcp.remote_port=ntohs(inp->inp_fport);
617 			     tcp.family=AF_INET;
618 			     gkrellm_inet_log_tcp_port_data(&tcp);
619             }
620 #ifdef INET6
621 			else if (inp->inp_vflag & INP_IPV6) {
622 			     tcp.local_port=ntohs(inp->inp_lport);
623     			 memcpy(&(tcp.remote_addr6),&(inp->in6p_faddr),sizeof(struct in6_addr));
624 			     tcp.remote_port=ntohs(inp->inp_fport);
625 			     tcp.family=AF_INET6;
626 			     gkrellm_inet_log_tcp_port_data(&tcp);
627 			} /* else nothing printed now */
628 #endif /* INET6 */
629 }
630 free(buf);
631 }
632 
633  gboolean
gkrellm_sys_inet_init(void)634  gkrellm_sys_inet_init(void)
635  	{
636 	return TRUE;
637  	}
638 
639 
640 
641 /* ===================================================================== */
642 /* Memory/Swap monitor interface */
643 
644 #include <mach/mach_init.h>
645 #include <mach/mach_host.h>
646 #include <mach/host_info.h>
647 #include <mach/mach_error.h>
648 #include <sys/types.h>
649 #include <dirent.h>
650 #include <mach/mach_types.h>
651 #include <mach/machine/vm_param.h>
652 
653 static guint64	swapin,
654 		swapout,
655 		swap_total,
656 		swap_used;
657 
658 void
gkrellm_sys_mem_read_data(void)659 gkrellm_sys_mem_read_data(void)
660 	{
661 	static gint	psize, pshift, first_time_done = 0;
662 	vm_statistics_data_t vm_info;
663 	mach_msg_type_number_t info_count;
664 	kern_return_t	error;
665 	static DIR *dirp;
666 	struct dirent *dp;
667 	guint64		total, used, free, shared, buffers, cached;
668 
669 	info_count = HOST_VM_INFO_COUNT;
670 
671 	error = host_statistics (mach_host_self (), HOST_VM_INFO, (host_info_t)&vm_info, &info_count);
672 	if (error != KERN_SUCCESS)
673 	{
674 		mach_error("host_info", error);
675 		return;
676 	}
677 
678 	if (pshift == 0)
679 	{
680 		for (psize = getpagesize(); psize > 1; psize >>= 1)
681 			pshift++;
682 	}
683 
684 	used = (guint64)(vm_info.active_count) << pshift;
685 	free = (guint64)vm_info.free_count << pshift;
686 	total = (guint64)(vm_info.active_count + vm_info.inactive_count + vm_info.free_count + vm_info.wire_count) << pshift;
687 	/* Don't know how to get cached or buffers. */
688 	buffers =  (guint64) (vm_info.wire_count) << pshift;
689 	cached = (guint64) (vm_info.inactive_count) << pshift;
690 	/* shared  0 for now, shared is a PITA */
691         shared = 0;
692 	gkrellm_mem_assign_data(total, used, free, shared, buffers, cached);
693 
694 	/* Swap is available at same time as mem, so grab values here.
695 	*/
696 	swapin = vm_info.pageins;
697 	swapout = vm_info.pageouts;
698 	swap_used = vm_info.pageouts << pshift;
699 
700 	/* Figure out total swap. This adds up the size of the swapfiles */
701 	if (!first_time_done)
702 	{
703 		dirp = opendir ("/private/var/vm");
704 		if (!dirp)
705 			return;
706 		++first_time_done;
707 	}
708 	swap_total = 0;
709 	while ((dp = readdir (dirp)) != NULL) {
710 		struct stat sb;
711 		char fname [MAXNAMLEN];
712 		if (strncmp (dp->d_name, "swapfile", 8))
713 			continue;
714 		strcpy (fname, "/private/var/vm/");
715 		strcat (fname, dp->d_name);
716 		if (stat (fname, &sb) < 0)
717 			continue;
718 		swap_total += sb.st_size;
719 	}
720 	/*  Save overhead, leave it open. where can we close it? */
721 	rewinddir(dirp);
722 	/*	closedir (dirp); */
723 	}
724 
725 void
gkrellm_sys_swap_read_data(void)726 gkrellm_sys_swap_read_data(void)
727 	{
728 	gkrellm_swap_assign_data(swap_total, swap_used, swapin, swapout);
729 	}
730 
731 gboolean
gkrellm_sys_mem_init(void)732 gkrellm_sys_mem_init(void)
733 	{
734 	return TRUE;
735 	}
736 
737 
738 /* ===================================================================== */
739 /* Battery monitor interface - not implemented */
740 
741 void
gkrellm_sys_battery_read_data(void)742 gkrellm_sys_battery_read_data(void)
743 	{
744 //	gkrellm_battery_assign_data(0, available, on_line, charging,
745 //					percent, time_left);
746 	}
747 
748 gboolean
gkrellm_sys_battery_init(void)749 gkrellm_sys_battery_init(void)
750 	{
751 	return FALSE;
752 	}
753 
754 /* ===================================================================== */
755 /* Sensor monitor interface - not implemented */
756 
757 gboolean
gkrellm_sys_sensors_get_temperature(gchar * path,gint id,gint iodev,gint interface,gfloat * temp)758 gkrellm_sys_sensors_get_temperature(gchar *path, gint id,
759 		gint iodev, gint interface, gfloat *temp)
760 
761 	{
762 	return FALSE;
763 	}
764 
765 gboolean
gkrellm_sys_sensors_get_fan(gchar * path,gint id,gint iodev,gint interface,gfloat * fan)766 gkrellm_sys_sensors_get_fan(gchar *path, gint id,
767 		gint iodev, gint interface, gfloat *fan)
768 	{
769 	return FALSE;
770 	}
771 
772 gboolean
gkrellm_sys_sensors_get_voltage(gchar * path,gint id,gint iodev,gint interface,gfloat * volt)773 gkrellm_sys_sensors_get_voltage(gchar *path, gint id,
774 		gint iodev, gint interface, gfloat *volt)
775 	{
776 	return FALSE;
777 	}
778 
779 gboolean
gkrellm_sys_sensors_init(void)780 gkrellm_sys_sensors_init(void)
781 	{
782 	return FALSE;
783 	}
784