Replace all calls to `strerror' with `sstrerror'
[collectd.git] / src / nfs.c
1 /**
2  * collectd - src/nfs.c
3  * Copyright (C) 2005,2006  Jason Pepas
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; only version 2 of the License is applicable.
8  *
9  * This program is distributed in the hope that it will be useful, but
10  * WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License along
15  * with this program; if not, write to the Free Software Foundation, Inc.,
16  * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
17  *
18  * Authors:
19  *   Jason Pepas <cell at ices.utexas.edu>
20  *   Florian octo Forster <octo at verplant.org>
21  **/
22
23 #include "collectd.h"
24 #include "common.h"
25 #include "plugin.h"
26
27 #define MODULE_NAME "nfs"
28
29 /* #if defined(KERNEL_LINUX) || defined(HAVE_LIBKSTAT) */
30 #if KERNEL_LINUX
31 # define NFS_HAVE_READ 1
32 #else
33 # define NFS_HAVE_READ 0
34 #endif
35
36 /*
37 see /proc/net/rpc/nfs
38 see http://www.missioncriticallinux.com/orph/NFS-Statistics
39
40 net x x x x
41 rpc_stat.netcnt         Not used; always zero.
42 rpc_stat.netudpcnt      Not used; always zero.
43 rpc_stat.nettcpcnt      Not used; always zero.
44 rpc_stat.nettcpconn     Not used; always zero.
45
46 rpc x x x
47 rpc_stat.rpccnt             The number of RPC calls.
48 rpc_stat.rpcretrans         The number of retransmitted RPC calls.
49 rpc_stat.rpcauthrefresh     The number of credential refreshes.
50
51 proc2 x x x...
52 proc3 x x x...
53
54 Procedure   NFS Version NFS Version 3
55 Number      Procedures  Procedures
56
57 0           null        null
58 1           getattr     getattr
59 2           setattr     setattr
60 3           root        lookup
61 4           lookup      access
62 5           readlink    readlink
63 6           read        read
64 7           wrcache     write
65 8           write       create
66 9           create      mkdir
67 10          remove      symlink
68 11          rename      mknod
69 12          link        remove
70 13          symlink     rmdir
71 14          mkdir       rename
72 15          rmdir       link
73 16          readdir     readdir
74 17          fsstat      readdirplus
75 18                      fsstat
76 19                      fsinfo
77 20                      pathconf
78 21                      commit
79 */
80
81 static data_source_t procedure_dsrc[1] =
82 {
83         {"value", DS_TYPE_COUNTER, 0, 4294967295.0}
84 };
85
86 static data_set_t procedure_ds =
87 {
88         "nfs_procedure", 1, procedure_dsrc
89 };
90
91 #if NFS_HAVE_READ
92 static const char *nfs2_procedures_names[] =
93 {
94         "null",
95         "getattr",
96         "setattr",
97         "root",
98         "lookup",
99         "readlink",
100         "read",
101         "wrcache",
102         "write",
103         "create",
104         "remove",
105         "rename",
106         "link",
107         "symlink",
108         "mkdir",
109         "rmdir",
110         "readdir",
111         "fsstat",
112         NULL
113 };
114 static int nfs2_procedures_names_num = 18;
115
116 static const char *nfs3_procedures_names[] =
117 {
118         "null",
119         "getattr",
120         "setattr",
121         "lookup",
122         "access",
123         "readlink",
124         "read",
125         "write",
126         "create",
127         "mkdir",
128         "symlink",
129         "mknod",
130         "remove",
131         "rmdir",
132         "rename",
133         "link",
134         "readdir",
135         "readdirplus",
136         "fsstat",
137         "fsinfo",
138         "pathconf",
139         "commit",
140         NULL
141 };
142 static int nfs3_procedures_names_num = 22;
143
144 #if HAVE_LIBKSTAT && 0
145 extern kstat_ctl_t *kc;
146 static kstat_t *nfs2_ksp_client;
147 static kstat_t *nfs2_ksp_server;
148 static kstat_t *nfs3_ksp_client;
149 static kstat_t *nfs3_ksp_server;
150 static kstat_t *nfs4_ksp_client;
151 static kstat_t *nfs4_ksp_server;
152 #endif
153
154 /* Possibly TODO: NFSv4 statistics */
155
156 #if 0
157 static int nfs_init (void)
158 {
159 #if HAVE_LIBKSTAT && 0
160         kstat_t *ksp_chain;
161
162         nfs2_ksp_client = NULL;
163         nfs2_ksp_server = NULL;
164         nfs3_ksp_client = NULL;
165         nfs3_ksp_server = NULL;
166         nfs4_ksp_client = NULL;
167         nfs4_ksp_server = NULL;
168         
169         if (kc == NULL)
170                 return;
171
172         for (ksp_chain = kc->kc_chain; ksp_chain != NULL;
173                         ksp_chain = ksp_chain->ks_next)
174         {
175                 if (strncmp (ksp_chain->ks_module, "nfs", 3) != 0)
176                         continue;
177                 else if (strncmp (ksp_chain->ks_name, "rfsproccnt_v2", 13) == 0)
178                         nfs2_ksp_server = ksp_chain;
179                 else if (strncmp (ksp_chain->ks_name, "rfsproccnt_v3", 13) == 0)
180                         nfs3_ksp_server = ksp_chain;
181                 else if (strncmp (ksp_chain->ks_name, "rfsproccnt_v4", 13) == 0)
182                         nfs4_ksp_server = ksp_chain;
183                 else if (strncmp (ksp_chain->ks_name, "rfsreqcnt_v2", 12) == 0)
184                         nfs2_ksp_client = ksp_chain;
185                 else if (strncmp (ksp_chain->ks_name, "rfsreqcnt_v3", 12) == 0)
186                         nfs3_ksp_client = ksp_chain;
187                 else if (strncmp (ksp_chain->ks_name, "rfsreqcnt_v4", 12) == 0)
188                         nfs4_ksp_client = ksp_chain;
189         }
190 #endif
191
192         return (0);
193 } /* int nfs_init */
194 #endif
195
196 #define BUFSIZE 1024
197 static void nfs_procedures_submit (const char *plugin_instance,
198                 unsigned long long *val, const char **names, int len)
199 {
200         value_t values[1];
201         value_list_t vl = VALUE_LIST_INIT;
202         int i;
203
204         vl.values = values;
205         vl.values_len = 1;
206         vl.time = time (NULL);
207         strcpy (vl.host, hostname_g);
208         strcpy (vl.plugin, "nfs");
209         strncpy (vl.plugin_instance, plugin_instance,
210                         sizeof (vl.plugin_instance));
211
212         for (i = 0; i < len; i++)
213         {
214                 values[0].counter = val[i];
215                 strncpy (vl.type_instance, names[i],
216                                 sizeof (vl.type_instance));
217                 DEBUG ("%s-%s/nfs_procedure-%s = %llu",
218                                 vl.plugin, vl.plugin_instance,
219                                 vl.type_instance, val[i]);
220                 plugin_dispatch_values ("nfs_procedure", &vl);
221         }
222 } /* void nfs_procedures_submit */
223
224 #if KERNEL_LINUX
225 static void nfs_read_stats_file (FILE *fh, char *inst)
226 {
227         char buffer[BUFSIZE];
228
229         char plugin_instance[DATA_MAX_NAME_LEN];
230
231         char *fields[48];
232         int numfields = 0;
233
234         if (fh == NULL)
235                 return;
236
237         while (fgets (buffer, BUFSIZE, fh) != NULL)
238         {
239                 numfields = strsplit (buffer, fields, 48);
240
241                 if (((numfields - 2) != nfs2_procedures_names_num)
242                                 && ((numfields - 2)
243                                         != nfs3_procedures_names_num))
244                         continue;
245
246                 if (strcmp (fields[0], "proc2") == 0)
247                 {
248                         int i;
249                         unsigned long long *values;
250
251                         if ((numfields - 2) != nfs2_procedures_names_num)
252                         {
253                                 WARNING ("nfs plugin: Wrong "
254                                                 "number of fields (= %i) "
255                                                 "for NFSv2 statistics.",
256                                                 numfields - 2);
257                                 continue;
258                         }
259
260                         snprintf (plugin_instance, sizeof (plugin_instance),
261                                         "v2%s", inst);
262                         plugin_instance[DATA_MAX_NAME_LEN - 1] = '\0';
263
264                         values = (unsigned long long *) malloc (nfs2_procedures_names_num * sizeof (unsigned long long));
265                         if (values == NULL)
266                         {
267                                 char errbuf[1024];
268                                 ERROR ("nfs plugin: malloc "
269                                                 "failed: %s",
270                                                 sstrerror (errno, errbuf, sizeof (errbuf)));
271                                 continue;
272                         }
273
274                         for (i = 0; i < nfs2_procedures_names_num; i++)
275                                 values[i] = atoll (fields[i + 2]);
276
277                         nfs_procedures_submit (plugin_instance, values,
278                                         nfs2_procedures_names,
279                                         nfs2_procedures_names_num);
280
281                         free (values);
282                 }
283                 else if (strncmp (fields[0], "proc3", 5) == 0)
284                 {
285                         int i;
286                         unsigned long long *values;
287
288                         if ((numfields - 2) != nfs3_procedures_names_num)
289                         {
290                                 WARNING ("nfs plugin: Wrong "
291                                                 "number of fields (= %i) "
292                                                 "for NFSv3 statistics.",
293                                                 numfields - 2);
294                                 continue;
295                         }
296
297                         snprintf (plugin_instance, sizeof (plugin_instance),
298                                         "v3%s", inst);
299                         plugin_instance[DATA_MAX_NAME_LEN - 1] = '\0';
300
301                         values = (unsigned long long *) malloc (nfs3_procedures_names_num * sizeof (unsigned long long));
302                         if (values == NULL)
303                         {
304                                 char errbuf[1024];
305                                 ERROR ("nfs plugin: malloc "
306                                                 "failed: %s",
307                                                 sstrerror (errno, errbuf, sizeof (errbuf)));
308                                 continue;
309                         }
310
311                         for (i = 0; i < nfs3_procedures_names_num; i++)
312                                 values[i] = atoll (fields[i + 2]);
313
314                         nfs_procedures_submit (plugin_instance, values,
315                                         nfs3_procedures_names,
316                                         nfs3_procedures_names_num);
317
318                         free (values);
319                 }
320         } /* while (fgets (buffer, BUFSIZE, fh) != NULL) */
321 } /* void nfs_read_stats_file */
322 #endif /* defined(KERNEL_LINUX) */
323 #undef BUFSIZE
324
325 #if HAVE_LIBKSTAT && 0
326 static void nfs2_read_kstat (kstat_t *ksp, char *inst)
327 {
328         unsigned long long values[18];
329
330         values[0] = get_kstat_value (ksp, "null");
331         values[1] = get_kstat_value (ksp, "getattr");
332         values[2] = get_kstat_value (ksp, "setattr");
333         values[3] = get_kstat_value (ksp, "root");
334         values[4] = get_kstat_value (ksp, "lookup");
335         values[5] = get_kstat_value (ksp, "readlink");
336         values[6] = get_kstat_value (ksp, "read");
337         values[7] = get_kstat_value (ksp, "wrcache");
338         values[8] = get_kstat_value (ksp, "write");
339         values[9] = get_kstat_value (ksp, "create");
340         values[10] = get_kstat_value (ksp, "remove");
341         values[11] = get_kstat_value (ksp, "rename");
342         values[12] = get_kstat_value (ksp, "link");
343         values[13] = get_kstat_value (ksp, "symlink");
344         values[14] = get_kstat_value (ksp, "mkdir");
345         values[15] = get_kstat_value (ksp, "rmdir");
346         values[16] = get_kstat_value (ksp, "readdir");
347         values[17] = get_kstat_value (ksp, "statfs");
348
349         nfs2_procedures_submit (values, inst);
350 }
351 #endif
352
353 static int nfs_read (void)
354 {
355 #if KERNEL_LINUX
356         FILE *fh;
357
358         if ((fh = fopen ("/proc/net/rpc/nfs", "r")) != NULL)
359         {
360                 nfs_read_stats_file (fh, "client");
361                 fclose (fh);
362         }
363
364         if ((fh = fopen ("/proc/net/rpc/nfsd", "r")) != NULL)
365         {
366                 nfs_read_stats_file (fh, "server");
367                 fclose (fh);
368         }
369
370 /* #endif defined(KERNEL_LINUX) */
371
372 #elif HAVE_LIBKSTAT && 0
373         if (nfs2_ksp_client != NULL)
374                 nfs2_read_kstat (nfs2_ksp_client, "client");
375         if (nfs2_ksp_server != NULL)
376                 nfs2_read_kstat (nfs2_ksp_server, "server");
377 #endif /* defined(HAVE_LIBKSTAT) */
378
379         return (0);
380 }
381 #endif /* NFS_HAVE_READ */
382
383 void module_register (void)
384 {
385         plugin_register_data_set (&procedure_ds);
386
387 #if NFS_HAVE_READ
388         plugin_register_read ("nfs", nfs_read);
389 #endif
390 }
391
392 #undef MODULE_NAME