| Dmitriy Ivanov | 623b0d0 | 2014-05-14 23:11:05 -0700 | [diff] [blame] | 1 | /*	$OpenBSD: findfp.c,v 1.15 2013/12/17 16:33:27 deraadt Exp $ */ | 
| The Android Open Source Project | 1dc9e47 | 2009-03-03 19:28:35 -0800 | [diff] [blame] | 2 | /*- | 
|  | 3 | * Copyright (c) 1990, 1993 | 
|  | 4 | *	The Regents of the University of California.  All rights reserved. | 
|  | 5 | * | 
|  | 6 | * This code is derived from software contributed to Berkeley by | 
|  | 7 | * Chris Torek. | 
|  | 8 | * | 
|  | 9 | * Redistribution and use in source and binary forms, with or without | 
|  | 10 | * modification, are permitted provided that the following conditions | 
|  | 11 | * are met: | 
|  | 12 | * 1. Redistributions of source code must retain the above copyright | 
|  | 13 | *    notice, this list of conditions and the following disclaimer. | 
|  | 14 | * 2. Redistributions in binary form must reproduce the above copyright | 
|  | 15 | *    notice, this list of conditions and the following disclaimer in the | 
|  | 16 | *    documentation and/or other materials provided with the distribution. | 
|  | 17 | * 3. Neither the name of the University nor the names of its contributors | 
|  | 18 | *    may be used to endorse or promote products derived from this software | 
|  | 19 | *    without specific prior written permission. | 
|  | 20 | * | 
|  | 21 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND | 
|  | 22 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | 
|  | 23 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | 
|  | 24 | * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | 
|  | 25 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | 
|  | 26 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | 
|  | 27 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | 
|  | 28 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | 
|  | 29 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | 
|  | 30 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | 
|  | 31 | * SUCH DAMAGE. | 
|  | 32 | */ | 
|  | 33 |  | 
|  | 34 | #include <sys/param.h> | 
|  | 35 | #include <unistd.h> | 
|  | 36 | #include <stdio.h> | 
|  | 37 | #include <errno.h> | 
|  | 38 | #include <stdlib.h> | 
|  | 39 | #include <string.h> | 
|  | 40 | #include "local.h" | 
|  | 41 | #include "glue.h" | 
| Elliott Hughes | 6a03abc | 2014-11-03 12:32:17 -0800 | [diff] [blame] | 42 | #include "private/thread_private.h" | 
|  | 43 |  | 
|  | 44 | #define ALIGNBYTES (sizeof(uintptr_t) - 1) | 
|  | 45 | #define ALIGN(p) (((uintptr_t)(p) + ALIGNBYTES) &~ ALIGNBYTES) | 
| Calin Juravle | c20de90 | 2014-03-20 15:21:32 +0000 | [diff] [blame] | 46 |  | 
| The Android Open Source Project | 1dc9e47 | 2009-03-03 19:28:35 -0800 | [diff] [blame] | 47 | int	__sdidinit; | 
|  | 48 |  | 
|  | 49 | #define	NDYNAMIC 10		/* add ten more whenever necessary */ | 
|  | 50 |  | 
|  | 51 | #define	std(flags, file) \ | 
| Chih-Hung Hsieh | dc6599e | 2014-11-04 12:09:35 -0800 | [diff] [blame] | 52 | {0,0,0,flags,file,{0,0},0,__sF+file,__sclose,__sread,__sseek,__swrite, \ | 
|  | 53 | {(unsigned char *)(__sFext+file), 0},NULL,0,{0},{0},{0,0},0,0} | 
| The Android Open Source Project | 1dc9e47 | 2009-03-03 19:28:35 -0800 | [diff] [blame] | 54 |  | 
| Dmitriy Ivanov | 623b0d0 | 2014-05-14 23:11:05 -0700 | [diff] [blame] | 55 | /* the usual - (stdin + stdout + stderr) */ | 
| The Android Open Source Project | 1dc9e47 | 2009-03-03 19:28:35 -0800 | [diff] [blame] | 56 | static FILE usual[FOPEN_MAX - 3]; | 
|  | 57 | static struct __sfileext usualext[FOPEN_MAX - 3]; | 
|  | 58 | static struct glue uglue = { 0, FOPEN_MAX - 3, usual }; | 
| Kenny Root | f582340 | 2011-02-12 07:13:44 -0800 | [diff] [blame] | 59 | static struct glue *lastglue = &uglue; | 
|  | 60 | _THREAD_PRIVATE_MUTEX(__sfp_mutex); | 
| The Android Open Source Project | 1dc9e47 | 2009-03-03 19:28:35 -0800 | [diff] [blame] | 61 |  | 
| Elliott Hughes | 168667c | 2014-11-14 14:42:59 -0800 | [diff] [blame] | 62 | static struct __sfileext __sFext[3]; | 
| The Android Open Source Project | 1dc9e47 | 2009-03-03 19:28:35 -0800 | [diff] [blame] | 63 | FILE __sF[3] = { | 
|  | 64 | std(__SRD, STDIN_FILENO),		/* stdin */ | 
|  | 65 | std(__SWR, STDOUT_FILENO),		/* stdout */ | 
|  | 66 | std(__SWR|__SNBF, STDERR_FILENO)	/* stderr */ | 
|  | 67 | }; | 
| Elliott Hughes | 168667c | 2014-11-14 14:42:59 -0800 | [diff] [blame] | 68 | FILE* stdin = &__sF[0]; | 
|  | 69 | FILE* stdout = &__sF[1]; | 
|  | 70 | FILE* stderr = &__sF[2]; | 
| The Android Open Source Project | 1dc9e47 | 2009-03-03 19:28:35 -0800 | [diff] [blame] | 71 | struct glue __sglue = { &uglue, 3, __sF }; | 
|  | 72 |  | 
|  | 73 | static struct glue * | 
|  | 74 | moreglue(int n) | 
|  | 75 | { | 
|  | 76 | struct glue *g; | 
|  | 77 | FILE *p; | 
|  | 78 | struct __sfileext *pext; | 
|  | 79 | static FILE empty; | 
|  | 80 | char *data; | 
|  | 81 |  | 
|  | 82 | data = malloc(sizeof(*g) + ALIGNBYTES + n * sizeof(FILE) | 
|  | 83 | + n * sizeof(struct __sfileext)); | 
|  | 84 | if (data == NULL) | 
|  | 85 | return (NULL); | 
|  | 86 | g = (struct glue *)data; | 
|  | 87 | p = (FILE *)ALIGN(data + sizeof(*g)); | 
|  | 88 | pext = (struct __sfileext *) | 
|  | 89 | (ALIGN(data + sizeof(*g)) + n * sizeof(FILE)); | 
|  | 90 | g->next = NULL; | 
|  | 91 | g->niobs = n; | 
|  | 92 | g->iobs = p; | 
|  | 93 | while (--n >= 0) { | 
|  | 94 | *p = empty; | 
|  | 95 | _FILEEXT_SETUP(p, pext); | 
|  | 96 | p++; | 
|  | 97 | pext++; | 
|  | 98 | } | 
|  | 99 | return (g); | 
|  | 100 | } | 
|  | 101 |  | 
|  | 102 | /* | 
|  | 103 | * Find a free FILE for fopen et al. | 
|  | 104 | */ | 
|  | 105 | FILE * | 
|  | 106 | __sfp(void) | 
|  | 107 | { | 
|  | 108 | FILE *fp; | 
|  | 109 | int n; | 
|  | 110 | struct glue *g; | 
|  | 111 |  | 
|  | 112 | if (!__sdidinit) | 
|  | 113 | __sinit(); | 
| Kenny Root | f582340 | 2011-02-12 07:13:44 -0800 | [diff] [blame] | 114 |  | 
|  | 115 | _THREAD_PRIVATE_MUTEX_LOCK(__sfp_mutex); | 
|  | 116 | for (g = &__sglue; g != NULL; g = g->next) { | 
| The Android Open Source Project | 1dc9e47 | 2009-03-03 19:28:35 -0800 | [diff] [blame] | 117 | for (fp = g->iobs, n = g->niobs; --n >= 0; fp++) | 
|  | 118 | if (fp->_flags == 0) | 
|  | 119 | goto found; | 
| The Android Open Source Project | 1dc9e47 | 2009-03-03 19:28:35 -0800 | [diff] [blame] | 120 | } | 
| Kenny Root | f582340 | 2011-02-12 07:13:44 -0800 | [diff] [blame] | 121 |  | 
|  | 122 | /* release lock while mallocing */ | 
|  | 123 | _THREAD_PRIVATE_MUTEX_UNLOCK(__sfp_mutex); | 
|  | 124 | if ((g = moreglue(NDYNAMIC)) == NULL) | 
|  | 125 | return (NULL); | 
|  | 126 | _THREAD_PRIVATE_MUTEX_LOCK(__sfp_mutex); | 
|  | 127 | lastglue->next = g; | 
|  | 128 | lastglue = g; | 
|  | 129 | fp = g->iobs; | 
| The Android Open Source Project | 1dc9e47 | 2009-03-03 19:28:35 -0800 | [diff] [blame] | 130 | found: | 
|  | 131 | fp->_flags = 1;		/* reserve this slot; caller sets real flags */ | 
| Kenny Root | f582340 | 2011-02-12 07:13:44 -0800 | [diff] [blame] | 132 | _THREAD_PRIVATE_MUTEX_UNLOCK(__sfp_mutex); | 
| The Android Open Source Project | 1dc9e47 | 2009-03-03 19:28:35 -0800 | [diff] [blame] | 133 | fp->_p = NULL;		/* no current pointer */ | 
|  | 134 | fp->_w = 0;		/* nothing to read or write */ | 
|  | 135 | fp->_r = 0; | 
|  | 136 | fp->_bf._base = NULL;	/* no buffer */ | 
|  | 137 | fp->_bf._size = 0; | 
|  | 138 | fp->_lbfsize = 0;	/* not line buffered */ | 
|  | 139 | fp->_file = -1;		/* no file */ | 
|  | 140 | /*	fp->_cookie = <any>; */	/* caller sets cookie, _read/_write etc */ | 
|  | 141 | fp->_lb._base = NULL;	/* no line buffer */ | 
|  | 142 | fp->_lb._size = 0; | 
|  | 143 | _FILEEXT_INIT(fp); | 
|  | 144 | return (fp); | 
|  | 145 | } | 
|  | 146 |  | 
| The Android Open Source Project | 1dc9e47 | 2009-03-03 19:28:35 -0800 | [diff] [blame] | 147 | /* | 
| Dmitriy Ivanov | 623b0d0 | 2014-05-14 23:11:05 -0700 | [diff] [blame] | 148 | * exit() and abort() call _cleanup() through the callback registered | 
|  | 149 | * with __atexit_register_cleanup(), set whenever we open or buffer a | 
|  | 150 | * file. This chicanery is done so that programs that do not use stdio | 
|  | 151 | * need not link it all in. | 
| The Android Open Source Project | 1dc9e47 | 2009-03-03 19:28:35 -0800 | [diff] [blame] | 152 | * | 
|  | 153 | * The name `_cleanup' is, alas, fairly well known outside stdio. | 
|  | 154 | */ | 
|  | 155 | void | 
|  | 156 | _cleanup(void) | 
|  | 157 | { | 
|  | 158 | /* (void) _fwalk(fclose); */ | 
|  | 159 | (void) _fwalk(__sflush);		/* `cheating' */ | 
|  | 160 | } | 
|  | 161 |  | 
|  | 162 | /* | 
|  | 163 | * __sinit() is called whenever stdio's internal variables must be set up. | 
|  | 164 | */ | 
|  | 165 | void | 
|  | 166 | __sinit(void) | 
|  | 167 | { | 
| Kenny Root | f582340 | 2011-02-12 07:13:44 -0800 | [diff] [blame] | 168 | _THREAD_PRIVATE_MUTEX(__sinit_mutex); | 
| The Android Open Source Project | 1dc9e47 | 2009-03-03 19:28:35 -0800 | [diff] [blame] | 169 |  | 
| Kenny Root | f582340 | 2011-02-12 07:13:44 -0800 | [diff] [blame] | 170 | _THREAD_PRIVATE_MUTEX_LOCK(__sinit_mutex); | 
| Elliott Hughes | 6a03abc | 2014-11-03 12:32:17 -0800 | [diff] [blame] | 171 | if (__sdidinit) { | 
|  | 172 | /* bail out if caller lost the race */ | 
|  | 173 | _THREAD_PRIVATE_MUTEX_UNLOCK(__sinit_mutex); | 
|  | 174 | return; | 
|  | 175 | } | 
|  | 176 |  | 
|  | 177 | /* Initialize stdin/stdout/stderr (for the recursive mutex). http://b/18208568. */ | 
|  | 178 | for (size_t i = 0; i < 3; ++i) { | 
|  | 179 | _FILEEXT_SETUP(__sF+i, __sFext+i); | 
|  | 180 | } | 
|  | 181 | /* Initialize the pre-allocated (but initially unused) streams. */ | 
|  | 182 | for (size_t i = 0; i < FOPEN_MAX - 3; ++i) { | 
| The Android Open Source Project | 1dc9e47 | 2009-03-03 19:28:35 -0800 | [diff] [blame] | 183 | _FILEEXT_SETUP(usual+i, usualext+i); | 
|  | 184 | } | 
| Elliott Hughes | 6a03abc | 2014-11-03 12:32:17 -0800 | [diff] [blame] | 185 |  | 
| The Android Open Source Project | 1dc9e47 | 2009-03-03 19:28:35 -0800 | [diff] [blame] | 186 | /* make sure we clean up on exit */ | 
| Dmitriy Ivanov | 623b0d0 | 2014-05-14 23:11:05 -0700 | [diff] [blame] | 187 | __atexit_register_cleanup(_cleanup); /* conservative */ | 
| The Android Open Source Project | 1dc9e47 | 2009-03-03 19:28:35 -0800 | [diff] [blame] | 188 | __sdidinit = 1; | 
| Elliott Hughes | 6a03abc | 2014-11-03 12:32:17 -0800 | [diff] [blame] | 189 |  | 
| Kenny Root | f582340 | 2011-02-12 07:13:44 -0800 | [diff] [blame] | 190 | _THREAD_PRIVATE_MUTEX_UNLOCK(__sinit_mutex); | 
| The Android Open Source Project | 1dc9e47 | 2009-03-03 19:28:35 -0800 | [diff] [blame] | 191 | } |