/*-1* SPDX-License-Identifier: BSD-3-Clause2*3* Copyright (c) 1990, 19934* The Regents of the University of California. All rights reserved.5*6* This code is derived from software contributed to Berkeley by7* Chris Torek.8*9* Redistribution and use in source and binary forms, with or without10* modification, are permitted provided that the following conditions11* are met:12* 1. Redistributions of source code must retain the above copyright13* notice, this list of conditions and the following disclaimer.14* 2. Redistributions in binary form must reproduce the above copyright15* notice, this list of conditions and the following disclaimer in the16* documentation and/or other materials provided with the distribution.17* 3. Neither the name of the University nor the names of its contributors18* may be used to endorse or promote products derived from this software19* without specific prior written permission.20*21* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND22* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE23* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE24* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE25* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL26* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS27* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)28* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT29* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY30* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF31* SUCH DAMAGE.32*/3334#include <sys/param.h>35#include <machine/atomic.h>36#include <unistd.h>37#include <stdio.h>38#include <stdlib.h>39#include <stdint.h>40#include <string.h>4142#include <spinlock.h>4344#include "libc_private.h"45#include "local.h"46#include "glue.h"4748int __sdidinit;4950#define NDYNAMIC 10 /* add ten more whenever necessary */5152#define std(flags, file) { \53._flags = (flags), \54._file = (file), \55._cookie = __sF + (file), \56._close = __sclose, \57._read = __sread, \58._seek = __sseek, \59._write = __swrite, \60._fl_mutex = PTHREAD_MUTEX_INITIALIZER, \61}62/* the usual - (stdin + stdout + stderr) */63static FILE usual[FOPEN_MAX - 3];64static struct glue uglue = { NULL, FOPEN_MAX - 3, usual };6566static FILE __sF[3] = {67std(__SRD, STDIN_FILENO),68std(__SWR, STDOUT_FILENO),69std(__SWR|__SNBF, STDERR_FILENO)70};7172FILE *__stdinp = &__sF[0];73FILE *__stdoutp = &__sF[1];74FILE *__stderrp = &__sF[2];7576struct glue __sglue = { &uglue, 3, __sF };77static struct glue *lastglue = &uglue;7879static struct glue * moreglue(int);8081spinlock_t __stdio_thread_lock = _SPINLOCK_INITIALIZER;8283#if NOT_YET84#define SET_GLUE_PTR(ptr, val) atomic_set_rel_ptr(&(ptr), (uintptr_t)(val))85#else86#define SET_GLUE_PTR(ptr, val) ptr = val87#endif8889static struct glue *90moreglue(int n)91{92struct glue *g;93static FILE empty = { ._fl_mutex = PTHREAD_MUTEX_INITIALIZER };94FILE *p;95size_t align;9697align = __alignof__(FILE);98g = (struct glue *)malloc(sizeof(*g) + align + n * sizeof(FILE));99if (g == NULL)100return (NULL);101p = (FILE *)roundup((uintptr_t)(g + 1), align);102g->next = NULL;103g->niobs = n;104g->iobs = p;105while (--n >= 0)106*p++ = empty;107return (g);108}109110/*111* Find a free FILE for fopen et al.112*/113FILE *114__sfp(void)115{116FILE *fp;117int n;118struct glue *g;119120if (!__sdidinit)121__sinit();122/*123* The list must be locked because a FILE may be updated.124*/125STDIO_THREAD_LOCK();126for (g = &__sglue; g != NULL; g = g->next) {127for (fp = g->iobs, n = g->niobs; --n >= 0; fp++)128if (fp->_flags == 0)129goto found;130}131STDIO_THREAD_UNLOCK(); /* don't hold lock while malloc()ing. */132if ((g = moreglue(NDYNAMIC)) == NULL)133return (NULL);134STDIO_THREAD_LOCK(); /* reacquire the lock */135SET_GLUE_PTR(lastglue->next, g); /* atomically append glue to list */136lastglue = g; /* not atomic; only accessed when locked */137fp = g->iobs;138found:139fp->_flags = 1; /* reserve this slot; caller sets real flags */140STDIO_THREAD_UNLOCK();141fp->_p = NULL; /* no current pointer */142fp->_w = 0; /* nothing to read or write */143fp->_r = 0;144fp->_bf._base = NULL; /* no buffer */145fp->_bf._size = 0;146fp->_lbfsize = 0; /* not line buffered */147fp->_file = -1; /* no file */148/* fp->_cookie = <any>; */ /* caller sets cookie, _read/_write etc */149fp->_ub._base = NULL; /* no ungetc buffer */150fp->_ub._size = 0;151fp->_lb._base = NULL; /* no line buffer */152fp->_lb._size = 0;153/* fp->_fl_mutex = NULL; */ /* once set always set (reused) */154fp->_orientation = 0;155memset(&fp->_mbstate, 0, sizeof(mbstate_t));156fp->_flags2 = 0;157return (fp);158}159160/*161* XXX. Force immediate allocation of internal memory. Not used by stdio,162* but documented historically for certain applications. Bad applications.163*/164__warn_references(f_prealloc,165"warning: this program uses f_prealloc(), which is not recommended.");166void f_prealloc(void);167168void169f_prealloc(void)170{171struct glue *g;172int n;173174n = getdtablesize() - FOPEN_MAX + 20; /* 20 for slop. */175/*176* It should be safe to walk the list without locking it;177* new nodes are only added to the end and none are ever178* removed.179*/180for (g = &__sglue; (n -= g->niobs) > 0 && g->next; g = g->next)181/* void */;182if ((n > 0) && ((g = moreglue(n)) != NULL)) {183STDIO_THREAD_LOCK();184SET_GLUE_PTR(lastglue->next, g);185lastglue = g;186STDIO_THREAD_UNLOCK();187}188}189190/*191* exit() calls _cleanup() through *__cleanup, set whenever we192* open or buffer a file. This chicanery is done so that programs193* that do not use stdio need not link it all in.194*195* The name `_cleanup' is, alas, fairly well known outside stdio.196*/197void198_cleanup(void)199{200/* (void) _fwalk(fclose); */201(void) _fwalk(__sflush); /* `cheating' */202}203204/*205* __sinit() is called whenever stdio's internal variables must be set up.206*/207void208__sinit(void)209{210211/* Make sure we clean up on exit. */212__cleanup = _cleanup; /* conservative */213__sdidinit = 1;214}215216217