aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKonstantin Belousov <kib@FreeBSD.org>2017-05-23 09:29:05 +0000
committerKonstantin Belousov <kib@FreeBSD.org>2017-05-23 09:29:05 +0000
commit69921123490b99c2588b0c743bc4af32bbe6601c (patch)
tree4828066c23bd9bbd1672af14fbf0a9e31e47f4a0
parent5f7c516f216995249523ed43e57e3f91bd8f5ff0 (diff)
downloadsrc-69921123490b99c2588b0c743bc4af32bbe6601c.tar.gz
src-69921123490b99c2588b0c743bc4af32bbe6601c.zip
Commit the 64-bit inode project.
Extend the ino_t, dev_t, nlink_t types to 64-bit ints. Modify struct dirent layout to add d_off, increase the size of d_fileno to 64-bits, increase the size of d_namlen to 16-bits, and change the required alignment. Increase struct statfs f_mntfromname[] and f_mntonname[] array length MNAMELEN to 1024. ABI breakage is mitigated by providing compatibility using versioned symbols, ingenious use of the existing padding in structures, and by employing other tricks. Unfortunately, not everything can be fixed, especially outside the base system. For instance, third-party APIs which pass struct stat around are broken in backward and forward incompatible ways. Kinfo sysctl MIBs ABI is changed in backward-compatible way, but there is no general mechanism to handle other sysctl MIBS which return structures where the layout has changed. It was considered that the breakage is either in the management interfaces, where we usually allow ABI slip, or is not important. Struct xvnode changed layout, no compat shims are provided. For struct xtty, dev_t tty device member was reduced to uint32_t. It was decided that keeping ABI compat in this case is more useful than reporting 64-bit dev_t, for the sake of pstat. Update note: strictly follow the instructions in UPDATING. Build and install the new kernel with COMPAT_FREEBSD11 option enabled, then reboot, and only then install new world. Credits: The 64-bit inode project, also known as ino64, started life many years ago as a project by Gleb Kurtsou (gleb). Kirk McKusick (mckusick) then picked up and updated the patch, and acted as a flag-waver. Feedback, suggestions, and discussions were carried by Ed Maste (emaste), John Baldwin (jhb), Jilles Tjoelker (jilles), and Rick Macklem (rmacklem). Kris Moore (kris) performed an initial ports investigation followed by an exp-run by Antoine Brodin (antoine). Essential and all-embracing testing was done by Peter Holm (pho). The heavy lifting of coordinating all these efforts and bringing the project to completion were done by Konstantin Belousov (kib). Sponsored by: The FreeBSD Foundation (emaste, kib) Differential revision: https://reviews.freebsd.org/D10439
Notes
Notes: svn path=/head/; revision=318736
-rw-r--r--cddl/lib/libzfs/Makefile1
-rw-r--r--contrib/compiler-rt/lib/sanitizer_common/sanitizer_linux.cc10
-rw-r--r--contrib/compiler-rt/lib/sanitizer_common/sanitizer_platform_limits_posix.h3
-rw-r--r--contrib/openbsm/libbsm/bsm_wrappers.c4
-rw-r--r--include/dirent.h23
-rw-r--r--lib/libarchive/Makefile2
-rw-r--r--lib/libc/gen/Makefile.inc10
-rw-r--r--lib/libc/gen/Symbol.map40
-rw-r--r--lib/libc/gen/closedir.c1
-rw-r--r--lib/libc/gen/devname-compat11.c50
-rw-r--r--lib/libc/gen/fts-compat.c33
-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/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/telldir.h5
-rw-r--r--lib/libc/include/compat.h21
-rw-r--r--lib/libc/include/libc_private.h3
-rw-r--r--lib/libc/sys/Makefile.inc2
-rw-r--r--lib/libc/sys/Symbol.map41
-rw-r--r--lib/libc/sys/getdents.c41
-rw-r--r--lib/libc/sys/getdirentries.28
-rw-r--r--lib/libc/sys/lstat.c43
-rw-r--r--lib/libc/sys/mknod.c45
-rw-r--r--lib/libc/sys/stat.c43
-rw-r--r--lib/libc/sys/statfs.26
-rw-r--r--lib/libkvm/kvm_proc.c1
-rw-r--r--lib/libmilter/Makefile1
-rw-r--r--lib/libprocstat/Makefile4
-rw-r--r--lib/libprocstat/Symbol.map8
-rw-r--r--lib/libprocstat/libprocstat.c12
-rw-r--r--lib/libprocstat/libprocstat.h6
-rw-r--r--lib/libprocstat/libprocstat_compat.c144
-rw-r--r--lib/libufs/libufs.h4
-rw-r--r--sbin/badsect/badsect.c13
-rw-r--r--sbin/fsck_ffs/suj.c8
-rw-r--r--share/man/man5/acct.58
-rw-r--r--share/man/man5/dir.531
-rw-r--r--sys/bsm/audit.h4
-rw-r--r--sys/cddl/compat/opensolaris/sys/dirent.h4
-rw-r--r--sys/compat/freebsd32/capabilities.conf5
-rw-r--r--sys/compat/freebsd32/freebsd32.h57
-rw-r--r--sys/compat/freebsd32/freebsd32_misc.c214
-rw-r--r--sys/compat/freebsd32/syscalls.master77
-rw-r--r--sys/compat/linux/linux_file.c28
-rw-r--r--sys/dev/snp/snp.c8
-rw-r--r--sys/fs/devfs/devfs_devs.c14
-rw-r--r--sys/fs/devfs/devfs_vnops.c1
-rw-r--r--sys/fs/fdescfs/fdesc_vnops.c2
-rw-r--r--sys/fs/nandfs/nandfs_fs.h2
-rw-r--r--sys/fs/nfs/nfsport.h6
-rw-r--r--sys/fs/nfsclient/nfs_clrpcops.c68
-rw-r--r--sys/fs/nfsclient/nfs_clvnops.c2
-rw-r--r--sys/fs/nfsserver/nfs_nfsdport.c39
-rw-r--r--sys/kern/capabilities.conf5
-rw-r--r--sys/kern/kern_acct.c9
-rw-r--r--sys/kern/kern_descrip.c53
-rw-r--r--sys/kern/kern_proc.c11
-rw-r--r--sys/kern/makesyscalls.sh37
-rw-r--r--sys/kern/sys_socket.c21
-rw-r--r--sys/kern/syscalls.master64
-rw-r--r--sys/kern/tty.c2
-rw-r--r--sys/kern/tty_pts.c2
-rw-r--r--sys/kern/vfs_syscalls.c602
-rw-r--r--sys/kern/vfs_vnops.c6
-rw-r--r--sys/nlm/nlm_advlock.c5
-rw-r--r--sys/security/audit/audit_private.h8
-rw-r--r--sys/sys/_types.h6
-rw-r--r--sys/sys/acct.h35
-rw-r--r--sys/sys/dirent.h43
-rw-r--r--sys/sys/mount.h32
-rw-r--r--sys/sys/param.h2
-rw-r--r--sys/sys/stat.h63
-rw-r--r--sys/sys/syscallsubr.h11
-rw-r--r--sys/sys/tty.h2
-rw-r--r--sys/sys/user.h74
-rw-r--r--sys/sys/vnode.h9
-rw-r--r--sys/vm/swap_pager.c27
-rw-r--r--sys/vm/vm_object.c3
-rw-r--r--sys/vm/vm_param.h2
-rw-r--r--usr.bin/kdump/kdump.c1
-rw-r--r--usr.bin/lastcomm/lastcomm.c12
-rw-r--r--usr.bin/lastcomm/readrec.c94
-rw-r--r--usr.sbin/pstat/pstat.c2
-rw-r--r--usr.sbin/sa/extern.h2
-rw-r--r--usr.sbin/sa/main.c2
97 files changed, 4966 insertions, 644 deletions
diff --git a/cddl/lib/libzfs/Makefile b/cddl/lib/libzfs/Makefile
index a13c50281cd8..e8de72f18275 100644
--- a/cddl/lib/libzfs/Makefile
+++ b/cddl/lib/libzfs/Makefile
@@ -37,6 +37,7 @@ SRCS+= libzfs_changelist.c \
zprop_common.c \
WARNS?= 0
+SHLIB_MAJOR= 3
CSTD= c99
CFLAGS+= -DZFS_NO_ACL
CFLAGS+= -I${SRCTOP}/sbin/mount
diff --git a/contrib/compiler-rt/lib/sanitizer_common/sanitizer_linux.cc b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_linux.cc
index 7328a5c0ac18..4b59a39ee272 100644
--- a/contrib/compiler-rt/lib/sanitizer_common/sanitizer_linux.cc
+++ b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_linux.cc
@@ -223,7 +223,8 @@ static void kernel_stat_to_stat(struct kernel_stat *in, struct stat *out) {
uptr internal_stat(const char *path, void *buf) {
#if SANITIZER_FREEBSD
- return internal_syscall(SYSCALL(stat), path, buf);
+ return internal_syscall(SYSCALL(fstatat), AT_FDCWD, (uptr)path,
+ (uptr)buf, 0);
#elif SANITIZER_USES_CANONICAL_LINUX_SYSCALLS
return internal_syscall(SYSCALL(newfstatat), AT_FDCWD, (uptr)path,
(uptr)buf, 0);
@@ -247,7 +248,8 @@ uptr internal_stat(const char *path, void *buf) {
uptr internal_lstat(const char *path, void *buf) {
#if SANITIZER_FREEBSD
- return internal_syscall(SYSCALL(lstat), path, buf);
+ return internal_syscall(SYSCALL(fstatat), AT_FDCWD, (uptr)path,
+ (uptr)buf, AT_SYMLINK_NOFOLLOW);
#elif SANITIZER_USES_CANONICAL_LINUX_SYSCALLS
return internal_syscall(SYSCALL(newfstatat), AT_FDCWD, (uptr)path,
(uptr)buf, AT_SYMLINK_NOFOLLOW);
@@ -590,7 +592,9 @@ uptr internal_getppid() {
}
uptr internal_getdents(fd_t fd, struct linux_dirent *dirp, unsigned int count) {
-#if SANITIZER_USES_CANONICAL_LINUX_SYSCALLS
+#if SANITIZER_FREEBSD
+ return internal_syscall(SYSCALL(getdirentries), fd, (uptr)dirp, count, NULL);
+#elif SANITIZER_USES_CANONICAL_LINUX_SYSCALLS
return internal_syscall(SYSCALL(getdents64), fd, (uptr)dirp, count);
#else
return internal_syscall(SYSCALL(getdents), fd, (uptr)dirp, count);
diff --git a/contrib/compiler-rt/lib/sanitizer_common/sanitizer_platform_limits_posix.h b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_platform_limits_posix.h
index 5cbd78d3c1bf..d7ce7b501f7b 100644
--- a/contrib/compiler-rt/lib/sanitizer_common/sanitizer_platform_limits_posix.h
+++ b/contrib/compiler-rt/lib/sanitizer_common/sanitizer_platform_limits_posix.h
@@ -489,7 +489,8 @@ namespace __sanitizer {
};
#elif SANITIZER_FREEBSD
struct __sanitizer_dirent {
- unsigned int d_fileno;
+ unsigned long long d_fileno;
+ unsigned long long d_off;
unsigned short d_reclen;
// more fields that we don't care about
};
diff --git a/contrib/openbsm/libbsm/bsm_wrappers.c b/contrib/openbsm/libbsm/bsm_wrappers.c
index ca367c957837..cd40a6555a54 100644
--- a/contrib/openbsm/libbsm/bsm_wrappers.c
+++ b/contrib/openbsm/libbsm/bsm_wrappers.c
@@ -264,12 +264,14 @@ audit_set_terminal_host(uint32_t *m)
int
audit_set_terminal_id(au_tid_t *tid)
{
+ dev_t port;
int ret;
if (tid == NULL)
return (kAUBadParamErr);
- if ((ret = audit_set_terminal_port(&tid->port)) != kAUNoErr)
+ if ((ret = audit_set_terminal_port(&port)) != kAUNoErr)
return (ret);
+ tid->port = port;
return (audit_set_terminal_host(&tid->machine));
}
diff --git a/include/dirent.h b/include/dirent.h
index 1ab949ccb378..e98752683c8e 100644
--- a/include/dirent.h
+++ b/include/dirent.h
@@ -41,6 +41,25 @@
#include <sys/_types.h>
#include <sys/dirent.h>
+#if __BSD_VISIBLE
+
+#ifndef _SIZE_T_DECLARED
+typedef __size_t size_t;
+#define _SIZE_T_DECLARED
+#endif
+
+#ifndef _SSIZE_T_DECLARED
+typedef __ssize_t ssize_t;
+#define _SSIZE_T_DECLARED
+#endif
+
+#ifndef _OFF_T_DECLARED
+typedef __off_t off_t;
+#define _OFF_T_DECLARED
+#endif
+
+#endif /* __BSD_VISIBLE */
+
#if __XSI_VISIBLE
#ifndef _INO_T_DECLARED
@@ -89,8 +108,8 @@ int dirfd(DIR *);
#if __BSD_VISIBLE
DIR *__opendir2(const char *, int);
int fdclosedir(DIR *);
-int getdents(int, char *, int);
-int getdirentries(int, char *, int, long *);
+ssize_t getdents(int, char *, size_t);
+ssize_t getdirentries(int, char *, size_t, off_t *);
#endif
DIR *opendir(const char *);
DIR *fdopendir(int);
diff --git a/lib/libarchive/Makefile b/lib/libarchive/Makefile
index 53d4cc994183..646ee28f6c94 100644
--- a/lib/libarchive/Makefile
+++ b/lib/libarchive/Makefile
@@ -11,7 +11,7 @@ CFLAGS+= -DHAVE_BZLIB_H=1 -DHAVE_LIBLZMA=1 -DHAVE_LZMA_H=1
# FreeBSD SHLIB_MAJOR value is managed as part of the FreeBSD system.
# It has no real relation to the libarchive version number.
-SHLIB_MAJOR= 6
+SHLIB_MAJOR= 7
CFLAGS+= -DPLATFORM_CONFIG_H=\"${.CURDIR}/config_freebsd.h\"
CFLAGS+= -I${.OBJDIR}
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/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/fts-compat.c b/lib/libc/gen/fts-compat.c
index 64a73e9ea28a..0415a59ec212 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;
};
@@ -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..7653d32752f6
--- /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;
+
+ /* Shush, GCC. */
+ tmp = NULL;
+
+ /* 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;
+
+ /* 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/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/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/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..6409ff331754 100644
--- a/lib/libc/include/libc_private.h
+++ b/lib/libc/include/libc_private.h
@@ -307,6 +307,7 @@ struct pollfd;
struct rusage;
struct sigaction;
struct sockaddr;
+struct stat;
struct timespec;
struct timeval;
struct timezone;
@@ -323,8 +324,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/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/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/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/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/libkvm/kvm_proc.c b/lib/libkvm/kvm_proc.c
index ac14ef613990..a7886ab556ab 100644
--- a/lib/libkvm/kvm_proc.c
+++ b/lib/libkvm/kvm_proc.c
@@ -452,6 +452,7 @@ nopgrp:
} else {
kp->ki_stat = SZOMB;
}
+ kp->ki_tdev_freebsd11 = kp->ki_tdev; /* truncate */
bcopy(&kinfo_proc, bp, sizeof(kinfo_proc));
++bp;
++cnt;
diff --git a/lib/libmilter/Makefile b/lib/libmilter/Makefile
index a8efe9cec7bd..17bb09857fcf 100644
--- a/lib/libmilter/Makefile
+++ b/lib/libmilter/Makefile
@@ -29,6 +29,7 @@ SRCS+= main.c engine.c listener.c handler.c comm.c monitor.c smfi.c \
CLEANFILES+=sm_os.h
WARNS?= 0
+SHLIB_MAJOR= 6
sm_os.h: ${SENDMAIL_DIR}/include/sm/os/sm_os_freebsd.h .NOMETA
ln -sf ${.ALLSRC} ${.TARGET}
diff --git a/lib/libprocstat/Makefile b/lib/libprocstat/Makefile
index 8d4fae0dffe9..9d80d17e16a8 100644
--- a/lib/libprocstat/Makefile
+++ b/lib/libprocstat/Makefile
@@ -13,6 +13,10 @@ SRCS= cd9660.c \
smbfs.c \
udf.c
+.if ${MK_SYMVER} == yes
+SRCS+= libprocstat_compat.c
+.endif
+
VERSION_DEF= ${LIBCSRCDIR}/Versions.def
SYMBOL_MAPS= ${.CURDIR}/Symbol.map
diff --git a/lib/libprocstat/Symbol.map b/lib/libprocstat/Symbol.map
index 75a8916aca67..a78a4691fe5d 100644
--- a/lib/libprocstat/Symbol.map
+++ b/lib/libprocstat/Symbol.map
@@ -6,9 +6,7 @@ FBSD_1.2 {
procstat_freefiles;
procstat_freeprocs;
procstat_get_pipe_info;
- procstat_get_pts_info;
procstat_get_socket_info;
- procstat_get_vnode_info;
procstat_getfiles;
procstat_getprocs;
procstat_open_kvm;
@@ -22,8 +20,6 @@ FBSD_1.3 {
procstat_freegroups;
procstat_freekstack;
procstat_freevmmap;
- procstat_get_sem_info;
- procstat_get_shm_info;
procstat_getargv;
procstat_getauxv;
procstat_getenvv;
@@ -40,4 +36,8 @@ FBSD_1.3 {
FBSD_1.5 {
procstat_freeptlwpinfo;
procstat_getptlwpinfo;
+ procstat_get_pts_info;
+ procstat_get_sem_info;
+ procstat_get_shm_info;
+ procstat_get_vnode_info;
};
diff --git a/lib/libprocstat/libprocstat.c b/lib/libprocstat/libprocstat.c
index 7d42acce4201..d674adc4f9ea 100644
--- a/lib/libprocstat/libprocstat.c
+++ b/lib/libprocstat/libprocstat.c
@@ -1337,12 +1337,12 @@ procstat_get_vnode_info_sysctl(struct filestat *fst, struct vnstat *vn,
struct statfs stbuf;
struct kinfo_file *kif;
struct kinfo_vmentry *kve;
+ char *name, *path;
uint64_t fileid;
uint64_t size;
- char *name, *path;
- uint32_t fsid;
+ uint64_t fsid;
+ uint64_t rdev;
uint16_t mode;
- uint32_t rdev;
int vntype;
int status;
@@ -1545,8 +1545,10 @@ procstat_get_socket_info_sysctl(struct filestat *fst, struct sockstat *sock,
sock->dom_family = kif->kf_sock_domain;
sock->so_pcb = kif->kf_un.kf_sock.kf_sock_pcb;
strlcpy(sock->dname, kif->kf_path, sizeof(sock->dname));
- bcopy(&kif->kf_sa_local, &sock->sa_local, kif->kf_sa_local.ss_len);
- bcopy(&kif->kf_sa_peer, &sock->sa_peer, kif->kf_sa_peer.ss_len);
+ bcopy(&kif->kf_un.kf_sock.kf_sa_local, &sock->sa_local,
+ kif->kf_un.kf_sock.kf_sa_local.ss_len);
+ bcopy(&kif->kf_un.kf_sock.kf_sa_peer, &sock->sa_peer,
+ kif->kf_un.kf_sock.kf_sa_peer.ss_len);
/*
* Protocol specific data.
diff --git a/lib/libprocstat/libprocstat.h b/lib/libprocstat/libprocstat.h
index 00b6f1c1c110..7584878252d4 100644
--- a/lib/libprocstat/libprocstat.h
+++ b/lib/libprocstat/libprocstat.h
@@ -120,15 +120,15 @@ struct filestat {
struct vnstat {
uint64_t vn_fileid;
uint64_t vn_size;
+ uint64_t vn_dev;
+ uint64_t vn_fsid;
char *vn_mntdir;
- uint32_t vn_dev;
- uint32_t vn_fsid;
int vn_type;
uint16_t vn_mode;
char vn_devname[SPECNAMELEN + 1];
};
struct ptsstat {
- uint32_t dev;
+ uint64_t dev;
char devname[SPECNAMELEN + 1];
};
struct pipestat {
diff --git a/lib/libprocstat/libprocstat_compat.c b/lib/libprocstat/libprocstat_compat.c
new file mode 100644
index 000000000000..52d80c7afab4
--- /dev/null
+++ b/lib/libprocstat/libprocstat_compat.c
@@ -0,0 +1,144 @@
+/*-
+ * Copyright (c) 2014 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 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.
+ *
+ * $FreeBSD$
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/user.h>
+#include <sys/socket.h>
+#include <string.h>
+
+#include "libprocstat.h"
+
+struct freebsd11_ptsstat {
+ uint32_t dev;
+ char devname[SPECNAMELEN + 1];
+};
+
+struct freebsd11_vnstat {
+ uint64_t vn_fileid;
+ uint64_t vn_size;
+ char *vn_mntdir;
+ uint32_t vn_dev;
+ uint32_t vn_fsid;
+ int vn_type;
+ uint16_t vn_mode;
+ char vn_devname[SPECNAMELEN + 1];
+};
+struct freebsd11_semstat {
+ uint32_t value;
+ uint16_t mode;
+};
+struct freebsd11_shmstat {
+ uint64_t size;
+ uint16_t mode;
+};
+
+int freebsd11_procstat_get_pts_info(struct procstat *procstat,
+ struct filestat *fst, struct freebsd11_ptsstat *pts, char *errbuf);
+int freebsd11_procstat_get_sem_info(struct procstat *procstat,
+ struct filestat *fst, struct freebsd11_semstat *sem, char *errbuf);
+int freebsd11_procstat_get_shm_info(struct procstat *procstat,
+ struct filestat *fst, struct freebsd11_shmstat *shm, char *errbuf);
+int freebsd11_procstat_get_vnode_info(struct procstat *procstat,
+ struct filestat *fst, struct freebsd11_vnstat *vn, char *errbuf);
+
+int
+freebsd11_procstat_get_pts_info(struct procstat *procstat,
+ struct filestat *fst, struct freebsd11_ptsstat *pts_compat, char *errbuf)
+{
+ struct ptsstat pts;
+ int r;
+
+ r = procstat_get_pts_info(procstat, fst, &pts, errbuf);
+ if (r != 0)
+ return (r);
+ pts_compat->dev = pts.dev;
+ memcpy(pts_compat->devname, pts.devname,
+ sizeof(pts_compat->devname));
+ return (0);
+}
+
+int
+freebsd11_procstat_get_sem_info(struct procstat *procstat,
+ struct filestat *fst, struct freebsd11_semstat *sem_compat, char *errbuf)
+{
+ struct semstat sem;
+ int r;
+
+ r = procstat_get_sem_info(procstat, fst, &sem, errbuf);
+ if (r != 0)
+ return (r);
+ sem_compat->value = sem.value;
+ sem_compat->mode = sem.mode;
+ return (0);
+}
+
+int
+freebsd11_procstat_get_shm_info(struct procstat *procstat,
+ struct filestat *fst, struct freebsd11_shmstat *shm_compat, char *errbuf)
+{
+ struct shmstat shm;
+ int r;
+
+ r = procstat_get_shm_info(procstat, fst, &shm, errbuf);
+ if (r != 0)
+ return (r);
+ shm_compat->size = shm.size;
+ shm_compat->mode = shm.mode;
+ return (0);
+}
+
+int
+freebsd11_procstat_get_vnode_info(struct procstat *procstat,
+ struct filestat *fst, struct freebsd11_vnstat *vn_compat, char *errbuf)
+{
+ struct vnstat vn;
+ int r;
+
+ r = procstat_get_vnode_info(procstat, fst, &vn, errbuf);
+ if (r != 0)
+ return (r);
+ vn_compat->vn_fileid = vn.vn_fileid;
+ vn_compat->vn_size = vn.vn_size;
+ vn_compat->vn_mntdir = vn.vn_mntdir;
+ vn_compat->vn_dev = vn.vn_dev;
+ vn_compat->vn_fsid = vn.vn_fsid;
+ vn_compat->vn_type = vn.vn_type;
+ vn_compat->vn_mode = vn.vn_mode;
+ memcpy(vn_compat->vn_devname, vn.vn_devname,
+ sizeof(vn_compat->vn_devname));
+ return (0);
+}
+
+__sym_compat(procstat_get_pts_info, freebsd11_procstat_get_pts_info, FBSD_1.2);
+__sym_compat(procstat_get_vnode_info, freebsd11_procstat_get_vnode_info,
+ FBSD_1.2);
+__sym_compat(procstat_get_sem_info, freebsd11_procstat_get_sem_info, FBSD_1.3);
+__sym_compat(procstat_get_shm_info, freebsd11_procstat_get_shm_info, FBSD_1.3);
diff --git a/lib/libufs/libufs.h b/lib/libufs/libufs.h
index a16d82b604ad..ddc5c9b6b055 100644
--- a/lib/libufs/libufs.h
+++ b/lib/libufs/libufs.h
@@ -45,8 +45,8 @@ struct uufsd {
ufs2_daddr_t d_sblock; /* superblock location */
struct csum *d_sbcsum; /* Superblock summary info */
caddr_t d_inoblock; /* inode block */
- ino_t d_inomin; /* low inode */
- ino_t d_inomax; /* high inode */
+ uint32_t d_inomin; /* low inode (not ino_t for ABI compat) */
+ uint32_t d_inomax; /* high inode (not ino_t for ABI compat) */
union {
struct fs d_fs; /* filesystem information */
char d_sb[MAXBSIZE];
diff --git a/sbin/badsect/badsect.c b/sbin/badsect/badsect.c
index f9d2a1afe727..097e3b112f67 100644
--- a/sbin/badsect/badsect.c
+++ b/sbin/badsect/badsect.c
@@ -129,19 +129,8 @@ main(int argc, char *argv[])
err(8, "%s", *argv);
if (chkuse(number, 1))
continue;
- /*
- * Print a warning if converting the block number to a dev_t
- * will truncate it. badsect was not very useful in versions
- * of BSD before 4.4 because dev_t was 16 bits and another
- * bit was lost by bogus sign extensions.
- */
diskbn = dbtofsb(fs, number);
- if ((dev_t)diskbn != diskbn) {
- printf("sector %ld cannot be represented as a dev_t\n",
- (long)number);
- errs++;
- }
- else if (mknod(*argv, IFMT|0600, (dev_t)diskbn) < 0) {
+ if (mknod(*argv, IFMT|0600, (dev_t)diskbn) < 0) {
warn("%s", *argv);
errs++;
}
diff --git a/sbin/fsck_ffs/suj.c b/sbin/fsck_ffs/suj.c
index f0c6524e3ff1..72bf83cdb2f5 100644
--- a/sbin/fsck_ffs/suj.c
+++ b/sbin/fsck_ffs/suj.c
@@ -1347,8 +1347,8 @@ ino_adjust(struct suj_ino *sino)
struct suj_ino *stmp;
union dinode *ip;
nlink_t nlink;
+ nlink_t reqlink;
int recmode;
- int reqlink;
int isdot;
int mode;
ino_t ino;
@@ -1635,9 +1635,9 @@ ino_check(struct suj_ino *sino)
struct suj_rec *srec;
struct jrefrec *rrec;
nlink_t dotlinks;
- int newlinks;
- int removes;
- int nlink;
+ nlink_t newlinks;
+ nlink_t removes;
+ nlink_t nlink;
ino_t ino;
int isdot;
int isat;
diff --git a/share/man/man5/acct.5 b/share/man/man5/acct.5
index 06c72b2af727..549eef2c70bb 100644
--- a/share/man/man5/acct.5
+++ b/share/man/man5/acct.5
@@ -28,7 +28,7 @@
.\" @(#)acct.5 8.1 (Berkeley) 6/5/93
.\" $FreeBSD$
.\"
-.Dd May 15, 2007
+.Dd February 13, 2017
.Dt ACCT 5
.Os
.Sh NAME
@@ -51,12 +51,12 @@ to the accounting file.
#define AC_COMM_LEN 16
/*
- * Accounting structure version 2 (current).
+ * Accounting structure version 3 (current).
* The first byte is always zero.
* Time units are microseconds.
*/
-struct acctv2 {
+struct acctv3 {
uint8_t ac_zero; /* zero identifies new version */
uint8_t ac_version; /* record version number */
uint16_t ac_len; /* record length */
@@ -74,7 +74,7 @@ struct acctv2 {
uint16_t ac_len2; /* record length */
union {
- __dev_t ac_align; /* force v1 compatible alignment */
+ uint32_t ac_align; /* force v1 compatible alignment */
#define AFORK 0x01 /* forked but not exec'ed */
/* ASU is no longer supported */
diff --git a/share/man/man5/dir.5 b/share/man/man5/dir.5
index 19dfc56705c2..01b7d850a3b0 100644
--- a/share/man/man5/dir.5
+++ b/share/man/man5/dir.5
@@ -28,7 +28,7 @@
.\" @(#)dir.5 8.3 (Berkeley) 4/19/94
.\" $FreeBSD$
.\"
-.Dd April 19, 1994
+.Dd February 13, 2017
.Dt DIR 5
.Os
.Sh NAME
@@ -93,18 +93,24 @@ The directory entry format is defined in the file
* contained in the entry. These are followed by the name padded to a 4
* byte boundary with null bytes. All names are guaranteed null terminated.
* The maximum length of a name in a directory is MAXNAMLEN.
+ * Explicit pad is added between the last member of the header and
+ * d_name, to avoid having the ABI padding in the end of dirent on
+ * LP64 arches. There is code depending on d_name being last. Also,
+ * keeping this pad for ILP32 architectures simplifies compat32 layer.
*/
struct dirent {
- __uint32_t d_fileno; /* file number of entry */
+ ino_t d_fileno; /* file number of entry */
+ off_t d_off; /* directory offset of entry */
__uint16_t d_reclen; /* length of this record */
- __uint8_t d_type; /* file type, see below */
+ __uint8_t d_type; /* file type, see below */
__uint8_t d_namlen; /* length of string in d_name */
-#ifdef _POSIX_SOURCE
- char d_name[255 + 1]; /* name must be no longer than this */
-#else
+ __uint32_t d_pad0;
+#if __BSD_VISIBLE
#define MAXNAMLEN 255
char d_name[MAXNAMLEN + 1]; /* name must be no longer than this */
+#else
+ char d_name[255 + 1]; /* name must be no longer than this */
#endif
};
@@ -129,12 +135,17 @@ struct dirent {
/*
* The _GENERIC_DIRSIZ macro gives the minimum record length which will hold
- * the directory entry. This requires the amount of space in struct direct
+ * the directory entry. This returns the amount of space in struct direct
* without the d_name field, plus enough space for the name with a terminating
- * null byte (dp->d_namlen+1), rounded up to a 4 byte boundary.
+ * null byte (dp->d_namlen+1), rounded up to a 8 byte boundary.
+ *
+ * XXX although this macro is in the implementation namespace, it requires
+ * a manifest constant that is not.
*/
-#define _GENERIC_DIRSIZ(dp) \
- ((sizeof (struct dirent) - (MAXNAMLEN+1)) + (((dp)->d_namlen+1 + 3) &~ 3))
+#define _GENERIC_DIRLEN(namlen) \
+ ((__offsetof(struct dirent, d_name) + (namlen) + 1 + 7) & ~7)
+#define _GENERIC_DIRSIZ(dp) _GENERIC_DIRLEN((dp)->d_namlen)
+#endif /* __BSD_VISIBLE */
#ifdef _KERNEL
#define GENERIC_DIRSIZ(dp) _GENERIC_DIRSIZ(dp)
diff --git a/sys/bsm/audit.h b/sys/bsm/audit.h
index af9622af314e..57edb5e4e83f 100644
--- a/sys/bsm/audit.h
+++ b/sys/bsm/audit.h
@@ -183,13 +183,13 @@ typedef u_int32_t au_class_t;
typedef u_int64_t au_asflgs_t __attribute__ ((aligned (8)));
struct au_tid {
- dev_t port;
+ u_int32_t port; /* XXX dev_t compatibility */
u_int32_t machine;
};
typedef struct au_tid au_tid_t;
struct au_tid_addr {
- dev_t at_port;
+ u_int32_t at_port; /* XXX dev_t compatibility */
u_int32_t at_type;
u_int32_t at_addr[4];
};
diff --git a/sys/cddl/compat/opensolaris/sys/dirent.h b/sys/cddl/compat/opensolaris/sys/dirent.h
index d273f8a0fce4..81ea4fa3a97f 100644
--- a/sys/cddl/compat/opensolaris/sys/dirent.h
+++ b/sys/cddl/compat/opensolaris/sys/dirent.h
@@ -40,8 +40,6 @@ typedef ino_t ino64_t;
#define d_ino d_fileno
-#define DIRENT64_RECLEN(len) ((sizeof(struct dirent) - \
- sizeof(((struct dirent *)NULL)->d_name) + \
- (len) + 1 + 3) & ~3)
+#define DIRENT64_RECLEN(len) _GENERIC_DIRLEN(len)
#endif /* !_OPENSOLARIS_SYS_DIRENT_H_ */
diff --git a/sys/compat/freebsd32/capabilities.conf b/sys/compat/freebsd32/capabilities.conf
index 6d815f1ab522..1a5670cade91 100644
--- a/sys/compat/freebsd32/capabilities.conf
+++ b/sys/compat/freebsd32/capabilities.conf
@@ -94,6 +94,11 @@ freebsd32_fexecve
flock
fork
fpathconf
+freebsd11_freebsd32_fstat
+freebsd11_freebsd32_fstatat
+freebsd11_freebsd32_getdirentries
+freebsd11_freebsd32_fstatfs
+freebsd11_freebsd32_mknodat
freebsd6_freebsd32_ftruncate
freebsd6_freebsd32_lseek
freebsd6_freebsd32_mmap
diff --git a/sys/compat/freebsd32/freebsd32.h b/sys/compat/freebsd32/freebsd32.h
index 39213aec94d3..05447da3696b 100644
--- a/sys/compat/freebsd32/freebsd32.h
+++ b/sys/compat/freebsd32/freebsd32.h
@@ -107,7 +107,8 @@ struct itimerval32 {
struct timeval32 it_value;
};
-#define FREEBSD4_MNAMELEN (88 - 2 * sizeof(int32_t)) /* size of on/from name bufs */
+#define FREEBSD4_MFSNAMELEN 16
+#define FREEBSD4_MNAMELEN (88 - 2 * sizeof(int32_t))
/* 4.x version */
struct statfs32 {
@@ -125,7 +126,7 @@ struct statfs32 {
int32_t f_flags;
int32_t f_syncwrites;
int32_t f_asyncwrites;
- char f_fstypename[MFSNAMELEN];
+ char f_fstypename[FREEBSD4_MFSNAMELEN];
char f_mntonname[FREEBSD4_MNAMELEN];
int32_t f_syncreads;
int32_t f_asyncreads;
@@ -159,14 +160,51 @@ struct msghdr32 {
int msg_flags;
};
+#if defined(__amd64__)
+#define __STAT32_TIME_T_EXT 1
+#endif
+
struct stat32 {
- dev_t st_dev;
- ino_t st_ino;
+ dev_t st_dev;
+ ino_t st_ino;
+ nlink_t st_nlink;
+ mode_t st_mode;
+ u_int16_t st_padding0;
+ uid_t st_uid;
+ gid_t st_gid;
+ u_int32_t st_padding1;
+ dev_t st_rdev;
+#ifdef __STAT32_TIME_T_EXT
+ __int32_t st_atim_ext;
+#endif
+ struct timespec32 st_atim;
+#ifdef __STAT32_TIME_T_EXT
+ __int32_t st_mtim_ext;
+#endif
+ struct timespec32 st_mtim;
+#ifdef __STAT32_TIME_T_EXT
+ __int32_t st_ctim_ext;
+#endif
+ struct timespec32 st_ctim;
+#ifdef __STAT32_TIME_T_EXT
+ __int32_t st_btim_ext;
+#endif
+ struct timespec32 st_birthtim;
+ off_t st_size;
+ int64_t st_blocks;
+ u_int32_t st_blksize;
+ u_int32_t st_flags;
+ u_int64_t st_gen;
+ u_int64_t st_spare[10];
+};
+struct freebsd11_stat32 {
+ u_int32_t st_dev;
+ u_int32_t st_ino;
mode_t st_mode;
- nlink_t st_nlink;
+ u_int16_t st_nlink;
uid_t st_uid;
gid_t st_gid;
- dev_t st_rdev;
+ u_int32_t st_rdev;
struct timespec32 st_atim;
struct timespec32 st_mtim;
struct timespec32 st_ctim;
@@ -183,9 +221,9 @@ struct stat32 {
struct ostat32 {
__uint16_t st_dev;
- ino_t st_ino;
+ __uint32_t st_ino;
mode_t st_mode;
- nlink_t st_nlink;
+ __uint16_t st_nlink;
__uint16_t st_uid;
__uint16_t st_gid;
__uint16_t st_rdev;
@@ -270,7 +308,7 @@ struct kinfo_proc32 {
pid_t ki_tsid;
short ki_jobc;
short ki_spare_short1;
- dev_t ki_tdev;
+ uint32_t ki_tdev_freebsd11;
sigset_t ki_siglist;
sigset_t ki_sigmask;
sigset_t ki_sigignore;
@@ -318,6 +356,7 @@ struct kinfo_proc32 {
char ki_moretdname[MAXCOMLEN-TDNAMLEN+1];
char ki_sparestrings[46];
int ki_spareints[KI_NSPARE_INT];
+ uint64_t ki_tdev;
int ki_oncpu;
int ki_lastcpu;
int ki_tracer;
diff --git a/sys/compat/freebsd32/freebsd32_misc.c b/sys/compat/freebsd32/freebsd32_misc.c
index a8e69b731fe7..d73f95f3d071 100644
--- a/sys/compat/freebsd32/freebsd32_misc.c
+++ b/sys/compat/freebsd32/freebsd32_misc.c
@@ -122,8 +122,11 @@ CTASSERT(sizeof(struct sigaltstack32) == 12);
CTASSERT(sizeof(struct kevent32) == 20);
CTASSERT(sizeof(struct iovec32) == 8);
CTASSERT(sizeof(struct msghdr32) == 28);
+#ifdef __amd64__
+CTASSERT(sizeof(struct stat32) == 208);
+#endif
#ifndef __mips__
-CTASSERT(sizeof(struct stat32) == 96);
+CTASSERT(sizeof(struct freebsd11_stat32) == 96);
#endif
CTASSERT(sizeof(struct sigaction32) == 24);
@@ -448,6 +451,26 @@ freebsd32_fexecve(struct thread *td, struct freebsd32_fexecve_args *uap)
return (error);
}
+#if defined(COMPAT_FREEBSD11)
+int
+freebsd11_freebsd32_mknod(struct thread *td,
+ struct freebsd11_freebsd32_mknod_args *uap)
+{
+
+ return (kern_mknodat(td, AT_FDCWD, uap->path, UIO_USERSPACE, uap->mode,
+ uap->dev));
+}
+
+int
+freebsd11_freebsd32_mknodat(struct thread *td,
+ struct freebsd11_freebsd32_mknodat_args *uap)
+{
+
+ return (kern_mknodat(td, uap->fd, uap->path, UIO_USERSPACE, uap->mode,
+ uap->dev));
+}
+#endif /* COMPAT_FREEBSD11 */
+
int
freebsd32_mprotect(struct thread *td, struct freebsd32_mprotect_args *uap)
{
@@ -1519,6 +1542,40 @@ ofreebsd32_getdirentries(struct thread *td,
}
#endif
+#if defined(COMPAT_FREEBSD11)
+int
+freebsd11_freebsd32_getdirentries(struct thread *td,
+ struct freebsd11_freebsd32_getdirentries_args *uap)
+{
+ long base;
+ int32_t base32;
+ int error;
+
+ error = freebsd11_kern_getdirentries(td, uap->fd, uap->buf, uap->count,
+ &base, NULL);
+ if (error)
+ return (error);
+ if (uap->basep != NULL) {
+ base32 = base;
+ error = copyout(&base32, uap->basep, sizeof(int32_t));
+ }
+ return (error);
+}
+
+int
+freebsd11_freebsd32_getdents(struct thread *td,
+ struct freebsd11_freebsd32_getdents_args *uap)
+{
+ struct freebsd11_freebsd32_getdirentries_args ap;
+
+ ap.fd = uap->fd;
+ ap.buf = uap->buf;
+ ap.count = uap->count;
+ ap.basep = NULL;
+ return (freebsd11_freebsd32_getdirentries(td, &ap));
+}
+#endif /* COMPAT_FREEBSD11 */
+
int
freebsd32_getdirentries(struct thread *td,
struct freebsd32_getdirentries_args *uap)
@@ -1709,6 +1766,15 @@ copy_stat(struct stat *in, struct stat32 *out)
CP(*in, *out, st_flags);
CP(*in, *out, st_gen);
TS_CP(*in, *out, st_birthtim);
+ out->st_padding0 = 0;
+ out->st_padding1 = 0;
+#ifdef __STAT32_TIME_T_EXT
+ out->st_atim_ext = 0;
+ out->st_mtim_ext = 0;
+ out->st_ctim_ext = 0;
+ out->st_btim_ext = 0;
+#endif
+ bzero(out->st_spare, sizeof(out->st_spare));
}
#ifdef COMPAT_43
@@ -1734,22 +1800,6 @@ copy_ostat(struct stat *in, struct ostat32 *out)
}
#endif
-int
-freebsd32_stat(struct thread *td, struct freebsd32_stat_args *uap)
-{
- struct stat sb;
- struct stat32 sb32;
- int error;
-
- error = kern_statat(td, 0, AT_FDCWD, uap->path, UIO_USERSPACE,
- &sb, NULL);
- if (error)
- return (error);
- copy_stat(&sb, &sb32);
- error = copyout(&sb32, uap->ub, sizeof (sb32));
- return (error);
-}
-
#ifdef COMPAT_43
int
ofreebsd32_stat(struct thread *td, struct ofreebsd32_stat_args *uap)
@@ -1816,38 +1866,156 @@ freebsd32_fstatat(struct thread *td, struct freebsd32_fstatat_args *uap)
return (error);
}
+#ifdef COMPAT_43
int
-freebsd32_lstat(struct thread *td, struct freebsd32_lstat_args *uap)
+ofreebsd32_lstat(struct thread *td, struct ofreebsd32_lstat_args *uap)
{
struct stat sb;
- struct stat32 sb32;
+ struct ostat32 sb32;
int error;
error = kern_statat(td, AT_SYMLINK_NOFOLLOW, AT_FDCWD, uap->path,
UIO_USERSPACE, &sb, NULL);
if (error)
return (error);
+ copy_ostat(&sb, &sb32);
+ error = copyout(&sb32, uap->ub, sizeof (sb32));
+ return (error);
+}
+#endif
+
+int
+freebsd32_fhstat(struct thread *td, struct freebsd32_fhstat_args *uap)
+{
+ struct stat sb;
+ struct stat32 sb32;
+ struct fhandle fh;
+ int error;
+
+ error = copyin(uap->u_fhp, &fh, sizeof(fhandle_t));
+ if (error != 0)
+ return (error);
+ error = kern_fhstat(td, fh, &sb);
+ if (error != 0)
+ return (error);
copy_stat(&sb, &sb32);
+ error = copyout(&sb32, uap->sb, sizeof (sb32));
+ return (error);
+}
+
+#if defined(COMPAT_FREEBSD11)
+static void
+freebsd11_cvtstat32(struct stat *in, struct freebsd11_stat32 *out)
+{
+
+ CP(*in, *out, st_ino);
+ CP(*in, *out, st_nlink);
+ CP(*in, *out, st_dev);
+ CP(*in, *out, st_mode);
+ CP(*in, *out, st_uid);
+ CP(*in, *out, st_gid);
+ CP(*in, *out, st_rdev);
+ TS_CP(*in, *out, st_atim);
+ TS_CP(*in, *out, st_mtim);
+ TS_CP(*in, *out, st_ctim);
+ CP(*in, *out, st_size);
+ CP(*in, *out, st_blocks);
+ CP(*in, *out, st_blksize);
+ CP(*in, *out, st_flags);
+ CP(*in, *out, st_gen);
+ TS_CP(*in, *out, st_birthtim);
+ out->st_lspare = 0;
+ bzero((char *)&out->st_birthtim + sizeof(out->st_birthtim),
+ sizeof(*out) - offsetof(struct freebsd11_stat32,
+ st_birthtim) - sizeof(out->st_birthtim));
+}
+
+int
+freebsd11_freebsd32_stat(struct thread *td,
+ struct freebsd11_freebsd32_stat_args *uap)
+{
+ struct stat sb;
+ struct freebsd11_stat32 sb32;
+ int error;
+
+ error = kern_statat(td, 0, AT_FDCWD, uap->path, UIO_USERSPACE,
+ &sb, NULL);
+ if (error != 0)
+ return (error);
+ freebsd11_cvtstat32(&sb, &sb32);
error = copyout(&sb32, uap->ub, sizeof (sb32));
return (error);
}
-#ifdef COMPAT_43
int
-ofreebsd32_lstat(struct thread *td, struct ofreebsd32_lstat_args *uap)
+freebsd11_freebsd32_fstat(struct thread *td,
+ struct freebsd11_freebsd32_fstat_args *uap)
{
struct stat sb;
- struct ostat32 sb32;
+ struct freebsd11_stat32 sb32;
+ int error;
+
+ error = kern_fstat(td, uap->fd, &sb);
+ if (error != 0)
+ return (error);
+ freebsd11_cvtstat32(&sb, &sb32);
+ error = copyout(&sb32, uap->ub, sizeof (sb32));
+ return (error);
+}
+
+int
+freebsd11_freebsd32_fstatat(struct thread *td,
+ struct freebsd11_freebsd32_fstatat_args *uap)
+{
+ struct stat sb;
+ struct freebsd11_stat32 sb32;
+ int error;
+
+ error = kern_statat(td, uap->flag, uap->fd, uap->path, UIO_USERSPACE,
+ &sb, NULL);
+ if (error != 0)
+ return (error);
+ freebsd11_cvtstat32(&sb, &sb32);
+ error = copyout(&sb32, uap->buf, sizeof (sb32));
+ return (error);
+}
+
+int
+freebsd11_freebsd32_lstat(struct thread *td,
+ struct freebsd11_freebsd32_lstat_args *uap)
+{
+ struct stat sb;
+ struct freebsd11_stat32 sb32;
int error;
error = kern_statat(td, AT_SYMLINK_NOFOLLOW, AT_FDCWD, uap->path,
UIO_USERSPACE, &sb, NULL);
if (error)
return (error);
- copy_ostat(&sb, &sb32);
+ freebsd11_cvtstat32(&sb, &sb32);
error = copyout(&sb32, uap->ub, sizeof (sb32));
return (error);
}
+
+int
+freebsd11_freebsd32_fhstat(struct thread *td,
+ struct freebsd11_freebsd32_fhstat_args *uap)
+{
+ struct stat sb;
+ struct freebsd11_stat32 sb32;
+ struct fhandle fh;
+ int error;
+
+ error = copyin(uap->u_fhp, &fh, sizeof(fhandle_t));
+ if (error != 0)
+ return (error);
+ error = kern_fhstat(td, fh, &sb);
+ if (error != 0)
+ return (error);
+ freebsd11_cvtstat32(&sb, &sb32);
+ error = copyout(&sb32, uap->sb, sizeof (sb32));
+ return (error);
+}
#endif
int
diff --git a/sys/compat/freebsd32/syscalls.master b/sys/compat/freebsd32/syscalls.master
index ac624e4f7df2..fce75fe3488a 100644
--- a/sys/compat/freebsd32/syscalls.master
+++ b/sys/compat/freebsd32/syscalls.master
@@ -13,7 +13,7 @@
; case where the event exists, but we don't want auditing, the
; event should be #defined to AUE_NULL in audit_kevents.h.
; type one of STD, OBSOL, UNIMPL, COMPAT, COMPAT4, COMPAT6,
-; COMPAT7, NODEF, NOARGS, NOPROTO, NOSTD
+; COMPAT7, COMPAT11, NODEF, NOARGS, NOPROTO, NOSTD
; The COMPAT* options may be combined with one or more NO*
; options separated by '|' with no spaces (e.g. COMPAT|NOARGS)
; name psuedo-prototype of syscall routine
@@ -30,6 +30,7 @@
; COMPAT6 included on COMPAT6 #ifdef (FreeBSD 6 compat)
; COMPAT7 included on COMPAT7 #ifdef (FreeBSD 7 compat)
; COMPAT10 included on COMPAT10 #ifdef (FreeBSD 10 compat)
+; COMPAT11 included on COMPAT11 #ifdef (FreeBSD 11 compat)
; OBSOL obsolete, not included in system, only specifies name
; UNIMPL not implemented, placeholder only
; NOSTD implemented but as a lkm that can be statically
@@ -82,7 +83,8 @@
11 AUE_NULL OBSOL execv
12 AUE_CHDIR NOPROTO { int chdir(char *path); }
13 AUE_FCHDIR NOPROTO { int fchdir(int fd); }
-14 AUE_MKNOD NOPROTO { int mknod(char *path, int mode, int dev); }
+14 AUE_MKNOD COMPAT11 { int freebsd32_mknod(char *path, \
+ int mode, int dev); }
15 AUE_CHMOD NOPROTO { int chmod(char *path, int mode); }
16 AUE_CHOWN NOPROTO { int chown(char *path, int uid, int gid); }
17 AUE_NULL NOPROTO { int obreak(char *nsize); } break \
@@ -348,12 +350,12 @@
185 AUE_NULL UNIMPL lfs_markv
186 AUE_NULL UNIMPL lfs_segclean
187 AUE_NULL UNIMPL lfs_segwait
-188 AUE_STAT STD { int freebsd32_stat(char *path, \
- struct stat32 *ub); }
-189 AUE_FSTAT STD { int freebsd32_fstat(int fd, \
- struct stat32 *ub); }
-190 AUE_LSTAT STD { int freebsd32_lstat(char *path, \
- struct stat32 *ub); }
+188 AUE_STAT COMPAT11 { int freebsd32_stat(char *path, \
+ struct freebsd11_stat32 *ub); }
+189 AUE_FSTAT COMPAT11 { int freebsd32_fstat(int fd, \
+ struct freebsd11_stat32 *ub); }
+190 AUE_LSTAT COMPAT11 { int freebsd32_lstat(char *path, \
+ struct freebsd11_stat32 *ub); }
191 AUE_PATHCONF NOPROTO { int pathconf(char *path, int name); }
192 AUE_FPATHCONF NOPROTO { int fpathconf(int fd, int name); }
193 AUE_NULL UNIMPL nosys
@@ -363,7 +365,7 @@
195 AUE_SETRLIMIT NOPROTO { int setrlimit(u_int which, \
struct rlimit *rlp); } setrlimit \
__setrlimit_args int
-196 AUE_GETDIRENTRIES STD { int freebsd32_getdirentries(int fd, \
+196 AUE_GETDIRENTRIES COMPAT11 { int freebsd32_getdirentries(int fd, \
char *buf, u_int count, int32_t *basep); }
197 AUE_MMAP COMPAT6 { caddr_t freebsd32_mmap(caddr_t addr, \
size_t len, int prot, int flags, int fd, \
@@ -501,8 +503,8 @@
269 AUE_NULL UNIMPL nosys
270 AUE_NULL UNIMPL nosys
271 AUE_NULL UNIMPL nosys
-272 AUE_O_GETDENTS NOPROTO { int getdents(int fd, char *buf, \
- size_t count); }
+272 AUE_O_GETDENTS COMPAT11 { int freebsd32_getdents(int fd, char *buf, \
+ int count); }
273 AUE_NULL UNIMPL nosys
274 AUE_LCHMOD NOPROTO { int lchmod(char *path, mode_t mode); }
275 AUE_LCHOWN NOPROTO { int lchown(char *path, uid_t uid, \
@@ -512,9 +514,9 @@
struct timeval32 *tptr); }
277 AUE_MSYNC NOPROTO { int msync(void *addr, size_t len, \
int flags); } netbsd_msync msync_args int
-278 AUE_STAT NOPROTO { int nstat(char *path, struct nstat *ub); }
-279 AUE_FSTAT NOPROTO { int nfstat(int fd, struct nstat *sb); }
-280 AUE_LSTAT NOPROTO { int nlstat(char *path, struct nstat *ub); }
+278 AUE_STAT COMPAT11|NOPROTO { int nstat(char *path, struct nstat *ub); }
+279 AUE_FSTAT COMPAT11|NOPROTO { int nfstat(int fd, struct nstat *sb); }
+280 AUE_LSTAT COMPAT11|NOPROTO { int nlstat(char *path, struct nstat *ub); }
281 AUE_NULL UNIMPL nosys
282 AUE_NULL UNIMPL nosys
283 AUE_NULL UNIMPL nosys
@@ -544,8 +546,9 @@
struct statfs32 *buf); }
298 AUE_FHOPEN NOPROTO { int fhopen(const struct fhandle *u_fhp, \
int flags); }
-299 AUE_FHSTAT NOPROTO { int fhstat(const struct fhandle *u_fhp, \
- struct stat *sb); }
+299 AUE_FHSTAT COMPAT11 { int freebsd32_fhstat( \
+ const struct fhandle *u_fhp, \
+ struct freebsd11_stat32 *sb); }
; syscall numbers for FreeBSD
300 AUE_NULL NOPROTO { int modnext(int modid); }
301 AUE_NULL STD { int freebsd32_modstat(int modid, \
@@ -713,13 +716,16 @@
size_t nbytes, struct sf_hdtr32 *hdtr, \
off_t *sbytes, int flags); }
394 AUE_NULL UNIMPL mac_syscall
-395 AUE_GETFSSTAT NOPROTO { int getfsstat(struct statfs *buf, \
+395 AUE_GETFSSTAT COMPAT11|NOPROTO { int getfsstat( \
+ struct freebsd11_statfs *buf, \
long bufsize, int mode); }
-396 AUE_STATFS NOPROTO { int statfs(char *path, \
- struct statfs *buf); }
-397 AUE_FSTATFS NOPROTO { int fstatfs(int fd, struct statfs *buf); }
-398 AUE_FHSTATFS NOPROTO { int fhstatfs(const struct fhandle *u_fhp, \
+396 AUE_STATFS COMPAT11|NOPROTO { int statfs(char *path, \
struct statfs *buf); }
+397 AUE_FSTATFS COMPAT11|NOPROTO { int fstatfs(int fd, \
+ struct freebsd11_statfs *buf); }
+398 AUE_FHSTATFS COMPAT11|NOPROTO { int fhstatfs( \
+ const struct fhandle *u_fhp, \
+ struct freebsd11_statfs *buf); }
399 AUE_NULL UNIMPL nosys
400 AUE_SEMCLOSE NOSTD|NOPROTO { int ksem_close(semid_t id); }
401 AUE_SEMPOST NOSTD|NOPROTO { int ksem_post(semid_t id); }
@@ -936,8 +942,9 @@
gid_t gid, int flag); }
492 AUE_FEXECVE STD { int freebsd32_fexecve(int fd, \
uint32_t *argv, uint32_t *envv); }
-493 AUE_FSTATAT STD { int freebsd32_fstatat(int fd, char *path, \
- struct stat *buf, int flag); }
+493 AUE_FSTATAT COMPAT11 { int freebsd32_fstatat(int fd, \
+ char *path, struct freebsd11_stat32 *buf, \
+ int flag); }
494 AUE_FUTIMESAT STD { int freebsd32_futimesat(int fd, char *path, \
struct timeval *times); }
495 AUE_LINKAT NOPROTO { int linkat(int fd1, char *path1, int fd2, \
@@ -946,8 +953,8 @@
mode_t mode); }
497 AUE_MKFIFOAT NOPROTO { int mkfifoat(int fd, char *path, \
mode_t mode); }
-498 AUE_MKNODAT NOPROTO { int mknodat(int fd, char *path, \
- mode_t mode, dev_t dev); }
+498 AUE_MKNODAT COMPAT11 { int freebsd32_mknodat(int fd, char *path, \
+ mode_t mode, uint32_t dev); }
499 AUE_OPENAT_RWTC NOPROTO { int openat(int fd, char *path, int flag, \
mode_t mode); }
500 AUE_READLINKAT NOPROTO { int readlinkat(int fd, char *path, char *buf, \
@@ -1084,3 +1091,23 @@
id_t id, \
const struct vm_domain_policy *policy); }
550 AUE_FSYNC NOPROTO { int fdatasync(int fd); }
+551 AUE_FSTAT STD { int freebsd32_fstat(int fd, \
+ struct stat32 *ub); }
+552 AUE_FSTATAT STD { int freebsd32_fstatat(int fd, \
+ char *path, struct stat32 *buf, \
+ int flag); }
+553 AUE_FHSTAT STD { int freebsd32_fhstat( \
+ const struct fhandle *u_fhp, \
+ struct stat32 *sb); }
+554 AUE_GETDIRENTRIES STD { ssize_t freebsd32_getdirentries( \
+ int fd, char *buf, size_t count, \
+ int32_t *basep); }
+555 AUE_STATFS NOPROTO { int statfs(char *path, \
+ struct statfs32 *buf); }
+556 AUE_FSTATFS NOPROTO { int fstatfs(int fd, struct statfs32 *buf); }
+557 AUE_GETFSSTAT NOPROTO { int getfsstat(struct statfs32 *buf, \
+ long bufsize, int mode); }
+558 AUE_FHSTATFS NOPROTO { int fhstatfs(const struct fhandle *u_fhp, \
+ struct statfs32 *buf); }
+559 AUE_MKNODAT NOPROTO { int mknodat(int fd, char *path, mode_t mode, \
+ dev_t dev); }
diff --git a/sys/compat/linux/linux_file.c b/sys/compat/linux/linux_file.c
index 6480fc823a55..4bacee37df38 100644
--- a/sys/compat/linux/linux_file.c
+++ b/sys/compat/linux/linux_file.c
@@ -328,7 +328,7 @@ linux_getdents(struct thread *td, struct linux_getdents_args *args)
caddr_t outp; /* Linux-format */
int resid, linuxreclen; /* Linux-format */
caddr_t lbuf; /* Linux-format */
- long base;
+ off_t base;
struct l_dirent *linux_dirent;
int buflen, error;
size_t retval;
@@ -409,7 +409,7 @@ linux_getdents64(struct thread *td, struct linux_getdents64_args *args)
caddr_t outp; /* Linux-format */
int resid, linuxreclen; /* Linux-format */
caddr_t lbuf; /* Linux-format */
- long base;
+ off_t base;
struct l_dirent64 *linux_dirent64;
int buflen, error;
size_t retval;
@@ -486,7 +486,7 @@ linux_readdir(struct thread *td, struct linux_readdir_args *args)
caddr_t buf; /* BSD-format */
int linuxreclen; /* Linux-format */
caddr_t lbuf; /* Linux-format */
- long base;
+ off_t base;
struct l_dirent *linux_dirent;
int buflen, error;
@@ -1087,20 +1087,21 @@ int
linux_mount(struct thread *td, struct linux_mount_args *args)
{
char fstypename[MFSNAMELEN];
- char mntonname[MNAMELEN], mntfromname[MNAMELEN];
- int error;
- int fsflags;
+ char *mntonname, *mntfromname;
+ int error, fsflags;
+ mntonname = malloc(MNAMELEN, M_TEMP, M_WAITOK);
+ mntfromname = malloc(MNAMELEN, M_TEMP, M_WAITOK);
error = copyinstr(args->filesystemtype, fstypename, MFSNAMELEN - 1,
NULL);
- if (error)
- return (error);
+ if (error != 0)
+ goto out;
error = copyinstr(args->specialfile, mntfromname, MNAMELEN - 1, NULL);
- if (error)
- return (error);
+ if (error != 0)
+ goto out;
error = copyinstr(args->dir, mntonname, MNAMELEN - 1, NULL);
- if (error)
- return (error);
+ if (error != 0)
+ goto out;
#ifdef DEBUG
if (ldebug(mount))
@@ -1138,6 +1139,9 @@ linux_mount(struct thread *td, struct linux_mount_args *args)
"fspath", mntonname,
"from", mntfromname,
NULL);
+out:
+ free(mntonname, M_TEMP);
+ free(mntfromname, M_TEMP);
return (error);
}
diff --git a/sys/dev/snp/snp.c b/sys/dev/snp/snp.c
index 1c02660bec1d..84260182265c 100644
--- a/sys/dev/snp/snp.c
+++ b/sys/dev/snp/snp.c
@@ -60,6 +60,8 @@ SX_SYSINIT(snp_register_lock, &snp_register_lock,
#define SNP_UNLOCK() sx_xunlock(&snp_register_lock)
#endif
+#define SNPGTYY_32DEV _IOR('T', 89, uint32_t)
+
/*
* There is no need to have a big input buffer. In most typical setups,
* we won't inject much data into the TTY, because users can't type
@@ -275,6 +277,12 @@ snp_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int flags,
else
*(dev_t *)data = tty_udev(ss->snp_tty);
return (0);
+ case SNPGTYY_32DEV:
+ if (ss->snp_tty == NULL)
+ *(uint32_t *)data = -1;
+ else
+ *(uint32_t *)data = tty_udev(ss->snp_tty); /* trunc */
+ return (0);
case FIONREAD:
tp = ss->snp_tty;
if (tp != NULL) {
diff --git a/sys/fs/devfs/devfs_devs.c b/sys/fs/devfs/devfs_devs.c
index e600ff1cea47..695d3315cca6 100644
--- a/sys/fs/devfs/devfs_devs.c
+++ b/sys/fs/devfs/devfs_devs.c
@@ -28,6 +28,8 @@
* $FreeBSD$
*/
+#include "opt_compat.h"
+
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/conf.h>
@@ -80,10 +82,20 @@ sysctl_devname(SYSCTL_HANDLER_ARGS)
{
int error;
dev_t ud;
+#ifdef COMPAT_FREEBSD11
+ uint32_t ud_compat;
+#endif
struct cdev_priv *cdp;
struct cdev *dev;
- error = SYSCTL_IN(req, &ud, sizeof (ud));
+#ifdef COMPAT_FREEBSD11
+ if (req->newlen == sizeof(ud_compat)) {
+ error = SYSCTL_IN(req, &ud_compat, sizeof(ud_compat));
+ if (error == 0)
+ ud = ud_compat == (uint32_t)NODEV ? NODEV : ud_compat;
+ } else
+#endif
+ error = SYSCTL_IN(req, &ud, sizeof (ud));
if (error)
return (error);
if (ud == NODEV)
diff --git a/sys/fs/devfs/devfs_vnops.c b/sys/fs/devfs/devfs_vnops.c
index 49435608e2da..18b962eadffc 100644
--- a/sys/fs/devfs/devfs_vnops.c
+++ b/sys/fs/devfs/devfs_vnops.c
@@ -1315,6 +1315,7 @@ devfs_readdir(struct vop_readdir_args *ap)
else
de = dd;
dp = dd->de_dirent;
+ MPASS(dp->d_reclen == GENERIC_DIRSIZ(dp));
if (dp->d_reclen > uio->uio_resid)
break;
dp->d_fileno = de->de_inode;
diff --git a/sys/fs/fdescfs/fdesc_vnops.c b/sys/fs/fdescfs/fdesc_vnops.c
index 65b8a54657be..885cc35b038e 100644
--- a/sys/fs/fdescfs/fdesc_vnops.c
+++ b/sys/fs/fdescfs/fdesc_vnops.c
@@ -485,7 +485,7 @@ fdesc_setattr(struct vop_setattr_args *ap)
return (error);
}
-#define UIO_MX 16
+#define UIO_MX _GENERIC_DIRLEN(10) /* number of symbols in INT_MAX printout */
static int
fdesc_readdir(struct vop_readdir_args *ap)
diff --git a/sys/fs/nandfs/nandfs_fs.h b/sys/fs/nandfs/nandfs_fs.h
index 3e23d7729993..d010830a9042 100644
--- a/sys/fs/nandfs/nandfs_fs.h
+++ b/sys/fs/nandfs/nandfs_fs.h
@@ -537,7 +537,7 @@ struct nandfs_bdesc {
#ifndef _KERNEL
#ifndef MNAMELEN
-#define MNAMELEN 88
+#define MNAMELEN 1024
#endif
#endif
diff --git a/sys/fs/nfs/nfsport.h b/sys/fs/nfs/nfsport.h
index 0bdd26b1f8c5..67849e1543dc 100644
--- a/sys/fs/nfs/nfsport.h
+++ b/sys/fs/nfs/nfsport.h
@@ -730,12 +730,6 @@ int nfsmsleep(void *, void *, int, const char *, struct timespec *);
#define NFSMINOR(d) minor(d)
/*
- * Define this to be the macro that returns the minimum size required
- * for a directory entry.
- */
-#define DIRENT_SIZE(dp) GENERIC_DIRSIZ(dp)
-
-/*
* The vnode tag for nfsv4root.
*/
#define VT_NFSV4ROOT "nfsv4root"
diff --git a/sys/fs/nfsclient/nfs_clrpcops.c b/sys/fs/nfsclient/nfs_clrpcops.c
index c5c6592b84c5..c93ab0865b9e 100644
--- a/sys/fs/nfsclient/nfs_clrpcops.c
+++ b/sys/fs/nfsclient/nfs_clrpcops.c
@@ -72,7 +72,7 @@ short nfsv4_cbport = NFSV4_CBPORT;
int nfstest_openallsetattr = 0;
#endif /* !APPLEKEXT */
-#define DIRHDSIZ (sizeof (struct dirent) - (MAXNAMLEN + 1))
+#define DIRHDSIZ offsetof(struct dirent, d_name)
/*
* nfscl_getsameserver() can return one of three values:
@@ -2861,17 +2861,18 @@ nfsrpc_readdir(vnode_t vp, struct uio *uiop, nfsuint64 *cookiep,
if (error)
return (error);
nd->nd_mrep = NULL;
- dp = (struct dirent *) CAST_DOWN(caddr_t, uio_iov_base(uiop));
+ dp = (struct dirent *)uio_iov_base(uiop);
+ dp->d_off = 0;
dp->d_type = DT_DIR;
dp->d_fileno = dotfileid;
dp->d_namlen = 1;
+ *((uint64_t *)dp->d_name) = 0; /* Zero pad it. */
dp->d_name[0] = '.';
- dp->d_name[1] = '\0';
- dp->d_reclen = DIRENT_SIZE(dp) + NFSX_HYPER;
+ dp->d_reclen = _GENERIC_DIRSIZ(dp) + NFSX_HYPER;
/*
* Just make these offset cookie 0.
*/
- tl = (u_int32_t *)&dp->d_name[4];
+ tl = (u_int32_t *)&dp->d_name[8];
*tl++ = 0;
*tl = 0;
blksiz += dp->d_reclen;
@@ -2879,18 +2880,19 @@ nfsrpc_readdir(vnode_t vp, struct uio *uiop, nfsuint64 *cookiep,
uiop->uio_offset += dp->d_reclen;
uio_iov_base_add(uiop, dp->d_reclen);
uio_iov_len_add(uiop, -(dp->d_reclen));
- dp = (struct dirent *) CAST_DOWN(caddr_t, uio_iov_base(uiop));
+ dp = (struct dirent *)uio_iov_base(uiop);
+ dp->d_off = 0;
dp->d_type = DT_DIR;
dp->d_fileno = dotdotfileid;
dp->d_namlen = 2;
+ *((uint64_t *)dp->d_name) = 0;
dp->d_name[0] = '.';
dp->d_name[1] = '.';
- dp->d_name[2] = '\0';
- dp->d_reclen = DIRENT_SIZE(dp) + NFSX_HYPER;
+ dp->d_reclen = _GENERIC_DIRSIZ(dp) + NFSX_HYPER;
/*
* Just make these offset cookie 0.
*/
- tl = (u_int32_t *)&dp->d_name[4];
+ tl = (u_int32_t *)&dp->d_name[8];
*tl++ = 0;
*tl = 0;
blksiz += dp->d_reclen;
@@ -2987,11 +2989,11 @@ nfsrpc_readdir(vnode_t vp, struct uio *uiop, nfsuint64 *cookiep,
error = EBADRPC;
goto nfsmout;
}
- tlen = NFSM_RNDUP(len);
+ tlen = roundup2(len, 8);
if (tlen == len)
- tlen += 4; /* To ensure null termination */
+ tlen += 8; /* To ensure null termination. */
left = DIRBLKSIZ - blksiz;
- if ((int)(tlen + DIRHDSIZ + NFSX_HYPER) > left) {
+ if (_GENERIC_DIRLEN(len) + NFSX_HYPER > left) {
dp->d_reclen += left;
uio_iov_base_add(uiop, left);
uio_iov_len_add(uiop, -(left));
@@ -2999,12 +3001,15 @@ nfsrpc_readdir(vnode_t vp, struct uio *uiop, nfsuint64 *cookiep,
uiop->uio_offset += left;
blksiz = 0;
}
- if ((int)(tlen + DIRHDSIZ + NFSX_HYPER) > uio_uio_resid(uiop))
+ if (_GENERIC_DIRLEN(len) + NFSX_HYPER >
+ uio_uio_resid(uiop))
bigenough = 0;
if (bigenough) {
- dp = (struct dirent *) CAST_DOWN(caddr_t, uio_iov_base(uiop));
+ dp = (struct dirent *)uio_iov_base(uiop);
+ dp->d_off = 0;
dp->d_namlen = len;
- dp->d_reclen = tlen + DIRHDSIZ + NFSX_HYPER;
+ dp->d_reclen = _GENERIC_DIRLEN(len) +
+ NFSX_HYPER;
dp->d_type = DT_UNKNOWN;
blksiz += dp->d_reclen;
if (blksiz == DIRBLKSIZ)
@@ -3016,7 +3021,7 @@ nfsrpc_readdir(vnode_t vp, struct uio *uiop, nfsuint64 *cookiep,
error = nfsm_mbufuio(nd, uiop, len);
if (error)
goto nfsmout;
- cp = CAST_DOWN(caddr_t, uio_iov_base(uiop));
+ cp = uio_iov_base(uiop);
tlen -= len;
*cp = '\0'; /* null terminate */
cp += tlen; /* points to cookie storage */
@@ -3131,8 +3136,8 @@ nfsrpc_readdir(vnode_t vp, struct uio *uiop, nfsuint64 *cookiep,
/*
* Add extra empty records to any remaining DIRBLKSIZ chunks.
*/
- while (uio_uio_resid(uiop) > 0 && ((size_t)(uio_uio_resid(uiop))) != tresid) {
- dp = (struct dirent *) CAST_DOWN(caddr_t, uio_iov_base(uiop));
+ while (uio_uio_resid(uiop) > 0 && uio_uio_resid(uiop) != tresid) {
+ dp = (struct dirent *)uio_iov_base(uiop);
dp->d_type = DT_UNKNOWN;
dp->d_fileno = 0;
dp->d_namlen = 0;
@@ -3289,16 +3294,17 @@ nfsrpc_readdirplus(vnode_t vp, struct uio *uiop, nfsuint64 *cookiep,
return (error);
nd->nd_mrep = NULL;
dp = (struct dirent *)uio_iov_base(uiop);
+ dp->d_off = 0;
dp->d_type = DT_DIR;
dp->d_fileno = dotfileid;
dp->d_namlen = 1;
+ *((uint64_t *)dp->d_name) = 0; /* Zero pad it. */
dp->d_name[0] = '.';
- dp->d_name[1] = '\0';
- dp->d_reclen = DIRENT_SIZE(dp) + NFSX_HYPER;
+ dp->d_reclen = _GENERIC_DIRSIZ(dp) + NFSX_HYPER;
/*
* Just make these offset cookie 0.
*/
- tl = (u_int32_t *)&dp->d_name[4];
+ tl = (u_int32_t *)&dp->d_name[8];
*tl++ = 0;
*tl = 0;
blksiz += dp->d_reclen;
@@ -3307,17 +3313,18 @@ nfsrpc_readdirplus(vnode_t vp, struct uio *uiop, nfsuint64 *cookiep,
uio_iov_base_add(uiop, dp->d_reclen);
uio_iov_len_add(uiop, -(dp->d_reclen));
dp = (struct dirent *)uio_iov_base(uiop);
+ dp->d_off = 0;
dp->d_type = DT_DIR;
dp->d_fileno = dotdotfileid;
dp->d_namlen = 2;
+ *((uint64_t *)dp->d_name) = 0;
dp->d_name[0] = '.';
dp->d_name[1] = '.';
- dp->d_name[2] = '\0';
- dp->d_reclen = DIRENT_SIZE(dp) + NFSX_HYPER;
+ dp->d_reclen = _GENERIC_DIRSIZ(dp) + NFSX_HYPER;
/*
* Just make these offset cookie 0.
*/
- tl = (u_int32_t *)&dp->d_name[4];
+ tl = (u_int32_t *)&dp->d_name[8];
*tl++ = 0;
*tl = 0;
blksiz += dp->d_reclen;
@@ -3395,11 +3402,11 @@ nfsrpc_readdirplus(vnode_t vp, struct uio *uiop, nfsuint64 *cookiep,
error = EBADRPC;
goto nfsmout;
}
- tlen = NFSM_RNDUP(len);
+ tlen = roundup2(len, 8);
if (tlen == len)
- tlen += 4; /* To ensure null termination */
+ tlen += 8; /* To ensure null termination. */
left = DIRBLKSIZ - blksiz;
- if ((tlen + DIRHDSIZ + NFSX_HYPER) > left) {
+ if (_GENERIC_DIRLEN(len) + NFSX_HYPER > left) {
dp->d_reclen += left;
uio_iov_base_add(uiop, left);
uio_iov_len_add(uiop, -(left));
@@ -3407,12 +3414,15 @@ nfsrpc_readdirplus(vnode_t vp, struct uio *uiop, nfsuint64 *cookiep,
uiop->uio_offset += left;
blksiz = 0;
}
- if ((tlen + DIRHDSIZ + NFSX_HYPER) > uio_uio_resid(uiop))
+ if (_GENERIC_DIRLEN(len) + NFSX_HYPER >
+ uio_uio_resid(uiop))
bigenough = 0;
if (bigenough) {
dp = (struct dirent *)uio_iov_base(uiop);
+ dp->d_off = 0;
dp->d_namlen = len;
- dp->d_reclen = tlen + DIRHDSIZ + NFSX_HYPER;
+ dp->d_reclen = _GENERIC_DIRLEN(len) +
+ NFSX_HYPER;
dp->d_type = DT_UNKNOWN;
blksiz += dp->d_reclen;
if (blksiz == DIRBLKSIZ)
diff --git a/sys/fs/nfsclient/nfs_clvnops.c b/sys/fs/nfsclient/nfs_clvnops.c
index fae2551e1239..e00c25130b07 100644
--- a/sys/fs/nfsclient/nfs_clvnops.c
+++ b/sys/fs/nfsclient/nfs_clvnops.c
@@ -207,8 +207,6 @@ static int nfs_renameit(struct vnode *sdvp, struct vnode *svp,
/*
* Global variables
*/
-#define DIRHDSIZ (sizeof (struct dirent) - (MAXNAMLEN + 1))
-
SYSCTL_DECL(_vfs_nfs);
static int nfsaccess_cache_timeout = NFS_MAXATTRTIMO;
diff --git a/sys/fs/nfsserver/nfs_nfsdport.c b/sys/fs/nfsserver/nfs_nfsdport.c
index b0fd83e086b1..e6380238d1e6 100644
--- a/sys/fs/nfsserver/nfs_nfsdport.c
+++ b/sys/fs/nfsserver/nfs_nfsdport.c
@@ -2020,17 +2020,25 @@ again:
}
/*
- * For now ZFS requires VOP_LOOKUP as a workaround. Until ino_t is changed
- * to 64 bit type a ZFS filesystem with over 1 billion files in it
- * will suffer from 64bit -> 32bit truncation.
+ * Check to see if entries in this directory can be safely acquired
+ * via VFS_VGET() or if a switch to VOP_LOOKUP() is required.
+ * ZFS snapshot directories need VOP_LOOKUP(), so that any
+ * automount of the snapshot directory that is required will
+ * be done.
+ * This needs to be done here for NFSv4, since NFSv4 never does
+ * a VFS_VGET() for "." or "..".
*/
- if (is_zfs == 1)
- usevget = 0;
-
- cn.cn_nameiop = LOOKUP;
- cn.cn_lkflags = LK_SHARED | LK_RETRY;
- cn.cn_cred = nd->nd_cred;
- cn.cn_thread = p;
+ if (is_zfs == 1) {
+ r = VFS_VGET(mp, at.na_fileid, LK_SHARED, &nvp);
+ if (r == EOPNOTSUPP) {
+ usevget = 0;
+ cn.cn_nameiop = LOOKUP;
+ cn.cn_lkflags = LK_SHARED | LK_RETRY;
+ cn.cn_cred = nd->nd_cred;
+ cn.cn_thread = p;
+ } else if (r == 0)
+ vput(nvp);
+ }
/*
* Save this position, in case there is an error before one entry
@@ -2099,7 +2107,16 @@ again:
else
r = EOPNOTSUPP;
if (r == EOPNOTSUPP) {
- usevget = 0;
+ if (usevget) {
+ usevget = 0;
+ cn.cn_nameiop = LOOKUP;
+ cn.cn_lkflags =
+ LK_SHARED |
+ LK_RETRY;
+ cn.cn_cred =
+ nd->nd_cred;
+ cn.cn_thread = p;
+ }
cn.cn_nameptr = dp->d_name;
cn.cn_namelen = nlen;
cn.cn_flags = ISLASTCN |
diff --git a/sys/kern/capabilities.conf b/sys/kern/capabilities.conf
index 1c8ca0811d8d..a59601345c9c 100644
--- a/sys/kern/capabilities.conf
+++ b/sys/kern/capabilities.conf
@@ -197,6 +197,11 @@ fpathconf
## Allow various file descriptor-based I/O operations, subject to capability
## rights.
##
+freebsd11_fstat
+freebsd11_fstatat
+freebsd11_getdirentries
+freebsd11_fstatfs
+freebsd11_mknodat
freebsd6_ftruncate
freebsd6_lseek
freebsd6_mmap
diff --git a/sys/kern/kern_acct.c b/sys/kern/kern_acct.c
index 622a6a49ea19..c13baa5d3891 100644
--- a/sys/kern/kern_acct.c
+++ b/sys/kern/kern_acct.c
@@ -96,6 +96,11 @@ __FBSDID("$FreeBSD$");
#include <security/mac/mac_framework.h>
+_Static_assert(sizeof(struct acctv3) - offsetof(struct acctv3, ac_trailer) ==
+ sizeof(struct acctv2) - offsetof(struct acctv2, ac_trailer), "trailer");
+_Static_assert(sizeof(struct acctv3) - offsetof(struct acctv3, ac_len2) ==
+ sizeof(struct acctv2) - offsetof(struct acctv2, ac_len2), "len2");
+
/*
* The routines implemented in this file are described in:
* Leffler, et al.: The Design and Implementation of the 4.3BSD
@@ -339,7 +344,7 @@ acct_disable(struct thread *td, int logging)
int
acct_process(struct thread *td)
{
- struct acctv2 acct;
+ struct acctv3 acct;
struct timeval ut, st, tmp;
struct plimit *oldlim;
struct proc *p;
@@ -421,7 +426,7 @@ acct_process(struct thread *td)
/* Setup ancillary structure fields. */
acct.ac_flagx |= ANVER;
acct.ac_zero = 0;
- acct.ac_version = 2;
+ acct.ac_version = 3;
acct.ac_len = acct.ac_len2 = sizeof(acct);
/*
diff --git a/sys/kern/kern_descrip.c b/sys/kern/kern_descrip.c
index bb54f9d8acb7..2baaff77666b 100644
--- a/sys/kern/kern_descrip.c
+++ b/sys/kern/kern_descrip.c
@@ -1304,6 +1304,23 @@ ofstat(struct thread *td, struct ofstat_args *uap)
}
#endif /* COMPAT_43 */
+#if defined(COMPAT_FREEBSD11)
+int
+freebsd11_fstat(struct thread *td, struct freebsd11_fstat_args *uap)
+{
+ struct stat sb;
+ struct freebsd11_stat osb;
+ int error;
+
+ error = kern_fstat(td, uap->fd, &sb);
+ if (error != 0)
+ return (error);
+ freebsd11_cvtstat(&sb, &osb);
+ error = copyout(&osb, uap->sb, sizeof(osb));
+ return (error);
+}
+#endif /* COMPAT_FREEBSD11 */
+
/*
* Return status information about a file descriptor.
*/
@@ -1343,6 +1360,14 @@ kern_fstat(struct thread *td, int fd, struct stat *sbp)
error = fo_stat(fp, sbp, td->td_ucred, td);
fdrop(fp, td);
+#ifdef __STAT_TIME_T_EXT
+ if (error == 0) {
+ sbp->st_atim_ext = 0;
+ sbp->st_mtim_ext = 0;
+ sbp->st_ctim_ext = 0;
+ sbp->st_btim_ext = 0;
+ }
+#endif
#ifdef KTRACE
if (error == 0 && KTRPOINT(td, KTR_STRUCT))
ktrstat(sbp);
@@ -1350,18 +1375,19 @@ kern_fstat(struct thread *td, int fd, struct stat *sbp)
return (error);
}
+#if defined(COMPAT_FREEBSD11)
/*
* Return status information about a file descriptor.
*/
#ifndef _SYS_SYSPROTO_H_
-struct nfstat_args {
+struct freebsd11_nfstat_args {
int fd;
struct nstat *sb;
};
#endif
/* ARGSUSED */
int
-sys_nfstat(struct thread *td, struct nfstat_args *uap)
+freebsd11_nfstat(struct thread *td, struct freebsd11_nfstat_args *uap)
{
struct nstat nub;
struct stat ub;
@@ -1369,11 +1395,12 @@ sys_nfstat(struct thread *td, struct nfstat_args *uap)
error = kern_fstat(td, uap->fd, &ub);
if (error == 0) {
- cvtnstat(&ub, &nub);
+ freebsd11_cvtnstat(&ub, &nub);
error = copyout(&nub, uap->sb, sizeof(nub));
}
return (error);
}
+#endif /* COMPAT_FREEBSD11 */
/*
* Return pathconf information about a file descriptor.
@@ -3590,13 +3617,21 @@ kinfo_to_okinfo(struct kinfo_file *kif, struct kinfo_ofile *okif)
KF_FLAG_APPEND | KF_FLAG_ASYNC | KF_FLAG_FSYNC | KF_FLAG_NONBLOCK |
KF_FLAG_DIRECT | KF_FLAG_HASLOCK);
okif->kf_offset = kif->kf_offset;
- okif->kf_vnode_type = kif->kf_vnode_type;
- okif->kf_sock_domain = kif->kf_sock_domain;
- okif->kf_sock_type = kif->kf_sock_type;
- okif->kf_sock_protocol = kif->kf_sock_protocol;
+ if (kif->kf_type == KF_TYPE_VNODE)
+ okif->kf_vnode_type = kif->kf_un.kf_file.kf_file_type;
+ else
+ okif->kf_vnode_type = KF_VTYPE_VNON;
strlcpy(okif->kf_path, kif->kf_path, sizeof(okif->kf_path));
- okif->kf_sa_local = kif->kf_sa_local;
- okif->kf_sa_peer = kif->kf_sa_peer;
+ if (kif->kf_type == KF_TYPE_SOCKET) {
+ okif->kf_sock_domain = kif->kf_un.kf_sock.kf_sock_domain0;
+ okif->kf_sock_type = kif->kf_un.kf_sock.kf_sock_type0;
+ okif->kf_sock_protocol = kif->kf_un.kf_sock.kf_sock_protocol0;
+ okif->kf_sa_local = kif->kf_un.kf_sock.kf_sa_local;
+ okif->kf_sa_peer = kif->kf_un.kf_sock.kf_sa_peer;
+ } else {
+ okif->kf_sa_local.ss_family = AF_UNSPEC;
+ okif->kf_sa_peer.ss_family = AF_UNSPEC;
+ }
}
static int
diff --git a/sys/kern/kern_proc.c b/sys/kern/kern_proc.c
index 9b4ed9d88a01..c029567b6c44 100644
--- a/sys/kern/kern_proc.c
+++ b/sys/kern/kern_proc.c
@@ -986,11 +986,14 @@ fill_kinfo_proc_only(struct proc *p, struct kinfo_proc *kp)
}
if ((p->p_flag & P_CONTROLT) && tp != NULL) {
kp->ki_tdev = tty_udev(tp);
+ kp->ki_tdev_freebsd11 = kp->ki_tdev; /* truncate */
kp->ki_tpgid = tp->t_pgrp ? tp->t_pgrp->pg_id : NO_PID;
if (tp->t_session)
kp->ki_tsid = tp->t_session->s_sid;
- } else
+ } else {
kp->ki_tdev = NODEV;
+ kp->ki_tdev_freebsd11 = kp->ki_tdev; /* truncate */
+ }
if (p->p_comm[0] != '\0')
strlcpy(kp->ki_comm, p->p_comm, sizeof(kp->ki_comm));
if (p->p_sysent && p->p_sysent->sv_name != NULL &&
@@ -1232,6 +1235,7 @@ freebsd32_kinfo_proc_out(const struct kinfo_proc *ki, struct kinfo_proc32 *ki32)
CP(*ki, *ki32, ki_tsid);
CP(*ki, *ki32, ki_jobc);
CP(*ki, *ki32, ki_tdev);
+ CP(*ki, *ki32, ki_tdev_freebsd11);
CP(*ki, *ki32, ki_siglist);
CP(*ki, *ki32, ki_sigmask);
CP(*ki, *ki32, ki_sigignore);
@@ -2204,6 +2208,7 @@ sysctl_kern_proc_ovmmap(SYSCTL_HANDLER_ARGS)
vn_lock(vp, LK_SHARED | LK_RETRY);
if (VOP_GETATTR(vp, &va, cred) == 0) {
kve->kve_fileid = va.va_fileid;
+ /* truncate */
kve->kve_fsid = va.va_fsid;
}
vput(vp);
@@ -2443,10 +2448,14 @@ kern_proc_vmmap_out(struct proc *p, struct sbuf *sb, ssize_t maxlen, int flags)
if (VOP_GETATTR(vp, &va, cred) == 0) {
kve->kve_vn_fileid = va.va_fileid;
kve->kve_vn_fsid = va.va_fsid;
+ kve->kve_vn_fsid_freebsd11 =
+ kve->kve_vn_fsid; /* truncate */
kve->kve_vn_mode =
MAKEIMODE(va.va_type, va.va_mode);
kve->kve_vn_size = va.va_size;
kve->kve_vn_rdev = va.va_rdev;
+ kve->kve_vn_rdev_freebsd11 =
+ kve->kve_vn_rdev; /* truncate */
kve->kve_status = KF_ATTR_VALID;
}
vput(vp);
diff --git a/sys/kern/makesyscalls.sh b/sys/kern/makesyscalls.sh
index f220554ab04e..7ea37de6e53c 100644
--- a/sys/kern/makesyscalls.sh
+++ b/sys/kern/makesyscalls.sh
@@ -10,6 +10,7 @@ compat4=COMPAT_FREEBSD4
compat6=COMPAT_FREEBSD6
compat7=COMPAT_FREEBSD7
compat10=COMPAT_FREEBSD10
+compat11=COMPAT_FREEBSD11
# output files:
sysnames="syscalls.c"
@@ -36,6 +37,8 @@ syscompat7="sysent.compat7.$$"
syscompat7dcl="sysent.compat7dcl.$$"
syscompat10="sysent.compat10.$$"
syscompat10dcl="sysent.compat10dcl.$$"
+syscompat11="sysent.compat11.$$"
+syscompat11dcl="sysent.compat11dcl.$$"
sysent="sysent.switch.$$"
sysinc="sysinc.switch.$$"
sysarg="sysarg.switch.$$"
@@ -50,9 +53,9 @@ else
capenabled=""
fi
-trap "rm $sysaue $sysdcl $syscompat $syscompatdcl $syscompat4 $syscompat4dcl $syscompat6 $syscompat6dcl $syscompat7 $syscompat7dcl $syscompat10 $syscompat10dcl $sysent $sysinc $sysarg $sysprotoend $systracetmp $systraceret" 0
+trap "rm $sysaue $sysdcl $syscompat $syscompatdcl $syscompat4 $syscompat4dcl $syscompat6 $syscompat6dcl $syscompat7 $syscompat7dcl $syscompat10 $syscompat10dcl $syscompat11 $syscompat11dcl $sysent $sysinc $sysarg $sysprotoend $systracetmp $systraceret" 0
-touch $sysaue $sysdcl $syscompat $syscompatdcl $syscompat4 $syscompat4dcl $syscompat6 $syscompat6dcl $syscompat7 $syscompat7dcl $syscompat10 $syscompat10dcl $sysent $sysinc $sysarg $sysprotoend $systracetmp $systraceret
+touch $sysaue $sysdcl $syscompat $syscompatdcl $syscompat4 $syscompat4dcl $syscompat6 $syscompat6dcl $syscompat7 $syscompat7dcl $syscompat10 $syscompat10dcl $syscompat11 $syscompat11dcl $sysent $sysinc $sysarg $sysprotoend $systracetmp $systraceret
case $# in
0) echo "usage: $0 input-file <config-file>" 1>&2
@@ -92,6 +95,8 @@ sed -e '
syscompat7dcl = \"$syscompat7dcl\"
syscompat10 = \"$syscompat10\"
syscompat10dcl = \"$syscompat10dcl\"
+ syscompat11 = \"$syscompat11\"
+ syscompat11dcl = \"$syscompat11dcl\"
sysent = \"$sysent\"
syssw = \"$syssw\"
sysinc = \"$sysinc\"
@@ -107,6 +112,7 @@ sed -e '
compat6 = \"$compat6\"
compat7 = \"$compat7\"
compat10 = \"$compat10\"
+ compat11 = \"$compat11\"
syscallprefix = \"$syscallprefix\"
switchname = \"$switchname\"
namesname = \"$namesname\"
@@ -155,6 +161,7 @@ sed -e '
printf "\n#ifdef %s\n\n", compat6 > syscompat6
printf "\n#ifdef %s\n\n", compat7 > syscompat7
printf "\n#ifdef %s\n\n", compat10 > syscompat10
+ printf "\n#ifdef %s\n\n", compat11 > syscompat11
printf "/*\n * System call names.\n *\n" > sysnames
printf " * DO NOT EDIT-- this file is automatically generated.\n" > sysnames
@@ -205,6 +212,7 @@ sed -e '
print > syscompat6
print > syscompat7
print > syscompat10
+ print > syscompat11
print > sysnames
print > systrace
print > systracetmp
@@ -221,6 +229,7 @@ sed -e '
print > syscompat6
print > syscompat7
print > syscompat10
+ print > syscompat11
print > sysnames
print > systrace
print > systracetmp
@@ -237,6 +246,7 @@ sed -e '
print > syscompat6
print > syscompat7
print > syscompat10
+ print > syscompat11
print > sysnames
print > systrace
print > systracetmp
@@ -345,6 +355,8 @@ sed -e '
argalias = "freebsd7_" argalias
if (flag("COMPAT10"))
argalias = "freebsd10_" argalias
+ if (flag("COMPAT11"))
+ argalias = "freebsd11_" argalias
}
f++
@@ -497,7 +509,7 @@ sed -e '
next
}
type("COMPAT") || type("COMPAT4") || type("COMPAT6") || \
- type("COMPAT7") || type("COMPAT10") {
+ type("COMPAT7") || type("COMPAT10") || type("COMPAT11") {
if (flag("COMPAT")) {
ncompat++
out = syscompat
@@ -533,6 +545,13 @@ sed -e '
wrap = "compat10"
prefix = "freebsd10_"
descr = "freebsd10"
+ } else if (flag("COMPAT11")) {
+ ncompat11++
+ out = syscompat11
+ outdcl = syscompat11dcl
+ wrap = "compat11"
+ prefix = "freebsd11_"
+ descr = "freebsd11"
}
parseline()
if (argc != 0 && !flag("NOARGS") && !flag("NOPROTO") && \
@@ -608,7 +627,7 @@ sed -e '
END {
printf "\n#define AS(name) (sizeof(struct name) / sizeof(register_t))\n" > sysinc
- if (ncompat != 0 || ncompat4 != 0 || ncompat6 != 0 || ncompat7 != 0 || ncompat10 != 0)
+ if (ncompat != 0 || ncompat4 != 0 || ncompat6 != 0 || ncompat7 != 0 || ncompat10 != 0 || ncompat11 != 0)
printf "#include \"opt_compat.h\"\n\n" > syssw
if (ncompat != 0) {
@@ -649,11 +668,20 @@ sed -e '
printf "#define compat10(n, name) 0, (sy_call_t *)nosys\n" > sysinc
printf "#endif\n" > sysinc
}
+ if (ncompat11 != 0) {
+ printf "\n#ifdef %s\n", compat11 > sysinc
+ printf "#define compat11(n, name) n, (sy_call_t *)__CONCAT(freebsd11_,name)\n" > sysinc
+ printf "#else\n" > sysinc
+ printf "#define compat11(n, name) 0, (sy_call_t *)nosys\n" > sysinc
+ printf "#endif\n" > sysinc
+ }
+
printf("\n#endif /* %s */\n\n", compat) > syscompatdcl
printf("\n#endif /* %s */\n\n", compat4) > syscompat4dcl
printf("\n#endif /* %s */\n\n", compat6) > syscompat6dcl
printf("\n#endif /* %s */\n\n", compat7) > syscompat7dcl
printf("\n#endif /* %s */\n\n", compat10) > syscompat10dcl
+ printf("\n#endif /* %s */\n\n", compat11) > syscompat11dcl
printf("\n#undef PAD_\n") > sysprotoend
printf("#undef PADL_\n") > sysprotoend
@@ -677,6 +705,7 @@ cat $sysarg $sysdcl \
$syscompat6 $syscompat6dcl \
$syscompat7 $syscompat7dcl \
$syscompat10 $syscompat10dcl \
+ $syscompat11 $syscompat11dcl \
$sysaue $sysprotoend > $sysproto
cat $systracetmp >> $systrace
cat $systraceret >> $systrace
diff --git a/sys/kern/sys_socket.c b/sys/kern/sys_socket.c
index 441a628b7f78..a30260bfeebc 100644
--- a/sys/kern/sys_socket.c
+++ b/sys/kern/sys_socket.c
@@ -346,14 +346,15 @@ soo_fill_kinfo(struct file *fp, struct kinfo_file *kif, struct filedesc *fdp)
kif->kf_type = KF_TYPE_SOCKET;
so = fp->f_data;
- kif->kf_sock_domain = so->so_proto->pr_domain->dom_family;
- kif->kf_sock_type = so->so_type;
- kif->kf_sock_protocol = so->so_proto->pr_protocol;
+ kif->kf_un.kf_sock.kf_sock_domain0 =
+ so->so_proto->pr_domain->dom_family;
+ kif->kf_un.kf_sock.kf_sock_type0 = so->so_type;
+ kif->kf_un.kf_sock.kf_sock_protocol0 = so->so_proto->pr_protocol;
kif->kf_un.kf_sock.kf_sock_pcb = (uintptr_t)so->so_pcb;
- switch (kif->kf_sock_domain) {
+ switch (kif->kf_un.kf_sock.kf_sock_domain0) {
case AF_INET:
case AF_INET6:
- if (kif->kf_sock_protocol == IPPROTO_TCP) {
+ if (kif->kf_un.kf_sock.kf_sock_protocol0 == IPPROTO_TCP) {
if (so->so_pcb != NULL) {
inpcb = (struct inpcb *)(so->so_pcb);
kif->kf_un.kf_sock.kf_sock_inpcb =
@@ -376,13 +377,15 @@ soo_fill_kinfo(struct file *fp, struct kinfo_file *kif, struct filedesc *fdp)
break;
}
error = so->so_proto->pr_usrreqs->pru_sockaddr(so, &sa);
- if (error == 0 && sa->sa_len <= sizeof(kif->kf_sa_local)) {
- bcopy(sa, &kif->kf_sa_local, sa->sa_len);
+ if (error == 0 &&
+ sa->sa_len <= sizeof(kif->kf_un.kf_sock.kf_sa_local)) {
+ bcopy(sa, &kif->kf_un.kf_sock.kf_sa_local, sa->sa_len);
free(sa, M_SONAME);
}
error = so->so_proto->pr_usrreqs->pru_peeraddr(so, &sa);
- if (error == 0 && sa->sa_len <= sizeof(kif->kf_sa_peer)) {
- bcopy(sa, &kif->kf_sa_peer, sa->sa_len);
+ if (error == 0 &&
+ sa->sa_len <= sizeof(kif->kf_un.kf_sock.kf_sa_peer)) {
+ bcopy(sa, &kif->kf_un.kf_sock.kf_sa_peer, sa->sa_len);
free(sa, M_SONAME);
}
strncpy(kif->kf_path, so->so_proto->pr_domain->dom_name,
diff --git a/sys/kern/syscalls.master b/sys/kern/syscalls.master
index 999da9c884ce..ad0fdb27545f 100644
--- a/sys/kern/syscalls.master
+++ b/sys/kern/syscalls.master
@@ -12,7 +12,7 @@
; case where the event exists, but we don't want auditing, the
; event should be #defined to AUE_NULL in audit_kevents.h.
; type one of STD, OBSOL, UNIMPL, COMPAT, COMPAT4, COMPAT6,
-; COMPAT7, NODEF, NOARGS, NOPROTO, NOSTD
+; COMPAT7, COMPAT11, NODEF, NOARGS, NOPROTO, NOSTD
; The COMPAT* options may be combined with one or more NO*
; options separated by '|' with no spaces (e.g. COMPAT|NOARGS)
; name psuedo-prototype of syscall routine
@@ -29,6 +29,7 @@
; COMPAT6 included on COMPAT_FREEBSD6 #ifdef (FreeBSD 6 compat)
; COMPAT7 included on COMPAT_FREEBSD7 #ifdef (FreeBSD 7 compat)
; COMPAT10 included on COMPAT_FREEBSD10 #ifdef (FreeBSD 10 compat)
+; COMPAT11 included on COMPAT11 #ifdef (FreeBSD 11 compat)
; OBSOL obsolete, not included in system, only specifies name
; UNIMPL not implemented, placeholder only
; NOSTD implemented but as a lkm that can be statically
@@ -79,7 +80,7 @@
11 AUE_NULL OBSOL execv
12 AUE_CHDIR STD { int chdir(char *path); }
13 AUE_FCHDIR STD { int fchdir(int fd); }
-14 AUE_MKNOD STD { int mknod(char *path, int mode, int dev); }
+14 AUE_MKNOD COMPAT11 { int mknod(char *path, int mode, int dev); }
15 AUE_CHMOD STD { int chmod(char *path, int mode); }
16 AUE_CHOWN STD { int chown(char *path, int uid, int gid); }
17 AUE_NULL STD { int obreak(char *nsize); } break \
@@ -363,9 +364,12 @@
185 AUE_NULL UNIMPL lfs_markv
186 AUE_NULL UNIMPL lfs_segclean
187 AUE_NULL UNIMPL lfs_segwait
-188 AUE_STAT STD { int stat(char *path, struct stat *ub); }
-189 AUE_FSTAT STD { int fstat(int fd, struct stat *sb); }
-190 AUE_LSTAT STD { int lstat(char *path, struct stat *ub); }
+188 AUE_STAT COMPAT11 { int stat(char *path, \
+ struct freebsd11_stat *ub); }
+189 AUE_FSTAT COMPAT11 { int fstat(int fd, \
+ struct freebsd11_stat *sb); }
+190 AUE_LSTAT COMPAT11 { int lstat(char *path, \
+ struct freebsd11_stat *ub); }
191 AUE_PATHCONF STD { int pathconf(char *path, int name); }
192 AUE_FPATHCONF STD { int fpathconf(int fd, int name); }
193 AUE_NULL UNIMPL nosys
@@ -375,7 +379,7 @@
195 AUE_SETRLIMIT STD { int setrlimit(u_int which, \
struct rlimit *rlp); } setrlimit \
__setrlimit_args int
-196 AUE_GETDIRENTRIES STD { int getdirentries(int fd, char *buf, \
+196 AUE_GETDIRENTRIES COMPAT11 { int getdirentries(int fd, char *buf, \
u_int count, long *basep); }
197 AUE_MMAP COMPAT6 { caddr_t mmap(caddr_t addr, \
size_t len, int prot, int flags, int fd, \
@@ -496,7 +500,7 @@
269 AUE_NULL UNIMPL nosys
270 AUE_NULL UNIMPL nosys
271 AUE_NULL UNIMPL nosys
-272 AUE_O_GETDENTS STD { int getdents(int fd, char *buf, \
+272 AUE_O_GETDENTS COMPAT11 { int getdents(int fd, char *buf, \
size_t count); }
273 AUE_NULL UNIMPL nosys
274 AUE_LCHMOD STD { int lchmod(char *path, mode_t mode); }
@@ -507,9 +511,9 @@
struct timeval *tptr); }
277 AUE_MSYNC NOPROTO { int msync(void *addr, size_t len, \
int flags); } netbsd_msync msync_args int
-278 AUE_STAT STD { int nstat(char *path, struct nstat *ub); }
-279 AUE_FSTAT STD { int nfstat(int fd, struct nstat *sb); }
-280 AUE_LSTAT STD { int nlstat(char *path, struct nstat *ub); }
+278 AUE_STAT COMPAT11 { int nstat(char *path, struct nstat *ub); }
+279 AUE_FSTAT COMPAT11 { int nfstat(int fd, struct nstat *sb); }
+280 AUE_LSTAT COMPAT11 { int nlstat(char *path, struct nstat *ub); }
281 AUE_NULL UNIMPL nosys
282 AUE_NULL UNIMPL nosys
283 AUE_NULL UNIMPL nosys
@@ -535,8 +539,8 @@
struct ostatfs *buf); }
298 AUE_FHOPEN STD { int fhopen(const struct fhandle *u_fhp, \
int flags); }
-299 AUE_FHSTAT STD { int fhstat(const struct fhandle *u_fhp, \
- struct stat *sb); }
+299 AUE_FHSTAT COMPAT11 { int fhstat(const struct fhandle *u_fhp, \
+ struct freebsd11_stat *sb); }
; syscall numbers for FreeBSD
300 AUE_NULL STD { int modnext(int modid); }
301 AUE_NULL STD { int modstat(int modid, \
@@ -707,13 +711,14 @@
off_t *sbytes, int flags); }
394 AUE_NULL STD { int mac_syscall(const char *policy, \
int call, void *arg); }
-395 AUE_GETFSSTAT STD { int getfsstat(struct statfs *buf, \
+395 AUE_GETFSSTAT COMPAT11 { int getfsstat(struct freebsd11_statfs *buf, \
long bufsize, int mode); }
-396 AUE_STATFS STD { int statfs(char *path, \
- struct statfs *buf); }
-397 AUE_FSTATFS STD { int fstatfs(int fd, struct statfs *buf); }
-398 AUE_FHSTATFS STD { int fhstatfs(const struct fhandle *u_fhp, \
- struct statfs *buf); }
+396 AUE_STATFS COMPAT11 { int statfs(char *path, \
+ struct freebsd11_statfs *buf); }
+397 AUE_FSTATFS COMPAT11 { int fstatfs(int fd, \
+ struct freebsd11_statfs *buf); }
+398 AUE_FHSTATFS COMPAT11 { int fhstatfs(const struct fhandle *u_fhp, \
+ struct freebsd11_statfs *buf); }
399 AUE_NULL UNIMPL nosys
400 AUE_SEMCLOSE NOSTD { int ksem_close(semid_t id); }
401 AUE_SEMPOST NOSTD { int ksem_post(semid_t id); }
@@ -883,16 +888,16 @@
gid_t gid, int flag); }
492 AUE_FEXECVE STD { int fexecve(int fd, char **argv, \
char **envv); }
-493 AUE_FSTATAT STD { int fstatat(int fd, char *path, \
- struct stat *buf, int flag); }
+493 AUE_FSTATAT COMPAT11 { int fstatat(int fd, char *path, \
+ struct freebsd11_stat *buf, int flag); }
494 AUE_FUTIMESAT STD { int futimesat(int fd, char *path, \
struct timeval *times); }
495 AUE_LINKAT STD { int linkat(int fd1, char *path1, int fd2, \
char *path2, int flag); }
496 AUE_MKDIRAT STD { int mkdirat(int fd, char *path, mode_t mode); }
497 AUE_MKFIFOAT STD { int mkfifoat(int fd, char *path, mode_t mode); }
-498 AUE_MKNODAT STD { int mknodat(int fd, char *path, mode_t mode, \
- dev_t dev); }
+498 AUE_MKNODAT COMPAT11 { int mknodat(int fd, char *path, mode_t mode, \
+ uint32_t dev); }
; XXX: see the comment for open
499 AUE_OPENAT_RWTC STD { int openat(int fd, char *path, int flag, \
mode_t mode); }
@@ -997,6 +1002,21 @@
id_t id, const struct \
vm_domain_policy_entry *policy); }
550 AUE_FSYNC STD { int fdatasync(int fd); }
+551 AUE_FSTAT STD { int fstat(int fd, struct stat *sb); }
+552 AUE_FSTATAT STD { int fstatat(int fd, char *path, \
+ struct stat *buf, int flag); }
+553 AUE_FHSTAT STD { int fhstat(const struct fhandle *u_fhp, \
+ struct stat *sb); }
+554 AUE_GETDIRENTRIES STD { ssize_t getdirentries(int fd, char *buf, \
+ size_t count, off_t *basep); }
+555 AUE_STATFS STD { int statfs(char *path, struct statfs *buf); }
+556 AUE_FSTATFS STD { int fstatfs(int fd, struct statfs *buf); }
+557 AUE_GETFSSTAT STD { int getfsstat(struct statfs *buf, \
+ long bufsize, int mode); }
+558 AUE_FHSTATFS STD { int fhstatfs(const struct fhandle *u_fhp, \
+ struct statfs *buf); }
+559 AUE_MKNODAT STD { int mknodat(int fd, char *path, mode_t mode, \
+ dev_t dev); }
; Please copy any additions and changes to the following compatability tables:
; sys/compat/freebsd32/syscalls.master
diff --git a/sys/kern/tty.c b/sys/kern/tty.c
index b0a535cb67e3..63e195945d89 100644
--- a/sys/kern/tty.c
+++ b/sys/kern/tty.c
@@ -1205,7 +1205,7 @@ tty_to_xtty(struct tty *tp, struct xtty *xt)
xt->xt_pgid = tp->t_pgrp ? tp->t_pgrp->pg_id : 0;
xt->xt_sid = tp->t_session ? tp->t_session->s_sid : 0;
xt->xt_flags = tp->t_flags;
- xt->xt_dev = tp->t_dev ? dev2udev(tp->t_dev) : NODEV;
+ xt->xt_dev = tp->t_dev ? dev2udev(tp->t_dev) : (uint32_t)NODEV;
}
static int
diff --git a/sys/kern/tty_pts.c b/sys/kern/tty_pts.c
index a4c3dbb3cc22..b9a888c5a124 100644
--- a/sys/kern/tty_pts.c
+++ b/sys/kern/tty_pts.c
@@ -592,6 +592,8 @@ ptsdev_fill_kinfo(struct file *fp, struct kinfo_file *kif, struct filedesc *fdp)
kif->kf_type = KF_TYPE_PTS;
tp = fp->f_data;
kif->kf_un.kf_pts.kf_pts_dev = tty_udev(tp);
+ kif->kf_un.kf_pts.kf_pts_dev_freebsd11 =
+ kif->kf_un.kf_pts.kf_pts_dev; /* truncate */
strlcpy(kif->kf_path, tty_devname(tp), sizeof(kif->kf_path));
return (0);
}
diff --git a/sys/kern/vfs_syscalls.c b/sys/kern/vfs_syscalls.c
index 7671e1b84ac2..27b2635030d3 100644
--- a/sys/kern/vfs_syscalls.c
+++ b/sys/kern/vfs_syscalls.c
@@ -525,7 +525,7 @@ restart:
/*
* Get old format filesystem statistics.
*/
-static void cvtstatfs(struct statfs *, struct ostatfs *);
+static void freebsd4_cvtstatfs(struct statfs *, struct ostatfs *);
#ifndef _SYS_SYSPROTO_H_
struct freebsd4_statfs_args {
@@ -543,7 +543,7 @@ freebsd4_statfs(struct thread *td, struct freebsd4_statfs_args *uap)
sfp = malloc(sizeof(struct statfs), M_STATFS, M_WAITOK);
error = kern_statfs(td, uap->path, UIO_USERSPACE, sfp);
if (error == 0) {
- cvtstatfs(sfp, &osb);
+ freebsd4_cvtstatfs(sfp, &osb);
error = copyout(&osb, uap->buf, sizeof(osb));
}
free(sfp, M_STATFS);
@@ -569,7 +569,7 @@ freebsd4_fstatfs(struct thread *td, struct freebsd4_fstatfs_args *uap)
sfp = malloc(sizeof(struct statfs), M_STATFS, M_WAITOK);
error = kern_fstatfs(td, uap->fd, sfp);
if (error == 0) {
- cvtstatfs(sfp, &osb);
+ freebsd4_cvtstatfs(sfp, &osb);
error = copyout(&osb, uap->buf, sizeof(osb));
}
free(sfp, M_STATFS);
@@ -602,11 +602,12 @@ freebsd4_getfsstat(struct thread *td, struct freebsd4_getfsstat_args *uap)
size = count * sizeof(struct statfs);
error = kern_getfsstat(td, &buf, size, &count, UIO_SYSSPACE,
uap->mode);
- td->td_retval[0] = count;
+ if (error == 0)
+ td->td_retval[0] = count;
if (size != 0) {
sp = buf;
while (count != 0 && error == 0) {
- cvtstatfs(sp, &osb);
+ freebsd4_cvtstatfs(sp, &osb);
error = copyout(&osb, uap->buf, sizeof(osb));
sp++;
uap->buf++;
@@ -640,7 +641,7 @@ freebsd4_fhstatfs(struct thread *td, struct freebsd4_fhstatfs_args *uap)
sfp = malloc(sizeof(struct statfs), M_STATFS, M_WAITOK);
error = kern_fhstatfs(td, fh, sfp);
if (error == 0) {
- cvtstatfs(sfp, &osb);
+ freebsd4_cvtstatfs(sfp, &osb);
error = copyout(&osb, uap->buf, sizeof(osb));
}
free(sfp, M_STATFS);
@@ -651,7 +652,7 @@ freebsd4_fhstatfs(struct thread *td, struct freebsd4_fhstatfs_args *uap)
* Convert a new format statfs structure to an old format statfs structure.
*/
static void
-cvtstatfs(struct statfs *nsp, struct ostatfs *osp)
+freebsd4_cvtstatfs(struct statfs *nsp, struct ostatfs *osp)
{
statfs_scale_blocks(nsp, LONG_MAX);
@@ -680,6 +681,138 @@ cvtstatfs(struct statfs *nsp, struct ostatfs *osp)
}
#endif /* COMPAT_FREEBSD4 */
+#if defined(COMPAT_FREEBSD11)
+/*
+ * Get old format filesystem statistics.
+ */
+static void freebsd11_cvtstatfs(struct statfs *, struct freebsd11_statfs *);
+
+int
+freebsd11_statfs(struct thread *td, struct freebsd11_statfs_args *uap)
+{
+ struct freebsd11_statfs osb;
+ struct statfs *sfp;
+ int error;
+
+ sfp = malloc(sizeof(struct statfs), M_STATFS, M_WAITOK);
+ error = kern_statfs(td, uap->path, UIO_USERSPACE, sfp);
+ if (error == 0) {
+ freebsd11_cvtstatfs(sfp, &osb);
+ error = copyout(&osb, uap->buf, sizeof(osb));
+ }
+ free(sfp, M_STATFS);
+ return (error);
+}
+
+/*
+ * Get filesystem statistics.
+ */
+int
+freebsd11_fstatfs(struct thread *td, struct freebsd11_fstatfs_args *uap)
+{
+ struct freebsd11_statfs osb;
+ struct statfs *sfp;
+ int error;
+
+ sfp = malloc(sizeof(struct statfs), M_STATFS, M_WAITOK);
+ error = kern_fstatfs(td, uap->fd, sfp);
+ if (error == 0) {
+ freebsd11_cvtstatfs(sfp, &osb);
+ error = copyout(&osb, uap->buf, sizeof(osb));
+ }
+ free(sfp, M_STATFS);
+ return (error);
+}
+
+/*
+ * Get statistics on all filesystems.
+ */
+int
+freebsd11_getfsstat(struct thread *td, struct freebsd11_getfsstat_args *uap)
+{
+ struct freebsd11_statfs osb;
+ struct statfs *buf, *sp;
+ size_t count, size;
+ int error;
+
+ count = uap->bufsize / sizeof(struct ostatfs);
+ size = count * sizeof(struct statfs);
+ error = kern_getfsstat(td, &buf, size, &count, UIO_SYSSPACE,
+ uap->mode);
+ if (error == 0)
+ td->td_retval[0] = count;
+ if (size > 0) {
+ sp = buf;
+ while (count > 0 && error == 0) {
+ freebsd11_cvtstatfs(sp, &osb);
+ error = copyout(&osb, uap->buf, sizeof(osb));
+ sp++;
+ uap->buf++;
+ count--;
+ }
+ free(buf, M_STATFS);
+ }
+ return (error);
+}
+
+/*
+ * Implement fstatfs() for (NFS) file handles.
+ */
+int
+freebsd11_fhstatfs(struct thread *td, struct freebsd11_fhstatfs_args *uap)
+{
+ struct freebsd11_statfs osb;
+ struct statfs *sfp;
+ fhandle_t fh;
+ int error;
+
+ error = copyin(uap->u_fhp, &fh, sizeof(fhandle_t));
+ if (error)
+ return (error);
+ sfp = malloc(sizeof(struct statfs), M_STATFS, M_WAITOK);
+ error = kern_fhstatfs(td, fh, sfp);
+ if (error == 0) {
+ freebsd11_cvtstatfs(sfp, &osb);
+ error = copyout(&osb, uap->buf, sizeof(osb));
+ }
+ free(sfp, M_STATFS);
+ return (error);
+}
+
+/*
+ * Convert a new format statfs structure to an old format statfs structure.
+ */
+static void
+freebsd11_cvtstatfs(struct statfs *nsp, struct freebsd11_statfs *osp)
+{
+
+ bzero(osp, sizeof(*osp));
+ osp->f_version = FREEBSD11_STATFS_VERSION;
+ osp->f_type = nsp->f_type;
+ osp->f_flags = nsp->f_flags;
+ osp->f_bsize = nsp->f_bsize;
+ osp->f_iosize = nsp->f_iosize;
+ osp->f_blocks = nsp->f_blocks;
+ osp->f_bfree = nsp->f_bfree;
+ osp->f_bavail = nsp->f_bavail;
+ osp->f_files = nsp->f_files;
+ osp->f_ffree = nsp->f_ffree;
+ osp->f_syncwrites = nsp->f_syncwrites;
+ osp->f_asyncwrites = nsp->f_asyncwrites;
+ osp->f_syncreads = nsp->f_syncreads;
+ osp->f_asyncreads = nsp->f_asyncreads;
+ osp->f_namemax = nsp->f_namemax;
+ osp->f_owner = nsp->f_owner;
+ osp->f_fsid = nsp->f_fsid;
+ strlcpy(osp->f_fstypename, nsp->f_fstypename,
+ MIN(MFSNAMELEN, sizeof(osp->f_fstypename)));
+ strlcpy(osp->f_mntonname, nsp->f_mntonname,
+ MIN(MNAMELEN, sizeof(osp->f_mntonname)));
+ strlcpy(osp->f_mntfromname, nsp->f_mntfromname,
+ MIN(MNAMELEN, sizeof(osp->f_mntfromname)));
+}
+#endif /* COMPAT_FREEBSD11 */
+
/*
* Change current working directory to a given file descriptor.
*/
@@ -1060,39 +1193,44 @@ ocreat(struct thread *td, struct ocreat_args *uap)
* Create a special file.
*/
#ifndef _SYS_SYSPROTO_H_
-struct mknod_args {
+struct mknodat_args {
+ int fd;
char *path;
- int mode;
- int dev;
+ mode_t mode;
+ dev_t dev;
};
#endif
int
-sys_mknod(struct thread *td, struct mknod_args *uap)
+sys_mknodat(struct thread *td, struct mknodat_args *uap)
+{
+
+ return (kern_mknodat(td, uap->fd, uap->path, UIO_USERSPACE, uap->mode,
+ uap->dev));
+}
+
+#if defined(COMPAT_FREEBSD11)
+int
+freebsd11_mknod(struct thread *td,
+ struct freebsd11_mknod_args *uap)
{
return (kern_mknodat(td, AT_FDCWD, uap->path, UIO_USERSPACE,
uap->mode, uap->dev));
}
-#ifndef _SYS_SYSPROTO_H_
-struct mknodat_args {
- int fd;
- char *path;
- mode_t mode;
- dev_t dev;
-};
-#endif
int
-sys_mknodat(struct thread *td, struct mknodat_args *uap)
+freebsd11_mknodat(struct thread *td,
+ struct freebsd11_mknodat_args *uap)
{
return (kern_mknodat(td, uap->fd, uap->path, UIO_USERSPACE, uap->mode,
uap->dev));
}
+#endif /* COMPAT_FREEBSD11 */
int
kern_mknodat(struct thread *td, int fd, char *path, enum uio_seg pathseg,
- int mode, int dev)
+ int mode, dev_t dev)
{
struct vnode *vp;
struct mount *mp;
@@ -1968,28 +2106,104 @@ cvtstat(struct stat *st, struct ostat *ost)
}
#endif /* COMPAT_43 */
-/*
- * Get file status; this version follows links.
- */
-#ifndef _SYS_SYSPROTO_H_
-struct stat_args {
- char *path;
- struct stat *ub;
-};
-#endif
+#if defined(COMPAT_FREEBSD11)
+void
+freebsd11_cvtstat(struct stat *st, struct freebsd11_stat *ost)
+{
+
+ ost->st_dev = st->st_dev;
+ ost->st_ino = st->st_ino; /* truncate */
+ ost->st_mode = st->st_mode;
+ ost->st_nlink = st->st_nlink; /* truncate */
+ ost->st_uid = st->st_uid;
+ ost->st_gid = st->st_gid;
+ ost->st_rdev = st->st_rdev;
+ ost->st_atim = st->st_atim;
+ ost->st_mtim = st->st_mtim;
+ ost->st_ctim = st->st_ctim;
+ ost->st_size = st->st_size;
+ ost->st_blocks = st->st_blocks;
+ ost->st_blksize = st->st_blksize;
+ ost->st_flags = st->st_flags;
+ ost->st_gen = st->st_gen;
+ ost->st_lspare = 0;
+ ost->st_birthtim = st->st_birthtim;
+ bzero((char *)&ost->st_birthtim + sizeof(ost->st_birthtim),
+ sizeof(*ost) - offsetof(struct freebsd11_stat,
+ st_birthtim) - sizeof(ost->st_birthtim));
+}
+
int
-sys_stat(struct thread *td, struct stat_args *uap)
+freebsd11_stat(struct thread *td, struct freebsd11_stat_args* uap)
{
struct stat sb;
+ struct freebsd11_stat osb;
int error;
error = kern_statat(td, 0, AT_FDCWD, uap->path, UIO_USERSPACE,
&sb, NULL);
- if (error == 0)
- error = copyout(&sb, uap->ub, sizeof (sb));
+ if (error != 0)
+ return (error);
+ freebsd11_cvtstat(&sb, &osb);
+ error = copyout(&osb, uap->ub, sizeof(osb));
return (error);
}
+int
+freebsd11_lstat(struct thread *td, struct freebsd11_lstat_args* uap)
+{
+ struct stat sb;
+ struct freebsd11_stat osb;
+ int error;
+
+ error = kern_statat(td, AT_SYMLINK_NOFOLLOW, AT_FDCWD, uap->path,
+ UIO_USERSPACE, &sb, NULL);
+ if (error != 0)
+ return (error);
+ freebsd11_cvtstat(&sb, &osb);
+ error = copyout(&osb, uap->ub, sizeof(osb));
+ return (error);
+}
+
+int
+freebsd11_fhstat(struct thread *td, struct freebsd11_fhstat_args* uap)
+{
+ struct fhandle fh;
+ struct stat sb;
+ struct freebsd11_stat osb;
+ int error;
+
+ error = copyin(uap->u_fhp, &fh, sizeof(fhandle_t));
+ if (error != 0)
+ return (error);
+ error = kern_fhstat(td, fh, &sb);
+ if (error != 0)
+ return (error);
+ freebsd11_cvtstat(&sb, &osb);
+ error = copyout(&osb, uap->sb, sizeof(osb));
+ return (error);
+}
+
+int
+freebsd11_fstatat(struct thread *td, struct freebsd11_fstatat_args* uap)
+{
+ struct stat sb;
+ struct freebsd11_stat osb;
+ int error;
+
+ error = kern_statat(td, uap->flag, uap->fd, uap->path,
+ UIO_USERSPACE, &sb, NULL);
+ if (error != 0)
+ return (error);
+ freebsd11_cvtstat(&sb, &osb);
+ error = copyout(&osb, uap->buf, sizeof(osb));
+ return (error);
+}
+#endif /* COMPAT_FREEBSD11 */
+
+/*
+ * Get file status
+ */
#ifndef _SYS_SYSPROTO_H_
struct fstatat_args {
int fd;
@@ -2042,6 +2256,12 @@ kern_statat(struct thread *td, int flag, int fd, char *path,
vput(nd.ni_vp);
if (error != 0)
return (error);
+#ifdef __STAT_TIME_T_EXT
+ sb.st_atim_ext = 0;
+ sb.st_mtim_ext = 0;
+ sb.st_ctim_ext = 0;
+ sb.st_btim_ext = 0;
+#endif
*sbp = sb;
#ifdef KTRACE
if (KTRPOINT(td, KTR_STRUCT))
@@ -2050,36 +2270,15 @@ kern_statat(struct thread *td, int flag, int fd, char *path,
return (0);
}
-/*
- * Get file status; this version does not follow links.
- */
-#ifndef _SYS_SYSPROTO_H_
-struct lstat_args {
- char *path;
- struct stat *ub;
-};
-#endif
-int
-sys_lstat(struct thread *td, struct lstat_args *uap)
-{
- struct stat sb;
- int error;
-
- error = kern_statat(td, AT_SYMLINK_NOFOLLOW, AT_FDCWD, uap->path,
- UIO_USERSPACE, &sb, NULL);
- if (error == 0)
- error = copyout(&sb, uap->ub, sizeof (sb));
- return (error);
-}
-
+#if defined(COMPAT_FREEBSD11)
/*
* Implementation of the NetBSD [l]stat() functions.
*/
void
-cvtnstat( struct stat *sb, struct nstat *nsb)
+freebsd11_cvtnstat(struct stat *sb, struct nstat *nsb)
{
- bzero(nsb, sizeof *nsb);
+ bzero(nsb, sizeof(*nsb));
nsb->st_dev = sb->st_dev;
nsb->st_ino = sb->st_ino;
nsb->st_mode = sb->st_mode;
@@ -2099,13 +2298,13 @@ cvtnstat( struct stat *sb, struct nstat *nsb)
}
#ifndef _SYS_SYSPROTO_H_
-struct nstat_args {
+struct freebsd11_nstat_args {
char *path;
struct nstat *ub;
};
#endif
int
-sys_nstat(struct thread *td, struct nstat_args *uap)
+freebsd11_nstat(struct thread *td, struct freebsd11_nstat_args *uap)
{
struct stat sb;
struct nstat nsb;
@@ -2115,7 +2314,7 @@ sys_nstat(struct thread *td, struct nstat_args *uap)
&sb, NULL);
if (error != 0)
return (error);
- cvtnstat(&sb, &nsb);
+ freebsd11_cvtnstat(&sb, &nsb);
return (copyout(&nsb, uap->ub, sizeof (nsb)));
}
@@ -2123,13 +2322,13 @@ sys_nstat(struct thread *td, struct nstat_args *uap)
* NetBSD lstat. Get file status; this version does not follow links.
*/
#ifndef _SYS_SYSPROTO_H_
-struct lstat_args {
+struct freebsd11_nlstat_args {
char *path;
- struct stat *ub;
+ struct nstat *ub;
};
#endif
int
-sys_nlstat(struct thread *td, struct nlstat_args *uap)
+freebsd11_nlstat(struct thread *td, struct freebsd11_nlstat_args *uap)
{
struct stat sb;
struct nstat nsb;
@@ -2139,9 +2338,10 @@ sys_nlstat(struct thread *td, struct nlstat_args *uap)
UIO_USERSPACE, &sb, NULL);
if (error != 0)
return (error);
- cvtnstat(&sb, &nsb);
+ freebsd11_cvtnstat(&sb, &nsb);
return (copyout(&nsb, uap->ub, sizeof (nsb)));
}
+#endif /* COMPAT_FREEBSD11 */
/*
* Get configurable pathname variables.
@@ -3502,7 +3702,87 @@ out:
return (error);
}
+#if defined(COMPAT_43) || defined(COMPAT_FREEBSD11)
+int
+freebsd11_kern_getdirentries(struct thread *td, int fd, char *ubuf, u_int count,
+ long *basep, void (*func)(struct freebsd11_dirent *))
+{
+ struct freebsd11_dirent dstdp;
+ struct dirent *dp, *edp;
+ char *dirbuf;
+ off_t base;
+ ssize_t resid, ucount;
+ int error;
+
+ /* XXX arbitrary sanity limit on `count'. */
+ count = min(count, 64 * 1024);
+
+ dirbuf = malloc(count, M_TEMP, M_WAITOK);
+
+ error = kern_getdirentries(td, fd, dirbuf, count, &base, &resid,
+ UIO_SYSSPACE);
+ if (error != 0)
+ goto done;
+ if (basep != NULL)
+ *basep = base;
+
+ ucount = 0;
+ for (dp = (struct dirent *)dirbuf,
+ edp = (struct dirent *)&dirbuf[count - resid];
+ ucount < count && dp < edp; ) {
+ if (dp->d_reclen == 0)
+ break;
+ MPASS(dp->d_reclen >= _GENERIC_DIRLEN(0));
+ if (dp->d_namlen >= sizeof(dstdp.d_name))
+ continue;
+ dstdp.d_type = dp->d_type;
+ dstdp.d_namlen = dp->d_namlen;
+ dstdp.d_fileno = dp->d_fileno; /* truncate */
+ dstdp.d_reclen = sizeof(dstdp) - sizeof(dstdp.d_name) +
+ ((dp->d_namlen + 1 + 3) &~ 3);
+ bcopy(dp->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);
+ MPASS(dstdp.d_reclen <= dp->d_reclen);
+ MPASS(ucount + dstdp.d_reclen <= count);
+ if (func != NULL)
+ func(&dstdp);
+ error = copyout(&dstdp, ubuf + ucount, dstdp.d_reclen);
+ if (error != 0)
+ break;
+ dp = (struct dirent *)((char *)dp + dp->d_reclen);
+ ucount += dstdp.d_reclen;
+ }
+
+done:
+ free(dirbuf, M_TEMP);
+ if (error == 0)
+ td->td_retval[0] = ucount;
+ return (error);
+}
+#endif /* COMPAT */
+
#ifdef COMPAT_43
+static void
+ogetdirentries_cvt(struct freebsd11_dirent *dp)
+{
+#if (BYTE_ORDER == LITTLE_ENDIAN)
+ /*
+ * The expected low byte of dp->d_namlen is our dp->d_type.
+ * The high MBZ byte of dp->d_namlen is our dp->d_namlen.
+ */
+ dp->d_type = dp->d_namlen;
+ dp->d_namlen = 0;
+#else
+ /*
+ * The dp->d_type is the high byte of the expected dp->d_namlen,
+ * so must be zero'ed.
+ */
+ dp->d_type = 0;
+#endif
+}
+
/*
* Read a block of directory entries in a filesystem independent format.
*/
@@ -3530,138 +3810,26 @@ int
kern_ogetdirentries(struct thread *td, struct ogetdirentries_args *uap,
long *ploff)
{
- struct vnode *vp;
- struct file *fp;
- struct uio auio, kuio;
- struct iovec aiov, kiov;
- struct dirent *dp, *edp;
- cap_rights_t rights;
- caddr_t dirbuf;
- int error, eofflag, readcnt;
- long loff;
- off_t foffset;
+ long base;
+ int error;
/* XXX arbitrary sanity limit on `count'. */
if (uap->count > 64 * 1024)
return (EINVAL);
- error = getvnode(td, uap->fd, cap_rights_init(&rights, CAP_READ), &fp);
- if (error != 0)
- return (error);
- if ((fp->f_flag & FREAD) == 0) {
- fdrop(fp, td);
- return (EBADF);
- }
- vp = fp->f_vnode;
- foffset = foffset_lock(fp, 0);
-unionread:
- if (vp->v_type != VDIR) {
- foffset_unlock(fp, foffset, 0);
- fdrop(fp, td);
- return (EINVAL);
- }
- aiov.iov_base = uap->buf;
- aiov.iov_len = uap->count;
- auio.uio_iov = &aiov;
- auio.uio_iovcnt = 1;
- auio.uio_rw = UIO_READ;
- auio.uio_segflg = UIO_USERSPACE;
- auio.uio_td = td;
- auio.uio_resid = uap->count;
- vn_lock(vp, LK_SHARED | LK_RETRY);
- loff = auio.uio_offset = foffset;
-#ifdef MAC
- error = mac_vnode_check_readdir(td->td_ucred, vp);
- if (error != 0) {
- VOP_UNLOCK(vp, 0);
- foffset_unlock(fp, foffset, FOF_NOUPDATE);
- fdrop(fp, td);
- return (error);
- }
-#endif
-# if (BYTE_ORDER != LITTLE_ENDIAN)
- if (vp->v_mount->mnt_maxsymlinklen <= 0) {
- error = VOP_READDIR(vp, &auio, fp->f_cred, &eofflag,
- NULL, NULL);
- foffset = auio.uio_offset;
- } else
-# endif
- {
- kuio = auio;
- kuio.uio_iov = &kiov;
- kuio.uio_segflg = UIO_SYSSPACE;
- kiov.iov_len = uap->count;
- dirbuf = malloc(uap->count, M_TEMP, M_WAITOK);
- kiov.iov_base = dirbuf;
- error = VOP_READDIR(vp, &kuio, fp->f_cred, &eofflag,
- NULL, NULL);
- foffset = kuio.uio_offset;
- if (error == 0) {
- readcnt = uap->count - kuio.uio_resid;
- edp = (struct dirent *)&dirbuf[readcnt];
- for (dp = (struct dirent *)dirbuf; dp < edp; ) {
-# if (BYTE_ORDER == LITTLE_ENDIAN)
- /*
- * The expected low byte of
- * dp->d_namlen is our dp->d_type.
- * The high MBZ byte of dp->d_namlen
- * is our dp->d_namlen.
- */
- dp->d_type = dp->d_namlen;
- dp->d_namlen = 0;
-# else
- /*
- * The dp->d_type is the high byte
- * of the expected dp->d_namlen,
- * so must be zero'ed.
- */
- dp->d_type = 0;
-# endif
- if (dp->d_reclen > 0) {
- dp = (struct dirent *)
- ((char *)dp + dp->d_reclen);
- } else {
- error = EIO;
- break;
- }
- }
- if (dp >= edp)
- error = uiomove(dirbuf, readcnt, &auio);
- }
- free(dirbuf, M_TEMP);
- }
- if (error != 0) {
- VOP_UNLOCK(vp, 0);
- foffset_unlock(fp, foffset, 0);
- fdrop(fp, td);
- return (error);
- }
- if (uap->count == auio.uio_resid &&
- (vp->v_vflag & VV_ROOT) &&
- (vp->v_mount->mnt_flag & MNT_UNION)) {
- struct vnode *tvp = vp;
- vp = vp->v_mount->mnt_vnodecovered;
- VREF(vp);
- fp->f_vnode = vp;
- fp->f_data = vp;
- foffset = 0;
- vput(tvp);
- goto unionread;
- }
- VOP_UNLOCK(vp, 0);
- foffset_unlock(fp, foffset, 0);
- fdrop(fp, td);
- td->td_retval[0] = uap->count - auio.uio_resid;
- if (error == 0)
- *ploff = loff;
+
+ error = freebsd11_kern_getdirentries(td, uap->fd, uap->buf, uap->count,
+ &base, ogetdirentries_cvt);
+
+ if (error == 0 && uap->basep != NULL)
+ error = copyout(&base, uap->basep, sizeof(long));
+
return (error);
}
#endif /* COMPAT_43 */
-/*
- * Read a block of directory entries in a filesystem independent format.
- */
+#if defined(COMPAT_FREEBSD11)
#ifndef _SYS_SYSPROTO_H_
-struct getdirentries_args {
+struct freebsd11_getdirentries_args {
int fd;
char *buf;
u_int count;
@@ -3669,30 +3837,61 @@ struct getdirentries_args {
};
#endif
int
-sys_getdirentries(struct thread *td, struct getdirentries_args *uap)
+freebsd11_getdirentries(struct thread *td,
+ struct freebsd11_getdirentries_args *uap)
{
long base;
int error;
+ error = freebsd11_kern_getdirentries(td, uap->fd, uap->buf, uap->count,
+ &base, NULL);
+
+ if (error == 0 && uap->basep != NULL)
+ error = copyout(&base, uap->basep, sizeof(long));
+ return (error);
+}
+
+int
+freebsd11_getdents(struct thread *td, struct freebsd11_getdents_args *uap)
+{
+ struct freebsd11_getdirentries_args ap;
+
+ ap.fd = uap->fd;
+ ap.buf = uap->buf;
+ ap.count = uap->count;
+ ap.basep = NULL;
+ return (freebsd11_getdirentries(td, &ap));
+}
+#endif /* COMPAT_FREEBSD11 */
+
+/*
+ * Read a block of directory entries in a filesystem independent format.
+ */
+int
+sys_getdirentries(struct thread *td, struct getdirentries_args *uap)
+{
+ off_t base;
+ int error;
+
error = kern_getdirentries(td, uap->fd, uap->buf, uap->count, &base,
NULL, UIO_USERSPACE);
if (error != 0)
return (error);
if (uap->basep != NULL)
- error = copyout(&base, uap->basep, sizeof(long));
+ error = copyout(&base, uap->basep, sizeof(off_t));
return (error);
}
int
-kern_getdirentries(struct thread *td, int fd, char *buf, u_int count,
- long *basep, ssize_t *residp, enum uio_seg bufseg)
+kern_getdirentries(struct thread *td, int fd, char *buf, size_t count,
+ off_t *basep, ssize_t *residp, enum uio_seg bufseg)
{
struct vnode *vp;
struct file *fp;
struct uio auio;
struct iovec aiov;
cap_rights_t rights;
- long loff;
+ off_t loff;
int error, eofflag;
off_t foffset;
@@ -3759,25 +3958,6 @@ fail:
return (error);
}
-#ifndef _SYS_SYSPROTO_H_
-struct getdents_args {
- int fd;
- char *buf;
- size_t count;
-};
-#endif
-int
-sys_getdents(struct thread *td, struct getdents_args *uap)
-{
- struct getdirentries_args ap;
-
- ap.fd = uap->fd;
- ap.buf = uap->buf;
- ap.count = uap->count;
- ap.basep = NULL;
- return (sys_getdirentries(td, &ap));
-}
-
/*
* Set the mode mask for creation of filesystem nodes.
*/
diff --git a/sys/kern/vfs_vnops.c b/sys/kern/vfs_vnops.c
index d041c07920de..f61531783707 100644
--- a/sys/kern/vfs_vnops.c
+++ b/sys/kern/vfs_vnops.c
@@ -2340,7 +2340,7 @@ vn_fill_kinfo_vnode(struct vnode *vp, struct kinfo_file *kif)
char *fullpath, *freepath;
int error;
- kif->kf_vnode_type = vntype_to_kinfo(vp->v_type);
+ kif->kf_un.kf_file.kf_file_type = vntype_to_kinfo(vp->v_type);
freepath = NULL;
fullpath = "-";
error = vn_fullpath(curthread, vp, &fullpath, &freepath);
@@ -2369,10 +2369,14 @@ vn_fill_kinfo_vnode(struct vnode *vp, struct kinfo_file *kif)
else
kif->kf_un.kf_file.kf_file_fsid =
vp->v_mount->mnt_stat.f_fsid.val[0];
+ kif->kf_un.kf_file.kf_file_fsid_freebsd11 =
+ kif->kf_un.kf_file.kf_file_fsid; /* truncate */
kif->kf_un.kf_file.kf_file_fileid = va.va_fileid;
kif->kf_un.kf_file.kf_file_mode = MAKEIMODE(va.va_type, va.va_mode);
kif->kf_un.kf_file.kf_file_size = va.va_size;
kif->kf_un.kf_file.kf_file_rdev = va.va_rdev;
+ kif->kf_un.kf_file.kf_file_rdev_freebsd11 =
+ kif->kf_un.kf_file.kf_file_rdev; /* truncate */
return (0);
}
diff --git a/sys/nlm/nlm_advlock.c b/sys/nlm/nlm_advlock.c
index d6ccd2f8ef08..10b41ab0acff 100644
--- a/sys/nlm/nlm_advlock.c
+++ b/sys/nlm/nlm_advlock.c
@@ -202,7 +202,7 @@ nlm_advlock_internal(struct vnode *vp, void *id, int op, struct flock *fl,
union nfsfh fh;
struct sockaddr *sa;
struct sockaddr_storage ss;
- char servername[MNAMELEN];
+ char *servername;
struct timeval timo;
int retries;
rpcvers_t vers;
@@ -218,6 +218,7 @@ nlm_advlock_internal(struct vnode *vp, void *id, int op, struct flock *fl,
ASSERT_VOP_LOCKED(vp, "nlm_advlock_1");
+ servername = malloc(MNAMELEN, M_TEMP, M_WAITOK); /* XXXKIB vp locked */
nmp = VFSTONFS(vp->v_mount);
/*
* Push any pending writes to the server and flush our cache
@@ -381,7 +382,7 @@ nlm_advlock_internal(struct vnode *vp, void *id, int op, struct flock *fl,
AUTH_DESTROY(auth);
nlm_host_release(host);
-
+ free(servername, M_TEMP);
return (error);
}
diff --git a/sys/security/audit/audit_private.h b/sys/security/audit/audit_private.h
index 64afa87bc45d..3d99635f7de0 100644
--- a/sys/security/audit/audit_private.h
+++ b/sys/security/audit/audit_private.h
@@ -107,9 +107,9 @@ struct vnode_au_info {
mode_t vn_mode;
uid_t vn_uid;
gid_t vn_gid;
- dev_t vn_dev;
- long vn_fsid;
- long vn_fileid;
+ u_int32_t vn_dev; /* XXX dev_t compatibility */
+ long vn_fsid; /* XXX uint64_t compatibility */
+ long vn_fileid; /* XXX ino_t compatibility */
long vn_gen;
};
@@ -210,7 +210,7 @@ struct audit_record {
int ar_arg_atfd2;
int ar_arg_fflags;
mode_t ar_arg_mode;
- int ar_arg_dev;
+ int ar_arg_dev; /* XXX dev_t compatibility */
long ar_arg_value;
void *ar_arg_addr;
int ar_arg_len;
diff --git a/sys/sys/_types.h b/sys/sys/_types.h
index 8736651ba6f0..1dd7c7df4cf7 100644
--- a/sys/sys/_types.h
+++ b/sys/sys/_types.h
@@ -43,13 +43,13 @@ typedef __uint64_t __fsblkcnt_t;
typedef __uint64_t __fsfilcnt_t;
typedef __uint32_t __gid_t;
typedef __int64_t __id_t; /* can hold a gid_t, pid_t, or uid_t */
-typedef __uint32_t __ino_t; /* inode number */
+typedef __uint64_t __ino_t; /* inode number */
typedef long __key_t; /* IPC key (for Sys V IPC) */
typedef __int32_t __lwpid_t; /* Thread ID (a.k.a. LWP) */
typedef __uint16_t __mode_t; /* permissions */
typedef int __accmode_t; /* access permissions */
typedef int __nl_item;
-typedef __uint16_t __nlink_t; /* link count */
+typedef __uint64_t __nlink_t; /* link count */
typedef __int64_t __off_t; /* file offset */
typedef __int64_t __off64_t; /* file offset (alias) */
typedef __int32_t __pid_t; /* process [group] */
@@ -105,7 +105,7 @@ typedef struct {
long double __max_align2 __aligned(_Alignof(long double));
} __max_align_t;
-typedef __uint32_t __dev_t; /* device number */
+typedef __uint64_t __dev_t; /* device number */
typedef __uint32_t __fixpt_t; /* fixed point number */
diff --git a/sys/sys/acct.h b/sys/sys/acct.h
index 759fdc6e0aa7..fc033b588124 100644
--- a/sys/sys/acct.h
+++ b/sys/sys/acct.h
@@ -45,12 +45,12 @@
#define AC_COMM_LEN 16
/*
- * Accounting structure version 2 (current).
+ * Accounting structure version 3 (current).
* The first byte is always zero.
* Time units are microseconds.
*/
-struct acctv2 {
+struct acctv3 {
uint8_t ac_zero; /* zero identifies new version */
uint8_t ac_version; /* record version number */
uint16_t ac_len; /* record length */
@@ -65,10 +65,13 @@ struct acctv2 {
float ac_mem; /* average memory usage */
float ac_io; /* count of IO blocks */
__dev_t ac_tty; /* controlling tty */
-
+ uint32_t ac_pad0;
+#if defined(__powerpc__) && !defined(_LP64)
+ uint32_t ac_pad1;
+#endif
uint16_t ac_len2; /* record length */
union {
- __dev_t ac_align; /* force v1 compatible alignment */
+ uint32_t ac_align; /* force v1 compatible alignment */
#define AFORK 0x01 /* forked but not exec'ed */
/* ASU is no longer supported */
@@ -84,6 +87,28 @@ struct acctv2 {
#define ac_flagx ac_trailer.ac_flag
};
+struct acctv2 {
+ uint8_t ac_zero; /* zero identifies new version */
+ uint8_t ac_version; /* record version number */
+ uint16_t ac_len; /* record length */
+
+ char ac_comm[AC_COMM_LEN]; /* command name */
+ float ac_utime; /* user time */
+ float ac_stime; /* system time */
+ float ac_etime; /* elapsed time */
+ time_t ac_btime; /* starting time */
+ uid_t ac_uid; /* user id */
+ gid_t ac_gid; /* group id */
+ float ac_mem; /* average memory usage */
+ float ac_io; /* count of IO blocks */
+ uint32_t ac_tty; /* controlling tty */
+
+ uint16_t ac_len2; /* record length */
+ union {
+ uint32_t ac_align; /* force v1 compatible alignment */
+ uint8_t ac_flag; /* accounting flags */
+ } ac_trailer;
+};
/*
* Legacy accounting structure (rev. 1.5-1.18).
@@ -105,7 +130,7 @@ struct acctv1 {
gid_t ac_gid; /* group id */
uint16_t ac_mem; /* average memory usage */
comp_t ac_io; /* count of IO blocks */
- __dev_t ac_tty; /* controlling tty */
+ uint32_t ac_tty; /* controlling tty */
uint8_t ac_flag; /* accounting flags */
};
diff --git a/sys/sys/dirent.h b/sys/sys/dirent.h
index ed3f6f5c7746..472142f960b4 100644
--- a/sys/sys/dirent.h
+++ b/sys/sys/dirent.h
@@ -36,22 +36,39 @@
#include <sys/cdefs.h>
#include <sys/_types.h>
+#ifndef _INO_T_DECLARED
+typedef __ino_t ino_t;
+#define _INO_T_DECLARED
+#endif
+
+#ifndef _OFF_T_DECLARED
+typedef __off_t off_t;
+#define _OFF_T_DECLARED
+#endif
+
/*
* The dirent structure defines the format of directory entries returned by
* the getdirentries(2) system call.
*
* A directory entry has a struct dirent at the front of it, containing its
* inode number, the length of the entry, and the length of the name
- * contained in the entry. These are followed by the name padded to a 4
+ * contained in the entry. These are followed by the name padded to an 8
* byte boundary with null bytes. All names are guaranteed null terminated.
* The maximum length of a name in a directory is MAXNAMLEN.
+ *
+ * Explicit padding between the last member of the header (d_namelen) and
+ * d_name avoids ABI padding at the end of dirent on LP64 architectures.
+ * There is code depending on d_name being last.
*/
struct dirent {
- __uint32_t d_fileno; /* file number of entry */
+ ino_t d_fileno; /* file number of entry */
+ off_t d_off; /* directory offset of entry */
__uint16_t d_reclen; /* length of this record */
- __uint8_t d_type; /* file type, see below */
- __uint8_t d_namlen; /* length of string in d_name */
+ __uint8_t d_type; /* file type, see below */
+ __uint8_t d_pad0;
+ __uint16_t d_namlen; /* length of string in d_name */
+ __uint16_t d_pad1;
#if __BSD_VISIBLE
#define MAXNAMLEN 255
char d_name[MAXNAMLEN + 1]; /* name must be no longer than this */
@@ -60,7 +77,18 @@ struct dirent {
#endif
};
+#if defined(_WANT_FREEBSD11_DIRENT) || defined(_KERNEL)
+struct freebsd11_dirent {
+ __uint32_t d_fileno; /* file number of entry */
+ __uint16_t d_reclen; /* length of this record */
+ __uint8_t d_type; /* file type, see below */
+ __uint8_t d_namlen; /* length of string in d_name */
+ char d_name[255 + 1]; /* name must be no longer than this */
+};
+#endif /* _WANT_FREEBSD11_DIRENT || _KERNEL */
+
#if __BSD_VISIBLE
+
/*
* File types
*/
@@ -84,13 +112,14 @@ struct dirent {
* The _GENERIC_DIRSIZ macro gives the minimum record length which will hold
* the directory entry. This returns the amount of space in struct direct
* without the d_name field, plus enough space for the name with a terminating
- * null byte (dp->d_namlen+1), rounded up to a 4 byte boundary.
+ * null byte (dp->d_namlen+1), rounded up to a 8 byte boundary.
*
* XXX although this macro is in the implementation namespace, it requires
* a manifest constant that is not.
*/
-#define _GENERIC_DIRSIZ(dp) \
- ((sizeof (struct dirent) - (MAXNAMLEN+1)) + (((dp)->d_namlen+1 + 3) &~ 3))
+#define _GENERIC_DIRLEN(namlen) \
+ ((__offsetof(struct dirent, d_name) + (namlen) + 1 + 7) & ~7)
+#define _GENERIC_DIRSIZ(dp) _GENERIC_DIRLEN((dp)->d_namlen)
#endif /* __BSD_VISIBLE */
#ifdef _KERNEL
diff --git a/sys/sys/mount.h b/sys/sys/mount.h
index 9800d97df27e..519b4cf94f52 100644
--- a/sys/sys/mount.h
+++ b/sys/sys/mount.h
@@ -65,8 +65,8 @@ struct fid {
* filesystem statistics
*/
#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 */
uint32_t f_type; /* type of filesystem */
@@ -92,6 +92,34 @@ struct statfs {
char f_mntonname[MNAMELEN]; /* directory on which mounted */
};
+#if defined(_WANT_FREEBSD11_STATFS) || defined(_KERNEL)
+#define FREEBSD11_STATFS_VERSION 0x20030518 /* current version number */
+struct freebsd11_statfs {
+ uint32_t f_version; /* structure version number */
+ uint32_t f_type; /* type of filesystem */
+ uint64_t f_flags; /* copy of mount exported flags */
+ uint64_t f_bsize; /* filesystem fragment size */
+ uint64_t f_iosize; /* optimal transfer block size */
+ uint64_t f_blocks; /* total data blocks in filesystem */
+ uint64_t f_bfree; /* free blocks in filesystem */
+ int64_t f_bavail; /* free blocks avail to non-superuser */
+ uint64_t f_files; /* total file nodes in filesystem */
+ int64_t f_ffree; /* free nodes avail to non-superuser */
+ uint64_t f_syncwrites; /* count of sync writes since mount */
+ uint64_t f_asyncwrites; /* count of async writes since mount */
+ uint64_t f_syncreads; /* count of sync reads since mount */
+ uint64_t f_asyncreads; /* count of async reads since mount */
+ uint64_t f_spare[10]; /* unused spare */
+ uint32_t f_namemax; /* maximum filename length */
+ uid_t f_owner; /* user that mounted the filesystem */
+ fsid_t f_fsid; /* filesystem id */
+ char f_charspare[80]; /* spare string space */
+ char f_fstypename[16]; /* filesystem type name */
+ char f_mntfromname[88]; /* mounted filesystem */
+ char f_mntonname[88]; /* directory on which mounted */
+};
+#endif /* _WANT_FREEBSD11_STATFS || _KERNEL */
+
#ifdef _KERNEL
#define OMFSNAMELEN 16 /* length of fs type name, including null */
#define OMNAMELEN (88 - 2 * sizeof(long)) /* size of on/from name bufs */
diff --git a/sys/sys/param.h b/sys/sys/param.h
index db976774c7c0..97d1d379111f 100644
--- a/sys/sys/param.h
+++ b/sys/sys/param.h
@@ -58,7 +58,7 @@
* in the range 5 to 9.
*/
#undef __FreeBSD_version
-#define __FreeBSD_version 1200030 /* Master, propagated to newvers */
+#define __FreeBSD_version 1200031 /* Master, propagated to newvers */
/*
* __FreeBSD_kernel__ indicates that this system uses the kernel of FreeBSD,
diff --git a/sys/sys/stat.h b/sys/sys/stat.h
index 6af909aea7c1..95a42b24716a 100644
--- a/sys/sys/stat.h
+++ b/sys/sys/stat.h
@@ -102,9 +102,9 @@ typedef __uid_t uid_t;
#ifdef _KERNEL
struct ostat {
__uint16_t st_dev; /* inode's device */
- ino_t st_ino; /* inode's number */
+ __uint32_t st_ino; /* inode's number */
mode_t st_mode; /* inode protection mode */
- nlink_t st_nlink; /* number of hard links */
+ __uint16_t st_nlink; /* number of hard links */
__uint16_t st_uid; /* user ID of the file's owner */
__uint16_t st_gid; /* group ID of the file's group */
__uint16_t st_rdev; /* device type */
@@ -119,14 +119,15 @@ struct ostat {
};
#endif
-struct stat {
- __dev_t st_dev; /* inode's device */
- ino_t st_ino; /* inode's number */
+#if defined(_WANT_FREEBSD11_STAT) || defined(_KERNEL)
+struct freebsd11_stat {
+ __uint32_t st_dev; /* inode's device */
+ __uint32_t st_ino; /* inode's number */
mode_t st_mode; /* inode protection mode */
- nlink_t st_nlink; /* number of hard links */
+ __uint16_t st_nlink; /* number of hard links */
uid_t st_uid; /* user ID of the file's owner */
gid_t st_gid; /* group ID of the file's group */
- __dev_t st_rdev; /* device type */
+ __uint32_t st_rdev; /* device type */
struct timespec st_atim; /* time of last access */
struct timespec st_mtim; /* time of last data modification */
struct timespec st_ctim; /* time of last file status change */
@@ -148,16 +149,55 @@ struct stat {
unsigned int :(8 / 2) * (16 - (int)sizeof(struct timespec));
unsigned int :(8 / 2) * (16 - (int)sizeof(struct timespec));
};
+#endif /* _WANT_FREEBSD11_STAT || _KERNEL */
+
+#if defined(__i386__)
+#define __STAT_TIME_T_EXT 1
+#endif
+
+struct stat {
+ dev_t st_dev; /* inode's device */
+ ino_t st_ino; /* inode's number */
+ nlink_t st_nlink; /* number of hard links */
+ mode_t st_mode; /* inode protection mode */
+ __int16_t st_padding0;
+ uid_t st_uid; /* user ID of the file's owner */
+ gid_t st_gid; /* group ID of the file's group */
+ __int32_t st_padding1;
+ dev_t st_rdev; /* device type */
+#ifdef __STAT_TIME_T_EXT
+ __int32_t st_atim_ext;
+#endif
+ struct timespec st_atim; /* time of last access */
+#ifdef __STAT_TIME_T_EXT
+ __int32_t st_mtim_ext;
+#endif
+ struct timespec st_mtim; /* time of last data modification */
+#ifdef __STAT_TIME_T_EXT
+ __int32_t st_ctim_ext;
+#endif
+ struct timespec st_ctim; /* time of last file status change */
+#ifdef __STAT_TIME_T_EXT
+ __int32_t st_btim_ext;
+#endif
+ struct timespec st_birthtim; /* time of file creation */
+ off_t st_size; /* file size, in bytes */
+ blkcnt_t st_blocks; /* blocks allocated for file */
+ blksize_t st_blksize; /* optimal blocksize for I/O */
+ fflags_t st_flags; /* user defined flags for file */
+ __uint64_t st_gen; /* file generation number */
+ __uint64_t st_spare[10];
+};
#ifdef _KERNEL
struct nstat {
- __dev_t st_dev; /* inode's device */
- ino_t st_ino; /* inode's number */
+ __uint32_t st_dev; /* inode's device */
+ __uint32_t st_ino; /* inode's number */
__uint32_t st_mode; /* inode protection mode */
__uint32_t st_nlink; /* number of hard links */
uid_t st_uid; /* user ID of the file's owner */
gid_t st_gid; /* group ID of the file's group */
- __dev_t st_rdev; /* device type */
+ __uint32_t st_rdev; /* device type */
struct timespec st_atim; /* time of last access */
struct timespec st_mtim; /* time of last data modification */
struct timespec st_ctim; /* time of last file status change */
@@ -168,7 +208,8 @@ struct nstat {
__uint32_t st_gen; /* file generation number */
struct timespec st_birthtim; /* time of file creation */
/*
- * See above about the following padding.
+ * See comment in the definition of struct freebsd11_stat
+ * above about the following padding.
*/
unsigned int :(8 / 2) * (16 - (int)sizeof(struct timespec));
unsigned int :(8 / 2) * (16 - (int)sizeof(struct timespec));
diff --git a/sys/sys/syscallsubr.h b/sys/sys/syscallsubr.h
index d4cfa26045e9..c994ee94f829 100644
--- a/sys/sys/syscallsubr.h
+++ b/sys/sys/syscallsubr.h
@@ -117,8 +117,8 @@ int kern_futimes(struct thread *td, int fd, struct timeval *tptr,
enum uio_seg tptrseg);
int kern_futimens(struct thread *td, int fd, struct timespec *tptr,
enum uio_seg tptrseg);
-int kern_getdirentries(struct thread *td, int fd, char *buf, u_int count,
- long *basep, ssize_t *residp, enum uio_seg bufseg);
+int kern_getdirentries(struct thread *td, int fd, char *buf, size_t count,
+ off_t *basep, ssize_t *residp, enum uio_seg bufseg);
int kern_getfsstat(struct thread *td, struct statfs **buf, size_t bufsize,
size_t *countp, enum uio_seg bufseg, int mode);
int kern_getitimer(struct thread *, u_int, struct itimerval *);
@@ -158,7 +158,7 @@ int kern_mkdirat(struct thread *td, int fd, char *path,
int kern_mkfifoat(struct thread *td, int fd, char *path,
enum uio_seg pathseg, int mode);
int kern_mknodat(struct thread *td, int fd, char *path,
- enum uio_seg pathseg, int mode, int dev);
+ enum uio_seg pathseg, int mode, dev_t dev);
int kern_mlock(struct proc *proc, struct ucred *cred, uintptr_t addr,
size_t len);
int kern_mmap(struct thread *td, uintptr_t addr, size_t size, int prot,
@@ -292,4 +292,9 @@ int kern_socketpair(struct thread *td, int domain, int type, int protocol,
#define KSA_OSIGSET 0x0001 /* uses osigact_t */
#define KSA_FREEBSD4 0x0002 /* uses ucontext4 */
+struct freebsd11_dirent;
+
+int freebsd11_kern_getdirentries(struct thread *td, int fd, char *ubuf, u_int
+ count, long *basep, void (*func)(struct freebsd11_dirent *));
+
#endif /* !_SYS_SYSCALLSUBR_H_ */
diff --git a/sys/sys/tty.h b/sys/sys/tty.h
index 09e04195ae55..c37d0bf3d073 100644
--- a/sys/sys/tty.h
+++ b/sys/sys/tty.h
@@ -148,7 +148,7 @@ struct xtty {
pid_t xt_pgid; /* Foreground process group. */
pid_t xt_sid; /* Session. */
unsigned int xt_flags; /* Terminal option flags. */
- dev_t xt_dev; /* Userland device. */
+ uint32_t xt_dev; /* Userland device. XXXKIB truncated */
};
#ifdef _KERNEL
diff --git a/sys/sys/user.h b/sys/sys/user.h
index ab9cee5c8b91..ba5e43a74158 100644
--- a/sys/sys/user.h
+++ b/sys/sys/user.h
@@ -84,7 +84,7 @@
* it in two places: function fill_kinfo_proc in sys/kern/kern_proc.c and
* function kvm_proclist in lib/libkvm/kvm_proc.c .
*/
-#define KI_NSPARE_INT 4
+#define KI_NSPARE_INT 2
#define KI_NSPARE_LONG 12
#define KI_NSPARE_PTR 6
@@ -135,7 +135,7 @@ struct kinfo_proc {
pid_t ki_tsid; /* Terminal session ID */
short ki_jobc; /* job control counter */
short ki_spare_short1; /* unused (just here for alignment) */
- dev_t ki_tdev; /* controlling tty dev */
+ uint32_t ki_tdev_freebsd11; /* controlling tty dev */
sigset_t ki_siglist; /* Signals arrived but not delivered */
sigset_t ki_sigmask; /* Current signal mask */
sigset_t ki_sigignore; /* Signals being ignored */
@@ -188,6 +188,7 @@ struct kinfo_proc {
*/
char ki_sparestrings[46]; /* spare string space */
int ki_spareints[KI_NSPARE_INT]; /* spare room for growth */
+ uint64_t ki_tdev; /* controlling tty dev */
int ki_oncpu; /* Which cpu we are on */
int ki_lastcpu; /* Last cpu we were on */
int ki_tracer; /* Pid of tracing process */
@@ -341,14 +342,19 @@ struct kinfo_file {
int kf_flags; /* Flags. */
int kf_pad0; /* Round to 64 bit alignment. */
int64_t kf_offset; /* Seek location. */
- int kf_vnode_type; /* Vnode type. */
- int kf_sock_domain; /* Socket domain. */
- int kf_sock_type; /* Socket type. */
- int kf_sock_protocol; /* Socket protocol. */
- struct sockaddr_storage kf_sa_local; /* Socket address. */
- struct sockaddr_storage kf_sa_peer; /* Peer address. */
union {
struct {
+ uint32_t kf_spareint;
+ /* Socket domain. */
+ int kf_sock_domain0;
+ /* Socket type. */
+ int kf_sock_type0;
+ /* Socket protocol. */
+ int kf_sock_protocol0;
+ /* Socket address. */
+ struct sockaddr_storage kf_sa_local;
+ /* Peer address. */
+ struct sockaddr_storage kf_sa_peer;
/* Address of so_pcb. */
uint64_t kf_sock_pcb;
/* Address of inp_ppcb. */
@@ -363,14 +369,23 @@ struct kinfo_file {
uint32_t kf_sock_pad0;
} kf_sock;
struct {
+ /* Vnode type. */
+ int kf_file_type;
+ /* Space for future use */
+ int kf_spareint[3];
+ uint64_t kf_spareint64[30];
+ /* Vnode filesystem id. */
+ uint64_t kf_file_fsid;
+ /* File device. */
+ uint64_t kf_file_rdev;
/* Global file id. */
uint64_t kf_file_fileid;
/* File size. */
uint64_t kf_file_size;
- /* Vnode filesystem id. */
- uint32_t kf_file_fsid;
- /* File device. */
- uint32_t kf_file_rdev;
+ /* Vnode filesystem id, FreeBSD 11 compat. */
+ uint32_t kf_file_fsid_freebsd11;
+ /* File device, FreeBSD 11 compat. */
+ uint32_t kf_file_rdev_freebsd11;
/* File mode. */
uint16_t kf_file_mode;
/* Round to 64 bit alignment. */
@@ -378,10 +393,14 @@ struct kinfo_file {
uint32_t kf_file_pad1;
} kf_file;
struct {
+ uint32_t kf_spareint[4];
+ uint64_t kf_spareint64[32];
uint32_t kf_sem_value;
uint16_t kf_sem_mode;
} kf_sem;
struct {
+ uint32_t kf_spareint[4];
+ uint64_t kf_spareint64[32];
uint64_t kf_pipe_addr;
uint64_t kf_pipe_peer;
uint32_t kf_pipe_buffer_cnt;
@@ -389,11 +408,17 @@ struct kinfo_file {
uint32_t kf_pipe_pad0[3];
} kf_pipe;
struct {
- uint32_t kf_pts_dev;
+ uint32_t kf_spareint[4];
+ uint64_t kf_spareint64[32];
+ uint32_t kf_pts_dev_freebsd11;
+ uint32_t kf_pts_pad0;
+ uint64_t kf_pts_dev;
/* Round to 64 bit alignment. */
- uint32_t kf_pts_pad0[7];
+ uint32_t kf_pts_pad1[4];
} kf_pts;
struct {
+ uint32_t kf_spareint[4];
+ uint64_t kf_spareint64[32];
pid_t kf_pid;
} kf_proc;
} kf_un;
@@ -405,6 +430,12 @@ struct kinfo_file {
/* Truncated before copyout in sysctl */
char kf_path[PATH_MAX]; /* Path to file, if any. */
};
+#ifndef _KERNEL
+#define kf_vnode_type kf_un.kf_file.kf_file_type
+#define kf_sock_domain kf_un.kf_sock.kf_sock_domain0
+#define kf_sock_type kf_un.kf_sock.kf_sock_type0
+#define kf_sock_protocol kf_un.kf_sock.kf_sock_protocol0
+#endif
/*
* The KERN_PROC_VMMAP sysctl allows a process to dump the VM layout of
@@ -454,7 +485,7 @@ struct kinfo_ovmentry {
void *_kve_pspare[8]; /* Space for more stuff. */
off_t kve_offset; /* Mapping offset in object */
uint64_t kve_fileid; /* inode number if vnode */
- dev_t kve_fsid; /* dev_t of vnode location */
+ uint32_t kve_fsid; /* dev_t of vnode location */
int _kve_ispare[3]; /* Space for more stuff. */
};
@@ -469,7 +500,7 @@ struct kinfo_vmentry {
uint64_t kve_end; /* Finishing address. */
uint64_t kve_offset; /* Mapping offset in object */
uint64_t kve_vn_fileid; /* inode number if vnode */
- uint32_t kve_vn_fsid; /* dev_t of vnode location */
+ uint32_t kve_vn_fsid_freebsd11; /* dev_t of vnode location */
int kve_flags; /* Flags on map entry. */
int kve_resident; /* Number of resident pages. */
int kve_private_resident; /* Number of private pages. */
@@ -478,10 +509,12 @@ struct kinfo_vmentry {
int kve_shadow_count; /* VM obj shadow count. */
int kve_vn_type; /* Vnode type. */
uint64_t kve_vn_size; /* File size. */
- uint32_t kve_vn_rdev; /* Device id if device. */
+ uint32_t kve_vn_rdev_freebsd11; /* Device id if device. */
uint16_t kve_vn_mode; /* File mode. */
uint16_t kve_status; /* Status flags. */
- int _kve_ispare[12]; /* Space for more stuff. */
+ uint64_t kve_vn_fsid; /* dev_t of vnode location */
+ uint64_t kve_vn_rdev; /* Device id if device. */
+ int _kve_ispare[8]; /* Space for more stuff. */
/* Truncated before copyout in sysctl */
char kve_path[PATH_MAX]; /* Path to VM obj, if any. */
};
@@ -495,14 +528,15 @@ struct kinfo_vmobject {
int kvo_type; /* Object type: KVME_TYPE_*. */
uint64_t kvo_size; /* Object size in pages. */
uint64_t kvo_vn_fileid; /* inode number if vnode. */
- uint32_t kvo_vn_fsid; /* dev_t of vnode location. */
+ uint32_t kvo_vn_fsid_freebsd11; /* dev_t of vnode location. */
int kvo_ref_count; /* Reference count. */
int kvo_shadow_count; /* Shadow count. */
int kvo_memattr; /* Memory attribute. */
uint64_t kvo_resident; /* Number of resident pages. */
uint64_t kvo_active; /* Number of active pages. */
uint64_t kvo_inactive; /* Number of inactive pages. */
- uint64_t _kvo_qspare[8];
+ uint64_t kvo_vn_fsid;
+ uint64_t _kvo_qspare[7];
uint32_t _kvo_ispare[8];
char kvo_path[PATH_MAX]; /* Pathname, if any. */
};
diff --git a/sys/sys/vnode.h b/sys/sys/vnode.h
index b688bfd143d2..8bfe851c55e6 100644
--- a/sys/sys/vnode.h
+++ b/sys/sys/vnode.h
@@ -266,11 +266,12 @@ struct xvnode {
struct vattr {
enum vtype va_type; /* vnode type (for create) */
u_short va_mode; /* files access mode and type */
- short va_nlink; /* number of references to file */
+ u_short va_padding0;
uid_t va_uid; /* owner user id */
gid_t va_gid; /* owner group id */
+ nlink_t va_nlink; /* number of references to file */
dev_t va_fsid; /* filesystem id */
- long va_fileid; /* file id */
+ ino_t va_fileid; /* file id */
u_quad_t va_size; /* file size in bytes */
long va_blocksize; /* blocksize preferred for i/o */
struct timespec va_atime; /* time of last access */
@@ -585,6 +586,7 @@ struct file;
struct mount;
struct nameidata;
struct ostat;
+struct freebsd11_stat;
struct thread;
struct proc;
struct stat;
@@ -613,7 +615,8 @@ void cache_purge_negative(struct vnode *vp);
void cache_purgevfs(struct mount *mp, bool force);
int change_dir(struct vnode *vp, struct thread *td);
void cvtstat(struct stat *st, struct ostat *ost);
-void cvtnstat(struct stat *sb, struct nstat *nsb);
+void freebsd11_cvtnstat(struct stat *sb, struct nstat *nsb);
+void freebsd11_cvtstat(struct stat *st, struct freebsd11_stat *ost);
int getnewvnode(const char *tag, struct mount *mp, struct vop_vector *vops,
struct vnode **vpp);
void getnewvnode_reserve(u_int count);
diff --git a/sys/vm/swap_pager.c b/sys/vm/swap_pager.c
index 76b69e5053e9..2a73acaad666 100644
--- a/sys/vm/swap_pager.c
+++ b/sys/vm/swap_pager.c
@@ -69,6 +69,7 @@
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
+#include "opt_compat.h"
#include "opt_swap.h"
#include "opt_vm.h"
@@ -2417,10 +2418,24 @@ swap_dev_info(int name, struct xswdev *xs, char *devname, size_t len)
return (error);
}
+#if defined(COMPAT_FREEBSD11)
+#define XSWDEV_VERSION_11 1
+struct xswdev11 {
+ u_int xsw_version;
+ uint32_t xsw_dev;
+ int xsw_flags;
+ int xsw_nblks;
+ int xsw_used;
+};
+#endif
+
static int
sysctl_vm_swap_info(SYSCTL_HANDLER_ARGS)
{
struct xswdev xs;
+#if defined(COMPAT_FREEBSD11)
+ struct xswdev11 xs11;
+#endif
int error;
if (arg2 != 1) /* name length */
@@ -2428,7 +2443,17 @@ sysctl_vm_swap_info(SYSCTL_HANDLER_ARGS)
error = swap_dev_info(*(int *)arg1, &xs, NULL, 0);
if (error != 0)
return (error);
- error = SYSCTL_OUT(req, &xs, sizeof(xs));
+#if defined(COMPAT_FREEBSD11)
+ if (req->oldlen == sizeof(xs11)) {
+ xs11.xsw_version = XSWDEV_VERSION_11;
+ xs11.xsw_dev = xs.xsw_dev; /* truncation */
+ xs11.xsw_flags = xs.xsw_flags;
+ xs11.xsw_nblks = xs.xsw_nblks;
+ xs11.xsw_used = xs.xsw_used;
+ error = SYSCTL_OUT(req, &xs11, sizeof(xs11));
+ } else
+#endif
+ error = SYSCTL_OUT(req, &xs, sizeof(xs));
return (error);
}
diff --git a/sys/vm/vm_object.c b/sys/vm/vm_object.c
index 022fbd57c882..a751ac6ea2ff 100644
--- a/sys/vm/vm_object.c
+++ b/sys/vm/vm_object.c
@@ -2342,6 +2342,7 @@ sysctl_vm_object_list(SYSCTL_HANDLER_ARGS)
kvo.kvo_vn_fileid = 0;
kvo.kvo_vn_fsid = 0;
+ kvo.kvo_vn_fsid_freebsd11 = 0;
freepath = NULL;
fullpath = "";
vp = NULL;
@@ -2383,6 +2384,8 @@ sysctl_vm_object_list(SYSCTL_HANDLER_ARGS)
if (VOP_GETATTR(vp, &va, curthread->td_ucred) == 0) {
kvo.kvo_vn_fileid = va.va_fileid;
kvo.kvo_vn_fsid = va.va_fsid;
+ kvo.kvo_vn_fsid_freebsd11 = va.va_fsid;
+ /* truncate */
}
vput(vp);
}
diff --git a/sys/vm/vm_param.h b/sys/vm/vm_param.h
index c4d72237fd40..8ca83bf18ddf 100644
--- a/sys/vm/vm_param.h
+++ b/sys/vm/vm_param.h
@@ -89,7 +89,7 @@
/*
* Structure for swap device statistics
*/
-#define XSWDEV_VERSION 1
+#define XSWDEV_VERSION 2
struct xswdev {
u_int xsw_version;
dev_t xsw_dev;
diff --git a/usr.bin/kdump/kdump.c b/usr.bin/kdump/kdump.c
index 60898fde8772..0432449755bb 100644
--- a/usr.bin/kdump/kdump.c
+++ b/usr.bin/kdump/kdump.c
@@ -932,7 +932,6 @@ ktrsyscall(struct ktr_syscall *ktr, u_int sv_flags)
ip++;
narg--;
break;
- case SYS_mknod:
case SYS_mknodat:
print_number(ip, narg, c);
putchar(',');
diff --git a/usr.bin/lastcomm/lastcomm.c b/usr.bin/lastcomm/lastcomm.c
index 57acfb583bd7..e3b9aea50644 100644
--- a/usr.bin/lastcomm/lastcomm.c
+++ b/usr.bin/lastcomm/lastcomm.c
@@ -61,9 +61,9 @@ __FBSDID("$FreeBSD$");
time_t expand(u_int);
char *flagbits(int);
const char *getdev(dev_t);
-int readrec_forward(FILE *f, struct acctv2 *av2);
-int readrec_backward(FILE *f, struct acctv2 *av2);
-int requested(char *[], struct acctv2 *);
+int readrec_forward(FILE *f, struct acctv3 *av3);
+int readrec_backward(FILE *f, struct acctv3 *av3);
+int requested(char *[], struct acctv3 *);
static void usage(void);
#define AC_UTIME 1 /* user */
@@ -77,10 +77,10 @@ static void usage(void);
int
main(int argc, char *argv[])
{
- struct acctv2 ab;
+ struct acctv3 ab;
char *p;
FILE *fp;
- int (*readrec)(FILE *f, struct acctv2 *av2);
+ int (*readrec)(FILE *f, struct acctv3 *av3);
time_t t;
int ch, rv;
const char *acctfile, *format;
@@ -234,7 +234,7 @@ flagbits(int f)
}
int
-requested(char *argv[], struct acctv2 *acp)
+requested(char *argv[], struct acctv3 *acp)
{
const char *p;
diff --git a/usr.bin/lastcomm/readrec.c b/usr.bin/lastcomm/readrec.c
index 5de7c5c4c808..0a3e9306e063 100644
--- a/usr.bin/lastcomm/readrec.c
+++ b/usr.bin/lastcomm/readrec.c
@@ -38,8 +38,8 @@ __FBSDID("$FreeBSD$");
#include <stdio.h>
#include <string.h>
-int readrec_forward(FILE *f, struct acctv2 *av2);
-int readrec_backward(FILE *f, struct acctv2 *av2);
+int readrec_forward(FILE *f, struct acctv3 *av2);
+int readrec_backward(FILE *f, struct acctv3 *av2);
/*
* Reverse offsetof: return the offset of field f
@@ -90,27 +90,27 @@ decode_comp(comp_t v)
* Return EOF on error or end-of-file.
*/
static int
-readrec_v1(FILE *f, struct acctv2 *av2)
+readrec_v1(FILE *f, struct acctv3 *av3)
{
struct acctv1 av1;
int rv;
if ((rv = fread_record(&av1, sizeof(av1), f)) == EOF)
return (EOF);
- av2->ac_zero = 0;
- av2->ac_version = 2;
- av2->ac_len = av2->ac_len2 = sizeof(*av2);
- memcpy(av2->ac_comm, av1.ac_comm, AC_COMM_LEN);
- av2->ac_utime = decode_comp(av1.ac_utime) * 1000000;
- av2->ac_stime = decode_comp(av1.ac_stime) * 1000000;
- av2->ac_etime = decode_comp(av1.ac_etime) * 1000000;
- av2->ac_btime = av1.ac_btime;
- av2->ac_uid = av1.ac_uid;
- av2->ac_gid = av1.ac_gid;
- av2->ac_mem = av1.ac_mem;
- av2->ac_io = decode_comp(av1.ac_io);
- av2->ac_tty = av1.ac_tty;
- av2->ac_flagx = av1.ac_flag | ANVER;
+ av3->ac_zero = 0;
+ av3->ac_version = 3;
+ av3->ac_len = av3->ac_len2 = sizeof(*av3);
+ memcpy(av3->ac_comm, av1.ac_comm, AC_COMM_LEN);
+ av3->ac_utime = decode_comp(av1.ac_utime) * 1000000;
+ av3->ac_stime = decode_comp(av1.ac_stime) * 1000000;
+ av3->ac_etime = decode_comp(av1.ac_etime) * 1000000;
+ av3->ac_btime = av1.ac_btime;
+ av3->ac_uid = av1.ac_uid;
+ av3->ac_gid = av1.ac_gid;
+ av3->ac_mem = av1.ac_mem;
+ av3->ac_io = decode_comp(av1.ac_io);
+ av3->ac_tty = av1.ac_tty;
+ av3->ac_flagx = av1.ac_flag | ANVER;
return (0);
}
@@ -120,9 +120,40 @@ readrec_v1(FILE *f, struct acctv2 *av2)
* Return EOF on error or end-of-file.
*/
static int
-readrec_v2(FILE *f, struct acctv2 *av2)
+readrec_v2(FILE *f, struct acctv3 *av3)
{
- return (fread_record(av2, sizeof(*av2), f));
+ struct acctv2 av2;
+ int rv;
+
+ if ((rv = fread_record(&av2, sizeof(av2), f)) == EOF)
+ return (EOF);
+ av3->ac_zero = 0;
+ av3->ac_version = 3;
+ av3->ac_len = av3->ac_len2 = sizeof(*av3);
+ memcpy(av3->ac_comm, av2.ac_comm, AC_COMM_LEN);
+ av3->ac_utime = av2.ac_utime;
+ av3->ac_stime = av2.ac_stime;
+ av3->ac_etime = av2.ac_etime;
+ av3->ac_btime = av2.ac_btime;
+ av3->ac_uid = av2.ac_uid;
+ av3->ac_gid = av2.ac_gid;
+ av3->ac_mem = av2.ac_mem;
+ av3->ac_io = av2.ac_io;
+ av3->ac_tty = av2.ac_tty;
+ av3->ac_flagx = av2.ac_flagx;
+ return (0);
+}
+
+/*
+ * Read an v2 accounting record stored at the current
+ * position of stream f.
+ * Return EOF on error or end-of-file.
+ */
+static int
+readrec_v3(FILE *f, struct acctv3 *av3)
+{
+
+ return (fread_record(av3, sizeof(*av3), f));
}
/*
@@ -132,7 +163,7 @@ readrec_v2(FILE *f, struct acctv2 *av2)
* Return EOF on error or end-of-file.
*/
static int
-readrec_vx(FILE *f, struct acctv2 *av2)
+readrec_vx(FILE *f, struct acctv3 *av3)
{
uint8_t magic, version;
@@ -143,7 +174,9 @@ readrec_vx(FILE *f, struct acctv2 *av2)
return (EOF);
switch (version) {
case 2:
- return (readrec_v2(f, av2));
+ return (readrec_v2(f, av3));
+ case 3:
+ return (readrec_v3(f, av3));
/* Add handling for more versions here. */
@@ -162,7 +195,7 @@ readrec_vx(FILE *f, struct acctv2 *av2)
* or EOF on error.
*/
int
-readrec_forward(FILE *f, struct acctv2 *av2)
+readrec_forward(FILE *f, struct acctv3 *av3)
{
int magic, rv;
@@ -172,10 +205,10 @@ readrec_forward(FILE *f, struct acctv2 *av2)
return (EOF);
if (magic != 0)
/* Old record format. */
- rv = readrec_v1(f, av2);
+ rv = readrec_v1(f, av3);
else
/* New record formats. */
- rv = readrec_vx(f, av2);
+ rv = readrec_vx(f, av3);
return (rv == EOF ? EOF : 1);
}
@@ -190,7 +223,7 @@ readrec_forward(FILE *f, struct acctv2 *av2)
* or EOF on error.
*/
int
-readrec_backward(FILE *f, struct acctv2 *av2)
+readrec_backward(FILE *f, struct acctv3 *av3)
{
off_t pos;
int c;
@@ -200,17 +233,20 @@ readrec_backward(FILE *f, struct acctv2 *av2)
return (EOF);
if (pos == 0)
return (0);
- if (fseek(f, -roffsetof(struct acctv2, ac_trailer),
+ if (fseek(f, -roffsetof(struct acctv3, ac_trailer),
SEEK_CUR) == EOF ||
(c = getc(f)) == EOF)
return (EOF);
if (c & ANVER) {
- /* New record formats. */
+ /*
+ * New record formats. For v2 and v3 offset from the
+ * end for ac_len2 should be same.
+ */
if (fseeko(f, pos - roffsetof(struct acctv2, ac_len2),
SEEK_SET) == EOF ||
fread_record(&len, sizeof(len), f) == EOF ||
fseeko(f, pos - len, SEEK_SET) == EOF ||
- readrec_vx(f, av2) == EOF ||
+ readrec_vx(f, av3) == EOF ||
fseeko(f, pos - len, SEEK_SET) == EOF)
return (EOF);
else
@@ -218,7 +254,7 @@ readrec_backward(FILE *f, struct acctv2 *av2)
} else {
/* Old record format. */
if (fseeko(f, pos - sizeof(struct acctv1), SEEK_SET) == EOF ||
- readrec_v1(f, av2) == EOF ||
+ readrec_v1(f, av3) == EOF ||
fseeko(f, pos - sizeof(struct acctv1), SEEK_SET) == EOF)
return (EOF);
else
diff --git a/usr.sbin/pstat/pstat.c b/usr.sbin/pstat/pstat.c
index 700323be8fbc..ec801822fdb2 100644
--- a/usr.sbin/pstat/pstat.c
+++ b/usr.sbin/pstat/pstat.c
@@ -255,7 +255,7 @@ ttymode_kvm(void)
/* xt.xt_pgid = ... */
/* xt.xt_sid = ... */
xt.xt_flags = tty.t_flags;
- xt.xt_dev = NODEV;
+ xt.xt_dev = (uint32_t)NODEV;
ttyprt(&xt);
tp = TAILQ_NEXT(&tty, t_list);
}
diff --git a/usr.sbin/sa/extern.h b/usr.sbin/sa/extern.h
index 70f97a7ff51b..62acf71e263a 100644
--- a/usr.sbin/sa/extern.h
+++ b/usr.sbin/sa/extern.h
@@ -79,7 +79,7 @@ int pacct_update(void);
void pacct_print(void);
/* external functions in readrec.c */
-int readrec_forward(FILE *f, struct acctv2 *av2);
+int readrec_forward(FILE *f, struct acctv3 *av2);
/* external functions in usrdb.c */
int usracct_init(void);
diff --git a/usr.sbin/sa/main.c b/usr.sbin/sa/main.c
index 64736ac340cf..d8ad5f5a912d 100644
--- a/usr.sbin/sa/main.c
+++ b/usr.sbin/sa/main.c
@@ -310,7 +310,7 @@ usage(void)
static FILE *
acct_load(const char *pn, int wr)
{
- struct acctv2 ac;
+ struct acctv3 ac;
struct cmdinfo ci;
ssize_t rv;
FILE *f;