Rework source layout in preparation for modular sudo.
This commit is contained in:
39
compat/charclass.h
Normal file
39
compat/charclass.h
Normal file
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Copyright (c) 2008 Todd C. Miller <Todd.Miller@courtesan.com>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
/*
|
||||
* POSIX character class support for fnmatch() and glob().
|
||||
*/
|
||||
static struct cclass {
|
||||
const char *name;
|
||||
int (*isctype) __P((int));
|
||||
} cclasses[] = {
|
||||
{ "alnum", isalnum },
|
||||
{ "alpha", isalpha },
|
||||
{ "blank", isblank },
|
||||
{ "cntrl", iscntrl },
|
||||
{ "digit", isdigit },
|
||||
{ "graph", isgraph },
|
||||
{ "lower", islower },
|
||||
{ "print", isprint },
|
||||
{ "punct", ispunct },
|
||||
{ "space", isspace },
|
||||
{ "upper", isupper },
|
||||
{ "xdigit", isxdigit },
|
||||
{ NULL, NULL }
|
||||
};
|
||||
|
||||
#define NCCLASSES (sizeof(cclasses) / sizeof(cclasses[0]) - 1)
|
121
compat/closefrom.c
Normal file
121
compat/closefrom.c
Normal file
@@ -0,0 +1,121 @@
|
||||
/*
|
||||
* Copyright (c) 2004-2005, 2007
|
||||
* Todd C. Miller <Todd.Miller@courtesan.com>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/param.h>
|
||||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
#ifdef STDC_HEADERS
|
||||
# include <stdlib.h>
|
||||
# include <stddef.h>
|
||||
#else
|
||||
# ifdef HAVE_STDLIB_H
|
||||
# include <stdlib.h>
|
||||
# endif
|
||||
#endif /* STDC_HEADERS */
|
||||
#include <fcntl.h>
|
||||
#ifdef HAVE_DIRENT_H
|
||||
# include <dirent.h>
|
||||
# define NAMLEN(dirent) strlen((dirent)->d_name)
|
||||
#else
|
||||
# define dirent direct
|
||||
# define NAMLEN(dirent) (dirent)->d_namlen
|
||||
# ifdef HAVE_SYS_NDIR_H
|
||||
# include <sys/ndir.h>
|
||||
# endif
|
||||
# ifdef HAVE_SYS_DIR_H
|
||||
# include <sys/dir.h>
|
||||
# endif
|
||||
# ifdef HAVE_NDIR_H
|
||||
# include <ndir.h>
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#include "sudo.h"
|
||||
|
||||
#ifndef HAVE_FCNTL_CLOSEM
|
||||
# ifndef HAVE_DIRFD
|
||||
# define closefrom_fallback closefrom
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Close all file descriptors greater than or equal to lowfd.
|
||||
* This is the expensive (ballback) method.
|
||||
*/
|
||||
void
|
||||
closefrom_fallback(lowfd)
|
||||
int lowfd;
|
||||
{
|
||||
long fd, maxfd;
|
||||
|
||||
/*
|
||||
* Fall back on sysconf() or getdtablesize(). We avoid checking
|
||||
* resource limits since it is possible to open a file descriptor
|
||||
* and then drop the rlimit such that it is below the open fd.
|
||||
*/
|
||||
#ifdef HAVE_SYSCONF
|
||||
maxfd = sysconf(_SC_OPEN_MAX);
|
||||
#else
|
||||
maxfd = getdtablesize();
|
||||
#endif /* HAVE_SYSCONF */
|
||||
if (maxfd < 0)
|
||||
maxfd = OPEN_MAX;
|
||||
|
||||
for (fd = lowfd; fd < maxfd; fd++)
|
||||
(void) close((int) fd);
|
||||
}
|
||||
|
||||
/*
|
||||
* Close all file descriptors greater than or equal to lowfd.
|
||||
* We try the fast way first, falling back on the slow method.
|
||||
*/
|
||||
#ifdef HAVE_FCNTL_CLOSEM
|
||||
void
|
||||
closefrom(lowfd)
|
||||
int lowfd;
|
||||
{
|
||||
if (fcntl(lowfd, F_CLOSEM, 0) == -1)
|
||||
closefrom_fallback(lowfd);
|
||||
}
|
||||
#else
|
||||
# ifdef HAVE_DIRFD
|
||||
void
|
||||
closefrom(lowfd)
|
||||
int lowfd;
|
||||
{
|
||||
struct dirent *dent;
|
||||
DIR *dirp;
|
||||
char *endp;
|
||||
long fd;
|
||||
|
||||
/* Use /proc/self/fd directory if it exists. */
|
||||
if ((dirp = opendir("/proc/self/fd")) != NULL) {
|
||||
while ((dent = readdir(dirp)) != NULL) {
|
||||
fd = strtol(dent->d_name, &endp, 10);
|
||||
if (dent->d_name != endp && *endp == '\0' &&
|
||||
fd >= 0 && fd < INT_MAX && fd >= lowfd && fd != dirfd(dirp))
|
||||
(void) close((int) fd);
|
||||
}
|
||||
(void) closedir(dirp);
|
||||
} else
|
||||
closefrom_fallback(lowfd);
|
||||
}
|
||||
#endif /* HAVE_DIRFD */
|
||||
#endif /* HAVE_FCNTL_CLOSEM */
|
282
compat/fnmatch.c
Normal file
282
compat/fnmatch.c
Normal file
@@ -0,0 +1,282 @@
|
||||
/*
|
||||
* Copyright (c) 2008 Todd C. Miller <Todd.Miller@courtesan.com>
|
||||
* Copyright (c) 1989, 1993, 1994
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* This code is derived from software contributed to Berkeley by
|
||||
* Guido van Rossum.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Function fnmatch() as specified in POSIX 1003.2-1992, section B.6.
|
||||
* Compares a filename or pathname to a pattern.
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <ctype.h>
|
||||
#ifdef HAVE_STRING_H
|
||||
# include <string.h>
|
||||
#else
|
||||
# ifdef HAVE_STRINGS_H
|
||||
# include <strings.h>
|
||||
# endif
|
||||
#endif /* HAVE_STRING_H */
|
||||
|
||||
#include <compat.h>
|
||||
#include "emul/fnmatch.h"
|
||||
#include "emul/charclass.h"
|
||||
|
||||
#undef EOS
|
||||
#define EOS '\0'
|
||||
|
||||
#define RANGE_MATCH 1
|
||||
#define RANGE_NOMATCH 0
|
||||
#define RANGE_ERROR (-1)
|
||||
|
||||
#if defined(LIBC_SCCS) && !defined(lint)
|
||||
__unused static const char rcsid[] = "$OpenBSD: fnmatch.c,v 1.6 1998/03/19 00:29:59 millert Exp $";
|
||||
#endif /* LIBC_SCCS and not lint */
|
||||
|
||||
static int rangematch __P((const char *, int, int, char **));
|
||||
static int classmatch __P((const char *, int, int, const char **));
|
||||
|
||||
int
|
||||
fnmatch(pattern, string, flags)
|
||||
const char *pattern, *string;
|
||||
int flags;
|
||||
{
|
||||
const char *stringstart;
|
||||
char *newp;
|
||||
char c, test;
|
||||
|
||||
for (stringstart = string;;)
|
||||
switch (c = *pattern++) {
|
||||
case EOS:
|
||||
if (ISSET(flags, FNM_LEADING_DIR) && *string == '/')
|
||||
return (0);
|
||||
return (*string == EOS ? 0 : FNM_NOMATCH);
|
||||
case '?':
|
||||
if (*string == EOS)
|
||||
return (FNM_NOMATCH);
|
||||
if (*string == '/' && ISSET(flags, FNM_PATHNAME))
|
||||
return (FNM_NOMATCH);
|
||||
if (*string == '.' && ISSET(flags, FNM_PERIOD) &&
|
||||
(string == stringstart ||
|
||||
(ISSET(flags, FNM_PATHNAME) && *(string - 1) == '/')))
|
||||
return (FNM_NOMATCH);
|
||||
++string;
|
||||
break;
|
||||
case '*':
|
||||
c = *pattern;
|
||||
/* Collapse multiple stars. */
|
||||
while (c == '*')
|
||||
c = *++pattern;
|
||||
|
||||
if (*string == '.' && ISSET(flags, FNM_PERIOD) &&
|
||||
(string == stringstart ||
|
||||
(ISSET(flags, FNM_PATHNAME) && *(string - 1) == '/')))
|
||||
return (FNM_NOMATCH);
|
||||
|
||||
/* Optimize for pattern with * at end or before /. */
|
||||
if (c == EOS) {
|
||||
if (ISSET(flags, FNM_PATHNAME))
|
||||
return (ISSET(flags, FNM_LEADING_DIR) ||
|
||||
strchr(string, '/') == NULL ?
|
||||
0 : FNM_NOMATCH);
|
||||
else
|
||||
return (0);
|
||||
} else if (c == '/' && ISSET(flags, FNM_PATHNAME)) {
|
||||
if ((string = strchr(string, '/')) == NULL)
|
||||
return (FNM_NOMATCH);
|
||||
break;
|
||||
}
|
||||
|
||||
/* General case, use recursion. */
|
||||
while ((test = *string) != EOS) {
|
||||
if (!fnmatch(pattern, string, flags & ~FNM_PERIOD))
|
||||
return (0);
|
||||
if (test == '/' && ISSET(flags, FNM_PATHNAME))
|
||||
break;
|
||||
++string;
|
||||
}
|
||||
return (FNM_NOMATCH);
|
||||
case '[':
|
||||
if (*string == EOS)
|
||||
return (FNM_NOMATCH);
|
||||
if (*string == '/' && ISSET(flags, FNM_PATHNAME))
|
||||
return (FNM_NOMATCH);
|
||||
if (*string == '.' && ISSET(flags, FNM_PERIOD) &&
|
||||
(string == stringstart ||
|
||||
(ISSET(flags, FNM_PATHNAME) && *(string - 1) == '/')))
|
||||
return (FNM_NOMATCH);
|
||||
|
||||
switch (rangematch(pattern, *string, flags, &newp)) {
|
||||
case RANGE_ERROR:
|
||||
/* not a good range, treat as normal text */
|
||||
goto normal;
|
||||
case RANGE_MATCH:
|
||||
pattern = newp;
|
||||
break;
|
||||
case RANGE_NOMATCH:
|
||||
return (FNM_NOMATCH);
|
||||
}
|
||||
++string;
|
||||
break;
|
||||
case '\\':
|
||||
if (!ISSET(flags, FNM_NOESCAPE)) {
|
||||
if ((c = *pattern++) == EOS) {
|
||||
c = '\\';
|
||||
--pattern;
|
||||
}
|
||||
}
|
||||
/* FALLTHROUGH */
|
||||
default:
|
||||
normal:
|
||||
if (c != *string && !(ISSET(flags, FNM_CASEFOLD) &&
|
||||
(tolower((unsigned char)c) ==
|
||||
tolower((unsigned char)*string))))
|
||||
return (FNM_NOMATCH);
|
||||
++string;
|
||||
break;
|
||||
}
|
||||
/* NOTREACHED */
|
||||
}
|
||||
|
||||
static int
|
||||
#ifdef __STDC__
|
||||
rangematch(const char *pattern, int test, int flags, char **newp)
|
||||
#else
|
||||
rangematch(pattern, test, flags, newp)
|
||||
const char *pattern;
|
||||
int test;
|
||||
int flags;
|
||||
char **newp;
|
||||
#endif
|
||||
{
|
||||
int negate, ok, rv;
|
||||
char c, c2;
|
||||
|
||||
/*
|
||||
* A bracket expression starting with an unquoted circumflex
|
||||
* character produces unspecified results (IEEE 1003.2-1992,
|
||||
* 3.13.2). This implementation treats it like '!', for
|
||||
* consistency with the regular expression syntax.
|
||||
* J.T. Conklin (conklin@ngai.kaleida.com)
|
||||
*/
|
||||
if ((negate = (*pattern == '!' || *pattern == '^')))
|
||||
++pattern;
|
||||
|
||||
if (ISSET(flags, FNM_CASEFOLD))
|
||||
test = tolower(test);
|
||||
|
||||
/*
|
||||
* A right bracket shall lose its special meaning and represent
|
||||
* itself in a bracket expression if it occurs first in the list.
|
||||
* -- POSIX.2 2.8.3.2
|
||||
*/
|
||||
ok = 0;
|
||||
c = *pattern++;
|
||||
do {
|
||||
if (c == '[' && *pattern == ':') {
|
||||
do {
|
||||
rv = classmatch(pattern + 1, test,
|
||||
(flags & FNM_CASEFOLD), &pattern);
|
||||
if (rv == RANGE_MATCH)
|
||||
ok = 1;
|
||||
c = *pattern++;
|
||||
} while (rv != RANGE_ERROR && c == '[' && *pattern == ':');
|
||||
if (c == ']')
|
||||
break;
|
||||
}
|
||||
if (c == '\\' && !ISSET(flags, FNM_NOESCAPE))
|
||||
c = *pattern++;
|
||||
if (c == EOS)
|
||||
return (RANGE_ERROR);
|
||||
if (c == '/' && ISSET(flags, FNM_PATHNAME))
|
||||
return (RANGE_NOMATCH);
|
||||
if (ISSET(flags, FNM_CASEFOLD))
|
||||
c = tolower((unsigned char)c);
|
||||
if (*pattern == '-'
|
||||
&& (c2 = *(pattern+1)) != EOS && c2 != ']') {
|
||||
pattern += 2;
|
||||
if (c2 == '\\' && !ISSET(flags, FNM_NOESCAPE))
|
||||
c2 = *pattern++;
|
||||
if (c2 == EOS)
|
||||
return (RANGE_ERROR);
|
||||
if (ISSET(flags, FNM_CASEFOLD))
|
||||
c2 = tolower((unsigned char)c2);
|
||||
if (c <= test && test <= c2)
|
||||
ok = 1;
|
||||
} else if (c == test)
|
||||
ok = 1;
|
||||
} while ((c = *pattern++) != ']');
|
||||
|
||||
*newp = (char *)pattern;
|
||||
return (ok == negate ? RANGE_NOMATCH : RANGE_MATCH);
|
||||
}
|
||||
|
||||
static int
|
||||
#ifdef __STDC__
|
||||
classmatch(const char *pattern, int test, int foldcase, const char **ep)
|
||||
#else
|
||||
classmatch(pattern, test, foldcase, ep)
|
||||
const char *pattern;
|
||||
int test;
|
||||
int foldcase;
|
||||
const char **ep;
|
||||
#endif
|
||||
{
|
||||
struct cclass *cc;
|
||||
const char *colon;
|
||||
size_t len;
|
||||
int rval = RANGE_NOMATCH;
|
||||
|
||||
if ((colon = strchr(pattern, ':')) == NULL || colon[1] != ']') {
|
||||
*ep = pattern - 2;
|
||||
return(RANGE_ERROR);
|
||||
}
|
||||
*ep = colon + 2;
|
||||
len = (size_t)(colon - pattern);
|
||||
|
||||
if (foldcase && strncmp(pattern, "upper:]", 7) == 0)
|
||||
pattern = "lower:]";
|
||||
for (cc = cclasses; cc->name != NULL; cc++) {
|
||||
if (!strncmp(pattern, cc->name, len) && cc->name[len] == '\0') {
|
||||
if (cc->isctype(test))
|
||||
rval = RANGE_MATCH;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (cc->name == NULL) {
|
||||
/* invalid character class, return EOS */
|
||||
*ep = colon + strlen(colon);
|
||||
rval = RANGE_ERROR;
|
||||
}
|
||||
return(rval);
|
||||
}
|
46
compat/fnmatch.h
Normal file
46
compat/fnmatch.h
Normal file
@@ -0,0 +1,46 @@
|
||||
/*-
|
||||
* Copyright (c) 1992, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* @(#)fnmatch.h 8.1 (Berkeley) 6/2/93
|
||||
* $OpenBSD: fnmatch.h,v 1.4 1997/09/22 05:25:32 millert Exp $
|
||||
*/
|
||||
|
||||
#ifndef _FNMATCH_H_
|
||||
#define _FNMATCH_H_
|
||||
|
||||
#define FNM_NOMATCH 1 /* Match failed. */
|
||||
|
||||
#define FNM_NOESCAPE 0x01 /* Disable backslash escaping. */
|
||||
#define FNM_PATHNAME 0x02 /* Slash must be matched by slash. */
|
||||
#define FNM_PERIOD 0x04 /* Period must be matched by period. */
|
||||
#define FNM_LEADING_DIR 0x08 /* Ignore /<tail> after Imatch. */
|
||||
#define FNM_CASEFOLD 0x10 /* Case insensitive search. */
|
||||
|
||||
int fnmatch __P((const char *, const char *, int));
|
||||
|
||||
#endif /* !_FNMATCH_H_ */
|
267
compat/getcwd.c
Normal file
267
compat/getcwd.c
Normal file
@@ -0,0 +1,267 @@
|
||||
/*
|
||||
* Copyright (c) 1989, 1991, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#ifdef STDC_HEADERS
|
||||
# include <stdlib.h>
|
||||
# include <stddef.h>
|
||||
#else
|
||||
# ifdef HAVE_STDLIB_H
|
||||
# include <stdlib.h>
|
||||
# endif
|
||||
#endif /* STDC_HEADERS */
|
||||
#ifdef HAVE_STRING_H
|
||||
# include <string.h>
|
||||
#else
|
||||
# ifdef HAVE_STRINGS_H
|
||||
# include <strings.h>
|
||||
# endif
|
||||
#endif /* HAVE_STRING_H */
|
||||
#if defined(HAVE_MALLOC_H) && !defined(STDC_HEADERS)
|
||||
# include <malloc.h>
|
||||
#endif /* HAVE_MALLOC_H && !STDC_HEADERS */
|
||||
#ifdef HAVE_UNISTD_H
|
||||
# include <unistd.h>
|
||||
#endif /* HAVE_UNISTD_H */
|
||||
#ifdef HAVE_DIRENT_H
|
||||
# include <dirent.h>
|
||||
# define NAMLEN(dirent) strlen((dirent)->d_name)
|
||||
#else
|
||||
# define dirent direct
|
||||
# define NAMLEN(dirent) (dirent)->d_namlen
|
||||
# ifdef HAVE_SYS_NDIR_H
|
||||
# include <sys/ndir.h>
|
||||
# endif
|
||||
# ifdef HAVE_SYS_DIR_H
|
||||
# include <sys/dir.h>
|
||||
# endif
|
||||
# ifdef HAVE_NDIR_H
|
||||
# include <ndir.h>
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#include <compat.h>
|
||||
|
||||
#define ISDOT(dp) \
|
||||
(dp->d_name[0] == '.' && (dp->d_name[1] == '\0' || \
|
||||
(dp->d_name[1] == '.' && dp->d_name[2] == '\0')))
|
||||
|
||||
char *
|
||||
getcwd(pt, size)
|
||||
char *pt;
|
||||
size_t size;
|
||||
{
|
||||
struct dirent *dp;
|
||||
DIR *dir = NULL;
|
||||
dev_t dev;
|
||||
ino_t ino;
|
||||
int first;
|
||||
char *bpt, *bup;
|
||||
struct stat s;
|
||||
dev_t root_dev;
|
||||
ino_t root_ino;
|
||||
size_t ptsize, upsize;
|
||||
int save_errno;
|
||||
char *ept, *eup, *up;
|
||||
|
||||
/*
|
||||
* If no buffer specified by the user, allocate one as necessary.
|
||||
* If a buffer is specified, the size has to be non-zero. The path
|
||||
* is built from the end of the buffer backwards.
|
||||
*/
|
||||
if (pt) {
|
||||
ptsize = 0;
|
||||
if (!size) {
|
||||
errno = EINVAL;
|
||||
return (NULL);
|
||||
}
|
||||
ept = pt + size;
|
||||
} else {
|
||||
if ((pt = malloc(ptsize = 1024 - 4)) == NULL)
|
||||
return (NULL);
|
||||
ept = pt + ptsize;
|
||||
}
|
||||
bpt = ept - 1;
|
||||
*bpt = '\0';
|
||||
|
||||
/*
|
||||
* Allocate bytes (1024 - malloc space) for the string of "../"'s.
|
||||
* Should always be enough (it's 340 levels). If it's not, allocate
|
||||
* as necessary. Special * case the first stat, it's ".", not "..".
|
||||
*/
|
||||
if ((up = malloc(upsize = 1024 - 4)) == NULL)
|
||||
goto err;
|
||||
eup = up + PATH_MAX;
|
||||
bup = up;
|
||||
up[0] = '.';
|
||||
up[1] = '\0';
|
||||
|
||||
/* Save root values, so know when to stop. */
|
||||
if (stat("/", &s))
|
||||
goto err;
|
||||
root_dev = s.st_dev;
|
||||
root_ino = s.st_ino;
|
||||
|
||||
errno = 0; /* XXX readdir has no error return. */
|
||||
|
||||
for (first = 1;; first = 0) {
|
||||
/* Stat the current level. */
|
||||
if (lstat(up, &s))
|
||||
goto err;
|
||||
|
||||
/* Save current node values. */
|
||||
ino = s.st_ino;
|
||||
dev = s.st_dev;
|
||||
|
||||
/* Check for reaching root. */
|
||||
if (root_dev == dev && root_ino == ino) {
|
||||
*--bpt = '/';
|
||||
/*
|
||||
* It's unclear that it's a requirement to copy the
|
||||
* path to the beginning of the buffer, but it's always
|
||||
* been that way and stuff would probably break.
|
||||
*/
|
||||
bcopy(bpt, pt, ept - bpt);
|
||||
free(up);
|
||||
return (pt);
|
||||
}
|
||||
|
||||
/*
|
||||
* Build pointer to the parent directory, allocating memory
|
||||
* as necessary. Max length is 3 for "../", the largest
|
||||
* possible component name, plus a trailing NULL.
|
||||
*/
|
||||
if (bup + 3 + MAXNAMLEN + 1 >= eup) {
|
||||
char *nup;
|
||||
|
||||
if ((nup = realloc(up, upsize *= 2)) == NULL)
|
||||
goto err;
|
||||
up = nup;
|
||||
bup = up;
|
||||
eup = up + upsize;
|
||||
}
|
||||
*bup++ = '.';
|
||||
*bup++ = '.';
|
||||
*bup = '\0';
|
||||
|
||||
/* Open and stat parent directory. */
|
||||
if (!(dir = opendir(up)) || fstat(dirfd(dir), &s))
|
||||
goto err;
|
||||
|
||||
/* Add trailing slash for next directory. */
|
||||
*bup++ = '/';
|
||||
|
||||
/*
|
||||
* If it's a mount point, have to stat each element because
|
||||
* the inode number in the directory is for the entry in the
|
||||
* parent directory, not the inode number of the mounted file.
|
||||
*/
|
||||
save_errno = 0;
|
||||
if (s.st_dev == dev) {
|
||||
for (;;) {
|
||||
if (!(dp = readdir(dir)))
|
||||
goto notfound;
|
||||
if (dp->d_fileno == ino)
|
||||
break;
|
||||
}
|
||||
} else
|
||||
for (;;) {
|
||||
if (!(dp = readdir(dir)))
|
||||
goto notfound;
|
||||
if (ISDOT(dp))
|
||||
continue;
|
||||
bcopy(dp->d_name, bup, NAMLEN(dp) + 1);
|
||||
|
||||
/* Save the first error for later. */
|
||||
if (lstat(up, &s)) {
|
||||
if (!save_errno)
|
||||
save_errno = errno;
|
||||
errno = 0;
|
||||
continue;
|
||||
}
|
||||
if (s.st_dev == dev && s.st_ino == ino)
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check for length of the current name, preceding slash,
|
||||
* leading slash.
|
||||
*/
|
||||
if (bpt - pt <= NAMLEN(dp) + (first ? 1 : 2)) {
|
||||
size_t len, off;
|
||||
char *npt;
|
||||
|
||||
if (!ptsize) {
|
||||
errno = ERANGE;
|
||||
goto err;
|
||||
}
|
||||
off = bpt - pt;
|
||||
len = ept - bpt;
|
||||
if ((npt = realloc(pt, ptsize *= 2)) == NULL)
|
||||
goto err;
|
||||
pt = npt;
|
||||
bpt = pt + off;
|
||||
ept = pt + ptsize;
|
||||
bcopy(bpt, ept - len, len);
|
||||
bpt = ept - len;
|
||||
}
|
||||
if (!first)
|
||||
*--bpt = '/';
|
||||
bpt -= NAMLEN(dp);
|
||||
bcopy(dp->d_name, bpt, NAMLEN(dp));
|
||||
(void)closedir(dir);
|
||||
|
||||
/* Truncate any file name. */
|
||||
*bup = '\0';
|
||||
}
|
||||
|
||||
notfound:
|
||||
/*
|
||||
* If readdir set errno, use it, not any saved error; otherwise,
|
||||
* didn't find the current directory in its parent directory, set
|
||||
* errno to ENOENT.
|
||||
*/
|
||||
if (!errno)
|
||||
errno = save_errno ? save_errno : ENOENT;
|
||||
/* FALLTHROUGH */
|
||||
err:
|
||||
if (ptsize)
|
||||
free(pt);
|
||||
if (up)
|
||||
free(up);
|
||||
if (dir)
|
||||
(void)closedir(dir);
|
||||
return (NULL);
|
||||
}
|
103
compat/getline.c
Normal file
103
compat/getline.c
Normal file
@@ -0,0 +1,103 @@
|
||||
/*
|
||||
* Copyright (c) 2009 Todd C. Miller <Todd.Miller@courtesan.com>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#ifdef STDC_HEADERS
|
||||
# include <stdlib.h>
|
||||
# include <stddef.h>
|
||||
#else
|
||||
# ifdef HAVE_STDLIB_H
|
||||
# include <stdlib.h>
|
||||
# endif
|
||||
#endif /* STDC_HEADERS */
|
||||
#ifdef HAVE_STRING_H
|
||||
# include <string.h>
|
||||
#else
|
||||
# ifdef HAVE_STRINGS_H
|
||||
# include <strings.h>
|
||||
# endif
|
||||
#endif /* HAVE_STRING_H */
|
||||
#include <limits.h>
|
||||
|
||||
#include "compat.h"
|
||||
#include "alloc.h"
|
||||
|
||||
#ifndef LINE_MAX
|
||||
# define LINE_MAX 2048
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_FGETLN
|
||||
ssize_t
|
||||
getline(bufp, bufsizep, fp)
|
||||
char **bufp;
|
||||
size_t *bufsizep;
|
||||
FILE *fp;
|
||||
{
|
||||
char *buf;
|
||||
size_t bufsize;
|
||||
size_t len;
|
||||
|
||||
buf = fgetln(fp, &len);
|
||||
if (buf) {
|
||||
bufsize = *bufp ? *bufsizep : 0;
|
||||
if (bufsize < len + 1) {
|
||||
bufsize = len + 1;
|
||||
*bufp = erealloc(*bufp, bufsize);
|
||||
*bufsizep = bufsize;
|
||||
}
|
||||
memcpy(*bufp, buf, len);
|
||||
(*bufp)[len] = '\0';
|
||||
}
|
||||
return(buf ? len : -1);
|
||||
}
|
||||
#else
|
||||
ssize_t
|
||||
getline(bufp, bufsizep, fp)
|
||||
char **bufp;
|
||||
size_t *bufsizep;
|
||||
FILE *fp;
|
||||
{
|
||||
char *buf;
|
||||
size_t bufsize;
|
||||
ssize_t len = 0;
|
||||
|
||||
buf = *bufp;
|
||||
bufsize = *bufsizep;
|
||||
if (buf == NULL || bufsize == 0) {
|
||||
bufsize = LINE_MAX;
|
||||
buf = erealloc(buf, LINE_MAX);
|
||||
}
|
||||
|
||||
for (;;) {
|
||||
if (fgets(buf + len, bufsize - len, fp) == NULL) {
|
||||
len = -1;
|
||||
break;
|
||||
}
|
||||
len = strlen(buf);
|
||||
if (!len || buf[len - 1] == '\n' || feof(fp))
|
||||
break;
|
||||
bufsize *= 2;
|
||||
buf = erealloc(buf, bufsize);
|
||||
}
|
||||
*bufp = buf;
|
||||
*bufsizep = bufsize;
|
||||
return(len);
|
||||
}
|
||||
#endif
|
43
compat/getprogname.c
Normal file
43
compat/getprogname.c
Normal file
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* Copyright (c) 2003-2005 Todd C. Miller <Todd.Miller@courtesan.com>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*
|
||||
* Sponsored in part by the Defense Advanced Research Projects
|
||||
* Agency (DARPA) and Air Force Research Laboratory, Air Force
|
||||
* Materiel Command, USAF, under agreement number F39502-99-1-0512.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <config.h>
|
||||
#include <compat.h>
|
||||
|
||||
const char *
|
||||
getprogname()
|
||||
{
|
||||
static const char *progname;
|
||||
extern int Argc;
|
||||
extern char **Argv;
|
||||
|
||||
if (progname == NULL) {
|
||||
if (Argc < 0)
|
||||
progname = "sudo";
|
||||
else if ((progname = strrchr(Argv[0], '/')) != NULL)
|
||||
progname++;
|
||||
else
|
||||
progname = Argv[0];
|
||||
}
|
||||
return(progname);
|
||||
}
|
950
compat/glob.c
Normal file
950
compat/glob.c
Normal file
@@ -0,0 +1,950 @@
|
||||
/*
|
||||
* Copyright (c) 2008-2009 Todd C. Miller <Todd.Miller@courtesan.com>
|
||||
* Copyright (c) 1989, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* This code is derived from software contributed to Berkeley by
|
||||
* Guido van Rossum.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* @(#)glob.c 8.3 (Berkeley) 10/13/93
|
||||
*/
|
||||
|
||||
/*
|
||||
* glob(3) -- a superset of the one defined in POSIX 1003.2.
|
||||
*
|
||||
* The [!...] convention to negate a range is supported (SysV, Posix, ksh).
|
||||
*
|
||||
* Optional extra services, controlled by flags not defined by POSIX:
|
||||
*
|
||||
* GLOB_MAGCHAR:
|
||||
* Set in gl_flags if pattern contained a globbing character.
|
||||
* GLOB_TILDE:
|
||||
* expand ~user/foo to the /home/dir/of/user/foo
|
||||
* GLOB_BRACE:
|
||||
* expand {1,2}{a,b} to 1a 1b 2a 2b
|
||||
* gl_matchc:
|
||||
* Number of matches in the current invocation of glob.
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#ifdef STDC_HEADERS
|
||||
# include <stdlib.h>
|
||||
# include <stddef.h>
|
||||
#else
|
||||
# ifdef HAVE_STDLIB_H
|
||||
# include <stdlib.h>
|
||||
# endif
|
||||
#endif /* STDC_HEADERS */
|
||||
#if defined(HAVE_MALLOC_H) && !defined(STDC_HEADERS)
|
||||
# include <malloc.h>
|
||||
#endif /* HAVE_MALLOC_H && !STDC_HEADERS */
|
||||
#ifdef HAVE_STRING_H
|
||||
# include <string.h>
|
||||
#else
|
||||
# ifdef HAVE_STRINGS_H
|
||||
# include <strings.h>
|
||||
# endif
|
||||
#endif /* HAVE_STRING_H */
|
||||
#ifdef HAVE_UNISTD_H
|
||||
# include <unistd.h>
|
||||
#endif /* HAVE_UNISTD_H */
|
||||
#include <ctype.h>
|
||||
#ifdef HAVE_DIRENT_H
|
||||
# include <dirent.h>
|
||||
#else
|
||||
# define dirent direct
|
||||
# ifdef HAVE_SYS_NDIR_H
|
||||
# include <sys/ndir.h>
|
||||
# endif
|
||||
# ifdef HAVE_SYS_DIR_H
|
||||
# include <sys/dir.h>
|
||||
# endif
|
||||
# ifdef HAVE_NDIR_H
|
||||
# include <ndir.h>
|
||||
# endif
|
||||
#endif
|
||||
#include <errno.h>
|
||||
#include <limits.h>
|
||||
#include <pwd.h>
|
||||
|
||||
#include <compat.h>
|
||||
#include "emul/glob.h"
|
||||
#include "emul/charclass.h"
|
||||
|
||||
#define DOLLAR '$'
|
||||
#define DOT '.'
|
||||
#define EOS '\0'
|
||||
#define LBRACKET '['
|
||||
#define NOT '!'
|
||||
#define QUESTION '?'
|
||||
#define QUOTE '\\'
|
||||
#define RANGE '-'
|
||||
#define RBRACKET ']'
|
||||
#define SEP '/'
|
||||
#define STAR '*'
|
||||
#define TILDE '~'
|
||||
#define UNDERSCORE '_'
|
||||
#define LBRACE '{'
|
||||
#define RBRACE '}'
|
||||
#define SLASH '/'
|
||||
#define COMMA ','
|
||||
|
||||
#ifndef DEBUG
|
||||
|
||||
#define M_QUOTE 0x8000
|
||||
#define M_PROTECT 0x4000
|
||||
#define M_MASK 0xffff
|
||||
#define M_ASCII 0x00ff
|
||||
|
||||
typedef unsigned short Char;
|
||||
|
||||
#else
|
||||
|
||||
#define M_QUOTE 0x80
|
||||
#define M_PROTECT 0x40
|
||||
#define M_MASK 0xff
|
||||
#define M_ASCII 0x7f
|
||||
|
||||
typedef char Char;
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
#define CHAR(c) ((Char)((c)&M_ASCII))
|
||||
#define META(c) ((Char)((c)|M_QUOTE))
|
||||
#define M_ALL META('*')
|
||||
#define M_END META(']')
|
||||
#define M_NOT META('!')
|
||||
#define M_ONE META('?')
|
||||
#define M_RNG META('-')
|
||||
#define M_SET META('[')
|
||||
#define M_CLASS META(':')
|
||||
#define ismeta(c) (((c)&M_QUOTE) != 0)
|
||||
|
||||
|
||||
static int compare __P((const void *, const void *));
|
||||
static int g_Ctoc __P((const Char *, char *, unsigned int));
|
||||
static int g_lstat __P((Char *, struct stat *, glob_t *));
|
||||
static DIR *g_opendir __P((Char *, glob_t *));
|
||||
static Char *g_strchr __P((const Char *, int));
|
||||
static int g_strncmp __P((const Char *, const char *, size_t));
|
||||
static int g_stat __P((Char *, struct stat *, glob_t *));
|
||||
static int glob0 __P((const Char *, glob_t *));
|
||||
static int glob1 __P((Char *, Char *, glob_t *));
|
||||
static int glob2 __P((Char *, Char *, Char *, Char *, Char *, Char *,
|
||||
glob_t *));
|
||||
static int glob3 __P((Char *, Char *, Char *, Char *, Char *, Char *,
|
||||
Char *, Char *, glob_t *));
|
||||
static int globextend __P((const Char *, glob_t *));
|
||||
static const Char *
|
||||
globtilde __P((const Char *, Char *, size_t, glob_t *));
|
||||
static int globexp1 __P((const Char *, glob_t *));
|
||||
static int globexp2 __P((const Char *, const Char *, glob_t *, int *));
|
||||
static int match __P((Char *, Char *, Char *));
|
||||
#ifdef DEBUG
|
||||
static void qprintf __P((const char *, Char *));
|
||||
#endif
|
||||
|
||||
extern struct passwd *sudo_getpwnam __P((const char *));
|
||||
extern struct passwd *sudo_getpwuid __P((uid_t));
|
||||
|
||||
int
|
||||
glob(pattern, flags, errfunc, pglob)
|
||||
const char *pattern;
|
||||
int flags, (*errfunc) __P((const char *, int));
|
||||
glob_t *pglob;
|
||||
{
|
||||
const unsigned char *patnext;
|
||||
int c;
|
||||
Char *bufnext, *bufend, patbuf[PATH_MAX];
|
||||
|
||||
patnext = (unsigned char *) pattern;
|
||||
if (!(flags & GLOB_APPEND)) {
|
||||
pglob->gl_pathc = 0;
|
||||
pglob->gl_pathv = NULL;
|
||||
if (!(flags & GLOB_DOOFFS))
|
||||
pglob->gl_offs = 0;
|
||||
}
|
||||
pglob->gl_flags = flags & ~GLOB_MAGCHAR;
|
||||
pglob->gl_errfunc = errfunc;
|
||||
pglob->gl_matchc = 0;
|
||||
|
||||
bufnext = patbuf;
|
||||
bufend = bufnext + PATH_MAX - 1;
|
||||
if (flags & GLOB_NOESCAPE)
|
||||
while (bufnext < bufend && (c = *patnext++) != EOS)
|
||||
*bufnext++ = c;
|
||||
else {
|
||||
/* Protect the quoted characters. */
|
||||
while (bufnext < bufend && (c = *patnext++) != EOS)
|
||||
if (c == QUOTE) {
|
||||
if ((c = *patnext++) == EOS) {
|
||||
c = QUOTE;
|
||||
--patnext;
|
||||
}
|
||||
*bufnext++ = c | M_PROTECT;
|
||||
} else
|
||||
*bufnext++ = c;
|
||||
}
|
||||
*bufnext = EOS;
|
||||
|
||||
if (flags & GLOB_BRACE)
|
||||
return globexp1(patbuf, pglob);
|
||||
else
|
||||
return glob0(patbuf, pglob);
|
||||
}
|
||||
|
||||
/*
|
||||
* Expand recursively a glob {} pattern. When there is no more expansion
|
||||
* invoke the standard globbing routine to glob the rest of the magic
|
||||
* characters
|
||||
*/
|
||||
static int
|
||||
globexp1(pattern, pglob)
|
||||
const Char *pattern;
|
||||
glob_t *pglob;
|
||||
{
|
||||
const Char* ptr = pattern;
|
||||
int rv;
|
||||
|
||||
/* Protect a single {}, for find(1), like csh */
|
||||
if (pattern[0] == LBRACE && pattern[1] == RBRACE && pattern[2] == EOS)
|
||||
return glob0(pattern, pglob);
|
||||
|
||||
while ((ptr = (const Char *) g_strchr(ptr, LBRACE)) != NULL)
|
||||
if (!globexp2(ptr, pattern, pglob, &rv))
|
||||
return rv;
|
||||
|
||||
return glob0(pattern, pglob);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Recursive brace globbing helper. Tries to expand a single brace.
|
||||
* If it succeeds then it invokes globexp1 with the new pattern.
|
||||
* If it fails then it tries to glob the rest of the pattern and returns.
|
||||
*/
|
||||
static int
|
||||
globexp2(ptr, pattern, pglob, rv)
|
||||
const Char *ptr, *pattern;
|
||||
glob_t *pglob;
|
||||
int *rv;
|
||||
{
|
||||
int i;
|
||||
Char *lm, *ls;
|
||||
const Char *pe, *pm, *pl;
|
||||
Char patbuf[PATH_MAX];
|
||||
|
||||
/* copy part up to the brace */
|
||||
for (lm = patbuf, pm = pattern; pm != ptr; *lm++ = *pm++)
|
||||
continue;
|
||||
*lm = EOS;
|
||||
ls = lm;
|
||||
|
||||
/* Find the balanced brace */
|
||||
for (i = 0, pe = ++ptr; *pe; pe++)
|
||||
if (*pe == LBRACKET) {
|
||||
/* Ignore everything between [] */
|
||||
for (pm = pe++; *pe != RBRACKET && *pe != EOS; pe++)
|
||||
continue;
|
||||
if (*pe == EOS) {
|
||||
/*
|
||||
* We could not find a matching RBRACKET.
|
||||
* Ignore and just look for RBRACE
|
||||
*/
|
||||
pe = pm;
|
||||
}
|
||||
} else if (*pe == LBRACE)
|
||||
i++;
|
||||
else if (*pe == RBRACE) {
|
||||
if (i == 0)
|
||||
break;
|
||||
i--;
|
||||
}
|
||||
|
||||
/* Non matching braces; just glob the pattern */
|
||||
if (i != 0 || *pe == EOS) {
|
||||
*rv = glob0(patbuf, pglob);
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (i = 0, pl = pm = ptr; pm <= pe; pm++) {
|
||||
switch (*pm) {
|
||||
case LBRACKET:
|
||||
/* Ignore everything between [] */
|
||||
for (pl = pm++; *pm != RBRACKET && *pm != EOS; pm++)
|
||||
continue;
|
||||
if (*pm == EOS) {
|
||||
/*
|
||||
* We could not find a matching RBRACKET.
|
||||
* Ignore and just look for RBRACE
|
||||
*/
|
||||
pm = pl;
|
||||
}
|
||||
break;
|
||||
|
||||
case LBRACE:
|
||||
i++;
|
||||
break;
|
||||
|
||||
case RBRACE:
|
||||
if (i) {
|
||||
i--;
|
||||
break;
|
||||
}
|
||||
/* FALLTHROUGH */
|
||||
case COMMA:
|
||||
if (i && *pm == COMMA)
|
||||
break;
|
||||
else {
|
||||
/* Append the current string */
|
||||
for (lm = ls; (pl < pm); *lm++ = *pl++)
|
||||
continue;
|
||||
|
||||
/*
|
||||
* Append the rest of the pattern after the
|
||||
* closing brace
|
||||
*/
|
||||
for (pl = pe + 1; (*lm++ = *pl++) != EOS; )
|
||||
continue;
|
||||
|
||||
/* Expand the current pattern */
|
||||
#ifdef DEBUG
|
||||
qprintf("globexp2:", patbuf);
|
||||
#endif
|
||||
*rv = globexp1(patbuf, pglob);
|
||||
|
||||
/* move after the comma, to the next string */
|
||||
pl = pm + 1;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
*rv = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* expand tilde from the passwd file.
|
||||
*/
|
||||
static const Char *
|
||||
globtilde(pattern, patbuf, patbuf_len, pglob)
|
||||
const Char *pattern;
|
||||
Char *patbuf;
|
||||
size_t patbuf_len;
|
||||
glob_t *pglob;
|
||||
{
|
||||
struct passwd *pwd;
|
||||
char *h;
|
||||
const Char *p;
|
||||
Char *b, *eb;
|
||||
|
||||
if (*pattern != TILDE || !(pglob->gl_flags & GLOB_TILDE))
|
||||
return pattern;
|
||||
|
||||
/* Copy up to the end of the string or / */
|
||||
eb = &patbuf[patbuf_len - 1];
|
||||
for (p = pattern + 1, h = (char *) patbuf;
|
||||
h < (char *)eb && *p && *p != SLASH; *h++ = *p++)
|
||||
continue;
|
||||
|
||||
*h = EOS;
|
||||
|
||||
if (((char *) patbuf)[0] == EOS) {
|
||||
/*
|
||||
* handle a plain ~ or ~/ by expanding $HOME
|
||||
* first and then trying the password file
|
||||
*/
|
||||
if ((h = getenv("HOME")) == NULL) {
|
||||
if ((pwd = sudo_getpwuid(getuid())) == NULL)
|
||||
return pattern;
|
||||
else
|
||||
h = pwd->pw_dir;
|
||||
}
|
||||
} else {
|
||||
/*
|
||||
* Expand a ~user
|
||||
*/
|
||||
if ((pwd = sudo_getpwnam((char*) patbuf)) == NULL)
|
||||
return pattern;
|
||||
else
|
||||
h = pwd->pw_dir;
|
||||
}
|
||||
|
||||
/* Copy the home directory */
|
||||
for (b = patbuf; b < eb && *h; *b++ = *h++)
|
||||
continue;
|
||||
|
||||
/* Append the rest of the pattern */
|
||||
while (b < eb && (*b++ = *p++) != EOS)
|
||||
continue;
|
||||
*b = EOS;
|
||||
|
||||
return patbuf;
|
||||
}
|
||||
|
||||
static int
|
||||
g_strncmp(s1, s2, n)
|
||||
const Char *s1;
|
||||
const char *s2;
|
||||
size_t n;
|
||||
{
|
||||
int rv = 0;
|
||||
|
||||
while (n--) {
|
||||
rv = *(Char *)s1 - *(const unsigned char *)s2++;
|
||||
if (rv)
|
||||
break;
|
||||
if (*s1++ == '\0')
|
||||
break;
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
static int
|
||||
g_charclass(patternp, bufnextp)
|
||||
const Char **patternp;
|
||||
Char **bufnextp;
|
||||
{
|
||||
const Char *pattern = *patternp + 1;
|
||||
Char *bufnext = *bufnextp;
|
||||
const Char *colon;
|
||||
struct cclass *cc;
|
||||
size_t len;
|
||||
|
||||
if ((colon = g_strchr(pattern, ':')) == NULL || colon[1] != ']')
|
||||
return 1; /* not a character class */
|
||||
|
||||
len = (size_t)(colon - pattern);
|
||||
for (cc = cclasses; cc->name != NULL; cc++) {
|
||||
if (!g_strncmp(pattern, cc->name, len) && cc->name[len] == '\0')
|
||||
break;
|
||||
}
|
||||
if (cc->name == NULL)
|
||||
return -1; /* invalid character class */
|
||||
*bufnext++ = M_CLASS;
|
||||
*bufnext++ = (Char)(cc - &cclasses[0]);
|
||||
*bufnextp = bufnext;
|
||||
*patternp += len + 3;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* The main glob() routine: compiles the pattern (optionally processing
|
||||
* quotes), calls glob1() to do the real pattern matching, and finally
|
||||
* sorts the list (unless unsorted operation is requested). Returns 0
|
||||
* if things went well, nonzero if errors occurred. It is not an error
|
||||
* to find no matches.
|
||||
*/
|
||||
static int
|
||||
glob0(pattern, pglob)
|
||||
const Char *pattern;
|
||||
glob_t *pglob;
|
||||
{
|
||||
const Char *qpatnext;
|
||||
int c, err, oldpathc;
|
||||
Char *bufnext, patbuf[PATH_MAX];
|
||||
|
||||
qpatnext = globtilde(pattern, patbuf, PATH_MAX, pglob);
|
||||
oldpathc = pglob->gl_pathc;
|
||||
bufnext = patbuf;
|
||||
|
||||
/* We don't need to check for buffer overflow any more. */
|
||||
while ((c = *qpatnext++) != EOS) {
|
||||
switch (c) {
|
||||
case LBRACKET:
|
||||
c = *qpatnext;
|
||||
if (c == NOT)
|
||||
++qpatnext;
|
||||
if (*qpatnext == EOS ||
|
||||
g_strchr(qpatnext+1, RBRACKET) == NULL) {
|
||||
*bufnext++ = LBRACKET;
|
||||
if (c == NOT)
|
||||
--qpatnext;
|
||||
break;
|
||||
}
|
||||
*bufnext++ = M_SET;
|
||||
if (c == NOT)
|
||||
*bufnext++ = M_NOT;
|
||||
c = *qpatnext++;
|
||||
do {
|
||||
if (c == LBRACKET && *qpatnext == ':') {
|
||||
do {
|
||||
err = g_charclass(&qpatnext,
|
||||
&bufnext);
|
||||
if (err)
|
||||
break;
|
||||
c = *qpatnext++;
|
||||
} while (c == LBRACKET && *qpatnext == ':');
|
||||
if (err == -1 &&
|
||||
!(pglob->gl_flags & GLOB_NOCHECK))
|
||||
return GLOB_NOMATCH;
|
||||
if (c == RBRACKET)
|
||||
break;
|
||||
}
|
||||
*bufnext++ = CHAR(c);
|
||||
if (*qpatnext == RANGE &&
|
||||
(c = qpatnext[1]) != RBRACKET) {
|
||||
*bufnext++ = M_RNG;
|
||||
*bufnext++ = CHAR(c);
|
||||
qpatnext += 2;
|
||||
}
|
||||
} while ((c = *qpatnext++) != RBRACKET);
|
||||
pglob->gl_flags |= GLOB_MAGCHAR;
|
||||
*bufnext++ = M_END;
|
||||
break;
|
||||
case QUESTION:
|
||||
pglob->gl_flags |= GLOB_MAGCHAR;
|
||||
*bufnext++ = M_ONE;
|
||||
break;
|
||||
case STAR:
|
||||
pglob->gl_flags |= GLOB_MAGCHAR;
|
||||
/* collapse adjacent stars to one,
|
||||
* to avoid exponential behavior
|
||||
*/
|
||||
if (bufnext == patbuf || bufnext[-1] != M_ALL)
|
||||
*bufnext++ = M_ALL;
|
||||
break;
|
||||
default:
|
||||
*bufnext++ = CHAR(c);
|
||||
break;
|
||||
}
|
||||
}
|
||||
*bufnext = EOS;
|
||||
#ifdef DEBUG
|
||||
qprintf("glob0:", patbuf);
|
||||
#endif
|
||||
|
||||
if ((err = glob1(patbuf, patbuf + PATH_MAX - 1, pglob)) != 0)
|
||||
return(err);
|
||||
|
||||
/*
|
||||
* If there was no match we are going to append the pattern
|
||||
* if GLOB_NOCHECK was specified.
|
||||
*/
|
||||
if (pglob->gl_pathc == oldpathc) {
|
||||
if (pglob->gl_flags & GLOB_NOCHECK)
|
||||
return(globextend(pattern, pglob));
|
||||
else
|
||||
return(GLOB_NOMATCH);
|
||||
}
|
||||
if (!(pglob->gl_flags & GLOB_NOSORT))
|
||||
qsort(pglob->gl_pathv + pglob->gl_offs + oldpathc,
|
||||
pglob->gl_pathc - oldpathc, sizeof(char *), compare);
|
||||
return(0);
|
||||
}
|
||||
|
||||
static int
|
||||
compare(p, q)
|
||||
const void *p, *q;
|
||||
{
|
||||
return(strcmp(*(char **)p, *(char **)q));
|
||||
}
|
||||
|
||||
static int
|
||||
glob1(pattern, pattern_last, pglob)
|
||||
Char *pattern, *pattern_last;
|
||||
glob_t *pglob;
|
||||
{
|
||||
Char pathbuf[PATH_MAX];
|
||||
|
||||
/* A null pathname is invalid -- POSIX 1003.1 sect. 2.4. */
|
||||
if (*pattern == EOS)
|
||||
return(0);
|
||||
return(glob2(pathbuf, pathbuf + PATH_MAX - 1,
|
||||
pathbuf, pathbuf + PATH_MAX - 1,
|
||||
pattern, pattern_last, pglob));
|
||||
}
|
||||
|
||||
/*
|
||||
* The functions glob2 and glob3 are mutually recursive; there is one level
|
||||
* of recursion for each segment in the pattern that contains one or more
|
||||
* meta characters.
|
||||
*/
|
||||
static int
|
||||
glob2(pathbuf, pathbuf_last, pathend, pathend_last, pattern, pattern_last, pglob)
|
||||
Char *pathbuf, *pathbuf_last;
|
||||
Char *pathend, *pathend_last;
|
||||
Char *pattern, *pattern_last;
|
||||
glob_t *pglob;
|
||||
{
|
||||
struct stat sb;
|
||||
Char *p, *q;
|
||||
int anymeta;
|
||||
|
||||
/*
|
||||
* Loop over pattern segments until end of pattern or until
|
||||
* segment with meta character found.
|
||||
*/
|
||||
for (anymeta = 0;;) {
|
||||
if (*pattern == EOS) { /* End of pattern? */
|
||||
*pathend = EOS;
|
||||
if (g_lstat(pathbuf, &sb, pglob))
|
||||
return(0);
|
||||
|
||||
if (((pglob->gl_flags & GLOB_MARK) &&
|
||||
pathend[-1] != SEP) && (S_ISDIR(sb.st_mode) ||
|
||||
(S_ISLNK(sb.st_mode) &&
|
||||
(g_stat(pathbuf, &sb, pglob) == 0) &&
|
||||
S_ISDIR(sb.st_mode)))) {
|
||||
if (pathend+1 > pathend_last)
|
||||
return (1);
|
||||
*pathend++ = SEP;
|
||||
*pathend = EOS;
|
||||
}
|
||||
++pglob->gl_matchc;
|
||||
return(globextend(pathbuf, pglob));
|
||||
}
|
||||
|
||||
/* Find end of next segment, copy tentatively to pathend. */
|
||||
q = pathend;
|
||||
p = pattern;
|
||||
while (*p != EOS && *p != SEP) {
|
||||
if (ismeta(*p))
|
||||
anymeta = 1;
|
||||
if (q+1 > pathend_last)
|
||||
return (1);
|
||||
*q++ = *p++;
|
||||
}
|
||||
|
||||
if (!anymeta) { /* No expansion, do next segment. */
|
||||
pathend = q;
|
||||
pattern = p;
|
||||
while (*pattern == SEP) {
|
||||
if (pathend+1 > pathend_last)
|
||||
return (1);
|
||||
*pathend++ = *pattern++;
|
||||
}
|
||||
} else
|
||||
/* Need expansion, recurse. */
|
||||
return(glob3(pathbuf, pathbuf_last, pathend,
|
||||
pathend_last, pattern, pattern_last,
|
||||
p, pattern_last, pglob));
|
||||
}
|
||||
/* NOTREACHED */
|
||||
}
|
||||
|
||||
static int
|
||||
glob3(pathbuf, pathbuf_last, pathend, pathend_last, pattern, pattern_last,
|
||||
restpattern, restpattern_last, pglob)
|
||||
Char *pathbuf, *pathbuf_last, *pathend, *pathend_last;
|
||||
Char *pattern, *pattern_last, *restpattern, *restpattern_last;
|
||||
glob_t *pglob;
|
||||
{
|
||||
struct dirent *dp;
|
||||
DIR *dirp;
|
||||
int err;
|
||||
char buf[PATH_MAX];
|
||||
|
||||
if (pathend > pathend_last)
|
||||
return (1);
|
||||
*pathend = EOS;
|
||||
errno = 0;
|
||||
|
||||
if ((dirp = g_opendir(pathbuf, pglob)) == NULL) {
|
||||
/* TODO: don't call for ENOENT or ENOTDIR? */
|
||||
if (pglob->gl_errfunc) {
|
||||
if (g_Ctoc(pathbuf, buf, sizeof(buf)))
|
||||
return(GLOB_ABORTED);
|
||||
if (pglob->gl_errfunc(buf, errno) ||
|
||||
pglob->gl_flags & GLOB_ERR)
|
||||
return(GLOB_ABORTED);
|
||||
}
|
||||
return(0);
|
||||
}
|
||||
|
||||
err = 0;
|
||||
|
||||
/* Search directory for matching names. */
|
||||
while ((dp = readdir(dirp))) {
|
||||
unsigned char *sc;
|
||||
Char *dc;
|
||||
|
||||
/* Initial DOT must be matched literally. */
|
||||
if (dp->d_name[0] == DOT && *pattern != DOT)
|
||||
continue;
|
||||
dc = pathend;
|
||||
sc = (unsigned char *) dp->d_name;
|
||||
while (dc < pathend_last && (*dc++ = *sc++) != EOS)
|
||||
continue;
|
||||
if (dc >= pathend_last) {
|
||||
*dc = EOS;
|
||||
err = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!match(pathend, pattern, restpattern)) {
|
||||
*pathend = EOS;
|
||||
continue;
|
||||
}
|
||||
err = glob2(pathbuf, pathbuf_last, --dc, pathend_last,
|
||||
restpattern, restpattern_last, pglob);
|
||||
if (err)
|
||||
break;
|
||||
}
|
||||
|
||||
closedir(dirp);
|
||||
return(err);
|
||||
}
|
||||
|
||||
/*
|
||||
* Extend the gl_pathv member of a glob_t structure to accommodate a new item,
|
||||
* add the new item, and update gl_pathc.
|
||||
*
|
||||
* This assumes the BSD realloc, which only copies the block when its size
|
||||
* crosses a power-of-two boundary; for v7 realloc, this would cause quadratic
|
||||
* behavior.
|
||||
*
|
||||
* Return 0 if new item added, error code if memory couldn't be allocated.
|
||||
*
|
||||
* Invariant of the glob_t structure:
|
||||
* Either gl_pathc is zero and gl_pathv is NULL; or gl_pathc > 0 and
|
||||
* gl_pathv points to (gl_offs + gl_pathc + 1) items.
|
||||
*/
|
||||
static int
|
||||
globextend(path, pglob)
|
||||
const Char *path;
|
||||
glob_t *pglob;
|
||||
{
|
||||
char **pathv;
|
||||
int i;
|
||||
unsigned int newsize, len;
|
||||
char *copy;
|
||||
const Char *p;
|
||||
|
||||
newsize = sizeof(*pathv) * (2 + pglob->gl_pathc + pglob->gl_offs);
|
||||
pathv = pglob->gl_pathv ?
|
||||
(char **)realloc((char *)pglob->gl_pathv, newsize) :
|
||||
(char **)malloc(newsize);
|
||||
if (pathv == NULL) {
|
||||
if (pglob->gl_pathv) {
|
||||
free(pglob->gl_pathv);
|
||||
pglob->gl_pathv = NULL;
|
||||
}
|
||||
return(GLOB_NOSPACE);
|
||||
}
|
||||
|
||||
if (pglob->gl_pathv == NULL && pglob->gl_offs > 0) {
|
||||
/* first time around -- clear initial gl_offs items */
|
||||
pathv += pglob->gl_offs;
|
||||
for (i = pglob->gl_offs; --i >= 0; )
|
||||
*--pathv = NULL;
|
||||
}
|
||||
pglob->gl_pathv = pathv;
|
||||
|
||||
for (p = path; *p++;)
|
||||
continue;
|
||||
len = (size_t)(p - path);
|
||||
if ((copy = malloc(len)) != NULL) {
|
||||
if (g_Ctoc(path, copy, len)) {
|
||||
free(copy);
|
||||
return(GLOB_NOSPACE);
|
||||
}
|
||||
pathv[pglob->gl_offs + pglob->gl_pathc++] = copy;
|
||||
}
|
||||
pathv[pglob->gl_offs + pglob->gl_pathc] = NULL;
|
||||
|
||||
return(copy == NULL ? GLOB_NOSPACE : 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* pattern matching function for filenames. Each occurrence of the *
|
||||
* pattern causes a recursion level.
|
||||
*/
|
||||
static int
|
||||
match(name, pat, patend)
|
||||
Char *name, *pat, *patend;
|
||||
{
|
||||
int ok, negate_range;
|
||||
Char c, k;
|
||||
|
||||
while (pat < patend) {
|
||||
c = *pat++;
|
||||
switch (c & M_MASK) {
|
||||
case M_ALL:
|
||||
if (pat == patend)
|
||||
return(1);
|
||||
do {
|
||||
if (match(name, pat, patend))
|
||||
return(1);
|
||||
} while (*name++ != EOS);
|
||||
return(0);
|
||||
case M_ONE:
|
||||
if (*name++ == EOS)
|
||||
return(0);
|
||||
break;
|
||||
case M_SET:
|
||||
ok = 0;
|
||||
if ((k = *name++) == EOS)
|
||||
return(0);
|
||||
if ((negate_range = ((*pat & M_MASK) == M_NOT)) != EOS)
|
||||
++pat;
|
||||
while (((c = *pat++) & M_MASK) != M_END) {
|
||||
if ((c & M_MASK) == M_CLASS) {
|
||||
int idx = *pat & M_MASK;
|
||||
if (idx < NCCLASSES &&
|
||||
cclasses[idx].isctype(k))
|
||||
ok = 1;
|
||||
++pat;
|
||||
}
|
||||
if ((*pat & M_MASK) == M_RNG) {
|
||||
if (c <= k && k <= pat[1])
|
||||
ok = 1;
|
||||
pat += 2;
|
||||
} else if (c == k)
|
||||
ok = 1;
|
||||
}
|
||||
if (ok == negate_range)
|
||||
return(0);
|
||||
break;
|
||||
default:
|
||||
if (*name++ != c)
|
||||
return(0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return(*name == EOS);
|
||||
}
|
||||
|
||||
/* Free allocated data belonging to a glob_t structure. */
|
||||
void
|
||||
globfree(pglob)
|
||||
glob_t *pglob;
|
||||
{
|
||||
int i;
|
||||
char **pp;
|
||||
|
||||
if (pglob->gl_pathv != NULL) {
|
||||
pp = pglob->gl_pathv + pglob->gl_offs;
|
||||
for (i = pglob->gl_pathc; i--; ++pp)
|
||||
if (*pp)
|
||||
free(*pp);
|
||||
free(pglob->gl_pathv);
|
||||
pglob->gl_pathv = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static DIR *
|
||||
g_opendir(str, pglob)
|
||||
Char *str;
|
||||
glob_t *pglob;
|
||||
{
|
||||
char buf[PATH_MAX];
|
||||
|
||||
if (!*str) {
|
||||
buf[0] = '.';
|
||||
buf[1] = '\0';
|
||||
} else {
|
||||
if (g_Ctoc(str, buf, sizeof(buf)))
|
||||
return(NULL);
|
||||
}
|
||||
return(opendir(buf));
|
||||
}
|
||||
|
||||
static int
|
||||
g_lstat(fn, sb, pglob)
|
||||
Char *fn;
|
||||
struct stat *sb;
|
||||
glob_t *pglob;
|
||||
{
|
||||
char buf[PATH_MAX];
|
||||
|
||||
if (g_Ctoc(fn, buf, sizeof(buf)))
|
||||
return(-1);
|
||||
return(lstat(buf, sb));
|
||||
}
|
||||
|
||||
static int
|
||||
g_stat(fn, sb, pglob)
|
||||
Char *fn;
|
||||
struct stat *sb;
|
||||
glob_t *pglob;
|
||||
{
|
||||
char buf[PATH_MAX];
|
||||
|
||||
if (g_Ctoc(fn, buf, sizeof(buf)))
|
||||
return(-1);
|
||||
return(stat(buf, sb));
|
||||
}
|
||||
|
||||
static Char *
|
||||
g_strchr(str, ch)
|
||||
const Char *str;
|
||||
int ch;
|
||||
{
|
||||
do {
|
||||
if (*str == ch)
|
||||
return ((Char *)str);
|
||||
} while (*str++);
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
static int
|
||||
g_Ctoc(str, buf, len)
|
||||
const Char *str;
|
||||
char *buf;
|
||||
unsigned int len;
|
||||
{
|
||||
|
||||
while (len--) {
|
||||
if ((*buf++ = *str++) == EOS)
|
||||
return (0);
|
||||
}
|
||||
return (1);
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
static void
|
||||
qprintf(str, s)
|
||||
const char *str;
|
||||
Char *s;
|
||||
{
|
||||
Char *p;
|
||||
|
||||
(void)printf("%s:\n", str);
|
||||
for (p = s; *p; p++)
|
||||
(void)printf("%c", CHAR(*p));
|
||||
(void)printf("\n");
|
||||
for (p = s; *p; p++)
|
||||
(void)printf("%c", *p & M_PROTECT ? '"' : ' ');
|
||||
(void)printf("\n");
|
||||
for (p = s; *p; p++)
|
||||
(void)printf("%c", ismeta(*p) ? '_' : ' ');
|
||||
(void)printf("\n");
|
||||
}
|
||||
#endif
|
84
compat/glob.h
Normal file
84
compat/glob.h
Normal file
@@ -0,0 +1,84 @@
|
||||
/* $OpenBSD: glob.h,v 1.8 2003/06/02 19:34:12 millert Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 1989, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* This code is derived from software contributed to Berkeley by
|
||||
* Guido van Rossum.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* @(#)glob.h 8.1 (Berkeley) 6/2/93
|
||||
*/
|
||||
|
||||
#ifndef _GLOB_H_
|
||||
#define _GLOB_H_
|
||||
|
||||
struct stat;
|
||||
typedef struct {
|
||||
int gl_pathc; /* Count of total paths so far. */
|
||||
int gl_matchc; /* Count of paths matching pattern. */
|
||||
int gl_offs; /* Reserved at beginning of gl_pathv. */
|
||||
int gl_flags; /* Copy of flags parameter to glob. */
|
||||
char **gl_pathv; /* List of paths matching pattern. */
|
||||
/* Copy of errfunc parameter to glob. */
|
||||
#ifdef __STDC__
|
||||
int (*gl_errfunc)(const char *, int);
|
||||
#else
|
||||
int (*gl_errfunc)();
|
||||
#endif
|
||||
} glob_t;
|
||||
|
||||
/* Flags */
|
||||
#define GLOB_APPEND 0x0001 /* Append to output from previous call. */
|
||||
#define GLOB_DOOFFS 0x0002 /* Use gl_offs. */
|
||||
#define GLOB_ERR 0x0004 /* Return on error. */
|
||||
#define GLOB_MARK 0x0008 /* Append / to matching directories. */
|
||||
#define GLOB_NOCHECK 0x0010 /* Return pattern itself if nothing matches. */
|
||||
#define GLOB_NOSORT 0x0020 /* Don't sort. */
|
||||
#define GLOB_NOESCAPE 0x0040 /* Disable backslash escaping. */
|
||||
|
||||
/* Non-POSIX extensions */
|
||||
#define GLOB_MAGCHAR 0x0080 /* Pattern had globbing characters. */
|
||||
#define GLOB_BRACE 0x0100 /* Expand braces ala csh. */
|
||||
#define GLOB_TILDE 0x0200 /* Expand tilde names from the passwd file. */
|
||||
|
||||
/* Error values returned by glob(3) */
|
||||
#define GLOB_NOSPACE (-1) /* Malloc call failed. */
|
||||
#define GLOB_ABORTED (-2) /* Unignored error. */
|
||||
#define GLOB_NOMATCH (-3) /* No match and GLOB_NOCHECK not set. */
|
||||
#define GLOB_NOSYS (-4) /* Function not supported. */
|
||||
#define GLOB_ABEND GLOB_ABORTED
|
||||
|
||||
#ifdef __STDC__
|
||||
int glob(const char *, int, int (*)(const char *, int), glob_t *);
|
||||
void globfree(glob_t *);
|
||||
#else
|
||||
int glob();
|
||||
void globfree();
|
||||
#endif
|
||||
|
||||
#endif /* !_GLOB_H_ */
|
26
compat/isblank.c
Normal file
26
compat/isblank.c
Normal file
@@ -0,0 +1,26 @@
|
||||
/*
|
||||
* Copyright (c) 2008 Todd C. Miller <Todd.Miller@courtesan.com>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
#include <compat.h>
|
||||
|
||||
#undef isblank
|
||||
int
|
||||
isblank(ch)
|
||||
int ch;
|
||||
{
|
||||
return(ch == ' ' || ch == '\t');
|
||||
}
|
44
compat/memrchr.c
Normal file
44
compat/memrchr.c
Normal file
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* Copyright (c) 2007 Todd C. Miller <Todd.Miller@courtesan.com>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <config.h>
|
||||
#include <compat.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <config.h>
|
||||
|
||||
/*
|
||||
* Reverse memchr()
|
||||
* Find the last occurrence of 'c' in the buffer 's' of size 'n'.
|
||||
*/
|
||||
void *
|
||||
memrchr(s, c, n)
|
||||
const void *s;
|
||||
int c;
|
||||
size_t n;
|
||||
{
|
||||
const unsigned char *cp;
|
||||
|
||||
if (n != 0) {
|
||||
cp = (unsigned char *)s + n;
|
||||
do {
|
||||
if (*(--cp) == (unsigned char)c)
|
||||
return((void *)cp);
|
||||
} while (--n != 0);
|
||||
}
|
||||
return((void *)0);
|
||||
}
|
112
compat/mkstemp.c
Normal file
112
compat/mkstemp.c
Normal file
@@ -0,0 +1,112 @@
|
||||
/*
|
||||
* Copyright (c) 2001, 2003, 2008 Todd C. Miller <Todd.Miller@courtesan.com>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdio.h>
|
||||
#ifdef HAVE_STDLIB_H
|
||||
# include <stdlib.h>
|
||||
#endif /* HAVE_STDLIB_H */
|
||||
#include <ctype.h>
|
||||
#ifdef HAVE_UNISTD_H
|
||||
# include <unistd.h>
|
||||
#endif /* HAVE_UNISTD_H */
|
||||
|
||||
#include "sudo.h"
|
||||
|
||||
static unsigned int get_random __P((void));
|
||||
static void seed_random __P((void));
|
||||
|
||||
int
|
||||
mkstemp(path)
|
||||
char *path;
|
||||
{
|
||||
char *start, *cp;
|
||||
int fd, r;
|
||||
char *alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
|
||||
|
||||
if (*path == '\0') {
|
||||
errno = EINVAL;
|
||||
return(0);
|
||||
}
|
||||
|
||||
for (cp = path; *cp; cp++)
|
||||
;
|
||||
do {
|
||||
cp--;
|
||||
} while (cp >= path && *cp == 'X');
|
||||
start = cp + 1;
|
||||
|
||||
for (;;) {
|
||||
for (cp = start; *cp; cp++) {
|
||||
r = get_random % (26 + 26);
|
||||
*cp = alphabet[r];
|
||||
}
|
||||
|
||||
fd = open(path, O_CREAT|O_EXCL|O_RDWR, S_IRUSR|S_IWUSR);
|
||||
if (fd != -1 || errno != EEXIST)
|
||||
return(fd);
|
||||
}
|
||||
/*NOTREACHED*/
|
||||
}
|
||||
|
||||
#ifdef HAVE_RANDOM
|
||||
# define RAND random
|
||||
# define SRAND srandom
|
||||
# define SEED_T unsigned int
|
||||
#else
|
||||
# ifdef HAVE_LRAND48
|
||||
# define RAND lrand48
|
||||
# define SRAND srand48
|
||||
# define SEED_T long
|
||||
# else
|
||||
# define RAND rand
|
||||
# define SRAND srand
|
||||
# define SEED_T unsigned int
|
||||
# endif
|
||||
#endif
|
||||
|
||||
static void
|
||||
seed_random()
|
||||
{
|
||||
SEED_T seed;
|
||||
struct timespec ts;
|
||||
|
||||
/*
|
||||
* Seed from time of day and process id multiplied by small primes.
|
||||
*/
|
||||
(void) gettime(&ts);
|
||||
seed = (ts.tv_sec % 10000) * 523 + ts.tv_nsec / 1000 * 13 +
|
||||
(getpid() % 1000) * 983;
|
||||
SRAND(seed);
|
||||
}
|
||||
|
||||
static unsigned int
|
||||
get_random()
|
||||
{
|
||||
static int initialized;
|
||||
|
||||
if (!initialized) {
|
||||
seed_random();
|
||||
initialized = 1;
|
||||
}
|
||||
|
||||
return(RAND() & 0xffffffff);
|
||||
}
|
56
compat/nanosleep.c
Normal file
56
compat/nanosleep.c
Normal file
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
* Copyright (c) 2009 Todd C. Miller <Todd.Miller@courtesan.com>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/time.h>
|
||||
#ifdef HAVE_SYS_SELECT_H
|
||||
#include <sys/select.h>
|
||||
#endif /* HAVE_SYS_SELECT_H */
|
||||
#if TIME_WITH_SYS_TIME
|
||||
# include <time.h>
|
||||
#endif
|
||||
#ifndef HAVE_TIMESPEC
|
||||
# include <emul/timespec.h>
|
||||
#endif
|
||||
#include <errno.h>
|
||||
|
||||
#include "compat.h"
|
||||
|
||||
int
|
||||
nanosleep(ts, rts)
|
||||
const struct timespec *ts;
|
||||
struct timespec *rts;
|
||||
{
|
||||
struct timeval timeout, endtime, now;
|
||||
int rval;
|
||||
|
||||
timeout.tv_sec = ts->tv_sec;
|
||||
timeout.tv_usec = ts->tv_nsec / 1000;
|
||||
if (rts != NULL) {
|
||||
gettimeofday(&endtime, NULL);
|
||||
timeradd(&endtime, &timeout, &endtime);
|
||||
}
|
||||
rval = select(0, NULL, NULL, NULL, &timeout);
|
||||
if (rts != NULL && rval == -1 && errno == EINTR) {
|
||||
gettimeofday(&now, NULL);
|
||||
timersub(&endtime, &now, &timeout);
|
||||
rts->tv_sec = timeout.tv_sec;
|
||||
rts->tv_nsec = timeout.tv_usec * 1000;
|
||||
}
|
||||
return(rval);
|
||||
}
|
137
compat/sigaction.c
Normal file
137
compat/sigaction.c
Normal file
@@ -0,0 +1,137 @@
|
||||
/*
|
||||
* Copyright (c) 2001-2005 Todd C. Miller <Todd.Miller@courtesan.com>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*
|
||||
* Sponsored in part by the Defense Advanced Research Projects
|
||||
* Agency (DARPA) and Air Force Research Laboratory, Air Force
|
||||
* Materiel Command, USAF, under agreement number F39502-99-1-0512.
|
||||
*/
|
||||
|
||||
#include <signal.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <compat.h>
|
||||
|
||||
int
|
||||
sigaction(signo, sa, osa)
|
||||
int signo;
|
||||
const sigaction_t *sa;
|
||||
sigaction_t *osa;
|
||||
{
|
||||
sigaction_t nsa;
|
||||
int error;
|
||||
|
||||
/* We must reverse SV_INTERRUPT since it is the opposite of SA_RESTART */
|
||||
if (sa) {
|
||||
nsa = *sa;
|
||||
nsa.sa_flags ^= SV_INTERRUPT;
|
||||
sa = &nsa;
|
||||
}
|
||||
|
||||
error = sigvec(signo, sa, osa);
|
||||
if (!error && osa)
|
||||
osa->sa_flags ^= SV_INTERRUPT; /* flip SV_INTERRUPT as above */
|
||||
|
||||
return(error);
|
||||
}
|
||||
|
||||
int
|
||||
sigemptyset(set)
|
||||
sigset_t *set;
|
||||
{
|
||||
|
||||
*set = 0;
|
||||
return(0);
|
||||
}
|
||||
|
||||
int
|
||||
sigfillset(set)
|
||||
sigset_t *set;
|
||||
{
|
||||
|
||||
*set = ~0;;
|
||||
return(0);
|
||||
}
|
||||
|
||||
int
|
||||
sigaddset(set, signo)
|
||||
sigset_t *set;
|
||||
int signo;
|
||||
{
|
||||
|
||||
if (signo <= 0 || signo >= NSIG) {
|
||||
errno = EINVAL;
|
||||
return(-1);
|
||||
}
|
||||
|
||||
SET(*set, sigmask(signo));
|
||||
return(0);
|
||||
}
|
||||
|
||||
int
|
||||
sigdelset(set, signo)
|
||||
sigset_t *set;
|
||||
int signo;
|
||||
{
|
||||
|
||||
if (signo <= 0 || signo >= NSIG) {
|
||||
errno = EINVAL;
|
||||
return(-1);
|
||||
}
|
||||
|
||||
CLR(*set, sigmask(signo));
|
||||
return(0);
|
||||
}
|
||||
|
||||
int
|
||||
sigismember(set, signo)
|
||||
sigset_t *set;
|
||||
int signo;
|
||||
{
|
||||
|
||||
return(ISSET(*set, sigmask(signo)));
|
||||
}
|
||||
|
||||
int
|
||||
sigprocmask(how, set, oset)
|
||||
int how;
|
||||
const sigset_t *set;
|
||||
sigset_t *oset;
|
||||
{
|
||||
int mask;
|
||||
|
||||
/* If 'set' is NULL the user just wants the current signal mask. */
|
||||
if (set == 0)
|
||||
mask = sigblock(0);
|
||||
else
|
||||
switch (how) {
|
||||
case SIG_BLOCK:
|
||||
mask = sigblock(*set);
|
||||
break;
|
||||
case SIG_UNBLOCK:
|
||||
mask = sigsetmask(~*set);
|
||||
break;
|
||||
case SIG_SETMASK:
|
||||
mask = sigsetmask(*set);
|
||||
break;
|
||||
default:
|
||||
return(-1);
|
||||
}
|
||||
|
||||
if (mask == -1)
|
||||
return(-1);
|
||||
if (oset)
|
||||
*oset = mask;
|
||||
return(0);
|
||||
}
|
774
compat/snprintf.c
Normal file
774
compat/snprintf.c
Normal file
@@ -0,0 +1,774 @@
|
||||
/*
|
||||
* Copyright (c) 1999-2005, 2008 Todd C. Miller <Todd.Miller@courtesan.com>
|
||||
* Copyright (c) 1990, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* This code is derived from software contributed to Berkeley by
|
||||
* Chris Torek.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* From: @(#)vfprintf.c 8.1 (Berkeley) 6/4/93
|
||||
*/
|
||||
|
||||
/*
|
||||
* v?snprintf/v?asprintf based on 4.4BSD stdio.
|
||||
* NOTE: does not support floating point.
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/param.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#ifdef STDC_HEADERS
|
||||
# include <stdlib.h>
|
||||
# include <stddef.h>
|
||||
#else
|
||||
# ifdef HAVE_STDLIB_H
|
||||
# include <stdlib.h>
|
||||
# endif
|
||||
#endif /* STDC_HEADERS */
|
||||
#ifdef HAVE_STDINT_H
|
||||
# include <stdint.h>
|
||||
#endif
|
||||
#ifdef HAVE_STRING_H
|
||||
# if defined(HAVE_MEMORY_H) && !defined(STDC_HEADERS)
|
||||
# include <memory.h>
|
||||
# endif
|
||||
# include <string.h>
|
||||
#else
|
||||
# ifdef HAVE_STRINGS_H
|
||||
# include <strings.h>
|
||||
# endif
|
||||
#endif /* HAVE_STRING_H */
|
||||
#if defined(HAVE_MALLOC_H) && !defined(STDC_HEADERS)
|
||||
# include <malloc.h>
|
||||
#endif /* HAVE_MALLOC_H && !STDC_HEADERS */
|
||||
#include <limits.h>
|
||||
|
||||
#ifdef __STDC__
|
||||
# include <stdarg.h>
|
||||
#else
|
||||
# include <varargs.h>
|
||||
#endif
|
||||
|
||||
#include <compat.h>
|
||||
|
||||
static int xxxprintf __P((char **, size_t, int, const char *, va_list));
|
||||
|
||||
/*
|
||||
* Some systems may not have these defined in <limits.h>
|
||||
*/
|
||||
#ifndef ULONG_MAX
|
||||
# define ULONG_MAX ((unsigned long)-1)
|
||||
#endif
|
||||
#ifndef LONG_MAX
|
||||
# define LONG_MAX (ULONG_MAX / 2)
|
||||
#endif
|
||||
#ifdef HAVE_LONG_LONG
|
||||
# ifndef ULLONG_MAX
|
||||
# ifdef UQUAD_MAX
|
||||
# define ULLONG_MAX UQUAD_MAX
|
||||
# else
|
||||
# define ULLONG_MAX ((unsigned long long)-1)
|
||||
# endif
|
||||
# endif
|
||||
# ifndef LLONG_MAX
|
||||
# ifdef QUAD_MAX
|
||||
# define LLONG_MAX QUAD_MAX
|
||||
# else
|
||||
# define LLONG_MAX (ULLONG_MAX / 2)
|
||||
# endif
|
||||
# endif
|
||||
#endif /* HAVE_LONG_LONG */
|
||||
|
||||
/*
|
||||
* Macros for converting digits to letters and vice versa
|
||||
*/
|
||||
#define to_digit(c) ((c) - '0')
|
||||
#define is_digit(c) ((unsigned int)to_digit(c) <= 9)
|
||||
#define to_char(n) ((n) + '0')
|
||||
|
||||
/*
|
||||
* Flags used during conversion.
|
||||
*/
|
||||
#define ALT 0x001 /* alternate form */
|
||||
#define HEXPREFIX 0x002 /* add 0x or 0X prefix */
|
||||
#define LADJUST 0x004 /* left adjustment */
|
||||
#define LONGDBL 0x008 /* long double; unimplemented */
|
||||
#define LONGINT 0x010 /* long integer */
|
||||
#define QUADINT 0x020 /* quad integer */
|
||||
#define SHORTINT 0x040 /* short integer */
|
||||
#define ZEROPAD 0x080 /* zero (as opposed to blank) pad */
|
||||
|
||||
#define BUF 68
|
||||
|
||||
#ifndef HAVE_MEMCHR
|
||||
void *
|
||||
memchr(s, c, n)
|
||||
const void *s;
|
||||
unsigned char c;
|
||||
size_t n;
|
||||
{
|
||||
if (n != 0) {
|
||||
const unsigned char *p = s;
|
||||
|
||||
do {
|
||||
if (*p++ == c)
|
||||
return ((void *)(p - 1));
|
||||
} while (--n != 0);
|
||||
}
|
||||
return (NULL);
|
||||
}
|
||||
#endif /* !HAVE_MEMCHR */
|
||||
|
||||
/*
|
||||
* Convert an unsigned long to ASCII for printf purposes, returning
|
||||
* a pointer to the first character of the string representation.
|
||||
* Octal numbers can be forced to have a leading zero; hex numbers
|
||||
* use the given digits.
|
||||
*/
|
||||
static char *
|
||||
__ultoa(val, endp, base, octzero, xdigs)
|
||||
unsigned long val;
|
||||
char *endp;
|
||||
int base, octzero;
|
||||
char *xdigs;
|
||||
{
|
||||
char *cp = endp;
|
||||
long sval;
|
||||
|
||||
/*
|
||||
* Handle the three cases separately, in the hope of getting
|
||||
* better/faster code.
|
||||
*/
|
||||
switch (base) {
|
||||
case 10:
|
||||
if (val < 10) { /* many numbers are 1 digit */
|
||||
*--cp = to_char(val);
|
||||
return (cp);
|
||||
}
|
||||
/*
|
||||
* On many machines, unsigned arithmetic is harder than
|
||||
* signed arithmetic, so we do at most one unsigned mod and
|
||||
* divide; this is sufficient to reduce the range of
|
||||
* the incoming value to where signed arithmetic works.
|
||||
*/
|
||||
if (val > LONG_MAX) {
|
||||
*--cp = to_char(val % 10);
|
||||
sval = val / 10;
|
||||
} else
|
||||
sval = val;
|
||||
do {
|
||||
*--cp = to_char(sval % 10);
|
||||
sval /= 10;
|
||||
} while (sval != 0);
|
||||
break;
|
||||
|
||||
case 8:
|
||||
do {
|
||||
*--cp = to_char(val & 7);
|
||||
val >>= 3;
|
||||
} while (val);
|
||||
if (octzero && *cp != '0')
|
||||
*--cp = '0';
|
||||
break;
|
||||
|
||||
case 16:
|
||||
do {
|
||||
*--cp = xdigs[val & 15];
|
||||
val >>= 4;
|
||||
} while (val);
|
||||
break;
|
||||
|
||||
default: /* oops */
|
||||
abort();
|
||||
}
|
||||
return (cp);
|
||||
}
|
||||
|
||||
/* Identical to __ultoa, but for quads. */
|
||||
#ifdef HAVE_LONG_LONG
|
||||
# ifdef LONG_IS_QUAD
|
||||
# define __uqtoa(v, e, b, o, x) __ultoa((unsigned long)(v), (e), (b), (o), (x))
|
||||
# else
|
||||
static char *
|
||||
__uqtoa(val, endp, base, octzero, xdigs)
|
||||
unsigned long long val;
|
||||
char *endp;
|
||||
int base, octzero;
|
||||
char *xdigs;
|
||||
{
|
||||
char *cp = endp;
|
||||
long long sval;
|
||||
|
||||
/* quick test for small values; __ultoa is typically much faster */
|
||||
/* (perhaps instead we should run until small, then call __ultoa?) */
|
||||
if (val <= (unsigned long long)ULONG_MAX)
|
||||
return (__ultoa((unsigned long)val, endp, base, octzero, xdigs));
|
||||
switch (base) {
|
||||
case 10:
|
||||
if (val < 10) {
|
||||
*--cp = to_char(val % 10);
|
||||
return (cp);
|
||||
}
|
||||
if (val > LLONG_MAX) {
|
||||
*--cp = to_char(val % 10);
|
||||
sval = val / 10;
|
||||
} else
|
||||
sval = val;
|
||||
do {
|
||||
*--cp = to_char(sval % 10);
|
||||
sval /= 10;
|
||||
} while (sval != 0);
|
||||
break;
|
||||
|
||||
case 8:
|
||||
do {
|
||||
*--cp = to_char(val & 7);
|
||||
val >>= 3;
|
||||
} while (val);
|
||||
if (octzero && *cp != '0')
|
||||
*--cp = '0';
|
||||
break;
|
||||
|
||||
case 16:
|
||||
do {
|
||||
*--cp = xdigs[val & 15];
|
||||
val >>= 4;
|
||||
} while (val);
|
||||
break;
|
||||
|
||||
default: /* oops */
|
||||
abort();
|
||||
}
|
||||
return (cp);
|
||||
}
|
||||
# endif /* !LONG_IS_QUAD */
|
||||
#endif /* HAVE_LONG_LONG */
|
||||
|
||||
/*
|
||||
* Actual printf innards.
|
||||
*/
|
||||
static int
|
||||
xxxprintf(strp, strsize, alloc, fmt0, ap)
|
||||
char **strp;
|
||||
size_t strsize;
|
||||
int alloc;
|
||||
const char *fmt0;
|
||||
va_list ap;
|
||||
{
|
||||
char *fmt; /* format string */
|
||||
int ch; /* character from fmt */
|
||||
int n; /* handy integer (short term usage) */
|
||||
char *cp; /* handy char pointer (short term usage) */
|
||||
int flags; /* flags as above */
|
||||
int ret; /* return value accumulator */
|
||||
int width; /* width from format (%8d), or 0 */
|
||||
int prec; /* precision from format (%.3d), or -1 */
|
||||
char sign; /* sign prefix (' ', '+', '-', or \0) */
|
||||
unsigned long ulval; /* integer arguments %[diouxX] */
|
||||
#ifdef HAVE_LONG_LONG
|
||||
unsigned long long uqval; /* %q (quad) integers */
|
||||
#endif
|
||||
int base; /* base for [diouxX] conversion */
|
||||
int dprec; /* a copy of prec if [diouxX], 0 otherwise */
|
||||
int fieldsz; /* field size expanded by sign, etc */
|
||||
int realsz; /* field size expanded by dprec */
|
||||
int size; /* size of converted field or string */
|
||||
char *xdigs; /* digits for [xX] conversion */
|
||||
char buf[BUF]; /* space for %c, %[diouxX], %[eEfgG] */
|
||||
char ox[2]; /* space for 0x hex-prefix */
|
||||
char *str; /* pointer to string to fill */
|
||||
char *estr; /* pointer to last char in str */
|
||||
|
||||
/*
|
||||
* Choose PADSIZE to trade efficiency vs. size. If larger printf
|
||||
* fields occur frequently, increase PADSIZE and make the initialisers
|
||||
* below longer.
|
||||
*/
|
||||
#define PADSIZE 16 /* pad chunk size */
|
||||
static char blanks[PADSIZE] =
|
||||
{' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' '};
|
||||
static char zeroes[PADSIZE] =
|
||||
{'0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0'};
|
||||
|
||||
/* Print chars to "str", (allocate as needed if alloc is set). */
|
||||
#define PRINT(ptr, len) do { \
|
||||
const char *p = ptr; \
|
||||
const char *endp = ptr + len; \
|
||||
while (p < endp && (str < estr || alloc)) { \
|
||||
if (alloc && str >= estr) { \
|
||||
char *t; \
|
||||
strsize = (strsize << 1) + 1; \
|
||||
if (!(t = (char *)realloc(*strp, strsize))) { \
|
||||
free(str); \
|
||||
*strp = NULL; \
|
||||
ret = -1; \
|
||||
goto done; \
|
||||
} \
|
||||
str = t + (str - *strp); \
|
||||
estr = t + strsize - 1; \
|
||||
*strp = t; \
|
||||
} \
|
||||
*str++ = *p++; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
/* BEWARE, PAD uses `n'. */
|
||||
#define PAD(howmany, with) do { \
|
||||
if ((n = (howmany)) > 0) { \
|
||||
while (n > PADSIZE) { \
|
||||
PRINT(with, PADSIZE); \
|
||||
n -= PADSIZE; \
|
||||
} \
|
||||
PRINT(with, n); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
/*
|
||||
* To extend shorts properly, we need both signed and unsigned
|
||||
* argument extraction methods.
|
||||
*/
|
||||
#define SARG() \
|
||||
(flags&LONGINT ? va_arg(ap, long) : \
|
||||
flags&SHORTINT ? (long)(short)va_arg(ap, int) : \
|
||||
(long)va_arg(ap, int))
|
||||
#define UARG() \
|
||||
(flags&LONGINT ? va_arg(ap, unsigned long) : \
|
||||
flags&SHORTINT ? (unsigned long)(unsigned short)va_arg(ap, int) : \
|
||||
(unsigned long)va_arg(ap, unsigned int))
|
||||
|
||||
fmt = (char *)fmt0;
|
||||
ret = 0;
|
||||
|
||||
if (alloc) {
|
||||
strsize = 128;
|
||||
*strp = str = (char *)malloc(strsize);
|
||||
if (str == NULL) {
|
||||
ret = -1;
|
||||
goto done;
|
||||
}
|
||||
estr = str + 127;
|
||||
} else {
|
||||
str = *strp;
|
||||
if (strsize)
|
||||
estr = str + strsize - 1;
|
||||
else
|
||||
estr = NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Scan the format for conversions (`%' character).
|
||||
*/
|
||||
for (;;) {
|
||||
for (cp = fmt; (ch = *fmt) != '\0' && ch != '%'; fmt++)
|
||||
/* void */;
|
||||
if ((n = fmt - cp) != 0) {
|
||||
PRINT(cp, n);
|
||||
ret += n;
|
||||
}
|
||||
if (ch == '\0')
|
||||
goto done;
|
||||
fmt++; /* skip over '%' */
|
||||
|
||||
flags = 0;
|
||||
dprec = 0;
|
||||
width = 0;
|
||||
prec = -1;
|
||||
sign = '\0';
|
||||
|
||||
rflag: ch = *fmt++;
|
||||
reswitch: switch (ch) {
|
||||
case ' ':
|
||||
/*
|
||||
* ``If the space and + flags both appear, the space
|
||||
* flag will be ignored.''
|
||||
* -- ANSI X3J11
|
||||
*/
|
||||
if (!sign)
|
||||
sign = ' ';
|
||||
goto rflag;
|
||||
case '#':
|
||||
flags |= ALT;
|
||||
goto rflag;
|
||||
case '*':
|
||||
/*
|
||||
* ``A negative field width argument is taken as a
|
||||
* - flag followed by a positive field width.''
|
||||
* -- ANSI X3J11
|
||||
* They don't exclude field widths read from args.
|
||||
*/
|
||||
if ((width = va_arg(ap, int)) >= 0)
|
||||
goto rflag;
|
||||
width = -width;
|
||||
/* FALLTHROUGH */
|
||||
case '-':
|
||||
flags |= LADJUST;
|
||||
goto rflag;
|
||||
case '+':
|
||||
sign = '+';
|
||||
goto rflag;
|
||||
case '.':
|
||||
if ((ch = *fmt++) == '*') {
|
||||
n = va_arg(ap, int);
|
||||
prec = n < 0 ? -1 : n;
|
||||
goto rflag;
|
||||
}
|
||||
n = 0;
|
||||
while (is_digit(ch)) {
|
||||
n = 10 * n + to_digit(ch);
|
||||
ch = *fmt++;
|
||||
}
|
||||
prec = n < 0 ? -1 : n;
|
||||
goto reswitch;
|
||||
case '0':
|
||||
/*
|
||||
* ``Note that 0 is taken as a flag, not as the
|
||||
* beginning of a field width.''
|
||||
* -- ANSI X3J11
|
||||
*/
|
||||
flags |= ZEROPAD;
|
||||
goto rflag;
|
||||
case '1': case '2': case '3': case '4':
|
||||
case '5': case '6': case '7': case '8': case '9':
|
||||
n = 0;
|
||||
do {
|
||||
n = 10 * n + to_digit(ch);
|
||||
ch = *fmt++;
|
||||
} while (is_digit(ch));
|
||||
width = n;
|
||||
goto reswitch;
|
||||
case 'h':
|
||||
flags |= SHORTINT;
|
||||
goto rflag;
|
||||
case 'l':
|
||||
flags |= LONGINT;
|
||||
goto rflag;
|
||||
#ifdef HAVE_LONG_LONG
|
||||
case 'q':
|
||||
flags |= QUADINT;
|
||||
goto rflag;
|
||||
#endif /* HAVE_LONG_LONG */
|
||||
case 'c':
|
||||
*(cp = buf) = va_arg(ap, int);
|
||||
size = 1;
|
||||
sign = '\0';
|
||||
break;
|
||||
case 'D':
|
||||
flags |= LONGINT;
|
||||
/*FALLTHROUGH*/
|
||||
case 'd':
|
||||
case 'i':
|
||||
#ifdef HAVE_LONG_LONG
|
||||
if (flags & QUADINT) {
|
||||
uqval = va_arg(ap, long long);
|
||||
if ((long long)uqval < 0) {
|
||||
uqval = -uqval;
|
||||
sign = '-';
|
||||
}
|
||||
}
|
||||
else
|
||||
#endif /* HAVE_LONG_LONG */
|
||||
{
|
||||
ulval = SARG();
|
||||
if ((long)ulval < 0) {
|
||||
ulval = -ulval;
|
||||
sign = '-';
|
||||
}
|
||||
}
|
||||
base = 10;
|
||||
goto number;
|
||||
case 'n':
|
||||
#ifdef HAVE_LONG_LONG
|
||||
if (flags & QUADINT)
|
||||
*va_arg(ap, long long *) = ret;
|
||||
else
|
||||
#endif /* HAVE_LONG_LONG */
|
||||
if (flags & LONGINT)
|
||||
*va_arg(ap, long *) = ret;
|
||||
else if (flags & SHORTINT)
|
||||
*va_arg(ap, short *) = ret;
|
||||
else
|
||||
*va_arg(ap, int *) = ret;
|
||||
continue; /* no output */
|
||||
case 'O':
|
||||
flags |= LONGINT;
|
||||
/*FALLTHROUGH*/
|
||||
case 'o':
|
||||
#ifdef HAVE_LONG_LONG
|
||||
if (flags & QUADINT)
|
||||
uqval = va_arg(ap, unsigned long long);
|
||||
else
|
||||
#endif /* HAVE_LONG_LONG */
|
||||
ulval = UARG();
|
||||
base = 8;
|
||||
goto nosign;
|
||||
case 'p':
|
||||
/*
|
||||
* ``The argument shall be a pointer to void. The
|
||||
* value of the pointer is converted to a sequence
|
||||
* of printable characters, in an implementation-
|
||||
* defined manner.''
|
||||
* -- ANSI X3J11
|
||||
*/
|
||||
ulval = (unsigned long)va_arg(ap, void *);
|
||||
base = 16;
|
||||
xdigs = "0123456789abcdef";
|
||||
flags = (flags & ~QUADINT) | HEXPREFIX;
|
||||
ch = 'x';
|
||||
goto nosign;
|
||||
case 's':
|
||||
if ((cp = va_arg(ap, char *)) == NULL)
|
||||
cp = "(null)";
|
||||
if (prec >= 0) {
|
||||
/*
|
||||
* can't use strlen; can only look for the
|
||||
* NUL in the first `prec' characters, and
|
||||
* strlen() will go further.
|
||||
*/
|
||||
char *p = memchr(cp, 0, prec);
|
||||
|
||||
if (p != NULL) {
|
||||
size = p - cp;
|
||||
if (size > prec)
|
||||
size = prec;
|
||||
} else
|
||||
size = prec;
|
||||
} else
|
||||
size = strlen(cp);
|
||||
sign = '\0';
|
||||
break;
|
||||
case 'U':
|
||||
flags |= LONGINT;
|
||||
/*FALLTHROUGH*/
|
||||
case 'u':
|
||||
#ifdef HAVE_LONG_LONG
|
||||
if (flags & QUADINT)
|
||||
uqval = va_arg(ap, unsigned long long);
|
||||
else
|
||||
#endif /* HAVE_LONG_LONG */
|
||||
ulval = UARG();
|
||||
base = 10;
|
||||
goto nosign;
|
||||
case 'X':
|
||||
xdigs = "0123456789ABCDEF";
|
||||
goto hex;
|
||||
case 'x':
|
||||
xdigs = "0123456789abcdef";
|
||||
hex:
|
||||
#ifdef HAVE_LONG_LONG
|
||||
if (flags & QUADINT)
|
||||
uqval = va_arg(ap, unsigned long long);
|
||||
else
|
||||
#endif /* HAVE_LONG_LONG */
|
||||
ulval = UARG();
|
||||
base = 16;
|
||||
/* leading 0x/X only if non-zero */
|
||||
if (flags & ALT &&
|
||||
#ifdef HAVE_LONG_LONG
|
||||
(flags & QUADINT ? uqval != 0 : ulval != 0))
|
||||
#else
|
||||
ulval != 0)
|
||||
#endif /* HAVE_LONG_LONG */
|
||||
flags |= HEXPREFIX;
|
||||
|
||||
/* unsigned conversions */
|
||||
nosign: sign = '\0';
|
||||
/*
|
||||
* ``... diouXx conversions ... if a precision is
|
||||
* specified, the 0 flag will be ignored.''
|
||||
* -- ANSI X3J11
|
||||
*/
|
||||
number: if ((dprec = prec) >= 0)
|
||||
flags &= ~ZEROPAD;
|
||||
|
||||
/*
|
||||
* ``The result of converting a zero value with an
|
||||
* explicit precision of zero is no characters.''
|
||||
* -- ANSI X3J11
|
||||
*/
|
||||
cp = buf + BUF;
|
||||
#ifdef HAVE_LONG_LONG
|
||||
if (flags & QUADINT) {
|
||||
if (uqval != 0 || prec != 0)
|
||||
cp = __uqtoa(uqval, cp, base,
|
||||
flags & ALT, xdigs);
|
||||
}
|
||||
else
|
||||
#endif /* HAVE_LONG_LONG */
|
||||
{
|
||||
if (ulval != 0 || prec != 0)
|
||||
cp = __ultoa(ulval, cp, base,
|
||||
flags & ALT, xdigs);
|
||||
}
|
||||
size = buf + BUF - cp;
|
||||
break;
|
||||
default: /* "%?" prints ?, unless ? is NUL */
|
||||
if (ch == '\0')
|
||||
goto done;
|
||||
/* pretend it was %c with argument ch */
|
||||
cp = buf;
|
||||
*cp = ch;
|
||||
size = 1;
|
||||
sign = '\0';
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* All reasonable formats wind up here. At this point, `cp'
|
||||
* points to a string which (if not flags&LADJUST) should be
|
||||
* padded out to `width' places. If flags&ZEROPAD, it should
|
||||
* first be prefixed by any sign or other prefix; otherwise,
|
||||
* it should be blank padded before the prefix is emitted.
|
||||
* After any left-hand padding and prefixing, emit zeroes
|
||||
* required by a decimal [diouxX] precision, then print the
|
||||
* string proper, then emit zeroes required by any leftover
|
||||
* floating precision; finally, if LADJUST, pad with blanks.
|
||||
*
|
||||
* Compute actual size, so we know how much to pad.
|
||||
* fieldsz excludes decimal prec; realsz includes it.
|
||||
*/
|
||||
fieldsz = size;
|
||||
if (sign)
|
||||
fieldsz++;
|
||||
else if (flags & HEXPREFIX)
|
||||
fieldsz += 2;
|
||||
realsz = dprec > fieldsz ? dprec : fieldsz;
|
||||
|
||||
/* right-adjusting blank padding */
|
||||
if ((flags & (LADJUST|ZEROPAD)) == 0)
|
||||
PAD(width - realsz, blanks);
|
||||
|
||||
/* prefix */
|
||||
if (sign) {
|
||||
PRINT(&sign, 1);
|
||||
} else if (flags & HEXPREFIX) {
|
||||
ox[0] = '0';
|
||||
ox[1] = ch;
|
||||
PRINT(ox, 2);
|
||||
}
|
||||
|
||||
/* right-adjusting zero padding */
|
||||
if ((flags & (LADJUST|ZEROPAD)) == ZEROPAD)
|
||||
PAD(width - realsz, zeroes);
|
||||
|
||||
/* leading zeroes from decimal precision */
|
||||
PAD(dprec - fieldsz, zeroes);
|
||||
|
||||
/* the string or number proper */
|
||||
PRINT(cp, size);
|
||||
|
||||
/* left-adjusting padding (always blank) */
|
||||
if (flags & LADJUST)
|
||||
PAD(width - realsz, blanks);
|
||||
|
||||
/* finally, adjust ret */
|
||||
ret += width > realsz ? width : realsz;
|
||||
}
|
||||
done:
|
||||
if (strsize)
|
||||
*str = '\0';
|
||||
return (ret);
|
||||
/* NOTREACHED */
|
||||
}
|
||||
|
||||
#ifndef HAVE_VSNPRINTF
|
||||
int
|
||||
vsnprintf(str, n, fmt, ap)
|
||||
char *str;
|
||||
size_t n;
|
||||
const char *fmt;
|
||||
va_list ap;
|
||||
{
|
||||
|
||||
return (xxxprintf(&str, n, 0, fmt, ap));
|
||||
}
|
||||
#endif /* HAVE_VSNPRINTF */
|
||||
|
||||
#ifndef HAVE_SNPRINTF
|
||||
int
|
||||
#ifdef __STDC__
|
||||
snprintf(char *str, size_t n, char const *fmt, ...)
|
||||
#else
|
||||
snprintf(str, n, fmt, va_alist)
|
||||
char *str;
|
||||
size_t n;
|
||||
char const *fmt;
|
||||
va_dcl
|
||||
#endif
|
||||
{
|
||||
int ret;
|
||||
va_list ap;
|
||||
|
||||
#ifdef __STDC__
|
||||
va_start(ap, fmt);
|
||||
#else
|
||||
va_start(ap);
|
||||
#endif
|
||||
ret = xxxprintf(&str, n, 0, fmt, ap);
|
||||
va_end(ap);
|
||||
return (ret);
|
||||
}
|
||||
#endif /* HAVE_SNPRINTF */
|
||||
|
||||
#ifndef HAVE_VASPRINTF
|
||||
int
|
||||
vasprintf(str, fmt, ap)
|
||||
char **str;
|
||||
const char *fmt;
|
||||
va_list ap;
|
||||
{
|
||||
|
||||
return (xxxprintf(str, 0, 1, fmt, ap));
|
||||
}
|
||||
#endif /* HAVE_VASPRINTF */
|
||||
|
||||
#ifndef HAVE_ASPRINTF
|
||||
int
|
||||
#ifdef __STDC__
|
||||
asprintf(char **str, char const *fmt, ...)
|
||||
#else
|
||||
asprintf(str, fmt, va_alist)
|
||||
char **str;
|
||||
char const *fmt;
|
||||
va_dcl
|
||||
#endif
|
||||
{
|
||||
int ret;
|
||||
va_list ap;
|
||||
|
||||
#ifdef __STDC__
|
||||
va_start(ap, fmt);
|
||||
#else
|
||||
va_start(ap);
|
||||
#endif
|
||||
ret = xxxprintf(str, 0, 1, fmt, ap);
|
||||
va_end(ap);
|
||||
return (ret);
|
||||
}
|
||||
#endif /* HAVE_ASPRINTF */
|
91
compat/strcasecmp.c
Normal file
91
compat/strcasecmp.c
Normal file
@@ -0,0 +1,91 @@
|
||||
/*
|
||||
* Copyright (c) 2004-2005 Todd C. Miller <Todd.Miller@courtesan.com>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <config.h>
|
||||
#include <compat.h>
|
||||
|
||||
/*
|
||||
* Case insensitive string compare routines, same semantics as str[n]cmp()
|
||||
* (assumes ASCII..).
|
||||
* Derived from a public domain implementation included with the pdksh shell.
|
||||
*/
|
||||
static const char ichars[256] = {
|
||||
0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7,
|
||||
0x8, 0x9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf,
|
||||
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
|
||||
0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
|
||||
0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
|
||||
0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
|
||||
0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
|
||||
0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
|
||||
0x40, 'a', 'b', 'c', 'd', 'e', 'f', 'g',
|
||||
'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
|
||||
'p', 'q', 'r', 's', 't', 'u', 'v', 'w',
|
||||
'x', 'y', 'z', 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,
|
||||
0x60, 'a', 'b', 'c', 'd', 'e', 'f', 'g',
|
||||
'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
|
||||
'p', 'q', 'r', 's', 't', 'u', 'v', 'w',
|
||||
'x', 'y', 'z', 0x7b, 0x7c, 0x7d, 0x7e, 0x7f,
|
||||
0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
|
||||
0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
|
||||
0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
|
||||
0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
|
||||
0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
|
||||
0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,
|
||||
0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7,
|
||||
0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf,
|
||||
0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
|
||||
0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf,
|
||||
0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7,
|
||||
0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf,
|
||||
0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7,
|
||||
0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef,
|
||||
0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
|
||||
0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff
|
||||
};
|
||||
|
||||
int
|
||||
strcasecmp(s1, s2)
|
||||
const char *s1;
|
||||
const char *s2;
|
||||
{
|
||||
const unsigned char *us1 = (const unsigned char *) s1;
|
||||
const unsigned char *us2 = (const unsigned char *) s2;
|
||||
|
||||
while (ichars[*us1] == ichars[*us2++]) {
|
||||
if (*us1++ == '\0')
|
||||
return 0;
|
||||
}
|
||||
return ichars[*us1] - ichars[*--us2];
|
||||
}
|
||||
|
||||
int
|
||||
strncasecmp(s1, s2, n)
|
||||
const char *s1;
|
||||
const char *s2;
|
||||
size_t n;
|
||||
{
|
||||
const unsigned char *us1 = (const unsigned char *) s1;
|
||||
const unsigned char *us2 = (const unsigned char *) s2;
|
||||
|
||||
while (n != 0 && ichars[*us1] == ichars[*us2++]) {
|
||||
if (*us1++ == '\0')
|
||||
return 0;
|
||||
n--;
|
||||
}
|
||||
return n ? ichars[*us1] - ichars[*--us2] : 0;
|
||||
}
|
41
compat/strerror.c
Normal file
41
compat/strerror.c
Normal file
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* Copyright (c) 1999-2005 Todd C. Miller <Todd.Miller@courtesan.com>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*
|
||||
* Sponsored in part by the Defense Advanced Research Projects
|
||||
* Agency (DARPA) and Air Force Research Laboratory, Air Force
|
||||
* Materiel Command, USAF, under agreement number F39502-99-1-0512.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <config.h>
|
||||
#include <compat.h>
|
||||
|
||||
/*
|
||||
* Map errno -> error string.
|
||||
*/
|
||||
char *
|
||||
strerror(n)
|
||||
int n;
|
||||
{
|
||||
extern int sys_nerr;
|
||||
extern char *sys_errlist[];
|
||||
|
||||
if (n > 0 && n < sys_nerr)
|
||||
return(sys_errlist[n]);
|
||||
errno = EINVAL;
|
||||
return("Unknown error");
|
||||
}
|
62
compat/strlcat.c
Normal file
62
compat/strlcat.c
Normal file
@@ -0,0 +1,62 @@
|
||||
/* $OpenBSD: strlcat.c,v 1.8 2001/05/13 15:40:15 deraadt Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 1998, 2003-2005 Todd C. Miller <Todd.Miller@courtesan.com>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <config.h>
|
||||
#include <compat.h>
|
||||
|
||||
|
||||
/*
|
||||
* Appends src to string dst of size siz (unlike strncat, siz is the
|
||||
* full size of dst, not space left). At most siz-1 characters
|
||||
* will be copied. Always NUL terminates (unless siz <= strlen(dst)).
|
||||
* Returns strlen(src) + MIN(siz, strlen(initial dst)).
|
||||
* If retval >= siz, truncation occurred.
|
||||
*/
|
||||
size_t
|
||||
strlcat(dst, src, siz)
|
||||
char *dst;
|
||||
const char *src;
|
||||
size_t siz;
|
||||
{
|
||||
char *d = dst;
|
||||
const char *s = src;
|
||||
size_t n = siz;
|
||||
size_t dlen;
|
||||
|
||||
/* Find the end of dst and adjust bytes left but don't go past end */
|
||||
while (n-- != 0 && *d != '\0')
|
||||
d++;
|
||||
dlen = d - dst;
|
||||
n = siz - dlen;
|
||||
|
||||
if (n == 0)
|
||||
return(dlen + strlen(s));
|
||||
while (*s != '\0') {
|
||||
if (n != 1) {
|
||||
*d++ = *s;
|
||||
n--;
|
||||
}
|
||||
s++;
|
||||
}
|
||||
*d = '\0';
|
||||
|
||||
return(dlen + (s - src)); /* count does not include NUL */
|
||||
}
|
56
compat/strlcpy.c
Normal file
56
compat/strlcpy.c
Normal file
@@ -0,0 +1,56 @@
|
||||
/* $OpenBSD: strlcpy.c,v 1.5 2001/05/13 15:40:16 deraadt Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 1998, 2003-2005 Todd C. Miller <Todd.Miller@courtesan.com>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <config.h>
|
||||
#include <compat.h>
|
||||
|
||||
/*
|
||||
* Copy src to string dst of size siz. At most siz-1 characters
|
||||
* will be copied. Always NUL terminates (unless siz == 0).
|
||||
* Returns strlen(src); if retval >= siz, truncation occurred.
|
||||
*/
|
||||
size_t
|
||||
strlcpy(dst, src, siz)
|
||||
char *dst;
|
||||
const char *src;
|
||||
size_t siz;
|
||||
{
|
||||
char *d = dst;
|
||||
const char *s = src;
|
||||
size_t n = siz;
|
||||
|
||||
/* Copy as many bytes as will fit */
|
||||
if (n != 0 && --n != 0) {
|
||||
do {
|
||||
if ((*d++ = *s++) == 0)
|
||||
break;
|
||||
} while (--n != 0);
|
||||
}
|
||||
|
||||
/* Not enough room in dst, add NUL and traverse rest of src */
|
||||
if (n == 0) {
|
||||
if (siz != 0)
|
||||
*d = '\0'; /* NUL-terminate dst */
|
||||
while (*s++)
|
||||
;
|
||||
}
|
||||
|
||||
return(s - src - 1); /* count does not include NUL */
|
||||
}
|
35
compat/strsignal.c
Normal file
35
compat/strsignal.c
Normal file
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* Copyright (c) 2009 Todd C. Miller <Todd.Miller@courtesan.com>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <signal.h>
|
||||
|
||||
#include <config.h>
|
||||
#include <compat.h>
|
||||
|
||||
/*
|
||||
* Get signal description string
|
||||
*/
|
||||
char *
|
||||
strsignal(signo)
|
||||
int signo;
|
||||
{
|
||||
extern const char *const sys_siglist[];
|
||||
|
||||
if (signo > 0 && signo < NSIG)
|
||||
return((char *)sys_siglist[signo]);
|
||||
return("Unknown signal");
|
||||
}
|
25
compat/timespec.h
Normal file
25
compat/timespec.h
Normal file
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
* Copyright (c) 2005 Todd C. Miller <Todd.Miller@courtesan.com>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef _SUDO_TIMESPEC_H
|
||||
#define _SUDO_TIMESPEC_H
|
||||
|
||||
struct timespec {
|
||||
time_t tv_sec;
|
||||
long tv_nsec;
|
||||
};
|
||||
|
||||
#endif /* _SUDO_TIMESPEC_H */
|
31
compat/utime.h
Normal file
31
compat/utime.h
Normal file
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* Copyright (c) 1996, 1998-2005 Todd C. Miller <Todd.Miller@courtesan.com>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef _UTIME_H
|
||||
#define _UTIME_H
|
||||
|
||||
struct utimbuf {
|
||||
time_t actime; /* access time */
|
||||
time_t modtime; /* mod time */
|
||||
};
|
||||
|
||||
#ifdef __STDC__
|
||||
int utime(const char *, const struct utimbuf *);
|
||||
#else
|
||||
int utime();
|
||||
#endif
|
||||
|
||||
#endif /* _UTIME_H */
|
72
compat/utimes.c
Normal file
72
compat/utimes.c
Normal file
@@ -0,0 +1,72 @@
|
||||
/*
|
||||
* Copyright (c) 2004-2005, 2007 Todd C. Miller <Todd.Miller@courtesan.com>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/time.h>
|
||||
#include <stdio.h>
|
||||
#if TIME_WITH_SYS_TIME
|
||||
# include <time.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_UTIME_H
|
||||
# include <utime.h>
|
||||
#else
|
||||
# include <emul/utime.h>
|
||||
#endif
|
||||
|
||||
#include <compat.h>
|
||||
|
||||
#ifndef HAVE_UTIMES
|
||||
/*
|
||||
* Emulate utimes() via utime()
|
||||
*/
|
||||
int
|
||||
utimes(file, times)
|
||||
const char *file;
|
||||
const struct timeval *times;
|
||||
{
|
||||
if (times != NULL) {
|
||||
struct utimbuf utb;
|
||||
|
||||
utb.actime = (time_t)(times[0].tv_sec + times[0].tv_usec / 1000000);
|
||||
utb.modtime = (time_t)(times[1].tv_sec + times[1].tv_usec / 1000000);
|
||||
return(utime(file, &utb));
|
||||
} else
|
||||
return(utime(file, NULL));
|
||||
}
|
||||
#endif /* !HAVE_UTIMES */
|
||||
|
||||
#ifdef HAVE_FUTIME
|
||||
/*
|
||||
* Emulate futimes() via futime()
|
||||
*/
|
||||
int
|
||||
futimes(fd, times)
|
||||
int fd;
|
||||
const struct timeval *times;
|
||||
{
|
||||
if (times != NULL) {
|
||||
struct utimbuf utb;
|
||||
|
||||
utb.actime = (time_t)(times[0].tv_sec + times[0].tv_usec / 1000000);
|
||||
utb.modtime = (time_t)(times[1].tv_sec + times[1].tv_usec / 1000000);
|
||||
return(futime(fd, &utb));
|
||||
} else
|
||||
return(futime(fd, NULL));
|
||||
}
|
||||
#endif /* HAVE_FUTIME */
|
Reference in New Issue
Block a user