summaryrefslogtreecommitdiff
path: root/lib/libc
diff options
context:
space:
mode:
authorDimitry Andric <dim@FreeBSD.org>2017-05-26 19:11:24 +0000
committerDimitry Andric <dim@FreeBSD.org>2017-05-26 19:11:24 +0000
commitd02c951f8ec631d059ec7a8addb8a104cd160280 (patch)
tree95a3b1baea805cde74e09666d77a5b9f11d95aff /lib/libc
parentd8866befb86698415f5ef82446c22f6da5fb2bd9 (diff)
parentb5617df55b52e1be5b9f07bf00ac345f304c2497 (diff)
Notes
Diffstat (limited to 'lib/libc')
-rw-r--r--lib/libc/gen/Makefile.inc10
-rw-r--r--lib/libc/gen/Symbol.map40
-rw-r--r--lib/libc/gen/basename.322
-rw-r--r--lib/libc/gen/closedir.c1
-rw-r--r--lib/libc/gen/devname-compat11.c50
-rw-r--r--lib/libc/gen/directory.39
-rw-r--r--lib/libc/gen/dirname.320
-rw-r--r--lib/libc/gen/err.c8
-rw-r--r--lib/libc/gen/fts-compat.c39
-rw-r--r--lib/libc/gen/fts-compat.h10
-rw-r--r--lib/libc/gen/fts-compat11.c1199
-rw-r--r--lib/libc/gen/fts-compat11.h95
-rw-r--r--lib/libc/gen/fts.c6
-rw-r--r--lib/libc/gen/ftw-compat11.c98
-rw-r--r--lib/libc/gen/gen-compat.h57
-rw-r--r--lib/libc/gen/gen-private.h6
-rw-r--r--lib/libc/gen/getmntinfo-compat11.c72
-rw-r--r--lib/libc/gen/glob-compat11.c1093
-rw-r--r--lib/libc/gen/glob-compat11.h72
-rw-r--r--lib/libc/gen/nftw-compat11.c115
-rw-r--r--lib/libc/gen/opendir.c1
-rw-r--r--lib/libc/gen/readdir-compat11.c120
-rw-r--r--lib/libc/gen/readdir.c32
-rw-r--r--lib/libc/gen/scandir-compat11.c174
-rw-r--r--lib/libc/gen/scandir.c13
-rw-r--r--lib/libc/gen/sem_timedwait.34
-rw-r--r--lib/libc/gen/tcsendbreak.31
-rw-r--r--lib/libc/gen/telldir.h5
-rw-r--r--lib/libc/iconv/__iconv_get_list.32
-rw-r--r--lib/libc/include/compat.h21
-rw-r--r--lib/libc/include/libc_private.h6
-rw-r--r--lib/libc/locale/localeconv.33
-rw-r--r--lib/libc/net/sctp_bindx.32
-rw-r--r--lib/libc/net/sctp_getassocid.32
-rw-r--r--lib/libc/net/sctp_send.34
-rw-r--r--lib/libc/posix1e/acl_create_entry.32
-rw-r--r--lib/libc/posix1e/acl_to_text.35
-rw-r--r--lib/libc/posix1e/posix1e.32
-rw-r--r--lib/libc/stdio/fopen.315
-rw-r--r--lib/libc/stdio/fopencookie.38
-rw-r--r--lib/libc/stdlib/quick_exit.36
-rw-r--r--lib/libc/sys/Makefile.inc2
-rw-r--r--lib/libc/sys/Symbol.map41
-rw-r--r--lib/libc/sys/_umtx_op.246
-rw-r--r--lib/libc/sys/cap_enter.28
-rw-r--r--lib/libc/sys/cpuset_getaffinity.28
-rw-r--r--lib/libc/sys/fsync.24
-rw-r--r--lib/libc/sys/getdents.c41
-rw-r--r--lib/libc/sys/getdirentries.28
-rw-r--r--lib/libc/sys/kill.22
-rw-r--r--lib/libc/sys/lstat.c43
-rw-r--r--lib/libc/sys/mknod.c45
-rw-r--r--lib/libc/sys/open.222
-rw-r--r--lib/libc/sys/ptrace.24
-rw-r--r--lib/libc/sys/rctl_add_rule.28
-rw-r--r--lib/libc/sys/setfib.22
-rw-r--r--lib/libc/sys/stat.c43
-rw-r--r--lib/libc/sys/statfs.26
-rw-r--r--lib/libc/xdr/xdr.32
59 files changed, 3571 insertions, 214 deletions
diff --git a/lib/libc/gen/Makefile.inc b/lib/libc/gen/Makefile.inc
index ac6e077207a8..b8a969276c5e 100644
--- a/lib/libc/gen/Makefile.inc
+++ b/lib/libc/gen/Makefile.inc
@@ -148,7 +148,15 @@ SRCS+= __getosreldate.c \
waitid.c \
wordexp.c
.if ${MK_SYMVER} == yes
-SRCS+= fts-compat.c \
+SRCS+= devname-compat11.c \
+ fts-compat.c \
+ fts-compat11.c \
+ ftw-compat11.c \
+ getmntinfo-compat11.c \
+ glob-compat11.c \
+ nftw-compat11.c \
+ readdir-compat11.c \
+ scandir-compat11.c \
unvis-compat.c
.endif
diff --git a/lib/libc/gen/Symbol.map b/lib/libc/gen/Symbol.map
index bada246e0b3c..3108f822b675 100644
--- a/lib/libc/gen/Symbol.map
+++ b/lib/libc/gen/Symbol.map
@@ -75,8 +75,6 @@ FBSD_1.0 {
ctermid;
ctermid_r;
daemon;
- devname;
- devname_r;
getdiskbyname;
dladdr;
dlclose;
@@ -128,9 +126,6 @@ FBSD_1.0 {
setfsent;
endfsent;
ftok;
- ftw;
- glob;
- globfree;
getbootfile;
getbsize;
cgetset;
@@ -163,7 +158,6 @@ FBSD_1.0 {
getloadavg;
getlogin;
getlogin_r;
- getmntinfo;
setnetgrent;
getnetgrent;
endnetgrent;
@@ -209,7 +203,6 @@ FBSD_1.0 {
lrand48;
modf;
mrand48;
- nftw;
nice;
nlist;
nrand48;
@@ -220,13 +213,9 @@ FBSD_1.0 {
pclose;
psignal;
raise;
- readdir;
- readdir_r;
readpassphrase;
getpass;
rewinddir;
- scandir;
- alphasort;
seed48;
seekdir;
user_from_uid;
@@ -314,14 +303,6 @@ FBSD_1.1 {
fdevname_r;
fdopendir;
feature_present;
- fts_children;
- fts_close;
- fts_get_clientptr;
- fts_get_stream;
- fts_open;
- fts_read;
- fts_set;
- fts_set_clientptr;
posix_spawn;
posix_spawn_file_actions_addclose;
posix_spawn_file_actions_adddup2;
@@ -408,13 +389,32 @@ FBSD_1.4 {
pthread_mutex_consistent;
pthread_mutexattr_getrobust;
pthread_mutexattr_setrobust;
- scandir_b;
stravis;
};
FBSD_1.5 {
+ alphasort;
basename;
+ devname;
+ devname_r;
dirname;
+ fts_children;
+ fts_close;
+ fts_get_clientptr;
+ fts_get_stream;
+ fts_open;
+ fts_read;
+ fts_set;
+ fts_set_clientptr;
+ ftw;
+ getmntinfo;
+ glob;
+ globfree;
+ nftw;
+ readdir;
+ readdir_r;
+ scandir;
+ scandir_b;
sem_clockwait_np;
};
diff --git a/lib/libc/gen/basename.3 b/lib/libc/gen/basename.3
index 51a90e404746..3bbddd9233e2 100644
--- a/lib/libc/gen/basename.3
+++ b/lib/libc/gen/basename.3
@@ -16,7 +16,7 @@
.\"
.\" $FreeBSD$
.\"
-.Dd October 29, 2016
+.Dd May 22, 2017
.Dt BASENAME 3
.Os
.Sh NAME
@@ -34,6 +34,16 @@ function returns the last component from the pathname pointed to by
deleting any trailing
.Sq \&/
characters.
+.Sh IMPLEMENTATION NOTES
+This implementation of
+.Fn basename
+uses the buffer provided by the caller to store the resulting pathname
+component.
+Other vendor implementations may return a pointer to internal storage
+space instead.
+The advantage of the former approach is that it ensures thread-safety,
+while also placing no upper limit on the supported length of the
+pathname.
.Sh RETURN VALUES
If
.Fa path
@@ -50,16 +60,6 @@ is returned.
Otherwise,
it returns a pointer to the last component of
.Fa path .
-.Sh IMPLEMENTATION NOTES
-This implementation of
-.Fn basename
-uses the buffer provided by the caller to store the resulting pathname
-component.
-Other vendor implementations may return a pointer to internal storage
-space instead.
-The advantage of the former approach is that it ensures thread-safety,
-while also placing no upper limit on the supported length of the
-pathname.
.Sh SEE ALSO
.Xr basename 1 ,
.Xr dirname 1 ,
diff --git a/lib/libc/gen/closedir.c b/lib/libc/gen/closedir.c
index afdab45f6c49..098bc1959eb0 100644
--- a/lib/libc/gen/closedir.c
+++ b/lib/libc/gen/closedir.c
@@ -59,6 +59,7 @@ fdclosedir(DIR *dirp)
dirp->dd_fd = -1;
dirp->dd_loc = 0;
free((void *)dirp->dd_buf);
+ free(dirp->dd_compat_de);
_reclaim_telldir(dirp);
if (__isthreaded) {
_pthread_mutex_unlock(&dirp->dd_lock);
diff --git a/lib/libc/gen/devname-compat11.c b/lib/libc/gen/devname-compat11.c
new file mode 100644
index 000000000000..70cb6f0d641e
--- /dev/null
+++ b/lib/libc/gen/devname-compat11.c
@@ -0,0 +1,50 @@
+/*-
+ * Copyright (c) 2011 Gleb Kurtsou <gleb@FreeBSD.org>
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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 <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <stdlib.h>
+#include "gen-compat.h"
+
+char *
+freebsd11_devname(uint32_t dev, mode_t type)
+{
+
+ return (devname(dev, type));
+}
+
+char *
+freebsd11_devname_r(uint32_t dev, mode_t type, char *buf, int len)
+{
+
+ return (devname_r(dev, type, buf, len));
+}
+
+__sym_compat(devname, freebsd11_devname, FBSD_1.0);
+__sym_compat(devname_r, freebsd11_devname_r, FBSD_1.0);
diff --git a/lib/libc/gen/directory.3 b/lib/libc/gen/directory.3
index da5cdb3e9538..6fdb96ad9760 100644
--- a/lib/libc/gen/directory.3
+++ b/lib/libc/gen/directory.3
@@ -28,7 +28,7 @@
.\" @(#)directory.3 8.1 (Berkeley) 6/4/93
.\" $FreeBSD$
.\"
-.Dd August 31, 2016
+.Dd May 22, 2017
.Dt DIRECTORY 3
.Os
.Sh NAME
@@ -292,14 +292,15 @@ is likely to be wrong if there are parallel unlinks happening
and the directory is larger than one page.
There is code to ensure that a
.Fn seekdir
-to the location given by a
+to the location given by a
.Fn telldir
-immediately before the last
+immediately before the last
.Fn readdir
will always set the correct location to return the same value as that last
.Fn readdir
performed.
-This is enough for some applications which want to "push back the last entry read" E.g. Samba.
+This is enough for some applications which want to
+"push back the last entry read", e.g., Samba.
Seeks back to any other location,
other than the beginning of the directory,
may result in unexpected behaviour if deletes are present.
diff --git a/lib/libc/gen/dirname.3 b/lib/libc/gen/dirname.3
index 60f44e298614..67eee664a1e1 100644
--- a/lib/libc/gen/dirname.3
+++ b/lib/libc/gen/dirname.3
@@ -37,6 +37,16 @@ Any trailing
.Sq \&/
characters are not counted as part of the directory
name.
+.Sh IMPLEMENTATION NOTES
+This implementation of
+.Fn dirname
+uses the buffer provided by the caller to store the resulting parent
+directory.
+Other vendor implementations may return a pointer to internal storage
+space instead.
+The advantage of the former approach is that it ensures thread-safety,
+while also placing no upper limit on the supported length of the
+pathname.
.Sh RETURN VALUES
If
.Fa path
@@ -50,16 +60,6 @@ signifying the current directory.
Otherwise,
it returns a pointer to the parent directory of
.Fa path .
-.Sh IMPLEMENTATION NOTES
-This implementation of
-.Fn dirname
-uses the buffer provided by the caller to store the resulting parent
-directory.
-Other vendor implementations may return a pointer to internal storage
-space instead.
-The advantage of the former approach is that it ensures thread-safety,
-while also placing no upper limit on the supported length of the
-pathname.
.Sh SEE ALSO
.Xr basename 1 ,
.Xr dirname 1 ,
diff --git a/lib/libc/gen/err.c b/lib/libc/gen/err.c
index 9af672f497c1..20ce3e326203 100644
--- a/lib/libc/gen/err.c
+++ b/lib/libc/gen/err.c
@@ -97,7 +97,7 @@ void
verrc(int eval, int code, const char *fmt, va_list ap)
{
if (err_file == NULL)
- err_set_file((FILE *)0);
+ err_set_file(NULL);
fprintf(err_file, "%s: ", _getprogname());
if (fmt != NULL) {
vfprintf(err_file, fmt, ap);
@@ -122,7 +122,7 @@ void
verrx(int eval, const char *fmt, va_list ap)
{
if (err_file == NULL)
- err_set_file((FILE *)0);
+ err_set_file(NULL);
fprintf(err_file, "%s: ", _getprogname());
if (fmt != NULL)
vfprintf(err_file, fmt, ap);
@@ -162,7 +162,7 @@ void
vwarnc(int code, const char *fmt, va_list ap)
{
if (err_file == NULL)
- err_set_file((FILE *)0);
+ err_set_file(NULL);
fprintf(err_file, "%s: ", _getprogname());
if (fmt != NULL) {
vfprintf(err_file, fmt, ap);
@@ -184,7 +184,7 @@ void
vwarnx(const char *fmt, va_list ap)
{
if (err_file == NULL)
- err_set_file((FILE *)0);
+ err_set_file(NULL);
fprintf(err_file, "%s: ", _getprogname());
if (fmt != NULL)
vfprintf(err_file, fmt, ap);
diff --git a/lib/libc/gen/fts-compat.c b/lib/libc/gen/fts-compat.c
index 64a73e9ea28a..b1632207b76e 100644
--- a/lib/libc/gen/fts-compat.c
+++ b/lib/libc/gen/fts-compat.c
@@ -40,15 +40,19 @@ __FBSDID("$FreeBSD$");
#include "namespace.h"
#include <sys/param.h>
+#define _WANT_FREEBSD11_STATFS
#include <sys/mount.h>
+#define _WANT_FREEBSD11_STAT
#include <sys/stat.h>
+#define _WANT_FREEBSD11_DIRENT
#include <dirent.h>
#include <errno.h>
#include <fcntl.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
+#include "gen-compat.h"
#include "fts-compat.h"
#include "un-namespace.h"
@@ -96,8 +100,8 @@ static int fts_ufslinks(FTS *, const FTSENT *);
*/
struct _fts_private {
FTS ftsp_fts;
- struct statfs ftsp_statfs;
- dev_t ftsp_dev;
+ struct freebsd11_statfs ftsp_statfs;
+ uint32_t ftsp_dev;
int ftsp_linksreliable;
};
@@ -142,9 +146,6 @@ __fts_open_44bsd(char * const *argv, int options,
sp->fts_compar = compar;
sp->fts_options = options;
- /* Shush, GCC. */
- tmp = NULL;
-
/* Logical walks turn on NOCHDIR; symbolic links are too hard. */
if (ISSET(FTS_LOGICAL))
SET(FTS_NOCHDIR);
@@ -161,6 +162,9 @@ __fts_open_44bsd(char * const *argv, int options,
goto mem2;
parent->fts_level = FTS_ROOTPARENTLEVEL;
+ /* Shush, GCC. */
+ tmp = NULL;
+
/* Allocate/initialize root(s). */
for (root = NULL, nitems = 0; *argv != NULL; ++argv, ++nitems) {
/* Don't allow zero-length paths. */
@@ -626,7 +630,7 @@ __fts_set_clientptr_44bsd(FTS *sp, void *clientptr)
static FTSENT *
fts_build(FTS *sp, int type)
{
- struct dirent *dp;
+ struct freebsd11_dirent *dp;
FTSENT *p, *head;
int nitems;
FTSENT *cur, *tail;
@@ -738,7 +742,8 @@ fts_build(FTS *sp, int type)
/* Read the directory, attaching each entry to the `link' pointer. */
doadjust = 0;
- for (head = tail = NULL, nitems = 0; dirp && (dp = readdir(dirp));) {
+ for (head = tail = NULL, nitems = 0;
+ dirp && (dp = freebsd11_readdir(dirp));) {
dnamlen = dp->d_namlen;
if (!ISSET(FTS_SEEDOT) && ISDOT(dp->d_name))
continue;
@@ -891,9 +896,9 @@ static u_short
fts_stat(FTS *sp, FTSENT *p, int follow)
{
FTSENT *t;
- dev_t dev;
- ino_t ino;
- struct stat *sbp, sb;
+ uint32_t dev;
+ uint32_t ino;
+ struct freebsd11_stat *sbp, sb;
int saved_errno;
/* If user needs stat info, stat buffer already allocated. */
@@ -916,16 +921,16 @@ fts_stat(FTS *sp, FTSENT *p, int follow)
* fail, set the errno from the stat call.
*/
if (ISSET(FTS_LOGICAL) || follow) {
- if (stat(p->fts_accpath, sbp)) {
+ if (freebsd11_stat(p->fts_accpath, sbp)) {
saved_errno = errno;
- if (!lstat(p->fts_accpath, sbp)) {
+ if (!freebsd11_lstat(p->fts_accpath, sbp)) {
errno = 0;
return (FTS_SLNONE);
}
p->fts_errno = saved_errno;
goto err;
}
- } else if (lstat(p->fts_accpath, sbp)) {
+ } else if (freebsd11_lstat(p->fts_accpath, sbp)) {
p->fts_errno = errno;
err: memset(sbp, 0, sizeof(struct stat));
return (FTS_NS);
@@ -1019,7 +1024,7 @@ fts_alloc(FTS *sp, char *name, int namelen)
struct ftsent_withstat {
FTSENT ent;
- struct stat statbuf;
+ struct freebsd11_stat statbuf;
};
/*
@@ -1145,14 +1150,14 @@ static int
fts_safe_changedir(FTS *sp, FTSENT *p, int fd, char *path)
{
int ret, oerrno, newfd;
- struct stat sb;
+ struct freebsd11_stat sb;
newfd = fd;
if (ISSET(FTS_NOCHDIR))
return (0);
if (fd < 0 && (newfd = _open(path, O_RDONLY | O_CLOEXEC, 0)) < 0)
return (-1);
- if (_fstat(newfd, &sb)) {
+ if (freebsd11_fstat(newfd, &sb)) {
ret = -1;
goto bail;
}
@@ -1187,7 +1192,7 @@ fts_ufslinks(FTS *sp, const FTSENT *ent)
* avoidance.
*/
if (priv->ftsp_dev != ent->fts_dev) {
- if (statfs(ent->fts_path, &priv->ftsp_statfs) != -1) {
+ if (freebsd11_statfs(ent->fts_path, &priv->ftsp_statfs) != -1) {
priv->ftsp_dev = ent->fts_dev;
priv->ftsp_linksreliable = 0;
for (cpp = ufslike_filesystems; *cpp; cpp++) {
diff --git a/lib/libc/gen/fts-compat.h b/lib/libc/gen/fts-compat.h
index d8fe6895f11c..4c661e5cf7cc 100644
--- a/lib/libc/gen/fts-compat.h
+++ b/lib/libc/gen/fts-compat.h
@@ -37,7 +37,7 @@ typedef struct {
struct _ftsent *fts_cur; /* current node */
struct _ftsent *fts_child; /* linked list of children */
struct _ftsent **fts_array; /* sort array */
- dev_t fts_dev; /* starting device # */
+ uint32_t fts_dev; /* starting device # */
char *fts_path; /* path for this descent */
int fts_rfd; /* fd for root */
int fts_pathlen; /* sizeof(path) */
@@ -82,9 +82,9 @@ typedef struct _ftsent {
u_short fts_pathlen; /* strlen(fts_path) */
u_short fts_namelen; /* strlen(fts_name) */
- ino_t fts_ino; /* inode */
- dev_t fts_dev; /* device */
- nlink_t fts_nlink; /* link count */
+ uint32_t fts_ino; /* inode */
+ uint32_t fts_dev; /* device */
+ uint16_t fts_nlink; /* link count */
#define FTS_ROOTPARENTLEVEL -1
#define FTS_ROOTLEVEL 0
@@ -117,7 +117,7 @@ typedef struct _ftsent {
#define FTS_SKIP 4 /* discard node */
u_short fts_instr; /* fts_set() instructions */
- struct stat *fts_statp; /* stat(2) information */
+ struct freebsd11_stat *fts_statp; /* stat(2) information */
char *fts_name; /* file name */
FTS *fts_fts; /* back pointer to main FTS */
} FTSENT;
diff --git a/lib/libc/gen/fts-compat11.c b/lib/libc/gen/fts-compat11.c
new file mode 100644
index 000000000000..1fc63d0d73ec
--- /dev/null
+++ b/lib/libc/gen/fts-compat11.c
@@ -0,0 +1,1199 @@
+/*-
+ * Copyright (c) 1990, 1993, 1994
+ * 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.
+ *
+ * from: $OpenBSD: fts.c,v 1.22 1999/10/03 19:22:22 millert Exp $
+ */
+
+#if 0
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)fts.c 8.6 (Berkeley) 8/14/94";
+#endif /* LIBC_SCCS and not lint */
+#endif
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "namespace.h"
+#include <sys/param.h>
+#define _WANT_FREEBSD11_STATFS
+#include <sys/mount.h>
+#define _WANT_FREEBSD11_STAT
+#include <sys/stat.h>
+
+#define _WANT_FREEBSD11_DIRENT
+#include <dirent.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <fts.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include "gen-compat.h"
+#include "fts-compat11.h"
+#include "un-namespace.h"
+
+#include "gen-private.h"
+
+static FTSENT11 *fts_alloc(FTS11 *, char *, size_t);
+static FTSENT11 *fts_build(FTS11 *, int);
+static void fts_lfree(FTSENT11 *);
+static void fts_load(FTS11 *, FTSENT11 *);
+static size_t fts_maxarglen(char * const *);
+static void fts_padjust(FTS11 *, FTSENT11 *);
+static int fts_palloc(FTS11 *, size_t);
+static FTSENT11 *fts_sort(FTS11 *, FTSENT11 *, size_t);
+static int fts_stat(FTS11 *, FTSENT11 *, int, int);
+static int fts_safe_changedir(FTS11 *, FTSENT11 *, int, char *);
+static int fts_ufslinks(FTS11 *, const FTSENT11 *);
+
+#define ISDOT(a) (a[0] == '.' && (!a[1] || (a[1] == '.' && !a[2])))
+
+#define CLR(opt) (sp->fts_options &= ~(opt))
+#define ISSET(opt) (sp->fts_options & (opt))
+#define SET(opt) (sp->fts_options |= (opt))
+
+#define FCHDIR(sp, fd) (!ISSET(FTS_NOCHDIR) && fchdir(fd))
+
+/* fts_build flags */
+#define BCHILD 1 /* fts_children */
+#define BNAMES 2 /* fts_children, names only */
+#define BREAD 3 /* fts_read */
+
+/*
+ * Internal representation of an FTS, including extra implementation
+ * details. The FTS returned from fts_open points to this structure's
+ * ftsp_fts member (and can be cast to an _fts_private as required)
+ */
+struct _fts_private11 {
+ FTS11 ftsp_fts;
+ struct freebsd11_statfs ftsp_statfs;
+ uint32_t ftsp_dev;
+ int ftsp_linksreliable;
+};
+
+/*
+ * The "FTS_NOSTAT" option can avoid a lot of calls to stat(2) if it
+ * knows that a directory could not possibly have subdirectories. This
+ * is decided by looking at the link count: a subdirectory would
+ * increment its parent's link count by virtue of its own ".." entry.
+ * This assumption only holds for UFS-like filesystems that implement
+ * links and directories this way, so we must punt for others.
+ */
+
+static const char *ufslike_filesystems[] = {
+ "ufs",
+ "zfs",
+ "nfs",
+ "ext2fs",
+ 0
+};
+
+FTS11 *
+freebsd11_fts_open(char * const *argv, int options,
+ int (*compar)(const FTSENT11 * const *, const FTSENT11 * const *))
+{
+ struct _fts_private11 *priv;
+ FTS11 *sp;
+ FTSENT11 *p, *root;
+ FTSENT11 *parent, *tmp;
+ size_t len, nitems;
+
+ /* Options check. */
+ if (options & ~FTS_OPTIONMASK) {
+ errno = EINVAL;
+ return (NULL);
+ }
+
+ /* fts_open() requires at least one path */
+ if (*argv == NULL) {
+ errno = EINVAL;
+ return (NULL);
+ }
+
+ /* Allocate/initialize the stream. */
+ if ((priv = calloc(1, sizeof(*priv))) == NULL)
+ return (NULL);
+ sp = &priv->ftsp_fts;
+ sp->fts_compar = compar;
+ sp->fts_options = options;
+
+ /* Logical walks turn on NOCHDIR; symbolic links are too hard. */
+ if (ISSET(FTS_LOGICAL))
+ SET(FTS_NOCHDIR);
+
+ /*
+ * Start out with 1K of path space, and enough, in any case,
+ * to hold the user's paths.
+ */
+ if (fts_palloc(sp, MAX(fts_maxarglen(argv), MAXPATHLEN)))
+ goto mem1;
+
+ /* Allocate/initialize root's parent. */
+ if ((parent = fts_alloc(sp, "", 0)) == NULL)
+ goto mem2;
+ parent->fts_level = FTS_ROOTPARENTLEVEL;
+
+ /* Shush, GCC. */
+ tmp = NULL;
+
+ /* Allocate/initialize root(s). */
+ for (root = NULL, nitems = 0; *argv != NULL; ++argv, ++nitems) {
+ len = strlen(*argv);
+
+ p = fts_alloc(sp, *argv, len);
+ p->fts_level = FTS_ROOTLEVEL;
+ p->fts_parent = parent;
+ p->fts_accpath = p->fts_name;
+ p->fts_info = fts_stat(sp, p, ISSET(FTS_COMFOLLOW), -1);
+
+ /* Command-line "." and ".." are real directories. */
+ if (p->fts_info == FTS_DOT)
+ p->fts_info = FTS_D;
+
+ /*
+ * If comparison routine supplied, traverse in sorted
+ * order; otherwise traverse in the order specified.
+ */
+ if (compar) {
+ p->fts_link = root;
+ root = p;
+ } else {
+ p->fts_link = NULL;
+ if (root == NULL)
+ tmp = root = p;
+ else {
+ tmp->fts_link = p;
+ tmp = p;
+ }
+ }
+ }
+ if (compar && nitems > 1)
+ root = fts_sort(sp, root, nitems);
+
+ /*
+ * Allocate a dummy pointer and make fts_read think that we've just
+ * finished the node before the root(s); set p->fts_info to FTS_INIT
+ * so that everything about the "current" node is ignored.
+ */
+ if ((sp->fts_cur = fts_alloc(sp, "", 0)) == NULL)
+ goto mem3;
+ sp->fts_cur->fts_link = root;
+ sp->fts_cur->fts_info = FTS_INIT;
+
+ /*
+ * If using chdir(2), grab a file descriptor pointing to dot to ensure
+ * that we can get back here; this could be avoided for some paths,
+ * but almost certainly not worth the effort. Slashes, symbolic links,
+ * and ".." are all fairly nasty problems. Note, if we can't get the
+ * descriptor we run anyway, just more slowly.
+ */
+ if (!ISSET(FTS_NOCHDIR) &&
+ (sp->fts_rfd = _open(".", O_RDONLY | O_CLOEXEC, 0)) < 0)
+ SET(FTS_NOCHDIR);
+
+ return (sp);
+
+mem3: fts_lfree(root);
+ free(parent);
+mem2: free(sp->fts_path);
+mem1: free(sp);
+ return (NULL);
+}
+
+static void
+fts_load(FTS11 *sp, FTSENT11 *p)
+{
+ size_t len;
+ char *cp;
+
+ /*
+ * Load the stream structure for the next traversal. Since we don't
+ * actually enter the directory until after the preorder visit, set
+ * the fts_accpath field specially so the chdir gets done to the right
+ * place and the user can access the first node. From fts_open it's
+ * known that the path will fit.
+ */
+ len = p->fts_pathlen = p->fts_namelen;
+ memmove(sp->fts_path, p->fts_name, len + 1);
+ if ((cp = strrchr(p->fts_name, '/')) && (cp != p->fts_name || cp[1])) {
+ len = strlen(++cp);
+ memmove(p->fts_name, cp, len + 1);
+ p->fts_namelen = len;
+ }
+ p->fts_accpath = p->fts_path = sp->fts_path;
+ sp->fts_dev = p->fts_dev;
+}
+
+int
+freebsd11_fts_close(FTS11 *sp)
+{
+ FTSENT11 *freep, *p;
+ int saved_errno;
+
+ /*
+ * This still works if we haven't read anything -- the dummy structure
+ * points to the root list, so we step through to the end of the root
+ * list which has a valid parent pointer.
+ */
+ if (sp->fts_cur) {
+ for (p = sp->fts_cur; p->fts_level >= FTS_ROOTLEVEL;) {
+ freep = p;
+ p = p->fts_link != NULL ? p->fts_link : p->fts_parent;
+ free(freep);
+ }
+ free(p);
+ }
+
+ /* Free up child linked list, sort array, path buffer. */
+ if (sp->fts_child)
+ fts_lfree(sp->fts_child);
+ if (sp->fts_array)
+ free(sp->fts_array);
+ free(sp->fts_path);
+
+ /* Return to original directory, save errno if necessary. */
+ if (!ISSET(FTS_NOCHDIR)) {
+ saved_errno = fchdir(sp->fts_rfd) ? errno : 0;
+ (void)_close(sp->fts_rfd);
+
+ /* Set errno and return. */
+ if (saved_errno != 0) {
+ /* Free up the stream pointer. */
+ free(sp);
+ errno = saved_errno;
+ return (-1);
+ }
+ }
+
+ /* Free up the stream pointer. */
+ free(sp);
+ return (0);
+}
+
+/*
+ * Special case of "/" at the end of the path so that slashes aren't
+ * appended which would cause paths to be written as "....//foo".
+ */
+#define NAPPEND(p) \
+ (p->fts_path[p->fts_pathlen - 1] == '/' \
+ ? p->fts_pathlen - 1 : p->fts_pathlen)
+
+FTSENT11 *
+freebsd11_fts_read(FTS11 *sp)
+{
+ FTSENT11 *p, *tmp;
+ int instr;
+ char *t;
+ int saved_errno;
+
+ /* If finished or unrecoverable error, return NULL. */
+ if (sp->fts_cur == NULL || ISSET(FTS_STOP))
+ return (NULL);
+
+ /* Set current node pointer. */
+ p = sp->fts_cur;
+
+ /* Save and zero out user instructions. */
+ instr = p->fts_instr;
+ p->fts_instr = FTS_NOINSTR;
+
+ /* Any type of file may be re-visited; re-stat and re-turn. */
+ if (instr == FTS_AGAIN) {
+ p->fts_info = fts_stat(sp, p, 0, -1);
+ return (p);
+ }
+
+ /*
+ * Following a symlink -- SLNONE test allows application to see
+ * SLNONE and recover. If indirecting through a symlink, have
+ * keep a pointer to current location. If unable to get that
+ * pointer, follow fails.
+ */
+ if (instr == FTS_FOLLOW &&
+ (p->fts_info == FTS_SL || p->fts_info == FTS_SLNONE)) {
+ p->fts_info = fts_stat(sp, p, 1, -1);
+ if (p->fts_info == FTS_D && !ISSET(FTS_NOCHDIR)) {
+ if ((p->fts_symfd = _open(".", O_RDONLY | O_CLOEXEC,
+ 0)) < 0) {
+ p->fts_errno = errno;
+ p->fts_info = FTS_ERR;
+ } else
+ p->fts_flags |= FTS_SYMFOLLOW;
+ }
+ return (p);
+ }
+
+ /* Directory in pre-order. */
+ if (p->fts_info == FTS_D) {
+ /* If skipped or crossed mount point, do post-order visit. */
+ if (instr == FTS_SKIP ||
+ (ISSET(FTS_XDEV) && p->fts_dev != sp->fts_dev)) {
+ if (p->fts_flags & FTS_SYMFOLLOW)
+ (void)_close(p->fts_symfd);
+ if (sp->fts_child) {
+ fts_lfree(sp->fts_child);
+ sp->fts_child = NULL;
+ }
+ p->fts_info = FTS_DP;
+ return (p);
+ }
+
+ /* Rebuild if only read the names and now traversing. */
+ if (sp->fts_child != NULL && ISSET(FTS_NAMEONLY)) {
+ CLR(FTS_NAMEONLY);
+ fts_lfree(sp->fts_child);
+ sp->fts_child = NULL;
+ }
+
+ /*
+ * Cd to the subdirectory.
+ *
+ * If have already read and now fail to chdir, whack the list
+ * to make the names come out right, and set the parent errno
+ * so the application will eventually get an error condition.
+ * Set the FTS_DONTCHDIR flag so that when we logically change
+ * directories back to the parent we don't do a chdir.
+ *
+ * If haven't read do so. If the read fails, fts_build sets
+ * FTS_STOP or the fts_info field of the node.
+ */
+ if (sp->fts_child != NULL) {
+ if (fts_safe_changedir(sp, p, -1, p->fts_accpath)) {
+ p->fts_errno = errno;
+ p->fts_flags |= FTS_DONTCHDIR;
+ for (p = sp->fts_child; p != NULL;
+ p = p->fts_link)
+ p->fts_accpath =
+ p->fts_parent->fts_accpath;
+ }
+ } else if ((sp->fts_child = fts_build(sp, BREAD)) == NULL) {
+ if (ISSET(FTS_STOP))
+ return (NULL);
+ return (p);
+ }
+ p = sp->fts_child;
+ sp->fts_child = NULL;
+ goto name;
+ }
+
+ /* Move to the next node on this level. */
+next: tmp = p;
+ if ((p = p->fts_link) != NULL) {
+ /*
+ * If reached the top, return to the original directory (or
+ * the root of the tree), and load the paths for the next root.
+ */
+ if (p->fts_level == FTS_ROOTLEVEL) {
+ if (FCHDIR(sp, sp->fts_rfd)) {
+ SET(FTS_STOP);
+ return (NULL);
+ }
+ free(tmp);
+ fts_load(sp, p);
+ return (sp->fts_cur = p);
+ }
+
+ /*
+ * User may have called fts_set on the node. If skipped,
+ * ignore. If followed, get a file descriptor so we can
+ * get back if necessary.
+ */
+ if (p->fts_instr == FTS_SKIP) {
+ free(tmp);
+ goto next;
+ }
+ if (p->fts_instr == FTS_FOLLOW) {
+ p->fts_info = fts_stat(sp, p, 1, -1);
+ if (p->fts_info == FTS_D && !ISSET(FTS_NOCHDIR)) {
+ if ((p->fts_symfd =
+ _open(".", O_RDONLY | O_CLOEXEC, 0)) < 0) {
+ p->fts_errno = errno;
+ p->fts_info = FTS_ERR;
+ } else
+ p->fts_flags |= FTS_SYMFOLLOW;
+ }
+ p->fts_instr = FTS_NOINSTR;
+ }
+
+ free(tmp);
+
+name: t = sp->fts_path + NAPPEND(p->fts_parent);
+ *t++ = '/';
+ memmove(t, p->fts_name, p->fts_namelen + 1);
+ return (sp->fts_cur = p);
+ }
+
+ /* Move up to the parent node. */
+ p = tmp->fts_parent;
+
+ if (p->fts_level == FTS_ROOTPARENTLEVEL) {
+ /*
+ * Done; free everything up and set errno to 0 so the user
+ * can distinguish between error and EOF.
+ */
+ free(tmp);
+ free(p);
+ errno = 0;
+ return (sp->fts_cur = NULL);
+ }
+
+ /* NUL terminate the pathname. */
+ sp->fts_path[p->fts_pathlen] = '\0';
+
+ /*
+ * Return to the parent directory. If at a root node or came through
+ * a symlink, go back through the file descriptor. Otherwise, cd up
+ * one directory.
+ */
+ if (p->fts_level == FTS_ROOTLEVEL) {
+ if (FCHDIR(sp, sp->fts_rfd)) {
+ SET(FTS_STOP);
+ return (NULL);
+ }
+ } else if (p->fts_flags & FTS_SYMFOLLOW) {
+ if (FCHDIR(sp, p->fts_symfd)) {
+ saved_errno = errno;
+ (void)_close(p->fts_symfd);
+ errno = saved_errno;
+ SET(FTS_STOP);
+ return (NULL);
+ }
+ (void)_close(p->fts_symfd);
+ } else if (!(p->fts_flags & FTS_DONTCHDIR) &&
+ fts_safe_changedir(sp, p->fts_parent, -1, "..")) {
+ SET(FTS_STOP);
+ return (NULL);
+ }
+ free(tmp);
+ p->fts_info = p->fts_errno ? FTS_ERR : FTS_DP;
+ return (sp->fts_cur = p);
+}
+
+/*
+ * Fts_set takes the stream as an argument although it's not used in this
+ * implementation; it would be necessary if anyone wanted to add global
+ * semantics to fts using fts_set. An error return is allowed for similar
+ * reasons.
+ */
+/* ARGSUSED */
+int
+freebsd11_fts_set(FTS11 *sp, FTSENT11 *p, int instr)
+{
+ if (instr != 0 && instr != FTS_AGAIN && instr != FTS_FOLLOW &&
+ instr != FTS_NOINSTR && instr != FTS_SKIP) {
+ errno = EINVAL;
+ return (1);
+ }
+ p->fts_instr = instr;
+ return (0);
+}
+
+FTSENT11 *
+freebsd11_fts_children(FTS11 *sp, int instr)
+{
+ FTSENT11 *p;
+ int fd, rc, serrno;
+
+ if (instr != 0 && instr != FTS_NAMEONLY) {
+ errno = EINVAL;
+ return (NULL);
+ }
+
+ /* Set current node pointer. */
+ p = sp->fts_cur;
+
+ /*
+ * Errno set to 0 so user can distinguish empty directory from
+ * an error.
+ */
+ errno = 0;
+
+ /* Fatal errors stop here. */
+ if (ISSET(FTS_STOP))
+ return (NULL);
+
+ /* Return logical hierarchy of user's arguments. */
+ if (p->fts_info == FTS_INIT)
+ return (p->fts_link);
+
+ /*
+ * If not a directory being visited in pre-order, stop here. Could
+ * allow FTS_DNR, assuming the user has fixed the problem, but the
+ * same effect is available with FTS_AGAIN.
+ */
+ if (p->fts_info != FTS_D /* && p->fts_info != FTS_DNR */)
+ return (NULL);
+
+ /* Free up any previous child list. */
+ if (sp->fts_child != NULL)
+ fts_lfree(sp->fts_child);
+
+ if (instr == FTS_NAMEONLY) {
+ SET(FTS_NAMEONLY);
+ instr = BNAMES;
+ } else
+ instr = BCHILD;
+
+ /*
+ * If using chdir on a relative path and called BEFORE fts_read does
+ * its chdir to the root of a traversal, we can lose -- we need to
+ * chdir into the subdirectory, and we don't know where the current
+ * directory is, so we can't get back so that the upcoming chdir by
+ * fts_read will work.
+ */
+ if (p->fts_level != FTS_ROOTLEVEL || p->fts_accpath[0] == '/' ||
+ ISSET(FTS_NOCHDIR))
+ return (sp->fts_child = fts_build(sp, instr));
+
+ if ((fd = _open(".", O_RDONLY | O_CLOEXEC, 0)) < 0)
+ return (NULL);
+ sp->fts_child = fts_build(sp, instr);
+ serrno = (sp->fts_child == NULL) ? errno : 0;
+ rc = fchdir(fd);
+ if (rc < 0 && serrno == 0)
+ serrno = errno;
+ (void)_close(fd);
+ errno = serrno;
+ if (rc < 0)
+ return (NULL);
+ return (sp->fts_child);
+}
+
+#ifndef freebsd11_fts_get_clientptr
+#error "freebsd11_fts_get_clientptr not defined"
+#endif
+
+void *
+(freebsd11_fts_get_clientptr)(FTS11 *sp)
+{
+
+ return (freebsd11_fts_get_clientptr(sp));
+}
+
+#ifndef freebsd11_fts_get_stream
+#error "freebsd11_fts_get_stream not defined"
+#endif
+
+FTS11 *
+(freebsd11_fts_get_stream)(FTSENT11 *p)
+{
+ return (freebsd11_fts_get_stream(p));
+}
+
+void
+freebsd11_fts_set_clientptr(FTS11 *sp, void *clientptr)
+{
+
+ sp->fts_clientptr = clientptr;
+}
+
+/*
+ * This is the tricky part -- do not casually change *anything* in here. The
+ * idea is to build the linked list of entries that are used by fts_children
+ * and fts_read. There are lots of special cases.
+ *
+ * The real slowdown in walking the tree is the stat calls. If FTS_NOSTAT is
+ * set and it's a physical walk (so that symbolic links can't be directories),
+ * we can do things quickly. First, if it's a 4.4BSD file system, the type
+ * of the file is in the directory entry. Otherwise, we assume that the number
+ * of subdirectories in a node is equal to the number of links to the parent.
+ * The former skips all stat calls. The latter skips stat calls in any leaf
+ * directories and for any files after the subdirectories in the directory have
+ * been found, cutting the stat calls by about 2/3.
+ */
+static FTSENT11 *
+fts_build(FTS11 *sp, int type)
+{
+ struct freebsd11_dirent *dp;
+ FTSENT11 *p, *head;
+ FTSENT11 *cur, *tail;
+ DIR *dirp;
+ void *oldaddr;
+ char *cp;
+ int cderrno, descend, oflag, saved_errno, nostat, doadjust;
+ long level;
+ long nlinks; /* has to be signed because -1 is a magic value */
+ size_t dnamlen, len, maxlen, nitems;
+
+ /* Set current node pointer. */
+ cur = sp->fts_cur;
+
+ /*
+ * Open the directory for reading. If this fails, we're done.
+ * If being called from fts_read, set the fts_info field.
+ */
+#ifdef FTS_WHITEOUT
+ if (ISSET(FTS_WHITEOUT))
+ oflag = DTF_NODUP | DTF_REWIND;
+ else
+ oflag = DTF_HIDEW | DTF_NODUP | DTF_REWIND;
+#else
+#define __opendir2(path, flag) opendir(path)
+#endif
+ if ((dirp = __opendir2(cur->fts_accpath, oflag)) == NULL) {
+ if (type == BREAD) {
+ cur->fts_info = FTS_DNR;
+ cur->fts_errno = errno;
+ }
+ return (NULL);
+ }
+
+ /*
+ * Nlinks is the number of possible entries of type directory in the
+ * directory if we're cheating on stat calls, 0 if we're not doing
+ * any stat calls at all, -1 if we're doing stats on everything.
+ */
+ if (type == BNAMES) {
+ nlinks = 0;
+ /* Be quiet about nostat, GCC. */
+ nostat = 0;
+ } else if (ISSET(FTS_NOSTAT) && ISSET(FTS_PHYSICAL)) {
+ if (fts_ufslinks(sp, cur))
+ nlinks = cur->fts_nlink - (ISSET(FTS_SEEDOT) ? 0 : 2);
+ else
+ nlinks = -1;
+ nostat = 1;
+ } else {
+ nlinks = -1;
+ nostat = 0;
+ }
+
+#ifdef notdef
+ (void)printf("nlinks == %d (cur: %d)\n", nlinks, cur->fts_nlink);
+ (void)printf("NOSTAT %d PHYSICAL %d SEEDOT %d\n",
+ ISSET(FTS_NOSTAT), ISSET(FTS_PHYSICAL), ISSET(FTS_SEEDOT));
+#endif
+ /*
+ * If we're going to need to stat anything or we want to descend
+ * and stay in the directory, chdir. If this fails we keep going,
+ * but set a flag so we don't chdir after the post-order visit.
+ * We won't be able to stat anything, but we can still return the
+ * names themselves. Note, that since fts_read won't be able to
+ * chdir into the directory, it will have to return different path
+ * names than before, i.e. "a/b" instead of "b". Since the node
+ * has already been visited in pre-order, have to wait until the
+ * post-order visit to return the error. There is a special case
+ * here, if there was nothing to stat then it's not an error to
+ * not be able to stat. This is all fairly nasty. If a program
+ * needed sorted entries or stat information, they had better be
+ * checking FTS_NS on the returned nodes.
+ */
+ cderrno = 0;
+ if (nlinks || type == BREAD) {
+ if (fts_safe_changedir(sp, cur, _dirfd(dirp), NULL)) {
+ if (nlinks && type == BREAD)
+ cur->fts_errno = errno;
+ cur->fts_flags |= FTS_DONTCHDIR;
+ descend = 0;
+ cderrno = errno;
+ } else
+ descend = 1;
+ } else
+ descend = 0;
+
+ /*
+ * Figure out the max file name length that can be stored in the
+ * current path -- the inner loop allocates more path as necessary.
+ * We really wouldn't have to do the maxlen calculations here, we
+ * could do them in fts_read before returning the path, but it's a
+ * lot easier here since the length is part of the dirent structure.
+ *
+ * If not changing directories set a pointer so that can just append
+ * each new name into the path.
+ */
+ len = NAPPEND(cur);
+ if (ISSET(FTS_NOCHDIR)) {
+ cp = sp->fts_path + len;
+ *cp++ = '/';
+ } else {
+ /* GCC, you're too verbose. */
+ cp = NULL;
+ }
+ len++;
+ maxlen = sp->fts_pathlen - len;
+
+ level = cur->fts_level + 1;
+
+ /* Read the directory, attaching each entry to the `link' pointer. */
+ doadjust = 0;
+ for (head = tail = NULL, nitems = 0;
+ dirp && (dp = freebsd11_readdir(dirp));) {
+ dnamlen = dp->d_namlen;
+ if (!ISSET(FTS_SEEDOT) && ISDOT(dp->d_name))
+ continue;
+
+ if ((p = fts_alloc(sp, dp->d_name, dnamlen)) == NULL)
+ goto mem1;
+ if (dnamlen >= maxlen) { /* include space for NUL */
+ oldaddr = sp->fts_path;
+ if (fts_palloc(sp, dnamlen + len + 1)) {
+ /*
+ * No more memory for path or structures. Save
+ * errno, free up the current structure and the
+ * structures already allocated.
+ */
+mem1: saved_errno = errno;
+ if (p)
+ free(p);
+ fts_lfree(head);
+ (void)closedir(dirp);
+ cur->fts_info = FTS_ERR;
+ SET(FTS_STOP);
+ errno = saved_errno;
+ return (NULL);
+ }
+ /* Did realloc() change the pointer? */
+ if (oldaddr != sp->fts_path) {
+ doadjust = 1;
+ if (ISSET(FTS_NOCHDIR))
+ cp = sp->fts_path + len;
+ }
+ maxlen = sp->fts_pathlen - len;
+ }
+
+ p->fts_level = level;
+ p->fts_parent = sp->fts_cur;
+ p->fts_pathlen = len + dnamlen;
+
+#ifdef FTS_WHITEOUT
+ if (dp->d_type == DT_WHT)
+ p->fts_flags |= FTS_ISW;
+#endif
+
+ if (cderrno) {
+ if (nlinks) {
+ p->fts_info = FTS_NS;
+ p->fts_errno = cderrno;
+ } else
+ p->fts_info = FTS_NSOK;
+ p->fts_accpath = cur->fts_accpath;
+ } else if (nlinks == 0
+#ifdef DT_DIR
+ || (nostat &&
+ dp->d_type != DT_DIR && dp->d_type != DT_UNKNOWN)
+#endif
+ ) {
+ p->fts_accpath =
+ ISSET(FTS_NOCHDIR) ? p->fts_path : p->fts_name;
+ p->fts_info = FTS_NSOK;
+ } else {
+ /* Build a file name for fts_stat to stat. */
+ if (ISSET(FTS_NOCHDIR)) {
+ p->fts_accpath = p->fts_path;
+ memmove(cp, p->fts_name, p->fts_namelen + 1);
+ p->fts_info = fts_stat(sp, p, 0, _dirfd(dirp));
+ } else {
+ p->fts_accpath = p->fts_name;
+ p->fts_info = fts_stat(sp, p, 0, -1);
+ }
+
+ /* Decrement link count if applicable. */
+ if (nlinks > 0 && (p->fts_info == FTS_D ||
+ p->fts_info == FTS_DC || p->fts_info == FTS_DOT))
+ --nlinks;
+ }
+
+ /* We walk in directory order so "ls -f" doesn't get upset. */
+ p->fts_link = NULL;
+ if (head == NULL)
+ head = tail = p;
+ else {
+ tail->fts_link = p;
+ tail = p;
+ }
+ ++nitems;
+ }
+ if (dirp)
+ (void)closedir(dirp);
+
+ /*
+ * If realloc() changed the address of the path, adjust the
+ * addresses for the rest of the tree and the dir list.
+ */
+ if (doadjust)
+ fts_padjust(sp, head);
+
+ /*
+ * If not changing directories, reset the path back to original
+ * state.
+ */
+ if (ISSET(FTS_NOCHDIR))
+ sp->fts_path[cur->fts_pathlen] = '\0';
+
+ /*
+ * If descended after called from fts_children or after called from
+ * fts_read and nothing found, get back. At the root level we use
+ * the saved fd; if one of fts_open()'s arguments is a relative path
+ * to an empty directory, we wind up here with no other way back. If
+ * can't get back, we're done.
+ */
+ if (descend && (type == BCHILD || !nitems) &&
+ (cur->fts_level == FTS_ROOTLEVEL ?
+ FCHDIR(sp, sp->fts_rfd) :
+ fts_safe_changedir(sp, cur->fts_parent, -1, ".."))) {
+ fts_lfree(head);
+ cur->fts_info = FTS_ERR;
+ SET(FTS_STOP);
+ return (NULL);
+ }
+
+ /* If didn't find anything, return NULL. */
+ if (!nitems) {
+ if (type == BREAD)
+ cur->fts_info = FTS_DP;
+ return (NULL);
+ }
+
+ /* Sort the entries. */
+ if (sp->fts_compar && nitems > 1)
+ head = fts_sort(sp, head, nitems);
+ return (head);
+}
+
+static int
+fts_stat(FTS11 *sp, FTSENT11 *p, int follow, int dfd)
+{
+ FTSENT11 *t;
+ uint32_t dev;
+ uint32_t ino;
+ struct freebsd11_stat *sbp, sb;
+ int saved_errno;
+ const char *path;
+
+ if (dfd == -1)
+ path = p->fts_accpath, dfd = AT_FDCWD;
+ else
+ path = p->fts_name;
+
+ /* If user needs stat info, stat buffer already allocated. */
+ sbp = ISSET(FTS_NOSTAT) ? &sb : p->fts_statp;
+
+#ifdef FTS_WHITEOUT
+ /* Check for whiteout. */
+ if (p->fts_flags & FTS_ISW) {
+ if (sbp != &sb) {
+ memset(sbp, '\0', sizeof(*sbp));
+ sbp->st_mode = S_IFWHT;
+ }
+ return (FTS_W);
+ }
+#endif
+
+ /*
+ * If doing a logical walk, or application requested FTS_FOLLOW, do
+ * a stat(2). If that fails, check for a non-existent symlink. If
+ * fail, set the errno from the stat call.
+ */
+ if (ISSET(FTS_LOGICAL) || follow) {
+ if (freebsd11_fstatat(dfd, path, sbp, 0)) {
+ saved_errno = errno;
+ if (freebsd11_fstatat(dfd, path, sbp,
+ AT_SYMLINK_NOFOLLOW)) {
+ p->fts_errno = saved_errno;
+ goto err;
+ }
+ errno = 0;
+ if (S_ISLNK(sbp->st_mode))
+ return (FTS_SLNONE);
+ }
+ } else if (freebsd11_fstatat(dfd, path, sbp, AT_SYMLINK_NOFOLLOW)) {
+ p->fts_errno = errno;
+err: memset(sbp, 0, sizeof(*sbp));
+ return (FTS_NS);
+ }
+
+ if (S_ISDIR(sbp->st_mode)) {
+ /*
+ * Set the device/inode. Used to find cycles and check for
+ * crossing mount points. Also remember the link count, used
+ * in fts_build to limit the number of stat calls. It is
+ * understood that these fields are only referenced if fts_info
+ * is set to FTS_D.
+ */
+ dev = p->fts_dev = sbp->st_dev;
+ ino = p->fts_ino = sbp->st_ino;
+ p->fts_nlink = sbp->st_nlink;
+
+ if (ISDOT(p->fts_name))
+ return (FTS_DOT);
+
+ /*
+ * Cycle detection is done by brute force when the directory
+ * is first encountered. If the tree gets deep enough or the
+ * number of symbolic links to directories is high enough,
+ * something faster might be worthwhile.
+ */
+ for (t = p->fts_parent;
+ t->fts_level >= FTS_ROOTLEVEL; t = t->fts_parent)
+ if (ino == t->fts_ino && dev == t->fts_dev) {
+ p->fts_cycle = t;
+ return (FTS_DC);
+ }
+ return (FTS_D);
+ }
+ if (S_ISLNK(sbp->st_mode))
+ return (FTS_SL);
+ if (S_ISREG(sbp->st_mode))
+ return (FTS_F);
+ return (FTS_DEFAULT);
+}
+
+/*
+ * The comparison function takes pointers to pointers to FTSENT structures.
+ * Qsort wants a comparison function that takes pointers to void.
+ * (Both with appropriate levels of const-poisoning, of course!)
+ * Use a trampoline function to deal with the difference.
+ */
+static int
+fts_compar(const void *a, const void *b)
+{
+ FTS11 *parent;
+
+ parent = (*(const FTSENT11 * const *)a)->fts_fts;
+ return (*parent->fts_compar)(a, b);
+}
+
+static FTSENT11 *
+fts_sort(FTS11 *sp, FTSENT11 *head, size_t nitems)
+{
+ FTSENT11 **ap, *p;
+
+ /*
+ * Construct an array of pointers to the structures and call qsort(3).
+ * Reassemble the array in the order returned by qsort. If unable to
+ * sort for memory reasons, return the directory entries in their
+ * current order. Allocate enough space for the current needs plus
+ * 40 so don't realloc one entry at a time.
+ */
+ if (nitems > sp->fts_nitems) {
+ sp->fts_nitems = nitems + 40;
+ if ((sp->fts_array = reallocf(sp->fts_array,
+ sp->fts_nitems * sizeof(FTSENT11 *))) == NULL) {
+ sp->fts_nitems = 0;
+ return (head);
+ }
+ }
+ for (ap = sp->fts_array, p = head; p; p = p->fts_link)
+ *ap++ = p;
+ qsort(sp->fts_array, nitems, sizeof(FTSENT11 *), fts_compar);
+ for (head = *(ap = sp->fts_array); --nitems; ++ap)
+ ap[0]->fts_link = ap[1];
+ ap[0]->fts_link = NULL;
+ return (head);
+}
+
+static FTSENT11 *
+fts_alloc(FTS11 *sp, char *name, size_t namelen)
+{
+ FTSENT11 *p;
+ size_t len;
+
+ struct ftsent11_withstat {
+ FTSENT11 ent;
+ struct freebsd11_stat statbuf;
+ };
+
+ /*
+ * The file name is a variable length array and no stat structure is
+ * necessary if the user has set the nostat bit. Allocate the FTSENT
+ * structure, the file name and the stat structure in one chunk, but
+ * be careful that the stat structure is reasonably aligned.
+ */
+ if (ISSET(FTS_NOSTAT))
+ len = sizeof(FTSENT11) + namelen + 1;
+ else
+ len = sizeof(struct ftsent11_withstat) + namelen + 1;
+
+ if ((p = malloc(len)) == NULL)
+ return (NULL);
+
+ if (ISSET(FTS_NOSTAT)) {
+ p->fts_name = (char *)(p + 1);
+ p->fts_statp = NULL;
+ } else {
+ p->fts_name = (char *)((struct ftsent11_withstat *)p + 1);
+ p->fts_statp = &((struct ftsent11_withstat *)p)->statbuf;
+ }
+
+ /* Copy the name and guarantee NUL termination. */
+ memcpy(p->fts_name, name, namelen);
+ p->fts_name[namelen] = '\0';
+ p->fts_namelen = namelen;
+ p->fts_path = sp->fts_path;
+ p->fts_errno = 0;
+ p->fts_flags = 0;
+ p->fts_instr = FTS_NOINSTR;
+ p->fts_number = 0;
+ p->fts_pointer = NULL;
+ p->fts_fts = sp;
+ return (p);
+}
+
+static void
+fts_lfree(FTSENT11 *head)
+{
+ FTSENT11 *p;
+
+ /* Free a linked list of structures. */
+ while ((p = head)) {
+ head = head->fts_link;
+ free(p);
+ }
+}
+
+/*
+ * Allow essentially unlimited paths; find, rm, ls should all work on any tree.
+ * Most systems will allow creation of paths much longer than MAXPATHLEN, even
+ * though the kernel won't resolve them. Add the size (not just what's needed)
+ * plus 256 bytes so don't realloc the path 2 bytes at a time.
+ */
+static int
+fts_palloc(FTS11 *sp, size_t more)
+{
+
+ sp->fts_pathlen += more + 256;
+ sp->fts_path = reallocf(sp->fts_path, sp->fts_pathlen);
+ return (sp->fts_path == NULL);
+}
+
+/*
+ * When the path is realloc'd, have to fix all of the pointers in structures
+ * already returned.
+ */
+static void
+fts_padjust(FTS11 *sp, FTSENT11 *head)
+{
+ FTSENT11 *p;
+ char *addr = sp->fts_path;
+
+#define ADJUST(p) do { \
+ if ((p)->fts_accpath != (p)->fts_name) { \
+ (p)->fts_accpath = \
+ (char *)addr + ((p)->fts_accpath - (p)->fts_path); \
+ } \
+ (p)->fts_path = addr; \
+} while (0)
+ /* Adjust the current set of children. */
+ for (p = sp->fts_child; p; p = p->fts_link)
+ ADJUST(p);
+
+ /* Adjust the rest of the tree, including the current level. */
+ for (p = head; p->fts_level >= FTS_ROOTLEVEL;) {
+ ADJUST(p);
+ p = p->fts_link ? p->fts_link : p->fts_parent;
+ }
+}
+
+static size_t
+fts_maxarglen(char * const *argv)
+{
+ size_t len, max;
+
+ for (max = 0; *argv; ++argv)
+ if ((len = strlen(*argv)) > max)
+ max = len;
+ return (max + 1);
+}
+
+/*
+ * Change to dir specified by fd or p->fts_accpath without getting
+ * tricked by someone changing the world out from underneath us.
+ * Assumes p->fts_dev and p->fts_ino are filled in.
+ */
+static int
+fts_safe_changedir(FTS11 *sp, FTSENT11 *p, int fd, char *path)
+{
+ int ret, oerrno, newfd;
+ struct freebsd11_stat sb;
+
+ newfd = fd;
+ if (ISSET(FTS_NOCHDIR))
+ return (0);
+ if (fd < 0 && (newfd = _open(path, O_RDONLY | O_DIRECTORY |
+ O_CLOEXEC, 0)) < 0)
+ return (-1);
+ if (freebsd11_fstat(newfd, &sb)) {
+ ret = -1;
+ goto bail;
+ }
+ if (p->fts_dev != sb.st_dev || p->fts_ino != sb.st_ino) {
+ errno = ENOENT; /* disinformation */
+ ret = -1;
+ goto bail;
+ }
+ ret = fchdir(newfd);
+bail:
+ oerrno = errno;
+ if (fd < 0)
+ (void)_close(newfd);
+ errno = oerrno;
+ return (ret);
+}
+
+/*
+ * Check if the filesystem for "ent" has UFS-style links.
+ */
+static int
+fts_ufslinks(FTS11 *sp, const FTSENT11 *ent)
+{
+ struct _fts_private11 *priv;
+ const char **cpp;
+
+ priv = (struct _fts_private11 *)sp;
+ /*
+ * If this node's device is different from the previous, grab
+ * the filesystem information, and decide on the reliability
+ * of the link information from this filesystem for stat(2)
+ * avoidance.
+ */
+ if (priv->ftsp_dev != ent->fts_dev) {
+ if (freebsd11_statfs(ent->fts_path, &priv->ftsp_statfs) != -1) {
+ priv->ftsp_dev = ent->fts_dev;
+ priv->ftsp_linksreliable = 0;
+ for (cpp = ufslike_filesystems; *cpp; cpp++) {
+ if (strcmp(priv->ftsp_statfs.f_fstypename,
+ *cpp) == 0) {
+ priv->ftsp_linksreliable = 1;
+ break;
+ }
+ }
+ } else {
+ priv->ftsp_linksreliable = 0;
+ }
+ }
+ return (priv->ftsp_linksreliable);
+}
+
+__sym_compat(fts_open, freebsd11_fts_open, FBSD_1.1);
+__sym_compat(fts_close, freebsd11_fts_close, FBSD_1.1);
+__sym_compat(fts_read, freebsd11_fts_read, FBSD_1.1);
+__sym_compat(fts_set, freebsd11_fts_set, FBSD_1.1);
+__sym_compat(fts_children, freebsd11_fts_children, FBSD_1.1);
+__sym_compat(fts_get_clientptr, freebsd11_fts_get_clientptr, FBSD_1.1);
+__sym_compat(fts_get_stream, freebsd11_fts_get_stream, FBSD_1.1);
+__sym_compat(fts_set_clientptr, freebsd11_fts_set_clientptr, FBSD_1.1);
diff --git a/lib/libc/gen/fts-compat11.h b/lib/libc/gen/fts-compat11.h
new file mode 100644
index 000000000000..52c0637395fb
--- /dev/null
+++ b/lib/libc/gen/fts-compat11.h
@@ -0,0 +1,95 @@
+/*
+ * Copyright (c) 1989, 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.
+ *
+ * @(#)fts.h 8.3 (Berkeley) 8/14/94
+ * $FreeBSD$
+ */
+
+#ifndef _FTS_COPMAT11_H_
+#define _FTS_COPMAT11_H_
+
+typedef struct {
+ struct _ftsent11 *fts_cur; /* current node */
+ struct _ftsent11 *fts_child; /* linked list of children */
+ struct _ftsent11 **fts_array; /* sort array */
+ uint32_t fts_dev; /* starting device # */
+ char *fts_path; /* path for this descent */
+ int fts_rfd; /* fd for root */
+ __size_t fts_pathlen; /* sizeof(path) */
+ __size_t fts_nitems; /* elements in the sort array */
+ int (*fts_compar) /* compare function */
+ (const struct _ftsent11 * const *,
+ const struct _ftsent11 * const *);
+ int fts_options; /* fts_open options, global flags */
+ void *fts_clientptr; /* thunk for sort function */
+} FTS11;
+
+typedef struct _ftsent11 {
+ struct _ftsent11 *fts_cycle; /* cycle node */
+ struct _ftsent11 *fts_parent; /* parent directory */
+ struct _ftsent11 *fts_link; /* next file in directory */
+ long long fts_number; /* local numeric value */
+ void *fts_pointer; /* local address value */
+ char *fts_accpath; /* access path */
+ char *fts_path; /* root path */
+ int fts_errno; /* errno for this node */
+ int fts_symfd; /* fd for symlink */
+ __size_t fts_pathlen; /* strlen(fts_path) */
+ __size_t fts_namelen; /* strlen(fts_name) */
+
+ uint32_t fts_ino; /* inode */
+ uint32_t fts_dev; /* device */
+ uint16_t fts_nlink; /* link count */
+
+ long fts_level; /* depth (-1 to N) */
+
+ int fts_info; /* user status for FTSENT structure */
+
+ unsigned fts_flags; /* private flags for FTSENT structure */
+
+ int fts_instr; /* fts_set() instructions */
+
+ struct freebsd11_stat *fts_statp; /* stat(2) information */
+ char *fts_name; /* file name */
+ FTS11 *fts_fts; /* back pointer to main FTS */
+} FTSENT11;
+
+FTSENT11 *freebsd11_fts_children(FTS11 *, int);
+int freebsd11_fts_close(FTS11 *);
+void *freebsd11_fts_get_clientptr(FTS11 *);
+#define freebsd11_fts_get_clientptr(fts) ((fts)->fts_clientptr)
+FTS11 *freebsd11_fts_get_stream(FTSENT11 *);
+#define freebsd11_fts_get_stream(ftsent) ((ftsent)->fts_fts)
+FTS11 *freebsd11_fts_open(char * const *, int,
+ int (*)(const FTSENT11 * const *,
+ const FTSENT11 * const *));
+FTSENT11 *freebsd11_fts_read(FTS11 *);
+int freebsd11_fts_set(FTS11 *, FTSENT11 *, int);
+void freebsd11_fts_set_clientptr(FTS11 *, void *);
+
+#endif /* !_FTS_COMPAT11_H_ */
diff --git a/lib/libc/gen/fts.c b/lib/libc/gen/fts.c
index 2d51b8b379c1..b8a1b48f6558 100644
--- a/lib/libc/gen/fts.c
+++ b/lib/libc/gen/fts.c
@@ -137,9 +137,6 @@ fts_open(char * const *argv, int options,
sp->fts_compar = compar;
sp->fts_options = options;
- /* Shush, GCC. */
- tmp = NULL;
-
/* Logical walks turn on NOCHDIR; symbolic links are too hard. */
if (ISSET(FTS_LOGICAL))
SET(FTS_NOCHDIR);
@@ -156,6 +153,9 @@ fts_open(char * const *argv, int options,
goto mem2;
parent->fts_level = FTS_ROOTPARENTLEVEL;
+ /* Shush, GCC. */
+ tmp = NULL;
+
/* Allocate/initialize root(s). */
for (root = NULL, nitems = 0; *argv != NULL; ++argv, ++nitems) {
len = strlen(*argv);
diff --git a/lib/libc/gen/ftw-compat11.c b/lib/libc/gen/ftw-compat11.c
new file mode 100644
index 000000000000..cad536d2dcd6
--- /dev/null
+++ b/lib/libc/gen/ftw-compat11.c
@@ -0,0 +1,98 @@
+/* $OpenBSD: ftw.c,v 1.5 2005/08/08 08:05:34 espie Exp $ */
+
+/*
+ * Copyright (c) 2003, 2004 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.
+ *
+ * from: $FreeBSD$
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <errno.h>
+#include <fts.h>
+#include <ftw.h>
+
+#include "fts-compat11.h"
+
+int
+freebsd11_ftw(const char *path,
+ int (*fn)(const char *, const struct freebsd11_stat *, int), int nfds)
+{
+ char * const paths[2] = { (char *)path, NULL };
+ FTSENT11 *cur;
+ FTS11 *ftsp;
+ int error = 0, fnflag, sverrno;
+
+ /* XXX - nfds is currently unused */
+ if (nfds < 1) {
+ errno = EINVAL;
+ return (-1);
+ }
+
+ ftsp = freebsd11_fts_open(paths,
+ FTS_LOGICAL | FTS_COMFOLLOW | FTS_NOCHDIR, NULL);
+ if (ftsp == NULL)
+ return (-1);
+ while ((cur = freebsd11_fts_read(ftsp)) != NULL) {
+ switch (cur->fts_info) {
+ case FTS_D:
+ fnflag = FTW_D;
+ break;
+ case FTS_DNR:
+ fnflag = FTW_DNR;
+ break;
+ case FTS_DP:
+ /* we only visit in preorder */
+ continue;
+ case FTS_F:
+ case FTS_DEFAULT:
+ fnflag = FTW_F;
+ break;
+ case FTS_NS:
+ case FTS_NSOK:
+ case FTS_SLNONE:
+ fnflag = FTW_NS;
+ break;
+ case FTS_SL:
+ fnflag = FTW_SL;
+ break;
+ case FTS_DC:
+ errno = ELOOP;
+ /* FALLTHROUGH */
+ default:
+ error = -1;
+ goto done;
+ }
+ error = fn(cur->fts_path, cur->fts_statp, fnflag);
+ if (error != 0)
+ break;
+ }
+done:
+ sverrno = errno;
+ if (freebsd11_fts_close(ftsp) != 0 && error == 0)
+ error = -1;
+ else
+ errno = sverrno;
+ return (error);
+}
+
+__sym_compat(ftw, freebsd11_ftw, FBSD_1.0);
diff --git a/lib/libc/gen/gen-compat.h b/lib/libc/gen/gen-compat.h
new file mode 100644
index 000000000000..728a15a51b18
--- /dev/null
+++ b/lib/libc/gen/gen-compat.h
@@ -0,0 +1,57 @@
+/*-
+ * Copyright (c) 2012 Gleb Kurtsou <gleb@FreeBSD.org>
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _GEN_COMPAT_H_
+#define _GEN_COMPAT_H_
+
+#include <dirent.h>
+
+#define FREEBSD11_DIRSIZ(dp) \
+ (sizeof(struct freebsd11_dirent) - sizeof((dp)->d_name) + \
+ (((dp)->d_namlen + 1 + 3) &~ 3))
+
+struct freebsd11_dirent;
+struct freebsd11_stat;
+struct freebsd11_statfs;
+
+struct freebsd11_dirent *freebsd11_readdir(DIR *);
+int freebsd11_readdir_r(DIR *, struct freebsd11_dirent *,
+ struct freebsd11_dirent **);
+int freebsd11_stat(const char *, struct freebsd11_stat *);
+int freebsd11_lstat(const char *, struct freebsd11_stat *);
+int freebsd11_fstat(int, struct freebsd11_stat *);
+int freebsd11_fstatat(int, const char *, struct freebsd11_stat *, int);
+
+int freebsd11_statfs(const char *, struct freebsd11_statfs *);
+int freebsd11_getfsstat(struct freebsd11_statfs *, long, int);
+int freebsd11_getmntinfo(struct freebsd11_statfs **, int);
+
+char *freebsd11_devname(__uint32_t dev, __mode_t type);
+char *freebsd11_devname_r(__uint32_t dev, __mode_t type, char *buf, int len);
+
+#endif /* _GEN_COMPAT_H_ */
diff --git a/lib/libc/gen/gen-private.h b/lib/libc/gen/gen-private.h
index d1fab5f31462..0366cbfad8b9 100644
--- a/lib/libc/gen/gen-private.h
+++ b/lib/libc/gen/gen-private.h
@@ -47,12 +47,16 @@ struct _dirdesc {
long dd_size; /* amount of data returned by getdirentries */
char *dd_buf; /* data buffer */
int dd_len; /* size of data buffer */
- long dd_seek; /* magic cookie returned by getdirentries */
+ off_t dd_seek; /* magic cookie returned by getdirentries */
int dd_flags; /* flags for readdir */
struct pthread_mutex *dd_lock; /* lock */
struct _telldir *dd_td; /* telldir position recording */
+ void *dd_compat_de; /* compat dirent */
};
#define _dirfd(dirp) ((dirp)->dd_fd)
+struct dirent;
+int __readdir_r(DIR *dirp, struct dirent *entry, struct dirent **result);
+
#endif /* !_GEN_PRIVATE_H_ */
diff --git a/lib/libc/gen/getmntinfo-compat11.c b/lib/libc/gen/getmntinfo-compat11.c
new file mode 100644
index 000000000000..05ffb74dc8c5
--- /dev/null
+++ b/lib/libc/gen/getmntinfo-compat11.c
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 1989, 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.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)getmntinfo.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/ucred.h>
+#define _WANT_FREEBSD11_STATFS
+#include <sys/mount.h>
+#include <stdlib.h>
+#include "gen-compat.h"
+
+/*
+ * Return information about mounted filesystems.
+ */
+int
+freebsd11_getmntinfo(struct freebsd11_statfs **mntbufp, int flags)
+{
+ static struct freebsd11_statfs *mntbuf;
+ static int mntsize;
+ static long bufsize;
+
+ if (mntsize <= 0 &&
+ (mntsize = freebsd11_getfsstat(0, 0, MNT_NOWAIT)) < 0)
+ return (0);
+ if (bufsize > 0 &&
+ (mntsize = freebsd11_getfsstat(mntbuf, bufsize, flags)) < 0)
+ return (0);
+ while (bufsize <= mntsize * sizeof(struct freebsd11_statfs)) {
+ if (mntbuf)
+ free(mntbuf);
+ bufsize = (mntsize + 1) * sizeof(struct freebsd11_statfs);
+ if ((mntbuf = (struct freebsd11_statfs *)malloc(bufsize)) == 0)
+ return (0);
+ if ((mntsize = freebsd11_getfsstat(mntbuf, bufsize, flags)) < 0)
+ return (0);
+ }
+ *mntbufp = mntbuf;
+ return (mntsize);
+}
+
+__sym_compat(getmntinfo, freebsd11_getmntinfo, FBSD_1.0);
diff --git a/lib/libc/gen/glob-compat11.c b/lib/libc/gen/glob-compat11.c
new file mode 100644
index 000000000000..2bdf99a0bf64
--- /dev/null
+++ b/lib/libc/gen/glob-compat11.c
@@ -0,0 +1,1093 @@
+/*
+ * 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.
+ *
+ * Copyright (c) 2011 The FreeBSD Foundation
+ * All rights reserved.
+ * Portions of this software were developed by David Chisnall
+ * under sponsorship from the FreeBSD Foundation.
+ *
+ * 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: $FreeBSD$
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)glob.c 8.3 (Berkeley) 10/13/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#define _WANT_FREEBSD11_STAT
+#include <sys/stat.h>
+
+#include <ctype.h>
+#define _WANT_FREEBSD11_DIRENT
+#include <dirent.h>
+#include <errno.h>
+#include <glob.h>
+#include <limits.h>
+#include <pwd.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <wchar.h>
+
+#include "collate.h"
+#include "gen-compat.h"
+#include "glob-compat11.h"
+
+/*
+ * glob(3) expansion limits. Stop the expansion if any of these limits
+ * is reached. This caps the runtime in the face of DoS attacks. See
+ * also CVE-2010-2632
+ */
+#define GLOB_LIMIT_BRACE 128 /* number of brace calls */
+#define GLOB_LIMIT_PATH 65536 /* number of path elements */
+#define GLOB_LIMIT_READDIR 16384 /* number of readdirs */
+#define GLOB_LIMIT_STAT 1024 /* number of stat system calls */
+#define GLOB_LIMIT_STRING ARG_MAX /* maximum total size for paths */
+
+struct glob_limit {
+ size_t l_brace_cnt;
+ size_t l_path_lim;
+ size_t l_readdir_cnt;
+ size_t l_stat_cnt;
+ size_t l_string_cnt;
+};
+
+#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
+#define M_MASK 0xffffffffffULL
+#define M_CHAR 0x00ffffffffULL
+
+typedef uint_fast64_t Char;
+
+#define CHAR(c) ((Char)((c)&M_CHAR))
+#define META(c) ((Char)((c)|M_QUOTE))
+#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);
+static int g_lstat(Char *, struct freebsd11_stat *, glob11_t *);
+static DIR *g_opendir(Char *, glob11_t *);
+static const Char *g_strchr(const Char *, wchar_t);
+#ifdef notdef
+static Char *g_strcat(Char *, const Char *);
+#endif
+static int g_stat(Char *, struct freebsd11_stat *, glob11_t *);
+static int glob0(const Char *, glob11_t *, struct glob_limit *,
+ const char *);
+static int glob1(Char *, glob11_t *, struct glob_limit *);
+static int glob2(Char *, Char *, Char *, Char *, glob11_t *,
+ struct glob_limit *);
+static int glob3(Char *, Char *, Char *, Char *, Char *, glob11_t *,
+ struct glob_limit *);
+static int globextend(const Char *, glob11_t *, struct glob_limit *,
+ const char *);
+static const Char *
+ globtilde(const Char *, Char *, size_t, glob11_t *);
+static int globexp0(const Char *, glob11_t *, struct glob_limit *,
+ const char *);
+static int globexp1(const Char *, glob11_t *, struct glob_limit *);
+static int globexp2(const Char *, const Char *, glob11_t *,
+ struct glob_limit *);
+static int globfinal(glob11_t *, struct glob_limit *, size_t,
+ const char *);
+static int match(Char *, Char *, Char *);
+static int err_nomatch(glob11_t *, struct glob_limit *, const char *);
+static int err_aborted(glob11_t *, int, char *);
+#ifdef DEBUG
+static void qprintf(const char *, Char *);
+#endif
+
+int
+freebsd11_glob(const char * __restrict pattern, int flags,
+ int (*errfunc)(const char *, int), glob11_t * __restrict pglob)
+{
+ struct glob_limit limit = { 0, 0, 0, 0, 0 };
+ const char *patnext;
+ Char *bufnext, *bufend, patbuf[MAXPATHLEN], prot;
+ mbstate_t mbs;
+ wchar_t wc;
+ size_t clen;
+ int too_long;
+
+ patnext = pattern;
+ if (!(flags & GLOB_APPEND)) {
+ pglob->gl_pathc = 0;
+ pglob->gl_pathv = NULL;
+ if (!(flags & GLOB_DOOFFS))
+ pglob->gl_offs = 0;
+ }
+ if (flags & GLOB_LIMIT) {
+ limit.l_path_lim = pglob->gl_matchc;
+ if (limit.l_path_lim == 0)
+ limit.l_path_lim = GLOB_LIMIT_PATH;
+ }
+ pglob->gl_flags = flags & ~GLOB_MAGCHAR;
+ pglob->gl_errfunc = errfunc;
+ pglob->gl_matchc = 0;
+
+ bufnext = patbuf;
+ bufend = bufnext + MAXPATHLEN - 1;
+ too_long = 1;
+ if (flags & GLOB_NOESCAPE) {
+ memset(&mbs, 0, sizeof(mbs));
+ while (bufnext <= bufend) {
+ clen = mbrtowc(&wc, patnext, MB_LEN_MAX, &mbs);
+ if (clen == (size_t)-1 || clen == (size_t)-2)
+ 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 (bufnext <= bufend) {
+ if (*patnext == '\\') {
+ if (*++patnext == '\0') {
+ *bufnext++ = QUOTE;
+ continue;
+ }
+ prot = M_PROTECT;
+ } else
+ prot = 0;
+ clen = mbrtowc(&wc, patnext, MB_LEN_MAX, &mbs);
+ if (clen == (size_t)-1 || clen == (size_t)-2)
+ 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 (globexp0(patbuf, pglob, &limit, pattern));
+ else
+ return (glob0(patbuf, pglob, &limit, pattern));
+}
+
+static int
+globexp0(const Char *pattern, glob11_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));
+}
+
+/*
+ * 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(const Char *pattern, glob11_t *pglob, struct glob_limit *limit)
+{
+ const Char* ptr;
+
+ 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));
+ }
+
+ return (glob0(pattern, pglob, limit, NULL));
+}
+
+
+/*
+ * 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(const Char *ptr, const Char *pattern, glob11_t *pglob,
+ struct glob_limit *limit)
+{
+ int i, rv;
+ Char *lm, *ls;
+ const Char *pe, *pm, *pm1, *pl;
+ Char patbuf[MAXPATHLEN];
+
+ /* 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 != EOS; 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)
+ return (glob0(pattern, pglob, limit, NULL));
+
+ for (i = 0, pl = pm = ptr; pm <= pe; pm++)
+ switch (*pm) {
+ case LBRACKET:
+ /* Ignore everything between [] */
+ for (pm1 = pm++; *pm != RBRACKET && *pm != EOS; pm++)
+ continue;
+ if (*pm == EOS) {
+ /*
+ * We could not find a matching RBRACKET.
+ * Ignore and just look for RBRACE
+ */
+ pm = pm1;
+ }
+ 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, limit);
+ if (rv)
+ return (rv);
+
+ /* move after the comma, to the next string */
+ pl = pm + 1;
+ }
+ break;
+
+ default:
+ break;
+ }
+ return (0);
+}
+
+
+
+/*
+ * expand tilde from the passwd file.
+ */
+static const Char *
+globtilde(const Char *pattern, Char *patbuf, size_t patbuf_len, glob11_t *pglob)
+{
+ struct passwd *pwd;
+ 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);
+
+ /*
+ * Copy up to the end of the string or /
+ */
+ eb = &patbuf[patbuf_len - 1];
+ for (p = pattern + 1, b = patbuf;
+ b < eb && *p != EOS && UNPROT(*p) != SEP; *b++ = *p++)
+ continue;
+
+ if (*p != EOS && UNPROT(*p) != SEP)
+ return (NULL);
+
+ *b = EOS;
+ h = NULL;
+
+ if (patbuf[0] == EOS) {
+ /*
+ * handle a plain ~ or ~/ by expanding $HOME first (iff
+ * we're not running setuid or setgid) and then trying
+ * the password file
+ */
+ if (issetugid() != 0 ||
+ (h = getenv("HOME")) == NULL) {
+ if (((h = getlogin()) != NULL &&
+ (pwd = getpwnam(h)) != NULL) ||
+ (pwd = getpwuid(getuid())) != NULL)
+ h = pwd->pw_dir;
+ else
+ return (pattern);
+ }
+ }
+ else {
+ /*
+ * Expand a ~user
+ */
+ 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 */
+ 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 */
+ 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);
+}
+
+
+/*
+ * 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.
+ */
+static int
+glob0(const Char *pattern, glob11_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;
+
+ /* 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 {
+ *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, pglob, limit)) != 0)
+ return(err);
+
+ if (origpat != NULL)
+ return (globfinal(pglob, limit, oldpathc, origpat));
+
+ return (0);
+}
+
+static int
+globfinal(glob11_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 (strcoll(*(char **)p, *(char **)q));
+}
+
+static int
+glob1(Char *pattern, glob11_t *pglob, struct glob_limit *limit)
+{
+ Char pathbuf[MAXPATHLEN];
+
+ /* A null pathname is invalid -- POSIX 1003.1 sect. 2.4. */
+ if (*pattern == EOS)
+ return (0);
+ return (glob2(pathbuf, pathbuf, pathbuf + MAXPATHLEN - 1,
+ pattern, pglob, limit));
+}
+
+/*
+ * 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(Char *pathbuf, Char *pathend, Char *pathend_last, Char *pattern,
+ glob11_t *pglob, struct glob_limit *limit)
+{
+ struct freebsd11_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_LIMIT) &&
+ limit->l_stat_cnt++ >= GLOB_LIMIT_STAT) {
+ errno = E2BIG;
+ return (GLOB_NOSPACE);
+ }
+ 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) {
+ errno = E2BIG;
+ return (GLOB_NOSPACE);
+ }
+ *pathend++ = SEP;
+ *pathend = EOS;
+ }
+ ++pglob->gl_matchc;
+ return (globextend(pathbuf, pglob, limit, NULL));
+ }
+
+ /* Find end of next segment, copy tentatively to pathend. */
+ q = pathend;
+ p = pattern;
+ while (*p != EOS && UNPROT(*p) != SEP) {
+ if (ismeta(*p))
+ anymeta = 1;
+ if (q + 1 > pathend_last) {
+ errno = E2BIG;
+ return (GLOB_NOSPACE);
+ }
+ *q++ = *p++;
+ }
+
+ if (!anymeta) { /* No expansion, do next segment. */
+ pathend = q;
+ pattern = p;
+ while (UNPROT(*pattern) == SEP) {
+ if (pathend + 1 > pathend_last) {
+ errno = E2BIG;
+ return (GLOB_NOSPACE);
+ }
+ *pathend++ = *pattern++;
+ }
+ } else /* Need expansion, recurse. */
+ return (glob3(pathbuf, pathend, pathend_last, pattern,
+ p, pglob, limit));
+ }
+ /* NOTREACHED */
+}
+
+static int
+glob3(Char *pathbuf, Char *pathend, Char *pathend_last,
+ Char *pattern, Char *restpattern,
+ glob11_t *pglob, struct glob_limit *limit)
+{
+ struct freebsd11_dirent *dp;
+ DIR *dirp;
+ int err, too_long, saverrno, saverrno2;
+ char buf[MAXPATHLEN + MB_LEN_MAX - 1];
+
+ struct freebsd11_dirent *(*readdirfunc)(DIR *);
+
+ if (pathend > pathend_last) {
+ errno = E2BIG;
+ return (GLOB_NOSPACE);
+ }
+ *pathend = EOS;
+ 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) {
+ if (errno == ENOENT || errno == ENOTDIR)
+ return (0);
+ err = err_aborted(pglob, errno, buf);
+ if (errno == 0)
+ errno = saverrno;
+ return (err);
+ }
+
+ err = 0;
+
+ /* pglob->gl_readdir takes a void *, fix this manually */
+ if (pglob->gl_flags & GLOB_ALTDIRFUNC)
+ readdirfunc =
+ (struct freebsd11_dirent *(*)(DIR *))pglob->gl_readdir;
+ else
+ readdirfunc = freebsd11_readdir;
+
+ errno = 0;
+ /* Search directory for matching names. */
+ while ((dp = (*readdirfunc)(dirp)) != NULL) {
+ char *sc;
+ Char *dc;
+ wchar_t wc;
+ size_t clen;
+ mbstate_t mbs;
+
+ if ((pglob->gl_flags & GLOB_LIMIT) &&
+ limit->l_readdir_cnt++ >= GLOB_LIMIT_READDIR) {
+ errno = E2BIG;
+ err = GLOB_NOSPACE;
+ break;
+ }
+
+ /* Initial DOT must be matched literally. */
+ if (dp->d_name[0] == '.' && UNPROT(*pattern) != DOT) {
+ errno = 0;
+ continue;
+ }
+ memset(&mbs, 0, sizeof(mbs));
+ dc = pathend;
+ sc = dp->d_name;
+ too_long = 1;
+ while (dc <= pathend_last) {
+ 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 && (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);
+ 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);
+}
+
+
+/*
+ * Extend the gl_pathv member of a glob11_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 glob11_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(const Char *path, glob11_t *pglob, struct glob_limit *limit,
+ const char *origpat)
+{
+ char **pathv;
+ size_t i, newn, len;
+ char *copy;
+ const Char *p;
+
+ if ((pglob->gl_flags & GLOB_LIMIT) &&
+ pglob->gl_matchc > limit->l_path_lim) {
+ errno = E2BIG;
+ return (GLOB_NOSPACE);
+ }
+
+ newn = 2 + pglob->gl_pathc + pglob->gl_offs;
+ /* reallocarray(NULL, newn, size) is equivalent to malloc(newn*size). */
+ pathv = reallocarray(pglob->gl_pathv, newn, sizeof(*pathv));
+ if (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 + 1; --i > 0; )
+ *--pathv = NULL;
+ }
+ pglob->gl_pathv = pathv;
+
+ 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 != 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;
+ }
+ pathv[pglob->gl_offs + pglob->gl_pathc] = NULL;
+ return (copy == NULL ? GLOB_NOSPACE : 0);
+}
+
+/*
+ * pattern matching function for filenames.
+ */
+static int
+match(Char *name, Char *pat, Char *patend)
+{
+ int ok, negate_range;
+ Char c, k, *nextp, *nextn;
+ struct xlocale_collate *table =
+ (struct xlocale_collate*)__get_locale()->components[XLC_COLLATE];
+
+ nextn = NULL;
+ nextp = NULL;
+
+ while (1) {
+ while (pat < patend) {
+ c = *pat++;
+ switch (c & M_MASK) {
+ case M_ALL:
+ if (pat == patend)
+ return (1);
+ if (*name == EOS)
+ return (0);
+ nextn = name + 1;
+ nextp = pat - 1;
+ break;
+ case M_ONE:
+ if (*name++ == EOS)
+ goto fail;
+ break;
+ case M_SET:
+ ok = 0;
+ if ((k = *name++) == EOS)
+ goto fail;
+ negate_range = ((*pat & M_MASK) == M_NOT);
+ if (negate_range != 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)
+ ok = 1;
+ pat += 2;
+ } else if (c == k)
+ ok = 1;
+ if (ok == negate_range)
+ goto fail;
+ break;
+ default:
+ if (*name++ != c)
+ goto fail;
+ break;
+ }
+ }
+ if (*name == EOS)
+ return (1);
+
+ fail:
+ if (nextn == NULL)
+ break;
+ pat = nextp;
+ name = nextn;
+ }
+ return (0);
+}
+
+/* Free allocated data belonging to a glob11_t structure. */
+void
+freebsd11_globfree(glob11_t *pglob)
+{
+ size_t 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(Char *str, glob11_t *pglob)
+{
+ char buf[MAXPATHLEN + MB_LEN_MAX - 1];
+
+ if (*str == EOS)
+ strcpy(buf, ".");
+ else {
+ if (g_Ctoc(str, buf, sizeof(buf))) {
+ errno = ENAMETOOLONG;
+ return (NULL);
+ }
+ }
+
+ if (pglob->gl_flags & GLOB_ALTDIRFUNC)
+ return ((*pglob->gl_opendir)(buf));
+
+ return (opendir(buf));
+}
+
+static int
+g_lstat(Char *fn, struct freebsd11_stat *sb, glob11_t *pglob)
+{
+ char buf[MAXPATHLEN + MB_LEN_MAX - 1];
+
+ if (g_Ctoc(fn, buf, sizeof(buf))) {
+ errno = ENAMETOOLONG;
+ return (-1);
+ }
+ if (pglob->gl_flags & GLOB_ALTDIRFUNC)
+ return((*pglob->gl_lstat)(buf, sb));
+ return (freebsd11_lstat(buf, sb));
+}
+
+static int
+g_stat(Char *fn, struct freebsd11_stat *sb, glob11_t *pglob)
+{
+ char buf[MAXPATHLEN + MB_LEN_MAX - 1];
+
+ if (g_Ctoc(fn, buf, sizeof(buf))) {
+ errno = ENAMETOOLONG;
+ return (-1);
+ }
+ if (pglob->gl_flags & GLOB_ALTDIRFUNC)
+ return ((*pglob->gl_stat)(buf, sb));
+ return (freebsd11_stat(buf, sb));
+}
+
+static const Char *
+g_strchr(const Char *str, wchar_t ch)
+{
+
+ do {
+ if (*str == ch)
+ return (str);
+ } while (*str++);
+ return (NULL);
+}
+
+static int
+g_Ctoc(const Char *str, char *buf, size_t len)
+{
+ mbstate_t mbs;
+ size_t clen;
+
+ memset(&mbs, 0, sizeof(mbs));
+ while (len >= MB_CUR_MAX) {
+ 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;
+ len -= clen;
+ }
+ return (1);
+}
+
+static int
+err_nomatch(glob11_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(glob11_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);
+ 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
+
+__sym_compat(glob, freebsd11_glob, FBSD_1.0);
+__sym_compat(globfree, freebsd11_globfree, FBSD_1.0);
diff --git a/lib/libc/gen/glob-compat11.h b/lib/libc/gen/glob-compat11.h
new file mode 100644
index 000000000000..d43086f819c5
--- /dev/null
+++ b/lib/libc/gen/glob-compat11.h
@@ -0,0 +1,72 @@
+/*
+ * 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
+ * from: $FreeBSD$
+ * $FreeBSD$
+ */
+
+#ifndef _GLOB_COMPAT11_H_
+#define _GLOB_COMPAT11_H_
+
+#include <sys/cdefs.h>
+#include <sys/types.h>
+#include <glob.h>
+
+struct freebsd11_stat;
+typedef struct {
+ size_t gl_pathc; /* Count of total paths so far. */
+ size_t gl_matchc; /* Count of paths matching pattern. */
+ size_t 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. */
+ int (*gl_errfunc)(const char *, int);
+
+ /*
+ * Alternate filesystem access methods for glob; replacement
+ * versions of closedir(3), readdir(3), opendir(3), stat(2)
+ * and lstat(2).
+ */
+ void (*gl_closedir)(void *);
+ struct freebsd11_dirent *(*gl_readdir)(void *);
+ void *(*gl_opendir)(const char *);
+ int (*gl_lstat)(const char *, struct freebsd11_stat *);
+ int (*gl_stat)(const char *, struct freebsd11_stat *);
+} glob11_t;
+
+__BEGIN_DECLS
+int freebsd11_glob(const char * __restrict, int,
+ int (*)(const char *, int), glob11_t * __restrict);
+void freebsd11_globfree(glob11_t *);
+__END_DECLS
+
+#endif /* !_GLOB_COMPAT11_H_ */
diff --git a/lib/libc/gen/nftw-compat11.c b/lib/libc/gen/nftw-compat11.c
new file mode 100644
index 000000000000..5293f9ed6ad4
--- /dev/null
+++ b/lib/libc/gen/nftw-compat11.c
@@ -0,0 +1,115 @@
+/*
+ * Copyright (c) 2003, 2004 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.
+ *
+ * from: $OpenBSD: nftw.c,v 1.7 2006/03/31 19:41:44 millert Exp $
+ * from: $FreeBSD$
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <errno.h>
+#include <fts.h>
+#include <ftw.h>
+
+#include "fts-compat11.h"
+
+int
+freebsd11_nftw(const char *path,
+ int (*fn)(const char *, const struct freebsd11_stat *, int, struct FTW *),
+ int nfds, int ftwflags)
+{
+ char * const paths[2] = { (char *)path, NULL };
+ struct FTW ftw;
+ FTSENT11 *cur;
+ FTS11 *ftsp;
+ int error = 0, ftsflags, fnflag, postorder, sverrno;
+
+ /* XXX - nfds is currently unused */
+ if (nfds < 1) {
+ errno = EINVAL;
+ return (-1);
+ }
+
+ ftsflags = FTS_COMFOLLOW;
+ if (!(ftwflags & FTW_CHDIR))
+ ftsflags |= FTS_NOCHDIR;
+ if (ftwflags & FTW_MOUNT)
+ ftsflags |= FTS_XDEV;
+ if (ftwflags & FTW_PHYS)
+ ftsflags |= FTS_PHYSICAL;
+ else
+ ftsflags |= FTS_LOGICAL;
+ postorder = (ftwflags & FTW_DEPTH) != 0;
+ ftsp = freebsd11_fts_open(paths, ftsflags, NULL);
+ if (ftsp == NULL)
+ return (-1);
+ while ((cur = freebsd11_fts_read(ftsp)) != NULL) {
+ switch (cur->fts_info) {
+ case FTS_D:
+ if (postorder)
+ continue;
+ fnflag = FTW_D;
+ break;
+ case FTS_DC:
+ continue;
+ case FTS_DNR:
+ fnflag = FTW_DNR;
+ break;
+ case FTS_DP:
+ if (!postorder)
+ continue;
+ fnflag = FTW_DP;
+ break;
+ case FTS_F:
+ case FTS_DEFAULT:
+ fnflag = FTW_F;
+ break;
+ case FTS_NS:
+ case FTS_NSOK:
+ fnflag = FTW_NS;
+ break;
+ case FTS_SL:
+ fnflag = FTW_SL;
+ break;
+ case FTS_SLNONE:
+ fnflag = FTW_SLN;
+ break;
+ default:
+ error = -1;
+ goto done;
+ }
+ ftw.base = cur->fts_pathlen - cur->fts_namelen;
+ ftw.level = cur->fts_level;
+ error = fn(cur->fts_path, cur->fts_statp, fnflag, &ftw);
+ if (error != 0)
+ break;
+ }
+done:
+ sverrno = errno;
+ if (freebsd11_fts_close(ftsp) != 0 && error == 0)
+ error = -1;
+ else
+ errno = sverrno;
+ return (error);
+}
+
+__sym_compat(nftw, freebsd11_nftw, FBSD_1.0);
diff --git a/lib/libc/gen/opendir.c b/lib/libc/gen/opendir.c
index f828b8d7598f..927e08b8fcc8 100644
--- a/lib/libc/gen/opendir.c
+++ b/lib/libc/gen/opendir.c
@@ -296,6 +296,7 @@ __opendir_common(int fd, int flags, bool use_current_pos)
dirp->dd_td = (struct _telldir *)((char *)dirp + sizeof(DIR));
LIST_INIT(&dirp->dd_td->td_locq);
dirp->dd_td->td_loccnt = 0;
+ dirp->dd_compat_de = NULL;
/*
* Use the system page size if that is a multiple of DIRBLKSIZ.
diff --git a/lib/libc/gen/readdir-compat11.c b/lib/libc/gen/readdir-compat11.c
new file mode 100644
index 000000000000..c374d35e7392
--- /dev/null
+++ b/lib/libc/gen/readdir-compat11.c
@@ -0,0 +1,120 @@
+/*
+ * Copyright (c) 1983, 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.
+ *
+ * from:
+ * $FreeBSD$
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)readdir.c 8.3 (Berkeley) 9/29/94";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "namespace.h"
+#include <sys/param.h>
+#define _WANT_FREEBSD11_DIRENT
+#include <dirent.h>
+#include <errno.h>
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <pthread.h>
+#include "un-namespace.h"
+
+#include "libc_private.h"
+#include "gen-private.h"
+#include "telldir.h"
+
+#include "gen-compat.h"
+
+static bool
+freebsd11_cvtdirent(struct freebsd11_dirent *dstdp, struct dirent *srcdp)
+{
+
+ if (srcdp->d_namlen >= sizeof(dstdp->d_name))
+ return (false);
+ dstdp->d_type = srcdp->d_type;
+ dstdp->d_namlen = srcdp->d_namlen;
+ dstdp->d_fileno = srcdp->d_fileno; /* truncate */
+ dstdp->d_reclen = FREEBSD11_DIRSIZ(dstdp);
+ bcopy(srcdp->d_name, dstdp->d_name, dstdp->d_namlen);
+ bzero(dstdp->d_name + dstdp->d_namlen,
+ dstdp->d_reclen - offsetof(struct freebsd11_dirent, d_name) -
+ dstdp->d_namlen);
+ return (true);
+}
+
+struct freebsd11_dirent *
+freebsd11_readdir(DIR *dirp)
+{
+ struct freebsd11_dirent *dstdp;
+ struct dirent *dp;
+
+ if (__isthreaded)
+ _pthread_mutex_lock(&dirp->dd_lock);
+ dp = _readdir_unlocked(dirp, RDU_SKIP);
+ if (dp != NULL) {
+ if (dirp->dd_compat_de == NULL)
+ dirp->dd_compat_de = malloc(sizeof(struct
+ freebsd11_dirent));
+ if (freebsd11_cvtdirent(dirp->dd_compat_de, dp))
+ dstdp = dirp->dd_compat_de;
+ else
+ dstdp = NULL;
+ } else
+ dstdp = NULL;
+ if (__isthreaded)
+ _pthread_mutex_unlock(&dirp->dd_lock);
+
+ return (dstdp);
+}
+
+int
+freebsd11_readdir_r(DIR *dirp, struct freebsd11_dirent *entry,
+ struct freebsd11_dirent **result)
+{
+ struct dirent xentry, *xresult;
+ int error;
+
+ error = __readdir_r(dirp, &xentry, &xresult);
+ if (error != 0)
+ return (error);
+ if (xresult != NULL) {
+ if (freebsd11_cvtdirent(entry, &xentry))
+ *result = entry;
+ else /* should not happen due to RDU_SHORT */
+ *result = NULL;
+ } else
+ *result = NULL;
+ return (0);
+}
+
+__sym_compat(readdir, freebsd11_readdir, FBSD_1.0);
+__sym_compat(readdir_r, freebsd11_readdir_r, FBSD_1.0);
diff --git a/lib/libc/gen/readdir.c b/lib/libc/gen/readdir.c
index a547f47857bb..22623bb0876b 100644
--- a/lib/libc/gen/readdir.c
+++ b/lib/libc/gen/readdir.c
@@ -49,7 +49,7 @@ __FBSDID("$FreeBSD$");
* get next entry in a directory.
*/
struct dirent *
-_readdir_unlocked(DIR *dirp, int skip)
+_readdir_unlocked(DIR *dirp, int flags)
{
struct dirent *dp;
long initial_seek;
@@ -80,10 +80,13 @@ _readdir_unlocked(DIR *dirp, int skip)
dp->d_reclen > dirp->dd_len + 1 - dirp->dd_loc)
return (NULL);
dirp->dd_loc += dp->d_reclen;
- if (dp->d_ino == 0 && skip)
+ if (dp->d_ino == 0 && (flags & RDU_SKIP) != 0)
continue;
if (dp->d_type == DT_WHT && (dirp->dd_flags & DTF_HIDEW))
continue;
+ if (dp->d_namlen >= sizeof(dp->d_name) &&
+ (flags & RDU_SHORT) != 0)
+ continue;
return (dp);
}
}
@@ -91,34 +94,31 @@ _readdir_unlocked(DIR *dirp, int skip)
struct dirent *
readdir(DIR *dirp)
{
- struct dirent *dp;
+ struct dirent *dp;
- if (__isthreaded) {
+ if (__isthreaded)
_pthread_mutex_lock(&dirp->dd_lock);
- dp = _readdir_unlocked(dirp, 1);
+ dp = _readdir_unlocked(dirp, RDU_SKIP);
+ if (__isthreaded)
_pthread_mutex_unlock(&dirp->dd_lock);
- }
- else
- dp = _readdir_unlocked(dirp, 1);
return (dp);
}
int
-readdir_r(DIR *dirp, struct dirent *entry, struct dirent **result)
+__readdir_r(DIR *dirp, struct dirent *entry, struct dirent **result)
{
struct dirent *dp;
int saved_errno;
saved_errno = errno;
errno = 0;
- if (__isthreaded) {
+ if (__isthreaded)
_pthread_mutex_lock(&dirp->dd_lock);
- if ((dp = _readdir_unlocked(dirp, 1)) != NULL)
- memcpy(entry, dp, _GENERIC_DIRSIZ(dp));
- _pthread_mutex_unlock(&dirp->dd_lock);
- }
- else if ((dp = _readdir_unlocked(dirp, 1)) != NULL)
+ dp = _readdir_unlocked(dirp, RDU_SKIP | RDU_SHORT);
+ if (dp != NULL)
memcpy(entry, dp, _GENERIC_DIRSIZ(dp));
+ if (__isthreaded)
+ _pthread_mutex_unlock(&dirp->dd_lock);
if (errno != 0) {
if (dp == NULL)
@@ -133,3 +133,5 @@ readdir_r(DIR *dirp, struct dirent *entry, struct dirent **result)
return (0);
}
+
+__strong_reference(__readdir_r, readdir_r);
diff --git a/lib/libc/gen/scandir-compat11.c b/lib/libc/gen/scandir-compat11.c
new file mode 100644
index 000000000000..28120c0bc13d
--- /dev/null
+++ b/lib/libc/gen/scandir-compat11.c
@@ -0,0 +1,174 @@
+/*
+ * Copyright (c) 1983, 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.
+ *
+ * from:
+ * $FreeBSD$
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)scandir.c 8.3 (Berkeley) 1/2/94";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * Scan the directory dirname calling select to make a list of selected
+ * directory entries then sort using qsort and compare routine dcomp.
+ * Returns the number of entries and a pointer to a list of pointers to
+ * struct dirent (through namelist). Returns -1 if there were any errors.
+ */
+
+#include "namespace.h"
+#define _WANT_FREEBSD11_DIRENT
+#include <dirent.h>
+#include <stdlib.h>
+#include <string.h>
+#include "un-namespace.h"
+
+#include "gen-compat.h"
+
+#ifdef I_AM_SCANDIR_B
+#include "block_abi.h"
+#define SELECT(x) CALL_BLOCK(select, x)
+#ifndef __BLOCKS__
+void
+qsort_b(void *, size_t, size_t, void*);
+#endif
+#else
+#define SELECT(x) select(x)
+#endif
+
+static int freebsd11_alphasort_thunk(void *thunk, const void *p1,
+ const void *p2);
+
+int
+#ifdef I_AM_SCANDIR_B
+freebsd11_scandir_b(const char *dirname, struct freebsd11_dirent ***namelist,
+ DECLARE_BLOCK(int, select, const struct freebsd11_dirent *),
+ DECLARE_BLOCK(int, dcomp, const struct freebsd11_dirent **,
+ const struct freebsd11_dirent **))
+#else
+freebsd11_scandir(const char *dirname, struct freebsd11_dirent ***namelist,
+ int (*select)(const struct freebsd11_dirent *),
+ int (*dcomp)(const struct freebsd11_dirent **,
+ const struct freebsd11_dirent **))
+#endif
+{
+ struct freebsd11_dirent *d, *p, **names = NULL;
+ size_t arraysz, numitems;
+ DIR *dirp;
+
+ if ((dirp = opendir(dirname)) == NULL)
+ return(-1);
+
+ numitems = 0;
+ arraysz = 32; /* initial estimate of the array size */
+ names = (struct freebsd11_dirent **)malloc(
+ arraysz * sizeof(struct freebsd11_dirent *));
+ if (names == NULL)
+ goto fail;
+
+ while ((d = freebsd11_readdir(dirp)) != NULL) {
+ if (select != NULL && !SELECT(d))
+ continue; /* just selected names */
+ /*
+ * Make a minimum size copy of the data
+ */
+ p = (struct freebsd11_dirent *)malloc(FREEBSD11_DIRSIZ(d));
+ if (p == NULL)
+ goto fail;
+ p->d_fileno = d->d_fileno;
+ p->d_type = d->d_type;
+ p->d_reclen = d->d_reclen;
+ p->d_namlen = d->d_namlen;
+ bcopy(d->d_name, p->d_name, p->d_namlen + 1);
+ /*
+ * Check to make sure the array has space left and
+ * realloc the maximum size.
+ */
+ if (numitems >= arraysz) {
+ struct freebsd11_dirent **names2;
+
+ names2 = reallocarray(names, arraysz,
+ 2 * sizeof(struct freebsd11_dirent *));
+ if (names2 == NULL) {
+ free(p);
+ goto fail;
+ }
+ names = names2;
+ arraysz *= 2;
+ }
+ names[numitems++] = p;
+ }
+ closedir(dirp);
+ if (numitems && dcomp != NULL)
+#ifdef I_AM_SCANDIR_B
+ qsort_b(names, numitems, sizeof(struct freebsd11_dirent *),
+ (void*)dcomp);
+#else
+ qsort_r(names, numitems, sizeof(struct freebsd11_dirent *),
+ &dcomp, freebsd11_alphasort_thunk);
+#endif
+ *namelist = names;
+ return (numitems);
+
+fail:
+ while (numitems > 0)
+ free(names[--numitems]);
+ free(names);
+ closedir(dirp);
+ return (-1);
+}
+
+/*
+ * Alphabetic order comparison routine for those who want it.
+ * POSIX 2008 requires that alphasort() uses strcoll().
+ */
+int
+freebsd11_alphasort(const struct freebsd11_dirent **d1,
+ const struct freebsd11_dirent **d2)
+{
+
+ return (strcoll((*d1)->d_name, (*d2)->d_name));
+}
+
+static int
+freebsd11_alphasort_thunk(void *thunk, const void *p1, const void *p2)
+{
+ int (*dc)(const struct freebsd11_dirent **, const struct
+ freebsd11_dirent **);
+
+ dc = *(int (**)(const struct freebsd11_dirent **,
+ const struct freebsd11_dirent **))thunk;
+ return (dc((const struct freebsd11_dirent **)p1,
+ (const struct freebsd11_dirent **)p2));
+}
+
+__sym_compat(alphasort, freebsd11_alphasort, FBSD_1.0);
+__sym_compat(scandir, freebsd11_scandir, FBSD_1.0);
+__sym_compat(scandir_b, freebsd11_scandir_b, FBSD_1.4);
diff --git a/lib/libc/gen/scandir.c b/lib/libc/gen/scandir.c
index 00183b61de73..b7ec171764c4 100644
--- a/lib/libc/gen/scandir.c
+++ b/lib/libc/gen/scandir.c
@@ -59,17 +59,6 @@ qsort_b(void *, size_t, size_t, void*);
static int alphasort_thunk(void *thunk, const void *p1, const void *p2);
-/*
- * The DIRSIZ macro is the minimum record length which will hold the directory
- * entry. This requires the amount of space in struct dirent without the
- * d_name field, plus enough space for the name and a terminating nul byte
- * (dp->d_namlen + 1), rounded up to a 4 byte boundary.
- */
-#undef DIRSIZ
-#define DIRSIZ(dp) \
- ((sizeof(struct dirent) - sizeof(dp)->d_name) + \
- (((dp)->d_namlen + 1 + 3) &~ 3))
-
int
#ifdef I_AM_SCANDIR_B
scandir_b(const char *dirname, struct dirent ***namelist,
@@ -100,7 +89,7 @@ scandir(const char *dirname, struct dirent ***namelist,
/*
* Make a minimum size copy of the data
*/
- p = (struct dirent *)malloc(DIRSIZ(d));
+ p = (struct dirent *)malloc(_GENERIC_DIRSIZ(d));
if (p == NULL)
goto fail;
p->d_fileno = d->d_fileno;
diff --git a/lib/libc/gen/sem_timedwait.3 b/lib/libc/gen/sem_timedwait.3
index 15617b7df0f1..e5e651541d37 100644
--- a/lib/libc/gen/sem_timedwait.3
+++ b/lib/libc/gen/sem_timedwait.3
@@ -34,7 +34,7 @@
.\"
.\" $FreeBSD$
.\"
-.Dd February 28, 2017
+.Dd May 24, 2017
.Dt SEM_TIMEDWAIT 3
.Os
.Sh NAME
@@ -160,4 +160,4 @@ function first appeared in
The
.Fn sem_clockwait_np
function first appeared in
-.Fx 12.0 .
+.Fx 11.1 .
diff --git a/lib/libc/gen/tcsendbreak.3 b/lib/libc/gen/tcsendbreak.3
index 50b664704ce8..4fa3fab4906f 100644
--- a/lib/libc/gen/tcsendbreak.3
+++ b/lib/libc/gen/tcsendbreak.3
@@ -177,4 +177,3 @@ without writing all output.
The default value for
.Va kern.tty_drainwait
is 300 seconds.
-
diff --git a/lib/libc/gen/telldir.h b/lib/libc/gen/telldir.h
index bccabb1aea53..50adb351e91d 100644
--- a/lib/libc/gen/telldir.h
+++ b/lib/libc/gen/telldir.h
@@ -47,7 +47,7 @@
struct ddloc {
LIST_ENTRY(ddloc) loc_lqe; /* entry in list */
long loc_index; /* key associated with structure */
- long loc_seek; /* magic cookie returned by getdirentries */
+ off_t loc_seek; /* magic cookie returned by getdirentries */
long loc_loc; /* offset of entry in buffer */
};
@@ -66,4 +66,7 @@ void _reclaim_telldir(DIR *);
void _seekdir(DIR *, long);
void _fixtelldir(DIR *dirp, long oldseek, long oldloc);
+#define RDU_SKIP 0x0001
+#define RDU_SHORT 0x0002
+
#endif
diff --git a/lib/libc/iconv/__iconv_get_list.3 b/lib/libc/iconv/__iconv_get_list.3
index 076f4d5b6a1d..14f1560d56f4 100644
--- a/lib/libc/iconv/__iconv_get_list.3
+++ b/lib/libc/iconv/__iconv_get_list.3
@@ -38,7 +38,7 @@
.Dt __ICONV_GET_LIST 3
.Os
.Sh NAME
-.Nm __iconv_get_list
+.Nm __iconv_get_list ,
.Nm __iconv_free_list
.Nd retrieving a list of character encodings supported by
.Xr iconv 3
diff --git a/lib/libc/include/compat.h b/lib/libc/include/compat.h
index d0abfdf70fdb..559c8502fb93 100644
--- a/lib/libc/include/compat.h
+++ b/lib/libc/include/compat.h
@@ -44,6 +44,27 @@ __sym_compat(msgctl, freebsd7_msgctl, FBSD_1.0);
__sym_compat(shmctl, freebsd7_shmctl, FBSD_1.0);
#endif
+__sym_compat(nfstat, freebsd11_nfstat, FBSD_1.0);
+__sym_compat(nlstat, freebsd11_nlstat, FBSD_1.0);
+__sym_compat(nstat, freebsd11_nstat, FBSD_1.0);
+
+__sym_compat(fhstat, freebsd11_fhstat, FBSD_1.0);
+__sym_compat(fstat, freebsd11_fstat, FBSD_1.0);
+__sym_compat(fstatat, freebsd11_fstatat, FBSD_1.1);
+__sym_compat(lstat, freebsd11_lstat, FBSD_1.0);
+__sym_compat(stat, freebsd11_stat, FBSD_1.0);
+
+__sym_compat(getdents, freebsd11_getdents, FBSD_1.0);
+__sym_compat(getdirentries, freebsd11_getdirentries, FBSD_1.0);
+
+__sym_compat(getfsstat, freebsd11_getfsstat, FBSD_1.0);
+__sym_compat(fhstatfs, freebsd11_fhstatfs, FBSD_1.0);
+__sym_compat(fstatfs, freebsd11_fstatfs, FBSD_1.0);
+__sym_compat(statfs, freebsd11_statfs, FBSD_1.0);
+
+__sym_compat(mknod, freebsd11_mknod, FBSD_1.0);
+__sym_compat(mknodat, freebsd11_mknodat, FBSD_1.1);
+
#undef __sym_compat
#define __weak_reference(sym,alias) \
diff --git a/lib/libc/include/libc_private.h b/lib/libc/include/libc_private.h
index 384f61fb223b..3602a4260053 100644
--- a/lib/libc/include/libc_private.h
+++ b/lib/libc/include/libc_private.h
@@ -42,7 +42,10 @@
* or more threads. It is used to avoid calling locking functions
* when they are not required.
*/
+#ifndef __LIBC_ISTHREADED_DECLARED
+#define __LIBC_ISTHREADED_DECLARED
extern int __isthreaded;
+#endif
/*
* Elf_Auxinfo *__elf_aux_vector, the pointer to the ELF aux vector
@@ -307,6 +310,7 @@ struct pollfd;
struct rusage;
struct sigaction;
struct sockaddr;
+struct stat;
struct timespec;
struct timeval;
struct timezone;
@@ -323,8 +327,10 @@ int __sys_clock_nanosleep(__clockid_t, int,
const struct timespec *, struct timespec *);
int __sys_close(int);
int __sys_connect(int, const struct sockaddr *, __socklen_t);
+__ssize_t __sys_getdirentries(int, char *, __size_t, __off_t *);
int __sys_fcntl(int, int, ...);
int __sys_fdatasync(int);
+int __sys_fstatat(int, const char *, struct stat *, int);
int __sys_fsync(int);
__pid_t __sys_fork(void);
int __sys_ftruncate(int, __off_t);
diff --git a/lib/libc/locale/localeconv.3 b/lib/libc/locale/localeconv.3
index d18bf8754198..6262bf886346 100644
--- a/lib/libc/locale/localeconv.3
+++ b/lib/libc/locale/localeconv.3
@@ -202,7 +202,8 @@ result similarly denotes an unavailable value.
.Pp
The
.Fn localeconv_l
-function takes an explicit locale parameter. For more information, see
+function takes an explicit locale parameter.
+For more information, see
.Xr xlocale 3 .
.Sh RETURN VALUES
The
diff --git a/lib/libc/net/sctp_bindx.3 b/lib/libc/net/sctp_bindx.3
index 96d63cda39cc..c121eb4d9eeb 100644
--- a/lib/libc/net/sctp_bindx.3
+++ b/lib/libc/net/sctp_bindx.3
@@ -33,7 +33,7 @@
.Os
.Sh NAME
.Nm sctp_bindx
-.Nd bind or unbind an SCTP socket to a list of addresses.
+.Nd bind or unbind an SCTP socket to a list of addresses
.Sh LIBRARY
.Lb libc
.Sh SYNOPSIS
diff --git a/lib/libc/net/sctp_getassocid.3 b/lib/libc/net/sctp_getassocid.3
index 3c89fdc0c057..e0da322f943a 100644
--- a/lib/libc/net/sctp_getassocid.3
+++ b/lib/libc/net/sctp_getassocid.3
@@ -32,7 +32,7 @@
.Os
.Sh NAME
.Nm sctp_getassocid
-.Nd return an association id for a specified socket address.
+.Nd return an association id for a specified socket address
.Sh LIBRARY
.Lb libc
.Sh SYNOPSIS
diff --git a/lib/libc/net/sctp_send.3 b/lib/libc/net/sctp_send.3
index 9c7f833918ba..18a3e99473d8 100644
--- a/lib/libc/net/sctp_send.3
+++ b/lib/libc/net/sctp_send.3
@@ -105,8 +105,8 @@ struct sctp_sndrcvinfo {
The
.Fa sinfo->sinfo_ppid
argument is an opaque 32 bit value that is passed transparently
-through the stack to the peer endpoint. It will be available on
-reception of a message (see
+through the stack to the peer endpoint.
+It will be available on reception of a message (see
.Xr sctp_recvmsg 3 ) .
Note that the stack passes this value without regard to byte
order.
diff --git a/lib/libc/posix1e/acl_create_entry.3 b/lib/libc/posix1e/acl_create_entry.3
index 76c14f3f0e91..5732672c50a2 100644
--- a/lib/libc/posix1e/acl_create_entry.3
+++ b/lib/libc/posix1e/acl_create_entry.3
@@ -29,7 +29,7 @@
.Dt ACL_CREATE_ENTRY 3
.Os
.Sh NAME
-.Nm acl_create_entry
+.Nm acl_create_entry ,
.Nm acl_create_entry_np
.Nd create a new ACL entry
.Sh LIBRARY
diff --git a/lib/libc/posix1e/acl_to_text.3 b/lib/libc/posix1e/acl_to_text.3
index 08fec2005195..d6dcae0232e2 100644
--- a/lib/libc/posix1e/acl_to_text.3
+++ b/lib/libc/posix1e/acl_to_text.3
@@ -58,8 +58,9 @@ including the NULL terminator) in the location pointed to by
.Va len_p .
If the ACL is POSIX.1e, the format of the text string returned by
.Fn acl_to_text
-shall be the POSIX.1e long ACL form. If the ACL is NFSv4, the format
-of the text string shall be the compact form, unless the
+shall be the POSIX.1e long ACL form.
+If the ACL is NFSv4, the format of the text string shall be the compact form, unless
+the
.Va ACL_TEXT_VERBOSE
flag is given.
.Pp
diff --git a/lib/libc/posix1e/posix1e.3 b/lib/libc/posix1e/posix1e.3
index 02fb3ef27e99..6cdbc87bc6c1 100644
--- a/lib/libc/posix1e/posix1e.3
+++ b/lib/libc/posix1e/posix1e.3
@@ -63,7 +63,7 @@ flow label APIs.
However,
.Fx
does implement the
-.Xr libbsm
+.Xr libbsm 3
audit API.
It also provides
.Xr capsicum 4 ,
diff --git a/lib/libc/stdio/fopen.3 b/lib/libc/stdio/fopen.3
index cbd633e2f139..f639f858d5bf 100644
--- a/lib/libc/stdio/fopen.3
+++ b/lib/libc/stdio/fopen.3
@@ -230,15 +230,20 @@ argument,
.Fn fmemopen
allocates
.Fa size
-bytes of memory. This buffer is automatically freed when the
-stream is closed. Buffers can be opened in text-mode (default) or binary-mode
+bytes of memory.
+This buffer is automatically freed when the stream is closed.
+Buffers can be opened in text-mode (default) or binary-mode
(if
.Dq Li b
is present in the second or third position of the
.Fa mode
-argument). Buffers opened in text-mode make sure that writes are terminated with
-a NULL byte, if the last write hasn't filled up the whole buffer. Buffers
-opened in binary-mode never append a NULL byte.
+argument).
+Buffers opened in text-mode make sure that writes are terminated with a
+.Dv NULL
+byte, if the last write hasn't filled up the whole buffer.
+Buffers opened in binary-mode never append a
+.Dv NULL
+byte.
.Sh RETURN VALUES
Upon successful completion
.Fn fopen ,
diff --git a/lib/libc/stdio/fopencookie.3 b/lib/libc/stdio/fopencookie.3
index 4903e915a422..349b3499b6bb 100644
--- a/lib/libc/stdio/fopencookie.3
+++ b/lib/libc/stdio/fopencookie.3
@@ -35,13 +35,13 @@
.Sh SYNOPSIS
.In stdio.h
.Ft typedef ssize_t
-.Fn (cookie_read_function_t) "void *cookie" "char *buf" "size_t size"
+.Fn (*cookie_read_function_t) "void *cookie" "char *buf" "size_t size"
.Ft typedef ssize_t
-.Fn (cookie_write_function_t) "void *cookie" "const char *buf" "size_t size"
+.Fn (*cookie_write_function_t) "void *cookie" "const char *buf" "size_t size"
.Ft typedef int
-.Fn (cookie_seek_function_t) "void *cookie" "off64_t *offset" "int whence"
+.Fn (*cookie_seek_function_t) "void *cookie" "off64_t *offset" "int whence"
.Ft typedef int
-.Fn (cookie_close_function_t) "void *cookie"
+.Fn (*cookie_close_function_t) "void *cookie"
.Bd -literal
typedef struct {
cookie_read_function_t *read;
diff --git a/lib/libc/stdlib/quick_exit.3 b/lib/libc/stdlib/quick_exit.3
index 7bbd2f3d53b7..fb1e346bb106 100644
--- a/lib/libc/stdlib/quick_exit.3
+++ b/lib/libc/stdlib/quick_exit.3
@@ -1,6 +1,6 @@
.\" Copyright (c) 2011 David Chisnall
.\" All rights reserved.
-.\"
+.\"
.\" Redistribution and use in source and binary forms, with or without
.\" modification, are permitted provided that the following conditions
.\" are met:
@@ -9,7 +9,7 @@
.\" 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.
-.\"
+.\"
.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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
@@ -21,7 +21,7 @@
.\" 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.
-.\"
+.\"
.\" $FreeBSD$
.\"
.Dd December 13, 2014
diff --git a/lib/libc/sys/Makefile.inc b/lib/libc/sys/Makefile.inc
index 76eeebd9d71c..b641125096d1 100644
--- a/lib/libc/sys/Makefile.inc
+++ b/lib/libc/sys/Makefile.inc
@@ -35,6 +35,8 @@ SRCS+= \
__error.c \
interposing_table.c
+SRCS+= getdents.c lstat.c mknod.c stat.c
+
SRCS+= futimens.c utimensat.c
NOASM+= futimens.o utimensat.o
PSEUDO+= _futimens.o _utimensat.o
diff --git a/lib/libc/sys/Symbol.map b/lib/libc/sys/Symbol.map
index 6a5c838a762b..feccda6f6bf4 100644
--- a/lib/libc/sys/Symbol.map
+++ b/lib/libc/sys/Symbol.map
@@ -85,26 +85,19 @@ FBSD_1.0 {
fchown;
fcntl;
fhopen;
- fhstat;
- fhstatfs;
flock;
fork;
fpathconf;
- fstat;
- fstatfs;
fsync;
futimes;
getaudit;
getaudit_addr;
getauid;
getcontext;
- getdents;
- getdirentries;
getdtablesize;
getegid;
geteuid;
getfh;
- getfsstat;
getgid;
getgroups;
getitimer;
@@ -163,7 +156,6 @@ FBSD_1.0 {
link;
lio_listio;
listen;
- lstat;
lutimes;
mac_syscall;
madvise;
@@ -171,7 +163,6 @@ FBSD_1.0 {
minherit;
mkdir;
mkfifo;
- mknod;
mlock;
mlockall;
modfind;
@@ -192,10 +183,7 @@ FBSD_1.0 {
netbsd_lchown;
netbsd_msync;
nfssvc;
- nfstat;
- nlstat;
nmount;
- nstat;
ntp_adjtime;
ntp_gettime;
open;
@@ -275,8 +263,6 @@ FBSD_1.0 {
sigwaitinfo;
socket;
socketpair;
- stat;
- statfs;
swapoff;
swapon;
symlink;
@@ -330,7 +316,6 @@ FBSD_1.1 {
fchmodat;
fchownat;
fexecve;
- fstatat;
futimesat;
jail_get;
jail_set;
@@ -339,7 +324,6 @@ FBSD_1.1 {
lpathconf;
mkdirat;
mkfifoat;
- mknodat;
msgctl;
readlinkat;
renameat;
@@ -401,6 +385,19 @@ FBSD_1.4 {
FBSD_1.5 {
clock_nanosleep;
fdatasync;
+ fhstat;
+ fhstatfs;
+ fstat;
+ fstatat;
+ fstatfs;
+ getdents;
+ getdirentries;
+ getfsstat;
+ lstat;
+ mknod;
+ mknodat;
+ stat;
+ statfs;
};
FBSDprivate_1.0 {
@@ -606,8 +603,6 @@ FBSDprivate_1.0 {
__sys_getauid;
_getcontext;
__sys_getcontext;
- _getdents;
- __sys_getdents;
_getdirentries;
__sys_getdirentries;
_getdtablesize;
@@ -736,8 +731,6 @@ FBSDprivate_1.0 {
__sys_lio_listio;
_listen;
__sys_listen;
- _lstat;
- __sys_lstat;
_lutimes;
__sys_lutimes;
_mac_syscall;
@@ -796,14 +789,8 @@ FBSDprivate_1.0 {
__sys_netbsd_msync;
_nfssvc;
__sys_nfssvc;
- _nfstat;
- __sys_nfstat;
- _nlstat;
- __sys_nlstat;
_nmount;
__sys_nmount;
- _nstat;
- __sys_nstat;
_ntp_adjtime;
__sys_ntp_adjtime;
_ntp_gettime;
@@ -971,8 +958,6 @@ FBSDprivate_1.0 {
__sys_socket;
_socketpair;
__sys_socketpair;
- _stat;
- __sys_stat;
_statfs;
__sys_statfs;
_swapcontext;
diff --git a/lib/libc/sys/_umtx_op.2 b/lib/libc/sys/_umtx_op.2
index 63509991ad24..4682b3426cf8 100644
--- a/lib/libc/sys/_umtx_op.2
+++ b/lib/libc/sys/_umtx_op.2
@@ -28,7 +28,7 @@
.\"
.\" $FreeBSD$
.\"
-.Dd May 29, 2016
+.Dd May 23, 2017
.Dt _UMTX_OP 2
.Os
.Sh NAME
@@ -1382,32 +1382,11 @@ Mutex lock requests without timeout specified are restartable.
The error is not returned to userspace code since restart
is handled by usual adjustment of the instruction counter.
.El
-.Sh BUGS
-A window between a unlocking robust mutex and resetting the pointer in the
-.Dv robust_inact_offset
-member of the registered
-.Vt struct umtx_robust_lists_params
-allows another thread to destroy the mutex, thus making the kernel inspect
-freed or reused memory.
-The
-.Li libthr
-implementation is only vulnerable to this race when operating on
-a shared mutex.
-A possible fix for the current implementation is to strengthen the checks
-for shared mutexes before terminating them, in particular, verifying
-that the mutex memory is mapped from a shared memory object allocated
-by the
-.Dv UMTX_OP_SHM
-request.
-This is not done because it is believed that the race is adequately
-covered by other consistency checks, while adding the check would
-prevent alternative implementations of
-.Li libpthread .
.Sh SEE ALSO
.Xr clock_gettime 2 ,
.Xr mmap 2 ,
-.Xr shm_open 2 ,
.Xr setrlimit 2 ,
+.Xr shm_open 2 ,
.Xr sigaction 2 ,
.Xr thr_exit 2 ,
.Xr thr_kill 2 ,
@@ -1425,3 +1404,24 @@ to implement
.St -p1003.1-2001
.Xr pthread 3
functionality.
+.Sh BUGS
+A window between a unlocking robust mutex and resetting the pointer in the
+.Dv robust_inact_offset
+member of the registered
+.Vt struct umtx_robust_lists_params
+allows another thread to destroy the mutex, thus making the kernel inspect
+freed or reused memory.
+The
+.Li libthr
+implementation is only vulnerable to this race when operating on
+a shared mutex.
+A possible fix for the current implementation is to strengthen the checks
+for shared mutexes before terminating them, in particular, verifying
+that the mutex memory is mapped from a shared memory object allocated
+by the
+.Dv UMTX_OP_SHM
+request.
+This is not done because it is believed that the race is adequately
+covered by other consistency checks, while adding the check would
+prevent alternative implementations of
+.Li libpthread .
diff --git a/lib/libc/sys/cap_enter.2 b/lib/libc/sys/cap_enter.2
index 8612098b5721..43e21100f909 100644
--- a/lib/libc/sys/cap_enter.2
+++ b/lib/libc/sys/cap_enter.2
@@ -28,7 +28,7 @@
.\"
.\" $FreeBSD$
.\"
-.Dd September 27, 2016
+.Dd May 23, 2017
.Dt CAP_ENTER 2
.Os
.Sh NAME
@@ -144,11 +144,11 @@ points outside the process's allocated address space.
.Xr cap_fcntls_limit 2 ,
.Xr cap_ioctls_limit 2 ,
.Xr cap_rights_limit 2 ,
-.Xr procctl 2 ,
-.Xr sysctl 2 ,
.Xr fexecve 2 ,
+.Xr procctl 2 ,
.Xr cap_sandboxed 3 ,
-.Xr capsicum 4
+.Xr capsicum 4 ,
+.Xr sysctl 9
.Sh HISTORY
Support for capabilities and capabilities mode was developed as part of the
.Tn TrustedBSD
diff --git a/lib/libc/sys/cpuset_getaffinity.2 b/lib/libc/sys/cpuset_getaffinity.2
index c379518214b8..dbf27ad9c295 100644
--- a/lib/libc/sys/cpuset_getaffinity.2
+++ b/lib/libc/sys/cpuset_getaffinity.2
@@ -25,7 +25,7 @@
.\"
.\" $FreeBSD$
.\"
-.Dd June 2, 2016
+.Dd May 23, 2017
.Dt CPUSET_GETAFFINITY 2
.Os
.Sh NAME
@@ -148,8 +148,14 @@ was either preposterously large or smaller than the kernel set size.
.It Bq Er EPERM
The calling process did not have the credentials required to complete the
operation.
+.It Bq Er ECAPMODE
+The calling process attempted to act on a process other than itself, while
+in capability mode.
+See
+.Xr capsicum 4 .
.El
.Sh SEE ALSO
+.Xr capsicum 4 ,
.Xr cpuset 1 ,
.Xr cpuset 2 ,
.Xr cpuset_getid 2 ,
diff --git a/lib/libc/sys/fsync.2 b/lib/libc/sys/fsync.2
index ed5bcb288eba..c2e1ea388053 100644
--- a/lib/libc/sys/fsync.2
+++ b/lib/libc/sys/fsync.2
@@ -34,7 +34,7 @@
.\" @(#)fsync.2 8.1 (Berkeley) 6/4/93
.\" $FreeBSD$
.\"
-.Dd August 17, 2016
+.Dd May 24, 2017
.Dt FSYNC 2
.Os
.Sh NAME
@@ -119,7 +119,7 @@ system call appeared in
The
.Fn fdatasync
system call appeared in
-.Fx 12.0
+.Fx 11.1 .
.Sh BUGS
The
.Fn fdatasync
diff --git a/lib/libc/sys/getdents.c b/lib/libc/sys/getdents.c
new file mode 100644
index 000000000000..c8a2878c972f
--- /dev/null
+++ b/lib/libc/sys/getdents.c
@@ -0,0 +1,41 @@
+/*-
+ * Copyright (c) 2012 Gleb Kurtsou <gleb@FreeBSD.org>
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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 <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "namespace.h"
+#include <sys/param.h>
+#include <sys/syscall.h>
+#include <dirent.h>
+#include "libc_private.h"
+
+ssize_t
+getdents(int fd, char *buf, size_t nbytes)
+{
+
+ return (__sys_getdirentries(fd, buf, nbytes, NULL));
+}
diff --git a/lib/libc/sys/getdirentries.2 b/lib/libc/sys/getdirentries.2
index ace8faa7521c..d3f2129d400f 100644
--- a/lib/libc/sys/getdirentries.2
+++ b/lib/libc/sys/getdirentries.2
@@ -40,10 +40,10 @@
.Sh SYNOPSIS
.In sys/types.h
.In dirent.h
-.Ft int
-.Fn getdirentries "int fd" "char *buf" "int nbytes" "long *basep"
-.Ft int
-.Fn getdents "int fd" "char *buf" "int nbytes"
+.Ft ssize_t
+.Fn getdirentries "int fd" "char *buf" "size_t nbytes" "off_t *basep"
+.Ft ssize_t
+.Fn getdents "int fd" "char *buf" "size_t nbytes"
.Sh DESCRIPTION
The
.Fn getdirentries
diff --git a/lib/libc/sys/kill.2 b/lib/libc/sys/kill.2
index 86214c752857..d5e55ca51ea0 100644
--- a/lib/libc/sys/kill.2
+++ b/lib/libc/sys/kill.2
@@ -71,7 +71,7 @@ A single exception is the signal SIGCONT, which may always be sent
to any process with the same session ID as the sender.
In addition, if the
.Va security.bsd.conservative_signals
-.Xr sysctl
+.Xr sysctl 9
is set to 1, the user is not a super-user, and
the receiver is set-uid, then
only job control and terminal control signals may
diff --git a/lib/libc/sys/lstat.c b/lib/libc/sys/lstat.c
new file mode 100644
index 000000000000..ccc73e3d3d06
--- /dev/null
+++ b/lib/libc/sys/lstat.c
@@ -0,0 +1,43 @@
+/*-
+ * Copyright (c) 2012 Gleb Kurtsou <gleb@FreeBSD.org>
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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 <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "namespace.h"
+#include <sys/param.h>
+#include <sys/fcntl.h>
+#include <sys/syscall.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include "libc_private.h"
+
+int
+lstat(const char *path, struct stat *sb)
+{
+
+ return (__sys_fstatat(AT_FDCWD, path, sb, AT_SYMLINK_NOFOLLOW));
+}
diff --git a/lib/libc/sys/mknod.c b/lib/libc/sys/mknod.c
new file mode 100644
index 000000000000..3bb3853b5849
--- /dev/null
+++ b/lib/libc/sys/mknod.c
@@ -0,0 +1,45 @@
+/*-
+ * Copyright (c) 2011 Gleb Kurtsou <gleb@FreeBSD.org>
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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 <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "namespace.h"
+#include <sys/param.h>
+#include <sys/fcntl.h>
+#include <sys/syscall.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include "libc_private.h"
+
+int __sys_mknodat(int, const char *, mode_t, dev_t);
+
+int
+mknod(const char *path, mode_t mode, dev_t dev)
+{
+
+ return (__sys_mknodat(AT_FDCWD, path, mode, dev));
+}
diff --git a/lib/libc/sys/open.2 b/lib/libc/sys/open.2
index 5fae5c63dfe3..69274c00a729 100644
--- a/lib/libc/sys/open.2
+++ b/lib/libc/sys/open.2
@@ -490,7 +490,6 @@ was called and the process is in capability mode.
is an absolute path or contained "..".
.El
.Sh SEE ALSO
-.Xr capsicum 4 ,
.Xr chmod 2 ,
.Xr close 2 ,
.Xr dup 2 ,
@@ -503,16 +502,8 @@ is an absolute path or contained "..".
.Xr read 2 ,
.Xr umask 2 ,
.Xr write 2 ,
-.Xr fopen 3
-.Sh HISTORY
-The
-.Fn open
-function appeared in
-.At v6 .
-The
-.Fn openat
-function was introduced in
-.Fx 8.0 .
+.Xr fopen 3 ,
+.Xr capsicum 4
.Sh STANDARDS
These functions are specified by
.St -p1003.1-2008 .
@@ -529,6 +520,15 @@ when
is set in flags and the final component of pathname is a symbolic link
to distinguish it from the case of too many symbolic link traversals
in one of its non-final components.
+.Sh HISTORY
+The
+.Fn open
+function appeared in
+.At v6 .
+The
+.Fn openat
+function was introduced in
+.Fx 8.0 .
.Sh BUGS
The Open Group Extended API Set 2 specification requires that the test
for whether
diff --git a/lib/libc/sys/ptrace.2 b/lib/libc/sys/ptrace.2
index 2cd26ee3465a..8eb26dd9279b 100644
--- a/lib/libc/sys/ptrace.2
+++ b/lib/libc/sys/ptrace.2
@@ -166,7 +166,7 @@ new child processes will execute without tracing enabled.
This event flag controls tracing of LWP
.Pq kernel thread
creation and destruction.
-When this event is enabled,
+When this event is enabled,
new LWPs will stop and report an event with
.Dv PL_FLAG_BORN
set before executing their first instruction,
@@ -215,7 +215,7 @@ or
includes only
.Dv PTRACE_EXEC
events.
-All other event flags are disabled.
+All other event flags are disabled.
.Pp
The
.Fa request
diff --git a/lib/libc/sys/rctl_add_rule.2 b/lib/libc/sys/rctl_add_rule.2
index 667a0059470d..b1d807baa80c 100644
--- a/lib/libc/sys/rctl_add_rule.2
+++ b/lib/libc/sys/rctl_add_rule.2
@@ -28,10 +28,10 @@
.Dt RCTL_ADD_RULE 2
.Os
.Sh NAME
-.Nm rctl_add_rule,
-.Nm rctl_get_limits
-.Nm rctl_get_racct,
-.Nm rctl_get_rules,
+.Nm rctl_add_rule ,
+.Nm rctl_get_limits ,
+.Nm rctl_get_racct ,
+.Nm rctl_get_rules ,
.Nm rctl_remove_rule
.Nd manipulate and query the resource limits database
.Sh LIBRARY
diff --git a/lib/libc/sys/setfib.2 b/lib/libc/sys/setfib.2
index d759109fa39e..83cc7376de39 100644
--- a/lib/libc/sys/setfib.2
+++ b/lib/libc/sys/setfib.2
@@ -29,7 +29,7 @@
.Os
.Sh NAME
.Nm setfib
-.Nd set the default FIB (routing table) for the calling process.
+.Nd set the default FIB (routing table) for the calling process
.Sh LIBRARY
.Lb libc
.Sh SYNOPSIS
diff --git a/lib/libc/sys/stat.c b/lib/libc/sys/stat.c
new file mode 100644
index 000000000000..6b58daa9e515
--- /dev/null
+++ b/lib/libc/sys/stat.c
@@ -0,0 +1,43 @@
+/*-
+ * Copyright (c) 2012 Gleb Kurtsou <gleb@FreeBSD.org>
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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 <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "namespace.h"
+#include <sys/param.h>
+#include <sys/fcntl.h>
+#include <sys/syscall.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include "libc_private.h"
+
+int
+stat(const char *path, struct stat *sb)
+{
+
+ return (__sys_fstatat(AT_FDCWD, path, sb, 0));
+}
diff --git a/lib/libc/sys/statfs.2 b/lib/libc/sys/statfs.2
index 7a95871125ca..a7383c4ce12b 100644
--- a/lib/libc/sys/statfs.2
+++ b/lib/libc/sys/statfs.2
@@ -28,7 +28,7 @@
.\" @(#)statfs.2 8.5 (Berkeley) 5/24/95
.\" $FreeBSD$
.\"
-.Dd November 1, 2006
+.Dd February 13, 2017
.Dt STATFS 2
.Os
.Sh NAME
@@ -66,8 +66,8 @@ typedef struct fsid { int32_t val[2]; } fsid_t; /* file system id type */
*/
#define MFSNAMELEN 16 /* length of type name including null */
-#define MNAMELEN 88 /* size of on/from name bufs */
-#define STATFS_VERSION 0x20030518 /* current version number */
+#define MNAMELEN 1024 /* size of on/from name bufs */
+#define STATFS_VERSION 0x20140518 /* current version number */
struct statfs {
uint32_t f_version; /* structure version number */
diff --git a/lib/libc/xdr/xdr.3 b/lib/libc/xdr/xdr.3
index 69f25449be67..6c16cfc3fcfb 100644
--- a/lib/libc/xdr/xdr.3
+++ b/lib/libc/xdr/xdr.3
@@ -31,7 +31,7 @@
.Nm xdr_reference ,
.Nm xdr_setpos ,
.Nm xdr_short ,
-.Nm xdr_sizeof,
+.Nm xdr_sizeof ,
.Nm xdrstdio_create ,
.Nm xdr_string ,
.Nm xdr_u_char ,