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.
20 #include <linux/types.h>
21 #include <sys/statvfs.h>
25 #include "mon_fsstatd.h"
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";
44 * Clean up when SIGTERM or SIGINT received
46 void stop_fsstatd(int UNUSED(a
))
53 * Set up for handling SIGTERM or SIGINT
55 static void fsstatd_handle_signals(void)
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
));
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
));
79 static void fsstatd_open_monwriter(void)
81 mw_dev
= open("/dev/monwriter", O_EXCL
| O_RDWR
);
83 printf("cannot open /dev/monwriter: %s\n", strerror(errno
));
89 * Store daemon's pid so it can be stopped
91 static void store_pid(void)
93 FILE *f
= fopen(pid_file
, "w");
96 syslog(LOG_ERR
, "cannot open pid file %s: %s", pid_file
,
100 fprintf(f
, "%d\n", getpid());
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
;
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",
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
;
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
;
167 struct mw_name_lens mw_lens
;
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
;
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
;
194 /* fill in rest of monwrite_hdr */
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)
245 /* Fork off the parent process */
248 syslog(LOG_ERR
, "fork error: %s\n", strerror(errno
));
254 /* Change the file mode mask */
257 /* Store daemon 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 */
264 syslog(LOG_ERR
, "setsid error: %s\n", strerror(errno
));
268 /* Change the current working directory */
269 if (chdir("/") < 0) {
270 syslog(LOG_ERR
, "chdir error: %s\n", strerror(errno
));
274 /* Close out the standard file descriptors */
276 close(STDOUT_FILENO
);
277 close(STDERR_FILENO
);
280 static int fsstatd_do_work(void)
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
298 syslog(LOG_INFO
, "sample interval: %lu\n", sample_interval
);
301 mnttab
= fopen("/etc/mtab", "r");
302 if (mnttab
== NULL
) {
303 syslog(LOG_ERR
, "cannot open /etc/mtab: %s\n",
310 ent
= getmntent(mnttab
);
312 syslog(LOG_ERR
, "getmntent error: %s\n",
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
);
328 result
= statvfs(ent
->mnt_dir
, &buf
);
331 syslog(LOG_ERR
, "statvfs error on %s: %s\n",
332 ent
->mnt_dir
, strerror(errno
));
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
;
350 sleep(sample_interval
);
359 static int parse_options(int argc
, char **argv
)
364 opt
= getopt_long(argc
, argv
, opt_string
, options
, NULL
);
367 /* Reached end of parameter list. */
370 printf("%s", help_text
);
373 printf("mon_fsstatd: version %s\n", RELEASE_STRING
);
374 printf("Copyright IBM Corp. 2006\n");
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");
388 fprintf(stderr
, "Try ' --help' for more"
396 int main(int argc
, char **argv
)
400 rc
= parse_options(argc
, argv
);
403 fsstatd_open_monwriter();
404 openlog("mon_fsstatd", 0, LOG_DAEMON
);
407 rc
= fsstatd_do_work();