/usr.bin/csup/misc.c

https://bitbucket.org/freebsd/freebsd-head/ · C · 644 lines · 486 code · 84 blank · 74 comment · 130 complexity · 9b68cfe7c295a2614c58a00f29aecb08 MD5 · raw file

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