diff options
Diffstat (limited to 'lib')
40 files changed, 3612 insertions, 119 deletions
diff --git a/lib/libarchive/Makefile b/lib/libarchive/Makefile index 53d4cc994183..646ee28f6c94 100644 --- a/lib/libarchive/Makefile +++ b/lib/libarchive/Makefile @@ -11,7 +11,7 @@ CFLAGS+= -DHAVE_BZLIB_H=1 -DHAVE_LIBLZMA=1 -DHAVE_LZMA_H=1 # FreeBSD SHLIB_MAJOR value is managed as part of the FreeBSD system. # It has no real relation to the libarchive version number. -SHLIB_MAJOR= 6 +SHLIB_MAJOR= 7 CFLAGS+= -DPLATFORM_CONFIG_H=\"${.CURDIR}/config_freebsd.h\" CFLAGS+= -I${.OBJDIR} diff --git a/lib/libc/gen/Makefile.inc b/lib/libc/gen/Makefile.inc index ac6e077207a8..b8a969276c5e 100644 --- a/lib/libc/gen/Makefile.inc +++ b/lib/libc/gen/Makefile.inc @@ -148,7 +148,15 @@ SRCS+= __getosreldate.c \ waitid.c \ wordexp.c .if ${MK_SYMVER} == yes -SRCS+= fts-compat.c \ +SRCS+= devname-compat11.c \ + fts-compat.c \ + fts-compat11.c \ + ftw-compat11.c \ + getmntinfo-compat11.c \ + glob-compat11.c \ + nftw-compat11.c \ + readdir-compat11.c \ + scandir-compat11.c \ unvis-compat.c .endif diff --git a/lib/libc/gen/Symbol.map b/lib/libc/gen/Symbol.map index bada246e0b3c..3108f822b675 100644 --- a/lib/libc/gen/Symbol.map +++ b/lib/libc/gen/Symbol.map @@ -75,8 +75,6 @@ FBSD_1.0 { ctermid; ctermid_r; daemon; - devname; - devname_r; getdiskbyname; dladdr; dlclose; @@ -128,9 +126,6 @@ FBSD_1.0 { setfsent; endfsent; ftok; - ftw; - glob; - globfree; getbootfile; getbsize; cgetset; @@ -163,7 +158,6 @@ FBSD_1.0 { getloadavg; getlogin; getlogin_r; - getmntinfo; setnetgrent; getnetgrent; endnetgrent; @@ -209,7 +203,6 @@ FBSD_1.0 { lrand48; modf; mrand48; - nftw; nice; nlist; nrand48; @@ -220,13 +213,9 @@ FBSD_1.0 { pclose; psignal; raise; - readdir; - readdir_r; readpassphrase; getpass; rewinddir; - scandir; - alphasort; seed48; seekdir; user_from_uid; @@ -314,14 +303,6 @@ FBSD_1.1 { fdevname_r; fdopendir; feature_present; - fts_children; - fts_close; - fts_get_clientptr; - fts_get_stream; - fts_open; - fts_read; - fts_set; - fts_set_clientptr; posix_spawn; posix_spawn_file_actions_addclose; posix_spawn_file_actions_adddup2; @@ -408,13 +389,32 @@ FBSD_1.4 { pthread_mutex_consistent; pthread_mutexattr_getrobust; pthread_mutexattr_setrobust; - scandir_b; stravis; }; FBSD_1.5 { + alphasort; basename; + devname; + devname_r; dirname; + fts_children; + fts_close; + fts_get_clientptr; + fts_get_stream; + fts_open; + fts_read; + fts_set; + fts_set_clientptr; + ftw; + getmntinfo; + glob; + globfree; + nftw; + readdir; + readdir_r; + scandir; + scandir_b; sem_clockwait_np; }; diff --git a/lib/libc/gen/closedir.c b/lib/libc/gen/closedir.c index afdab45f6c49..098bc1959eb0 100644 --- a/lib/libc/gen/closedir.c +++ b/lib/libc/gen/closedir.c @@ -59,6 +59,7 @@ fdclosedir(DIR *dirp) dirp->dd_fd = -1; dirp->dd_loc = 0; free((void *)dirp->dd_buf); + free(dirp->dd_compat_de); _reclaim_telldir(dirp); if (__isthreaded) { _pthread_mutex_unlock(&dirp->dd_lock); diff --git a/lib/libc/gen/devname-compat11.c b/lib/libc/gen/devname-compat11.c new file mode 100644 index 000000000000..70cb6f0d641e --- /dev/null +++ b/lib/libc/gen/devname-compat11.c @@ -0,0 +1,50 @@ +/*- + * Copyright (c) 2011 Gleb Kurtsou <gleb@FreeBSD.org> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <sys/types.h> +#include <sys/stat.h> +#include <stdlib.h> +#include "gen-compat.h" + +char * +freebsd11_devname(uint32_t dev, mode_t type) +{ + + return (devname(dev, type)); +} + +char * +freebsd11_devname_r(uint32_t dev, mode_t type, char *buf, int len) +{ + + return (devname_r(dev, type, buf, len)); +} + +__sym_compat(devname, freebsd11_devname, FBSD_1.0); +__sym_compat(devname_r, freebsd11_devname_r, FBSD_1.0); diff --git a/lib/libc/gen/fts-compat.c b/lib/libc/gen/fts-compat.c index 64a73e9ea28a..0415a59ec212 100644 --- a/lib/libc/gen/fts-compat.c +++ b/lib/libc/gen/fts-compat.c @@ -40,15 +40,19 @@ __FBSDID("$FreeBSD$"); #include "namespace.h" #include <sys/param.h> +#define _WANT_FREEBSD11_STATFS #include <sys/mount.h> +#define _WANT_FREEBSD11_STAT #include <sys/stat.h> +#define _WANT_FREEBSD11_DIRENT #include <dirent.h> #include <errno.h> #include <fcntl.h> #include <stdlib.h> #include <string.h> #include <unistd.h> +#include "gen-compat.h" #include "fts-compat.h" #include "un-namespace.h" @@ -96,8 +100,8 @@ static int fts_ufslinks(FTS *, const FTSENT *); */ struct _fts_private { FTS ftsp_fts; - struct statfs ftsp_statfs; - dev_t ftsp_dev; + struct freebsd11_statfs ftsp_statfs; + uint32_t ftsp_dev; int ftsp_linksreliable; }; @@ -626,7 +630,7 @@ __fts_set_clientptr_44bsd(FTS *sp, void *clientptr) static FTSENT * fts_build(FTS *sp, int type) { - struct dirent *dp; + struct freebsd11_dirent *dp; FTSENT *p, *head; int nitems; FTSENT *cur, *tail; @@ -738,7 +742,8 @@ fts_build(FTS *sp, int type) /* Read the directory, attaching each entry to the `link' pointer. */ doadjust = 0; - for (head = tail = NULL, nitems = 0; dirp && (dp = readdir(dirp));) { + for (head = tail = NULL, nitems = 0; + dirp && (dp = freebsd11_readdir(dirp));) { dnamlen = dp->d_namlen; if (!ISSET(FTS_SEEDOT) && ISDOT(dp->d_name)) continue; @@ -891,9 +896,9 @@ static u_short fts_stat(FTS *sp, FTSENT *p, int follow) { FTSENT *t; - dev_t dev; - ino_t ino; - struct stat *sbp, sb; + uint32_t dev; + uint32_t ino; + struct freebsd11_stat *sbp, sb; int saved_errno; /* If user needs stat info, stat buffer already allocated. */ @@ -916,16 +921,16 @@ fts_stat(FTS *sp, FTSENT *p, int follow) * fail, set the errno from the stat call. */ if (ISSET(FTS_LOGICAL) || follow) { - if (stat(p->fts_accpath, sbp)) { + if (freebsd11_stat(p->fts_accpath, sbp)) { saved_errno = errno; - if (!lstat(p->fts_accpath, sbp)) { + if (!freebsd11_lstat(p->fts_accpath, sbp)) { errno = 0; return (FTS_SLNONE); } p->fts_errno = saved_errno; goto err; } - } else if (lstat(p->fts_accpath, sbp)) { + } else if (freebsd11_lstat(p->fts_accpath, sbp)) { p->fts_errno = errno; err: memset(sbp, 0, sizeof(struct stat)); return (FTS_NS); @@ -1019,7 +1024,7 @@ fts_alloc(FTS *sp, char *name, int namelen) struct ftsent_withstat { FTSENT ent; - struct stat statbuf; + struct freebsd11_stat statbuf; }; /* @@ -1145,14 +1150,14 @@ static int fts_safe_changedir(FTS *sp, FTSENT *p, int fd, char *path) { int ret, oerrno, newfd; - struct stat sb; + struct freebsd11_stat sb; newfd = fd; if (ISSET(FTS_NOCHDIR)) return (0); if (fd < 0 && (newfd = _open(path, O_RDONLY | O_CLOEXEC, 0)) < 0) return (-1); - if (_fstat(newfd, &sb)) { + if (freebsd11_fstat(newfd, &sb)) { ret = -1; goto bail; } @@ -1187,7 +1192,7 @@ fts_ufslinks(FTS *sp, const FTSENT *ent) * avoidance. */ if (priv->ftsp_dev != ent->fts_dev) { - if (statfs(ent->fts_path, &priv->ftsp_statfs) != -1) { + if (freebsd11_statfs(ent->fts_path, &priv->ftsp_statfs) != -1) { priv->ftsp_dev = ent->fts_dev; priv->ftsp_linksreliable = 0; for (cpp = ufslike_filesystems; *cpp; cpp++) { diff --git a/lib/libc/gen/fts-compat.h b/lib/libc/gen/fts-compat.h index d8fe6895f11c..4c661e5cf7cc 100644 --- a/lib/libc/gen/fts-compat.h +++ b/lib/libc/gen/fts-compat.h @@ -37,7 +37,7 @@ typedef struct { struct _ftsent *fts_cur; /* current node */ struct _ftsent *fts_child; /* linked list of children */ struct _ftsent **fts_array; /* sort array */ - dev_t fts_dev; /* starting device # */ + uint32_t fts_dev; /* starting device # */ char *fts_path; /* path for this descent */ int fts_rfd; /* fd for root */ int fts_pathlen; /* sizeof(path) */ @@ -82,9 +82,9 @@ typedef struct _ftsent { u_short fts_pathlen; /* strlen(fts_path) */ u_short fts_namelen; /* strlen(fts_name) */ - ino_t fts_ino; /* inode */ - dev_t fts_dev; /* device */ - nlink_t fts_nlink; /* link count */ + uint32_t fts_ino; /* inode */ + uint32_t fts_dev; /* device */ + uint16_t fts_nlink; /* link count */ #define FTS_ROOTPARENTLEVEL -1 #define FTS_ROOTLEVEL 0 @@ -117,7 +117,7 @@ typedef struct _ftsent { #define FTS_SKIP 4 /* discard node */ u_short fts_instr; /* fts_set() instructions */ - struct stat *fts_statp; /* stat(2) information */ + struct freebsd11_stat *fts_statp; /* stat(2) information */ char *fts_name; /* file name */ FTS *fts_fts; /* back pointer to main FTS */ } FTSENT; diff --git a/lib/libc/gen/fts-compat11.c b/lib/libc/gen/fts-compat11.c new file mode 100644 index 000000000000..7653d32752f6 --- /dev/null +++ b/lib/libc/gen/fts-compat11.c @@ -0,0 +1,1199 @@ +/*- + * Copyright (c) 1990, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * from: $OpenBSD: fts.c,v 1.22 1999/10/03 19:22:22 millert Exp $ + */ + +#if 0 +#if defined(LIBC_SCCS) && !defined(lint) +static char sccsid[] = "@(#)fts.c 8.6 (Berkeley) 8/14/94"; +#endif /* LIBC_SCCS and not lint */ +#endif + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include "namespace.h" +#include <sys/param.h> +#define _WANT_FREEBSD11_STATFS +#include <sys/mount.h> +#define _WANT_FREEBSD11_STAT +#include <sys/stat.h> + +#define _WANT_FREEBSD11_DIRENT +#include <dirent.h> +#include <errno.h> +#include <fcntl.h> +#include <fts.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include "gen-compat.h" +#include "fts-compat11.h" +#include "un-namespace.h" + +#include "gen-private.h" + +static FTSENT11 *fts_alloc(FTS11 *, char *, size_t); +static FTSENT11 *fts_build(FTS11 *, int); +static void fts_lfree(FTSENT11 *); +static void fts_load(FTS11 *, FTSENT11 *); +static size_t fts_maxarglen(char * const *); +static void fts_padjust(FTS11 *, FTSENT11 *); +static int fts_palloc(FTS11 *, size_t); +static FTSENT11 *fts_sort(FTS11 *, FTSENT11 *, size_t); +static int fts_stat(FTS11 *, FTSENT11 *, int, int); +static int fts_safe_changedir(FTS11 *, FTSENT11 *, int, char *); +static int fts_ufslinks(FTS11 *, const FTSENT11 *); + +#define ISDOT(a) (a[0] == '.' && (!a[1] || (a[1] == '.' && !a[2]))) + +#define CLR(opt) (sp->fts_options &= ~(opt)) +#define ISSET(opt) (sp->fts_options & (opt)) +#define SET(opt) (sp->fts_options |= (opt)) + +#define FCHDIR(sp, fd) (!ISSET(FTS_NOCHDIR) && fchdir(fd)) + +/* fts_build flags */ +#define BCHILD 1 /* fts_children */ +#define BNAMES 2 /* fts_children, names only */ +#define BREAD 3 /* fts_read */ + +/* + * Internal representation of an FTS, including extra implementation + * details. The FTS returned from fts_open points to this structure's + * ftsp_fts member (and can be cast to an _fts_private as required) + */ +struct _fts_private11 { + FTS11 ftsp_fts; + struct freebsd11_statfs ftsp_statfs; + uint32_t ftsp_dev; + int ftsp_linksreliable; +}; + +/* + * The "FTS_NOSTAT" option can avoid a lot of calls to stat(2) if it + * knows that a directory could not possibly have subdirectories. This + * is decided by looking at the link count: a subdirectory would + * increment its parent's link count by virtue of its own ".." entry. + * This assumption only holds for UFS-like filesystems that implement + * links and directories this way, so we must punt for others. + */ + +static const char *ufslike_filesystems[] = { + "ufs", + "zfs", + "nfs", + "ext2fs", + 0 +}; + +FTS11 * +freebsd11_fts_open(char * const *argv, int options, + int (*compar)(const FTSENT11 * const *, const FTSENT11 * const *)) +{ + struct _fts_private11 *priv; + FTS11 *sp; + FTSENT11 *p, *root; + FTSENT11 *parent, *tmp; + size_t len, nitems; + + /* Options check. */ + if (options & ~FTS_OPTIONMASK) { + errno = EINVAL; + return (NULL); + } + + /* fts_open() requires at least one path */ + if (*argv == NULL) { + errno = EINVAL; + return (NULL); + } + + /* Allocate/initialize the stream. */ + if ((priv = calloc(1, sizeof(*priv))) == NULL) + return (NULL); + sp = &priv->ftsp_fts; + sp->fts_compar = compar; + sp->fts_options = options; + + /* Shush, GCC. */ + tmp = NULL; + + /* Logical walks turn on NOCHDIR; symbolic links are too hard. */ + if (ISSET(FTS_LOGICAL)) + SET(FTS_NOCHDIR); + + /* + * Start out with 1K of path space, and enough, in any case, + * to hold the user's paths. + */ + if (fts_palloc(sp, MAX(fts_maxarglen(argv), MAXPATHLEN))) + goto mem1; + + /* Allocate/initialize root's parent. */ + if ((parent = fts_alloc(sp, "", 0)) == NULL) + goto mem2; + parent->fts_level = FTS_ROOTPARENTLEVEL; + + /* Allocate/initialize root(s). */ + for (root = NULL, nitems = 0; *argv != NULL; ++argv, ++nitems) { + len = strlen(*argv); + + p = fts_alloc(sp, *argv, len); + p->fts_level = FTS_ROOTLEVEL; + p->fts_parent = parent; + p->fts_accpath = p->fts_name; + p->fts_info = fts_stat(sp, p, ISSET(FTS_COMFOLLOW), -1); + + /* Command-line "." and ".." are real directories. */ + if (p->fts_info == FTS_DOT) + p->fts_info = FTS_D; + + /* + * If comparison routine supplied, traverse in sorted + * order; otherwise traverse in the order specified. + */ + if (compar) { + p->fts_link = root; + root = p; + } else { + p->fts_link = NULL; + if (root == NULL) + tmp = root = p; + else { + tmp->fts_link = p; + tmp = p; + } + } + } + if (compar && nitems > 1) + root = fts_sort(sp, root, nitems); + + /* + * Allocate a dummy pointer and make fts_read think that we've just + * finished the node before the root(s); set p->fts_info to FTS_INIT + * so that everything about the "current" node is ignored. + */ + if ((sp->fts_cur = fts_alloc(sp, "", 0)) == NULL) + goto mem3; + sp->fts_cur->fts_link = root; + sp->fts_cur->fts_info = FTS_INIT; + + /* + * If using chdir(2), grab a file descriptor pointing to dot to ensure + * that we can get back here; this could be avoided for some paths, + * but almost certainly not worth the effort. Slashes, symbolic links, + * and ".." are all fairly nasty problems. Note, if we can't get the + * descriptor we run anyway, just more slowly. + */ + if (!ISSET(FTS_NOCHDIR) && + (sp->fts_rfd = _open(".", O_RDONLY | O_CLOEXEC, 0)) < 0) + SET(FTS_NOCHDIR); + + return (sp); + +mem3: fts_lfree(root); + free(parent); +mem2: free(sp->fts_path); +mem1: free(sp); + return (NULL); +} + +static void +fts_load(FTS11 *sp, FTSENT11 *p) +{ + size_t len; + char *cp; + + /* + * Load the stream structure for the next traversal. Since we don't + * actually enter the directory until after the preorder visit, set + * the fts_accpath field specially so the chdir gets done to the right + * place and the user can access the first node. From fts_open it's + * known that the path will fit. + */ + len = p->fts_pathlen = p->fts_namelen; + memmove(sp->fts_path, p->fts_name, len + 1); + if ((cp = strrchr(p->fts_name, '/')) && (cp != p->fts_name || cp[1])) { + len = strlen(++cp); + memmove(p->fts_name, cp, len + 1); + p->fts_namelen = len; + } + p->fts_accpath = p->fts_path = sp->fts_path; + sp->fts_dev = p->fts_dev; +} + +int +freebsd11_fts_close(FTS11 *sp) +{ + FTSENT11 *freep, *p; + int saved_errno; + + /* + * This still works if we haven't read anything -- the dummy structure + * points to the root list, so we step through to the end of the root + * list which has a valid parent pointer. + */ + if (sp->fts_cur) { + for (p = sp->fts_cur; p->fts_level >= FTS_ROOTLEVEL;) { + freep = p; + p = p->fts_link != NULL ? p->fts_link : p->fts_parent; + free(freep); + } + free(p); + } + + /* Free up child linked list, sort array, path buffer. */ + if (sp->fts_child) + fts_lfree(sp->fts_child); + if (sp->fts_array) + free(sp->fts_array); + free(sp->fts_path); + + /* Return to original directory, save errno if necessary. */ + if (!ISSET(FTS_NOCHDIR)) { + saved_errno = fchdir(sp->fts_rfd) ? errno : 0; + (void)_close(sp->fts_rfd); + + /* Set errno and return. */ + if (saved_errno != 0) { + /* Free up the stream pointer. */ + free(sp); + errno = saved_errno; + return (-1); + } + } + + /* Free up the stream pointer. */ + free(sp); + return (0); +} + +/* + * Special case of "/" at the end of the path so that slashes aren't + * appended which would cause paths to be written as "....//foo". + */ +#define NAPPEND(p) \ + (p->fts_path[p->fts_pathlen - 1] == '/' \ + ? p->fts_pathlen - 1 : p->fts_pathlen) + +FTSENT11 * +freebsd11_fts_read(FTS11 *sp) +{ + FTSENT11 *p, *tmp; + int instr; + char *t; + int saved_errno; + + /* If finished or unrecoverable error, return NULL. */ + if (sp->fts_cur == NULL || ISSET(FTS_STOP)) + return (NULL); + + /* Set current node pointer. */ + p = sp->fts_cur; + + /* Save and zero out user instructions. */ + instr = p->fts_instr; + p->fts_instr = FTS_NOINSTR; + + /* Any type of file may be re-visited; re-stat and re-turn. */ + if (instr == FTS_AGAIN) { + p->fts_info = fts_stat(sp, p, 0, -1); + return (p); + } + + /* + * Following a symlink -- SLNONE test allows application to see + * SLNONE and recover. If indirecting through a symlink, have + * keep a pointer to current location. If unable to get that + * pointer, follow fails. + */ + if (instr == FTS_FOLLOW && + (p->fts_info == FTS_SL || p->fts_info == FTS_SLNONE)) { + p->fts_info = fts_stat(sp, p, 1, -1); + if (p->fts_info == FTS_D && !ISSET(FTS_NOCHDIR)) { + if ((p->fts_symfd = _open(".", O_RDONLY | O_CLOEXEC, + 0)) < 0) { + p->fts_errno = errno; + p->fts_info = FTS_ERR; + } else + p->fts_flags |= FTS_SYMFOLLOW; + } + return (p); + } + + /* Directory in pre-order. */ + if (p->fts_info == FTS_D) { + /* If skipped or crossed mount point, do post-order visit. */ + if (instr == FTS_SKIP || + (ISSET(FTS_XDEV) && p->fts_dev != sp->fts_dev)) { + if (p->fts_flags & FTS_SYMFOLLOW) + (void)_close(p->fts_symfd); + if (sp->fts_child) { + fts_lfree(sp->fts_child); + sp->fts_child = NULL; + } + p->fts_info = FTS_DP; + return (p); + } + + /* Rebuild if only read the names and now traversing. */ + if (sp->fts_child != NULL && ISSET(FTS_NAMEONLY)) { + CLR(FTS_NAMEONLY); + fts_lfree(sp->fts_child); + sp->fts_child = NULL; + } + + /* + * Cd to the subdirectory. + * + * If have already read and now fail to chdir, whack the list + * to make the names come out right, and set the parent errno + * so the application will eventually get an error condition. + * Set the FTS_DONTCHDIR flag so that when we logically change + * directories back to the parent we don't do a chdir. + * + * If haven't read do so. If the read fails, fts_build sets + * FTS_STOP or the fts_info field of the node. + */ + if (sp->fts_child != NULL) { + if (fts_safe_changedir(sp, p, -1, p->fts_accpath)) { + p->fts_errno = errno; + p->fts_flags |= FTS_DONTCHDIR; + for (p = sp->fts_child; p != NULL; + p = p->fts_link) + p->fts_accpath = + p->fts_parent->fts_accpath; + } + } else if ((sp->fts_child = fts_build(sp, BREAD)) == NULL) { + if (ISSET(FTS_STOP)) + return (NULL); + return (p); + } + p = sp->fts_child; + sp->fts_child = NULL; + goto name; + } + + /* Move to the next node on this level. */ +next: tmp = p; + if ((p = p->fts_link) != NULL) { + /* + * If reached the top, return to the original directory (or + * the root of the tree), and load the paths for the next root. + */ + if (p->fts_level == FTS_ROOTLEVEL) { + if (FCHDIR(sp, sp->fts_rfd)) { + SET(FTS_STOP); + return (NULL); + } + free(tmp); + fts_load(sp, p); + return (sp->fts_cur = p); + } + + /* + * User may have called fts_set on the node. If skipped, + * ignore. If followed, get a file descriptor so we can + * get back if necessary. + */ + if (p->fts_instr == FTS_SKIP) { + free(tmp); + goto next; + } + if (p->fts_instr == FTS_FOLLOW) { + p->fts_info = fts_stat(sp, p, 1, -1); + if (p->fts_info == FTS_D && !ISSET(FTS_NOCHDIR)) { + if ((p->fts_symfd = + _open(".", O_RDONLY | O_CLOEXEC, 0)) < 0) { + p->fts_errno = errno; + p->fts_info = FTS_ERR; + } else + p->fts_flags |= FTS_SYMFOLLOW; + } + p->fts_instr = FTS_NOINSTR; + } + + free(tmp); + +name: t = sp->fts_path + NAPPEND(p->fts_parent); + *t++ = '/'; + memmove(t, p->fts_name, p->fts_namelen + 1); + return (sp->fts_cur = p); + } + + /* Move up to the parent node. */ + p = tmp->fts_parent; + + if (p->fts_level == FTS_ROOTPARENTLEVEL) { + /* + * Done; free everything up and set errno to 0 so the user + * can distinguish between error and EOF. + */ + free(tmp); + free(p); + errno = 0; + return (sp->fts_cur = NULL); + } + + /* NUL terminate the pathname. */ + sp->fts_path[p->fts_pathlen] = '\0'; + + /* + * Return to the parent directory. If at a root node or came through + * a symlink, go back through the file descriptor. Otherwise, cd up + * one directory. + */ + if (p->fts_level == FTS_ROOTLEVEL) { + if (FCHDIR(sp, sp->fts_rfd)) { + SET(FTS_STOP); + return (NULL); + } + } else if (p->fts_flags & FTS_SYMFOLLOW) { + if (FCHDIR(sp, p->fts_symfd)) { + saved_errno = errno; + (void)_close(p->fts_symfd); + errno = saved_errno; + SET(FTS_STOP); + return (NULL); + } + (void)_close(p->fts_symfd); + } else if (!(p->fts_flags & FTS_DONTCHDIR) && + fts_safe_changedir(sp, p->fts_parent, -1, "..")) { + SET(FTS_STOP); + return (NULL); + } + free(tmp); + p->fts_info = p->fts_errno ? FTS_ERR : FTS_DP; + return (sp->fts_cur = p); +} + +/* + * Fts_set takes the stream as an argument although it's not used in this + * implementation; it would be necessary if anyone wanted to add global + * semantics to fts using fts_set. An error return is allowed for similar + * reasons. + */ +/* ARGSUSED */ +int +freebsd11_fts_set(FTS11 *sp, FTSENT11 *p, int instr) +{ + if (instr != 0 && instr != FTS_AGAIN && instr != FTS_FOLLOW && + instr != FTS_NOINSTR && instr != FTS_SKIP) { + errno = EINVAL; + return (1); + } + p->fts_instr = instr; + return (0); +} + +FTSENT11 * +freebsd11_fts_children(FTS11 *sp, int instr) +{ + FTSENT11 *p; + int fd, rc, serrno; + + if (instr != 0 && instr != FTS_NAMEONLY) { + errno = EINVAL; + return (NULL); + } + + /* Set current node pointer. */ + p = sp->fts_cur; + + /* + * Errno set to 0 so user can distinguish empty directory from + * an error. + */ + errno = 0; + + /* Fatal errors stop here. */ + if (ISSET(FTS_STOP)) + return (NULL); + + /* Return logical hierarchy of user's arguments. */ + if (p->fts_info == FTS_INIT) + return (p->fts_link); + + /* + * If not a directory being visited in pre-order, stop here. Could + * allow FTS_DNR, assuming the user has fixed the problem, but the + * same effect is available with FTS_AGAIN. + */ + if (p->fts_info != FTS_D /* && p->fts_info != FTS_DNR */) + return (NULL); + + /* Free up any previous child list. */ + if (sp->fts_child != NULL) + fts_lfree(sp->fts_child); + + if (instr == FTS_NAMEONLY) { + SET(FTS_NAMEONLY); + instr = BNAMES; + } else + instr = BCHILD; + + /* + * If using chdir on a relative path and called BEFORE fts_read does + * its chdir to the root of a traversal, we can lose -- we need to + * chdir into the subdirectory, and we don't know where the current + * directory is, so we can't get back so that the upcoming chdir by + * fts_read will work. + */ + if (p->fts_level != FTS_ROOTLEVEL || p->fts_accpath[0] == '/' || + ISSET(FTS_NOCHDIR)) + return (sp->fts_child = fts_build(sp, instr)); + + if ((fd = _open(".", O_RDONLY | O_CLOEXEC, 0)) < 0) + return (NULL); + sp->fts_child = fts_build(sp, instr); + serrno = (sp->fts_child == NULL) ? errno : 0; + rc = fchdir(fd); + if (rc < 0 && serrno == 0) + serrno = errno; + (void)_close(fd); + errno = serrno; + if (rc < 0) + return (NULL); + return (sp->fts_child); +} + +#ifndef freebsd11_fts_get_clientptr +#error "freebsd11_fts_get_clientptr not defined" +#endif + +void * +(freebsd11_fts_get_clientptr)(FTS11 *sp) +{ + + return (freebsd11_fts_get_clientptr(sp)); +} + +#ifndef freebsd11_fts_get_stream +#error "freebsd11_fts_get_stream not defined" +#endif + +FTS11 * +(freebsd11_fts_get_stream)(FTSENT11 *p) +{ + return (freebsd11_fts_get_stream(p)); +} + +void +freebsd11_fts_set_clientptr(FTS11 *sp, void *clientptr) +{ + + sp->fts_clientptr = clientptr; +} + +/* + * This is the tricky part -- do not casually change *anything* in here. The + * idea is to build the linked list of entries that are used by fts_children + * and fts_read. There are lots of special cases. + * + * The real slowdown in walking the tree is the stat calls. If FTS_NOSTAT is + * set and it's a physical walk (so that symbolic links can't be directories), + * we can do things quickly. First, if it's a 4.4BSD file system, the type + * of the file is in the directory entry. Otherwise, we assume that the number + * of subdirectories in a node is equal to the number of links to the parent. + * The former skips all stat calls. The latter skips stat calls in any leaf + * directories and for any files after the subdirectories in the directory have + * been found, cutting the stat calls by about 2/3. + */ +static FTSENT11 * +fts_build(FTS11 *sp, int type) +{ + struct freebsd11_dirent *dp; + FTSENT11 *p, *head; + FTSENT11 *cur, *tail; + DIR *dirp; + void *oldaddr; + char *cp; + int cderrno, descend, oflag, saved_errno, nostat, doadjust; + long level; + long nlinks; /* has to be signed because -1 is a magic value */ + size_t dnamlen, len, maxlen, nitems; + + /* Set current node pointer. */ + cur = sp->fts_cur; + + /* + * Open the directory for reading. If this fails, we're done. + * If being called from fts_read, set the fts_info field. + */ +#ifdef FTS_WHITEOUT + if (ISSET(FTS_WHITEOUT)) + oflag = DTF_NODUP | DTF_REWIND; + else + oflag = DTF_HIDEW | DTF_NODUP | DTF_REWIND; +#else +#define __opendir2(path, flag) opendir(path) +#endif + if ((dirp = __opendir2(cur->fts_accpath, oflag)) == NULL) { + if (type == BREAD) { + cur->fts_info = FTS_DNR; + cur->fts_errno = errno; + } + return (NULL); + } + + /* + * Nlinks is the number of possible entries of type directory in the + * directory if we're cheating on stat calls, 0 if we're not doing + * any stat calls at all, -1 if we're doing stats on everything. + */ + if (type == BNAMES) { + nlinks = 0; + /* Be quiet about nostat, GCC. */ + nostat = 0; + } else if (ISSET(FTS_NOSTAT) && ISSET(FTS_PHYSICAL)) { + if (fts_ufslinks(sp, cur)) + nlinks = cur->fts_nlink - (ISSET(FTS_SEEDOT) ? 0 : 2); + else + nlinks = -1; + nostat = 1; + } else { + nlinks = -1; + nostat = 0; + } + +#ifdef notdef + (void)printf("nlinks == %d (cur: %d)\n", nlinks, cur->fts_nlink); + (void)printf("NOSTAT %d PHYSICAL %d SEEDOT %d\n", + ISSET(FTS_NOSTAT), ISSET(FTS_PHYSICAL), ISSET(FTS_SEEDOT)); +#endif + /* + * If we're going to need to stat anything or we want to descend + * and stay in the directory, chdir. If this fails we keep going, + * but set a flag so we don't chdir after the post-order visit. + * We won't be able to stat anything, but we can still return the + * names themselves. Note, that since fts_read won't be able to + * chdir into the directory, it will have to return different path + * names than before, i.e. "a/b" instead of "b". Since the node + * has already been visited in pre-order, have to wait until the + * post-order visit to return the error. There is a special case + * here, if there was nothing to stat then it's not an error to + * not be able to stat. This is all fairly nasty. If a program + * needed sorted entries or stat information, they had better be + * checking FTS_NS on the returned nodes. + */ + cderrno = 0; + if (nlinks || type == BREAD) { + if (fts_safe_changedir(sp, cur, _dirfd(dirp), NULL)) { + if (nlinks && type == BREAD) + cur->fts_errno = errno; + cur->fts_flags |= FTS_DONTCHDIR; + descend = 0; + cderrno = errno; + } else + descend = 1; + } else + descend = 0; + + /* + * Figure out the max file name length that can be stored in the + * current path -- the inner loop allocates more path as necessary. + * We really wouldn't have to do the maxlen calculations here, we + * could do them in fts_read before returning the path, but it's a + * lot easier here since the length is part of the dirent structure. + * + * If not changing directories set a pointer so that can just append + * each new name into the path. + */ + len = NAPPEND(cur); + if (ISSET(FTS_NOCHDIR)) { + cp = sp->fts_path + len; + *cp++ = '/'; + } else { + /* GCC, you're too verbose. */ + cp = NULL; + } + len++; + maxlen = sp->fts_pathlen - len; + + level = cur->fts_level + 1; + + /* Read the directory, attaching each entry to the `link' pointer. */ + doadjust = 0; + for (head = tail = NULL, nitems = 0; + dirp && (dp = freebsd11_readdir(dirp));) { + dnamlen = dp->d_namlen; + if (!ISSET(FTS_SEEDOT) && ISDOT(dp->d_name)) + continue; + + if ((p = fts_alloc(sp, dp->d_name, dnamlen)) == NULL) + goto mem1; + if (dnamlen >= maxlen) { /* include space for NUL */ + oldaddr = sp->fts_path; + if (fts_palloc(sp, dnamlen + len + 1)) { + /* + * No more memory for path or structures. Save + * errno, free up the current structure and the + * structures already allocated. + */ +mem1: saved_errno = errno; + if (p) + free(p); + fts_lfree(head); + (void)closedir(dirp); + cur->fts_info = FTS_ERR; + SET(FTS_STOP); + errno = saved_errno; + return (NULL); + } + /* Did realloc() change the pointer? */ + if (oldaddr != sp->fts_path) { + doadjust = 1; + if (ISSET(FTS_NOCHDIR)) + cp = sp->fts_path + len; + } + maxlen = sp->fts_pathlen - len; + } + + p->fts_level = level; + p->fts_parent = sp->fts_cur; + p->fts_pathlen = len + dnamlen; + +#ifdef FTS_WHITEOUT + if (dp->d_type == DT_WHT) + p->fts_flags |= FTS_ISW; +#endif + + if (cderrno) { + if (nlinks) { + p->fts_info = FTS_NS; + p->fts_errno = cderrno; + } else + p->fts_info = FTS_NSOK; + p->fts_accpath = cur->fts_accpath; + } else if (nlinks == 0 +#ifdef DT_DIR + || (nostat && + dp->d_type != DT_DIR && dp->d_type != DT_UNKNOWN) +#endif + ) { + p->fts_accpath = + ISSET(FTS_NOCHDIR) ? p->fts_path : p->fts_name; + p->fts_info = FTS_NSOK; + } else { + /* Build a file name for fts_stat to stat. */ + if (ISSET(FTS_NOCHDIR)) { + p->fts_accpath = p->fts_path; + memmove(cp, p->fts_name, p->fts_namelen + 1); + p->fts_info = fts_stat(sp, p, 0, _dirfd(dirp)); + } else { + p->fts_accpath = p->fts_name; + p->fts_info = fts_stat(sp, p, 0, -1); + } + + /* Decrement link count if applicable. */ + if (nlinks > 0 && (p->fts_info == FTS_D || + p->fts_info == FTS_DC || p->fts_info == FTS_DOT)) + --nlinks; + } + + /* We walk in directory order so "ls -f" doesn't get upset. */ + p->fts_link = NULL; + if (head == NULL) + head = tail = p; + else { + tail->fts_link = p; + tail = p; + } + ++nitems; + } + if (dirp) + (void)closedir(dirp); + + /* + * If realloc() changed the address of the path, adjust the + * addresses for the rest of the tree and the dir list. + */ + if (doadjust) + fts_padjust(sp, head); + + /* + * If not changing directories, reset the path back to original + * state. + */ + if (ISSET(FTS_NOCHDIR)) + sp->fts_path[cur->fts_pathlen] = '\0'; + + /* + * If descended after called from fts_children or after called from + * fts_read and nothing found, get back. At the root level we use + * the saved fd; if one of fts_open()'s arguments is a relative path + * to an empty directory, we wind up here with no other way back. If + * can't get back, we're done. + */ + if (descend && (type == BCHILD || !nitems) && + (cur->fts_level == FTS_ROOTLEVEL ? + FCHDIR(sp, sp->fts_rfd) : + fts_safe_changedir(sp, cur->fts_parent, -1, ".."))) { + fts_lfree(head); + cur->fts_info = FTS_ERR; + SET(FTS_STOP); + return (NULL); + } + + /* If didn't find anything, return NULL. */ + if (!nitems) { + if (type == BREAD) + cur->fts_info = FTS_DP; + return (NULL); + } + + /* Sort the entries. */ + if (sp->fts_compar && nitems > 1) + head = fts_sort(sp, head, nitems); + return (head); +} + +static int +fts_stat(FTS11 *sp, FTSENT11 *p, int follow, int dfd) +{ + FTSENT11 *t; + uint32_t dev; + uint32_t ino; + struct freebsd11_stat *sbp, sb; + int saved_errno; + const char *path; + + if (dfd == -1) + path = p->fts_accpath, dfd = AT_FDCWD; + else + path = p->fts_name; + + /* If user needs stat info, stat buffer already allocated. */ + sbp = ISSET(FTS_NOSTAT) ? &sb : p->fts_statp; + +#ifdef FTS_WHITEOUT + /* Check for whiteout. */ + if (p->fts_flags & FTS_ISW) { + if (sbp != &sb) { + memset(sbp, '\0', sizeof(*sbp)); + sbp->st_mode = S_IFWHT; + } + return (FTS_W); + } +#endif + + /* + * If doing a logical walk, or application requested FTS_FOLLOW, do + * a stat(2). If that fails, check for a non-existent symlink. If + * fail, set the errno from the stat call. + */ + if (ISSET(FTS_LOGICAL) || follow) { + if (freebsd11_fstatat(dfd, path, sbp, 0)) { + saved_errno = errno; + if (freebsd11_fstatat(dfd, path, sbp, + AT_SYMLINK_NOFOLLOW)) { + p->fts_errno = saved_errno; + goto err; + } + errno = 0; + if (S_ISLNK(sbp->st_mode)) + return (FTS_SLNONE); + } + } else if (freebsd11_fstatat(dfd, path, sbp, AT_SYMLINK_NOFOLLOW)) { + p->fts_errno = errno; +err: memset(sbp, 0, sizeof(*sbp)); + return (FTS_NS); + } + + if (S_ISDIR(sbp->st_mode)) { + /* + * Set the device/inode. Used to find cycles and check for + * crossing mount points. Also remember the link count, used + * in fts_build to limit the number of stat calls. It is + * understood that these fields are only referenced if fts_info + * is set to FTS_D. + */ + dev = p->fts_dev = sbp->st_dev; + ino = p->fts_ino = sbp->st_ino; + p->fts_nlink = sbp->st_nlink; + + if (ISDOT(p->fts_name)) + return (FTS_DOT); + + /* + * Cycle detection is done by brute force when the directory + * is first encountered. If the tree gets deep enough or the + * number of symbolic links to directories is high enough, + * something faster might be worthwhile. + */ + for (t = p->fts_parent; + t->fts_level >= FTS_ROOTLEVEL; t = t->fts_parent) + if (ino == t->fts_ino && dev == t->fts_dev) { + p->fts_cycle = t; + return (FTS_DC); + } + return (FTS_D); + } + if (S_ISLNK(sbp->st_mode)) + return (FTS_SL); + if (S_ISREG(sbp->st_mode)) + return (FTS_F); + return (FTS_DEFAULT); +} + +/* + * The comparison function takes pointers to pointers to FTSENT structures. + * Qsort wants a comparison function that takes pointers to void. + * (Both with appropriate levels of const-poisoning, of course!) + * Use a trampoline function to deal with the difference. + */ +static int +fts_compar(const void *a, const void *b) +{ + FTS11 *parent; + + parent = (*(const FTSENT11 * const *)a)->fts_fts; + return (*parent->fts_compar)(a, b); +} + +static FTSENT11 * +fts_sort(FTS11 *sp, FTSENT11 *head, size_t nitems) +{ + FTSENT11 **ap, *p; + + /* + * Construct an array of pointers to the structures and call qsort(3). + * Reassemble the array in the order returned by qsort. If unable to + * sort for memory reasons, return the directory entries in their + * current order. Allocate enough space for the current needs plus + * 40 so don't realloc one entry at a time. + */ + if (nitems > sp->fts_nitems) { + sp->fts_nitems = nitems + 40; + if ((sp->fts_array = reallocf(sp->fts_array, + sp->fts_nitems * sizeof(FTSENT11 *))) == NULL) { + sp->fts_nitems = 0; + return (head); + } + } + for (ap = sp->fts_array, p = head; p; p = p->fts_link) + *ap++ = p; + qsort(sp->fts_array, nitems, sizeof(FTSENT11 *), fts_compar); + for (head = *(ap = sp->fts_array); --nitems; ++ap) + ap[0]->fts_link = ap[1]; + ap[0]->fts_link = NULL; + return (head); +} + +static FTSENT11 * +fts_alloc(FTS11 *sp, char *name, size_t namelen) +{ + FTSENT11 *p; + size_t len; + + struct ftsent11_withstat { + FTSENT11 ent; + struct freebsd11_stat statbuf; + }; + + /* + * The file name is a variable length array and no stat structure is + * necessary if the user has set the nostat bit. Allocate the FTSENT + * structure, the file name and the stat structure in one chunk, but + * be careful that the stat structure is reasonably aligned. + */ + if (ISSET(FTS_NOSTAT)) + len = sizeof(FTSENT11) + namelen + 1; + else + len = sizeof(struct ftsent11_withstat) + namelen + 1; + + if ((p = malloc(len)) == NULL) + return (NULL); + + if (ISSET(FTS_NOSTAT)) { + p->fts_name = (char *)(p + 1); + p->fts_statp = NULL; + } else { + p->fts_name = (char *)((struct ftsent11_withstat *)p + 1); + p->fts_statp = &((struct ftsent11_withstat *)p)->statbuf; + } + + /* Copy the name and guarantee NUL termination. */ + memcpy(p->fts_name, name, namelen); + p->fts_name[namelen] = '\0'; + p->fts_namelen = namelen; + p->fts_path = sp->fts_path; + p->fts_errno = 0; + p->fts_flags = 0; + p->fts_instr = FTS_NOINSTR; + p->fts_number = 0; + p->fts_pointer = NULL; + p->fts_fts = sp; + return (p); +} + +static void +fts_lfree(FTSENT11 *head) +{ + FTSENT11 *p; + + /* Free a linked list of structures. */ + while ((p = head)) { + head = head->fts_link; + free(p); + } +} + +/* + * Allow essentially unlimited paths; find, rm, ls should all work on any tree. + * Most systems will allow creation of paths much longer than MAXPATHLEN, even + * though the kernel won't resolve them. Add the size (not just what's needed) + * plus 256 bytes so don't realloc the path 2 bytes at a time. + */ +static int +fts_palloc(FTS11 *sp, size_t more) +{ + + sp->fts_pathlen += more + 256; + sp->fts_path = reallocf(sp->fts_path, sp->fts_pathlen); + return (sp->fts_path == NULL); +} + +/* + * When the path is realloc'd, have to fix all of the pointers in structures + * already returned. + */ +static void +fts_padjust(FTS11 *sp, FTSENT11 *head) +{ + FTSENT11 *p; + char *addr = sp->fts_path; + +#define ADJUST(p) do { \ + if ((p)->fts_accpath != (p)->fts_name) { \ + (p)->fts_accpath = \ + (char *)addr + ((p)->fts_accpath - (p)->fts_path); \ + } \ + (p)->fts_path = addr; \ +} while (0) + /* Adjust the current set of children. */ + for (p = sp->fts_child; p; p = p->fts_link) + ADJUST(p); + + /* Adjust the rest of the tree, including the current level. */ + for (p = head; p->fts_level >= FTS_ROOTLEVEL;) { + ADJUST(p); + p = p->fts_link ? p->fts_link : p->fts_parent; + } +} + +static size_t +fts_maxarglen(char * const *argv) +{ + size_t len, max; + + for (max = 0; *argv; ++argv) + if ((len = strlen(*argv)) > max) + max = len; + return (max + 1); +} + +/* + * Change to dir specified by fd or p->fts_accpath without getting + * tricked by someone changing the world out from underneath us. + * Assumes p->fts_dev and p->fts_ino are filled in. + */ +static int +fts_safe_changedir(FTS11 *sp, FTSENT11 *p, int fd, char *path) +{ + int ret, oerrno, newfd; + struct freebsd11_stat sb; + + newfd = fd; + if (ISSET(FTS_NOCHDIR)) + return (0); + if (fd < 0 && (newfd = _open(path, O_RDONLY | O_DIRECTORY | + O_CLOEXEC, 0)) < 0) + return (-1); + if (freebsd11_fstat(newfd, &sb)) { + ret = -1; + goto bail; + } + if (p->fts_dev != sb.st_dev || p->fts_ino != sb.st_ino) { + errno = ENOENT; /* disinformation */ + ret = -1; + goto bail; + } + ret = fchdir(newfd); +bail: + oerrno = errno; + if (fd < 0) + (void)_close(newfd); + errno = oerrno; + return (ret); +} + +/* + * Check if the filesystem for "ent" has UFS-style links. + */ +static int +fts_ufslinks(FTS11 *sp, const FTSENT11 *ent) +{ + struct _fts_private11 *priv; + const char **cpp; + + priv = (struct _fts_private11 *)sp; + /* + * If this node's device is different from the previous, grab + * the filesystem information, and decide on the reliability + * of the link information from this filesystem for stat(2) + * avoidance. + */ + if (priv->ftsp_dev != ent->fts_dev) { + if (freebsd11_statfs(ent->fts_path, &priv->ftsp_statfs) != -1) { + priv->ftsp_dev = ent->fts_dev; + priv->ftsp_linksreliable = 0; + for (cpp = ufslike_filesystems; *cpp; cpp++) { + if (strcmp(priv->ftsp_statfs.f_fstypename, + *cpp) == 0) { + priv->ftsp_linksreliable = 1; + break; + } + } + } else { + priv->ftsp_linksreliable = 0; + } + } + return (priv->ftsp_linksreliable); +} + +__sym_compat(fts_open, freebsd11_fts_open, FBSD_1.1); +__sym_compat(fts_close, freebsd11_fts_close, FBSD_1.1); +__sym_compat(fts_read, freebsd11_fts_read, FBSD_1.1); +__sym_compat(fts_set, freebsd11_fts_set, FBSD_1.1); +__sym_compat(fts_children, freebsd11_fts_children, FBSD_1.1); +__sym_compat(fts_get_clientptr, freebsd11_fts_get_clientptr, FBSD_1.1); +__sym_compat(fts_get_stream, freebsd11_fts_get_stream, FBSD_1.1); +__sym_compat(fts_set_clientptr, freebsd11_fts_set_clientptr, FBSD_1.1); diff --git a/lib/libc/gen/fts-compat11.h b/lib/libc/gen/fts-compat11.h new file mode 100644 index 000000000000..52c0637395fb --- /dev/null +++ b/lib/libc/gen/fts-compat11.h @@ -0,0 +1,95 @@ +/* + * Copyright (c) 1989, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)fts.h 8.3 (Berkeley) 8/14/94 + * $FreeBSD$ + */ + +#ifndef _FTS_COPMAT11_H_ +#define _FTS_COPMAT11_H_ + +typedef struct { + struct _ftsent11 *fts_cur; /* current node */ + struct _ftsent11 *fts_child; /* linked list of children */ + struct _ftsent11 **fts_array; /* sort array */ + uint32_t fts_dev; /* starting device # */ + char *fts_path; /* path for this descent */ + int fts_rfd; /* fd for root */ + __size_t fts_pathlen; /* sizeof(path) */ + __size_t fts_nitems; /* elements in the sort array */ + int (*fts_compar) /* compare function */ + (const struct _ftsent11 * const *, + const struct _ftsent11 * const *); + int fts_options; /* fts_open options, global flags */ + void *fts_clientptr; /* thunk for sort function */ +} FTS11; + +typedef struct _ftsent11 { + struct _ftsent11 *fts_cycle; /* cycle node */ + struct _ftsent11 *fts_parent; /* parent directory */ + struct _ftsent11 *fts_link; /* next file in directory */ + long long fts_number; /* local numeric value */ + void *fts_pointer; /* local address value */ + char *fts_accpath; /* access path */ + char *fts_path; /* root path */ + int fts_errno; /* errno for this node */ + int fts_symfd; /* fd for symlink */ + __size_t fts_pathlen; /* strlen(fts_path) */ + __size_t fts_namelen; /* strlen(fts_name) */ + + uint32_t fts_ino; /* inode */ + uint32_t fts_dev; /* device */ + uint16_t fts_nlink; /* link count */ + + long fts_level; /* depth (-1 to N) */ + + int fts_info; /* user status for FTSENT structure */ + + unsigned fts_flags; /* private flags for FTSENT structure */ + + int fts_instr; /* fts_set() instructions */ + + struct freebsd11_stat *fts_statp; /* stat(2) information */ + char *fts_name; /* file name */ + FTS11 *fts_fts; /* back pointer to main FTS */ +} FTSENT11; + +FTSENT11 *freebsd11_fts_children(FTS11 *, int); +int freebsd11_fts_close(FTS11 *); +void *freebsd11_fts_get_clientptr(FTS11 *); +#define freebsd11_fts_get_clientptr(fts) ((fts)->fts_clientptr) +FTS11 *freebsd11_fts_get_stream(FTSENT11 *); +#define freebsd11_fts_get_stream(ftsent) ((ftsent)->fts_fts) +FTS11 *freebsd11_fts_open(char * const *, int, + int (*)(const FTSENT11 * const *, + const FTSENT11 * const *)); +FTSENT11 *freebsd11_fts_read(FTS11 *); +int freebsd11_fts_set(FTS11 *, FTSENT11 *, int); +void freebsd11_fts_set_clientptr(FTS11 *, void *); + +#endif /* !_FTS_COMPAT11_H_ */ diff --git a/lib/libc/gen/ftw-compat11.c b/lib/libc/gen/ftw-compat11.c new file mode 100644 index 000000000000..cad536d2dcd6 --- /dev/null +++ b/lib/libc/gen/ftw-compat11.c @@ -0,0 +1,98 @@ +/* $OpenBSD: ftw.c,v 1.5 2005/08/08 08:05:34 espie Exp $ */ + +/* + * Copyright (c) 2003, 2004 Todd C. Miller <Todd.Miller@courtesan.com> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Sponsored in part by the Defense Advanced Research Projects + * Agency (DARPA) and Air Force Research Laboratory, Air Force + * Materiel Command, USAF, under agreement number F39502-99-1-0512. + * + * from: $FreeBSD$ + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <sys/types.h> +#include <sys/stat.h> +#include <errno.h> +#include <fts.h> +#include <ftw.h> + +#include "fts-compat11.h" + +int +freebsd11_ftw(const char *path, + int (*fn)(const char *, const struct freebsd11_stat *, int), int nfds) +{ + char * const paths[2] = { (char *)path, NULL }; + FTSENT11 *cur; + FTS11 *ftsp; + int error = 0, fnflag, sverrno; + + /* XXX - nfds is currently unused */ + if (nfds < 1) { + errno = EINVAL; + return (-1); + } + + ftsp = freebsd11_fts_open(paths, + FTS_LOGICAL | FTS_COMFOLLOW | FTS_NOCHDIR, NULL); + if (ftsp == NULL) + return (-1); + while ((cur = freebsd11_fts_read(ftsp)) != NULL) { + switch (cur->fts_info) { + case FTS_D: + fnflag = FTW_D; + break; + case FTS_DNR: + fnflag = FTW_DNR; + break; + case FTS_DP: + /* we only visit in preorder */ + continue; + case FTS_F: + case FTS_DEFAULT: + fnflag = FTW_F; + break; + case FTS_NS: + case FTS_NSOK: + case FTS_SLNONE: + fnflag = FTW_NS; + break; + case FTS_SL: + fnflag = FTW_SL; + break; + case FTS_DC: + errno = ELOOP; + /* FALLTHROUGH */ + default: + error = -1; + goto done; + } + error = fn(cur->fts_path, cur->fts_statp, fnflag); + if (error != 0) + break; + } +done: + sverrno = errno; + if (freebsd11_fts_close(ftsp) != 0 && error == 0) + error = -1; + else + errno = sverrno; + return (error); +} + +__sym_compat(ftw, freebsd11_ftw, FBSD_1.0); diff --git a/lib/libc/gen/gen-compat.h b/lib/libc/gen/gen-compat.h new file mode 100644 index 000000000000..728a15a51b18 --- /dev/null +++ b/lib/libc/gen/gen-compat.h @@ -0,0 +1,57 @@ +/*- + * Copyright (c) 2012 Gleb Kurtsou <gleb@FreeBSD.org> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#ifndef _GEN_COMPAT_H_ +#define _GEN_COMPAT_H_ + +#include <dirent.h> + +#define FREEBSD11_DIRSIZ(dp) \ + (sizeof(struct freebsd11_dirent) - sizeof((dp)->d_name) + \ + (((dp)->d_namlen + 1 + 3) &~ 3)) + +struct freebsd11_dirent; +struct freebsd11_stat; +struct freebsd11_statfs; + +struct freebsd11_dirent *freebsd11_readdir(DIR *); +int freebsd11_readdir_r(DIR *, struct freebsd11_dirent *, + struct freebsd11_dirent **); +int freebsd11_stat(const char *, struct freebsd11_stat *); +int freebsd11_lstat(const char *, struct freebsd11_stat *); +int freebsd11_fstat(int, struct freebsd11_stat *); +int freebsd11_fstatat(int, const char *, struct freebsd11_stat *, int); + +int freebsd11_statfs(const char *, struct freebsd11_statfs *); +int freebsd11_getfsstat(struct freebsd11_statfs *, long, int); +int freebsd11_getmntinfo(struct freebsd11_statfs **, int); + +char *freebsd11_devname(__uint32_t dev, __mode_t type); +char *freebsd11_devname_r(__uint32_t dev, __mode_t type, char *buf, int len); + +#endif /* _GEN_COMPAT_H_ */ diff --git a/lib/libc/gen/gen-private.h b/lib/libc/gen/gen-private.h index d1fab5f31462..0366cbfad8b9 100644 --- a/lib/libc/gen/gen-private.h +++ b/lib/libc/gen/gen-private.h @@ -47,12 +47,16 @@ struct _dirdesc { long dd_size; /* amount of data returned by getdirentries */ char *dd_buf; /* data buffer */ int dd_len; /* size of data buffer */ - long dd_seek; /* magic cookie returned by getdirentries */ + off_t dd_seek; /* magic cookie returned by getdirentries */ int dd_flags; /* flags for readdir */ struct pthread_mutex *dd_lock; /* lock */ struct _telldir *dd_td; /* telldir position recording */ + void *dd_compat_de; /* compat dirent */ }; #define _dirfd(dirp) ((dirp)->dd_fd) +struct dirent; +int __readdir_r(DIR *dirp, struct dirent *entry, struct dirent **result); + #endif /* !_GEN_PRIVATE_H_ */ diff --git a/lib/libc/gen/getmntinfo-compat11.c b/lib/libc/gen/getmntinfo-compat11.c new file mode 100644 index 000000000000..05ffb74dc8c5 --- /dev/null +++ b/lib/libc/gen/getmntinfo-compat11.c @@ -0,0 +1,72 @@ +/* + * Copyright (c) 1989, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static char sccsid[] = "@(#)getmntinfo.c 8.1 (Berkeley) 6/4/93"; +#endif /* LIBC_SCCS and not lint */ +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <sys/param.h> +#include <sys/ucred.h> +#define _WANT_FREEBSD11_STATFS +#include <sys/mount.h> +#include <stdlib.h> +#include "gen-compat.h" + +/* + * Return information about mounted filesystems. + */ +int +freebsd11_getmntinfo(struct freebsd11_statfs **mntbufp, int flags) +{ + static struct freebsd11_statfs *mntbuf; + static int mntsize; + static long bufsize; + + if (mntsize <= 0 && + (mntsize = freebsd11_getfsstat(0, 0, MNT_NOWAIT)) < 0) + return (0); + if (bufsize > 0 && + (mntsize = freebsd11_getfsstat(mntbuf, bufsize, flags)) < 0) + return (0); + while (bufsize <= mntsize * sizeof(struct freebsd11_statfs)) { + if (mntbuf) + free(mntbuf); + bufsize = (mntsize + 1) * sizeof(struct freebsd11_statfs); + if ((mntbuf = (struct freebsd11_statfs *)malloc(bufsize)) == 0) + return (0); + if ((mntsize = freebsd11_getfsstat(mntbuf, bufsize, flags)) < 0) + return (0); + } + *mntbufp = mntbuf; + return (mntsize); +} + +__sym_compat(getmntinfo, freebsd11_getmntinfo, FBSD_1.0); diff --git a/lib/libc/gen/glob-compat11.c b/lib/libc/gen/glob-compat11.c new file mode 100644 index 000000000000..2bdf99a0bf64 --- /dev/null +++ b/lib/libc/gen/glob-compat11.c @@ -0,0 +1,1093 @@ +/* + * Copyright (c) 1989, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Guido van Rossum. + * + * Copyright (c) 2011 The FreeBSD Foundation + * All rights reserved. + * Portions of this software were developed by David Chisnall + * under sponsorship from the FreeBSD Foundation. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * from: $FreeBSD$ + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static char sccsid[] = "@(#)glob.c 8.3 (Berkeley) 10/13/93"; +#endif /* LIBC_SCCS and not lint */ +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <sys/param.h> +#define _WANT_FREEBSD11_STAT +#include <sys/stat.h> + +#include <ctype.h> +#define _WANT_FREEBSD11_DIRENT +#include <dirent.h> +#include <errno.h> +#include <glob.h> +#include <limits.h> +#include <pwd.h> +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <wchar.h> + +#include "collate.h" +#include "gen-compat.h" +#include "glob-compat11.h" + +/* + * glob(3) expansion limits. Stop the expansion if any of these limits + * is reached. This caps the runtime in the face of DoS attacks. See + * also CVE-2010-2632 + */ +#define GLOB_LIMIT_BRACE 128 /* number of brace calls */ +#define GLOB_LIMIT_PATH 65536 /* number of path elements */ +#define GLOB_LIMIT_READDIR 16384 /* number of readdirs */ +#define GLOB_LIMIT_STAT 1024 /* number of stat system calls */ +#define GLOB_LIMIT_STRING ARG_MAX /* maximum total size for paths */ + +struct glob_limit { + size_t l_brace_cnt; + size_t l_path_lim; + size_t l_readdir_cnt; + size_t l_stat_cnt; + size_t l_string_cnt; +}; + +#define DOT L'.' +#define EOS L'\0' +#define LBRACKET L'[' +#define NOT L'!' +#define QUESTION L'?' +#define QUOTE L'\\' +#define RANGE L'-' +#define RBRACKET L']' +#define SEP L'/' +#define STAR L'*' +#define TILDE L'~' +#define LBRACE L'{' +#define RBRACE L'}' +#define COMMA L',' + +#define M_QUOTE 0x8000000000ULL +#define M_PROTECT 0x4000000000ULL +#define M_MASK 0xffffffffffULL +#define M_CHAR 0x00ffffffffULL + +typedef uint_fast64_t Char; + +#define CHAR(c) ((Char)((c)&M_CHAR)) +#define META(c) ((Char)((c)|M_QUOTE)) +#define UNPROT(c) ((c) & ~M_PROTECT) +#define M_ALL META(L'*') +#define M_END META(L']') +#define M_NOT META(L'!') +#define M_ONE META(L'?') +#define M_RNG META(L'-') +#define M_SET META(L'[') +#define ismeta(c) (((c)&M_QUOTE) != 0) +#ifdef DEBUG +#define isprot(c) (((c)&M_PROTECT) != 0) +#endif + +static int compare(const void *, const void *); +static int g_Ctoc(const Char *, char *, size_t); +static int g_lstat(Char *, struct freebsd11_stat *, glob11_t *); +static DIR *g_opendir(Char *, glob11_t *); +static const Char *g_strchr(const Char *, wchar_t); +#ifdef notdef +static Char *g_strcat(Char *, const Char *); +#endif +static int g_stat(Char *, struct freebsd11_stat *, glob11_t *); +static int glob0(const Char *, glob11_t *, struct glob_limit *, + const char *); +static int glob1(Char *, glob11_t *, struct glob_limit *); +static int glob2(Char *, Char *, Char *, Char *, glob11_t *, + struct glob_limit *); +static int glob3(Char *, Char *, Char *, Char *, Char *, glob11_t *, + struct glob_limit *); +static int globextend(const Char *, glob11_t *, struct glob_limit *, + const char *); +static const Char * + globtilde(const Char *, Char *, size_t, glob11_t *); +static int globexp0(const Char *, glob11_t *, struct glob_limit *, + const char *); +static int globexp1(const Char *, glob11_t *, struct glob_limit *); +static int globexp2(const Char *, const Char *, glob11_t *, + struct glob_limit *); +static int globfinal(glob11_t *, struct glob_limit *, size_t, + const char *); +static int match(Char *, Char *, Char *); +static int err_nomatch(glob11_t *, struct glob_limit *, const char *); +static int err_aborted(glob11_t *, int, char *); +#ifdef DEBUG +static void qprintf(const char *, Char *); +#endif + +int +freebsd11_glob(const char * __restrict pattern, int flags, + int (*errfunc)(const char *, int), glob11_t * __restrict pglob) +{ + struct glob_limit limit = { 0, 0, 0, 0, 0 }; + const char *patnext; + Char *bufnext, *bufend, patbuf[MAXPATHLEN], prot; + mbstate_t mbs; + wchar_t wc; + size_t clen; + int too_long; + + patnext = pattern; + if (!(flags & GLOB_APPEND)) { + pglob->gl_pathc = 0; + pglob->gl_pathv = NULL; + if (!(flags & GLOB_DOOFFS)) + pglob->gl_offs = 0; + } + if (flags & GLOB_LIMIT) { + limit.l_path_lim = pglob->gl_matchc; + if (limit.l_path_lim == 0) + limit.l_path_lim = GLOB_LIMIT_PATH; + } + pglob->gl_flags = flags & ~GLOB_MAGCHAR; + pglob->gl_errfunc = errfunc; + pglob->gl_matchc = 0; + + bufnext = patbuf; + bufend = bufnext + MAXPATHLEN - 1; + too_long = 1; + if (flags & GLOB_NOESCAPE) { + memset(&mbs, 0, sizeof(mbs)); + while (bufnext <= bufend) { + clen = mbrtowc(&wc, patnext, MB_LEN_MAX, &mbs); + if (clen == (size_t)-1 || clen == (size_t)-2) + return (err_nomatch(pglob, &limit, pattern)); + else if (clen == 0) { + too_long = 0; + break; + } + *bufnext++ = wc; + patnext += clen; + } + } else { + /* Protect the quoted characters. */ + memset(&mbs, 0, sizeof(mbs)); + while (bufnext <= bufend) { + if (*patnext == '\\') { + if (*++patnext == '\0') { + *bufnext++ = QUOTE; + continue; + } + prot = M_PROTECT; + } else + prot = 0; + clen = mbrtowc(&wc, patnext, MB_LEN_MAX, &mbs); + if (clen == (size_t)-1 || clen == (size_t)-2) + return (err_nomatch(pglob, &limit, pattern)); + else if (clen == 0) { + too_long = 0; + break; + } + *bufnext++ = wc | prot; + patnext += clen; + } + } + if (too_long) + return (err_nomatch(pglob, &limit, pattern)); + *bufnext = EOS; + + if (flags & GLOB_BRACE) + return (globexp0(patbuf, pglob, &limit, pattern)); + else + return (glob0(patbuf, pglob, &limit, pattern)); +} + +static int +globexp0(const Char *pattern, glob11_t *pglob, struct glob_limit *limit, + const char *origpat) { + int rv; + size_t oldpathc; + + /* Protect a single {}, for find(1), like csh */ + if (pattern[0] == LBRACE && pattern[1] == RBRACE && pattern[2] == EOS) { + if ((pglob->gl_flags & GLOB_LIMIT) && + limit->l_brace_cnt++ >= GLOB_LIMIT_BRACE) { + errno = E2BIG; + return (GLOB_NOSPACE); + } + return (glob0(pattern, pglob, limit, origpat)); + } + + oldpathc = pglob->gl_pathc; + + if ((rv = globexp1(pattern, pglob, limit)) != 0) + return rv; + + return (globfinal(pglob, limit, oldpathc, origpat)); +} + +/* + * Expand recursively a glob {} pattern. When there is no more expansion + * invoke the standard globbing routine to glob the rest of the magic + * characters + */ +static int +globexp1(const Char *pattern, glob11_t *pglob, struct glob_limit *limit) +{ + const Char* ptr; + + if ((ptr = g_strchr(pattern, LBRACE)) != NULL) { + if ((pglob->gl_flags & GLOB_LIMIT) && + limit->l_brace_cnt++ >= GLOB_LIMIT_BRACE) { + errno = E2BIG; + return (GLOB_NOSPACE); + } + return (globexp2(ptr, pattern, pglob, limit)); + } + + return (glob0(pattern, pglob, limit, NULL)); +} + + +/* + * Recursive brace globbing helper. Tries to expand a single brace. + * If it succeeds then it invokes globexp1 with the new pattern. + * If it fails then it tries to glob the rest of the pattern and returns. + */ +static int +globexp2(const Char *ptr, const Char *pattern, glob11_t *pglob, + struct glob_limit *limit) +{ + int i, rv; + Char *lm, *ls; + const Char *pe, *pm, *pm1, *pl; + Char patbuf[MAXPATHLEN]; + + /* copy part up to the brace */ + for (lm = patbuf, pm = pattern; pm != ptr; *lm++ = *pm++) + continue; + *lm = EOS; + ls = lm; + + /* Find the balanced brace */ + for (i = 0, pe = ++ptr; *pe != EOS; pe++) + if (*pe == LBRACKET) { + /* Ignore everything between [] */ + for (pm = pe++; *pe != RBRACKET && *pe != EOS; pe++) + continue; + if (*pe == EOS) { + /* + * We could not find a matching RBRACKET. + * Ignore and just look for RBRACE + */ + pe = pm; + } + } + else if (*pe == LBRACE) + i++; + else if (*pe == RBRACE) { + if (i == 0) + break; + i--; + } + + /* Non matching braces; just glob the pattern */ + if (i != 0 || *pe == EOS) + return (glob0(pattern, pglob, limit, NULL)); + + for (i = 0, pl = pm = ptr; pm <= pe; pm++) + switch (*pm) { + case LBRACKET: + /* Ignore everything between [] */ + for (pm1 = pm++; *pm != RBRACKET && *pm != EOS; pm++) + continue; + if (*pm == EOS) { + /* + * We could not find a matching RBRACKET. + * Ignore and just look for RBRACE + */ + pm = pm1; + } + break; + + case LBRACE: + i++; + break; + + case RBRACE: + if (i) { + i--; + break; + } + /* FALLTHROUGH */ + case COMMA: + if (i && *pm == COMMA) + break; + else { + /* Append the current string */ + for (lm = ls; (pl < pm); *lm++ = *pl++) + continue; + /* + * Append the rest of the pattern after the + * closing brace + */ + for (pl = pe + 1; (*lm++ = *pl++) != EOS;) + continue; + + /* Expand the current pattern */ +#ifdef DEBUG + qprintf("globexp2:", patbuf); +#endif + rv = globexp1(patbuf, pglob, limit); + if (rv) + return (rv); + + /* move after the comma, to the next string */ + pl = pm + 1; + } + break; + + default: + break; + } + return (0); +} + + + +/* + * expand tilde from the passwd file. + */ +static const Char * +globtilde(const Char *pattern, Char *patbuf, size_t patbuf_len, glob11_t *pglob) +{ + struct passwd *pwd; + char *h, *sc; + const Char *p; + Char *b, *eb; + wchar_t wc; + wchar_t wbuf[MAXPATHLEN]; + wchar_t *wbufend, *dc; + size_t clen; + mbstate_t mbs; + int too_long; + + if (*pattern != TILDE || !(pglob->gl_flags & GLOB_TILDE)) + return (pattern); + + /* + * Copy up to the end of the string or / + */ + eb = &patbuf[patbuf_len - 1]; + for (p = pattern + 1, b = patbuf; + b < eb && *p != EOS && UNPROT(*p) != SEP; *b++ = *p++) + continue; + + if (*p != EOS && UNPROT(*p) != SEP) + return (NULL); + + *b = EOS; + h = NULL; + + if (patbuf[0] == EOS) { + /* + * handle a plain ~ or ~/ by expanding $HOME first (iff + * we're not running setuid or setgid) and then trying + * the password file + */ + if (issetugid() != 0 || + (h = getenv("HOME")) == NULL) { + if (((h = getlogin()) != NULL && + (pwd = getpwnam(h)) != NULL) || + (pwd = getpwuid(getuid())) != NULL) + h = pwd->pw_dir; + else + return (pattern); + } + } + else { + /* + * Expand a ~user + */ + if (g_Ctoc(patbuf, (char *)wbuf, sizeof(wbuf))) + return (NULL); + if ((pwd = getpwnam((char *)wbuf)) == NULL) + return (pattern); + else + h = pwd->pw_dir; + } + + /* Copy the home directory */ + dc = wbuf; + sc = h; + wbufend = wbuf + MAXPATHLEN - 1; + too_long = 1; + memset(&mbs, 0, sizeof(mbs)); + while (dc <= wbufend) { + clen = mbrtowc(&wc, sc, MB_LEN_MAX, &mbs); + if (clen == (size_t)-1 || clen == (size_t)-2) { + /* XXX See initial comment #2. */ + wc = (unsigned char)*sc; + clen = 1; + memset(&mbs, 0, sizeof(mbs)); + } + if ((*dc++ = wc) == EOS) { + too_long = 0; + break; + } + sc += clen; + } + if (too_long) + return (NULL); + + dc = wbuf; + for (b = patbuf; b < eb && *dc != EOS; *b++ = *dc++ | M_PROTECT) + continue; + if (*dc != EOS) + return (NULL); + + /* Append the rest of the pattern */ + if (*p != EOS) { + too_long = 1; + while (b <= eb) { + if ((*b++ = *p++) == EOS) { + too_long = 0; + break; + } + } + if (too_long) + return (NULL); + } else + *b = EOS; + + return (patbuf); +} + + +/* + * The main glob() routine: compiles the pattern (optionally processing + * quotes), calls glob1() to do the real pattern matching, and finally + * sorts the list (unless unsorted operation is requested). Returns 0 + * if things went well, nonzero if errors occurred. + */ +static int +glob0(const Char *pattern, glob11_t *pglob, struct glob_limit *limit, + const char *origpat) { + const Char *qpatnext; + int err; + size_t oldpathc; + Char *bufnext, c, patbuf[MAXPATHLEN]; + + qpatnext = globtilde(pattern, patbuf, MAXPATHLEN, pglob); + if (qpatnext == NULL) { + errno = E2BIG; + return (GLOB_NOSPACE); + } + oldpathc = pglob->gl_pathc; + bufnext = patbuf; + + /* We don't need to check for buffer overflow any more. */ + while ((c = *qpatnext++) != EOS) { + switch (c) { + case LBRACKET: + c = *qpatnext; + if (c == NOT) + ++qpatnext; + if (*qpatnext == EOS || + g_strchr(qpatnext+1, RBRACKET) == NULL) { + *bufnext++ = LBRACKET; + if (c == NOT) + --qpatnext; + break; + } + *bufnext++ = M_SET; + if (c == NOT) + *bufnext++ = M_NOT; + c = *qpatnext++; + do { + *bufnext++ = CHAR(c); + if (*qpatnext == RANGE && + (c = qpatnext[1]) != RBRACKET) { + *bufnext++ = M_RNG; + *bufnext++ = CHAR(c); + qpatnext += 2; + } + } while ((c = *qpatnext++) != RBRACKET); + pglob->gl_flags |= GLOB_MAGCHAR; + *bufnext++ = M_END; + break; + case QUESTION: + pglob->gl_flags |= GLOB_MAGCHAR; + *bufnext++ = M_ONE; + break; + case STAR: + pglob->gl_flags |= GLOB_MAGCHAR; + /* collapse adjacent stars to one, + * to avoid exponential behavior + */ + if (bufnext == patbuf || bufnext[-1] != M_ALL) + *bufnext++ = M_ALL; + break; + default: + *bufnext++ = CHAR(c); + break; + } + } + *bufnext = EOS; +#ifdef DEBUG + qprintf("glob0:", patbuf); +#endif + + if ((err = glob1(patbuf, pglob, limit)) != 0) + return(err); + + if (origpat != NULL) + return (globfinal(pglob, limit, oldpathc, origpat)); + + return (0); +} + +static int +globfinal(glob11_t *pglob, struct glob_limit *limit, size_t oldpathc, + const char *origpat) { + if (pglob->gl_pathc == oldpathc) + return (err_nomatch(pglob, limit, origpat)); + + if (!(pglob->gl_flags & GLOB_NOSORT)) + qsort(pglob->gl_pathv + pglob->gl_offs + oldpathc, + pglob->gl_pathc - oldpathc, sizeof(char *), compare); + + return (0); +} + +static int +compare(const void *p, const void *q) +{ + return (strcoll(*(char **)p, *(char **)q)); +} + +static int +glob1(Char *pattern, glob11_t *pglob, struct glob_limit *limit) +{ + Char pathbuf[MAXPATHLEN]; + + /* A null pathname is invalid -- POSIX 1003.1 sect. 2.4. */ + if (*pattern == EOS) + return (0); + return (glob2(pathbuf, pathbuf, pathbuf + MAXPATHLEN - 1, + pattern, pglob, limit)); +} + +/* + * The functions glob2 and glob3 are mutually recursive; there is one level + * of recursion for each segment in the pattern that contains one or more + * meta characters. + */ +static int +glob2(Char *pathbuf, Char *pathend, Char *pathend_last, Char *pattern, + glob11_t *pglob, struct glob_limit *limit) +{ + struct freebsd11_stat sb; + Char *p, *q; + int anymeta; + + /* + * Loop over pattern segments until end of pattern or until + * segment with meta character found. + */ + for (anymeta = 0;;) { + if (*pattern == EOS) { /* End of pattern? */ + *pathend = EOS; + if (g_lstat(pathbuf, &sb, pglob)) + return (0); + + if ((pglob->gl_flags & GLOB_LIMIT) && + limit->l_stat_cnt++ >= GLOB_LIMIT_STAT) { + errno = E2BIG; + return (GLOB_NOSPACE); + } + if ((pglob->gl_flags & GLOB_MARK) && + UNPROT(pathend[-1]) != SEP && + (S_ISDIR(sb.st_mode) || + (S_ISLNK(sb.st_mode) && + g_stat(pathbuf, &sb, pglob) == 0 && + S_ISDIR(sb.st_mode)))) { + if (pathend + 1 > pathend_last) { + errno = E2BIG; + return (GLOB_NOSPACE); + } + *pathend++ = SEP; + *pathend = EOS; + } + ++pglob->gl_matchc; + return (globextend(pathbuf, pglob, limit, NULL)); + } + + /* Find end of next segment, copy tentatively to pathend. */ + q = pathend; + p = pattern; + while (*p != EOS && UNPROT(*p) != SEP) { + if (ismeta(*p)) + anymeta = 1; + if (q + 1 > pathend_last) { + errno = E2BIG; + return (GLOB_NOSPACE); + } + *q++ = *p++; + } + + if (!anymeta) { /* No expansion, do next segment. */ + pathend = q; + pattern = p; + while (UNPROT(*pattern) == SEP) { + if (pathend + 1 > pathend_last) { + errno = E2BIG; + return (GLOB_NOSPACE); + } + *pathend++ = *pattern++; + } + } else /* Need expansion, recurse. */ + return (glob3(pathbuf, pathend, pathend_last, pattern, + p, pglob, limit)); + } + /* NOTREACHED */ +} + +static int +glob3(Char *pathbuf, Char *pathend, Char *pathend_last, + Char *pattern, Char *restpattern, + glob11_t *pglob, struct glob_limit *limit) +{ + struct freebsd11_dirent *dp; + DIR *dirp; + int err, too_long, saverrno, saverrno2; + char buf[MAXPATHLEN + MB_LEN_MAX - 1]; + + struct freebsd11_dirent *(*readdirfunc)(DIR *); + + if (pathend > pathend_last) { + errno = E2BIG; + return (GLOB_NOSPACE); + } + *pathend = EOS; + if (pglob->gl_errfunc != NULL && + g_Ctoc(pathbuf, buf, sizeof(buf))) { + errno = E2BIG; + return (GLOB_NOSPACE); + } + + saverrno = errno; + errno = 0; + if ((dirp = g_opendir(pathbuf, pglob)) == NULL) { + if (errno == ENOENT || errno == ENOTDIR) + return (0); + err = err_aborted(pglob, errno, buf); + if (errno == 0) + errno = saverrno; + return (err); + } + + err = 0; + + /* pglob->gl_readdir takes a void *, fix this manually */ + if (pglob->gl_flags & GLOB_ALTDIRFUNC) + readdirfunc = + (struct freebsd11_dirent *(*)(DIR *))pglob->gl_readdir; + else + readdirfunc = freebsd11_readdir; + + errno = 0; + /* Search directory for matching names. */ + while ((dp = (*readdirfunc)(dirp)) != NULL) { + char *sc; + Char *dc; + wchar_t wc; + size_t clen; + mbstate_t mbs; + + if ((pglob->gl_flags & GLOB_LIMIT) && + limit->l_readdir_cnt++ >= GLOB_LIMIT_READDIR) { + errno = E2BIG; + err = GLOB_NOSPACE; + break; + } + + /* Initial DOT must be matched literally. */ + if (dp->d_name[0] == '.' && UNPROT(*pattern) != DOT) { + errno = 0; + continue; + } + memset(&mbs, 0, sizeof(mbs)); + dc = pathend; + sc = dp->d_name; + too_long = 1; + while (dc <= pathend_last) { + clen = mbrtowc(&wc, sc, MB_LEN_MAX, &mbs); + if (clen == (size_t)-1 || clen == (size_t)-2) { + /* XXX See initial comment #2. */ + wc = (unsigned char)*sc; + clen = 1; + memset(&mbs, 0, sizeof(mbs)); + } + if ((*dc++ = wc) == EOS) { + too_long = 0; + break; + } + sc += clen; + } + if (too_long && (err = err_aborted(pglob, ENAMETOOLONG, + buf))) { + errno = ENAMETOOLONG; + break; + } + if (too_long || !match(pathend, pattern, restpattern)) { + *pathend = EOS; + errno = 0; + continue; + } + if (errno == 0) + errno = saverrno; + err = glob2(pathbuf, --dc, pathend_last, restpattern, + pglob, limit); + if (err) + break; + errno = 0; + } + + saverrno2 = errno; + if (pglob->gl_flags & GLOB_ALTDIRFUNC) + (*pglob->gl_closedir)(dirp); + else + closedir(dirp); + errno = saverrno2; + + if (err) + return (err); + + if (dp == NULL && errno != 0 && + (err = err_aborted(pglob, errno, buf))) + return (err); + + if (errno == 0) + errno = saverrno; + return (0); +} + + +/* + * Extend the gl_pathv member of a glob11_t structure to accommodate a new item, + * add the new item, and update gl_pathc. + * + * This assumes the BSD realloc, which only copies the block when its size + * crosses a power-of-two boundary; for v7 realloc, this would cause quadratic + * behavior. + * + * Return 0 if new item added, error code if memory couldn't be allocated. + * + * Invariant of the glob11_t structure: + * Either gl_pathc is zero and gl_pathv is NULL; or gl_pathc > 0 and + * gl_pathv points to (gl_offs + gl_pathc + 1) items. + */ +static int +globextend(const Char *path, glob11_t *pglob, struct glob_limit *limit, + const char *origpat) +{ + char **pathv; + size_t i, newn, len; + char *copy; + const Char *p; + + if ((pglob->gl_flags & GLOB_LIMIT) && + pglob->gl_matchc > limit->l_path_lim) { + errno = E2BIG; + return (GLOB_NOSPACE); + } + + newn = 2 + pglob->gl_pathc + pglob->gl_offs; + /* reallocarray(NULL, newn, size) is equivalent to malloc(newn*size). */ + pathv = reallocarray(pglob->gl_pathv, newn, sizeof(*pathv)); + if (pathv == NULL) + return (GLOB_NOSPACE); + + if (pglob->gl_pathv == NULL && pglob->gl_offs > 0) { + /* first time around -- clear initial gl_offs items */ + pathv += pglob->gl_offs; + for (i = pglob->gl_offs + 1; --i > 0; ) + *--pathv = NULL; + } + pglob->gl_pathv = pathv; + + if (origpat != NULL) + copy = strdup(origpat); + else { + for (p = path; *p++ != EOS;) + continue; + len = MB_CUR_MAX * (size_t)(p - path); /* XXX overallocation */ + if ((copy = malloc(len)) != NULL) { + if (g_Ctoc(path, copy, len)) { + free(copy); + errno = E2BIG; + return (GLOB_NOSPACE); + } + } + } + if (copy != NULL) { + limit->l_string_cnt += strlen(copy) + 1; + if ((pglob->gl_flags & GLOB_LIMIT) && + limit->l_string_cnt >= GLOB_LIMIT_STRING) { + free(copy); + errno = E2BIG; + return (GLOB_NOSPACE); + } + pathv[pglob->gl_offs + pglob->gl_pathc++] = copy; + } + pathv[pglob->gl_offs + pglob->gl_pathc] = NULL; + return (copy == NULL ? GLOB_NOSPACE : 0); +} + +/* + * pattern matching function for filenames. + */ +static int +match(Char *name, Char *pat, Char *patend) +{ + int ok, negate_range; + Char c, k, *nextp, *nextn; + struct xlocale_collate *table = + (struct xlocale_collate*)__get_locale()->components[XLC_COLLATE]; + + nextn = NULL; + nextp = NULL; + + while (1) { + while (pat < patend) { + c = *pat++; + switch (c & M_MASK) { + case M_ALL: + if (pat == patend) + return (1); + if (*name == EOS) + return (0); + nextn = name + 1; + nextp = pat - 1; + break; + case M_ONE: + if (*name++ == EOS) + goto fail; + break; + case M_SET: + ok = 0; + if ((k = *name++) == EOS) + goto fail; + negate_range = ((*pat & M_MASK) == M_NOT); + if (negate_range != 0) + ++pat; + while (((c = *pat++) & M_MASK) != M_END) + if ((*pat & M_MASK) == M_RNG) { + if (table->__collate_load_error ? + CHAR(c) <= CHAR(k) && + CHAR(k) <= CHAR(pat[1]) : + __wcollate_range_cmp(CHAR(c), + CHAR(k)) <= 0 && + __wcollate_range_cmp(CHAR(k), + CHAR(pat[1])) <= 0) + ok = 1; + pat += 2; + } else if (c == k) + ok = 1; + if (ok == negate_range) + goto fail; + break; + default: + if (*name++ != c) + goto fail; + break; + } + } + if (*name == EOS) + return (1); + + fail: + if (nextn == NULL) + break; + pat = nextp; + name = nextn; + } + return (0); +} + +/* Free allocated data belonging to a glob11_t structure. */ +void +freebsd11_globfree(glob11_t *pglob) +{ + size_t i; + char **pp; + + if (pglob->gl_pathv != NULL) { + pp = pglob->gl_pathv + pglob->gl_offs; + for (i = pglob->gl_pathc; i--; ++pp) + if (*pp) + free(*pp); + free(pglob->gl_pathv); + pglob->gl_pathv = NULL; + } +} + +static DIR * +g_opendir(Char *str, glob11_t *pglob) +{ + char buf[MAXPATHLEN + MB_LEN_MAX - 1]; + + if (*str == EOS) + strcpy(buf, "."); + else { + if (g_Ctoc(str, buf, sizeof(buf))) { + errno = ENAMETOOLONG; + return (NULL); + } + } + + if (pglob->gl_flags & GLOB_ALTDIRFUNC) + return ((*pglob->gl_opendir)(buf)); + + return (opendir(buf)); +} + +static int +g_lstat(Char *fn, struct freebsd11_stat *sb, glob11_t *pglob) +{ + char buf[MAXPATHLEN + MB_LEN_MAX - 1]; + + if (g_Ctoc(fn, buf, sizeof(buf))) { + errno = ENAMETOOLONG; + return (-1); + } + if (pglob->gl_flags & GLOB_ALTDIRFUNC) + return((*pglob->gl_lstat)(buf, sb)); + return (freebsd11_lstat(buf, sb)); +} + +static int +g_stat(Char *fn, struct freebsd11_stat *sb, glob11_t *pglob) +{ + char buf[MAXPATHLEN + MB_LEN_MAX - 1]; + + if (g_Ctoc(fn, buf, sizeof(buf))) { + errno = ENAMETOOLONG; + return (-1); + } + if (pglob->gl_flags & GLOB_ALTDIRFUNC) + return ((*pglob->gl_stat)(buf, sb)); + return (freebsd11_stat(buf, sb)); +} + +static const Char * +g_strchr(const Char *str, wchar_t ch) +{ + + do { + if (*str == ch) + return (str); + } while (*str++); + return (NULL); +} + +static int +g_Ctoc(const Char *str, char *buf, size_t len) +{ + mbstate_t mbs; + size_t clen; + + memset(&mbs, 0, sizeof(mbs)); + while (len >= MB_CUR_MAX) { + clen = wcrtomb(buf, CHAR(*str), &mbs); + if (clen == (size_t)-1) { + /* XXX See initial comment #2. */ + *buf = (char)CHAR(*str); + clen = 1; + memset(&mbs, 0, sizeof(mbs)); + } + if (CHAR(*str) == EOS) + return (0); + str++; + buf += clen; + len -= clen; + } + return (1); +} + +static int +err_nomatch(glob11_t *pglob, struct glob_limit *limit, const char *origpat) { + /* + * If there was no match we are going to append the origpat + * if GLOB_NOCHECK was specified or if GLOB_NOMAGIC was specified + * and the origpat did not contain any magic characters + * GLOB_NOMAGIC is there just for compatibility with csh. + */ + if ((pglob->gl_flags & GLOB_NOCHECK) || + ((pglob->gl_flags & GLOB_NOMAGIC) && + !(pglob->gl_flags & GLOB_MAGCHAR))) + return (globextend(NULL, pglob, limit, origpat)); + return (GLOB_NOMATCH); +} + +static int +err_aborted(glob11_t *pglob, int err, char *buf) { + if ((pglob->gl_errfunc != NULL && pglob->gl_errfunc(buf, err)) || + (pglob->gl_flags & GLOB_ERR)) + return (GLOB_ABORTED); + return (0); +} + +#ifdef DEBUG +static void +qprintf(const char *str, Char *s) +{ + Char *p; + + (void)printf("%s\n", str); + if (s != NULL) { + for (p = s; *p != EOS; p++) + (void)printf("%c", (char)CHAR(*p)); + (void)printf("\n"); + for (p = s; *p != EOS; p++) + (void)printf("%c", (isprot(*p) ? '\\' : ' ')); + (void)printf("\n"); + for (p = s; *p != EOS; p++) + (void)printf("%c", (ismeta(*p) ? '_' : ' ')); + (void)printf("\n"); + } +} +#endif + +__sym_compat(glob, freebsd11_glob, FBSD_1.0); +__sym_compat(globfree, freebsd11_globfree, FBSD_1.0); diff --git a/lib/libc/gen/glob-compat11.h b/lib/libc/gen/glob-compat11.h new file mode 100644 index 000000000000..d43086f819c5 --- /dev/null +++ b/lib/libc/gen/glob-compat11.h @@ -0,0 +1,72 @@ +/* + * Copyright (c) 1989, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Guido van Rossum. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)glob.h 8.1 (Berkeley) 6/2/93 + * from: $FreeBSD$ + * $FreeBSD$ + */ + +#ifndef _GLOB_COMPAT11_H_ +#define _GLOB_COMPAT11_H_ + +#include <sys/cdefs.h> +#include <sys/types.h> +#include <glob.h> + +struct freebsd11_stat; +typedef struct { + size_t gl_pathc; /* Count of total paths so far. */ + size_t gl_matchc; /* Count of paths matching pattern. */ + size_t gl_offs; /* Reserved at beginning of gl_pathv. */ + int gl_flags; /* Copy of flags parameter to glob. */ + char **gl_pathv; /* List of paths matching pattern. */ + /* Copy of errfunc parameter to glob. */ + int (*gl_errfunc)(const char *, int); + + /* + * Alternate filesystem access methods for glob; replacement + * versions of closedir(3), readdir(3), opendir(3), stat(2) + * and lstat(2). + */ + void (*gl_closedir)(void *); + struct freebsd11_dirent *(*gl_readdir)(void *); + void *(*gl_opendir)(const char *); + int (*gl_lstat)(const char *, struct freebsd11_stat *); + int (*gl_stat)(const char *, struct freebsd11_stat *); +} glob11_t; + +__BEGIN_DECLS +int freebsd11_glob(const char * __restrict, int, + int (*)(const char *, int), glob11_t * __restrict); +void freebsd11_globfree(glob11_t *); +__END_DECLS + +#endif /* !_GLOB_COMPAT11_H_ */ diff --git a/lib/libc/gen/nftw-compat11.c b/lib/libc/gen/nftw-compat11.c new file mode 100644 index 000000000000..5293f9ed6ad4 --- /dev/null +++ b/lib/libc/gen/nftw-compat11.c @@ -0,0 +1,115 @@ +/* + * Copyright (c) 2003, 2004 Todd C. Miller <Todd.Miller@courtesan.com> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Sponsored in part by the Defense Advanced Research Projects + * Agency (DARPA) and Air Force Research Laboratory, Air Force + * Materiel Command, USAF, under agreement number F39502-99-1-0512. + * + * from: $OpenBSD: nftw.c,v 1.7 2006/03/31 19:41:44 millert Exp $ + * from: $FreeBSD$ + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <sys/types.h> +#include <sys/stat.h> +#include <errno.h> +#include <fts.h> +#include <ftw.h> + +#include "fts-compat11.h" + +int +freebsd11_nftw(const char *path, + int (*fn)(const char *, const struct freebsd11_stat *, int, struct FTW *), + int nfds, int ftwflags) +{ + char * const paths[2] = { (char *)path, NULL }; + struct FTW ftw; + FTSENT11 *cur; + FTS11 *ftsp; + int error = 0, ftsflags, fnflag, postorder, sverrno; + + /* XXX - nfds is currently unused */ + if (nfds < 1) { + errno = EINVAL; + return (-1); + } + + ftsflags = FTS_COMFOLLOW; + if (!(ftwflags & FTW_CHDIR)) + ftsflags |= FTS_NOCHDIR; + if (ftwflags & FTW_MOUNT) + ftsflags |= FTS_XDEV; + if (ftwflags & FTW_PHYS) + ftsflags |= FTS_PHYSICAL; + else + ftsflags |= FTS_LOGICAL; + postorder = (ftwflags & FTW_DEPTH) != 0; + ftsp = freebsd11_fts_open(paths, ftsflags, NULL); + if (ftsp == NULL) + return (-1); + while ((cur = freebsd11_fts_read(ftsp)) != NULL) { + switch (cur->fts_info) { + case FTS_D: + if (postorder) + continue; + fnflag = FTW_D; + break; + case FTS_DC: + continue; + case FTS_DNR: + fnflag = FTW_DNR; + break; + case FTS_DP: + if (!postorder) + continue; + fnflag = FTW_DP; + break; + case FTS_F: + case FTS_DEFAULT: + fnflag = FTW_F; + break; + case FTS_NS: + case FTS_NSOK: + fnflag = FTW_NS; + break; + case FTS_SL: + fnflag = FTW_SL; + break; + case FTS_SLNONE: + fnflag = FTW_SLN; + break; + default: + error = -1; + goto done; + } + ftw.base = cur->fts_pathlen - cur->fts_namelen; + ftw.level = cur->fts_level; + error = fn(cur->fts_path, cur->fts_statp, fnflag, &ftw); + if (error != 0) + break; + } +done: + sverrno = errno; + if (freebsd11_fts_close(ftsp) != 0 && error == 0) + error = -1; + else + errno = sverrno; + return (error); +} + +__sym_compat(nftw, freebsd11_nftw, FBSD_1.0); diff --git a/lib/libc/gen/opendir.c b/lib/libc/gen/opendir.c index f828b8d7598f..927e08b8fcc8 100644 --- a/lib/libc/gen/opendir.c +++ b/lib/libc/gen/opendir.c @@ -296,6 +296,7 @@ __opendir_common(int fd, int flags, bool use_current_pos) dirp->dd_td = (struct _telldir *)((char *)dirp + sizeof(DIR)); LIST_INIT(&dirp->dd_td->td_locq); dirp->dd_td->td_loccnt = 0; + dirp->dd_compat_de = NULL; /* * Use the system page size if that is a multiple of DIRBLKSIZ. diff --git a/lib/libc/gen/readdir-compat11.c b/lib/libc/gen/readdir-compat11.c new file mode 100644 index 000000000000..c374d35e7392 --- /dev/null +++ b/lib/libc/gen/readdir-compat11.c @@ -0,0 +1,120 @@ +/* + * Copyright (c) 1983, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * from: + * $FreeBSD$ + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static char sccsid[] = "@(#)readdir.c 8.3 (Berkeley) 9/29/94"; +#endif /* LIBC_SCCS and not lint */ +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include "namespace.h" +#include <sys/param.h> +#define _WANT_FREEBSD11_DIRENT +#include <dirent.h> +#include <errno.h> +#include <stdbool.h> +#include <stddef.h> +#include <stdlib.h> +#include <string.h> +#include <pthread.h> +#include "un-namespace.h" + +#include "libc_private.h" +#include "gen-private.h" +#include "telldir.h" + +#include "gen-compat.h" + +static bool +freebsd11_cvtdirent(struct freebsd11_dirent *dstdp, struct dirent *srcdp) +{ + + if (srcdp->d_namlen >= sizeof(dstdp->d_name)) + return (false); + dstdp->d_type = srcdp->d_type; + dstdp->d_namlen = srcdp->d_namlen; + dstdp->d_fileno = srcdp->d_fileno; /* truncate */ + dstdp->d_reclen = FREEBSD11_DIRSIZ(dstdp); + bcopy(srcdp->d_name, dstdp->d_name, dstdp->d_namlen); + bzero(dstdp->d_name + dstdp->d_namlen, + dstdp->d_reclen - offsetof(struct freebsd11_dirent, d_name) - + dstdp->d_namlen); + return (true); +} + +struct freebsd11_dirent * +freebsd11_readdir(DIR *dirp) +{ + struct freebsd11_dirent *dstdp; + struct dirent *dp; + + if (__isthreaded) + _pthread_mutex_lock(&dirp->dd_lock); + dp = _readdir_unlocked(dirp, RDU_SKIP); + if (dp != NULL) { + if (dirp->dd_compat_de == NULL) + dirp->dd_compat_de = malloc(sizeof(struct + freebsd11_dirent)); + if (freebsd11_cvtdirent(dirp->dd_compat_de, dp)) + dstdp = dirp->dd_compat_de; + else + dstdp = NULL; + } else + dstdp = NULL; + if (__isthreaded) + _pthread_mutex_unlock(&dirp->dd_lock); + + return (dstdp); +} + +int +freebsd11_readdir_r(DIR *dirp, struct freebsd11_dirent *entry, + struct freebsd11_dirent **result) +{ + struct dirent xentry, *xresult; + int error; + + error = __readdir_r(dirp, &xentry, &xresult); + if (error != 0) + return (error); + if (xresult != NULL) { + if (freebsd11_cvtdirent(entry, &xentry)) + *result = entry; + else /* should not happen due to RDU_SHORT */ + *result = NULL; + } else + *result = NULL; + return (0); +} + +__sym_compat(readdir, freebsd11_readdir, FBSD_1.0); +__sym_compat(readdir_r, freebsd11_readdir_r, FBSD_1.0); diff --git a/lib/libc/gen/readdir.c b/lib/libc/gen/readdir.c index a547f47857bb..22623bb0876b 100644 --- a/lib/libc/gen/readdir.c +++ b/lib/libc/gen/readdir.c @@ -49,7 +49,7 @@ __FBSDID("$FreeBSD$"); * get next entry in a directory. */ struct dirent * -_readdir_unlocked(DIR *dirp, int skip) +_readdir_unlocked(DIR *dirp, int flags) { struct dirent *dp; long initial_seek; @@ -80,10 +80,13 @@ _readdir_unlocked(DIR *dirp, int skip) dp->d_reclen > dirp->dd_len + 1 - dirp->dd_loc) return (NULL); dirp->dd_loc += dp->d_reclen; - if (dp->d_ino == 0 && skip) + if (dp->d_ino == 0 && (flags & RDU_SKIP) != 0) continue; if (dp->d_type == DT_WHT && (dirp->dd_flags & DTF_HIDEW)) continue; + if (dp->d_namlen >= sizeof(dp->d_name) && + (flags & RDU_SHORT) != 0) + continue; return (dp); } } @@ -91,34 +94,31 @@ _readdir_unlocked(DIR *dirp, int skip) struct dirent * readdir(DIR *dirp) { - struct dirent *dp; + struct dirent *dp; - if (__isthreaded) { + if (__isthreaded) _pthread_mutex_lock(&dirp->dd_lock); - dp = _readdir_unlocked(dirp, 1); + dp = _readdir_unlocked(dirp, RDU_SKIP); + if (__isthreaded) _pthread_mutex_unlock(&dirp->dd_lock); - } - else - dp = _readdir_unlocked(dirp, 1); return (dp); } int -readdir_r(DIR *dirp, struct dirent *entry, struct dirent **result) +__readdir_r(DIR *dirp, struct dirent *entry, struct dirent **result) { struct dirent *dp; int saved_errno; saved_errno = errno; errno = 0; - if (__isthreaded) { + if (__isthreaded) _pthread_mutex_lock(&dirp->dd_lock); - if ((dp = _readdir_unlocked(dirp, 1)) != NULL) - memcpy(entry, dp, _GENERIC_DIRSIZ(dp)); - _pthread_mutex_unlock(&dirp->dd_lock); - } - else if ((dp = _readdir_unlocked(dirp, 1)) != NULL) + dp = _readdir_unlocked(dirp, RDU_SKIP | RDU_SHORT); + if (dp != NULL) memcpy(entry, dp, _GENERIC_DIRSIZ(dp)); + if (__isthreaded) + _pthread_mutex_unlock(&dirp->dd_lock); if (errno != 0) { if (dp == NULL) @@ -133,3 +133,5 @@ readdir_r(DIR *dirp, struct dirent *entry, struct dirent **result) return (0); } + +__strong_reference(__readdir_r, readdir_r); diff --git a/lib/libc/gen/scandir-compat11.c b/lib/libc/gen/scandir-compat11.c new file mode 100644 index 000000000000..28120c0bc13d --- /dev/null +++ b/lib/libc/gen/scandir-compat11.c @@ -0,0 +1,174 @@ +/* + * Copyright (c) 1983, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * from: + * $FreeBSD$ + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static char sccsid[] = "@(#)scandir.c 8.3 (Berkeley) 1/2/94"; +#endif /* LIBC_SCCS and not lint */ +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +/* + * Scan the directory dirname calling select to make a list of selected + * directory entries then sort using qsort and compare routine dcomp. + * Returns the number of entries and a pointer to a list of pointers to + * struct dirent (through namelist). Returns -1 if there were any errors. + */ + +#include "namespace.h" +#define _WANT_FREEBSD11_DIRENT +#include <dirent.h> +#include <stdlib.h> +#include <string.h> +#include "un-namespace.h" + +#include "gen-compat.h" + +#ifdef I_AM_SCANDIR_B +#include "block_abi.h" +#define SELECT(x) CALL_BLOCK(select, x) +#ifndef __BLOCKS__ +void +qsort_b(void *, size_t, size_t, void*); +#endif +#else +#define SELECT(x) select(x) +#endif + +static int freebsd11_alphasort_thunk(void *thunk, const void *p1, + const void *p2); + +int +#ifdef I_AM_SCANDIR_B +freebsd11_scandir_b(const char *dirname, struct freebsd11_dirent ***namelist, + DECLARE_BLOCK(int, select, const struct freebsd11_dirent *), + DECLARE_BLOCK(int, dcomp, const struct freebsd11_dirent **, + const struct freebsd11_dirent **)) +#else +freebsd11_scandir(const char *dirname, struct freebsd11_dirent ***namelist, + int (*select)(const struct freebsd11_dirent *), + int (*dcomp)(const struct freebsd11_dirent **, + const struct freebsd11_dirent **)) +#endif +{ + struct freebsd11_dirent *d, *p, **names = NULL; + size_t arraysz, numitems; + DIR *dirp; + + if ((dirp = opendir(dirname)) == NULL) + return(-1); + + numitems = 0; + arraysz = 32; /* initial estimate of the array size */ + names = (struct freebsd11_dirent **)malloc( + arraysz * sizeof(struct freebsd11_dirent *)); + if (names == NULL) + goto fail; + + while ((d = freebsd11_readdir(dirp)) != NULL) { + if (select != NULL && !SELECT(d)) + continue; /* just selected names */ + /* + * Make a minimum size copy of the data + */ + p = (struct freebsd11_dirent *)malloc(FREEBSD11_DIRSIZ(d)); + if (p == NULL) + goto fail; + p->d_fileno = d->d_fileno; + p->d_type = d->d_type; + p->d_reclen = d->d_reclen; + p->d_namlen = d->d_namlen; + bcopy(d->d_name, p->d_name, p->d_namlen + 1); + /* + * Check to make sure the array has space left and + * realloc the maximum size. + */ + if (numitems >= arraysz) { + struct freebsd11_dirent **names2; + + names2 = reallocarray(names, arraysz, + 2 * sizeof(struct freebsd11_dirent *)); + if (names2 == NULL) { + free(p); + goto fail; + } + names = names2; + arraysz *= 2; + } + names[numitems++] = p; + } + closedir(dirp); + if (numitems && dcomp != NULL) +#ifdef I_AM_SCANDIR_B + qsort_b(names, numitems, sizeof(struct freebsd11_dirent *), + (void*)dcomp); +#else + qsort_r(names, numitems, sizeof(struct freebsd11_dirent *), + &dcomp, freebsd11_alphasort_thunk); +#endif + *namelist = names; + return (numitems); + +fail: + while (numitems > 0) + free(names[--numitems]); + free(names); + closedir(dirp); + return (-1); +} + +/* + * Alphabetic order comparison routine for those who want it. + * POSIX 2008 requires that alphasort() uses strcoll(). + */ +int +freebsd11_alphasort(const struct freebsd11_dirent **d1, + const struct freebsd11_dirent **d2) +{ + + return (strcoll((*d1)->d_name, (*d2)->d_name)); +} + +static int +freebsd11_alphasort_thunk(void *thunk, const void *p1, const void *p2) +{ + int (*dc)(const struct freebsd11_dirent **, const struct + freebsd11_dirent **); + + dc = *(int (**)(const struct freebsd11_dirent **, + const struct freebsd11_dirent **))thunk; + return (dc((const struct freebsd11_dirent **)p1, + (const struct freebsd11_dirent **)p2)); +} + +__sym_compat(alphasort, freebsd11_alphasort, FBSD_1.0); +__sym_compat(scandir, freebsd11_scandir, FBSD_1.0); +__sym_compat(scandir_b, freebsd11_scandir_b, FBSD_1.4); diff --git a/lib/libc/gen/scandir.c b/lib/libc/gen/scandir.c index 00183b61de73..b7ec171764c4 100644 --- a/lib/libc/gen/scandir.c +++ b/lib/libc/gen/scandir.c @@ -59,17 +59,6 @@ qsort_b(void *, size_t, size_t, void*); static int alphasort_thunk(void *thunk, const void *p1, const void *p2); -/* - * The DIRSIZ macro is the minimum record length which will hold the directory - * entry. This requires the amount of space in struct dirent without the - * d_name field, plus enough space for the name and a terminating nul byte - * (dp->d_namlen + 1), rounded up to a 4 byte boundary. - */ -#undef DIRSIZ -#define DIRSIZ(dp) \ - ((sizeof(struct dirent) - sizeof(dp)->d_name) + \ - (((dp)->d_namlen + 1 + 3) &~ 3)) - int #ifdef I_AM_SCANDIR_B scandir_b(const char *dirname, struct dirent ***namelist, @@ -100,7 +89,7 @@ scandir(const char *dirname, struct dirent ***namelist, /* * Make a minimum size copy of the data */ - p = (struct dirent *)malloc(DIRSIZ(d)); + p = (struct dirent *)malloc(_GENERIC_DIRSIZ(d)); if (p == NULL) goto fail; p->d_fileno = d->d_fileno; diff --git a/lib/libc/gen/telldir.h b/lib/libc/gen/telldir.h index bccabb1aea53..50adb351e91d 100644 --- a/lib/libc/gen/telldir.h +++ b/lib/libc/gen/telldir.h @@ -47,7 +47,7 @@ struct ddloc { LIST_ENTRY(ddloc) loc_lqe; /* entry in list */ long loc_index; /* key associated with structure */ - long loc_seek; /* magic cookie returned by getdirentries */ + off_t loc_seek; /* magic cookie returned by getdirentries */ long loc_loc; /* offset of entry in buffer */ }; @@ -66,4 +66,7 @@ void _reclaim_telldir(DIR *); void _seekdir(DIR *, long); void _fixtelldir(DIR *dirp, long oldseek, long oldloc); +#define RDU_SKIP 0x0001 +#define RDU_SHORT 0x0002 + #endif diff --git a/lib/libc/include/compat.h b/lib/libc/include/compat.h index d0abfdf70fdb..559c8502fb93 100644 --- a/lib/libc/include/compat.h +++ b/lib/libc/include/compat.h @@ -44,6 +44,27 @@ __sym_compat(msgctl, freebsd7_msgctl, FBSD_1.0); __sym_compat(shmctl, freebsd7_shmctl, FBSD_1.0); #endif +__sym_compat(nfstat, freebsd11_nfstat, FBSD_1.0); +__sym_compat(nlstat, freebsd11_nlstat, FBSD_1.0); +__sym_compat(nstat, freebsd11_nstat, FBSD_1.0); + +__sym_compat(fhstat, freebsd11_fhstat, FBSD_1.0); +__sym_compat(fstat, freebsd11_fstat, FBSD_1.0); +__sym_compat(fstatat, freebsd11_fstatat, FBSD_1.1); +__sym_compat(lstat, freebsd11_lstat, FBSD_1.0); +__sym_compat(stat, freebsd11_stat, FBSD_1.0); + +__sym_compat(getdents, freebsd11_getdents, FBSD_1.0); +__sym_compat(getdirentries, freebsd11_getdirentries, FBSD_1.0); + +__sym_compat(getfsstat, freebsd11_getfsstat, FBSD_1.0); +__sym_compat(fhstatfs, freebsd11_fhstatfs, FBSD_1.0); +__sym_compat(fstatfs, freebsd11_fstatfs, FBSD_1.0); +__sym_compat(statfs, freebsd11_statfs, FBSD_1.0); + +__sym_compat(mknod, freebsd11_mknod, FBSD_1.0); +__sym_compat(mknodat, freebsd11_mknodat, FBSD_1.1); + #undef __sym_compat #define __weak_reference(sym,alias) \ diff --git a/lib/libc/include/libc_private.h b/lib/libc/include/libc_private.h index 384f61fb223b..6409ff331754 100644 --- a/lib/libc/include/libc_private.h +++ b/lib/libc/include/libc_private.h @@ -307,6 +307,7 @@ struct pollfd; struct rusage; struct sigaction; struct sockaddr; +struct stat; struct timespec; struct timeval; struct timezone; @@ -323,8 +324,10 @@ int __sys_clock_nanosleep(__clockid_t, int, const struct timespec *, struct timespec *); int __sys_close(int); int __sys_connect(int, const struct sockaddr *, __socklen_t); +__ssize_t __sys_getdirentries(int, char *, __size_t, __off_t *); int __sys_fcntl(int, int, ...); int __sys_fdatasync(int); +int __sys_fstatat(int, const char *, struct stat *, int); int __sys_fsync(int); __pid_t __sys_fork(void); int __sys_ftruncate(int, __off_t); diff --git a/lib/libc/sys/Makefile.inc b/lib/libc/sys/Makefile.inc index 76eeebd9d71c..b641125096d1 100644 --- a/lib/libc/sys/Makefile.inc +++ b/lib/libc/sys/Makefile.inc @@ -35,6 +35,8 @@ SRCS+= \ __error.c \ interposing_table.c +SRCS+= getdents.c lstat.c mknod.c stat.c + SRCS+= futimens.c utimensat.c NOASM+= futimens.o utimensat.o PSEUDO+= _futimens.o _utimensat.o diff --git a/lib/libc/sys/Symbol.map b/lib/libc/sys/Symbol.map index 6a5c838a762b..feccda6f6bf4 100644 --- a/lib/libc/sys/Symbol.map +++ b/lib/libc/sys/Symbol.map @@ -85,26 +85,19 @@ FBSD_1.0 { fchown; fcntl; fhopen; - fhstat; - fhstatfs; flock; fork; fpathconf; - fstat; - fstatfs; fsync; futimes; getaudit; getaudit_addr; getauid; getcontext; - getdents; - getdirentries; getdtablesize; getegid; geteuid; getfh; - getfsstat; getgid; getgroups; getitimer; @@ -163,7 +156,6 @@ FBSD_1.0 { link; lio_listio; listen; - lstat; lutimes; mac_syscall; madvise; @@ -171,7 +163,6 @@ FBSD_1.0 { minherit; mkdir; mkfifo; - mknod; mlock; mlockall; modfind; @@ -192,10 +183,7 @@ FBSD_1.0 { netbsd_lchown; netbsd_msync; nfssvc; - nfstat; - nlstat; nmount; - nstat; ntp_adjtime; ntp_gettime; open; @@ -275,8 +263,6 @@ FBSD_1.0 { sigwaitinfo; socket; socketpair; - stat; - statfs; swapoff; swapon; symlink; @@ -330,7 +316,6 @@ FBSD_1.1 { fchmodat; fchownat; fexecve; - fstatat; futimesat; jail_get; jail_set; @@ -339,7 +324,6 @@ FBSD_1.1 { lpathconf; mkdirat; mkfifoat; - mknodat; msgctl; readlinkat; renameat; @@ -401,6 +385,19 @@ FBSD_1.4 { FBSD_1.5 { clock_nanosleep; fdatasync; + fhstat; + fhstatfs; + fstat; + fstatat; + fstatfs; + getdents; + getdirentries; + getfsstat; + lstat; + mknod; + mknodat; + stat; + statfs; }; FBSDprivate_1.0 { @@ -606,8 +603,6 @@ FBSDprivate_1.0 { __sys_getauid; _getcontext; __sys_getcontext; - _getdents; - __sys_getdents; _getdirentries; __sys_getdirentries; _getdtablesize; @@ -736,8 +731,6 @@ FBSDprivate_1.0 { __sys_lio_listio; _listen; __sys_listen; - _lstat; - __sys_lstat; _lutimes; __sys_lutimes; _mac_syscall; @@ -796,14 +789,8 @@ FBSDprivate_1.0 { __sys_netbsd_msync; _nfssvc; __sys_nfssvc; - _nfstat; - __sys_nfstat; - _nlstat; - __sys_nlstat; _nmount; __sys_nmount; - _nstat; - __sys_nstat; _ntp_adjtime; __sys_ntp_adjtime; _ntp_gettime; @@ -971,8 +958,6 @@ FBSDprivate_1.0 { __sys_socket; _socketpair; __sys_socketpair; - _stat; - __sys_stat; _statfs; __sys_statfs; _swapcontext; diff --git a/lib/libc/sys/getdents.c b/lib/libc/sys/getdents.c new file mode 100644 index 000000000000..c8a2878c972f --- /dev/null +++ b/lib/libc/sys/getdents.c @@ -0,0 +1,41 @@ +/*- + * Copyright (c) 2012 Gleb Kurtsou <gleb@FreeBSD.org> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include "namespace.h" +#include <sys/param.h> +#include <sys/syscall.h> +#include <dirent.h> +#include "libc_private.h" + +ssize_t +getdents(int fd, char *buf, size_t nbytes) +{ + + return (__sys_getdirentries(fd, buf, nbytes, NULL)); +} diff --git a/lib/libc/sys/getdirentries.2 b/lib/libc/sys/getdirentries.2 index ace8faa7521c..d3f2129d400f 100644 --- a/lib/libc/sys/getdirentries.2 +++ b/lib/libc/sys/getdirentries.2 @@ -40,10 +40,10 @@ .Sh SYNOPSIS .In sys/types.h .In dirent.h -.Ft int -.Fn getdirentries "int fd" "char *buf" "int nbytes" "long *basep" -.Ft int -.Fn getdents "int fd" "char *buf" "int nbytes" +.Ft ssize_t +.Fn getdirentries "int fd" "char *buf" "size_t nbytes" "off_t *basep" +.Ft ssize_t +.Fn getdents "int fd" "char *buf" "size_t nbytes" .Sh DESCRIPTION The .Fn getdirentries diff --git a/lib/libc/sys/lstat.c b/lib/libc/sys/lstat.c new file mode 100644 index 000000000000..ccc73e3d3d06 --- /dev/null +++ b/lib/libc/sys/lstat.c @@ -0,0 +1,43 @@ +/*- + * Copyright (c) 2012 Gleb Kurtsou <gleb@FreeBSD.org> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include "namespace.h" +#include <sys/param.h> +#include <sys/fcntl.h> +#include <sys/syscall.h> +#include <sys/stat.h> +#include <unistd.h> +#include "libc_private.h" + +int +lstat(const char *path, struct stat *sb) +{ + + return (__sys_fstatat(AT_FDCWD, path, sb, AT_SYMLINK_NOFOLLOW)); +} diff --git a/lib/libc/sys/mknod.c b/lib/libc/sys/mknod.c new file mode 100644 index 000000000000..3bb3853b5849 --- /dev/null +++ b/lib/libc/sys/mknod.c @@ -0,0 +1,45 @@ +/*- + * Copyright (c) 2011 Gleb Kurtsou <gleb@FreeBSD.org> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include "namespace.h" +#include <sys/param.h> +#include <sys/fcntl.h> +#include <sys/syscall.h> +#include <sys/stat.h> +#include <unistd.h> +#include "libc_private.h" + +int __sys_mknodat(int, const char *, mode_t, dev_t); + +int +mknod(const char *path, mode_t mode, dev_t dev) +{ + + return (__sys_mknodat(AT_FDCWD, path, mode, dev)); +} diff --git a/lib/libc/sys/stat.c b/lib/libc/sys/stat.c new file mode 100644 index 000000000000..6b58daa9e515 --- /dev/null +++ b/lib/libc/sys/stat.c @@ -0,0 +1,43 @@ +/*- + * Copyright (c) 2012 Gleb Kurtsou <gleb@FreeBSD.org> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include "namespace.h" +#include <sys/param.h> +#include <sys/fcntl.h> +#include <sys/syscall.h> +#include <sys/stat.h> +#include <unistd.h> +#include "libc_private.h" + +int +stat(const char *path, struct stat *sb) +{ + + return (__sys_fstatat(AT_FDCWD, path, sb, 0)); +} diff --git a/lib/libc/sys/statfs.2 b/lib/libc/sys/statfs.2 index 7a95871125ca..a7383c4ce12b 100644 --- a/lib/libc/sys/statfs.2 +++ b/lib/libc/sys/statfs.2 @@ -28,7 +28,7 @@ .\" @(#)statfs.2 8.5 (Berkeley) 5/24/95 .\" $FreeBSD$ .\" -.Dd November 1, 2006 +.Dd February 13, 2017 .Dt STATFS 2 .Os .Sh NAME @@ -66,8 +66,8 @@ typedef struct fsid { int32_t val[2]; } fsid_t; /* file system id type */ */ #define MFSNAMELEN 16 /* length of type name including null */ -#define MNAMELEN 88 /* size of on/from name bufs */ -#define STATFS_VERSION 0x20030518 /* current version number */ +#define MNAMELEN 1024 /* size of on/from name bufs */ +#define STATFS_VERSION 0x20140518 /* current version number */ struct statfs { uint32_t f_version; /* structure version number */ diff --git a/lib/libkvm/kvm_proc.c b/lib/libkvm/kvm_proc.c index ac14ef613990..a7886ab556ab 100644 --- a/lib/libkvm/kvm_proc.c +++ b/lib/libkvm/kvm_proc.c @@ -452,6 +452,7 @@ nopgrp: } else { kp->ki_stat = SZOMB; } + kp->ki_tdev_freebsd11 = kp->ki_tdev; /* truncate */ bcopy(&kinfo_proc, bp, sizeof(kinfo_proc)); ++bp; ++cnt; diff --git a/lib/libmilter/Makefile b/lib/libmilter/Makefile index a8efe9cec7bd..17bb09857fcf 100644 --- a/lib/libmilter/Makefile +++ b/lib/libmilter/Makefile @@ -29,6 +29,7 @@ SRCS+= main.c engine.c listener.c handler.c comm.c monitor.c smfi.c \ CLEANFILES+=sm_os.h WARNS?= 0 +SHLIB_MAJOR= 6 sm_os.h: ${SENDMAIL_DIR}/include/sm/os/sm_os_freebsd.h .NOMETA ln -sf ${.ALLSRC} ${.TARGET} diff --git a/lib/libprocstat/Makefile b/lib/libprocstat/Makefile index 8d4fae0dffe9..9d80d17e16a8 100644 --- a/lib/libprocstat/Makefile +++ b/lib/libprocstat/Makefile @@ -13,6 +13,10 @@ SRCS= cd9660.c \ smbfs.c \ udf.c +.if ${MK_SYMVER} == yes +SRCS+= libprocstat_compat.c +.endif + VERSION_DEF= ${LIBCSRCDIR}/Versions.def SYMBOL_MAPS= ${.CURDIR}/Symbol.map diff --git a/lib/libprocstat/Symbol.map b/lib/libprocstat/Symbol.map index 75a8916aca67..a78a4691fe5d 100644 --- a/lib/libprocstat/Symbol.map +++ b/lib/libprocstat/Symbol.map @@ -6,9 +6,7 @@ FBSD_1.2 { procstat_freefiles; procstat_freeprocs; procstat_get_pipe_info; - procstat_get_pts_info; procstat_get_socket_info; - procstat_get_vnode_info; procstat_getfiles; procstat_getprocs; procstat_open_kvm; @@ -22,8 +20,6 @@ FBSD_1.3 { procstat_freegroups; procstat_freekstack; procstat_freevmmap; - procstat_get_sem_info; - procstat_get_shm_info; procstat_getargv; procstat_getauxv; procstat_getenvv; @@ -40,4 +36,8 @@ FBSD_1.3 { FBSD_1.5 { procstat_freeptlwpinfo; procstat_getptlwpinfo; + procstat_get_pts_info; + procstat_get_sem_info; + procstat_get_shm_info; + procstat_get_vnode_info; }; diff --git a/lib/libprocstat/libprocstat.c b/lib/libprocstat/libprocstat.c index 7d42acce4201..d674adc4f9ea 100644 --- a/lib/libprocstat/libprocstat.c +++ b/lib/libprocstat/libprocstat.c @@ -1337,12 +1337,12 @@ procstat_get_vnode_info_sysctl(struct filestat *fst, struct vnstat *vn, struct statfs stbuf; struct kinfo_file *kif; struct kinfo_vmentry *kve; + char *name, *path; uint64_t fileid; uint64_t size; - char *name, *path; - uint32_t fsid; + uint64_t fsid; + uint64_t rdev; uint16_t mode; - uint32_t rdev; int vntype; int status; @@ -1545,8 +1545,10 @@ procstat_get_socket_info_sysctl(struct filestat *fst, struct sockstat *sock, sock->dom_family = kif->kf_sock_domain; sock->so_pcb = kif->kf_un.kf_sock.kf_sock_pcb; strlcpy(sock->dname, kif->kf_path, sizeof(sock->dname)); - bcopy(&kif->kf_sa_local, &sock->sa_local, kif->kf_sa_local.ss_len); - bcopy(&kif->kf_sa_peer, &sock->sa_peer, kif->kf_sa_peer.ss_len); + bcopy(&kif->kf_un.kf_sock.kf_sa_local, &sock->sa_local, + kif->kf_un.kf_sock.kf_sa_local.ss_len); + bcopy(&kif->kf_un.kf_sock.kf_sa_peer, &sock->sa_peer, + kif->kf_un.kf_sock.kf_sa_peer.ss_len); /* * Protocol specific data. diff --git a/lib/libprocstat/libprocstat.h b/lib/libprocstat/libprocstat.h index 00b6f1c1c110..7584878252d4 100644 --- a/lib/libprocstat/libprocstat.h +++ b/lib/libprocstat/libprocstat.h @@ -120,15 +120,15 @@ struct filestat { struct vnstat { uint64_t vn_fileid; uint64_t vn_size; + uint64_t vn_dev; + uint64_t vn_fsid; char *vn_mntdir; - uint32_t vn_dev; - uint32_t vn_fsid; int vn_type; uint16_t vn_mode; char vn_devname[SPECNAMELEN + 1]; }; struct ptsstat { - uint32_t dev; + uint64_t dev; char devname[SPECNAMELEN + 1]; }; struct pipestat { diff --git a/lib/libprocstat/libprocstat_compat.c b/lib/libprocstat/libprocstat_compat.c new file mode 100644 index 000000000000..52d80c7afab4 --- /dev/null +++ b/lib/libprocstat/libprocstat_compat.c @@ -0,0 +1,144 @@ +/*- + * Copyright (c) 2014 Gleb Kurtsou <gleb@FreeBSD.org> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <sys/param.h> +#include <sys/user.h> +#include <sys/socket.h> +#include <string.h> + +#include "libprocstat.h" + +struct freebsd11_ptsstat { + uint32_t dev; + char devname[SPECNAMELEN + 1]; +}; + +struct freebsd11_vnstat { + uint64_t vn_fileid; + uint64_t vn_size; + char *vn_mntdir; + uint32_t vn_dev; + uint32_t vn_fsid; + int vn_type; + uint16_t vn_mode; + char vn_devname[SPECNAMELEN + 1]; +}; +struct freebsd11_semstat { + uint32_t value; + uint16_t mode; +}; +struct freebsd11_shmstat { + uint64_t size; + uint16_t mode; +}; + +int freebsd11_procstat_get_pts_info(struct procstat *procstat, + struct filestat *fst, struct freebsd11_ptsstat *pts, char *errbuf); +int freebsd11_procstat_get_sem_info(struct procstat *procstat, + struct filestat *fst, struct freebsd11_semstat *sem, char *errbuf); +int freebsd11_procstat_get_shm_info(struct procstat *procstat, + struct filestat *fst, struct freebsd11_shmstat *shm, char *errbuf); +int freebsd11_procstat_get_vnode_info(struct procstat *procstat, + struct filestat *fst, struct freebsd11_vnstat *vn, char *errbuf); + +int +freebsd11_procstat_get_pts_info(struct procstat *procstat, + struct filestat *fst, struct freebsd11_ptsstat *pts_compat, char *errbuf) +{ + struct ptsstat pts; + int r; + + r = procstat_get_pts_info(procstat, fst, &pts, errbuf); + if (r != 0) + return (r); + pts_compat->dev = pts.dev; + memcpy(pts_compat->devname, pts.devname, + sizeof(pts_compat->devname)); + return (0); +} + +int +freebsd11_procstat_get_sem_info(struct procstat *procstat, + struct filestat *fst, struct freebsd11_semstat *sem_compat, char *errbuf) +{ + struct semstat sem; + int r; + + r = procstat_get_sem_info(procstat, fst, &sem, errbuf); + if (r != 0) + return (r); + sem_compat->value = sem.value; + sem_compat->mode = sem.mode; + return (0); +} + +int +freebsd11_procstat_get_shm_info(struct procstat *procstat, + struct filestat *fst, struct freebsd11_shmstat *shm_compat, char *errbuf) +{ + struct shmstat shm; + int r; + + r = procstat_get_shm_info(procstat, fst, &shm, errbuf); + if (r != 0) + return (r); + shm_compat->size = shm.size; + shm_compat->mode = shm.mode; + return (0); +} + +int +freebsd11_procstat_get_vnode_info(struct procstat *procstat, + struct filestat *fst, struct freebsd11_vnstat *vn_compat, char *errbuf) +{ + struct vnstat vn; + int r; + + r = procstat_get_vnode_info(procstat, fst, &vn, errbuf); + if (r != 0) + return (r); + vn_compat->vn_fileid = vn.vn_fileid; + vn_compat->vn_size = vn.vn_size; + vn_compat->vn_mntdir = vn.vn_mntdir; + vn_compat->vn_dev = vn.vn_dev; + vn_compat->vn_fsid = vn.vn_fsid; + vn_compat->vn_type = vn.vn_type; + vn_compat->vn_mode = vn.vn_mode; + memcpy(vn_compat->vn_devname, vn.vn_devname, + sizeof(vn_compat->vn_devname)); + return (0); +} + +__sym_compat(procstat_get_pts_info, freebsd11_procstat_get_pts_info, FBSD_1.2); +__sym_compat(procstat_get_vnode_info, freebsd11_procstat_get_vnode_info, + FBSD_1.2); +__sym_compat(procstat_get_sem_info, freebsd11_procstat_get_sem_info, FBSD_1.3); +__sym_compat(procstat_get_shm_info, freebsd11_procstat_get_shm_info, FBSD_1.3); diff --git a/lib/libufs/libufs.h b/lib/libufs/libufs.h index a16d82b604ad..ddc5c9b6b055 100644 --- a/lib/libufs/libufs.h +++ b/lib/libufs/libufs.h @@ -45,8 +45,8 @@ struct uufsd { ufs2_daddr_t d_sblock; /* superblock location */ struct csum *d_sbcsum; /* Superblock summary info */ caddr_t d_inoblock; /* inode block */ - ino_t d_inomin; /* low inode */ - ino_t d_inomax; /* high inode */ + uint32_t d_inomin; /* low inode (not ino_t for ABI compat) */ + uint32_t d_inomax; /* high inode (not ino_t for ABI compat) */ union { struct fs d_fs; /* filesystem information */ char d_sb[MAXBSIZE]; |
