# Functions for opening and closing file descriptors # # Copyright (C) 2013 Patrick McDermott # # This file is part of the ProteanOS Development Kit. # # The ProteanOS Development Kit is free software: you can redistribute # it and/or modify it under the terms of the GNU General Public License # as published by the Free Software Foundation, either version 3 of the # License, or (at your option) any later version. # # The ProteanOS Development Kit is distributed in the hope that it # will be useful, but WITHOUT ANY WARRANTY; without even the implied # warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. # See the GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with the ProteanOS Development Kit. If not, see # . # FD 3 is available as a temporary FD. _FD_MIN=4 # Shells and the file descriptors they reserve for the user: # * Debian Almquist Shell # - The shell doesn't understand any file descriptor greater than 9. # - File descriptors starting at 10 are used for I/O redirection. # * BusyBox ash # - File descriptors starting at 10 are used for job control and I/O # redirection. # * GNU Bash: # - GNU Readline uses file descriptor 255 in interactive shells. # - File descriptors starting at 10 are used for I/O redirection. # * MirOS Korn Shell # - File descriptors starting at either 10 or 24 are used for the shell's # tty_fd and shl_dbg_fd. # * Solaris ksh # - The shell doesn't understand any file descriptor greater than 9. _FD_MAX=9 FD= fdalloc() { local i= local fd= # Find first available file descriptor. i=${_FD_MIN} while [ ${i} -le ${_FD_MAX} ]; do if [ "x$(eval "printf '%s' \"\${_fd_${i}+set}\"")" != 'xset' ] then fd=${i} break fi i=$((${i} + 1)) done if [ "x${fd:+set}" != 'xset' ]; then error "$(get_msg 'emfile')" return 1 fi FD="${fd}" return 0 } fopen() { local path="${1}" local mode="${2}" shift 2 case "${mode}" in 'r') mode='<' ;; 'w') mode='>' ;; 'a') mode='>>';; 'rw') mode='<>';; *) return 125;; esac fdalloc || return 1 if eval "exec ${FD}${mode}\"\${path}\""; then eval "_fd_${FD}=\"\${mode}\${path}\"" return 0 else error "$(get_msg 'cant_fopen')" FD= return 1 fi } fclose() { local fd="${1}" shift 1 # Make sure the file descriptor is open. if [ "x$(eval "printf '%s' \"\${_fd_${fd}+set}\"")" != 'xset' ]; then error "$(get_msg 'ebadf')" return 1 fi eval "exec ${fd}>&-" unset "_fd_${fd}" return 0 }