1 /*
2  * mem_gnu.c - module to get memory/swap usages, for GNU/Hurd
3  *
4  * Copyright(C) 2014       Svante Signell <svante.signell@gmail.com>
5  * Copyright(C) 2001,2002  Seiichi SATO <ssato@sh.rim.or.jp>
6  * Copyright(C) 2001       John McCutchan <ttb@tentacle.dhs.org>
7  *
8  * licensed under the GPL
9  */
10 
11 #ifdef HAVE_CONFIG_H
12 #include "config.h"
13 #endif
14 
15 #include <stdio.h>
16 #include <unistd.h>
17 #include <stdlib.h>
18 
19 #if defined(HAVE_STRING_H)
20 #include <string.h>
21 #elif defined(HAVE_STRINGS_H)
22 #include <strings.h>
23 #endif
24 
25 #include <sys/types.h>
26 #include <sys/stat.h>
27 #include <fcntl.h>
28 #include <ctype.h>
29 #include <sys/utsname.h>
30 #include "mem.h"
31 
32 #ifdef DEBUG
33 #  define INLINE_STATIC static
34 #else
35 #  define INLINE_STATIC static inline
36 #endif
37 
38 /* initialize function */
mem_init(void)39 void mem_init(void)
40 {
41 	struct utsname un;
42 	int version, patchlevel;
43 
44 	/* get kernel version */
45 	if (uname(&un) == -1)
46 		perror("uname()");
47 	sscanf(un.release, "%d.%d", &version, &patchlevel);
48 }
49 
50 
skip_line(const char * p)51 INLINE_STATIC char *skip_line(const char *p)
52 {
53 	while (*p != '\n')
54 		p++;
55 	return (char *) ++p;
56 }
57 
skip_token(const char * p)58 INLINE_STATIC char *skip_token(const char *p)
59 {
60 	while (isspace(*p))
61 		p++;
62 	while (*p && !isspace(*p))
63 		p++;
64 	return (char *)p;
65 }
66 
skip_multiple_token(const char * p,int count)67 INLINE_STATIC char *skip_multiple_token(const char *p, int count)
68 {
69 	int i;
70 	for (i = 0; i < count; i++)
71 		p = skip_token(p);
72 	return (char *)p;
73 }
74 
75 /* return mem/swap usage in percent 0 to 100 */
mem_getusage(int * per_mem,int * per_swap,const struct mem_options * opts)76 void mem_getusage(int *per_mem, int *per_swap, const struct mem_options *opts)
77 {
78 	char buffer[BUFSIZ], *p;
79 	int fd, len, i;
80 	u_int64_t mtotal, mused, mfree, mbuffer, mcached;
81 	u_int64_t stotal, sused, sfree, scached = 0;
82 
83 	/* read /proc/meminfo */
84 	fd = open("/proc/meminfo", O_RDONLY);
85 	if (fd < 0) {
86 		perror("can't open /proc/meminfo");
87 		exit(1);
88 	}
89 	len = read(fd, buffer, BUFSIZ - 1);
90 	if (len < 0) {
91 		perror("can't read /proc/meminfo");
92 		exit(1);
93 	}
94 	close(fd);
95 
96 	buffer[len] = '\0';
97 	p = buffer;
98 
99 	p = skip_token(p);
100 	/* examine each line of file */
101 	mtotal  = strtoul(p, &p, 0); p = skip_multiple_token(p, 2);
102 	mfree   = strtoul(p, &p, 0); p = skip_multiple_token(p, 2);
103 	mbuffer = strtoul(p, &p, 0); p = skip_multiple_token(p, 2);
104 	mcached = strtoul(p, &p, 0); p = skip_multiple_token(p, 2);
105 	scached = strtoul(p, &p, 0);
106 
107 	/* skip N lines and examine info about swap */
108 	while (isprint(p[0])) {
109 		p = skip_line(p);
110 		if (strncmp(p, "SwapTotal", 9) == 0)
111 			break;
112 	}
113 
114 	p = skip_token(p);
115 	stotal = strtoul(p, &p, 0); p = skip_multiple_token(p, 2);
116 	sfree  = strtoul(p, &p, 0);
117 
118 	/* calculate memory usage in percent */
119 	mused = mtotal - mfree;
120 	if (opts->ignore_buffers)
121 		mused -= mbuffer;
122 	if (opts->ignore_cached)
123 		mused -= mcached;
124 	*per_mem = 100 * (double) mused / (double) mtotal;
125 
126 	/* calculate swap usage in percent */
127 	sused = stotal - sfree;
128 	if (opts->ignore_cached)
129 		sused -= scached;
130 	if (!stotal)
131 		*per_swap = 0;
132 	else
133 		*per_swap = 100 * (double) sused / (double) stotal;
134 
135 #if DEBUG
136 	printf("-----------------------\n");
137 	printf("MemTotal:  %12ld\n", (unsigned long)mtotal);
138 	printf("MemFree:   %12ld\n", (unsigned long)mfree);
139 	printf("Buffers:   %12ld\n", (unsigned long)mbuffer);
140 	printf("Cached:    %12ld\n", (unsigned long)mcached);
141 	printf("SwapTotal: %12ld\n", (unsigned long)stotal);
142 	printf("SwapFree:  %12ld\n", (unsigned long)sfree);
143 	printf("SwapCached:%12ld\n", (unsigned long)scached);
144 	printf("-----------------------\n\n");
145 #endif
146 
147 }
148