VirtualBox

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

Last change on this file since 3387 was 3322, checked in by bird, 4 years ago

kmk/kbuild: kbuild_apply_defpath must walk quoted file tokens rather than simple space separated tokens. Added find_next_file_token to do the parsing. Updated find_next_token_eos with correct variable expansion skipping.

  • Property svn:eol-style set to native
File size: 32.0 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
603#ifdef KMK
604/* Finds the ends of the variable expansion starting at S, stopping at EOS if
605 not found before. */
606static char *find_end_of_variable_expansion (const char *s, char const *eos)
607{
608 char const openparen = s[1];
609 char const closeparen = openparen == '(' ? ')' : '}';
610 int levels = 0;
611
612 assert (s[0] == '$');
613 assert (s[1] == '(' || s[1] == '{');
614
615 s += 2;
616 while (s != eos)
617 {
618 unsigned char ch = *s;
619 if (ch != '\0')
620 {
621 if (ch != closeparen)
622 {
623 if (ch != openparen)
624 { /* likely */ }
625 else
626 levels++;
627 }
628 else if (levels <= 1)
629 break;
630 else
631 levels--;
632 }
633 else
634 break;
635 s++;
636 }
637
638 return (char *)s;
639}
640
641/* Same as find_next_token with two exception:
642 - The string ends at EOS or '\0'.
643 - We keep track of $() and ${}, allowing functions to be used. */
644
645char *
646find_next_token_eos (const char **ptr, const char *eos, unsigned int *lengthptr)
647{
648 const char *p = *ptr;
649 const char *e;
650
651 /* skip blanks */
652 while (p != eos)
653 {
654 unsigned char const ch = *p;
655 unsigned int const map = stopchar_map[ch] & (MAP_NUL | MAP_BLANK);
656 if (map & MAP_BLANK)
657 p++;
658 else if (!(map & MAP_NUL))
659 break;
660 else
661 return NULL;
662 }
663 if (p == eos)
664 return NULL;
665
666 /* skip ahead until EOS or blanks. */
667 e = p;
668 while (e != eos)
669 {
670 unsigned char const ch = *e;
671 unsigned int const map = stopchar_map[ch] & (MAP_NUL | MAP_BLANK | MAP_VARIABLE);
672 if (!map)
673 e++; /* likely */
674 /* Dollar can be escaped by duplication ($$) and when not, they need to
675 be skipped over. */
676 else if (map & MAP_VARIABLE)
677 {
678 e++;
679 if (&e[1] != eos)
680 {
681 unsigned ch2 = *e;
682 if (ch2 == ch)
683 e++; /* escaped */
684 else if (ch == '(' || ch == '}')
685 e = find_end_of_variable_expansion (e - 1, eos);
686 }
687 else
688 break;
689 }
690 else
691 break; /* MAP_NUL or MAP_BLANK */
692 }
693
694 *ptr = e;
695 if (lengthptr != 0)
696 *lengthptr = e - p;
697
698 return (char *)p;
699}
700
701/* Same as find_next_token_eos but takes GNU make quoting into account,
702 but without doing any unquoting like find_char_unquote & parse_file_seq. */
703
704char *
705find_next_file_token (const char **ptr, const char *eos, unsigned int *lengthptr)
706{
707 const char *p = *ptr;
708 const char *e;
709
710 /* skip blanks */
711 while (p != eos)
712 {
713 unsigned char const ch = *p;
714 unsigned int const map = stopchar_map[ch] & (MAP_NUL | MAP_BLANK);
715 if (map & MAP_BLANK)
716 p++;
717 else if (!(map & MAP_NUL))
718 break;
719 else
720 return NULL;
721 }
722 if (p == eos)
723 return NULL;
724
725 /* skip ahead until EOS or blanks. */
726 e = p;
727 while (e != eos)
728 {
729 unsigned char const ch = *e;
730 unsigned int const map = stopchar_map[ch] & (MAP_NUL | MAP_BLANK | MAP_VARIABLE);
731 if (!map)
732 e++; /* likely */
733 /* Dollar can be escaped by duplication ($$) and when not, they need to
734 be skipped over. */
735 else if (map & MAP_VARIABLE)
736 {
737 e++;
738 if (&e[1] != eos)
739 {
740 unsigned ch2 = *e;
741 if (ch2 == ch)
742 e++; /* escaped */
743 else if (ch == '(' || ch == '}')
744 e = find_end_of_variable_expansion (e - 1, eos);
745 }
746 else
747 break;
748 }
749 else if (map & MAP_NUL)
750 break;
751 /* A blank can be escaped using a backslash. */
752 else if (e[-1] != '\\')
753 break;
754 else
755 {
756 int slashes = 1;
757 while (&e[-slashes] != p && e[-slashes - 1] == '\\')
758 slashes++;
759 if (slashes & 1)
760 e++;
761 else
762 break;
763 }
764 }
765
766 *ptr = e;
767 if (lengthptr != 0)
768 *lengthptr = e - p;
769
770 return (char *)p;
771}
772
773#endif /* KMK */
774
775
776
777/* Copy a chain of 'struct dep'. For 2nd expansion deps, dup the name. */
778
779struct dep *
780copy_dep_chain (const struct dep *d)
781{
782 struct dep *firstnew = 0;
783 struct dep *lastnew = 0;
784
785 while (d != 0)
786 {
787#ifndef CONFIG_WITH_ALLOC_CACHES
788 struct dep *c = xmalloc (sizeof (struct dep));
789#else
790 struct dep *c = alloccache_alloc(&dep_cache);
791#endif
792 memcpy (c, d, sizeof (struct dep));
793
794 /** @todo KMK: Check if we need this duplication! */
795 if (c->need_2nd_expansion)
796 c->name = xstrdup (c->name);
797
798 c->next = 0;
799 if (firstnew == 0)
800 firstnew = lastnew = c;
801 else
802 lastnew = lastnew->next = c;
803
804 d = d->next;
805 }
806
807 return firstnew;
808}
809
810/* Free a chain of struct nameseq.
811 For struct dep chains use free_dep_chain. */
812
813void
814free_ns_chain (struct nameseq *ns)
815{
816 while (ns != 0)
817 {
818 struct nameseq *t = ns;
819 ns = ns->next;
820#ifndef CONFIG_WITH_ALLOC_CACHES
821 free_ns (t);
822#else
823 alloccache_free (&nameseq_cache, t);
824#endif
825 }
826}
827
828
829#ifdef CONFIG_WITH_ALLOC_CACHES
830
831void
832free_dep_chain (struct dep *d)
833{
834 while (d != 0)
835 {
836 struct dep *tofree = d;
837 d = d->next;
838 alloccache_free (&dep_cache, tofree);
839 }
840}
841
842void
843free_goal_chain (struct goaldep *g)
844{
845 while (g != 0)
846 {
847 struct goaldep *tofree = g;
848 g = g->next;
849 alloccache_free (&dep_cache, tofree);
850 }
851}
852
853#endif /* CONFIG_WITH_ALLOC_CACHES */
854
855
856
857#if !HAVE_STRCASECMP && !HAVE_STRICMP && !HAVE_STRCMPI
858/* If we don't have strcasecmp() (from POSIX), or anything that can substitute
859 for it, define our own version. */
860
861int
862strcasecmp (const char *s1, const char *s2)
863{
864 while (1)
865 {
866 int c1 = (int) *(s1++);
867 int c2 = (int) *(s2++);
868
869 if (isalpha (c1))
870 c1 = tolower (c1);
871 if (isalpha (c2))
872 c2 = tolower (c2);
873
874 if (c1 != '\0' && c1 == c2)
875 continue;
876
877 return (c1 - c2);
878 }
879}
880#endif
881
882#if !HAVE_STRNCASECMP && !HAVE_STRNICMP && !HAVE_STRNCMPI
883/* If we don't have strncasecmp() (from POSIX), or anything that can
884 substitute for it, define our own version. */
885
886int
887strncasecmp (const char *s1, const char *s2, int n)
888{
889 while (n-- > 0)
890 {
891 int c1 = (int) *(s1++);
892 int c2 = (int) *(s2++);
893
894 if (isalpha (c1))
895 c1 = tolower (c1);
896 if (isalpha (c2))
897 c2 = tolower (c2);
898
899 if (c1 != '\0' && c1 == c2)
900 continue;
901
902 return (c1 - c2);
903 }
904
905 return 0;
906}
907#endif
908
909
910#ifdef GETLOADAVG_PRIVILEGED
911
912#ifdef POSIX
913
914/* Hopefully if a system says it's POSIX.1 and has the setuid and setgid
915 functions, they work as POSIX.1 says. Some systems (Alpha OSF/1 1.2,
916 for example) which claim to be POSIX.1 also have the BSD setreuid and
917 setregid functions, but they don't work as in BSD and only the POSIX.1
918 way works. */
919
920#undef HAVE_SETREUID
921#undef HAVE_SETREGID
922
923#else /* Not POSIX. */
924
925/* Some POSIX.1 systems have the seteuid and setegid functions. In a
926 POSIX-like system, they are the best thing to use. However, some
927 non-POSIX systems have them too but they do not work in the POSIX style
928 and we must use setreuid and setregid instead. */
929
930#undef HAVE_SETEUID
931#undef HAVE_SETEGID
932
933#endif /* POSIX. */
934
935#ifndef HAVE_UNISTD_H
936extern int getuid (), getgid (), geteuid (), getegid ();
937extern int setuid (), setgid ();
938#ifdef HAVE_SETEUID
939extern int seteuid ();
940#else
941#ifdef HAVE_SETREUID
942extern int setreuid ();
943#endif /* Have setreuid. */
944#endif /* Have seteuid. */
945#ifdef HAVE_SETEGID
946extern int setegid ();
947#else
948#ifdef HAVE_SETREGID
949extern int setregid ();
950#endif /* Have setregid. */
951#endif /* Have setegid. */
952#endif /* No <unistd.h>. */
953
954/* Keep track of the user and group IDs for user- and make- access. */
955static int user_uid = -1, user_gid = -1, make_uid = -1, make_gid = -1;
956#define access_inited (user_uid != -1)
957static enum { make, user } current_access;
958
959
960/* Under -d, write a message describing the current IDs. */
961
962static void
963log_access (const char *flavor)
964{
965 if (! ISDB (DB_JOBS))
966 return;
967
968 /* All the other debugging messages go to stdout,
969 but we write this one to stderr because it might be
970 run in a child fork whose stdout is piped. */
971
972 fprintf (stderr, _("%s: user %lu (real %lu), group %lu (real %lu)\n"),
973 flavor, (unsigned long) geteuid (), (unsigned long) getuid (),
974 (unsigned long) getegid (), (unsigned long) getgid ());
975 fflush (stderr);
976}
977
978
979static void
980init_access (void)
981{
982#ifndef VMS
983 user_uid = getuid ();
984 user_gid = getgid ();
985
986 make_uid = geteuid ();
987 make_gid = getegid ();
988
989 /* Do these ever fail? */
990 if (user_uid == -1 || user_gid == -1 || make_uid == -1 || make_gid == -1)
991 pfatal_with_name ("get{e}[gu]id");
992
993 log_access (_("Initialized access"));
994
995 current_access = make;
996#endif
997}
998
999#endif /* GETLOADAVG_PRIVILEGED */
1000
1001/* Give the process appropriate permissions for access to
1002 user data (i.e., to stat files, or to spawn a child process). */
1003void
1004user_access (void)
1005{
1006#ifdef GETLOADAVG_PRIVILEGED
1007
1008 if (!access_inited)
1009 init_access ();
1010
1011 if (current_access == user)
1012 return;
1013
1014 /* We are in "make access" mode. This means that the effective user and
1015 group IDs are those of make (if it was installed setuid or setgid).
1016 We now want to set the effective user and group IDs to the real IDs,
1017 which are the IDs of the process that exec'd make. */
1018
1019#ifdef HAVE_SETEUID
1020
1021 /* Modern systems have the seteuid/setegid calls which set only the
1022 effective IDs, which is ideal. */
1023
1024 if (seteuid (user_uid) < 0)
1025 pfatal_with_name ("user_access: seteuid");
1026
1027#else /* Not HAVE_SETEUID. */
1028
1029#ifndef HAVE_SETREUID
1030
1031 /* System V has only the setuid/setgid calls to set user/group IDs.
1032 There is an effective ID, which can be set by setuid/setgid.
1033 It can be set (unless you are root) only to either what it already is
1034 (returned by geteuid/getegid, now in make_uid/make_gid),
1035 the real ID (return by getuid/getgid, now in user_uid/user_gid),
1036 or the saved set ID (what the effective ID was before this set-ID
1037 executable (make) was exec'd). */
1038
1039 if (setuid (user_uid) < 0)
1040 pfatal_with_name ("user_access: setuid");
1041
1042#else /* HAVE_SETREUID. */
1043
1044 /* In 4BSD, the setreuid/setregid calls set both the real and effective IDs.
1045 They may be set to themselves or each other. So you have two alternatives
1046 at any one time. If you use setuid/setgid, the effective will be set to
1047 the real, leaving only one alternative. Using setreuid/setregid, however,
1048 you can toggle between your two alternatives by swapping the values in a
1049 single setreuid or setregid call. */
1050
1051 if (setreuid (make_uid, user_uid) < 0)
1052 pfatal_with_name ("user_access: setreuid");
1053
1054#endif /* Not HAVE_SETREUID. */
1055#endif /* HAVE_SETEUID. */
1056
1057#ifdef HAVE_SETEGID
1058 if (setegid (user_gid) < 0)
1059 pfatal_with_name ("user_access: setegid");
1060#else
1061#ifndef HAVE_SETREGID
1062 if (setgid (user_gid) < 0)
1063 pfatal_with_name ("user_access: setgid");
1064#else
1065 if (setregid (make_gid, user_gid) < 0)
1066 pfatal_with_name ("user_access: setregid");
1067#endif
1068#endif
1069
1070 current_access = user;
1071
1072 log_access (_("User access"));
1073
1074#endif /* GETLOADAVG_PRIVILEGED */
1075}
1076
1077/* Give the process appropriate permissions for access to
1078 make data (i.e., the load average). */
1079void
1080make_access (void)
1081{
1082#ifdef GETLOADAVG_PRIVILEGED
1083
1084 if (!access_inited)
1085 init_access ();
1086
1087 if (current_access == make)
1088 return;
1089
1090 /* See comments in user_access, above. */
1091
1092#ifdef HAVE_SETEUID
1093 if (seteuid (make_uid) < 0)
1094 pfatal_with_name ("make_access: seteuid");
1095#else
1096#ifndef HAVE_SETREUID
1097 if (setuid (make_uid) < 0)
1098 pfatal_with_name ("make_access: setuid");
1099#else
1100 if (setreuid (user_uid, make_uid) < 0)
1101 pfatal_with_name ("make_access: setreuid");
1102#endif
1103#endif
1104
1105#ifdef HAVE_SETEGID
1106 if (setegid (make_gid) < 0)
1107 pfatal_with_name ("make_access: setegid");
1108#else
1109#ifndef HAVE_SETREGID
1110 if (setgid (make_gid) < 0)
1111 pfatal_with_name ("make_access: setgid");
1112#else
1113 if (setregid (user_gid, make_gid) < 0)
1114 pfatal_with_name ("make_access: setregid");
1115#endif
1116#endif
1117
1118 current_access = make;
1119
1120 log_access (_("Make access"));
1121
1122#endif /* GETLOADAVG_PRIVILEGED */
1123}
1124
1125/* Give the process appropriate permissions for a child process.
1126 This is like user_access, but you can't get back to make_access. */
1127void
1128child_access (void)
1129{
1130#ifdef GETLOADAVG_PRIVILEGED
1131
1132 if (!access_inited)
1133 abort ();
1134
1135 /* Set both the real and effective UID and GID to the user's.
1136 They cannot be changed back to make's. */
1137
1138#ifndef HAVE_SETREUID
1139 if (setuid (user_uid) < 0)
1140 pfatal_with_name ("child_access: setuid");
1141#else
1142 if (setreuid (user_uid, user_uid) < 0)
1143 pfatal_with_name ("child_access: setreuid");
1144#endif
1145
1146#ifndef HAVE_SETREGID
1147 if (setgid (user_gid) < 0)
1148 pfatal_with_name ("child_access: setgid");
1149#else
1150 if (setregid (user_gid, user_gid) < 0)
1151 pfatal_with_name ("child_access: setregid");
1152#endif
1153
1154 log_access (_("Child access"));
1155
1156#endif /* GETLOADAVG_PRIVILEGED */
1157}
1158
1159#ifdef NEED_GET_PATH_MAX
1160unsigned int
1161get_path_max (void)
1162{
1163 static unsigned int value;
1164
1165 if (value == 0)
1166 {
1167 long int x = pathconf ("/", _PC_PATH_MAX);
1168 if (x > 0)
1169 value = x;
1170 else
1171 return MAXPATHLEN;
1172 }
1173
1174 return value;
1175}
1176#endif
1177
1178#ifdef CONFIG_WITH_PRINT_STATS_SWITCH
1179/* Print heap statistics if supported by the platform. */
1180void
1181print_heap_stats (void)
1182{
1183 /* Darwin / Mac OS X */
1184# ifdef __APPLE__
1185 malloc_statistics_t s;
1186
1187 malloc_zone_statistics (NULL, &s);
1188 printf (_("\n# CRT Heap: %u bytes in use, in %u blocks, avg %u bytes/block\n"),
1189 (unsigned)s.size_in_use, (unsigned)s.blocks_in_use,
1190 s.blocks_in_use ? (unsigned)(s.size_in_use / s.blocks_in_use) : 0);
1191 printf (_("# %u bytes max in use (high water mark)\n"),
1192 (unsigned)s.max_size_in_use);
1193 printf (_("# %u bytes reserved, %u bytes free (estimate)\n"),
1194 (unsigned)s.size_allocated,
1195 (unsigned)(s.size_allocated - s.size_in_use));
1196# endif /* __APPLE__ */
1197
1198 /* MSC / Windows */
1199# ifdef _MSC_VER
1200 unsigned int blocks_used = 0;
1201 unsigned int bytes_used = 0;
1202 unsigned int blocks_avail = 0;
1203 unsigned int bytes_avail = 0;
1204 _HEAPINFO hinfo;
1205
1206 memset (&hinfo, '\0', sizeof (hinfo));
1207 while (_heapwalk(&hinfo) == _HEAPOK)
1208 {
1209 if (hinfo._useflag == _USEDENTRY)
1210 {
1211 blocks_used++;
1212 bytes_used += hinfo._size;
1213 }
1214 else
1215 {
1216 blocks_avail++;
1217 bytes_avail += hinfo._size;
1218 }
1219 }
1220
1221 printf (_("\n# CRT Heap: %u bytes in use, in %u blocks, avg %u bytes/block\n"),
1222 bytes_used, blocks_used, blocks_used ? bytes_used / blocks_used : 0);
1223 printf (_("# %u bytes avail, in %u blocks, avg %u bytes/block\n"),
1224 bytes_avail, blocks_avail, blocks_avail ? bytes_avail / blocks_avail : 0);
1225# endif /* _MSC_VER */
1226
1227 /* Darwin Libc sources indicates that something like this may be
1228 found in GLIBC, however, it's not in any current one... */
1229# if 0 /* ??? */
1230 struct mstats m;
1231
1232 m = mstats();
1233 printf (_("\n# CRT Heap: %zu blocks / %zu bytes in use, %zu blocks / %zu bytes free\n"),
1234 m.chunks_used, m.bytes_used, m.chunks_free, m.bytes_free);
1235 printf (_("# %zu bytes reserved\n"),
1236 m.bytes_total);
1237# endif /* ??? */
1238
1239 /* XVID2/XPG mallinfo (displayed per GLIBC documentation). */
1240# if defined(__GLIBC__) || defined(HAVE_MALLINFO)
1241 struct mallinfo m;
1242
1243 m = mallinfo();
1244 printf (_("\n# CRT Heap: %d bytes in use, %d bytes free\n"),
1245 m.uordblks, m.fordblks);
1246
1247 printf (_("# # free chunks=%d, # fastbin blocks=%d\n"),
1248 m.ordblks, m.smblks);
1249 printf (_("# # mapped regions=%d, space in mapped regions=%d\n"),
1250 m.hblks, m.hblkhd);
1251 printf (_("# non-mapped space allocated from system=%d\n"),
1252 m.arena);
1253 printf (_("# maximum total allocated space=%d\n"),
1254 m.usmblks);
1255 printf (_("# top-most releasable space=%d\n"),
1256 m.keepcost);
1257# endif /* __GLIBC__ || HAVE_MALLINFO */
1258
1259# ifdef CONFIG_WITH_MAKE_STATS
1260 printf(_("# %lu malloc calls, %lu realloc calls\n"),
1261 make_stats_allocations, make_stats_reallocations);
1262 printf(_("# %lu MBs alloc sum, not counting freed, add pinch of salt\n"), /* XXX: better wording */
1263 make_stats_allocated / (1024*1024));
1264# endif
1265
1266 /* XXX: windows */
1267}
1268#endif /* CONFIG_WITH_PRINT_STATS_SWITCH */
1269
1270#if defined(CONFIG_WITH_PRINT_TIME_SWITCH) || defined(CONFIG_WITH_KMK_BUILTIN_STATS)
1271/* Get a nanosecond timestamp, from a monotonic time source if
1272 possible. Returns -1 after calling error() on failure. */
1273
1274big_int
1275nano_timestamp (void)
1276{
1277 big_int ts;
1278#if defined (WINDOWS32)
1279 static int s_state = -1;
1280 static LARGE_INTEGER s_freq;
1281
1282 if (s_state == -1)
1283 s_state = QueryPerformanceFrequency (&s_freq);
1284 if (s_state)
1285 {
1286 LARGE_INTEGER pc;
1287 if (!QueryPerformanceCounter (&pc))
1288 {
1289 s_state = 0;
1290 return nano_timestamp ();
1291 }
1292 ts = (big_int)((long double)pc.QuadPart / (long double)s_freq.QuadPart * 1000000000);
1293 }
1294 else
1295 {
1296 /* fall back to low resolution system time. */
1297 LARGE_INTEGER bigint;
1298 FILETIME ft = {0,0};
1299 GetSystemTimeAsFileTime (&ft);
1300 bigint.u.LowPart = ft.dwLowDateTime;
1301 bigint.u.HighPart = ft.dwLowDateTime;
1302 ts = bigint.QuadPart * 100;
1303 }
1304
1305#elif HAVE_GETTIMEOFDAY
1306/* FIXME: Linux and others have the realtime clock_* api, detect and use it. */
1307 struct timeval tv;
1308 if (!gettimeofday (&tv, NULL))
1309 ts = (big_int)tv.tv_sec * 1000000000
1310 + tv.tv_usec * 1000;
1311 else
1312 {
1313 O (error, NILF, _("gettimeofday failed"));
1314 ts = -1;
1315 }
1316
1317#else
1318# error "PORTME"
1319#endif
1320
1321 return ts;
1322}
1323
1324/* Formats the elapsed time (nano seconds) in the manner easiest
1325 to read, with millisecond percision for larger numbers. */
1326
1327int
1328format_elapsed_nano (char *buf, size_t size, big_int ts)
1329{
1330 unsigned sz;
1331 if (ts < 1000)
1332 sz = sprintf (buf, "%uns", (unsigned)ts);
1333 else if (ts < 100000)
1334 sz = sprintf (buf, "%u.%03uus",
1335 (unsigned)(ts / 1000),
1336 (unsigned)(ts % 1000));
1337 else
1338 {
1339 ts /= 1000;
1340 if (ts < 1000)
1341 sz = sprintf (buf, "%uus", (unsigned)ts);
1342 else if (ts < 100000)
1343 sz = sprintf (buf, "%u.%03ums",
1344 (unsigned)(ts / 1000),
1345 (unsigned)(ts % 1000));
1346 else
1347 {
1348 ts /= 1000;
1349 if (ts < BIG_INT_C(60000))
1350 sz = sprintf (buf,
1351 "%u.%03us",
1352 (unsigned)(ts / 1000),
1353 (unsigned)(ts % 1000));
1354 else
1355 sz = sprintf (buf,
1356 "%um%u.%03us",
1357 (unsigned)( ts / BIG_INT_C(60000)),
1358 (unsigned)((ts % BIG_INT_C(60000)) / 1000),
1359 (unsigned)((ts % BIG_INT_C(60000)) % 1000));
1360 }
1361 }
1362 if (sz >= size)
1363 ONN (fatal, NILF, _("format_elapsed_nano buffer overflow: %u written, %lu buffer"),
1364 sz, (unsigned long)size);
1365 return sz;
1366}
1367#endif /* CONFIG_WITH_PRINT_TIME_SWITCH || defined(CONFIG_WITH_KMK_BUILTIN_STATS) */
1368
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use