#include <stdlib.h>
#include <stdio.h>
#include <fcntl.h>
#include <signal.h>
#include <string.h>
#include <syslog.h>
#include <time.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/sysctl.h>
#define DAEMON_NAME "rrd_temp"
const char *pidfname = "/var/run/rrd_temp.pid";
FILE *outfile = NULL;
void usage(const char *executable)
{
const char *r = executable + strlen(executable);
while (--r >= executable && *r != '/');
r++;
printf("\nusage: %s [-p file] [-f] [-n] [-t] [-h]\n", r);
printf(" -p file the path to the pid file [default: /var/run/rrd_temp.pid]\n");
printf(" -f foreground mode, don't fork off as a daemon.\n");
printf(" -n no console, don't fork off as a daemon - started/managed by launchd.\n");
printf(" -t idle time in seconds, [default: 4 s].\n");
printf(" -h shows these usage instructions.\n\n");
}
static void signals(int sig)
{
switch (sig)
{
case SIGHUP:
syslog(LOG_ERR, "Received SIGHUP signal.");
kill(0, SIGHUP);
if (outfile) fclose(outfile);
unlink(pidfname);
exit(0);
break;
case SIGINT:
syslog(LOG_ERR, "Received SIGINT signal.");
kill(0, SIGINT);
if (outfile) fclose(outfile);
unlink(pidfname);
exit(0);
break;
case SIGQUIT:
syslog(LOG_ERR, "Received SIGQUIT signal.");
kill(0, SIGQUIT);
if (outfile) fclose(outfile);
unlink(pidfname);
exit(0);
break;
case SIGTERM:
syslog(LOG_ERR, "Received SIGTERM signal.");
kill(0, SIGTERM);
if (outfile) fclose(outfile);
unlink(pidfname);
exit(0);
break;
default:
syslog(LOG_ERR, "Unhandled signal (%d) %s", sig, strsignal(sig));
break;
}
}
typedef enum
{
noDaemon,
launchdDaemon,
discreteDaemon
} DaemonKind;
void daemonize(DaemonKind kind)
{
switch (kind)
{
case noDaemon:
openlog(DAEMON_NAME, LOG_NDELAY | LOG_PID | LOG_CONS, LOG_USER);
break;
case launchdDaemon:
signal(SIGTERM, signals);
openlog(DAEMON_NAME, LOG_NDELAY | LOG_PID, LOG_USER);
break;
case discreteDaemon:
{
// fork off the parent process
pid_t pid = fork();
if (pid < 0)
exit(EXIT_FAILURE);
// if we got a good PID, then we can exit the parent process.
if (pid > 0)
exit(EXIT_SUCCESS);
// The child process continues here.
// first close all open descriptors
for (int i = getdtablesize(); i >= 0; --i)
close(i);
// re-open stdin, stdout, stderr connected to /dev/null
int inouterr = open("/dev/null", O_RDWR); // stdin
dup(inouterr); // stdout
dup(inouterr); // stderr
// Change the file mode mask, 027 = complement of 750
umask(027);
pid_t sid = setsid();
if (sid < 0)
exit(EXIT_FAILURE); // should log the failure before exiting?
// Check and write our pid lock file
// and mutually exclude other instances from running
int pidfile = open(pidfname, O_RDWR|O_CREAT, 0640);
if (pidfile < 0)
exit(1); // can not open our pid file
if (lockf(pidfile, F_TLOCK, 0) < 0)
exit(0); // can not lock our pid file -- was locked already
// only first instance continues beyound this
char s[256];
int l = snprintf(s, 256, "%d\n", getpid());
write(pidfile, s, l); // record pid to our pid file
signal(SIGHUP, signals);
signal(SIGINT, signals);
signal(SIGQUIT, signals);
signal(SIGTERM, signals);
signal(SIGCHLD, SIG_IGN); // ignore child
signal(SIGTSTP, SIG_IGN); // ignore tty signals
signal(SIGTTOU, SIG_IGN);
signal(SIGTTIN, SIG_IGN);
openlog(DAEMON_NAME, LOG_NDELAY | LOG_PID, LOG_USER);
break;
}
}
}
int main(int argc, char *argv[])
{
char ch, *p;
int64_t idle = 4;
const char *cmd = argv[0];
DaemonKind dKind = discreteDaemon;
while ((ch = getopt(argc, argv, "p:fnt:h")) != -1)
{
switch (ch)
{
case 'p':
pidfname = optarg;
break;
case 'f':
dKind = noDaemon;
break;
case 'n':
dKind = launchdDaemon;
break;
case 't':
if ((idle = strtol(optarg, &p, 10)) <= 0)
{
usage(cmd);
exit(0);
}
break;
case 'h':
default:
usage(cmd);
exit(0);
break;
}
}
daemonize(dKind);
outfile = fopen("/tmp/rrd_temp.log", "w");
char isotime[20];
time_t stamp;
size_t size = sizeof(int);
int buf;
double tval;
for (;;)
{
sleep(idle);
stamp = time(NULL);
strftime(isotime, 20, "%Y-%m-%d %H:%M:%S", localtime(&stamp));
sysctlbyname("dev.cpu.0.temperature", &buf, &size, NULL, 0);
tval = (buf - 2731.5)*1.8e-1 + 32.0;
fprintf(outfile, "%s\t%.2f °F \n" , isotime, tval);
fflush(outfile);
}
}