Do ioctl(file, BLKRRPART) if supported to reread partitions when they are already...
[polld.git] / polld.c
blob58ff4b9af93a5d37fd75820bef46940e23fac225
1 /*
2 * Polling daemon
4 * Copyright (c) 2004-2006 by Michal Čihař <michal@cihar.com>
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation; either version 2.
10 * This code is distributed in the hope that it will be useful, but WITHOUT
11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
13 * more details.
15 * You should have received a copy of the GNU General Public License along with
16 * this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
20 #define _GNU_SOURCE
21 #include <stdio.h>
22 #include <string.h>
23 #include <errno.h>
24 #include <stdlib.h>
25 #include <sys/types.h>
26 #include <unistd.h>
27 #include <getopt.h>
28 #include <signal.h>
29 #include <sys/types.h>
30 #include <sys/stat.h>
31 #include <fcntl.h>
32 #if LINUX
33 #include <sys/ioctl.h>
34 #include <linux/fs.h>
35 #endif
37 /* These are usually defined by make: */
38 #ifndef CONFIGFILE
39 # define CONFIGFILE "/etc/polld"
40 #endif
41 #ifndef PIDFILE
42 # define PIDFILE "/var/run/polld.pid"
43 #endif
44 #ifndef SLEEPTIME
45 # define SLEEPTIME 10
46 #endif
47 #ifndef VERSION
48 # define VERSION "unknown"
49 #endif
51 /* From linux/fs.h */
52 #define BLKRRPART _IO(0x12,95) /* re-read partition table */
54 /* Commandline params */
55 char *config = NULL;
56 char *pid = NULL;
57 int sleeptime = SLEEPTIME;
59 /* Parameters */
60 char **filelist = NULL;
61 int listlen = 0;
62 int alloclen = 0;
64 /* Global flags */
65 volatile int shutdown = 0;
66 volatile int reload = 0;
68 #define ERRORPREFIX "polld: "
70 void show_version(void) {
71 printf("polld version " VERSION "\n"
72 "Copyright (C) 2004-2006 Michal Cihar <michal@cihar.com>\n"
73 "This is free software. You may redistribute copies of it under the terms of\n"
74 "the GNU General Public License <http://www.gnu.org/licenses/gpl.html>.\n"
75 "There is NO WARRANTY, to the extent permitted by law.\n");
76 exit(0);
79 void show_help(void) {
80 printf( "Usage: polld [params]\n"
81 "Parameters\n"
82 " -h --help show this help\n"
83 " -v --version show version information\n"
84 " -c --config file configuration file to use\n"
85 " -p --pid file lock file for storing pid, empty for no locking\n"
86 " -s --sleep seconds number of seconds to sleep in sleep cycle\n"
87 "\n");
88 exit(0);
91 void parse_params(int argc, char **argv) {
92 struct option long_options[] = {
93 {"help" , 0, 0, 'h'},
94 {"version" , 0, 0, 'v'},
95 {"config" , 1, 0, 'c'},
96 {"sleep" , 1, 0, 's'},
97 {"pid" , 1, 0, 'p'},
98 {0 , 0, 0, 0}
100 int c;
101 int option_index;
103 /* No error messages from getopt */
104 opterr = 0;
106 while ((c = getopt_long (argc, argv, "hvc:s:p:", long_options, &option_index)) != -1) {
107 switch (c) {
108 case 'h':
109 show_help();
110 break;
111 case 'v':
112 show_version();
113 break;
114 case 'c':
115 if (config != NULL) free(config);
116 config = strdup(optarg);
117 break;
118 case 'p':
119 if (pid != NULL) free(pid);
120 pid = strdup(optarg);
121 break;
122 case 's':
123 sleeptime = atoi(optarg);
124 if (sleeptime <= 0) {
125 fprintf(stderr, ERRORPREFIX "Invalid sleep time!\n");
126 exit(1);
128 break;
129 default:
130 fprintf(stderr, ERRORPREFIX "Invalid parameters, use --help for help.\n");
131 exit(1);
132 break;
136 if (optind < argc) {
137 fprintf(stderr, ERRORPREFIX "Invalid parameters, use --help for help.\n");
138 exit(1);
140 if (config == NULL) {
141 config = strdup(CONFIGFILE);
143 if (pid == NULL) {
144 pid = strdup(PIDFILE);
148 void load_config() {
149 FILE *file;
150 char *line = NULL;
151 size_t len = 0;
153 /* Open configuration */
154 file = fopen(config, "r");
155 if (file == NULL) {
156 fprintf(stderr, ERRORPREFIX "Failed to open configuration %s (%s)\n", config, strerror(errno));
157 exit(1);
160 /* Read config file lines */
161 while (getline(&line, &len, file) != -1) {
162 /* Ignore comments */
163 if (line[0] == '#') continue;
165 len = strlen(line);
167 /* Remove trailing \n */
168 if (len > 0 && line[len - 1] == '\n') {
169 len[line - 1] = 0;
170 len--;
173 /* Ignore empty lines */
174 if (len == 0) {
175 free(line);
176 line = NULL;
177 continue;
180 /* Okay, we seem to have valid line */
181 listlen++;
183 /* Do we need to reallocate list? */
184 if (listlen > alloclen) {
185 filelist = (char **)realloc(filelist, (listlen + 4 ) * sizeof(char *));
186 if (filelist == NULL) {
187 fprintf(stderr, "polld: not enough memory\n");
188 exit(2);
190 alloclen = listlen + 4;
193 /* Add to list */
194 filelist[listlen - 1] = line;
196 /* Zero to force getline to malloc this for us */
197 line = NULL;
198 len = 0;
201 /* Close config file */
202 fclose(file);
205 void check_lock(void) {
206 FILE *file;
207 int other;
209 if (strlen(pid) == 0) return;
211 /* Read existing pid */
212 file = fopen(pid, "r");
213 if (file != NULL) {
214 if (fscanf(file, "%d", &other) == 1) {
215 if (kill(other, 0) == 0) {
216 fprintf(stderr, ERRORPREFIX "Another instance is running, please stop it first!\n");
217 exit(1);
219 } else {
220 fprintf(stderr, ERRORPREFIX "Can not parse pidfile, ignoring!\n");
222 fclose(file);
227 void do_lock(void) {
228 FILE *file;
230 if (strlen(pid) == 0) return;
232 /* Write pid file */
233 file = fopen(pid, "w");
234 if (file != NULL) {
235 fprintf(file, "%d\n", getpid());
236 fclose(file);
237 } else {
238 fprintf(stderr, ERRORPREFIX "Can not create pidfile!\n");
239 exit(1);
243 void bye(void) {
244 /* Remove lock file */
245 if (strlen(pid) != 0) {
246 unlink(pid);
249 exit(0);
252 /* Signal handlers */
253 void interrupt(int sign)
255 signal(sign, SIG_IGN);
256 shutdown = 1;
257 bye();
260 void hup(int sign)
262 reload = 1;
266 int main(int argc, char **argv) {
267 int i;
268 int file;
270 /* Parse parameters is optionally config file name */
271 parse_params(argc, argv);
273 /* Load configuration */
274 load_config();
276 /* Check for locking while we have terminal */
277 check_lock();
279 /* Fake lock while we have terminal */
280 do_lock();
282 /* Disconnect terminal.. */
283 daemon(0, 0);
285 /* Real lock */
286 do_lock();
288 /* Trap signals */
289 signal(SIGINT, interrupt);
290 signal(SIGQUIT, interrupt);
291 signal(SIGTERM, interrupt);
292 signal(SIGHUP, hup);
294 /* Main loop */
295 while (!shutdown) {
296 sleep(sleeptime);
298 /* Should we reload? */
299 if (reload) {
300 for (i = 0; i < listlen; i++) {
301 free(filelist[i]);
304 free(filelist);
305 filelist = NULL;
306 listlen = 0;
307 alloclen = 0;
309 load_config();
312 /* Do the main work */
313 for (i = 0; i < listlen; i++) {
314 file = open(filelist[i], O_RDONLY);
315 if (file != -1) {
316 #if LINUX
317 ioctl(file, BLKRRPART);
318 #endif
319 close(file);
324 /* Cleanup */
325 bye();
327 /* Just to make gcc happy */
328 return 0;