1 /*
2  * Copyright (C) 1986-2005 The Free Software Foundation, Inc.
3  *
4  * Portions Copyright (C) 1998-2005 Derek Price, Ximbiot <http://ximbiot.com>,
5  *                                  and others.
6  *
7  * Portions Copyright (C) 1992, Brian Berliner and Jeff Polk
8  * Portions Copyright (C) 1989-1992, Brian Berliner
9  *
10  * You may distribute under the terms of the GNU General Public License as
11  * specified in the README file that comes with the CVS source distribution.
12  *
13  * Various useful functions for the CVS support code.
14  */
15 
16 #include "cvs.h"
17 
18 #include "canonicalize.h"
19 #include "canon-host.h"
20 #include "getline.h"
21 #include "vasprintf.h"
22 #include "vasnprintf.h"
23 
24 /* Get wint_t.  */
25 #ifdef HAVE_WINT_T
26 # include <wchar.h>
27 #endif
28 
29 __RCSID("$MirOS: src/gnu/usr.bin/cvs/src/subr.c,v 1.6 2011/07/28 15:54:35 tg Exp $");
30 
31 
32 extern char *getlogin (void);
33 
34 
35 
36 /* *STRPTR is a pointer returned from malloc (or NULL), pointing to *N
37    characters of space.  Reallocate it so that points to at least
38    NEWSIZE bytes of space.  Gives a fatal error if out of memory;
39    if it returns it was successful.  */
40 void
expand_string(char ** strptr,size_t * n,size_t newsize)41 expand_string (char **strptr, size_t *n, size_t newsize)
42 {
43     while (*n < newsize)
44 	*strptr = x2realloc (*strptr, n);
45 }
46 
47 
48 
49 /* char *
50  * Xreadlink (const char *link, size_t size)
51  *
52  * INPUTS
53  *  link	The original path.
54  *  size	A guess as to the size needed for the path. It need
55  *              not be right.
56  * RETURNS
57  *  The resolution of the final symbolic link in the path.
58  *
59  * ERRORS
60  *  This function exits with a fatal error if it fails to read the
61  *  link for any reason.
62  */
63 char *
Xreadlink(const char * link,size_t size)64 Xreadlink (const char *link, size_t size)
65 {
66     char *file = xreadlink (link, size);
67 
68     if (file == NULL)
69 	error (1, errno, "cannot readlink %s", link);
70 
71     return file;
72 }
73 
74 
75 
76 /* *STR is a pointer to a malloc'd string or NULL.  *LENP is its allocated
77  * length.  If *STR is NULL then *LENP must be 0 and visa-versa.
78  * Add SRC to the end of *STR, reallocating *STR if necessary.  */
79 void
xrealloc_and_strcat(char ** str,size_t * lenp,const char * src)80 xrealloc_and_strcat (char **str, size_t *lenp, const char *src)
81 {
82     bool newstr = !*lenp;
83     expand_string (str, lenp, (newstr ? 0 : strlen (*str)) + strlen (src) + 1);
84     if (newstr)
85 	strcpy (*str, src);
86     else
87 	strcat (*str, src);
88 }
89 
90 
91 
92 /* Remove trailing newlines from STRING, destructively.
93  *
94  * RETURNS
95  *
96  *   True if any newlines were removed, false otherwise.
97  */
98 int
strip_trailing_newlines(char * str)99 strip_trailing_newlines (char *str)
100 {
101     size_t index, origlen;
102     index = origlen = strlen (str);
103 
104     while (index > 0 && str[index-1] == '\n')
105 	str[--index] = '\0';
106 
107     return index != origlen;
108 }
109 
110 
111 
112 /* Return the number of levels that PATH ascends above where it starts.
113  * For example:
114  *
115  *   "../../foo" -> 2
116  *   "foo/../../bar" -> 1
117  */
118 int
pathname_levels(const char * p)119 pathname_levels (const char *p)
120 {
121     int level;
122     int max_level;
123 
124     if (p == NULL) return 0;
125 
126     max_level = 0;
127     level = 0;
128     do
129     {
130 	/* Now look for pathname level-ups.  */
131 	if (p[0] == '.' && p[1] == '.' && (p[2] == '\0' || ISSLASH (p[2])))
132 	{
133 	    --level;
134 	    if (-level > max_level)
135 		max_level = -level;
136 	}
137 	else if (p[0] == '\0' || ISSLASH (p[0]) ||
138 		 (p[0] == '.' && (p[1] == '\0' || ISSLASH (p[1]))))
139 	    ;
140 	else
141 	    ++level;
142 
143 	/* q = strchr (p, '/'); but sub ISSLASH() for '/': */
144 	while (*p != '\0' && !ISSLASH (*p)) p++;
145 	if (*p != '\0') p++;
146     } while (*p != '\0');
147     return max_level;
148 }
149 
150 
151 
152 /* Free a vector, where (*ARGV)[0], (*ARGV)[1], ... (*ARGV)[*PARGC - 1]
153    are malloc'd and so is *ARGV itself.  Such a vector is allocated by
154    line2argv or expand_wild, for example.  */
155 void
free_names(int * pargc,char ** argv)156 free_names (int *pargc, char **argv)
157 {
158     register int i;
159 
160     for (i = 0; i < *pargc; i++)
161     {					/* only do through *pargc */
162 	free (argv[i]);
163     }
164     free (argv);
165     *pargc = 0;				/* and set it to zero when done */
166 }
167 
168 
169 
170 /* Convert LINE into arguments separated by SEPCHARS.  Set *ARGC
171    to the number of arguments found, and (*ARGV)[0] to the first argument,
172    (*ARGV)[1] to the second, etc.  *ARGV is malloc'd and so are each of
173    (*ARGV)[0], (*ARGV)[1], ...  Use free_names() to return the memory
174    allocated here back to the free pool.  */
175 void
line2argv(int * pargc,char *** argv,char * line,char * sepchars)176 line2argv (int *pargc, char ***argv, char *line, char *sepchars)
177 {
178     char *cp;
179     /* Could make a case for size_t or some other unsigned type, but
180        we'll stick with int to avoid signed/unsigned warnings when
181        comparing with *pargc.  */
182     int argv_allocated;
183 
184     /* Small for testing.  */
185     argv_allocated = 1;
186     *argv = xnmalloc (argv_allocated, sizeof (**argv));
187 
188     *pargc = 0;
189     for (cp = strtok (line, sepchars); cp; cp = strtok (NULL, sepchars))
190     {
191 	if (*pargc == argv_allocated)
192 	{
193 	    argv_allocated *= 2;
194 	    *argv = xnrealloc (*argv, argv_allocated, sizeof (**argv));
195 	}
196 	(*argv)[*pargc] = xstrdup (cp);
197 	(*pargc)++;
198     }
199 }
200 
201 
202 
203 /*
204  * Returns the number of dots ('.') found in an RCS revision number
205  */
206 int
numdots(const char * s)207 numdots (const char *s)
208 {
209     int dots = 0;
210 
211     for (; *s; s++)
212     {
213 	if (*s == '.')
214 	    dots++;
215     }
216     return (dots);
217 }
218 
219 
220 
221 /* Compare revision numbers REV1 and REV2 by consecutive fields.
222    Return negative, zero, or positive in the manner of strcmp.  The
223    two revision numbers must have the same number of fields, or else
224    compare_revnums will return an inaccurate result. */
225 int
compare_revnums(const char * rev1,const char * rev2)226 compare_revnums (const char *rev1, const char *rev2)
227 {
228     const char *sp, *tp;
229     char *snext, *tnext;
230     int result = 0;
231 
232     sp = rev1;
233     tp = rev2;
234     while (result == 0)
235     {
236 	result = strtoul (sp, &snext, 10) - strtoul (tp, &tnext, 10);
237 	if (*snext == '\0' || *tnext == '\0')
238 	    break;
239 	sp = snext + 1;
240 	tp = tnext + 1;
241     }
242 
243     return result;
244 }
245 
246 
247 
248 /* Increment a revision number.  Working on the string is a bit awkward,
249    but it avoid problems with integer overflow should the revision numbers
250    get really big.  */
251 char *
increment_revnum(const char * rev)252 increment_revnum (const char *rev)
253 {
254     char *newrev, *p;
255     size_t len = strlen (rev);
256 
257     newrev = xmalloc (len + 2);
258     memcpy (newrev, rev, len + 1);
259     for (p = newrev + len; p != newrev; )
260     {
261 	--p;
262 	if (!isdigit(*p))
263 	{
264 	    ++p;
265 	    break;
266 	}
267 	if (*p != '9')
268 	{
269 	    ++*p;
270 	    return newrev;
271 	}
272 	*p = '0';
273     }
274     /* The number was all 9s, so change the first character to 1 and add
275        a 0 to the end.  */
276     *p = '1';
277     p = newrev + len;
278     *p++ = '0';
279     *p = '\0';
280     return newrev;
281 }
282 
283 
284 
285 /* Return the username by which the caller should be identified in
286    CVS, in contexts such as the author field of RCS files, various
287    logs, etc.  */
288 char *
getcaller(void)289 getcaller (void)
290 {
291 #ifndef SYSTEM_GETCALLER
292     static char *cache;
293     struct passwd *pw;
294     uid_t uid;
295 #endif
296 
297     /* If there is a CVS username, return it.  */
298 #ifdef AUTH_SERVER_SUPPORT
299     if (CVS_Username != NULL)
300 	return CVS_Username;
301 #endif
302 
303 #ifdef SYSTEM_GETCALLER
304     return SYSTEM_GETCALLER ();
305 #else
306     /* Get the caller's login from his uid.  If the real uid is "root"
307        try LOGNAME USER or getlogin(). If getlogin() and getpwuid()
308        both fail, return the uid as a string.  */
309 
310     if (cache != NULL)
311 	return cache;
312 
313     uid = getuid ();
314     if (uid == (uid_t) 0)
315     {
316 	char *name;
317 
318 	/* super-user; try getlogin() to distinguish */
319 	if (((name = getlogin ()) || (name = getenv("LOGNAME")) ||
320 	     (name = getenv("USER"))) && *name)
321 	{
322 	    cache = xstrdup (name);
323 	    return cache;
324 	}
325     }
326     if ((pw = (struct passwd *) getpwuid (uid)) == NULL)
327     {
328 	cache = Xasprintf ("uid%lu", (unsigned long) uid);
329 	return cache;
330     }
331     cache = xstrdup (pw->pw_name);
332     return cache;
333 #endif
334 }
335 
336 
337 
338 #ifdef lint
339 # ifndef __GNUC__
340 /* ARGSUSED */
341 bool
get_date(struct timespec * result,char const * p,struct timespec const * now)342 get_date (struct timespec *result, char const *p, struct timespec const *now)
343 {
344     result->tv_sec = 0;
345     result->tv_nsec = 0;
346 
347     return false;
348 }
349 # endif
350 #endif
351 
352 
353 
354 /* Given some revision, REV, return the first prior revision that exists in the
355  * RCS file, RCS.
356  *
357  * ASSUMPTIONS
358  *   REV exists.
359  *
360  * INPUTS
361  *   RCS	The RCS node pointer.
362  *   REV	An existing revision in the RCS file referred to by RCS.
363  *
364  * RETURNS
365  *   The first prior revision that exists in the RCS file, or NULL if no prior
366  *   revision exists.  The caller is responsible for disposing of this string.
367  *
368  * NOTES
369  *   This function currently neglects the case where we are on the trunk with
370  *   rev = X.1, where X != 1.  If rev = X.Y, where X != 1 and Y > 1, then this
371  *   function should work fine, as revision X.1 must exist, due to RCS rules.
372  */
373 char *
previous_rev(RCSNode * rcs,const char * rev)374 previous_rev (RCSNode *rcs, const char *rev)
375 {
376     char *p;
377     char *tmp = xstrdup (rev);
378     long r1;
379     char *retval;
380 
381     /* Our retval can have no more digits and dots than our input revision.  */
382     retval = xmalloc (strlen (rev) + 1);
383     p = strrchr (tmp, '.');
384     *p = '\0';
385     r1 = strtol (p+1, NULL, 10);
386     do {
387 	if (--r1 == 0)
388 	{
389 		/* If r1 == 0, then we must be on a branch and our parent must
390 		 * exist, or we must be on the trunk with a REV like X.1.
391 		 * We are neglecting the X.1 with X != 1 case by assuming that
392 		 * there is no previous revision when we discover we were on
393 		 * the trunk.
394 		 */
395 		p = strrchr (tmp, '.');
396 		if (p == NULL)
397 		    /* We are on the trunk.  */
398 		    retval = NULL;
399 		else
400 		{
401 		    *p = '\0';
402 		    sprintf (retval, "%s", tmp);
403 		}
404 		break;
405 	}
406 	sprintf (retval, "%s.%ld", tmp, r1);
407     } while (!RCS_exist_rev (rcs, retval));
408 
409     free (tmp);
410     return retval;
411 }
412 
413 
414 
415 /* Given two revisions, find their greatest common ancestor.  If the
416    two input revisions exist, then rcs guarantees that the gca will
417    exist.  */
418 char *
gca(const char * rev1,const char * rev2)419 gca (const char *rev1, const char *rev2)
420 {
421     int dots;
422     char *gca, *g;
423     const char *p1, *p2;
424     int r1, r2;
425     char *retval;
426 
427     if (rev1 == NULL || rev2 == NULL)
428     {
429 	error (0, 0, "sanity failure in gca");
430 	abort();
431     }
432 
433     /* The greatest common ancestor will have no more dots, and numbers
434        of digits for each component no greater than the arguments.  Therefore
435        this string will be big enough.  */
436     g = gca = xmalloc (strlen (rev1) + strlen (rev2) + 100);
437 
438     /* walk the strings, reading the common parts. */
439     p1 = rev1;
440     p2 = rev2;
441     do
442     {
443 	r1 = strtol (p1, (char **) &p1, 10);
444 	r2 = strtol (p2, (char **) &p2, 10);
445 
446 	/* use the lowest. */
447 	(void) sprintf (g, "%d.", r1 < r2 ? r1 : r2);
448 	g += strlen (g);
449 	if (*p1 == '.') ++p1;
450 	else break;
451 	if (*p2 == '.') ++p2;
452 	else break;
453     } while (r1 == r2);
454 
455     /* erase that last dot. */
456     *--g = '\0';
457 
458     /* numbers differ, or we ran out of strings.  we're done with the
459        common parts.  */
460 
461     dots = numdots (gca);
462     if (dots == 0)
463     {
464 	/* revisions differ in trunk major number.  */
465 
466 	if (r2 < r1) p1 = p2;
467 	if (*p1 == '\0')
468 	{
469 	    /* we only got one number.  this is strange.  */
470 	    error (0, 0, "bad revisions %s or %s", rev1, rev2);
471 	    abort();
472 	}
473 	else
474 	{
475 	    /* we have a minor number.  use it.  */
476 	    *g++ = '.';
477 	    while (*p1 != '.' && *p1 != '\0')
478 		*g++ = *p1++;
479 	    *g = '\0';
480 	}
481     }
482     else if ((dots & 1) == 0)
483     {
484 	/* if we have an even number of dots, then we have a branch.
485 	   remove the last number in order to make it a revision.  */
486 
487 	g = strrchr (gca, '.');
488 	*g = '\0';
489     }
490 
491     retval = xstrdup (gca);
492     free (gca);
493     return retval;
494 }
495 
496 
497 
498 /* Give fatal error if REV is numeric and ARGC,ARGV imply we are
499    planning to operate on more than one file.  The current directory
500    should be the working directory.  Note that callers assume that we
501    will only be checking the first character of REV; it need not have
502    '\0' at the end of the tag name and other niceties.  Right now this
503    is only called from admin.c, but if people like the concept it probably
504    should also be called from diff -r, update -r, get -r, and log -r.  */
505 void
check_numeric(const char * rev,int argc,char ** argv)506 check_numeric (const char *rev, int argc, char **argv)
507 {
508     if (rev == NULL || !isdigit ((unsigned char) *rev))
509 	return;
510 
511     /* Note that the check for whether we are processing more than one
512        file is (basically) syntactic; that is, we don't behave differently
513        depending on whether a directory happens to contain only a single
514        file or whether it contains more than one.  I strongly suspect this
515        is the least confusing behavior.  */
516     if (argc != 1
517 	|| (!wrap_name_has (argv[0], WRAP_TOCVS) && isdir (argv[0])))
518     {
519 	error (0, 0, "while processing more than one file:");
520 	error (1, 0, "attempt to specify a numeric revision");
521     }
522 }
523 
524 
525 
526 /*
527  *  Sanity checks and any required fix-up on message passed to RCS via '-m'.
528  *  RCS 5.7 requires that a non-total-whitespace, non-null message be provided
529  *  with '-m'.  Returns a newly allocated, non-empty buffer with whitespace
530  *  stripped from end of lines and end of buffer.
531  *
532  *  TODO: We no longer use RCS to manage repository files, so maybe this
533  *  nonsense about non-empty log fields can be dropped.
534  */
535 char *
make_message_rcsvalid(const char * message)536 make_message_rcsvalid (const char *message)
537 {
538     char *dst, *dp;
539     const char *mp;
540 
541     if (message == NULL) message = "";
542 
543     /* Strip whitespace from end of lines and end of string. */
544     dp = dst = (char *) xmalloc (strlen (message) + 1);
545     for (mp = message; *mp != '\0'; ++mp)
546     {
547 	if (*mp == '\n')
548 	{
549 	    /* At end-of-line; backtrack to last non-space. */
550 	    while (dp > dst && (dp[-1] == ' ' || dp[-1] == '\t'))
551 		--dp;
552 	}
553 	*dp++ = *mp;
554     }
555 
556     /* Backtrack to last non-space at end of string, and truncate. */
557     while (dp > dst && isspace ((unsigned char) dp[-1]))
558 	--dp;
559     *dp = '\0';
560 
561     /* After all that, if there was no non-space in the string,
562        substitute a non-empty message. */
563     if (*dst == '\0')
564     {
565 	free (dst);
566 	dst = xstrdup ("*** empty log message ***");
567     }
568 
569     return dst;
570 }
571 
572 
573 
574 /* Does the file FINFO contain conflict markers?  The whole concept
575    of looking at the contents of the file to figure out whether there are
576    unresolved conflicts is kind of bogus (people do want to manage files
577    which contain those patterns not as conflict markers), but for now it
578    is what we do.  */
579 int
file_has_markers(const struct file_info * finfo)580 file_has_markers (const struct file_info *finfo)
581 {
582     FILE *fp;
583     char *line = NULL;
584     size_t line_allocated = 0;
585     int result;
586 
587     result = 0;
588     fp = CVS_FOPEN (finfo->file, "r");
589     if (fp == NULL)
590 	error (1, errno, "cannot open %s", finfo->fullname);
591     while (getline (&line, &line_allocated, fp) > 0)
592     {
593 	if (strncmp (line, RCS_MERGE_PAT_1, sizeof RCS_MERGE_PAT_1 - 1) == 0 ||
594 	    strncmp (line, RCS_MERGE_PAT_2, sizeof RCS_MERGE_PAT_2 - 1) == 0 ||
595 	    strncmp (line, RCS_MERGE_PAT_3, sizeof RCS_MERGE_PAT_3 - 1) == 0)
596 	{
597 	    result = 1;
598 	    goto out;
599 	}
600     }
601     if (ferror (fp))
602 	error (0, errno, "cannot read %s", finfo->fullname);
603 out:
604     if (fclose (fp) < 0)
605 	error (0, errno, "cannot close %s", finfo->fullname);
606     if (line != NULL)
607 	free (line);
608     return result;
609 }
610 
611 
612 
613 /* Read the entire contents of the file NAME into *BUF.
614    If NAME is NULL, read from stdin.  *BUF
615    is a pointer returned from malloc (or NULL), pointing to *BUFSIZE
616    bytes of space.  The actual size is returned in *LEN.  On error,
617    give a fatal error.  The name of the file to use in error messages
618    (typically will include a directory if we have changed directory)
619    is FULLNAME.  MODE is "r" for text or "rb" for binary.  */
620 void
get_file(const char * name,const char * fullname,const char * mode,char ** buf,size_t * bufsize,size_t * len)621 get_file (const char *name, const char *fullname, const char *mode, char **buf,
622 	  size_t *bufsize, size_t *len)
623 {
624     struct stat s;
625     size_t nread;
626     char *tobuf;
627     FILE *e;
628     size_t filesize;
629 
630     if (name == NULL)
631     {
632 	e = stdin;
633 	filesize = 100;	/* force allocation of minimum buffer */
634     }
635     else
636     {
637 	/* Although it would be cleaner in some ways to just read
638 	   until end of file, reallocating the buffer, this function
639 	   does get called on files in the working directory which can
640 	   be of arbitrary size, so I think we better do all that
641 	   extra allocation.  */
642 
643 	if (stat (name, &s) < 0)
644 	    error (1, errno, "can't stat %s", fullname);
645 
646 	/* Convert from signed to unsigned.  */
647 	filesize = s.st_size;
648 
649 	e = xfopen (name, mode);
650     }
651 
652     if (*buf == NULL || *bufsize <= filesize)
653     {
654 	*bufsize = filesize + 1;
655 	*buf = xrealloc (*buf, *bufsize);
656     }
657 
658     tobuf = *buf;
659     nread = 0;
660     while (1)
661     {
662 	size_t got;
663 
664 	got = fread (tobuf, 1, *bufsize - (tobuf - *buf), e);
665 	if (ferror (e))
666 	    error (1, errno, "can't read %s", fullname);
667 	nread += got;
668 	tobuf += got;
669 
670 	if (feof (e))
671 	    break;
672 
673 	/* Allocate more space if needed.  */
674 	if (tobuf == *buf + *bufsize)
675 	{
676 	    int c;
677 	    long off;
678 
679 	    c = getc (e);
680 	    if (c == EOF)
681 		break;
682 	    off = tobuf - *buf;
683 	    expand_string (buf, bufsize, *bufsize + 100);
684 	    tobuf = *buf + off;
685 	    *tobuf++ = c;
686 	    ++nread;
687 	}
688     }
689 
690     if (e != stdin && fclose (e) < 0)
691 	error (0, errno, "cannot close %s", fullname);
692 
693     *len = nread;
694 
695     /* Force *BUF to be large enough to hold a null terminator. */
696     if (nread == *bufsize)
697 	expand_string (buf, bufsize, *bufsize + 1);
698     (*buf)[nread] = '\0';
699 }
700 
701 
702 
703 /* Follow a chain of symbolic links to its destination.  FILENAME
704    should be a handle to a malloc'd block of memory which contains the
705    beginning of the chain.  This routine will replace the contents of
706    FILENAME with the destination (a real file).  */
707 void
resolve_symlink(char ** filename)708 resolve_symlink (char **filename)
709 {
710     ssize_t rsize;
711 
712     if (filename == NULL || *filename == NULL)
713 	return;
714 
715     while ((rsize = islink (*filename)) > 0)
716     {
717 #ifdef HAVE_READLINK
718 	/* The clean thing to do is probably to have each filesubr.c
719 	   implement this (with an error if not supported by the
720 	   platform, in which case islink would presumably return 0).
721 	   But that would require editing each filesubr.c and so the
722 	   expedient hack seems to be looking at HAVE_READLINK.  */
723 	char *newname = Xreadlink (*filename, rsize);
724 
725 	if (ISABSOLUTE (newname))
726 	{
727 	    free (*filename);
728 	    *filename = newname;
729 	}
730 	else
731 	{
732 	    const char *oldname = last_component (*filename);
733 	    int dirlen = oldname - *filename;
734 	    char *fullnewname = xmalloc (dirlen + strlen (newname) + 1);
735 	    strncpy (fullnewname, *filename, dirlen);
736 	    strcpy (fullnewname + dirlen, newname);
737 	    free (newname);
738 	    free (*filename);
739 	    *filename = fullnewname;
740 	}
741 #else
742 	error (1, 0, "internal error: islink doesn't like readlink");
743 #endif
744     }
745 }
746 
747 
748 
749 /*
750  * Rename a file to an appropriate backup name based on BAKPREFIX.
751  * If suffix non-null, then ".<suffix>" is appended to the new name.
752  *
753  * Returns the new name, which caller may free() if desired.
754  */
755 char *
backup_file(const char * filename,const char * suffix)756 backup_file (const char *filename, const char *suffix)
757 {
758     char *backup_name = Xasprintf ("%s%s%s%s", BAKPREFIX, filename,
759 				   suffix ? "." : "", suffix ? suffix : "");
760 
761     if (isfile (filename))
762         copy_file (filename, backup_name);
763 
764     return backup_name;
765 }
766 
767 
768 
769 /*
770  * Copy a string into a buffer escaping any shell metacharacters.  The
771  * buffer should be at least twice as long as the string.
772  *
773  * Returns a pointer to the terminating NUL byte in buffer.
774  */
775 char *
shell_escape(char * buf,const char * str)776 shell_escape(char *buf, const char *str)
777 {
778     static const char meta[] = "$`\\\"";
779     const char *p;
780 
781     for (;;)
782     {
783 	p = strpbrk(str, meta);
784 	if (!p) p = str + strlen(str);
785 	if (p > str)
786 	{
787 	    memcpy(buf, str, p - str);
788 	    buf += p - str;
789 	}
790 	if (!*p) break;
791 	*buf++ = '\\';
792 	*buf++ = *p++;
793 	str = p;
794     }
795     *buf = '\0';
796     return buf;
797 }
798 
799 
800 
801 /*
802  * We can only travel forwards in time, not backwards.  :)
803  */
804 void
sleep_past(time_t desttime)805 sleep_past (time_t desttime)
806 {
807     time_t t;
808     long s;
809     long us;
810 
811     if (time (&t) > desttime) return;
812 
813     while (time (&t) <= desttime)
814     {
815 #ifdef HAVE_GETTIMEOFDAY
816 	struct timeval tv;
817 	gettimeofday (&tv, NULL);
818 	if (tv.tv_sec > desttime)
819 	    break;
820 	s = desttime - tv.tv_sec;
821 	if (tv.tv_usec > 0)
822 	    us = 1000000 - tv.tv_usec;
823 	else
824 	{
825 	    s++;
826 	    us = 0;
827 	}
828 #else
829 	/* default to 20 ms increments */
830 	s = desttime - t;
831 	us = 20000;
832 #endif
833 
834 	{
835 	    struct timespec ts;
836 	    ts.tv_sec = s;
837 	    ts.tv_nsec = us * 1000;
838 	    (void)nanosleep (&ts, NULL);
839 	}
840     }
841 
842     /* sleep another 20 ms (2 HZ) to avoid races */
843     {
844         struct timespec ts;
845         ts.tv_sec = 0;
846         ts.tv_nsec = 20 * 1000 * 1000;
847         (void)nanosleep (&ts, NULL);
848     }
849 }
850 
851 
852 
853 /* used to store callback data in a list indexed by the user format string
854  */
855 typedef int (*CONVPROC_t) (Node *, void *);
856 struct cmdline_bindings
857 {
858     char conversion;
859     void *data;
860     CONVPROC_t convproc;
861     void *closure;
862 };
863 /* since we store the above in a list, we need to dispose of the data field.
864  * we don't have to worry about convproc or closure since pointers are stuck
865  * in there directly and format_cmdline's caller is responsible for disposing
866  * of those if necessary.
867  */
868 static void
cmdline_bindings_hash_node_delete(Node * p)869 cmdline_bindings_hash_node_delete (Node *p)
870 {
871     struct cmdline_bindings *b = p->data;
872 
873     if (b->conversion != ',')
874     {
875 	free (b->data);
876     }
877     free (b);
878 }
879 
880 
881 
882 /*
883  * assume s is a literal argument and put it between quotes,
884  * escaping as appropriate for a shell command line
885  *
886  * the caller is responsible for disposing of the new string
887  */
888 char *
cmdlinequote(char quotes,char * s)889 cmdlinequote (char quotes, char *s)
890 {
891     char *quoted = cmdlineescape (quotes, s);
892     char *buf = Xasprintf ("%c%s%c", quotes, quoted, quotes);
893 
894     free (quoted);
895     return buf;
896 }
897 
898 
899 
900 /* read quotes as the type of quotes we are between (if any) and then make our
901  * argument so it could make it past a cmdline parser (using sh as a model)
902  * inside the quotes (if any).
903  *
904  * if you were planning on expanding any paths, it should be done before
905  * calling this function, as it escapes shell metacharacters.
906  *
907  * the caller is responsible for disposing of the new string
908  *
909  * FIXME: See about removing/combining this functionality with shell_escape()
910  * in subr.c.
911  */
912 char *
cmdlineescape(char quotes,char * s)913 cmdlineescape (char quotes, char *s)
914 {
915     char *buf = NULL;
916     size_t length = 0;
917     char *d = NULL;
918     size_t doff;
919     char *lastspace;
920 
921     lastspace = s - 1;
922     do
923     {
924 	/* FIXME: Single quotes only require other single quotes to be escaped
925 	 * for Bourne Shell.
926 	 */
927 	if ( isspace( *s ) ) lastspace = s;
928 	if( quotes
929 	    ? ( *s == quotes
930 	        || ( quotes == '"'
931 	             && ( *s == '$' || *s == '`' || *s == '\\' ) ) )
932 	    : ( strchr( "\\$`'\"*?", *s )
933 	        || isspace( *s )
934 	        || ( lastspace == ( s - 1 )
935 	             && *s == '~' ) ) )
936 	{
937 	    doff = d - buf;
938 	    expand_string (&buf, &length, doff + 1);
939 	    d = buf + doff;
940 	    *d++ = '\\';
941 	}
942 	doff = d - buf;
943 	expand_string (&buf, &length, doff + 1);
944 	d = buf + doff;
945     } while ((*d++ = *s++) != '\0');
946     return (buf);
947 }
948 
949 
950 
951 /* expand format strings in a command line.  modeled roughly after printf
952  *
953  * this function's arg list must be NULL terminated
954  *
955  * assume a space delimited list of args is the desired final output,
956  * but args can be quoted (" or ').
957  *
958  * the best usage examples are in tag.c & logmsg.c, but here goes:
959  *
960  * INPUTS
961  *    int oldway	to support old format strings
962  *    char *srepos	you guessed it
963  *    char *format	the format string to parse
964  *    ...		NULL terminated data list in the following format:
965  *    			char *userformat, char *printfformat, <type> data
966  *    			    where
967  *    				char *userformat	a list of possible
968  *    							format characters the
969  *    							end user might pass us
970  *    							in the format string
971  *    							(e.g. those found in
972  *    							taginfo or loginfo)
973  *    							multiple characters in
974  *    							this strings will be
975  *    							aliases for each other
976  *    				char *printfformat	the same list of args
977  *    							printf uses to
978  *    							determine what kind of
979  *    							data the next arg will
980  *    							be
981  *    				<type> data		a piece of data to be
982  *    							formatted into the user
983  *    							string, <type>
984  *    							determined by the
985  *    							printfformat string.
986  *    		or
987  *    			char *userformat, char *printfformat, List *data,
988  *    				int (*convproc) (Node *, void *), void *closure
989  *    			    where
990  *    				char *userformat	same as above, except
991  *    							multiple characters in
992  *    							this string represent
993  *    							different node
994  *    							attributes which can be
995  *    							retrieved from data by
996  *    							convproc
997  *    				char *printfformat	= ","
998  *				List *data		the list to be walked
999  *							with walklist &
1000  *							convproc to retrieve
1001  *							data for each of the
1002  *							possible format
1003  *							characters in
1004  *							userformat
1005  *				int (*convproc)()	see data
1006  *				void *closure		arg to be passed into
1007  *							walklist as closure
1008  *							data for convproc
1009  *
1010  * EXAMPLE
1011  *    (ignoring oldway variable and srepos since those are only around while we
1012  *    SUPPORT_OLD_INFO_FMT_STRINGS)
1013  *    format_cmdline ("/cvsroot/CVSROOT/mytaginfoproc %t %o %{sVv}",
1014  *                    "t", "s", "newtag",
1015  *                    "o", "s", "mov",
1016  *                    "xG", "ld", longintwhichwontbeusedthispass,
1017  *                    "sVv", ",", tlist, pretag_list_to_args_proc,
1018  *                    (void *) mydata,
1019  *                    (char *) NULL);
1020  *
1021  *    would generate the following command line, assuming two files in tlist,
1022  *    file1 & file2, each with old versions 1.1 and new version 1.1.2.3:
1023  *
1024  *    	  /cvsroot/CVSROOT/mytaginfoproc "newtag" "mov" "file1" "1.1" "1.1.2.3" "file2" "1.1" "1.1.2.3"
1025  *
1026  * RETURNS
1027  *    pointer to newly allocated string.  the caller is responsible for
1028  *    disposing of this string.
1029  */
1030 char *
1031 #ifdef SUPPORT_OLD_INFO_FMT_STRINGS
format_cmdline(bool oldway,const char * srepos,const char * format,...)1032 format_cmdline (bool oldway, const char *srepos, const char *format, ...)
1033 #else /* SUPPORT_OLD_INFO_FMT_STRINGS */
1034 format_cmdline (const char *format, ...)
1035 #endif /* SUPPORT_OLD_INFO_FMT_STRINGS */
1036 {
1037     va_list args;	/* our input function args */
1038     char *buf;		/* where we store our output string */
1039     size_t length;	/* the allocated length of our output string in bytes.
1040 			 * used as a temporary storage for the length of the
1041 			 * next function argument during function
1042 			 * initialization
1043 			 */
1044     char *pfmt;		/* initially the list of fmt keys passed in,
1045 			 * but used as a temporary key buffer later
1046 			 */
1047     char *fmt;		/* buffer for format string which we are processing */
1048     size_t flen;	/* length of fmt buffer */
1049     char *d, *q, *r;    /* for walking strings */
1050     const char *s;
1051     size_t doff, qoff;
1052     char inquotes;
1053 
1054     List *pflist = getlist();	/* our list of input data indexed by format
1055 				 * "strings"
1056 				 */
1057     Node *p;
1058     struct cmdline_bindings *b;
1059     static int warned_of_deprecation = 0;
1060     char key[] = "?";		/* Used as temporary storage for a single
1061 				 * character search string used to locate a
1062 				 * hash key.
1063 				 */
1064 #ifdef SUPPORT_OLD_INFO_FMT_STRINGS
1065     /* state varialbes in the while loop which parses the actual
1066      * format string in the final parsing pass*/
1067     int onearg;
1068     int subbedsomething;
1069 #endif /* SUPPORT_OLD_INFO_FMT_STRINGS */
1070 
1071 #ifdef SUPPORT_OLD_INFO_FMT_STRINGS
1072     if (oldway && !warned_of_deprecation)
1073     {
1074 	/* warn the user that we don't like his kind 'round these parts */
1075 	warned_of_deprecation = 1;
1076 	error (0, 0,
1077 "warning:  Set to use deprecated info format strings.  Establish\n"
1078 "compatibility with the new info file format strings (add a temporary '1' in\n"
1079 "all info files after each '%%' which doesn't represent a literal percent)\n"
1080 "and set UseNewInfoFmtStrings=yes in CVSROOT/config.  After that, convert\n"
1081 "individual command lines and scripts to handle the new format at your\n"
1082 "leisure.");
1083     }
1084 #endif /* SUPPORT_OLD_INFO_FMT_STRINGS */
1085 
1086     va_start (args, format);
1087 
1088     /* read our possible format strings
1089      * expect a certain number of arguments by type and a NULL format
1090      * string to terminate the list.
1091      */
1092     while ((pfmt = va_arg (args, char *)) != NULL)
1093     {
1094 	char *conversion = va_arg (args, char *);
1095 
1096 	char conversion_error = 0;
1097 	char char_conversion = 0;
1098 	char decimal_conversion = 0;
1099 	char integer_conversion = 0;
1100 	char string_conversion = 0;
1101 
1102 	/* allocate space to save our data */
1103 	b = xmalloc(sizeof(struct cmdline_bindings));
1104 
1105 	/* where did you think we were going to store all this data??? */
1106 	b->convproc = NULL;
1107 	b->closure = NULL;
1108 
1109 	/* read a length from the conversion string */
1110 	s = conversion;
1111 	length = 0;
1112 	while (!length && *s)
1113 	{
1114 	    switch (*s)
1115 	    {
1116 		case 'h':
1117 		    integer_conversion = 1;
1118 		    if (s[1] == 'h')
1119 		    {
1120 			length = sizeof (char);
1121 			s += 2;
1122 		    }
1123 		    else
1124 		    {
1125 			char_conversion = 1;
1126 			length = sizeof (short);
1127 			s++;
1128 		    }
1129 		    break;
1130 #ifdef HAVE_INTMAX_T
1131 		case 'j':
1132 		    integer_conversion = 1;
1133 		    length = sizeof (intmax_t);
1134 		    s++;
1135 		    break;
1136 #endif /* HAVE_INTMAX_T */
1137 		case 'l':
1138 		    integer_conversion = 1;
1139 		    if (s[1] == 'l')
1140 		    {
1141 #ifdef HAVE_LONG_LONG
1142 			length = sizeof (long long);
1143 #endif
1144 			s += 2;
1145 		    }
1146 		    else
1147 		    {
1148 			char_conversion = 2;
1149 			string_conversion = 2;
1150 			length = sizeof (long);
1151 			s++;
1152 		    }
1153 		    break;
1154 		case 't':
1155 		    integer_conversion = 1;
1156 		    length = sizeof (ptrdiff_t);
1157 		    s++;
1158 		    break;
1159 		case 'z':
1160 		    integer_conversion = 1;
1161 		    length = sizeof (size_t);
1162 		    s++;
1163 		    break;
1164 #ifdef HAVE_LONG_DOUBLE
1165 		case 'L':
1166 		    decimal_conversion = 1;
1167 		    length = sizeof (long double);
1168 		    s++;
1169 		    break;
1170 #endif
1171 		default:
1172 		    char_conversion = 1;
1173 		    decimal_conversion = 1;
1174 		    integer_conversion = 1;
1175 		    string_conversion = 1;
1176 		    /* take care of it when we find out what we're looking for */
1177 		    length = -1;
1178 		    break;
1179 	    }
1180 	}
1181 	/* if we don't have a valid conversion left, that is an error */
1182 	/* read an argument conversion */
1183 	buf = xmalloc (strlen(conversion) + 2);
1184 	*buf = '%';
1185 	strcpy (buf+1, conversion);
1186 	switch (*s)
1187 	{
1188 	    case 'c':
1189 		/* chars (an integer conversion) */
1190 		if (!char_conversion)
1191 		{
1192 		    conversion_error = 1;
1193 		    break;
1194 		}
1195 		if (char_conversion == 2)
1196 		{
1197 #ifdef HAVE_WINT_T
1198 		    length = sizeof (wint_t);
1199 #else
1200 		    conversion_error = 1;
1201 		    break;
1202 #endif
1203 		}
1204 		else
1205 		    length = sizeof (char);
1206 		/* fall through... */
1207 	    case 'd':
1208 	    case 'i':
1209 	    case 'o':
1210 	    case 'u':
1211 	    case 'x':
1212 	    case 'X':
1213 		/* integer conversions */
1214 		if (!integer_conversion)
1215 		{
1216 		    conversion_error = 1;
1217 		    break;
1218 		}
1219 		if (length == -1)
1220 		{
1221 		    length = sizeof (int);
1222 		}
1223 		switch (length)
1224 		{
1225 		    case sizeof(char):
1226 		    {
1227 		    	char arg_char = (char) va_arg (args, int);
1228 			b->data = Xasprintf (buf, arg_char);
1229 			break;
1230 		    }
1231 #ifdef UNIQUE_INT_TYPE_WINT_T		/* implies HAVE_WINT_T */
1232 		    case sizeof(wint_t):
1233 		    {
1234 		    	wint_t arg_wint_t = va_arg (args, wint_t);
1235 			b->data = Xasprintf (buf, arg_wint_t);
1236 			break;
1237 		    }
1238 #endif /* UNIQUE_INT_TYPE_WINT_T */
1239 #ifdef UNIQUE_INT_TYPE_SHORT
1240 		    case sizeof(short):
1241 		    {
1242 		    	short arg_short = (short) va_arg (args, int);
1243 			b->data = Xasprintf (buf, arg_short);
1244 			break;
1245 		    }
1246 #endif /* UNIQUE_INT_TYPE_SHORT */
1247 #ifdef UNIQUE_INT_TYPE_INT
1248 		    case sizeof(int):
1249 		    {
1250 		    	int arg_int = va_arg (args, int);
1251 			b->data = Xasprintf(buf, arg_int);
1252 			break;
1253 		    }
1254 #endif /* UNIQUE_INT_TYPE_INT */
1255 #ifdef UNIQUE_INT_TYPE_LONG
1256 		    case sizeof(long):
1257 		    {
1258 		    	long arg_long = va_arg (args, long);
1259 			b->data = Xasprintf (buf, arg_long);
1260 			break;
1261 		    }
1262 #endif /* UNIQUE_INT_TYPE_LONG */
1263 #ifdef UNIQUE_INT_TYPE_LONG_LONG	/* implies HAVE_LONG_LONG */
1264 		    case sizeof(long long):
1265 		    {
1266 		    	long long arg_long_long = va_arg (args, long long);
1267 			b->data = Xasprintf (buf, arg_long_long);
1268 			break;
1269 		    }
1270 #endif /* UNIQUE_INT_TYPE_LONG_LONG */
1271 #ifdef UNIQUE_INT_TYPE_INTMAX_T		/* implies HAVE_INTMAX_T */
1272 		    case sizeof(intmax_t):
1273 		    {
1274 		    	intmax_t arg_intmax_t = va_arg (args, intmax_t);
1275 			b->data = Xasprintf (buf, arg_intmax_t);
1276 			break;
1277 		    }
1278 #endif /* UNIQUE_INT_TYPE_INTMAX_T */
1279 #ifdef UNIQUE_INT_TYPE_SIZE_T
1280 		    case sizeof(size_t):
1281 		    {
1282 		    	size_t arg_size_t = va_arg (args, size_t);
1283 			b->data = Xasprintf (buf, arg_size_t);
1284 			break;
1285 		    }
1286 #endif /* UNIQUE_INT_TYPE_SIZE_T */
1287 #ifdef UNIQUE_INT_TYPE_PTRDIFF_T
1288 		    case sizeof(ptrdiff_t):
1289 		    {
1290 		    	ptrdiff_t arg_ptrdiff_t = va_arg (args, ptrdiff_t);
1291 			b->data = Xasprintf (buf, arg_ptrdiff_t);
1292 			break;
1293 		    }
1294 #endif /* UNIQUE_INT_TYPE_PTRDIFF_T */
1295 		    default:
1296 	    		dellist(&pflist);
1297 	    		free(b);
1298 			error (1, 0,
1299 "internal error:  unknown integer arg size (%zd)",
1300                                length);
1301 			break;
1302 		}
1303 		break;
1304 	    case 'a':
1305 	    case 'A':
1306 	    case 'e':
1307 	    case 'E':
1308 	    case 'f':
1309 	    case 'F':
1310 	    case 'g':
1311 	    case 'G':
1312 		/* decimal conversions */
1313 		if (!decimal_conversion)
1314 		{
1315 		    conversion_error = 1;
1316 		    break;
1317 		}
1318 		if (length == -1)
1319 		{
1320 		    length = sizeof (double);
1321 		}
1322 		switch (length)
1323 		{
1324 		    case sizeof(double):
1325 		    {
1326 		    	double arg_double = va_arg (args, double);
1327 			b->data = Xasprintf (buf, arg_double);
1328 			break;
1329 		    }
1330 #ifdef UNIQUE_FLOAT_TYPE_LONG_DOUBLE	/* implies HAVE_LONG_DOUBLE */
1331 		    case sizeof(long double):
1332 		    {
1333 		    	long double arg_long_double = va_arg (args, long double);
1334 			b->data = Xasprintf (buf, arg_long_double);
1335 			break;
1336 		    }
1337 #endif /* UNIQUE_FLOAT_TYPE_LONG_DOUBLE */
1338 		    default:
1339 	    		dellist(&pflist);
1340 	    		free(b);
1341 			error (1, 0,
1342 "internal error:  unknown floating point arg size (%zd)",
1343                                length);
1344 			break;
1345 		}
1346 		break;
1347 	    case 's':
1348 		switch (string_conversion)
1349 		{
1350 		    case 1:
1351 			b->data = xstrdup (va_arg (args, char *));
1352 			break;
1353 #ifdef HAVE_WCHAR_T
1354 		    case 2:
1355 		    {
1356 		    	wchar_t *arg_wchar_t_string = va_arg (args, wchar_t *);
1357 			b->data = Xasprintf (buf, arg_wchar_t_string);
1358 			break;
1359 		    }
1360 #endif /* HAVE_WCHAR_T */
1361 		    default:
1362 			conversion_error = 1;
1363 			break;
1364 		}
1365 		break;
1366 	    case ',':
1367 		if (length != -1)
1368 		{
1369 		    conversion_error = 1;
1370 		    break;
1371 		}
1372 		b->data = va_arg (args, List *);
1373 		b->convproc = va_arg (args, CONVPROC_t);
1374 		b->closure = va_arg (args, void *);
1375 		break;
1376 	    default:
1377 		conversion_error = 1;
1378 		break;
1379 	}
1380 	free (buf);
1381 	/* fail if we found an error or haven't found the end of the string */
1382 	if (conversion_error || s[1])
1383 	{
1384 	    error (1, 0,
1385 "internal error (format_cmdline): '%s' is not a valid conversion!!!",
1386                    conversion);
1387 	}
1388 
1389 
1390 	/* save our type  - we really only care wheter it's a list type (',')
1391 	 * or not from now on, but what the hell...
1392 	 */
1393 	b->conversion = *s;
1394 
1395 	/* separate the user format string into parts and stuff our data into
1396 	 * the pflist (once for each possible string - diverse keys can have
1397 	 * duplicate data).
1398 	 */
1399 	q = pfmt;
1400 	while (*q)
1401 	{
1402     	    struct cmdline_bindings *tb;
1403 	    if (*q == '{')
1404 	    {
1405 		s = q + 1;
1406 		while (*++q && *q != '}');
1407 		r = q + 1;
1408 	    }
1409 	    else
1410 	    {
1411 		s = q++;
1412 		r = q;
1413 	    }
1414 	    if (*r)
1415 	    {
1416 		/* copy the data since we'll need it again */
1417     	    	tb = xmalloc(sizeof(struct cmdline_bindings));
1418 		if (b->conversion == ',')
1419 		{
1420 		    tb->data = b->data;
1421 		}
1422 		else
1423 		{
1424 		    tb->data = xstrdup(b->data);
1425 		}
1426 		tb->conversion = b->conversion;
1427 		tb->convproc = b->convproc;
1428 		tb->closure = b->closure;
1429 	    }
1430 	    else
1431 	    {
1432 		/* we're done after this, so we don't need to copy the data */
1433 		tb = b;
1434 	    }
1435 	    p = getnode();
1436 	    p->key = xmalloc((q - s) + 1);
1437 	    strncpy (p->key, s, q - s);
1438 	    p->key[q-s] = '\0';
1439 	    p->data = tb;
1440 	    p->delproc = cmdline_bindings_hash_node_delete;
1441 	    addnode(pflist,p);
1442 	}
1443     }
1444 
1445     /* we're done with va_list */
1446     va_end(args);
1447 
1448     /* All formatted strings include a format character that resolves to the
1449      * empty string by default, so put it in pflist.
1450      */
1451     /* allocate space to save our data */
1452     b = xmalloc(sizeof(struct cmdline_bindings));
1453     b->conversion = 's';
1454     b->convproc = NULL;
1455     b->closure = NULL;
1456     b->data = xstrdup( "" );
1457     p = getnode();
1458     p->key = xstrdup( "n" );
1459     p->data = b;
1460     p->delproc = cmdline_bindings_hash_node_delete;
1461     addnode( pflist,p );
1462 
1463     /* finally, read the user string and copy it into rargv as appropriate */
1464     /* user format strings look as follows:
1465      *
1466      * %% is a literal %
1467      * \X, where X is any character = \X, (this is the escape you'd expect, but
1468      *        we are leaving the \ for an expected final pass which splits our
1469      *        output string into separate arguments
1470      *
1471      * %X means sub var "X" into location
1472      * %{VWXYZ} means sub V,W,X,Y,Z into location as a single arg.  The shell
1473      *        || would be to quote the comma separated arguments.  Each list
1474      *        that V, W, X, Y, and Z represent attributes of will cause a new
1475      *        tuple to be inserted for each list item with a space between
1476      *        items.
1477      *        e.g."V W1,X1,Z1 W2,X2,Z2 W3,X3,Z3 Y1 Y2" where V is not a list
1478      *        variable, W,X,&Z are attributes of a list with 3 items and Y is an
1479      *        attribute of a second list with 2 items.
1480      * %,{VWXYZ} means to separate the args.  The previous example would produce
1481      *        V W1 X1 Z1 W2 X2 Z2 W3 X3 Z3 Y1 Y2, where each variable is now a
1482      *        separate, space delimited, arguments within a single argument.
1483      * a%{XY}, where 'a' is a literal, still produces a single arg (a"X Y", in
1484      *        shell)
1485      * a%1{XY}, where 'a' is a literal, splits the literal as it produces
1486      *        multiple args (a X Y).  The rule is that each sub will produce a
1487      *        separate arg.  Without a comma, attributes will still be grouped
1488      *        together & comma separated in what could be a single argument,
1489      *        but internal quotes, commas, and spaces are not excaped.
1490      *
1491      * clearing the variable oldway, passed into this function, causes the
1492      * behavior of '1' and "," in the format string to reverse.
1493      */
1494 
1495     /* for convenience, use fmt as a temporary key buffer.
1496      * for speed, attempt to realloc it as little as possible
1497      */
1498     fmt = NULL;
1499     flen = 0;
1500 
1501     /* buf = current argv entry being built
1502      * length = current length of buf
1503      * s = next char in source buffer to read
1504      * d = next char location to write (in buf)
1505      * inquotes = current quote char or NUL
1506      */
1507     s = format;
1508     d = buf = NULL;
1509     length = 0;
1510     doff = d - buf;
1511     expand_string (&buf, &length, doff + 1);
1512     d = buf + doff;
1513 
1514     inquotes = '\0';
1515 #ifdef SUPPORT_OLD_INFO_FMT_STRINGS
1516     subbedsomething = 0;
1517 #endif /* SUPPORT_OLD_INFO_FMT_STRINGS */
1518     while ((*d++ = *s) != '\0')
1519     {
1520 	int list = 0;
1521 	switch (*s++)
1522 	{
1523 	    case '\\':
1524 		/* the character after a \ goes unprocessed but leave the \ in
1525 		 * the string so the function that splits this string into a
1526 		 * command line later can deal with quotes properly
1527 		 *
1528 		 * ignore a NUL
1529 		 */
1530 		if (*s)
1531 		{
1532     		    doff = d - buf;
1533 		    expand_string (&buf, &length, doff + 1);
1534 		    d = buf + doff;
1535 		    *d++ = *s++;
1536 		}
1537 		break;
1538 	    case '\'':
1539 	    case '"':
1540 		/* keep track of quotes so we can escape quote chars we sub in
1541 		 * - the API is that a quoted format string will guarantee that
1542 		 * it gets passed into the command as a single arg
1543 		 */
1544 		if (!inquotes) inquotes = s[-1];
1545 		else if (s[-1] == inquotes) inquotes = '\0';
1546 		break;
1547 	    case '%':
1548 		if (*s == '%')
1549 		{
1550 		    /* "%%" is a literal "%" */
1551 		    s++;
1552 		    break;
1553 		}
1554 #ifdef SUPPORT_OLD_INFO_FMT_STRINGS
1555 		if (oldway && subbedsomething)
1556 		{
1557 		    /* the old method was to sub only the first format string */
1558 		    break;
1559 		}
1560 		/* initialize onearg each time we get a new format string */
1561 		onearg = oldway ? 1 : 0;
1562 		subbedsomething = 1;
1563 #endif /* SUPPORT_OLD_INFO_FMT_STRINGS */
1564 		d--;	/* we're going to overwrite the '%' regardless
1565 			 * of other factors... */
1566 #ifdef SUPPORT_OLD_INFO_FMT_STRINGS
1567 		/* detect '1' && ',' in the fmt string. */
1568 		if (*s == '1')
1569 		{
1570 		    onearg = 1;
1571 		    s++;
1572 		    if (!oldway)
1573 		    {
1574 			/* FIXME - add FILE && LINE */
1575 			error (0, 0,
1576 "Using deprecated info format strings.  Convert your scripts to use\n"
1577 "the new argument format and remove '1's from your info file format strings.");
1578 		    }
1579 		}
1580 #endif /* SUPPORT_OLD_INFO_FMT_STRINGS */
1581 
1582 		/* parse the format string and sub in... */
1583 		if (*s == '{')
1584 		{
1585 		    list = 1;
1586 		    s++;
1587 		}
1588 		/* q = fmt start
1589 		 * r = fmt end + 1
1590 		 */
1591 		q = fmt;
1592 		do
1593 		{
1594 		    qoff = q - fmt;
1595 		    expand_string (&fmt, &flen, qoff + 1);
1596 		    q = fmt + qoff;
1597 		} while ((*q = *s++) && list && *q++ != '}');
1598 		/* we will always copy one character, so, whether in list mode
1599 		 * or not, if we just copied a '\0', then we hit the end of the
1600 		 * string before we should have
1601 		 */
1602 		if (!s[-1])
1603 		{
1604 		    /* if we copied a NUL while processing a list, fail
1605 		     * - we had an empty fmt string or didn't find a list
1606 		     * terminator ('}')
1607 		     */
1608 		    /* FIXME - this wants a file name and line number in a bad
1609 		     * way.
1610 		     */
1611 		    error(1, 0,
1612 "unterminated format string encountered in command spec.\n"
1613 "This error is likely to have been caused by an invalid line in a hook script\n"
1614 "spec (see taginfo, loginfo, verifymsginfo, etc. in the Cederqvist).  Most\n"
1615 "likely the offending line would end with a '%%' character or contain a string\n"
1616 "beginning \"%%{\" and no closing '}' before the end of the line.");
1617 		}
1618 		if (list)
1619 		{
1620 		    q[-1] = '\0';
1621 		}
1622 		else
1623 		{
1624 		    /* We're not in a list, so we must have just copied a
1625 		     * single character.  Terminate the string.
1626 		     */
1627 		    q++;
1628 		    qoff = q - fmt;
1629 		    expand_string (&fmt, &flen, qoff + 1);
1630 		    q = fmt + qoff;
1631 		    *q = '\0';
1632 		}
1633 		/* fmt is now a pointer to a list of fmt chars, though the list
1634 		 * could be a single element one
1635 		 */
1636 		q = fmt;
1637 #ifdef SUPPORT_OLD_INFO_FMT_STRINGS
1638 		/* always add quotes in the deprecated onearg case - for
1639 		 * backwards compatibility
1640 		 */
1641 		if (onearg)
1642 		{
1643 		    doff = d - buf;
1644 		    expand_string (&buf, &length, doff + 1);
1645 		    d = buf + doff;
1646 		    *d++ = '"';
1647 		}
1648 #endif /* SUPPORT_OLD_INFO_FMT_STRINGS */
1649 		/*
1650 		 * for each character in the fmt string,
1651 		 *
1652 		 * all output will be separate quoted arguments (with
1653 		 * internal quotes escaped) if the argument is in quotes
1654 		 * unless the oldway variable is set, in which case the fmt
1655 		 * statment will correspond to a single argument with
1656 		 * internal space or comma delimited arguments
1657 		 *
1658 		 * see the "user format strings" section above for more info
1659 		 */
1660 		key[0] = *q;
1661 		if ((p = findnode (pflist, key)) != NULL)
1662 		{
1663 		    b = p->data;
1664 		    if (b->conversion == ',')
1665 		    {
1666 			/* process the rest of the format string as a list */
1667 			struct format_cmdline_walklist_closure c;
1668 			c.format = q;
1669 			c.buf = &buf;
1670 			c.length = &length;
1671 			c.d = &d;
1672 			c.quotes = inquotes;
1673 			c.closure = b->closure;
1674 #ifdef SUPPORT_OLD_INFO_FMT_STRINGS
1675 			c.onearg = onearg;
1676 			c.firstpass = 1;
1677 			c.srepos = srepos;
1678 #endif /* SUPPORT_OLD_INFO_FMT_STRINGS */
1679 			walklist(b->data, b->convproc, &c);
1680 			d--;	/* back up one space.  we know that ^
1681 				   always adds 1 extra */
1682 			q += strlen(q);
1683 		    }
1684 		    else
1685 		    {
1686 			/* got a flat item */
1687 			char *outstr;
1688 			if (strlen(q) > 1)
1689 			{
1690 			    error (1, 0,
1691 "Multiple non-list variables are not allowed in a single format string.");
1692 			}
1693 #ifdef SUPPORT_OLD_INFO_FMT_STRINGS
1694 			if (onearg)
1695 			{
1696 			    outstr = b->data;
1697 			}
1698 			else /* !onearg */
1699 			{
1700 #endif /* SUPPORT_OLD_INFO_FMT_STRINGS */
1701 			    /* the *only* case possible without
1702 			     * SUPPORT_OLD_INFO_FORMAT_STRINGS
1703 			     * - !onearg */
1704 			    if (!inquotes)
1705 			    {
1706 				doff = d - buf;
1707 				expand_string (&buf, &length, doff + 1);
1708 				d = buf + doff;
1709 				*d++ = '"';
1710 			    }
1711 			    outstr = cmdlineescape (inquotes ? inquotes : '"', b->data);
1712 #ifdef SUPPORT_OLD_INFO_FMT_STRINGS
1713 			} /* onearg */
1714 #endif /* SUPPORT_OLD_INFO_FMT_STRINGS */
1715 			doff = d - buf;
1716 			expand_string (&buf, &length, doff + strlen(outstr));
1717 			d = buf + doff;
1718 			strncpy(d, outstr, strlen(outstr));
1719 			d += strlen(outstr);
1720 #ifdef SUPPORT_OLD_INFO_FMT_STRINGS
1721 			if (!onearg)
1722 			{
1723 			    free(outstr);
1724 #endif /* SUPPORT_OLD_INFO_FMT_STRINGS */
1725 			    if (!inquotes)
1726 			    {
1727 				doff = d - buf;
1728 				expand_string (&buf, &length, doff + 1);
1729 				d = buf + doff;
1730 				*d++ = '"';
1731 			    }
1732 #ifdef SUPPORT_OLD_INFO_FMT_STRINGS
1733 			}
1734 #endif /* SUPPORT_OLD_INFO_FMT_STRINGS */
1735 			q++;
1736 		    }
1737 		}
1738 #ifdef SUPPORT_OLD_INFO_FMT_STRINGS
1739 		else if (onearg)
1740 		{
1741 		    /* the old standard was to ignore unknown format
1742 		     * characters (print the empty string), but also that
1743 		     * any format character meant print srepos first
1744 		     */
1745 		    q++;
1746 		    doff = d - buf;
1747 		    expand_string (&buf, &length, doff + strlen(srepos));
1748 		    d = buf + doff;
1749 		    strncpy(d, srepos, strlen(srepos));
1750 		    d += strlen(srepos);
1751 		}
1752 #endif /* SUPPORT_OLD_INFO_FMT_STRINGS */
1753 		else /* no key */
1754 		{
1755 		    /* print an error message to the user
1756 		     * FIXME - this should have a file and line number!!! */
1757 		    error (1, 0,
1758 "Unknown format character in info file ('%s').\n"
1759 "Info files are the hook files, verifymsg, taginfo, commitinfo, etc.",
1760                            q);
1761 		}
1762 #ifdef SUPPORT_OLD_INFO_FMT_STRINGS
1763 		/* always add quotes in the deprecated onearg case - for
1764 		 * backwards compatibility
1765 		 */
1766 		if (onearg)
1767 		{
1768 		    doff = d - buf;
1769 		    expand_string (&buf, &length, doff + 1);
1770 		    d = buf + doff;
1771 		    *d++ = '"';
1772 		}
1773 #endif /* SUPPORT_OLD_INFO_FMT_STRINGS */
1774 		break;
1775 	}
1776 	doff = d - buf;
1777 	expand_string (&buf, &length, doff + 1);
1778 	d = buf + doff;
1779     } /* while (*d++ = *s) */
1780     if (fmt) free (fmt);
1781     if (inquotes)
1782     {
1783 	/* FIXME - we shouldn't need this - Parse_Info should be handling
1784 	 * multiple lines...
1785 	 */
1786 	error (1, 0, "unterminated quote in format string: %s", format);
1787     }
1788 
1789     dellist (&pflist);
1790     return buf;
1791 }
1792 
1793 
1794 
1795 /* Like xstrdup (), but can handle a NULL argument.
1796  */
1797 char *
Xstrdup(const char * string)1798 Xstrdup (const char *string)
1799 {
1800   if (string == NULL) return NULL;
1801   return xmemdup (string, strlen (string) + 1);
1802 }
1803 
1804 
1805 
1806 /* Like xasprintf(), but consider all errors fatal (may never return NULL).
1807  */
1808 char *
Xasprintf(const char * format,...)1809 Xasprintf (const char *format, ...)
1810 {
1811     va_list args;
1812     char *result;
1813 
1814     va_start (args, format);
1815     if (vasprintf (&result, format, args) < 0)
1816 	error (1, errno, "Failed to write to string.");
1817     va_end (args);
1818 
1819     return result;
1820 }
1821 
1822 
1823 
1824 /* Like xasnprintf(), but consider all errors fatal (may never return NULL).
1825  */
1826 char *
Xasnprintf(char * resultbuf,size_t * lengthp,const char * format,...)1827 Xasnprintf (char *resultbuf, size_t *lengthp, const char *format, ...)
1828 {
1829     va_list args;
1830     char *result;
1831 
1832     va_start (args, format);
1833     result = vasnprintf (resultbuf, lengthp, format, args);
1834     if (result == NULL)
1835 	error (1, errno, "Failed to write to string.");
1836     va_end (args);
1837 
1838     return result;
1839 }
1840 
1841 
1842 
1843 /* Print a warning and return false if P doesn't look like a string specifying
1844  * a boolean value.
1845  *
1846  * Sets *VAL to the parsed value when it is found to be valid.  *VAL will not
1847  * be altered when false is returned.
1848  *
1849  * INPUTS
1850  *   infopath	Where the error is reported to be from on error.  This could
1851  *		be, for example, the name of the file the boolean is being read
1852  *		from.
1853  *   option	An option name being parsed, reported in traces and any error
1854  *		message.
1855  *   p		The string to actually read the option from.
1856  *   val	Pointer to where to store the boolean read from P.
1857  *
1858  * OUTPUTS
1859  *   val	TRUE/FALSE stored, as read, when there are no errors.
1860  *
1861  * RETURNS
1862  *   true	If VAL was read.
1863  *   false	On error.
1864  */
1865 bool
readBool(const char * infopath,const char * option,const char * p,bool * val)1866 readBool (const char *infopath, const char *option, const char *p, bool *val)
1867 {
1868     TRACE (TRACE_FLOW, "readBool (%s, %s, %s)", infopath, option, p);
1869     if (!strcasecmp (p, "no") || !strcasecmp (p, "false")
1870         || !strcasecmp (p, "off") || !strcmp (p, "0"))
1871     {
1872 	TRACE (TRACE_DATA, "Read %d for %s", *val, option);
1873 	*val = false;
1874 	return true;
1875     }
1876     else if (!strcasecmp (p, "yes") || !strcasecmp (p, "true")
1877 	     || !strcasecmp (p, "on") || !strcmp (p, "1"))
1878     {
1879 	TRACE (TRACE_DATA, "Read %d for %s", *val, option);
1880 	*val = true;
1881 	return true;
1882     }
1883 
1884     error (0, 0, "%s: unrecognized value `%s' for `%s'",
1885 	   infopath, p, option);
1886     return false;
1887 }
1888 
1889 
1890 
1891 /*
1892  * Open a file, exiting with a message on error.
1893  *
1894  * INPUTS
1895  *   name	The name of the file to open.
1896  *   mode	Mode to open file in, as POSIX fopen().
1897  *
1898  * NOTES
1899  *   If you want to handle errors, just call fopen (NAME, MODE).
1900  *
1901  * RETURNS
1902  *   The new FILE pointer.
1903  */
1904 FILE *
xfopen(const char * name,const char * mode)1905 xfopen (const char *name, const char *mode)
1906 {
1907     FILE *fp;
1908 
1909     if (!(fp = fopen (name, mode)))
1910 	error (1, errno, "cannot open %s", name);
1911     return fp;
1912 }
1913 
1914 
1915 
1916 /* char *
1917  * xcanonicalize_file_name (const char *path)
1918  *
1919  * Like canonicalize_file_name(), but exit on error.
1920  *
1921  * INPUTS
1922  *  path	The original path.
1923  *
1924  * RETURNS
1925  *  The path with any symbolic links, `.'s, or `..'s, expanded.
1926  *
1927  * ERRORS
1928  *  This function exits with a fatal error if it fails to read the link for
1929  *  any reason.
1930  */
1931 char *
xcanonicalize_file_name(const char * path)1932 xcanonicalize_file_name (const char *path)
1933 {
1934     char *hardpath = canonicalize_file_name (path);
1935     if (!hardpath)
1936 	error (1, errno, "Failed to resolve path: `%s'", path);
1937     return hardpath;
1938 }
1939 
1940 
1941 
1942 /* Declared in main.c.  */
1943 extern char *server_hostname;
1944 
1945 /* Return true if OTHERHOST resolves to this host in the DNS.
1946  *
1947  * GLOBALS
1948  *   server_hostname	The name of this host, as determined by the call to
1949  *			xgethostname() in main().
1950  *
1951  * RETURNS
1952  *   true	If OTHERHOST equals or resolves to HOSTNAME.
1953  *   false	Otherwise.
1954  */
1955 bool
isThisHost(const char * otherhost)1956 isThisHost (const char *otherhost)
1957 {
1958     char *fqdno;
1959     char *fqdns;
1960     bool retval;
1961 
1962     /* As an optimization, check the literal strings before looking up
1963      * OTHERHOST in the DNS.
1964      */
1965     if (!strcasecmp (server_hostname, otherhost))
1966 	return true;
1967 
1968     fqdno = canon_host (otherhost);
1969     if (!fqdno)
1970 	error (1, 0, "Name lookup failed for `%s': %s",
1971 	       otherhost, ch_strerror ());
1972     fqdns = canon_host (server_hostname);
1973     if (!fqdns)
1974 	error (1, 0, "Name lookup failed for `%s': %s",
1975 	       server_hostname, ch_strerror ());
1976 
1977     retval = !strcasecmp (fqdns, fqdno);
1978 
1979     free (fqdno);
1980     free (fqdns);
1981     return retval;
1982 }
1983 
1984 
1985 
1986 /* Return true if two paths match, resolving symlinks.
1987  */
1988 bool
isSamePath(const char * path1_in,const char * path2_in)1989 isSamePath (const char *path1_in, const char *path2_in)
1990 {
1991     char *p1, *p2;
1992     bool same;
1993 
1994     if (!strcmp (path1_in, path2_in))
1995 	return true;
1996 
1997     /* Path didn't match, but try to resolve any links that may be
1998      * present.
1999      */
2000     if (!isdir (path1_in) || !isdir (path2_in))
2001 	/* To be resolvable, paths must exist on this server.  */
2002 	return false;
2003 
2004     p1 = xcanonicalize_file_name (path1_in);
2005     p2 = xcanonicalize_file_name (path2_in);
2006     if (strcmp (p1, p2))
2007 	same = false;
2008     else
2009 	same = true;
2010 
2011     free (p1);
2012     free (p2);
2013     return same;
2014 }
2015