1994-03-23 14:12:55 +00:00
|
|
|
|
/* Miscellaneous generic support functions for GNU Make.
|
2013-05-17 05:46:11 +00:00
|
|
|
|
Copyright (C) 1988-2013 Free Software Foundation, Inc.
|
1991-10-07 22:04:20 +00:00
|
|
|
|
This file is part of GNU Make.
|
|
|
|
|
|
2006-02-11 20:00:39 +00:00
|
|
|
|
GNU Make is free software; you can redistribute it and/or modify it under the
|
|
|
|
|
terms of the GNU General Public License as published by the Free Software
|
2007-07-04 19:35:15 +00:00
|
|
|
|
Foundation; either version 3 of the License, or (at your option) any later
|
|
|
|
|
version.
|
1991-10-07 22:04:20 +00:00
|
|
|
|
|
2006-02-11 20:00:39 +00:00
|
|
|
|
GNU Make is distributed in the hope that it will be useful, but WITHOUT ANY
|
|
|
|
|
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
|
|
|
|
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
1991-10-07 22:04:20 +00:00
|
|
|
|
|
2006-02-11 20:00:39 +00:00
|
|
|
|
You should have received a copy of the GNU General Public License along with
|
2007-07-04 19:35:15 +00:00
|
|
|
|
this program. If not, see <http://www.gnu.org/licenses/>. */
|
1991-10-07 22:04:20 +00:00
|
|
|
|
|
2013-01-20 16:01:01 +00:00
|
|
|
|
#include "makeint.h"
|
1991-10-07 22:04:20 +00:00
|
|
|
|
#include "dep.h"
|
1999-11-22 06:15:35 +00:00
|
|
|
|
#include "debug.h"
|
1991-10-07 22:04:20 +00:00
|
|
|
|
|
2013-04-28 21:59:28 +00:00
|
|
|
|
/* GNU make no longer supports pre-ANSI89 environments. */
|
|
|
|
|
|
|
|
|
|
#include <stdarg.h>
|
1998-10-03 05:39:55 +00:00
|
|
|
|
|
2013-06-29 01:57:59 +00:00
|
|
|
|
#ifdef HAVE_FCNTL_H
|
|
|
|
|
# include <fcntl.h>
|
|
|
|
|
#else
|
|
|
|
|
# include <sys/file.h>
|
|
|
|
|
#endif
|
1998-10-03 05:39:55 +00:00
|
|
|
|
|
1991-10-07 22:04:20 +00:00
|
|
|
|
/* Compare strings *S1 and *S2.
|
|
|
|
|
Return negative if the first is less, positive if it is greater,
|
|
|
|
|
zero if they are equal. */
|
|
|
|
|
|
|
|
|
|
int
|
2002-10-14 21:54:04 +00:00
|
|
|
|
alpha_compare (const void *v1, const void *v2)
|
1991-10-07 22:04:20 +00:00
|
|
|
|
{
|
1998-10-03 05:39:55 +00:00
|
|
|
|
const char *s1 = *((char **)v1);
|
|
|
|
|
const char *s2 = *((char **)v2);
|
|
|
|
|
|
|
|
|
|
if (*s1 != *s2)
|
|
|
|
|
return *s1 - *s2;
|
|
|
|
|
return strcmp (s1, s2);
|
1991-10-07 22:04:20 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Discard each backslash-newline combination from LINE.
|
|
|
|
|
Backslash-backslash-newline combinations become backslash-newlines.
|
|
|
|
|
This is done by copying the text at LINE into itself. */
|
|
|
|
|
|
|
|
|
|
void
|
2002-10-14 21:54:04 +00:00
|
|
|
|
collapse_continuations (char *line)
|
1991-10-07 22:04:20 +00:00
|
|
|
|
{
|
2013-07-21 21:52:13 +00:00
|
|
|
|
char *in, *out, *p;
|
1991-10-07 22:04:20 +00:00
|
|
|
|
|
1999-10-15 07:00:58 +00:00
|
|
|
|
in = strchr (line, '\n');
|
1991-10-07 22:04:20 +00:00
|
|
|
|
if (in == 0)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
out = in;
|
1995-12-12 04:24:17 +00:00
|
|
|
|
while (out > line && out[-1] == '\\')
|
|
|
|
|
--out;
|
1991-10-07 22:04:20 +00:00
|
|
|
|
|
|
|
|
|
while (*in != '\0')
|
|
|
|
|
{
|
|
|
|
|
/* BS_WRITE gets the number of quoted backslashes at
|
2013-05-17 06:29:46 +00:00
|
|
|
|
the end just before IN, and BACKSLASH gets nonzero
|
|
|
|
|
if the next character is quoted. */
|
2013-07-21 21:52:13 +00:00
|
|
|
|
unsigned int backslash = 0;
|
|
|
|
|
unsigned int bs_write = 0;
|
1991-10-07 22:04:20 +00:00
|
|
|
|
for (p = in - 1; p >= line && *p == '\\'; --p)
|
2013-05-17 06:29:46 +00:00
|
|
|
|
{
|
|
|
|
|
if (backslash)
|
|
|
|
|
++bs_write;
|
|
|
|
|
backslash = !backslash;
|
1991-10-07 22:04:20 +00:00
|
|
|
|
|
2013-05-17 06:29:46 +00:00
|
|
|
|
/* It should be impossible to go back this far without exiting,
|
|
|
|
|
but if we do, we can't get the right answer. */
|
|
|
|
|
if (in == out - 1)
|
|
|
|
|
abort ();
|
|
|
|
|
}
|
1991-10-07 22:04:20 +00:00
|
|
|
|
|
|
|
|
|
/* Output the appropriate number of backslashes. */
|
|
|
|
|
while (bs_write-- > 0)
|
2013-05-17 06:29:46 +00:00
|
|
|
|
*out++ = '\\';
|
1991-10-07 22:04:20 +00:00
|
|
|
|
|
|
|
|
|
/* Skip the newline. */
|
|
|
|
|
++in;
|
|
|
|
|
|
|
|
|
|
if (backslash)
|
2013-05-17 06:29:46 +00:00
|
|
|
|
{
|
2012-03-03 18:45:08 +00:00
|
|
|
|
/* Backslash/newline handling:
|
|
|
|
|
In traditional GNU make all trailing whitespace, consecutive
|
|
|
|
|
backslash/newlines, and any leading whitespace on the next line
|
|
|
|
|
is reduced to a single space.
|
|
|
|
|
In POSIX, each backslash/newline and is replaced by a space. */
|
2013-05-17 06:29:46 +00:00
|
|
|
|
in = next_token (in);
|
2012-03-03 18:45:08 +00:00
|
|
|
|
if (! posix_pedantic)
|
|
|
|
|
while (out > line && isblank ((unsigned char)out[-1]))
|
|
|
|
|
--out;
|
2013-05-17 06:29:46 +00:00
|
|
|
|
*out++ = ' ';
|
|
|
|
|
}
|
1991-10-07 22:04:20 +00:00
|
|
|
|
else
|
2013-05-17 06:29:46 +00:00
|
|
|
|
/* If the newline isn't quoted, put it in the output. */
|
|
|
|
|
*out++ = '\n';
|
1991-10-07 22:04:20 +00:00
|
|
|
|
|
|
|
|
|
/* Now copy the following line to the output.
|
2013-05-17 06:29:46 +00:00
|
|
|
|
Stop when we find backslashes followed by a newline. */
|
1991-10-07 22:04:20 +00:00
|
|
|
|
while (*in != '\0')
|
2013-05-17 06:29:46 +00:00
|
|
|
|
if (*in == '\\')
|
|
|
|
|
{
|
|
|
|
|
p = in + 1;
|
|
|
|
|
while (*p == '\\')
|
|
|
|
|
++p;
|
|
|
|
|
if (*p == '\n')
|
|
|
|
|
{
|
|
|
|
|
in = p;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
while (in < p)
|
|
|
|
|
*out++ = *in++;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
*out++ = *in++;
|
1991-10-07 22:04:20 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
*out = '\0';
|
|
|
|
|
}
|
|
|
|
|
|
1999-11-22 06:15:35 +00:00
|
|
|
|
/* Print N spaces (used in debug for target-depth). */
|
1991-10-07 22:04:20 +00:00
|
|
|
|
|
|
|
|
|
void
|
2002-10-14 21:54:04 +00:00
|
|
|
|
print_spaces (unsigned int n)
|
1991-10-07 22:04:20 +00:00
|
|
|
|
{
|
|
|
|
|
while (n-- > 0)
|
|
|
|
|
putchar (' ');
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2009-09-16 17:07:01 +00:00
|
|
|
|
/* Return a string whose contents concatenate the NUM strings provided
|
2007-03-20 03:02:26 +00:00
|
|
|
|
This string lives in static, re-used memory. */
|
1991-10-07 22:04:20 +00:00
|
|
|
|
|
2009-09-16 17:07:01 +00:00
|
|
|
|
const char *
|
|
|
|
|
concat (unsigned int num, ...)
|
1991-10-07 22:04:20 +00:00
|
|
|
|
{
|
2007-03-20 03:02:26 +00:00
|
|
|
|
static unsigned int rlen = 0;
|
|
|
|
|
static char *result = NULL;
|
2011-11-14 02:26:00 +00:00
|
|
|
|
unsigned int ri = 0;
|
2009-09-16 17:07:01 +00:00
|
|
|
|
va_list args;
|
1991-10-07 22:04:20 +00:00
|
|
|
|
|
2013-04-28 21:59:28 +00:00
|
|
|
|
va_start (args, num);
|
1991-10-07 22:04:20 +00:00
|
|
|
|
|
2009-09-16 17:07:01 +00:00
|
|
|
|
while (num-- > 0)
|
|
|
|
|
{
|
|
|
|
|
const char *s = va_arg (args, const char *);
|
|
|
|
|
unsigned int l = s ? strlen (s) : 0;
|
1991-10-07 22:04:20 +00:00
|
|
|
|
|
2009-09-16 17:07:01 +00:00
|
|
|
|
if (l == 0)
|
|
|
|
|
continue;
|
2007-03-20 03:02:26 +00:00
|
|
|
|
|
2009-09-16 17:07:01 +00:00
|
|
|
|
if (ri + l > rlen)
|
|
|
|
|
{
|
|
|
|
|
rlen = ((rlen ? rlen : 60) + l) * 2;
|
|
|
|
|
result = xrealloc (result, rlen);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
memcpy (result + ri, s, l);
|
|
|
|
|
ri += l;
|
|
|
|
|
}
|
|
|
|
|
|
2013-04-28 21:59:28 +00:00
|
|
|
|
va_end (args);
|
2009-09-16 17:07:01 +00:00
|
|
|
|
|
2010-07-16 13:01:15 +00:00
|
|
|
|
/* Get some more memory if we don't have enough space for the
|
|
|
|
|
terminating '\0'. */
|
|
|
|
|
if (ri == rlen)
|
|
|
|
|
{
|
|
|
|
|
rlen = (rlen ? rlen : 60) * 2;
|
|
|
|
|
result = xrealloc (result, rlen);
|
|
|
|
|
}
|
|
|
|
|
|
2009-09-16 17:07:01 +00:00
|
|
|
|
result[ri] = '\0';
|
1991-10-07 22:04:20 +00:00
|
|
|
|
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
2013-04-28 23:09:20 +00:00
|
|
|
|
|
2013-05-04 17:10:56 +00:00
|
|
|
|
/* Return a formatted string buffer.
|
2013-05-05 21:03:51 +00:00
|
|
|
|
LENGTH must be the maximum length of all format arguments, stringified.
|
|
|
|
|
If we had a standard-compliant vsnprintf() this would be a lot simpler.
|
|
|
|
|
Maybe in the future we'll include gnulib's version. */
|
2013-04-28 23:09:20 +00:00
|
|
|
|
|
|
|
|
|
const char *
|
|
|
|
|
message_s (unsigned int length, int prefix, const char *fmt, ...)
|
|
|
|
|
{
|
|
|
|
|
static char *buffer = NULL;
|
|
|
|
|
static unsigned int bsize = 0;
|
|
|
|
|
char *bp;
|
|
|
|
|
va_list args;
|
|
|
|
|
|
|
|
|
|
/* Compute the maximum buffer size we'll need, and make sure we have it. */
|
2013-05-04 17:10:56 +00:00
|
|
|
|
length += strlen (fmt) + strlen (program) + 4 + INTEGER_LENGTH + 2;
|
2013-04-28 23:09:20 +00:00
|
|
|
|
if (length > bsize)
|
|
|
|
|
{
|
|
|
|
|
bsize = length * 2;
|
|
|
|
|
buffer = xrealloc (buffer, bsize);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bp = buffer;
|
|
|
|
|
if (prefix)
|
|
|
|
|
{
|
|
|
|
|
if (makelevel == 0)
|
|
|
|
|
sprintf (bp, "%s: ", program);
|
|
|
|
|
else
|
|
|
|
|
sprintf (bp, "%s[%u]: ", program, makelevel);
|
|
|
|
|
bp += strlen (buffer);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
va_start (args, fmt);
|
|
|
|
|
vsprintf (bp, fmt, args);
|
|
|
|
|
va_end (args);
|
|
|
|
|
|
|
|
|
|
return buffer;
|
|
|
|
|
}
|
|
|
|
|
|
2013-05-04 17:10:56 +00:00
|
|
|
|
/* Return a formatted error message in a buffer.
|
|
|
|
|
LENGTH must be the maximum length of all format arguments, stringified. */
|
2013-04-28 23:09:20 +00:00
|
|
|
|
|
|
|
|
|
const char *
|
|
|
|
|
error_s (unsigned int length, const gmk_floc *flocp, const char *fmt, ...)
|
|
|
|
|
{
|
|
|
|
|
static char *buffer = NULL;
|
|
|
|
|
static unsigned int bsize = 0;
|
|
|
|
|
char *bp;
|
|
|
|
|
va_list args;
|
|
|
|
|
|
|
|
|
|
/* Compute the maximum buffer size we'll need, and make sure we have it. */
|
2013-05-04 17:10:56 +00:00
|
|
|
|
length += (strlen (fmt) + strlen (program) + 4 + INTEGER_LENGTH + 2
|
2013-04-28 23:09:20 +00:00
|
|
|
|
+ (flocp && flocp->filenm ? strlen (flocp->filenm) : 0));
|
|
|
|
|
if (length > bsize)
|
|
|
|
|
{
|
|
|
|
|
bsize = length * 2;
|
|
|
|
|
buffer = xrealloc (buffer, bsize);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bp = buffer;
|
|
|
|
|
if (flocp && flocp->filenm)
|
|
|
|
|
sprintf (bp, "%s:%lu: ", flocp->filenm, flocp->lineno);
|
|
|
|
|
else if (makelevel == 0)
|
|
|
|
|
sprintf (bp, "%s: ", program);
|
|
|
|
|
else
|
|
|
|
|
sprintf (bp, "%s[%u]: ", program, makelevel);
|
|
|
|
|
bp += strlen (bp);
|
|
|
|
|
|
|
|
|
|
va_start (args, fmt);
|
|
|
|
|
vsprintf (bp, fmt, args);
|
|
|
|
|
va_end (args);
|
|
|
|
|
|
|
|
|
|
return buffer;
|
|
|
|
|
}
|
|
|
|
|
|
2013-05-04 17:10:56 +00:00
|
|
|
|
/* Print a message on stdout. We could use message_s() to format it but then
|
|
|
|
|
we'd need a va_list version... */
|
1991-10-07 22:04:20 +00:00
|
|
|
|
|
|
|
|
|
void
|
1998-10-03 05:39:55 +00:00
|
|
|
|
message (int prefix, const char *fmt, ...)
|
1991-10-07 22:04:20 +00:00
|
|
|
|
{
|
1998-10-03 05:39:55 +00:00
|
|
|
|
va_list args;
|
|
|
|
|
|
2013-04-14 19:38:07 +00:00
|
|
|
|
log_working_directory (1, 0);
|
1995-11-26 01:35:05 +00:00
|
|
|
|
|
1998-10-03 05:39:55 +00:00
|
|
|
|
if (fmt != 0)
|
1995-11-26 01:35:05 +00:00
|
|
|
|
{
|
|
|
|
|
if (prefix)
|
2013-05-17 06:29:46 +00:00
|
|
|
|
{
|
|
|
|
|
if (makelevel == 0)
|
|
|
|
|
printf ("%s: ", program);
|
|
|
|
|
else
|
|
|
|
|
printf ("%s[%u]: ", program, makelevel);
|
|
|
|
|
}
|
2013-04-28 21:59:28 +00:00
|
|
|
|
va_start (args, fmt);
|
|
|
|
|
vfprintf (stdout, fmt, args);
|
|
|
|
|
va_end (args);
|
1995-11-26 01:35:05 +00:00
|
|
|
|
putchar ('\n');
|
|
|
|
|
}
|
|
|
|
|
|
1991-10-07 22:04:20 +00:00
|
|
|
|
fflush (stdout);
|
|
|
|
|
}
|
|
|
|
|
|
1998-10-03 05:39:55 +00:00
|
|
|
|
/* Print an error message. */
|
1991-10-07 22:04:20 +00:00
|
|
|
|
|
|
|
|
|
void
|
2013-01-20 18:16:46 +00:00
|
|
|
|
error (const gmk_floc *flocp, const char *fmt, ...)
|
1991-10-07 22:04:20 +00:00
|
|
|
|
{
|
1998-10-03 05:39:55 +00:00
|
|
|
|
va_list args;
|
1991-10-07 22:04:20 +00:00
|
|
|
|
|
2013-05-05 21:03:51 +00:00
|
|
|
|
log_working_directory (1, 0);
|
1995-11-26 01:35:05 +00:00
|
|
|
|
|
1998-10-03 05:39:55 +00:00
|
|
|
|
if (flocp && flocp->filenm)
|
|
|
|
|
fprintf (stderr, "%s:%lu: ", flocp->filenm, flocp->lineno);
|
|
|
|
|
else if (makelevel == 0)
|
1991-10-07 22:04:20 +00:00
|
|
|
|
fprintf (stderr, "%s: ", program);
|
|
|
|
|
else
|
|
|
|
|
fprintf (stderr, "%s[%u]: ", program, makelevel);
|
|
|
|
|
|
2013-04-28 21:59:28 +00:00
|
|
|
|
va_start (args, fmt);
|
|
|
|
|
vfprintf (stderr, fmt, args);
|
|
|
|
|
va_end (args);
|
1995-11-26 01:35:05 +00:00
|
|
|
|
|
1991-10-07 22:04:20 +00:00
|
|
|
|
putc ('\n', stderr);
|
|
|
|
|
fflush (stderr);
|
|
|
|
|
}
|
|
|
|
|
|
1998-10-03 05:39:55 +00:00
|
|
|
|
/* Print an error message and exit. */
|
|
|
|
|
|
1991-10-07 22:04:20 +00:00
|
|
|
|
void
|
2013-01-20 18:16:46 +00:00
|
|
|
|
fatal (const gmk_floc *flocp, const char *fmt, ...)
|
1991-10-07 22:04:20 +00:00
|
|
|
|
{
|
1998-10-03 05:39:55 +00:00
|
|
|
|
va_list args;
|
1998-07-30 20:54:47 +00:00
|
|
|
|
|
2013-05-13 05:30:24 +00:00
|
|
|
|
log_working_directory (1, 0);
|
1995-11-26 01:35:05 +00:00
|
|
|
|
|
1998-10-03 05:39:55 +00:00
|
|
|
|
if (flocp && flocp->filenm)
|
|
|
|
|
fprintf (stderr, "%s:%lu: *** ", flocp->filenm, flocp->lineno);
|
|
|
|
|
else if (makelevel == 0)
|
|
|
|
|
fprintf (stderr, "%s: *** ", program);
|
|
|
|
|
else
|
|
|
|
|
fprintf (stderr, "%s[%u]: *** ", program, makelevel);
|
|
|
|
|
|
2013-04-28 21:59:28 +00:00
|
|
|
|
va_start (args, fmt);
|
|
|
|
|
vfprintf (stderr, fmt, args);
|
|
|
|
|
va_end (args);
|
1998-10-03 05:39:55 +00:00
|
|
|
|
|
1999-07-28 06:23:37 +00:00
|
|
|
|
fputs (_(". Stop.\n"), stderr);
|
1991-10-07 22:04:20 +00:00
|
|
|
|
|
2013-05-13 05:30:24 +00:00
|
|
|
|
log_working_directory (0, 1);
|
2013-04-14 19:38:07 +00:00
|
|
|
|
|
1994-04-21 02:01:24 +00:00
|
|
|
|
die (2);
|
1991-10-07 22:04:20 +00:00
|
|
|
|
}
|
|
|
|
|
|
1993-12-02 20:37:46 +00:00
|
|
|
|
#ifndef HAVE_STRERROR
|
1994-02-03 07:21:18 +00:00
|
|
|
|
|
2013-05-17 06:29:46 +00:00
|
|
|
|
#undef strerror
|
1994-02-03 07:21:18 +00:00
|
|
|
|
|
2002-09-12 22:15:58 +00:00
|
|
|
|
char *
|
2002-10-14 21:54:04 +00:00
|
|
|
|
strerror (int errnum)
|
1993-12-02 20:37:46 +00:00
|
|
|
|
{
|
|
|
|
|
extern int errno, sys_nerr;
|
1996-03-20 14:57:41 +00:00
|
|
|
|
#ifndef __DECC
|
1993-12-02 20:37:46 +00:00
|
|
|
|
extern char *sys_errlist[];
|
1996-03-20 14:57:41 +00:00
|
|
|
|
#endif
|
1993-12-02 20:37:46 +00:00
|
|
|
|
static char buf[] = "Unknown error 12345678901234567890";
|
|
|
|
|
|
|
|
|
|
if (errno < sys_nerr)
|
|
|
|
|
return sys_errlist[errnum];
|
|
|
|
|
|
1999-07-28 06:23:37 +00:00
|
|
|
|
sprintf (buf, _("Unknown error %d"), errnum);
|
1993-12-02 20:37:46 +00:00
|
|
|
|
return buf;
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
1991-10-07 22:04:20 +00:00
|
|
|
|
/* Print an error message from errno. */
|
|
|
|
|
|
|
|
|
|
void
|
2002-10-14 21:54:04 +00:00
|
|
|
|
perror_with_name (const char *str, const char *name)
|
1991-10-07 22:04:20 +00:00
|
|
|
|
{
|
2002-08-08 05:39:17 +00:00
|
|
|
|
error (NILF, _("%s%s: %s"), str, name, strerror (errno));
|
1991-10-07 22:04:20 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Print an error message from errno and exit. */
|
|
|
|
|
|
|
|
|
|
void
|
2002-10-14 21:54:04 +00:00
|
|
|
|
pfatal_with_name (const char *name)
|
1991-10-07 22:04:20 +00:00
|
|
|
|
{
|
2002-08-08 05:39:17 +00:00
|
|
|
|
fatal (NILF, _("%s: %s"), name, strerror (errno));
|
1991-10-07 22:04:20 +00:00
|
|
|
|
|
|
|
|
|
/* NOTREACHED */
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Like malloc but get fatal error if memory is exhausted. */
|
1999-07-21 05:53:23 +00:00
|
|
|
|
/* Don't bother if we're using dmalloc; it provides these for us. */
|
|
|
|
|
|
|
|
|
|
#ifndef HAVE_DMALLOC_H
|
1991-10-07 22:04:20 +00:00
|
|
|
|
|
|
|
|
|
#undef xmalloc
|
2009-09-16 17:07:01 +00:00
|
|
|
|
#undef xcalloc
|
1991-10-07 22:04:20 +00:00
|
|
|
|
#undef xrealloc
|
1999-07-21 05:53:23 +00:00
|
|
|
|
#undef xstrdup
|
1991-10-07 22:04:20 +00:00
|
|
|
|
|
2006-04-09 22:09:24 +00:00
|
|
|
|
void *
|
2002-10-14 21:54:04 +00:00
|
|
|
|
xmalloc (unsigned int size)
|
1991-10-07 22:04:20 +00:00
|
|
|
|
{
|
2009-09-16 17:07:01 +00:00
|
|
|
|
/* Make sure we don't allocate 0, for pre-ISO implementations. */
|
2006-04-09 22:09:24 +00:00
|
|
|
|
void *result = malloc (size ? size : 1);
|
1991-10-07 22:04:20 +00:00
|
|
|
|
if (result == 0)
|
1999-07-28 06:23:37 +00:00
|
|
|
|
fatal (NILF, _("virtual memory exhausted"));
|
1991-10-07 22:04:20 +00:00
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2009-09-16 17:07:01 +00:00
|
|
|
|
void *
|
|
|
|
|
xcalloc (unsigned int size)
|
|
|
|
|
{
|
|
|
|
|
/* Make sure we don't allocate 0, for pre-ISO implementations. */
|
|
|
|
|
void *result = calloc (size ? size : 1, 1);
|
|
|
|
|
if (result == 0)
|
|
|
|
|
fatal (NILF, _("virtual memory exhausted"));
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2006-04-09 22:09:24 +00:00
|
|
|
|
void *
|
|
|
|
|
xrealloc (void *ptr, unsigned int size)
|
1991-10-07 22:04:20 +00:00
|
|
|
|
{
|
2006-04-09 22:09:24 +00:00
|
|
|
|
void *result;
|
1999-07-21 05:53:23 +00:00
|
|
|
|
|
2009-09-16 17:07:01 +00:00
|
|
|
|
/* Some older implementations of realloc() don't conform to ISO. */
|
2004-01-07 19:36:39 +00:00
|
|
|
|
if (! size)
|
|
|
|
|
size = 1;
|
1999-07-21 05:53:23 +00:00
|
|
|
|
result = ptr ? realloc (ptr, size) : malloc (size);
|
1991-10-07 22:04:20 +00:00
|
|
|
|
if (result == 0)
|
1999-07-28 06:23:37 +00:00
|
|
|
|
fatal (NILF, _("virtual memory exhausted"));
|
1991-10-07 22:04:20 +00:00
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
1999-03-05 07:13:12 +00:00
|
|
|
|
|
1999-03-19 04:27:56 +00:00
|
|
|
|
char *
|
2002-10-14 21:54:04 +00:00
|
|
|
|
xstrdup (const char *ptr)
|
1999-03-05 07:13:12 +00:00
|
|
|
|
{
|
|
|
|
|
char *result;
|
|
|
|
|
|
|
|
|
|
#ifdef HAVE_STRDUP
|
|
|
|
|
result = strdup (ptr);
|
|
|
|
|
#else
|
2006-04-09 22:09:24 +00:00
|
|
|
|
result = malloc (strlen (ptr) + 1);
|
1999-03-05 07:13:12 +00:00
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
if (result == 0)
|
1999-07-28 06:23:37 +00:00
|
|
|
|
fatal (NILF, _("virtual memory exhausted"));
|
1999-03-05 07:13:12 +00:00
|
|
|
|
|
|
|
|
|
#ifdef HAVE_STRDUP
|
|
|
|
|
return result;
|
|
|
|
|
#else
|
2006-04-09 22:09:24 +00:00
|
|
|
|
return strcpy (result, ptr);
|
1999-03-05 07:13:12 +00:00
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
1999-07-21 05:53:23 +00:00
|
|
|
|
#endif /* HAVE_DMALLOC_H */
|
|
|
|
|
|
1991-10-07 22:04:20 +00:00
|
|
|
|
char *
|
2009-05-24 18:31:18 +00:00
|
|
|
|
xstrndup (const char *str, unsigned int length)
|
1991-10-07 22:04:20 +00:00
|
|
|
|
{
|
2009-05-24 18:31:18 +00:00
|
|
|
|
char *result;
|
|
|
|
|
|
|
|
|
|
#ifdef HAVE_STRNDUP
|
|
|
|
|
result = strndup (str, length);
|
|
|
|
|
if (result == 0)
|
|
|
|
|
fatal (NILF, _("virtual memory exhausted"));
|
|
|
|
|
#else
|
|
|
|
|
result = xmalloc (length + 1);
|
2009-09-24 02:41:44 +00:00
|
|
|
|
if (length > 0)
|
|
|
|
|
strncpy (result, str, length);
|
2009-05-24 18:31:18 +00:00
|
|
|
|
result[length] = '\0';
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
return result;
|
1991-10-07 22:04:20 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Limited INDEX:
|
|
|
|
|
Search through the string STRING, which ends at LIMIT, for the character C.
|
|
|
|
|
Returns a pointer to the first occurrence, or nil if none is found.
|
|
|
|
|
Like INDEX except that the string searched ends where specified
|
|
|
|
|
instead of at the first null. */
|
|
|
|
|
|
|
|
|
|
char *
|
2002-10-14 21:54:04 +00:00
|
|
|
|
lindex (const char *s, const char *limit, int c)
|
1991-10-07 22:04:20 +00:00
|
|
|
|
{
|
|
|
|
|
while (s < limit)
|
|
|
|
|
if (*s++ == c)
|
1999-07-21 05:53:23 +00:00
|
|
|
|
return (char *)(s - 1);
|
1991-10-07 22:04:20 +00:00
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Return the address of the first whitespace or null in the string S. */
|
|
|
|
|
|
|
|
|
|
char *
|
2005-02-28 07:48:22 +00:00
|
|
|
|
end_of_token (const char *s)
|
1991-10-07 22:04:20 +00:00
|
|
|
|
{
|
2013-06-22 04:22:08 +00:00
|
|
|
|
while (! STOP_SET (*s, MAP_BLANK|MAP_NUL))
|
1994-03-04 05:10:20 +00:00
|
|
|
|
++s;
|
2005-02-28 07:48:22 +00:00
|
|
|
|
return (char *)s;
|
1991-10-07 22:04:20 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Return the address of the first nonwhitespace or null in the string S. */
|
|
|
|
|
|
|
|
|
|
char *
|
2002-10-14 21:54:04 +00:00
|
|
|
|
next_token (const char *s)
|
1991-10-07 22:04:20 +00:00
|
|
|
|
{
|
2002-07-08 02:26:47 +00:00
|
|
|
|
while (isblank ((unsigned char)*s))
|
|
|
|
|
++s;
|
|
|
|
|
return (char *)s;
|
1991-10-07 22:04:20 +00:00
|
|
|
|
}
|
|
|
|
|
|
2007-03-20 03:02:26 +00:00
|
|
|
|
/* Find the next token in PTR; return the address of it, and store the length
|
|
|
|
|
of the token into *LENGTHPTR if LENGTHPTR is not nil. Set *PTR to the end
|
|
|
|
|
of the token, so this function can be called repeatedly in a loop. */
|
1991-10-07 22:04:20 +00:00
|
|
|
|
|
|
|
|
|
char *
|
2007-03-20 03:02:26 +00:00
|
|
|
|
find_next_token (const char **ptr, unsigned int *lengthptr)
|
1991-10-07 22:04:20 +00:00
|
|
|
|
{
|
2007-03-20 03:02:26 +00:00
|
|
|
|
const char *p = next_token (*ptr);
|
1991-10-07 22:04:20 +00:00
|
|
|
|
|
|
|
|
|
if (*p == '\0')
|
|
|
|
|
return 0;
|
|
|
|
|
|
2007-03-20 03:02:26 +00:00
|
|
|
|
*ptr = end_of_token (p);
|
1991-10-07 22:04:20 +00:00
|
|
|
|
if (lengthptr != 0)
|
2007-03-20 03:02:26 +00:00
|
|
|
|
*lengthptr = *ptr - p;
|
|
|
|
|
|
|
|
|
|
return (char *)p;
|
1991-10-07 22:04:20 +00:00
|
|
|
|
}
|
|
|
|
|
|
2006-03-17 14:24:20 +00:00
|
|
|
|
|
2012-03-04 00:24:20 +00:00
|
|
|
|
/* Copy a chain of 'struct dep'. For 2nd expansion deps, dup the name. */
|
1991-10-07 22:04:20 +00:00
|
|
|
|
|
|
|
|
|
struct dep *
|
2005-10-24 13:01:39 +00:00
|
|
|
|
copy_dep_chain (const struct dep *d)
|
1991-10-07 22:04:20 +00:00
|
|
|
|
{
|
|
|
|
|
struct dep *firstnew = 0;
|
1998-07-30 20:54:47 +00:00
|
|
|
|
struct dep *lastnew = 0;
|
1991-10-07 22:04:20 +00:00
|
|
|
|
|
|
|
|
|
while (d != 0)
|
|
|
|
|
{
|
2007-03-20 03:02:26 +00:00
|
|
|
|
struct dep *c = xmalloc (sizeof (struct dep));
|
2006-04-09 22:09:24 +00:00
|
|
|
|
memcpy (c, d, sizeof (struct dep));
|
2006-03-17 14:24:20 +00:00
|
|
|
|
|
2009-09-24 02:41:44 +00:00
|
|
|
|
if (c->need_2nd_expansion)
|
|
|
|
|
c->name = xstrdup (c->name);
|
|
|
|
|
|
1991-10-07 22:04:20 +00:00
|
|
|
|
c->next = 0;
|
|
|
|
|
if (firstnew == 0)
|
2013-05-17 06:29:46 +00:00
|
|
|
|
firstnew = lastnew = c;
|
1991-10-07 22:04:20 +00:00
|
|
|
|
else
|
2013-05-17 06:29:46 +00:00
|
|
|
|
lastnew = lastnew->next = c;
|
1991-10-07 22:04:20 +00:00
|
|
|
|
|
|
|
|
|
d = d->next;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return firstnew;
|
|
|
|
|
}
|
2005-10-24 13:01:39 +00:00
|
|
|
|
|
|
|
|
|
/* Free a chain of 'struct dep'. */
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
free_dep_chain (struct dep *d)
|
|
|
|
|
{
|
|
|
|
|
while (d != 0)
|
|
|
|
|
{
|
|
|
|
|
struct dep *df = d;
|
|
|
|
|
d = d->next;
|
2006-03-17 14:24:20 +00:00
|
|
|
|
free_dep (df);
|
2005-10-24 13:01:39 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
2005-02-27 21:40:23 +00:00
|
|
|
|
|
2007-03-20 03:02:26 +00:00
|
|
|
|
/* Free a chain of struct nameseq.
|
|
|
|
|
For struct dep chains use free_dep_chain. */
|
2005-02-27 21:40:23 +00:00
|
|
|
|
|
2007-03-20 03:02:26 +00:00
|
|
|
|
void
|
|
|
|
|
free_ns_chain (struct nameseq *ns)
|
1991-10-07 22:04:20 +00:00
|
|
|
|
{
|
2007-03-20 03:02:26 +00:00
|
|
|
|
while (ns != 0)
|
|
|
|
|
{
|
|
|
|
|
struct nameseq *t = ns;
|
|
|
|
|
ns = ns->next;
|
|
|
|
|
free (t);
|
|
|
|
|
}
|
1991-10-07 22:04:20 +00:00
|
|
|
|
}
|
|
|
|
|
|
2007-05-09 02:01:53 +00:00
|
|
|
|
|
|
|
|
|
#if !HAVE_STRCASECMP && !HAVE_STRICMP && !HAVE_STRCMPI
|
|
|
|
|
|
|
|
|
|
/* If we don't have strcasecmp() (from POSIX), or anything that can substitute
|
|
|
|
|
for it, define our own version. */
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
strcasecmp (const char *s1, const char *s2)
|
|
|
|
|
{
|
|
|
|
|
while (1)
|
|
|
|
|
{
|
|
|
|
|
int c1 = (int) *(s1++);
|
|
|
|
|
int c2 = (int) *(s2++);
|
|
|
|
|
|
|
|
|
|
if (isalpha (c1))
|
|
|
|
|
c1 = tolower (c1);
|
|
|
|
|
if (isalpha (c2))
|
|
|
|
|
c2 = tolower (c2);
|
|
|
|
|
|
|
|
|
|
if (c1 != '\0' && c1 == c2)
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
return (c1 - c2);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
#endif
|
2010-07-19 07:10:53 +00:00
|
|
|
|
|
|
|
|
|
#if !HAVE_STRNCASECMP && !HAVE_STRNICMP && !HAVE_STRNCMPI
|
|
|
|
|
|
|
|
|
|
/* If we don't have strncasecmp() (from POSIX), or anything that can
|
|
|
|
|
substitute for it, define our own version. */
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
strncasecmp (const char *s1, const char *s2, int n)
|
|
|
|
|
{
|
|
|
|
|
while (n-- > 0)
|
|
|
|
|
{
|
|
|
|
|
int c1 = (int) *(s1++);
|
|
|
|
|
int c2 = (int) *(s2++);
|
|
|
|
|
|
|
|
|
|
if (isalpha (c1))
|
|
|
|
|
c1 = tolower (c1);
|
|
|
|
|
if (isalpha (c2))
|
|
|
|
|
c2 = tolower (c2);
|
|
|
|
|
|
|
|
|
|
if (c1 != '\0' && c1 == c2)
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
return (c1 - c2);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
#endif
|
2007-05-09 02:01:53 +00:00
|
|
|
|
|
2013-05-17 06:29:46 +00:00
|
|
|
|
#ifdef GETLOADAVG_PRIVILEGED
|
1993-01-11 19:45:54 +00:00
|
|
|
|
|
1994-02-16 21:25:32 +00:00
|
|
|
|
#ifdef POSIX
|
1994-05-17 03:09:02 +00:00
|
|
|
|
|
1994-02-16 21:25:32 +00:00
|
|
|
|
/* Hopefully if a system says it's POSIX.1 and has the setuid and setgid
|
|
|
|
|
functions, they work as POSIX.1 says. Some systems (Alpha OSF/1 1.2,
|
|
|
|
|
for example) which claim to be POSIX.1 also have the BSD setreuid and
|
|
|
|
|
setregid functions, but they don't work as in BSD and only the POSIX.1
|
|
|
|
|
way works. */
|
|
|
|
|
|
|
|
|
|
#undef HAVE_SETREUID
|
|
|
|
|
#undef HAVE_SETREGID
|
1994-05-17 03:09:02 +00:00
|
|
|
|
|
2013-05-17 06:29:46 +00:00
|
|
|
|
#else /* Not POSIX. */
|
1994-05-17 03:09:02 +00:00
|
|
|
|
|
|
|
|
|
/* Some POSIX.1 systems have the seteuid and setegid functions. In a
|
|
|
|
|
POSIX-like system, they are the best thing to use. However, some
|
|
|
|
|
non-POSIX systems have them too but they do not work in the POSIX style
|
|
|
|
|
and we must use setreuid and setregid instead. */
|
|
|
|
|
|
|
|
|
|
#undef HAVE_SETEUID
|
|
|
|
|
#undef HAVE_SETEGID
|
|
|
|
|
|
2013-05-17 06:29:46 +00:00
|
|
|
|
#endif /* POSIX. */
|
1994-02-16 21:25:32 +00:00
|
|
|
|
|
2013-05-17 06:29:46 +00:00
|
|
|
|
#ifndef HAVE_UNISTD_H
|
1991-10-07 22:04:20 +00:00
|
|
|
|
extern int getuid (), getgid (), geteuid (), getegid ();
|
|
|
|
|
extern int setuid (), setgid ();
|
1994-04-21 02:41:36 +00:00
|
|
|
|
#ifdef HAVE_SETEUID
|
|
|
|
|
extern int seteuid ();
|
|
|
|
|
#else
|
2013-05-17 06:29:46 +00:00
|
|
|
|
#ifdef HAVE_SETREUID
|
1993-01-22 21:32:00 +00:00
|
|
|
|
extern int setreuid ();
|
2013-05-17 06:29:46 +00:00
|
|
|
|
#endif /* Have setreuid. */
|
|
|
|
|
#endif /* Have seteuid. */
|
1994-04-21 02:41:36 +00:00
|
|
|
|
#ifdef HAVE_SETEGID
|
|
|
|
|
extern int setegid ();
|
|
|
|
|
#else
|
2013-05-17 06:29:46 +00:00
|
|
|
|
#ifdef HAVE_SETREGID
|
1993-01-22 21:32:00 +00:00
|
|
|
|
extern int setregid ();
|
2013-05-17 06:29:46 +00:00
|
|
|
|
#endif /* Have setregid. */
|
|
|
|
|
#endif /* Have setegid. */
|
|
|
|
|
#endif /* No <unistd.h>. */
|
1991-10-07 22:04:20 +00:00
|
|
|
|
|
|
|
|
|
/* Keep track of the user and group IDs for user- and make- access. */
|
|
|
|
|
static int user_uid = -1, user_gid = -1, make_uid = -1, make_gid = -1;
|
2013-05-17 06:29:46 +00:00
|
|
|
|
#define access_inited (user_uid != -1)
|
1991-10-07 22:04:20 +00:00
|
|
|
|
static enum { make, user } current_access;
|
|
|
|
|
|
1993-04-14 20:43:53 +00:00
|
|
|
|
|
|
|
|
|
/* Under -d, write a message describing the current IDs. */
|
|
|
|
|
|
|
|
|
|
static void
|
2006-04-01 06:36:40 +00:00
|
|
|
|
log_access (const char *flavor)
|
1993-04-14 20:43:53 +00:00
|
|
|
|
{
|
1999-11-22 06:15:35 +00:00
|
|
|
|
if (! ISDB (DB_JOBS))
|
1993-04-14 20:43:53 +00:00
|
|
|
|
return;
|
|
|
|
|
|
1993-08-01 20:03:45 +00:00
|
|
|
|
/* All the other debugging messages go to stdout,
|
|
|
|
|
but we write this one to stderr because it might be
|
|
|
|
|
run in a child fork whose stdout is piped. */
|
|
|
|
|
|
2001-08-19 04:55:51 +00:00
|
|
|
|
fprintf (stderr, _("%s: user %lu (real %lu), group %lu (real %lu)\n"),
|
2013-05-17 06:29:46 +00:00
|
|
|
|
flavor, (unsigned long) geteuid (), (unsigned long) getuid (),
|
1998-07-30 20:54:47 +00:00
|
|
|
|
(unsigned long) getegid (), (unsigned long) getgid ());
|
1993-08-01 20:03:45 +00:00
|
|
|
|
fflush (stderr);
|
1993-04-14 20:43:53 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
1991-10-07 22:04:20 +00:00
|
|
|
|
static void
|
2002-10-14 21:54:04 +00:00
|
|
|
|
init_access (void)
|
1991-10-07 22:04:20 +00:00
|
|
|
|
{
|
1996-03-20 14:57:41 +00:00
|
|
|
|
#ifndef VMS
|
1991-10-07 22:04:20 +00:00
|
|
|
|
user_uid = getuid ();
|
|
|
|
|
user_gid = getgid ();
|
|
|
|
|
|
|
|
|
|
make_uid = geteuid ();
|
|
|
|
|
make_gid = getegid ();
|
|
|
|
|
|
|
|
|
|
/* Do these ever fail? */
|
|
|
|
|
if (user_uid == -1 || user_gid == -1 || make_uid == -1 || make_gid == -1)
|
|
|
|
|
pfatal_with_name ("get{e}[gu]id");
|
|
|
|
|
|
2001-08-19 04:55:51 +00:00
|
|
|
|
log_access (_("Initialized access"));
|
1993-04-14 20:43:53 +00:00
|
|
|
|
|
1991-10-07 22:04:20 +00:00
|
|
|
|
current_access = make;
|
1996-03-20 14:57:41 +00:00
|
|
|
|
#endif
|
1991-10-07 22:04:20 +00:00
|
|
|
|
}
|
|
|
|
|
|
2013-05-17 06:29:46 +00:00
|
|
|
|
#endif /* GETLOADAVG_PRIVILEGED */
|
1993-01-11 19:45:54 +00:00
|
|
|
|
|
1991-10-07 22:04:20 +00:00
|
|
|
|
/* Give the process appropriate permissions for access to
|
|
|
|
|
user data (i.e., to stat files, or to spawn a child process). */
|
|
|
|
|
void
|
2002-10-14 21:54:04 +00:00
|
|
|
|
user_access (void)
|
1991-10-07 22:04:20 +00:00
|
|
|
|
{
|
2013-05-17 06:29:46 +00:00
|
|
|
|
#ifdef GETLOADAVG_PRIVILEGED
|
1993-01-11 19:45:54 +00:00
|
|
|
|
|
1991-10-07 22:04:20 +00:00
|
|
|
|
if (!access_inited)
|
|
|
|
|
init_access ();
|
|
|
|
|
|
|
|
|
|
if (current_access == user)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
/* We are in "make access" mode. This means that the effective user and
|
|
|
|
|
group IDs are those of make (if it was installed setuid or setgid).
|
|
|
|
|
We now want to set the effective user and group IDs to the real IDs,
|
|
|
|
|
which are the IDs of the process that exec'd make. */
|
|
|
|
|
|
2013-05-17 06:29:46 +00:00
|
|
|
|
#ifdef HAVE_SETEUID
|
1994-04-21 02:41:36 +00:00
|
|
|
|
|
|
|
|
|
/* Modern systems have the seteuid/setegid calls which set only the
|
|
|
|
|
effective IDs, which is ideal. */
|
|
|
|
|
|
|
|
|
|
if (seteuid (user_uid) < 0)
|
|
|
|
|
pfatal_with_name ("user_access: seteuid");
|
|
|
|
|
|
2013-05-17 06:29:46 +00:00
|
|
|
|
#else /* Not HAVE_SETEUID. */
|
1994-04-21 02:41:36 +00:00
|
|
|
|
|
2013-05-17 06:29:46 +00:00
|
|
|
|
#ifndef HAVE_SETREUID
|
1993-01-05 23:02:42 +00:00
|
|
|
|
|
1991-10-07 22:04:20 +00:00
|
|
|
|
/* System V has only the setuid/setgid calls to set user/group IDs.
|
|
|
|
|
There is an effective ID, which can be set by setuid/setgid.
|
|
|
|
|
It can be set (unless you are root) only to either what it already is
|
|
|
|
|
(returned by geteuid/getegid, now in make_uid/make_gid),
|
|
|
|
|
the real ID (return by getuid/getgid, now in user_uid/user_gid),
|
|
|
|
|
or the saved set ID (what the effective ID was before this set-ID
|
|
|
|
|
executable (make) was exec'd). */
|
1993-01-05 23:02:42 +00:00
|
|
|
|
|
1991-10-07 22:04:20 +00:00
|
|
|
|
if (setuid (user_uid) < 0)
|
1993-01-05 23:02:42 +00:00
|
|
|
|
pfatal_with_name ("user_access: setuid");
|
|
|
|
|
|
2013-05-17 06:29:46 +00:00
|
|
|
|
#else /* HAVE_SETREUID. */
|
1993-01-05 23:02:42 +00:00
|
|
|
|
|
1991-10-07 22:04:20 +00:00
|
|
|
|
/* In 4BSD, the setreuid/setregid calls set both the real and effective IDs.
|
|
|
|
|
They may be set to themselves or each other. So you have two alternatives
|
|
|
|
|
at any one time. If you use setuid/setgid, the effective will be set to
|
|
|
|
|
the real, leaving only one alternative. Using setreuid/setregid, however,
|
|
|
|
|
you can toggle between your two alternatives by swapping the values in a
|
|
|
|
|
single setreuid or setregid call. */
|
1993-01-05 23:02:42 +00:00
|
|
|
|
|
1991-10-07 22:04:20 +00:00
|
|
|
|
if (setreuid (make_uid, user_uid) < 0)
|
1993-01-05 23:02:42 +00:00
|
|
|
|
pfatal_with_name ("user_access: setreuid");
|
|
|
|
|
|
2013-05-17 06:29:46 +00:00
|
|
|
|
#endif /* Not HAVE_SETREUID. */
|
|
|
|
|
#endif /* HAVE_SETEUID. */
|
1993-01-05 23:02:42 +00:00
|
|
|
|
|
2013-05-17 06:29:46 +00:00
|
|
|
|
#ifdef HAVE_SETEGID
|
1994-04-21 02:41:36 +00:00
|
|
|
|
if (setegid (user_gid) < 0)
|
|
|
|
|
pfatal_with_name ("user_access: setegid");
|
|
|
|
|
#else
|
2013-05-17 06:29:46 +00:00
|
|
|
|
#ifndef HAVE_SETREGID
|
1993-01-05 23:02:42 +00:00
|
|
|
|
if (setgid (user_gid) < 0)
|
|
|
|
|
pfatal_with_name ("user_access: setgid");
|
|
|
|
|
#else
|
1991-10-07 22:04:20 +00:00
|
|
|
|
if (setregid (make_gid, user_gid) < 0)
|
1993-01-05 23:02:42 +00:00
|
|
|
|
pfatal_with_name ("user_access: setregid");
|
1994-04-21 02:41:36 +00:00
|
|
|
|
#endif
|
1991-10-07 22:04:20 +00:00
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
current_access = user;
|
1993-01-11 19:45:54 +00:00
|
|
|
|
|
2001-08-19 04:55:51 +00:00
|
|
|
|
log_access (_("User access"));
|
1993-04-14 20:43:53 +00:00
|
|
|
|
|
2013-05-17 06:29:46 +00:00
|
|
|
|
#endif /* GETLOADAVG_PRIVILEGED */
|
1991-10-07 22:04:20 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Give the process appropriate permissions for access to
|
|
|
|
|
make data (i.e., the load average). */
|
|
|
|
|
void
|
2002-10-14 21:54:04 +00:00
|
|
|
|
make_access (void)
|
1991-10-07 22:04:20 +00:00
|
|
|
|
{
|
2013-05-17 06:29:46 +00:00
|
|
|
|
#ifdef GETLOADAVG_PRIVILEGED
|
1993-01-11 19:45:54 +00:00
|
|
|
|
|
1991-10-07 22:04:20 +00:00
|
|
|
|
if (!access_inited)
|
|
|
|
|
init_access ();
|
|
|
|
|
|
|
|
|
|
if (current_access == make)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
/* See comments in user_access, above. */
|
|
|
|
|
|
2013-05-17 06:29:46 +00:00
|
|
|
|
#ifdef HAVE_SETEUID
|
1994-04-21 02:41:36 +00:00
|
|
|
|
if (seteuid (make_uid) < 0)
|
|
|
|
|
pfatal_with_name ("make_access: seteuid");
|
|
|
|
|
#else
|
2013-05-17 06:29:46 +00:00
|
|
|
|
#ifndef HAVE_SETREUID
|
1991-10-07 22:04:20 +00:00
|
|
|
|
if (setuid (make_uid) < 0)
|
1993-01-05 23:02:42 +00:00
|
|
|
|
pfatal_with_name ("make_access: setuid");
|
1991-10-07 22:04:20 +00:00
|
|
|
|
#else
|
|
|
|
|
if (setreuid (user_uid, make_uid) < 0)
|
1993-01-05 23:02:42 +00:00
|
|
|
|
pfatal_with_name ("make_access: setreuid");
|
|
|
|
|
#endif
|
1994-04-21 02:41:36 +00:00
|
|
|
|
#endif
|
1993-01-05 23:02:42 +00:00
|
|
|
|
|
2013-05-17 06:29:46 +00:00
|
|
|
|
#ifdef HAVE_SETEGID
|
1994-04-21 02:41:36 +00:00
|
|
|
|
if (setegid (make_gid) < 0)
|
|
|
|
|
pfatal_with_name ("make_access: setegid");
|
|
|
|
|
#else
|
2013-05-17 06:29:46 +00:00
|
|
|
|
#ifndef HAVE_SETREGID
|
1993-01-05 23:02:42 +00:00
|
|
|
|
if (setgid (make_gid) < 0)
|
|
|
|
|
pfatal_with_name ("make_access: setgid");
|
|
|
|
|
#else
|
1991-10-07 22:04:20 +00:00
|
|
|
|
if (setregid (user_gid, make_gid) < 0)
|
1993-01-05 23:02:42 +00:00
|
|
|
|
pfatal_with_name ("make_access: setregid");
|
1994-04-21 02:41:36 +00:00
|
|
|
|
#endif
|
1991-10-07 22:04:20 +00:00
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
current_access = make;
|
1993-01-11 19:45:54 +00:00
|
|
|
|
|
2001-08-19 04:55:51 +00:00
|
|
|
|
log_access (_("Make access"));
|
1993-04-14 20:43:53 +00:00
|
|
|
|
|
2013-05-17 06:29:46 +00:00
|
|
|
|
#endif /* GETLOADAVG_PRIVILEGED */
|
1991-10-07 22:04:20 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Give the process appropriate permissions for a child process.
|
|
|
|
|
This is like user_access, but you can't get back to make_access. */
|
|
|
|
|
void
|
2002-10-14 21:54:04 +00:00
|
|
|
|
child_access (void)
|
1991-10-07 22:04:20 +00:00
|
|
|
|
{
|
2013-05-17 06:29:46 +00:00
|
|
|
|
#ifdef GETLOADAVG_PRIVILEGED
|
1993-04-15 22:42:20 +00:00
|
|
|
|
|
1993-04-14 20:43:53 +00:00
|
|
|
|
if (!access_inited)
|
|
|
|
|
abort ();
|
|
|
|
|
|
1991-10-07 22:04:20 +00:00
|
|
|
|
/* Set both the real and effective UID and GID to the user's.
|
|
|
|
|
They cannot be changed back to make's. */
|
|
|
|
|
|
2013-05-17 06:29:46 +00:00
|
|
|
|
#ifndef HAVE_SETREUID
|
1991-10-07 22:04:20 +00:00
|
|
|
|
if (setuid (user_uid) < 0)
|
1993-01-05 23:02:42 +00:00
|
|
|
|
pfatal_with_name ("child_access: setuid");
|
1993-01-08 20:32:36 +00:00
|
|
|
|
#else
|
|
|
|
|
if (setreuid (user_uid, user_uid) < 0)
|
|
|
|
|
pfatal_with_name ("child_access: setreuid");
|
|
|
|
|
#endif
|
|
|
|
|
|
2013-05-17 06:29:46 +00:00
|
|
|
|
#ifndef HAVE_SETREGID
|
1991-10-07 22:04:20 +00:00
|
|
|
|
if (setgid (user_gid) < 0)
|
1993-01-05 23:02:42 +00:00
|
|
|
|
pfatal_with_name ("child_access: setgid");
|
1993-01-08 20:32:36 +00:00
|
|
|
|
#else
|
|
|
|
|
if (setregid (user_gid, user_gid) < 0)
|
|
|
|
|
pfatal_with_name ("child_access: setregid");
|
|
|
|
|
#endif
|
1993-01-11 19:45:54 +00:00
|
|
|
|
|
2001-08-19 04:55:51 +00:00
|
|
|
|
log_access (_("Child access"));
|
1993-04-14 20:43:53 +00:00
|
|
|
|
|
2013-05-17 06:29:46 +00:00
|
|
|
|
#endif /* GETLOADAVG_PRIVILEGED */
|
1991-10-07 22:04:20 +00:00
|
|
|
|
}
|
1992-10-15 23:01:34 +00:00
|
|
|
|
|
|
|
|
|
#ifdef NEED_GET_PATH_MAX
|
|
|
|
|
unsigned int
|
2002-10-14 21:54:04 +00:00
|
|
|
|
get_path_max (void)
|
1992-10-15 23:01:34 +00:00
|
|
|
|
{
|
|
|
|
|
static unsigned int value;
|
|
|
|
|
|
|
|
|
|
if (value == 0)
|
|
|
|
|
{
|
|
|
|
|
long int x = pathconf ("/", _PC_PATH_MAX);
|
|
|
|
|
if (x > 0)
|
2013-05-17 06:29:46 +00:00
|
|
|
|
value = x;
|
1992-10-15 23:01:34 +00:00
|
|
|
|
else
|
2013-05-17 06:29:46 +00:00
|
|
|
|
return MAXPATHLEN;
|
1992-10-15 23:01:34 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return value;
|
|
|
|
|
}
|
|
|
|
|
#endif
|
2005-06-12 22:22:07 +00:00
|
|
|
|
|
|
|
|
|
|
2013-06-29 01:57:59 +00:00
|
|
|
|
/* Set a file descriptor to be in O_APPEND mode.
|
|
|
|
|
If it fails, just ignore it. */
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
set_append_mode (int fd)
|
|
|
|
|
{
|
|
|
|
|
#if defined(F_GETFL) && defined(F_SETFL) && defined(O_APPEND)
|
|
|
|
|
int flags = fcntl (fd, F_GETFL, 0);
|
|
|
|
|
if (flags >= 0)
|
|
|
|
|
fcntl (fd, F_SETFL, flags | O_APPEND);
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
2013-04-16 04:35:48 +00:00
|
|
|
|
/* Provide support for temporary files. */
|
|
|
|
|
|
|
|
|
|
#ifndef HAVE_STDLIB_H
|
|
|
|
|
# ifdef HAVE_MKSTEMP
|
|
|
|
|
int mkstemp (char *template);
|
|
|
|
|
# else
|
|
|
|
|
char *mktemp (char *template);
|
|
|
|
|
# endif
|
|
|
|
|
#endif
|
|
|
|
|
|
2013-05-04 17:10:56 +00:00
|
|
|
|
/* This is only used by output-sync, and it may not be portable. */
|
2013-04-16 04:35:48 +00:00
|
|
|
|
#ifdef OUTPUT_SYNC
|
|
|
|
|
|
|
|
|
|
/* Returns a file descriptor to a temporary file. The file is automatically
|
|
|
|
|
closed/deleted on exit. Don't use a FILE* stream. */
|
|
|
|
|
int
|
2013-05-17 06:29:46 +00:00
|
|
|
|
open_tmpfd ()
|
2013-04-16 04:35:48 +00:00
|
|
|
|
{
|
|
|
|
|
int fd = -1;
|
2013-05-17 06:29:46 +00:00
|
|
|
|
FILE *tfile = tmpfile ();
|
2013-04-16 04:35:48 +00:00
|
|
|
|
|
|
|
|
|
if (! tfile)
|
|
|
|
|
pfatal_with_name ("tmpfile");
|
|
|
|
|
|
|
|
|
|
/* Create a duplicate so we can close the stream. */
|
|
|
|
|
fd = dup (fileno (tfile));
|
|
|
|
|
if (fd < 0)
|
|
|
|
|
pfatal_with_name ("dup");
|
|
|
|
|
|
|
|
|
|
fclose (tfile);
|
|
|
|
|
|
2013-06-29 01:57:59 +00:00
|
|
|
|
set_append_mode (fd);
|
|
|
|
|
|
2013-04-16 04:35:48 +00:00
|
|
|
|
return fd;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
FILE *
|
2013-05-17 06:29:46 +00:00
|
|
|
|
open_tmpfile (char **name, const char *template)
|
2013-04-16 04:35:48 +00:00
|
|
|
|
{
|
|
|
|
|
#ifdef HAVE_FDOPEN
|
|
|
|
|
int fd;
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
#if defined HAVE_MKSTEMP || defined HAVE_MKTEMP
|
|
|
|
|
# define TEMPLATE_LEN strlen (template)
|
|
|
|
|
#else
|
|
|
|
|
# define TEMPLATE_LEN L_tmpnam
|
|
|
|
|
#endif
|
|
|
|
|
*name = xmalloc (TEMPLATE_LEN + 1);
|
|
|
|
|
strcpy (*name, template);
|
|
|
|
|
|
|
|
|
|
#if defined HAVE_MKSTEMP && defined HAVE_FDOPEN
|
|
|
|
|
/* It's safest to use mkstemp(), if we can. */
|
|
|
|
|
fd = mkstemp (*name);
|
|
|
|
|
if (fd == -1)
|
|
|
|
|
return 0;
|
|
|
|
|
return fdopen (fd, "w");
|
|
|
|
|
#else
|
|
|
|
|
# ifdef HAVE_MKTEMP
|
|
|
|
|
(void) mktemp (*name);
|
|
|
|
|
# else
|
|
|
|
|
(void) tmpnam (*name);
|
|
|
|
|
# endif
|
|
|
|
|
|
|
|
|
|
# ifdef HAVE_FDOPEN
|
|
|
|
|
/* Can't use mkstemp(), but guard against a race condition. */
|
|
|
|
|
fd = open (*name, O_CREAT|O_EXCL|O_WRONLY, 0600);
|
|
|
|
|
if (fd == -1)
|
|
|
|
|
return 0;
|
|
|
|
|
return fdopen (fd, "w");
|
|
|
|
|
# else
|
|
|
|
|
/* Not secure, but what can we do? */
|
|
|
|
|
return fopen (*name, "w");
|
|
|
|
|
# endif
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2005-06-12 22:22:07 +00:00
|
|
|
|
/* This code is stolen from gnulib.
|
|
|
|
|
If/when we abandon the requirement to work with K&R compilers, we can
|
|
|
|
|
remove this (and perhaps other parts of GNU make!) and migrate to using
|
|
|
|
|
gnulib directly.
|
|
|
|
|
|
|
|
|
|
This is called only through atexit(), which means die() has already been
|
|
|
|
|
invoked. So, call exit() here directly. Apparently that works...?
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
/* Close standard output, exiting with status 'exit_failure' on failure.
|
|
|
|
|
If a program writes *anything* to stdout, that program should close
|
|
|
|
|
stdout and make sure that it succeeds before exiting. Otherwise,
|
|
|
|
|
suppose that you go to the extreme of checking the return status
|
|
|
|
|
of every function that does an explicit write to stdout. The last
|
|
|
|
|
printf can succeed in writing to the internal stream buffer, and yet
|
|
|
|
|
the fclose(stdout) could still fail (due e.g., to a disk full error)
|
|
|
|
|
when it tries to write out that buffered data. Thus, you would be
|
|
|
|
|
left with an incomplete output file and the offending program would
|
|
|
|
|
exit successfully. Even calling fflush is not always sufficient,
|
|
|
|
|
since some file systems (NFS and CODA) buffer written/flushed data
|
|
|
|
|
until an actual close call.
|
|
|
|
|
|
|
|
|
|
Besides, it's wasteful to check the return value from every call
|
|
|
|
|
that writes to stdout -- just let the internal stream state record
|
|
|
|
|
the failure. That's what the ferror test is checking below.
|
|
|
|
|
|
|
|
|
|
It's important to detect such failures and exit nonzero because many
|
2012-03-04 00:24:20 +00:00
|
|
|
|
tools (most notably 'make' and other build-management systems) depend
|
2005-06-12 22:22:07 +00:00
|
|
|
|
on being able to detect failure in other tools via their exit status. */
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
close_stdout (void)
|
|
|
|
|
{
|
|
|
|
|
int prev_fail = ferror (stdout);
|
|
|
|
|
int fclose_fail = fclose (stdout);
|
|
|
|
|
|
|
|
|
|
if (prev_fail || fclose_fail)
|
|
|
|
|
{
|
|
|
|
|
if (fclose_fail)
|
|
|
|
|
error (NILF, _("write error: %s"), strerror (errno));
|
|
|
|
|
else
|
|
|
|
|
error (NILF, _("write error"));
|
|
|
|
|
exit (EXIT_FAILURE);
|
|
|
|
|
}
|
|
|
|
|
}
|