Bug Summary

File:src/gnu/usr.bin/cvs/src/subr.c
Warning:line 291, column 10
Although the value stored to 's' is used in the enclosing expression, the value is never actually read from 's'

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple amd64-unknown-openbsd7.0 -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name subr.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 1 -pic-is-pie -mframe-pointer=all -relaxed-aliasing -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -target-feature +retpoline-indirect-calls -target-feature +retpoline-indirect-branches -tune-cpu generic -debugger-tuning=gdb -fcoverage-compilation-dir=/usr/src/gnu/usr.bin/cvs/obj/src -resource-dir /usr/local/lib/clang/13.0.0 -D HAVE_CONFIG_H -I . -I /usr/src/gnu/usr.bin/cvs/src -I .. -I . -I /usr/src/gnu/usr.bin/cvs/lib -I /usr/src/gnu/usr.bin/cvs/diff -internal-isystem /usr/local/lib/clang/13.0.0/include -internal-externc-isystem /usr/include -O2 -fdebug-compilation-dir=/usr/src/gnu/usr.bin/cvs/obj/src -ferror-limit 19 -fwrapv -D_RET_PROTECTOR -ret-protector -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -fno-builtin-malloc -fno-builtin-calloc -fno-builtin-realloc -fno-builtin-valloc -fno-builtin-free -fno-builtin-strdup -fno-builtin-strndup -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /home/ben/Projects/vmm/scan-build/2022-01-12-194120-40624-1 -x c /usr/src/gnu/usr.bin/cvs/src/subr.c
1/*
2 * Copyright (c) 1992, Brian Berliner and Jeff Polk
3 * Copyright (c) 1989-1992, Brian Berliner
4 *
5 * You may distribute under the terms of the GNU General Public License as
6 * specified in the README file that comes with the CVS source distribution.
7 *
8 * Various useful functions for the CVS support code.
9 */
10
11#include "cvs.h"
12#include "getline.h"
13
14#ifdef HAVE_NANOSLEEP1
15# include "xtime.h"
16#else /* HAVE_NANOSLEEP */
17# if !defined HAVE_USLEEP && defined HAVE_SELECT
18 /* use select as a workaround */
19# include "xselect.h"
20# endif /* !defined HAVE_USLEEP && defined HAVE_SELECT */
21#endif /* !HAVE_NANOSLEEP */
22
23extern char *getlogin ();
24
25/*
26 * malloc some data and die if it fails
27 */
28void *
29xmalloc (bytes)
30 size_t bytes;
31{
32 char *cp;
33
34 /* Parts of CVS try to xmalloc zero bytes and then free it. Some
35 systems have a malloc which returns NULL for zero byte
36 allocations but a free which can't handle NULL, so compensate. */
37 if (bytes == 0)
38 bytes = 1;
39
40 cp = malloc (bytes);
41 if (cp == NULL((void*)0))
42 {
43 char buf[80];
44 snprintf (buf, sizeof buf, "out of memory; can not allocate %lu bytes",
45 (unsigned long) bytes);
46 error (1, 0, buf);
47 }
48 return (cp);
49}
50
51/*
52 * realloc data and die if it fails [I've always wanted to have "realloc" do
53 * a "malloc" if the argument is NULL, but you can't depend on it. Here, I
54 * can *force* it.
55 */
56void *
57xrealloc (ptr, bytes)
58 void *ptr;
59 size_t bytes;
60{
61 char *cp;
62
63 if (!ptr)
64 cp = malloc (bytes);
65 else
66 cp = realloc (ptr, bytes);
67
68 if (cp == NULL((void*)0))
69 {
70 char buf[80];
71 snprintf (buf, sizeof buf, "out of memory; can not reallocate %lu bytes",
72 (unsigned long) bytes);
73 error (1, 0, buf);
74 }
75 return (cp);
76}
77
78/* Two constants which tune expand_string. Having MIN_INCR as large
79 as 1024 might waste a bit of memory, but it shouldn't be too bad
80 (CVS used to allocate arrays of, say, 3000, PATH_MAX (8192, often),
81 or other such sizes). Probably anything which is going to allocate
82 memory which is likely to get as big as MAX_INCR shouldn't be doing
83 it in one block which must be contiguous, but since getrcskey does
84 so, we might as well limit the wasted memory to MAX_INCR or so
85 bytes.
86
87 MIN_INCR and MAX_INCR should both be powers of two and we generally
88 try to keep our allocations to powers of two for the most part.
89 Most malloc implementations these days tend to like that. */
90
91#define MIN_INCR1024 1024
92#define MAX_INCR(2*1024*1024) (2*1024*1024)
93
94/* *STRPTR is a pointer returned from malloc (or NULL), pointing to *N
95 characters of space. Reallocate it so that points to at least
96 NEWSIZE bytes of space. Gives a fatal error if out of memory;
97 if it returns it was successful. */
98void
99expand_string (strptr, n, newsize)
100 char **strptr;
101 size_t *n;
102 size_t newsize;
103{
104 if (*n < newsize)
105 {
106 while (*n < newsize)
107 {
108 if (*n < MIN_INCR1024)
109 *n = MIN_INCR1024;
110 else if (*n >= MAX_INCR(2*1024*1024))
111 *n += MAX_INCR(2*1024*1024);
112 else
113 {
114 *n *= 2;
115 if (*n > MAX_INCR(2*1024*1024))
116 *n = MAX_INCR(2*1024*1024);
117 }
118 }
119 *strptr = xrealloc (*strptr, *n);
120 }
121}
122
123/* *STR is a pointer to a malloc'd string. *LENP is its allocated
124 length. Add SRC to the end of it, reallocating if necessary. */
125void
126allocate_and_strcat (str, lenp, src)
127 char **str;
128 size_t *lenp;
129 const char *src;
130{
131
132 expand_string (str, lenp, strlen (*str) + strlen (src) + 1);
133 strcat (*str, src);
134}
135
136/*
137 * Duplicate a string, calling xmalloc to allocate some dynamic space
138 */
139char *
140xstrdup (str)
141 const char *str;
142{
143 char *s;
144
145 if (str == NULL((void*)0))
146 return ((char *) NULL((void*)0));
147 s = xmalloc (strlen (str) + 1);
148 (void) strcpy (s, str);
149 return (s);
150}
151
152/* Remove trailing newlines from STRING, destructively. */
153void
154strip_trailing_newlines (str)
155 char *str;
156{
157 int len;
158 len = strlen (str) - 1;
159
160 while (str[len] == '\n')
161 str[len--] = '\0';
162}
163
164/* Return the number of levels that path ascends above where it starts.
165 For example:
166 "../../foo" -> 2
167 "foo/../../bar" -> 1
168 */
169/* FIXME: Should be using ISDIRSEP, last_component, or some other
170 mechanism which is more general than just looking at slashes,
171 particularly for the client.c caller. The server.c caller might
172 want something different, so be careful. */
173int
174pathname_levels (path)
175 char *path;
176{
177 char *p;
178 char *q;
179 int level;
180 int max_level;
181
182 max_level = 0;
183 p = path;
184 level = 0;
185 do
186 {
187 q = strchr (p, '/');
188 if (q != NULL((void*)0))
189 ++q;
190 if (p[0] == '.' && p[1] == '.' && (p[2] == '\0' || p[2] == '/'))
191 {
192 --level;
193 if (-level > max_level)
194 max_level = -level;
195 }
196 else if (p[0] == '\0' || p[0] == '/' ||
197 (p[0] == '.' && (p[1] == '\0' || p[1] == '/')))
198 ;
199 else
200 ++level;
201 p = q;
202 } while (p != NULL((void*)0));
203 return max_level;
204}
205
206
207/* Free a vector, where (*ARGV)[0], (*ARGV)[1], ... (*ARGV)[*PARGC - 1]
208 are malloc'd and so is *ARGV itself. Such a vector is allocated by
209 line2argv or expand_wild, for example. */
210void
211free_names (pargc, argv)
212 int *pargc;
213 char **argv;
214{
215 register int i;
216
217 for (i = 0; i < *pargc; i++)
218 { /* only do through *pargc */
219 free (argv[i]);
220 }
221 free (argv);
222 *pargc = 0; /* and set it to zero when done */
223}
224
225/* Convert LINE into arguments separated by SEPCHARS. Set *ARGC
226 to the number of arguments found, and (*ARGV)[0] to the first argument,
227 (*ARGV)[1] to the second, etc. *ARGV is malloc'd and so are each of
228 (*ARGV)[0], (*ARGV)[1], ... Use free_names() to return the memory
229 allocated here back to the free pool. */
230void
231line2argv (pargc, argv, line, sepchars)
232 int *pargc;
233 char ***argv;
234 char *line;
235 char *sepchars;
236{
237 char *cp;
238 /* Could make a case for size_t or some other unsigned type, but
239 we'll stick with int to avoid signed/unsigned warnings when
240 comparing with *pargc. */
241 int argv_allocated;
242
243 /* Small for testing. */
244 argv_allocated = 1;
245 *argv = (char **) xmalloc (argv_allocated * sizeof (**argv));
246
247 *pargc = 0;
248 for (cp = strtok (line, sepchars); cp; cp = strtok ((char *) NULL((void*)0), sepchars))
249 {
250 if (*pargc == argv_allocated)
251 {
252 argv_allocated *= 2;
253 *argv = xrealloc (*argv, argv_allocated * sizeof (**argv));
254 }
255 (*argv)[*pargc] = xstrdup (cp);
256 (*pargc)++;
257 }
258}
259
260/*
261 * Returns the number of dots ('.') found in an RCS revision number
262 */
263int
264numdots (s)
265 const char *s;
266{
267 int dots = 0;
268
269 for (; *s; s++)
270 {
271 if (*s == '.')
272 dots++;
273 }
274 return (dots);
275}
276
277/* Compare revision numbers REV1 and REV2 by consecutive fields.
278 Return negative, zero, or positive in the manner of strcmp. The
279 two revision numbers must have the same number of fields, or else
280 compare_revnums will return an inaccurate result. */
281int
282compare_revnums (rev1, rev2)
283 const char *rev1;
284 const char *rev2;
285{
286 const char *s, *sp;
287 const char *t, *tp;
288 char *snext, *tnext;
289 int result = 0;
290
291 sp = s = rev1;
Although the value stored to 's' is used in the enclosing expression, the value is never actually read from 's'
292 tp = t = rev2;
293 while (result == 0)
294 {
295 result = strtoul (sp, &snext, 10) - strtoul (tp, &tnext, 10);
296 if (*snext == '\0' || *tnext == '\0')
297 break;
298 sp = snext + 1;
299 tp = tnext + 1;
300 }
301
302 return result;
303}
304
305char *
306increment_revnum (rev)
307 const char *rev;
308{
309 char *newrev, *p;
310 int lastfield;
311 size_t len = strlen (rev);
312
313 newrev = (char *) xmalloc (len + 2);
314 memcpy (newrev, rev, len + 1);
315 p = strrchr (newrev, '.');
316 if (p == NULL((void*)0))
317 {
318 free (newrev);
319 return NULL((void*)0);
320 }
321 lastfield = atoi (++p);
322 sprintf (p, "%d", lastfield + 1);
323
324 return newrev;
325}
326
327/* Return the username by which the caller should be identified in
328 CVS, in contexts such as the author field of RCS files, various
329 logs, etc. */
330char *
331getcaller ()
332{
333#ifndef SYSTEM_GETCALLER
334 static char *cache;
335 struct passwd *pw;
336 uid_t uid;
337#endif
338
339 /* If there is a CVS username, return it. */
340#ifdef AUTH_SERVER_SUPPORT
341 if (CVS_Username != NULL((void*)0))
342 return CVS_Username;
343#endif
344
345#ifdef SYSTEM_GETCALLER
346 return SYSTEM_GETCALLER ();
347#else
348 /* Get the caller's login from his uid. If the real uid is "root"
349 try LOGNAME USER or getlogin(). If getlogin() and getpwuid()
350 both fail, return the uid as a string. */
351
352 if (cache != NULL((void*)0))
353 return cache;
354
355 uid = getuid ();
356 if (uid == (uid_t) 0)
357 {
358 char *name;
359
360 /* super-user; try getlogin() to distinguish */
361 if (((name = getlogin ()) || (name = getenv("LOGNAME")) ||
362 (name = getenv("USER"))) && *name)
363 {
364 cache = xstrdup (name);
365 return cache;
366 }
367 }
368 if ((pw = (struct passwd *) getpwuid (uid)) == NULL((void*)0))
369 {
370 char uidname[20];
371
372 (void) snprintf (uidname, sizeof uidname, "uid%lu", (unsigned long) uid);
373 cache = xstrdup (uidname);
374 return cache;
375 }
376 cache = xstrdup (pw->pw_name);
377 return cache;
378#endif
379}
380
381#ifdef lint
382#ifndef __GNUC__4
383/* ARGSUSED */
384time_t
385get_date (date)
386 char *date;
387{
388 time_t foo = 0;
389
390 return (foo);
391}
392#endif
393#endif
394
395/* Given two revisions, find their greatest common ancestor. If the
396 two input revisions exist, then rcs guarantees that the gca will
397 exist. */
398
399char *
400gca (rev1, rev2)
401 const char *rev1;
402 const char *rev2;
403{
404 int dots;
405 char *gca;
406 const char *p[2];
407 int j[2];
408 char *retval;
409
410 if (rev1 == NULL((void*)0) || rev2 == NULL((void*)0))
411 {
412 error (0, 0, "sanity failure in gca");
413 abort();
414 }
415
416 /* The greatest common ancestor will have no more dots, and numbers
417 of digits for each component no greater than the arguments. Therefore
418 this string will be big enough. */
419 gca = xmalloc (strlen (rev1) + strlen (rev2) + 100);
420
421 /* walk the strings, reading the common parts. */
422 gca[0] = '\0';
423 p[0] = rev1;
424 p[1] = rev2;
425 do
426 {
427 int i;
428 char c[2];
429 char *s[2];
430
431 for (i = 0; i < 2; ++i)
432 {
433 /* swap out the dot */
434 s[i] = strchr (p[i], '.');
435 if (s[i] != NULL((void*)0)) {
436 c[i] = *s[i];
437 }
438
439 /* read an int */
440 j[i] = atoi (p[i]);
441
442 /* swap back the dot... */
443 if (s[i] != NULL((void*)0)) {
444 *s[i] = c[i];
445 p[i] = s[i] + 1;
446 }
447 else
448 {
449 /* or mark us at the end */
450 p[i] = NULL((void*)0);
451 }
452
453 }
454
455 /* use the lowest. */
456 (void) sprintf (gca + strlen (gca), "%d.",
457 j[0] < j[1] ? j[0] : j[1]);
458
459 } while (j[0] == j[1]
460 && p[0] != NULL((void*)0)
461 && p[1] != NULL((void*)0));
462
463 /* back up over that last dot. */
464 gca[strlen(gca) - 1] = '\0';
465
466 /* numbers differ, or we ran out of strings. we're done with the
467 common parts. */
468
469 dots = numdots (gca);
470 if (dots == 0)
471 {
472 /* revisions differ in trunk major number. */
473
474 char *q;
475 const char *s;
476
477 s = (j[0] < j[1]) ? p[0] : p[1];
478
479 if (s == NULL((void*)0))
480 {
481 /* we only got one number. this is strange. */
482 error (0, 0, "bad revisions %s or %s", rev1, rev2);
483 abort();
484 }
485 else
486 {
487 /* we have a minor number. use it. */
488 q = gca + strlen (gca);
489
490 *q++ = '.';
491 for ( ; *s != '.' && *s != '\0'; )
492 *q++ = *s++;
493
494 *q = '\0';
495 }
496 }
497 else if ((dots & 1) == 0)
498 {
499 /* if we have an even number of dots, then we have a branch.
500 remove the last number in order to make it a revision. */
501
502 char *s;
503
504 s = strrchr(gca, '.');
505 *s = '\0';
506 }
507
508 retval = xstrdup (gca);
509 free (gca);
510 return retval;
511}
512
513/* Give fatal error if REV is numeric and ARGC,ARGV imply we are
514 planning to operate on more than one file. The current directory
515 should be the working directory. Note that callers assume that we
516 will only be checking the first character of REV; it need not have
517 '\0' at the end of the tag name and other niceties. Right now this
518 is only called from admin.c, but if people like the concept it probably
519 should also be called from diff -r, update -r, get -r, and log -r. */
520
521void
522check_numeric (rev, argc, argv)
523 const char *rev;
524 int argc;
525 char **argv;
526{
527 if (rev == NULL((void*)0) || !isdigit ((unsigned char) *rev))
528 return;
529
530 /* Note that the check for whether we are processing more than one
531 file is (basically) syntactic; that is, we don't behave differently
532 depending on whether a directory happens to contain only a single
533 file or whether it contains more than one. I strongly suspect this
534 is the least confusing behavior. */
535 if (argc != 1
536 || (!wrap_name_has (argv[0], WRAP_TOCVS) && isdir (argv[0])))
537 {
538 error (0, 0, "while processing more than one file:");
539 error (1, 0, "attempt to specify a numeric revision");
540 }
541}
542
543/*
544 * Sanity checks and any required fix-up on message passed to RCS via '-m'.
545 * RCS 5.7 requires that a non-total-whitespace, non-null message be provided
546 * with '-m'. Returns a newly allocated, non-empty buffer with whitespace
547 * stripped from end of lines and end of buffer.
548 *
549 * TODO: We no longer use RCS to manage repository files, so maybe this
550 * nonsense about non-empty log fields can be dropped.
551 */
552char *
553make_message_rcslegal (message)
554 char *message;
555{
556 char *dst, *dp, *mp;
557
558 if (message == NULL((void*)0)) message = "";
559
560 /* Strip whitespace from end of lines and end of string. */
561 dp = dst = (char *) xmalloc (strlen (message) + 1);
562 for (mp = message; *mp != '\0'; ++mp)
563 {
564 if (*mp == '\n')
565 {
566 /* At end-of-line; backtrack to last non-space. */
567 while (dp > dst && (dp[-1] == ' ' || dp[-1] == '\t'))
568 --dp;
569 }
570 *dp++ = *mp;
571 }
572
573 /* Backtrack to last non-space at end of string, and truncate. */
574 while (dp > dst && isspace ((unsigned char) dp[-1]))
575 --dp;
576 *dp = '\0';
577
578 /* After all that, if there was no non-space in the string,
579 substitute a non-empty message. */
580 if (*dst == '\0')
581 {
582 free (dst);
583 dst = xstrdup ("*** empty log message ***");
584 }
585
586 return dst;
587}
588
589/* Does the file FINFO contain conflict markers? The whole concept
590 of looking at the contents of the file to figure out whether there are
591 unresolved conflicts is kind of bogus (people do want to manage files
592 which contain those patterns not as conflict markers), but for now it
593 is what we do. */
594int
595file_has_markers (finfo)
596 const struct file_info *finfo;
597{
598 FILE *fp;
599 char *line = NULL((void*)0);
600 size_t line_allocated = 0;
601 int result;
602
603 result = 0;
604 fp = CVS_FOPENfopen (finfo->file, "r");
605 if (fp == NULL((void*)0))
606 error (1, errno(*__errno()), "cannot open %s", finfo->fullname);
607 while (get_line (&line, &line_allocated, fp) > 0)
608 {
609 if (strncmp (line, RCS_MERGE_PAT_1"<<<<<<< ", sizeof RCS_MERGE_PAT_1"<<<<<<< " - 1) == 0 ||
610 strncmp (line, RCS_MERGE_PAT_2"=======\n", sizeof RCS_MERGE_PAT_2"=======\n" - 1) == 0 ||
611 strncmp (line, RCS_MERGE_PAT_3">>>>>>> ", sizeof RCS_MERGE_PAT_3">>>>>>> " - 1) == 0)
612 {
613 result = 1;
614 goto out;
615 }
616 }
617 if (ferror (fp)(!__isthreaded ? (((fp)->_flags & 0x0040) != 0) : (ferror
)(fp))
)
618 error (0, errno(*__errno()), "cannot read %s", finfo->fullname);
619out:
620 if (fclose (fp) < 0)
621 error (0, errno(*__errno()), "cannot close %s", finfo->fullname);
622 if (line != NULL((void*)0))
623 free (line);
624 return result;
625}
626
627/* Read the entire contents of the file NAME into *BUF.
628 If NAME is NULL, read from stdin. *BUF
629 is a pointer returned from malloc (or NULL), pointing to *BUFSIZE
630 bytes of space. The actual size is returned in *LEN. On error,
631 give a fatal error. The name of the file to use in error messages
632 (typically will include a directory if we have changed directory)
633 is FULLNAME. MODE is "r" for text or "rb" for binary. */
634
635void
636get_file (name, fullname, mode, buf, bufsize, len)
637 const char *name;
638 const char *fullname;
639 const char *mode;
640 char **buf;
641 size_t *bufsize;
642 size_t *len;
643{
644 struct stat s;
645 size_t nread;
646 char *tobuf;
647 FILE *e;
648 size_t filesize;
649
650 if (name == NULL((void*)0))
651 {
652 e = stdin(&__sF[0]);
653 filesize = 100; /* force allocation of minimum buffer */
654 }
655 else
656 {
657 /* Although it would be cleaner in some ways to just read
658 until end of file, reallocating the buffer, this function
659 does get called on files in the working directory which can
660 be of arbitrary size, so I think we better do all that
661 extra allocation. */
662
663 if (CVS_STATstat (name, &s) < 0)
664 error (1, errno(*__errno()), "can't stat %s", fullname);
665
666 /* Convert from signed to unsigned. */
667 filesize = s.st_size;
668
669 e = open_file (name, mode);
670 }
671
672 if (*buf == NULL((void*)0) || *bufsize <= filesize)
673 {
674 *bufsize = filesize + 1;
675 *buf = xrealloc (*buf, *bufsize);
676 }
677
678 tobuf = *buf;
679 nread = 0;
680 while (1)
681 {
682 size_t got;
683
684 got = fread (tobuf, 1, *bufsize - (tobuf - *buf), e);
685 if (ferror (e)(!__isthreaded ? (((e)->_flags & 0x0040) != 0) : (ferror
)(e))
)
686 error (1, errno(*__errno()), "can't read %s", fullname);
687 nread += got;
688 tobuf += got;
689
690 if (feof (e)(!__isthreaded ? (((e)->_flags & 0x0020) != 0) : (feof
)(e))
)
691 break;
692
693 /* Allocate more space if needed. */
694 if (tobuf == *buf + *bufsize)
695 {
696 int c;
697 long off;
698
699 c = getc (e)(!__isthreaded ? (--(e)->_r < 0 ? __srget(e) : (int)(*(
e)->_p++)) : (getc)(e))
;
700 if (c == EOF(-1))
701 break;
702 off = tobuf - *buf;
703 expand_string (buf, bufsize, *bufsize + 100);
704 tobuf = *buf + off;
705 *tobuf++ = c;
706 ++nread;
707 }
708 }
709
710 if (e != stdin(&__sF[0]) && fclose (e) < 0)
711 error (0, errno(*__errno()), "cannot close %s", fullname);
712
713 *len = nread;
714
715 /* Force *BUF to be large enough to hold a null terminator. */
716 if (nread == *bufsize)
717 expand_string (buf, bufsize, *bufsize + 1);
718 (*buf)[nread] = '\0';
719}
720
721
722/* Follow a chain of symbolic links to its destination. FILENAME
723 should be a handle to a malloc'd block of memory which contains the
724 beginning of the chain. This routine will replace the contents of
725 FILENAME with the destination (a real file). */
726
727void
728resolve_symlink (filename)
729 char **filename;
730{
731 if ((! filename) || (! *filename))
732 return;
733
734 while (islink (*filename))
735 {
736 char *newname;
737#ifdef HAVE_READLINK1
738 /* The clean thing to do is probably to have each filesubr.c
739 implement this (with an error if not supported by the
740 platform, in which case islink would presumably return 0).
741 But that would require editing each filesubr.c and so the
742 expedient hack seems to be looking at HAVE_READLINK. */
743 newname = xreadlink (*filename);
744#else
745 error (1, 0, "internal error: islink doesn't like readlink");
746#endif
747
748 if (isabsolute (newname))
749 {
750 free (*filename);
751 *filename = newname;
752 }
753 else
754 {
755 char *oldname = last_component (*filename);
756 int dirlen = oldname - *filename;
757 char *fullnewname = xmalloc (dirlen + strlen (newname) + 1);
758 strncpy (fullnewname, *filename, dirlen);
759 strcpy (fullnewname + dirlen, newname);
760 free (newname);
761 free (*filename);
762 *filename = fullnewname;
763 }
764 }
765}
766
767/*
768 * Rename a file to an appropriate backup name based on BAKPREFIX.
769 * If suffix non-null, then ".<suffix>" is appended to the new name.
770 *
771 * Returns the new name, which caller may free() if desired.
772 */
773char *
774backup_file (filename, suffix)
775 const char *filename;
776 const char *suffix;
777{
778 char *backup_name;
779
780 if (suffix == NULL((void*)0))
781 {
782 backup_name = xmalloc (sizeof (BAKPREFIX".#") + strlen (filename) + 1);
783 sprintf (backup_name, "%s%s", BAKPREFIX".#", filename);
784 }
785 else
786 {
787 backup_name = xmalloc (sizeof (BAKPREFIX".#")
788 + strlen (filename)
789 + strlen (suffix)
790 + 2); /* one for dot, one for trailing '\0' */
791 sprintf (backup_name, "%s%s.%s", BAKPREFIX".#", filename, suffix);
792 }
793
794 if (isfile (filename))
795 copy_file (filename, backup_name);
796
797 return backup_name;
798}
799
800/*
801 * Copy a string into a buffer escaping any shell metacharacters. The
802 * buffer should be at least twice as long as the string.
803 *
804 * Returns a pointer to the terminating NUL byte in buffer.
805 */
806
807char *
808shell_escape(buf, str)
809 char *buf;
810 const char *str;
811{
812 static const char meta[] = "$`\\\"";
813 const char *p;
814
815 for (;;)
816 {
817 p = strpbrk(str, meta);
818 if (!p) p = str + strlen(str);
819 if (p > str)
820 {
821 memcpy(buf, str, p - str);
822 buf += p - str;
823 }
824 if (!*p) break;
825 *buf++ = '\\';
826 *buf++ = *p++;
827 str = p;
828 }
829 *buf = '\0';
830 return buf;
831}
832
833/*
834 * We can only travel forwards in time, not backwards. :)
835 */
836void
837sleep_past (desttime)
838 time_t desttime;
839{
840 time_t t;
841 long s;
842 long us;
843
844 while (time (&t) <= desttime)
845 {
846#ifdef HAVE_GETTIMEOFDAY1
847 struct timeval tv;
848 gettimeofday (&tv, NULL((void*)0));
849 if (tv.tv_sec > desttime)
850 break;
851 s = desttime - tv.tv_sec;
852 if (tv.tv_usec > 0)
853 us = 1000000 - tv.tv_usec;
854 else
855 {
856 s++;
857 us = 0;
858 }
859#else
860 /* default to 20 ms increments */
861 s = desttime - t;
862 us = 20000;
863#endif
864
865#if defined(HAVE_NANOSLEEP1)
866 {
867 struct timespec ts;
868 ts.tv_sec = s;
869 ts.tv_nsec = us * 1000;
870 (void)nanosleep (&ts, NULL((void*)0));
871 }
872#elif defined(HAVE_USLEEP)
873 if (s > 0)
874 (void)sleep (s);
875 else
876 (void)usleep (us);
877#elif defined(HAVE_SELECT)
878 {
879 /* use select instead of sleep since it is a fairly portable way of
880 * sleeping for ms.
881 */
882 struct timeval tv;
883 tv.tv_sec = s;
884 tv.tv_usec = us;
885 (void)select (0, (fd_set *)NULL((void*)0), (fd_set *)NULL((void*)0), (fd_set *)NULL((void*)0), &tv);
886 }
887#else
888 if (us > 0) s++;
889 (void)sleep(s);
890#endif
891 }
892}