1 |
torben |
328 |
/*************************************************************************** |
2 |
|
|
* Copyright (C) 2006 by Torben H. Nielsen * |
3 |
|
|
* torben@t-hoerup.dk * |
4 |
|
|
* * |
5 |
|
|
* This program is free software; you can redistribute it and/or modify * |
6 |
|
|
* it under the terms of the GNU General Public License as published by * |
7 |
|
|
* the Free Software Foundation; either version 2 of the License, or * |
8 |
|
|
* (at your option) any later version. * |
9 |
|
|
* * |
10 |
|
|
* This program is distributed in the hope that it will be useful, * |
11 |
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of * |
12 |
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * |
13 |
|
|
* GNU General Public License for more details. * |
14 |
|
|
* * |
15 |
|
|
* You should have received a copy of the GNU General Public License * |
16 |
|
|
* along with this program; if not, write to the * |
17 |
|
|
* Free Software Foundation, Inc., * |
18 |
|
|
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * |
19 |
|
|
***************************************************************************/ |
20 |
|
|
|
21 |
|
|
/* daemon.[hc] indeholder alle daemon relaterede functioner incl. |
22 |
|
|
* getConfig(); |
23 |
|
|
* daemonize(); |
24 |
|
|
* writelog(); |
25 |
|
|
*/ |
26 |
|
|
|
27 |
|
|
#include <stdlib.h> |
28 |
|
|
#include <stdio.h> |
29 |
|
|
#include <fcntl.h> |
30 |
|
|
#include <signal.h> |
31 |
|
|
#include <unistd.h> |
32 |
|
|
#include <string.h> |
33 |
|
|
#include <time.h> |
34 |
|
|
#include <sys/types.h> |
35 |
|
|
#include <sys/stat.h> |
36 |
|
|
|
37 |
|
|
#include "daemon.h" |
38 |
|
|
|
39 |
|
|
|
40 |
|
|
static const char *months[] = { |
41 |
|
|
"Jan","Feb","Mar","Apr","May","Jun", |
42 |
|
|
"Jul","Aug","Sep","Oct","Nov","Dec" |
43 |
|
|
}; |
44 |
|
|
|
45 |
|
|
// write message to the logfile |
46 |
|
|
void log_message(char *message) |
47 |
|
|
{ |
48 |
|
|
FILE *logfile; |
49 |
|
|
char buf[30]; |
50 |
|
|
long n = time(NULL); |
51 |
|
|
struct tm *now; |
52 |
|
|
now = localtime(&n); |
53 |
|
|
|
54 |
|
|
sprintf(buf, "%02d:%02d:%02d %s %02d %02d", |
55 |
|
|
now->tm_hour, now->tm_min, now->tm_sec,months[now->tm_mon], |
56 |
|
|
now->tm_mday,now->tm_year % 100); |
57 |
|
|
|
58 |
|
|
if (CONFIG->debug) { |
59 |
|
|
printf("%s: %s\n", buf, message); |
60 |
|
|
fflush(stdout); |
61 |
|
|
} else { |
62 |
|
|
logfile = fopen(CONFIG->logfile, "a"); |
63 |
|
|
if (!logfile) |
64 |
|
|
return; |
65 |
|
|
fprintf(logfile, "%s: %s\n", buf, message); |
66 |
|
|
fclose(logfile); |
67 |
|
|
} |
68 |
|
|
} |
69 |
|
|
|
70 |
|
|
|
71 |
|
|
void signal_handler(int sig) |
72 |
|
|
{ |
73 |
|
|
switch(sig) { |
74 |
|
|
case SIGHUP: |
75 |
|
|
log_message("hangup signal catched"); |
76 |
|
|
break; |
77 |
|
|
case SIGTERM: |
78 |
|
|
log_message("terminate signal catched...exiting"); |
79 |
|
|
unlink(CONFIG->lock); |
80 |
|
|
daemon_shutdown(0); |
81 |
|
|
break; |
82 |
|
|
} |
83 |
|
|
} |
84 |
|
|
|
85 |
|
|
|
86 |
|
|
void daemonize() |
87 |
|
|
{ |
88 |
|
|
int i, lfp; |
89 |
|
|
char str[10]; |
90 |
|
|
|
91 |
|
|
if (getppid() == 1) /* already a daemon */ |
92 |
|
|
return; |
93 |
|
|
|
94 |
|
|
i=fork(); |
95 |
|
|
|
96 |
|
|
if (i<0) /* fork error */ |
97 |
|
|
daemon_shutdown(FORK_ERROR); |
98 |
|
|
if (i>0) /* parent exits */ |
99 |
|
|
daemon_shutdown(0); |
100 |
|
|
/* child daemon continues */ |
101 |
|
|
|
102 |
|
|
setsid(); /* obtain a new process group */ |
103 |
|
|
|
104 |
|
|
for (i=getdtablesize(); i>=0; --i) |
105 |
|
|
close(i); /*close all descriptors*/ |
106 |
|
|
|
107 |
|
|
i=open("/dev/null", O_RDWR); /* handle std. io */ |
108 |
|
|
dup(i); |
109 |
|
|
dup(i); |
110 |
|
|
|
111 |
|
|
umask(027); /* set newly created file permissions */ |
112 |
|
|
|
113 |
|
|
chdir(CONFIG->rundir); /* change running directory*/ |
114 |
|
|
|
115 |
|
|
//attempt to create lockfile and put a file-lock on it |
116 |
|
|
lfp=open(CONFIG->lock, O_RDWR|O_CREAT, 0640); |
117 |
|
|
if (lfp<0) /* can not open */ |
118 |
|
|
daemon_shutdown(CANT_OPEN_LOCK); |
119 |
|
|
if (lockf(lfp,F_TLOCK,0) < 0) /* can not lock */ |
120 |
|
|
daemon_shutdown(ALREADY_LOCKED); |
121 |
|
|
|
122 |
|
|
/* first instance continues */ |
123 |
|
|
sprintf(str, "%d\n", getpid() ); /* record pid to lockfile */ |
124 |
|
|
write(lfp, str, strlen(str) ); |
125 |
|
|
signal(SIGCHLD, SIG_IGN); /* ignore child */ |
126 |
|
|
signal(SIGTSTP, SIG_IGN); /* ignore tty signals */ |
127 |
|
|
signal(SIGTTOU, SIG_IGN); |
128 |
|
|
signal(SIGTTIN, SIG_IGN); |
129 |
|
|
signal(SIGHUP, signal_handler); /* catch hangup signal */ |
130 |
|
|
signal(SIGTERM, signal_handler); /* catch kill signal */ |
131 |
|
|
log_message("downloadd started ..."); |
132 |
|
|
} |
133 |
|
|
|
134 |
|
|
|
135 |
|
|
void read_config_file(char *configfile) { |
136 |
|
|
char buf[120]; |
137 |
|
|
FILE *input = 0; |
138 |
|
|
int pos; |
139 |
|
|
char *cptr; |
140 |
|
|
|
141 |
|
|
// first populate config with default values |
142 |
|
|
strcpy(CONFIG->logfile, "/tmp/downloadd.log"); |
143 |
|
|
strcpy(CONFIG->lock, "/tmp/downloadd.lock"); |
144 |
|
|
strcpy(CONFIG->rundir, "/tmp"); |
145 |
|
|
|
146 |
|
|
strcpy(CONFIG->dbuser, "myuser"); |
147 |
|
|
strcpy(CONFIG->dbpass, "mypass"); |
148 |
|
|
strcpy(CONFIG->dbhost, "localhost"); |
149 |
|
|
strcpy(CONFIG->dbname, "downloadd"); |
150 |
|
|
CONFIG->dbport = 3306; |
151 |
|
|
|
152 |
|
|
// first try to open the file |
153 |
|
|
if (configfile && strlen(configfile) >0) { |
154 |
|
|
input = fopen(configfile, "r"); |
155 |
|
|
|
156 |
|
|
if (input) { |
157 |
|
|
while (!feof(input)) { |
158 |
|
|
fgets(buf, 120, input); |
159 |
|
|
|
160 |
|
|
pos = strlen(buf); |
161 |
|
|
if (strlen(buf)>0 && buf[pos-1] == '\n') |
162 |
|
|
buf[pos-1] = 0; //ignore trailing newline |
163 |
|
|
|
164 |
|
|
if (strlen(buf)==0 || buf[0] == '#' || buf[0] == ';') |
165 |
|
|
continue; |
166 |
|
|
cptr = strchr(buf, ' '); |
167 |
|
|
cptr++; |
168 |
|
|
if(strncmp(buf,"logfile ",8)==0) { |
169 |
|
|
strcpy(CONFIG->logfile, cptr); |
170 |
|
|
} else if (strncmp(buf,"lock ",5)==0) { |
171 |
|
|
strcpy(CONFIG->lock, cptr); |
172 |
|
|
} else if (strncmp(buf, "rundir ",7)==0) { |
173 |
|
|
strcpy(CONFIG->rundir, cptr); |
174 |
|
|
} else if (strncmp(buf, "dbuser ",7)==0) { |
175 |
|
|
strcpy(CONFIG->dbuser,cptr); |
176 |
|
|
} else if (strncmp(buf, "dbpass ",7)==0) { |
177 |
|
|
strcpy(CONFIG->dbpass,cptr); |
178 |
|
|
} else if (strncmp(buf, "dbhost ",7)==0) { |
179 |
|
|
strcpy(CONFIG->dbhost,cptr); |
180 |
|
|
} else if (strncmp(buf, "dbname ",7)==0) { |
181 |
|
|
strcpy(CONFIG->dbname,cptr); |
182 |
|
|
} else if (strncmp(buf, "dbport ",7)==0) { |
183 |
|
|
CONFIG->dbport = atoi(cptr); |
184 |
|
|
} else { |
185 |
|
|
printf("unknown config directive: %s\n", buf); |
186 |
|
|
fflush(stdout); |
187 |
|
|
} |
188 |
|
|
//make the buffer look empty |
189 |
|
|
buf[0] = 0; |
190 |
|
|
} |
191 |
|
|
} else { |
192 |
|
|
sprintf(buf,"Could not open config file %s, using default values.", configfile); |
193 |
|
|
log_message(buf); |
194 |
|
|
} |
195 |
|
|
} else { |
196 |
|
|
log_message( "No config file specified. Using default values."); |
197 |
|
|
} |
198 |
|
|
|
199 |
|
|
//at the end we should at least validate lock, logfile & rundir |
200 |
|
|
} |
201 |
|
|
|
202 |
|
|
void daemon_shutdown(int errorlevel) { |
203 |
|
|
log_message("Shutting down..."); |
204 |
|
|
exit(errorlevel); |
205 |
|
|
} |