source: trunk/src/kmk/misc.c@ 1921

Last change on this file since 1921 was 1918, checked in by bird, 17 years ago

kmk: New switch --print-stats which will print variable, file, strcache, allocation and heap statistics.

  • Property svn:eol-style set to native
File size: 32.8 KB
Line 
1/* Miscellaneous generic support functions for GNU Make.
2Copyright (C) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997,
31998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006 Free Software
4Foundation, Inc.
5This file is part of GNU Make.
6
7GNU Make is free software; you can redistribute it and/or modify it under the
8terms of the GNU General Public License as published by the Free Software
9Foundation; either version 2, or (at your option) any later version.
10
11GNU Make is distributed in the hope that it will be useful, but WITHOUT ANY
12WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
13A PARTICULAR PURPOSE. See the GNU General Public License for more details.
14
15You should have received a copy of the GNU General Public License along with
16GNU Make; see the file COPYING. If not, write to the Free Software
17Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. */
18
19#include "make.h"
20#include "dep.h"
21#include "debug.h"
22#ifdef CONFIG_WITH_VALUE_LENGTH
23# include <assert.h>
24#endif
25#ifdef CONFIG_WITH_PRINT_STATS_SWITCH
26# ifdef __APPLE__
27# include <malloc/malloc.h>
28# endif
29#endif
30
31/* All bcopy calls in this file can be replaced by memcpy and save a tick or two. */
32#ifdef CONFIG_WITH_OPTIMIZATION_HACKS
33# undef bcopy
34# if defined(__GNUC__) && defined(CONFIG_WITH_OPTIMIZATION_HACKS)
35# define bcopy(src, dst, size) __builtin_memcpy ((dst), (src), (size))
36# else
37# define bcopy(src, dst, size) memcpy ((dst), (src), (size))
38# endif
39#endif
40
41/* Variadic functions. We go through contortions to allow proper function
42 prototypes for both ANSI and pre-ANSI C compilers, and also for those
43 which support stdarg.h vs. varargs.h, and finally those which have
44 vfprintf(), etc. and those who have _doprnt... or nothing.
45
46 This fancy stuff all came from GNU fileutils, except for the VA_PRINTF and
47 VA_END macros used here since we have multiple print functions. */
48
49#if USE_VARIADIC
50# if HAVE_STDARG_H
51# include <stdarg.h>
52# define VA_START(args, lastarg) va_start(args, lastarg)
53# else
54# include <varargs.h>
55# define VA_START(args, lastarg) va_start(args)
56# endif
57# if HAVE_VPRINTF
58# define VA_PRINTF(fp, lastarg, args) vfprintf((fp), (lastarg), (args))
59# else
60# define VA_PRINTF(fp, lastarg, args) _doprnt((lastarg), (args), (fp))
61# endif
62# define VA_END(args) va_end(args)
63#else
64/* We can't use any variadic interface! */
65# define va_alist a1, a2, a3, a4, a5, a6, a7, a8
66# define va_dcl char *a1, *a2, *a3, *a4, *a5, *a6, *a7, *a8;
67# define VA_START(args, lastarg)
68# define VA_PRINTF(fp, lastarg, args) fprintf((fp), (lastarg), va_alist)
69# define VA_END(args)
70#endif
71
72
73/* Compare strings *S1 and *S2.
74 Return negative if the first is less, positive if it is greater,
75 zero if they are equal. */
76
77int
78alpha_compare (const void *v1, const void *v2)
79{
80 const char *s1 = *((char **)v1);
81 const char *s2 = *((char **)v2);
82
83 if (*s1 != *s2)
84 return *s1 - *s2;
85 return strcmp (s1, s2);
86}
87
88
89/* Discard each backslash-newline combination from LINE.
90 Backslash-backslash-newline combinations become backslash-newlines.
91 This is done by copying the text at LINE into itself. */
92
93#ifndef CONFIG_WITH_VALUE_LENGTH
94void
95collapse_continuations (char *line)
96#else
97char *
98collapse_continuations (char *line, unsigned int linelen)
99#endif
100{
101 register char *in, *out, *p;
102 register int backslash;
103 register unsigned int bs_write;
104
105#ifndef CONFIG_WITH_VALUE_LENGTH
106 in = strchr (line, '\n');
107 if (in == 0)
108 return;
109#else
110 assert (strlen (line) == linelen);
111 in = memchr (line, '\n', linelen);
112 if (in == 0)
113 return line + linelen;
114#endif
115
116 out = in;
117 while (out > line && out[-1] == '\\')
118 --out;
119
120 while (*in != '\0')
121 {
122 /* BS_WRITE gets the number of quoted backslashes at
123 the end just before IN, and BACKSLASH gets nonzero
124 if the next character is quoted. */
125 backslash = 0;
126 bs_write = 0;
127 for (p = in - 1; p >= line && *p == '\\'; --p)
128 {
129 if (backslash)
130 ++bs_write;
131 backslash = !backslash;
132
133 /* It should be impossible to go back this far without exiting,
134 but if we do, we can't get the right answer. */
135 if (in == out - 1)
136 abort ();
137 }
138
139 /* Output the appropriate number of backslashes. */
140 while (bs_write-- > 0)
141 *out++ = '\\';
142
143 /* Skip the newline. */
144 ++in;
145
146 /* If the newline is quoted, discard following whitespace
147 and any preceding whitespace; leave just one space. */
148 if (backslash)
149 {
150 in = next_token (in);
151 while (out > line && isblank ((unsigned char)out[-1]))
152 --out;
153 *out++ = ' ';
154 }
155 else
156 /* If the newline isn't quoted, put it in the output. */
157 *out++ = '\n';
158
159 /* Now copy the following line to the output.
160 Stop when we find backslashes followed by a newline. */
161 while (*in != '\0')
162 if (*in == '\\')
163 {
164 p = in + 1;
165 while (*p == '\\')
166 ++p;
167 if (*p == '\n')
168 {
169 in = p;
170 break;
171 }
172 while (in < p)
173 *out++ = *in++;
174 }
175 else
176 *out++ = *in++;
177 }
178
179 *out = '\0';
180#ifdef CONFIG_WITH_VALUE_LENGTH
181 assert (strchr (line, '\0') == out);
182 return out;
183#endif
184}
185
186
187/* Print N spaces (used in debug for target-depth). */
188
189void
190print_spaces (unsigned int n)
191{
192 while (n-- > 0)
193 putchar (' ');
194}
195
196
197
198/* Return a string whose contents concatenate those of s1, s2, s3.
199 This string lives in static, re-used memory. */
200
201char *
202concat (const char *s1, const char *s2, const char *s3)
203{
204 unsigned int len1, len2, len3;
205 static unsigned int rlen = 0;
206 static char *result = NULL;
207
208 len1 = (s1 && *s1 != '\0') ? strlen (s1) : 0;
209 len2 = (s2 && *s2 != '\0') ? strlen (s2) : 0;
210 len3 = (s3 && *s3 != '\0') ? strlen (s3) : 0;
211
212 if (len1 + len2 + len3 + 1 > rlen)
213 result = xrealloc (result, (rlen = len1 + len2 + len3 + 10));
214
215 if (len1)
216 memcpy (result, s1, len1);
217 if (len2)
218 memcpy (result + len1, s2, len2);
219 if (len3)
220 memcpy (result + len1 + len2, s3, len3);
221
222 result[len1+len2+len3] = '\0';
223
224 return result;
225}
226
227
228/* Print a message on stdout. */
229
230void
231#if HAVE_ANSI_COMPILER && USE_VARIADIC && HAVE_STDARG_H
232message (int prefix, const char *fmt, ...)
233#else
234message (prefix, fmt, va_alist)
235 int prefix;
236 const char *fmt;
237 va_dcl
238#endif
239{
240#if USE_VARIADIC
241 va_list args;
242#endif
243
244 log_working_directory (1);
245
246 if (fmt != 0)
247 {
248 if (prefix)
249 {
250 if (makelevel == 0)
251 printf ("%s: ", program);
252 else
253 printf ("%s[%u]: ", program, makelevel);
254 }
255 VA_START (args, fmt);
256 VA_PRINTF (stdout, fmt, args);
257 VA_END (args);
258 putchar ('\n');
259 }
260
261 fflush (stdout);
262}
263
264/* Print an error message. */
265
266void
267#if HAVE_ANSI_COMPILER && USE_VARIADIC && HAVE_STDARG_H
268error (const struct floc *flocp, const char *fmt, ...)
269#else
270error (flocp, fmt, va_alist)
271 const struct floc *flocp;
272 const char *fmt;
273 va_dcl
274#endif
275{
276#if USE_VARIADIC
277 va_list args;
278#endif
279
280 log_working_directory (1);
281
282 if (flocp && flocp->filenm)
283 fprintf (stderr, "%s:%lu: ", flocp->filenm, flocp->lineno);
284 else if (makelevel == 0)
285 fprintf (stderr, "%s: ", program);
286 else
287 fprintf (stderr, "%s[%u]: ", program, makelevel);
288
289 VA_START(args, fmt);
290 VA_PRINTF (stderr, fmt, args);
291 VA_END (args);
292
293 putc ('\n', stderr);
294 fflush (stderr);
295}
296
297/* Print an error message and exit. */
298
299void
300#if HAVE_ANSI_COMPILER && USE_VARIADIC && HAVE_STDARG_H
301fatal (const struct floc *flocp, const char *fmt, ...)
302#else
303fatal (flocp, fmt, va_alist)
304 const struct floc *flocp;
305 const char *fmt;
306 va_dcl
307#endif
308{
309#if USE_VARIADIC
310 va_list args;
311#endif
312
313 log_working_directory (1);
314
315 if (flocp && flocp->filenm)
316 fprintf (stderr, "%s:%lu: *** ", flocp->filenm, flocp->lineno);
317 else if (makelevel == 0)
318 fprintf (stderr, "%s: *** ", program);
319 else
320 fprintf (stderr, "%s[%u]: *** ", program, makelevel);
321
322 VA_START(args, fmt);
323 VA_PRINTF (stderr, fmt, args);
324 VA_END (args);
325
326 fputs (_(". Stop.\n"), stderr);
327
328 die (2);
329}
330
331#ifndef HAVE_STRERROR
332
333#undef strerror
334
335char *
336strerror (int errnum)
337{
338 extern int errno, sys_nerr;
339#ifndef __DECC
340 extern char *sys_errlist[];
341#endif
342 static char buf[] = "Unknown error 12345678901234567890";
343
344 if (errno < sys_nerr)
345 return sys_errlist[errnum];
346
347 sprintf (buf, _("Unknown error %d"), errnum);
348 return buf;
349}
350#endif
351
352/* Print an error message from errno. */
353
354void
355perror_with_name (const char *str, const char *name)
356{
357 error (NILF, _("%s%s: %s"), str, name, strerror (errno));
358}
359
360/* Print an error message from errno and exit. */
361
362void
363pfatal_with_name (const char *name)
364{
365 fatal (NILF, _("%s: %s"), name, strerror (errno));
366
367 /* NOTREACHED */
368}
369
370
371/* Like malloc but get fatal error if memory is exhausted. */
372/* Don't bother if we're using dmalloc; it provides these for us. */
373
374#if !defined(HAVE_DMALLOC_H) && !defined(ELECTRIC_HEAP) /* bird */
375
376#undef xmalloc
377#undef xrealloc
378#undef xstrdup
379
380void *
381xmalloc (unsigned int size)
382{
383 /* Make sure we don't allocate 0, for pre-ANSI libraries. */
384 void *result = malloc (size ? size : 1);
385 if (result == 0)
386 fatal (NILF, _("virtual memory exhausted"));
387#ifdef CONFIG_WITH_MAKE_STATS
388 make_stats_allocations++;
389 if (make_expensive_statistics)
390 {
391 unsigned int actual_size = SIZE_OF_HEAP_BLOCK (result);
392 make_stats_allocated += actual_size;
393 make_stats_allocated_sum += actual_size;
394 }
395#endif
396 return result;
397}
398
399
400void *
401xrealloc (void *ptr, unsigned int size)
402{
403 void *result;
404#ifdef CONFIG_WITH_MAKE_STATS
405 if (make_expensive_statistics && ptr != NULL)
406 {
407 unsigned int actual_size = SIZE_OF_HEAP_BLOCK (ptr);
408 make_stats_allocated -= actual_size;
409 make_stats_allocated_sum -= actual_size;
410 }
411#endif
412
413 /* Some older implementations of realloc() don't conform to ANSI. */
414 if (! size)
415 size = 1;
416 result = ptr ? realloc (ptr, size) : malloc (size);
417 if (result == 0)
418 fatal (NILF, _("virtual memory exhausted"));
419#ifdef CONFIG_WITH_MAKE_STATS
420 if (!ptr)
421 make_stats_allocations++;
422 if (make_expensive_statistics)
423 {
424 unsigned int actual_size = SIZE_OF_HEAP_BLOCK (result);
425 make_stats_allocated += actual_size;
426 make_stats_allocated_sum += actual_size;
427 }
428#endif
429 return result;
430}
431
432
433char *
434xstrdup (const char *ptr)
435{
436 char *result;
437
438#ifdef HAVE_STRDUP
439 result = strdup (ptr);
440#else
441 result = malloc (strlen (ptr) + 1);
442#endif
443
444 if (result == 0)
445 fatal (NILF, _("virtual memory exhausted"));
446
447#ifdef CONFIG_WITH_MAKE_STATS
448 make_stats_allocations++;
449 if (make_expensive_statistics)
450 {
451 unsigned int actual_size = SIZE_OF_HEAP_BLOCK (result);
452 make_stats_allocated += actual_size;
453 make_stats_allocated_sum += actual_size;
454 }
455#endif
456#ifdef HAVE_STRDUP
457 return result;
458#else
459 return strcpy (result, ptr);
460#endif
461}
462
463#endif /* HAVE_DMALLOC_H */
464
465char *
466savestring (const char *str, unsigned int length)
467{
468 char *out = xmalloc (length + 1);
469 if (length > 0)
470 memcpy (out, str, length);
471 out[length] = '\0';
472 return out;
473}
474
475
476
477#ifndef CONFIG_WITH_OPTIMIZATION_HACKS /* This is really a reimplemntation of
478 memchr, only slower. It's been replaced by a macro in the header file. */
479
480/* Limited INDEX:
481 Search through the string STRING, which ends at LIMIT, for the character C.
482 Returns a pointer to the first occurrence, or nil if none is found.
483 Like INDEX except that the string searched ends where specified
484 instead of at the first null. */
485
486char *
487lindex (const char *s, const char *limit, int c)
488{
489 while (s < limit)
490 if (*s++ == c)
491 return (char *)(s - 1);
492
493 return 0;
494}
495#endif /* CONFIG_WITH_OPTIMIZATION_HACKS */
496
497
498/* Return the address of the first whitespace or null in the string S. */
499
500char *
501end_of_token (const char *s)
502{
503#ifdef KMK
504 for (;;)
505 {
506 unsigned char ch0, ch1, ch2, ch3;
507
508 ch0 = *s;
509 if (MY_PREDICT_FALSE(MY_IS_BLANK_OR_EOS(ch0)))
510 return (char *)s;
511 ch1 = s[1];
512 if (MY_PREDICT_FALSE(MY_IS_BLANK_OR_EOS(ch1)))
513 return (char *)s + 1;
514 ch2 = s[2];
515 if (MY_PREDICT_FALSE(MY_IS_BLANK_OR_EOS(ch2)))
516 return (char *)s + 2;
517 ch3 = s[3];
518 if (MY_PREDICT_FALSE(MY_IS_BLANK_OR_EOS(ch3)))
519 return (char *)s + 3;
520
521 s += 4;
522 }
523
524#else
525 while (*s != '\0' && !isblank ((unsigned char)*s))
526 ++s;
527 return (char *)s;
528#endif
529}
530
531#ifdef WINDOWS32
532/*
533 * Same as end_of_token, but take into account a stop character
534 */
535char *
536end_of_token_w32 (const char *s, char stopchar)
537{
538 const char *p = s;
539 int backslash = 0;
540
541 while (*p != '\0' && *p != stopchar
542 && (backslash || !isblank ((unsigned char)*p)))
543 {
544 if (*p++ == '\\')
545 {
546 backslash = !backslash;
547 while (*p == '\\')
548 {
549 backslash = !backslash;
550 ++p;
551 }
552 }
553 else
554 backslash = 0;
555 }
556
557 return (char *)p;
558}
559#endif
560
561/* Return the address of the first nonwhitespace or null in the string S. */
562
563char *
564next_token (const char *s)
565{
566#ifdef KMK
567 for (;;)
568 {
569 unsigned char ch0, ch1, ch2, ch3;
570
571 ch0 = *s;
572 if (MY_PREDICT_FALSE(!MY_IS_BLANK(ch0)))
573 return (char *)s;
574 ch1 = s[1];
575 if (MY_PREDICT_TRUE(!MY_IS_BLANK(ch1)))
576 return (char *)s + 1;
577 ch2 = s[2];
578 if (MY_PREDICT_FALSE(!MY_IS_BLANK(ch2)))
579 return (char *)s + 2;
580 ch3 = s[3];
581 if (MY_PREDICT_TRUE(!MY_IS_BLANK(ch3)))
582 return (char *)s + 3;
583
584 s += 4;
585 }
586
587#else /* !KMK */
588 while (isblank ((unsigned char)*s))
589 ++s;
590 return (char *)s;
591#endif /* !KMK */
592}
593
594/* Find the next token in PTR; return the address of it, and store the length
595 of the token into *LENGTHPTR if LENGTHPTR is not nil. Set *PTR to the end
596 of the token, so this function can be called repeatedly in a loop. */
597
598char *
599find_next_token (const char **ptr, unsigned int *lengthptr)
600{
601#ifdef KMK
602 const char *p = *ptr;
603 const char *e;
604
605 /* skip blanks */
606# if 0 /* a moderate version */
607 for (;; p++)
608 {
609 unsigned char ch = *p;
610 if (!MY_IS_BLANK(ch))
611 {
612 if (!ch)
613 return NULL;
614 break;
615 }
616 }
617
618# else /* (too) big unroll */
619 for (;; p += 4)
620 {
621 unsigned char ch0, ch1, ch2, ch3;
622
623 ch0 = *p;
624 if (MY_PREDICT_FALSE(!MY_IS_BLANK(ch0)))
625 {
626 if (!ch0)
627 return NULL;
628 break;
629 }
630 ch1 = p[1];
631 if (MY_PREDICT_TRUE(!MY_IS_BLANK(ch1)))
632 {
633 if (!ch1)
634 return NULL;
635 p += 1;
636 break;
637 }
638 ch2 = p[2];
639 if (MY_PREDICT_FALSE(!MY_IS_BLANK(ch2)))
640 {
641 if (!ch2)
642 return NULL;
643 p += 2;
644 break;
645 }
646 ch3 = p[3];
647 if (MY_PREDICT_TRUE(!MY_IS_BLANK(ch3)))
648 {
649 if (!ch3)
650 return NULL;
651 p += 3;
652 break;
653 }
654 }
655# endif
656
657 /* skip ahead until EOS or blanks. */
658# if 0 /* a moderate version */
659 for (e = p + 1; ; e++)
660 {
661 unsigned char ch = *e;
662 if (MY_PREDICT_FALSE(MY_IS_BLANK_OR_EOS(ch)))
663 break;
664 }
665# else /* (too) big unroll */
666 for (e = p + 1; ; e += 4)
667 {
668 unsigned char ch0, ch1, ch2, ch3;
669
670 ch0 = *e;
671 if (MY_PREDICT_FALSE(MY_IS_BLANK_OR_EOS(ch0)))
672 break;
673 ch1 = e[1];
674 if (MY_PREDICT_FALSE(MY_IS_BLANK_OR_EOS(ch1)))
675 {
676 e += 1;
677 break;
678 }
679 ch2 = e[2];
680 if (MY_PREDICT_FALSE(MY_IS_BLANK_OR_EOS(ch2)))
681 {
682 e += 2;
683 break;
684 }
685 ch3 = e[3];
686 if (MY_PREDICT_FALSE(MY_IS_BLANK_OR_EOS(ch3)))
687 {
688 e += 3;
689 break;
690 }
691 }
692# endif
693 *ptr = e;
694
695 if (lengthptr != 0)
696 *lengthptr = e - p;
697
698 return (char *)p;
699
700#else
701 const char *p = next_token (*ptr);
702
703 if (*p == '\0')
704 return 0;
705
706 *ptr = end_of_token (p);
707 if (lengthptr != 0)
708 *lengthptr = *ptr - p;
709
710 return (char *)p;
711#endif
712}
713
714
715
716/* Allocate a new `struct dep' with all fields initialized to 0. */
717
718struct dep *
719alloc_dep ()
720{
721#ifndef CONFIG_WITH_ALLOC_CACHES
722 struct dep *d = xmalloc (sizeof (struct dep));
723 memset (d, '\0', sizeof (struct dep));
724 return d;
725#else
726 return (struct dep *) alloccache_calloc (&dep_cache);
727#endif
728}
729
730
731/* Free `struct dep' along with `name' and `stem'. */
732
733void
734free_dep (struct dep *d)
735{
736#ifndef CONFIG_WITH_ALLOC_CACHES
737 free (d);
738#else
739 alloccache_free (&dep_cache, d);
740#endif
741}
742
743/* Copy a chain of `struct dep', making a new chain
744 with the same contents as the old one. */
745
746struct dep *
747copy_dep_chain (const struct dep *d)
748{
749 struct dep *firstnew = 0;
750 struct dep *lastnew = 0;
751
752 while (d != 0)
753 {
754#ifndef CONFIG_WITH_ALLOC_CACHES
755 struct dep *c = xmalloc (sizeof (struct dep));
756#else
757 struct dep *c = (struct dep *) alloccache_alloc (&dep_cache);
758#endif
759 memcpy (c, d, sizeof (struct dep));
760
761 c->next = 0;
762 if (firstnew == 0)
763 firstnew = lastnew = c;
764 else
765 lastnew = lastnew->next = c;
766
767 d = d->next;
768 }
769
770 return firstnew;
771}
772
773/* Free a chain of 'struct dep'. */
774
775void
776free_dep_chain (struct dep *d)
777{
778 while (d != 0)
779 {
780 struct dep *df = d;
781 d = d->next;
782#ifndef CONFIG_WITH_ALLOC_CACHES
783 free_dep (df);
784#else
785 alloccache_free (&dep_cache, df);
786#endif
787 }
788}
789
790/* Free a chain of struct nameseq.
791 For struct dep chains use free_dep_chain. */
792
793void
794free_ns_chain (struct nameseq *ns)
795{
796 while (ns != 0)
797 {
798 struct nameseq *t = ns;
799 ns = ns->next;
800#ifndef CONFIG_WITH_ALLOC_CACHES
801 free (t);
802#else
803 alloccache_free (&nameseq_cache, t);
804#endif
805 }
806}
807
808
809
810#if !HAVE_STRCASECMP && !HAVE_STRICMP && !HAVE_STRCMPI
811
812/* If we don't have strcasecmp() (from POSIX), or anything that can substitute
813 for it, define our own version. */
814
815int
816strcasecmp (const char *s1, const char *s2)
817{
818 while (1)
819 {
820 int c1 = (int) *(s1++);
821 int c2 = (int) *(s2++);
822
823 if (isalpha (c1))
824 c1 = tolower (c1);
825 if (isalpha (c2))
826 c2 = tolower (c2);
827
828 if (c1 != '\0' && c1 == c2)
829 continue;
830
831 return (c1 - c2);
832 }
833}
834#endif
835
836
837#ifdef GETLOADAVG_PRIVILEGED
838
839#ifdef POSIX
840
841/* Hopefully if a system says it's POSIX.1 and has the setuid and setgid
842 functions, they work as POSIX.1 says. Some systems (Alpha OSF/1 1.2,
843 for example) which claim to be POSIX.1 also have the BSD setreuid and
844 setregid functions, but they don't work as in BSD and only the POSIX.1
845 way works. */
846
847#undef HAVE_SETREUID
848#undef HAVE_SETREGID
849
850#else /* Not POSIX. */
851
852/* Some POSIX.1 systems have the seteuid and setegid functions. In a
853 POSIX-like system, they are the best thing to use. However, some
854 non-POSIX systems have them too but they do not work in the POSIX style
855 and we must use setreuid and setregid instead. */
856
857#undef HAVE_SETEUID
858#undef HAVE_SETEGID
859
860#endif /* POSIX. */
861
862#ifndef HAVE_UNISTD_H
863extern int getuid (), getgid (), geteuid (), getegid ();
864extern int setuid (), setgid ();
865#ifdef HAVE_SETEUID
866extern int seteuid ();
867#else
868#ifdef HAVE_SETREUID
869extern int setreuid ();
870#endif /* Have setreuid. */
871#endif /* Have seteuid. */
872#ifdef HAVE_SETEGID
873extern int setegid ();
874#else
875#ifdef HAVE_SETREGID
876extern int setregid ();
877#endif /* Have setregid. */
878#endif /* Have setegid. */
879#endif /* No <unistd.h>. */
880
881/* Keep track of the user and group IDs for user- and make- access. */
882static int user_uid = -1, user_gid = -1, make_uid = -1, make_gid = -1;
883#define access_inited (user_uid != -1)
884static enum { make, user } current_access;
885
886
887/* Under -d, write a message describing the current IDs. */
888
889static void
890log_access (const char *flavor)
891{
892 if (! ISDB (DB_JOBS))
893 return;
894
895 /* All the other debugging messages go to stdout,
896 but we write this one to stderr because it might be
897 run in a child fork whose stdout is piped. */
898
899 fprintf (stderr, _("%s: user %lu (real %lu), group %lu (real %lu)\n"),
900 flavor, (unsigned long) geteuid (), (unsigned long) getuid (),
901 (unsigned long) getegid (), (unsigned long) getgid ());
902 fflush (stderr);
903}
904
905
906static void
907init_access (void)
908{
909#ifndef VMS
910 user_uid = getuid ();
911 user_gid = getgid ();
912
913 make_uid = geteuid ();
914 make_gid = getegid ();
915
916 /* Do these ever fail? */
917 if (user_uid == -1 || user_gid == -1 || make_uid == -1 || make_gid == -1)
918 pfatal_with_name ("get{e}[gu]id");
919
920 log_access (_("Initialized access"));
921
922 current_access = make;
923#endif
924}
925
926#endif /* GETLOADAVG_PRIVILEGED */
927
928/* Give the process appropriate permissions for access to
929 user data (i.e., to stat files, or to spawn a child process). */
930void
931user_access (void)
932{
933#ifdef GETLOADAVG_PRIVILEGED
934
935 if (!access_inited)
936 init_access ();
937
938 if (current_access == user)
939 return;
940
941 /* We are in "make access" mode. This means that the effective user and
942 group IDs are those of make (if it was installed setuid or setgid).
943 We now want to set the effective user and group IDs to the real IDs,
944 which are the IDs of the process that exec'd make. */
945
946#ifdef HAVE_SETEUID
947
948 /* Modern systems have the seteuid/setegid calls which set only the
949 effective IDs, which is ideal. */
950
951 if (seteuid (user_uid) < 0)
952 pfatal_with_name ("user_access: seteuid");
953
954#else /* Not HAVE_SETEUID. */
955
956#ifndef HAVE_SETREUID
957
958 /* System V has only the setuid/setgid calls to set user/group IDs.
959 There is an effective ID, which can be set by setuid/setgid.
960 It can be set (unless you are root) only to either what it already is
961 (returned by geteuid/getegid, now in make_uid/make_gid),
962 the real ID (return by getuid/getgid, now in user_uid/user_gid),
963 or the saved set ID (what the effective ID was before this set-ID
964 executable (make) was exec'd). */
965
966 if (setuid (user_uid) < 0)
967 pfatal_with_name ("user_access: setuid");
968
969#else /* HAVE_SETREUID. */
970
971 /* In 4BSD, the setreuid/setregid calls set both the real and effective IDs.
972 They may be set to themselves or each other. So you have two alternatives
973 at any one time. If you use setuid/setgid, the effective will be set to
974 the real, leaving only one alternative. Using setreuid/setregid, however,
975 you can toggle between your two alternatives by swapping the values in a
976 single setreuid or setregid call. */
977
978 if (setreuid (make_uid, user_uid) < 0)
979 pfatal_with_name ("user_access: setreuid");
980
981#endif /* Not HAVE_SETREUID. */
982#endif /* HAVE_SETEUID. */
983
984#ifdef HAVE_SETEGID
985 if (setegid (user_gid) < 0)
986 pfatal_with_name ("user_access: setegid");
987#else
988#ifndef HAVE_SETREGID
989 if (setgid (user_gid) < 0)
990 pfatal_with_name ("user_access: setgid");
991#else
992 if (setregid (make_gid, user_gid) < 0)
993 pfatal_with_name ("user_access: setregid");
994#endif
995#endif
996
997 current_access = user;
998
999 log_access (_("User access"));
1000
1001#endif /* GETLOADAVG_PRIVILEGED */
1002}
1003
1004/* Give the process appropriate permissions for access to
1005 make data (i.e., the load average). */
1006void
1007make_access (void)
1008{
1009#ifdef GETLOADAVG_PRIVILEGED
1010
1011 if (!access_inited)
1012 init_access ();
1013
1014 if (current_access == make)
1015 return;
1016
1017 /* See comments in user_access, above. */
1018
1019#ifdef HAVE_SETEUID
1020 if (seteuid (make_uid) < 0)
1021 pfatal_with_name ("make_access: seteuid");
1022#else
1023#ifndef HAVE_SETREUID
1024 if (setuid (make_uid) < 0)
1025 pfatal_with_name ("make_access: setuid");
1026#else
1027 if (setreuid (user_uid, make_uid) < 0)
1028 pfatal_with_name ("make_access: setreuid");
1029#endif
1030#endif
1031
1032#ifdef HAVE_SETEGID
1033 if (setegid (make_gid) < 0)
1034 pfatal_with_name ("make_access: setegid");
1035#else
1036#ifndef HAVE_SETREGID
1037 if (setgid (make_gid) < 0)
1038 pfatal_with_name ("make_access: setgid");
1039#else
1040 if (setregid (user_gid, make_gid) < 0)
1041 pfatal_with_name ("make_access: setregid");
1042#endif
1043#endif
1044
1045 current_access = make;
1046
1047 log_access (_("Make access"));
1048
1049#endif /* GETLOADAVG_PRIVILEGED */
1050}
1051
1052/* Give the process appropriate permissions for a child process.
1053 This is like user_access, but you can't get back to make_access. */
1054void
1055child_access (void)
1056{
1057#ifdef GETLOADAVG_PRIVILEGED
1058
1059 if (!access_inited)
1060 abort ();
1061
1062 /* Set both the real and effective UID and GID to the user's.
1063 They cannot be changed back to make's. */
1064
1065#ifndef HAVE_SETREUID
1066 if (setuid (user_uid) < 0)
1067 pfatal_with_name ("child_access: setuid");
1068#else
1069 if (setreuid (user_uid, user_uid) < 0)
1070 pfatal_with_name ("child_access: setreuid");
1071#endif
1072
1073#ifndef HAVE_SETREGID
1074 if (setgid (user_gid) < 0)
1075 pfatal_with_name ("child_access: setgid");
1076#else
1077 if (setregid (user_gid, user_gid) < 0)
1078 pfatal_with_name ("child_access: setregid");
1079#endif
1080
1081 log_access (_("Child access"));
1082
1083#endif /* GETLOADAVG_PRIVILEGED */
1084}
1085
1086
1087#ifdef NEED_GET_PATH_MAX
1088unsigned int
1089get_path_max (void)
1090{
1091 static unsigned int value;
1092
1093 if (value == 0)
1094 {
1095 long int x = pathconf ("/", _PC_PATH_MAX);
1096 if (x > 0)
1097 value = x;
1098 else
1099 return MAXPATHLEN;
1100 }
1101
1102 return value;
1103}
1104#endif
1105
1106
1107
1108/* This code is stolen from gnulib.
1109 If/when we abandon the requirement to work with K&R compilers, we can
1110 remove this (and perhaps other parts of GNU make!) and migrate to using
1111 gnulib directly.
1112
1113 This is called only through atexit(), which means die() has already been
1114 invoked. So, call exit() here directly. Apparently that works...?
1115*/
1116
1117/* Close standard output, exiting with status 'exit_failure' on failure.
1118 If a program writes *anything* to stdout, that program should close
1119 stdout and make sure that it succeeds before exiting. Otherwise,
1120 suppose that you go to the extreme of checking the return status
1121 of every function that does an explicit write to stdout. The last
1122 printf can succeed in writing to the internal stream buffer, and yet
1123 the fclose(stdout) could still fail (due e.g., to a disk full error)
1124 when it tries to write out that buffered data. Thus, you would be
1125 left with an incomplete output file and the offending program would
1126 exit successfully. Even calling fflush is not always sufficient,
1127 since some file systems (NFS and CODA) buffer written/flushed data
1128 until an actual close call.
1129
1130 Besides, it's wasteful to check the return value from every call
1131 that writes to stdout -- just let the internal stream state record
1132 the failure. That's what the ferror test is checking below.
1133
1134 It's important to detect such failures and exit nonzero because many
1135 tools (most notably `make' and other build-management systems) depend
1136 on being able to detect failure in other tools via their exit status. */
1137
1138void
1139close_stdout (void)
1140{
1141 int prev_fail = ferror (stdout);
1142 int fclose_fail = fclose (stdout);
1143
1144 if (prev_fail || fclose_fail)
1145 {
1146 if (fclose_fail)
1147 error (NILF, _("write error: %s"), strerror (errno));
1148 else
1149 error (NILF, _("write error"));
1150 exit (EXIT_FAILURE);
1151 }
1152}
1153
1154#if defined(CONFIG_WITH_MAKE_STATS) && !defined(ELECTRIC_HEAP)
1155#undef free
1156void xfree(void *ptr)
1157{
1158 if (ptr)
1159 {
1160 make_stats_allocations--;
1161 if (make_expensive_statistics)
1162 make_stats_allocated -= SIZE_OF_HEAP_BLOCK (ptr);
1163 free (ptr);
1164 }
1165}
1166#endif
1167
1168
1169#ifdef CONFIG_WITH_ALLOC_CACHES
1170
1171/* Default allocator. */
1172static void *
1173alloccache_default_grow_alloc(void *ignore, unsigned int size)
1174{
1175 return xmalloc (size);
1176}
1177
1178/* Worker for growing the cache. */
1179struct alloccache_free_ent *
1180alloccache_alloc_grow (struct alloccache *cache)
1181{
1182 void *item;
1183 unsigned int items = (64*1024 - 32) / cache->size;
1184 cache->free_start = cache->grow_alloc (cache->grow_arg, items * cache->size);
1185 cache->free_end = cache->free_start + items * cache->size;
1186 cache->total_count+= items;
1187
1188#ifndef NDEBUG /* skip the first item so the heap can detect free(). */
1189 cache->total_count--;
1190 cache->free_start += cache->size;
1191#endif
1192
1193 item = cache->free_start;
1194 cache->free_start += cache->size;
1195 /* caller counts */
1196 return (struct alloccache_free_ent *)item;
1197}
1198
1199/* List of alloc caches, for printing. */
1200static struct alloccache *alloccache_head = NULL;
1201
1202/* Initializes an alloc cache */
1203void
1204alloccache_init (struct alloccache *cache, unsigned int size, const char *name,
1205 void *(*grow_alloc)(void *grow_arg, unsigned int size), void *grow_arg)
1206{
1207 unsigned act_size;
1208
1209 /* ensure OK alignment and min sizeof (struct alloccache_free_ent). */
1210 if (size <= sizeof (struct alloccache_free_ent))
1211 act_size = sizeof (struct alloccache_free_ent);
1212 else if (size <= 32)
1213 {
1214 act_size = 4;
1215 while (act_size < size)
1216 act_size <<= 1;
1217 }
1218 else
1219 act_size = (size + 31U) & ~(size_t)31;
1220
1221 /* align the structure. */
1222 cache->free_start = NULL;
1223 cache->free_end = NULL;
1224 cache->free_head = NULL;
1225 cache->size = act_size;
1226 cache->alloc_count = 0;
1227 cache->total_count = 0;
1228 cache->name = name;
1229 cache->grow_arg = grow_arg;
1230 cache->grow_alloc = grow_alloc ? grow_alloc : alloccache_default_grow_alloc;
1231
1232 /* link it. */
1233 cache->next = alloccache_head;
1234 alloccache_head = cache;
1235}
1236
1237/* Terminate an alloc cache, free all the memory it contains. */
1238void
1239alloccache_term (struct alloccache *cache,
1240 void (*term_free)(void *term_arg, void *ptr, unsigned int size), void *term_arg)
1241{
1242 /*cache->size = 0;*/
1243 (void)cache;
1244 (void)term_free;
1245 (void)term_arg;
1246 /* FIXME: Implement memory segment tracking and cleanup. */
1247}
1248
1249/* Joins to caches, unlinking the 2nd one. */
1250void
1251alloccache_join (struct alloccache *cache, struct alloccache *eat)
1252{
1253 assert (cache->size == eat->size);
1254
1255#if 0 /* probably a waste of time */ /* FIXME: Optimize joining, avoid all list walking. */
1256 /* add the free list... */
1257 if (eat->free_head)
1258 {
1259 if (!cache->free_head)
1260 cache->free_head = eat->free_head;
1261 else if (eat->total_count - eat->alloc_count < cache->total_count - cache->alloc_count)
1262 {
1263 struct alloccache_free_ent *last = eat->free_head;
1264 while (last->next)
1265 last = last->next;
1266 last->next = cache->free_head;
1267 cache->free_head = eat->free_head;
1268 }
1269 else
1270 {
1271 struct alloccache_free_ent *last = cache->free_head;
1272 while (last->next)
1273 last = last->next;
1274 last->next = eat->free_head;
1275 }
1276 }
1277
1278 /* ... and the free space. */
1279 while (eat->free_start != eat->free_end)
1280 {
1281 struct alloccache_free_ent *f = (struct alloccache_free_ent *)eat->free_start;
1282 eat->free_start += eat->size;
1283 f->next = cache->free_head;
1284 cache->free_head = f;
1285 }
1286
1287 /* and statistics */
1288 cache->alloc_count += eat->alloc_count;
1289 cache->total_count += eat->total_count;
1290#else
1291 /* and statistics */
1292 cache->alloc_count += eat->alloc_count;
1293 cache->total_count += eat->alloc_count;
1294#endif
1295
1296 /* unlink and disable the eat cache */
1297 if (alloccache_head == eat)
1298 alloccache_head = eat->next;
1299 else
1300 {
1301 struct alloccache *cur = alloccache_head;
1302 while (cur->next != eat)
1303 cur = cur->next;
1304 assert (cur && cur->next == eat);
1305 cur->next = eat->next;
1306 }
1307
1308 eat->size = 0;
1309 eat->free_end = eat->free_start = NULL;
1310 eat->free_head = NULL;
1311}
1312
1313/* Print one alloc cache. */
1314void
1315alloccache_print (struct alloccache *cache)
1316{
1317 printf (_("\n# Alloc Cache: %s\n"
1318 "# Items: size = %-3u in-use = %-6d total = %-6u\n"),
1319 cache->name, cache->size, (int)cache->alloc_count, cache->total_count);
1320}
1321
1322/* Print all alloc caches. */
1323void
1324alloccache_print_all (void)
1325{
1326 struct alloccache *cur;
1327 puts ("");
1328 for (cur = alloccache_head; cur; cur = cur->next)
1329 alloccache_print (cur);
1330}
1331
1332#endif /* CONFIG_WITH_ALLOC_CACHES */
1333
1334#ifdef CONFIG_WITH_PRINT_STATS_SWITCH
1335/* Print heap statistics if supported by the platform. */
1336void print_heap_stats (void)
1337{
1338 /* Darwin / Mac OS X */
1339# ifdef __APPLE__
1340 malloc_statistics_t s;
1341
1342 malloc_zone_statistics (NULL, &s);
1343 printf (_("\n# CRT Heap: %zu bytes in use, in %u block, avg %zu bytes/block\n"),
1344 s.size_in_use, s.blocks_in_use, s.size_in_use / s.blocks_in_use);
1345 printf (_("# %zu bytes max in use (high water mark)\n"),
1346 s.max_size_in_use);
1347 printf (_("# %zu bytes reserved, %zu bytes free (estimate)\n"),
1348 s.size_allocated, s.size_allocated - s.size_in_use);
1349# endif /* __APPLE__ */
1350
1351 /* Darwin Libc sources indicates that something like this may be
1352 found in GLIBC, however, it's not in any current one... */
1353# if 0 /* ??? */
1354 struct mstats m;
1355
1356 m = mstats();
1357 printf (_("\n# CRT Heap: %zu blocks / %zu bytes in use, %zu blocks / %zu bytes free\n"),
1358 m.chunks_used, m.bytes_used, m.chunks_free, m.bytes_free);
1359 printf (_("# %zu bytes reserved\n"),
1360 m.bytes_total);
1361# endif /* ??? */
1362
1363 /* XVID2/XPG mallinfo (displayed per GLIBC documentation). */
1364# if 0 && defined(__GLIBC__) /* XXX: finish on linux, check older glibc versions. */
1365 struct mallinfo m;
1366
1367 m = mallinfo();
1368 printf (_("\n# CRT Heap: %d bytes in use, %d bytes free\n"),
1369 m.uordblks, s.fordblks);
1370
1371 printf (_("# # free chunks=%d, # fastbin blocks=%d\n"),
1372 m.ordblks, m.smblks);
1373 printf (_("# # mapped regions=%d, space in mapped regions=%d\n"),
1374 m.hblks, m.hblkhd);
1375 printf (_("# non-mapped space allocated from system=%d\n"),
1376 m.arena);
1377 printf (_("# maximum total allocated space=%d\n"),
1378 m.usmblks);
1379 printf (_("# top-most releasable space=%d\n"),
1380 m.keepcost);
1381# endif /* __GLIBC__ */
1382
1383 /* XXX: windows */
1384}
1385#endif /* CONFIG_WITH_PRINT_STATS_SWITCH */
1386
Note: See TracBrowser for help on using the repository browser.