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