]> git.itanic.dy.fi Git - rrdd/blob - main.c
onewire_parser.c: Fix compiler warnings about string lengths
[rrdd] / main.c
1 #include <sys/types.h>
2 #include <sys/stat.h>
3 #include <fcntl.h>
4 #include <unistd.h>
5 #include <getopt.h>
6 #include <time.h>
7
8 #include "version.h"
9 #include "process.h"
10 #include "rrdtool.h"
11 #include "parser.h"
12 #include "debug.h"
13
14 #include "config.h"
15 #include "built_in_parsers.h"
16
17 #include "plugin_manager.h"
18
19 struct user_options {
20         int max_jobs;
21         int daemonize;
22         char *config_file;
23         char *pid_file;
24 };
25
26 int read_args(int argc, char *argv[], struct user_options *opts)
27 {
28         int option_index = 0, c;
29         static struct option long_options[] = {
30                 { .val = 'j', .has_arg = 1, .name = "jobs", },
31                 { .val = 'c', .has_arg = 1, .name = "config", },
32                 { .val = 'l', .has_arg = 1, .name = "log-file", },
33                 { .val = 'p', .has_arg = 1, .name = "pid-file", },
34                 { .val = 'd', .name = "daemon", },
35                 { .val = 'v', .name = "verbose", },
36                 { .val = 'q', .name = "quiet", },
37                 { },
38         };
39         char short_options[] = "j:c:l:p:dvq";
40
41         while (1) {
42                 c = getopt_long(argc, argv, short_options, long_options,
43                                 &option_index);
44
45                 if (c == -1)
46                         break;
47
48                 switch (c) {
49                 case 'j':
50                         opts->max_jobs = atoi(optarg);
51                         break;
52
53                 case 'c':
54                         opts->config_file = optarg;
55                         break;
56
57                 case 'l':
58                         open_log_file(optarg);
59                         break;
60
61                 case 'v':
62                         trace_level++;
63                         break;
64
65                 case 'q':
66                         trace_level--;
67                         break;
68
69                 case 'd':
70                         opts->daemonize = 1;
71                         break;
72
73                 case 'p':
74                         opts->pid_file = optarg;
75                         break;
76
77                 case '?':
78                         return -1;
79                 }
80         }
81
82         while (optind < argc) {
83                 opts->config_file = argv[optind];
84                 optind++;
85         }
86
87         return 0;
88 }
89
90 static int is_already_running(const char *pidfile)
91 {
92         struct stat s;
93         char pidstr[16], procpath[256] = { 0 };
94         int fd, ret, pid;
95
96         fd = open(pidfile, O_RDONLY);
97         if (fd < 0) {
98                 /* No pid, no running instance */
99                 return 0;
100         }
101
102         ret = read(fd, pidstr, sizeof(pidstr) - 1);
103         if (ret < 0) {
104                 pr_err("Failed to read pid file: %m\n");
105                 close(fd);
106
107                 return ret;
108         }
109         close(fd);
110
111         pidstr[ret] = 0;
112
113         ret = sscanf(pidstr, "%d", &pid);
114
115         /* Corrupted pid data? Maybe leftover from prev boot or something */
116         if (ret != 1)
117                 return 0;
118
119         snprintf(procpath, sizeof(procpath) - 1, "/proc/%d/", pid);
120
121         ret = stat(procpath, &s);
122
123         if (ret < 0) {
124                 pr_info("Ignoring stale pid %d from pid file %s\n",
125                         pid, pidfile);
126
127                 return 0;
128         }
129
130         pr_err("Process %d is already running as stated in pid file %s\n",
131                 pid, pidfile);
132
133         return 1;
134 }
135
136 static int write_pidfile(const char *pidfile)
137 {
138         char pidstr[16];
139         int fd, ret;
140
141         fd = open(pidfile, O_WRONLY | O_CREAT, 0644);
142         if (fd < 0) {
143                 pr_err("Failed to open pidfile %s for writing: %m\n", pidfile);
144                 return -1;
145         }
146
147         ret = snprintf(pidstr, sizeof(pidstr), "%d", getpid());
148         ret = write(fd, pidstr, ret);
149         if (ret < 0)
150                 pr_err("Failed to write to pidfile %s: %m\n", pidfile);
151
152         close(fd);
153
154         return ret;
155 }
156
157 int main(int argc, char *argv[])
158 {
159         struct user_options opts;
160         struct rrd_database *db, **db_list = NULL;
161         int sleeptime;
162         int ret = 0;
163
164         pr_info("%s Version %s starting\n", argv[0], RRDD_VERSION);
165
166         bzero(&opts, sizeof(opts));
167
168         if (read_args(argc, argv, &opts) < 0)
169                 return -1;
170
171         if (opts.daemonize) {
172                 pr_info("Setting itself as a daemon\n");
173                 ret = daemon(1, 0);
174                 if (ret < 0) {
175                         pr_err("Failed to daemonize: %m\n");
176                         return -1;
177                 }
178         }
179
180         if (opts.pid_file) {
181                 if (is_already_running(opts.pid_file))
182                         return -1;
183
184                 if (write_pidfile(opts.pid_file) < 0)
185                         return -1;
186         }
187
188         init_plugin_manager(argv[0]);
189         register_built_in_parsers();
190         register_network_parser();
191
192         if (!opts.config_file) {
193                 pr_err("No database config file given. Nothing to do\n");
194                 return 1;
195         }
196
197         db_list = populate_database(opts.config_file);
198
199         if (ret || !db_list)
200                 return 1;
201
202         if (rrdtool_create_missing_databases(db_list))
203                 return 1;
204
205         if (init_jobcontrol(opts.max_jobs))
206                 return -1;
207
208         while (1) {
209                 const char *db_name;
210                 char timestr[128];
211                 time_t t;
212
213                 /*
214                  * Update all databases parallel in one shot
215                  */
216                 while ((db = get_outdated_db(db_list)))
217                         rrdtool_update_data(db);
218
219                 sleeptime = get_next_update(db_list, &db_name);
220
221                 if (sleeptime >=  0) {
222                         t = time(0) + sleeptime;
223                         strftime(timestr, sizeof(timestr), "%T", localtime(&t));
224                         pr_info("Next scheduled event \"%s\" at %s, in %d seconds\n",
225                                 db_name, timestr, sleeptime);
226                 } else
227                         pr_info("All jobs active, sleeping until event arrives\n");
228
229                 poll_job_requests(sleeptime);
230         }
231         return 0;
232 }