18bcec95c2214c02315f05b5e02777aab28f22c7
1 /**
2 * collectd - src/processes.c
3 * Copyright (C) 2005 Lyonel Vincent
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the
7 * Free Software Foundation; either version 2 of the License, or (at your
8 * option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
18 *
19 * Authors:
20 * Lyonel Vincent <lyonel at ezix.org>
21 * Florian octo Forster <octo at verplant.org>
22 **/
24 #include "collectd.h"
25 #include "common.h"
26 #include "plugin.h"
27 #include "utils_debug.h"
29 #if HAVE_SYS_SYSCTL_H
30 # include <sys/sysctl.h>
31 #endif
33 #define MODULE_NAME "processes"
35 #if defined(KERNEL_LINUX) || defined(HAVE_SYSCTLBYNAME)
36 # define PROCESSES_HAVE_READ 1
37 #else
38 # define PROCESSES_HAVE_READ 0
39 #endif
41 #define BUFSIZE 256
43 static char *ps_file = "processes.rrd";
45 static char *ds_def[] =
46 {
47 "DS:running:GAUGE:"COLLECTD_HEARTBEAT":0:65535",
48 "DS:sleeping:GAUGE:"COLLECTD_HEARTBEAT":0:65535",
49 "DS:zombies:GAUGE:"COLLECTD_HEARTBEAT":0:65535",
50 "DS:stopped:GAUGE:"COLLECTD_HEARTBEAT":0:65535",
51 "DS:paging:GAUGE:"COLLECTD_HEARTBEAT":0:65535",
52 "DS:blocked:GAUGE:"COLLECTD_HEARTBEAT":0:65535",
53 NULL
54 };
55 static int ds_num = 6;
57 static void ps_init (void)
58 {
59 }
61 static void ps_write (char *host, char *inst, char *val)
62 {
63 rrd_update_file (host, ps_file, val, ds_def, ds_num);
64 }
66 #if PROCESSES_HAVE_READ
67 static void ps_submit (unsigned int running,
68 unsigned int sleeping,
69 unsigned int zombies,
70 unsigned int stopped,
71 unsigned int paging,
72 unsigned int blocked)
73 {
74 char buf[BUFSIZE];
76 if (snprintf (buf, BUFSIZE, "%u:%u:%u:%u:%u:%u:%u",
77 (unsigned int) curtime,
78 running, sleeping, zombies, stopped, paging,
79 blocked) >= BUFSIZE)
80 return;
82 plugin_submit (MODULE_NAME, "-", buf);
83 }
85 static void ps_read (void)
86 {
87 #ifdef KERNEL_LINUX
88 unsigned int running, sleeping, zombies, stopped, paging, blocked;
90 char buf[BUFSIZE];
91 char filename[20]; /* need 17 bytes */
92 char *fields[BUFSIZE];
94 struct dirent *ent;
95 DIR *proc;
96 FILE *fh;
98 running = sleeping = zombies = stopped = paging = blocked = 0;
100 if ((proc = opendir ("/proc")) == NULL)
101 {
102 syslog (LOG_ERR, "Cannot open `/proc': %s", strerror (errno));
103 return;
104 }
106 while ((ent = readdir (proc)) != NULL)
107 {
108 if (!isdigit (ent->d_name[0]))
109 continue;
111 if (snprintf (filename, 20, "/proc/%s/stat", ent->d_name) >= 20)
112 continue;
114 if ((fh = fopen (filename, "r")) == NULL)
115 {
116 syslog (LOG_ERR, "Cannot open `%s': %s", filename, strerror (errno));
117 continue;
118 }
120 if (fgets (buf, BUFSIZE, fh) == NULL)
121 {
122 fclose (fh);
123 continue;
124 }
126 fclose (fh);
128 if (strsplit (buf, fields, BUFSIZE) < 3)
129 continue;
131 switch (fields[2][0])
132 {
133 case 'R': running++; break;
134 case 'S': sleeping++; break;
135 case 'D': blocked++; break;
136 case 'Z': zombies++; break;
137 case 'T': stopped++; break;
138 case 'W': paging++; break;
139 }
140 }
142 closedir(proc);
144 ps_submit (running, sleeping, zombies, stopped, paging, blocked);
145 /* #endif defined(KERNEL_LINUX) */
147 #elif HAVE_SYSCTLBYNAME
148 int mib[3];
149 size_t len;
150 size_t num;
151 int i;
152 int tries;
153 struct kinfo_proc *kp;
155 unsigned int state_idle = 0;
156 unsigned int state_run = 0;
157 unsigned int state_sleep = 0;
158 unsigned int state_stop = 0;
159 unsigned int state_zombie = 0;
161 mib[0] = CTL_KERN;
162 mib[1] = KERN_PROC;
163 mib[2] = KERN_PROC_ALL;
165 tries = 0;
166 kp = NULL;
167 while (1)
168 {
169 if (tries >= 3)
170 return;
171 tries++;
173 len = 0;
174 if (sysctl(mib, 3, NULL, &len, NULL, 0) != 0)
175 {
176 syslog (LOG_ERR, "processes: sysctl failed: %s",
177 strerror (errno));
178 return;
179 }
181 if ((kp = (struct kinfo_proc *) malloc (len)) == NULL)
182 {
183 syslog (LOG_ERR, "processes: malloc failed: %s",
184 strerror (errno));
185 return;
186 }
188 if (sysctl(mib, 3, (void *) kp, &len, NULL, 0) != 0)
189 {
190 syslog (LOG_WARNING, "processes: sysctl failed: %s",
191 strerror (errno));
192 free (kp);
193 kp = NULL;
194 continue;
195 }
197 break;
198 } /* while true */
200 /* If we get past the while-loop, `kp' containes a valid `struct
201 * kinfo_proc'. */
203 num = len / sizeof (struct kinfo_proc);
205 for (i = 0; i < num; i++)
206 {
207 DBG ("%3i: Process %i is in state %i", i,
208 (int) kp[i].kp_proc.p_pid,
209 (int) kp[i].kp_proc.p_stat);
211 switch (kp[i].kp_proc.p_stat)
212 {
213 case SIDL:
214 state_idle++;
215 break;
217 case SRUN:
218 state_run++;
219 break;
221 case SSLEEP:
222 #ifdef P_SINTR
223 if ((kp[i].kp_proc.p_flag & P_SINTR) == 0)
224 state_sleep++; /* TODO change this to `state_blocked' or something.. */
225 else
226 #endif /* P_SINTR */
227 state_sleep++;
228 break;
230 case SSTOP:
231 state_stop++;
232 break;
234 case SZOMB:
235 state_zombie++;
236 break;
238 default:
239 syslog (LOG_WARNING, "processes: PID %i in unknown state 0x%2x",
240 (int) kp[i].kp_proc.p_pid,
241 (int) kp[i].kp_proc.p_stat);
242 } /* switch (state) */
243 } /* for (i = 0 .. num-1) */
245 free (kp);
247 if (state_run || state_idle || state_sleep || state_zombie)
248 ps_submit (state_run, state_idle + state_sleep, state_zombie,
249 state_stop, -1, -1);
250 #endif /* HAVE_SYSCTLBYNAME */
251 }
252 #else
253 # define ps_read NULL
254 #endif /* PROCESSES_HAVE_READ */
256 void module_register (void)
257 {
258 plugin_register (MODULE_NAME, ps_init, ps_read, ps_write);
259 }
261 #undef BUFSIZE
262 #undef MODULE_NAME