1 /*-
2  * Copyright (c) 2000-2005 MAEKAWA Masahide <maekawa@cvsync.org>
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  * 3. Neither the name of the author nor the names of its contributors
14  *    may be used to endorse or promote products derived from this software
15  *    without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  */
29 
30 #include <sys/types.h>
31 #include <sys/mman.h>
32 #include <sys/stat.h>
33 
34 #include <stdlib.h>
35 
36 #include <errno.h>
37 #include <fcntl.h>
38 #include <limits.h>
39 #include <signal.h>
40 #include <string.h>
41 #include <strings.h>
42 #include <unistd.h>
43 
44 #include "compat_stdbool.h"
45 #include "compat_stdint.h"
46 #include "compat_inttypes.h"
47 #include "compat_limits.h"
48 #include "compat_strings.h"
49 
50 #include "cvsync.h"
51 #include "logmsg.h"
52 
53 struct cvsync_token_type {
54 	const char	*name;
55 	int		type;
56 };
57 
58 static const struct cvsync_token_type cvsync_compress_types[] = {
59 	{ "none",	CVSYNC_COMPRESS_NO },
60 	{ "zlib",	CVSYNC_COMPRESS_ZLIB },
61 	{ NULL,		CVSYNC_COMPRESS_UNSPEC },
62 };
63 
64 static const struct cvsync_token_type cvsync_list_types[] = {
65 	{ "all",	CVSYNC_LIST_ALL },
66 	{ "rcs",	CVSYNC_LIST_RCS },
67 	{ NULL,		CVSYNC_LIST_UNKNOWN },
68 };
69 
70 static const struct cvsync_token_type cvsync_release_types[] = {
71 	{ "list",	CVSYNC_RELEASE_LIST },
72 	{ "rcs",	CVSYNC_RELEASE_RCS },
73 	{ NULL,		CVSYNC_RELEASE_UNKNOWN },
74 };
75 
76 bool __cvsync_isinterrupted(void);
77 bool __cvsync_isterminated(void);
78 
79 static struct sigaction cvsync_sig_ign;
80 static bool cvsync_process_interrupted = false;
81 static bool cvsync_process_terminated = false;
82 
83 bool
cvsync_init(void)84 cvsync_init(void)
85 {
86 	struct sigaction act;
87 
88 	cvsync_sig_ign.sa_handler = cvsync_signal;
89 	if (sigemptyset(&cvsync_sig_ign.sa_mask) == -1) {
90 		logmsg_err("sigemptyset: %s", strerror(errno));
91 		return (false);
92 	}
93 	cvsync_sig_ign.sa_flags = 0;
94 
95 	if (sigaction(SIGHUP, &cvsync_sig_ign, NULL) == -1) {
96 		logmsg_err("sigaction: %s", strerror(errno));
97 		return (false);
98 	}
99 	if (sigaction(SIGPIPE, &cvsync_sig_ign, NULL) == -1) {
100 		logmsg_err("sigaction: %s", strerror(errno));
101 		return (false);
102 	}
103 
104 	if (sigaction(SIGINT, NULL, &act) == -1) {
105 		logmsg_err("sigaction: %s", strerror(errno));
106 		return (false);
107 	}
108 	act.sa_handler = cvsync_signal;
109 	act.sa_flags &= ~SA_RESTART;
110 	if (sigaction(SIGINT, &act, NULL) == -1) {
111 		logmsg_err("sigaction: %s", strerror(errno));
112 		return (false);
113 	}
114 
115 	if (sigaction(SIGTERM, NULL, &act) == -1) {
116 		logmsg_err("sigaction: %s", strerror(errno));
117 		return (false);
118 	}
119 	act.sa_handler = cvsync_signal;
120 	act.sa_flags &= ~SA_RESTART;
121 	if (sigaction(SIGTERM, &act, NULL) == -1) {
122 		logmsg_err("sigaction: %s", strerror(errno));
123 		return (false);
124 	}
125 
126 	return (true);
127 }
128 
129 int
cvsync_compress_pton(const char * name)130 cvsync_compress_pton(const char *name)
131 {
132 	const struct cvsync_token_type *t;
133 
134 	for (t = cvsync_compress_types ; t->name != NULL ; t++) {
135 		if (strcasecmp(t->name, name) == 0)
136 			return (t->type);
137 	}
138 
139 	return (CVSYNC_COMPRESS_UNSPEC);
140 }
141 
142 const char *
cvsync_compress_ntop(int type)143 cvsync_compress_ntop(int type)
144 {
145 	const struct cvsync_token_type *t;
146 
147 	for (t = cvsync_compress_types ; t->name != NULL ; t++) {
148 		if (t->type == type)
149 			return (t->name);
150 	}
151 
152 	return ("unspecified");
153 }
154 
155 int
cvsync_list_pton(const char * name)156 cvsync_list_pton(const char *name)
157 {
158 	const struct cvsync_token_type *t;
159 
160 	for (t = cvsync_list_types ; t->name != NULL ; t++) {
161 		if (strcasecmp(t->name, name) == 0)
162 			return (t->type);
163 	}
164 
165 	return (CVSYNC_LIST_UNKNOWN);
166 }
167 
168 const char *
cvsync_list_ntop(int type)169 cvsync_list_ntop(int type)
170 {
171 	const struct cvsync_token_type *t;
172 
173 	for (t = cvsync_list_types ; t->name != NULL ; t++) {
174 		if (t->type == type)
175 			return (t->name);
176 	}
177 
178 	return ("unknown");
179 }
180 
181 int
cvsync_release_pton(const char * name)182 cvsync_release_pton(const char *name)
183 {
184 	const struct cvsync_token_type *t;
185 
186 	for (t = cvsync_release_types ; t->name != NULL ; t++) {
187 		if (strcasecmp(t->name, name) == 0)
188 			return (t->type);
189 	}
190 
191 	return (CVSYNC_RELEASE_UNKNOWN);
192 }
193 
194 const char *
cvsync_release_ntop(int type)195 cvsync_release_ntop(int type)
196 {
197 	const struct cvsync_token_type *t;
198 
199 	for (t = cvsync_release_types ; t->name != NULL ; t++) {
200 		if (t->type == type)
201 			return (t->name);
202 	}
203 
204 	return ("unknown");
205 }
206 
207 void *
cvsync_memdup(void * ptr,size_t size)208 cvsync_memdup(void *ptr, size_t size)
209 {
210 	void *newptr;
211 
212 	if ((newptr = malloc(size)) == NULL) {
213 		logmsg_err("%s", strerror(errno));
214 		return (NULL);
215 	}
216 	(void)memcpy(newptr, ptr, size);
217 
218 	return (newptr);
219 }
220 
221 int
cvsync_cmp_pathname(const char * n1,size_t nlen1,const char * n2,size_t nlen2)222 cvsync_cmp_pathname(const char *n1, size_t nlen1, const char *n2, size_t nlen2)
223 {
224 	const char *bp1 = n1 + nlen1, *bp2 = n2 + nlen2;
225 
226 	while ((n1 < bp1) && (n2 < bp2)) {
227 		if (*n1 == *n2) {
228 			n1++;
229 			n2++;
230 			continue;
231 		}
232 
233 		if (*n1 == '/')
234 			return (-1);
235 		if (*n2 == '/')
236 			return (1);
237 
238 		if (*n1 < *n2)
239 			return (-1);
240 		else /* *n1 > *n2 */
241 			return (1);
242 	}
243 
244 	return ((int)(nlen1 - nlen2));
245 }
246 
247 struct cvsync_file *
cvsync_fopen(const char * path)248 cvsync_fopen(const char *path)
249 {
250 	struct cvsync_file *cfp;
251 	struct stat st;
252 
253 	if ((cfp = malloc(sizeof(*cfp))) == NULL) {
254 		logmsg_err("%s", strerror(errno));
255 		return (NULL);
256 	}
257 
258 	if ((cfp->cf_fileno = open(path, O_RDONLY, 0)) == -1) {
259 		logmsg_err("%s: %s", path, strerror(errno));
260 		free(cfp);
261 		return (NULL);
262 	}
263 	if (fstat(cfp->cf_fileno, &st) == -1) {
264 		logmsg_err("%s: %s", path, strerror(errno));
265 		(void)close(cfp->cf_fileno);
266 		free(cfp);
267 		return (NULL);
268 	}
269 	if (!S_ISREG(st.st_mode)) {
270 		logmsg_err("%s: Not a regular file", path);
271 		(void)close(cfp->cf_fileno);
272 		free(cfp);
273 		return (NULL);
274 	}
275 
276 	cfp->cf_size = st.st_size;
277 	cfp->cf_mtime = st.st_mtime;
278 	cfp->cf_mode = st.st_mode;
279 
280 	cfp->cf_addr = NULL;
281 	cfp->cf_msize = 0;
282 
283 	return (cfp);
284 }
285 
286 bool
cvsync_fclose(struct cvsync_file * cfp)287 cvsync_fclose(struct cvsync_file *cfp)
288 {
289 	if (cfp->cf_addr != NULL) {
290 		if (munmap(cfp->cf_addr, cfp->cf_msize) == -1) {
291 			logmsg_err("%s", strerror(errno));
292 			(void)close(cfp->cf_fileno);
293 			free(cfp);
294 			return (false);
295 		}
296 	}
297 	if (close(cfp->cf_fileno) == -1) {
298 		logmsg_err("%s", strerror(errno));
299 		free(cfp);
300 		return (false);
301 	}
302 	free(cfp);
303 
304 	return (true);
305 }
306 
307 bool
cvsync_mmap(struct cvsync_file * cfp,off_t offset,off_t size)308 cvsync_mmap(struct cvsync_file *cfp, off_t offset, off_t size)
309 {
310 	uint64_t size64 = (uint64_t)size;
311 
312 	if (size64 > SIZE_MAX) {
313 		logmsg_err("%" PRIu64 ": %s", size64, strerror(ERANGE));
314 		return (false);
315 	}
316 
317 	if ((cfp->cf_msize = (size_t)size) == 0) {
318 		cfp->cf_addr = NULL;
319 		return (true);
320 	}
321 	if ((cfp->cf_addr = mmap(NULL, cfp->cf_msize, PROT_READ, MAP_PRIVATE,
322 				 cfp->cf_fileno, offset)) == MAP_FAILED) {
323 		logmsg_err("%s", strerror(errno));
324 		return (false);
325 	}
326 
327 	return (true);
328 }
329 
330 bool
cvsync_munmap(struct cvsync_file * cfp)331 cvsync_munmap(struct cvsync_file *cfp)
332 {
333 	if (cfp->cf_addr != NULL) {
334 		if (munmap(cfp->cf_addr, cfp->cf_msize) == -1) {
335 			logmsg_err("%s", strerror(errno));
336 			return (false);
337 		}
338 		cfp->cf_addr = NULL;
339 		cfp->cf_msize = 0;
340 	}
341 
342 	return (true);
343 }
344 
345 void
cvsync_signal(int sig)346 cvsync_signal(int sig)
347 {
348 	sigaction(SIGINT, &cvsync_sig_ign, NULL);
349 	sigaction(SIGTERM, &cvsync_sig_ign, NULL);
350 
351 	switch (sig) {
352 	case SIGHUP:
353 	case SIGPIPE:
354 		/* Just ignore */
355 		break;
356 	case SIGINT:
357 		cvsync_process_terminated = true;
358 		/* FALLTHROUGH */
359 	case SIGTERM:
360 		cvsync_process_interrupted = true;
361 		break;
362 	default:
363 		break;
364 	}
365 }
366 
367 bool
__cvsync_isinterrupted(void)368 __cvsync_isinterrupted(void)
369 {
370 	return (cvsync_process_interrupted);
371 }
372 
373 bool
__cvsync_isterminated(void)374 __cvsync_isterminated(void)
375 {
376 	return (cvsync_process_terminated);
377 }
378