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