1 /*-
2 * Copyright (c) 2003-2006, Maxime Henrion <mux@FreeBSD.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 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 *
26 * $FreeBSD$
27 */
28
29 #include <sys/types.h>
30 #include <sys/stat.h>
31
32 #include <assert.h>
33 #include <err.h>
34 #include <errno.h>
35 #include <fcntl.h>
36 #include <limits.h>
37 #include <pthread.h>
38 #include <stdarg.h>
39 #include <stdio.h>
40 #include <stdlib.h>
41 #include <string.h>
42 #include <time.h>
43 #include <unistd.h>
44
45 #include "fattr.h"
46 #include "main.h"
47 #include "misc.h"
48
49 struct pattlist {
50 char **patterns;
51 size_t size;
52 size_t in;
53 };
54
55 struct backoff_timer {
56 time_t min;
57 time_t max;
58 time_t interval;
59 float backoff;
60 float jitter;
61 };
62
63 static void bt_update(struct backoff_timer *);
64 static void bt_addjitter(struct backoff_timer *);
65
66 int
asciitoint(const char * s,int * val,int base)67 asciitoint(const char *s, int *val, int base)
68 {
69 char *end;
70 long longval;
71
72 errno = 0;
73 longval = strtol(s, &end, base);
74 if (errno || *end != '\0')
75 return (-1);
76 if (longval > INT_MAX || longval < INT_MIN) {
77 errno = ERANGE;
78 return (-1);
79 }
80 *val = longval;
81 return (0);
82 }
83
84 int
lprintf(int level,const char * fmt,...)85 lprintf(int level, const char *fmt, ...)
86 {
87 FILE *to;
88 va_list ap;
89 int ret;
90
91 if (level > verbose)
92 return (0);
93 if (level == -1)
94 to = stderr;
95 else
96 to = stdout;
97 va_start(ap, fmt);
98 ret = vfprintf(to, fmt, ap);
99 va_end(ap);
100 fflush(to);
101 return (ret);
102 }
103
104 /*
105 * Compute the MD5 checksum of a file. The md parameter must
106 * point to a buffer containing at least MD5_DIGEST_SIZE bytes.
107 *
108 * Do not confuse OpenSSL's MD5_DIGEST_LENGTH with our own
109 * MD5_DIGEST_SIZE macro.
110 */
111 int
MD5_File(char * path,char * md)112 MD5_File(char *path, char *md)
113 {
114 char buf[1024];
115 MD5_CTX ctx;
116 ssize_t n;
117 int fd;
118
119 fd = open(path, O_RDONLY);
120 if (fd == -1)
121 return (-1);
122 MD5_Init(&ctx);
123 while ((n = read(fd, buf, sizeof(buf))) > 0)
124 MD5_Update(&ctx, buf, n);
125 close(fd);
126 if (n == -1)
127 return (-1);
128 MD5_End(md, &ctx);
129 return (0);
130 }
131
132 /*
133 * Wrapper around MD5_Final() that converts the 128 bits MD5 hash
134 * to an ASCII string representing this value in hexadecimal.
135 */
136 void
MD5_End(char * md,MD5_CTX * c)137 MD5_End(char *md, MD5_CTX *c)
138 {
139 unsigned char md5[MD5_DIGEST_LENGTH];
140 const char hex[] = "0123456789abcdef";
141 int i, j;
142
143 MD5_Final(md5, c);
144 j = 0;
145 for (i = 0; i < MD5_DIGEST_LENGTH; i++) {
146 md[j++] = hex[md5[i] >> 4];
147 md[j++] = hex[md5[i] & 0xf];
148 }
149 md[j] = '\0';
150 }
151
152 int
pathcmp(const char * s1,const char * s2)153 pathcmp(const char *s1, const char *s2)
154 {
155 char c1, c2;
156
157 do {
158 c1 = *s1++;
159 if (c1 == '/')
160 c1 = 1;
161 c2 = *s2++;
162 if (c2 == '/')
163 c2 = 1;
164 } while (c1 == c2 && c1 != '\0');
165
166 return (c1 - c2);
167 }
168
169 size_t
commonpathlength(const char * a,size_t alen,const char * b,size_t blen)170 commonpathlength(const char *a, size_t alen, const char *b, size_t blen)
171 {
172 size_t i, minlen, lastslash;
173
174 minlen = min(alen, blen);
175 lastslash = 0;
176 for (i = 0; i < minlen; i++) {
177 if (a[i] != b[i])
178 return (lastslash);
179 if (a[i] == '/') {
180 if (i == 0) /* Include the leading slash. */
181 lastslash = 1;
182 else
183 lastslash = i;
184 }
185 }
186
187 /* One path is a prefix of the other/ */
188 if (alen > minlen) { /* Path "b" is a prefix of "a". */
189 if (a[minlen] == '/')
190 return (minlen);
191 else
192 return (lastslash);
193 } else if (blen > minlen) { /* Path "a" is a prefix of "b". */
194 if (b[minlen] == '/')
195 return (minlen);
196 else
197 return (lastslash);
198 }
199
200 /* The paths are identical. */
201 return (minlen);
202 }
203
204 const char *
pathlast(const char * path)205 pathlast(const char *path)
206 {
207 const char *s;
208
209 s = strrchr(path, '/');
210 if (s == NULL)
211 return (path);
212 return (++s);
213 }
214
215 int
rcsdatetotm(const char * revdate,struct tm * tm)216 rcsdatetotm(const char *revdate, struct tm *tm)
217 {
218 char *cp;
219 size_t len;
220
221 cp = strchr(revdate, '.');
222 if (cp == NULL)
223 return (-1);
224 len = cp - revdate;
225 if (len >= 4)
226 cp = strptime(revdate, "%Y.%m.%d.%H.%M.%S", tm);
227 else if (len == 2)
228 cp = strptime(revdate, "%y.%m.%d.%H.%M.%S", tm);
229 else
230 return (-1);
231 if (cp == NULL || *cp != '\0')
232 return (-1);
233 return (0);
234 }
235
236 time_t
rcsdatetotime(const char * revdate)237 rcsdatetotime(const char *revdate)
238 {
239 struct tm tm;
240 time_t t;
241 int error;
242
243 error = rcsdatetotm(revdate, &tm);
244 if (error)
245 return (error);
246 t = timegm(&tm);
247 return (t);
248 }
249
250 /*
251 * Checks if a file is an RCS file.
252 */
253 int
isrcs(const char * file,size_t * len)254 isrcs(const char *file, size_t *len)
255 {
256 const char *cp;
257
258 if (file[0] == '/')
259 return (0);
260 cp = file;
261 while ((cp = strstr(cp, "..")) != NULL) {
262 if (cp == file || cp[2] == '\0' ||
263 (cp[-1] == '/' && cp[2] == '/'))
264 return (0);
265 cp += 2;
266 }
267 *len = strlen(file);
268 if (*len < 2 || file[*len - 1] != 'v' || file[*len - 2] != ',') {
269 return (0);
270 }
271
272 return (1);
273 }
274
275 /*
276 * Returns a buffer allocated with malloc() containing the absolute
277 * pathname to the checkout file made from the prefix and the path
278 * of the corresponding RCS file relatively to the prefix. If the
279 * filename is not an RCS filename, NULL will be returned.
280 */
281 char *
checkoutpath(const char * prefix,const char * file)282 checkoutpath(const char *prefix, const char *file)
283 {
284 char *path;
285 size_t len;
286
287 if (!isrcs(file, &len))
288 return (NULL);
289 xasprintf(&path, "%s/%.*s", prefix, (int)len - 2, file);
290 return (path);
291 }
292
293 /*
294 * Returns a cvs path allocated with malloc() containing absolute pathname to a
295 * file in cvs mode which can reside in the attic. XXX: filename has really no
296 * restrictions.
297 */
298 char *
cvspath(const char * prefix,const char * file,int attic)299 cvspath(const char *prefix, const char *file, int attic)
300 {
301 const char *last;
302 char *path;
303
304 last = pathlast(file);
305 if (attic)
306 xasprintf(&path, "%s/%.*sAttic/%s", prefix, (int)(last - file),
307 file, last);
308 else
309 xasprintf(&path, "%s/%s", prefix, file);
310
311 return (path);
312 }
313
314 /*
315 * Regular or attic path if regular fails.
316 * XXX: This should perhaps also check if the Attic file exists too, and return
317 * NULL if not.
318 */
319 char *
atticpath(const char * prefix,const char * file)320 atticpath(const char *prefix, const char *file)
321 {
322 char *path;
323
324 path = cvspath(prefix, file, 0);
325 if (access(path, F_OK) != 0) {
326 free(path);
327 path = cvspath(prefix, file, 1);
328 }
329 return (path);
330 }
331
332 int
mkdirhier(char * path,mode_t mask)333 mkdirhier(char *path, mode_t mask)
334 {
335 struct fattr *fa;
336 size_t i, last, len;
337 int error, finish, rv;
338
339 finish = 0;
340 last = 0;
341 len = strlen(path);
342 for (i = len - 1; i > 0; i--) {
343 if (path[i] == '/') {
344 path[i] = '\0';
345 if (access(path, F_OK) == 0) {
346 path[i] = '/';
347 break;
348 }
349 if (errno != ENOENT) {
350 path[i] = '/';
351 if (last == 0)
352 return (-1);
353 finish = 1;
354 break;
355 }
356 last = i;
357 }
358 }
359 if (last == 0)
360 return (0);
361
362 i = strlen(path);
363 fa = fattr_new(FT_DIRECTORY, -1);
364 fattr_mergedefault(fa);
365 fattr_umask(fa, mask);
366 while (i < len) {
367 if (!finish) {
368 rv = 0;
369 error = fattr_makenode(fa, path);
370 if (!error)
371 rv = fattr_install(fa, path, NULL);
372 if (error || rv == -1)
373 finish = 1;
374 }
375 path[i] = '/';
376 i += strlen(path + i);
377 }
378 assert(i == len);
379 if (finish)
380 return (-1);
381 return (0);
382 }
383
384 /*
385 * Compute temporary pathnames.
386 * This can look a bit like overkill but we mimic CVSup's behaviour.
387 */
388 #define TEMPNAME_PREFIX "#cvs.csup"
389
390 static pthread_mutex_t tempname_mtx = PTHREAD_MUTEX_INITIALIZER;
391 static pid_t tempname_pid = -1;
392 static int tempname_count;
393
394 char *
tempname(const char * path)395 tempname(const char *path)
396 {
397 char *cp, *temp;
398 int count, error;
399
400 error = pthread_mutex_lock(&tempname_mtx);
401 assert(!error);
402 if (tempname_pid == -1) {
403 tempname_pid = getpid();
404 tempname_count = 0;
405 }
406 count = tempname_count++;
407 error = pthread_mutex_unlock(&tempname_mtx);
408 assert(!error);
409 cp = strrchr(path, '/');
410 if (cp == NULL)
411 xasprintf(&temp, "%s-%ld.%d", TEMPNAME_PREFIX,
412 (long)tempname_pid, count);
413 else
414 xasprintf(&temp, "%.*s%s-%ld.%d", (int)(cp - path + 1), path,
415 TEMPNAME_PREFIX, (long)tempname_pid, count);
416 return (temp);
417 }
418
419 void *
xmalloc(size_t size)420 xmalloc(size_t size)
421 {
422 void *buf;
423
424 buf = malloc(size);
425 if (buf == NULL)
426 err(1, "malloc");
427 return (buf);
428 }
429
430 void *
xrealloc(void * buf,size_t size)431 xrealloc(void *buf, size_t size)
432 {
433
434 buf = realloc(buf, size);
435 if (buf == NULL)
436 err(1, "realloc");
437 return (buf);
438 }
439
440 char *
xstrdup(const char * str)441 xstrdup(const char *str)
442 {
443 char *buf;
444
445 buf = strdup(str);
446 if (buf == NULL)
447 err(1, "strdup");
448 return (buf);
449 }
450
451 int
xasprintf(char ** ret,const char * format,...)452 xasprintf(char **ret, const char *format, ...)
453 {
454 va_list ap;
455 int rv;
456
457 va_start(ap, format);
458 rv = vasprintf(ret, format, ap);
459 va_end(ap);
460 if (*ret == NULL)
461 err(1, "asprintf");
462 return (rv);
463 }
464
465 struct pattlist *
pattlist_new(void)466 pattlist_new(void)
467 {
468 struct pattlist *p;
469
470 p = xmalloc(sizeof(struct pattlist));
471 p->size = 4; /* Initial size. */
472 p->patterns = xmalloc(p->size * sizeof(char *));
473 p->in = 0;
474 return (p);
475 }
476
477 void
pattlist_add(struct pattlist * p,const char * pattern)478 pattlist_add(struct pattlist *p, const char *pattern)
479 {
480
481 if (p->in == p->size) {
482 p->size *= 2;
483 p->patterns = xrealloc(p->patterns, p->size * sizeof(char *));
484 }
485 assert(p->in < p->size);
486 p->patterns[p->in++] = xstrdup(pattern);
487 }
488
489 char *
pattlist_get(struct pattlist * p,size_t i)490 pattlist_get(struct pattlist *p, size_t i)
491 {
492
493 assert(i < p->in);
494 return (p->patterns[i]);
495 }
496
497 size_t
pattlist_size(struct pattlist * p)498 pattlist_size(struct pattlist *p)
499 {
500
501 return (p->in);
502 }
503
504 void
pattlist_free(struct pattlist * p)505 pattlist_free(struct pattlist *p)
506 {
507 size_t i;
508
509 for (i = 0; i < p->in; i++)
510 free(p->patterns[i]);
511 free(p->patterns);
512 free(p);
513 }
514
515 /* Creates a backoff timer. */
516 struct backoff_timer *
bt_new(time_t min,time_t max,float backoff,float jitter)517 bt_new(time_t min, time_t max, float backoff, float jitter)
518 {
519 struct backoff_timer *bt;
520
521 bt = xmalloc(sizeof(struct backoff_timer));
522 bt->min = min;
523 bt->max = max;
524 bt->backoff = backoff;
525 bt->jitter = jitter;
526 bt->interval = min;
527 bt_addjitter(bt);
528 srandom(time(0));
529 return (bt);
530 }
531
532 /* Updates the backoff timer. */
533 static void
bt_update(struct backoff_timer * bt)534 bt_update(struct backoff_timer *bt)
535 {
536
537 bt->interval = (time_t)min(bt->interval * bt->backoff, bt->max);
538 bt_addjitter(bt);
539 }
540
541 /* Adds some jitter. */
542 static void
bt_addjitter(struct backoff_timer * bt)543 bt_addjitter(struct backoff_timer *bt)
544 {
545 long mag;
546
547 mag = (long)(bt->jitter * bt->interval);
548 /* We want a random number between -mag and mag. */
549 bt->interval += (time_t)(random() % (2 * mag) - mag);
550 }
551
552 /* Returns the current timer value. */
553 time_t
bt_get(struct backoff_timer * bt)554 bt_get(struct backoff_timer *bt)
555 {
556
557 return (bt->interval);
558 }
559
560 /* Times out for bt->interval seconds. */
561 void
bt_pause(struct backoff_timer * bt)562 bt_pause(struct backoff_timer *bt)
563 {
564
565 sleep(bt->interval);
566 bt_update(bt);
567 }
568
569 void
bt_free(struct backoff_timer * bt)570 bt_free(struct backoff_timer *bt)
571 {
572
573 free(bt);
574 }
575
576 /* Compare two revisions. */
577 int
rcsnum_cmp(char * revision1,char * revision2)578 rcsnum_cmp(char *revision1, char *revision2)
579 {
580 char *ptr1, *ptr2, *dot1, *dot2;
581 int num1len, num2len, ret;
582
583 ptr1 = revision1;
584 ptr2 = revision2;
585 while (*ptr1 != '\0' && *ptr2 != '\0') {
586 dot1 = strchr(ptr1, '.');
587 dot2 = strchr(ptr2, '.');
588 if (dot1 == NULL)
589 dot1 = strchr(ptr1, '\0');
590 if (dot2 == NULL)
591 dot2 = strchr(ptr2, '\0');
592
593 num1len = dot1 - ptr1;
594 num2len = dot2 - ptr2;
595 /* Check the distance between each, showing how many digits */
596 if (num1len > num2len)
597 return (1);
598 else if (num1len < num2len)
599 return (-1);
600
601 /* Equal distance means we must check each character. */
602 ret = strncmp(ptr1, ptr2, num1len);
603 if (ret != 0)
604 return (ret);
605 ptr1 = (*dot1 == '.') ? (dot1 + 1) : dot1;
606 ptr2 = (*dot2 == '.') ? (dot2 + 1) : dot2;
607 }
608
609 if (*ptr1 != '\0' && *ptr2 == '\0')
610 return (1);
611 if (*ptr1 == '\0' && *ptr2 != '\0')
612 return (-1);
613 return (0);
614
615 }
616
617 /* Returns 0 if a rcsrev is not a trunk revision number. */
618 int
rcsrev_istrunk(char * revnum)619 rcsrev_istrunk(char *revnum)
620 {
621 char *tmp;
622
623 tmp = strchr(revnum, '.');
624 tmp++;
625 if (strchr(tmp, '.') != NULL)
626 return (0);
627 return (1);
628 }
629
630 /* Return prefix of rcsfile. */
631 char *
rcsrev_prefix(char * revnum)632 rcsrev_prefix(char *revnum)
633 {
634 char *modrev, *pos;
635
636 modrev = xstrdup(revnum);
637 pos = strrchr(modrev, '.');
638 if (pos == NULL) {
639 free(modrev);
640 return (NULL);
641 }
642 *pos = '\0';
643 return (modrev);
644 }
645