root/lm-sensors/trunk/prog/sensord/sensord.c

Revision 6025, 5.6 KB (checked in by khali, 3 months ago)

Fix memory leaks in sensord revealed by valgrind.

The leak in daemonize() is harmless, we're about to exit anyway. Fix
it still to make valgrind happy.

The leak in do_features() is real, as the function is called
periodically by the daemon, for all actions. If the intervals at set
low and the system has many sensors, the leak could be significant,
maybe 150 kB/day.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1/*
2 * sensord
3 *
4 * A daemon that periodically logs sensor information to syslog.
5 *
6 * Copyright (c) 1999-2002 Merlin Hughes <merlin@merlin.org>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
21 * MA 02110-1301 USA.
22 */
23
24#include <stdio.h>
25#include <stdlib.h>
26#include <errno.h>
27#include <limits.h>
28#include <string.h>
29#include <signal.h>
30#include <syslog.h>
31#include <unistd.h>
32#include <time.h>
33#include <sys/types.h>
34#include <sys/stat.h>
35
36#include "args.h"
37#include "sensord.h"
38
39static int logOpened = 0;
40
41static volatile sig_atomic_t done = 0;
42static volatile sig_atomic_t reload = 0;
43
44#define LOG_BUFFER 4096
45
46#include <stdarg.h>
47
48void sensorLog(int priority, const char *fmt, ...)
49{
50        static char buffer[1 + LOG_BUFFER];
51        va_list ap;
52        va_start(ap, fmt);
53        vsnprintf(buffer, LOG_BUFFER, fmt, ap);
54        buffer[LOG_BUFFER] = '\0';
55        va_end(ap);
56        if (sensord_args.debug || (priority < LOG_DEBUG)) {
57                if (logOpened) {
58                        syslog(priority, "%s", buffer);
59                } else {
60                        fprintf(stderr, "%s\n", buffer);
61                        fflush(stderr);
62                }
63        }
64}
65
66static void signalHandler(int sig)
67{
68        switch (sig) {
69        case SIGTERM:
70                done = 1;
71                break;
72        case SIGHUP:
73                reload = 1;
74                break;
75        }
76}
77
78static int sensord(void)
79{
80        int ret = 0;
81        int scanValue = 0, logValue = 0;
82        /*
83         * First RRD update at next RRD timeslot to prevent failures due
84         * one timeslot updated twice on restart for example.
85         */
86        int rrdValue = sensord_args.rrdTime - time(NULL) %
87                sensord_args.rrdTime;
88
89        sensorLog(LOG_INFO, "sensord started");
90
91        while (!done) {
92                if (reload) {
93                        ret = reloadLib(sensord_args.cfgFile);
94                        if (ret)
95                                sensorLog(LOG_NOTICE, "configuration reload"
96                                          " error");
97                        reload = 0;
98                }
99                if (sensord_args.scanTime && (scanValue <= 0)) {
100                        if ((ret = scanChips()))
101                                sensorLog(LOG_NOTICE,
102                                          "sensor scan error (%d)", ret);
103                        scanValue += sensord_args.scanTime;
104                }
105                if (sensord_args.logTime && (logValue <= 0)) {
106                        if ((ret = readChips()))
107                                sensorLog(LOG_NOTICE,
108                                          "sensor read error (%d)", ret);
109                        logValue += sensord_args.logTime;
110                }
111                if (sensord_args.rrdTime && sensord_args.rrdFile &&
112                    (rrdValue <= 0)) {
113                        if ((ret = rrdUpdate()))
114                                sensorLog(LOG_NOTICE,
115                                          "rrd update error (%d)", ret);
116                        /*
117                         * The amount of time to wait is computed using the
118                         * same method as in RRD instead of simply adding the
119                         * interval.
120                         */
121                        rrdValue = sensord_args.rrdTime - time(NULL) %
122                                sensord_args.rrdTime;
123                }
124                if (!done) {
125                        int a = sensord_args.logTime ? logValue : INT_MAX;
126                        int b = sensord_args.scanTime ? scanValue : INT_MAX;
127                        int c = (sensord_args.rrdTime && sensord_args.rrdFile)
128                                ? rrdValue : INT_MAX;
129                        int sleepTime = (a < b) ? ((a < c) ? a : c) :
130                                ((b < c) ? b : c);
131                        sleep(sleepTime);
132                        scanValue -= sleepTime;
133                        logValue -= sleepTime;
134                        rrdValue -= sleepTime;
135                }
136        }
137
138        sensorLog(LOG_INFO, "sensord stopped");
139
140        return ret;
141}
142
143static void openLog(void)
144{
145        openlog("sensord", 0, sensord_args.syslogFacility);
146        logOpened = 1;
147}
148
149static void install_sighandler(void)
150{
151        struct sigaction new;
152        int ret;
153
154        memset(&new, 0, sizeof(struct sigaction));
155        new.sa_handler = signalHandler;
156        sigemptyset(&new.sa_mask);
157        new.sa_flags = SA_RESTART;
158
159        ret = sigaction(SIGTERM, &new, NULL);
160        if (ret == -1) {
161                fprintf(stderr, "Could not set sighandler for SIGTERM: %s\n",
162                        strerror(errno));
163                exit(EXIT_FAILURE);
164        }
165
166        ret = sigaction(SIGHUP, &new, NULL);
167        if (ret == -1) {
168                fprintf(stderr, "Could not set sighandler for SIGHUP: %s\n",
169                        strerror(errno));
170                exit(EXIT_FAILURE);
171        }
172}
173
174static void daemonize(void)
175{
176        int pid;
177        struct stat fileStat;
178        FILE *file;
179
180        if (chdir("/") < 0) {
181                perror("chdir()");
182                exit(EXIT_FAILURE);
183        }
184
185        if (!(stat(sensord_args.pidFile, &fileStat)) &&
186            ((!S_ISREG(fileStat.st_mode)) || (fileStat.st_size > 11))) {
187                fprintf(stderr,
188                        "Error: PID file `%s' already exists and looks suspicious.\n",
189                        sensord_args.pidFile);
190                exit(EXIT_FAILURE);
191        }
192
193        if (!(file = fopen(sensord_args.pidFile, "w"))) {
194                fprintf(stderr, "fopen(\"%s\"): %s\n", sensord_args.pidFile,
195                        strerror(errno));
196                exit(EXIT_FAILURE);
197        }
198
199        install_sighandler();
200
201        if ((pid = fork()) == -1) {
202                perror("fork()");
203                exit(EXIT_FAILURE);
204        } else if (pid != 0) {
205                fprintf(file, "%d\n", pid);
206                fclose(file);
207
208                freeChips();
209                if (unloadLib())
210                        exit(EXIT_FAILURE);
211
212                exit(EXIT_SUCCESS);
213        }
214
215        if (setsid() < 0) {
216                perror("setsid()");
217                exit(EXIT_FAILURE);
218        }
219
220        fclose(file);
221        close(STDIN_FILENO);
222        close(STDOUT_FILENO);
223        close(STDERR_FILENO);
224}
225
226static void undaemonize(void)
227{
228        unlink(sensord_args.pidFile);
229        closelog();
230}
231
232int main(int argc, char **argv)
233{
234        int ret = 0;
235
236        if (parseArgs(argc, argv) ||
237            parseChips(argc, argv))
238                exit(EXIT_FAILURE);
239
240        if (loadLib(sensord_args.cfgFile)) {
241                freeChips();
242                exit(EXIT_FAILURE);
243        }
244
245        if (!sensord_args.doCGI)
246                openLog();
247
248        if (sensord_args.rrdFile) {
249                ret = rrdInit();
250                if (ret) {
251                        freeChips();
252                        exit(EXIT_FAILURE);
253                }
254        }
255
256        if (sensord_args.doCGI) {
257                ret = rrdCGI();
258        } else {
259                daemonize();
260                ret = sensord();
261                undaemonize();
262        }
263
264        freeChips();
265        if (unloadLib())
266                exit(EXIT_FAILURE);
267
268        return ret;
269}
Note: See TracBrowser for help on using the browser.