1 /*
2 ** SSYNCD: Simple minded filesystem sync daemon
3 ** Copyright (C) 2002 Michael W. Shaffer <mwshaffer@angrypot.com>
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 (see the file COPYING). If not, write to:
17 **
18 ** The Free Software Foundation, Inc.
19 ** 59 Temple Place, Suite 330,
20 ** Boston, MA 02111-1307 USA
21 */
22
23 #include <unistd.h>
24 #include <sys/types.h>
25 #include <sys/stat.h>
26 #include <sys/wait.h>
27 #include <sys/time.h>
28 #include <sys/resource.h>
29 #include <fcntl.h>
30 #include <dirent.h>
31 #include <utime.h>
32 #include <errno.h>
33 #include <signal.h>
34 #include <stdlib.h>
35 #include <stdio.h>
36 #include <string.h>
37 #include <time.h>
38 #include "conf.h"
39 #include "list.h"
40 #include "hash.h"
41 #include "log.h"
42 #include "ssync.h"
43
44 char *conf_path_default = "/usr/local/etc/ssyncd.conf";
45
create_pidfile(void)46 static void create_pidfile (void)
47 {
48 int fd = -1;
49 char msg[256];
50 char *path = NULL;
51
52 path = get_config_string ("pid-path");
53 if (path) {
54 fd = open (path, O_CREAT|O_EXCL|O_WRONLY|O_TRUNC, 0644);
55 if (fd > -1) {
56 memset (msg, 0, sizeof (msg));
57 snprintf (msg, (sizeof (msg) - 1),
58 "%d\n", getpid ());
59 write (fd, msg, strlen (msg));
60 close (fd);
61 } else {
62 memset (msg, 0, sizeof (msg));
63 snprintf (msg, (sizeof (msg) - 1),
64 "exiting due to existing pid file: %s", path);
65 LOG (fatal, msg);
66 log_free ();
67 config_free ();
68 exit (0);
69 }
70 }
71
72 return;
73 }
74
remove_pidfile(void)75 static void remove_pidfile (void)
76 {
77 unlink (get_config_string ("pid-path"));
78 return;
79 }
80
main_loop(void)81 static void main_loop (void)
82 {
83 int i = 0;
84 struct stat s;
85 struct stat d;
86 char *src = NULL;
87 char *dst = NULL;
88 struct datum *da = NULL;
89 struct list_item *curr = NULL;
90 unsigned long interval = 0;
91 unsigned long count = 0;
92 unsigned long stime = 0;
93 unsigned long etime = 0;
94 unsigned long dtime = 0;
95 char bytes[256];
96 char msg[256];
97
98 if ((interval = get_config_long ("interval")) < 1)
99 interval = 30;
100
101 while (1) {
102 count = 0;
103 LOG (info, "begin run");
104
105 memset (&stats, 0, sizeof (struct stats));
106
107 hash_table_free (&dups);
108 memset (&dups, 0, sizeof (struct hash_table));
109 dups.size = 2000;
110 hash_table_init (&dups);
111
112 stime = time(NULL);
113 for (i = 0 ; i < work.size ; i++) {
114 for (curr = work.tbl[i].head ; curr ; curr = curr->next) {
115 da = (struct datum *) curr->data;
116 if (da) {
117 src = (char *) da->key;
118 dst = (char *) da->val;
119
120 memset (&s, 0, sizeof (struct stat));
121 memset (&d, 0, sizeof (struct stat));
122
123 lstat (src, &s);
124 lstat (dst, &d);
125
126 memset (msg, 0, sizeof (msg));
127 snprintf (msg, (sizeof (msg) - 1),
128 "processing work item: %s --> %s",
129 src, dst);
130 LOG (info, msg);
131
132 process (src, &s, dst, &d);
133 count++;
134 }
135 }
136 }
137 etime = time (NULL);
138
139 memset (msg, 0, sizeof (msg));
140 snprintf (msg, (sizeof (msg) - 1),
141 "end run: %ld work items processed",
142 count);
143 LOG (info, msg);
144
145 dtime = etime - stime;
146 memset (bytes, 0, sizeof (bytes));
147 get_bytes (bytes, (sizeof (bytes) - 1));
148 memset (msg, 0, sizeof (msg));
149 snprintf (msg, (sizeof (msg) - 1),
150 "statistics: time: %02ld:%02ld:%02ld "
151 "dirs: %ld files: %ld links: %ld "
152 "updated: %ldd/%ldf/%ldl (%s) "
153 "deleted: %ld",
154 (dtime / 3600), ((dtime % 3600) / 60), ((dtime % 3600) % 60),
155 stats.dirs, stats.files, stats.links,
156 stats.dirs_updated, stats.regs_updated, stats.lnks_updated, bytes,
157 stats.deleted);
158 LOG (info, msg);
159
160 memset (msg, 0, sizeof (msg));
161 snprintf (msg, (sizeof (msg) - 1),
162 "exceptions: unknowns: %ld errors: %ld",
163 stats.unknowns, stats.errors);
164 LOG (info, msg);
165
166 memset (msg, 0, sizeof (msg));
167 snprintf (msg, (sizeof (msg) - 1),
168 "sleeping for %ld seconds...",
169 interval);
170 LOG (info, msg);
171
172 sleep (interval);
173 }
174
175 return;
176 }
177
signal_handler(int sig)178 static void signal_handler (int sig)
179 {
180 switch (sig) {
181 case SIGHUP:
182 log_free ();
183 log_init ();
184 break;
185 case SIGINT:
186 case SIGTERM:
187 ssync_shutdown ();
188 remove_pidfile ();
189 log_free ();
190 config_free ();
191 exit (0);
192 break;
193 default:
194 break;
195 }
196
197 return;
198 }
199
daemonize(void)200 static void daemonize (void)
201 {
202 int i = 0;
203 int pid = 0;
204 int num_fds = 0;
205 char msg[256];
206
207 pid = fork ();
208 switch (pid) {
209 case -1:
210 memset (msg, 0, sizeof (msg));
211 snprintf (msg, (sizeof (msg) - 1),
212 "parent fork failed: %s\n",
213 strerror (errno));
214 write (2, msg, strlen (msg));
215 exit (-1);
216 break;
217 case 0:
218 setsid ();
219 break;
220 default:
221 _exit (0);
222 break;
223 }
224
225 pid = fork ();
226 switch (pid) {
227 case -1:
228 memset (msg, 0, sizeof (msg));
229 snprintf (msg, (sizeof (msg) - 1),
230 "child fork failed: %s\n",
231 strerror (errno));
232 write (2, msg, strlen (msg));
233 exit (-1);
234 break;
235 case 0:
236 if (chdir ("/")) {
237 memset (msg, 0, sizeof (msg));
238 snprintf (msg, (sizeof (msg) - 1),
239 "chdir '/' failed: %s\n",
240 strerror (errno));
241 write (2, msg, strlen (msg));
242 exit (-1);
243 }
244
245 umask (022);
246
247 num_fds = (int) sysconf (_SC_OPEN_MAX);
248 for (i = 0 ; i < num_fds ; i++) {
249 close (i);
250 }
251
252 if (open ("/dev/null", O_RDWR) == -1)
253 exit (-1);
254 if (open ("/dev/null", O_RDWR) == -1)
255 exit (-1);
256 if (open ("/dev/null", O_RDWR) == -1)
257 exit (-1);
258
259 break;
260 default:
261 _exit (0);
262 break;
263 }
264
265 return;
266 }
267
main(int argc,char ** argv)268 int main (int argc, char **argv)
269 {
270 int pri = 0;
271 char *cfg = NULL;
272 int f_no_detach = 0;
273
274 signal (SIGINT, signal_handler);
275 signal (SIGTERM, signal_handler);
276 signal (SIGHUP, signal_handler);
277
278 config_load (argc, argv);
279
280 if ((cfg = get_config_string ("no-detach")) &&
281 ((cfg[0] == 'y') || (cfg[0] == 'Y'))) {
282 f_no_detach++;
283 }
284
285 if (!f_no_detach) {
286 daemonize ();
287 }
288
289 log_init ();
290
291 pri = (int) get_config_long ("priority");
292 if (pri > 20)
293 pri = 20;
294 if (pri < -20)
295 pri = -20;
296 setpriority (PRIO_PROCESS, 0, pri);
297
298 create_pidfile ();
299 if (ssync_startup (argc, argv) == -1)
300 exit (-1);
301 main_loop ();
302 ssync_shutdown ();
303 remove_pidfile ();
304
305 log_free ();
306 config_free ();
307
308 return 0;
309 }
310
311