1 /*----------------------------------------------------------------------------*/
2 /* Xymon message daemon. */
3 /* */
4 /* Client backend module for Linux */
5 /* */
6 /* Copyright (C) 2005-2011 Henrik Storner <henrik@hswn.dk> */
7 /* */
8 /* This program is released under the GNU General Public License (GPL), */
9 /* version 2. See the file "COPYING" for details. */
10 /* */
11 /*----------------------------------------------------------------------------*/
12
13 static char linux_rcsid[] = "$Id: linux.c 7886 2016-02-02 20:16:19Z jccleaver $";
14
handle_linux_client(char * hostname,char * clienttype,enum ostype_t os,void * hinfo,char * sender,time_t timestamp,char * clientdata)15 void handle_linux_client(char *hostname, char *clienttype, enum ostype_t os,
16 void *hinfo, char *sender, time_t timestamp,
17 char *clientdata)
18 {
19 char *timestr;
20 char *uptimestr;
21 char *clockstr;
22 char *msgcachestr;
23 char *whostr;
24 char *psstr;
25 char *topstr;
26 char *dfstr;
27 char *inodestr;
28 char *freestr;
29 char *msgsstr;
30 char *netstatstr;
31 char *vmstatstr;
32 char *ifstatstr;
33 char *portsstr;
34 char *mdstatstr;
35
36 char fromline[1024];
37
38 sprintf(fromline, "\nStatus message received from %s\n", sender);
39
40 splitmsg(clientdata);
41
42 timestr = getdata("date");
43 uptimestr = getdata("uptime");
44 clockstr = getdata("clock");
45 msgcachestr = getdata("msgcache");
46 whostr = getdata("who");
47 psstr = getdata("ps");
48 topstr = getdata("top");
49 dfstr = getdata("df");
50 inodestr = getdata("inode");
51 freestr = getdata("free");
52 msgsstr = getdata("msgs");
53 netstatstr = getdata("netstat");
54 ifstatstr = getdata("ifstat");
55 vmstatstr = getdata("vmstat");
56 portsstr = getdata("ports");
57 mdstatstr = getdata("mdstat");
58
59 unix_cpu_report(hostname, clienttype, os, hinfo, fromline, timestr, uptimestr, clockstr, msgcachestr,
60 whostr, 0, psstr, 0, topstr);
61 unix_disk_report(hostname, clienttype, os, hinfo, fromline, timestr, "Available", "Capacity", "Mounted", dfstr);
62 unix_inode_report(hostname, clienttype, os, hinfo, fromline, timestr, "IFree", "IUse%", "Mounted", inodestr);
63 unix_procs_report(hostname, clienttype, os, hinfo, fromline, timestr, "CMD", NULL, psstr);
64 unix_ports_report(hostname, clienttype, os, hinfo, fromline, timestr, 3, 4, 5, portsstr);
65
66 msgs_report(hostname, clienttype, os, hinfo, fromline, timestr, msgsstr);
67 file_report(hostname, clienttype, os, hinfo, fromline, timestr);
68 linecount_report(hostname, clienttype, os, hinfo, fromline, timestr);
69 deltacount_report(hostname, clienttype, os, hinfo, fromline, timestr);
70
71 unix_netstat_report(hostname, clienttype, os, hinfo, fromline, timestr, netstatstr);
72 unix_ifstat_report(hostname, clienttype, os, hinfo, fromline, timestr, ifstatstr);
73 unix_vmstat_report(hostname, clienttype, os, hinfo, fromline, timestr, vmstatstr);
74
75 /*
76 * Sigh. Recent kernels + procps-ng change things up a bit. If 'available' is present
77 * (roughly, 3.14+ and 2.6.27+, but depends on the vendor), then we'll use the inverse of that:
78 * (Physical - Available = ACTUALUSED)
79 * Otherwise, it's:
80 * (Physical Used - (buffers + cached) = ACTUALUSED)
81 *
82 * See discussions at http://lists.xymon.com/pipermail/xymon/2015-April/041628.html
83 * If the legacy meminfo display is NOT used, we should get the old format still
84 *
85 */
86
87 if (freestr) {
88 char *p;
89 long memphystotal, memphysused, memphysfree,
90 memacttotal, memactused, memactfree,
91 memswaptotal, memswapused, memswapfree;
92
93 memphystotal = memswaptotal = memphysused = memswapused = memacttotal = memactused = memactfree = -1;
94
95 /* check for old style */
96 p = strstr(freestr, "\n-/+ buffers/cache:");
97 if (p) {
98 p = strstr(freestr, "\nMem:");
99 if (p && (sscanf(p, "\nMem: %ld %ld %ld", &memphystotal, &memphysused, &memphysfree) == 3)) {
100 memphystotal /= 1024;
101 memphysused /= 1024;
102 memphysfree /= 1024;
103 }
104 p = strstr(freestr, "\n-/+ buffers/cache:");
105 if (sscanf(p, "\n-/+ buffers/cache: %ld %ld", &memactused, &memactfree) == 2) {
106 memacttotal = memphystotal;
107 memactused /= 1024;
108 memactfree /= 1024;
109 }
110
111 }
112 /* check for new style */
113 else if (strstr(freestr, "available\n")) {
114 long shared, buffcache;
115 p = strstr(freestr, "\nMem:");
116 if (p && (sscanf(p, "\nMem: %ld %ld %ld %ld %ld %ld", &memphystotal, &memphysused, &memphysfree,
117 &shared, &buffcache, &memactfree) == 6)) {
118 memphystotal /= 1024;
119 memphysused /= 1024;
120 memphysfree /= 1024;
121 /* Provide a Physical Used value that's compatible with previous thresholds. However, use the */
122 /* new 'Available' line as the basis for "Actual Used", since it'll be more accurate. */
123 memacttotal = memphystotal;
124 memactfree /= 1024;
125 memactused = memacttotal - memactfree; if (memactused < 0) memactused = 0;
126 memphysused += (buffcache / 1024);
127
128 }
129 }
130 else errprintf(" -> No readable memory data for %s in freestr\n", hostname);
131
132 /* There's always a swap line */
133 p = strstr(freestr, "\nSwap:");
134 if (p && (sscanf(p, "\nSwap: %ld %ld %ld", &memswaptotal, &memswapused, &memswapfree) == 3)) {
135 memswaptotal /= 1024;
136 memswapused /= 1024;
137 memswapfree /= 1024;
138 }
139
140 unix_memory_report(hostname, clienttype, os, hinfo, fromline, timestr,
141 memphystotal, memphysused,
142 memacttotal, memactused,
143 memswaptotal, memswapused);
144 }
145
146 if (mdstatstr) {
147 char *statcopy, *bol, *eol;
148 int color = COL_GREEN;
149 char *mdname = NULL, *mdstatus = NULL;
150 int mddevices = 0, mdactive = 0, recovering = 0;
151 strbuffer_t *alerttext = newstrbuffer(0);
152 char msgline[1024];
153 char *summary = NULL;
154 int arraycount = 0;
155
156 statcopy = (char *)malloc(strlen(mdstatstr) + 10);
157 sprintf(statcopy, "%s\nmd999\n", mdstatstr);
158
159 bol = statcopy;
160 while (bol) {
161 eol = strchr(bol, '\n'); if (eol) *eol = '\0';
162
163 if ((strncmp(bol, "md", 2) == 0) && (isdigit(*(bol+2)))) {
164 char *tok;
165
166 if (mdname && (mddevices >= 0) && (mdactive >= 0)) {
167 int onecolor = COL_GREEN;
168
169 /* Got a full md device status, flush it before we start on the next one */
170 arraycount++;
171 if (mddevices != mdactive) {
172 if (!recovering) {
173 onecolor = COL_RED;
174 snprintf(msgline, sizeof(msgline), "&red %s : Disk failure in array : %d devices of %d active\n", mdname, mdactive, mddevices);
175 addtobuffer(alerttext, msgline);
176 summary = "failure";
177 }
178 else {
179 onecolor = COL_YELLOW;
180 snprintf(msgline, sizeof(msgline), "&yellow %s status %s : %d devices of %d active\n", mdname, mdstatus, mdactive, mddevices);
181 addtobuffer(alerttext, msgline);
182 if (!summary) summary = "recovering";
183 }
184 }
185 else {
186 snprintf(msgline, sizeof(msgline), "&green %s : %d devices of %d active\n", mdname, mdactive, mddevices);
187 addtobuffer(alerttext, msgline);
188 }
189
190 if (onecolor > color) {
191 color = onecolor;
192 }
193 }
194
195 /* First line, holds the name of the array and the active/inactive status */
196 mddevices = mdactive = -1; recovering = 0;
197
198 mdname = strtok(bol, " ");
199 tok = strtok(NULL, " "); // Skip the ':'
200 mdstatus = strtok(NULL, " ");
201 }
202
203
204 if (mdname && ((mddevices == -1) && (mdactive == -1)) && (strchr(bol, '/'))) {
205 char *p = strchr(bol, '/');
206
207 /* Second line: Holds the number of configured/active devices */
208 mdactive = atoi(p+1);
209 while ((p > bol) && (isdigit(*(p-1)))) p--;
210 mddevices = atoi(p);
211 }
212
213 if (mdname && (mddevices != mdactive) && strstr(bol, "recovery = ")) {
214 /* Third line: Only present during recovery */
215 mdstatus = "recovery in progress";
216 recovering = 1;
217 }
218
219 bol = (eol ? eol+1 : NULL);
220 }
221
222
223 if (arraycount > 0) {
224 init_status(color);
225 sprintf(msgline, "status %s.raid %s %s - RAID %s\n\n",
226 commafy(hostname), colorname(color),
227 (timestr ? timestr : "<No timestamp data>"),
228 (summary ? summary : "OK"));
229 addtostatus(msgline);
230 if (STRBUFLEN(alerttext) > 0) {
231 addtostrstatus(alerttext);
232 addtostatus("\n\n");
233 }
234 addtostatus("============================ /proc/mdstat ===========================\n\n");
235 addtostatus(mdstatstr);
236 finish_status();
237 }
238
239 xfree(statcopy);
240 freestrbuffer(alerttext);
241 }
242
243 splitmsg_done();
244 }
245
246