第十三章 守护进程:
#include <syslog.h>
void openlog(const char * ident, int option, int facility);
void syslog(int priority, const char * format, ...);
void closelog(void);
int setlogmask(int maskpri);
return previous mask priority
option:
LOG_CONS, LOG_NDELAY, LOG_NOWAIT,
LOG_ODELAY, LOG_PERROR, LOG_PID
facility:
LOG_AUTH, LOG_AUTHPRIV, LOG_CRON, LOG_DAEMON,
LOG_FTP, LOG_KERN, LOG_LOCAL0, LOG_LOCAL1,
LOG_LOCAL2, LOG_LOCAL3, LOG_LOCAL4, LOG_LOCAL5,
LOG_LOCAL6, LOG_LOCAL7, LOG_LPR, LOG_MAIL,
LOG_NEWS, LOG_SYSLOG, LOG_USER, LOG_UUCP
level:
LOG_EMERG, LOG_ALERT, LOG_CRIT, LOG_ERR,
LOG_WARNING, LOG_NOTICE, LOG_INFO, LOG_DEBUG
priority:
facility | level
%m: ("%s", strerror(errno))
#include <syslog.h>
#include <stdarg.h>
void vsyslog(int priority, const char * format, va_list arg);
示例:
#ifndef __DAEMON_H__
#define __DAEMON_H__
#include <stdio.h>
#include <fcntl.h>
#include <stdlib.h>
#include <signal.h>
#include <syslog.h>
#include <sys/stat.h>
#include <sys/resource.h>
void
daemonize(const char * cmd)
{
int i;
int fd0;
int fd1;
int fd2;
pid_t pid;
struct rlimit rl;
struct sigaction sa;
/*
* clear file creation mask
*/
umask(0);
/*
* get maximum number of file descriptors
*/
if (getrlimit(RLIMIT_NOFILE, &rl) < 0) {
printf("%s: cannot get file limit\n", cmd);
exit(1);
}
/*
* become a session leader to lose controlling TTY
*/
if ((pid = fork()) < 0) {
printf("%s: cannot fork\n", cmd);
exit(1);
}
else if (pid > 0) {
exit(0);
}
setsid();
/*
* ensure future opens wonnot allocate controlling TTYs
*/
sa.sa_handler = SIG_IGN;
sigemptyset(&sa.sa_mask);
sa.sa_flags = 0;
if (sigaction(SIGHUP, &sa, NULL) < 0) {
printf("%s: cannot ignore SIGHUP\n", cmd);
exit(1);
}
if ((pid = fork()) < 0) {
printf("%s: cannot fork\n", cmd);
exit(1);
}
else if (pid > 0) {
exit(0);
}
/*
* change the current working directory to the root so
* we wonnot prevent file systems from being unmounted
*/
if (chdir("/") < 0) {
printf("%s: cannot change directory to /\n", cmd);
exit(1);
}
/*
* close all open file destriptors
*/
if (rl.rlim_max == RLIM_INFINITY) {
rl.rlim_max = 1024;
}
for (i = 0; i < rl.rlim_max; ++i) {
close(i);
}
/*
* attach file descriptors 0, 1, 2 to /dev/null
*/
fd0 = open("/dev/null", O_RDWR);
fd1 = dup(0);
fd2 = dup(0);
/*
* initialize the log file
*/
openlog(cmd, LOG_CONS, LOG_DAEMON);
if (fd0 != 0 || fd1 != 0 || fd2 != 0) {
syslog(LOG_ERR, "unexpected file descriptors %d %d %d",
fd0, fd1, fd2);
exit(1);
}
}
#endif
#ifndef __LOCKFILE_H__
#define __LOCKFILE_H__
#include <fcntl.h>
#include <unistd.h>
int
lockfile(int fd)
{
struct flock fl;
fl.l_type = F_WRLCK;
fl.l_start = 0;
fl.l_whence = SEEK_SET;
fl.l_len = 0;
return(fcntl(fd, F_SETLK, &fl));
}
#endif
#ifndef __SINGLE_H__
#define __SINGLE_H__
#include <stdio.h>
#include <fcntl.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <syslog.h>
#include <sys/stat.h>
#include "lockfile.h"
#define LOCKFILE "/var/run/mydaemon.pid"
#define LOCKMODE (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)
int
already_running(void)
{
int fd;
char buf[16];
if ((fd = open(LOCKFILE, O_RDWR | O_CREAT, LOCKMODE)) < 0) {
syslog(LOG_ERR, "cannot open %s: %s", LOCKFILE, strerror(errno));
exit(1);
}
if (lockfile(fd) < 0) {
if (errno == EACCES || errno == EAGAIN) {
close(fd);
return(1);
}
syslog(LOG_ERR, "cannot lock %s: %s", LOCKFILE, strerror(errno));
exit(1);
}
ftruncate(fd, 0);
sprintf(buf, "%ld", (long)getpid());
write(fd, buf, strlen(buf) + 1);
return(0);
}
#endif
#include <fcntl.h>
#include <unistd.h>
#include "daemon.h"
int
main(void)
{
FILE * fp;
char * p;
daemonize("getlog");
p = getlogin();
fp = fopen("/tmp/getlog.txt", "w");
if (fp != NULL) {
if (p == NULL) {
fprintf(fp, "no login name\n");
}
else {
fprintf(fp, "login name: %s\n", p);
}
}
exit(0);
}
#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include <syslog.h>
#include <pthread.h>
#include "daemon.h"
#include "single.h"
void
reread(void)
{
/* ... */
}
void
sig_term(int signo)
{
syslog(LOG_INFO, "got SIGTERM, exiting");
exit(0);
}
void
sig_hup(int signo)
{
syslog(LOG_INFO, "re-reading configuration file");
reread();
}
int
main(int argc, char * argv[])
{
char * cmd;
struct sigaction sa;
if ((cmd = strrchr(argv[0], '/')) == NULL) {
cmd = argv[0];
}
else {
++cmd;
}
/*
* become a daemon
*/
daemonize(cmd);
/*
* make sure only one copy of the daemon is running
*/
if (already_running()) {
syslog(LOG_ERR, "daemon already running");
exit(1);
}
/*
* handle signals of interest
*/
sa.sa_handler = sig_term;
sigemptyset(&sa.sa_mask);
sigaddset(&sa.sa_mask, SIGHUP);
sa.sa_flags = 0;
if (sigaction(SIGTERM, &sa, NULL) < 0) {
syslog(LOG_ERR, "cannot catch SIGTERM: %s", strerror(errno));
exit(1);
}
sa.sa_handler = sig_hup;
sigemptyset(&sa.sa_mask);
sigaddset(&sa.sa_mask, SIGTERM);
sa.sa_flags = 0;
if (sigaction(SIGHUP, &sa, NULL) < 0) {
syslog(LOG_ERR, "cannot catch SIGHUP: %s", strerror(errno));
exit(1);
}
/*
* proceed with the rest of the daemon
*/
/* ... */
exit(0);
}
#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include <syslog.h>
#include <pthread.h>
#include "daemon.h"
#include "single.h"
sigset_t mask;
void
reread(void)
{
/* ... */
}
void *
thr_fn(void * arg)
{
int err;
int signo;
for (;;) {
if ((err = sigwait(&mask, &signo)) != 0) {
syslog(LOG_ERR, "sigwait failded");
exit(1);
}
switch (signo) {
case SIGHUP:
{
syslog(LOG_INFO, "re-reading configuration file");
reread();
break;
}
case SIGTERM:
{
syslog(LOG_INFO, "got SIGTERM, exiting");
exit(0);
}
default:
{
syslog(LOG_INFO, "unexpected signal %d\n", signo);
break;
}
}
}
return(NULL);
}
int
main(int argc, char * argv[])
{
int err;
char * cmd;
pthread_t tid;
struct sigaction sa;
if ((cmd = strrchr(argv[0], '/')) == NULL) {
cmd = argv[0];
}
else {
++cmd;
}
/*
* become a daemon
*/
daemonize(cmd);
/*
* make sure only one copy of the daemon is running
*/
if (already_running()) {
syslog(LOG_ERR, "daemon already running");
exit(1);
}
/*
* restore SIGHUP default and block all signals
*/
sa.sa_handler = SIG_DFL;
sigemptyset(&sa.sa_mask);
sa.sa_flags = 0;
if (sigaction(SIGHUP, &sa, NULL) < 0) {
printf("%s: cannot restore SIGHUP default\n", strerror(errno));
exit(1);
}
sigfillset(&mask);
if ((err = pthread_sigmask(SIG_BLOCK, &mask, NULL)) != 0) {
printf("%s: SIG_BLOCK error\n", strerror(errno));
exit(1);
}
/*
* create a thread to handle SIGHUP and SIGTERM
*/
if ((err = pthread_create(&tid, NULL, thr_fn, NULL)) != 0) {
printf("%s: cannot create thread\n", strerror(errno));
exit(1);
}
/*
* proceed with the rest of the daemon
*/
/* ... */
exit(0);
}