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