root/lm-sensors/branches/lm-sensors-3.0.0/prog/sensord/sensord.c @ 4815

Revision 4815, 4.9 KB (checked in by khali, 6 years ago)

Fix a memory leak when daemonizing.

  • 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., 675 Mass Ave, Cambridge, MA 02139, USA.
21 */
22
23#include <stdio.h>
24#include <stdlib.h>
25#include <errno.h>
26#include <limits.h>
27#include <string.h>
28#include <signal.h>
29#include <syslog.h>
30#include <unistd.h>
31#include <time.h>
32#include <sys/types.h>
33#include <sys/stat.h>
34
35#include "sensord.h"
36
37static int logOpened = 0;
38
39static volatile sig_atomic_t done = 0;
40
41#define LOG_BUFFER 4096
42
43#include <stdarg.h>
44
45void
46sensorLog
47(int priority, const char *fmt, ...) {
48  static char buffer[1 + LOG_BUFFER];
49  va_list ap;
50  va_start (ap, fmt);
51  vsnprintf (buffer, LOG_BUFFER, fmt, ap);
52  buffer[LOG_BUFFER] = '\0';
53  va_end (ap);
54  if (debug || (priority < LOG_DEBUG)) {
55    if (logOpened) {
56      syslog (priority, "%s", buffer);
57    } else {
58      fprintf (stderr, "%s\n", buffer);
59      fflush (stderr);
60    }
61  }
62}
63
64static void
65signalHandler
66(int sig) {
67  signal (sig, signalHandler);
68  switch (sig) {
69    case SIGTERM:
70      done = 1;
71      break;
72  }
73}
74
75static int
76sensord
77(void) {
78  int ret = 0;
79  int scanValue = 0, logValue = 0;
80  /*
81   * First RRD update at next RRD timeslot to prevent failures due
82   * one timeslot updated twice on restart for example.
83   */
84  int rrdValue = rrdTime - time(NULL) % rrdTime;
85
86  sensorLog (LOG_INFO, "sensord started");
87
88  while (!done && (ret == 0)) {
89    if (ret == 0)
90      ret = reloadLib ();
91    if ((ret == 0) && scanTime) { /* should I scan on the read cycle? */
92      ret = scanChips ();
93      if (scanValue <= 0)
94        scanValue += scanTime;
95    }
96    if ((ret == 0) && logTime && (logValue <= 0)) {
97      ret = readChips ();
98      logValue += logTime;
99    }
100    if ((ret == 0) && rrdTime && rrdFile && (rrdValue <= 0)) {
101      ret = rrdUpdate ();
102      /*
103       * The amount of time to wait is computed using the same method as
104       * in RRD instead of simply adding the interval.
105       */
106      rrdValue = rrdTime - time(NULL) % rrdTime;
107    }
108    if (!done && (ret == 0)) {
109      int a = logTime ? logValue : INT_MAX;
110      int b = scanTime ? scanValue : INT_MAX;
111      int c = (rrdTime && rrdFile) ? rrdValue : INT_MAX;
112      int sleepTime = (a < b) ? ((a < c) ? a : c) : ((b < c) ? b : c);
113      sleep (sleepTime);
114      scanValue -= sleepTime;
115      logValue -= sleepTime;
116      rrdValue -= sleepTime;
117    }
118  }
119
120  sensorLog (LOG_INFO, "sensord %s", ret ? "failed" : "stopped");
121
122  return ret;
123}
124
125static void
126openLog
127(void) {
128  openlog ("sensord", 0, syslogFacility);
129  logOpened = 1; 
130}
131
132static void
133daemonize
134(void) {
135  int pid;
136  struct stat fileStat;
137  FILE *file;
138
139  if (chdir ("/") < 0) {
140    perror ("chdir()");
141    exit (EXIT_FAILURE);
142  }
143
144  if (!(stat (pidFile, &fileStat)) &&
145      ((!S_ISREG (fileStat.st_mode)) || (fileStat.st_size > 11))) {
146    fprintf (stderr, "Error: PID file `%s' already exists and looks suspicious.\n", pidFile);
147    exit (EXIT_FAILURE);
148  }
149 
150  if (!(file = fopen (pidFile, "w"))) {
151    fprintf (stderr, "fopen(\"%s\"): %s\n", pidFile, strerror (errno));
152    exit (EXIT_FAILURE);
153  }
154 
155  /* I should use sigaction but... */
156  if (signal (SIGTERM, signalHandler) == SIG_ERR) {
157    perror ("signal(SIGTERM)");
158    exit (EXIT_FAILURE);
159  }
160
161  if ((pid = fork ()) == -1) {
162    perror ("fork()");
163    exit (EXIT_FAILURE);
164  } else if (pid != 0) {
165    fprintf (file, "%d\n", pid);
166    fclose (file);
167    unloadLib ();
168    exit (EXIT_SUCCESS);
169  }
170
171  if (setsid () < 0) {
172    perror ("setsid()");
173    exit (EXIT_FAILURE);
174  }
175
176  fclose (file);
177  close (STDIN_FILENO);
178  close (STDOUT_FILENO);
179  close (STDERR_FILENO);
180}
181
182static void 
183undaemonize
184(void) {
185  unlink (pidFile);
186  closelog ();
187}
188
189int
190main
191(int argc, char **argv) {
192  int ret = 0;
193 
194  if (parseArgs (argc, argv) ||
195      parseChips (argc, argv))
196    exit (EXIT_FAILURE);
197 
198  if (initLib () ||
199      loadLib ())
200    exit (EXIT_FAILURE);
201
202  if (isDaemon)
203    openLog ();
204  if (rrdFile)
205    ret = rrdInit ();
206 
207  if (ret) {
208  } else if (doCGI) {
209    ret = rrdCGI ();
210  } else if (isDaemon) {
211    daemonize ();
212    ret = sensord ();
213    undaemonize ();
214  } else {
215    if (doSet)
216      ret = setChips ();
217    else if (doScan)
218      ret = scanChips ();
219    else if (rrdFile)
220      ret = rrdUpdate ();
221    else
222      ret = readChips ();
223  }
224 
225  if (unloadLib ())
226    exit (EXIT_FAILURE);
227 
228  return ret;
229}
Note: See TracBrowser for help on using the browser.