Import version 1.8.3
[s390-tools.git] / mon_tools / mon_fsstatd.c
blobe46df62199106f7646fe3129d60990f013752b86
1 /*
2 * mon_fsstatd
3 * Author: Melissa Howland <melissa.howland@us.ibm.com>
5 * Copyright IBM Corp. 2006.
7 * Daemon that writes filesystem utilization data to the z/VM monitor stream.
8 */
9 #include <unistd.h>
10 #include <mntent.h>
11 #include <sys/vfs.h>
12 #include <stdlib.h>
13 #include <stdio.h>
14 #include <string.h>
15 #include <fcntl.h>
16 #include <syslog.h>
17 #include <errno.h>
18 #include <time.h>
19 #include <stdarg.h>
20 #include <linux/types.h>
21 #include <sys/statvfs.h>
22 #include <sys/stat.h>
23 #include <getopt.h>
24 #include <signal.h>
25 #include "mon_fsstatd.h"
27 static int attach;
28 static int mw_dev;
29 static char small_mon_record[SMALL_MON_RECORD_LEN];
30 static char large_mon_record[LARGE_MON_RECORD_LEN];
31 static long sample_interval = 60;
33 static const char *pid_file = "/var/run/mon_fsstatd.pid";
35 struct mw_name_lens {
36 __u16 mw_name_len;
37 __u16 mw_dir_len;
38 __u16 mw_type_len;
39 __u16 mw_fsdata_len;
40 __u16 mw_total;
44 * Clean up when SIGTERM or SIGINT received
46 void stop_fsstatd(int UNUSED(a))
48 remove(pid_file);
49 exit(0);
53 * Set up for handling SIGTERM or SIGINT
55 static void fsstatd_handle_signals(void)
57 struct sigaction act;
59 act.sa_flags = 0;
60 sigemptyset(&act.sa_mask);
62 act.sa_handler = stop_fsstatd;
63 if (sigaction(SIGTERM, &act, NULL) < 0) {
64 fprintf(stderr, "sigaction( SIGTERM, ... ) failed - "
65 "reason %s\n", strerror(errno));
66 exit(1);
68 act.sa_handler = stop_fsstatd;
69 if (sigaction(SIGINT, &act, NULL) < 0) {
70 fprintf(stderr, "sigaction( SIGINT, ... ) failed - "
71 "reason %s\n", strerror(errno));
72 exit(1);
77 * Open /dev/monwriter
79 static void fsstatd_open_monwriter(void)
81 mw_dev = open("/dev/monwriter", O_EXCL | O_RDWR);
82 if (mw_dev == -1) {
83 printf("cannot open /dev/monwriter: %s\n", strerror(errno));
84 exit(1);
89 * Store daemon's pid so it can be stopped
91 static void store_pid(void)
93 FILE *f = fopen(pid_file, "w");
95 if (!f) {
96 syslog(LOG_ERR, "cannot open pid file %s: %s", pid_file,
97 strerror(errno));
98 exit(1);
100 fprintf(f, "%d\n", getpid());
101 fclose(f);
105 * Stop sampling of any buffers that are not longer needed
107 static void stop_unused(int curr_max, int prev_max)
109 struct monwrite_hdr *mw_hdrp;
110 int i;
112 mw_hdrp = (struct monwrite_hdr *)small_mon_record;
113 mw_hdrp->mon_function = MONWRITE_STOP_INTERVAL;
114 mw_hdrp->datalen = 0;
115 for (i = 0; i < prev_max - curr_max; i += 2) {
116 mw_hdrp->mod_level = curr_max + i;
117 if (write(mw_dev, mw_hdrp, sizeof(struct monwrite_hdr)) == -1)
118 syslog(LOG_ERR, "write error on STOP: %s\n",
119 strerror(errno));
124 * Calculate lengths of data to be written to monitor stream
126 static struct mw_name_lens fsstatd_get_lens(struct mntent *ent)
128 struct mw_name_lens name_lens;
130 name_lens.mw_name_len = strlen(ent->mnt_fsname);
131 name_lens.mw_dir_len = strlen(ent->mnt_dir);
132 name_lens.mw_type_len = strlen(ent->mnt_type);
133 /* if name & dir too long to fit both, truncate them */
134 if (name_lens.mw_name_len +
135 name_lens.mw_dir_len +
136 name_lens.mw_type_len > MAX_NAMES_LEN) {
137 if (name_lens.mw_name_len > MAX_NAME_LEN)
138 name_lens.mw_name_len = MAX_NAME_LEN;
139 if (name_lens.mw_dir_len > MAX_DIR_LEN)
140 name_lens.mw_dir_len = MAX_DIR_LEN;
141 if (name_lens.mw_type_len > MAX_TYPE_LEN)
142 name_lens.mw_type_len = MAX_TYPE_LEN;
144 /* total fs data to be written */
145 name_lens.mw_fsdata_len = sizeof(__u16) + name_lens.mw_name_len +
146 sizeof(__u16) + name_lens.mw_dir_len +
147 sizeof(__u16) + name_lens.mw_type_len +
148 sizeof(struct fsstatd_data);
149 /* total monitor data to be written in monitor record */
150 name_lens.mw_total = sizeof(struct fsstatd_hdr) +
151 name_lens.mw_fsdata_len;
152 return name_lens;
156 * Write fs data for ent to monitor stream
158 static void fsstatd_write_ent(struct mntent *ent, time_t curr_time,
159 int *small_maxp, int *big_maxp, struct statvfs buf)
161 struct monwrite_hdr *mw_hdrp;
162 struct fsstatd_hdr *mw_fshdrp;
163 struct fsstatd_data *mw_fsdatap;
165 char *mw_tmpp;
166 char *mw_bufp;
167 struct mw_name_lens mw_lens;
168 int write_len;
170 mw_lens = fsstatd_get_lens(ent);
172 if ((mw_lens.mw_total + sizeof(struct monwrite_hdr))
173 <= sizeof(small_mon_record)) {
174 mw_bufp = small_mon_record;
175 memset(&small_mon_record, 0, sizeof(small_mon_record));
176 mw_hdrp = (struct monwrite_hdr *)mw_bufp;
178 mw_hdrp->datalen = sizeof(small_mon_record) -
179 sizeof(struct monwrite_hdr);
180 write_len = sizeof(small_mon_record);
181 mw_hdrp->mod_level = *small_maxp;
182 *small_maxp += 2;
183 } else {
184 mw_bufp = large_mon_record;
185 memset(&large_mon_record, 0, sizeof(large_mon_record));
186 mw_hdrp = (struct monwrite_hdr *)mw_bufp;
187 mw_hdrp->datalen = sizeof(large_mon_record) -
188 sizeof(struct monwrite_hdr);
189 write_len = sizeof(large_mon_record);
190 mw_hdrp->mod_level = *big_maxp;
191 *big_maxp += 2;
194 /* fill in rest of monwrite_hdr */
195 mw_tmpp = mw_bufp;
196 mw_hdrp->applid = FSSTATD_APPLID;
197 mw_hdrp->hdrlen = sizeof(struct monwrite_hdr);
198 mw_hdrp->mon_function = MONWRITE_START_INTERVAL;
200 /* fill in fsstatd_hdr */
201 mw_tmpp += sizeof(struct monwrite_hdr);
202 mw_fshdrp = (struct fsstatd_hdr *)mw_tmpp;
203 mw_fshdrp->time_stamp = (__u64) curr_time;
204 mw_fshdrp->fsstat_data_len = (__u16) mw_lens.mw_fsdata_len;
205 mw_fshdrp->fsstat_data_offset = (__u16) sizeof(struct fsstatd_hdr);
207 /* fill in fs name, dir name and fs type and lengths */
208 mw_tmpp += sizeof(struct fsstatd_hdr);
209 memcpy(mw_tmpp, &mw_lens.mw_name_len, sizeof(__u16));
210 mw_tmpp += sizeof(__u16);
211 strncpy(mw_tmpp, ent->mnt_fsname, mw_lens.mw_name_len);
212 mw_tmpp += mw_lens.mw_name_len;
213 memcpy(mw_tmpp, &mw_lens.mw_dir_len, sizeof(__u16));
214 mw_tmpp += sizeof(__u16);
215 strncpy(mw_tmpp, ent->mnt_dir, mw_lens.mw_dir_len);
216 mw_tmpp += mw_lens.mw_dir_len;
217 memcpy(mw_tmpp, &mw_lens.mw_type_len, sizeof(__u16));
218 mw_tmpp += sizeof(__u16);
219 strncpy(mw_tmpp, ent->mnt_type, mw_lens.mw_type_len);
221 /* fill in fsstatd_data */
222 mw_tmpp += mw_lens.mw_type_len;
223 mw_fsdatap = (struct fsstatd_data *)mw_tmpp;
224 mw_fsdatap->fs_bsize = (__u64)buf.f_bsize;
225 mw_fsdatap->fs_frsize = (__u64) buf.f_frsize;
226 mw_fsdatap->fs_blocks = (__u64) buf.f_blocks;
227 mw_fsdatap->fs_bfree = (__u64) buf.f_bfree;
228 mw_fsdatap->fs_bavail = (__u64) buf.f_bavail;
229 mw_fsdatap->fs_files = (__u64) buf.f_files;
230 mw_fsdatap->fs_ffree = (__u64) buf.f_ffree;
231 mw_fsdatap->fs_favail = (__u64) buf.f_favail;
232 mw_fsdatap->fs_flag = (__u64) buf.f_flag;
234 if (write(mw_dev, mw_bufp, write_len) == -1)
235 syslog(LOG_ERR, "write error: %s\n", strerror(errno));
239 * Run as background process
241 static void fsstatd_daemonize(void)
243 pid_t pid;
245 /* Fork off the parent process */
246 pid = fork();
247 if (pid < 0) {
248 syslog(LOG_ERR, "fork error: %s\n", strerror(errno));
249 exit(1);
251 if (pid > 0)
252 exit(0);
254 /* Change the file mode mask */
255 umask(0);
257 /* Store daemon pid */
258 store_pid();
259 /* Catch SIGINT and SIGTERM to clean up pid file on exit */
260 fsstatd_handle_signals();
262 /* Create a new SID for the child process */
263 if (setsid() < 0) {
264 syslog(LOG_ERR, "setsid error: %s\n", strerror(errno));
265 exit(1);
268 /* Change the current working directory */
269 if (chdir("/") < 0) {
270 syslog(LOG_ERR, "chdir error: %s\n", strerror(errno));
271 exit(1);
274 /* Close out the standard file descriptors */
275 close(STDIN_FILENO);
276 close(STDOUT_FILENO);
277 close(STDERR_FILENO);
280 static int fsstatd_do_work(void)
282 FILE *mnttab;
284 time_t curr_time;
285 struct statvfs buf;
286 struct mntent *ent;
288 int result;
289 int curr_small_max, prev_small_max;
290 int curr_big_max, prev_big_max;
293 * small buffers use even mod_levels,
294 * big buffers use odd mod_levels
296 prev_small_max = 0;
297 prev_big_max = 1;
298 syslog(LOG_INFO, "sample interval: %lu\n", sample_interval);
299 while (1) {
300 time(&curr_time);
301 mnttab = fopen("/etc/mtab", "r");
302 if (mnttab == NULL) {
303 syslog(LOG_ERR, "cannot open /etc/mtab: %s\n",
304 strerror(errno));
305 break;
307 curr_small_max = 0;
308 curr_big_max = 1;
310 ent = getmntent(mnttab);
311 if (ent == NULL) {
312 syslog(LOG_ERR, "getmntent error: %s\n",
313 strerror(errno));
314 fclose(mnttab);
315 break;
318 while (ent) {
319 /* Only sample physical filesystem size data */
320 if ((strncmp(ent->mnt_type, "autofs", 6) == 0 ||
321 strncmp(ent->mnt_type, "none", 4) == 0 ||
322 strncmp(ent->mnt_type, "proc", 4) == 0 ||
323 strncmp(ent->mnt_type, "subfs", 5) == 0 ||
324 strncmp(ent->mnt_type, "ignore", 6) == 0)) {
325 ent = getmntent(mnttab);
326 continue;
328 result = statvfs(ent->mnt_dir, &buf);
329 if (result != 0) {
330 fclose(mnttab);
331 syslog(LOG_ERR, "statvfs error on %s: %s\n",
332 ent->mnt_dir, strerror(errno));
333 break;
336 if (buf.f_blocks > 0)
337 fsstatd_write_ent(ent, curr_time,
338 &curr_small_max, &curr_big_max, buf);
339 ent = getmntent(mnttab);
342 if (curr_small_max < prev_small_max)
343 stop_unused(curr_small_max, prev_small_max);
344 if (curr_big_max < prev_big_max)
345 stop_unused(curr_big_max, prev_big_max);
347 prev_small_max = curr_small_max;
348 prev_big_max = curr_big_max;
349 fclose(mnttab);
350 sleep(sample_interval);
352 return 1;
357 Parse options
359 static int parse_options(int argc, char **argv)
361 int opt;
363 do {
364 opt = getopt_long(argc, argv, opt_string, options, NULL);
365 switch (opt) {
366 case -1:
367 /* Reached end of parameter list. */
368 break;
369 case 'h':
370 printf("%s", help_text);
371 exit(0);
372 case 'v':
373 printf("mon_fsstatd: version %s\n", RELEASE_STRING);
374 printf("Copyright IBM Corp. 2006\n");
375 exit(0);
376 case 'a':
377 attach = 1;
378 break;
379 case 'i':
380 sample_interval = strtol(optarg, NULL, 10);
381 if (sample_interval <= 0) {
382 fprintf(stderr, "Error: Invalid interval "
383 "(needs to be greater than 0)\n");
384 return(1);
386 break;
387 default:
388 fprintf(stderr, "Try ' --help' for more"
389 " information.\n");
390 return(1) ;
392 } while (opt != -1);
393 return(0);
396 int main(int argc, char **argv)
398 int rc;
400 rc = parse_options(argc, argv);
401 if (rc > 0)
402 return rc;
403 fsstatd_open_monwriter();
404 openlog("mon_fsstatd", 0, LOG_DAEMON);
405 if (!attach)
406 fsstatd_daemonize();
407 rc = fsstatd_do_work();
408 close(mw_dev);
409 return rc;