Index: head/cddl/lib/libzfs/Makefile =================================================================== --- head/cddl/lib/libzfs/Makefile +++ head/cddl/lib/libzfs/Makefile @@ -37,6 +37,7 @@ zprop_common.c \ WARNS?= 0 +SHLIB_MAJOR= 3 CSTD= c99 CFLAGS+= -DZFS_NO_ACL CFLAGS+= -I${SRCTOP}/sbin/mount Index: head/contrib/compiler-rt/lib/sanitizer_common/sanitizer_linux.cc =================================================================== --- head/contrib/compiler-rt/lib/sanitizer_common/sanitizer_linux.cc +++ head/contrib/compiler-rt/lib/sanitizer_common/sanitizer_linux.cc @@ -223,7 +223,8 @@ 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_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_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); Index: head/contrib/compiler-rt/lib/sanitizer_common/sanitizer_platform_limits_posix.h =================================================================== --- head/contrib/compiler-rt/lib/sanitizer_common/sanitizer_platform_limits_posix.h +++ head/contrib/compiler-rt/lib/sanitizer_common/sanitizer_platform_limits_posix.h @@ -489,7 +489,8 @@ }; #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 }; Index: head/contrib/openbsm/libbsm/bsm_wrappers.c =================================================================== --- head/contrib/openbsm/libbsm/bsm_wrappers.c +++ head/contrib/openbsm/libbsm/bsm_wrappers.c @@ -264,12 +264,14 @@ 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)); } Index: head/include/dirent.h =================================================================== --- head/include/dirent.h +++ head/include/dirent.h @@ -41,6 +41,25 @@ #include #include +#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 @@ #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); Index: head/lib/libarchive/Makefile =================================================================== --- head/lib/libarchive/Makefile +++ head/lib/libarchive/Makefile @@ -11,7 +11,7 @@ # 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} Index: head/lib/libc/gen/Makefile.inc =================================================================== --- head/lib/libc/gen/Makefile.inc +++ head/lib/libc/gen/Makefile.inc @@ -148,7 +148,15 @@ 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 Index: head/lib/libc/gen/Symbol.map =================================================================== --- head/lib/libc/gen/Symbol.map +++ head/lib/libc/gen/Symbol.map @@ -75,8 +75,6 @@ ctermid; ctermid_r; daemon; - devname; - devname_r; getdiskbyname; dladdr; dlclose; @@ -128,9 +126,6 @@ setfsent; endfsent; ftok; - ftw; - glob; - globfree; getbootfile; getbsize; cgetset; @@ -163,7 +158,6 @@ getloadavg; getlogin; getlogin_r; - getmntinfo; setnetgrent; getnetgrent; endnetgrent; @@ -209,7 +203,6 @@ lrand48; modf; mrand48; - nftw; nice; nlist; nrand48; @@ -220,13 +213,9 @@ pclose; psignal; raise; - readdir; - readdir_r; readpassphrase; getpass; rewinddir; - scandir; - alphasort; seed48; seekdir; user_from_uid; @@ -314,14 +303,6 @@ 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 @@ 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; }; Index: head/lib/libc/gen/closedir.c =================================================================== --- head/lib/libc/gen/closedir.c +++ head/lib/libc/gen/closedir.c @@ -59,6 +59,7 @@ 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); Index: head/lib/libc/gen/devname-compat11.c =================================================================== --- head/lib/libc/gen/devname-compat11.c +++ head/lib/libc/gen/devname-compat11.c @@ -0,0 +1,50 @@ +/*- + * Copyright (c) 2011 Gleb Kurtsou + * 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 +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#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); Index: head/lib/libc/gen/fts-compat.h =================================================================== --- head/lib/libc/gen/fts-compat.h +++ head/lib/libc/gen/fts-compat.h @@ -37,7 +37,7 @@ 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 @@ 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 @@ #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; Index: head/lib/libc/gen/fts-compat.c =================================================================== --- head/lib/libc/gen/fts-compat.c +++ head/lib/libc/gen/fts-compat.c @@ -40,15 +40,19 @@ #include "namespace.h" #include +#define _WANT_FREEBSD11_STATFS #include +#define _WANT_FREEBSD11_STAT #include +#define _WANT_FREEBSD11_DIRENT #include #include #include #include #include #include +#include "gen-compat.h" #include "fts-compat.h" #include "un-namespace.h" @@ -96,8 +100,8 @@ */ 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 @@ 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 @@ /* 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 @@ 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 @@ * 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 @@ struct ftsent_withstat { FTSENT ent; - struct stat statbuf; + struct freebsd11_stat statbuf; }; /* @@ -1145,14 +1150,14 @@ 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 @@ * 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++) { Index: head/lib/libc/gen/fts-compat11.h =================================================================== --- head/lib/libc/gen/fts-compat11.h +++ head/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_ */ Index: head/lib/libc/gen/fts-compat11.c =================================================================== --- head/lib/libc/gen/fts-compat11.c +++ head/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 +__FBSDID("$FreeBSD$"); + +#include "namespace.h" +#include +#define _WANT_FREEBSD11_STATFS +#include +#define _WANT_FREEBSD11_STAT +#include + +#define _WANT_FREEBSD11_DIRENT +#include +#include +#include +#include +#include +#include +#include +#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); Index: head/lib/libc/gen/ftw-compat11.c =================================================================== --- head/lib/libc/gen/ftw-compat11.c +++ head/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 + * + * 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 +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include + +#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); Index: head/lib/libc/gen/gen-compat.h =================================================================== --- head/lib/libc/gen/gen-compat.h +++ head/lib/libc/gen/gen-compat.h @@ -0,0 +1,57 @@ +/*- + * Copyright (c) 2012 Gleb Kurtsou + * 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 + +#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_ */ Index: head/lib/libc/gen/gen-private.h =================================================================== --- head/lib/libc/gen/gen-private.h +++ head/lib/libc/gen/gen-private.h @@ -47,12 +47,16 @@ 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_ */ Index: head/lib/libc/gen/getmntinfo-compat11.c =================================================================== --- head/lib/libc/gen/getmntinfo-compat11.c +++ head/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 +__FBSDID("$FreeBSD$"); + +#include +#include +#define _WANT_FREEBSD11_STATFS +#include +#include +#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); Index: head/lib/libc/gen/glob-compat11.h =================================================================== --- head/lib/libc/gen/glob-compat11.h +++ head/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 +#include +#include + +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_ */ Index: head/lib/libc/gen/glob-compat11.c =================================================================== --- head/lib/libc/gen/glob-compat11.c +++ head/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 +__FBSDID("$FreeBSD$"); + +#include +#define _WANT_FREEBSD11_STAT +#include + +#include +#define _WANT_FREEBSD11_DIRENT +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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); Index: head/lib/libc/gen/nftw-compat11.c =================================================================== --- head/lib/libc/gen/nftw-compat11.c +++ head/lib/libc/gen/nftw-compat11.c @@ -0,0 +1,115 @@ +/* + * Copyright (c) 2003, 2004 Todd C. Miller + * + * 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 +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include + +#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); Index: head/lib/libc/gen/opendir.c =================================================================== --- head/lib/libc/gen/opendir.c +++ head/lib/libc/gen/opendir.c @@ -296,6 +296,7 @@ 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. Index: head/lib/libc/gen/readdir-compat11.c =================================================================== --- head/lib/libc/gen/readdir-compat11.c +++ head/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 +__FBSDID("$FreeBSD$"); + +#include "namespace.h" +#include +#define _WANT_FREEBSD11_DIRENT +#include +#include +#include +#include +#include +#include +#include +#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); Index: head/lib/libc/gen/readdir.c =================================================================== --- head/lib/libc/gen/readdir.c +++ head/lib/libc/gen/readdir.c @@ -49,7 +49,7 @@ * 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 @@ 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 @@ 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 @@ return (0); } + +__strong_reference(__readdir_r, readdir_r); Index: head/lib/libc/gen/scandir-compat11.c =================================================================== --- head/lib/libc/gen/scandir-compat11.c +++ head/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 +__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 +#include +#include +#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); Index: head/lib/libc/gen/scandir.c =================================================================== --- head/lib/libc/gen/scandir.c +++ head/lib/libc/gen/scandir.c @@ -59,17 +59,6 @@ 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 @@ /* * 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; Index: head/lib/libc/gen/telldir.h =================================================================== --- head/lib/libc/gen/telldir.h +++ head/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 */ }; @@ -65,5 +65,8 @@ 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 Index: head/lib/libc/include/compat.h =================================================================== --- head/lib/libc/include/compat.h +++ head/lib/libc/include/compat.h @@ -44,6 +44,27 @@ __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) \ Index: head/lib/libc/include/libc_private.h =================================================================== --- head/lib/libc/include/libc_private.h +++ head/lib/libc/include/libc_private.h @@ -307,6 +307,7 @@ struct rusage; struct sigaction; struct sockaddr; +struct stat; struct timespec; struct timeval; struct timezone; @@ -323,8 +324,10 @@ 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); Index: head/lib/libc/sys/Makefile.inc =================================================================== --- head/lib/libc/sys/Makefile.inc +++ head/lib/libc/sys/Makefile.inc @@ -35,6 +35,8 @@ __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 Index: head/lib/libc/sys/Symbol.map =================================================================== --- head/lib/libc/sys/Symbol.map +++ head/lib/libc/sys/Symbol.map @@ -85,26 +85,19 @@ 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 @@ link; lio_listio; listen; - lstat; lutimes; mac_syscall; madvise; @@ -171,7 +163,6 @@ minherit; mkdir; mkfifo; - mknod; mlock; mlockall; modfind; @@ -192,10 +183,7 @@ netbsd_lchown; netbsd_msync; nfssvc; - nfstat; - nlstat; nmount; - nstat; ntp_adjtime; ntp_gettime; open; @@ -275,8 +263,6 @@ sigwaitinfo; socket; socketpair; - stat; - statfs; swapoff; swapon; symlink; @@ -330,7 +316,6 @@ fchmodat; fchownat; fexecve; - fstatat; futimesat; jail_get; jail_set; @@ -339,7 +324,6 @@ lpathconf; mkdirat; mkfifoat; - mknodat; msgctl; readlinkat; renameat; @@ -401,6 +385,19 @@ 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 @@ __sys_getauid; _getcontext; __sys_getcontext; - _getdents; - __sys_getdents; _getdirentries; __sys_getdirentries; _getdtablesize; @@ -736,8 +731,6 @@ __sys_lio_listio; _listen; __sys_listen; - _lstat; - __sys_lstat; _lutimes; __sys_lutimes; _mac_syscall; @@ -796,14 +789,8 @@ __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 @@ __sys_socket; _socketpair; __sys_socketpair; - _stat; - __sys_stat; _statfs; __sys_statfs; _swapcontext; Index: head/lib/libc/sys/getdents.c =================================================================== --- head/lib/libc/sys/getdents.c +++ head/lib/libc/sys/getdents.c @@ -0,0 +1,41 @@ +/*- + * Copyright (c) 2012 Gleb Kurtsou + * 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 +__FBSDID("$FreeBSD$"); + +#include "namespace.h" +#include +#include +#include +#include "libc_private.h" + +ssize_t +getdents(int fd, char *buf, size_t nbytes) +{ + + return (__sys_getdirentries(fd, buf, nbytes, NULL)); +} Index: head/lib/libc/sys/getdirentries.2 =================================================================== --- head/lib/libc/sys/getdirentries.2 +++ head/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 Index: head/lib/libc/sys/lstat.c =================================================================== --- head/lib/libc/sys/lstat.c +++ head/lib/libc/sys/lstat.c @@ -0,0 +1,43 @@ +/*- + * Copyright (c) 2012 Gleb Kurtsou + * 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 +__FBSDID("$FreeBSD$"); + +#include "namespace.h" +#include +#include +#include +#include +#include +#include "libc_private.h" + +int +lstat(const char *path, struct stat *sb) +{ + + return (__sys_fstatat(AT_FDCWD, path, sb, AT_SYMLINK_NOFOLLOW)); +} Index: head/lib/libc/sys/mknod.c =================================================================== --- head/lib/libc/sys/mknod.c +++ head/lib/libc/sys/mknod.c @@ -0,0 +1,45 @@ +/*- + * Copyright (c) 2011 Gleb Kurtsou + * 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 +__FBSDID("$FreeBSD$"); + +#include "namespace.h" +#include +#include +#include +#include +#include +#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)); +} Index: head/lib/libc/sys/stat.c =================================================================== --- head/lib/libc/sys/stat.c +++ head/lib/libc/sys/stat.c @@ -0,0 +1,43 @@ +/*- + * Copyright (c) 2012 Gleb Kurtsou + * 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 +__FBSDID("$FreeBSD$"); + +#include "namespace.h" +#include +#include +#include +#include +#include +#include "libc_private.h" + +int +stat(const char *path, struct stat *sb) +{ + + return (__sys_fstatat(AT_FDCWD, path, sb, 0)); +} Index: head/lib/libc/sys/statfs.2 =================================================================== --- head/lib/libc/sys/statfs.2 +++ head/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 @@ */ #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 */ Index: head/lib/libkvm/kvm_proc.c =================================================================== --- head/lib/libkvm/kvm_proc.c +++ head/lib/libkvm/kvm_proc.c @@ -452,6 +452,7 @@ } else { kp->ki_stat = SZOMB; } + kp->ki_tdev_freebsd11 = kp->ki_tdev; /* truncate */ bcopy(&kinfo_proc, bp, sizeof(kinfo_proc)); ++bp; ++cnt; Index: head/lib/libmilter/Makefile =================================================================== --- head/lib/libmilter/Makefile +++ head/lib/libmilter/Makefile @@ -29,6 +29,7 @@ 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} Index: head/lib/libprocstat/Makefile =================================================================== --- head/lib/libprocstat/Makefile +++ head/lib/libprocstat/Makefile @@ -13,6 +13,10 @@ smbfs.c \ udf.c +.if ${MK_SYMVER} == yes +SRCS+= libprocstat_compat.c +.endif + VERSION_DEF= ${LIBCSRCDIR}/Versions.def SYMBOL_MAPS= ${.CURDIR}/Symbol.map Index: head/lib/libprocstat/Symbol.map =================================================================== --- head/lib/libprocstat/Symbol.map +++ head/lib/libprocstat/Symbol.map @@ -6,9 +6,7 @@ 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 @@ 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.5 { procstat_freeptlwpinfo; procstat_getptlwpinfo; + procstat_get_pts_info; + procstat_get_sem_info; + procstat_get_shm_info; + procstat_get_vnode_info; }; Index: head/lib/libprocstat/libprocstat.h =================================================================== --- head/lib/libprocstat/libprocstat.h +++ head/lib/libprocstat/libprocstat.h @@ -120,15 +120,15 @@ 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 { Index: head/lib/libprocstat/libprocstat.c =================================================================== --- head/lib/libprocstat/libprocstat.c +++ head/lib/libprocstat/libprocstat.c @@ -1337,12 +1337,12 @@ 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 @@ 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. Index: head/lib/libprocstat/libprocstat_compat.c =================================================================== --- head/lib/libprocstat/libprocstat_compat.c +++ head/lib/libprocstat/libprocstat_compat.c @@ -0,0 +1,144 @@ +/*- + * Copyright (c) 2014 Gleb Kurtsou + * 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 +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include + +#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); Index: head/lib/libufs/libufs.h =================================================================== --- head/lib/libufs/libufs.h +++ head/lib/libufs/libufs.h @@ -45,8 +45,8 @@ 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]; Index: head/sbin/badsect/badsect.c =================================================================== --- head/sbin/badsect/badsect.c +++ head/sbin/badsect/badsect.c @@ -129,19 +129,8 @@ 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++; } Index: head/sbin/fsck_ffs/suj.c =================================================================== --- head/sbin/fsck_ffs/suj.c +++ head/sbin/fsck_ffs/suj.c @@ -1347,8 +1347,8 @@ 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 @@ 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; Index: head/share/man/man5/acct.5 =================================================================== --- head/share/man/man5/acct.5 +++ head/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 @@ #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 @@ 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 */ Index: head/share/man/man5/dir.5 =================================================================== --- head/share/man/man5/dir.5 +++ head/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 @@ * 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 @@ /* * 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) Index: head/sys/bsm/audit.h =================================================================== --- head/sys/bsm/audit.h +++ head/sys/bsm/audit.h @@ -183,13 +183,13 @@ 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]; }; Index: head/sys/cddl/compat/opensolaris/sys/dirent.h =================================================================== --- head/sys/cddl/compat/opensolaris/sys/dirent.h +++ head/sys/cddl/compat/opensolaris/sys/dirent.h @@ -40,8 +40,6 @@ #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_ */ Index: head/sys/compat/freebsd32/capabilities.conf =================================================================== --- head/sys/compat/freebsd32/capabilities.conf +++ head/sys/compat/freebsd32/capabilities.conf @@ -94,6 +94,11 @@ 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 Index: head/sys/compat/freebsd32/freebsd32.h =================================================================== --- head/sys/compat/freebsd32/freebsd32.h +++ head/sys/compat/freebsd32/freebsd32.h @@ -107,7 +107,8 @@ 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 @@ 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,21 +160,58 @@ 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; - nlink_t st_nlink; + u_int16_t st_padding0; uid_t st_uid; gid_t st_gid; - dev_t st_rdev; + 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; + u_int16_t st_nlink; + uid_t st_uid; + gid_t st_gid; + u_int32_t st_rdev; + struct timespec32 st_atim; + struct timespec32 st_mtim; + struct timespec32 st_ctim; + off_t st_size; + int64_t st_blocks; + u_int32_t st_blksize; + u_int32_t st_flags; u_int32_t st_gen; int32_t st_lspare; struct timespec32 st_birthtim; @@ -183,9 +221,9 @@ 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 @@ 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 @@ 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; Index: head/sys/compat/freebsd32/freebsd32_misc.c =================================================================== --- head/sys/compat/freebsd32/freebsd32_misc.c +++ head/sys/compat/freebsd32/freebsd32_misc.c @@ -122,8 +122,11 @@ 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,7 +451,27 @@ 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) { int prot; @@ -1519,7 +1542,41 @@ } #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 @@ 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 @@ } #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,36 +1866,154 @@ 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 Index: head/sys/compat/freebsd32/syscalls.master =================================================================== --- head/sys/compat/freebsd32/syscalls.master +++ head/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, \ +396 AUE_STATFS COMPAT11|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, \ - 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); } Index: head/sys/compat/linux/linux_file.c =================================================================== --- head/sys/compat/linux/linux_file.c +++ head/sys/compat/linux/linux_file.c @@ -328,7 +328,7 @@ 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 @@ 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 @@ 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 @@ 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 @@ "fspath", mntonname, "from", mntfromname, NULL); +out: + free(mntonname, M_TEMP); + free(mntfromname, M_TEMP); return (error); } Index: head/sys/dev/snp/snp.c =================================================================== --- head/sys/dev/snp/snp.c +++ head/sys/dev/snp/snp.c @@ -60,6 +60,8 @@ #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 @@ -274,6 +276,12 @@ *(dev_t *)data = NODEV; 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; Index: head/sys/fs/devfs/devfs_devs.c =================================================================== --- head/sys/fs/devfs/devfs_devs.c +++ head/sys/fs/devfs/devfs_devs.c @@ -28,6 +28,8 @@ * $FreeBSD$ */ +#include "opt_compat.h" + #include #include #include @@ -80,10 +82,20 @@ { 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) Index: head/sys/fs/devfs/devfs_vnops.c =================================================================== --- head/sys/fs/devfs/devfs_vnops.c +++ head/sys/fs/devfs/devfs_vnops.c @@ -1315,6 +1315,7 @@ 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; Index: head/sys/fs/fdescfs/fdesc_vnops.c =================================================================== --- head/sys/fs/fdescfs/fdesc_vnops.c +++ head/sys/fs/fdescfs/fdesc_vnops.c @@ -485,7 +485,7 @@ 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) Index: head/sys/fs/nandfs/nandfs_fs.h =================================================================== --- head/sys/fs/nandfs/nandfs_fs.h +++ head/sys/fs/nandfs/nandfs_fs.h @@ -537,7 +537,7 @@ #ifndef _KERNEL #ifndef MNAMELEN -#define MNAMELEN 88 +#define MNAMELEN 1024 #endif #endif Index: head/sys/fs/nfs/nfsport.h =================================================================== --- head/sys/fs/nfs/nfsport.h +++ head/sys/fs/nfs/nfsport.h @@ -730,12 +730,6 @@ #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" Index: head/sys/fs/nfsclient/nfs_clrpcops.c =================================================================== --- head/sys/fs/nfsclient/nfs_clrpcops.c +++ head/sys/fs/nfsclient/nfs_clrpcops.c @@ -72,7 +72,7 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ /* * 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 @@ 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 @@ 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 @@ 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 @@ 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) Index: head/sys/fs/nfsclient/nfs_clvnops.c =================================================================== --- head/sys/fs/nfsclient/nfs_clvnops.c +++ head/sys/fs/nfsclient/nfs_clvnops.c @@ -207,8 +207,6 @@ /* * Global variables */ -#define DIRHDSIZ (sizeof (struct dirent) - (MAXNAMLEN + 1)) - SYSCTL_DECL(_vfs_nfs); static int nfsaccess_cache_timeout = NFS_MAXATTRTIMO; Index: head/sys/fs/nfsserver/nfs_nfsdport.c =================================================================== --- head/sys/fs/nfsserver/nfs_nfsdport.c +++ head/sys/fs/nfsserver/nfs_nfsdport.c @@ -2020,18 +2020,26 @@ } /* - * 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; + 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); + } - cn.cn_nameiop = LOOKUP; - cn.cn_lkflags = LK_SHARED | LK_RETRY; - cn.cn_cred = nd->nd_cred; - cn.cn_thread = p; - /* * Save this position, in case there is an error before one entry * is created. @@ -2099,7 +2107,16 @@ 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 | Index: head/sys/kern/capabilities.conf =================================================================== --- head/sys/kern/capabilities.conf +++ head/sys/kern/capabilities.conf @@ -197,6 +197,11 @@ ## 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 Index: head/sys/kern/kern_acct.c =================================================================== --- head/sys/kern/kern_acct.c +++ head/sys/kern/kern_acct.c @@ -96,6 +96,11 @@ #include +_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 @@ 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 @@ /* 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); /* Index: head/sys/kern/kern_descrip.c =================================================================== --- head/sys/kern/kern_descrip.c +++ head/sys/kern/kern_descrip.c @@ -1304,6 +1304,23 @@ } #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 @@ 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 @@ 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 @@ 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 @@ 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 Index: head/sys/kern/kern_proc.c =================================================================== --- head/sys/kern/kern_proc.c +++ head/sys/kern/kern_proc.c @@ -986,11 +986,14 @@ } 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 @@ 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 @@ 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 @@ 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); Index: head/sys/kern/makesyscalls.sh =================================================================== --- head/sys/kern/makesyscalls.sh +++ head/sys/kern/makesyscalls.sh @@ -10,6 +10,7 @@ compat6=COMPAT_FREEBSD6 compat7=COMPAT_FREEBSD7 compat10=COMPAT_FREEBSD10 +compat11=COMPAT_FREEBSD11 # output files: sysnames="syscalls.c" @@ -36,6 +37,8 @@ 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 @@ 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 " 1>&2 @@ -92,6 +95,8 @@ syscompat7dcl = \"$syscompat7dcl\" syscompat10 = \"$syscompat10\" syscompat10dcl = \"$syscompat10dcl\" + syscompat11 = \"$syscompat11\" + syscompat11dcl = \"$syscompat11dcl\" sysent = \"$sysent\" syssw = \"$syssw\" sysinc = \"$sysinc\" @@ -107,6 +112,7 @@ compat6 = \"$compat6\" compat7 = \"$compat7\" compat10 = \"$compat10\" + compat11 = \"$compat11\" syscallprefix = \"$syscallprefix\" switchname = \"$switchname\" namesname = \"$namesname\" @@ -155,6 +161,7 @@ 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 @@ print > syscompat6 print > syscompat7 print > syscompat10 + print > syscompat11 print > sysnames print > systrace print > systracetmp @@ -221,6 +229,7 @@ print > syscompat6 print > syscompat7 print > syscompat10 + print > syscompat11 print > sysnames print > systrace print > systracetmp @@ -237,6 +246,7 @@ print > syscompat6 print > syscompat7 print > syscompat10 + print > syscompat11 print > sysnames print > systrace print > systracetmp @@ -345,6 +355,8 @@ argalias = "freebsd7_" argalias if (flag("COMPAT10")) argalias = "freebsd10_" argalias + if (flag("COMPAT11")) + argalias = "freebsd11_" argalias } f++ @@ -497,7 +509,7 @@ 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 @@ 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 @@ 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 @@ 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 @@ $syscompat6 $syscompat6dcl \ $syscompat7 $syscompat7dcl \ $syscompat10 $syscompat10dcl \ + $syscompat11 $syscompat11dcl \ $sysaue $sysprotoend > $sysproto cat $systracetmp >> $systrace cat $systraceret >> $systrace Index: head/sys/kern/sys_socket.c =================================================================== --- head/sys/kern/sys_socket.c +++ head/sys/kern/sys_socket.c @@ -346,14 +346,15 @@ 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 @@ 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, Index: head/sys/kern/syscalls.master =================================================================== --- head/sys/kern/syscalls.master +++ head/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 Index: head/sys/kern/tty.c =================================================================== --- head/sys/kern/tty.c +++ head/sys/kern/tty.c @@ -1205,7 +1205,7 @@ 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 Index: head/sys/kern/tty_pts.c =================================================================== --- head/sys/kern/tty_pts.c +++ head/sys/kern/tty_pts.c @@ -592,6 +592,8 @@ 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); } Index: head/sys/kern/vfs_syscalls.c =================================================================== --- head/sys/kern/vfs_syscalls.c +++ head/sys/kern/vfs_syscalls.c @@ -525,7 +525,7 @@ /* * 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ * 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,7 +681,139 @@ } #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. */ #ifndef _SYS_SYSPROTO_H_ @@ -1060,39 +1193,44 @@ * 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 @@ } #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 @@ 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 @@ return (0); } +#if defined(COMPAT_FREEBSD11) /* - * 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); -} - -/* * 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 @@ } #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 @@ &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 @@ * 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 @@ 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 @@ 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 @@ 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 @@ }; #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; @@ -3757,25 +3956,6 @@ foffset_unlock(fp, foffset, 0); fdrop(fp, td); 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)); } /* Index: head/sys/kern/vfs_vnops.c =================================================================== --- head/sys/kern/vfs_vnops.c +++ head/sys/kern/vfs_vnops.c @@ -2340,7 +2340,7 @@ 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 @@ 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); } Index: head/sys/nlm/nlm_advlock.c =================================================================== --- head/sys/nlm/nlm_advlock.c +++ head/sys/nlm/nlm_advlock.c @@ -202,7 +202,7 @@ 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 @@ 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 @@ AUTH_DESTROY(auth); nlm_host_release(host); - + free(servername, M_TEMP); return (error); } Index: head/sys/security/audit/audit_private.h =================================================================== --- head/sys/security/audit/audit_private.h +++ head/sys/security/audit/audit_private.h @@ -107,9 +107,9 @@ 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 @@ 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; Index: head/sys/sys/_types.h =================================================================== --- head/sys/sys/_types.h +++ head/sys/sys/_types.h @@ -43,13 +43,13 @@ 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 @@ 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 */ Index: head/sys/sys/acct.h =================================================================== --- head/sys/sys/acct.h +++ head/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 @@ 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,7 +87,29 @@ #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). * The first byte is always non-zero. @@ -105,7 +130,7 @@ 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 */ }; Index: head/sys/sys/dirent.h =================================================================== --- head/sys/sys/dirent.h +++ head/sys/sys/dirent.h @@ -36,22 +36,39 @@ #include #include +#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 @@ #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 @@ * 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 Index: head/sys/sys/mount.h =================================================================== --- head/sys/sys/mount.h +++ head/sys/sys/mount.h @@ -65,8 +65,8 @@ * 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 */ @@ -91,6 +91,34 @@ char f_mntfromname[MNAMELEN]; /* mounted filesystem */ 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 */ Index: head/sys/sys/param.h =================================================================== --- head/sys/sys/param.h +++ head/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, Index: head/sys/sys/stat.h =================================================================== --- head/sys/sys/stat.h +++ head/sys/sys/stat.h @@ -102,9 +102,9 @@ #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 @@ }; #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 @@ 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 @@ __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)); Index: head/sys/sys/syscallsubr.h =================================================================== --- head/sys/sys/syscallsubr.h +++ head/sys/sys/syscallsubr.h @@ -117,8 +117,8 @@ 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_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, @@ -291,5 +291,10 @@ /* flags for kern_sigaction */ #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_ */ Index: head/sys/sys/tty.h =================================================================== --- head/sys/sys/tty.h +++ head/sys/sys/tty.h @@ -148,7 +148,7 @@ 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 Index: head/sys/sys/user.h =================================================================== --- head/sys/sys/user.h +++ head/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 @@ 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 @@ */ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ /* 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 @@ 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 @@ 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 @@ 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 @@ 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. */ }; Index: head/sys/sys/vnode.h =================================================================== --- head/sys/sys/vnode.h +++ head/sys/sys/vnode.h @@ -266,11 +266,12 @@ 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 mount; struct nameidata; struct ostat; +struct freebsd11_stat; struct thread; struct proc; struct stat; @@ -613,7 +615,8 @@ 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); Index: head/sys/vm/swap_pager.c =================================================================== --- head/sys/vm/swap_pager.c +++ head/sys/vm/swap_pager.c @@ -69,6 +69,7 @@ #include __FBSDID("$FreeBSD$"); +#include "opt_compat.h" #include "opt_swap.h" #include "opt_vm.h" @@ -2417,10 +2418,24 @@ 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 @@ 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); } Index: head/sys/vm/vm_object.c =================================================================== --- head/sys/vm/vm_object.c +++ head/sys/vm/vm_object.c @@ -2342,6 +2342,7 @@ 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 @@ 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); } Index: head/sys/vm/vm_param.h =================================================================== --- head/sys/vm/vm_param.h +++ head/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; Index: head/usr.bin/kdump/kdump.c =================================================================== --- head/usr.bin/kdump/kdump.c +++ head/usr.bin/kdump/kdump.c @@ -932,7 +932,6 @@ ip++; narg--; break; - case SYS_mknod: case SYS_mknodat: print_number(ip, narg, c); putchar(','); Index: head/usr.bin/lastcomm/lastcomm.c =================================================================== --- head/usr.bin/lastcomm/lastcomm.c +++ head/usr.bin/lastcomm/lastcomm.c @@ -61,9 +61,9 @@ 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 @@ 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 @@ } int -requested(char *argv[], struct acctv2 *acp) +requested(char *argv[], struct acctv3 *acp) { const char *p; Index: head/usr.bin/lastcomm/readrec.c =================================================================== --- head/usr.bin/lastcomm/readrec.c +++ head/usr.bin/lastcomm/readrec.c @@ -38,8 +38,8 @@ #include #include -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 @@ * 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,19 +120,50 @@ * 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)); +} + +/* * Read a new-style (post-v1) accounting record stored at * the current position of stream f. * Convert the data to the current record format. * 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 @@ 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 @@ * 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 @@ 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 @@ * 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 @@ 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 @@ } 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 Index: head/usr.sbin/pstat/pstat.c =================================================================== --- head/usr.sbin/pstat/pstat.c +++ head/usr.sbin/pstat/pstat.c @@ -255,7 +255,7 @@ /* 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); } Index: head/usr.sbin/sa/extern.h =================================================================== --- head/usr.sbin/sa/extern.h +++ head/usr.sbin/sa/extern.h @@ -79,7 +79,7 @@ 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); Index: head/usr.sbin/sa/main.c =================================================================== --- head/usr.sbin/sa/main.c +++ head/usr.sbin/sa/main.c @@ -310,7 +310,7 @@ static FILE * acct_load(const char *pn, int wr) { - struct acctv2 ac; + struct acctv3 ac; struct cmdinfo ci; ssize_t rv; FILE *f;