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