VirtualBox

source: kBuild/trunk/src/kmk/misc.c@ 3219

Last change on this file since 3219 was 3173, checked in by bird, 6 years ago

kmkbultin: environment fixes and stats.

  • Property svn:eol-style set to native
File size: 29.2 KB
Line 
1/* Miscellaneous generic support functions for GNU Make.
2Copyright (C) 1988-2016 Free Software Foundation, Inc.
3This file is part of GNU Make.
4
5GNU Make is free software; you can redistribute it and/or modify it under the
6terms of the GNU General Public License as published by the Free Software
7Foundation; either version 3 of the License, or (at your option) any later
8version.
9
10GNU Make is distributed in the hope that it will be useful, but WITHOUT ANY
11WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
12A PARTICULAR PURPOSE. See the GNU General Public License for more details.
13
14You should have received a copy of the GNU General Public License along with
15this program. If not, see <http://www.gnu.org/licenses/>. */
16
17#include "makeint.h"
18#include "filedef.h"
19#include "dep.h"
20#include "debug.h"
21
22/* GNU make no longer supports pre-ANSI89 environments. */
23
24#include <stdarg.h>
25
26#ifdef HAVE_FCNTL_H
27# include <fcntl.h>
28#else
29# include <sys/file.h>
30#endif
31
32#if defined (CONFIG_WITH_VALUE_LENGTH) || defined (CONFIG_WITH_ALLOC_CACHES)
33# include <assert.h>
34#endif
35#ifdef CONFIG_WITH_PRINT_STATS_SWITCH
36# ifdef __APPLE__
37# include <malloc/malloc.h>
38# endif
39# if defined(__GLIBC__) || defined(HAVE_MALLINFO)
40# include <malloc.h>
41# endif
42#endif
43#if defined (CONFIG_WITH_NANOTS) || defined (CONFIG_WITH_PRINT_TIME_SWITCH)
44# ifdef WINDOWS32
45# include <Windows.h>
46# endif
47#endif
48
49/* All bcopy calls in this file can be replaced by memcpy and save a tick or two. */
50#ifdef CONFIG_WITH_OPTIMIZATION_HACKS
51# undef bcopy
52# if defined(__GNUC__) && defined(CONFIG_WITH_OPTIMIZATION_HACKS)
53# define bcopy(src, dst, size) __builtin_memcpy ((dst), (src), (size))
54# else
55# define bcopy(src, dst, size) memcpy ((dst), (src), (size))
56# endif
57#endif
58
59
60/* Compare strings *S1 and *S2.
61 Return negative if the first is less, positive if it is greater,
62 zero if they are equal. */
63
64int
65alpha_compare (const void *v1, const void *v2)
66{
67 const char *s1 = *((char **)v1);
68 const char *s2 = *((char **)v2);
69
70 if (*s1 != *s2)
71 return *s1 - *s2;
72 return strcmp (s1, s2);
73}
74
75
76/* Discard each backslash-newline combination from LINE.
77 Backslash-backslash-newline combinations become backslash-newlines.
78 This is done by copying the text at LINE into itself. */
79
80#ifndef CONFIG_WITH_VALUE_LENGTH
81void
82collapse_continuations (char *line)
83#else
84char *
85collapse_continuations (char *line, unsigned int linelen)
86#endif
87{
88 char *in, *out, *p;
89
90#ifndef CONFIG_WITH_VALUE_LENGTH
91 in = strchr (line, '\n');
92 if (in == 0)
93 return;
94#else
95 assert (strlen (line) == linelen);
96 in = memchr (line, '\n', linelen);
97 if (in == 0)
98 return line + linelen;
99 if (in == line || in[-1] != '\\')
100 {
101 do
102 {
103 unsigned int off_in = in - line;
104 if (off_in == linelen)
105 return in;
106 in = memchr (in + 1, '\n', linelen - off_in - 1);
107 if (in == 0)
108 return line + linelen;
109 }
110 while (in[-1] != '\\');
111 }
112#endif
113
114 out = in;
115 while (out > line && out[-1] == '\\')
116 --out;
117
118 while (*in != '\0')
119 {
120 /* BS_WRITE gets the number of quoted backslashes at
121 the end just before IN, and BACKSLASH gets nonzero
122 if the next character is quoted. */
123 unsigned int backslash = 0;
124 unsigned int bs_write = 0;
125 for (p = in - 1; p >= line && *p == '\\'; --p)
126 {
127 if (backslash)
128 ++bs_write;
129 backslash = !backslash;
130
131 /* It should be impossible to go back this far without exiting,
132 but if we do, we can't get the right answer. */
133 if (in == out - 1)
134 abort ();
135 }
136
137 /* Output the appropriate number of backslashes. */
138 while (bs_write-- > 0)
139 *out++ = '\\';
140
141 /* Skip the newline. */
142 ++in;
143
144 if (backslash)
145 {
146 /* Backslash/newline handling:
147 In traditional GNU make all trailing whitespace, consecutive
148 backslash/newlines, and any leading non-newline whitespace on the
149 next line is reduced to a single space.
150 In POSIX, each backslash/newline and is replaced by a space. */
151 while (ISBLANK (*in))
152 ++in;
153 if (! posix_pedantic)
154 while (out > line && ISBLANK (out[-1]))
155 --out;
156 *out++ = ' ';
157 }
158 else
159 /* If the newline isn't quoted, put it in the output. */
160 *out++ = '\n';
161
162 /* Now copy the following line to the output.
163 Stop when we find backslashes followed by a newline. */
164 while (*in != '\0')
165 if (*in == '\\')
166 {
167 p = in + 1;
168 while (*p == '\\')
169 ++p;
170 if (*p == '\n')
171 {
172 in = p;
173 break;
174 }
175 while (in < p)
176 *out++ = *in++;
177 }
178 else
179 *out++ = *in++;
180 }
181
182 *out = '\0';
183#ifdef CONFIG_WITH_VALUE_LENGTH
184 assert (strchr (line, '\0') == out);
185 return out;
186#endif
187}
188
189
190/* Print N spaces (used in debug for target-depth). */
191
192void
193print_spaces (unsigned int n)
194{
195 while (n-- > 0)
196 putchar (' ');
197}
198
199
200
201/* Return a string whose contents concatenate the NUM strings provided
202 This string lives in static, re-used memory. */
203
204const char *
205concat (unsigned int num, ...)
206{
207 static unsigned int rlen = 0;
208 static char *result = NULL;
209 unsigned int ri = 0;
210 va_list args;
211
212 va_start (args, num);
213
214 while (num-- > 0)
215 {
216 const char *s = va_arg (args, const char *);
217 unsigned int l = xstrlen (s);
218
219 if (l == 0)
220 continue;
221
222 if (ri + l > rlen)
223 {
224 rlen = ((rlen ? rlen : 60) + l) * 2;
225 result = xrealloc (result, rlen);
226 }
227
228 memcpy (result + ri, s, l);
229 ri += l;
230 }
231
232 va_end (args);
233
234 /* Get some more memory if we don't have enough space for the
235 terminating '\0'. */
236 if (ri == rlen)
237 {
238 rlen = (rlen ? rlen : 60) * 2;
239 result = xrealloc (result, rlen);
240 }
241
242 result[ri] = '\0';
243
244 return result;
245}
246
247
248
249#ifndef HAVE_STRERROR
250#undef strerror
251char *
252strerror (int errnum)
253{
254 extern int errno, sys_nerr;
255#ifndef __DECC
256 extern char *sys_errlist[];
257#endif
258 static char buf[] = "Unknown error 12345678901234567890";
259
260 if (errno < sys_nerr)
261 return sys_errlist[errnum];
262
263 sprintf (buf, _("Unknown error %d"), errnum);
264 return buf;
265}
266#endif
267
268
269/* Like malloc but get fatal error if memory is exhausted. */
270/* Don't bother if we're using dmalloc; it provides these for us. */
271
272#if !defined(HAVE_DMALLOC_H) && !defined(ELECTRIC_HEAP) /* bird */
273
274#undef xmalloc
275#undef xcalloc
276#undef xrealloc
277#undef xstrdup
278
279void *
280xmalloc (unsigned int size)
281{
282 /* Make sure we don't allocate 0, for pre-ISO implementations. */
283 void *result = malloc (size ? size : 1);
284 if (result == 0)
285 OUT_OF_MEM();
286
287#ifdef CONFIG_WITH_MAKE_STATS
288 make_stats_allocations++;
289 if (make_expensive_statistics)
290 make_stats_allocated += SIZE_OF_HEAP_BLOCK (result);
291 else
292 make_stats_allocated += size;
293#endif
294 return result;
295}
296
297
298void *
299xcalloc (unsigned int size)
300{
301 /* Make sure we don't allocate 0, for pre-ISO implementations. */
302 void *result = calloc (size ? size : 1, 1);
303 if (result == 0)
304 OUT_OF_MEM();
305
306#ifdef CONFIG_WITH_MAKE_STATS
307 make_stats_allocations++;
308 if (make_expensive_statistics)
309 make_stats_allocated += SIZE_OF_HEAP_BLOCK (result);
310 else
311 make_stats_allocated += size;
312#endif
313 return result;
314}
315
316
317void *
318xrealloc (void *ptr, unsigned int size)
319{
320 void *result;
321#ifdef CONFIG_WITH_MAKE_STATS
322 if (make_expensive_statistics && ptr != NULL)
323 make_stats_allocated -= SIZE_OF_HEAP_BLOCK (ptr);
324 if (ptr)
325 make_stats_reallocations++;
326 else
327 make_stats_allocations++;
328#endif
329
330 /* Some older implementations of realloc() don't conform to ISO. */
331 if (! size)
332 size = 1;
333 result = ptr ? realloc (ptr, size) : malloc (size);
334 if (result == 0)
335 OUT_OF_MEM();
336
337#ifdef CONFIG_WITH_MAKE_STATS
338 if (make_expensive_statistics)
339 make_stats_allocated += SIZE_OF_HEAP_BLOCK (result);
340 else
341 make_stats_allocated += size;
342#endif
343 return result;
344}
345
346
347char *
348xstrdup (const char *ptr)
349{
350 char *result;
351
352#ifdef HAVE_STRDUP
353 result = strdup (ptr);
354#else
355 result = malloc (strlen (ptr) + 1);
356#endif
357
358 if (result == 0)
359 OUT_OF_MEM();
360
361#ifdef CONFIG_WITH_MAKE_STATS
362 make_stats_allocations++;
363 if (make_expensive_statistics)
364 make_stats_allocated += SIZE_OF_HEAP_BLOCK (result);
365 else
366 make_stats_allocated += strlen (ptr) + 1;
367#endif
368#ifdef HAVE_STRDUP
369 return result;
370#else
371 return strcpy (result, ptr);
372#endif
373}
374
375#endif /* HAVE_DMALLOC_H */
376
377char *
378xstrndup (const char *str, unsigned int length)
379{
380 char *result;
381
382#if defined(HAVE_STRNDUP) && !defined(KMK)
383 result = strndup (str, length);
384 if (result == 0)
385 OUT_OF_MEM();
386#else
387 result = xmalloc (length + 1);
388 if (length > 0)
389 strncpy (result, str, length);
390 result[length] = '\0';
391#endif
392
393 return result;
394}
395
396
397
398#ifndef CONFIG_WITH_OPTIMIZATION_HACKS /* This is really a reimplemntation of
399 memchr, only slower. It's been replaced by a macro in the header file. */
400
401/* Limited INDEX:
402 Search through the string STRING, which ends at LIMIT, for the character C.
403 Returns a pointer to the first occurrence, or nil if none is found.
404 Like INDEX except that the string searched ends where specified
405 instead of at the first null. */
406
407char *
408lindex (const char *s, const char *limit, int c)
409{
410 while (s < limit)
411 if (*s++ == c)
412 return (char *)(s - 1);
413
414 return 0;
415}
416#endif /* CONFIG_WITH_OPTIMIZATION_HACKS */
417
418
419/* Return the address of the first whitespace or null in the string S. */
420
421char *
422end_of_token (const char *s)
423{
424#if 0 /* @todo def KMK */
425 for (;;)
426 {
427 unsigned char ch0, ch1, ch2, ch3;
428
429 ch0 = *s;
430 if (MY_PREDICT_FALSE(MY_IS_BLANK_OR_EOS(ch0)))
431 return (char *)s;
432 ch1 = s[1];
433 if (MY_PREDICT_FALSE(MY_IS_BLANK_OR_EOS(ch1)))
434 return (char *)s + 1;
435 ch2 = s[2];
436 if (MY_PREDICT_FALSE(MY_IS_BLANK_OR_EOS(ch2)))
437 return (char *)s + 2;
438 ch3 = s[3];
439 if (MY_PREDICT_FALSE(MY_IS_BLANK_OR_EOS(ch3)))
440 return (char *)s + 3;
441
442 s += 4;
443 }
444
445#else
446 END_OF_TOKEN (s);
447 return (char *)s;
448#endif
449}
450
451/* Return the address of the first nonwhitespace or null in the string S. */
452
453char *
454next_token (const char *s)
455{
456#if 0 /* @todo def KMK */
457 for (;;)
458 {
459 unsigned char ch0, ch1, ch2, ch3;
460
461 ch0 = *s;
462 if (MY_PREDICT_FALSE(!MY_IS_BLANK(ch0)))
463 return (char *)s;
464 ch1 = s[1];
465 if (MY_PREDICT_TRUE(!MY_IS_BLANK(ch1)))
466 return (char *)s + 1;
467 ch2 = s[2];
468 if (MY_PREDICT_FALSE(!MY_IS_BLANK(ch2)))
469 return (char *)s + 2;
470 ch3 = s[3];
471 if (MY_PREDICT_TRUE(!MY_IS_BLANK(ch3)))
472 return (char *)s + 3;
473
474 s += 4;
475 }
476
477#else /* !KMK */
478 NEXT_TOKEN (s);
479 return (char *)s;
480#endif /* !KMK */
481}
482
483/* Find the next token in PTR; return the address of it, and store the length
484 of the token into *LENGTHPTR if LENGTHPTR is not nil. Set *PTR to the end
485 of the token, so this function can be called repeatedly in a loop. */
486
487char *
488find_next_token (const char **ptr, unsigned int *lengthptr)
489{
490#ifdef KMK
491 const char *p = *ptr;
492 const char *e;
493
494 /* skip blanks */
495# if 0 /* a moderate version */
496 for (;; p++)
497 {
498 unsigned char ch = *p;
499 if (!MY_IS_BLANK(ch))
500 {
501 if (!ch)
502 return NULL;
503 break;
504 }
505 }
506
507# else /* (too) big unroll */
508 for (;; p += 4)
509 {
510 unsigned char ch0, ch1, ch2, ch3;
511
512 ch0 = *p;
513 if (MY_PREDICT_FALSE(!MY_IS_BLANK(ch0)))
514 {
515 if (!ch0)
516 return NULL;
517 break;
518 }
519 ch1 = p[1];
520 if (MY_PREDICT_TRUE(!MY_IS_BLANK(ch1)))
521 {
522 if (!ch1)
523 return NULL;
524 p += 1;
525 break;
526 }
527 ch2 = p[2];
528 if (MY_PREDICT_FALSE(!MY_IS_BLANK(ch2)))
529 {
530 if (!ch2)
531 return NULL;
532 p += 2;
533 break;
534 }
535 ch3 = p[3];
536 if (MY_PREDICT_TRUE(!MY_IS_BLANK(ch3)))
537 {
538 if (!ch3)
539 return NULL;
540 p += 3;
541 break;
542 }
543 }
544# endif
545
546 /* skip ahead until EOS or blanks. */
547# if 0 /* a moderate version */
548 for (e = p + 1; ; e++)
549 {
550 unsigned char ch = *e;
551 if (MY_PREDICT_FALSE(MY_IS_BLANK_OR_EOS(ch)))
552 break;
553 }
554# else /* (too) big unroll */
555 for (e = p + 1; ; e += 4)
556 {
557 unsigned char ch0, ch1, ch2, ch3;
558
559 ch0 = *e;
560 if (MY_PREDICT_FALSE(MY_IS_BLANK_OR_EOS(ch0)))
561 break;
562 ch1 = e[1];
563 if (MY_PREDICT_FALSE(MY_IS_BLANK_OR_EOS(ch1)))
564 {
565 e += 1;
566 break;
567 }
568 ch2 = e[2];
569 if (MY_PREDICT_FALSE(MY_IS_BLANK_OR_EOS(ch2)))
570 {
571 e += 2;
572 break;
573 }
574 ch3 = e[3];
575 if (MY_PREDICT_FALSE(MY_IS_BLANK_OR_EOS(ch3)))
576 {
577 e += 3;
578 break;
579 }
580 }
581# endif
582 *ptr = e;
583
584 if (lengthptr != 0)
585 *lengthptr = e - p;
586
587 return (char *)p;
588
589#else
590 const char *p = next_token (*ptr);
591
592 if (*p == '\0')
593 return 0;
594
595 *ptr = end_of_token (p);
596 if (lengthptr != 0)
597 *lengthptr = *ptr - p;
598
599 return (char *)p;
600#endif
601}
602#ifdef KMK
603
604/* Same as find_next_token with two exception:
605 - The string ends at EOS or '\0'.
606 - We keep track of $() and ${}, allowing functions to be used. */
607
608char *
609find_next_token_eos (const char **ptr, const char *eos, unsigned int *lengthptr)
610{
611 const char *p = *ptr;
612 const char *e;
613 int level = 0;
614
615 /* skip blanks */
616 for (; p != eos; p++)
617 {
618 unsigned char ch = *p;
619 if (!MY_IS_BLANK(ch))
620 {
621 if (!ch)
622 return NULL;
623 break;
624 }
625 }
626 if (p == eos)
627 return NULL;
628
629 /* skip ahead until EOS or blanks. */
630 for (e = p; e != eos; e++)
631 {
632 unsigned char ch = *e;
633 if (MY_IS_BLANK_OR_EOS(ch))
634 {
635 if (!ch || level == 0)
636 break;
637 }
638 else if (ch == '$')
639 {
640 if (&e[1] != eos && (e[1] == '(' || e[1] == '{'))
641 {
642 level++;
643 e++;
644 }
645 }
646 else if ((ch == ')' || ch == '}') && level > 0)
647 level--;
648 }
649
650 *ptr = e;
651 if (lengthptr != 0)
652 *lengthptr = e - p;
653
654 return (char *)p;
655}
656
657#endif /* KMK */
658
659
660
661/* Copy a chain of 'struct dep'. For 2nd expansion deps, dup the name. */
662
663struct dep *
664copy_dep_chain (const struct dep *d)
665{
666 struct dep *firstnew = 0;
667 struct dep *lastnew = 0;
668
669 while (d != 0)
670 {
671#ifndef CONFIG_WITH_ALLOC_CACHES
672 struct dep *c = xmalloc (sizeof (struct dep));
673#else
674 struct dep *c = alloccache_alloc(&dep_cache);
675#endif
676 memcpy (c, d, sizeof (struct dep));
677
678 /** @todo KMK: Check if we need this duplication! */
679 if (c->need_2nd_expansion)
680 c->name = xstrdup (c->name);
681
682 c->next = 0;
683 if (firstnew == 0)
684 firstnew = lastnew = c;
685 else
686 lastnew = lastnew->next = c;
687
688 d = d->next;
689 }
690
691 return firstnew;
692}
693
694/* Free a chain of struct nameseq.
695 For struct dep chains use free_dep_chain. */
696
697void
698free_ns_chain (struct nameseq *ns)
699{
700 while (ns != 0)
701 {
702 struct nameseq *t = ns;
703 ns = ns->next;
704#ifndef CONFIG_WITH_ALLOC_CACHES
705 free_ns (t);
706#else
707 alloccache_free (&nameseq_cache, t);
708#endif
709 }
710}
711
712
713#ifdef CONFIG_WITH_ALLOC_CACHES
714
715void
716free_dep_chain (struct dep *d)
717{
718 while (d != 0)
719 {
720 struct dep *tofree = d;
721 d = d->next;
722 alloccache_free (&dep_cache, tofree);
723 }
724}
725
726void
727free_goal_chain (struct goaldep *g)
728{
729 while (g != 0)
730 {
731 struct goaldep *tofree = g;
732 g = g->next;
733 alloccache_free (&dep_cache, tofree);
734 }
735}
736
737#endif /* CONFIG_WITH_ALLOC_CACHES */
738
739
740
741#if !HAVE_STRCASECMP && !HAVE_STRICMP && !HAVE_STRCMPI
742/* If we don't have strcasecmp() (from POSIX), or anything that can substitute
743 for it, define our own version. */
744
745int
746strcasecmp (const char *s1, const char *s2)
747{
748 while (1)
749 {
750 int c1 = (int) *(s1++);
751 int c2 = (int) *(s2++);
752
753 if (isalpha (c1))
754 c1 = tolower (c1);
755 if (isalpha (c2))
756 c2 = tolower (c2);
757
758 if (c1 != '\0' && c1 == c2)
759 continue;
760
761 return (c1 - c2);
762 }
763}
764#endif
765
766#if !HAVE_STRNCASECMP && !HAVE_STRNICMP && !HAVE_STRNCMPI
767/* If we don't have strncasecmp() (from POSIX), or anything that can
768 substitute for it, define our own version. */
769
770int
771strncasecmp (const char *s1, const char *s2, int n)
772{
773 while (n-- > 0)
774 {
775 int c1 = (int) *(s1++);
776 int c2 = (int) *(s2++);
777
778 if (isalpha (c1))
779 c1 = tolower (c1);
780 if (isalpha (c2))
781 c2 = tolower (c2);
782
783 if (c1 != '\0' && c1 == c2)
784 continue;
785
786 return (c1 - c2);
787 }
788
789 return 0;
790}
791#endif
792
793
794#ifdef GETLOADAVG_PRIVILEGED
795
796#ifdef POSIX
797
798/* Hopefully if a system says it's POSIX.1 and has the setuid and setgid
799 functions, they work as POSIX.1 says. Some systems (Alpha OSF/1 1.2,
800 for example) which claim to be POSIX.1 also have the BSD setreuid and
801 setregid functions, but they don't work as in BSD and only the POSIX.1
802 way works. */
803
804#undef HAVE_SETREUID
805#undef HAVE_SETREGID
806
807#else /* Not POSIX. */
808
809/* Some POSIX.1 systems have the seteuid and setegid functions. In a
810 POSIX-like system, they are the best thing to use. However, some
811 non-POSIX systems have them too but they do not work in the POSIX style
812 and we must use setreuid and setregid instead. */
813
814#undef HAVE_SETEUID
815#undef HAVE_SETEGID
816
817#endif /* POSIX. */
818
819#ifndef HAVE_UNISTD_H
820extern int getuid (), getgid (), geteuid (), getegid ();
821extern int setuid (), setgid ();
822#ifdef HAVE_SETEUID
823extern int seteuid ();
824#else
825#ifdef HAVE_SETREUID
826extern int setreuid ();
827#endif /* Have setreuid. */
828#endif /* Have seteuid. */
829#ifdef HAVE_SETEGID
830extern int setegid ();
831#else
832#ifdef HAVE_SETREGID
833extern int setregid ();
834#endif /* Have setregid. */
835#endif /* Have setegid. */
836#endif /* No <unistd.h>. */
837
838/* Keep track of the user and group IDs for user- and make- access. */
839static int user_uid = -1, user_gid = -1, make_uid = -1, make_gid = -1;
840#define access_inited (user_uid != -1)
841static enum { make, user } current_access;
842
843
844/* Under -d, write a message describing the current IDs. */
845
846static void
847log_access (const char *flavor)
848{
849 if (! ISDB (DB_JOBS))
850 return;
851
852 /* All the other debugging messages go to stdout,
853 but we write this one to stderr because it might be
854 run in a child fork whose stdout is piped. */
855
856 fprintf (stderr, _("%s: user %lu (real %lu), group %lu (real %lu)\n"),
857 flavor, (unsigned long) geteuid (), (unsigned long) getuid (),
858 (unsigned long) getegid (), (unsigned long) getgid ());
859 fflush (stderr);
860}
861
862
863static void
864init_access (void)
865{
866#ifndef VMS
867 user_uid = getuid ();
868 user_gid = getgid ();
869
870 make_uid = geteuid ();
871 make_gid = getegid ();
872
873 /* Do these ever fail? */
874 if (user_uid == -1 || user_gid == -1 || make_uid == -1 || make_gid == -1)
875 pfatal_with_name ("get{e}[gu]id");
876
877 log_access (_("Initialized access"));
878
879 current_access = make;
880#endif
881}
882
883#endif /* GETLOADAVG_PRIVILEGED */
884
885/* Give the process appropriate permissions for access to
886 user data (i.e., to stat files, or to spawn a child process). */
887void
888user_access (void)
889{
890#ifdef GETLOADAVG_PRIVILEGED
891
892 if (!access_inited)
893 init_access ();
894
895 if (current_access == user)
896 return;
897
898 /* We are in "make access" mode. This means that the effective user and
899 group IDs are those of make (if it was installed setuid or setgid).
900 We now want to set the effective user and group IDs to the real IDs,
901 which are the IDs of the process that exec'd make. */
902
903#ifdef HAVE_SETEUID
904
905 /* Modern systems have the seteuid/setegid calls which set only the
906 effective IDs, which is ideal. */
907
908 if (seteuid (user_uid) < 0)
909 pfatal_with_name ("user_access: seteuid");
910
911#else /* Not HAVE_SETEUID. */
912
913#ifndef HAVE_SETREUID
914
915 /* System V has only the setuid/setgid calls to set user/group IDs.
916 There is an effective ID, which can be set by setuid/setgid.
917 It can be set (unless you are root) only to either what it already is
918 (returned by geteuid/getegid, now in make_uid/make_gid),
919 the real ID (return by getuid/getgid, now in user_uid/user_gid),
920 or the saved set ID (what the effective ID was before this set-ID
921 executable (make) was exec'd). */
922
923 if (setuid (user_uid) < 0)
924 pfatal_with_name ("user_access: setuid");
925
926#else /* HAVE_SETREUID. */
927
928 /* In 4BSD, the setreuid/setregid calls set both the real and effective IDs.
929 They may be set to themselves or each other. So you have two alternatives
930 at any one time. If you use setuid/setgid, the effective will be set to
931 the real, leaving only one alternative. Using setreuid/setregid, however,
932 you can toggle between your two alternatives by swapping the values in a
933 single setreuid or setregid call. */
934
935 if (setreuid (make_uid, user_uid) < 0)
936 pfatal_with_name ("user_access: setreuid");
937
938#endif /* Not HAVE_SETREUID. */
939#endif /* HAVE_SETEUID. */
940
941#ifdef HAVE_SETEGID
942 if (setegid (user_gid) < 0)
943 pfatal_with_name ("user_access: setegid");
944#else
945#ifndef HAVE_SETREGID
946 if (setgid (user_gid) < 0)
947 pfatal_with_name ("user_access: setgid");
948#else
949 if (setregid (make_gid, user_gid) < 0)
950 pfatal_with_name ("user_access: setregid");
951#endif
952#endif
953
954 current_access = user;
955
956 log_access (_("User access"));
957
958#endif /* GETLOADAVG_PRIVILEGED */
959}
960
961/* Give the process appropriate permissions for access to
962 make data (i.e., the load average). */
963void
964make_access (void)
965{
966#ifdef GETLOADAVG_PRIVILEGED
967
968 if (!access_inited)
969 init_access ();
970
971 if (current_access == make)
972 return;
973
974 /* See comments in user_access, above. */
975
976#ifdef HAVE_SETEUID
977 if (seteuid (make_uid) < 0)
978 pfatal_with_name ("make_access: seteuid");
979#else
980#ifndef HAVE_SETREUID
981 if (setuid (make_uid) < 0)
982 pfatal_with_name ("make_access: setuid");
983#else
984 if (setreuid (user_uid, make_uid) < 0)
985 pfatal_with_name ("make_access: setreuid");
986#endif
987#endif
988
989#ifdef HAVE_SETEGID
990 if (setegid (make_gid) < 0)
991 pfatal_with_name ("make_access: setegid");
992#else
993#ifndef HAVE_SETREGID
994 if (setgid (make_gid) < 0)
995 pfatal_with_name ("make_access: setgid");
996#else
997 if (setregid (user_gid, make_gid) < 0)
998 pfatal_with_name ("make_access: setregid");
999#endif
1000#endif
1001
1002 current_access = make;
1003
1004 log_access (_("Make access"));
1005
1006#endif /* GETLOADAVG_PRIVILEGED */
1007}
1008
1009/* Give the process appropriate permissions for a child process.
1010 This is like user_access, but you can't get back to make_access. */
1011void
1012child_access (void)
1013{
1014#ifdef GETLOADAVG_PRIVILEGED
1015
1016 if (!access_inited)
1017 abort ();
1018
1019 /* Set both the real and effective UID and GID to the user's.
1020 They cannot be changed back to make's. */
1021
1022#ifndef HAVE_SETREUID
1023 if (setuid (user_uid) < 0)
1024 pfatal_with_name ("child_access: setuid");
1025#else
1026 if (setreuid (user_uid, user_uid) < 0)
1027 pfatal_with_name ("child_access: setreuid");
1028#endif
1029
1030#ifndef HAVE_SETREGID
1031 if (setgid (user_gid) < 0)
1032 pfatal_with_name ("child_access: setgid");
1033#else
1034 if (setregid (user_gid, user_gid) < 0)
1035 pfatal_with_name ("child_access: setregid");
1036#endif
1037
1038 log_access (_("Child access"));
1039
1040#endif /* GETLOADAVG_PRIVILEGED */
1041}
1042
1043#ifdef NEED_GET_PATH_MAX
1044unsigned int
1045get_path_max (void)
1046{
1047 static unsigned int value;
1048
1049 if (value == 0)
1050 {
1051 long int x = pathconf ("/", _PC_PATH_MAX);
1052 if (x > 0)
1053 value = x;
1054 else
1055 return MAXPATHLEN;
1056 }
1057
1058 return value;
1059}
1060#endif
1061
1062#ifdef CONFIG_WITH_PRINT_STATS_SWITCH
1063/* Print heap statistics if supported by the platform. */
1064void
1065print_heap_stats (void)
1066{
1067 /* Darwin / Mac OS X */
1068# ifdef __APPLE__
1069 malloc_statistics_t s;
1070
1071 malloc_zone_statistics (NULL, &s);
1072 printf (_("\n# CRT Heap: %u bytes in use, in %u blocks, avg %u bytes/block\n"),
1073 (unsigned)s.size_in_use, (unsigned)s.blocks_in_use,
1074 s.blocks_in_use ? (unsigned)(s.size_in_use / s.blocks_in_use : 0));
1075 printf (_("# %u bytes max in use (high water mark)\n"),
1076 (unsigned)s.max_size_in_use);
1077 printf (_("# %u bytes reserved, %u bytes free (estimate)\n"),
1078 (unsigned)s.size_allocated,
1079 (unsigned)(s.size_allocated - s.size_in_use));
1080# endif /* __APPLE__ */
1081
1082 /* MSC / Windows */
1083# ifdef _MSC_VER
1084 unsigned int blocks_used = 0;
1085 unsigned int bytes_used = 0;
1086 unsigned int blocks_avail = 0;
1087 unsigned int bytes_avail = 0;
1088 _HEAPINFO hinfo;
1089
1090 memset (&hinfo, '\0', sizeof (hinfo));
1091 while (_heapwalk(&hinfo) == _HEAPOK)
1092 {
1093 if (hinfo._useflag == _USEDENTRY)
1094 {
1095 blocks_used++;
1096 bytes_used += hinfo._size;
1097 }
1098 else
1099 {
1100 blocks_avail++;
1101 bytes_avail += hinfo._size;
1102 }
1103 }
1104
1105 printf (_("\n# CRT Heap: %u bytes in use, in %u blocks, avg %u bytes/block\n"),
1106 bytes_used, blocks_used, blocks_used ? bytes_used / blocks_used : 0);
1107 printf (_("# %u bytes avail, in %u blocks, avg %u bytes/block\n"),
1108 bytes_avail, blocks_avail, blocks_avail ? bytes_avail / blocks_avail : 0);
1109# endif /* _MSC_VER */
1110
1111 /* Darwin Libc sources indicates that something like this may be
1112 found in GLIBC, however, it's not in any current one... */
1113# if 0 /* ??? */
1114 struct mstats m;
1115
1116 m = mstats();
1117 printf (_("\n# CRT Heap: %zu blocks / %zu bytes in use, %zu blocks / %zu bytes free\n"),
1118 m.chunks_used, m.bytes_used, m.chunks_free, m.bytes_free);
1119 printf (_("# %zu bytes reserved\n"),
1120 m.bytes_total);
1121# endif /* ??? */
1122
1123 /* XVID2/XPG mallinfo (displayed per GLIBC documentation). */
1124# if defined(__GLIBC__) || defined(HAVE_MALLINFO)
1125 struct mallinfo m;
1126
1127 m = mallinfo();
1128 printf (_("\n# CRT Heap: %d bytes in use, %d bytes free\n"),
1129 m.uordblks, m.fordblks);
1130
1131 printf (_("# # free chunks=%d, # fastbin blocks=%d\n"),
1132 m.ordblks, m.smblks);
1133 printf (_("# # mapped regions=%d, space in mapped regions=%d\n"),
1134 m.hblks, m.hblkhd);
1135 printf (_("# non-mapped space allocated from system=%d\n"),
1136 m.arena);
1137 printf (_("# maximum total allocated space=%d\n"),
1138 m.usmblks);
1139 printf (_("# top-most releasable space=%d\n"),
1140 m.keepcost);
1141# endif /* __GLIBC__ || HAVE_MALLINFO */
1142
1143# ifdef CONFIG_WITH_MAKE_STATS
1144 printf(_("# %lu malloc calls, %lu realloc calls\n"),
1145 make_stats_allocations, make_stats_reallocations);
1146 printf(_("# %lu MBs alloc sum, not counting freed, add pinch of salt\n"), /* XXX: better wording */
1147 make_stats_allocated / (1024*1024));
1148# endif
1149
1150 /* XXX: windows */
1151}
1152#endif /* CONFIG_WITH_PRINT_STATS_SWITCH */
1153
1154#if defined(CONFIG_WITH_PRINT_TIME_SWITCH) || defined(CONFIG_WITH_KMK_BUILTIN_STATS)
1155/* Get a nanosecond timestamp, from a monotonic time source if
1156 possible. Returns -1 after calling error() on failure. */
1157
1158big_int
1159nano_timestamp (void)
1160{
1161 big_int ts;
1162#if defined (WINDOWS32)
1163 static int s_state = -1;
1164 static LARGE_INTEGER s_freq;
1165
1166 if (s_state == -1)
1167 s_state = QueryPerformanceFrequency (&s_freq);
1168 if (s_state)
1169 {
1170 LARGE_INTEGER pc;
1171 if (!QueryPerformanceCounter (&pc))
1172 {
1173 s_state = 0;
1174 return nano_timestamp ();
1175 }
1176 ts = (big_int)((long double)pc.QuadPart / (long double)s_freq.QuadPart * 1000000000);
1177 }
1178 else
1179 {
1180 /* fall back to low resolution system time. */
1181 LARGE_INTEGER bigint;
1182 FILETIME ft = {0,0};
1183 GetSystemTimeAsFileTime (&ft);
1184 bigint.u.LowPart = ft.dwLowDateTime;
1185 bigint.u.HighPart = ft.dwLowDateTime;
1186 ts = bigint.QuadPart * 100;
1187 }
1188
1189#elif HAVE_GETTIMEOFDAY
1190/* FIXME: Linux and others have the realtime clock_* api, detect and use it. */
1191 struct timeval tv;
1192 if (!gettimeofday (&tv, NULL))
1193 ts = (big_int)tv.tv_sec * 1000000000
1194 + tv.tv_usec * 1000;
1195 else
1196 {
1197 O (error, NILF, _("gettimeofday failed"));
1198 ts = -1;
1199 }
1200
1201#else
1202# error "PORTME"
1203#endif
1204
1205 return ts;
1206}
1207
1208/* Formats the elapsed time (nano seconds) in the manner easiest
1209 to read, with millisecond percision for larger numbers. */
1210
1211int
1212format_elapsed_nano (char *buf, size_t size, big_int ts)
1213{
1214 unsigned sz;
1215 if (ts < 1000)
1216 sz = sprintf (buf, "%uns", (unsigned)ts);
1217 else if (ts < 100000)
1218 sz = sprintf (buf, "%u.%03uus",
1219 (unsigned)(ts / 1000),
1220 (unsigned)(ts % 1000));
1221 else
1222 {
1223 ts /= 1000;
1224 if (ts < 1000)
1225 sz = sprintf (buf, "%uus", (unsigned)ts);
1226 else if (ts < 100000)
1227 sz = sprintf (buf, "%u.%03ums",
1228 (unsigned)(ts / 1000),
1229 (unsigned)(ts % 1000));
1230 else
1231 {
1232 ts /= 1000;
1233 if (ts < BIG_INT_C(60000))
1234 sz = sprintf (buf,
1235 "%u.%03us",
1236 (unsigned)(ts / 1000),
1237 (unsigned)(ts % 1000));
1238 else
1239 sz = sprintf (buf,
1240 "%um%u.%03us",
1241 (unsigned)( ts / BIG_INT_C(60000)),
1242 (unsigned)((ts % BIG_INT_C(60000)) / 1000),
1243 (unsigned)((ts % BIG_INT_C(60000)) % 1000));
1244 }
1245 }
1246 if (sz >= size)
1247 ONN (fatal, NILF, _("format_elapsed_nano buffer overflow: %u written, %lu buffer"),
1248 sz, (unsigned long)size);
1249 return sz;
1250}
1251#endif /* CONFIG_WITH_PRINT_TIME_SWITCH || defined(CONFIG_WITH_KMK_BUILTIN_STATS) */
1252
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use