diff options
author | Dan McDonald <danmcd@joyent.com> | 2021-08-20 17:08:39 -0400 |
---|---|---|
committer | Dan McDonald <danmcd@joyent.com> | 2021-08-20 17:08:39 -0400 |
commit | a2147f7a3c06d97137a8fe90bd5a977834ce127e (patch) | |
tree | c0c7e9853712f3a675df762f911cfd0c0e86e45a | |
parent | 11a4a3baf9e07b7dce7a0bf888f756236a4037e4 (diff) | |
parent | a2027c5d4c477546faea39a790b019c3480c9b9b (diff) | |
download | illumos-joyent-a2147f7a3c06d97137a8fe90bd5a977834ce127e.tar.gz |
[illumos-gate merge]
commit a2027c5d4c477546faea39a790b019c3480c9b9b
13965 loader: open file list should be dynamic
commit d6bf170859287b7b5b26419e266a7e6fdee7ff4d
13997 Want memrchr in libc
Conflicts:
manifest
30 files changed, 887 insertions, 304 deletions
@@ -13801,6 +13801,7 @@ s usr/share/man/man3c/memcmp.3c=memory.3c s usr/share/man/man3c/memcpy.3c=memory.3c s usr/share/man/man3c/memmem.3c=memory.3c s usr/share/man/man3c/memmove.3c=memory.3c +s usr/share/man/man3c/memrchr.3c=memory.3c f usr/share/man/man3c/memory.3c 0444 root bin s usr/share/man/man3c/memset.3c=memory.3c f usr/share/man/man3c/memset_s.3c 0444 root bin diff --git a/usr/src/boot/Makefile.version b/usr/src/boot/Makefile.version index ffa5854c66..a45290a429 100644 --- a/usr/src/boot/Makefile.version +++ b/usr/src/boot/Makefile.version @@ -34,4 +34,4 @@ LOADER_VERSION = 1.1 # Use date like formatting here, YYYY.MM.DD.XX, without leading zeroes. # The version is processed from left to right, the version number can only # be increased. -BOOT_VERSION = $(LOADER_VERSION)-2021.08.03.1 +BOOT_VERSION = $(LOADER_VERSION)-2021.08.03.2 diff --git a/usr/src/boot/lib/libstand/close.c b/usr/src/boot/lib/libstand/close.c index 573cef4dbd..546dd98600 100644 --- a/usr/src/boot/lib/libstand/close.c +++ b/usr/src/boot/lib/libstand/close.c @@ -67,23 +67,38 @@ int close(int fd) { - struct open_file *f = &files[fd]; + struct open_file *f, *last; int err1 = 0, err2 = 0; - if ((unsigned)fd >= SOPEN_MAX || f->f_flags == 0) { + f = fd2open_file(fd); + if (f == NULL) { errno = EBADF; return (-1); } free(f->f_rabuf); f->f_rabuf = NULL; - if (!(f->f_flags & F_RAW) && f->f_ops) - err1 = (f->f_ops->fo_close)(f); - if (!(f->f_flags & F_NODEV) && f->f_dev) - err2 = (f->f_dev->dv_close)(f); - if (f->f_devdata != NULL) - devclose(f); - f->f_flags = 0; + if (f->f_flags != 0) { + if (!(f->f_flags & F_RAW) && f->f_ops) + err1 = (f->f_ops->fo_close)(f); + if (!(f->f_flags & F_NODEV) && f->f_dev) + err2 = (f->f_dev->dv_close)(f); + if (f->f_devdata != NULL) + devclose(f); + f->f_flags = 0; + } else { + /* Attempt to close already closed file. */ + err1 = EBADF; + } + + /* free unused entries from tail. */ + TAILQ_FOREACH_REVERSE_SAFE(last, &files, file_list, f_link, f) { + if (last->f_flags != 0) + break; + TAILQ_REMOVE(&files, last, f_link); + free(last); + } + if (err1) { errno = err1; return (-1); diff --git a/usr/src/boot/lib/libstand/closeall.c b/usr/src/boot/lib/libstand/closeall.c index 13ff905a7e..425cd334b7 100644 --- a/usr/src/boot/lib/libstand/closeall.c +++ b/usr/src/boot/lib/libstand/closeall.c @@ -1,11 +1,7 @@ -/* $NetBSD: closeall.c,v 1.1 1996/01/13 22:25:36 leo Exp $ */ - -/* - * Copyright (c) 1993 - * The Regents of the University of California. All rights reserved. +/*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD * - * This code is derived from software contributed to Berkeley by - * The Mach Operating System project at Carnegie-Mellon University. + * Copyright (c) 2021 Toomas Soome <tsoome@me.com> * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -15,14 +11,11 @@ * 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 + * 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 REGENTS OR CONTRIBUTORS BE LIABLE + * 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) @@ -30,34 +23,6 @@ * 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. - * - * @(#)close.c 8.1 (Berkeley) 6/11/93 - * - * - * Copyright (c) 1989, 1990, 1991 Carnegie Mellon University - * All Rights Reserved. - * - * Author: Alessandro Forin - * - * Permission to use, copy, modify and distribute this software and its - * documentation is hereby granted, provided that both the copyright - * notice and this permission notice appear in all copies of the - * software, derivative works or modified versions, and any portions - * thereof, and that both notices appear in supporting documentation. - * - * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" - * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR - * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. - * - * Carnegie Mellon requests users of this software to return to - * - * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU - * School of Computer Science - * Carnegie Mellon University - * Pittsburgh PA 15213-3890 - * - * any improvements or extensions that they make and grant Carnegie the - * rights to redistribute these changes. */ #include <sys/cdefs.h> @@ -67,9 +32,15 @@ void closeall(void) { - int i; + struct open_file *f; - for (i = 0; i < SOPEN_MAX; i++) - if (files[i].f_flags != 0) - (void) close(i); + /* + * Pick up last entry and close it, this will also trigger + * the removal of this entry, and we end up with empty list. + */ + while ((f = TAILQ_LAST(&files, file_list)) != NULL) { + (void) close(f->f_id); + } + /* reset errno from close() */ + errno = 0; } diff --git a/usr/src/boot/lib/libstand/fstat.c b/usr/src/boot/lib/libstand/fstat.c index 3c33de0cc3..44030d085e 100644 --- a/usr/src/boot/lib/libstand/fstat.c +++ b/usr/src/boot/lib/libstand/fstat.c @@ -38,9 +38,10 @@ int fstat(int fd, struct stat *sb) { - struct open_file *f = &files[fd]; + struct open_file *f; - if ((unsigned)fd >= SOPEN_MAX || f->f_flags == 0) { + f = fd2open_file(fd); + if (f == NULL || f->f_flags == 0) { errno = EBADF; return (-1); } diff --git a/usr/src/boot/lib/libstand/ioctl.c b/usr/src/boot/lib/libstand/ioctl.c index 557cddf3ef..67c95c77d6 100644 --- a/usr/src/boot/lib/libstand/ioctl.c +++ b/usr/src/boot/lib/libstand/ioctl.c @@ -67,9 +67,10 @@ int ioctl(int fd, ulong_t cmd, char *arg) { - struct open_file *f = &files[fd]; + struct open_file *f; - if ((unsigned)fd >= SOPEN_MAX || f->f_flags == 0) { + f = fd2open_file(fd); + if (f == NULL || f->f_flags == 0) { errno = EBADF; return (-1); } diff --git a/usr/src/boot/lib/libstand/iodesc.h b/usr/src/boot/lib/libstand/iodesc.h index 37ae044af9..2086c586d2 100644 --- a/usr/src/boot/lib/libstand/iodesc.h +++ b/usr/src/boot/lib/libstand/iodesc.h @@ -1,7 +1,7 @@ /* $NetBSD: iodesc.h,v 1.4 1995/09/23 03:31:50 gwr Exp $ */ /* - * Copyright (c) 1993 Adam Glass + * Copyright (c) 1993 Adam Glass * Copyright (c) 1992 Regents of the University of California. * All rights reserved. * @@ -47,6 +47,8 @@ struct iodesc { u_long xid; /* transaction identification */ u_char myea[6]; /* my ethernet address */ struct netif *io_netif; + int io_id; /* descriptor id */ + TAILQ_ENTRY(iodesc) io_link; /* next entry in list */ }; #endif /* __SYS_LIBNETBOOT_IODESC_H */ diff --git a/usr/src/boot/lib/libstand/lseek.c b/usr/src/boot/lib/libstand/lseek.c index bfac8624a6..eb063394a1 100644 --- a/usr/src/boot/lib/libstand/lseek.c +++ b/usr/src/boot/lib/libstand/lseek.c @@ -32,30 +32,30 @@ * SUCH DAMAGE. * * @(#)lseek.c 8.1 (Berkeley) 6/11/93 - * + * * * Copyright (c) 1989, 1990, 1991 Carnegie Mellon University * All Rights Reserved. * * Author: Alessandro Forin - * + * * Permission to use, copy, modify and distribute this software and its * documentation is hereby granted, provided that both the copyright * notice and this permission notice appear in all copies of the * software, derivative works or modified versions, and any portions * thereof, and that both notices appear in supporting documentation. - * + * * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. - * + * * Carnegie Mellon requests users of this software to return to - * + * * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU * School of Computer Science * Carnegie Mellon University * Pittsburgh PA 15213-3890 - * + * * any improvements or extensions that they make and grant Carnegie the * rights to redistribute these changes. */ @@ -66,74 +66,76 @@ off_t lseek(int fd, off_t offset, int where) { - off_t bufpos, filepos, target; - struct open_file *f = &files[fd]; + off_t bufpos, filepos, target; + struct open_file *f; - if ((unsigned)fd >= SOPEN_MAX || f->f_flags == 0) { - errno = EBADF; - return (-1); - } - - if (f->f_flags & F_RAW) { - /* - * On RAW devices, update internal offset. - */ - switch (where) { - case SEEK_SET: - f->f_offset = offset; - break; - case SEEK_CUR: - f->f_offset += offset; - break; - default: - errno = EOFFSET; - return (-1); + f = fd2open_file(fd); + if (f == NULL || f->f_flags == 0) { + errno = EBADF; + return (-1); } - return (f->f_offset); - } - /* - * If there is some unconsumed data in the readahead buffer and it - * contains the desired offset, simply adjust the buffer offset and - * length. We don't bother with SEEK_END here, since the code to - * handle it would fail in the same cases where the non-readahead - * code fails (namely, for streams which cannot seek backward and whose - * size isn't known in advance). - */ - if (f->f_ralen != 0 && where != SEEK_END) { - if ((filepos = (f->f_ops->fo_seek)(f, (off_t)0, SEEK_CUR)) == -1) - return (-1); - bufpos = filepos - f->f_ralen; - switch (where) { - case SEEK_SET: - target = offset; - break; - case SEEK_CUR: - target = bufpos + offset; - break; - default: - errno = EINVAL; - return (-1); + if (f->f_flags & F_RAW) { + /* + * On RAW devices, update internal offset. + */ + switch (where) { + case SEEK_SET: + f->f_offset = offset; + break; + case SEEK_CUR: + f->f_offset += offset; + break; + default: + errno = EOFFSET; + return (-1); + } + return (f->f_offset); } - if (bufpos <= target && target < filepos) { - f->f_raoffset += target - bufpos; - f->f_ralen -= target - bufpos; - return (target); + + /* + * If there is some unconsumed data in the readahead buffer and it + * contains the desired offset, simply adjust the buffer offset and + * length. We don't bother with SEEK_END here, since the code to + * handle it would fail in the same cases where the non-readahead + * code fails (namely, for streams which cannot seek backward and whose + * size isn't known in advance). + */ + if (f->f_ralen != 0 && where != SEEK_END) { + filepos = (f->f_ops->fo_seek)(f, 0, SEEK_CUR); + if (filepos == -1) + return (-1); + bufpos = filepos - f->f_ralen; + switch (where) { + case SEEK_SET: + target = offset; + break; + case SEEK_CUR: + target = bufpos + offset; + break; + default: + errno = EINVAL; + return (-1); + } + if (bufpos <= target && target < filepos) { + f->f_raoffset += target - bufpos; + f->f_ralen -= target - bufpos; + return (target); + } } - } - /* - * If this is a relative seek, we need to correct the offset for - * bytes that we have already read but the caller doesn't know - * about. - */ - if (where == SEEK_CUR) - offset -= f->f_ralen; + /* + * If this is a relative seek, we need to correct the offset for + * bytes that we have already read but the caller doesn't know + * about. + */ + if (where == SEEK_CUR) + offset -= f->f_ralen; - /* - * Invalidate the readahead buffer. - */ - f->f_ralen = 0; + /* + * Invalidate the readahead buffer. + */ + f->f_ralen = 0; - return (f->f_ops->fo_seek)(f, offset, where); + return (f->f_ops->fo_seek)(f, offset, where); } diff --git a/usr/src/boot/lib/libstand/net.h b/usr/src/boot/lib/libstand/net.h index 99081a634a..93ab8d84e7 100644 --- a/usr/src/boot/lib/libstand/net.h +++ b/usr/src/boot/lib/libstand/net.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 1993 Adam Glass + * Copyright (c) 1993 Adam Glass * Copyright (c) 1992 Regents of the University of California. * All rights reserved. * @@ -93,8 +93,6 @@ extern u_int intf_mtu; extern int debug; /* defined in the machdep sources */ -extern struct iodesc sockets[SOPEN_MAX]; - /* ARP/RevARP functions: */ u_char *arpwhohas(struct iodesc *, struct in_addr); void arp_reply(struct iodesc *, void *); diff --git a/usr/src/boot/lib/libstand/netif.c b/usr/src/boot/lib/libstand/netif.c index 0e6c71569d..74364e9098 100644 --- a/usr/src/boot/lib/libstand/netif.c +++ b/usr/src/boot/lib/libstand/netif.c @@ -46,7 +46,19 @@ #include "net.h" #include "netif.h" -struct iodesc sockets[SOPEN_MAX]; +typedef TAILQ_HEAD(socket_list, iodesc) socket_list_t; + +/* + * Open socket list. The current implementation and assumption is, + * we only remove entries from tail and we only add new entries to tail. + * This decision is to keep iodesc id management simple - we get list + * entries ordered by continiously growing io_id field. + * If we do have multiple sockets open and we do close socket not from tail, + * this entry will be marked unused. netif_open() will reuse unused entry, or + * netif_close() will free all unused tail entries. + */ +static socket_list_t sockets = TAILQ_HEAD_INITIALIZER(sockets); + #ifdef NETIF_DEBUG int netif_debug = 0; #endif @@ -258,32 +270,67 @@ netif_put(struct iodesc *desc, void *pkt, size_t len) return (rv); } +/* + * socktodesc_impl: + * + * Walk socket list and return pointer to iodesc structure. + * if id is < 0, return first unused iodesc. + */ +static struct iodesc * +socktodesc_impl(int socket) +{ + struct iodesc *s; + + TAILQ_FOREACH(s, &sockets, io_link) { + /* search by socket id */ + if (socket >= 0) { + if (s->io_id == socket) + break; + continue; + } + /* search for first unused entry */ + if (s->io_netif == NULL) + break; + } + return (s); +} + struct iodesc * socktodesc(int sock) { - if (sock >= SOPEN_MAX) { + struct iodesc *desc; + + if (sock < 0) + desc = NULL; + else + desc = socktodesc_impl(sock); + + if (desc == NULL) errno = EBADF; - return (NULL); - } - return (&sockets[sock]); + + return (desc); } int netif_open(void *machdep_hint) { - int fd; struct iodesc *s; struct netif *nif; /* find a free socket */ - for (fd = 0, s = sockets; fd < SOPEN_MAX; fd++, s++) - if (s->io_netif == (struct netif *)0) - goto fnd; - errno = EMFILE; - return (-1); - -fnd: - bzero(s, sizeof (*s)); + s = socktodesc_impl(-1); + if (s == NULL) { + struct iodesc *last; + + s = calloc(1, sizeof (*s)); + if (s == NULL) + return (-1); + last = TAILQ_LAST(&sockets, socket_list); + if (last != NULL) + s->io_id = last->io_id + 1; + TAILQ_INSERT_TAIL(&sockets, s, io_link); + } + netif_init(); nif = netif_select(machdep_hint); if (!nif) @@ -296,18 +343,43 @@ fnd: } netif_attach(nif, s, machdep_hint); - return (fd); + return (s->io_id); } int netif_close(int sock) { - if (sock >= SOPEN_MAX) { - errno = EBADF; + struct iodesc *s, *last; + int err; + + err = 0; + s = socktodesc_impl(sock); + if (s == NULL || sock < 0) { + err = EBADF; + return (-1); + } + netif_detach(s->io_netif); + + bzero(&s->destip, sizeof (s->destip)); + bzero(&s->myip, sizeof (s->myip)); + s->destport = 0; + s->myport = 0; + s->xid = 0; + bzero(s->myea, sizeof (s->myea)); + s->io_netif = NULL; + + /* free unused entries from tail. */ + TAILQ_FOREACH_REVERSE_SAFE(last, &sockets, socket_list, io_link, s) { + if (last->io_netif != NULL) + break; + TAILQ_REMOVE(&sockets, last, io_link); + free(last); + } + + if (err) { + errno = err; return (-1); } - netif_detach(sockets[sock].io_netif); - sockets[sock].io_netif = (struct netif *)0; return (0); } diff --git a/usr/src/boot/lib/libstand/open.c b/usr/src/boot/lib/libstand/open.c index 5fd6c2a5fb..6d026f1ca6 100644 --- a/usr/src/boot/lib/libstand/open.c +++ b/usr/src/boot/lib/libstand/open.c @@ -66,17 +66,65 @@ struct fs_ops *exclusive_file_system; -struct open_file files[SOPEN_MAX]; +/* + * Open file list. The current implementation and assumption is, + * we only remove entries from tail and we only add new entries to tail. + * This decision is to keep file id management simple - we get list + * entries ordered by continiously growing f_id field. + * If we do have multiple files open and we do close file not from tail, + * this entry will be marked unused. open() will reuse unused entry, or + * close will free all unused tail entries. + * + * Only case we expect open file list to grow long, is with zfs pools with + * many disks. + */ +file_list_t files = TAILQ_HEAD_INITIALIZER(files); + +/* + * Walk file list and return pointer to open_file structure. + * if fd is < 0, return first unused open_file. + */ +struct open_file * +fd2open_file(int fd) +{ + struct open_file *f; + + TAILQ_FOREACH(f, &files, f_link) { + if (fd >= 0) { + if (f->f_id == fd) + break; + continue; + } + if (f->f_flags == 0) + break; + } + return (f); +} static int -o_gethandle(void) +o_gethandle(struct open_file **ptr) { - int fd; + struct open_file *f, *last; - for (fd = 0; fd < SOPEN_MAX; fd++) - if (files[fd].f_flags == 0) - return (fd); - return (-1); + /* Pick up unused entry */ + f = fd2open_file(-1); + if (f != NULL) { + *ptr = f; + return (f->f_id); + } + + /* Add new entry */ + f = calloc(1, sizeof (*f)); + if (f == NULL) + return (-1); + + last = TAILQ_LAST(&files, file_list); + if (last != NULL) + f->f_id = last->f_id + 1; + TAILQ_INSERT_TAIL(&files, f, f_link); + + *ptr = f; + return (f->f_id); } static void @@ -95,12 +143,11 @@ open(const char *fname, int mode) int fd, i, error, besterror; const char *file; - if ((fd = o_gethandle()) == -1) { + if ((fd = o_gethandle(&f)) == -1) { errno = EMFILE; return (-1); } - f = &files[fd]; f->f_flags = mode + 1; f->f_dev = NULL; f->f_ops = NULL; diff --git a/usr/src/boot/lib/libstand/read.c b/usr/src/boot/lib/libstand/read.c index 41e94a4f8b..ebbc082705 100644 --- a/usr/src/boot/lib/libstand/read.c +++ b/usr/src/boot/lib/libstand/read.c @@ -68,10 +68,11 @@ ssize_t read(int fd, void *dest, size_t bcount) { - struct open_file *f = &files[fd]; + struct open_file *f; size_t resid; - if ((unsigned)fd >= SOPEN_MAX || !(f->f_flags & F_READ)) { + f = fd2open_file(fd); + if (f == NULL || !(f->f_flags & F_READ)) { errno = EBADF; return (-1); } diff --git a/usr/src/boot/lib/libstand/readdir.c b/usr/src/boot/lib/libstand/readdir.c index e49d93d15e..6920f5b5fe 100644 --- a/usr/src/boot/lib/libstand/readdir.c +++ b/usr/src/boot/lib/libstand/readdir.c @@ -25,7 +25,6 @@ */ #include <sys/cdefs.h> -__FBSDID("$FreeBSD$"); #include <sys/param.h> #include "stand.h" @@ -34,9 +33,10 @@ struct dirent * readdirfd(int fd) { static struct dirent dir; /* XXX not thread safe */ - struct open_file *f = &files[fd]; + struct open_file *f; - if ((unsigned)fd >= SOPEN_MAX || !(f->f_flags & F_READ)) { + f = fd2open_file(fd); + if (f == NULL || !(f->f_flags & F_READ)) { errno = EBADF; return (NULL); } diff --git a/usr/src/boot/lib/libstand/stand.h b/usr/src/boot/lib/libstand/stand.h index 1af513b5fa..408ebd73da 100644 --- a/usr/src/boot/lib/libstand/stand.h +++ b/usr/src/boot/lib/libstand/stand.h @@ -65,6 +65,7 @@ #include <sys/cdefs.h> #include <sys/stat.h> #include <sys/dirent.h> +#include <sys/queue.h> /* this header intentionally exports NULL from <string.h> */ #include <string.h> @@ -183,11 +184,14 @@ struct open_file { char *f_rabuf; /* readahead buffer pointer */ size_t f_ralen; /* valid data in readahead buffer */ off_t f_raoffset; /* consumer offset in readahead buffer */ + int f_id; /* file number */ + TAILQ_ENTRY(open_file) f_link; /* next entry */ #define SOPEN_RASIZE 512 }; -#define SOPEN_MAX 64 -extern struct open_file files[]; +typedef TAILQ_HEAD(file_list, open_file) file_list_t; +extern file_list_t files; +extern struct open_file *fd2open_file(int); /* f_flags values */ #define F_READ 0x0001 /* file opened for reading */ diff --git a/usr/src/boot/lib/libstand/write.c b/usr/src/boot/lib/libstand/write.c index 86bc162fe5..3edab25428 100644 --- a/usr/src/boot/lib/libstand/write.c +++ b/usr/src/boot/lib/libstand/write.c @@ -68,10 +68,11 @@ ssize_t write(int fd, const void *dest, size_t bcount) { - struct open_file *f = &files[fd]; + struct open_file *f; size_t resid; - if ((unsigned)fd >= SOPEN_MAX || !(f->f_flags & F_WRITE)) { + f = fd2open_file(fd); + if (f == NULL || !(f->f_flags & F_WRITE)) { errno = EBADF; return (-1); } diff --git a/usr/src/head/string.h b/usr/src/head/string.h index f75c14c59c..f7d90e827e 100644 --- a/usr/src/head/string.h +++ b/usr/src/head/string.h @@ -121,6 +121,7 @@ extern int fls(int); extern int flsl(long); extern int flsll(long long); extern void *memmem(const void *, size_t, const void *, size_t); +extern void *memrchr(const void *, int, size_t); extern char *strcasestr(const char *, const char *); extern char *strnstr(const char *, const char *, size_t); extern size_t strlcpy(char *, const char *, size_t); @@ -130,7 +131,7 @@ extern char *strchrnul(const char *, int); extern char *strcasestr_l(const char *, const char *, locale_t); extern int strcasecmp(const char *, const char *); extern int strncasecmp(const char *, const char *, size_t); -#endif /* defined(__EXTENSIONS__)... */ +#endif /* !defined(__STRICT_SYMBOLS) */ #if defined(__EXTENSIONS__) || \ (!defined(_STRICT_STDC) && !defined(__XOPEN_OR_POSIX)) || \ diff --git a/usr/src/lib/libc/amd64/Makefile b/usr/src/lib/libc/amd64/Makefile index 710a72e87e..848ad4a6bd 100644 --- a/usr/src/lib/libc/amd64/Makefile +++ b/usr/src/lib/libc/amd64/Makefile @@ -470,6 +470,7 @@ PORTGEN= \ madvise.o \ malloc.o \ memalign.o \ + memrchr.o \ memset_s.o \ mkdev.o \ mkdtemp.o \ diff --git a/usr/src/lib/libc/i386/Makefile.com b/usr/src/lib/libc/i386/Makefile.com index a074accf08..df33074538 100644 --- a/usr/src/lib/libc/i386/Makefile.com +++ b/usr/src/lib/libc/i386/Makefile.com @@ -506,6 +506,7 @@ PORTGEN= \ madvise.o \ malloc.o \ memalign.o \ + memrchr.o \ memset_s.o \ mkdev.o \ mkdtemp.o \ diff --git a/usr/src/lib/libc/port/gen/memrchr.c b/usr/src/lib/libc/port/gen/memrchr.c new file mode 100644 index 0000000000..f7a8bbc9ab --- /dev/null +++ b/usr/src/lib/libc/port/gen/memrchr.c @@ -0,0 +1,38 @@ +/* + * This file and its contents are supplied under the terms of the + * Common Development and Distribution License ("CDDL"), version 1.0. + * You may only use this file in accordance with the terms of version + * 1.0 of the CDDL. + * + * A full copy of the text of the CDDL should have accompanied this + * source. A copy of the CDDL is also available via the Internet at + * http://www.illumos.org/license/CDDL. + */ + +/* + * Copyright 2021 Oxide Computer Company + */ + +/* + * memrchr(3C) implementation. Find the first occurence of 'c' as an unsigned + * char in 's', by searching in reverse. + */ + +#include <string.h> + +void * +memrchr(const void *s, int c, size_t len) +{ + unsigned char val = (unsigned char)c; + const unsigned char *data = s; + + for (; len > 0; len--) { + size_t pos = len - 1; + + if (data[pos] == val) { + return ((void *)&data[pos]); + } + } + + return (NULL); +} diff --git a/usr/src/lib/libc/port/mapfile-vers b/usr/src/lib/libc/port/mapfile-vers index fc31a271fd..aa208035dc 100644 --- a/usr/src/lib/libc/port/mapfile-vers +++ b/usr/src/lib/libc/port/mapfile-vers @@ -78,6 +78,11 @@ $if _x86 && _ELF64 $add amd64 $endif +SYMBOL_VERSION ILLUMOS_0.39 { + protected: + memrchr; +} ILLUMOS_0.38; + SYMBOL_VERSION ILLUMOS_0.38 { protected: getgrouplist; diff --git a/usr/src/lib/libc/sparc/Makefile.com b/usr/src/lib/libc/sparc/Makefile.com index 2b20606aa6..f5570084da 100644 --- a/usr/src/lib/libc/sparc/Makefile.com +++ b/usr/src/lib/libc/sparc/Makefile.com @@ -533,6 +533,7 @@ PORTGEN= \ madvise.o \ malloc.o \ memalign.o \ + memrchr.o \ memset_s.o \ mkdev.o \ mkdtemp.o \ diff --git a/usr/src/lib/libc/sparcv9/Makefile.com b/usr/src/lib/libc/sparcv9/Makefile.com index 42a6048ff8..f229f21e50 100644 --- a/usr/src/lib/libc/sparcv9/Makefile.com +++ b/usr/src/lib/libc/sparcv9/Makefile.com @@ -491,6 +491,7 @@ PORTGEN= \ madvise.o \ malloc.o \ memalign.o \ + memrchr.o \ memset_s.o \ mkdev.o \ mkdtemp.o \ diff --git a/usr/src/man/man3c/Makefile b/usr/src/man/man3c/Makefile index e9f8f2cafd..c50fdfd7c5 100644 --- a/usr/src/man/man3c/Makefile +++ b/usr/src/man/man3c/Makefile @@ -1029,6 +1029,7 @@ MANLINKS= FD_CLR.3c \ memcpy.3c \ memmem.3c \ memmove.3c \ + memrchr.3c \ memset.3c \ minor.3c \ mkdtemp.3c \ @@ -2049,6 +2050,7 @@ memcmp.3c := LINKSRC = memory.3c memcpy.3c := LINKSRC = memory.3c memmem.3c := LINKSRC = memory.3c memmove.3c := LINKSRC = memory.3c +memrchr.3c := LINKSRC = memory.3c memset.3c := LINKSRC = memory.3c mkfifoat.3c := LINKSRC = mkfifo.3c diff --git a/usr/src/man/man3c/memory.3c b/usr/src/man/man3c/memory.3c index 368956c97f..5a11990914 100644 --- a/usr/src/man/man3c/memory.3c +++ b/usr/src/man/man3c/memory.3c @@ -1,144 +1,253 @@ -'\" te +.\" .\" Copyright (c) 2014, Joyent, Inc. .\" Copyright (c) 2009, Sun Microsystems, Inc. All Rights Reserved. .\" Copyright 1989 AT&T -.\" The contents of this file are subject to the terms of the Common Development and Distribution License (the "License"). You may not use this file except in compliance with the License. -.\" You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE or http://www.opensolaris.org/os/licensing. See the License for the specific language governing permissions and limitations under the License. -.\" When distributing Covered Code, include this CDDL HEADER in each file and include the License file at usr/src/OPENSOLARIS.LICENSE. If applicable, add the following below this CDDL HEADER, with the fields enclosed by brackets "[]" replaced with your own identifying information: Portions Copyright [yyyy] [name of copyright owner] -.TH MEMORY 3C "Feb 4, 2009" -.SH NAME -memory, memccpy, memchr, memcmp, memcpy, memmem, memmove, memset \- memory operations -.SH SYNOPSIS -.LP -.nf -#include <string.h> - -\fBvoid *\fR\fBmemccpy\fR(\fBvoid *restrict\fR \fIs1\fR, \fBconst void *restrict\fR \fIs2\fR, - \fBint\fR \fIc\fR, \fBsize_t\fR \fIn\fR); -.fi - -.LP -.nf -\fBvoid *\fR\fBmemchr\fR(\fBconst void *\fR\fIs\fR, \fBint\fR \fIc\fR, \fBsize_t\fR \fIn\fR); -.fi - -.LP -.nf -\fBint\fR \fBmemcmp\fR(\fBconst void *\fR\fIs1\fR, \fBconst void *\fR\fIs2\fR, \fBsize_t\fR \fIn\fR); -.fi - -.LP -.nf -\fBvoid *\fR\fBmemcpy\fR(\fBvoid *restrict\fR \fIs1\fR, \fBconst void *restrict\fR \fIs2\fR, \fBsize_t\fR \fIn\fR); -.fi - -.LP -.nf -\fBvoid *\fR\fBmemmem\fR(\fBconst void *\fR\fIl\fR, \fBsize_t\fR \fIl_len\fR, \fBconst void *\fR\fIs\fR, \fBsize_t\fR \fIs_len\fR); -.fi - -.LP -.nf -\fBvoid *\fR\fBmemmove\fR(\fBvoid *\fR\fIs1\fR, \fBconst void *\fR\fIs2\fR, \fBsize_t\fR \fIn\fR); -.fi - -.LP -.nf -\fBvoid *\fR\fBmemset\fR(\fBvoid *\fR\fIs\fR, \fBint\fR \fIc\fR, \fBsize_t\fR \fIn\fR); -.fi - -.SS "ISO C++" -.LP -.nf -#include <string.h> - -\fBconst void *\fR\fBmemchr\fR(\fBconst void *\fR\fIs\fR, \fBint\fR \fIc\fR, \fBsize_t\fR \fIn\fR); -.fi - -.LP -.nf -#include <cstring> - -\fBvoid *std::\fR\fBmemchr\fR(\fBvoid *\fR\fIs\fR, \fBint\fR \fIc\fR, \fBsize_t\fR \fIn\fR); -.fi - -.SH DESCRIPTION -.LP +.\" Copyright 2021 Oxide Computer Company +.\" +.\" The contents of this file are subject to the terms of the +.\" Common Development and Distribution License (the "License"). +.\" You may not use this file except in compliance with the License. +.\" +.\" You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +.\" or http://www.opensolaris.org/os/licensing. +.\" See the License for the specific language governing permissions +.\" and limitations under the License. +.\" +.\" When distributing Covered Code, include this CDDL HEADER in each +.\" file and include the License file at usr/src/OPENSOLARIS.LICENSE. +.\" If applicable, add the following below this CDDL HEADER, with the +.\" fields enclosed by brackets "[]" replaced with your own identifying +.\" information: Portions Copyright [yyyy] [name of copyright owner] +.\" +.Dd August 6, 2021 +.Dt MEMORY 3C +.Os +.Sh NAME +.Nm memory , +.Nm memccpy , +.Nm memchr , +.Nm memcmp , +.Nm memcpy , +.Nm memmem , +.Nm memmove , +.Nm memrchr , +.Nm memset +.Nd memory operations +.Sh SYNOPSIS +.In string.h +.Ft "void *" +.Fo memccpy +.Fa "void *restrict s1" +.Fa "const void *restrict s2" +.Fa "int c" +.Fa "size_t n" +.Fc +.Ft "void *" +.Fo memchr +.Fa "void *s", +.Fa "int c" +.Fa "size_t n" +.Fc +.Ft int +.Fo memcmp +.Fa "const void *s1" +.Fa "const void *s2" +.Fa "size_t n" +.Fc +.Ft "void *" +.Fo memcpy +.Fa "void *restrict s1" +.Fa "const void *restrict s2" +.Fa "size_t n" +.Fc +.Ft "void *" +.Fo memmem +.Fa "const void *l" +.Fa "size_t l_len" +.Fa "const void *s" +.Fa "size_t s_len" +.Fc +.Ft "void *" +.Fo memmove +.Fa "void *s1" +.Fa "const void *s2" +.Fa "size_t n" +.Fc +.Ft "void *" +.Fo memrchr +.Fa "void *s", +.Fa "int c" +.Fa "size_t n" +.Fc +.Ft "void *" +.Fo memset +.Fa "void *s" +.Fa int c +.Fa "size_t n" +.Fc +.Sh DESCRIPTION These functions operate as efficiently as possible on memory areas (arrays of -bytes bounded by a count, not terminated by a null character). They do not -check for the overflow of any receiving memory area. -.sp -.LP -The \fBmemccpy()\fR function copies bytes from memory area \fIs2\fR into -\fIs1\fR, stopping after the first occurrence of \fIc\fR (converted to an -\fBunsigned char\fR) has been copied, or after \fIn\fR bytes have been copied, -whichever comes first. It returns a pointer to the byte after the copy of -\fIc\fR in \fIs1\fR, or a null pointer if \fIc\fR was not found in the first -\fIn\fR bytes of \fIs2\fR. -.sp -.LP -The \fBmemchr()\fR function returns a pointer to the first occurrence of -\fIc\fR (converted to an \fBunsigned char\fR) in the first \fIn\fR bytes (each -interpreted as an \fBunsigned char\fR) of memory area \fIs\fR, or a null -pointer if \fIc\fR does not occur. -.sp -.LP -The \fBmemcmp()\fR function compares its arguments, looking at the first -\fIn\fR bytes (each interpreted as an \fBunsigned char\fR), and returns an -integer less than, equal to, or greater than 0, according as \fIs1\fR is -lexicographically less than, equal to, or greater than \fIs2\fR when taken to -be unsigned characters. -.sp -.LP -The \fBmemcpy()\fR function copies \fIn\fR bytes from memory area \fIs2\fR to -\fIs1\fR. It returns \fIs1\fR. If copying takes place between objects that -overlap, the behavior is undefined. -.sp -.LP -The \fBmemmem()\fR function searches for the \fIs_len\fR long byte pattern -\fIs\fR in the memory region starting at \fIl\fR for \fIl_len\fR bytes. If a -match is found, a pointer to the starting location in \fIl\fR is returned. If no -match is found, \fIl_len\fR is zero, \fIs_len\fR is zero, or \fIl_len\fR is less -than \fIs_len\fR, then a null pointer is return. -.sp -.LP -The \fBmemmove()\fR function copies \fIn\fR bytes from memory area \fIs2\fR to -memory area \fIs1\fR. Copying between objects that overlap will take place -correctly. It returns \fIs1\fR. -.sp -.LP -The \fBmemset()\fR function sets the first \fIn\fR bytes in memory area \fIs\fR -to the value of \fIc\fR (converted to an \fBunsigned char\fR). It returns -\fIs\fR. -.SH USAGE -.LP -Using \fBmemcpy()\fR might be faster than using \fBmemmove()\fR if the +bytes bounded by a count, not terminated by a null character). +They do not check for the overflow of any receiving memory area. +.Pp +The +.Fn memccpy +function copies bytes from memory area +.Fa s2 +into +.Fa s1 , +stopping after the first occurrence of +.Fa c +.Po +converted to an +.Vt unsigned char +.Pc +has been copied, or after +.Fa n +bytes have been copied, whichever comes first. +It returns a pointer to the byte after the copy of +.Fa c +in +.Fa s1 , +or a +.Dv NULL +pointer if +.Fa c +was not found in the first +.Fa n +bytes of +.Fa s2 . +.Pp +The +.Fn memchr +function returns a pointer to the first occurrence of +.Fa c +.Po +converted to an +.Vt unsigned char +.Pc +in the first +.Fa n +bytes +.Po +each interpreted as an +.Vt unsigned char +.Pc +of memory area +.Fa s , +or a +.Dv NULL +pointer if +.Fa c +does not occur. +.Pp +The +.Fn memrchr +function behaves similarly to the +.Fn memchr +function, except that the memory area is searched in reverse from the +last byte. +.Pp +The +.Fn memcmp +function compares its arguments, looking at the first +.Fa n +bytes +.Po +each interpreted as an +.Vt unsigned char +.Pc , +and returns an integer less than, equal to, or greater than 0, according as +.Fa s1 +is less than, equal to, or greater than +.Fa s2 +when taken to be unsigned characters. +.Pp +The +.Fn memcpy +function copies +.Fa n +bytes from memory area +.Fa s2 +to +.Fa s1 +It returns +.Fa s1 . +If copying takes place between objects that overlap, the behavior is undefined. +In such cases, use +.Fn memmove +instead. +.Pp +The +.Fn memmem +function searches for the +.Fa s_len +long byte pattern +.Fa s +in the memory region starting at +.Fa l +for +.Fa l_len +bytes. +If a match is found, a pointer to the starting location in +.Fa l +is returned. +If no match is found, +.Fa l_len +is zero, +.Fa s_len +is zero, or +.Fa l_len +is less than +.Fa s_len +then a +.Dv NULL +pointer is return. +.Pp +The +.Fn memmove +function copies +.Fa n +bytes from memory area +.Fa s2 +to memory area +.Fa s1 . +Copying between objects that overlap will take place correctly. +It returns +.Fa s1 . +.Pp +The +.Fn memset +function sets the first +.Fa n +bytes in memory area +.Fa s +to the value of +.Fa c +.Po +converted to an +.Vt unsigned char +.Pc . +It returns +.Fa s . +.Sh USAGE +Using +.Fn memcpy +might be faster than using +.Fn memmove +if the application knows that the objects being copied do not overlap. -.SH ATTRIBUTES -.LP -See \fBattributes\fR(5) for descriptions of the following attributes: -.sp - -.sp -.TS -box; -c | c -l | l . -ATTRIBUTE TYPE ATTRIBUTE VALUE -_ -Interface Stability Stable -_ -MT-Level MT-Safe -_ -Standard See \fBstandards\fR(5). -.TE - -.SH SEE ALSO -.LP -\fBstring\fR(3C), \fBattributes\fR(5), \fBstandards\fR(5) -.SH NOTES -.LP -Overlap between objects being copied can arise even when their (virtual) +.Sh INTERFACE STABILITY +.Sy Committed +.Sh MT-LEVEL +.Sy MT-Safe +.Sh SEE ALSO +.Xr string 3C , +.Xr attributes 5 , +.Xr standards 5 +.Sh NOTES +Overlap between objects being copied can arise even when their +.Pq virtual address ranges appear to be disjoint; for example, as a result of memory-mapping overlapping portions of the same underlying file, or of attaching the same shared memory segment more than once. diff --git a/usr/src/pkg/manifests/system-library.man3c.inc b/usr/src/pkg/manifests/system-library.man3c.inc index 70c9189c0f..b45024541a 100644 --- a/usr/src/pkg/manifests/system-library.man3c.inc +++ b/usr/src/pkg/manifests/system-library.man3c.inc @@ -1029,6 +1029,7 @@ link path=usr/share/man/man3c/memcmp.3c target=memory.3c link path=usr/share/man/man3c/memcpy.3c target=memory.3c link path=usr/share/man/man3c/memmem.3c target=memory.3c link path=usr/share/man/man3c/memmove.3c target=memory.3c +link path=usr/share/man/man3c/memrchr.3c target=memory.3c link path=usr/share/man/man3c/memset.3c target=memory.3c link path=usr/share/man/man3c/minor.3c target=makedev.3c link path=usr/share/man/man3c/mkdtemp.3c target=mkstemp.3c diff --git a/usr/src/pkg/manifests/system-test-libctest.mf b/usr/src/pkg/manifests/system-test-libctest.mf index 092bbde222..e1844c6f05 100644 --- a/usr/src/pkg/manifests/system-test-libctest.mf +++ b/usr/src/pkg/manifests/system-test-libctest.mf @@ -101,6 +101,8 @@ file path=opt/libc-tests/tests/fpround_test.$(ARCH64) mode=0555 file path=opt/libc-tests/tests/i18n/bindtextdomain_test mode=0555 file path=opt/libc-tests/tests/i18n/bindtextdomain_test.$(ARCH) mode=0555 file path=opt/libc-tests/tests/i18n/bindtextdomain_test.$(ARCH64) mode=0555 +file path=opt/libc-tests/tests/memchr.32 mode=0555 +file path=opt/libc-tests/tests/memchr.64 mode=0555 file path=opt/libc-tests/tests/memset_s.32 mode=0555 file path=opt/libc-tests/tests/memset_s.64 mode=0555 file path=opt/libc-tests/tests/newlocale_test mode=0555 diff --git a/usr/src/test/libc-tests/cfg/symbols/string_h.cfg b/usr/src/test/libc-tests/cfg/symbols/string_h.cfg index 64506eb9dd..890d5f6459 100644 --- a/usr/src/test/libc-tests/cfg/symbols/string_h.cfg +++ b/usr/src/test/libc-tests/cfg/symbols/string_h.cfg @@ -29,5 +29,13 @@ type | locale_t | string.h | -ALL +SUSv4+ # # Functions # +func | memchr |\ + void * |\ + const void *; int; size_t |\ + string.h | ALL +func | memrchr |\ + void * |\ + const void *; int; size_t |\ + string.h | -ALL func | strerror_l | char * | int; locale_t | string.h |\ -ALL +SUSv4+ diff --git a/usr/src/test/libc-tests/runfiles/default.run b/usr/src/test/libc-tests/runfiles/default.run index 6ccb7c794f..99ba6d14c4 100644 --- a/usr/src/test/libc-tests/runfiles/default.run +++ b/usr/src/test/libc-tests/runfiles/default.run @@ -112,6 +112,8 @@ timeout = 600 [/opt/libc-tests/tests/env-7076.64] [/opt/libc-tests/tests/fnmatch.32] [/opt/libc-tests/tests/fnmatch.64] +[/opt/libc-tests/tests/memchr.32] +[/opt/libc-tests/tests/memchr.64] [/opt/libc-tests/tests/memset_s.32] [/opt/libc-tests/tests/memset_s.64] [/opt/libc-tests/tests/posix_memalign.32] diff --git a/usr/src/test/libc-tests/tests/Makefile b/usr/src/test/libc-tests/tests/Makefile index 016b2a0dab..51b8ac60f2 100644 --- a/usr/src/test/libc-tests/tests/Makefile +++ b/usr/src/test/libc-tests/tests/Makefile @@ -43,6 +43,7 @@ PROGS = \ endian \ env-7076 \ fnmatch \ + memchr \ memset_s \ posix_memalign \ printf-9511 \ diff --git a/usr/src/test/libc-tests/tests/memchr.c b/usr/src/test/libc-tests/tests/memchr.c new file mode 100644 index 0000000000..9ec3c6e0ef --- /dev/null +++ b/usr/src/test/libc-tests/tests/memchr.c @@ -0,0 +1,294 @@ +/* + * This file and its contents are supplied under the terms of the + * Common Development and Distribution License ("CDDL"), version 1.0. + * You may only use this file in accordance with the terms of version + * 1.0 of the CDDL. + * + * A full copy of the text of the CDDL should have accompanied this + * source. A copy of the CDDL is also available via the Internet at + * http://www.illumos.org/license/CDDL. + */ + +/* + * Copyright 2021 Oxide Computer Company + */ + +/* + * Various tests for memchr() and memrchr(). Note, this test assumes that the + * system is either ILP32 or LP64 with an 8-bit unsigned char due to the tests + * that are explicitly looking at making sure memchr() and memrchr() truncate + * correctly. + */ + +#include <string.h> +#include <unistd.h> +#include <sys/mman.h> +#include <err.h> +#include <stdlib.h> + +/* + * memchr_buf is a page sized buffer surrounded by two PROT_NONE pages which are + * meant to try and catch us walking over the edge of the buffer. + */ +static uint8_t *memchr_buf; +static size_t memchr_buflen; + +static void +memchr_setup(void) +{ + size_t pgsz = getpagesize(); + void *addr; + + if (pgsz <= 0) { + err(EXIT_FAILURE, "failed to get system page size"); + } + + addr = mmap(NULL, 3 * pgsz, PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANON, -1, 0); + if (addr == MAP_FAILED) { + err(EXIT_FAILURE, "failed to mmap %zu bytes", 3 * pgsz); + } + + memchr_buf = (uint8_t *)addr + pgsz; + memchr_buflen = pgsz; + + if (mprotect(addr, pgsz, PROT_NONE) != 0) { + err(EXIT_FAILURE, "failed to protect leading PROT_NONE guard " + "at %p", addr); + } + + addr = (uint8_t *)addr + 2 * pgsz; + if (mprotect(addr, pgsz, PROT_NONE) != 0) { + err(EXIT_FAILURE, "failed to protect trailing PROT_NONE guard " + "at %p", addr); + } +} + +static boolean_t +memchr_basic(void) +{ + boolean_t ret = B_TRUE; + const void *targ; + const void *found; + + (void) memset(memchr_buf, 0, memchr_buflen); + memchr_buf[0] = 'r'; + + if ((found = memchr(memchr_buf, 'r', memchr_buflen)) != memchr_buf) { + warnx("TEST FAILED: memchr failed to find 'r' (1), found %p, " + "expected %p", found, memchr_buf); + ret = B_FALSE; + } + + if ((found = memrchr(memchr_buf, 'r', memchr_buflen)) != memchr_buf) { + warnx("TEST FAILED: memrchr failed to find 'r' (1), found %p, " + "expected %p", found, memchr_buf); + ret = B_FALSE; + } + + memchr_buf[memchr_buflen - 1] = 'r'; + targ = &memchr_buf[memchr_buflen - 1]; + + if ((found = memchr(memchr_buf, 'r', memchr_buflen)) != memchr_buf) { + warnx("TEST FAILED: memchr failed to find 'r' (2), found %p, " + "expected %p", found, memchr_buf); + ret = B_FALSE; + } + + if ((found = memrchr(memchr_buf, 'r', memchr_buflen)) != targ) { + warnx("TEST FAILED: memrchr failed to find 'r' (2), found %p, " + "expected %p", found, targ); + warnx("TEST FAILED: memchr failed to find 'r'"); + ret = B_FALSE; + } + + memchr_buf[0] = 0; + + if ((found = memchr(memchr_buf, 'r', memchr_buflen)) != targ) { + warnx("TEST FAILED: memchr failed to find 'r' (3), found %p, " + "expected %p", found, targ); + ret = B_FALSE; + } + + if ((found = memrchr(memchr_buf, 'r', memchr_buflen)) != targ) { + warnx("TEST FAILED: memrchr failed to find 'r' (3), found %p, " + "expected %p", found, targ); + ret = B_FALSE; + } + + if (ret) { + (void) printf("TEST PASSED: basic memchr() and memrchr()\n"); + } + return (ret); +} + +static boolean_t +memchr_notfound(void) +{ + boolean_t ret = B_TRUE; + const void *found; + + (void) memset(memchr_buf, 0x23, memchr_buflen); + + if ((found = memchr(memchr_buf, 0, memchr_buflen)) != NULL) { + warnx("TEST FAILED: memchr unexpectedly found value (1), " + "found %p, expected %p", found, NULL); + ret = B_FALSE; + } + + if (memrchr(memchr_buf, 0, memchr_buflen) != NULL) { + warnx("TEST FAILED: memrchr unexpectedly found value (1), " + "found %p, expected %p", found, NULL); + ret = B_FALSE; + } + + if (memchr(memchr_buf, 0x24, memchr_buflen) != NULL) { + warnx("TEST FAILED: memchr unexpectedly found value (2), " + "found %p, expected %p", found, NULL); + ret = B_FALSE; + } + + if (memrchr(memchr_buf, 0x24, memchr_buflen) != NULL) { + warnx("TEST FAILED: memrchr unexpectedly found value (2), " + "found %p, expected %p", found, NULL); + ret = B_FALSE; + } + + memchr_buf[1] = 0x24; + + if (memchr(memchr_buf, 0x24, 1) != NULL) { + warnx("TEST FAILED: memchr unexpectedly found value (3), " + "found %p, expected %p", found, NULL); + ret = B_FALSE; + } + + if (memrchr(memchr_buf, 0x24, 1) != NULL) { + warnx("TEST FAILED: memrchr unexpectedly found value (3), " + "found %p, expected %p", found, NULL); + ret = B_FALSE; + } + + memchr_buf[1] = 0x24; + + if (memchr(memchr_buf + 1, 0x23, 1) != NULL) { + warnx("TEST FAILED: memchr unexpectedly found value (4), " + "found %p, expected %p", found, NULL); + ret = B_FALSE; + } + + if (memrchr(memchr_buf + 1, 0x23, 1) != NULL) { + warnx("TEST FAILED: memrchr unexpectedly found value (4), " + "found %p, expected %p", found, NULL); + ret = B_FALSE; + } + + if (ret) { + (void) printf("TEST PASSED: memchr() and memrchr() on " + "missing values\n"); + } + + return (ret); +} + +static boolean_t +memchr_truncation(void) +{ + boolean_t ret = B_TRUE; + const void *found; + const void *targ; + + (void) memset(memchr_buf, 0x42, memchr_buflen); + + if ((found = memchr(memchr_buf, 0x42, memchr_buflen)) != memchr_buf) { + warnx("TEST FAILED: memchr failed to find 0x42, found %p, " + "expected %p", found, memchr_buf); + ret = B_FALSE; + } + + targ = &memchr_buf[memchr_buflen - 1]; + + if ((found = memrchr(memchr_buf, 0x42, memchr_buflen)) != targ) { + warnx("TEST FAILED: memrchr failed to find 0x42, found %p, " + "expected %p", found, targ); + ret = B_FALSE; + } + + if ((found = memchr(memchr_buf, 0x430042, memchr_buflen)) != + memchr_buf) { + warnx("TEST FAILED: memchr failed to find 0x42 with 0x430042, " + "found %p, expected %p", found, memchr_buf); + ret = B_FALSE; + } + + if ((found = memrchr(memchr_buf, 0x430042, memchr_buflen)) != targ) { + warnx("TEST FAILED: memrchr failed to find 0x42 with 0x430042, " + "found %p, expected %p", found, targ); + ret = B_FALSE; + } + + /* + * -190 is -0xbe, which when cast to an unsigned char will be 0x42. + */ + if ((found = memchr(memchr_buf, -190, memchr_buflen)) != memchr_buf) { + warnx("TEST FAILED: memchr failed to find 0x42 with -190, " + "found %p, expected %p", found, memchr_buf); + ret = B_FALSE; + } + + if ((found = memrchr(memchr_buf, -190, memchr_buflen)) != targ) { + warnx("TEST FAILED: memrchr failed to find 0x42 with -190, " + "found %p, expected %p", found, targ); + ret = B_FALSE; + } + + if ((found = memchr(memchr_buf, -190, memchr_buflen)) != memchr_buf) { + warnx("TEST FAILED: memchr failed to find 0x42 with -190, " + "found %p, expected %p", found, memchr_buf); + ret = B_FALSE; + } + + if ((found = memrchr(memchr_buf, -190, memchr_buflen)) != targ) { + warnx("TEST FAILED: memrchr failed to find 0x42 with -190, " + "found %p, expected %p", found, targ); + ret = B_FALSE; + } + + if ((found = memchr(memchr_buf, 0x42424200, memchr_buflen)) != NULL) { + warnx("TEST FAILED: memchr somehow found 0x42 with " + "0x42424200, found %p, expected NULL", found); + ret = B_FALSE; + } + + if ((found = memrchr(memchr_buf, 0x42424200, memchr_buflen)) != NULL) { + warnx("TEST FAILED: memrchr somehow found 0x42 with " + "0x42424200, found %p, expected NULL", found); + ret = B_FALSE; + } + + if (ret) { + (void) printf("TEST PASSED: truncated values\n"); + } + + return (B_TRUE); +} + +int +main(void) +{ + int ret = EXIT_SUCCESS; + + memchr_setup(); + + if (!memchr_basic()) + ret = EXIT_FAILURE; + if (!memchr_notfound()) + ret = EXIT_FAILURE; + if (!memchr_truncation()) + ret = EXIT_FAILURE; + + if (ret == EXIT_SUCCESS) { + (void) printf("All tests passed successfully\n"); + } + + return (ret); +} |