├── .gitignore ├── .mailmap ├── COPYRIGHT ├── Makefile ├── README ├── config.mak.dist ├── configure ├── dist └── src │ ├── nsswitch.tab.c │ └── nsswitch.yy.c ├── include ├── cache_add.h ├── cache_query.h ├── hash.h ├── list.h ├── modules.h ├── nscd.h ├── nss.h ├── parse.h ├── parse_common.h └── util.h ├── musl-nscd.8 ├── port ├── gr_passwd.c ├── pw_gecos.c └── pw_passwd.c ├── src ├── asprintf.c ├── cache.c ├── die.c ├── full_read.c ├── full_write.c ├── hash.c ├── list.c ├── main.c ├── nsswitch.l ├── nsswitch.y ├── program_invocation_name.c ├── socket_handle.c ├── swap32.c └── write_val.c └── tools ├── gen_config.sh └── install.sh /.gitignore: -------------------------------------------------------------------------------- 1 | /obj/ 2 | config.mak 3 | -------------------------------------------------------------------------------- /.mailmap: -------------------------------------------------------------------------------- 1 | Ada Worcester 2 | -------------------------------------------------------------------------------- /COPYRIGHT: -------------------------------------------------------------------------------- 1 | musl-nscd as a whole is licensed under the following standard MIT license: 2 | 3 | ---------------------------------------------------------------------- 4 | Copyright © 2016-2021 Contauro Ltd. 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining 7 | a copy of this software and associated documentation files (the 8 | "Software"), to deal in the Software without restriction, including 9 | without limitation the rights to use, copy, modify, merge, publish, 10 | distribute, sublicense, and/or sell copies of the Software, and to 11 | permit persons to whom the Software is furnished to do so, subject to 12 | the following conditions: 13 | 14 | The above copyright notice and this permission notice shall be 15 | included in all copies or substantial portions of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 18 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 19 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 20 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 21 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 22 | TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 23 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 24 | ---------------------------------------------------------------------- 25 | 26 | The intrusive data structures library in src/list.c and include/list.h 27 | is licensed under the following terms: 28 | 29 | ---------------------------------------------------------------------- 30 | 31 | This is free and unencumbered software released into the public domain. 32 | 33 | Anyone is free to copy, modify, publish, use, compile, sell, or 34 | distribute this software, either in source code form or as a compiled 35 | binary, for any purpose, commercial or non-commercial, and by any 36 | means. 37 | 38 | In jurisdictions that recognize copyright laws, the author or authors 39 | of this software dedicate any and all copyright interest in the 40 | software to the public domain. We make this dedication for the benefit 41 | of the public at large and to the detriment of our heirs and 42 | successors. We intend this dedication to be an overt act of 43 | relinquishment in perpetuity of all present and future rights to this 44 | software under copyright law. 45 | 46 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 47 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 48 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 49 | IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR 50 | OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 51 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 52 | OTHER DEALINGS IN THE SOFTWARE. 53 | 54 | For more information, please refer to 55 | 56 | ---------------------------------------------------------------------- 57 | 58 | The configure script and Makefile are based heavily on that of musl 59 | libc, which is licensed under the following standard MIT license: 60 | 61 | ---------------------------------------------------------------------- 62 | Copyright © 2005-2014 Rich Felker, et al. 63 | 64 | Permission is hereby granted, free of charge, to any person obtaining 65 | a copy of this software and associated documentation files (the 66 | "Software"), to deal in the Software without restriction, including 67 | without limitation the rights to use, copy, modify, merge, publish, 68 | distribute, sublicense, and/or sell copies of the Software, and to 69 | permit persons to whom the Software is furnished to do so, subject to 70 | the following conditions: 71 | 72 | The above copyright notice and this permission notice shall be 73 | included in all copies or substantial portions of the Software. 74 | 75 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 76 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 77 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 78 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 79 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 80 | TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 81 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 82 | ---------------------------------------------------------------------- 83 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | srcdir = . 2 | exec_prefix = /usr/local 3 | bindir = $(exec_prefix)/bin 4 | sbindir = $(exec_prefix)/sbin 5 | prefix = /usr/local 6 | includedir = $(prefix)/include 7 | libdir = $(prefix)/lib 8 | mandir = $(prefix)/share/man 9 | 10 | SRC_DIRS = $(addprefix $(srcdir)/,src port) 11 | GEN_SRCS = $(sort $(patsubst $(srcdir)/%.y,obj/%.tab.c,$(wildcard $(addsuffix /*.y,$(SRC_DIRS)))) \ 12 | $(patsubst $(srcdir)/%.l,obj/%.yy.c,$(wildcard $(addsuffix /*.l,$(SRC_DIRS))))) 13 | SRCS = $(sort $(wildcard $(addsuffix /*.c,$(SRC_DIRS)))) 14 | OBJS = $(sort $(patsubst %,%.o,$(basename $(GEN_SRCS))) \ 15 | $(addprefix obj/,$(patsubst $(srcdir)/%,%.o,$(basename $(SRCS))))) 16 | PORTS = $(sort $(wildcard $(srcdir)/port/*.c)) 17 | TESTS = $(addprefix obj/test/,$(sort $(patsubst $(srcdir)/%,%,$(basename $(PORTS))))) 18 | HEADERS = $(sort $(wildcard $(srcdir)/include/*)) 19 | TOOLS = obj/nscd 20 | 21 | GENH = obj/include/config.h 22 | 23 | LDFLAGS = 24 | CPPFLAGS = 25 | CFLAGS = -Os -pipe 26 | CFLAGS_C99 = -std=c99 27 | 28 | CFLAGS_ALL = $(CFLAGS_C99) 29 | CFLAGS_ALL += -D_XOPEN_SOURCE=700 -I$(srcdir)/include -Iobj/include 30 | CFLAGS_ALL += $(CPPFLAGS) $(CFLAGS_AUTO) $(CFLAGS) 31 | 32 | LDFLAGS_ALL = $(LDFLAGS_AUTO) $(LDFLAGS) 33 | LDLIBS += $(LDLIBS_AUTO) 34 | 35 | INSTALL = $(srcdir)/tools/install.sh 36 | 37 | -include config.mak 38 | 39 | all: $(TOOLS) 40 | 41 | OBJ_DIRS = $(sort $(patsubst %/,%,$(dir $(BINS) $(OBJS) $(TESTS) $(GENH))) obj/src obj/include) 42 | 43 | $(TESTS) $(BINS) $(OBJS) $(GENH): | $(OBJ_DIRS) 44 | 45 | $(OBJ_DIRS): 46 | mkdir -p $@ 47 | 48 | obj/include/config.h: $(srcdir)/tools/gen_config.sh $(TESTS) 49 | $(srcdir)/tools/gen_config.sh $(srcdir) >$@ 50 | 51 | $(OBJS): $(HEADERS) 52 | 53 | obj/%.o: obj/%.c $(GENH) 54 | $(CC) $(CFLAGS_ALL) -c -o $@ $< 55 | 56 | obj/%.o: $(srcdir)/%.c $(GENH) 57 | $(CC) $(CFLAGS_ALL) -c -o $@ $< 58 | 59 | ifdef MODIFY_SRC 60 | $(srcdir)/dist/%.yy.c: $(srcdir)/%.l 61 | $(LEX) -t $< >$@ 62 | 63 | $(srcdir)/dist/%.tab.c: $(srcdir)/%.y 64 | $(YACC) -b $* $< 65 | 66 | $(srcdir)/dist/src: 67 | mkdir -p $@ 68 | 69 | genfiles: $(srcdir)/dist/src 70 | genfiles: $(patsubst $(srcdir)/%.l,$(srcdir)/dist/%.yy.c,$(wildcard $(add_suffix /*.l,$(SRC_DIRS)))) 71 | genfiles: $(patsubst $(srcdir)/%.y,$(srcdir)/dist/%.tab.c,$(wildcard $(add_suffix /*.y,$(SRC_DIRS)))) 72 | endif 73 | 74 | ifdef LEX 75 | obj/%.yy.c: $(srcdir)/%.l 76 | $(LEX) -t $< >$@ 77 | else 78 | obj/%.yy.c: $(srcdir)/dist/%.yy.c 79 | cp $< $@ 80 | endif 81 | 82 | ifdef YACC 83 | obj/%.tab.c: $(srcdir)/%.y 84 | $(YACC) -b obj/$* $< 85 | else 86 | obj/%.tab.c: $(srcdir)/dist/%.tab.c 87 | cp $< $@ 88 | endif 89 | 90 | obj/nscd: $(OBJS) 91 | $(CC) $(CFLAGS_ALL) $(LDFLAGS_ALL) $^ $(LDLIBS) -o $@ 92 | 93 | obj/test/%: $(srcdir)/%.c 94 | $(CC) $(CFLAGS_ALL) -DTEST $(LDFLAGS_ALL) $< $(LDLIBS) -o $@ >/dev/null 2>&1 || cat $@ 95 | 96 | $(DESTDIR)$(bindir)/%: obj/% 97 | $(INSTALL) -D $< $@ 98 | 99 | $(DESTDIR)$(sbindir)/%: obj/% 100 | $(INSTALL) -D $< $@ 101 | 102 | $(DESTDIR)$(includedir)/%: $(srcdir)/include/% 103 | $(INSTALL) -D -m 644 $< $@ 104 | 105 | $(DESTDIR)$(mandir)/man8/%: % 106 | $(INSTALL) -D -m 644 $< $@ 107 | 108 | install-headers: $(DESTDIR)$(includedir)/nss.h 109 | 110 | install-manpage: $(DESTDIR)$(mandir)/man8/musl-nscd.8 111 | 112 | install-tools: $(TOOLS:obj/%=$(DESTDIR)$(sbindir)/%) 113 | 114 | install: install-tools install-headers install-manpage 115 | 116 | clean: 117 | rm -rf obj 118 | 119 | distclean: clean 120 | rm -f config.mak 121 | 122 | .PHONY: all install-tools install clean dist-clean genfiles 123 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | musl-nscd is an implementation of the NSCD protocol. It makes use of NSS 2 | modules, just like with glibc. This permits alternative backends for the user 3 | and group databases for musl libc. The protocol it uses is a subset of that 4 | used by glibc. This project was created with the help of Contauro Ltd. 5 | 6 | Configuration of which modules to use should be given in /etc/nsswitch.conf. 7 | The syntax of the file matches glibc's. 8 | 9 | To build and install: 10 | ./configure 11 | make 12 | -------------------------------------------------------------------------------- /config.mak.dist: -------------------------------------------------------------------------------- 1 | srcdir = . 2 | prefix = /usr/local 3 | exec_prefix = $(prefix) 4 | sbindir = $(exec_prefix)/sbin 5 | bindir = $(exec_prefix)/bin 6 | libdir = $(prefix)/lib 7 | includedir = $(prefix)/include 8 | syslibdir = /lib 9 | CROSS_COMPILE = 10 | CC = $(CROSS_COMPILE)gcc 11 | YACC = yacc 12 | LEX = lex 13 | CFLAGS = -O2 -pipe 14 | CFLAGS_C99 = -std=c99 15 | CPPFLAGS = 16 | LDFLAGS = -s 17 | LDLIBS = -ll -ly -ldl -lpthread 18 | -------------------------------------------------------------------------------- /configure: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | usage () { 4 | cat </dev/null 2>&1 && { echo "$1" ; return 0 ; } 50 | $1 51 | EOF 52 | printf %s\\n "$1" | sed -e "s/'/'\\\\''/g" -e "1s/^/'/" -e "\$s/\$/'/" -e "s#^'\([-[:alnum:]_,./:]*\)=\(.*\)\$#\1='\2#" 53 | } 54 | echo () { printf "%s\n" "$*" ; } 55 | fail () { echo "$*" ; exit 1 ; } 56 | fnmatch () { eval "case \"\$2\" in $1) return 0 ;; *) return 1 ;; esac" ; } 57 | cmdexists () { type "$1" >/dev/null 2>&1 ; } 58 | trycc () { test -z "$CC" && cmdexists "$1" && CC=$1 ; } 59 | tryyacc () { test -z "$YACC" && cmdexists "$1" && YACC=$1 ; } 60 | trylex () { test -z "$LEX" && cmdexists "$1" && LEX=$1 ; } 61 | 62 | stripdir () { 63 | while eval "fnmatch '*/' \"\${$1}\"" ; do eval "$1=\${$1%/}" ; done 64 | } 65 | 66 | trycppif () { 67 | printf "checking preprocessor condition %s... " "$1" 68 | echo "typedef int x;" > "$tmpc" 69 | echo "#if $1" >> "$tmpc" 70 | echo "#error yes" >> "$tmpc" 71 | echo "#endif" >> "$tmpc" 72 | if $CC $2 -c -o /dev/null "$tmpc" >/dev/null 2>&1 ; then 73 | printf "false\n" 74 | return 1 75 | else 76 | printf "true\n" 77 | return 0 78 | fi 79 | } 80 | 81 | tryflag () { 82 | printf "checking whether compiler accepts %s... " "$2" 83 | echo "typedef int x;" > "$tmpc" 84 | if $CC $CFLAGS_TRY $2 -c -o /dev/null "$tmpc" >/dev/null 2>&1 ; then 85 | printf "yes\n" 86 | eval "$1=\"\${$1} \$2\"" 87 | eval "$1=\${$1# }" 88 | return 0 89 | else 90 | printf "no\n" 91 | return 1 92 | fi 93 | } 94 | 95 | tryldlib () { 96 | printf "checking whether library %s exists..." "$2" 97 | echo "$3" >"$tmpc" 98 | echo "int main(){" "$4" ";}" > "$tmpc" 99 | if $CC $CFLAGS_TRY $LDFLAGS_TRY -o /dev/null "$tmpc" "$2" >/dev/null 2>&1 ; then 100 | printf "yes\n" 101 | eval "$1=\"\${$1} \$2\"" 102 | eval "$1=\${$1# }" 103 | return 0 104 | else 105 | printf "no\n" 106 | return 1 107 | fi 108 | } 109 | 110 | tryldflag () { 111 | printf "checking whether linker accepts %s... " "$2" 112 | echo "int main(){return 0;}" > "$tmpc" 113 | if $CC $LDFLAGS_TRY "$2" -o /dev/null "$tmpc" >/dev/null 2>&1 ; then 114 | printf "yes\n" 115 | eval "$1=\"\${$1} \$2\"" 116 | eval "$1=\${$1# }" 117 | return 0 118 | else 119 | printf "no\n" 120 | return 1 121 | fi 122 | } 123 | 124 | 125 | 126 | # Beginning of actual script 127 | 128 | CFLAGS_C99= 129 | CFLAGS_AUTO= 130 | CFLAGS_TRY= 131 | LDFLAGS_AUTO= 132 | LDFLAGS_TRY= 133 | LDLIBS_AUTO= 134 | srcdir= 135 | prefix=/usr/local/ 136 | exec_prefix='$(prefix)' 137 | sbindir='$(exec_prefix)/sbin' 138 | bindir='$(exec_prefix)/bin' 139 | libdir='$(exec_prefix)/lib' 140 | includedir='$(prefix)/include' 141 | syslibdir='/lib' 142 | target= 143 | optimize=auto 144 | debug=no 145 | warnings=no 146 | 147 | for arg ; do 148 | case "$arg" in 149 | --help|-h) usage ;; 150 | --srcdir=*) srcdir=${arg#*=} ;; 151 | --prefix=*) prefix=${arg#*=} ;; 152 | --exec-prefix=*) exec_prefix=${arg#*=} ;; 153 | --bindir=*) bindir=${arg#*=} ;; 154 | --sbindir=*) sbindir=${arg#*=} ;; 155 | --libdir=*) libdir=${arg#*=} ;; 156 | --includedir=*) includedir=${arg#*=} ;; 157 | --syslibdir=*) syslibdir=${arg#*=} ;; 158 | --enable-optimize|--enable-optimize=yes) optimize=yes ;; 159 | --disable-optimize|--enable-optimize=no) optimize=no ;; 160 | --enable-debug|--enable-debug=yes) debug=yes ;; 161 | --disable-debug|--enable-debug=no) debug=no ;; 162 | --enable-warnings|--enable-warnings=yes) warnings=yes ;; 163 | --disable-warnings|--enable-warnings=no) warnings=no ;; 164 | --enable-visibility|--enable-visibility=yes) visibility=yes ;; 165 | --disable-visibility|--enable-visibility=no) visibility=no ;; 166 | --enable-*|--disable-*|--with-*|--without-*|--*dir=*|--build=*) ;; 167 | --host=*|--target=*) target=${arg#*=} ;; 168 | -* ) echo "$0: unknown option $arg" ;; 169 | CC=*) CC=${arg#*=} ;; 170 | CFLAGS=*) CFLAGS=${arg#*=} ;; 171 | CPPFLAGS=*) CPPFLAGS=${arg#*=} ;; 172 | LDFLAGS=*) LDFLAGS=${arg#*=} ;; 173 | CROSS_COMPILE=*) CROSS_COMPILE=${arg#*=} ;; 174 | *=*) ;; 175 | *) target=$arg ;; 176 | esac 177 | done 178 | 179 | for i in srcdir prefix exec_prefix bindir libdir includedir syslibdir ; do 180 | stripdir $i 181 | done 182 | 183 | # 184 | # Get the source dir for out-of-tree builds 185 | # 186 | if test -z "$srcdir" ; then 187 | srcdir="${0%/configure}" 188 | stripdir srcdir 189 | fi 190 | abs_builddir="$(pwd)" || fail "$0: cannot determine working directory" 191 | abs_srcdir="$(cd $srcdir && pwd)" || fail "$0: invalid source directory $srcdir" 192 | test "$abs_srcdir" = "$abs_builddir" && srcdir=. 193 | test "$srcdir" != "." && test -f Makefile && test ! -h Makefile && fail "$0: Makefile already exists in the working directory" 194 | 195 | # 196 | # Get a temp filename we can use 197 | # 198 | i=0 199 | set -C 200 | while : ; do i=$(($i+1)) 201 | tmpc="./conf$$-$PPID-$i.c" 202 | 2>|/dev/null > "$tmpc" && break 203 | test "$i" -gt 50 && fail "$0: cannot create temporary file $tmpc" 204 | done 205 | set +C 206 | trap 'rm "$tmpc"' EXIT INT QUIT TERM HUP 207 | 208 | # 209 | # Set CROSS_COMPILE from target if needed 210 | # 211 | if test -z "$CROSS_COMPILE" && test -n "$target";then 212 | CROSS_COMPILE=$target- 213 | fi 214 | 215 | # 216 | # Find a C compiler to use 217 | # 218 | printf "checking for C compiler... " 219 | trycc ${CROSS_COMPILE}gcc 220 | trycc ${CROSS_COMPILE}c99 221 | trycc ${CROSS_COMPILE}cc 222 | printf "%s\n" "$CC" 223 | test -n "$CC" || { echo "$0: cannot find a C compiler" ; exit 1 ; } 224 | 225 | printf "checking whether C compiler works... " 226 | echo "typedef int x;" > "$tmpc" 227 | if output=$($CC $CPPFLAGS $CFLAGS -c -o /dev/null "$tmpc" 2>&1) ; then 228 | printf "yes\n" 229 | else 230 | printf "no; compiler output follows:\n%s\n" "$output" 231 | exit 1 232 | fi 233 | 234 | # 235 | # Find a yacc to use 236 | # 237 | printf "checking for yacc... " 238 | tryyacc ${CROSS_COMPILE}yacc 239 | tryyacc yacc 240 | tryyacc ${CROSS_COMPILE}bison 241 | tryyacc bison 242 | printf "%s\n" "$YACC" 243 | test -n "$YACC" || echo "$0: cannot find yacc. Will try to use pre-provided source." 244 | 245 | # 246 | # Find a lex to use 247 | # 248 | printf "checking for lex... " 249 | trylex ${CROSS_COMPILE}lex 250 | trylex lex 251 | trylex ${CROSS_COMPILE}flex 252 | trylex flex 253 | printf "%s\n" "$LEX" 254 | test -n "$LEX" || echo "$0: cannot find lex. Will try to use pre-provided source." 255 | 256 | 257 | # 258 | # Figure out options to force errors on unknown flags. 259 | # 260 | tryflag CFLAGS_TRY -Werror=unknown-warning-option 261 | tryflag CFLAGS_TRY -Werror=unused-command-line-argument 262 | tryldflag LDFLAGS_TRY -Werror=unknown-warning-option 263 | tryldflag LDFLAGS_TRY -Werror=unused-command-line-argument 264 | 265 | # 266 | # Try libs necessary for features we use 267 | # 268 | tryldlib LDLIBS_AUTO -lpthread "#include " "pthread_create(0, 0, (void*(*)(void*))0, 0);" 269 | tryldlib LDLIBS_AUTO -ll "" "" 270 | tryldlib LDLIBS_AUTO -ly "" "" 271 | tryldlib LDLIBS_AUTO -lxnet "#include " "listen(0, 0);" 272 | tryldlib LDLIBS_AUTO -ldl "#include " "dlclose(0);" 273 | 274 | # 275 | # Try to get a conforming C99 environment 276 | # 277 | tryflag CFLAGS_C99 -std=c99 278 | 279 | # 280 | # Enable debugging if requessted. 281 | # 282 | test "$debug" = yes && CFLAGS_AUTO=-g 283 | test "$debug" = no && LDFLAGS_AUTO=-s 284 | 285 | # 286 | # Add a -O option to CFLAGS based on --enable-optimize and provided CFLAGS. 287 | # 288 | printf "checking for optimization settings... " 289 | case "x$optimize" in 290 | xauto) 291 | if fnmatch '-O*|*\ -O*' "$CFLAGS_AUTO $CFLAGS" ; then 292 | printf "using provided CFLAGS\n" ;optimize=no 293 | else 294 | printf "using defaults\n" ; optimize=yes 295 | fi 296 | ;; 297 | xsize|xnone) printf "minimize size\n" ; optimize=size ;; 298 | xno|x) printf "disabled\n" ; optimize=no ;; 299 | *) printf "custom\n" ;; 300 | esac 301 | 302 | case "x$optimize" in 303 | xyes) tryflag CFLAGS_AUTO -O2 || tryflag CFLAGS_AUTO -O ;; 304 | xsize) tryflag CFLAGS_AUTO -Os || tryflag CFLAGS_AUTO -O ;; 305 | esac 306 | 307 | # Always try -pipe 308 | tryflag CFLAGS_AUTO -pipe 309 | 310 | # 311 | # If debugging is disabled, omit frame pointer. Modern GCC does this 312 | # anyway on most archs even when debugging is enabled since the frame 313 | # pointer is no longer needed for debugging. 314 | # 315 | if fnmatch '-g*|*\ -g*' "$CFLAGS_AUTO $CFLAGS" ; then : 316 | else 317 | tryflag CFLAGS_AUTO -fomit-frame-pointer 318 | fi 319 | 320 | # 321 | # Attempt to put each function and each data object in its own 322 | # section. This both allows additional size optimizations at link 323 | # time and works around a dangerous class of compiler/assembler bugs 324 | # whereby relative address expressions are constant-folded by the 325 | # assembler even when one or more of the symbols involved is 326 | # replaceable. See gas pr 18561 and gcc pr 66609, 68178, etc. 327 | # 328 | tryflag CFLAGS_AUTO -ffunction-sections 329 | tryflag CFLAGS_AUTO -fdata-sections 330 | 331 | # 332 | # On x86, make sure we don't have incompatible instruction set 333 | # extensions enabled by default. This is bad for making static binaries. 334 | # We cheat and use i486 rather than i386 because i386 really does not 335 | # work anyway (issues with atomic ops). 336 | # Some build environments pass -march and -mtune options via CC, so 337 | # check both CC and CFLAGS. 338 | # 339 | if test "$ARCH" = "i386" ; then 340 | fnmatch '-march=*|*\ -march=*' "$CC $CFLAGS" || tryldflag CFLAGS_AUTO -march=i486 341 | fnmatch '-mtune=*|*\ -mtune=*' "$CC $CFLAGS" || tryldflag CFLAGS_AUTO -mtune=generic 342 | fi 343 | 344 | # 345 | # Even with -std=c99, gcc accepts some constructs which are constraint 346 | # violations. We want to treat these as errors regardless of whether 347 | # other purely stylistic warnings are enabled -- especially implicit 348 | # function declarations, which are a dangerous programming error. 349 | # 350 | tryflag CFLAGS_AUTO -Werror=implicit-function-declaration 351 | tryflag CFLAGS_AUTO -Werror=implicit-int 352 | tryflag CFLAGS_AUTO -Werror=pointer-sign 353 | tryflag CFLAGS_AUTO -Werror=pointer-arith 354 | 355 | if test "x$warnings" = xyes ; then 356 | tryflag CFLAGS_AUTO -Wall 357 | tryflag CFLAGS_AUTO -Wextra 358 | tryflag CFLAGS_AUTO -Wno-unused-parameter 359 | fi 360 | 361 | # Omit empty sections from unreferenced functions or data 362 | tryldflag LDFLAGS_AUTO -Wl,--gc-sections 363 | 364 | # 365 | # Some build systems globally pass in broken CFLAGS like -ffast-math 366 | # for all packages. On recent GCC we can detect this and error out 367 | # early rather than producing a seriously-broken math library. 368 | # 369 | if trycppif "__FAST_MATH__" \ 370 | "$CFLAGS_C99FSE $CPPFLAGS $CFLAGS" ; then 371 | fail "$0: error: compiler has broken floating point; check CFLAGS" 372 | fi 373 | 374 | printf "creating config.mak... " 375 | 376 | cmdline=$(quote "$0") 377 | for i ; do cmdline="$cmdline $(quote "$i")" ; done 378 | 379 | exec 3>&1 1>config.mak 380 | 381 | 382 | cat << EOF 383 | # This version of config.mak was generated by: 384 | # $cmdline 385 | # Any changes made here will be lost if configure is re-run 386 | srcdir = $srcdir 387 | prefix = $prefix 388 | exec_prefix = $exec_prefix 389 | sbindir = $sbindir 390 | bindir = $bindir 391 | libdir = $libdir 392 | includedir = $includedir 393 | syslibdir = $syslibdir 394 | CC = $CC 395 | YACC = $YACC 396 | LEX = $LEX 397 | CFLAGS = $CFLAGS 398 | CFLAGS_AUTO = $CFLAGS_AUTO 399 | CFLAGS_C99 = $CFLAGS_C99 400 | CPPFLAGS = $CPPFLAGS 401 | LDFLAGS = $LDFLAGS 402 | LDFLAGS_AUTO = $LDFLAGS_AUTO 403 | LDLIBS_AUTO = $LDLIBS_AUTO 404 | CROSS_COMPILE = $CROSS_COMPILE 405 | LIBCC = $LIBCC 406 | OPTIMIZE_GLOBS = $OPTIMIZE_GLOBS 407 | ALL_TOOLS = $tools 408 | TOOL_LIBS = $tool_libs 409 | ADD_CFI = $ADD_CFI 410 | EOF 411 | exec 1>&3 3>&- 412 | 413 | test "$srcdir" = "." || ln -sf $srcdir/Makefile . 414 | 415 | printf "done\n" 416 | -------------------------------------------------------------------------------- /dist/src/nsswitch.tab.c: -------------------------------------------------------------------------------- 1 | /* A Bison parser, made by GNU Bison 3.0.4. */ 2 | 3 | /* Bison implementation for Yacc-like parsers in C 4 | 5 | Copyright (C) 1984, 1989-1990, 2000-2015 Free Software Foundation, Inc. 6 | 7 | This program is free software: you can redistribute it and/or modify 8 | it under the terms of the GNU General Public License as published by 9 | the Free Software Foundation, either version 3 of the License, or 10 | (at your option) any later version. 11 | 12 | This program is distributed in the hope that it will be useful, 13 | but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | GNU General Public License for more details. 16 | 17 | You should have received a copy of the GNU General Public License 18 | along with this program. If not, see . */ 19 | 20 | /* As a special exception, you may create a larger work that contains 21 | part or all of the Bison parser skeleton and distribute that work 22 | under terms of your choice, so long as that work isn't itself a 23 | parser generator using the skeleton or a modified version thereof 24 | as a parser skeleton. Alternatively, if you modify or redistribute 25 | the parser skeleton itself, you may (at your option) remove this 26 | special exception, which will cause the skeleton and the resulting 27 | Bison output files to be licensed under the GNU General Public 28 | License without this special exception. 29 | 30 | This special exception was added by the Free Software Foundation in 31 | version 2.2 of Bison. */ 32 | 33 | /* C LALR(1) parser skeleton written by Richard Stallman, by 34 | simplifying the original so-called "semantic" parser. */ 35 | 36 | /* All symbols defined below should begin with yy or YY, to avoid 37 | infringing on user name space. This should be done even for local 38 | variables, as they might otherwise be expanded by user macros. 39 | There are some unavoidable exceptions within include files to 40 | define necessary library symbols; they are noted "INFRINGES ON 41 | USER NAME SPACE" below. */ 42 | 43 | /* Identify Bison output. */ 44 | #define YYBISON 1 45 | 46 | /* Bison version. */ 47 | #define YYBISON_VERSION "3.0.4" 48 | 49 | /* Skeleton name. */ 50 | #define YYSKELETON_NAME "yacc.c" 51 | 52 | /* Pure parsers. */ 53 | #define YYPURE 0 54 | 55 | /* Push parsers. */ 56 | #define YYPUSH 0 57 | 58 | /* Pull parsers. */ 59 | #define YYPULL 1 60 | 61 | 62 | 63 | 64 | /* Copy the first part of user declarations. */ 65 | #line 1 "src/nsswitch.y" /* yacc.c:339 */ 66 | 67 | 68 | #include 69 | #include 70 | #include 71 | #include "parse_common.h" 72 | 73 | list_t parsed_output; 74 | 75 | int yyerror(const char*); 76 | 77 | static const action default_actions[] = { 78 | ACT_RETURN, 79 | ACT_CONTINUE, 80 | ACT_CONTINUE, 81 | ACT_CONTINUE 82 | }; 83 | 84 | 85 | #line 86 "src/nsswitch.tab.c" /* yacc.c:339 */ 86 | 87 | # ifndef YY_NULLPTR 88 | # if defined __cplusplus && 201103L <= __cplusplus 89 | # define YY_NULLPTR nullptr 90 | # else 91 | # define YY_NULLPTR 0 92 | # endif 93 | # endif 94 | 95 | /* Enabling verbose error messages. */ 96 | #ifdef YYERROR_VERBOSE 97 | # undef YYERROR_VERBOSE 98 | # define YYERROR_VERBOSE 1 99 | #else 100 | # define YYERROR_VERBOSE 0 101 | #endif 102 | 103 | 104 | /* Debug traces. */ 105 | #ifndef YYDEBUG 106 | # define YYDEBUG 0 107 | #endif 108 | #if YYDEBUG 109 | extern int yydebug; 110 | #endif 111 | 112 | /* Token type. */ 113 | #ifndef YYTOKENTYPE 114 | # define YYTOKENTYPE 115 | enum yytokentype 116 | { 117 | STRING = 258, 118 | DB = 259, 119 | STS = 260, 120 | ACT = 261 121 | }; 122 | #endif 123 | /* Tokens. */ 124 | #define STRING 258 125 | #define DB 259 126 | #define STS 260 127 | #define ACT 261 128 | 129 | /* Value type. */ 130 | 131 | 132 | extern YYSTYPE yylval; 133 | 134 | int yyparse (void); 135 | 136 | 137 | 138 | /* Copy the second part of user declarations. */ 139 | 140 | #line 141 "src/nsswitch.tab.c" /* yacc.c:358 */ 141 | 142 | #ifdef short 143 | # undef short 144 | #endif 145 | 146 | #ifdef YYTYPE_UINT8 147 | typedef YYTYPE_UINT8 yytype_uint8; 148 | #else 149 | typedef unsigned char yytype_uint8; 150 | #endif 151 | 152 | #ifdef YYTYPE_INT8 153 | typedef YYTYPE_INT8 yytype_int8; 154 | #else 155 | typedef signed char yytype_int8; 156 | #endif 157 | 158 | #ifdef YYTYPE_UINT16 159 | typedef YYTYPE_UINT16 yytype_uint16; 160 | #else 161 | typedef unsigned short int yytype_uint16; 162 | #endif 163 | 164 | #ifdef YYTYPE_INT16 165 | typedef YYTYPE_INT16 yytype_int16; 166 | #else 167 | typedef short int yytype_int16; 168 | #endif 169 | 170 | #ifndef YYSIZE_T 171 | # ifdef __SIZE_TYPE__ 172 | # define YYSIZE_T __SIZE_TYPE__ 173 | # elif defined size_t 174 | # define YYSIZE_T size_t 175 | # elif ! defined YYSIZE_T 176 | # include /* INFRINGES ON USER NAME SPACE */ 177 | # define YYSIZE_T size_t 178 | # else 179 | # define YYSIZE_T unsigned int 180 | # endif 181 | #endif 182 | 183 | #define YYSIZE_MAXIMUM ((YYSIZE_T) -1) 184 | 185 | #ifndef YY_ 186 | # if defined YYENABLE_NLS && YYENABLE_NLS 187 | # if ENABLE_NLS 188 | # include /* INFRINGES ON USER NAME SPACE */ 189 | # define YY_(Msgid) dgettext ("bison-runtime", Msgid) 190 | # endif 191 | # endif 192 | # ifndef YY_ 193 | # define YY_(Msgid) Msgid 194 | # endif 195 | #endif 196 | 197 | #ifndef YY_ATTRIBUTE 198 | # if (defined __GNUC__ \ 199 | && (2 < __GNUC__ || (__GNUC__ == 2 && 96 <= __GNUC_MINOR__))) \ 200 | || defined __SUNPRO_C && 0x5110 <= __SUNPRO_C 201 | # define YY_ATTRIBUTE(Spec) __attribute__(Spec) 202 | # else 203 | # define YY_ATTRIBUTE(Spec) /* empty */ 204 | # endif 205 | #endif 206 | 207 | #ifndef YY_ATTRIBUTE_PURE 208 | # define YY_ATTRIBUTE_PURE YY_ATTRIBUTE ((__pure__)) 209 | #endif 210 | 211 | #ifndef YY_ATTRIBUTE_UNUSED 212 | # define YY_ATTRIBUTE_UNUSED YY_ATTRIBUTE ((__unused__)) 213 | #endif 214 | 215 | #if !defined _Noreturn \ 216 | && (!defined __STDC_VERSION__ || __STDC_VERSION__ < 201112) 217 | # if defined _MSC_VER && 1200 <= _MSC_VER 218 | # define _Noreturn __declspec (noreturn) 219 | # else 220 | # define _Noreturn YY_ATTRIBUTE ((__noreturn__)) 221 | # endif 222 | #endif 223 | 224 | /* Suppress unused-variable warnings by "using" E. */ 225 | #if ! defined lint || defined __GNUC__ 226 | # define YYUSE(E) ((void) (E)) 227 | #else 228 | # define YYUSE(E) /* empty */ 229 | #endif 230 | 231 | #if defined __GNUC__ && 407 <= __GNUC__ * 100 + __GNUC_MINOR__ 232 | /* Suppress an incorrect diagnostic about yylval being uninitialized. */ 233 | # define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN \ 234 | _Pragma ("GCC diagnostic push") \ 235 | _Pragma ("GCC diagnostic ignored \"-Wuninitialized\"")\ 236 | _Pragma ("GCC diagnostic ignored \"-Wmaybe-uninitialized\"") 237 | # define YY_IGNORE_MAYBE_UNINITIALIZED_END \ 238 | _Pragma ("GCC diagnostic pop") 239 | #else 240 | # define YY_INITIAL_VALUE(Value) Value 241 | #endif 242 | #ifndef YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN 243 | # define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN 244 | # define YY_IGNORE_MAYBE_UNINITIALIZED_END 245 | #endif 246 | #ifndef YY_INITIAL_VALUE 247 | # define YY_INITIAL_VALUE(Value) /* Nothing. */ 248 | #endif 249 | 250 | 251 | #if ! defined yyoverflow || YYERROR_VERBOSE 252 | 253 | /* The parser invokes alloca or malloc; define the necessary symbols. */ 254 | 255 | # ifdef YYSTACK_USE_ALLOCA 256 | # if YYSTACK_USE_ALLOCA 257 | # ifdef __GNUC__ 258 | # define YYSTACK_ALLOC __builtin_alloca 259 | # elif defined __BUILTIN_VA_ARG_INCR 260 | # include /* INFRINGES ON USER NAME SPACE */ 261 | # elif defined _AIX 262 | # define YYSTACK_ALLOC __alloca 263 | # elif defined _MSC_VER 264 | # include /* INFRINGES ON USER NAME SPACE */ 265 | # define alloca _alloca 266 | # else 267 | # define YYSTACK_ALLOC alloca 268 | # if ! defined _ALLOCA_H && ! defined EXIT_SUCCESS 269 | # include /* INFRINGES ON USER NAME SPACE */ 270 | /* Use EXIT_SUCCESS as a witness for stdlib.h. */ 271 | # ifndef EXIT_SUCCESS 272 | # define EXIT_SUCCESS 0 273 | # endif 274 | # endif 275 | # endif 276 | # endif 277 | # endif 278 | 279 | # ifdef YYSTACK_ALLOC 280 | /* Pacify GCC's 'empty if-body' warning. */ 281 | # define YYSTACK_FREE(Ptr) do { /* empty */; } while (0) 282 | # ifndef YYSTACK_ALLOC_MAXIMUM 283 | /* The OS might guarantee only one guard page at the bottom of the stack, 284 | and a page size can be as small as 4096 bytes. So we cannot safely 285 | invoke alloca (N) if N exceeds 4096. Use a slightly smaller number 286 | to allow for a few compiler-allocated temporary stack slots. */ 287 | # define YYSTACK_ALLOC_MAXIMUM 4032 /* reasonable circa 2006 */ 288 | # endif 289 | # else 290 | # define YYSTACK_ALLOC YYMALLOC 291 | # define YYSTACK_FREE YYFREE 292 | # ifndef YYSTACK_ALLOC_MAXIMUM 293 | # define YYSTACK_ALLOC_MAXIMUM YYSIZE_MAXIMUM 294 | # endif 295 | # if (defined __cplusplus && ! defined EXIT_SUCCESS \ 296 | && ! ((defined YYMALLOC || defined malloc) \ 297 | && (defined YYFREE || defined free))) 298 | # include /* INFRINGES ON USER NAME SPACE */ 299 | # ifndef EXIT_SUCCESS 300 | # define EXIT_SUCCESS 0 301 | # endif 302 | # endif 303 | # ifndef YYMALLOC 304 | # define YYMALLOC malloc 305 | # if ! defined malloc && ! defined EXIT_SUCCESS 306 | void *malloc (YYSIZE_T); /* INFRINGES ON USER NAME SPACE */ 307 | # endif 308 | # endif 309 | # ifndef YYFREE 310 | # define YYFREE free 311 | # if ! defined free && ! defined EXIT_SUCCESS 312 | void free (void *); /* INFRINGES ON USER NAME SPACE */ 313 | # endif 314 | # endif 315 | # endif 316 | #endif /* ! defined yyoverflow || YYERROR_VERBOSE */ 317 | 318 | 319 | #if (! defined yyoverflow \ 320 | && (! defined __cplusplus \ 321 | || (defined YYSTYPE_IS_TRIVIAL && YYSTYPE_IS_TRIVIAL))) 322 | 323 | /* A type that is properly aligned for any stack member. */ 324 | union yyalloc 325 | { 326 | yytype_int16 yyss_alloc; 327 | YYSTYPE yyvs_alloc; 328 | }; 329 | 330 | /* The size of the maximum gap between one aligned stack and the next. */ 331 | # define YYSTACK_GAP_MAXIMUM (sizeof (union yyalloc) - 1) 332 | 333 | /* The size of an array large to enough to hold all stacks, each with 334 | N elements. */ 335 | # define YYSTACK_BYTES(N) \ 336 | ((N) * (sizeof (yytype_int16) + sizeof (YYSTYPE)) \ 337 | + YYSTACK_GAP_MAXIMUM) 338 | 339 | # define YYCOPY_NEEDED 1 340 | 341 | /* Relocate STACK from its old location to the new one. The 342 | local variables YYSIZE and YYSTACKSIZE give the old and new number of 343 | elements in the stack, and YYPTR gives the new location of the 344 | stack. Advance YYPTR to a properly aligned location for the next 345 | stack. */ 346 | # define YYSTACK_RELOCATE(Stack_alloc, Stack) \ 347 | do \ 348 | { \ 349 | YYSIZE_T yynewbytes; \ 350 | YYCOPY (&yyptr->Stack_alloc, Stack, yysize); \ 351 | Stack = &yyptr->Stack_alloc; \ 352 | yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAXIMUM; \ 353 | yyptr += yynewbytes / sizeof (*yyptr); \ 354 | } \ 355 | while (0) 356 | 357 | #endif 358 | 359 | #if defined YYCOPY_NEEDED && YYCOPY_NEEDED 360 | /* Copy COUNT objects from SRC to DST. The source and destination do 361 | not overlap. */ 362 | # ifndef YYCOPY 363 | # if defined __GNUC__ && 1 < __GNUC__ 364 | # define YYCOPY(Dst, Src, Count) \ 365 | __builtin_memcpy (Dst, Src, (Count) * sizeof (*(Src))) 366 | # else 367 | # define YYCOPY(Dst, Src, Count) \ 368 | do \ 369 | { \ 370 | YYSIZE_T yyi; \ 371 | for (yyi = 0; yyi < (Count); yyi++) \ 372 | (Dst)[yyi] = (Src)[yyi]; \ 373 | } \ 374 | while (0) 375 | # endif 376 | # endif 377 | #endif /* !YYCOPY_NEEDED */ 378 | 379 | /* YYFINAL -- State number of the termination state. */ 380 | #define YYFINAL 3 381 | /* YYLAST -- Last index in YYTABLE. */ 382 | #define YYLAST 17 383 | 384 | /* YYNTOKENS -- Number of terminals. */ 385 | #define YYNTOKENS 12 386 | /* YYNNTS -- Number of nonterminals. */ 387 | #define YYNNTS 8 388 | /* YYNRULES -- Number of rules. */ 389 | #define YYNRULES 15 390 | /* YYNSTATES -- Number of states. */ 391 | #define YYNSTATES 25 392 | 393 | /* YYTRANSLATE[YYX] -- Symbol number corresponding to YYX as returned 394 | by yylex, with out-of-bounds checking. */ 395 | #define YYUNDEFTOK 2 396 | #define YYMAXUTOK 262 397 | 398 | #define YYTRANSLATE(YYX) \ 399 | ((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK) 400 | 401 | /* YYTRANSLATE[TOKEN-NUM] -- Symbol number corresponding to TOKEN-NUM 402 | as returned by yylex, without out-of-bounds checking. */ 403 | static const yytype_uint8 yytranslate[] = 404 | { 405 | 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 406 | 7, 2, 2, 2, 2, 2, 2, 2, 2, 2, 407 | 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 408 | 2, 2, 2, 10, 2, 2, 2, 2, 2, 2, 409 | 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 410 | 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 411 | 2, 11, 2, 2, 2, 2, 2, 2, 2, 2, 412 | 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 413 | 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 414 | 2, 8, 2, 9, 2, 2, 2, 2, 2, 2, 415 | 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 416 | 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 417 | 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 418 | 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 419 | 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 420 | 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 421 | 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 422 | 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 423 | 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 424 | 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 425 | 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 426 | 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 427 | 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 428 | 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 429 | 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 430 | 2, 2, 2, 2, 2, 2, 1, 2, 3, 4, 431 | 5, 6, 2 432 | }; 433 | 434 | #if YYDEBUG 435 | /* YYRLINE[YYN] -- Source line where rule number YYN was defined. */ 436 | static const yytype_uint8 yyrline[] = 437 | { 438 | 0, 35, 35, 41, 44, 58, 61, 68, 73, 78, 439 | 83, 91, 94, 108, 115, 118 440 | }; 441 | #endif 442 | 443 | #if YYDEBUG || YYERROR_VERBOSE || 0 444 | /* YYTNAME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM. 445 | First, the terminals, then, starting at YYNTOKENS, nonterminals. */ 446 | static const char *const yytname[] = 447 | { 448 | "$end", "error", "$undefined", "STRING", "DB", "STS", "ACT", "'\\n'", 449 | "'['", "']'", "'!'", "'='", "$accept", "top", "file", "line", "modifier", 450 | "modifiers", "item", "list", YY_NULLPTR 451 | }; 452 | #endif 453 | 454 | # ifdef YYPRINT 455 | /* YYTOKNUM[NUM] -- (External) token number corresponding to the 456 | (internal) symbol number NUM (which must be that of a token). */ 457 | static const yytype_uint16 yytoknum[] = 458 | { 459 | 0, 256, 262, 258, 259, 260, 261, 10, 91, 93, 460 | 33, 61 461 | }; 462 | # endif 463 | 464 | #define YYPACT_NINF -6 465 | 466 | #define yypact_value_is_default(Yystate) \ 467 | (!!((Yystate) == (-6))) 468 | 469 | #define YYTABLE_NINF -1 470 | 471 | #define yytable_value_is_error(Yytable_value) \ 472 | 0 473 | 474 | /* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing 475 | STATE-NUM. */ 476 | static const yytype_int8 yypact[] = 477 | { 478 | -6, 3, -3, -6, -6, -6, -6, -1, -6, -6, 479 | -6, 0, -5, -6, -2, 6, -6, 7, 1, 5, 480 | -6, 9, -6, 8, -6 481 | }; 482 | 483 | /* YYDEFACT[STATE-NUM] -- Default reduction number in state STATE-NUM. 484 | Performed when YYTABLE does not specify something else to do. Zero 485 | means the default is an error. */ 486 | static const yytype_uint8 yydefact[] = 487 | { 488 | 3, 0, 2, 1, 14, 5, 4, 0, 11, 6, 489 | 15, 13, 0, 12, 0, 0, 7, 0, 0, 0, 490 | 8, 0, 9, 0, 10 491 | }; 492 | 493 | /* YYPGOTO[NTERM-NUM]. */ 494 | static const yytype_int8 yypgoto[] = 495 | { 496 | -6, -6, -6, -6, -6, -6, -6, -6 497 | }; 498 | 499 | /* YYDEFGOTO[NTERM-NUM]. */ 500 | static const yytype_int8 yydefgoto[] = 501 | { 502 | -1, 1, 2, 6, 13, 11, 10, 7 503 | }; 504 | 505 | /* YYTABLE[YYPACT[STATE-NUM]] -- What to do in state STATE-NUM. If 506 | positive, shift that token. If negative, reduce the rule whose 507 | number is the opposite. If YYTABLE_NINF, syntax error. */ 508 | static const yytype_uint8 yytable[] = 509 | { 510 | 14, 4, 8, 3, 5, 15, 9, 16, 12, 17, 511 | 20, 18, 21, 19, 22, 23, 0, 24 512 | }; 513 | 514 | static const yytype_int8 yycheck[] = 515 | { 516 | 5, 4, 3, 0, 7, 10, 7, 9, 8, 11, 517 | 9, 5, 11, 6, 9, 6, -1, 9 518 | }; 519 | 520 | /* YYSTOS[STATE-NUM] -- The (internal number of the) accessing 521 | symbol of state STATE-NUM. */ 522 | static const yytype_uint8 yystos[] = 523 | { 524 | 0, 13, 14, 0, 4, 7, 15, 19, 3, 7, 525 | 18, 17, 8, 16, 5, 10, 9, 11, 5, 6, 526 | 9, 11, 9, 6, 9 527 | }; 528 | 529 | /* YYR1[YYN] -- Symbol number of symbol that rule YYN derives. */ 530 | static const yytype_uint8 yyr1[] = 531 | { 532 | 0, 12, 13, 14, 14, 15, 15, 16, 16, 16, 533 | 16, 17, 17, 18, 19, 19 534 | }; 535 | 536 | /* YYR2[YYN] -- Number of symbols on the right hand side of rule YYN. */ 537 | static const yytype_uint8 yyr2[] = 538 | { 539 | 0, 2, 1, 0, 2, 1, 3, 3, 4, 5, 540 | 6, 0, 2, 2, 0, 2 541 | }; 542 | 543 | 544 | #define yyerrok (yyerrstatus = 0) 545 | #define yyclearin (yychar = YYEMPTY) 546 | #define YYEMPTY (-2) 547 | #define YYEOF 0 548 | 549 | #define YYACCEPT goto yyacceptlab 550 | #define YYABORT goto yyabortlab 551 | #define YYERROR goto yyerrorlab 552 | 553 | 554 | #define YYRECOVERING() (!!yyerrstatus) 555 | 556 | #define YYBACKUP(Token, Value) \ 557 | do \ 558 | if (yychar == YYEMPTY) \ 559 | { \ 560 | yychar = (Token); \ 561 | yylval = (Value); \ 562 | YYPOPSTACK (yylen); \ 563 | yystate = *yyssp; \ 564 | goto yybackup; \ 565 | } \ 566 | else \ 567 | { \ 568 | yyerror (YY_("syntax error: cannot back up")); \ 569 | YYERROR; \ 570 | } \ 571 | while (0) 572 | 573 | /* Error token number */ 574 | #define YYTERROR 1 575 | #define YYERRCODE 256 576 | 577 | 578 | 579 | /* Enable debugging if requested. */ 580 | #if YYDEBUG 581 | 582 | # ifndef YYFPRINTF 583 | # include /* INFRINGES ON USER NAME SPACE */ 584 | # define YYFPRINTF fprintf 585 | # endif 586 | 587 | # define YYDPRINTF(Args) \ 588 | do { \ 589 | if (yydebug) \ 590 | YYFPRINTF Args; \ 591 | } while (0) 592 | 593 | /* This macro is provided for backward compatibility. */ 594 | #ifndef YY_LOCATION_PRINT 595 | # define YY_LOCATION_PRINT(File, Loc) ((void) 0) 596 | #endif 597 | 598 | 599 | # define YY_SYMBOL_PRINT(Title, Type, Value, Location) \ 600 | do { \ 601 | if (yydebug) \ 602 | { \ 603 | YYFPRINTF (stderr, "%s ", Title); \ 604 | yy_symbol_print (stderr, \ 605 | Type, Value); \ 606 | YYFPRINTF (stderr, "\n"); \ 607 | } \ 608 | } while (0) 609 | 610 | 611 | /*----------------------------------------. 612 | | Print this symbol's value on YYOUTPUT. | 613 | `----------------------------------------*/ 614 | 615 | static void 616 | yy_symbol_value_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep) 617 | { 618 | FILE *yyo = yyoutput; 619 | YYUSE (yyo); 620 | if (!yyvaluep) 621 | return; 622 | # ifdef YYPRINT 623 | if (yytype < YYNTOKENS) 624 | YYPRINT (yyoutput, yytoknum[yytype], *yyvaluep); 625 | # endif 626 | YYUSE (yytype); 627 | } 628 | 629 | 630 | /*--------------------------------. 631 | | Print this symbol on YYOUTPUT. | 632 | `--------------------------------*/ 633 | 634 | static void 635 | yy_symbol_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep) 636 | { 637 | YYFPRINTF (yyoutput, "%s %s (", 638 | yytype < YYNTOKENS ? "token" : "nterm", yytname[yytype]); 639 | 640 | yy_symbol_value_print (yyoutput, yytype, yyvaluep); 641 | YYFPRINTF (yyoutput, ")"); 642 | } 643 | 644 | /*------------------------------------------------------------------. 645 | | yy_stack_print -- Print the state stack from its BOTTOM up to its | 646 | | TOP (included). | 647 | `------------------------------------------------------------------*/ 648 | 649 | static void 650 | yy_stack_print (yytype_int16 *yybottom, yytype_int16 *yytop) 651 | { 652 | YYFPRINTF (stderr, "Stack now"); 653 | for (; yybottom <= yytop; yybottom++) 654 | { 655 | int yybot = *yybottom; 656 | YYFPRINTF (stderr, " %d", yybot); 657 | } 658 | YYFPRINTF (stderr, "\n"); 659 | } 660 | 661 | # define YY_STACK_PRINT(Bottom, Top) \ 662 | do { \ 663 | if (yydebug) \ 664 | yy_stack_print ((Bottom), (Top)); \ 665 | } while (0) 666 | 667 | 668 | /*------------------------------------------------. 669 | | Report that the YYRULE is going to be reduced. | 670 | `------------------------------------------------*/ 671 | 672 | static void 673 | yy_reduce_print (yytype_int16 *yyssp, YYSTYPE *yyvsp, int yyrule) 674 | { 675 | unsigned long int yylno = yyrline[yyrule]; 676 | int yynrhs = yyr2[yyrule]; 677 | int yyi; 678 | YYFPRINTF (stderr, "Reducing stack by rule %d (line %lu):\n", 679 | yyrule - 1, yylno); 680 | /* The symbols being reduced. */ 681 | for (yyi = 0; yyi < yynrhs; yyi++) 682 | { 683 | YYFPRINTF (stderr, " $%d = ", yyi + 1); 684 | yy_symbol_print (stderr, 685 | yystos[yyssp[yyi + 1 - yynrhs]], 686 | &(yyvsp[(yyi + 1) - (yynrhs)]) 687 | ); 688 | YYFPRINTF (stderr, "\n"); 689 | } 690 | } 691 | 692 | # define YY_REDUCE_PRINT(Rule) \ 693 | do { \ 694 | if (yydebug) \ 695 | yy_reduce_print (yyssp, yyvsp, Rule); \ 696 | } while (0) 697 | 698 | /* Nonzero means print parse trace. It is left uninitialized so that 699 | multiple parsers can coexist. */ 700 | int yydebug; 701 | #else /* !YYDEBUG */ 702 | # define YYDPRINTF(Args) 703 | # define YY_SYMBOL_PRINT(Title, Type, Value, Location) 704 | # define YY_STACK_PRINT(Bottom, Top) 705 | # define YY_REDUCE_PRINT(Rule) 706 | #endif /* !YYDEBUG */ 707 | 708 | 709 | /* YYINITDEPTH -- initial size of the parser's stacks. */ 710 | #ifndef YYINITDEPTH 711 | # define YYINITDEPTH 200 712 | #endif 713 | 714 | /* YYMAXDEPTH -- maximum size the stacks can grow to (effective only 715 | if the built-in stack extension method is used). 716 | 717 | Do not make this value too large; the results are undefined if 718 | YYSTACK_ALLOC_MAXIMUM < YYSTACK_BYTES (YYMAXDEPTH) 719 | evaluated with infinite-precision integer arithmetic. */ 720 | 721 | #ifndef YYMAXDEPTH 722 | # define YYMAXDEPTH 10000 723 | #endif 724 | 725 | 726 | #if YYERROR_VERBOSE 727 | 728 | # ifndef yystrlen 729 | # if defined __GLIBC__ && defined _STRING_H 730 | # define yystrlen strlen 731 | # else 732 | /* Return the length of YYSTR. */ 733 | static YYSIZE_T 734 | yystrlen (const char *yystr) 735 | { 736 | YYSIZE_T yylen; 737 | for (yylen = 0; yystr[yylen]; yylen++) 738 | continue; 739 | return yylen; 740 | } 741 | # endif 742 | # endif 743 | 744 | # ifndef yystpcpy 745 | # if defined __GLIBC__ && defined _STRING_H && defined _GNU_SOURCE 746 | # define yystpcpy stpcpy 747 | # else 748 | /* Copy YYSRC to YYDEST, returning the address of the terminating '\0' in 749 | YYDEST. */ 750 | static char * 751 | yystpcpy (char *yydest, const char *yysrc) 752 | { 753 | char *yyd = yydest; 754 | const char *yys = yysrc; 755 | 756 | while ((*yyd++ = *yys++) != '\0') 757 | continue; 758 | 759 | return yyd - 1; 760 | } 761 | # endif 762 | # endif 763 | 764 | # ifndef yytnamerr 765 | /* Copy to YYRES the contents of YYSTR after stripping away unnecessary 766 | quotes and backslashes, so that it's suitable for yyerror. The 767 | heuristic is that double-quoting is unnecessary unless the string 768 | contains an apostrophe, a comma, or backslash (other than 769 | backslash-backslash). YYSTR is taken from yytname. If YYRES is 770 | null, do not copy; instead, return the length of what the result 771 | would have been. */ 772 | static YYSIZE_T 773 | yytnamerr (char *yyres, const char *yystr) 774 | { 775 | if (*yystr == '"') 776 | { 777 | YYSIZE_T yyn = 0; 778 | char const *yyp = yystr; 779 | 780 | for (;;) 781 | switch (*++yyp) 782 | { 783 | case '\'': 784 | case ',': 785 | goto do_not_strip_quotes; 786 | 787 | case '\\': 788 | if (*++yyp != '\\') 789 | goto do_not_strip_quotes; 790 | /* Fall through. */ 791 | default: 792 | if (yyres) 793 | yyres[yyn] = *yyp; 794 | yyn++; 795 | break; 796 | 797 | case '"': 798 | if (yyres) 799 | yyres[yyn] = '\0'; 800 | return yyn; 801 | } 802 | do_not_strip_quotes: ; 803 | } 804 | 805 | if (! yyres) 806 | return yystrlen (yystr); 807 | 808 | return yystpcpy (yyres, yystr) - yyres; 809 | } 810 | # endif 811 | 812 | /* Copy into *YYMSG, which is of size *YYMSG_ALLOC, an error message 813 | about the unexpected token YYTOKEN for the state stack whose top is 814 | YYSSP. 815 | 816 | Return 0 if *YYMSG was successfully written. Return 1 if *YYMSG is 817 | not large enough to hold the message. In that case, also set 818 | *YYMSG_ALLOC to the required number of bytes. Return 2 if the 819 | required number of bytes is too large to store. */ 820 | static int 821 | yysyntax_error (YYSIZE_T *yymsg_alloc, char **yymsg, 822 | yytype_int16 *yyssp, int yytoken) 823 | { 824 | YYSIZE_T yysize0 = yytnamerr (YY_NULLPTR, yytname[yytoken]); 825 | YYSIZE_T yysize = yysize0; 826 | enum { YYERROR_VERBOSE_ARGS_MAXIMUM = 5 }; 827 | /* Internationalized format string. */ 828 | const char *yyformat = YY_NULLPTR; 829 | /* Arguments of yyformat. */ 830 | char const *yyarg[YYERROR_VERBOSE_ARGS_MAXIMUM]; 831 | /* Number of reported tokens (one for the "unexpected", one per 832 | "expected"). */ 833 | int yycount = 0; 834 | 835 | /* There are many possibilities here to consider: 836 | - If this state is a consistent state with a default action, then 837 | the only way this function was invoked is if the default action 838 | is an error action. In that case, don't check for expected 839 | tokens because there are none. 840 | - The only way there can be no lookahead present (in yychar) is if 841 | this state is a consistent state with a default action. Thus, 842 | detecting the absence of a lookahead is sufficient to determine 843 | that there is no unexpected or expected token to report. In that 844 | case, just report a simple "syntax error". 845 | - Don't assume there isn't a lookahead just because this state is a 846 | consistent state with a default action. There might have been a 847 | previous inconsistent state, consistent state with a non-default 848 | action, or user semantic action that manipulated yychar. 849 | - Of course, the expected token list depends on states to have 850 | correct lookahead information, and it depends on the parser not 851 | to perform extra reductions after fetching a lookahead from the 852 | scanner and before detecting a syntax error. Thus, state merging 853 | (from LALR or IELR) and default reductions corrupt the expected 854 | token list. However, the list is correct for canonical LR with 855 | one exception: it will still contain any token that will not be 856 | accepted due to an error action in a later state. 857 | */ 858 | if (yytoken != YYEMPTY) 859 | { 860 | int yyn = yypact[*yyssp]; 861 | yyarg[yycount++] = yytname[yytoken]; 862 | if (!yypact_value_is_default (yyn)) 863 | { 864 | /* Start YYX at -YYN if negative to avoid negative indexes in 865 | YYCHECK. In other words, skip the first -YYN actions for 866 | this state because they are default actions. */ 867 | int yyxbegin = yyn < 0 ? -yyn : 0; 868 | /* Stay within bounds of both yycheck and yytname. */ 869 | int yychecklim = YYLAST - yyn + 1; 870 | int yyxend = yychecklim < YYNTOKENS ? yychecklim : YYNTOKENS; 871 | int yyx; 872 | 873 | for (yyx = yyxbegin; yyx < yyxend; ++yyx) 874 | if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR 875 | && !yytable_value_is_error (yytable[yyx + yyn])) 876 | { 877 | if (yycount == YYERROR_VERBOSE_ARGS_MAXIMUM) 878 | { 879 | yycount = 1; 880 | yysize = yysize0; 881 | break; 882 | } 883 | yyarg[yycount++] = yytname[yyx]; 884 | { 885 | YYSIZE_T yysize1 = yysize + yytnamerr (YY_NULLPTR, yytname[yyx]); 886 | if (! (yysize <= yysize1 887 | && yysize1 <= YYSTACK_ALLOC_MAXIMUM)) 888 | return 2; 889 | yysize = yysize1; 890 | } 891 | } 892 | } 893 | } 894 | 895 | switch (yycount) 896 | { 897 | # define YYCASE_(N, S) \ 898 | case N: \ 899 | yyformat = S; \ 900 | break 901 | YYCASE_(0, YY_("syntax error")); 902 | YYCASE_(1, YY_("syntax error, unexpected %s")); 903 | YYCASE_(2, YY_("syntax error, unexpected %s, expecting %s")); 904 | YYCASE_(3, YY_("syntax error, unexpected %s, expecting %s or %s")); 905 | YYCASE_(4, YY_("syntax error, unexpected %s, expecting %s or %s or %s")); 906 | YYCASE_(5, YY_("syntax error, unexpected %s, expecting %s or %s or %s or %s")); 907 | # undef YYCASE_ 908 | } 909 | 910 | { 911 | YYSIZE_T yysize1 = yysize + yystrlen (yyformat); 912 | if (! (yysize <= yysize1 && yysize1 <= YYSTACK_ALLOC_MAXIMUM)) 913 | return 2; 914 | yysize = yysize1; 915 | } 916 | 917 | if (*yymsg_alloc < yysize) 918 | { 919 | *yymsg_alloc = 2 * yysize; 920 | if (! (yysize <= *yymsg_alloc 921 | && *yymsg_alloc <= YYSTACK_ALLOC_MAXIMUM)) 922 | *yymsg_alloc = YYSTACK_ALLOC_MAXIMUM; 923 | return 1; 924 | } 925 | 926 | /* Avoid sprintf, as that infringes on the user's name space. 927 | Don't have undefined behavior even if the translation 928 | produced a string with the wrong number of "%s"s. */ 929 | { 930 | char *yyp = *yymsg; 931 | int yyi = 0; 932 | while ((*yyp = *yyformat) != '\0') 933 | if (*yyp == '%' && yyformat[1] == 's' && yyi < yycount) 934 | { 935 | yyp += yytnamerr (yyp, yyarg[yyi++]); 936 | yyformat += 2; 937 | } 938 | else 939 | { 940 | yyp++; 941 | yyformat++; 942 | } 943 | } 944 | return 0; 945 | } 946 | #endif /* YYERROR_VERBOSE */ 947 | 948 | /*-----------------------------------------------. 949 | | Release the memory associated to this symbol. | 950 | `-----------------------------------------------*/ 951 | 952 | static void 953 | yydestruct (const char *yymsg, int yytype, YYSTYPE *yyvaluep) 954 | { 955 | YYUSE (yyvaluep); 956 | if (!yymsg) 957 | yymsg = "Deleting"; 958 | YY_SYMBOL_PRINT (yymsg, yytype, yyvaluep, yylocationp); 959 | 960 | YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN 961 | YYUSE (yytype); 962 | YY_IGNORE_MAYBE_UNINITIALIZED_END 963 | } 964 | 965 | 966 | 967 | 968 | /* The lookahead symbol. */ 969 | int yychar; 970 | 971 | /* The semantic value of the lookahead symbol. */ 972 | YYSTYPE yylval; 973 | /* Number of syntax errors so far. */ 974 | int yynerrs; 975 | 976 | 977 | /*----------. 978 | | yyparse. | 979 | `----------*/ 980 | 981 | int 982 | yyparse (void) 983 | { 984 | int yystate; 985 | /* Number of tokens to shift before error messages enabled. */ 986 | int yyerrstatus; 987 | 988 | /* The stacks and their tools: 989 | 'yyss': related to states. 990 | 'yyvs': related to semantic values. 991 | 992 | Refer to the stacks through separate pointers, to allow yyoverflow 993 | to reallocate them elsewhere. */ 994 | 995 | /* The state stack. */ 996 | yytype_int16 yyssa[YYINITDEPTH]; 997 | yytype_int16 *yyss; 998 | yytype_int16 *yyssp; 999 | 1000 | /* The semantic value stack. */ 1001 | YYSTYPE yyvsa[YYINITDEPTH]; 1002 | YYSTYPE *yyvs; 1003 | YYSTYPE *yyvsp; 1004 | 1005 | YYSIZE_T yystacksize; 1006 | 1007 | int yyn; 1008 | int yyresult; 1009 | /* Lookahead token as an internal (translated) token number. */ 1010 | int yytoken = 0; 1011 | /* The variables used to return semantic value and location from the 1012 | action routines. */ 1013 | YYSTYPE yyval; 1014 | 1015 | #if YYERROR_VERBOSE 1016 | /* Buffer for error messages, and its allocated size. */ 1017 | char yymsgbuf[128]; 1018 | char *yymsg = yymsgbuf; 1019 | YYSIZE_T yymsg_alloc = sizeof yymsgbuf; 1020 | #endif 1021 | 1022 | #define YYPOPSTACK(N) (yyvsp -= (N), yyssp -= (N)) 1023 | 1024 | /* The number of symbols on the RHS of the reduced rule. 1025 | Keep to zero when no symbol should be popped. */ 1026 | int yylen = 0; 1027 | 1028 | yyssp = yyss = yyssa; 1029 | yyvsp = yyvs = yyvsa; 1030 | yystacksize = YYINITDEPTH; 1031 | 1032 | YYDPRINTF ((stderr, "Starting parse\n")); 1033 | 1034 | yystate = 0; 1035 | yyerrstatus = 0; 1036 | yynerrs = 0; 1037 | yychar = YYEMPTY; /* Cause a token to be read. */ 1038 | goto yysetstate; 1039 | 1040 | /*------------------------------------------------------------. 1041 | | yynewstate -- Push a new state, which is found in yystate. | 1042 | `------------------------------------------------------------*/ 1043 | yynewstate: 1044 | /* In all cases, when you get here, the value and location stacks 1045 | have just been pushed. So pushing a state here evens the stacks. */ 1046 | yyssp++; 1047 | 1048 | yysetstate: 1049 | *yyssp = yystate; 1050 | 1051 | if (yyss + yystacksize - 1 <= yyssp) 1052 | { 1053 | /* Get the current used size of the three stacks, in elements. */ 1054 | YYSIZE_T yysize = yyssp - yyss + 1; 1055 | 1056 | #ifdef yyoverflow 1057 | { 1058 | /* Give user a chance to reallocate the stack. Use copies of 1059 | these so that the &'s don't force the real ones into 1060 | memory. */ 1061 | YYSTYPE *yyvs1 = yyvs; 1062 | yytype_int16 *yyss1 = yyss; 1063 | 1064 | /* Each stack pointer address is followed by the size of the 1065 | data in use in that stack, in bytes. This used to be a 1066 | conditional around just the two extra args, but that might 1067 | be undefined if yyoverflow is a macro. */ 1068 | yyoverflow (YY_("memory exhausted"), 1069 | &yyss1, yysize * sizeof (*yyssp), 1070 | &yyvs1, yysize * sizeof (*yyvsp), 1071 | &yystacksize); 1072 | 1073 | yyss = yyss1; 1074 | yyvs = yyvs1; 1075 | } 1076 | #else /* no yyoverflow */ 1077 | # ifndef YYSTACK_RELOCATE 1078 | goto yyexhaustedlab; 1079 | # else 1080 | /* Extend the stack our own way. */ 1081 | if (YYMAXDEPTH <= yystacksize) 1082 | goto yyexhaustedlab; 1083 | yystacksize *= 2; 1084 | if (YYMAXDEPTH < yystacksize) 1085 | yystacksize = YYMAXDEPTH; 1086 | 1087 | { 1088 | yytype_int16 *yyss1 = yyss; 1089 | union yyalloc *yyptr = 1090 | (union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize)); 1091 | if (! yyptr) 1092 | goto yyexhaustedlab; 1093 | YYSTACK_RELOCATE (yyss_alloc, yyss); 1094 | YYSTACK_RELOCATE (yyvs_alloc, yyvs); 1095 | # undef YYSTACK_RELOCATE 1096 | if (yyss1 != yyssa) 1097 | YYSTACK_FREE (yyss1); 1098 | } 1099 | # endif 1100 | #endif /* no yyoverflow */ 1101 | 1102 | yyssp = yyss + yysize - 1; 1103 | yyvsp = yyvs + yysize - 1; 1104 | 1105 | YYDPRINTF ((stderr, "Stack size increased to %lu\n", 1106 | (unsigned long int) yystacksize)); 1107 | 1108 | if (yyss + yystacksize - 1 <= yyssp) 1109 | YYABORT; 1110 | } 1111 | 1112 | YYDPRINTF ((stderr, "Entering state %d\n", yystate)); 1113 | 1114 | if (yystate == YYFINAL) 1115 | YYACCEPT; 1116 | 1117 | goto yybackup; 1118 | 1119 | /*-----------. 1120 | | yybackup. | 1121 | `-----------*/ 1122 | yybackup: 1123 | 1124 | /* Do appropriate processing given the current state. Read a 1125 | lookahead token if we need one and don't already have one. */ 1126 | 1127 | /* First try to decide what to do without reference to lookahead token. */ 1128 | yyn = yypact[yystate]; 1129 | if (yypact_value_is_default (yyn)) 1130 | goto yydefault; 1131 | 1132 | /* Not known => get a lookahead token if don't already have one. */ 1133 | 1134 | /* YYCHAR is either YYEMPTY or YYEOF or a valid lookahead symbol. */ 1135 | if (yychar == YYEMPTY) 1136 | { 1137 | YYDPRINTF ((stderr, "Reading a token: ")); 1138 | yychar = yylex (); 1139 | } 1140 | 1141 | if (yychar <= YYEOF) 1142 | { 1143 | yychar = yytoken = YYEOF; 1144 | YYDPRINTF ((stderr, "Now at end of input.\n")); 1145 | } 1146 | else 1147 | { 1148 | yytoken = YYTRANSLATE (yychar); 1149 | YY_SYMBOL_PRINT ("Next token is", yytoken, &yylval, &yylloc); 1150 | } 1151 | 1152 | /* If the proper action on seeing token YYTOKEN is to reduce or to 1153 | detect an error, take that action. */ 1154 | yyn += yytoken; 1155 | if (yyn < 0 || YYLAST < yyn || yycheck[yyn] != yytoken) 1156 | goto yydefault; 1157 | yyn = yytable[yyn]; 1158 | if (yyn <= 0) 1159 | { 1160 | if (yytable_value_is_error (yyn)) 1161 | goto yyerrlab; 1162 | yyn = -yyn; 1163 | goto yyreduce; 1164 | } 1165 | 1166 | /* Count tokens shifted since error; after three, turn off error 1167 | status. */ 1168 | if (yyerrstatus) 1169 | yyerrstatus--; 1170 | 1171 | /* Shift the lookahead token. */ 1172 | YY_SYMBOL_PRINT ("Shifting", yytoken, &yylval, &yylloc); 1173 | 1174 | /* Discard the shifted token. */ 1175 | yychar = YYEMPTY; 1176 | 1177 | yystate = yyn; 1178 | YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN 1179 | *++yyvsp = yylval; 1180 | YY_IGNORE_MAYBE_UNINITIALIZED_END 1181 | 1182 | goto yynewstate; 1183 | 1184 | 1185 | /*-----------------------------------------------------------. 1186 | | yydefault -- do the default action for the current state. | 1187 | `-----------------------------------------------------------*/ 1188 | yydefault: 1189 | yyn = yydefact[yystate]; 1190 | if (yyn == 0) 1191 | goto yyerrlab; 1192 | goto yyreduce; 1193 | 1194 | 1195 | /*-----------------------------. 1196 | | yyreduce -- Do a reduction. | 1197 | `-----------------------------*/ 1198 | yyreduce: 1199 | /* yyn is the number of a rule to reduce with. */ 1200 | yylen = yyr2[yyn]; 1201 | 1202 | /* If YYLEN is nonzero, implement the default value of the action: 1203 | '$$ = $1'. 1204 | 1205 | Otherwise, the following line sets YYVAL to garbage. 1206 | This behavior is undocumented and Bison 1207 | users should not rely upon it. Assigning to YYVAL 1208 | unconditionally makes the parser a bit smaller, and it avoids a 1209 | GCC warning that YYVAL may be used uninitialized. */ 1210 | yyval = yyvsp[1-yylen]; 1211 | 1212 | 1213 | YY_REDUCE_PRINT (yyn); 1214 | switch (yyn) 1215 | { 1216 | case 2: 1217 | #line 35 "src/nsswitch.y" /* yacc.c:1646 */ 1218 | { 1219 | parsed_output = (yyvsp[0].list); 1220 | } 1221 | #line 1222 "src/nsswitch.tab.c" /* yacc.c:1646 */ 1222 | break; 1223 | 1224 | case 3: 1225 | #line 41 "src/nsswitch.y" /* yacc.c:1646 */ 1226 | { 1227 | list_init(&(yyval.list)); 1228 | } 1229 | #line 1230 "src/nsswitch.tab.c" /* yacc.c:1646 */ 1230 | break; 1231 | 1232 | case 4: 1233 | #line 44 "src/nsswitch.y" /* yacc.c:1646 */ 1234 | { 1235 | if((yyvsp[0].entry).database == (unsigned char)-1) { 1236 | (yyval.list) = (yyvsp[-1].list); 1237 | } else { 1238 | struct entry *entry = malloc(sizeof(*entry)); 1239 | if(!entry) YYABORT; 1240 | memcpy(entry, &(yyvsp[0].entry), sizeof(*entry)); 1241 | (yyval.list) = (yyvsp[-1].list); 1242 | list_push_back(&(yyval.list), &(entry->link)); 1243 | } 1244 | } 1245 | #line 1246 "src/nsswitch.tab.c" /* yacc.c:1646 */ 1246 | break; 1247 | 1248 | case 5: 1249 | #line 58 "src/nsswitch.y" /* yacc.c:1646 */ 1250 | { 1251 | (yyval.entry).database = (unsigned char)-1; 1252 | } 1253 | #line 1254 "src/nsswitch.tab.c" /* yacc.c:1646 */ 1254 | break; 1255 | 1256 | case 6: 1257 | #line 61 "src/nsswitch.y" /* yacc.c:1646 */ 1258 | { 1259 | (yyval.entry).database = (yyvsp[-2].database); 1260 | (yyval.entry).services = (yyvsp[-1].list); 1261 | } 1262 | #line 1263 "src/nsswitch.tab.c" /* yacc.c:1646 */ 1263 | break; 1264 | 1265 | case 7: 1266 | #line 68 "src/nsswitch.y" /* yacc.c:1646 */ 1267 | { 1268 | (yyval.modifier).status = (yyvsp[-1].status); 1269 | (yyval.modifier).action = (yyvsp[-1].status) == STS_SUCCESS ? ACT_RETURN : ACT_CONTINUE; 1270 | (yyval.modifier).negate = false; 1271 | } 1272 | #line 1273 "src/nsswitch.tab.c" /* yacc.c:1646 */ 1273 | break; 1274 | 1275 | case 8: 1276 | #line 73 "src/nsswitch.y" /* yacc.c:1646 */ 1277 | { 1278 | (yyval.modifier).status = (yyvsp[-1].status); 1279 | (yyval.modifier).action = (yyvsp[-1].status) == STS_SUCCESS ? ACT_RETURN : ACT_CONTINUE; 1280 | (yyval.modifier).negate = true; 1281 | } 1282 | #line 1283 "src/nsswitch.tab.c" /* yacc.c:1646 */ 1283 | break; 1284 | 1285 | case 9: 1286 | #line 78 "src/nsswitch.y" /* yacc.c:1646 */ 1287 | { 1288 | (yyval.modifier).status = (yyvsp[-3].status); 1289 | (yyval.modifier).action = (yyvsp[-1].action); 1290 | (yyval.modifier).negate = false; 1291 | } 1292 | #line 1293 "src/nsswitch.tab.c" /* yacc.c:1646 */ 1293 | break; 1294 | 1295 | case 10: 1296 | #line 83 "src/nsswitch.y" /* yacc.c:1646 */ 1297 | { 1298 | (yyval.modifier).status = (yyvsp[-3].status); 1299 | (yyval.modifier).action = (yyvsp[-1].action); 1300 | (yyval.modifier).negate = true; 1301 | } 1302 | #line 1303 "src/nsswitch.tab.c" /* yacc.c:1646 */ 1303 | break; 1304 | 1305 | case 11: 1306 | #line 91 "src/nsswitch.y" /* yacc.c:1646 */ 1307 | { 1308 | memcpy((yyval.modifiers), default_actions, sizeof((yyval.modifiers))); 1309 | } 1310 | #line 1311 "src/nsswitch.tab.c" /* yacc.c:1646 */ 1311 | break; 1312 | 1313 | case 12: 1314 | #line 94 "src/nsswitch.y" /* yacc.c:1646 */ 1315 | { 1316 | int i; 1317 | memcpy((yyval.modifiers), (yyvsp[-1].modifiers), sizeof((yyval.modifiers))); 1318 | for(i = 0; i < sizeof((yyval.modifiers))/sizeof((yyval.modifiers)[0]); i++) { 1319 | if(i == (yyvsp[0].modifier).status && !(yyvsp[0].modifier).negate) { 1320 | (yyval.modifiers)[i] = (yyvsp[0].modifier).action; 1321 | } 1322 | if(i != (yyvsp[0].modifier).status && (yyvsp[0].modifier).negate) { 1323 | (yyval.modifiers)[i] = (yyvsp[0].modifier).action; 1324 | } 1325 | } 1326 | } 1327 | #line 1328 "src/nsswitch.tab.c" /* yacc.c:1646 */ 1328 | break; 1329 | 1330 | case 13: 1331 | #line 108 "src/nsswitch.y" /* yacc.c:1646 */ 1332 | { 1333 | memcpy((yyval.service).on_status, (yyvsp[0].modifiers), sizeof((yyvsp[0].modifiers))); 1334 | (yyval.service).service = (yyvsp[-1].str); 1335 | } 1336 | #line 1337 "src/nsswitch.tab.c" /* yacc.c:1646 */ 1337 | break; 1338 | 1339 | case 14: 1340 | #line 115 "src/nsswitch.y" /* yacc.c:1646 */ 1341 | { 1342 | list_init(&(yyval.list)); 1343 | } 1344 | #line 1345 "src/nsswitch.tab.c" /* yacc.c:1646 */ 1345 | break; 1346 | 1347 | case 15: 1348 | #line 118 "src/nsswitch.y" /* yacc.c:1646 */ 1349 | { 1350 | (yyval.list) = (yyvsp[-1].list); 1351 | struct service *service = malloc(sizeof(*service)); 1352 | if(!service) YYABORT; 1353 | memcpy(service, &(yyvsp[0].service), sizeof(*service)); 1354 | list_push_back(&(yyval.list), &(service->link)); 1355 | } 1356 | #line 1357 "src/nsswitch.tab.c" /* yacc.c:1646 */ 1357 | break; 1358 | 1359 | 1360 | #line 1361 "src/nsswitch.tab.c" /* yacc.c:1646 */ 1361 | default: break; 1362 | } 1363 | /* User semantic actions sometimes alter yychar, and that requires 1364 | that yytoken be updated with the new translation. We take the 1365 | approach of translating immediately before every use of yytoken. 1366 | One alternative is translating here after every semantic action, 1367 | but that translation would be missed if the semantic action invokes 1368 | YYABORT, YYACCEPT, or YYERROR immediately after altering yychar or 1369 | if it invokes YYBACKUP. In the case of YYABORT or YYACCEPT, an 1370 | incorrect destructor might then be invoked immediately. In the 1371 | case of YYERROR or YYBACKUP, subsequent parser actions might lead 1372 | to an incorrect destructor call or verbose syntax error message 1373 | before the lookahead is translated. */ 1374 | YY_SYMBOL_PRINT ("-> $$ =", yyr1[yyn], &yyval, &yyloc); 1375 | 1376 | YYPOPSTACK (yylen); 1377 | yylen = 0; 1378 | YY_STACK_PRINT (yyss, yyssp); 1379 | 1380 | *++yyvsp = yyval; 1381 | 1382 | /* Now 'shift' the result of the reduction. Determine what state 1383 | that goes to, based on the state we popped back to and the rule 1384 | number reduced by. */ 1385 | 1386 | yyn = yyr1[yyn]; 1387 | 1388 | yystate = yypgoto[yyn - YYNTOKENS] + *yyssp; 1389 | if (0 <= yystate && yystate <= YYLAST && yycheck[yystate] == *yyssp) 1390 | yystate = yytable[yystate]; 1391 | else 1392 | yystate = yydefgoto[yyn - YYNTOKENS]; 1393 | 1394 | goto yynewstate; 1395 | 1396 | 1397 | /*--------------------------------------. 1398 | | yyerrlab -- here on detecting error. | 1399 | `--------------------------------------*/ 1400 | yyerrlab: 1401 | /* Make sure we have latest lookahead translation. See comments at 1402 | user semantic actions for why this is necessary. */ 1403 | yytoken = yychar == YYEMPTY ? YYEMPTY : YYTRANSLATE (yychar); 1404 | 1405 | /* If not already recovering from an error, report this error. */ 1406 | if (!yyerrstatus) 1407 | { 1408 | ++yynerrs; 1409 | #if ! YYERROR_VERBOSE 1410 | yyerror (YY_("syntax error")); 1411 | #else 1412 | # define YYSYNTAX_ERROR yysyntax_error (&yymsg_alloc, &yymsg, \ 1413 | yyssp, yytoken) 1414 | { 1415 | char const *yymsgp = YY_("syntax error"); 1416 | int yysyntax_error_status; 1417 | yysyntax_error_status = YYSYNTAX_ERROR; 1418 | if (yysyntax_error_status == 0) 1419 | yymsgp = yymsg; 1420 | else if (yysyntax_error_status == 1) 1421 | { 1422 | if (yymsg != yymsgbuf) 1423 | YYSTACK_FREE (yymsg); 1424 | yymsg = (char *) YYSTACK_ALLOC (yymsg_alloc); 1425 | if (!yymsg) 1426 | { 1427 | yymsg = yymsgbuf; 1428 | yymsg_alloc = sizeof yymsgbuf; 1429 | yysyntax_error_status = 2; 1430 | } 1431 | else 1432 | { 1433 | yysyntax_error_status = YYSYNTAX_ERROR; 1434 | yymsgp = yymsg; 1435 | } 1436 | } 1437 | yyerror (yymsgp); 1438 | if (yysyntax_error_status == 2) 1439 | goto yyexhaustedlab; 1440 | } 1441 | # undef YYSYNTAX_ERROR 1442 | #endif 1443 | } 1444 | 1445 | 1446 | 1447 | if (yyerrstatus == 3) 1448 | { 1449 | /* If just tried and failed to reuse lookahead token after an 1450 | error, discard it. */ 1451 | 1452 | if (yychar <= YYEOF) 1453 | { 1454 | /* Return failure if at end of input. */ 1455 | if (yychar == YYEOF) 1456 | YYABORT; 1457 | } 1458 | else 1459 | { 1460 | yydestruct ("Error: discarding", 1461 | yytoken, &yylval); 1462 | yychar = YYEMPTY; 1463 | } 1464 | } 1465 | 1466 | /* Else will try to reuse lookahead token after shifting the error 1467 | token. */ 1468 | goto yyerrlab1; 1469 | 1470 | 1471 | /*---------------------------------------------------. 1472 | | yyerrorlab -- error raised explicitly by YYERROR. | 1473 | `---------------------------------------------------*/ 1474 | yyerrorlab: 1475 | 1476 | /* Pacify compilers like GCC when the user code never invokes 1477 | YYERROR and the label yyerrorlab therefore never appears in user 1478 | code. */ 1479 | if (/*CONSTCOND*/ 0) 1480 | goto yyerrorlab; 1481 | 1482 | /* Do not reclaim the symbols of the rule whose action triggered 1483 | this YYERROR. */ 1484 | YYPOPSTACK (yylen); 1485 | yylen = 0; 1486 | YY_STACK_PRINT (yyss, yyssp); 1487 | yystate = *yyssp; 1488 | goto yyerrlab1; 1489 | 1490 | 1491 | /*-------------------------------------------------------------. 1492 | | yyerrlab1 -- common code for both syntax error and YYERROR. | 1493 | `-------------------------------------------------------------*/ 1494 | yyerrlab1: 1495 | yyerrstatus = 3; /* Each real token shifted decrements this. */ 1496 | 1497 | for (;;) 1498 | { 1499 | yyn = yypact[yystate]; 1500 | if (!yypact_value_is_default (yyn)) 1501 | { 1502 | yyn += YYTERROR; 1503 | if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYTERROR) 1504 | { 1505 | yyn = yytable[yyn]; 1506 | if (0 < yyn) 1507 | break; 1508 | } 1509 | } 1510 | 1511 | /* Pop the current state because it cannot handle the error token. */ 1512 | if (yyssp == yyss) 1513 | YYABORT; 1514 | 1515 | 1516 | yydestruct ("Error: popping", 1517 | yystos[yystate], yyvsp); 1518 | YYPOPSTACK (1); 1519 | yystate = *yyssp; 1520 | YY_STACK_PRINT (yyss, yyssp); 1521 | } 1522 | 1523 | YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN 1524 | *++yyvsp = yylval; 1525 | YY_IGNORE_MAYBE_UNINITIALIZED_END 1526 | 1527 | 1528 | /* Shift the error token. */ 1529 | YY_SYMBOL_PRINT ("Shifting", yystos[yyn], yyvsp, yylsp); 1530 | 1531 | yystate = yyn; 1532 | goto yynewstate; 1533 | 1534 | 1535 | /*-------------------------------------. 1536 | | yyacceptlab -- YYACCEPT comes here. | 1537 | `-------------------------------------*/ 1538 | yyacceptlab: 1539 | yyresult = 0; 1540 | goto yyreturn; 1541 | 1542 | /*-----------------------------------. 1543 | | yyabortlab -- YYABORT comes here. | 1544 | `-----------------------------------*/ 1545 | yyabortlab: 1546 | yyresult = 1; 1547 | goto yyreturn; 1548 | 1549 | #if !defined yyoverflow || YYERROR_VERBOSE 1550 | /*-------------------------------------------------. 1551 | | yyexhaustedlab -- memory exhaustion comes here. | 1552 | `-------------------------------------------------*/ 1553 | yyexhaustedlab: 1554 | yyerror (YY_("memory exhausted")); 1555 | yyresult = 2; 1556 | /* Fall through. */ 1557 | #endif 1558 | 1559 | yyreturn: 1560 | if (yychar != YYEMPTY) 1561 | { 1562 | /* Make sure we have latest lookahead translation. See comments at 1563 | user semantic actions for why this is necessary. */ 1564 | yytoken = YYTRANSLATE (yychar); 1565 | yydestruct ("Cleanup: discarding lookahead", 1566 | yytoken, &yylval); 1567 | } 1568 | /* Do not reclaim the symbols of the rule whose action triggered 1569 | this YYABORT or YYACCEPT. */ 1570 | YYPOPSTACK (yylen); 1571 | YY_STACK_PRINT (yyss, yyssp); 1572 | while (yyssp != yyss) 1573 | { 1574 | yydestruct ("Cleanup: popping", 1575 | yystos[*yyssp], yyvsp); 1576 | YYPOPSTACK (1); 1577 | } 1578 | #ifndef yyoverflow 1579 | if (yyss != yyssa) 1580 | YYSTACK_FREE (yyss); 1581 | #endif 1582 | #if YYERROR_VERBOSE 1583 | if (yymsg != yymsgbuf) 1584 | YYSTACK_FREE (yymsg); 1585 | #endif 1586 | return yyresult; 1587 | } 1588 | #line 127 "src/nsswitch.y" /* yacc.c:1906 */ 1589 | 1590 | 1591 | int yyerror(const char *s) 1592 | { 1593 | fprintf(stderr, "%s\n", s); 1594 | } 1595 | 1596 | #if TEST_PARSER 1597 | 1598 | static const char *dbmap[] = { 1599 | "aliases", 1600 | "ethers", 1601 | "group", 1602 | "hosts", 1603 | "initgroups", 1604 | "netgroup", 1605 | "networks", 1606 | "passwd", 1607 | "protocols", 1608 | "publickey", 1609 | "rpc", 1610 | "services", 1611 | "shadow" 1612 | }; 1613 | 1614 | static const char *stsmap[] = { 1615 | "SUCCESS", 1616 | "NOTFOUND", 1617 | "UNAVAIL", 1618 | "TRYAGAIN" 1619 | }; 1620 | 1621 | static const char *actmap[] = { 1622 | "return", 1623 | "continue", 1624 | "merge" 1625 | }; 1626 | 1627 | int main() 1628 | { 1629 | #if YYDEBUG 1630 | yydebug = 1; 1631 | #endif 1632 | if(yyparse()) return 1; 1633 | link_t *line, *service; 1634 | line = list_head(&parsed_output); 1635 | while(line) { 1636 | struct entry *entry = list_ref(line, struct entry, link); 1637 | printf("%s: ", dbmap[entry->database]); 1638 | service = list_head(&entry->services); 1639 | while(service) { 1640 | struct service *svc = list_ref(service, struct service, link); 1641 | printf("%s ", svc->service); 1642 | for(int i = 0; i < 4; i++) { 1643 | if(svc->on_status[i] != default_actions[i]) 1644 | printf("[%s=%s] ", stsmap[i], actmap[svc->on_status[i]]); 1645 | } 1646 | service = list_next(service); 1647 | free(svc->service); 1648 | free(svc); 1649 | } 1650 | printf("\n"); 1651 | line = list_next(line); 1652 | free(entry); 1653 | } 1654 | } 1655 | 1656 | #endif 1657 | -------------------------------------------------------------------------------- /dist/src/nsswitch.yy.c: -------------------------------------------------------------------------------- 1 | 2 | #line 3 "" 3 | 4 | #define YY_INT_ALIGNED short int 5 | 6 | /* A lexical scanner generated by flex */ 7 | 8 | #define FLEX_SCANNER 9 | #define YY_FLEX_MAJOR_VERSION 2 10 | #define YY_FLEX_MINOR_VERSION 6 11 | #define YY_FLEX_SUBMINOR_VERSION 0 12 | #if YY_FLEX_SUBMINOR_VERSION > 0 13 | #define FLEX_BETA 14 | #endif 15 | 16 | /* First, we deal with platform-specific or compiler-specific issues. */ 17 | 18 | /* begin standard C headers. */ 19 | #include 20 | #include 21 | #include 22 | #include 23 | 24 | /* end standard C headers. */ 25 | 26 | /* flex integer type definitions */ 27 | 28 | #ifndef FLEXINT_H 29 | #define FLEXINT_H 30 | 31 | /* C99 systems have . Non-C99 systems may or may not. */ 32 | 33 | #if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L 34 | 35 | /* C99 says to define __STDC_LIMIT_MACROS before including stdint.h, 36 | * if you want the limit (max/min) macros for int types. 37 | */ 38 | #ifndef __STDC_LIMIT_MACROS 39 | #define __STDC_LIMIT_MACROS 1 40 | #endif 41 | 42 | #include 43 | typedef int8_t flex_int8_t; 44 | typedef uint8_t flex_uint8_t; 45 | typedef int16_t flex_int16_t; 46 | typedef uint16_t flex_uint16_t; 47 | typedef int32_t flex_int32_t; 48 | typedef uint32_t flex_uint32_t; 49 | #else 50 | typedef signed char flex_int8_t; 51 | typedef short int flex_int16_t; 52 | typedef int flex_int32_t; 53 | typedef unsigned char flex_uint8_t; 54 | typedef unsigned short int flex_uint16_t; 55 | typedef unsigned int flex_uint32_t; 56 | 57 | /* Limits of integral types. */ 58 | #ifndef INT8_MIN 59 | #define INT8_MIN (-128) 60 | #endif 61 | #ifndef INT16_MIN 62 | #define INT16_MIN (-32767-1) 63 | #endif 64 | #ifndef INT32_MIN 65 | #define INT32_MIN (-2147483647-1) 66 | #endif 67 | #ifndef INT8_MAX 68 | #define INT8_MAX (127) 69 | #endif 70 | #ifndef INT16_MAX 71 | #define INT16_MAX (32767) 72 | #endif 73 | #ifndef INT32_MAX 74 | #define INT32_MAX (2147483647) 75 | #endif 76 | #ifndef UINT8_MAX 77 | #define UINT8_MAX (255U) 78 | #endif 79 | #ifndef UINT16_MAX 80 | #define UINT16_MAX (65535U) 81 | #endif 82 | #ifndef UINT32_MAX 83 | #define UINT32_MAX (4294967295U) 84 | #endif 85 | 86 | #endif /* ! C99 */ 87 | 88 | #endif /* ! FLEXINT_H */ 89 | 90 | #ifdef __cplusplus 91 | 92 | /* The "const" storage-class-modifier is valid. */ 93 | #define YY_USE_CONST 94 | 95 | #else /* ! __cplusplus */ 96 | 97 | /* C99 requires __STDC__ to be defined as 1. */ 98 | #if defined (__STDC__) 99 | 100 | #define YY_USE_CONST 101 | 102 | #endif /* defined (__STDC__) */ 103 | #endif /* ! __cplusplus */ 104 | 105 | #ifdef YY_USE_CONST 106 | #define yyconst const 107 | #else 108 | #define yyconst 109 | #endif 110 | 111 | /* Returned upon end-of-file. */ 112 | #define YY_NULL 0 113 | 114 | /* Promotes a possibly negative, possibly signed char to an unsigned 115 | * integer for use as an array index. If the signed char is negative, 116 | * we want to instead treat it as an 8-bit unsigned char, hence the 117 | * double cast. 118 | */ 119 | #define YY_SC_TO_UI(c) ((unsigned int) (unsigned char) c) 120 | 121 | /* Enter a start condition. This macro really ought to take a parameter, 122 | * but we do it the disgusting crufty way forced on us by the ()-less 123 | * definition of BEGIN. 124 | */ 125 | #define BEGIN (yy_start) = 1 + 2 * 126 | 127 | /* Translate the current start state into a value that can be later handed 128 | * to BEGIN to return to the state. The YYSTATE alias is for lex 129 | * compatibility. 130 | */ 131 | #define YY_START (((yy_start) - 1) / 2) 132 | #define YYSTATE YY_START 133 | 134 | /* Action number for EOF rule of a given start state. */ 135 | #define YY_STATE_EOF(state) (YY_END_OF_BUFFER + state + 1) 136 | 137 | /* Special action meaning "start processing a new file". */ 138 | #define YY_NEW_FILE yyrestart(yyin ) 139 | 140 | #define YY_END_OF_BUFFER_CHAR 0 141 | 142 | /* Size of default input buffer. */ 143 | #ifndef YY_BUF_SIZE 144 | #ifdef __ia64__ 145 | /* On IA-64, the buffer size is 16k, not 8k. 146 | * Moreover, YY_BUF_SIZE is 2*YY_READ_BUF_SIZE in the general case. 147 | * Ditto for the __ia64__ case accordingly. 148 | */ 149 | #define YY_BUF_SIZE 32768 150 | #else 151 | #define YY_BUF_SIZE 16384 152 | #endif /* __ia64__ */ 153 | #endif 154 | 155 | /* The state buf must be large enough to hold one state per character in the main buffer. 156 | */ 157 | #define YY_STATE_BUF_SIZE ((YY_BUF_SIZE + 2) * sizeof(yy_state_type)) 158 | 159 | #ifndef YY_TYPEDEF_YY_BUFFER_STATE 160 | #define YY_TYPEDEF_YY_BUFFER_STATE 161 | typedef struct yy_buffer_state *YY_BUFFER_STATE; 162 | #endif 163 | 164 | #ifndef YY_TYPEDEF_YY_SIZE_T 165 | #define YY_TYPEDEF_YY_SIZE_T 166 | typedef size_t yy_size_t; 167 | #endif 168 | 169 | extern yy_size_t yyleng; 170 | 171 | extern FILE *yyin, *yyout; 172 | 173 | #define EOB_ACT_CONTINUE_SCAN 0 174 | #define EOB_ACT_END_OF_FILE 1 175 | #define EOB_ACT_LAST_MATCH 2 176 | 177 | #define YY_LESS_LINENO(n) 178 | #define YY_LINENO_REWIND_TO(ptr) 179 | 180 | /* Return all but the first "n" matched characters back to the input stream. */ 181 | #define yyless(n) \ 182 | do \ 183 | { \ 184 | /* Undo effects of setting up yytext. */ \ 185 | int yyless_macro_arg = (n); \ 186 | YY_LESS_LINENO(yyless_macro_arg);\ 187 | *yy_cp = (yy_hold_char); \ 188 | YY_RESTORE_YY_MORE_OFFSET \ 189 | (yy_c_buf_p) = yy_cp = yy_bp + yyless_macro_arg - YY_MORE_ADJ; \ 190 | YY_DO_BEFORE_ACTION; /* set up yytext again */ \ 191 | } \ 192 | while ( 0 ) 193 | 194 | #define unput(c) yyunput( c, (yytext_ptr) ) 195 | 196 | #ifndef YY_STRUCT_YY_BUFFER_STATE 197 | #define YY_STRUCT_YY_BUFFER_STATE 198 | struct yy_buffer_state 199 | { 200 | FILE *yy_input_file; 201 | 202 | char *yy_ch_buf; /* input buffer */ 203 | char *yy_buf_pos; /* current position in input buffer */ 204 | 205 | /* Size of input buffer in bytes, not including room for EOB 206 | * characters. 207 | */ 208 | yy_size_t yy_buf_size; 209 | 210 | /* Number of characters read into yy_ch_buf, not including EOB 211 | * characters. 212 | */ 213 | int yy_n_chars; 214 | 215 | /* Whether we "own" the buffer - i.e., we know we created it, 216 | * and can realloc() it to grow it, and should free() it to 217 | * delete it. 218 | */ 219 | int yy_is_our_buffer; 220 | 221 | /* Whether this is an "interactive" input source; if so, and 222 | * if we're using stdio for input, then we want to use getc() 223 | * instead of fread(), to make sure we stop fetching input after 224 | * each newline. 225 | */ 226 | int yy_is_interactive; 227 | 228 | /* Whether we're considered to be at the beginning of a line. 229 | * If so, '^' rules will be active on the next match, otherwise 230 | * not. 231 | */ 232 | int yy_at_bol; 233 | 234 | int yy_bs_lineno; /**< The line count. */ 235 | int yy_bs_column; /**< The column count. */ 236 | 237 | /* Whether to try to fill the input buffer when we reach the 238 | * end of it. 239 | */ 240 | int yy_fill_buffer; 241 | 242 | int yy_buffer_status; 243 | 244 | #define YY_BUFFER_NEW 0 245 | #define YY_BUFFER_NORMAL 1 246 | /* When an EOF's been seen but there's still some text to process 247 | * then we mark the buffer as YY_EOF_PENDING, to indicate that we 248 | * shouldn't try reading from the input source any more. We might 249 | * still have a bunch of tokens to match, though, because of 250 | * possible backing-up. 251 | * 252 | * When we actually see the EOF, we change the status to "new" 253 | * (via yyrestart()), so that the user can continue scanning by 254 | * just pointing yyin at a new input file. 255 | */ 256 | #define YY_BUFFER_EOF_PENDING 2 257 | 258 | }; 259 | #endif /* !YY_STRUCT_YY_BUFFER_STATE */ 260 | 261 | /* Stack of input buffers. */ 262 | static size_t yy_buffer_stack_top = 0; /**< index of top of stack. */ 263 | static size_t yy_buffer_stack_max = 0; /**< capacity of stack. */ 264 | static YY_BUFFER_STATE * yy_buffer_stack = 0; /**< Stack as an array. */ 265 | 266 | /* We provide macros for accessing buffer states in case in the 267 | * future we want to put the buffer states in a more general 268 | * "scanner state". 269 | * 270 | * Returns the top of the stack, or NULL. 271 | */ 272 | #define YY_CURRENT_BUFFER ( (yy_buffer_stack) \ 273 | ? (yy_buffer_stack)[(yy_buffer_stack_top)] \ 274 | : NULL) 275 | 276 | /* Same as previous macro, but useful when we know that the buffer stack is not 277 | * NULL or when we need an lvalue. For internal use only. 278 | */ 279 | #define YY_CURRENT_BUFFER_LVALUE (yy_buffer_stack)[(yy_buffer_stack_top)] 280 | 281 | /* yy_hold_char holds the character lost when yytext is formed. */ 282 | static char yy_hold_char; 283 | static int yy_n_chars; /* number of characters read into yy_ch_buf */ 284 | yy_size_t yyleng; 285 | 286 | /* Points to current character in buffer. */ 287 | static char *yy_c_buf_p = (char *) 0; 288 | static int yy_init = 0; /* whether we need to initialize */ 289 | static int yy_start = 0; /* start state number */ 290 | 291 | /* Flag which is used to allow yywrap()'s to do buffer switches 292 | * instead of setting up a fresh yyin. A bit of a hack ... 293 | */ 294 | static int yy_did_buffer_switch_on_eof; 295 | 296 | void yyrestart (FILE *input_file ); 297 | void yy_switch_to_buffer (YY_BUFFER_STATE new_buffer ); 298 | YY_BUFFER_STATE yy_create_buffer (FILE *file,int size ); 299 | void yy_delete_buffer (YY_BUFFER_STATE b ); 300 | void yy_flush_buffer (YY_BUFFER_STATE b ); 301 | void yypush_buffer_state (YY_BUFFER_STATE new_buffer ); 302 | void yypop_buffer_state (void ); 303 | 304 | static void yyensure_buffer_stack (void ); 305 | static void yy_load_buffer_state (void ); 306 | static void yy_init_buffer (YY_BUFFER_STATE b,FILE *file ); 307 | 308 | #define YY_FLUSH_BUFFER yy_flush_buffer(YY_CURRENT_BUFFER ) 309 | 310 | YY_BUFFER_STATE yy_scan_buffer (char *base,yy_size_t size ); 311 | YY_BUFFER_STATE yy_scan_string (yyconst char *yy_str ); 312 | YY_BUFFER_STATE yy_scan_bytes (yyconst char *bytes,yy_size_t len ); 313 | 314 | void *yyalloc (yy_size_t ); 315 | void *yyrealloc (void *,yy_size_t ); 316 | void yyfree (void * ); 317 | 318 | #define yy_new_buffer yy_create_buffer 319 | 320 | #define yy_set_interactive(is_interactive) \ 321 | { \ 322 | if ( ! YY_CURRENT_BUFFER ){ \ 323 | yyensure_buffer_stack (); \ 324 | YY_CURRENT_BUFFER_LVALUE = \ 325 | yy_create_buffer(yyin,YY_BUF_SIZE ); \ 326 | } \ 327 | YY_CURRENT_BUFFER_LVALUE->yy_is_interactive = is_interactive; \ 328 | } 329 | 330 | #define yy_set_bol(at_bol) \ 331 | { \ 332 | if ( ! YY_CURRENT_BUFFER ){\ 333 | yyensure_buffer_stack (); \ 334 | YY_CURRENT_BUFFER_LVALUE = \ 335 | yy_create_buffer(yyin,YY_BUF_SIZE ); \ 336 | } \ 337 | YY_CURRENT_BUFFER_LVALUE->yy_at_bol = at_bol; \ 338 | } 339 | 340 | #define YY_AT_BOL() (YY_CURRENT_BUFFER_LVALUE->yy_at_bol) 341 | 342 | /* Begin user sect3 */ 343 | 344 | typedef unsigned char YY_CHAR; 345 | 346 | FILE *yyin = (FILE *) 0, *yyout = (FILE *) 0; 347 | 348 | typedef int yy_state_type; 349 | 350 | extern int yylineno; 351 | 352 | int yylineno = 1; 353 | 354 | extern char *yytext; 355 | #ifdef yytext_ptr 356 | #undef yytext_ptr 357 | #endif 358 | #define yytext_ptr yytext 359 | 360 | static yy_state_type yy_get_previous_state (void ); 361 | static yy_state_type yy_try_NUL_trans (yy_state_type current_state ); 362 | static int yy_get_next_buffer (void ); 363 | #if defined(__GNUC__) && __GNUC__ >= 3 364 | __attribute__((__noreturn__)) 365 | #endif 366 | static void yy_fatal_error (yyconst char msg[] ); 367 | 368 | /* Done after the current pattern has been matched and before the 369 | * corresponding action - sets up yytext. 370 | */ 371 | #define YY_DO_BEFORE_ACTION \ 372 | (yytext_ptr) = yy_bp; \ 373 | yyleng = (size_t) (yy_cp - yy_bp); \ 374 | (yy_hold_char) = *yy_cp; \ 375 | *yy_cp = '\0'; \ 376 | (yy_c_buf_p) = yy_cp; 377 | 378 | #define YY_NUM_RULES 31 379 | #define YY_END_OF_BUFFER 32 380 | /* This struct is not used in this scanner, 381 | but its presence is necessary. */ 382 | struct yy_trans_info 383 | { 384 | flex_int32_t yy_verify; 385 | flex_int32_t yy_nxt; 386 | }; 387 | static yyconst flex_int16_t yy_accept[169] = 388 | { 0, 389 | 0, 0, 29, 29, 0, 0, 0, 0, 32, 30, 390 | 1, 28, 30, 30, 30, 30, 30, 30, 30, 30, 391 | 30, 29, 2, 18, 17, 16, 19, 30, 30, 30, 392 | 30, 20, 30, 30, 30, 0, 0, 0, 0, 0, 393 | 0, 0, 0, 0, 0, 0, 0, 29, 17, 0, 394 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 395 | 0, 0, 0, 0, 0, 13, 0, 0, 0, 0, 396 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 397 | 0, 0, 0, 0, 0, 13, 0, 0, 0, 0, 398 | 0, 0, 0, 0, 0, 0, 0, 5, 6, 0, 399 | 400 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 401 | 0, 0, 27, 0, 0, 4, 5, 6, 0, 0, 402 | 0, 10, 0, 0, 0, 15, 0, 0, 0, 0, 403 | 0, 25, 3, 4, 0, 0, 0, 10, 0, 0, 404 | 0, 15, 0, 21, 0, 23, 0, 3, 0, 8, 405 | 9, 0, 0, 14, 22, 24, 26, 0, 8, 9, 406 | 11, 12, 14, 7, 11, 12, 7, 0 407 | } ; 408 | 409 | static yyconst YY_CHAR yy_ec[256] = 410 | { 0, 411 | 1, 1, 1, 1, 1, 1, 1, 1, 2, 3, 412 | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 413 | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 414 | 1, 2, 4, 1, 5, 1, 1, 1, 1, 1, 415 | 1, 1, 1, 1, 1, 1, 1, 6, 6, 6, 416 | 6, 6, 6, 6, 6, 6, 6, 7, 1, 1, 417 | 8, 1, 1, 1, 9, 6, 10, 11, 12, 13, 418 | 14, 6, 15, 6, 6, 16, 6, 17, 18, 6, 419 | 6, 19, 20, 21, 22, 23, 6, 6, 24, 6, 420 | 25, 1, 26, 1, 27, 1, 28, 29, 30, 31, 421 | 422 | 32, 6, 33, 34, 35, 6, 36, 37, 38, 39, 423 | 40, 41, 6, 42, 43, 44, 45, 46, 47, 6, 424 | 48, 6, 1, 1, 1, 1, 1, 1, 1, 1, 425 | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 426 | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 427 | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 428 | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 429 | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 430 | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 431 | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 432 | 433 | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 434 | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 435 | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 436 | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 437 | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 438 | 1, 1, 1, 1, 1 439 | } ; 440 | 441 | static yyconst YY_CHAR yy_meta[49] = 442 | { 0, 443 | 1, 1, 2, 1, 1, 3, 1, 1, 3, 3, 444 | 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 445 | 3, 3, 3, 3, 1, 1, 3, 3, 3, 3, 446 | 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 447 | 3, 3, 3, 3, 3, 3, 3, 3 448 | } ; 449 | 450 | static yyconst flex_uint16_t yy_base[174] = 451 | { 0, 452 | 0, 41, 217, 216, 84, 110, 134, 0, 218, 221, 453 | 221, 221, 180, 172, 173, 174, 174, 180, 3, 170, 454 | 4, 0, 221, 221, 0, 221, 221, 192, 187, 189, 455 | 190, 221, 166, 173, 172, 168, 168, 161, 157, 164, 456 | 154, 154, 156, 166, 164, 151, 164, 0, 0, 170, 457 | 180, 165, 178, 136, 132, 129, 143, 138, 124, 124, 458 | 123, 4, 123, 121, 126, 155, 115, 128, 145, 147, 459 | 144, 129, 106, 116, 103, 104, 104, 104, 101, 110, 460 | 99, 100, 92, 94, 98, 221, 97, 91, 112, 117, 461 | 114, 118, 91, 93, 82, 91, 79, 114, 113, 77, 462 | 463 | 76, 66, 76, 76, 75, 74, 56, 80, 81, 91, 464 | 84, 59, 221, 58, 53, 88, 221, 221, 54, 48, 465 | 54, 74, 39, 42, 45, 65, 54, 50, 53, 51, 466 | 21, 221, 58, 221, 19, 22, 19, 221, 24, 28, 467 | 16, 221, 47, 221, 40, 221, 24, 221, 14, 47, 468 | 46, 9, 2, 42, 221, 221, 221, 4, 221, 221, 469 | 2, 1, 221, 0, 221, 221, 221, 221, 176, 179, 470 | 182, 185, 1 471 | } ; 472 | 473 | static yyconst flex_int16_t yy_def[174] = 474 | { 0, 475 | 169, 169, 170, 170, 171, 171, 169, 7, 168, 168, 476 | 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 477 | 168, 172, 168, 168, 173, 168, 168, 168, 168, 168, 478 | 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 479 | 168, 168, 168, 168, 168, 168, 168, 172, 173, 168, 480 | 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 481 | 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 482 | 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 483 | 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 484 | 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 485 | 486 | 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 487 | 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 488 | 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 489 | 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 490 | 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 491 | 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 492 | 168, 168, 168, 168, 168, 168, 168, 0, 168, 168, 493 | 168, 168, 168 494 | } ; 495 | 496 | static yyconst flex_uint16_t yy_nxt[270] = 497 | { 0, 498 | 168, 168, 11, 49, 12, 168, 167, 166, 165, 168, 499 | 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 500 | 168, 168, 168, 168, 168, 168, 168, 13, 168, 168, 501 | 42, 14, 15, 16, 17, 46, 81, 47, 18, 168, 502 | 19, 20, 21, 11, 43, 12, 164, 44, 163, 162, 503 | 82, 161, 160, 159, 158, 157, 156, 155, 154, 153, 504 | 152, 151, 150, 149, 148, 147, 146, 145, 13, 144, 505 | 143, 142, 14, 15, 16, 17, 141, 140, 139, 18, 506 | 138, 19, 20, 21, 10, 24, 23, 10, 10, 137, 507 | 10, 10, 136, 135, 134, 133, 132, 131, 130, 129, 508 | 509 | 128, 127, 126, 125, 124, 123, 122, 121, 26, 10, 510 | 10, 24, 23, 10, 10, 120, 10, 10, 119, 118, 511 | 117, 116, 115, 114, 113, 112, 111, 110, 109, 108, 512 | 107, 106, 105, 104, 26, 10, 23, 27, 103, 102, 513 | 101, 27, 100, 99, 98, 97, 96, 95, 94, 93, 514 | 28, 92, 91, 29, 30, 31, 90, 89, 88, 32, 515 | 87, 86, 85, 33, 84, 83, 80, 79, 78, 77, 516 | 76, 34, 75, 74, 73, 35, 10, 10, 10, 22, 517 | 22, 22, 25, 25, 25, 48, 72, 48, 71, 70, 518 | 69, 68, 67, 66, 65, 64, 63, 62, 61, 60, 519 | 520 | 59, 58, 57, 56, 55, 54, 53, 52, 51, 50, 521 | 45, 41, 40, 39, 38, 37, 36, 168, 23, 23, 522 | 9, 168, 168, 168, 168, 168, 168, 168, 168, 168, 523 | 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 524 | 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 525 | 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 526 | 168, 168, 168, 168, 168, 168, 168, 168, 168 527 | } ; 528 | 529 | static yyconst flex_int16_t yy_chk[270] = 530 | { 0, 531 | 0, 0, 1, 173, 1, 0, 164, 162, 161, 0, 532 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 533 | 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 534 | 19, 1, 1, 1, 1, 21, 62, 21, 1, 0, 535 | 1, 1, 1, 2, 19, 2, 158, 19, 154, 153, 536 | 62, 152, 151, 150, 149, 147, 145, 143, 141, 140, 537 | 139, 137, 136, 135, 133, 131, 130, 129, 2, 128, 538 | 127, 126, 2, 2, 2, 2, 125, 124, 123, 2, 539 | 122, 2, 2, 2, 5, 5, 5, 5, 5, 121, 540 | 5, 5, 120, 119, 116, 115, 114, 112, 111, 110, 541 | 542 | 109, 108, 107, 106, 105, 104, 103, 102, 5, 5, 543 | 6, 6, 6, 6, 6, 101, 6, 6, 100, 99, 544 | 98, 97, 96, 95, 94, 93, 92, 91, 90, 89, 545 | 88, 87, 85, 84, 6, 6, 7, 7, 83, 82, 546 | 81, 7, 80, 79, 78, 77, 76, 75, 74, 73, 547 | 7, 72, 71, 7, 7, 7, 70, 69, 68, 7, 548 | 67, 66, 65, 7, 64, 63, 61, 60, 59, 58, 549 | 57, 7, 56, 55, 54, 7, 169, 169, 169, 170, 550 | 170, 170, 171, 171, 171, 172, 53, 172, 52, 51, 551 | 50, 47, 46, 45, 44, 43, 42, 41, 40, 39, 552 | 553 | 38, 37, 36, 35, 34, 33, 31, 30, 29, 28, 554 | 20, 18, 17, 16, 15, 14, 13, 9, 4, 3, 555 | 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 556 | 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 557 | 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 558 | 168, 168, 168, 168, 168, 168, 168, 168, 168, 168, 559 | 168, 168, 168, 168, 168, 168, 168, 168, 168 560 | } ; 561 | 562 | static yy_state_type yy_last_accepting_state; 563 | static char *yy_last_accepting_cpos; 564 | 565 | extern int yy_flex_debug; 566 | int yy_flex_debug = 0; 567 | 568 | /* The intent behind this definition is that it'll catch 569 | * any uses of REJECT which flex missed. 570 | */ 571 | #define REJECT reject_used_but_not_detected 572 | #define yymore() yymore_used_but_not_detected 573 | #define YY_MORE_ADJ 0 574 | #define YY_RESTORE_YY_MORE_OFFSET 575 | char *yytext; 576 | #line 1 "src/nsswitch.l" 577 | #line 2 "src/nsswitch.l" 578 | #include "parse_common.h" 579 | #include 580 | #include 581 | #include 582 | 583 | 584 | 585 | #line 586 "" 586 | 587 | #define INITIAL 0 588 | #define COMMENT 1 589 | #define LIST 2 590 | #define ACTION 3 591 | 592 | #ifndef YY_NO_UNISTD_H 593 | /* Special case for "unistd.h", since it is non-ANSI. We include it way 594 | * down here because we want the user's section 1 to have been scanned first. 595 | * The user has a chance to override it with an option. 596 | */ 597 | #include 598 | #endif 599 | 600 | #ifndef YY_EXTRA_TYPE 601 | #define YY_EXTRA_TYPE void * 602 | #endif 603 | 604 | static int yy_init_globals (void ); 605 | 606 | /* Accessor methods to globals. 607 | These are made visible to non-reentrant scanners for convenience. */ 608 | 609 | int yylex_destroy (void ); 610 | 611 | int yyget_debug (void ); 612 | 613 | void yyset_debug (int debug_flag ); 614 | 615 | YY_EXTRA_TYPE yyget_extra (void ); 616 | 617 | void yyset_extra (YY_EXTRA_TYPE user_defined ); 618 | 619 | FILE *yyget_in (void ); 620 | 621 | void yyset_in (FILE * _in_str ); 622 | 623 | FILE *yyget_out (void ); 624 | 625 | void yyset_out (FILE * _out_str ); 626 | 627 | yy_size_t yyget_leng (void ); 628 | 629 | char *yyget_text (void ); 630 | 631 | int yyget_lineno (void ); 632 | 633 | void yyset_lineno (int _line_number ); 634 | 635 | /* Macros after this point can all be overridden by user definitions in 636 | * section 1. 637 | */ 638 | 639 | #ifndef YY_SKIP_YYWRAP 640 | #ifdef __cplusplus 641 | extern "C" int yywrap (void ); 642 | #else 643 | extern int yywrap (void ); 644 | #endif 645 | #endif 646 | 647 | #ifndef YY_NO_UNPUT 648 | 649 | static void yyunput (int c,char *buf_ptr ); 650 | 651 | #endif 652 | 653 | #ifndef yytext_ptr 654 | static void yy_flex_strncpy (char *,yyconst char *,int ); 655 | #endif 656 | 657 | #ifdef YY_NEED_STRLEN 658 | static int yy_flex_strlen (yyconst char * ); 659 | #endif 660 | 661 | #ifndef YY_NO_INPUT 662 | 663 | #ifdef __cplusplus 664 | static int yyinput (void ); 665 | #else 666 | static int input (void ); 667 | #endif 668 | 669 | #endif 670 | 671 | /* Amount of stuff to slurp up with each read. */ 672 | #ifndef YY_READ_BUF_SIZE 673 | #ifdef __ia64__ 674 | /* On IA-64, the buffer size is 16k, not 8k */ 675 | #define YY_READ_BUF_SIZE 16384 676 | #else 677 | #define YY_READ_BUF_SIZE 8192 678 | #endif /* __ia64__ */ 679 | #endif 680 | 681 | /* Copy whatever the last rule matched to the standard output. */ 682 | #ifndef ECHO 683 | /* This used to be an fputs(), but since the string might contain NUL's, 684 | * we now use fwrite(). 685 | */ 686 | #define ECHO do { if (fwrite( yytext, yyleng, 1, yyout )) {} } while (0) 687 | #endif 688 | 689 | /* Gets input and stuffs it into "buf". number of characters read, or YY_NULL, 690 | * is returned in "result". 691 | */ 692 | #ifndef YY_INPUT 693 | #define YY_INPUT(buf,result,max_size) \ 694 | if ( YY_CURRENT_BUFFER_LVALUE->yy_is_interactive ) \ 695 | { \ 696 | int c = '*'; \ 697 | size_t n; \ 698 | for ( n = 0; n < max_size && \ 699 | (c = getc( yyin )) != EOF && c != '\n'; ++n ) \ 700 | buf[n] = (char) c; \ 701 | if ( c == '\n' ) \ 702 | buf[n++] = (char) c; \ 703 | if ( c == EOF && ferror( yyin ) ) \ 704 | YY_FATAL_ERROR( "input in flex scanner failed" ); \ 705 | result = n; \ 706 | } \ 707 | else \ 708 | { \ 709 | errno=0; \ 710 | while ( (result = fread(buf, 1, max_size, yyin))==0 && ferror(yyin)) \ 711 | { \ 712 | if( errno != EINTR) \ 713 | { \ 714 | YY_FATAL_ERROR( "input in flex scanner failed" ); \ 715 | break; \ 716 | } \ 717 | errno=0; \ 718 | clearerr(yyin); \ 719 | } \ 720 | }\ 721 | \ 722 | 723 | #endif 724 | 725 | /* No semi-colon after return; correct usage is to write "yyterminate();" - 726 | * we don't want an extra ';' after the "return" because that will cause 727 | * some compilers to complain about unreachable statements. 728 | */ 729 | #ifndef yyterminate 730 | #define yyterminate() return YY_NULL 731 | #endif 732 | 733 | /* Number of entries by which start-condition stack grows. */ 734 | #ifndef YY_START_STACK_INCR 735 | #define YY_START_STACK_INCR 25 736 | #endif 737 | 738 | /* Report a fatal error. */ 739 | #ifndef YY_FATAL_ERROR 740 | #define YY_FATAL_ERROR(msg) yy_fatal_error( msg ) 741 | #endif 742 | 743 | /* end tables serialization structures and prototypes */ 744 | 745 | /* Default declaration of generated scanner - a define so the user can 746 | * easily add parameters. 747 | */ 748 | #ifndef YY_DECL 749 | #define YY_DECL_IS_OURS 1 750 | 751 | extern int yylex (void); 752 | 753 | #define YY_DECL int yylex (void) 754 | #endif /* !YY_DECL */ 755 | 756 | /* Code executed at the beginning of each rule, after yytext and yyleng 757 | * have been set up. 758 | */ 759 | #ifndef YY_USER_ACTION 760 | #define YY_USER_ACTION 761 | #endif 762 | 763 | /* Code executed at the end of each rule. */ 764 | #ifndef YY_BREAK 765 | #define YY_BREAK /*LINTED*/break; 766 | #endif 767 | 768 | #define YY_RULE_SETUP \ 769 | YY_USER_ACTION 770 | 771 | /** The main scanner function which does all the work. 772 | */ 773 | YY_DECL 774 | { 775 | yy_state_type yy_current_state; 776 | char *yy_cp, *yy_bp; 777 | int yy_act; 778 | 779 | if ( !(yy_init) ) 780 | { 781 | (yy_init) = 1; 782 | 783 | #ifdef YY_USER_INIT 784 | YY_USER_INIT; 785 | #endif 786 | 787 | if ( ! (yy_start) ) 788 | (yy_start) = 1; /* first start state */ 789 | 790 | if ( ! yyin ) 791 | yyin = stdin; 792 | 793 | if ( ! yyout ) 794 | yyout = stdout; 795 | 796 | if ( ! YY_CURRENT_BUFFER ) { 797 | yyensure_buffer_stack (); 798 | YY_CURRENT_BUFFER_LVALUE = 799 | yy_create_buffer(yyin,YY_BUF_SIZE ); 800 | } 801 | 802 | yy_load_buffer_state( ); 803 | } 804 | 805 | { 806 | #line 12 "src/nsswitch.l" 807 | 808 | 809 | #line 810 "" 810 | 811 | while ( /*CONSTCOND*/1 ) /* loops until end-of-file is reached */ 812 | { 813 | yy_cp = (yy_c_buf_p); 814 | 815 | /* Support of yytext. */ 816 | *yy_cp = (yy_hold_char); 817 | 818 | /* yy_bp points to the position in yy_ch_buf of the start of 819 | * the current run. 820 | */ 821 | yy_bp = yy_cp; 822 | 823 | yy_current_state = (yy_start); 824 | yy_match: 825 | do 826 | { 827 | YY_CHAR yy_c = yy_ec[YY_SC_TO_UI(*yy_cp)] ; 828 | if ( yy_accept[yy_current_state] ) 829 | { 830 | (yy_last_accepting_state) = yy_current_state; 831 | (yy_last_accepting_cpos) = yy_cp; 832 | } 833 | while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) 834 | { 835 | yy_current_state = (int) yy_def[yy_current_state]; 836 | if ( yy_current_state >= 169 ) 837 | yy_c = yy_meta[(unsigned int) yy_c]; 838 | } 839 | yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; 840 | ++yy_cp; 841 | } 842 | while ( yy_base[yy_current_state] != 221 ); 843 | 844 | yy_find_action: 845 | yy_act = yy_accept[yy_current_state]; 846 | if ( yy_act == 0 ) 847 | { /* have to back up */ 848 | yy_cp = (yy_last_accepting_cpos); 849 | yy_current_state = (yy_last_accepting_state); 850 | yy_act = yy_accept[yy_current_state]; 851 | } 852 | 853 | YY_DO_BEFORE_ACTION; 854 | 855 | do_action: /* This label is used only to access EOF actions. */ 856 | 857 | switch ( yy_act ) 858 | { /* beginning of action switch */ 859 | case 0: /* must back up */ 860 | /* undo the effects of YY_DO_BEFORE_ACTION */ 861 | *yy_cp = (yy_hold_char); 862 | yy_cp = (yy_last_accepting_cpos); 863 | yy_current_state = (yy_last_accepting_state); 864 | goto yy_find_action; 865 | 866 | case 1: 867 | /* rule 1 can match eol */ 868 | #line 15 "src/nsswitch.l" 869 | case 2: 870 | /* rule 2 can match eol */ 871 | YY_RULE_SETUP 872 | #line 15 "src/nsswitch.l" 873 | { BEGIN INITIAL; return '\n'; } 874 | YY_BREAK 875 | case 3: 876 | YY_RULE_SETUP 877 | #line 17 "src/nsswitch.l" 878 | { yylval.database = DB_ALIASES; BEGIN LIST; return TOK_DB; } 879 | YY_BREAK 880 | case 4: 881 | YY_RULE_SETUP 882 | #line 18 "src/nsswitch.l" 883 | { yylval.database = DB_ETHERS; BEGIN LIST; return TOK_DB; } 884 | YY_BREAK 885 | case 5: 886 | YY_RULE_SETUP 887 | #line 19 "src/nsswitch.l" 888 | { yylval.database = DB_GROUP; BEGIN LIST; return TOK_DB; } 889 | YY_BREAK 890 | case 6: 891 | YY_RULE_SETUP 892 | #line 20 "src/nsswitch.l" 893 | { yylval.database = DB_HOSTS; BEGIN LIST; return TOK_DB; } 894 | YY_BREAK 895 | case 7: 896 | YY_RULE_SETUP 897 | #line 21 "src/nsswitch.l" 898 | { yylval.database = DB_INITGROUPS; BEGIN LIST; return TOK_DB; } 899 | YY_BREAK 900 | case 8: 901 | YY_RULE_SETUP 902 | #line 22 "src/nsswitch.l" 903 | { yylval.database = DB_NETGROUP; BEGIN LIST; return TOK_DB; } 904 | YY_BREAK 905 | case 9: 906 | YY_RULE_SETUP 907 | #line 23 "src/nsswitch.l" 908 | { yylval.database = DB_NETWORKS; BEGIN LIST; return TOK_DB; } 909 | YY_BREAK 910 | case 10: 911 | YY_RULE_SETUP 912 | #line 24 "src/nsswitch.l" 913 | { yylval.database = DB_PASSWD; BEGIN LIST; return TOK_DB; } 914 | YY_BREAK 915 | case 11: 916 | YY_RULE_SETUP 917 | #line 25 "src/nsswitch.l" 918 | { yylval.database = DB_PROTOCOLS; BEGIN LIST; return TOK_DB; } 919 | YY_BREAK 920 | case 12: 921 | YY_RULE_SETUP 922 | #line 26 "src/nsswitch.l" 923 | { yylval.database = DB_PUBLICKEY; BEGIN LIST; return TOK_DB; } 924 | YY_BREAK 925 | case 13: 926 | YY_RULE_SETUP 927 | #line 27 "src/nsswitch.l" 928 | { yylval.database = DB_RPC; BEGIN LIST; return TOK_DB; } 929 | YY_BREAK 930 | case 14: 931 | YY_RULE_SETUP 932 | #line 28 "src/nsswitch.l" 933 | { yylval.database = DB_SERVICES; BEGIN LIST; return TOK_DB; } 934 | YY_BREAK 935 | case 15: 936 | YY_RULE_SETUP 937 | #line 29 "src/nsswitch.l" 938 | { yylval.database = DB_SHADOW; BEGIN LIST; return TOK_DB; } 939 | YY_BREAK 940 | case 16: 941 | YY_RULE_SETUP 942 | #line 31 "src/nsswitch.l" 943 | { BEGIN ACTION; return '['; } 944 | YY_BREAK 945 | case 17: 946 | YY_RULE_SETUP 947 | #line 32 "src/nsswitch.l" 948 | { 949 | yylval.str = strndup(yytext, yyleng); 950 | return TOK_STRING; 951 | } 952 | YY_BREAK 953 | case 18: 954 | YY_RULE_SETUP 955 | #line 36 "src/nsswitch.l" 956 | { ; } 957 | YY_BREAK 958 | case 19: 959 | YY_RULE_SETUP 960 | #line 38 "src/nsswitch.l" 961 | { return *yytext; } 962 | YY_BREAK 963 | case 20: 964 | YY_RULE_SETUP 965 | #line 39 "src/nsswitch.l" 966 | { BEGIN LIST; return *yytext; } 967 | YY_BREAK 968 | case 21: 969 | YY_RULE_SETUP 970 | #line 40 "src/nsswitch.l" 971 | { yylval.status = STS_SUCCESS; return TOK_STS; } 972 | YY_BREAK 973 | case 22: 974 | YY_RULE_SETUP 975 | #line 41 "src/nsswitch.l" 976 | { yylval.status = STS_NOTFOUND; return TOK_STS; } 977 | YY_BREAK 978 | case 23: 979 | YY_RULE_SETUP 980 | #line 42 "src/nsswitch.l" 981 | { yylval.status = STS_UNAVAIL; return TOK_STS; } 982 | YY_BREAK 983 | case 24: 984 | YY_RULE_SETUP 985 | #line 43 "src/nsswitch.l" 986 | { yylval.status = STS_TRYAGAIN; return TOK_STS; } 987 | YY_BREAK 988 | case 25: 989 | YY_RULE_SETUP 990 | #line 44 "src/nsswitch.l" 991 | { yylval.action = ACT_RETURN; return TOK_ACT; } 992 | YY_BREAK 993 | case 26: 994 | YY_RULE_SETUP 995 | #line 45 "src/nsswitch.l" 996 | { yylval.action = ACT_CONTINUE; return TOK_ACT; } 997 | YY_BREAK 998 | case 27: 999 | YY_RULE_SETUP 1000 | #line 46 "src/nsswitch.l" 1001 | { yylval.action = ACT_MERGE; return TOK_ACT; } 1002 | YY_BREAK 1003 | case 28: 1004 | YY_RULE_SETUP 1005 | #line 48 "src/nsswitch.l" 1006 | BEGIN COMMENT; 1007 | YY_BREAK 1008 | case 29: 1009 | YY_RULE_SETUP 1010 | #line 50 "src/nsswitch.l" 1011 | ; 1012 | YY_BREAK 1013 | case 30: 1014 | YY_RULE_SETUP 1015 | #line 52 "src/nsswitch.l" 1016 | return *yytext; 1017 | YY_BREAK 1018 | case 31: 1019 | YY_RULE_SETUP 1020 | #line 53 "src/nsswitch.l" 1021 | ECHO; 1022 | YY_BREAK 1023 | #line 1024 "" 1024 | case YY_STATE_EOF(INITIAL): 1025 | case YY_STATE_EOF(COMMENT): 1026 | case YY_STATE_EOF(LIST): 1027 | case YY_STATE_EOF(ACTION): 1028 | yyterminate(); 1029 | 1030 | case YY_END_OF_BUFFER: 1031 | { 1032 | /* Amount of text matched not including the EOB char. */ 1033 | int yy_amount_of_matched_text = (int) (yy_cp - (yytext_ptr)) - 1; 1034 | 1035 | /* Undo the effects of YY_DO_BEFORE_ACTION. */ 1036 | *yy_cp = (yy_hold_char); 1037 | YY_RESTORE_YY_MORE_OFFSET 1038 | 1039 | if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_NEW ) 1040 | { 1041 | /* We're scanning a new file or input source. It's 1042 | * possible that this happened because the user 1043 | * just pointed yyin at a new source and called 1044 | * yylex(). If so, then we have to assure 1045 | * consistency between YY_CURRENT_BUFFER and our 1046 | * globals. Here is the right place to do so, because 1047 | * this is the first action (other than possibly a 1048 | * back-up) that will match for the new input source. 1049 | */ 1050 | (yy_n_chars) = YY_CURRENT_BUFFER_LVALUE->yy_n_chars; 1051 | YY_CURRENT_BUFFER_LVALUE->yy_input_file = yyin; 1052 | YY_CURRENT_BUFFER_LVALUE->yy_buffer_status = YY_BUFFER_NORMAL; 1053 | } 1054 | 1055 | /* Note that here we test for yy_c_buf_p "<=" to the position 1056 | * of the first EOB in the buffer, since yy_c_buf_p will 1057 | * already have been incremented past the NUL character 1058 | * (since all states make transitions on EOB to the 1059 | * end-of-buffer state). Contrast this with the test 1060 | * in input(). 1061 | */ 1062 | if ( (yy_c_buf_p) <= &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] ) 1063 | { /* This was really a NUL. */ 1064 | yy_state_type yy_next_state; 1065 | 1066 | (yy_c_buf_p) = (yytext_ptr) + yy_amount_of_matched_text; 1067 | 1068 | yy_current_state = yy_get_previous_state( ); 1069 | 1070 | /* Okay, we're now positioned to make the NUL 1071 | * transition. We couldn't have 1072 | * yy_get_previous_state() go ahead and do it 1073 | * for us because it doesn't know how to deal 1074 | * with the possibility of jamming (and we don't 1075 | * want to build jamming into it because then it 1076 | * will run more slowly). 1077 | */ 1078 | 1079 | yy_next_state = yy_try_NUL_trans( yy_current_state ); 1080 | 1081 | yy_bp = (yytext_ptr) + YY_MORE_ADJ; 1082 | 1083 | if ( yy_next_state ) 1084 | { 1085 | /* Consume the NUL. */ 1086 | yy_cp = ++(yy_c_buf_p); 1087 | yy_current_state = yy_next_state; 1088 | goto yy_match; 1089 | } 1090 | 1091 | else 1092 | { 1093 | yy_cp = (yy_c_buf_p); 1094 | goto yy_find_action; 1095 | } 1096 | } 1097 | 1098 | else switch ( yy_get_next_buffer( ) ) 1099 | { 1100 | case EOB_ACT_END_OF_FILE: 1101 | { 1102 | (yy_did_buffer_switch_on_eof) = 0; 1103 | 1104 | if ( yywrap( ) ) 1105 | { 1106 | /* Note: because we've taken care in 1107 | * yy_get_next_buffer() to have set up 1108 | * yytext, we can now set up 1109 | * yy_c_buf_p so that if some total 1110 | * hoser (like flex itself) wants to 1111 | * call the scanner after we return the 1112 | * YY_NULL, it'll still work - another 1113 | * YY_NULL will get returned. 1114 | */ 1115 | (yy_c_buf_p) = (yytext_ptr) + YY_MORE_ADJ; 1116 | 1117 | yy_act = YY_STATE_EOF(YY_START); 1118 | goto do_action; 1119 | } 1120 | 1121 | else 1122 | { 1123 | if ( ! (yy_did_buffer_switch_on_eof) ) 1124 | YY_NEW_FILE; 1125 | } 1126 | break; 1127 | } 1128 | 1129 | case EOB_ACT_CONTINUE_SCAN: 1130 | (yy_c_buf_p) = 1131 | (yytext_ptr) + yy_amount_of_matched_text; 1132 | 1133 | yy_current_state = yy_get_previous_state( ); 1134 | 1135 | yy_cp = (yy_c_buf_p); 1136 | yy_bp = (yytext_ptr) + YY_MORE_ADJ; 1137 | goto yy_match; 1138 | 1139 | case EOB_ACT_LAST_MATCH: 1140 | (yy_c_buf_p) = 1141 | &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)]; 1142 | 1143 | yy_current_state = yy_get_previous_state( ); 1144 | 1145 | yy_cp = (yy_c_buf_p); 1146 | yy_bp = (yytext_ptr) + YY_MORE_ADJ; 1147 | goto yy_find_action; 1148 | } 1149 | break; 1150 | } 1151 | 1152 | default: 1153 | YY_FATAL_ERROR( 1154 | "fatal flex scanner internal error--no action found" ); 1155 | } /* end of action switch */ 1156 | } /* end of scanning one token */ 1157 | } /* end of user's declarations */ 1158 | } /* end of yylex */ 1159 | 1160 | /* yy_get_next_buffer - try to read in a new buffer 1161 | * 1162 | * Returns a code representing an action: 1163 | * EOB_ACT_LAST_MATCH - 1164 | * EOB_ACT_CONTINUE_SCAN - continue scanning from current position 1165 | * EOB_ACT_END_OF_FILE - end of file 1166 | */ 1167 | static int yy_get_next_buffer (void) 1168 | { 1169 | char *dest = YY_CURRENT_BUFFER_LVALUE->yy_ch_buf; 1170 | char *source = (yytext_ptr); 1171 | yy_size_t number_to_move, i; 1172 | int ret_val; 1173 | 1174 | if ( (yy_c_buf_p) > &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars) + 1] ) 1175 | YY_FATAL_ERROR( 1176 | "fatal flex scanner internal error--end of buffer missed" ); 1177 | 1178 | if ( YY_CURRENT_BUFFER_LVALUE->yy_fill_buffer == 0 ) 1179 | { /* Don't try to fill the buffer, so this is an EOF. */ 1180 | if ( (yy_c_buf_p) - (yytext_ptr) - YY_MORE_ADJ == 1 ) 1181 | { 1182 | /* We matched a single character, the EOB, so 1183 | * treat this as a final EOF. 1184 | */ 1185 | return EOB_ACT_END_OF_FILE; 1186 | } 1187 | 1188 | else 1189 | { 1190 | /* We matched some text prior to the EOB, first 1191 | * process it. 1192 | */ 1193 | return EOB_ACT_LAST_MATCH; 1194 | } 1195 | } 1196 | 1197 | /* Try to read more data. */ 1198 | 1199 | /* First move last chars to start of buffer. */ 1200 | number_to_move = (yy_size_t) ((yy_c_buf_p) - (yytext_ptr)) - 1; 1201 | 1202 | for ( i = 0; i < number_to_move; ++i ) 1203 | *(dest++) = *(source++); 1204 | 1205 | if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_EOF_PENDING ) 1206 | /* don't do the read, it's not guaranteed to return an EOF, 1207 | * just force an EOF 1208 | */ 1209 | YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars) = 0; 1210 | 1211 | else 1212 | { 1213 | yy_size_t num_to_read = 1214 | YY_CURRENT_BUFFER_LVALUE->yy_buf_size - number_to_move - 1; 1215 | 1216 | while ( num_to_read <= 0 ) 1217 | { /* Not enough room in the buffer - grow it. */ 1218 | 1219 | /* just a shorter name for the current buffer */ 1220 | YY_BUFFER_STATE b = YY_CURRENT_BUFFER_LVALUE; 1221 | 1222 | int yy_c_buf_p_offset = 1223 | (int) ((yy_c_buf_p) - b->yy_ch_buf); 1224 | 1225 | if ( b->yy_is_our_buffer ) 1226 | { 1227 | yy_size_t new_size = b->yy_buf_size * 2; 1228 | 1229 | if ( new_size <= 0 ) 1230 | b->yy_buf_size += b->yy_buf_size / 8; 1231 | else 1232 | b->yy_buf_size *= 2; 1233 | 1234 | b->yy_ch_buf = (char *) 1235 | /* Include room in for 2 EOB chars. */ 1236 | yyrealloc((void *) b->yy_ch_buf,b->yy_buf_size + 2 ); 1237 | } 1238 | else 1239 | /* Can't grow it, we don't own it. */ 1240 | b->yy_ch_buf = 0; 1241 | 1242 | if ( ! b->yy_ch_buf ) 1243 | YY_FATAL_ERROR( 1244 | "fatal error - scanner input buffer overflow" ); 1245 | 1246 | (yy_c_buf_p) = &b->yy_ch_buf[yy_c_buf_p_offset]; 1247 | 1248 | num_to_read = YY_CURRENT_BUFFER_LVALUE->yy_buf_size - 1249 | number_to_move - 1; 1250 | 1251 | } 1252 | 1253 | if ( num_to_read > YY_READ_BUF_SIZE ) 1254 | num_to_read = YY_READ_BUF_SIZE; 1255 | 1256 | /* Read in more data. */ 1257 | YY_INPUT( (&YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move]), 1258 | (yy_n_chars), num_to_read ); 1259 | 1260 | YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars); 1261 | } 1262 | 1263 | if ( (yy_n_chars) == 0 ) 1264 | { 1265 | if ( number_to_move == YY_MORE_ADJ ) 1266 | { 1267 | ret_val = EOB_ACT_END_OF_FILE; 1268 | yyrestart(yyin ); 1269 | } 1270 | 1271 | else 1272 | { 1273 | ret_val = EOB_ACT_LAST_MATCH; 1274 | YY_CURRENT_BUFFER_LVALUE->yy_buffer_status = 1275 | YY_BUFFER_EOF_PENDING; 1276 | } 1277 | } 1278 | 1279 | else 1280 | ret_val = EOB_ACT_CONTINUE_SCAN; 1281 | 1282 | if ((int) ((yy_n_chars) + number_to_move) > YY_CURRENT_BUFFER_LVALUE->yy_buf_size) { 1283 | /* Extend the array by 50%, plus the number we really need. */ 1284 | int new_size = (yy_n_chars) + number_to_move + ((yy_n_chars) >> 1); 1285 | YY_CURRENT_BUFFER_LVALUE->yy_ch_buf = (char *) yyrealloc((void *) YY_CURRENT_BUFFER_LVALUE->yy_ch_buf,new_size ); 1286 | if ( ! YY_CURRENT_BUFFER_LVALUE->yy_ch_buf ) 1287 | YY_FATAL_ERROR( "out of dynamic memory in yy_get_next_buffer()" ); 1288 | } 1289 | 1290 | (yy_n_chars) += number_to_move; 1291 | YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] = YY_END_OF_BUFFER_CHAR; 1292 | YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars) + 1] = YY_END_OF_BUFFER_CHAR; 1293 | 1294 | (yytext_ptr) = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[0]; 1295 | 1296 | return ret_val; 1297 | } 1298 | 1299 | /* yy_get_previous_state - get the state just before the EOB char was reached */ 1300 | 1301 | static yy_state_type yy_get_previous_state (void) 1302 | { 1303 | yy_state_type yy_current_state; 1304 | char *yy_cp; 1305 | 1306 | yy_current_state = (yy_start); 1307 | 1308 | for ( yy_cp = (yytext_ptr) + YY_MORE_ADJ; yy_cp < (yy_c_buf_p); ++yy_cp ) 1309 | { 1310 | YY_CHAR yy_c = (*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : 1); 1311 | if ( yy_accept[yy_current_state] ) 1312 | { 1313 | (yy_last_accepting_state) = yy_current_state; 1314 | (yy_last_accepting_cpos) = yy_cp; 1315 | } 1316 | while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) 1317 | { 1318 | yy_current_state = (int) yy_def[yy_current_state]; 1319 | if ( yy_current_state >= 169 ) 1320 | yy_c = yy_meta[(unsigned int) yy_c]; 1321 | } 1322 | yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; 1323 | } 1324 | 1325 | return yy_current_state; 1326 | } 1327 | 1328 | /* yy_try_NUL_trans - try to make a transition on the NUL character 1329 | * 1330 | * synopsis 1331 | * next_state = yy_try_NUL_trans( current_state ); 1332 | */ 1333 | static yy_state_type yy_try_NUL_trans (yy_state_type yy_current_state ) 1334 | { 1335 | int yy_is_jam; 1336 | char *yy_cp = (yy_c_buf_p); 1337 | 1338 | YY_CHAR yy_c = 1; 1339 | if ( yy_accept[yy_current_state] ) 1340 | { 1341 | (yy_last_accepting_state) = yy_current_state; 1342 | (yy_last_accepting_cpos) = yy_cp; 1343 | } 1344 | while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) 1345 | { 1346 | yy_current_state = (int) yy_def[yy_current_state]; 1347 | if ( yy_current_state >= 169 ) 1348 | yy_c = yy_meta[(unsigned int) yy_c]; 1349 | } 1350 | yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; 1351 | yy_is_jam = (yy_current_state == 168); 1352 | 1353 | return yy_is_jam ? 0 : yy_current_state; 1354 | } 1355 | 1356 | #ifndef YY_NO_UNPUT 1357 | 1358 | static void yyunput (int c, char * yy_bp ) 1359 | { 1360 | char *yy_cp; 1361 | 1362 | yy_cp = (yy_c_buf_p); 1363 | 1364 | /* undo effects of setting up yytext */ 1365 | *yy_cp = (yy_hold_char); 1366 | 1367 | if ( yy_cp < YY_CURRENT_BUFFER_LVALUE->yy_ch_buf + 2 ) 1368 | { /* need to shift things up to make room */ 1369 | /* +2 for EOB chars. */ 1370 | yy_size_t number_to_move = (yy_n_chars) + 2; 1371 | char *dest = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[ 1372 | YY_CURRENT_BUFFER_LVALUE->yy_buf_size + 2]; 1373 | char *source = 1374 | &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move]; 1375 | 1376 | while ( source > YY_CURRENT_BUFFER_LVALUE->yy_ch_buf ) 1377 | *--dest = *--source; 1378 | 1379 | yy_cp += (int) (dest - source); 1380 | yy_bp += (int) (dest - source); 1381 | YY_CURRENT_BUFFER_LVALUE->yy_n_chars = 1382 | (yy_n_chars) = YY_CURRENT_BUFFER_LVALUE->yy_buf_size; 1383 | 1384 | if ( yy_cp < YY_CURRENT_BUFFER_LVALUE->yy_ch_buf + 2 ) 1385 | YY_FATAL_ERROR( "flex scanner push-back overflow" ); 1386 | } 1387 | 1388 | *--yy_cp = (char) c; 1389 | 1390 | (yytext_ptr) = yy_bp; 1391 | (yy_hold_char) = *yy_cp; 1392 | (yy_c_buf_p) = yy_cp; 1393 | } 1394 | 1395 | #endif 1396 | 1397 | #ifndef YY_NO_INPUT 1398 | #ifdef __cplusplus 1399 | static int yyinput (void) 1400 | #else 1401 | static int input (void) 1402 | #endif 1403 | 1404 | { 1405 | int c; 1406 | 1407 | *(yy_c_buf_p) = (yy_hold_char); 1408 | 1409 | if ( *(yy_c_buf_p) == YY_END_OF_BUFFER_CHAR ) 1410 | { 1411 | /* yy_c_buf_p now points to the character we want to return. 1412 | * If this occurs *before* the EOB characters, then it's a 1413 | * valid NUL; if not, then we've hit the end of the buffer. 1414 | */ 1415 | if ( (yy_c_buf_p) < &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] ) 1416 | /* This was really a NUL. */ 1417 | *(yy_c_buf_p) = '\0'; 1418 | 1419 | else 1420 | { /* need more input */ 1421 | yy_size_t offset = (yy_c_buf_p) - (yytext_ptr); 1422 | ++(yy_c_buf_p); 1423 | 1424 | switch ( yy_get_next_buffer( ) ) 1425 | { 1426 | case EOB_ACT_LAST_MATCH: 1427 | /* This happens because yy_g_n_b() 1428 | * sees that we've accumulated a 1429 | * token and flags that we need to 1430 | * try matching the token before 1431 | * proceeding. But for input(), 1432 | * there's no matching to consider. 1433 | * So convert the EOB_ACT_LAST_MATCH 1434 | * to EOB_ACT_END_OF_FILE. 1435 | */ 1436 | 1437 | /* Reset buffer status. */ 1438 | yyrestart(yyin ); 1439 | 1440 | /*FALLTHROUGH*/ 1441 | 1442 | case EOB_ACT_END_OF_FILE: 1443 | { 1444 | if ( yywrap( ) ) 1445 | return EOF; 1446 | 1447 | if ( ! (yy_did_buffer_switch_on_eof) ) 1448 | YY_NEW_FILE; 1449 | #ifdef __cplusplus 1450 | return yyinput(); 1451 | #else 1452 | return input(); 1453 | #endif 1454 | } 1455 | 1456 | case EOB_ACT_CONTINUE_SCAN: 1457 | (yy_c_buf_p) = (yytext_ptr) + offset; 1458 | break; 1459 | } 1460 | } 1461 | } 1462 | 1463 | c = *(unsigned char *) (yy_c_buf_p); /* cast for 8-bit char's */ 1464 | *(yy_c_buf_p) = '\0'; /* preserve yytext */ 1465 | (yy_hold_char) = *++(yy_c_buf_p); 1466 | 1467 | return c; 1468 | } 1469 | #endif /* ifndef YY_NO_INPUT */ 1470 | 1471 | /** Immediately switch to a different input stream. 1472 | * @param input_file A readable stream. 1473 | * 1474 | * @note This function does not reset the start condition to @c INITIAL . 1475 | */ 1476 | void yyrestart (FILE * input_file ) 1477 | { 1478 | 1479 | if ( ! YY_CURRENT_BUFFER ){ 1480 | yyensure_buffer_stack (); 1481 | YY_CURRENT_BUFFER_LVALUE = 1482 | yy_create_buffer(yyin,YY_BUF_SIZE ); 1483 | } 1484 | 1485 | yy_init_buffer(YY_CURRENT_BUFFER,input_file ); 1486 | yy_load_buffer_state( ); 1487 | } 1488 | 1489 | /** Switch to a different input buffer. 1490 | * @param new_buffer The new input buffer. 1491 | * 1492 | */ 1493 | void yy_switch_to_buffer (YY_BUFFER_STATE new_buffer ) 1494 | { 1495 | 1496 | /* TODO. We should be able to replace this entire function body 1497 | * with 1498 | * yypop_buffer_state(); 1499 | * yypush_buffer_state(new_buffer); 1500 | */ 1501 | yyensure_buffer_stack (); 1502 | if ( YY_CURRENT_BUFFER == new_buffer ) 1503 | return; 1504 | 1505 | if ( YY_CURRENT_BUFFER ) 1506 | { 1507 | /* Flush out information for old buffer. */ 1508 | *(yy_c_buf_p) = (yy_hold_char); 1509 | YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = (yy_c_buf_p); 1510 | YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars); 1511 | } 1512 | 1513 | YY_CURRENT_BUFFER_LVALUE = new_buffer; 1514 | yy_load_buffer_state( ); 1515 | 1516 | /* We don't actually know whether we did this switch during 1517 | * EOF (yywrap()) processing, but the only time this flag 1518 | * is looked at is after yywrap() is called, so it's safe 1519 | * to go ahead and always set it. 1520 | */ 1521 | (yy_did_buffer_switch_on_eof) = 1; 1522 | } 1523 | 1524 | static void yy_load_buffer_state (void) 1525 | { 1526 | (yy_n_chars) = YY_CURRENT_BUFFER_LVALUE->yy_n_chars; 1527 | (yytext_ptr) = (yy_c_buf_p) = YY_CURRENT_BUFFER_LVALUE->yy_buf_pos; 1528 | yyin = YY_CURRENT_BUFFER_LVALUE->yy_input_file; 1529 | (yy_hold_char) = *(yy_c_buf_p); 1530 | } 1531 | 1532 | /** Allocate and initialize an input buffer state. 1533 | * @param file A readable stream. 1534 | * @param size The character buffer size in bytes. When in doubt, use @c YY_BUF_SIZE. 1535 | * 1536 | * @return the allocated buffer state. 1537 | */ 1538 | YY_BUFFER_STATE yy_create_buffer (FILE * file, int size ) 1539 | { 1540 | YY_BUFFER_STATE b; 1541 | 1542 | b = (YY_BUFFER_STATE) yyalloc(sizeof( struct yy_buffer_state ) ); 1543 | if ( ! b ) 1544 | YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" ); 1545 | 1546 | b->yy_buf_size = (yy_size_t)size; 1547 | 1548 | /* yy_ch_buf has to be 2 characters longer than the size given because 1549 | * we need to put in 2 end-of-buffer characters. 1550 | */ 1551 | b->yy_ch_buf = (char *) yyalloc(b->yy_buf_size + 2 ); 1552 | if ( ! b->yy_ch_buf ) 1553 | YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" ); 1554 | 1555 | b->yy_is_our_buffer = 1; 1556 | 1557 | yy_init_buffer(b,file ); 1558 | 1559 | return b; 1560 | } 1561 | 1562 | /** Destroy the buffer. 1563 | * @param b a buffer created with yy_create_buffer() 1564 | * 1565 | */ 1566 | void yy_delete_buffer (YY_BUFFER_STATE b ) 1567 | { 1568 | 1569 | if ( ! b ) 1570 | return; 1571 | 1572 | if ( b == YY_CURRENT_BUFFER ) /* Not sure if we should pop here. */ 1573 | YY_CURRENT_BUFFER_LVALUE = (YY_BUFFER_STATE) 0; 1574 | 1575 | if ( b->yy_is_our_buffer ) 1576 | yyfree((void *) b->yy_ch_buf ); 1577 | 1578 | yyfree((void *) b ); 1579 | } 1580 | 1581 | /* Initializes or reinitializes a buffer. 1582 | * This function is sometimes called more than once on the same buffer, 1583 | * such as during a yyrestart() or at EOF. 1584 | */ 1585 | static void yy_init_buffer (YY_BUFFER_STATE b, FILE * file ) 1586 | 1587 | { 1588 | int oerrno = errno; 1589 | 1590 | yy_flush_buffer(b ); 1591 | 1592 | b->yy_input_file = file; 1593 | b->yy_fill_buffer = 1; 1594 | 1595 | /* If b is the current buffer, then yy_init_buffer was _probably_ 1596 | * called from yyrestart() or through yy_get_next_buffer. 1597 | * In that case, we don't want to reset the lineno or column. 1598 | */ 1599 | if (b != YY_CURRENT_BUFFER){ 1600 | b->yy_bs_lineno = 1; 1601 | b->yy_bs_column = 0; 1602 | } 1603 | 1604 | b->yy_is_interactive = file ? (isatty( fileno(file) ) > 0) : 0; 1605 | 1606 | errno = oerrno; 1607 | } 1608 | 1609 | /** Discard all buffered characters. On the next scan, YY_INPUT will be called. 1610 | * @param b the buffer state to be flushed, usually @c YY_CURRENT_BUFFER. 1611 | * 1612 | */ 1613 | void yy_flush_buffer (YY_BUFFER_STATE b ) 1614 | { 1615 | if ( ! b ) 1616 | return; 1617 | 1618 | b->yy_n_chars = 0; 1619 | 1620 | /* We always need two end-of-buffer characters. The first causes 1621 | * a transition to the end-of-buffer state. The second causes 1622 | * a jam in that state. 1623 | */ 1624 | b->yy_ch_buf[0] = YY_END_OF_BUFFER_CHAR; 1625 | b->yy_ch_buf[1] = YY_END_OF_BUFFER_CHAR; 1626 | 1627 | b->yy_buf_pos = &b->yy_ch_buf[0]; 1628 | 1629 | b->yy_at_bol = 1; 1630 | b->yy_buffer_status = YY_BUFFER_NEW; 1631 | 1632 | if ( b == YY_CURRENT_BUFFER ) 1633 | yy_load_buffer_state( ); 1634 | } 1635 | 1636 | /** Pushes the new state onto the stack. The new state becomes 1637 | * the current state. This function will allocate the stack 1638 | * if necessary. 1639 | * @param new_buffer The new state. 1640 | * 1641 | */ 1642 | void yypush_buffer_state (YY_BUFFER_STATE new_buffer ) 1643 | { 1644 | if (new_buffer == NULL) 1645 | return; 1646 | 1647 | yyensure_buffer_stack(); 1648 | 1649 | /* This block is copied from yy_switch_to_buffer. */ 1650 | if ( YY_CURRENT_BUFFER ) 1651 | { 1652 | /* Flush out information for old buffer. */ 1653 | *(yy_c_buf_p) = (yy_hold_char); 1654 | YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = (yy_c_buf_p); 1655 | YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars); 1656 | } 1657 | 1658 | /* Only push if top exists. Otherwise, replace top. */ 1659 | if (YY_CURRENT_BUFFER) 1660 | (yy_buffer_stack_top)++; 1661 | YY_CURRENT_BUFFER_LVALUE = new_buffer; 1662 | 1663 | /* copied from yy_switch_to_buffer. */ 1664 | yy_load_buffer_state( ); 1665 | (yy_did_buffer_switch_on_eof) = 1; 1666 | } 1667 | 1668 | /** Removes and deletes the top of the stack, if present. 1669 | * The next element becomes the new top. 1670 | * 1671 | */ 1672 | void yypop_buffer_state (void) 1673 | { 1674 | if (!YY_CURRENT_BUFFER) 1675 | return; 1676 | 1677 | yy_delete_buffer(YY_CURRENT_BUFFER ); 1678 | YY_CURRENT_BUFFER_LVALUE = NULL; 1679 | if ((yy_buffer_stack_top) > 0) 1680 | --(yy_buffer_stack_top); 1681 | 1682 | if (YY_CURRENT_BUFFER) { 1683 | yy_load_buffer_state( ); 1684 | (yy_did_buffer_switch_on_eof) = 1; 1685 | } 1686 | } 1687 | 1688 | /* Allocates the stack if it does not exist. 1689 | * Guarantees space for at least one push. 1690 | */ 1691 | static void yyensure_buffer_stack (void) 1692 | { 1693 | yy_size_t num_to_alloc; 1694 | 1695 | if (!(yy_buffer_stack)) { 1696 | 1697 | /* First allocation is just for 2 elements, since we don't know if this 1698 | * scanner will even need a stack. We use 2 instead of 1 to avoid an 1699 | * immediate realloc on the next call. 1700 | */ 1701 | num_to_alloc = 1; /* After all that talk, this was set to 1 anyways... */ 1702 | (yy_buffer_stack) = (struct yy_buffer_state**)yyalloc 1703 | (num_to_alloc * sizeof(struct yy_buffer_state*) 1704 | ); 1705 | if ( ! (yy_buffer_stack) ) 1706 | YY_FATAL_ERROR( "out of dynamic memory in yyensure_buffer_stack()" ); 1707 | 1708 | memset((yy_buffer_stack), 0, num_to_alloc * sizeof(struct yy_buffer_state*)); 1709 | 1710 | (yy_buffer_stack_max) = num_to_alloc; 1711 | (yy_buffer_stack_top) = 0; 1712 | return; 1713 | } 1714 | 1715 | if ((yy_buffer_stack_top) >= ((yy_buffer_stack_max)) - 1){ 1716 | 1717 | /* Increase the buffer to prepare for a possible push. */ 1718 | yy_size_t grow_size = 8 /* arbitrary grow size */; 1719 | 1720 | num_to_alloc = (yy_buffer_stack_max) + grow_size; 1721 | (yy_buffer_stack) = (struct yy_buffer_state**)yyrealloc 1722 | ((yy_buffer_stack), 1723 | num_to_alloc * sizeof(struct yy_buffer_state*) 1724 | ); 1725 | if ( ! (yy_buffer_stack) ) 1726 | YY_FATAL_ERROR( "out of dynamic memory in yyensure_buffer_stack()" ); 1727 | 1728 | /* zero only the new slots.*/ 1729 | memset((yy_buffer_stack) + (yy_buffer_stack_max), 0, grow_size * sizeof(struct yy_buffer_state*)); 1730 | (yy_buffer_stack_max) = num_to_alloc; 1731 | } 1732 | } 1733 | 1734 | /** Setup the input buffer state to scan directly from a user-specified character buffer. 1735 | * @param base the character buffer 1736 | * @param size the size in bytes of the character buffer 1737 | * 1738 | * @return the newly allocated buffer state object. 1739 | */ 1740 | YY_BUFFER_STATE yy_scan_buffer (char * base, yy_size_t size ) 1741 | { 1742 | YY_BUFFER_STATE b; 1743 | 1744 | if ( size < 2 || 1745 | base[size-2] != YY_END_OF_BUFFER_CHAR || 1746 | base[size-1] != YY_END_OF_BUFFER_CHAR ) 1747 | /* They forgot to leave room for the EOB's. */ 1748 | return 0; 1749 | 1750 | b = (YY_BUFFER_STATE) yyalloc(sizeof( struct yy_buffer_state ) ); 1751 | if ( ! b ) 1752 | YY_FATAL_ERROR( "out of dynamic memory in yy_scan_buffer()" ); 1753 | 1754 | b->yy_buf_size = size - 2; /* "- 2" to take care of EOB's */ 1755 | b->yy_buf_pos = b->yy_ch_buf = base; 1756 | b->yy_is_our_buffer = 0; 1757 | b->yy_input_file = 0; 1758 | b->yy_n_chars = b->yy_buf_size; 1759 | b->yy_is_interactive = 0; 1760 | b->yy_at_bol = 1; 1761 | b->yy_fill_buffer = 0; 1762 | b->yy_buffer_status = YY_BUFFER_NEW; 1763 | 1764 | yy_switch_to_buffer(b ); 1765 | 1766 | return b; 1767 | } 1768 | 1769 | /** Setup the input buffer state to scan a string. The next call to yylex() will 1770 | * scan from a @e copy of @a str. 1771 | * @param yystr a NUL-terminated string to scan 1772 | * 1773 | * @return the newly allocated buffer state object. 1774 | * @note If you want to scan bytes that may contain NUL values, then use 1775 | * yy_scan_bytes() instead. 1776 | */ 1777 | YY_BUFFER_STATE yy_scan_string (yyconst char * yystr ) 1778 | { 1779 | 1780 | return yy_scan_bytes(yystr,strlen(yystr) ); 1781 | } 1782 | 1783 | /** Setup the input buffer state to scan the given bytes. The next call to yylex() will 1784 | * scan from a @e copy of @a bytes. 1785 | * @param yybytes the byte buffer to scan 1786 | * @param _yybytes_len the number of bytes in the buffer pointed to by @a bytes. 1787 | * 1788 | * @return the newly allocated buffer state object. 1789 | */ 1790 | YY_BUFFER_STATE yy_scan_bytes (yyconst char * yybytes, yy_size_t _yybytes_len ) 1791 | { 1792 | YY_BUFFER_STATE b; 1793 | char *buf; 1794 | yy_size_t n; 1795 | yy_size_t i; 1796 | 1797 | /* Get memory for full buffer, including space for trailing EOB's. */ 1798 | n = _yybytes_len + 2; 1799 | buf = (char *) yyalloc(n ); 1800 | if ( ! buf ) 1801 | YY_FATAL_ERROR( "out of dynamic memory in yy_scan_bytes()" ); 1802 | 1803 | for ( i = 0; i < _yybytes_len; ++i ) 1804 | buf[i] = yybytes[i]; 1805 | 1806 | buf[_yybytes_len] = buf[_yybytes_len+1] = YY_END_OF_BUFFER_CHAR; 1807 | 1808 | b = yy_scan_buffer(buf,n ); 1809 | if ( ! b ) 1810 | YY_FATAL_ERROR( "bad buffer in yy_scan_bytes()" ); 1811 | 1812 | /* It's okay to grow etc. this buffer, and we should throw it 1813 | * away when we're done. 1814 | */ 1815 | b->yy_is_our_buffer = 1; 1816 | 1817 | return b; 1818 | } 1819 | 1820 | #ifndef YY_EXIT_FAILURE 1821 | #define YY_EXIT_FAILURE 2 1822 | #endif 1823 | 1824 | static void yy_fatal_error (yyconst char* msg ) 1825 | { 1826 | (void) fprintf( stderr, "%s\n", msg ); 1827 | exit( YY_EXIT_FAILURE ); 1828 | } 1829 | 1830 | /* Redefine yyless() so it works in section 3 code. */ 1831 | 1832 | #undef yyless 1833 | #define yyless(n) \ 1834 | do \ 1835 | { \ 1836 | /* Undo effects of setting up yytext. */ \ 1837 | int yyless_macro_arg = (n); \ 1838 | YY_LESS_LINENO(yyless_macro_arg);\ 1839 | yytext[yyleng] = (yy_hold_char); \ 1840 | (yy_c_buf_p) = yytext + yyless_macro_arg; \ 1841 | (yy_hold_char) = *(yy_c_buf_p); \ 1842 | *(yy_c_buf_p) = '\0'; \ 1843 | yyleng = yyless_macro_arg; \ 1844 | } \ 1845 | while ( 0 ) 1846 | 1847 | /* Accessor methods (get/set functions) to struct members. */ 1848 | 1849 | /** Get the current line number. 1850 | * 1851 | */ 1852 | int yyget_lineno (void) 1853 | { 1854 | 1855 | return yylineno; 1856 | } 1857 | 1858 | /** Get the input stream. 1859 | * 1860 | */ 1861 | FILE *yyget_in (void) 1862 | { 1863 | return yyin; 1864 | } 1865 | 1866 | /** Get the output stream. 1867 | * 1868 | */ 1869 | FILE *yyget_out (void) 1870 | { 1871 | return yyout; 1872 | } 1873 | 1874 | /** Get the length of the current token. 1875 | * 1876 | */ 1877 | yy_size_t yyget_leng (void) 1878 | { 1879 | return yyleng; 1880 | } 1881 | 1882 | /** Get the current token. 1883 | * 1884 | */ 1885 | 1886 | char *yyget_text (void) 1887 | { 1888 | return yytext; 1889 | } 1890 | 1891 | /** Set the current line number. 1892 | * @param _line_number line number 1893 | * 1894 | */ 1895 | void yyset_lineno (int _line_number ) 1896 | { 1897 | 1898 | yylineno = _line_number; 1899 | } 1900 | 1901 | /** Set the input stream. This does not discard the current 1902 | * input buffer. 1903 | * @param _in_str A readable stream. 1904 | * 1905 | * @see yy_switch_to_buffer 1906 | */ 1907 | void yyset_in (FILE * _in_str ) 1908 | { 1909 | yyin = _in_str ; 1910 | } 1911 | 1912 | void yyset_out (FILE * _out_str ) 1913 | { 1914 | yyout = _out_str ; 1915 | } 1916 | 1917 | int yyget_debug (void) 1918 | { 1919 | return yy_flex_debug; 1920 | } 1921 | 1922 | void yyset_debug (int _bdebug ) 1923 | { 1924 | yy_flex_debug = _bdebug ; 1925 | } 1926 | 1927 | static int yy_init_globals (void) 1928 | { 1929 | /* Initialization is the same as for the non-reentrant scanner. 1930 | * This function is called from yylex_destroy(), so don't allocate here. 1931 | */ 1932 | 1933 | (yy_buffer_stack) = 0; 1934 | (yy_buffer_stack_top) = 0; 1935 | (yy_buffer_stack_max) = 0; 1936 | (yy_c_buf_p) = (char *) 0; 1937 | (yy_init) = 0; 1938 | (yy_start) = 0; 1939 | 1940 | /* Defined in main.c */ 1941 | #ifdef YY_STDINIT 1942 | yyin = stdin; 1943 | yyout = stdout; 1944 | #else 1945 | yyin = (FILE *) 0; 1946 | yyout = (FILE *) 0; 1947 | #endif 1948 | 1949 | /* For future reference: Set errno on error, since we are called by 1950 | * yylex_init() 1951 | */ 1952 | return 0; 1953 | } 1954 | 1955 | /* yylex_destroy is for both reentrant and non-reentrant scanners. */ 1956 | int yylex_destroy (void) 1957 | { 1958 | 1959 | /* Pop the buffer stack, destroying each element. */ 1960 | while(YY_CURRENT_BUFFER){ 1961 | yy_delete_buffer(YY_CURRENT_BUFFER ); 1962 | YY_CURRENT_BUFFER_LVALUE = NULL; 1963 | yypop_buffer_state(); 1964 | } 1965 | 1966 | /* Destroy the stack itself. */ 1967 | yyfree((yy_buffer_stack) ); 1968 | (yy_buffer_stack) = NULL; 1969 | 1970 | /* Reset the globals. This is important in a non-reentrant scanner so the next time 1971 | * yylex() is called, initialization will occur. */ 1972 | yy_init_globals( ); 1973 | 1974 | return 0; 1975 | } 1976 | 1977 | /* 1978 | * Internal utility routines. 1979 | */ 1980 | 1981 | #ifndef yytext_ptr 1982 | static void yy_flex_strncpy (char* s1, yyconst char * s2, int n ) 1983 | { 1984 | 1985 | int i; 1986 | for ( i = 0; i < n; ++i ) 1987 | s1[i] = s2[i]; 1988 | } 1989 | #endif 1990 | 1991 | #ifdef YY_NEED_STRLEN 1992 | static int yy_flex_strlen (yyconst char * s ) 1993 | { 1994 | int n; 1995 | for ( n = 0; s[n]; ++n ) 1996 | ; 1997 | 1998 | return n; 1999 | } 2000 | #endif 2001 | 2002 | void *yyalloc (yy_size_t size ) 2003 | { 2004 | return (void *) malloc( size ); 2005 | } 2006 | 2007 | void *yyrealloc (void * ptr, yy_size_t size ) 2008 | { 2009 | 2010 | /* The cast to (char *) in the following accommodates both 2011 | * implementations that use char* generic pointers, and those 2012 | * that use void* generic pointers. It works with the latter 2013 | * because both ANSI C and C++ allow castless assignment from 2014 | * any pointer type to void*, and deal with argument conversions 2015 | * as though doing an assignment. 2016 | */ 2017 | return (void *) realloc( (char *) ptr, size ); 2018 | } 2019 | 2020 | void yyfree (void * ptr ) 2021 | { 2022 | free( (char *) ptr ); /* see yyrealloc() for (char *) cast */ 2023 | } 2024 | 2025 | #define YYTABLES_NAME "yytables" 2026 | 2027 | #line 53 "src/nsswitch.l" 2028 | 2029 | 2030 | 2031 | int yywrap(void) 2032 | { 2033 | return 1; 2034 | } 2035 | 2036 | -------------------------------------------------------------------------------- /include/cache_add.h: -------------------------------------------------------------------------------- 1 | /* This code is written this way in order to implement polimorphism: the struct 2 | * passwd and struct group caches are implemented in exactly the same way, the 3 | * only difference being the name of struct members and struct layout. 4 | * 5 | * The function to add values into the cache will #include this file in its 6 | * body, after defining the necessary macros: 7 | * - CACHE: name of the cache for that struct 8 | * - RESULT_TYPE: the type of a result stored in the cache 9 | * - HASH_ARG: the argument that will be passed to the hashing function, if 10 | * any 11 | * - COMPARISON: the equality check to determine if the entry being added to 12 | * cache is listed in it already 13 | * - ARGUMENT: the name of the struct member holding the struct passwd or 14 | * struct group being used 15 | */ 16 | 17 | IS_CACHING_FOR_WRITE(b); 18 | 19 | int ret = 0; 20 | /* variables for dealing with duplicates */ 21 | size_t i; 22 | bool found_outdated = false; 23 | 24 | /* studying the effects of contention on this lock might be important */ 25 | pthread_rwlock_wrlock(&CACHE.lock); 26 | 27 | /* since we can't initialize oldest to the maximum value of time_t, because it 28 | * doesn't exist, initialize it with the first entry (if there is a first entry 29 | * at all) */ 30 | time_t oldest = CACHE.len > 0 ? CACHE.res[0].t : 0; 31 | size_t oldest_i = 0; 32 | bool found_invalid = false; 33 | 34 | /* check if the new value hasn't been added by another thread */ 35 | time_t now = monotonic_seconds(); 36 | for(i = 0; i < CACHE.len; i++) { 37 | struct RESULT_TYPE *res = &CACHE.res[i]; 38 | 39 | bool comp = compare_timestamps(res->t, now); 40 | 41 | /* look for invalid entry with lowest timestamp as a heuristic for 42 | * least-recently-used */ 43 | if(!comp) { 44 | found_invalid = true; 45 | if(res->t < oldest) { 46 | oldest = res->t; 47 | oldest_i = i; 48 | } 49 | } 50 | 51 | /* since the ID is canonical, we only need to look for it to check for duplicates */ 52 | if (COMPARISON()) { 53 | /* valid entry */ 54 | if(comp) { 55 | goto cleanup; 56 | } 57 | /* outdated entry, should be replaced */ 58 | found_outdated = true; 59 | break; 60 | } 61 | } 62 | 63 | /* if we are here, we are necessarily going to add something to the cache */ 64 | struct RESULT_TYPE *res; 65 | if(found_outdated) { 66 | res = &CACHE.res[i]; 67 | 68 | /* we will simply overwrite the cache entry's ARGUMENT member */ 69 | memcpy(&res->ARGUMENT, ARGUMENT, sizeof(*ARGUMENT)); 70 | /* but we still need to free its underlying storage */ 71 | free(res->b); 72 | } else { 73 | if(found_invalid) { 74 | /* overwrite invalid entry */ 75 | i = oldest_i; 76 | /* we need to free all the underlying storage */ 77 | res = &CACHE.res[i]; 78 | free(res->b); 79 | } else { 80 | void *tmp_pointer = CACHE.res; 81 | if(!cache_increment_len(&CACHE.len, &CACHE.size, sizeof(*CACHE.res), &tmp_pointer, &i)) 82 | goto cleanup; 83 | CACHE.res = tmp_pointer; 84 | 85 | res = &CACHE.res[i]; 86 | } 87 | 88 | res->ARGUMENT = *ARGUMENT; 89 | } 90 | res->b = b; 91 | res->l = buf_len; 92 | res->t = now; 93 | #ifdef HASH_ARG 94 | res->h = hash(HASH_ARG); 95 | #endif 96 | b = 0; 97 | 98 | cleanup: 99 | pthread_rwlock_unlock(&CACHE.lock); 100 | /* if insertion fails, we should free the buffer */ 101 | free(b); 102 | return ret; 103 | 104 | #undef CACHE 105 | #undef RESULT_TYPE 106 | #undef HASH_ARG 107 | #undef COMPARISON 108 | #undef ARGUMENT 109 | -------------------------------------------------------------------------------- /include/cache_query.h: -------------------------------------------------------------------------------- 1 | /* This code is written this way in order to implement polimorphism: the struct 2 | * passwd and struct group caches are implemented in exactly the same way, the 3 | * only difference being the name of struct members and struct layout. 4 | * 5 | * The function to query values from cache will #include this file in its body, 6 | * after defining the necessary macros: 7 | * - CACHE: name of the cache for that struct 8 | * - RESULT_TYPE: the type of a result stored in the cache 9 | * - HASH_ARG: the argument that will be passed to the hashing function, if 10 | * any 11 | * - COMPARISON: the equality check to determine if the entry being queried is present in cache already 12 | * - ARGUMENT: the name of the struct member holding the struct passwd or 13 | * struct group being used 14 | */ 15 | 16 | IS_CACHING 17 | 18 | enum nss_status ret = NSS_STATUS_NOTFOUND; 19 | 20 | #ifdef HASH_ARG 21 | uint32_t h = hash(HASH_ARG); 22 | #endif 23 | 24 | pthread_rwlock_rdlock(&CACHE.lock); 25 | 26 | time_t now = monotonic_seconds(); 27 | for(size_t i = 0; i < CACHE.len; i++) { 28 | struct RESULT_TYPE *res = &CACHE.res[i]; 29 | if (COMPARISON()) { 30 | if(!compare_timestamps(res->t, now)) { 31 | break; 32 | } 33 | *buf = malloc(res->l); 34 | if(!*buf) { 35 | *err = errno; 36 | break; 37 | } 38 | COPY_FUNCTION(ARGUMENT, *buf, &CACHE.res[i].ARGUMENT, CACHE.res[i].b, res->l); 39 | ret = NSS_STATUS_SUCCESS; 40 | break; 41 | } 42 | } 43 | 44 | pthread_rwlock_unlock(&CACHE.lock); 45 | return ret; 46 | 47 | /* avoid polluting lines after this file is included */ 48 | #undef CACHE 49 | #undef RESULT_TYPE 50 | #undef HASH_ARG 51 | #undef COMPARISON 52 | #undef ARGUMENT 53 | #undef COPY_FUNCTION 54 | -------------------------------------------------------------------------------- /include/hash.h: -------------------------------------------------------------------------------- 1 | #ifndef HASH_HDR 2 | #define HASH_HDR 3 | #include 4 | 5 | #ifdef __cplusplus 6 | extern "C" { 7 | #endif 8 | 9 | typedef struct hashnode_s hashnode_t; 10 | typedef struct hashtable_s hashtable_t; 11 | 12 | struct hashnode_s { 13 | hashnode_t *next; 14 | size_t keylen; 15 | void *key; 16 | }; 17 | 18 | struct hashtable_s { 19 | size_t (*hash)(const void *key, size_t keylen); 20 | size_t size; 21 | hashnode_t **nodes; 22 | }; 23 | 24 | int hashtable_init(hashtable_t *table, size_t pow2size, size_t (*hash)(const void *key, size_t keylen)); 25 | void hashtable_destroy(hashtable_t *table); 26 | void hashtable_insert(hashtable_t *table, hashnode_t *node, void *key, size_t keylen); 27 | hashnode_t *hashtable_search(hashtable_t *table, const void *key, size_t keylen); 28 | void hashtable_remove(hashtable_t *table, const void *key, size_t keylen); 29 | 30 | #define hashtable_ref(ELEMENT, TYPE, MEMBER) \ 31 | ((TYPE *)((unsigned char *)(ELEMENT) - offsetof(TYPE, MEMBER))) 32 | 33 | #ifdef __cplusplus 34 | } 35 | #endif 36 | 37 | #endif 38 | -------------------------------------------------------------------------------- /include/list.h: -------------------------------------------------------------------------------- 1 | #ifndef LIST_HDR 2 | #define LIST_HDR 3 | #include 4 | 5 | #ifdef __cplusplus 6 | extern "C" { 7 | #endif 8 | 9 | typedef struct link_s link_t; 10 | typedef struct list_s list_t; 11 | 12 | struct link_s { 13 | link_t *prev; 14 | link_t *next; 15 | }; 16 | 17 | struct list_s { 18 | link_t *head; 19 | link_t *tail; 20 | }; 21 | 22 | void list_init(list_t *list); 23 | 24 | void list_push_front(list_t *list, link_t *link); 25 | void list_push_back(list_t *list, link_t *link); 26 | void list_insert_before(list_t *list, link_t *before, link_t *link); 27 | void list_insert_after(list_t *list, link_t *after, link_t *link); 28 | 29 | link_t *list_pop_front(list_t *list); 30 | link_t *list_pop_back(list_t *list); 31 | 32 | link_t *list_head(const list_t *list); 33 | link_t *list_tail(const list_t *list); 34 | 35 | link_t *list_next(const link_t *link); 36 | link_t *list_prev(const link_t *link); 37 | 38 | #define list_ref(ELEMENT, TYPE, MEMBER) \ 39 | ((TYPE *)((unsigned char *)(ELEMENT) - offsetof(TYPE, MEMBER))) 40 | 41 | #ifdef __cplusplus 42 | } 43 | #endif 44 | 45 | #endif 46 | -------------------------------------------------------------------------------- /include/modules.h: -------------------------------------------------------------------------------- 1 | #ifndef MODULES_H 2 | #define MODULES_H 3 | 4 | #include 5 | #include 6 | #include "nss.h" 7 | #include "parse.h" 8 | #include "list.h" 9 | 10 | typedef enum nss_status (*nss_getgrnam_r)(const char*, struct group*, char*, size_t, int*); 11 | typedef enum nss_status (*nss_getgrgid_r)(gid_t, struct group*, char*, size_t, int*); 12 | typedef enum nss_status (*nss_initgroups_dyn)(const char*, gid_t, long*, long*, gid_t**, long, int*); 13 | typedef enum nss_status (*nss_getpwnam_r)(const char*, struct passwd*, char*, size_t, int*); 14 | typedef enum nss_status (*nss_getpwuid_r)(uid_t, struct passwd*, char*, size_t, int*); 15 | 16 | struct mod_group { 17 | nss_getgrnam_r nss_getgrnam_r; 18 | nss_getgrgid_r nss_getgrgid_r; 19 | nss_initgroups_dyn nss_initgroups_dyn; 20 | action on_status[4]; 21 | link_t link; 22 | }; 23 | 24 | struct mod_passwd { 25 | nss_getpwnam_r nss_getpwnam_r; 26 | nss_getpwuid_r nss_getpwuid_r; 27 | action on_status[4]; 28 | link_t link; 29 | }; 30 | 31 | extern list_t passwd_mods; 32 | extern list_t group_mods; 33 | 34 | struct initgroups_res { 35 | long end; 36 | long alloc; 37 | gid_t *grps; 38 | }; 39 | 40 | enum nss_status cache_getpwnam_r(const char *, struct passwd *, char **, int *); 41 | enum nss_status cache_getpwuid_r(uid_t, struct passwd *, char **, int *); 42 | enum nss_status cache_getgrnam_r(const char *, struct group *, char **, int *); 43 | enum nss_status cache_getgrgid_r(gid_t, struct group *, char **, int *); 44 | enum nss_status cache_initgroups_dyn(const char *, struct initgroups_res *, int *); 45 | 46 | int init_caches(long, long); 47 | int cache_passwd_add(struct passwd *, char *, size_t); 48 | int cache_group_add(struct group *, char *, size_t); 49 | int cache_initgroups_add(struct initgroups_res *, const char *); 50 | 51 | #endif 52 | -------------------------------------------------------------------------------- /include/nscd.h: -------------------------------------------------------------------------------- 1 | #ifndef NSCD_H 2 | #define NSCD_H 3 | 4 | #include 5 | 6 | #define NSCDVERSION 2 7 | #define GETPWBYNAME 0 8 | #define GETPWBYUID 1 9 | #define GETGRBYNAME 2 10 | #define GETGRBYGID 3 11 | #define GETINITGR 15 12 | 13 | #define REQVERSION 0 14 | #define REQTYPE 1 15 | #define REQKEYLEN 2 16 | #define REQ_LEN 3 17 | 18 | #define PWVERSION 0 19 | #define PWFOUND 1 20 | #define PWNAMELEN 2 21 | #define PWPASSWDLEN 3 22 | #define PWUID 4 23 | #define PWGID 5 24 | #define PWGECOSLEN 6 25 | #define PWDIRLEN 7 26 | #define PWSHELLLEN 8 27 | #define PW_LEN 9 28 | 29 | #define INITGRVERSION 0 30 | #define INITGRFOUND 1 31 | #define INITGRNGRPS 2 32 | #define INITGR_LEN 3 33 | 34 | #define GRVERSION 0 35 | #define GRFOUND 1 36 | #define GRNAMELEN 2 37 | #define GRPASSWDLEN 3 38 | #define GRGID 4 39 | #define GRMEMCNT 5 40 | #define GR_LEN 6 41 | 42 | #define ISPWREQ(r) (r==GETPWBYNAME || r==GETPWBYUID) 43 | #define ISGRPREQ(r) (r==GETGRBYNAME || r==GETGRBYGID) 44 | 45 | #endif 46 | -------------------------------------------------------------------------------- /include/nss.h: -------------------------------------------------------------------------------- 1 | #ifndef NSS__H 2 | #define NSS__H 3 | 4 | enum nss_status 5 | { 6 | NSS_STATUS_TRYAGAIN = -2, 7 | NSS_STATUS_UNAVAIL = -1, 8 | NSS_STATUS_NOTFOUND = 0, 9 | NSS_STATUS_SUCCESS = 1, 10 | NSS_STATUS_RETURN = 2 11 | }; 12 | 13 | #endif 14 | -------------------------------------------------------------------------------- /include/parse.h: -------------------------------------------------------------------------------- 1 | #ifndef PARSE_H 2 | #define PARSE_H 3 | 4 | #include "list.h" 5 | 6 | #include 7 | 8 | typedef unsigned char database; 9 | typedef unsigned char status; 10 | typedef unsigned char action; 11 | 12 | enum { 13 | DB_ALIASES, 14 | DB_ETHERS, 15 | DB_GROUP, 16 | DB_HOSTS, 17 | DB_INITGROUPS, 18 | DB_NETGROUP, 19 | DB_NETWORKS, 20 | DB_PASSWD, 21 | DB_PROTOCOLS, 22 | DB_PUBLICKEY, 23 | DB_RPC, 24 | DB_SERVICES, 25 | DB_SHADOW 26 | }; 27 | 28 | enum { 29 | STS_SUCCESS, 30 | STS_NOTFOUND, 31 | STS_UNAVAIL, 32 | STS_TRYAGAIN 33 | }; 34 | 35 | enum { 36 | ACT_RETURN, 37 | ACT_CONTINUE, 38 | ACT_MERGE 39 | }; 40 | 41 | struct service { 42 | char *service; 43 | action on_status[4]; 44 | link_t link; 45 | }; 46 | 47 | struct entry { 48 | database database; 49 | list_t services; 50 | link_t link; 51 | }; 52 | 53 | extern FILE *yyin; 54 | extern list_t parsed_output; 55 | int yyparse(void); 56 | 57 | #endif 58 | -------------------------------------------------------------------------------- /include/parse_common.h: -------------------------------------------------------------------------------- 1 | #ifndef PARSE_COMMON_H 2 | #define PARSE_COMMON_H 3 | 4 | #include 5 | #include "parse.h" 6 | #include "list.h" 7 | 8 | union yystype { 9 | char *str; 10 | database database; 11 | status status; 12 | action action; 13 | action modifiers[4]; 14 | list_t list; 15 | struct entry entry; 16 | struct service service; 17 | 18 | struct { 19 | status status; 20 | action action; 21 | bool negate; 22 | } modifier; 23 | }; 24 | 25 | #define TOK_STRING 258 26 | #define TOK_DB 259 27 | #define TOK_STS 260 28 | #define TOK_ACT 261 29 | 30 | #define YYSTYPE union yystype 31 | extern YYSTYPE yylval; 32 | 33 | int yylex(); 34 | 35 | #endif 36 | -------------------------------------------------------------------------------- /include/util.h: -------------------------------------------------------------------------------- 1 | #ifndef UTIL_H 2 | #define UTIL_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #if __STDC_VERSION__ >= 201112L 11 | #include 12 | #elif defined(__GNUC__) 13 | #define noreturn __attribute__((__noreturn__)) 14 | #else 15 | #define noreturn 16 | #endif 17 | 18 | void init_program_invocation_name(const char*); 19 | extern const char *program_invocation_name; 20 | extern const char *program_invocation_short_name; 21 | noreturn void die(void); 22 | noreturn void die_fmt(const char*, ...); 23 | int asprintf(char**, const char*, ...); 24 | int full_write(int, const char*, size_t); 25 | int full_read(int, char*, size_t); 26 | uint32_t swap32(uint32_t); 27 | int write_pwd(int, int, struct passwd*); 28 | int write_grp(int, int, struct group*); 29 | int write_groups(int, int, size_t, gid_t*); 30 | int init_socket_handling(unsigned); 31 | void socket_handle(int); 32 | 33 | #endif 34 | -------------------------------------------------------------------------------- /musl-nscd.8: -------------------------------------------------------------------------------- 1 | .Dd July 19, 2021 2 | .Dt MUSL-NSCD 8 3 | .Os 4 | .Sh NAME 5 | .Nm musl-nscd 6 | .Nd 7 | daemon that provides 8 | .Xr nss 5 9 | functionality to applications via the NSCD protocol, avoiding the need for them to load the modules themselves. 10 | It can also cache requests made to it 11 | .Sh SYNOPSIS 12 | .Nm nscd 13 | .Op Fl c Ar config 14 | .Op Fl s Ar socket 15 | .Op Fl C Ar cache_invalidation_time 16 | .Op Fl n Ar cache_maximum_entries 17 | .Op Fl j Ar threads 18 | .Op Fl d 19 | .Sh DESCRIPTION 20 | .Nm 21 | provides access to the 22 | .Xr passwd 5 23 | and 24 | .Xr group 5 25 | databases through standard libc interfaces. 26 | .Pp 27 | Unlike the GNU 28 | .Xr nscd 8 29 | implementation, there is only a positive cache for items found, and caching is optional. 30 | .Sh OPTIONS 31 | .Bl -tag -width x 32 | .It Fl c Ar config 33 | Specifies the path to the configuration file. 34 | By default, 35 | .Pa /etc/nsswitch.conf 36 | is used. 37 | The syntax is specified in 38 | .Xr nsswitch.conf 5 , 39 | though the "merge" action is not supported. 40 | .It Fl s Ar socket 41 | Specifies the path to the socket where the daemon listens. 42 | By default, 43 | .Pa /var/run/nscd/socket 44 | is used. 45 | .It Fl C Ar cache_invalidation_time 46 | This option enables caching functionality: this reduces latency but increases memory consumption. 47 | This option takes the amount of seconds for which a result is valid as argument. 48 | Users should note that a stale entry will be treated as valid for the duration of the invalidation time. 49 | This means that any changes made to the authentication providers used by 50 | .Nm 51 | can take up to 52 | .Ar cache_invalidation_time 53 | seconds to be updated in 54 | .Nm , 55 | and, therefore, in applications. 56 | A suggested value that will provide most of the performance benefits without being too long is 120 seconds (2 minutes). 57 | System administrators should set this to fit site-specific policies, or consider not enabling caching at all. 58 | .It Fl n Ar cache_maximum_entries 59 | This options specifies the maximum amount of entries allowed in the cache. 60 | This maximum is per cache, therefore specifying 100 entries means 61 | there will be 3 separate caches (for each supported query type) 62 | with at most 100 entries each. 63 | The default is 1000 entries. 64 | .It Fl j Ar threads 65 | Specifies the number of threads the daemon should use. 66 | More threads can reduce latency. 67 | .It Fl d 68 | This option makes it so 69 | .Nm 70 | daemonizes itself to the background. 71 | .El 72 | .Sh SEE ALSO 73 | .Xr nss 5 , 74 | .Xr nsswitch.conf 5 , 75 | .Xr nscd 8 76 | .Sh BUGS 77 | Bugs should be reported to 78 | .Lk https://github.com/pikhq/musl-nscd 79 | -------------------------------------------------------------------------------- /port/gr_passwd.c: -------------------------------------------------------------------------------- 1 | #ifdef TEST 2 | #include 3 | 4 | int main() 5 | { 6 | struct group grp = {}; 7 | char *passwd; 8 | passwd = grp.gr_passwd; 9 | } 10 | #else 11 | typedef int x; 12 | #endif 13 | -------------------------------------------------------------------------------- /port/pw_gecos.c: -------------------------------------------------------------------------------- 1 | #ifdef TEST 2 | #include 3 | 4 | int main() 5 | { 6 | struct passwd pwd = {}; 7 | char *gecos; 8 | gecos = pwd.pw_gecos; 9 | } 10 | #else 11 | typedef int x; 12 | #endif 13 | -------------------------------------------------------------------------------- /port/pw_passwd.c: -------------------------------------------------------------------------------- 1 | #ifdef TEST 2 | #include 3 | 4 | int main() 5 | { 6 | struct passwd pwd = {}; 7 | char *passwd; 8 | passwd = pwd.pw_passwd; 9 | } 10 | #else 11 | typedef int x; 12 | #endif 13 | -------------------------------------------------------------------------------- /src/asprintf.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include "util.h" 6 | 7 | int asprintf(char **s, const char *fmt, ...) 8 | { 9 | int ret, l; 10 | va_list ap; 11 | va_start(ap, fmt); 12 | l = vsnprintf(0, 0, fmt, ap); 13 | va_end(ap); 14 | if(l < 0 || !(*s = malloc(l+1U))) return -1; 15 | va_start(ap, fmt); 16 | ret = vsnprintf(*s, l+1U, fmt, ap); 17 | va_end(ap); 18 | return ret; 19 | } 20 | -------------------------------------------------------------------------------- /src/cache.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include "config.h" 10 | #include "modules.h" 11 | 12 | static int cache = 0; 13 | #define IS_CACHING if(!cache) { *err = 0; return NSS_STATUS_UNAVAIL; } 14 | #define IS_CACHING_FOR_WRITE(storage_buffer) if(!cache) { free(storage_buffer); return -1; } 15 | 16 | #define CACHE_INITIAL_ENTRIES 32 17 | 18 | static time_t cache_invalidation_time; 19 | static size_t cache_max_entries; 20 | 21 | static time_t monotonic_seconds(void) 22 | { 23 | struct timespec res; 24 | if(clock_gettime(CLOCK_MONOTONIC, &res)) { 25 | /* this should never happen; abort? */ 26 | perror("clock_gettime"); 27 | return 0; 28 | } 29 | 30 | return res.tv_sec; 31 | } 32 | 33 | /* returns true if the timestamp is still valid */ 34 | static bool compare_timestamps(time_t t, time_t now) 35 | { 36 | return (now - t) < cache_invalidation_time; 37 | } 38 | 39 | /* increment len and store the index for that new member in index */ 40 | static bool cache_increment_len(size_t *len, size_t *size, size_t sizeof_element, void **data, size_t *index) 41 | { 42 | /* first simply try to increment len */ 43 | if(*len < *size) { 44 | *index = (*len)++; 45 | return true; 46 | } 47 | 48 | /* otherwise, try to increase cache size */ 49 | 50 | if(*size >= cache_max_entries) 51 | return false; 52 | 53 | size_t new_size; 54 | /* memory growth factor is 1.5x; see socket_handle.c for a similar impl */ 55 | if(*size > cache_max_entries - *size/2) 56 | new_size = cache_max_entries; 57 | else 58 | new_size = *size + *size/2; 59 | 60 | /* XXX: doesn't check for multiplication overflow */ 61 | void *tmp = realloc(*data, new_size * sizeof_element); 62 | if(!tmp) 63 | return false; 64 | 65 | *size = new_size; 66 | *data = tmp; 67 | *index = (*len)++; 68 | return true; 69 | } 70 | 71 | /* public domain hash, adapted from http://www.isthe.com/chongo/tech/comp/fnv/ 72 | * specifically http://www.isthe.com/chongo/src/fnv/hash_32.c */ 73 | #define FNV_32_PRIME ((uint32_t)0x01000193) 74 | #define FNV1_32_INIT ((uint32_t)0x811c9dc5) 75 | static uint32_t hash(const char *s) 76 | { 77 | uint32_t h = FNV1_32_INIT; 78 | for (; *s; s++) { 79 | h *= FNV_32_PRIME; 80 | h ^= (unsigned char)*s; 81 | } 82 | return h; 83 | } 84 | 85 | struct passwd_result { 86 | struct passwd p; 87 | char *b; 88 | size_t l; 89 | /* for validation */ 90 | time_t t; 91 | uint32_t h; 92 | }; 93 | struct passwd_cache { 94 | pthread_rwlock_t lock; 95 | struct passwd_result *res; 96 | size_t len, size; 97 | }; 98 | 99 | static struct passwd_cache passwd_cache = 100 | { .lock = PTHREAD_RWLOCK_INITIALIZER, .size = CACHE_INITIAL_ENTRIES }; 101 | 102 | static void copy_passwd(struct passwd *np, char *nb, const struct passwd *p, const char *b, size_t len) 103 | { 104 | memcpy(nb, b, len); 105 | 106 | #define NEW_ADDRESS(member) np->member = p->member ? nb + (p->member - b) : 0 107 | NEW_ADDRESS(pw_name); 108 | #ifdef HAVE_PW_PASSWD 109 | NEW_ADDRESS(pw_passwd); 110 | #endif 111 | np->pw_uid = p->pw_uid; 112 | np->pw_gid = p->pw_gid; 113 | #ifdef HAVE_PW_GECOS 114 | NEW_ADDRESS(pw_gecos); 115 | #endif 116 | NEW_ADDRESS(pw_dir); 117 | NEW_ADDRESS(pw_shell); 118 | #undef NEW_ADDRESS 119 | } 120 | 121 | enum nss_status cache_getpwnam_r(const char *name, struct passwd *p, char **buf, int *err) 122 | { 123 | #define CACHE passwd_cache 124 | #define RESULT_TYPE passwd_result 125 | #define HASH_ARG name 126 | #define COMPARISON() (h == res->h && strcmp(res->p.pw_name, name) == 0) 127 | #define ARGUMENT p 128 | #define COPY_FUNCTION copy_passwd 129 | #include "cache_query.h" 130 | } 131 | 132 | enum nss_status cache_getpwuid_r(uid_t id, struct passwd *p, char **buf, int *err) 133 | { 134 | #define CACHE passwd_cache 135 | #define RESULT_TYPE passwd_result 136 | #define COMPARISON() (res->p.pw_uid == id) 137 | #define ARGUMENT p 138 | #define COPY_FUNCTION copy_passwd 139 | #include "cache_query.h" 140 | } 141 | 142 | /* this function copies the passwd struct p points to and 143 | * takes ownership of the buffer b points to */ 144 | int cache_passwd_add(struct passwd *p, char *b, size_t buf_len) 145 | { 146 | #define CACHE passwd_cache 147 | #define RESULT_TYPE passwd_result 148 | #define HASH_ARG res->p.pw_name 149 | #define COMPARISON() (res->p.pw_uid == p->pw_uid) 150 | #define ARGUMENT p 151 | #include "cache_add.h" 152 | } 153 | 154 | struct group_result { 155 | struct group g; 156 | char *b; 157 | size_t l; 158 | /* for validation */ 159 | time_t t; 160 | uint32_t h; 161 | }; 162 | struct group_cache { 163 | pthread_rwlock_t lock; 164 | struct group_result *res; 165 | size_t len, size; 166 | }; 167 | 168 | static struct group_cache group_cache = 169 | { .lock = PTHREAD_RWLOCK_INITIALIZER, .size = CACHE_INITIAL_ENTRIES }; 170 | 171 | static void copy_group(struct group *ng, char *nb, const struct group *g, const char *b, size_t len) 172 | { 173 | memcpy(nb, b, len); 174 | 175 | /* copy the pointer offset */ 176 | #define NEW_ADDRESS(member) ng->member = g->member ? (void *)(nb + ((char *)(void *)g->member - (char *)(void *)b)) : 0 177 | NEW_ADDRESS(gr_name); 178 | #ifdef HAVE_GR_PASSWD 179 | NEW_ADDRESS(gr_passwd); 180 | #endif 181 | ng->gr_gid = g->gr_gid; 182 | 183 | NEW_ADDRESS(gr_mem); 184 | if(g->gr_mem) { 185 | for(size_t i = 0; g->gr_mem[i]; i++) { 186 | NEW_ADDRESS(gr_mem[i]); 187 | } 188 | } 189 | 190 | #undef NEW_ADDRESS 191 | } 192 | 193 | enum nss_status cache_getgrnam_r(const char *name, struct group *g, char **buf, int *err) 194 | { 195 | #define CACHE group_cache 196 | #define RESULT_TYPE group_result 197 | #define HASH_ARG name 198 | #define COMPARISON() (h == res->h && strcmp(res->g.gr_name, name) == 0) 199 | #define ARGUMENT g 200 | #define COPY_FUNCTION copy_group 201 | #include "cache_query.h" 202 | } 203 | 204 | enum nss_status cache_getgrgid_r(gid_t id, struct group *g, char **buf, int *err) 205 | { 206 | #define CACHE group_cache 207 | #define RESULT_TYPE group_result 208 | #define COMPARISON() (res->g.gr_gid == id) 209 | #define ARGUMENT g 210 | #define COPY_FUNCTION copy_group 211 | #include "cache_query.h" 212 | } 213 | 214 | /* this function copies the group struct p points to and 215 | * takes ownership of the buffer b points to */ 216 | int cache_group_add(struct group *g, char *b, size_t buf_len) 217 | { 218 | #define CACHE group_cache 219 | #define RESULT_TYPE group_result 220 | #define HASH_ARG res->g.gr_name 221 | #define COMPARISON() (res->g.gr_gid == g->gr_gid) 222 | #define ARGUMENT g 223 | #include "cache_add.h" 224 | } 225 | 226 | struct initgroups_result { 227 | struct initgroups_res g; 228 | char *name; 229 | /* for validation */ 230 | time_t t; 231 | uint32_t h; 232 | }; 233 | struct initgroups_cache { 234 | pthread_rwlock_t lock; 235 | struct initgroups_result *res; 236 | size_t len, size; 237 | }; 238 | 239 | static struct initgroups_cache initgroups_cache = 240 | { .lock = PTHREAD_RWLOCK_INITIALIZER, .size = CACHE_INITIAL_ENTRIES }; 241 | 242 | enum nss_status cache_initgroups_dyn(const char *name, struct initgroups_res *resp, int *err) 243 | { 244 | IS_CACHING 245 | 246 | enum nss_status ret = NSS_STATUS_NOTFOUND; 247 | 248 | uint32_t h = hash(name); 249 | 250 | pthread_rwlock_rdlock(&initgroups_cache.lock); 251 | 252 | time_t now = monotonic_seconds(); 253 | for(size_t i = 0; i < initgroups_cache.len; i++) { 254 | struct initgroups_result *res = &initgroups_cache.res[i]; 255 | if (h == res->h && strcmp(res->name, name) == 0) { 256 | if(!compare_timestamps(res->t, now)) { 257 | break; 258 | } 259 | 260 | resp->grps = malloc(res->g.end * sizeof(gid_t)); 261 | if(!resp->grps) { 262 | *err = errno; 263 | break; 264 | } 265 | resp->alloc = resp->end = res->g.end; 266 | 267 | memcpy(resp->grps, res->g.grps, res->g.end * sizeof(gid_t)); 268 | ret = NSS_STATUS_SUCCESS; 269 | break; 270 | } 271 | } 272 | 273 | pthread_rwlock_unlock(&initgroups_cache.lock); 274 | return ret; 275 | } 276 | 277 | /* see cache_add.h for comments on the implementation strategy */ 278 | int cache_initgroups_add(struct initgroups_res *g, const char *name) 279 | { 280 | IS_CACHING_FOR_WRITE(g->grps); 281 | 282 | int ret = 0; 283 | size_t i; 284 | bool found_outdated = false; 285 | 286 | uint32_t h = hash(name); 287 | 288 | pthread_rwlock_wrlock(&initgroups_cache.lock); 289 | 290 | time_t oldest = initgroups_cache.len > 0 ? initgroups_cache.res[0].t : 0; 291 | size_t oldest_i = 0; 292 | bool found_invalid = false; 293 | 294 | time_t now = monotonic_seconds(); 295 | for(i = 0; i < initgroups_cache.len; i++) { 296 | struct initgroups_result *res = &initgroups_cache.res[i]; 297 | 298 | bool comp = compare_timestamps(res->t, now); 299 | 300 | if(!comp) { 301 | found_invalid = true; 302 | if(res->t < oldest) { 303 | oldest = res->t; 304 | oldest_i = i; 305 | } 306 | } 307 | 308 | if (h == res->h && strcmp(res->name, name) == 0) { 309 | if(comp) { 310 | goto cleanup; 311 | } 312 | found_outdated = true; 313 | break; 314 | } 315 | } 316 | 317 | /* if we are here, we are necessarily going to add something to the cache */ 318 | struct initgroups_result *res; 319 | if(found_outdated) { 320 | res = &initgroups_cache.res[i]; 321 | /* we need to free the underlying storage, but we reuse res->name */ 322 | free(res->g.grps); 323 | } else { 324 | char *namedup = strdup(name); 325 | if (!namedup) 326 | goto cleanup; 327 | 328 | if(found_invalid) { 329 | /* overwrite invalid entry */ 330 | i = oldest_i; 331 | res = &initgroups_cache.res[i]; 332 | /* we need to free all the underlying storage */ 333 | free(res->name); 334 | free(res->g.grps); 335 | } else { 336 | void *tmp_pointer = initgroups_cache.res; 337 | if(!cache_increment_len(&initgroups_cache.len, &initgroups_cache.size, sizeof(*initgroups_cache.res), &tmp_pointer, &i)) { 338 | free(namedup); 339 | goto cleanup; 340 | } 341 | initgroups_cache.res = tmp_pointer; 342 | } 343 | 344 | res = &initgroups_cache.res[i]; 345 | res->name = namedup; 346 | } 347 | memcpy(&res->g, g, sizeof(*g)); 348 | res->t = now; 349 | res->h = h; 350 | g->grps = 0; 351 | 352 | cleanup: 353 | pthread_rwlock_unlock(&initgroups_cache.lock); 354 | /* if insertion fails, we should free the buffer */ 355 | free(g->grps); 356 | return ret; 357 | } 358 | 359 | int init_caches(long invalidation_time, long max_entries) 360 | { 361 | #define MALLOC_CACHE(cache) do{ if(!(cache.res = malloc(cache.size * sizeof(*cache.res)))) return -1; }while(0) 362 | MALLOC_CACHE(passwd_cache); 363 | MALLOC_CACHE(group_cache); 364 | MALLOC_CACHE(initgroups_cache); 365 | 366 | cache_invalidation_time = invalidation_time; 367 | if (max_entries > CACHE_INITIAL_ENTRIES) { 368 | cache_max_entries = max_entries; 369 | } else { 370 | cache_max_entries = CACHE_INITIAL_ENTRIES; 371 | } 372 | 373 | cache = 1; 374 | return 0; 375 | } 376 | -------------------------------------------------------------------------------- /src/die.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include "util.h" 7 | 8 | noreturn void die() 9 | { 10 | char buf[2048]; 11 | if(strerror_r(errno, buf, sizeof buf)) { 12 | snprintf(buf, sizeof buf, "unknown error"); 13 | } 14 | die_fmt("%s", buf); 15 | exit(1); 16 | } 17 | 18 | noreturn void die_fmt(const char *fmt, ...) 19 | { 20 | va_list ap; 21 | fprintf(stderr, "%s: ", program_invocation_short_name); 22 | va_start(ap, fmt); 23 | vfprintf(stderr, fmt, ap); 24 | va_end(ap); 25 | fprintf(stderr, "\n"); 26 | exit(1); 27 | } 28 | -------------------------------------------------------------------------------- /src/full_read.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "util.h" 4 | 5 | int full_read(int fd, char *buf, size_t n) 6 | { 7 | ssize_t cnt; 8 | while(n) { 9 | cnt = read(fd, buf, n); 10 | if(cnt < 0) { 11 | if(errno == EINTR) continue; 12 | return -1; 13 | } 14 | buf += cnt; 15 | n -= cnt; 16 | } 17 | return 0; 18 | } 19 | -------------------------------------------------------------------------------- /src/full_write.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "util.h" 4 | 5 | int full_write(int fd, const char *buf, size_t n) 6 | { 7 | ssize_t cnt; 8 | while(n) { 9 | cnt = write(fd, buf, n); 10 | if(cnt < 0) { 11 | if(errno == EINTR) continue; 12 | return -1; 13 | } 14 | buf += cnt; 15 | n -= cnt; 16 | } 17 | return 0; 18 | } 19 | -------------------------------------------------------------------------------- /src/hash.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include "hash.h" 6 | 7 | static hashnode_t *hash_node_find(hashnode_t *node, const void *key, size_t keylen) { 8 | while (node) { 9 | if (keylen != node->keylen) { 10 | node = node->next; 11 | continue; 12 | } 13 | if (memcmp(node->key, key, keylen) == 0) return node; 14 | node = node->next; 15 | } 16 | return NULL; 17 | } 18 | 19 | static void hash_node_init(hashnode_t *node, void *key, size_t keylen) { 20 | node->key = key; 21 | node->keylen = keylen; 22 | node->next = NULL; 23 | } 24 | 25 | static inline size_t hash_node_bin(size_t bins, size_t keyhash) { 26 | return keyhash & (bins - 1); 27 | } 28 | 29 | int hashtable_init(hashtable_t *table, size_t pow2size, size_t (*hash)(const void *key, size_t keylen)) { 30 | assert(pow2size < sizeof(int)*8); 31 | table->hash = hash; 32 | table->size = (1 << pow2size); 33 | table->nodes = calloc(sizeof(hashnode_t*), table->size); 34 | return table->nodes ? 0 : -1; 35 | } 36 | 37 | void hashtable_destroy(hashtable_t *table) { 38 | table->hash = NULL; 39 | table->size = 0; 40 | free(table->nodes); 41 | } 42 | 43 | void hashtable_insert(hashtable_t *table, hashnode_t *node, void *key, size_t keylen) { 44 | hash_node_init(node, key, keylen); 45 | size_t hash = table->hash(node->key, node->keylen); 46 | size_t bin = hash_node_bin(table->size, hash); 47 | hashnode_t *head = table->nodes[bin]; 48 | if (!head) { 49 | table->nodes[bin] = node; 50 | return; 51 | } 52 | if (hash_node_find(head, node->key, node->keylen)) return; 53 | table->nodes[bin] = node; 54 | node->next = head; 55 | } 56 | 57 | hashnode_t *hashtable_search(hashtable_t *table, const void *key, size_t keylen) { 58 | size_t hash = table->hash(key, keylen); 59 | size_t bin = hash_node_bin(table->size, hash); 60 | hashnode_t *node = table->nodes[bin]; 61 | return hash_node_find(node, key, keylen); 62 | } 63 | 64 | void hashtable_remove(hashtable_t *table, const void *key, size_t keylen) { 65 | size_t hash = table->hash(key, keylen); 66 | size_t bin = hash_node_bin(table->size, hash); 67 | hashnode_t *current = table->nodes[bin]; 68 | hashnode_t *prev = NULL; 69 | while (current) { 70 | if (keylen != current->keylen) { 71 | prev = current; 72 | current = current->next; 73 | continue; 74 | } 75 | if (memcmp(current->key, key, keylen) == 0) { 76 | if (prev) prev->next = current->next; 77 | else table->nodes[bin] = current->next; 78 | current->next = NULL; 79 | return; 80 | } 81 | prev = current; 82 | current = current->next; 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /src/list.c: -------------------------------------------------------------------------------- 1 | #include "list.h" 2 | 3 | void list_init(list_t *list) { 4 | list->head = NULL; 5 | list->tail = NULL; 6 | } 7 | 8 | void list_push_front(list_t *list, link_t *link) { 9 | if (list->head) { 10 | list->head->prev = link; 11 | link->prev = NULL; 12 | link->next = list->head; 13 | list->head = link; 14 | } else { 15 | list->head = link; 16 | list->tail = link; 17 | link->next = NULL; 18 | link->prev = NULL; 19 | } 20 | } 21 | 22 | void list_push_back(list_t *list, link_t *link) { 23 | if (list->tail) { 24 | list->tail->next = link; 25 | link->prev = list->tail; 26 | link->next = NULL; 27 | list->tail = link; 28 | } else { 29 | list->head = link; 30 | list->tail = link; 31 | link->next = NULL; 32 | link->prev = NULL; 33 | } 34 | } 35 | 36 | void list_insert_after(list_t *list, link_t *after, link_t *link) { 37 | link->next = after->next; 38 | link->prev = after; 39 | if (after->next) after->next->prev = link; 40 | else list->tail = link; 41 | after->next = link; 42 | } 43 | 44 | void list_insert_before(list_t *list, link_t *before, link_t *link) { 45 | link->prev = before->prev; 46 | link->next = before; 47 | if (before->prev) before->prev->next = link; 48 | else list->head = link; 49 | before->prev = link; 50 | } 51 | 52 | link_t *list_pop_front(list_t *list) { 53 | link_t *link = list->head; 54 | if (!link) return NULL; 55 | if (link->next) link->next->prev = link->prev; 56 | if (link->prev) link->prev->next = link->next; 57 | if (list->head == link) list->head = link->next; 58 | if (list->tail == link) list->tail = link->prev; 59 | return link; 60 | } 61 | 62 | link_t *list_pop_back(list_t *list) { 63 | link_t *link = list->tail; 64 | if (!link) return NULL; 65 | if (link->next) link->next->prev = link->prev; 66 | if (link->prev) link->prev->next = link->next; 67 | if (list->head == link) list->head = link->next; 68 | if (list->tail == link) list->tail = link->prev; 69 | return link; 70 | } 71 | 72 | void list_remove(list_t *list, link_t *link) { 73 | if (!link) return; 74 | if (link->next) link->next->prev = link->prev; 75 | if (link->prev) link->prev->next = link->next; 76 | if (list->head == link) list->head = link->next; 77 | if (list->tail == link) list->tail = link->prev; 78 | } 79 | 80 | link_t *list_head(const list_t *list) { 81 | return list->head; 82 | } 83 | 84 | link_t *list_tail(const list_t *list) { 85 | return list->tail; 86 | } 87 | 88 | link_t *list_next(const link_t *link) { 89 | return link->next; 90 | } 91 | 92 | link_t *list_prev(const link_t *link) { 93 | return link->prev; 94 | } 95 | -------------------------------------------------------------------------------- /src/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | #include "modules.h" 18 | #include "parse.h" 19 | #include "util.h" 20 | 21 | list_t passwd_mods; 22 | list_t group_mods; 23 | 24 | static void *get_dll(const char *service) 25 | { 26 | char *path; 27 | void *dll; 28 | if(asprintf(&path, "libnss_%s.so.2", service) < 0) die(); 29 | dll = dlopen(path, RTLD_NOW | RTLD_LOCAL); 30 | if(!dll) { 31 | sprintf(path, "libnss_%s.so", service); 32 | dll = dlopen(path, RTLD_NOW | RTLD_LOCAL); 33 | } 34 | if(!dll) die_fmt("%s: %s", path, dlerror()); 35 | free(path); 36 | return dll; 37 | } 38 | 39 | static void *get_fn(void *dll, const char *name, const char *service) 40 | { 41 | char *fnname; 42 | void *fn; 43 | if(asprintf(&fnname, "_nss_%s_%s", service, name) < 0) die(); 44 | fn = dlsym(dll, fnname); 45 | free(fnname); 46 | return fn; 47 | } 48 | 49 | static enum nss_status null_getpwnam_r(const char *a, struct passwd *b, char *c, size_t d, int *e) 50 | { 51 | return NSS_STATUS_NOTFOUND; 52 | } 53 | 54 | static enum nss_status null_getpwuid_r(uid_t a, struct passwd *b, char *c, size_t d, int *e) 55 | { 56 | return NSS_STATUS_NOTFOUND; 57 | } 58 | 59 | static enum nss_status null_getgrnam_r(const char *a, struct group *b, char *c, size_t d, int *e) 60 | { 61 | return NSS_STATUS_NOTFOUND; 62 | } 63 | 64 | static enum nss_status null_getgrgid_r(gid_t a, struct group *b, char *c, size_t d, int *e) 65 | { 66 | return NSS_STATUS_NOTFOUND; 67 | } 68 | 69 | static enum nss_status null_initgroups_dyn(const char *a, gid_t b, long *c, long *d, gid_t **e, long f, int *g) 70 | { 71 | return NSS_STATUS_NOTFOUND; 72 | } 73 | 74 | int main(int argc, char **argv) 75 | { 76 | int fd; 77 | char *socket_path = "/var/run/nscd/socket"; 78 | char *config_path = "/etc/nsswitch.conf"; 79 | char *pid_path = 0; 80 | bool daemonize = false; 81 | unsigned cache_invalidation_time = 0, cache_max_entries = 1000, jobs = 0; 82 | int c; 83 | 84 | signal(SIGPIPE, SIG_IGN); 85 | 86 | init_program_invocation_name(argv[0]); 87 | 88 | while((c = getopt(argc, argv, "c:s:p:C:n:j:d")) != -1) switch(c) { 89 | case 'c': 90 | config_path = optarg; 91 | break; 92 | case 's': 93 | socket_path = optarg; 94 | break; 95 | case 'p': 96 | pid_path = optarg; 97 | break; 98 | case 'j': 99 | jobs = atol(optarg); 100 | if(jobs <= 0) { 101 | die_fmt("invalid jobs parameter: '%s'", optarg); 102 | } 103 | break; 104 | case 'd': 105 | daemonize = true; 106 | break; 107 | case 'C': 108 | cache_invalidation_time = atol(optarg); 109 | if(cache_invalidation_time <= 0) { 110 | die_fmt("invalid cache invalidation time: '%s'", optarg); 111 | } 112 | break; 113 | case 'n': 114 | cache_max_entries = atol(optarg); 115 | if(cache_max_entries <= 0) { 116 | die_fmt("invalid maximum amount of cache entries: '%s'", optarg); 117 | } 118 | break; 119 | default: 120 | return 1; 121 | } 122 | 123 | yyin = fopen(config_path, "r"); 124 | if(!yyin) die_fmt("%s was not found", config_path); 125 | 126 | errno = 0; 127 | if(yyparse()) { 128 | if(errno) die(); 129 | return 1; 130 | } 131 | fclose(yyin); 132 | 133 | link_t *entry_l, *service_l; 134 | 135 | if(cache_invalidation_time) { 136 | if(init_caches(cache_invalidation_time, cache_max_entries)) die(); 137 | } 138 | 139 | entry_l = list_head(&parsed_output); 140 | while(entry_l) { 141 | struct entry *entry = list_ref(entry_l, struct entry, link); 142 | struct service *service; 143 | 144 | service_l = list_head(&entry->services); 145 | while(service_l) { 146 | service = list_ref(service_l, struct service, link); 147 | 148 | for(size_t i = 0; i < 4; i++) { 149 | /* TODO: implement ACT_MERGE */ 150 | if(service->on_status[i] == ACT_MERGE) { 151 | die_fmt("service '%s' is configured with a merge action in '%s', this is unsupported", service->service, config_path); 152 | } 153 | } 154 | 155 | if(entry->database == DB_PASSWD) { 156 | void *dll; 157 | struct mod_passwd *mod; 158 | mod = malloc(sizeof(*mod)); 159 | if(!mod) die(); 160 | 161 | dll = get_dll(service->service); 162 | mod->nss_getpwnam_r = (nss_getpwnam_r)get_fn(dll, "getpwnam_r", service->service); 163 | if(!mod->nss_getpwnam_r) mod->nss_getpwnam_r = null_getpwnam_r; 164 | mod->nss_getpwuid_r = (nss_getpwuid_r)get_fn(dll, "getpwuid_r", service->service); 165 | if(!mod->nss_getpwuid_r) mod->nss_getpwuid_r = null_getpwuid_r; 166 | 167 | memcpy(mod->on_status, service->on_status, sizeof(mod->on_status)); 168 | 169 | list_push_back(&passwd_mods, &mod->link); 170 | } else if(entry->database == DB_GROUP) { 171 | void *dll; 172 | struct mod_group *mod; 173 | mod = malloc(sizeof(*mod)); 174 | if(!mod) die(); 175 | 176 | dll = get_dll(service->service); 177 | mod->nss_getgrnam_r = (nss_getgrnam_r)get_fn(dll, "getgrnam_r", service->service); 178 | if(!mod->nss_getgrnam_r) mod->nss_getgrnam_r = null_getgrnam_r; 179 | mod->nss_getgrgid_r = (nss_getgrgid_r)get_fn(dll, "getgrgid_r", service->service); 180 | if(!mod->nss_getgrgid_r) mod->nss_getgrgid_r = null_getgrgid_r; 181 | mod->nss_initgroups_dyn = (nss_initgroups_dyn)get_fn(dll, "initgroups_dyn", service->service); 182 | if(!mod->nss_initgroups_dyn) mod->nss_initgroups_dyn = null_initgroups_dyn; 183 | 184 | memcpy(mod->on_status, service->on_status, sizeof(mod->on_status)); 185 | 186 | list_push_back(&group_mods, &mod->link); 187 | } 188 | service_l = list_next(service_l); 189 | free(service->service); 190 | free(service); 191 | } 192 | entry_l = list_next(entry_l); 193 | free(entry); 194 | } 195 | 196 | fd = socket(PF_UNIX, SOCK_STREAM, 0); 197 | if(fd < 0) die(); 198 | struct sockaddr_un addr = { 199 | .sun_family = AF_UNIX 200 | }; 201 | strncpy(addr.sun_path, socket_path, sizeof(addr.sun_path)); 202 | if(bind(fd, (struct sockaddr*)&addr, sizeof addr) < 0) { 203 | int tmp_fd; 204 | if(errno != EADDRINUSE) 205 | die(); 206 | tmp_fd = socket(PF_UNIX, SOCK_STREAM, 0); 207 | if(tmp_fd < 0) die(); 208 | if(connect(tmp_fd, (struct sockaddr*)&addr, sizeof addr) >= 0) { 209 | errno = EADDRINUSE; 210 | die(); 211 | } else if(errno != ECONNREFUSED) die(); 212 | close(tmp_fd); 213 | unlink(addr.sun_path); 214 | if(bind(fd, (struct sockaddr*)&addr, sizeof addr) < 0) die(); 215 | } 216 | 217 | chmod(socket_path, 0666); 218 | 219 | if(listen(fd, 100) < 0) die(); 220 | 221 | openlog("musl-nscd", 0 222 | #ifdef LOG_PERROR 223 | | LOG_PERROR 224 | #endif 225 | , LOG_DAEMON); 226 | 227 | if(daemonize) { 228 | int null_fd = 0; 229 | if((null_fd = open("/dev/null", O_RDWR)) < 0) { 230 | syslog(LOG_ERR, "%s", strerror(errno)); 231 | return 1; 232 | } 233 | if(dup2(null_fd, 0) < 0 || dup2(null_fd, 1) < 0 || dup2(null_fd, 2) < 0) { 234 | syslog(LOG_ERR, "%s", strerror(errno)); 235 | return 1; 236 | } 237 | if(null_fd > 2) close(null_fd); 238 | 239 | switch(fork()) { 240 | case 0: break; 241 | case -1: syslog(LOG_ERR, "%s", strerror(errno)); return 1; 242 | default: return 0; 243 | } 244 | 245 | if(setsid() < 0) die(); 246 | 247 | switch(fork()) { 248 | case 0: break; 249 | case -1: syslog(LOG_ERR, "%s", strerror(errno)); return 1; 250 | default: return 0; 251 | } 252 | } 253 | 254 | if(pid_path) { 255 | FILE *f = fopen(pid_path, "w"); 256 | if(!f) { syslog(LOG_ERR, "%s", strerror(errno)); return 1; } 257 | fprintf(f, "%ju\n", (uintmax_t)getpid()); 258 | fclose(f); 259 | } 260 | 261 | chdir("/"); 262 | 263 | if(init_socket_handling(jobs) < 0) die(); 264 | socket_handle(fd); 265 | } 266 | -------------------------------------------------------------------------------- /src/nsswitch.l: -------------------------------------------------------------------------------- 1 | %{ 2 | #include "parse_common.h" 3 | #include 4 | #include 5 | #include 6 | %} 7 | 8 | %x COMMENT 9 | %x LIST 10 | %x ACTION 11 | 12 | %% 13 | 14 | "\n" | 15 | "\n" { BEGIN INITIAL; return '\n'; } 16 | 17 | aliases:? { yylval.database = DB_ALIASES; BEGIN LIST; return TOK_DB; } 18 | ethers:? { yylval.database = DB_ETHERS; BEGIN LIST; return TOK_DB; } 19 | group:? { yylval.database = DB_GROUP; BEGIN LIST; return TOK_DB; } 20 | hosts:? { yylval.database = DB_HOSTS; BEGIN LIST; return TOK_DB; } 21 | initgroups:? { yylval.database = DB_INITGROUPS; BEGIN LIST; return TOK_DB; } 22 | netgroup:? { yylval.database = DB_NETGROUP; BEGIN LIST; return TOK_DB; } 23 | networks:? { yylval.database = DB_NETWORKS; BEGIN LIST; return TOK_DB; } 24 | passwd:? { yylval.database = DB_PASSWD; BEGIN LIST; return TOK_DB; } 25 | protocols:? { yylval.database = DB_PROTOCOLS; BEGIN LIST; return TOK_DB; } 26 | publickey:? { yylval.database = DB_PUBLICKEY; BEGIN LIST; return TOK_DB; } 27 | rpc:? { yylval.database = DB_RPC; BEGIN LIST; return TOK_DB; } 28 | services:? { yylval.database = DB_SERVICES; BEGIN LIST; return TOK_DB; } 29 | shadow:? { yylval.database = DB_SHADOW; BEGIN LIST; return TOK_DB; } 30 | 31 | "[" { BEGIN ACTION; return '['; } 32 | ([[:alnum:]]|_)+ { 33 | yylval.str = strndup(yytext, yyleng); 34 | return TOK_STRING; 35 | } 36 | [ \t] { ; } 37 | 38 | "!"|"=" { return *yytext; } 39 | "]" { BEGIN LIST; return *yytext; } 40 | "SUCCESS" { yylval.status = STS_SUCCESS; return TOK_STS; } 41 | "NOTFOUND" { yylval.status = STS_NOTFOUND; return TOK_STS; } 42 | "UNAVAIL" { yylval.status = STS_UNAVAIL; return TOK_STS; } 43 | "TRYAGAIN" { yylval.status = STS_TRYAGAIN; return TOK_STS; } 44 | "return" { yylval.action = ACT_RETURN; return TOK_ACT; } 45 | "continue" { yylval.action = ACT_CONTINUE; return TOK_ACT; } 46 | "merge" { yylval.action = ACT_MERGE; return TOK_ACT; } 47 | 48 | "#" BEGIN COMMENT; 49 | 50 | [^\n]* ; 51 | 52 | . return *yytext; 53 | %% 54 | 55 | int yywrap(void) 56 | { 57 | return 1; 58 | } 59 | -------------------------------------------------------------------------------- /src/nsswitch.y: -------------------------------------------------------------------------------- 1 | %{ 2 | 3 | #include 4 | #include 5 | #include 6 | #include "parse_common.h" 7 | 8 | list_t parsed_output; 9 | 10 | void yyerror(const char*); 11 | 12 | static const action default_actions[] = { 13 | ACT_RETURN, 14 | ACT_CONTINUE, 15 | ACT_CONTINUE, 16 | ACT_CONTINUE 17 | }; 18 | 19 | %} 20 | 21 | %token STRING 258 22 | %token DB 259 23 | %token STS 260 24 | %token ACT 261 25 | %type modifier 26 | %type item 27 | %type modifiers 28 | %type list 29 | %type line 30 | %type file 31 | 32 | %% 33 | 34 | top: 35 | file { 36 | parsed_output = $1; 37 | } 38 | ; 39 | 40 | file: 41 | %empty { 42 | list_init(&$$); 43 | } 44 | | file line { 45 | if($2.database == (unsigned char)-1) { 46 | $$ = $1; 47 | } else { 48 | struct entry *entry = malloc(sizeof(*entry)); 49 | if(!entry) YYABORT; 50 | memcpy(entry, &$2, sizeof(*entry)); 51 | $$ = $1; 52 | list_push_back(&$$, &(entry->link)); 53 | } 54 | } 55 | ; 56 | 57 | line: 58 | '\n' { 59 | $$.database = (unsigned char)-1; 60 | } 61 | | DB list '\n' { 62 | $$.database = $1; 63 | $$.services = $2; 64 | } 65 | ; 66 | 67 | modifier: 68 | '[' STS ']' { 69 | $$.status = $2; 70 | $$.action = $2 == STS_SUCCESS ? ACT_RETURN : ACT_CONTINUE; 71 | $$.negate = false; 72 | } 73 | | '[' '!' STS ']' { 74 | $$.status = $3; 75 | $$.action = $3 == STS_SUCCESS ? ACT_RETURN : ACT_CONTINUE; 76 | $$.negate = true; 77 | } 78 | | '[' STS '=' ACT ']' { 79 | $$.status = $2; 80 | $$.action = $4; 81 | $$.negate = false; 82 | } 83 | | '[' '!' STS '=' ACT ']' { 84 | $$.status = $3; 85 | $$.action = $5; 86 | $$.negate = true; 87 | } 88 | ; 89 | 90 | modifiers: 91 | %empty { 92 | memcpy($$, default_actions, sizeof($$)); 93 | } 94 | | modifiers modifier { 95 | int i; 96 | memcpy($$, $1, sizeof($$)); 97 | for(i = 0; i < sizeof($$)/sizeof($$[0]); i++) { 98 | if(i == $2.status && !$2.negate) { 99 | $$[i] = $2.action; 100 | } 101 | if(i != $2.status && $2.negate) { 102 | $$[i] = $2.action; 103 | } 104 | } 105 | } 106 | 107 | item: 108 | STRING modifiers { 109 | memcpy($$.on_status, $2, sizeof($2)); 110 | $$.service = $1; 111 | } 112 | ; 113 | 114 | list: 115 | %empty { 116 | list_init(&$$); 117 | } 118 | | list item { 119 | $$ = $1; 120 | struct service *service = malloc(sizeof(*service)); 121 | if(!service) YYABORT; 122 | memcpy(service, &$2, sizeof(*service)); 123 | list_push_back(&$$, &(service->link)); 124 | } 125 | ; 126 | 127 | %% 128 | 129 | void yyerror(const char *s) 130 | { 131 | fprintf(stderr, "%s\n", s); 132 | } 133 | 134 | #if TEST_PARSER 135 | 136 | static const char *dbmap[] = { 137 | "aliases", 138 | "ethers", 139 | "group", 140 | "hosts", 141 | "initgroups", 142 | "netgroup", 143 | "networks", 144 | "passwd", 145 | "protocols", 146 | "publickey", 147 | "rpc", 148 | "services", 149 | "shadow" 150 | }; 151 | 152 | static const char *stsmap[] = { 153 | "SUCCESS", 154 | "NOTFOUND", 155 | "UNAVAIL", 156 | "TRYAGAIN" 157 | }; 158 | 159 | static const char *actmap[] = { 160 | "return", 161 | "continue", 162 | "merge" 163 | }; 164 | 165 | int main() 166 | { 167 | #if YYDEBUG 168 | yydebug = 1; 169 | #endif 170 | if(yyparse()) return 1; 171 | link_t *line, *service; 172 | line = list_head(&parsed_output); 173 | while(line) { 174 | struct entry *entry = list_ref(line, struct entry, link); 175 | printf("%s: ", dbmap[entry->database]); 176 | service = list_head(&entry->services); 177 | while(service) { 178 | struct service *svc = list_ref(service, struct service, link); 179 | printf("%s ", svc->service); 180 | for(int i = 0; i < 4; i++) { 181 | if(svc->on_status[i] != default_actions[i]) 182 | printf("[%s=%s] ", stsmap[i], actmap[svc->on_status[i]]); 183 | } 184 | service = list_next(service); 185 | free(svc->service); 186 | free(svc); 187 | } 188 | printf("\n"); 189 | line = list_next(line); 190 | free(entry); 191 | } 192 | } 193 | 194 | #endif 195 | -------------------------------------------------------------------------------- /src/program_invocation_name.c: -------------------------------------------------------------------------------- 1 | #include "util.h" 2 | 3 | const char *program_invocation_name, *program_invocation_short_name; 4 | 5 | void init_program_invocation_name(const char *x) 6 | { 7 | size_t i; 8 | program_invocation_name = x; 9 | program_invocation_short_name = x; 10 | for(i = 0; x[i]; i++) if(x[i] == '/') program_invocation_short_name = x+i+1; 11 | } 12 | -------------------------------------------------------------------------------- /src/socket_handle.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | 18 | #include "config.h" 19 | #include "util.h" 20 | #include "nss.h" 21 | #include "nscd.h" 22 | #include "parse.h" 23 | #include "modules.h" 24 | #include "list.h" 25 | 26 | /* glibc's NSS_BUFLEN_PASSWD (from pwd/pwd.h) and NSS_BUFLEN_GROUP (from grp/grp.h) 27 | * are set to 1024 and consider it a reasonable default */ 28 | #define BUF_LEN_DEFAULT 1024 29 | /* NGROUPS_MAX value for musl as of 1.2.2, might change 30 | * to keep up with the kernel definition, so we define our own */ 31 | #define INITGR_ALLOC 32 32 | 33 | #define MIN_SERV_THREAD 2 34 | 35 | static int return_result(int fd, int swap, uint32_t reqtype, void *key); 36 | 37 | static int strtouid(const char *restrict buf, uint32_t *id) 38 | { 39 | char *end; 40 | unsigned long n; 41 | errno = 0; 42 | if(!isdigit(buf[0])) { 43 | errno = EINVAL; 44 | return 1; 45 | } 46 | n = strtoul(buf, &end, 10); 47 | if(n == ULONG_MAX) { 48 | if(errno) return 1; 49 | } 50 | if(n > UINT32_MAX || *end != '\0') { 51 | errno = EINVAL; 52 | return 1; 53 | } 54 | *id = n; 55 | return 0; 56 | } 57 | 58 | struct serv_thread { 59 | pthread_t t; 60 | sem_t s; 61 | /* needs to be atomic because it might be scanned by the listen thread. 62 | * a value of -1 means the thread is available to take a new query */ 63 | atomic_int fd; 64 | } static *serv_threads; 65 | 66 | /* number of server threads */ 67 | static size_t serv_n; 68 | /* semaphore holding how many server threads are available to take a query */ 69 | static sem_t listen_sem; 70 | 71 | static locale_t l; 72 | 73 | static void *serv_thread(void *arg) 74 | { 75 | struct serv_thread *st = arg; 76 | 77 | for(;;) { 78 | int n; 79 | int errno_stash; 80 | uint32_t buf[REQ_LEN]; 81 | char *str = 0; 82 | char idbuf[11]; 83 | uint32_t id; 84 | void *key; 85 | int swap = 0; 86 | 87 | /* wait for job to be posted to this thread */ 88 | sem_wait(&st->s); 89 | /* capture fd to be used */ 90 | n = st->fd; 91 | 92 | if(full_read(n, (char*)buf, sizeof buf) < 0) { 93 | syslog(LOG_ERR, "error in read: %s", strerror_l(errno, l)); 94 | goto cleanup_fd; 95 | } 96 | 97 | if(buf[REQVERSION] != NSCDVERSION && buf[REQVERSION] == swap32(NSCDVERSION)) { 98 | /* means our endianness doesn't match the requester's */ 99 | swap = 1; 100 | for(int i = 0; i < REQ_LEN; i++) 101 | buf[i] = swap32(buf[i]); 102 | } 103 | if(buf[REQVERSION] != NSCDVERSION) { 104 | syslog(LOG_WARNING, "Received invalid request for NSCD version %"PRIu32", expected 2", buf[REQVERSION]); 105 | goto cleanup_fd; 106 | } 107 | if(buf[REQKEYLEN] == 0) { 108 | syslog(LOG_WARNING, "Received invalid request with a key length of 0; expected greater than 0"); 109 | goto cleanup_fd; 110 | } 111 | 112 | switch(buf[REQTYPE]) { 113 | case GETPWBYNAME: case GETGRBYNAME: case GETINITGR: 114 | str = malloc(buf[REQKEYLEN]); 115 | if(!str) { 116 | syslog(LOG_ERR, "error in malloc: %s", strerror_l(errno, l)); 117 | goto cleanup_fd; 118 | } 119 | if(full_read(n, str, buf[REQKEYLEN]) < 0) { 120 | syslog(LOG_ERR, "error in read: %s", strerror_l(errno, l)); 121 | goto cleanup_mem; 122 | } 123 | if(str[buf[REQKEYLEN]-1]) { 124 | syslog(LOG_ERR, "Received invalid request"); 125 | goto cleanup_mem; 126 | } 127 | key = str; 128 | break; 129 | case GETPWBYUID: case GETGRBYGID: 130 | if(buf[REQKEYLEN] > 11) { 131 | syslog(LOG_ERR, "Received invalid request for %"PRIu32", expected length 11 or less got %"PRIu32, buf[REQTYPE], buf[REQKEYLEN]); 132 | goto cleanup_fd; 133 | } 134 | if(full_read(n, idbuf, buf[REQKEYLEN]) < 0) { 135 | syslog(LOG_ERR, "error in read: %s", strerror_l(errno, l)); 136 | goto cleanup_fd; 137 | } 138 | if(idbuf[buf[REQKEYLEN]-1]) { 139 | syslog(LOG_ERR, "Received invalid request"); 140 | goto cleanup_fd; 141 | } 142 | if(strtouid(idbuf, &id)) { 143 | syslog(LOG_ERR, "Received invalid request"); 144 | goto cleanup_fd; 145 | } 146 | key = &id; 147 | break; 148 | default: 149 | syslog(LOG_INFO, "Unsupported request %"PRIu32, buf[REQTYPE]); 150 | goto cleanup_fd; 151 | } 152 | 153 | /* if return_result fails for any reason, we will just close the socket */ 154 | return_result(n, swap, buf[REQTYPE], key); 155 | 156 | cleanup_mem: 157 | errno_stash = errno; 158 | if(str) free(str); 159 | errno = errno_stash; 160 | cleanup_fd: 161 | errno_stash = errno; 162 | close(n); 163 | errno = errno_stash; 164 | 165 | /* reset fd so listener thread knows this thread is available */ 166 | st->fd = -1; 167 | /* track number of available threads */ 168 | sem_post(&listen_sem); 169 | } 170 | 171 | return 0; 172 | } 173 | 174 | static size_t buf_len_passwd, buf_len_group; 175 | 176 | int init_socket_handling(unsigned jobs) 177 | { 178 | /* temporary variable needs to be signed */ 179 | long tmp; 180 | tmp = sysconf(_SC_GETPW_R_SIZE_MAX); 181 | buf_len_passwd = (tmp > 0) ? tmp : BUF_LEN_DEFAULT; 182 | tmp = sysconf(_SC_GETGR_R_SIZE_MAX); 183 | buf_len_group = (tmp > 0) ? tmp : BUF_LEN_DEFAULT; 184 | 185 | l = newlocale(LC_ALL_MASK, "C", (locale_t)0); 186 | if(!l) return -1; 187 | 188 | /* keep the total of threads at jobs */ 189 | serv_n = (jobs > MIN_SERV_THREAD ? jobs : MIN_SERV_THREAD) - 1; 190 | 191 | /* starts with all server threads available */ 192 | if(sem_init(&listen_sem, 0, serv_n) < 0) return -1; 193 | 194 | serv_threads = calloc(serv_n, sizeof(*serv_threads)); 195 | if(!serv_threads) return -1; 196 | for(size_t i = 0; i < serv_n; i++) { 197 | if(sem_init(&serv_threads[i].s, 0, 0) < 0) return -1; 198 | if(pthread_create(&serv_threads[i].t, 0, serv_thread, serv_threads+i) < 0) return -1; 199 | serv_threads[i].fd = -1; 200 | } 201 | 202 | return 0; 203 | } 204 | 205 | void socket_handle(int fd) 206 | { 207 | struct pollfd pollfd; 208 | pollfd.fd = fd; 209 | pollfd.events = POLLIN; 210 | 211 | for(;;) { 212 | int n; 213 | 214 | n = poll(&pollfd, 1, -1); 215 | if(n < 0) { 216 | if(errno == EINTR) continue; 217 | syslog(LOG_ERR, "error in poll: %s", strerror_l(errno, l)); 218 | continue; 219 | } 220 | n = accept(fd, 0, 0); 221 | if(n < 0) { 222 | if(errno == EINTR) continue; 223 | syslog(LOG_ERR, "error in accept: %s", strerror_l(errno, l)); 224 | continue; 225 | } 226 | 227 | /* wait for a server thread to be available */ 228 | do { 229 | sem_wait(&listen_sem); 230 | } while (errno == EINTR); 231 | 232 | /* find the available server thread */ 233 | for(size_t i = 0; i < serv_n; i++) { 234 | if(serv_threads[i].fd < 0) { 235 | serv_threads[i].fd = n; 236 | sem_post(&serv_threads[i].s); 237 | n = -1; 238 | break; 239 | } 240 | } 241 | 242 | /* we will always have called one thread */ 243 | assert(n == -1); 244 | } 245 | } 246 | 247 | static enum nss_status nss_getkey_cache(uint32_t reqtype, void *key, void *res, char **buf, int *ret) 248 | { 249 | switch(reqtype) { 250 | case GETPWBYNAME: 251 | return cache_getpwnam_r((char*)key, (struct passwd*)res, buf, ret); 252 | case GETPWBYUID: 253 | return cache_getpwuid_r((uid_t)*(uint32_t*)key, (struct passwd*)res, buf, ret); 254 | case GETGRBYNAME: 255 | return cache_getgrnam_r((char*)key, (struct group*)res, buf, ret); 256 | case GETGRBYGID: 257 | return cache_getgrgid_r((gid_t)*(uint32_t*)key, (struct group*)res, buf, ret); 258 | case GETINITGR: 259 | return cache_initgroups_dyn((char*)key, res, ret); 260 | } 261 | 262 | /* for debugging purposes, is unreachable */ 263 | abort(); 264 | } 265 | 266 | static enum nss_status nss_getkey(uint32_t reqtype, struct mod_passwd *mod_passwd, struct mod_group *mod_group, void *key, void *res, char *buf, size_t n, int *ret) 267 | { 268 | int retval = NSS_STATUS_UNAVAIL; 269 | struct initgroups_res *initgroups_res; 270 | 271 | /* for debug only: guarantee the nss_getkey function is being used correctly */ 272 | if(ISPWREQ(reqtype)) assert(mod_passwd); 273 | else assert(mod_group); 274 | 275 | switch(reqtype) { 276 | case GETPWBYNAME: 277 | retval = mod_passwd->nss_getpwnam_r((char*)key, (struct passwd*)res, buf, n, ret); 278 | break; 279 | case GETPWBYUID: 280 | retval = mod_passwd->nss_getpwuid_r((uid_t)*(uint32_t*)key, (struct passwd*)res, buf, n, ret); 281 | break; 282 | case GETGRBYNAME: 283 | retval = mod_group->nss_getgrnam_r((char*)key, (struct group*)res, buf, n, ret); 284 | break; 285 | case GETGRBYGID: 286 | retval = mod_group->nss_getgrgid_r((gid_t)*(uint32_t*)key, (struct group*)res, buf, n, ret); 287 | break; 288 | case GETINITGR: 289 | initgroups_res = res; 290 | initgroups_res->end = 0; 291 | initgroups_res->alloc = INITGR_ALLOC + 1; 292 | initgroups_res->grps = malloc(sizeof(gid_t) * initgroups_res->alloc); 293 | if(!initgroups_res->grps) { 294 | *ret = errno; 295 | return NSS_STATUS_TRYAGAIN; 296 | } 297 | retval = mod_group->nss_initgroups_dyn((char*)key, (gid_t)-1, &(initgroups_res->end), &(initgroups_res->alloc), &(initgroups_res->grps), UINT32_MAX, ret); 298 | break; 299 | } 300 | if(retval == NSS_STATUS_SUCCESS && ISPWREQ(reqtype)) { 301 | struct passwd *pwd = res; 302 | if(!pwd->pw_name) retval = NSS_STATUS_NOTFOUND; 303 | #ifdef HAVE_PW_PASSWD 304 | if(!pwd->pw_passwd) retval = NSS_STATUS_NOTFOUND; 305 | #endif 306 | #ifdef HAVE_PW_GECOS 307 | if(!pwd->pw_gecos) retval = NSS_STATUS_NOTFOUND; 308 | #endif 309 | if(!pwd->pw_dir) retval = NSS_STATUS_NOTFOUND; 310 | if(!pwd->pw_shell) retval = NSS_STATUS_NOTFOUND; 311 | } 312 | if(retval == NSS_STATUS_SUCCESS && ISGRPREQ(reqtype)) { 313 | struct group *grp = res; 314 | if(!grp->gr_name) retval = NSS_STATUS_NOTFOUND; 315 | #ifdef HAVE_GR_PASSWD 316 | if(!grp->gr_passwd) retval = NSS_STATUS_NOTFOUND; 317 | #endif 318 | if(!grp->gr_mem) retval = NSS_STATUS_NOTFOUND; 319 | } 320 | return retval; 321 | } 322 | 323 | int return_result(int fd, int swap, uint32_t reqtype, void *key) 324 | { 325 | union { 326 | struct passwd p; 327 | struct group g; 328 | struct initgroups_res l; 329 | } res; 330 | enum nss_status status; 331 | int ret = 0; 332 | char *buf = 0; 333 | /* true if using passwd_mods, false if using group_mods */ 334 | bool using_passwd; 335 | 336 | link_t *l; 337 | 338 | /* macro to free the temporary resources allocated by return_result: 339 | * getpw* and getgr* requests use buf, 340 | * while initgroups uses the array in res.l.grps */ 341 | #define FREE_ALLOC() \ 342 | do{ if(ISPWREQ(reqtype)||ISGRPREQ(reqtype)) free(buf); else free(res.l.grps); } while(0) 343 | 344 | if(ISPWREQ(reqtype)) { 345 | using_passwd = true; 346 | l = list_head(&passwd_mods); 347 | } else { 348 | using_passwd = false; 349 | l = list_head(&group_mods); 350 | } 351 | 352 | memset(&res, 0, sizeof res); 353 | if((status = nss_getkey_cache(reqtype, key, &res, &buf, &ret)) == NSS_STATUS_SUCCESS) { 354 | int err; 355 | if(ISPWREQ(reqtype)) { 356 | err = write_pwd(fd, swap, &res.p); 357 | } else if(ISGRPREQ(reqtype)) { 358 | err = write_grp(fd, swap, &res.g); 359 | } else { 360 | err = write_groups(fd, swap, res.l.end, res.l.grps); 361 | } 362 | /* functions only allocate if successful */ 363 | FREE_ALLOC(); 364 | return err; 365 | } 366 | 367 | for(; l; l = list_next(l)) { 368 | int act; 369 | action *on_status; 370 | struct mod_group *mod_group; 371 | struct mod_passwd *mod_passwd; 372 | size_t buf_len = 0; 373 | 374 | /* initialize same as above */ 375 | ret = 0; 376 | buf = 0; 377 | 378 | if(using_passwd) { 379 | mod_passwd = list_ref(l, struct mod_passwd, link); 380 | mod_group = 0; 381 | } else { 382 | mod_group = list_ref(l, struct mod_group, link); 383 | mod_passwd = 0; 384 | } 385 | 386 | /* GETINITGR doesn't use buf */ 387 | if(ISPWREQ(reqtype) || ISGRPREQ(reqtype)) { 388 | if(ISPWREQ(reqtype)) { 389 | buf_len = buf_len_passwd; 390 | } else if(ISGRPREQ(reqtype)) { 391 | buf_len = buf_len_group; 392 | } 393 | 394 | buf = malloc(buf_len); 395 | if(!buf) return -1; 396 | } 397 | 398 | do { 399 | memset(&res, 0, sizeof(res)); 400 | status = nss_getkey(reqtype, mod_passwd, mod_group, key, &res, buf, buf_len, &ret); 401 | if(status == NSS_STATUS_TRYAGAIN && ret == ERANGE) { 402 | size_t new_len; 403 | char *new_buf; 404 | if(buf_len == SIZE_MAX) { 405 | free(buf); 406 | errno = ENOMEM; 407 | return -1; 408 | } 409 | /* memory growth factor is 1.5x. 410 | * to avoid overshooting SIZE_MAX and overflowing, 411 | * we use the check below: buf_len > (2/3) * SIZE_MAX */ 412 | if(buf_len > SIZE_MAX - buf_len/2) { 413 | new_len = SIZE_MAX; 414 | } else { 415 | /* buf_len * 1.5 */ 416 | new_len = buf_len + buf_len/2; 417 | } 418 | /* TODO: doesn't need to be a realloc, 419 | * since we don't need to copy the memory; 420 | * evaluate if it's better or worse than malloc+free */ 421 | new_buf = realloc(buf, new_len); 422 | if(!new_buf) { 423 | free(buf); 424 | return -1; 425 | } 426 | buf = new_buf; 427 | buf_len = new_len; 428 | } 429 | } while(status == NSS_STATUS_TRYAGAIN && ret == ERANGE); 430 | 431 | on_status = using_passwd ? mod_passwd->on_status : mod_group->on_status; 432 | act = on_status[ 433 | status == NSS_STATUS_TRYAGAIN ? STS_TRYAGAIN : 434 | status == NSS_STATUS_UNAVAIL ? STS_UNAVAIL : 435 | status == NSS_STATUS_NOTFOUND ? STS_NOTFOUND : 436 | STS_SUCCESS]; 437 | 438 | if(act == ACT_RETURN) { 439 | int err; 440 | /* the write_* functions also validate the entry, and will return -2 441 | * in case it's invalid (basically, if it can't be sent via the nscd protocol) */ 442 | if(ISPWREQ(reqtype)) { 443 | err = write_pwd(fd, swap, status == NSS_STATUS_SUCCESS ? &res.p : 0); 444 | } else if(ISGRPREQ(reqtype)) { 445 | err = write_grp(fd, swap, status == NSS_STATUS_SUCCESS ? &res.g : 0); 446 | } else { 447 | err = write_groups(fd, swap, status == NSS_STATUS_SUCCESS ? res.l.end : 0, status == NSS_STATUS_SUCCESS ? res.l.grps : 0); 448 | } 449 | 450 | if(err == -2) { 451 | /* the buffers will no longer be used */ 452 | FREE_ALLOC(); 453 | /* we treat an invalid entry as the service being unavailable */ 454 | if(on_status[STS_UNAVAIL] == ACT_RETURN) { 455 | if(ISPWREQ(reqtype)) 456 | return write_pwd(fd, swap, 0) > 0 ? 0 : -1; 457 | else if(ISGRPREQ(reqtype)) 458 | return write_grp(fd, swap, 0) > 0 ? 0 : -1; 459 | else 460 | return write_groups(fd, swap, 0, 0) > 0 ? 0 : -1; 461 | } 462 | /* for actions other than ACT_RETURN we will try other modules */ 463 | continue; 464 | } 465 | 466 | /* if the write was successful, we will return 0, 467 | * otherwise, we will return -1 */ 468 | if(err > 0) 469 | err = 0; 470 | 471 | /* this entry wasn't in cache when we tried! */ 472 | if(status == NSS_STATUS_SUCCESS) { 473 | /* we null buf here when it's given to a cache_*_add functions, 474 | * since the cache function takes ownership of it. 475 | * this way, the free() call below will be a no op */ 476 | if(ISPWREQ(reqtype)) { 477 | cache_passwd_add(&res.p, buf, buf_len); 478 | buf = 0; 479 | } else if(ISGRPREQ(reqtype)) { 480 | cache_group_add(&res.g, buf, buf_len); 481 | buf = 0; 482 | } else { 483 | cache_initgroups_add(&res.l, key); 484 | res.l.grps = 0; 485 | } 486 | } 487 | /* we have to free resources for the case when status isn't SUCCESS */ 488 | FREE_ALLOC(); 489 | 490 | return err; 491 | } 492 | 493 | /* we have to free resources for the case when action isn't RETURN */ 494 | FREE_ALLOC(); 495 | } while(l); 496 | 497 | /* if everything else errored out, we send an empty message */ 498 | if(ISPWREQ(reqtype)) 499 | return write_pwd(fd, swap, 0) > 0 ? 0 : -1; 500 | else if(ISGRPREQ(reqtype)) 501 | return write_grp(fd, swap, 0) > 0 ? 0 : -1; 502 | else 503 | return write_groups(fd, swap, 0, 0) > 0 ? 0 : -1; 504 | } 505 | -------------------------------------------------------------------------------- /src/swap32.c: -------------------------------------------------------------------------------- 1 | #include "util.h" 2 | 3 | uint32_t swap32(uint32_t x) 4 | { 5 | return x>>24 | (x>>8&0xff00) | (x<<8&0xff0000) | x<<24; 6 | } 7 | -------------------------------------------------------------------------------- /src/write_val.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include "config.h" 7 | #include "util.h" 8 | #include "nscd.h" 9 | 10 | int write_pwd(int fd, int swap, struct passwd *pwd) 11 | { 12 | uint32_t head[PW_LEN] = { 13 | NSCDVERSION 14 | }; 15 | size_t namelen = 0, passwdlen = 0, gecoslen = 0, dirlen = 0, shelllen = 0; 16 | char *name_fld, *passwd_fld, *gecos_fld, *dir_fld, *shell_fld; 17 | 18 | if(!pwd) { 19 | if(swap) swap32(head[0]); 20 | return full_write(fd, (char*)head, sizeof(head)); 21 | } 22 | 23 | name_fld = pwd->pw_name ? pwd->pw_name : ""; 24 | namelen = strlen(name_fld) + 1; 25 | #ifdef HAVE_PW_PASSWD 26 | passwd_fld = pwd->pw_passwd ? pwd->pw_passwd : ""; 27 | #else 28 | passwd_fld = ""; 29 | #endif 30 | passwdlen = strlen(passwd_fld) + 1; 31 | #ifdef HAVE_PW_GECOS 32 | gecos_fld = pwd->pw_gecos ? pwd->pw_gecos : ""; 33 | #else 34 | gecos_fld = ""; 35 | #endif 36 | gecoslen = strlen(gecos_fld) + 1; 37 | dir_fld = pwd->pw_dir ? pwd->pw_dir : ""; 38 | dirlen = strlen(dir_fld) + 1; 39 | shell_fld = pwd->pw_shell ? pwd->pw_shell : ""; 40 | shelllen = strlen(shell_fld) + 1; 41 | 42 | if( namelen > UINT32_MAX || passwdlen > UINT32_MAX 43 | || gecoslen > UINT32_MAX || dirlen > UINT32_MAX 44 | || shelllen > UINT32_MAX 45 | || pwd->pw_uid < 0 || pwd->pw_uid > UINT32_MAX 46 | || pwd->pw_gid < 0 || pwd->pw_gid > UINT32_MAX) 47 | return -2; 48 | 49 | head[PWFOUND] = 1; 50 | head[PWNAMELEN] = namelen; 51 | head[PWPASSWDLEN] = passwdlen; 52 | head[PWUID] = pwd->pw_uid; 53 | head[PWGID] = pwd->pw_gid; 54 | head[PWGECOSLEN] = gecoslen; 55 | head[PWDIRLEN] = dirlen; 56 | head[PWSHELLLEN] = shelllen; 57 | 58 | if(swap) { 59 | int i; 60 | for(i = 0; i < PW_LEN; i++) 61 | head[i] = swap32(head[i]); 62 | } 63 | 64 | if(full_write(fd, (char*)head, sizeof head) < 0) return -1; 65 | 66 | if(full_write(fd, name_fld, namelen) < 0) return -1; 67 | if(full_write(fd, passwd_fld, passwdlen) < 0) return -1; 68 | if(full_write(fd, gecos_fld, gecoslen) < 0) return -1; 69 | if(full_write(fd, dir_fld, dirlen) < 0) return -1; 70 | if(full_write(fd, shell_fld, shelllen) < 0) return -1; 71 | return 0; 72 | } 73 | 74 | int write_grp(int fd, int swap, struct group *grp) 75 | { 76 | uint32_t head[GR_LEN] = { 77 | NSCDVERSION 78 | }; 79 | size_t namelen = 0, passwdlen = 0, memcnt = 0, i; 80 | char *name_fld, *passwd_fld; 81 | if(!grp) { 82 | if(swap) swap32(head[0]); 83 | return full_write(fd, (char*)head, sizeof(head)); 84 | } 85 | 86 | name_fld = grp->gr_name ? grp->gr_name : ""; 87 | namelen = strlen(name_fld) + 1; 88 | #ifdef HAVE_GR_PASSWD 89 | passwd_fld = grp->gr_passwd ? grp->gr_passwd : ""; 90 | #else 91 | passwd_fld = ""; 92 | #endif 93 | passwdlen = strlen(passwd_fld) + 1; 94 | 95 | for(i = 0; grp->gr_mem[i]; i++) { 96 | memcnt++; 97 | #if SIZE_MAX > UINT32_MAX 98 | if(strnlen(grp->gr_mem[i], UINT32_MAX) + 1 >= UINT32_MAX) 99 | return -2; 100 | #endif 101 | } 102 | 103 | if( namelen > UINT32_MAX || passwdlen > UINT32_MAX 104 | || memcnt > UINT32_MAX 105 | || grp->gr_gid < 0 || grp->gr_gid > UINT32_MAX) { 106 | return -2; 107 | } 108 | 109 | head[GRFOUND] = 1; 110 | head[GRNAMELEN] = namelen; 111 | head[GRPASSWDLEN] = passwdlen; 112 | head[GRGID] = grp->gr_gid; 113 | head[GRMEMCNT] = memcnt; 114 | 115 | if(swap) { 116 | for(i = 0; i < GR_LEN; i++) { 117 | head[i] = swap32(head[i]); 118 | } 119 | } 120 | 121 | if(full_write(fd, (char*)head, sizeof head) < 0) return -1; 122 | 123 | for(i = 0; grp->gr_mem[i]; i++) { 124 | uint32_t len, swaplen; 125 | swaplen = len = strlen(grp->gr_mem[i]) + 1; 126 | if(swap) swaplen = swap32(swaplen); 127 | if(full_write(fd, (char*)&swaplen, sizeof(uint32_t)) < 0) return -1; 128 | } 129 | if(full_write(fd, name_fld, namelen) < 0) return -1; 130 | if(full_write(fd, passwd_fld, passwdlen) < 0) return -1; 131 | for(i = 0; grp->gr_mem[i]; i++) { 132 | uint32_t len = strlen(grp->gr_mem[i]) + 1; 133 | if(full_write(fd, grp->gr_mem[i], len) < 0) return -1; 134 | } 135 | return 0; 136 | } 137 | 138 | int write_groups(int fd, int swap, size_t len, gid_t *groups) 139 | { 140 | uint32_t head[INITGR_LEN] = { 141 | NSCDVERSION 142 | }; 143 | size_t i; 144 | if(len > UINT32_MAX) { 145 | return -2; 146 | } 147 | head[INITGRNGRPS] = len; 148 | for(i = 0; i < len; i++) { 149 | if(groups[i] == (gid_t)-1) { 150 | head[INITGRNGRPS]--; 151 | continue; 152 | } 153 | if(groups[i] < 0 || groups[i] > UINT32_MAX) 154 | return -2; 155 | } 156 | head[INITGRFOUND] = !!len; 157 | 158 | if(swap) { 159 | for(i = 0; i < INITGR_LEN; i++) { 160 | head[i] = swap32(head[i]); 161 | } 162 | } 163 | 164 | if(full_write(fd, (char*)head, sizeof head) < 0) return -1; 165 | 166 | for(i = 0; i < len; i++) { 167 | if(groups[i] == (gid_t)-1) continue; 168 | uint32_t tmp = swap ? swap32(groups[i]) : groups[i]; 169 | if(full_write(fd, (char*)&tmp, sizeof(uint32_t)) < 0) return -1; 170 | } 171 | 172 | return 0; 173 | } 174 | -------------------------------------------------------------------------------- /tools/gen_config.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | echo "#ifndef CONFIG_H" 4 | echo "#define CONFIG_H 1" 5 | for i in $1/port/*.c;do 6 | f=$(basename "$i" .c) 7 | F=$(basename "$i" .c | tr a-z A-Z) 8 | if [ -s "obj/test/port/$f" ];then 9 | echo "#define HAVE_$F 1" 10 | else 11 | echo "#undef HAVE_$F" 12 | fi 13 | done 14 | echo "#endif" 15 | -------------------------------------------------------------------------------- /tools/install.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # 3 | # This is an actually-safe install command which installs the new 4 | # file atomically in the new location, rather than overwriting 5 | # existing files. 6 | # 7 | 8 | usage() { 9 | printf "usage: %s [-D] [-l] [-m mode] src dest\n" "$0" 1>&2 10 | exit 1 11 | } 12 | 13 | mkdirp= 14 | symlink= 15 | mode=755 16 | 17 | while getopts Dlm: name ; do 18 | case "$name" in 19 | D) mkdirp=yes ;; 20 | l) symlink=yes ;; 21 | m) mode=$OPTARG ;; 22 | ?) usage ;; 23 | esac 24 | done 25 | shift $(($OPTIND - 1)) 26 | 27 | test "$#" -eq 2 || usage 28 | src=$1 29 | dst=$2 30 | tmp="$dst.tmp.$$" 31 | 32 | case "$dst" in 33 | */) printf "%s: %s ends in /\n", "$0" "$dst" 1>&2 ; exit 1 ;; 34 | esac 35 | 36 | set -C 37 | set -e 38 | 39 | if test "$mkdirp" ; then 40 | umask 022 41 | case "$2" in 42 | */*) mkdir -p "${dst%/*}" ;; 43 | esac 44 | fi 45 | 46 | trap 'rm -f "$tmp"' EXIT INT QUIT TERM HUP 47 | 48 | umask 077 49 | 50 | if test "$symlink" ; then 51 | ln -s "$1" "$tmp" 52 | else 53 | cat < "$1" > "$tmp" 54 | chmod "$mode" "$tmp" 55 | fi 56 | 57 | mv -f "$tmp" "$2" 58 | test -d "$2" && { 59 | rm -f "$2/$tmp" 60 | printf "%s: %s is a directory\n" "$0" "$dst" 1>&2 61 | exit 1 62 | } 63 | 64 | exit 0 65 | --------------------------------------------------------------------------------