summaryrefslogtreecommitdiffstats
path: root/lib/libc
diff options
context:
space:
mode:
Diffstat (limited to 'lib/libc')
-rw-r--r--lib/libc/gen/glob.320
-rw-r--r--lib/libc/gen/glob.c528
-rw-r--r--lib/libc/sys/ptrace.2212
3 files changed, 528 insertions, 232 deletions
diff --git a/lib/libc/gen/glob.3 b/lib/libc/gen/glob.3
index 468a73b..398c14b 100644
--- a/lib/libc/gen/glob.3
+++ b/lib/libc/gen/glob.3
@@ -275,24 +275,10 @@ is
.Pf non- Dv NULL ,
.Fn glob
calls
-.Fa \*(lp*errfunc\*(rp Ns ( Fa path , errno ) .
-This may be unintuitive: a pattern like
-.Ql */Makefile
-will try to
-.Xr stat 2
-.Ql foo/Makefile
-even if
-.Ql foo
-is not a directory, resulting in a
-call to
-.Fa errfunc .
-The error routine can suppress this action by testing for
-.Er ENOENT
-and
-.Er ENOTDIR ;
+.Fa \*(lp*errfunc\*(rp Ns ( Fa path , errno ) ,
however, the
.Dv GLOB_ERR
-flag will still cause an immediate
+flag will cause an immediate
return when this happens.
.Pp
If
@@ -377,7 +363,7 @@ file
.It Dv GLOB_NOSPACE
An attempt to allocate memory failed, or if
.Fa errno
-was 0
+was E2BIG,
.Dv GLOB_LIMIT
was specified in the flags and
.Fa pglob\->gl_matchc
diff --git a/lib/libc/gen/glob.c b/lib/libc/gen/glob.c
index 6c86297..5df0b74 100644
--- a/lib/libc/gen/glob.c
+++ b/lib/libc/gen/glob.c
@@ -71,7 +71,7 @@ __FBSDID("$FreeBSD$");
* 1. Patterns with illegal byte sequences match nothing - even if
* GLOB_NOCHECK is specified.
* 2. Illegal byte sequences in filenames are handled by treating them as
- * single-byte characters with a value of the first byte of the sequence
+ * single-byte characters with a values of such bytes of the sequence
* cast to wchar_t.
* 3. State-dependent encodings are not currently supported.
*/
@@ -113,25 +113,20 @@ struct glob_limit {
size_t l_string_cnt;
};
-#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 DOT L'.'
+#define EOS L'\0'
+#define LBRACKET L'['
+#define NOT L'!'
+#define QUESTION L'?'
+#define QUOTE L'\\'
+#define RANGE L'-'
+#define RBRACKET L']'
+#define SEP L'/'
+#define STAR L'*'
+#define TILDE L'~'
+#define LBRACE L'{'
+#define RBRACE L'}'
+#define COMMA L','
#define M_QUOTE 0x8000000000ULL
#define M_PROTECT 0x4000000000ULL
@@ -140,28 +135,19 @@ struct glob_limit {
typedef uint_fast64_t Char;
-#else
-
-#define M_QUOTE 0x80
-#define M_PROTECT 0x40
-#define M_MASK 0xff
-#define M_CHAR 0x7f
-
-typedef char Char;
-
-#endif
-
-
#define CHAR(c) ((Char)((c)&M_CHAR))
#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 UNPROT(c) ((c) & ~M_PROTECT)
+#define M_ALL META(L'*')
+#define M_END META(L']')
+#define M_NOT META(L'!')
+#define M_ONE META(L'?')
+#define M_RNG META(L'-')
+#define M_SET META(L'[')
#define ismeta(c) (((c)&M_QUOTE) != 0)
-
+#ifdef DEBUG
+#define isprot(c) (((c)&M_PROTECT) != 0)
+#endif
static int compare(const void *, const void *);
static int g_Ctoc(const Char *, char *, size_t);
@@ -172,19 +158,27 @@ static const Char *g_strchr(const Char *, wchar_t);
static Char *g_strcat(Char *, const Char *);
#endif
static int g_stat(Char *, struct stat *, glob_t *);
-static int glob0(const Char *, glob_t *, struct glob_limit *);
+static int glob0(const Char *, glob_t *, struct glob_limit *,
+ const char *);
static int glob1(Char *, glob_t *, struct glob_limit *);
static int glob2(Char *, Char *, Char *, Char *, glob_t *,
struct glob_limit *);
static int glob3(Char *, Char *, Char *, Char *, Char *, glob_t *,
struct glob_limit *);
-static int globextend(const Char *, glob_t *, struct glob_limit *);
+static int globextend(const Char *, glob_t *, struct glob_limit *,
+ const char *);
static const Char *
globtilde(const Char *, Char *, size_t, glob_t *);
+static int globexp0(const Char *, glob_t *, struct glob_limit *,
+ const char *);
static int globexp1(const Char *, glob_t *, struct glob_limit *);
-static int globexp2(const Char *, const Char *, glob_t *, int *,
+static int globexp2(const Char *, const Char *, glob_t *,
struct glob_limit *);
+static int globfinal(glob_t *, struct glob_limit *, size_t,
+ const char *);
static int match(Char *, Char *, Char *);
+static int err_nomatch(glob_t *, struct glob_limit *, const char *);
+static int err_aborted(glob_t *, int, char *);
#ifdef DEBUG
static void qprintf(const char *, Char *);
#endif
@@ -199,6 +193,7 @@ glob(const char * __restrict pattern, int flags,
mbstate_t mbs;
wchar_t wc;
size_t clen;
+ int too_long;
patnext = pattern;
if (!(flags & GLOB_APPEND)) {
@@ -218,24 +213,27 @@ glob(const char * __restrict pattern, int flags,
bufnext = patbuf;
bufend = bufnext + MAXPATHLEN - 1;
+ too_long = 1;
if (flags & GLOB_NOESCAPE) {
memset(&mbs, 0, sizeof(mbs));
- while (bufend - bufnext >= MB_CUR_MAX) {
+ while (bufnext <= bufend) {
clen = mbrtowc(&wc, patnext, MB_LEN_MAX, &mbs);
if (clen == (size_t)-1 || clen == (size_t)-2)
- return (GLOB_NOMATCH);
- else if (clen == 0)
+ return (err_nomatch(pglob, &limit, pattern));
+ else if (clen == 0) {
+ too_long = 0;
break;
+ }
*bufnext++ = wc;
patnext += clen;
}
} else {
/* Protect the quoted characters. */
memset(&mbs, 0, sizeof(mbs));
- while (bufend - bufnext >= MB_CUR_MAX) {
- if (*patnext == QUOTE) {
- if (*++patnext == EOS) {
- *bufnext++ = QUOTE | M_PROTECT;
+ while (bufnext <= bufend) {
+ if (*patnext == '\\') {
+ if (*++patnext == '\0') {
+ *bufnext++ = QUOTE;
continue;
}
prot = M_PROTECT;
@@ -243,19 +241,47 @@ glob(const char * __restrict pattern, int flags,
prot = 0;
clen = mbrtowc(&wc, patnext, MB_LEN_MAX, &mbs);
if (clen == (size_t)-1 || clen == (size_t)-2)
- return (GLOB_NOMATCH);
- else if (clen == 0)
+ return (err_nomatch(pglob, &limit, pattern));
+ else if (clen == 0) {
+ too_long = 0;
break;
+ }
*bufnext++ = wc | prot;
patnext += clen;
}
}
+ if (too_long)
+ return (err_nomatch(pglob, &limit, pattern));
*bufnext = EOS;
if (flags & GLOB_BRACE)
- return (globexp1(patbuf, pglob, &limit));
+ return (globexp0(patbuf, pglob, &limit, pattern));
else
- return (glob0(patbuf, pglob, &limit));
+ return (glob0(patbuf, pglob, &limit, pattern));
+}
+
+static int
+globexp0(const Char *pattern, glob_t *pglob, struct glob_limit *limit,
+ const char *origpat) {
+ int rv;
+ size_t oldpathc;
+
+ /* Protect a single {}, for find(1), like csh */
+ if (pattern[0] == LBRACE && pattern[1] == RBRACE && pattern[2] == EOS) {
+ if ((pglob->gl_flags & GLOB_LIMIT) &&
+ limit->l_brace_cnt++ >= GLOB_LIMIT_BRACE) {
+ errno = E2BIG;
+ return (GLOB_NOSPACE);
+ }
+ return (glob0(pattern, pglob, limit, origpat));
+ }
+
+ oldpathc = pglob->gl_pathc;
+
+ if ((rv = globexp1(pattern, pglob, limit)) != 0)
+ return rv;
+
+ return (globfinal(pglob, limit, oldpathc, origpat));
}
/*
@@ -266,24 +292,18 @@ glob(const char * __restrict pattern, int flags,
static int
globexp1(const Char *pattern, glob_t *pglob, struct glob_limit *limit)
{
- const Char* ptr = pattern;
- int rv;
+ const Char* ptr;
- if ((pglob->gl_flags & GLOB_LIMIT) &&
- limit->l_brace_cnt++ >= GLOB_LIMIT_BRACE) {
- errno = 0;
- return (GLOB_NOSPACE);
+ if ((ptr = g_strchr(pattern, LBRACE)) != NULL) {
+ if ((pglob->gl_flags & GLOB_LIMIT) &&
+ limit->l_brace_cnt++ >= GLOB_LIMIT_BRACE) {
+ errno = E2BIG;
+ return (GLOB_NOSPACE);
+ }
+ return (globexp2(ptr, pattern, pglob, limit));
}
- /* Protect a single {}, for find(1), like csh */
- if (pattern[0] == LBRACE && pattern[1] == RBRACE && pattern[2] == EOS)
- return glob0(pattern, pglob, limit);
-
- while ((ptr = g_strchr(ptr, LBRACE)) != NULL)
- if (!globexp2(ptr, pattern, pglob, &rv, limit))
- return rv;
-
- return glob0(pattern, pglob, limit);
+ return (glob0(pattern, pglob, limit, NULL));
}
@@ -293,10 +313,10 @@ globexp1(const Char *pattern, glob_t *pglob, struct glob_limit *limit)
* If it fails then it tries to glob the rest of the pattern and returns.
*/
static int
-globexp2(const Char *ptr, const Char *pattern, glob_t *pglob, int *rv,
+globexp2(const Char *ptr, const Char *pattern, glob_t *pglob,
struct glob_limit *limit)
{
- int i;
+ int i, rv;
Char *lm, *ls;
const Char *pe, *pm, *pm1, *pl;
Char patbuf[MAXPATHLEN];
@@ -308,7 +328,7 @@ globexp2(const Char *ptr, const Char *pattern, glob_t *pglob, int *rv,
ls = lm;
/* Find the balanced brace */
- for (i = 0, pe = ++ptr; *pe; pe++)
+ for (i = 0, pe = ++ptr; *pe != EOS; pe++)
if (*pe == LBRACKET) {
/* Ignore everything between [] */
for (pm = pe++; *pe != RBRACKET && *pe != EOS; pe++)
@@ -330,10 +350,8 @@ globexp2(const Char *ptr, const Char *pattern, glob_t *pglob, int *rv,
}
/* Non matching braces; just glob the pattern */
- if (i != 0 || *pe == EOS) {
- *rv = glob0(patbuf, pglob, limit);
- return (0);
- }
+ if (i != 0 || *pe == EOS)
+ return (glob0(pattern, pglob, limit, NULL));
for (i = 0, pl = pm = ptr; pm <= pe; pm++)
switch (*pm) {
@@ -378,7 +396,9 @@ globexp2(const Char *ptr, const Char *pattern, glob_t *pglob, int *rv,
#ifdef DEBUG
qprintf("globexp2:", patbuf);
#endif
- *rv = globexp1(patbuf, pglob, limit);
+ rv = globexp1(patbuf, pglob, limit);
+ if (rv)
+ return (rv);
/* move after the comma, to the next string */
pl = pm + 1;
@@ -388,7 +408,6 @@ globexp2(const Char *ptr, const Char *pattern, glob_t *pglob, int *rv,
default:
break;
}
- *rv = 0;
return (0);
}
@@ -401,9 +420,15 @@ static const Char *
globtilde(const Char *pattern, Char *patbuf, size_t patbuf_len, glob_t *pglob)
{
struct passwd *pwd;
- char *h;
+ char *h, *sc;
const Char *p;
Char *b, *eb;
+ wchar_t wc;
+ wchar_t wbuf[MAXPATHLEN];
+ wchar_t *wbufend, *dc;
+ size_t clen;
+ mbstate_t mbs;
+ int too_long;
if (*pattern != TILDE || !(pglob->gl_flags & GLOB_TILDE))
return (pattern);
@@ -412,13 +437,17 @@ globtilde(const Char *pattern, Char *patbuf, size_t patbuf_len, glob_t *pglob)
* 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++)
+ for (p = pattern + 1, b = patbuf;
+ b < eb && *p != EOS && UNPROT(*p) != SEP; *b++ = *p++)
continue;
- *h = EOS;
+ if (*p != EOS && UNPROT(*p) != SEP)
+ return (NULL);
+
+ *b = EOS;
+ h = NULL;
- if (((char *) patbuf)[0] == EOS) {
+ if (patbuf[0] == EOS) {
/*
* handle a plain ~ or ~/ by expanding $HOME first (iff
* we're not running setuid or setgid) and then trying
@@ -438,20 +467,56 @@ globtilde(const Char *pattern, Char *patbuf, size_t patbuf_len, glob_t *pglob)
/*
* Expand a ~user
*/
- if ((pwd = getpwnam((char*) patbuf)) == NULL)
+ if (g_Ctoc(patbuf, (char *)wbuf, sizeof(wbuf)))
+ return (NULL);
+ if ((pwd = getpwnam((char *)wbuf)) == NULL)
return (pattern);
else
h = pwd->pw_dir;
}
/* Copy the home directory */
- for (b = patbuf; b < eb && *h; *b++ = *h++)
+ dc = wbuf;
+ sc = h;
+ wbufend = wbuf + MAXPATHLEN - 1;
+ too_long = 1;
+ memset(&mbs, 0, sizeof(mbs));
+ while (dc <= wbufend) {
+ clen = mbrtowc(&wc, sc, MB_LEN_MAX, &mbs);
+ if (clen == (size_t)-1 || clen == (size_t)-2) {
+ /* XXX See initial comment #2. */
+ wc = (unsigned char)*sc;
+ clen = 1;
+ memset(&mbs, 0, sizeof(mbs));
+ }
+ if ((*dc++ = wc) == EOS) {
+ too_long = 0;
+ break;
+ }
+ sc += clen;
+ }
+ if (too_long)
+ return (NULL);
+
+ dc = wbuf;
+ for (b = patbuf; b < eb && *dc != EOS; *b++ = *dc++ | M_PROTECT)
continue;
+ if (*dc != EOS)
+ return (NULL);
/* Append the rest of the pattern */
- while (b < eb && (*b++ = *p++) != EOS)
- continue;
- *b = EOS;
+ if (*p != EOS) {
+ too_long = 1;
+ while (b <= eb) {
+ if ((*b++ = *p++) == EOS) {
+ too_long = 0;
+ break;
+ }
+ }
+ if (too_long)
+ return (NULL);
+ } else
+ *b = EOS;
return (patbuf);
}
@@ -464,14 +529,18 @@ globtilde(const Char *pattern, Char *patbuf, size_t patbuf_len, glob_t *pglob)
* if things went well, nonzero if errors occurred.
*/
static int
-glob0(const Char *pattern, glob_t *pglob, struct glob_limit *limit)
-{
+glob0(const Char *pattern, glob_t *pglob, struct glob_limit *limit,
+ const char *origpat) {
const Char *qpatnext;
int err;
size_t oldpathc;
Char *bufnext, c, patbuf[MAXPATHLEN];
qpatnext = globtilde(pattern, patbuf, MAXPATHLEN, pglob);
+ if (qpatnext == NULL) {
+ errno = E2BIG;
+ return (GLOB_NOSPACE);
+ }
oldpathc = pglob->gl_pathc;
bufnext = patbuf;
@@ -530,30 +599,29 @@ glob0(const Char *pattern, glob_t *pglob, struct glob_limit *limit)
if ((err = glob1(patbuf, pglob, limit)) != 0)
return(err);
- /*
- * If there was no match we are going to append the pattern
- * if GLOB_NOCHECK was specified or if GLOB_NOMAGIC was specified
- * and the pattern did not contain any magic characters
- * GLOB_NOMAGIC is there just for compatibility with csh.
- */
- if (pglob->gl_pathc == oldpathc) {
- if (((pglob->gl_flags & GLOB_NOCHECK) ||
- ((pglob->gl_flags & GLOB_NOMAGIC) &&
- !(pglob->gl_flags & GLOB_MAGCHAR))))
- return (globextend(pattern, pglob, limit));
- else
- return (GLOB_NOMATCH);
- }
+ if (origpat != NULL)
+ return (globfinal(pglob, limit, oldpathc, origpat));
+
+ return (0);
+}
+
+static int
+globfinal(glob_t *pglob, struct glob_limit *limit, size_t oldpathc,
+ const char *origpat) {
+ if (pglob->gl_pathc == oldpathc)
+ return (err_nomatch(pglob, limit, origpat));
+
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(const void *p, const void *q)
{
- return (strcmp(*(char **)p, *(char **)q));
+ return (strcoll(*(char **)p, *(char **)q));
}
static int
@@ -593,44 +661,47 @@ glob2(Char *pathbuf, Char *pathend, Char *pathend_last, Char *pattern,
if ((pglob->gl_flags & GLOB_LIMIT) &&
limit->l_stat_cnt++ >= GLOB_LIMIT_STAT) {
- errno = 0;
- if (pathend + 1 > pathend_last)
- return (GLOB_ABORTED);
- *pathend++ = SEP;
- *pathend = EOS;
+ errno = E2BIG;
return (GLOB_NOSPACE);
}
- 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) &&
+ if ((pglob->gl_flags & GLOB_MARK) &&
+ UNPROT(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 (GLOB_ABORTED);
+ if (pathend + 1 > pathend_last) {
+ errno = E2BIG;
+ return (GLOB_NOSPACE);
+ }
*pathend++ = SEP;
*pathend = EOS;
}
++pglob->gl_matchc;
- return (globextend(pathbuf, pglob, limit));
+ return (globextend(pathbuf, pglob, limit, NULL));
}
/* Find end of next segment, copy tentatively to pathend. */
q = pathend;
p = pattern;
- while (*p != EOS && *p != SEP) {
+ while (*p != EOS && UNPROT(*p) != SEP) {
if (ismeta(*p))
anymeta = 1;
- if (q + 1 > pathend_last)
- return (GLOB_ABORTED);
+ if (q + 1 > pathend_last) {
+ errno = E2BIG;
+ return (GLOB_NOSPACE);
+ }
*q++ = *p++;
}
if (!anymeta) { /* No expansion, do next segment. */
pathend = q;
pattern = p;
- while (*pattern == SEP) {
- if (pathend + 1 > pathend_last)
- return (GLOB_ABORTED);
+ while (UNPROT(*pattern) == SEP) {
+ if (pathend + 1 > pathend_last) {
+ errno = E2BIG;
+ return (GLOB_NOSPACE);
+ }
*pathend++ = *pattern++;
}
} else /* Need expansion, recurse. */
@@ -647,42 +718,44 @@ glob3(Char *pathbuf, Char *pathend, Char *pathend_last,
{
struct dirent *dp;
DIR *dirp;
- int err;
- char buf[MAXPATHLEN];
+ int err, too_long, saverrno, saverrno2;
+ char buf[MAXPATHLEN + MB_LEN_MAX - 1];
- /*
- * The readdirfunc declaration can't be prototyped, because it is
- * assigned, below, to two functions which are prototyped in glob.h
- * and dirent.h as taking pointers to differently typed opaque
- * structures.
- */
- struct dirent *(*readdirfunc)();
+ struct dirent *(*readdirfunc)(DIR *);
- if (pathend > pathend_last)
- return (GLOB_ABORTED);
+ if (pathend > pathend_last) {
+ errno = E2BIG;
+ return (GLOB_NOSPACE);
+ }
*pathend = EOS;
- errno = 0;
+ if (pglob->gl_errfunc != NULL &&
+ g_Ctoc(pathbuf, buf, sizeof(buf))) {
+ errno = E2BIG;
+ return (GLOB_NOSPACE);
+ }
+ saverrno = errno;
+ 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);
+ if (errno == ENOENT || errno == ENOTDIR)
+ return (0);
+ err = err_aborted(pglob, errno, buf);
+ if (errno == 0)
+ errno = saverrno;
+ return (err);
}
err = 0;
- /* Search directory for matching names. */
+ /* pglob->gl_readdir takes a void *, fix this manually */
if (pglob->gl_flags & GLOB_ALTDIRFUNC)
- readdirfunc = pglob->gl_readdir;
+ readdirfunc = (struct dirent *(*)(DIR *))pglob->gl_readdir;
else
readdirfunc = readdir;
- while ((dp = (*readdirfunc)(dirp))) {
+
+ errno = 0;
+ /* Search directory for matching names. */
+ while ((dp = (*readdirfunc)(dirp)) != NULL) {
char *sc;
Char *dc;
wchar_t wc;
@@ -691,49 +764,70 @@ glob3(Char *pathbuf, Char *pathend, Char *pathend_last,
if ((pglob->gl_flags & GLOB_LIMIT) &&
limit->l_readdir_cnt++ >= GLOB_LIMIT_READDIR) {
- errno = 0;
- if (pathend + 1 > pathend_last)
- err = GLOB_ABORTED;
- else {
- *pathend++ = SEP;
- *pathend = EOS;
- err = GLOB_NOSPACE;
- }
+ errno = E2BIG;
+ err = GLOB_NOSPACE;
break;
}
/* Initial DOT must be matched literally. */
- if (dp->d_name[0] == DOT && *pattern != DOT)
+ if (dp->d_name[0] == '.' && UNPROT(*pattern) != DOT) {
+ errno = 0;
continue;
+ }
memset(&mbs, 0, sizeof(mbs));
dc = pathend;
sc = dp->d_name;
- while (dc < pathend_last) {
+ too_long = 1;
+ while (dc <= pathend_last) {
clen = mbrtowc(&wc, sc, MB_LEN_MAX, &mbs);
if (clen == (size_t)-1 || clen == (size_t)-2) {
- wc = *sc;
+ /* XXX See initial comment #2. */
+ wc = (unsigned char)*sc;
clen = 1;
memset(&mbs, 0, sizeof(mbs));
}
- if ((*dc++ = wc) == EOS)
+ if ((*dc++ = wc) == EOS) {
+ too_long = 0;
break;
+ }
sc += clen;
}
- if (!match(pathend, pattern, restpattern)) {
+ if (too_long && (err = err_aborted(pglob, ENAMETOOLONG,
+ buf))) {
+ errno = ENAMETOOLONG;
+ break;
+ }
+ if (too_long || !match(pathend, pattern, restpattern)) {
*pathend = EOS;
+ errno = 0;
continue;
}
+ if (errno == 0)
+ errno = saverrno;
err = glob2(pathbuf, --dc, pathend_last, restpattern,
pglob, limit);
if (err)
break;
+ errno = 0;
}
+ saverrno2 = errno;
if (pglob->gl_flags & GLOB_ALTDIRFUNC)
(*pglob->gl_closedir)(dirp);
else
closedir(dirp);
- return (err);
+ errno = saverrno2;
+
+ if (err)
+ return (err);
+
+ if (dp == NULL && errno != 0 &&
+ (err = err_aborted(pglob, errno, buf)))
+ return (err);
+
+ if (errno == 0)
+ errno = saverrno;
+ return (0);
}
@@ -752,7 +846,8 @@ glob3(Char *pathbuf, Char *pathend, Char *pathend_last,
* gl_pathv points to (gl_offs + gl_pathc + 1) items.
*/
static int
-globextend(const Char *path, glob_t *pglob, struct glob_limit *limit)
+globextend(const Char *path, glob_t *pglob, struct glob_limit *limit,
+ const char *origpat)
{
char **pathv;
size_t i, newsize, len;
@@ -761,7 +856,7 @@ globextend(const Char *path, glob_t *pglob, struct glob_limit *limit)
if ((pglob->gl_flags & GLOB_LIMIT) &&
pglob->gl_matchc > limit->l_path_lim) {
- errno = 0;
+ errno = E2BIG;
return (GLOB_NOSPACE);
}
@@ -779,18 +874,26 @@ globextend(const Char *path, glob_t *pglob, struct glob_limit *limit)
}
pglob->gl_pathv = pathv;
- for (p = path; *p++;)
- continue;
- len = MB_CUR_MAX * (size_t)(p - path); /* XXX overallocation */
- limit->l_string_cnt += len;
- if ((pglob->gl_flags & GLOB_LIMIT) &&
- limit->l_string_cnt >= GLOB_LIMIT_STRING) {
- errno = 0;
- return (GLOB_NOSPACE);
+ if (origpat != NULL)
+ copy = strdup(origpat);
+ else {
+ for (p = path; *p++ != EOS;)
+ continue;
+ len = MB_CUR_MAX * (size_t)(p - path); /* XXX overallocation */
+ if ((copy = malloc(len)) != NULL) {
+ if (g_Ctoc(path, copy, len)) {
+ free(copy);
+ errno = E2BIG;
+ return (GLOB_NOSPACE);
+ }
+ }
}
- if ((copy = malloc(len)) != NULL) {
- if (g_Ctoc(path, copy, len)) {
+ if (copy != NULL) {
+ limit->l_string_cnt += strlen(copy) + 1;
+ if ((pglob->gl_flags & GLOB_LIMIT) &&
+ limit->l_string_cnt >= GLOB_LIMIT_STRING) {
free(copy);
+ errno = E2BIG;
return (GLOB_NOSPACE);
}
pathv[pglob->gl_offs + pglob->gl_pathc++] = copy;
@@ -830,15 +933,17 @@ match(Char *name, Char *pat, Char *patend)
ok = 0;
if ((k = *name++) == EOS)
return (0);
- if ((negate_range = ((*pat & M_MASK) == M_NOT)) != EOS)
+ if ((negate_range = ((*pat & M_MASK) == M_NOT)) != 0)
++pat;
while (((c = *pat++) & M_MASK) != M_END)
if ((*pat & M_MASK) == M_RNG) {
if (table->__collate_load_error ?
- CHAR(c) <= CHAR(k) && CHAR(k) <= CHAR(pat[1]) :
- __wcollate_range_cmp(CHAR(c), CHAR(k)) <= 0
- && __wcollate_range_cmp(CHAR(k), CHAR(pat[1])) <= 0
- )
+ CHAR(c) <= CHAR(k) &&
+ CHAR(k) <= CHAR(pat[1]) :
+ __wcollate_range_cmp(CHAR(c),
+ CHAR(k)) <= 0 &&
+ __wcollate_range_cmp(CHAR(k),
+ CHAR(pat[1])) <= 0)
ok = 1;
pat += 2;
} else if (c == k)
@@ -875,13 +980,15 @@ globfree(glob_t *pglob)
static DIR *
g_opendir(Char *str, glob_t *pglob)
{
- char buf[MAXPATHLEN];
+ char buf[MAXPATHLEN + MB_LEN_MAX - 1];
- if (!*str)
+ if (*str == EOS)
strcpy(buf, ".");
else {
- if (g_Ctoc(str, buf, sizeof(buf)))
+ if (g_Ctoc(str, buf, sizeof(buf))) {
+ errno = ENAMETOOLONG;
return (NULL);
+ }
}
if (pglob->gl_flags & GLOB_ALTDIRFUNC)
@@ -893,7 +1000,7 @@ g_opendir(Char *str, glob_t *pglob)
static int
g_lstat(Char *fn, struct stat *sb, glob_t *pglob)
{
- char buf[MAXPATHLEN];
+ char buf[MAXPATHLEN + MB_LEN_MAX - 1];
if (g_Ctoc(fn, buf, sizeof(buf))) {
errno = ENAMETOOLONG;
@@ -907,7 +1014,7 @@ g_lstat(Char *fn, struct stat *sb, glob_t *pglob)
static int
g_stat(Char *fn, struct stat *sb, glob_t *pglob)
{
- char buf[MAXPATHLEN];
+ char buf[MAXPATHLEN + MB_LEN_MAX - 1];
if (g_Ctoc(fn, buf, sizeof(buf))) {
errno = ENAMETOOLONG;
@@ -937,10 +1044,14 @@ g_Ctoc(const Char *str, char *buf, size_t len)
memset(&mbs, 0, sizeof(mbs));
while (len >= MB_CUR_MAX) {
- clen = wcrtomb(buf, *str, &mbs);
- if (clen == (size_t)-1)
- return (1);
- if (*str == L'\0')
+ clen = wcrtomb(buf, CHAR(*str), &mbs);
+ if (clen == (size_t)-1) {
+ /* XXX See initial comment #2. */
+ *buf = (char)CHAR(*str);
+ clen = 1;
+ memset(&mbs, 0, sizeof(mbs));
+ }
+ if (CHAR(*str) == EOS)
return (0);
str++;
buf += clen;
@@ -949,21 +1060,46 @@ g_Ctoc(const Char *str, char *buf, size_t len)
return (1);
}
+static int
+err_nomatch(glob_t *pglob, struct glob_limit *limit, const char *origpat) {
+ /*
+ * If there was no match we are going to append the origpat
+ * if GLOB_NOCHECK was specified or if GLOB_NOMAGIC was specified
+ * and the origpat did not contain any magic characters
+ * GLOB_NOMAGIC is there just for compatibility with csh.
+ */
+ if ((pglob->gl_flags & GLOB_NOCHECK) ||
+ ((pglob->gl_flags & GLOB_NOMAGIC) &&
+ !(pglob->gl_flags & GLOB_MAGCHAR)))
+ return (globextend(NULL, pglob, limit, origpat));
+ return (GLOB_NOMATCH);
+}
+
+static int
+err_aborted(glob_t *pglob, int err, char *buf) {
+ if ((pglob->gl_errfunc != NULL && pglob->gl_errfunc(buf, err)) ||
+ (pglob->gl_flags & GLOB_ERR))
+ return (GLOB_ABORTED);
+ return (0);
+}
+
#ifdef DEBUG
static void
qprintf(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");
+ (void)printf("%s\n", str);
+ if (s != NULL) {
+ for (p = s; *p != EOS; p++)
+ (void)printf("%c", (char)CHAR(*p));
+ (void)printf("\n");
+ for (p = s; *p != EOS; p++)
+ (void)printf("%c", (isprot(*p) ? '\\' : ' '));
+ (void)printf("\n");
+ for (p = s; *p != EOS; p++)
+ (void)printf("%c", (ismeta(*p) ? '_' : ' '));
+ (void)printf("\n");
+ }
}
#endif
diff --git a/lib/libc/sys/ptrace.2 b/lib/libc/sys/ptrace.2
index a94e314..fc5c0ea 100644
--- a/lib/libc/sys/ptrace.2
+++ b/lib/libc/sys/ptrace.2
@@ -2,7 +2,7 @@
.\" $NetBSD: ptrace.2,v 1.2 1995/02/27 12:35:37 cgd Exp $
.\"
.\" This file is in the public domain.
-.Dd October 20, 2015
+.Dd July 28, 2016
.Dt PTRACE 2
.Os
.Sh NAME
@@ -58,8 +58,9 @@ The signal may be a normal process signal, generated as a result of
traced process behavior, or use of the
.Xr kill 2
system call; alternatively, it may be generated by the tracing facility
-as a result of attaching, system calls, or stepping by the tracing
-process.
+as a result of attaching, stepping by the tracing
+process,
+or an event in the traced process.
The tracing process may choose to intercept the signal, using it to
observe process behavior (such as
.Dv SIGTRAP ) ,
@@ -69,6 +70,121 @@ The
system call
is the mechanism by which all this happens.
.Pp
+A traced process may report additional signal stops corresponding to
+events in the traced process.
+These additional signal stops are reported as
+.Dv SIGTRAP
+or
+.Dv SIGSTOP
+signals.
+The tracing process can use the
+.Dv PT_LWPINFO
+request to determine which events are associated with a
+.Dv SIGTRAP
+or
+.Dv SIGSTOP
+signal.
+Note that multiple events may be associated with a single signal.
+For example, events indicated by the
+.Dv PL_FLAG_BORN ,
+.Dv PL_FLAG_FORKED ,
+and
+.Dv PL_FLAG_EXEC
+flags are also reported as a system call exit event
+.Pq Dv PL_FLAG_SCX .
+The signal stop for a new child process enabled via
+.Dv PTRACE_FORK
+will report a
+.Dv SIGSTOP
+signal.
+All other additional signal stops use
+.Dv SIGTRAP .
+.Pp
+Each traced process has a tracing event mask.
+An event in the traced process only reports a
+signal stop if the corresponding flag is set in the tracing event mask.
+The current set of tracing event flags include:
+.Bl -tag -width ".Dv PTRACE_SYSCALL"
+.It Dv PTRACE_EXEC
+Report a stop for a successful invocation of
+.Xr execve 2 .
+This event is indicated by the
+.Dv PL_FLAG_EXEC
+flag in the
+.Va pl_flags
+member of
+.Vt "struct ptrace_lwpinfo" .
+.It Dv PTRACE_SCE
+Report a stop on each system call entry.
+This event is indicated by the
+.Dv PL_FLAG_SCE
+flag in the
+.Va pl_flags
+member of
+.Vt "struct ptrace_lwpinfo" .
+.It Dv PTRACE_SCX
+Report a stop on each system call exit.
+This event is indicated by the
+.Dv PL_FLAG_SCX
+flag in the
+.Va pl_flags
+member of
+.Vt "struct ptrace_lwpinfo" .
+.It Dv PTRACE_SYSCALL
+Report stops for both system call entry and exit.
+.It Dv PTRACE_FORK
+This event flag controls tracing for new child processes of a traced process.
+.Pp
+When this event flag is enabled,
+new child processes will enable tracing and stop before executing their
+first instruction.
+The new child process will include the
+.Dv PL_FLAG_CHILD
+flag in the
+.Va pl_flags
+member of
+.Vt "struct ptrace_lwpinfo" .
+The traced process will report a stop that includes the
+.Dv PL_FLAG_FORKED
+flag.
+The process ID of the new child process will also be present in the
+.Va pl_child_pid
+member of
+.Vt "struct ptrace_lwpinfo" .
+Note that new child processes will be attached with the default
+tracing event mask;
+they do not inherit the event mask of the traced process.
+.Pp
+When this event flag is not enabled,
+new child processes will execute without tracing enabled.
+.It Dv PTRACE_LWP
+This event flag controls tracing of LWP
+.Pq kernel thread
+creation and destruction.
+When this event is enabled,
+new LWPs will stop and report an event with
+.Dv PL_FLAG_BORN
+set before executing their first instruction,
+and exiting LWPs will stop and report an event with
+.Dv PL_FLAG_EXITED
+set before completing their termination.
+.Pp
+Note that new processes do not report an event for the creation of their
+initial thread,
+and exiting processes do not report an event for the termination of the
+last thread.
+.El
+.Pp
+The default tracing event mask when attaching to a process via
+.Dv PT_ATTACH ,
+.Dv PT_TRACE_ME ,
+or
+.Dv PTRACE_FORK
+includes only
+.Dv PTRACE_EXEC
+events.
+All other event flags are disabled.
+.Pp
The
.Fa request
argument specifies what operation is being performed; the meaning of
@@ -368,10 +484,23 @@ The process identifier of the new process is available in the
member of
.Vt "struct ptrace_lwpinfo" .
.It PL_FLAG_CHILD
-The flag is set for first event reported from a new child, which is
-automatically attached due to
-.Dv PT_FOLLOW_FORK
-enabled.
+The flag is set for first event reported from a new child which is
+automatically attached when
+.Dv PTRACE_FORK
+is enabled.
+.It PL_FLAG_BORN
+This flag is set for the first event reported from a new LWP when
+.Dv PTRACE_LWP
+is enabled.
+It is reported along with
+.Dv PL_FLAG_SCX .
+.It PL_FLAG_EXITED
+This flag is set for the last event reported by an exiting LWP when
+.Dv PTRACE_LWP
+is enabled.
+Note that this event is not reported when the last LWP in a process exits.
+The termination of the last thread is reported via a normal process exit
+event.
.El
.It pl_sigmask
The current signal mask of the LWP
@@ -442,27 +571,72 @@ This request will suspend the specified thread.
.It PT_RESUME
This request will resume the specified thread.
.It PT_TO_SCE
-This request will trace the specified process on each system call entry.
+This request will set the
+.Dv PTRACE_SCE
+event flag to trace all future system call entries and continue the process.
+The
+.Fa addr
+and
+.Fa data
+arguments are used the same as for
+.Dv PT_CONTINUE.
.It PT_TO_SCX
-This request will trace the specified process on each system call exit.
+This request will set the
+.Dv PTRACE_SCX
+event flag to trace all future system call exits and continue the process.
+The
+.Fa addr
+and
+.Fa data
+arguments are used the same as for
+.Dv PT_CONTINUE.
.It PT_SYSCALL
-This request will trace the specified process
-on each system call entry and exit.
+This request will set the
+.Dv PTRACE_SYSCALL
+event flag to trace all future system call entries and exits and continue
+the process.
+The
+.Fa addr
+and
+.Fa data
+arguments are used the same as for
+.Dv PT_CONTINUE.
.It PT_FOLLOW_FORK
This request controls tracing for new child processes of a traced process.
If
.Fa data
is non-zero,
-then new child processes will enable tracing and stop before executing their
-first instruction.
+.Dv PTRACE_FORK
+is set in the traced process's event tracing mask.
If
.Fa data
-is zero, then new child processes will execute without tracing enabled.
-By default, tracing is not enabled for new child processes.
-Child processes do not inherit this property.
-The traced process will set the
-.Dv PL_FLAG_FORKED
-flag upon exit from a system call that creates a new process.
+is zero,
+.Dv PTRACE_FORK
+is cleared from the traced process's event tracing mask.
+.It PT_LWP_EVENTS
+This request controls tracing of LWP creation and destruction.
+If
+.Fa data
+is non-zero,
+.Dv PTRACE_LWP
+is set in the traced process's event tracing mask.
+If
+.Fa data
+is zero,
+.Dv PTRACE_LWP
+is cleared from the traced process's event tracing mask.
+.It PT_GET_EVENT_MASK
+This request reads the traced process's event tracing mask into the
+integer pointed to by
+.Fa addr .
+The size of the integer must be passed in
+.Fa data .
+.It PT_SET_EVENT_MASK
+This request sets the traced process's event tracing mask from the
+integer pointed to by
+.Fa addr .
+The size of the integer must be passed in
+.Fa data .
.It PT_VM_TIMESTAMP
This request returns the generation number or timestamp of the memory map of
the traced process as the return value from
OpenPOWER on IntegriCloud