VirtualBox

source: kBuild/trunk/src/gmake/misc.c@ 191

Last change on this file since 191 was 154, checked in by bird, 20 years ago

This commit was generated by cvs2svn to compensate for changes in r153,
which included commits to RCS files with non-trunk default branches.

  • Property svn:eol-style set to native
File size: 18.7 KB
Line 
1/* Miscellaneous generic support functions for GNU Make.
2Copyright (C) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1997,
32002 Free Software Foundation, Inc.
4This file is part of GNU Make.
5
6GNU Make is free software; you can redistribute it and/or modify
7it under the terms of the GNU General Public License as published by
8the Free Software Foundation; either version 2, or (at your option)
9any later version.
10
11GNU Make is distributed in the hope that it will be useful,
12but WITHOUT ANY WARRANTY; without even the implied warranty of
13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14GNU General Public License for more details.
15
16You should have received a copy of the GNU General Public License
17along with GNU Make; see the file COPYING. If not, write to
18the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19Boston, MA 02111-1307, USA. */
20
21#include "make.h"
22#include "dep.h"
23#include "debug.h"
24
25/* Variadic functions. We go through contortions to allow proper function
26 prototypes for both ANSI and pre-ANSI C compilers, and also for those
27 which support stdarg.h vs. varargs.h, and finally those which have
28 vfprintf(), etc. and those who have _doprnt... or nothing.
29
30 This fancy stuff all came from GNU fileutils, except for the VA_PRINTF and
31 VA_END macros used here since we have multiple print functions. */
32
33#if USE_VARIADIC
34# if HAVE_STDARG_H
35# include <stdarg.h>
36# define VA_START(args, lastarg) va_start(args, lastarg)
37# else
38# include <varargs.h>
39# define VA_START(args, lastarg) va_start(args)
40# endif
41# if HAVE_VPRINTF
42# define VA_PRINTF(fp, lastarg, args) vfprintf((fp), (lastarg), (args))
43# else
44# define VA_PRINTF(fp, lastarg, args) _doprnt((lastarg), (args), (fp))
45# endif
46# define VA_END(args) va_end(args)
47#else
48/* We can't use any variadic interface! */
49# define va_alist a1, a2, a3, a4, a5, a6, a7, a8
50# define va_dcl char *a1, *a2, *a3, *a4, *a5, *a6, *a7, *a8;
51# define VA_START(args, lastarg)
52# define VA_PRINTF(fp, lastarg, args) fprintf((fp), (lastarg), va_alist)
53# define VA_END(args)
54#endif
55
56
57/* Compare strings *S1 and *S2.
58 Return negative if the first is less, positive if it is greater,
59 zero if they are equal. */
60
61int
62alpha_compare (const void *v1, const void *v2)
63{
64 const char *s1 = *((char **)v1);
65 const char *s2 = *((char **)v2);
66
67 if (*s1 != *s2)
68 return *s1 - *s2;
69 return strcmp (s1, s2);
70}
71
72
73/* Discard each backslash-newline combination from LINE.
74 Backslash-backslash-newline combinations become backslash-newlines.
75 This is done by copying the text at LINE into itself. */
76
77void
78collapse_continuations (char *line)
79{
80 register char *in, *out, *p;
81 register int backslash;
82 register unsigned int bs_write;
83
84 in = strchr (line, '\n');
85 if (in == 0)
86 return;
87
88 out = in;
89 while (out > line && out[-1] == '\\')
90 --out;
91
92 while (*in != '\0')
93 {
94 /* BS_WRITE gets the number of quoted backslashes at
95 the end just before IN, and BACKSLASH gets nonzero
96 if the next character is quoted. */
97 backslash = 0;
98 bs_write = 0;
99 for (p = in - 1; p >= line && *p == '\\'; --p)
100 {
101 if (backslash)
102 ++bs_write;
103 backslash = !backslash;
104
105 /* It should be impossible to go back this far without exiting,
106 but if we do, we can't get the right answer. */
107 if (in == out - 1)
108 abort ();
109 }
110
111 /* Output the appropriate number of backslashes. */
112 while (bs_write-- > 0)
113 *out++ = '\\';
114
115 /* Skip the newline. */
116 ++in;
117
118 /* If the newline is quoted, discard following whitespace
119 and any preceding whitespace; leave just one space. */
120 if (backslash)
121 {
122 in = next_token (in);
123 while (out > line && isblank ((unsigned char)out[-1]))
124 --out;
125 *out++ = ' ';
126 }
127 else
128 /* If the newline isn't quoted, put it in the output. */
129 *out++ = '\n';
130
131 /* Now copy the following line to the output.
132 Stop when we find backslashes followed by a newline. */
133 while (*in != '\0')
134 if (*in == '\\')
135 {
136 p = in + 1;
137 while (*p == '\\')
138 ++p;
139 if (*p == '\n')
140 {
141 in = p;
142 break;
143 }
144 while (in < p)
145 *out++ = *in++;
146 }
147 else
148 *out++ = *in++;
149 }
150
151 *out = '\0';
152}
153
154
155/* Remove comments from LINE.
156 This is done by copying the text at LINE onto itself. */
157
158void
159remove_comments (char *line)
160{
161 char *comment;
162
163 comment = find_char_unquote (line, '#', 0, 0);
164
165 if (comment != 0)
166 /* Cut off the line at the #. */
167 *comment = '\0';
168}
169
170
171/* Print N spaces (used in debug for target-depth). */
172
173void
174print_spaces (unsigned int n)
175{
176 while (n-- > 0)
177 putchar (' ');
178}
179
180
181
182/* Return a newly-allocated string whose contents
183 concatenate those of s1, s2, s3. */
184
185char *
186concat (const char *s1, const char *s2, const char *s3)
187{
188 unsigned int len1, len2, len3;
189 char *result;
190
191 len1 = *s1 != '\0' ? strlen (s1) : 0;
192 len2 = *s2 != '\0' ? strlen (s2) : 0;
193 len3 = *s3 != '\0' ? strlen (s3) : 0;
194
195 result = (char *) xmalloc (len1 + len2 + len3 + 1);
196
197 if (*s1 != '\0')
198 bcopy (s1, result, len1);
199 if (*s2 != '\0')
200 bcopy (s2, result + len1, len2);
201 if (*s3 != '\0')
202 bcopy (s3, result + len1 + len2, len3);
203 *(result + len1 + len2 + len3) = '\0';
204
205 return result;
206}
207
208
209/* Print a message on stdout. */
210
211void
212#if HAVE_ANSI_COMPILER && USE_VARIADIC && HAVE_STDARG_H
213message (int prefix, const char *fmt, ...)
214#else
215message (prefix, fmt, va_alist)
216 int prefix;
217 const char *fmt;
218 va_dcl
219#endif
220{
221#if USE_VARIADIC
222 va_list args;
223#endif
224
225 log_working_directory (1);
226
227 if (fmt != 0)
228 {
229 if (prefix)
230 {
231 if (makelevel == 0)
232 printf ("%s: ", program);
233 else
234 printf ("%s[%u]: ", program, makelevel);
235 }
236 VA_START (args, fmt);
237 VA_PRINTF (stdout, fmt, args);
238 VA_END (args);
239 putchar ('\n');
240 }
241
242 fflush (stdout);
243}
244
245/* Print an error message. */
246
247void
248#if HAVE_ANSI_COMPILER && USE_VARIADIC && HAVE_STDARG_H
249error (const struct floc *flocp, const char *fmt, ...)
250#else
251error (flocp, fmt, va_alist)
252 const struct floc *flocp;
253 const char *fmt;
254 va_dcl
255#endif
256{
257#if USE_VARIADIC
258 va_list args;
259#endif
260
261 log_working_directory (1);
262
263 if (flocp && flocp->filenm)
264 fprintf (stderr, "%s:%lu: ", flocp->filenm, flocp->lineno);
265 else if (makelevel == 0)
266 fprintf (stderr, "%s: ", program);
267 else
268 fprintf (stderr, "%s[%u]: ", program, makelevel);
269
270 VA_START(args, fmt);
271 VA_PRINTF (stderr, fmt, args);
272 VA_END (args);
273
274 putc ('\n', stderr);
275 fflush (stderr);
276}
277
278/* Print an error message and exit. */
279
280void
281#if HAVE_ANSI_COMPILER && USE_VARIADIC && HAVE_STDARG_H
282fatal (const struct floc *flocp, const char *fmt, ...)
283#else
284fatal (flocp, fmt, va_alist)
285 const struct floc *flocp;
286 const char *fmt;
287 va_dcl
288#endif
289{
290#if USE_VARIADIC
291 va_list args;
292#endif
293
294 log_working_directory (1);
295
296 if (flocp && flocp->filenm)
297 fprintf (stderr, "%s:%lu: *** ", flocp->filenm, flocp->lineno);
298 else if (makelevel == 0)
299 fprintf (stderr, "%s: *** ", program);
300 else
301 fprintf (stderr, "%s[%u]: *** ", program, makelevel);
302
303 VA_START(args, fmt);
304 VA_PRINTF (stderr, fmt, args);
305 VA_END (args);
306
307 fputs (_(". Stop.\n"), stderr);
308
309 die (2);
310}
311
312#ifndef HAVE_STRERROR
313
314#undef strerror
315
316char *
317strerror (int errnum)
318{
319 extern int errno, sys_nerr;
320#ifndef __DECC
321 extern char *sys_errlist[];
322#endif
323 static char buf[] = "Unknown error 12345678901234567890";
324
325 if (errno < sys_nerr)
326 return sys_errlist[errnum];
327
328 sprintf (buf, _("Unknown error %d"), errnum);
329 return buf;
330}
331#endif
332
333/* Print an error message from errno. */
334
335void
336perror_with_name (const char *str, const char *name)
337{
338 error (NILF, _("%s%s: %s"), str, name, strerror (errno));
339}
340
341/* Print an error message from errno and exit. */
342
343void
344pfatal_with_name (const char *name)
345{
346 fatal (NILF, _("%s: %s"), name, strerror (errno));
347
348 /* NOTREACHED */
349}
350
351
352/* Like malloc but get fatal error if memory is exhausted. */
353/* Don't bother if we're using dmalloc; it provides these for us. */
354
355#ifndef HAVE_DMALLOC_H
356
357#undef xmalloc
358#undef xrealloc
359#undef xstrdup
360
361char *
362xmalloc (unsigned int size)
363{
364 /* Make sure we don't allocate 0, for pre-ANSI libraries. */
365 char *result = (char *) malloc (size ? size : 1);
366 if (result == 0)
367 fatal (NILF, _("virtual memory exhausted"));
368 return result;
369}
370
371
372char *
373xrealloc (char *ptr, unsigned int size)
374{
375 char *result;
376
377 /* Some older implementations of realloc() don't conform to ANSI. */
378 if (! size)
379 size = 1;
380 result = ptr ? realloc (ptr, size) : malloc (size);
381 if (result == 0)
382 fatal (NILF, _("virtual memory exhausted"));
383 return result;
384}
385
386
387char *
388xstrdup (const char *ptr)
389{
390 char *result;
391
392#ifdef HAVE_STRDUP
393 result = strdup (ptr);
394#else
395 result = (char *) malloc (strlen (ptr) + 1);
396#endif
397
398 if (result == 0)
399 fatal (NILF, _("virtual memory exhausted"));
400
401#ifdef HAVE_STRDUP
402 return result;
403#else
404 return strcpy(result, ptr);
405#endif
406}
407
408#endif /* HAVE_DMALLOC_H */
409
410char *
411savestring (const char *str, unsigned int length)
412{
413 register char *out = (char *) xmalloc (length + 1);
414 if (length > 0)
415 bcopy (str, out, length);
416 out[length] = '\0';
417 return out;
418}
419
420
421/* Search string BIG (length BLEN) for an occurrence of
422 string SMALL (length SLEN). Return a pointer to the
423 beginning of the first occurrence, or return nil if none found. */
424
425char *
426sindex (const char *big, unsigned int blen,
427 const char *small, unsigned int slen)
428{
429 if (!blen)
430 blen = strlen (big);
431 if (!slen)
432 slen = strlen (small);
433
434 if (slen && blen >= slen)
435 {
436 register unsigned int b;
437
438 /* Quit when there's not enough room left for the small string. */
439 --slen;
440 blen -= slen;
441
442 for (b = 0; b < blen; ++b, ++big)
443 if (*big == *small && strneq (big + 1, small + 1, slen))
444 return (char *)big;
445 }
446
447 return 0;
448}
449
450/* Limited INDEX:
451 Search through the string STRING, which ends at LIMIT, for the character C.
452 Returns a pointer to the first occurrence, or nil if none is found.
453 Like INDEX except that the string searched ends where specified
454 instead of at the first null. */
455
456char *
457lindex (const char *s, const char *limit, int c)
458{
459 while (s < limit)
460 if (*s++ == c)
461 return (char *)(s - 1);
462
463 return 0;
464}
465
466
467/* Return the address of the first whitespace or null in the string S. */
468
469char *
470end_of_token (char *s)
471{
472 while (*s != '\0' && !isblank ((unsigned char)*s))
473 ++s;
474 return s;
475}
476
477#ifdef WINDOWS32
478/*
479 * Same as end_of_token, but take into account a stop character
480 */
481char *
482end_of_token_w32 (char *s, char stopchar)
483{
484 register char *p = s;
485 register int backslash = 0;
486
487 while (*p != '\0' && *p != stopchar
488 && (backslash || !isblank ((unsigned char)*p)))
489 {
490 if (*p++ == '\\')
491 {
492 backslash = !backslash;
493 while (*p == '\\')
494 {
495 backslash = !backslash;
496 ++p;
497 }
498 }
499 else
500 backslash = 0;
501 }
502
503 return p;
504}
505#endif
506
507/* Return the address of the first nonwhitespace or null in the string S. */
508
509char *
510next_token (const char *s)
511{
512 while (isblank ((unsigned char)*s))
513 ++s;
514 return (char *)s;
515}
516
517/* Find the next token in PTR; return the address of it, and store the
518 length of the token into *LENGTHPTR if LENGTHPTR is not nil. */
519
520char *
521find_next_token (char **ptr, unsigned int *lengthptr)
522{
523 char *p = next_token (*ptr);
524 char *end;
525
526 if (*p == '\0')
527 return 0;
528
529 *ptr = end = end_of_token (p);
530 if (lengthptr != 0)
531 *lengthptr = end - p;
532 return p;
533}
534
535
536/* Copy a chain of `struct dep', making a new chain
537 with the same contents as the old one. */
538
539struct dep *
540copy_dep_chain (struct dep *d)
541{
542 register struct dep *c;
543 struct dep *firstnew = 0;
544 struct dep *lastnew = 0;
545
546 while (d != 0)
547 {
548 c = (struct dep *) xmalloc (sizeof (struct dep));
549 bcopy ((char *) d, (char *) c, sizeof (struct dep));
550 if (c->name != 0)
551 c->name = xstrdup (c->name);
552 c->next = 0;
553 if (firstnew == 0)
554 firstnew = lastnew = c;
555 else
556 lastnew = lastnew->next = c;
557
558 d = d->next;
559 }
560
561 return firstnew;
562}
563
564
565#ifdef iAPX286
566/* The losing compiler on this machine can't handle this macro. */
567
568char *
569dep_name (struct dep *dep)
570{
571 return dep->name == 0 ? dep->file->name : dep->name;
572}
573#endif
574
575
576#ifdef GETLOADAVG_PRIVILEGED
577
578#ifdef POSIX
579
580/* Hopefully if a system says it's POSIX.1 and has the setuid and setgid
581 functions, they work as POSIX.1 says. Some systems (Alpha OSF/1 1.2,
582 for example) which claim to be POSIX.1 also have the BSD setreuid and
583 setregid functions, but they don't work as in BSD and only the POSIX.1
584 way works. */
585
586#undef HAVE_SETREUID
587#undef HAVE_SETREGID
588
589#else /* Not POSIX. */
590
591/* Some POSIX.1 systems have the seteuid and setegid functions. In a
592 POSIX-like system, they are the best thing to use. However, some
593 non-POSIX systems have them too but they do not work in the POSIX style
594 and we must use setreuid and setregid instead. */
595
596#undef HAVE_SETEUID
597#undef HAVE_SETEGID
598
599#endif /* POSIX. */
600
601#ifndef HAVE_UNISTD_H
602extern int getuid (), getgid (), geteuid (), getegid ();
603extern int setuid (), setgid ();
604#ifdef HAVE_SETEUID
605extern int seteuid ();
606#else
607#ifdef HAVE_SETREUID
608extern int setreuid ();
609#endif /* Have setreuid. */
610#endif /* Have seteuid. */
611#ifdef HAVE_SETEGID
612extern int setegid ();
613#else
614#ifdef HAVE_SETREGID
615extern int setregid ();
616#endif /* Have setregid. */
617#endif /* Have setegid. */
618#endif /* No <unistd.h>. */
619
620/* Keep track of the user and group IDs for user- and make- access. */
621static int user_uid = -1, user_gid = -1, make_uid = -1, make_gid = -1;
622#define access_inited (user_uid != -1)
623static enum { make, user } current_access;
624
625
626/* Under -d, write a message describing the current IDs. */
627
628static void
629log_access (char *flavor)
630{
631 if (! ISDB (DB_JOBS))
632 return;
633
634 /* All the other debugging messages go to stdout,
635 but we write this one to stderr because it might be
636 run in a child fork whose stdout is piped. */
637
638 fprintf (stderr, _("%s: user %lu (real %lu), group %lu (real %lu)\n"),
639 flavor, (unsigned long) geteuid (), (unsigned long) getuid (),
640 (unsigned long) getegid (), (unsigned long) getgid ());
641 fflush (stderr);
642}
643
644
645static void
646init_access (void)
647{
648#ifndef VMS
649 user_uid = getuid ();
650 user_gid = getgid ();
651
652 make_uid = geteuid ();
653 make_gid = getegid ();
654
655 /* Do these ever fail? */
656 if (user_uid == -1 || user_gid == -1 || make_uid == -1 || make_gid == -1)
657 pfatal_with_name ("get{e}[gu]id");
658
659 log_access (_("Initialized access"));
660
661 current_access = make;
662#endif
663}
664
665#endif /* GETLOADAVG_PRIVILEGED */
666
667/* Give the process appropriate permissions for access to
668 user data (i.e., to stat files, or to spawn a child process). */
669void
670user_access (void)
671{
672#ifdef GETLOADAVG_PRIVILEGED
673
674 if (!access_inited)
675 init_access ();
676
677 if (current_access == user)
678 return;
679
680 /* We are in "make access" mode. This means that the effective user and
681 group IDs are those of make (if it was installed setuid or setgid).
682 We now want to set the effective user and group IDs to the real IDs,
683 which are the IDs of the process that exec'd make. */
684
685#ifdef HAVE_SETEUID
686
687 /* Modern systems have the seteuid/setegid calls which set only the
688 effective IDs, which is ideal. */
689
690 if (seteuid (user_uid) < 0)
691 pfatal_with_name ("user_access: seteuid");
692
693#else /* Not HAVE_SETEUID. */
694
695#ifndef HAVE_SETREUID
696
697 /* System V has only the setuid/setgid calls to set user/group IDs.
698 There is an effective ID, which can be set by setuid/setgid.
699 It can be set (unless you are root) only to either what it already is
700 (returned by geteuid/getegid, now in make_uid/make_gid),
701 the real ID (return by getuid/getgid, now in user_uid/user_gid),
702 or the saved set ID (what the effective ID was before this set-ID
703 executable (make) was exec'd). */
704
705 if (setuid (user_uid) < 0)
706 pfatal_with_name ("user_access: setuid");
707
708#else /* HAVE_SETREUID. */
709
710 /* In 4BSD, the setreuid/setregid calls set both the real and effective IDs.
711 They may be set to themselves or each other. So you have two alternatives
712 at any one time. If you use setuid/setgid, the effective will be set to
713 the real, leaving only one alternative. Using setreuid/setregid, however,
714 you can toggle between your two alternatives by swapping the values in a
715 single setreuid or setregid call. */
716
717 if (setreuid (make_uid, user_uid) < 0)
718 pfatal_with_name ("user_access: setreuid");
719
720#endif /* Not HAVE_SETREUID. */
721#endif /* HAVE_SETEUID. */
722
723#ifdef HAVE_SETEGID
724 if (setegid (user_gid) < 0)
725 pfatal_with_name ("user_access: setegid");
726#else
727#ifndef HAVE_SETREGID
728 if (setgid (user_gid) < 0)
729 pfatal_with_name ("user_access: setgid");
730#else
731 if (setregid (make_gid, user_gid) < 0)
732 pfatal_with_name ("user_access: setregid");
733#endif
734#endif
735
736 current_access = user;
737
738 log_access (_("User access"));
739
740#endif /* GETLOADAVG_PRIVILEGED */
741}
742
743/* Give the process appropriate permissions for access to
744 make data (i.e., the load average). */
745void
746make_access (void)
747{
748#ifdef GETLOADAVG_PRIVILEGED
749
750 if (!access_inited)
751 init_access ();
752
753 if (current_access == make)
754 return;
755
756 /* See comments in user_access, above. */
757
758#ifdef HAVE_SETEUID
759 if (seteuid (make_uid) < 0)
760 pfatal_with_name ("make_access: seteuid");
761#else
762#ifndef HAVE_SETREUID
763 if (setuid (make_uid) < 0)
764 pfatal_with_name ("make_access: setuid");
765#else
766 if (setreuid (user_uid, make_uid) < 0)
767 pfatal_with_name ("make_access: setreuid");
768#endif
769#endif
770
771#ifdef HAVE_SETEGID
772 if (setegid (make_gid) < 0)
773 pfatal_with_name ("make_access: setegid");
774#else
775#ifndef HAVE_SETREGID
776 if (setgid (make_gid) < 0)
777 pfatal_with_name ("make_access: setgid");
778#else
779 if (setregid (user_gid, make_gid) < 0)
780 pfatal_with_name ("make_access: setregid");
781#endif
782#endif
783
784 current_access = make;
785
786 log_access (_("Make access"));
787
788#endif /* GETLOADAVG_PRIVILEGED */
789}
790
791/* Give the process appropriate permissions for a child process.
792 This is like user_access, but you can't get back to make_access. */
793void
794child_access (void)
795{
796#ifdef GETLOADAVG_PRIVILEGED
797
798 if (!access_inited)
799 abort ();
800
801 /* Set both the real and effective UID and GID to the user's.
802 They cannot be changed back to make's. */
803
804#ifndef HAVE_SETREUID
805 if (setuid (user_uid) < 0)
806 pfatal_with_name ("child_access: setuid");
807#else
808 if (setreuid (user_uid, user_uid) < 0)
809 pfatal_with_name ("child_access: setreuid");
810#endif
811
812#ifndef HAVE_SETREGID
813 if (setgid (user_gid) < 0)
814 pfatal_with_name ("child_access: setgid");
815#else
816 if (setregid (user_gid, user_gid) < 0)
817 pfatal_with_name ("child_access: setregid");
818#endif
819
820 log_access (_("Child access"));
821
822#endif /* GETLOADAVG_PRIVILEGED */
823}
824
825
826#ifdef NEED_GET_PATH_MAX
827unsigned int
828get_path_max (void)
829{
830 static unsigned int value;
831
832 if (value == 0)
833 {
834 long int x = pathconf ("/", _PC_PATH_MAX);
835 if (x > 0)
836 value = x;
837 else
838 return MAXPATHLEN;
839 }
840
841 return value;
842}
843#endif
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette