Index: head/lib/libc/gen/auxv.c =================================================================== --- head/lib/libc/gen/auxv.c (revision 366206) +++ head/lib/libc/gen/auxv.c (revision 366207) @@ -1,359 +1,365 @@ /*- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD * * Copyright 2010, 2012 Konstantin Belousov . * 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 ``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 BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ #include __FBSDID("$FreeBSD$"); #include "namespace.h" #include #include #include #include #include #include #include "un-namespace.h" #include "libc_private.h" extern char **environ; extern int _DYNAMIC; #pragma weak _DYNAMIC void *__elf_aux_vector; static pthread_once_t aux_vector_once = PTHREAD_ONCE_INIT; static void init_aux_vector_once(void) { Elf_Addr *sp; sp = (Elf_Addr *)environ; while (*sp++ != 0) ; __elf_aux_vector = (Elf_Auxinfo *)sp; } void __init_elf_aux_vector(void) { if (&_DYNAMIC != NULL) return; _once(&aux_vector_once, init_aux_vector_once); } static pthread_once_t aux_once = PTHREAD_ONCE_INIT; -static int pagesize, osreldate, canary_len, ncpus, pagesizes_len, bsdflags; +static int pagesize, osreldate, ncpus, bsdflags; +static size_t canary_len, pagesizes_len; static int hwcap_present, hwcap2_present; static char *canary, *pagesizes, *execpath; static void *ps_strings, *timekeep; static u_long hwcap, hwcap2; #ifdef __powerpc__ static int powerpc_new_auxv_format = 0; static void _init_aux_powerpc_fixup(void); int _powerpc_elf_aux_info(int, void *, int); #endif static void init_aux(void) { Elf_Auxinfo *aux; for (aux = __elf_aux_vector; aux->a_type != AT_NULL; aux++) { switch (aux->a_type) { case AT_BSDFLAGS: bsdflags = aux->a_un.a_val; break; case AT_CANARY: canary = (char *)(aux->a_un.a_ptr); break; case AT_CANARYLEN: canary_len = aux->a_un.a_val; break; case AT_EXECPATH: execpath = (char *)(aux->a_un.a_ptr); break; case AT_HWCAP: hwcap_present = 1; hwcap = (u_long)(aux->a_un.a_val); break; case AT_HWCAP2: hwcap2_present = 1; hwcap2 = (u_long)(aux->a_un.a_val); break; case AT_PAGESIZES: pagesizes = (char *)(aux->a_un.a_ptr); break; case AT_PAGESIZESLEN: pagesizes_len = aux->a_un.a_val; break; case AT_PAGESZ: pagesize = aux->a_un.a_val; break; case AT_OSRELDATE: osreldate = aux->a_un.a_val; break; case AT_NCPUS: ncpus = aux->a_un.a_val; break; case AT_TIMEKEEP: timekeep = aux->a_un.a_ptr; break; case AT_PS_STRINGS: ps_strings = aux->a_un.a_ptr; break; #ifdef __powerpc__ /* * Since AT_STACKPROT is always set, and the common * value 23 is mutually exclusive with the legacy powerpc * value 21, the existence of AT_STACKPROT proves we are * on the common format. */ case AT_STACKPROT: /* 23 */ powerpc_new_auxv_format = 1; break; #endif } } #ifdef __powerpc__ if (!powerpc_new_auxv_format) _init_aux_powerpc_fixup(); #endif } #ifdef __powerpc__ static void _init_aux_powerpc_fixup(void) { Elf_Auxinfo *aux; /* * Before 1300070, PowerPC platforms had nonstandard numbering for * the aux vector. When running old binaries, the kernel will pass * the vector using the old numbering. Reload affected variables. */ for (aux = __elf_aux_vector; aux->a_type != AT_NULL; aux++) { switch (aux->a_type) { case AT_OLD_CANARY: canary = (char *)(aux->a_un.a_ptr); break; case AT_OLD_CANARYLEN: canary_len = aux->a_un.a_val; break; case AT_OLD_EXECPATH: execpath = (char *)(aux->a_un.a_ptr); break; case AT_OLD_PAGESIZES: pagesizes = (char *)(aux->a_un.a_ptr); break; case AT_OLD_PAGESIZESLEN: pagesizes_len = aux->a_un.a_val; break; case AT_OLD_OSRELDATE: osreldate = aux->a_un.a_val; break; case AT_OLD_NCPUS: ncpus = aux->a_un.a_val; break; } } } int _powerpc_elf_aux_info(int aux, void *buf, int buflen) { /* * If we are in the old auxv format, we need to translate the aux * parameter of elf_aux_info() calls into the common auxv format. * Internal libc calls always use the common format, and they * directly call _elf_aux_info instead of using the weak symbol. */ if (!powerpc_new_auxv_format) { switch (aux) { case AT_OLD_EXECPATH: aux = AT_EXECPATH; break; case AT_OLD_CANARY: aux = AT_CANARY; break; case AT_OLD_CANARYLEN: aux = AT_CANARYLEN; break; case AT_OLD_OSRELDATE: aux = AT_OSRELDATE; break; case AT_OLD_NCPUS: aux = AT_NCPUS; break; case AT_OLD_PAGESIZES: aux = AT_PAGESIZES; break; case AT_OLD_PAGESIZESLEN: aux = AT_PAGESIZESLEN; break; case AT_OLD_STACKPROT: aux = AT_STACKPROT; break; } } return _elf_aux_info(aux, buf, buflen); } __weak_reference(_powerpc_elf_aux_info, elf_aux_info); #else __weak_reference(_elf_aux_info, elf_aux_info); #endif int _elf_aux_info(int aux, void *buf, int buflen) { int res; + size_t buflen_; __init_elf_aux_vector(); if (__elf_aux_vector == NULL) return (ENOSYS); _once(&aux_once, init_aux); + if (buflen < 0) + return (EINVAL); + buflen_ = (size_t)buflen; + switch (aux) { case AT_CANARY: - if (canary != NULL && canary_len >= buflen) { - memcpy(buf, canary, buflen); + if (canary != NULL && canary_len >= buflen_) { + memcpy(buf, canary, buflen_); memset(canary, 0, canary_len); canary = NULL; res = 0; } else res = ENOENT; break; case AT_EXECPATH: if (execpath == NULL) res = ENOENT; else if (buf == NULL) res = EINVAL; else { - if (strlcpy(buf, execpath, buflen) >= buflen) + if (strlcpy(buf, execpath, buflen_) >= buflen_) res = EINVAL; else res = 0; } break; case AT_HWCAP: - if (hwcap_present && buflen == sizeof(u_long)) { + if (hwcap_present && buflen_ == sizeof(u_long)) { *(u_long *)buf = hwcap; res = 0; } else res = ENOENT; break; case AT_HWCAP2: - if (hwcap2_present && buflen == sizeof(u_long)) { + if (hwcap2_present && buflen_ == sizeof(u_long)) { *(u_long *)buf = hwcap2; res = 0; } else res = ENOENT; break; case AT_PAGESIZES: - if (pagesizes != NULL && pagesizes_len >= buflen) { - memcpy(buf, pagesizes, buflen); + if (pagesizes != NULL && pagesizes_len >= buflen_) { + memcpy(buf, pagesizes, buflen_); res = 0; } else res = ENOENT; break; case AT_PAGESZ: - if (buflen == sizeof(int)) { + if (buflen_ == sizeof(int)) { if (pagesize != 0) { *(int *)buf = pagesize; res = 0; } else res = ENOENT; } else res = EINVAL; break; case AT_OSRELDATE: - if (buflen == sizeof(int)) { + if (buflen_ == sizeof(int)) { if (osreldate != 0) { *(int *)buf = osreldate; res = 0; } else res = ENOENT; } else res = EINVAL; break; case AT_NCPUS: - if (buflen == sizeof(int)) { + if (buflen_ == sizeof(int)) { if (ncpus != 0) { *(int *)buf = ncpus; res = 0; } else res = ENOENT; } else res = EINVAL; break; case AT_TIMEKEEP: - if (buflen == sizeof(void *)) { + if (buflen_ == sizeof(void *)) { if (timekeep != NULL) { *(void **)buf = timekeep; res = 0; } else res = ENOENT; } else res = EINVAL; break; case AT_BSDFLAGS: - if (buflen == sizeof(int)) { + if (buflen_ == sizeof(int)) { *(int *)buf = bsdflags; res = 0; } else res = EINVAL; break; case AT_PS_STRINGS: - if (buflen == sizeof(void *)) { + if (buflen_ == sizeof(void *)) { if (ps_strings != NULL) { *(void **)buf = ps_strings; res = 0; } else res = ENOENT; } else res = EINVAL; break; default: res = ENOENT; break; } return (res); } Index: head/lib/libc/gen/basename_compat.c =================================================================== --- head/lib/libc/gen/basename_compat.c (revision 366206) +++ head/lib/libc/gen/basename_compat.c (revision 366207) @@ -1,82 +1,85 @@ /* $OpenBSD: basename.c,v 1.14 2005/08/08 08:05:33 espie Exp $ */ /* * Copyright (c) 1997, 2004 Todd C. Miller * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include +char * __freebsd11_basename_r(const char *path, char *bname); +char * __freebsd11_basename(char *path); + char * __freebsd11_basename_r(const char *path, char *bname) { const char *endp, *startp; size_t len; /* Empty or NULL string gets treated as "." */ if (path == NULL || *path == '\0') { bname[0] = '.'; bname[1] = '\0'; return (bname); } /* Strip any trailing slashes */ endp = path + strlen(path) - 1; while (endp > path && *endp == '/') endp--; /* All slashes becomes "/" */ if (endp == path && *endp == '/') { bname[0] = '/'; bname[1] = '\0'; return (bname); } /* Find the start of the base */ startp = endp; while (startp > path && *(startp - 1) != '/') startp--; len = endp - startp + 1; if (len >= MAXPATHLEN) { errno = ENAMETOOLONG; return (NULL); } memcpy(bname, startp, len); bname[len] = '\0'; return (bname); } char * __freebsd11_basename(char *path) { static char *bname = NULL; if (bname == NULL) { bname = (char *)malloc(MAXPATHLEN); if (bname == NULL) return (NULL); } return (__freebsd11_basename_r(path, bname)); } __sym_compat(basename_r, __freebsd11_basename_r, FBSD_1.2); __sym_compat(basename, __freebsd11_basename, FBSD_1.0); Index: head/lib/libc/gen/crypt.c =================================================================== --- head/lib/libc/gen/crypt.c (revision 366206) +++ head/lib/libc/gen/crypt.c (revision 366207) @@ -1,87 +1,92 @@ /*- * SPDX-License-Identifier: BSD-3-Clause * * Copyright (c) 1989 The Regents of the University of California. * All rights reserved. * * This code is derived from software contributed to Berkeley by * Tom Truscott. * * 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. */ #include __SCCSID("@(#)crypt.c 5.11 (Berkeley) 6/25/91"); __FBSDID("$FreeBSD$"); #include #include #include /* * UNIX password, and DES, encryption. * * since this is non-exportable, this is just a dummy. if you want real * encryption, make sure you've got libcrypt.a around. */ +int __freebsd11_des_setkey(const char *key); +int __freebsd11_des_cipher(const char *in, char *out, long salt, int num_iter); +int __freebsd11_setkey(const char *key); +int __freebsd11_encrypt(char *block, int flag); + /* ARGSUSED */ int __freebsd11_des_setkey(const char *key __unused) { fprintf(stderr, "WARNING! des_setkey(3) not present in the system!\n"); return (0); } /* ARGSUSED */ int __freebsd11_des_cipher(const char *in, char *out, long salt __unused, int num_iter __unused) { fprintf(stderr, "WARNING! des_cipher(3) not present in the system!\n"); bcopy(in, out, 8); return (0); } /* ARGSUSED */ int __freebsd11_setkey(const char *key __unused) { fprintf(stderr, "WARNING! setkey(3) not present in the system!\n"); return (0); } /* ARGSUSED */ int __freebsd11_encrypt(char *block __unused, int flag __unused) { fprintf(stderr, "WARNING! encrypt(3) not present in the system!\n"); return (0); } __sym_compat(des_setkey, __freebsd11_des_setkey, FBSD_1.0); __sym_compat(des_cipher, __freebsd11_des_cipher, FBSD_1.0); __sym_compat(setkey, __freebsd11_setkey, FBSD_1.0); __sym_compat(encrypt, __freebsd11_encrypt, FBSD_1.0); Index: head/lib/libc/gen/dirname_compat.c =================================================================== --- head/lib/libc/gen/dirname_compat.c (revision 366206) +++ head/lib/libc/gen/dirname_compat.c (revision 366207) @@ -1,79 +1,81 @@ /* $OpenBSD: dirname.c,v 1.13 2005/08/08 08:05:33 espie Exp $ */ /* * Copyright (c) 1997, 2004 Todd C. Miller * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include +char * __freebsd11_dirname(char *path); + char * __freebsd11_dirname(char *path) { static char *dname = NULL; size_t len; const char *endp; if (dname == NULL) { dname = (char *)malloc(MAXPATHLEN); if (dname == NULL) return(NULL); } /* Empty or NULL string gets treated as "." */ if (path == NULL || *path == '\0') { dname[0] = '.'; dname[1] = '\0'; return (dname); } /* Strip any trailing slashes */ endp = path + strlen(path) - 1; while (endp > path && *endp == '/') endp--; /* Find the start of the dir */ while (endp > path && *endp != '/') endp--; /* Either the dir is "/" or there are no slashes */ if (endp == path) { dname[0] = *endp == '/' ? '/' : '.'; dname[1] = '\0'; return (dname); } else { /* Move forward past the separating slashes */ do { endp--; } while (endp > path && *endp == '/'); } len = endp - path + 1; if (len >= MAXPATHLEN) { errno = ENAMETOOLONG; return (NULL); } memcpy(dname, path, len); dname[len] = '\0'; return (dname); } __sym_compat(dirname, __freebsd11_dirname, FBSD_1.0); Index: head/lib/libc/gen/fts-compat.c =================================================================== --- head/lib/libc/gen/fts-compat.c (revision 366206) +++ head/lib/libc/gen/fts-compat.c (revision 366207) @@ -1,1216 +1,1215 @@ /*- * SPDX-License-Identifier: BSD-3-Clause * * 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: @(#)fts.c 8.6 (Berkeley) 8/14/94 * From: $OpenBSD: fts.c,v 1.22 1999/10/03 19:22:22 millert Exp $ */ #include __FBSDID("$FreeBSD$"); #include "namespace.h" #include #define _WANT_FREEBSD11_STATFS #include #define _WANT_FREEBSD11_STAT #include #define _WANT_FREEBSD11_DIRENT #include #include #include #include #include #include #include "gen-compat.h" #include "fts-compat.h" #include "un-namespace.h" #include "gen-private.h" FTSENT *__fts_children_44bsd(FTS *, int); int __fts_close_44bsd(FTS *); void *__fts_get_clientptr_44bsd(FTS *); FTS *__fts_get_stream_44bsd(FTSENT *); FTS *__fts_open_44bsd(char * const *, int, int (*)(const FTSENT * const *, const FTSENT * const *)); FTSENT *__fts_read_44bsd(FTS *); int __fts_set_44bsd(FTS *, FTSENT *, int); void __fts_set_clientptr_44bsd(FTS *, void *); static FTSENT *fts_alloc(FTS *, char *, int); static FTSENT *fts_build(FTS *, int); static void fts_lfree(FTSENT *); static void fts_load(FTS *, FTSENT *); static size_t fts_maxarglen(char * const *); static void fts_padjust(FTS *, FTSENT *); static int fts_palloc(FTS *, size_t); static FTSENT *fts_sort(FTS *, FTSENT *, int); static u_short fts_stat(FTS *, FTSENT *, int); static int fts_safe_changedir(FTS *, FTSENT *, int, char *); static int fts_ufslinks(FTS *, const FTSENT *); #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_private { FTS 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 }; FTS * __fts_open_44bsd(char * const *argv, int options, int (*compar)(const FTSENT * const *, const FTSENT * const *)) { struct _fts_private *priv; FTS *sp; FTSENT *p, *root; int nitems; FTSENT *parent, *tmp; int len; /* Options check. */ if (options & ~FTS_OPTIONMASK) { errno = EINVAL; return (NULL); } /* Allocate/initialize the stream. */ if ((priv = calloc(1, sizeof(*priv))) == NULL) return (NULL); sp = &priv->ftsp_fts; sp->fts_compar = compar; sp->fts_options = options; /* Logical walks turn on NOCHDIR; symbolic links are too hard. */ if (ISSET(FTS_LOGICAL)) SET(FTS_NOCHDIR); /* * Start out with 1K of path space, and enough, in any case, * to hold the user's paths. */ if (fts_palloc(sp, MAX(fts_maxarglen(argv), MAXPATHLEN))) goto mem1; /* Allocate/initialize root's parent. */ if ((parent = fts_alloc(sp, "", 0)) == NULL) goto mem2; parent->fts_level = FTS_ROOTPARENTLEVEL; /* Shush, GCC. */ tmp = NULL; /* Allocate/initialize root(s). */ for (root = NULL, nitems = 0; *argv != NULL; ++argv, ++nitems) { /* Don't allow zero-length paths. */ if ((len = strlen(*argv)) == 0) { errno = ENOENT; goto mem3; } 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)); /* 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(FTS *sp, FTSENT *p) { int 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 __fts_close_44bsd(FTS *sp) { FTSENT *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) FTSENT * __fts_read_44bsd(FTS *sp) { FTSENT *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); 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); 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) { free(tmp); /* * 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); } 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) goto next; if (p->fts_instr == FTS_FOLLOW) { p->fts_info = fts_stat(sp, p, 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; } 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; free(tmp); 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(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); } 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 __fts_set_44bsd(FTS *sp, FTSENT *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); } FTSENT * __fts_children_44bsd(FTS *sp, int instr) { FTSENT *p; int fd; 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); if (fchdir(fd)) { (void)_close(fd); return (NULL); } (void)_close(fd); return (sp->fts_child); } #ifndef fts_get_clientptr #error "fts_get_clientptr not defined" #endif void * (__fts_get_clientptr_44bsd)(FTS *sp) { return (fts_get_clientptr(sp)); } #ifndef fts_get_stream #error "fts_get_stream not defined" #endif FTS * (__fts_get_stream_44bsd)(FTSENT *p) { return (fts_get_stream(p)); } void __fts_set_clientptr_44bsd(FTS *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 FTSENT * fts_build(FTS *sp, int type) { struct freebsd11_dirent *dp; FTSENT *p, *head; int nitems; FTSENT *cur, *tail; DIR *dirp; void *oldaddr; - size_t dnamlen; int cderrno, descend, len, level, maxlen, nlinks, oflag, saved_errno, - nostat, doadjust; + nostat, doadjust, dnamlen; char *cp; /* 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; else oflag = DTF_HIDEW | DTF_NODUP; #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, (int)dnamlen)) == NULL) + 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; } if (len + dnamlen >= USHRT_MAX) { /* * In an FTSENT, fts_pathlen is a u_short so it is * possible to wraparound here. If we do, free up * the current structure and the structures already * allocated, then error out with ENAMETOOLONG. */ free(p); fts_lfree(head); (void)closedir(dirp); cur->fts_info = FTS_ERR; SET(FTS_STOP); errno = ENAMETOOLONG; return (NULL); } 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); } else p->fts_accpath = p->fts_name; /* Stat it. */ p->fts_info = fts_stat(sp, p, 0); /* 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)) { if (len == sp->fts_pathlen || nitems == 0) --cp; *cp = '\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, ".."))) { 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 u_short fts_stat(FTS *sp, FTSENT *p, int follow) { FTSENT *t; uint32_t dev; uint32_t ino; struct freebsd11_stat *sbp, sb; int saved_errno; /* 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_stat(p->fts_accpath, sbp)) { saved_errno = errno; if (!freebsd11_lstat(p->fts_accpath, sbp)) { errno = 0; return (FTS_SLNONE); } p->fts_errno = saved_errno; goto err; } } else if (freebsd11_lstat(p->fts_accpath, sbp)) { 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) { FTS *parent; parent = (*(const FTSENT * const *)a)->fts_fts; return (*parent->fts_compar)(a, b); } static FTSENT * fts_sort(FTS *sp, FTSENT *head, int nitems) { FTSENT **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(FTSENT *))) == 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(FTSENT *), fts_compar); for (head = *(ap = sp->fts_array); --nitems; ++ap) ap[0]->fts_link = ap[1]; ap[0]->fts_link = NULL; return (head); } static FTSENT * fts_alloc(FTS *sp, char *name, int namelen) { FTSENT *p; size_t len; struct ftsent_withstat { FTSENT 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(FTSENT) + namelen + 1; else len = sizeof(struct ftsent_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 ftsent_withstat *)p + 1); p->fts_statp = &((struct ftsent_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(FTSENT *head) { FTSENT *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(FTS *sp, size_t more) { sp->fts_pathlen += more + 256; /* * Check for possible wraparound. In an FTS, fts_pathlen is * a signed int but in an FTSENT it is an unsigned short. * We limit fts_pathlen to USHRT_MAX to be safe in both cases. */ if (sp->fts_pathlen < 0 || sp->fts_pathlen >= USHRT_MAX) { if (sp->fts_path) free(sp->fts_path); sp->fts_path = NULL; errno = ENAMETOOLONG; return (1); } 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(FTS *sp, FTSENT *head) { FTSENT *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(FTS *sp, FTSENT *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_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(FTS *sp, const FTSENT *ent) { struct _fts_private *priv; const char **cpp; priv = (struct _fts_private *)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, __fts_open_44bsd, FBSD_1.0); __sym_compat(fts_close, __fts_close_44bsd, FBSD_1.0); __sym_compat(fts_read, __fts_read_44bsd, FBSD_1.0); __sym_compat(fts_set, __fts_set_44bsd, FBSD_1.0); __sym_compat(fts_children, __fts_children_44bsd, FBSD_1.0); __sym_compat(fts_get_clientptr, __fts_get_clientptr_44bsd, FBSD_1.0); __sym_compat(fts_get_stream, __fts_get_stream_44bsd, FBSD_1.0); __sym_compat(fts_set_clientptr, __fts_set_clientptr_44bsd, FBSD_1.0); Index: head/lib/libc/gen/ftw-compat11.c =================================================================== --- head/lib/libc/gen/ftw-compat11.c (revision 366206) +++ head/lib/libc/gen/ftw-compat11.c (revision 366207) @@ -1,98 +1,101 @@ /* $OpenBSD: ftw.c,v 1.5 2005/08/08 08:05:34 espie Exp $ */ /* * Copyright (c) 2003, 2004 Todd C. Miller * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * * Sponsored in part by the Defense Advanced Research Projects * Agency (DARPA) and Air Force Research Laboratory, Air Force * Materiel Command, USAF, under agreement number F39502-99-1-0512. * * From: FreeBSD: head/lib/libc/gen/ftw.c 239151 2012-08-09 15:11:38Z jilles */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include "fts-compat11.h" +int freebsd11_ftw(const char *path, int (*fn)(const char *, + const struct freebsd11_stat *, int), int nfds); + int freebsd11_ftw(const char *path, int (*fn)(const char *, const struct freebsd11_stat *, int), int nfds) { char * const paths[2] = { (char *)path, NULL }; FTSENT11 *cur; FTS11 *ftsp; int error = 0, fnflag, sverrno; /* XXX - nfds is currently unused */ if (nfds < 1) { errno = EINVAL; return (-1); } ftsp = freebsd11_fts_open(paths, FTS_LOGICAL | FTS_COMFOLLOW | FTS_NOCHDIR, NULL); if (ftsp == NULL) return (-1); while ((cur = freebsd11_fts_read(ftsp)) != NULL) { switch (cur->fts_info) { case FTS_D: fnflag = FTW_D; break; case FTS_DNR: fnflag = FTW_DNR; break; case FTS_DP: /* we only visit in preorder */ continue; case FTS_F: case FTS_DEFAULT: fnflag = FTW_F; break; case FTS_NS: case FTS_NSOK: case FTS_SLNONE: fnflag = FTW_NS; break; case FTS_SL: fnflag = FTW_SL; break; case FTS_DC: errno = ELOOP; /* FALLTHROUGH */ default: error = -1; goto done; } error = fn(cur->fts_path, cur->fts_statp, fnflag); if (error != 0) break; } done: sverrno = errno; if (freebsd11_fts_close(ftsp) != 0 && error == 0) error = -1; else errno = sverrno; return (error); } __sym_compat(ftw, freebsd11_ftw, FBSD_1.0); Index: head/lib/libc/gen/getentropy.c =================================================================== --- head/lib/libc/gen/getentropy.c (revision 366206) +++ head/lib/libc/gen/getentropy.c (revision 366207) @@ -1,158 +1,159 @@ /*- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD * * Copyright (c) 2018 Conrad Meyer * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include +#include #include "libc_private.h" /* First __FreeBSD_version bump after introduction of getrandom(2) (r331279) */ #define GETRANDOM_FIRST 1200061 extern int __sysctl(int *, u_int, void *, size_t *, void *, size_t); static inline void _getentropy_fail(void) { raise(SIGKILL); } static size_t arnd_sysctl(u_char *buf, size_t size) { int mib[2]; size_t len, done; mib[0] = CTL_KERN; mib[1] = KERN_ARND; done = 0; do { len = size; if (__sysctl(mib, 2, buf, &len, NULL, 0) == -1) return (done); done += len; buf += len; size -= len; } while (size > 0); return (done); } /* * If a newer libc is accidentally installed on an older kernel, provide high * quality random data anyway. The sysctl interface is not as fast and does * not block by itself, but is provided by even very old kernels. */ static int getentropy_fallback(void *buf, size_t buflen) { /* * oldp (buf) == NULL has a special meaning for sysctl that results in * no EFAULT. For compatibility with the kernel getrandom(2), detect * this case and return the appropriate error. */ if (buf == NULL && buflen > 0) { errno = EFAULT; return (-1); } if (arnd_sysctl(buf, buflen) != buflen) { if (errno == EFAULT) return (-1); /* * This cannot happen. arnd_sysctl() spins until the random * device is seeded and then repeatedly reads until the full * request is satisfied. The only way for this to return a zero * byte or short read is if sysctl(2) on the kern.arandom MIB * fails. In this case, excepting the user-provided-a-bogus- * buffer EFAULT, give up (like for arc4random(3)'s arc4_stir). */ _getentropy_fail(); } return (0); } int getentropy(void *buf, size_t buflen) { ssize_t rd; bool have_getrandom; if (buflen > 256) { errno = EIO; return (-1); } have_getrandom = (__getosreldate() >= GETRANDOM_FIRST); while (buflen > 0) { if (have_getrandom) { rd = getrandom(buf, buflen, 0); if (rd == -1) { switch (errno) { case ECAPMODE: /* * Kernel >= r331280 and < r337999 * will return ECAPMODE when the * caller is already in capability * mode, fallback to traditional * method in this case. */ have_getrandom = false; continue; case EINTR: continue; case EFAULT: return (-1); default: _getentropy_fail(); } } } else { return (getentropy_fallback(buf, buflen)); } /* This cannot happen. */ if (rd == 0) _getentropy_fail(); buf = (char *)buf + rd; buflen -= rd; } return (0); }