diff options
author | Yuri Pankov <yuri.pankov@nexenta.com> | 2017-06-12 20:16:28 -0700 |
---|---|---|
committer | Joshua M. Clulow <josh@sysmgr.org> | 2017-06-12 20:16:28 -0700 |
commit | 4585130b259133a26efae68275dbe56b08366deb (patch) | |
tree | 1946c836807dbd490b3395f65326f4d4664baefc /usr/src/lib/libc | |
parent | 61304e4faaed38301307f7f985160d1843473587 (diff) | |
download | illumos-joyent-4585130b259133a26efae68275dbe56b08366deb.tar.gz |
5428 provide fts(), reallocarray(), and strtonum()
Reviewed by: Robert Mustacchi <rm@joyent.com>
Approved by: Joshua M. Clulow <josh@sysmgr.org>
Diffstat (limited to 'usr/src/lib/libc')
-rw-r--r-- | usr/src/lib/libc/amd64/Makefile | 44 | ||||
-rw-r--r-- | usr/src/lib/libc/i386/Makefile.com | 48 | ||||
-rw-r--r-- | usr/src/lib/libc/port/gen/fts.c | 1037 | ||||
-rw-r--r-- | usr/src/lib/libc/port/gen/reallocarray.c | 37 | ||||
-rw-r--r-- | usr/src/lib/libc/port/gen/strtonum.c | 63 | ||||
-rw-r--r-- | usr/src/lib/libc/port/llib-lc | 18 | ||||
-rw-r--r-- | usr/src/lib/libc/port/mapfile-vers | 11 | ||||
-rw-r--r-- | usr/src/lib/libc/sparc/Makefile.com | 48 | ||||
-rw-r--r-- | usr/src/lib/libc/sparcv9/Makefile.com | 50 |
9 files changed, 1263 insertions, 93 deletions
diff --git a/usr/src/lib/libc/amd64/Makefile b/usr/src/lib/libc/amd64/Makefile index e77dd63255..8cee9dee02 100644 --- a/usr/src/lib/libc/amd64/Makefile +++ b/usr/src/lib/libc/amd64/Makefile @@ -18,14 +18,13 @@ # # CDDL HEADER END # + # # Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved. # Copyright 2016 Joyent, Inc. -# # Copyright (c) 2013, OmniTI Computer Consulting, Inc. All rights reserved. # Copyright 2013 Garrett D'Amore <garrett@damore.org> -# Copyright 2011 Nexenta Systems, Inc. All rights reserved. -# Use is subject to license terms. +# Copyright 2017 Nexenta Systems, Inc. # LIBCBASE= . @@ -350,13 +349,13 @@ PORTGEN= \ ascii_strcasecmp.o \ ascii_strncasecmp.o \ assert.o \ + atexit.o \ + atfork.o \ atof.o \ atoi.o \ atol.o \ atoll.o \ attropen.o \ - atexit.o \ - atfork.o \ basename.o \ calloc.o \ catgets.o \ @@ -398,8 +397,10 @@ PORTGEN= \ fmtmsg.o \ ftime.o \ ftok.o \ + fts.o \ ftw.o \ gcvt.o \ + get_nprocs.o \ getauxv.o \ getcwd.o \ getdate_err.o \ @@ -417,7 +418,6 @@ PORTGEN= \ getlogin.o \ getmntent.o \ getnetgrent.o \ - get_nprocs.o \ getopt.o \ getopt_long.o \ getpagesize.o \ @@ -498,8 +498,8 @@ PORTGEN= \ posix_madvise.o \ posix_memalign.o \ priocntl.o \ - privlib.o \ priv_str_xlate.o \ + privlib.o \ psecflags.o \ psiginfo.o \ psignal.o \ @@ -512,6 +512,7 @@ PORTGEN= \ rctlops.o \ readdir.o \ readdir_r.o \ + reallocarray.o \ realpath.o \ reboot.o \ regexpr.o \ @@ -555,6 +556,7 @@ PORTGEN= \ strtoimax.o \ strtok.o \ strtok_r.o \ + strtonum.o \ strtoumax.o \ swab.o \ swapctl.o \ @@ -1088,24 +1090,24 @@ SRCS= \ $(ATOMICOBJS:%.o=$(SRC)/common/atomic/%.c) \ $(XATTROBJS:%.o=$(SRC)/common/xattr/%.c) \ $(COMOBJS:%.o=$(SRC)/common/util/%.c) \ - $(PORTFP:%.o=$(LIBCDIR)/port/fp/%.c) \ - $(PORTGEN:%.o=$(LIBCDIR)/port/gen/%.c) \ - $(PORTI18N:%.o=$(LIBCDIR)/port/i18n/%.c) \ - $(PORTLOCALE:%.o=$(LIBCDIR)/port/locale/%.c) \ - $(PORTPRINT:%.o=$(LIBCDIR)/port/print/%.c) \ - $(PORTREGEX:%.o=$(LIBCDIR)/port/regex/%.c) \ - $(PORTSTDIO:%.o=$(LIBCDIR)/port/stdio/%.c) \ - $(PORTSYS:%.o=$(LIBCDIR)/port/sys/%.c) \ - $(AIOOBJS:%.o=$(LIBCDIR)/port/aio/%.c) \ - $(RTOBJS:%.o=$(LIBCDIR)/port/rt/%.c) \ - $(SECFLAGSOBJS:%.o=$(SRC)/common/secflags/%.c) \ - $(TPOOLOBJS:%.o=$(LIBCDIR)/port/tpool/%.c) \ - $(THREADSOBJS:%.o=$(LIBCDIR)/port/threads/%.c) \ + $(PORTFP:%.o=$(LIBCDIR)/port/fp/%.c) \ + $(PORTGEN:%.o=$(LIBCDIR)/port/gen/%.c) \ + $(PORTI18N:%.o=$(LIBCDIR)/port/i18n/%.c) \ + $(PORTLOCALE:%.o=$(LIBCDIR)/port/locale/%.c) \ + $(PORTPRINT:%.o=$(LIBCDIR)/port/print/%.c) \ + $(PORTREGEX:%.o=$(LIBCDIR)/port/regex/%.c) \ + $(PORTSTDIO:%.o=$(LIBCDIR)/port/stdio/%.c) \ + $(PORTSYS:%.o=$(LIBCDIR)/port/sys/%.c) \ + $(AIOOBJS:%.o=$(LIBCDIR)/port/aio/%.c) \ + $(RTOBJS:%.o=$(LIBCDIR)/port/rt/%.c) \ + $(SECFLAGSOBJS:%.o=$(SRC)/common/secflags/%.c) \ + $(TPOOLOBJS:%.o=$(LIBCDIR)/port/tpool/%.c) \ + $(THREADSOBJS:%.o=$(LIBCDIR)/port/threads/%.c) \ $(THREADSMACHOBJS:%.o=threads/%.c) \ $(UNICODEOBJS:%.o=$(SRC)/common/unicode/%.c) \ $(UNWINDMACHOBJS:%.o=unwind/%.c) \ $(FPOBJS:%.o=fp/%.c) \ - $(I386FPOBJS:%.o=$(LIBCDIR)/i386/fp/%.c) \ + $(I386FPOBJS:%.o=$(LIBCDIR)/i386/fp/%.c) \ $(LIBCBASE)/gen/ecvt.c \ $(LIBCBASE)/gen/makectxt.c \ $(LIBCBASE)/gen/siginfolst.c \ diff --git a/usr/src/lib/libc/i386/Makefile.com b/usr/src/lib/libc/i386/Makefile.com index 4d24e7f176..0a879e1508 100644 --- a/usr/src/lib/libc/i386/Makefile.com +++ b/usr/src/lib/libc/i386/Makefile.com @@ -18,14 +18,13 @@ # # CDDL HEADER END # + # # Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved. # Copyright 2016 Joyent, Inc. # Copyright (c) 2013, OmniTI Computer Consulting, Inc. All rights reserved. # Copyright 2013 Garrett D'Amore <garrett@damore.org> -# -# Copyright 2011 Nexenta Systems, Inc. All rights reserved. -# Use is subject to license terms. +# Copyright 2017 Nexenta Systems, Inc. # LIBCDIR= $(SRC)/lib/libc @@ -385,14 +384,14 @@ PORTGEN= \ ascii_strcasecmp.o \ ascii_strncasecmp.o \ assert.o \ + atexit.o \ + atfork.o \ atof.o \ atoi.o \ atol.o \ atoll.o \ attrat.o \ attropen.o \ - atexit.o \ - atfork.o \ basename.o \ calloc.o \ catgets.o \ @@ -434,8 +433,10 @@ PORTGEN= \ fmtmsg.o \ ftime.o \ ftok.o \ + fts.o \ ftw.o \ gcvt.o \ + get_nprocs.o \ getauxv.o \ getcwd.o \ getdate_err.o \ @@ -453,7 +454,6 @@ PORTGEN= \ getlogin.o \ getmntent.o \ getnetgrent.o \ - get_nprocs.o \ getopt.o \ getopt_long.o \ getpagesize.o \ @@ -534,8 +534,8 @@ PORTGEN= \ posix_madvise.o \ posix_memalign.o \ priocntl.o \ - privlib.o \ priv_str_xlate.o \ + privlib.o \ psecflags.o \ psiginfo.o \ psignal.o \ @@ -548,6 +548,7 @@ PORTGEN= \ rctlops.o \ readdir.o \ readdir_r.o \ + reallocarray.o \ realpath.o \ reboot.o \ regexpr.o \ @@ -587,6 +588,7 @@ PORTGEN= \ strtoimax.o \ strtok.o \ strtok_r.o \ + strtonum.o \ strtoumax.o \ swab.o \ swapctl.o \ @@ -1151,23 +1153,23 @@ SRCS= \ $(XATTROBJS:%.o=$(SRC)/common/xattr/%.c) \ $(COMOBJS:%.o=$(SRC)/common/util/%.c) \ $(DTRACEOBJS:%.o=$(SRC)/common/dtrace/%.c) \ - $(PORTFP:%.o=$(LIBCDIR)/port/fp/%.c) \ - $(PORTGEN:%.o=$(LIBCDIR)/port/gen/%.c) \ - $(PORTI18N:%.o=$(LIBCDIR)/port/i18n/%.c) \ - $(PORTLOCALE:%.o=$(LIBCDIR)/port/locale/%.c) \ - $(PORTPRINT:%.o=$(LIBCDIR)/port/print/%.c) \ - $(PORTREGEX:%.o=$(LIBCDIR)/port/regex/%.c) \ - $(PORTSTDIO:%.o=$(LIBCDIR)/port/stdio/%.c) \ - $(PORTSYS:%.o=$(LIBCDIR)/port/sys/%.c) \ - $(AIOOBJS:%.o=$(LIBCDIR)/port/aio/%.c) \ - $(RTOBJS:%.o=$(LIBCDIR)/port/rt/%.c) \ - $(SECFLAGSOBJS:%.o=$(SRC)/common/secflags/%.c) \ - $(TPOOLOBJS:%.o=$(LIBCDIR)/port/tpool/%.c) \ - $(THREADSOBJS:%.o=$(LIBCDIR)/port/threads/%.c) \ - $(THREADSMACHOBJS:%.o=$(LIBCDIR)/$(MACH)/threads/%.c) \ + $(PORTFP:%.o=$(LIBCDIR)/port/fp/%.c) \ + $(PORTGEN:%.o=$(LIBCDIR)/port/gen/%.c) \ + $(PORTI18N:%.o=$(LIBCDIR)/port/i18n/%.c) \ + $(PORTLOCALE:%.o=$(LIBCDIR)/port/locale/%.c) \ + $(PORTPRINT:%.o=$(LIBCDIR)/port/print/%.c) \ + $(PORTREGEX:%.o=$(LIBCDIR)/port/regex/%.c) \ + $(PORTSTDIO:%.o=$(LIBCDIR)/port/stdio/%.c) \ + $(PORTSYS:%.o=$(LIBCDIR)/port/sys/%.c) \ + $(AIOOBJS:%.o=$(LIBCDIR)/port/aio/%.c) \ + $(RTOBJS:%.o=$(LIBCDIR)/port/rt/%.c) \ + $(SECFLAGSOBJS:%.o=$(SRC)/common/secflags/%.c) \ + $(TPOOLOBJS:%.o=$(LIBCDIR)/port/tpool/%.c) \ + $(THREADSOBJS:%.o=$(LIBCDIR)/port/threads/%.c) \ + $(THREADSMACHOBJS:%.o=$(LIBCDIR)/$(MACH)/threads/%.c) \ $(UNICODEOBJS:%.o=$(SRC)/common/unicode/%.c) \ - $(UNWINDMACHOBJS:%.o=$(LIBCDIR)/port/unwind/%.c) \ - $(FPOBJS:%.o=$(LIBCDIR)/$(MACH)/fp/%.c) \ + $(UNWINDMACHOBJS:%.o=$(LIBCDIR)/port/unwind/%.c) \ + $(FPOBJS:%.o=$(LIBCDIR)/$(MACH)/fp/%.c) \ $(LIBCBASE)/gen/ecvt.c \ $(LIBCBASE)/gen/makectxt.c \ $(LIBCBASE)/gen/siginfolst.c \ diff --git a/usr/src/lib/libc/port/gen/fts.c b/usr/src/lib/libc/port/gen/fts.c new file mode 100644 index 0000000000..eac375ee6a --- /dev/null +++ b/usr/src/lib/libc/port/gen/fts.c @@ -0,0 +1,1037 @@ +/* + * 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. + */ + +#include <sys/stat.h> + +#include <dirent.h> +#include <errno.h> +#include <fcntl.h> +#include <fts.h> +#include <limits.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#define MAXIMUM(a, b) (((a) > (b)) ? (a) : (b)) + +#define ALIGNBYTES _POINTER_ALIGNMENT +#define ALIGN(p) (((unsigned long)(p) + ALIGNBYTES) & ~ALIGNBYTES) + +static FTSENT *fts_alloc(FTS *, char *, size_t); +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 ushort_t fts_stat(FTS *, FTSENT *, int, int); +static int fts_safe_changedir(FTS *, FTSENT *, int, char *); + +#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 */ + +FTS * +fts_open(char * const *argv, int options, + int (*compar)(const FTSENT **, const FTSENT **)) +{ + FTS *sp; + FTSENT *p, *root; + int nitems; + FTSENT *parent, *prev; + + /* Options check. */ + if (options & ~FTS_OPTIONMASK) { + errno = EINVAL; + return (NULL); + } + + /* At least one path must be specified. */ + if (*argv == NULL) { + errno = EINVAL; + return (NULL); + } + + /* Allocate/initialize the stream */ + if ((sp = calloc(1, sizeof (FTS))) == NULL) + return (NULL); + 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, MAXIMUM(fts_maxarglen(argv), PATH_MAX))) + 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 = prev = NULL, nitems = 0; *argv; ++argv, ++nitems) { + if ((p = fts_alloc(sp, *argv, strlen(*argv))) == NULL) + goto mem3; + 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) + root = p; + else + prev->fts_link = p; + prev = 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) + SET(FTS_NOCHDIR); + + if (nitems == 0) + free(parent); + + 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) +{ + 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; + (void) memmove(sp->fts_path, p->fts_name, len + 1); + if (((cp = strrchr(p->fts_name, '/')) != NULL) && + (cp != p->fts_name || cp[1])) { + len = strlen(++cp); + (void) 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(FTS *sp) +{ + FTSENT *freep, *p; + int rfd, error = 0; + + /* + * 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 ? p->fts_link : p->fts_parent; + free(freep); + } + free(p); + } + + /* Stash the original directory fd if needed. */ + rfd = ISSET(FTS_NOCHDIR) ? -1 : sp->fts_rfd; + + /* Free up child linked list, sort array, path buffer, stream ptr. */ + if (sp->fts_child) + fts_lfree(sp->fts_child); + free(sp->fts_array); + free(sp->fts_path); + free(sp); + + /* Return to original directory, checking for error. */ + if (rfd != -1) { + int saved_errno; + error = fchdir(rfd); + saved_errno = errno; + (void) close(rfd); + errno = saved_errno; + } + + return (error); +} + +/* + * 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(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, -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) { + 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 && 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) { + 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; 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, -1); + if (p->fts_info == FTS_D && !ISSET(FTS_NOCHDIR)) { + if ((p->fts_symfd = + open(".", O_RDONLY | O_CLOEXEC)) < 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++ = '/'; + (void) 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); + sp->fts_cur = p; + 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); + sp->fts_cur = p; + 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); + sp->fts_cur = p; + 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(FTS *sp, FTSENT *p, int instr) +{ + if (instr && 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(FTS *sp, int instr) +{ + FTSENT *p; + int fd; + + if (instr && 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) + 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) + return (NULL); + sp->fts_child = fts_build(sp, instr); + if (fchdir(fd)) { + (void) close(fd); + return (NULL); + } + (void) close(fd); + return (sp->fts_child); +} + +/* + * 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 dirent *dp; + FTSENT *p, *head; + FTSENT *cur, *tail; + DIR *dirp; + void *oldaddr; + size_t len, maxlen; + int nitems, cderrno, descend, level, nlinks, doadjust; + int saved_errno; + 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. + */ + if ((dirp = opendir(cur->fts_accpath)) == 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; + else if (ISSET(FTS_NOSTAT) && ISSET(FTS_PHYSICAL)) + nlinks = cur->fts_nlink - (ISSET(FTS_SEEDOT) ? 0 : 2); + else + nlinks = -1; + + /* + * 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; + (void) closedir(dirp); + dirp = NULL; + } 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++ = '/'; + } + len++; + maxlen = sp->fts_pathlen - len; + + /* + * fts_level is signed so we must prevent it from wrapping + * around to FTS_ROOTLEVEL and FTS_ROOTPARENTLEVEL. + */ + level = cur->fts_level; + if (level < FTS_MAXLEVEL) + level++; + + /* Read the directory, attaching each entry to the `link' pointer. */ + doadjust = 0; + for (head = tail = NULL, nitems = 0; dirp && (dp = readdir(dirp)); ) { + if (!ISSET(FTS_SEEDOT) && ISDOT(dp->d_name)) + continue; + + if (!(p = fts_alloc(sp, dp->d_name, strlen(dp->d_name)))) + goto mem1; + if (strlen(dp->d_name) >= maxlen) { /* include space for NUL */ + oldaddr = sp->fts_path; + if (fts_palloc(sp, strlen(dp->d_name) +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; + 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 + strlen(dp->d_name); + if (p->fts_pathlen < len) { + /* + * If we wrap, 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); + } + + 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) { + 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; + (void) 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)) { + 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 ushort_t +fts_stat(FTS *sp, FTSENT *p, int follow, int dfd) +{ + FTSENT *t; + dev_t dev; + ino_t ino; + struct 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; + + /* + * 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 (fstatat(dfd, path, sbp, 0)) { + saved_errno = errno; + if (!fstatat(dfd, path, sbp, AT_SYMLINK_NOFOLLOW)) { + errno = 0; + return (FTS_SLNONE); + } + p->fts_errno = saved_errno; + goto err; + } + } else if (fstatat(dfd, path, sbp, AT_SYMLINK_NOFOLLOW)) { + p->fts_errno = errno; +err: (void) memset(sbp, 0, sizeof (struct stat)); + 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); +} + +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) { + struct _ftsent **a; + + sp->fts_nitems = nitems + 40; + if ((a = reallocarray(sp->fts_array, + sp->fts_nitems, sizeof (FTSENT *))) == NULL) { + free(sp->fts_array); + sp->fts_array = NULL; + sp->fts_nitems = 0; + return (head); + } + sp->fts_array = a; + } + for (ap = sp->fts_array, p = head; p; p = p->fts_link) + *ap++ = p; + qsort(sp->fts_array, nitems, sizeof (FTSENT *), sp->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, size_t namelen) +{ + FTSENT *p; + size_t len; + + /* + * 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. Since the + * fts_name field is declared to be of size 1, the fts_name pointer is + * namelen + 2 before the first possible address of the stat structure. + */ + len = sizeof (FTSENT) + namelen; + if (!ISSET(FTS_NOSTAT)) + len += sizeof (struct stat) + ALIGNBYTES; + if ((p = calloc(1, len)) == NULL) + return (NULL); + + p->fts_path = sp->fts_path; + p->fts_namelen = namelen; + p->fts_instr = FTS_NOINSTR; + if (!ISSET(FTS_NOSTAT)) + p->fts_statp = (struct stat *)ALIGN(p->fts_name + namelen + 2); + (void) memcpy(p->fts_name, name, namelen); + + return (p); +} + +static void +fts_lfree(FTSENT *head) +{ + FTSENT *p; + + /* Free a linked list of structures. */ + while ((p = head) != NULL) { + 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 PATH_MAX, 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) +{ + char *p; + + /* + * Check for possible wraparound. + */ + more += 256; + if (sp->fts_pathlen + more < sp->fts_pathlen) { + free(sp->fts_path); + sp->fts_path = NULL; + errno = ENAMETOOLONG; + return (1); + } + sp->fts_pathlen += more; + p = realloc(sp->fts_path, sp->fts_pathlen); + if (p == NULL) { + free(sp->fts_path); + sp->fts_path = NULL; + return (1); + } + sp->fts_path = p; + return (0); +} + +/* + * 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) { \ + if ((p)->fts_accpath != (p)->fts_name) { \ + (p)->fts_accpath = \ + (char *)addr + ((p)->fts_accpath - (p)->fts_path); \ + } \ + (p)->fts_path = addr; \ +} + /* 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 stat sb; + + newfd = fd; + if (ISSET(FTS_NOCHDIR)) + return (0); + /* + * This originally specified O_DIRECTORY as well - restore once/if we + * implement the flag. + */ + if (fd < 0 && (newfd = open(path, O_RDONLY|O_CLOEXEC)) < 0) + return (-1); + if (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); +} diff --git a/usr/src/lib/libc/port/gen/reallocarray.c b/usr/src/lib/libc/port/gen/reallocarray.c new file mode 100644 index 0000000000..ecc4d25fa9 --- /dev/null +++ b/usr/src/lib/libc/port/gen/reallocarray.c @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2008 Otto Moerbeek <otto@drijf.net> + * + * 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 <sys/types.h> +#include <errno.h> +#include <stdint.h> +#include <stdlib.h> + +/* + * This is sqrt(SIZE_MAX+1), as s1*s2 <= SIZE_MAX + * if both s1 < MUL_NO_OVERFLOW and s2 < MUL_NO_OVERFLOW + */ +#define MUL_NO_OVERFLOW ((size_t)1 << (sizeof (size_t) * 4)) + +void * +reallocarray(void *optr, size_t nmemb, size_t size) +{ + if ((nmemb >= MUL_NO_OVERFLOW || size >= MUL_NO_OVERFLOW) && + nmemb > 0 && SIZE_MAX / nmemb < size) { + errno = ENOMEM; + return (NULL); + } + return (realloc(optr, size * nmemb)); +} diff --git a/usr/src/lib/libc/port/gen/strtonum.c b/usr/src/lib/libc/port/gen/strtonum.c new file mode 100644 index 0000000000..e180769313 --- /dev/null +++ b/usr/src/lib/libc/port/gen/strtonum.c @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2004 Ted Unangst and Todd Miller + * All rights reserved. + * + * 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 <errno.h> +#include <limits.h> +#include <stdlib.h> + +#define INVALID 1 +#define TOOSMALL 2 +#define TOOLARGE 3 + +long long +strtonum(const char *numstr, long long minval, long long maxval, + const char **errstrp) +{ + long long ll = 0; + int error = 0; + char *ep; + struct errval { + const char *errstr; + int err; + } ev[4] = { + { NULL, 0 }, + { "invalid", EINVAL }, + { "too small", ERANGE }, + { "too large", ERANGE }, + }; + + ev[0].err = errno; + errno = 0; + if (minval > maxval) { + error = INVALID; + } else { + ll = strtoll(numstr, &ep, 10); + if (numstr == ep || *ep != '\0') + error = INVALID; + else if ((ll == LLONG_MIN && errno == ERANGE) || ll < minval) + error = TOOSMALL; + else if ((ll == LLONG_MAX && errno == ERANGE) || ll > maxval) + error = TOOLARGE; + } + if (errstrp != NULL) + *errstrp = ev[error].errstr; + errno = ev[error].err; + if (error) + ll = 0; + + return (ll); +} diff --git a/usr/src/lib/libc/port/llib-lc b/usr/src/lib/libc/port/llib-lc index d33a1d39c2..db73a140f9 100644 --- a/usr/src/lib/libc/port/llib-lc +++ b/usr/src/lib/libc/port/llib-lc @@ -21,7 +21,7 @@ /* * Copyright (c) 1991, 2010, Oracle and/or its affiliates. All rights reserved. - * Copyright 2011 Nexenta Systems, Inc. All rights reserved. + * Copyright 2017 Nexenta Systems, Inc. * Copyright 2013 OmniTI Computer Consulting, Inc. All rights reserved. * Copyright (c) 2013 Gary Mills * Copyright 2014 Garrett D'Amore <garrett@damore.org> @@ -50,6 +50,7 @@ #include <float.h> #include <fmtmsg.h> #include <fnmatch.h> +#include <fts.h> #include <ftw.h> #include <glob.h> #include <getwidth.h> @@ -435,7 +436,7 @@ int flock(int filedes, int operation); /* fmtmsg.c */ int addseverity(int value, const char *string); int fmtmsg(long class, const char *label, int severity, const char *text, - const char *action, const char *tag); + const char *action, const char *tag); /* ftime.c */ int ftime(struct timeb *tp); @@ -443,6 +444,13 @@ int ftime(struct timeb *tp); /* ftok.c */ key_t ftok(const char *path, int id); +/* fts.c */ +FTSENT *fts_children(FTS *, int); +int fts_close(FTS *); +FTS *fts_open(char * const *, int, int (*)(const FTSENT **, const FTSENT **)); +FTSENT *fts_read(FTS *); +int fts_set(FTS *, FTSENT *, int); + /* gcvt.c */ char *gcvt(double number, int ndigit, char *buf); @@ -820,6 +828,9 @@ size_t rctlblk_size(void); /* readdir.c */ struct dirent *readdir(DIR *dirp); +/* reallocarray.c */ +void *reallocarray(void *, size_t, size_t); + /* realpath.c */ char *realpath(const char *_RESTRICT_KYWD raw, char *_RESTRICT_KYWD canon); @@ -973,6 +984,9 @@ char *strtok_r(char *_RESTRICT_KYWD, const char *_RESTRICT_KYWD, long strtol(const char *_RESTRICT_KYWD str, char **_RESTRICT_KYWD nptr, int base); +/* strtonum.c */ +long long strtonum(const char *, long long, long long, const char **); + /* strtoul.c */ unsigned long strtoul(const char *_RESTRICT_KYWD str, char **_RESTRICT_KYWD nptr, int base); diff --git a/usr/src/lib/libc/port/mapfile-vers b/usr/src/lib/libc/port/mapfile-vers index 9392abc540..c9e03580e2 100644 --- a/usr/src/lib/libc/port/mapfile-vers +++ b/usr/src/lib/libc/port/mapfile-vers @@ -93,6 +93,17 @@ $if _x86 && _ELF64 $add amd64 $endif +SYMBOL_VERSION ILLUMOS_0.23 { # openbsd compat + protected: + fts_children; + fts_close; + fts_open; + fts_read; + fts_set; + reallocarray; + strtonum; +} ILLUMOS_0.22; + SYMBOL_VERSION ILLUMOS_0.22 { # endian(3C) protected: htobe16; diff --git a/usr/src/lib/libc/sparc/Makefile.com b/usr/src/lib/libc/sparc/Makefile.com index 7c8f14372d..b478c61a74 100644 --- a/usr/src/lib/libc/sparc/Makefile.com +++ b/usr/src/lib/libc/sparc/Makefile.com @@ -18,14 +18,13 @@ # # CDDL HEADER END # + # # Copyright (c) 1989, 2010, Oracle and/or its affiliates. All rights reserved. # Copyright 2016 Joyent, Inc. # Copyright (c) 2013, OmniTI Computer Consulting, Inc. All rights reserved. # Copyright 2013 Garrett D'Amore <garrett@damore.org> -# -# Copyright 2011 Nexenta Systems, Inc. All rights reserved. -# Use is subject to license terms. +# Copyright 2017 Nexenta Systems, Inc. # LIBCDIR= $(SRC)/lib/libc @@ -410,14 +409,14 @@ PORTGEN= \ addsev.o \ ascii_strncasecmp.o \ assert.o \ + atexit.o \ + atfork.o \ atof.o \ atoi.o \ atol.o \ atoll.o \ attrat.o \ attropen.o \ - atexit.o \ - atfork.o \ basename.o \ calloc.o \ catgets.o \ @@ -459,8 +458,10 @@ PORTGEN= \ fmtmsg.o \ ftime.o \ ftok.o \ + fts.o \ ftw.o \ gcvt.o \ + get_nprocs.o \ getauxv.o \ getcwd.o \ getdate_err.o \ @@ -478,7 +479,6 @@ PORTGEN= \ getlogin.o \ getmntent.o \ getnetgrent.o \ - get_nprocs.o \ getopt.o \ getopt_long.o \ getpagesize.o \ @@ -560,8 +560,8 @@ PORTGEN= \ posix_madvise.o \ posix_memalign.o \ priocntl.o \ - privlib.o \ priv_str_xlate.o \ + privlib.o \ psecflags.o \ psiginfo.o \ psignal.o \ @@ -574,6 +574,7 @@ PORTGEN= \ rctlops.o \ readdir.o \ readdir_r.o \ + reallocarray.o \ realpath.o \ reboot.o \ regexpr.o \ @@ -615,6 +616,7 @@ PORTGEN= \ strtoimax.o \ strtok.o \ strtok_r.o \ + strtonum.o \ strtoumax.o \ swab.o \ swapctl.o \ @@ -1175,23 +1177,23 @@ SRCS= \ $(XATTROBJS:%.o=$(SRC)/common/xattr/%.c) \ $(COMOBJS:%.o=$(SRC)/common/util/%.c) \ $(DTRACEOBJS:%.o=$(SRC)/common/dtrace/%.c) \ - $(PORTFP:%.o=$(LIBCDIR)/port/fp/%.c) \ - $(PORTGEN:%.o=$(LIBCDIR)/port/gen/%.c) \ - $(PORTI18N:%.o=$(LIBCDIR)/port/i18n/%.c) \ - $(PORTLOCALE:%.o=$(LIBCDIR)/port/locale/%.c) \ - $(PORTPRINT:%.o=$(LIBCDIR)/port/print/%.c) \ - $(PORTREGEX:%.o=$(LIBCDIR)/port/regex/%.c) \ - $(PORTSTDIO:%.o=$(LIBCDIR)/port/stdio/%.c) \ - $(PORTSYS:%.o=$(LIBCDIR)/port/sys/%.c) \ - $(AIOOBJS:%.o=$(LIBCDIR)/port/aio/%.c) \ - $(RTOBJS:%.o=$(LIBCDIR)/port/rt/%.c) \ - $(SECFLAGSOBJS:%.o=$(SRC)/common/secflags/%.c) \ - $(TPOOLOBJS:%.o=$(LIBCDIR)/port/tpool/%.c) \ - $(THREADSOBJS:%.o=$(LIBCDIR)/port/threads/%.c) \ - $(THREADSMACHOBJS:%.o=$(LIBCDIR)/$(MACH)/threads/%.c) \ + $(PORTFP:%.o=$(LIBCDIR)/port/fp/%.c) \ + $(PORTGEN:%.o=$(LIBCDIR)/port/gen/%.c) \ + $(PORTI18N:%.o=$(LIBCDIR)/port/i18n/%.c) \ + $(PORTLOCALE:%.o=$(LIBCDIR)/port/locale/%.c) \ + $(PORTPRINT:%.o=$(LIBCDIR)/port/print/%.c) \ + $(PORTREGEX:%.o=$(LIBCDIR)/port/regex/%.c) \ + $(PORTSTDIO:%.o=$(LIBCDIR)/port/stdio/%.c) \ + $(PORTSYS:%.o=$(LIBCDIR)/port/sys/%.c) \ + $(AIOOBJS:%.o=$(LIBCDIR)/port/aio/%.c) \ + $(RTOBJS:%.o=$(LIBCDIR)/port/rt/%.c) \ + $(SECFLAGSOBJS:%.o=$(SRC)/common/secflags/%.c) \ + $(TPOOLOBJS:%.o=$(LIBCDIR)/port/tpool/%.c) \ + $(THREADSOBJS:%.o=$(LIBCDIR)/port/threads/%.c) \ + $(THREADSMACHOBJS:%.o=$(LIBCDIR)/$(MACH)/threads/%.c) \ $(UNICODEOBJS:%.o=$(SRC)/common/unicode/%.c) \ - $(UNWINDMACHOBJS:%.o=$(LIBCDIR)/port/unwind/%.c) \ - $(FPOBJS:%.o=$(LIBCDIR)/$(MACH)/fp/%.c) \ + $(UNWINDMACHOBJS:%.o=$(LIBCDIR)/port/unwind/%.c) \ + $(FPOBJS:%.o=$(LIBCDIR)/$(MACH)/fp/%.c) \ $(LIBCBASE)/crt/_ftou.c \ $(LIBCBASE)/gen/_xregs_clrptr.c \ $(LIBCBASE)/gen/byteorder.c \ diff --git a/usr/src/lib/libc/sparcv9/Makefile.com b/usr/src/lib/libc/sparcv9/Makefile.com index 6744289046..70d1fdea43 100644 --- a/usr/src/lib/libc/sparcv9/Makefile.com +++ b/usr/src/lib/libc/sparcv9/Makefile.com @@ -18,15 +18,14 @@ # # CDDL HEADER END # + # # Copyright 2016 Gary Mills # Copyright (c) 1989, 2010, Oracle and/or its affiliates. All rights reserved. # Copyright (c) 2015, Joyent, Inc. All rights reserved. # Copyright (c) 2013, OmniTI Computer Consulting, Inc. All rights reserved. # Copyright 2013 Garrett D'Amore <garrett@damore.org> -# -# Copyright 2011 Nexenta Systems, Inc. All rights reserved. -# Use is subject to license terms. +# Copyright 2017 Nexenta Systems, Inc. # LIBCDIR= $(SRC)/lib/libc @@ -368,14 +367,14 @@ PORTGEN= \ addsev.o \ ascii_strncasecmp.o \ assert.o \ - attrat.o \ + atexit.o \ + atfork.o \ atof.o \ atoi.o \ atol.o \ atoll.o \ + attrat.o \ attropen.o \ - atexit.o \ - atfork.o \ basename.o \ calloc.o \ catgets.o \ @@ -417,8 +416,10 @@ PORTGEN= \ fmtmsg.o \ ftime.o \ ftok.o \ + fts.o \ ftw.o \ gcvt.o \ + get_nprocs.o \ getauxv.o \ getcwd.o \ getdate_err.o \ @@ -436,7 +437,6 @@ PORTGEN= \ getlogin.o \ getmntent.o \ getnetgrent.o \ - get_nprocs.o \ getopt.o \ getopt_long.o \ getpagesize.o \ @@ -518,8 +518,8 @@ PORTGEN= \ posix_madvise.o \ posix_memalign.o \ priocntl.o \ - privlib.o \ priv_str_xlate.o \ + privlib.o \ psecflags.o \ psiginfo.o \ psignal.o \ @@ -532,6 +532,7 @@ PORTGEN= \ rctlops.o \ readdir.o \ readdir_r.o \ + reallocarray.o \ realpath.o \ reboot.o \ regexpr.o \ @@ -573,6 +574,7 @@ PORTGEN= \ strtoimax.o \ strtok.o \ strtok_r.o \ + strtonum.o \ strtoumax.o \ swab.o \ swapctl.o \ @@ -1105,23 +1107,23 @@ SRCS= \ $(ATOMICOBJS:%.o=$(SRC)/common/atomic/%.c) \ $(XATTROBJS:%.o=$(SRC)/common/xattr/%.c) \ $(COMOBJS:%.o=$(SRC)/common/util/%.c) \ - $(PORTFP:%.o=$(LIBCDIR)/port/fp/%.c) \ - $(PORTGEN:%.o=$(LIBCDIR)/port/gen/%.c) \ - $(PORTI18N:%.o=$(LIBCDIR)/port/i18n/%.c) \ - $(PORTLOCALE:%.o=$(LIBCDIR)/port/locale/%.c) \ - $(PORTPRINT:%.o=$(LIBCDIR)/port/print/%.c) \ - $(PORTREGEX:%.o=$(LIBCDIR)/port/regex/%.c) \ - $(PORTSTDIO:%.o=$(LIBCDIR)/port/stdio/%.c) \ - $(PORTSYS:%.o=$(LIBCDIR)/port/sys/%.c) \ - $(AIOOBJS:%.o=$(LIBCDIR)/port/aio/%.c) \ - $(RTOBJS:%.o=$(LIBCDIR)/port/rt/%.c) \ - $(SECFLAGSOBJS:%.o=$(SRC)/common/secflags/%.c) \ - $(TPOOLOBJS:%.o=$(LIBCDIR)/port/tpool/%.c) \ - $(THREADSOBJS:%.o=$(LIBCDIR)/port/threads/%.c) \ - $(THREADSMACHOBJS:%.o=$(LIBCDIR)/$(MACH)/threads/%.c) \ + $(PORTFP:%.o=$(LIBCDIR)/port/fp/%.c) \ + $(PORTGEN:%.o=$(LIBCDIR)/port/gen/%.c) \ + $(PORTI18N:%.o=$(LIBCDIR)/port/i18n/%.c) \ + $(PORTLOCALE:%.o=$(LIBCDIR)/port/locale/%.c) \ + $(PORTPRINT:%.o=$(LIBCDIR)/port/print/%.c) \ + $(PORTREGEX:%.o=$(LIBCDIR)/port/regex/%.c) \ + $(PORTSTDIO:%.o=$(LIBCDIR)/port/stdio/%.c) \ + $(PORTSYS:%.o=$(LIBCDIR)/port/sys/%.c) \ + $(AIOOBJS:%.o=$(LIBCDIR)/port/aio/%.c) \ + $(RTOBJS:%.o=$(LIBCDIR)/port/rt/%.c) \ + $(SECFLAGSOBJS:%.o=$(SRC)/common/secflags/%.c) \ + $(TPOOLOBJS:%.o=$(LIBCDIR)/port/tpool/%.c) \ + $(THREADSOBJS:%.o=$(LIBCDIR)/port/threads/%.c) \ + $(THREADSMACHOBJS:%.o=$(LIBCDIR)/$(MACH)/threads/%.c) \ $(UNICODEOBJS:%.o=$(SRC)/common/unicode/%.c) \ - $(UNWINDMACHOBJS:%.o=$(LIBCDIR)/port/unwind/%.c) \ - $(FPOBJS:%.o=$(LIBCDIR)/$(MACH)/fp/%.c) \ + $(UNWINDMACHOBJS:%.o=$(LIBCDIR)/port/unwind/%.c) \ + $(FPOBJS:%.o=$(LIBCDIR)/$(MACH)/fp/%.c) \ $(FPOBJS64:%.o=$(LIBCBASE)/fp/%.c) \ $(LIBCBASE)/crt/_ftou.c \ $(LIBCBASE)/gen/_xregs_clrptr.c \ |