/usr/share/scheme48-1.9/posix/io.scm is in scheme48 1.9-5.
This file is owned by root:root, with mode 0o644.
The actual contents of the file can be viewed below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 | ; Part of Scheme 48 1.9. See file COPYING for notices and license.
; Authors: Richard Kelsey, Jonathan Rees, Marcus Crestani, Mike Sperber
; Calls from Section 6 of POSIX.
(import-dynamic-externals "=scheme48external/posix")
; First some port manipulation routines.
(define (fd-port? port)
(if (port->channel port)
#t
#f))
(define (port->fd port)
(let ((channel (port->channel port)))
(if channel
(channel-os-index channel)
#f)))
;----------------
; 4.7 Terminal Identification
; Out of place, but it makes more sense here.
(define (port-is-a-terminal? port)
(cond ((not (port? port))
(assertion-violation 'port-is-a-terminal? "not a port" port))
((port->channel port)
=> channel-is-a-terminal?)
(else
#f)))
(define (port-terminal-name port)
(cond ((not (port? port))
(assertion-violation 'port-terminal-name "not a port" port))
((port->channel port)
=> (lambda (channel)
(byte-vector->os-string (channel-terminal-name channel))))
(else
#f)))
(import-lambda-definition-2 channel-is-a-terminal? (channel) "posix_is_a_tty")
(import-lambda-definition-2 channel-terminal-name (channel) "posix_tty_name")
;----------------
; 6.1 Pipes
(define (open-pipe)
(let ((in-out (call-imported-binding-2 posix-pipe)))
(values (input-channel->port (car in-out))
(output-channel->port (cdr in-out)))))
(import-definition posix-pipe)
;----------------
; 6.2 File descriptor manipulation.
; (DUP <fd-port>) -> fd-port
; (DUP2 <fd-port> <file descriptor>) -> fd-port
; (DUP-SWITCHING_MODE <fd-port>) -> fd-port
; (CHANNEL-DUP <channel>) -> channel
; (CHANNEL-DUP2 <channel> <file descriptor>) -> channel
; These change a ports file descriptor and return a new port (or channel)
; port that uses the old one's file descriptor. DUP uses the lowest unused
; file descriptor, DUP2 uses the one provided. If any existing channel
; uses the file descriptor passed to DUP2, that channel is closed.
; DUP-SWITCHING-MODE is the same as DUP except that the returned port has
; the opposite polarity.
(define (dup port)
(let ((channel (maybe-x->channel port)))
(if channel
((if (input-port? port)
input-channel->port
output-channel->port)
(channel-dup channel))
(assertion-violation 'dup "argument cannot be coerced to channel" port))))
(define (channel-dup channel)
(really-dup channel #f))
(define (dup-switching-mode port)
(let ((channel (maybe-x->channel port)))
(if channel
(if (input-port? port)
(output-channel->port
(really-dup channel (enum channel-status-option output)))
(input-channel->port
(really-dup channel (enum channel-status-option input))))
(assertion-violation 'dup-switching-mode "argument cannot be coerced to channel" port))))
(define (dup2 port fd)
(let ((channel (maybe-x->channel port)))
(if channel
((if (input-port? port)
input-channel->port
output-channel->port)
(channel-dup2 channel fd))
(assertion-violation 'dup2 "argument cannot be coerced to channel" port fd))))
(import-lambda-definition-2 really-dup (channel new-status) "posix_dup")
(import-lambda-definition-2 channel-dup2 (channel fd) "posix_dup2")
; A higher-level interface for DUP and DUP2.
;
; (remap-file-descriptors! . ports&channels)
;
; PORTS&CHANNELS gives the desired locations of the file descriptors associated
; with the ports and channels. (REMAP-FILE-DESCRIPTORS! P1 #F P2) moves P1's
; file descriptor to 0 and P2's to 2. All other channels are closed. The same
; file descriptor may be moved to multiple locations.
;
; It would be nice if this closed the port associated with a closed channel,
; but it doesn't.
;
; This is a classical parallel assignment problem. What we do is figure out a
; series of DUP()'s and DUP2()'s that produce the desired arrangement.
; FIND-TARGETS separates out the channels that must be moved to multiple file
; descriptors. We do the parallel assignment, and then do any duplications.
; Finally, any channels which were not mentioned in PORTS&CHANNELS are
; marked close-on-exec.
(define (remap-file-descriptors! . ports&channels)
(let ((channels (maybe-xs->channels ports&channels #t)))
(if channels
(call-with-values
(lambda ()
(find-targets channels))
(lambda (targets extras)
(do-dups targets)
(for-each (lambda (pair)
(channel-dup2 (cdr pair) (car pair)))
extras)
(let ((channels (list->vector channels)))
(for-each (lambda (channel)
(let ((index (channel-os-index channel)))
(if (or (<= (vector-length channels) index)
(not (vector-ref channels index)))
(set-close-on-exec?! channel #t))))
(open-channels-list)))))
(apply assertion-violation 'remap-file-descriptors!
"not all arguments can be mapped to channels"
ports&channels))))
(define (close-all-but . ports&channels)
(let ((channels (maybe-xs->channels ports&channels #f)))
(if channels
(for-each (lambda (channel)
(if (not (memq channel channels))
(close-channel channel)))
(open-channels-list))
(apply assertion-violation 'close-all-but
"not all arguments can be mapped to channels"
ports&channels))))
; Coerce PORT-OR-CHANNEL to a channel, if possible.
(define (maybe-x->channel port-or-channel)
(cond ((channel? port-or-channel)
port-or-channel)
((fd-port? port-or-channel)
(port->channel port-or-channel))
(else
#f)))
; Coerce PORTS&CHANNELS to a list of channels, returning #F if any cannot
; be coerced. If FALSE-OKAY? is true, then any #F's in the list are just
; passed along.
(define (maybe-xs->channels ports&channels false-okay?)
(let loop ((todo ports&channels) (res '()))
(cond ((null? todo)
(reverse res))
((and false-okay?
(not (car todo)))
(loop (cdr todo)
(cons #f res)))
((maybe-x->channel (car todo))
=> (lambda (channel)
(loop (cdr todo)
(cons channel res))))
(else #f))))
; Returns two lists of pairs (<target-fd> . <channel>). No channel appears twice
; in the first list and every channel in the second list appears in the first.
(define (find-targets channels)
(call-with-values
(lambda ()
(fold->3 (lambda (channel i targets extras)
(cond ((not channel)
(values (+ i 1)
targets
extras))
((any (lambda (pair)
(eq? channel (cdr pair)))
targets)
(values (+ i 1)
targets
`((,i . ,channel) . ,extras)))
(else
(values (+ i 1)
`((,i . ,channel) . ,targets)
extras))))
channels
0
'()
'()))
(lambda (i targets extras)
(values targets extras))))
; TARGETS is a list of pairs (<wanted-fd> . <channel>). We loop down doing
; DUP-TO-TARGET, which is guarenteed to make progress, but not guarenteed to
; actually move the argument we give it.
;
; All this depends on DUP and DUP2 switching the original channel to the new
; file descriptor and returning a new channel with the original file descriptor.
(define (do-dups targets)
(if (not (null? targets))
(let ((channel (cdar targets))
(target-fd (caar targets))
(rest (cdr targets)))
(dup-to-target channel target-fd rest '())
(do-dups (if (= (channel-os-index channel)
target-fd)
rest
targets)))))
; Move CHANNEL to TARGET-FD. TARGETS is a list of yet-to-be-done
; (<fd> . <channel>) pairs. PENDING is a list of fd's we are waiting to move
; out of. If TARGET-FD is in PENDING, then we have a loop and use dup() to move
; from HAVE-FD so some other location, thus breaking the loop. If there is
; already someone in the location we want, we move them and then ourselves.
(define (dup-to-target channel target-fd targets pending)
(let ((have-fd (channel-os-index channel)))
(cond ((= target-fd have-fd))
((memq target-fd pending)
(channel-dup channel))
(else
(let ((occupant (find-occupant target-fd targets)))
(if occupant
(dup-to-target (cdr occupant)
(car occupant)
targets
(cons have-fd pending)))
(channel-dup2 channel target-fd))))))
; Return the (<wanted-fd> . <channel>) pair from TARGETS where <channel>
; currently has FD, if there is such.
(define (find-occupant fd targets)
(let loop ((targets targets))
(cond ((null? targets)
#f)
((= fd (channel-os-index (cdar targets)))
(car targets))
(else
(loop (cdr targets))))))
;----------------
; 6.3 File Descriptor Reassignment
;
; int close(int fd) ; Use close-{input|output}-{port|channel}
;
; 6.4 Input and Output
;
; read() and write() ; Already available in various forms.
;----------------
; 6.5 Control Operations on Files
; fcntl(fd, F_DUPFD, target_fd) ; Use DUP instead.
; Descriptor flags
; fcntl(fd, F_GETFD)
; fcntl(fd, F_SETFD, flags)
;
; The only POSIX flag is FD_CLOEXEC, so that's all we do.
(import-lambda-definition-2 set-close-on-exec?! (channel bool)
"posix_set_close_on_exec")
(import-lambda-definition-2 close-on-exec? (channel) "posix_close_on_exec_p")
; Status flags
; fcntl(fd, F_GETFL)
; fcntl(fd, F_SETFL, flags)
(define (i/o-flags port-or-channel)
(let ((channel (maybe-x->channel port-or-channel)))
(if channel
(call-imported-binding-2 posix-io-flags channel #f)
(assertion-violation 'i/o-flags "argument cannot be coerced to channel" port-or-channel))))
(define (set-i/o-flags! port-or-channel options)
(let ((channel (maybe-x->channel port-or-channel)))
(if (and channel
(file-options? options))
(call-imported-binding-2 posix-io-flags channel options)
(assertion-violation 'set-i/o-flags! "argument type error" port-or-channel options))))
(import-definition posix-io-flags)
; off_t lseek(int fd, off_t offset, int whence)
;----------------
; 6. File Synchronization
;
; int fsync(int fd) ; optional
; int fdatasync(int fd) ; optional
;
; 7. Asynchronous Input and Output
;
; All optional
|