1 (cl:in-package
:sb-posix
)
3 (defmacro define-protocol-class
4 (name alien-type superclasses slots
&rest options
)
5 (let ((to-protocol (intern (format nil
"ALIEN-TO-~A" name
)))
6 (to-alien (intern (format nil
"~A-TO-ALIEN" name
))))
8 (export ',name
:sb-posix
)
9 (defclass ,name
,superclasses
10 ,(loop for slotd in slots
11 collect
(ldiff slotd
(member :array-length slotd
)))
13 (declaim (inline ,to-alien
,to-protocol
))
14 (declaim (inline ,to-protocol
,to-alien
))
15 (defun ,to-protocol
(alien &optional instance
)
16 (declare (type (sb-alien:alien
(* ,alien-type
)) alien
)
17 (type (or null
,name
) instance
))
19 (setf instance
(make-instance ',name
)))
20 ,@(loop for slotd in slots
21 ;; FIXME: slotds in source are more complicated in general
23 ;; FIXME: baroque construction of intricate fragility
24 for array-length
= (getf (cdr slotd
) :array-length
)
27 (let ((array (make-array ,array-length
)))
28 (setf (slot-value instance
',(car slotd
))
30 (dotimes (i ,array-length
)
33 (sb-alien:slot alien
',(car slotd
))
36 collect
`(setf (slot-value instance
',(car slotd
))
37 (sb-alien:slot alien
',(car slotd
))))
39 (defun ,to-alien
(instance &optional alien
)
40 (declare (type (or null
(sb-alien:alien
(* ,alien-type
))) alien
)
41 (type ,name instance
))
43 (setf alien
(sb-alien:make-alien
,alien-type
)))
44 ,@(loop for slotd in slots
45 for array-length
= (getf (cdr slotd
) :array-length
)
48 (let ((array (slot-value instance
',(car slotd
))))
49 (dotimes (i ,array-length
)
51 (sb-alien:slot alien
',(car slotd
))
55 collect
`(setf (sb-alien:slot alien
',(car slotd
))
56 (slot-value instance
',(car slotd
)))))
57 (find-class ',name
))))
59 (define-condition sb-posix
:syscall-error
(error)
60 ((errno :initarg
:errno
:reader sb-posix
:syscall-errno
))
61 (:report
(lambda (c s
)
62 (let ((errno (sb-posix:syscall-errno c
)))
63 (format s
"System call error ~A (~A)"
64 errno
(sb-int:strerror errno
))))))
69 (do-symbols (symbol (find-package "SB-POSIX"))
70 (when (get symbol
'errno
)
71 (let ((errno (symbol-value symbol
)))
72 (setf errno-max
(max errno errno-max
))
74 (eval `(define-condition ,symbol
(syscall-error) ())))
76 (let ((table (make-array (1+ errno-max
))))
77 (mapc #'(lambda (cons) (setf (elt table
(car cons
)) (cdr cons
))) list
)
80 (defun syscall-error ()
81 (let ((errno (get-errno)))
82 (error (elt *errno-table
* errno
) :errno errno
)))
84 (defun unsupported-error (lisp-name c-name
)
85 (error "~S is unsupported by SBCL on this platform due to lack of ~A()."
88 (defun unsupported-warning (lisp-name c-name
)
89 (warn "~S is unsupported by SBCL on this platform due to lack of ~A()."
92 ;; Note: it might prove convenient to develop a parallel set of
93 ;; condition classes for STREAM-ERRORs, too.
94 (declaim (inline never-fails
))
95 (defun never-fails (&rest args
)
96 (declare (ignore args
))
99 ;;; Some systems may need C-level wrappers, which can live in the
100 ;;; runtime (so that save-lisp-and-die can produce standalone
101 ;;; executables). See REAL-C-NAME in macros.lisp for the use of this
103 (eval-when (:compile-toplevel
:load-toplevel
)
104 (setf *c-functions-in-runtime
*
105 '`(#+netbsd
,@("stat" "lstat" "fstat" "readdir" "opendir"))))
108 ;;; filesystem access
109 (defmacro define-call
* (name &rest arguments
)
110 #-win32
`(define-call ,name
,@arguments
)
111 #+win32
`(define-call ,(if (consp name
)
112 `(,(concatenate 'string
"_" (car name
))
114 (concatenate 'string
"_" name
))
117 (define-call* "access" int minusp
(pathname filename
) (mode int
))
118 (define-call* "chdir" int minusp
(pathname filename
))
119 (define-call* "chmod" int minusp
(pathname filename
) (mode mode-t
))
120 (define-call* "close" int minusp
(fd file-descriptor
))
121 (define-call* "creat" int minusp
(pathname filename
) (mode mode-t
))
122 (define-call* "dup" int minusp
(oldfd file-descriptor
))
123 (define-call* "dup2" int minusp
(oldfd file-descriptor
)
124 (newfd file-descriptor
))
125 (define-call* ("lseek" :options
:largefile
)
126 off-t minusp
(fd file-descriptor
) (offset off-t
)
128 (define-call* "mkdir" int minusp
(pathname filename
) (mode mode-t
))
131 (define-call-internally open-with-mode
,x int minusp
132 (pathname filename
) (flags int
) (mode mode-t
))
133 (define-call-internally open-without-mode
,x int minusp
134 (pathname filename
) (flags int
))
135 (define-entry-point ,x
136 (pathname flags
&optional
(mode nil mode-supplied
))
138 (open-with-mode pathname flags mode
)
139 (open-without-mode pathname flags
))))))
140 (def #-win32
"open" #+win32
"_open"))
141 (define-call "rename" int minusp
(oldpath filename
) (newpath filename
))
142 (define-call* "rmdir" int minusp
(pathname filename
))
143 (define-call* "unlink" int minusp
(pathname filename
))
144 (define-call #-netbsd
"opendir" #+netbsd
"_opendir"
145 (* t
) null-alien
(pathname filename
))
146 (define-call (#-netbsd
"readdir" #+netbsd
"_readdir" :options
:largefile
)
148 ;; readdir() has the worst error convention in the world. It's just
149 ;; too painful to support. (return is NULL _and_ errno "unchanged"
150 ;; is not an error, it's EOF).
153 (define-call "closedir" int minusp
(dir (* t
)))
154 ;; need to do this here because we can't do it in the DEFPACKAGE
155 (define-call* "umask" mode-t never-fails
(mode mode-t
))
156 (define-call* "getpid" pid-t never-fails
)
160 (define-call "chown" int minusp
(pathname filename
)
161 (owner uid-t
) (group gid-t
))
162 (define-call "chroot" int minusp
(pathname filename
))
163 (define-call "fchdir" int minusp
(fd file-descriptor
))
164 (define-call "fchmod" int minusp
(fd file-descriptor
) (mode mode-t
))
165 (define-call "fchown" int minusp
(fd file-descriptor
)
166 (owner uid-t
) (group gid-t
))
167 (define-call "fdatasync" int minusp
(fd file-descriptor
))
168 (define-call ("ftruncate" :options
:largefile
)
169 int minusp
(fd file-descriptor
) (length off-t
))
170 (define-call "fsync" int minusp
(fd file-descriptor
))
171 (define-call "lchown" int minusp
(pathname filename
)
172 (owner uid-t
) (group gid-t
))
173 (define-call "link" int minusp
(oldpath filename
) (newpath filename
))
174 (define-call "lockf" int minusp
(fd file-descriptor
) (cmd int
) (len off-t
))
175 (define-call "mkfifo" int minusp
(pathname filename
) (mode mode-t
))
176 (define-call "symlink" int minusp
(oldpath filename
) (newpath filename
))
177 (define-call "sync" void never-fails
)
178 (define-call ("truncate" :options
:largefile
)
179 int minusp
(pathname filename
) (length off-t
))
181 (macrolet ((def-mk*temp
(lisp-name c-name result-type errorp dirp values
)
182 (declare (ignore dirp
))
183 (if (sb-sys:find-foreign-symbol-address c-name
)
185 (defun ,lisp-name
(template)
186 (let* ((external-format sb-alien
::*default-c-string-external-format
*)
187 (arg (sb-ext:string-to-octets
189 :external-format external-format
)))
190 (sb-sys:with-pinned-objects
(arg)
191 ;; accommodate for the call-by-reference
192 ;; nature of mks/dtemp's template strings.
193 (let ((result (alien-funcall (extern-alien ,c-name
194 (function ,result-type system-area-pointer
))
195 (sb-alien::vector-sap arg
))))
196 (when (,errorp result
)
198 ;; FIXME: We'd rather return pathnames, but other
199 ;; SB-POSIX functions like this return strings...
200 (let ((pathname (sb-ext:octets-to-string
201 arg
:external-format external-format
)))
203 '(values result pathname
)
205 (export ',lisp-name
))
207 (defun ,lisp-name
(template)
208 (declare (ignore template
))
209 (unsupported-error ',lisp-name
,c-name
))
210 (define-compiler-macro ,lisp-name
(&whole form template
)
211 (declare (ignore template
))
212 (unsupported-warning ',lisp-name
,c-name
)
214 (export ',lisp-name
)))))
215 (def-mk*temp mktemp
"mktemp" (* char
) null-alien nil nil
)
216 ;; FIXME: Windows does have _mktemp, which has a slightly different
218 (def-mk*temp mkstemp
"mkstemp" int minusp nil t
)
219 ;; FIXME: What about Windows?
220 (def-mk*temp mkdtemp
"mkdtemp" (* char
) null-alien t nil
))
221 (define-call-internally ioctl-without-arg
"ioctl" int minusp
222 (fd file-descriptor
) (cmd int
))
223 (define-call-internally ioctl-with-int-arg
"ioctl" int minusp
224 (fd file-descriptor
) (cmd int
) (arg int
))
225 (define-call-internally ioctl-with-pointer-arg
"ioctl" int minusp
226 (fd file-descriptor
) (cmd int
)
227 (arg alien-pointer-to-anything-or-nil
))
228 (define-entry-point "ioctl" (fd cmd
&optional
(arg nil argp
))
231 ((alien int
) (ioctl-with-int-arg fd cmd arg
))
232 ((or (alien (* t
)) null
) (ioctl-with-pointer-arg fd cmd arg
)))
233 (ioctl-without-arg fd cmd
)))
234 (define-call-internally fcntl-without-arg
"fcntl" int minusp
235 (fd file-descriptor
) (cmd int
))
236 (define-call-internally fcntl-with-int-arg
"fcntl" int minusp
237 (fd file-descriptor
) (cmd int
) (arg int
))
238 (define-call-internally fcntl-with-pointer-arg
"fcntl" int minusp
239 (fd file-descriptor
) (cmd int
)
240 (arg alien-pointer-to-anything-or-nil
))
241 (define-entry-point "fcntl" (fd cmd
&optional
(arg nil argp
))
244 ((alien int
) (fcntl-with-int-arg fd cmd arg
))
245 ((or (alien (* t
)) null
) (fcntl-with-pointer-arg fd cmd arg
)))
246 (fcntl-without-arg fd cmd
)))
249 (define-call "geteuid" uid-t never-fails
) ; "always successful", it says
250 (define-call "getresuid" uid-t never-fails
)
251 (define-call "getuid" uid-t never-fails
)
252 (define-call "seteuid" int minusp
(uid uid-t
))
253 (define-call "setfsuid" int minusp
(uid uid-t
))
254 (define-call "setreuid" int minusp
(ruid uid-t
) (euid uid-t
))
255 (define-call "setresuid" int minusp
(ruid uid-t
) (euid uid-t
) (suid uid-t
))
256 (define-call "setuid" int minusp
(uid uid-t
))
257 (define-call "getegid" gid-t never-fails
)
258 (define-call "getgid" gid-t never-fails
)
259 (define-call "getresgid" gid-t never-fails
)
260 (define-call "setegid" int minusp
(gid gid-t
))
261 (define-call "setfsgid" int minusp
(gid gid-t
))
262 (define-call "setgid" int minusp
(gid gid-t
))
263 (define-call "setregid" int minusp
(rgid gid-t
) (egid gid-t
))
264 (define-call "setresgid" int minusp
(rgid gid-t
) (egid gid-t
) (sgid gid-t
))
266 ;; processes, signals
267 (define-call "alarm" int never-fails
(seconds unsigned
))
271 #+mach-exception-handler
273 ;; FIXME this is a lie, of course this can fail, but there's no
274 ;; error handling here yet!
275 (define-call "setup_mach_exceptions" void never-fails
)
276 (define-call ("posix_fork" :c-name
"fork") pid-t minusp
)
278 (let ((pid (posix-fork)))
280 (setup-mach-exceptions))
282 (export 'fork
:sb-posix
))
284 #-mach-exception-handler
285 (define-call "fork" pid-t minusp
)
287 (define-call "getpgid" pid-t minusp
(pid pid-t
))
288 (define-call "getppid" pid-t never-fails
)
289 (define-call "getpgrp" pid-t never-fails
)
290 (define-call "getsid" pid-t minusp
(pid pid-t
))
291 (define-call "kill" int minusp
(pid pid-t
) (signal int
))
292 (define-call "killpg" int minusp
(pgrp int
) (signal int
))
293 (define-call "pause" int minusp
)
294 (define-call "setpgid" int minusp
(pid pid-t
) (pgid pid-t
))
295 (define-call "setpgrp" int minusp
))
297 (defmacro with-growing-c-string
((buffer size
) &body body
)
298 (sb-int:with-unique-names
(c-string-block)
299 `(block ,c-string-block
301 (flet ((,buffer
(&optional
(size-incl-null))
303 (setf (sb-sys:sap-ref-8
(sb-alien:alien-sap
,buffer
) size-incl-null
)
305 (return-from ,c-string-block
306 (sb-alien::c-string-to-string
307 (sb-alien:alien-sap
,buffer
)
308 (sb-impl::default-external-format
)
310 (loop for
,size
= 128 then
(* 2 ,size
)
313 (setf ,buffer
(make-alien c-string
,size
))
316 (free-alien ,buffer
)))))))))
320 (export 'readlink
:sb-posix
)
321 (defun readlink (pathspec)
322 "Returns the resolved target of a symbolic link as a string."
323 (flet ((%readlink
(path buf length
)
325 (extern-alien "readlink" (function int c-string
(* t
) int
))
327 (with-growing-c-string (buf size
)
328 (let ((count (%readlink
(filename pathspec
) buf size
)))
329 (cond ((minusp count
)
335 (export 'getcwd
:sb-posix
)
337 "Returns the process's current working directory as a string."
338 (flet ((%getcwd
(buffer size
)
340 (extern-alien #-win32
"getcwd"
341 #+win32
"_getcwd" (function c-string
(* t
) int
))
343 (with-growing-c-string (buf size
)
344 (let ((result (%getcwd buf size
)))
347 ((/= (get-errno) sb-posix
:erange
)
348 (syscall-error))))))))
352 (export 'wait
:sb-posix
)
353 (declaim (inline wait
))
354 (defun wait (&optional statusptr
)
355 (declare (type (or null
(simple-array (signed-byte 32) (1))) statusptr
))
356 (let* ((ptr (or statusptr
(make-array 1 :element-type
'(signed-byte 32))))
357 (pid (sb-sys:with-pinned-objects
(ptr)
359 (extern-alien "wait" (function pid-t
(* int
)))
360 (sb-sys:vector-sap ptr
)))))
363 (values pid
(aref ptr
0))))))
367 (export 'waitpid
:sb-posix
)
368 (declaim (inline waitpid
))
369 (defun waitpid (pid options
&optional statusptr
)
370 (declare (type (sb-alien:alien pid-t
) pid
)
371 (type (sb-alien:alien int
) options
)
372 (type (or null
(simple-array (signed-byte 32) (1))) statusptr
))
373 (let* ((ptr (or statusptr
(make-array 1 :element-type
'(signed-byte 32))))
374 (pid (sb-sys:with-pinned-objects
(ptr)
376 (extern-alien "waitpid" (function pid-t
378 pid
(sb-sys:vector-sap ptr
) options
))))
381 (values pid
(aref ptr
0)))))
383 (define-call "wifexited" boolean never-fails
(status int
))
384 (define-call "wexitstatus" int never-fails
(status int
))
385 (define-call "wifsignaled" boolean never-fails
(status int
))
386 (define-call "wtermsig" int never-fails
(status int
))
387 (define-call "wifstopped" boolean never-fails
(status int
))
388 (define-call "wstopsig" int never-fails
(status int
))
389 #+nil
; see alien/waitpid-macros.c
390 (define-call "wifcontinued" boolean never-fails
(status int
)))
395 (define-call ("mmap" :options
:largefile
) sb-sys
:system-area-pointer
397 (= (sb-sys:sap-int res
) #.
(1- (expt 2 sb-vm
::n-machine-word-bits
))))
398 (addr sap-or-nil
) (length unsigned
) (prot unsigned
)
399 (flags unsigned
) (fd file-descriptor
) (offset off-t
))
401 (define-call "munmap" int minusp
402 (start sb-sys
:system-area-pointer
) (length unsigned
))
404 (define-call "msync" int minusp
405 (addr sb-sys
:system-area-pointer
) (length unsigned
) (flags int
)))
408 (define-call "getpagesize" int minusp
)
410 ;;; KLUDGE: This could be taken from GetSystemInfo
411 (export (defun getpagesize () 4096))
414 ;; The docstrings are copied from the descriptions in SUSv3,
417 (define-protocol-class passwd alien-passwd
()
418 ((name :initarg
:name
:accessor passwd-name
419 :documentation
"User's login name.")
420 ;; Note: SUSv3 doesn't require this member.
421 (passwd :initarg
:passwd
:accessor passwd-passwd
422 :documentation
"The account's encrypted password.")
423 (uid :initarg
:uid
:accessor passwd-uid
424 :documentation
"Numerical user ID.")
425 (gid :initarg
:gid
:accessor passwd-gid
426 :documentation
"Numerical group ID.")
427 ;; Note: SUSv3 doesn't require this member.
428 (gecos :initarg
:gecos
:accessor passwd-gecos
429 :documentation
"User's name or comment field.")
430 (dir :initarg
:dir
:accessor passwd-dir
431 :documentation
"Initial working directory.")
432 (shell :initarg
:shell
:accessor passwd-shell
433 :documentation
"Program to use as shell."))
434 (:documentation
"Instances of this class represent entries in
435 the system's user database."))
437 (defmacro define-pw-call
(name arg type
)
439 ;; FIXME: this isn't the documented way of doing this, surely?
440 (let ((lisp-name (intern (string-upcase name
) :sb-posix
)))
442 (export ',lisp-name
:sb-posix
)
443 (declaim (inline ,lisp-name
))
444 (defun ,lisp-name
(,arg
)
445 (let ((r (alien-funcall (extern-alien ,name
,type
) ,arg
)))
448 (alien-to-passwd r
)))))))
450 (define-pw-call "getpwnam" login-name
(function (* alien-passwd
) c-string
))
451 (define-pw-call "getpwuid" uid
(function (* alien-passwd
) uid-t
))
455 (define-protocol-class group alien-group
()
456 ((name :initarg
:name
:accessor group-name
)
457 (passwd :initarg
:passwd
:accessor group-passwd
)
458 (gid :initarg
:gid
:accessor group-gid
)))
460 (defmacro define-gr-call
(name arg type
)
462 ;; FIXME: this isn't the documented way of doing this, surely?
463 (let ((lisp-name (intern (string-upcase name
) :sb-posix
)))
465 (export ',lisp-name
:sb-posix
)
466 (declaim (inline ,lisp-name
))
467 (defun ,lisp-name
(,arg
)
468 (let ((r (alien-funcall (extern-alien ,name
,type
) ,arg
)))
471 (alien-to-group r
)))))))
473 (define-gr-call "getgrnam" login-name
(function (* alien-group
) c-string
))
474 (define-gr-call "getgrgid" gid
(function (* alien-group
) gid-t
))
478 (define-protocol-class timeval alien-timeval
()
479 ((sec :initarg
:tv-sec
:accessor timeval-sec
480 :documentation
"Seconds.")
481 (usec :initarg
:tv-usec
:accessor timeval-usec
482 :documentation
"Microseconds."))
483 (:documentation
"Instances of this class represent time values."))
485 (define-protocol-class stat alien-stat
()
486 ((mode :initarg
:mode
:reader stat-mode
487 :documentation
"Mode of file.")
488 (ino :initarg
:ino
:reader stat-ino
489 :documentation
"File serial number.")
490 (dev :initarg
:dev
:reader stat-dev
491 :documentation
"Device ID of device containing file.")
492 (nlink :initarg
:nlink
:reader stat-nlink
493 :documentation
"Number of hard links to the file.")
494 (uid :initarg
:uid
:reader stat-uid
495 :documentation
"User ID of file.")
496 (gid :initarg
:gid
:reader stat-gid
497 :documentation
"Group ID of file.")
498 (size :initarg
:size
:reader stat-size
499 :documentation
"For regular files, the file size in
500 bytes. For symbolic links, the length
501 in bytes of the filename contained in
503 (atime :initarg
:atime
:reader stat-atime
504 :documentation
"Time of last access.")
505 (mtime :initarg
:mtime
:reader stat-mtime
506 :documentation
"Time of last data modification.")
507 (ctime :initarg
:ctime
:reader stat-ctime
508 :documentation
"Time of last status change"))
509 (:documentation
"Instances of this class represent Posix file
512 (defmacro define-stat-call
(name arg designator-fun type
)
513 ;; FIXME: this isn't the documented way of doing this, surely?
514 (let ((lisp-name (lisp-for-c-symbol name
)))
516 (export ',lisp-name
:sb-posix
)
517 (declaim (inline ,lisp-name
))
518 (defun ,lisp-name
(,arg
&optional stat
)
519 (declare (type (or null stat
) stat
))
520 (with-alien-stat a-stat
()
521 (let ((r (alien-funcall
522 (extern-alien ,(real-c-name (list name
:options
:largefile
)) ,type
)
523 (,designator-fun
,arg
)
527 (alien-to-stat a-stat stat
)))))))
529 (define-stat-call #-win32
"stat" #+win32
"_stat"
531 (function int c-string
(* alien-stat
)))
534 (define-stat-call "lstat"
536 (function int c-string
(* alien-stat
)))
537 ;;; No symbolic links on Windows, so use stat
540 (declaim (inline lstat
))
541 (export (defun lstat (filename &optional stat
)
542 (if stat
(stat filename stat
) (stat filename
)))))
544 (define-stat-call #-win32
"fstat" #+win32
"_fstat"
546 (function int int
(* alien-stat
)))
550 (define-call "s_isreg" boolean never-fails
(mode mode-t
))
551 (define-call "s_isdir" boolean never-fails
(mode mode-t
))
552 (define-call "s_ischr" boolean never-fails
(mode mode-t
))
553 (define-call "s_isblk" boolean never-fails
(mode mode-t
))
554 (define-call "s_isfifo" boolean never-fails
(mode mode-t
))
555 (define-call "s_islnk" boolean never-fails
(mode mode-t
))
556 (define-call "s_issock" boolean never-fails
(mode mode-t
))
560 (export 'pipe
:sb-posix
)
561 (declaim (inline pipe
))
562 (defun pipe (&optional filedes2
)
563 (declare (type (or null
(simple-array (signed-byte 32) (2))) filedes2
))
565 (setq filedes2
(make-array 2 :element-type
'(signed-byte 32))))
566 (let ((r (sb-sys:with-pinned-objects
(filedes2)
568 ;; FIXME: (* INT)? (ARRAY INT 2) would be better
569 (extern-alien "pipe" (function int
(* int
)))
570 (sb-sys:vector-sap filedes2
)))))
573 (values (aref filedes2
0) (aref filedes2
1))))
576 (define-protocol-class termios alien-termios
()
577 ((iflag :initarg
:iflag
:accessor sb-posix
:termios-iflag
578 :documentation
"Input modes.")
579 (oflag :initarg
:oflag
:accessor sb-posix
:termios-oflag
580 :documentation
"Output modes.")
581 (cflag :initarg
:cflag
:accessor sb-posix
:termios-cflag
582 :documentation
"Control modes.")
583 (lflag :initarg
:lflag
:accessor sb-posix
:termios-lflag
584 :documentation
"Local modes.")
585 (cc :initarg
:cc
:accessor sb-posix
:termios-cc
:array-length nccs
586 :documentation
"Control characters"))
587 (:documentation
"Instances of this class represent I/O
588 characteristics of the terminal."))
592 (export 'tcsetattr
:sb-posix
)
593 (declaim (inline tcsetattr
))
594 (defun tcsetattr (fd actions termios
)
595 (declare (type termios termios
))
596 (with-alien-termios a-termios
()
597 (termios-to-alien termios a-termios
)
598 (let ((fd (file-descriptor fd
)))
599 (let* ((r (alien-funcall
602 (function int int int
(* alien-termios
)))
603 fd actions a-termios
)))
607 (export 'tcgetattr
:sb-posix
)
608 (declaim (inline tcgetattr
))
609 (defun tcgetattr (fd &optional termios
)
610 (declare (type (or null termios
) termios
))
611 (with-alien-termios a-termios
()
612 (let ((r (alien-funcall
613 (extern-alien "tcgetattr"
614 (function int int
(* alien-termios
)))
619 (setf termios
(alien-to-termios a-termios termios
))))
621 (export 'cfsetispeed
:sb-posix
)
622 (declaim (inline cfsetispeed
))
623 (defun cfsetispeed (speed &optional termios
)
624 (declare (type (or null termios
) termios
))
625 (with-alien-termios a-termios
()
626 (let ((r (alien-funcall
627 (extern-alien "cfsetispeed"
628 (function int
(* alien-termios
) speed-t
))
633 (setf termios
(alien-to-termios a-termios termios
))))
635 (export 'cfsetospeed
:sb-posix
)
636 (declaim (inline cfsetospeed
))
637 (defun cfsetospeed (speed &optional termios
)
638 (declare (type (or null termios
) termios
))
639 (with-alien-termios a-termios
()
640 (let ((r (alien-funcall
641 (extern-alien "cfsetospeed"
642 (function int
(* alien-termios
) speed-t
))
647 (setf termios
(alien-to-termios a-termios termios
))))
649 (export 'cfgetispeed
:sb-posix
)
650 (declaim (inline cfgetispeed
))
651 (defun cfgetispeed (termios)
652 (declare (type termios termios
))
653 (with-alien-termios a-termios
()
654 (termios-to-alien termios a-termios
)
655 (alien-funcall (extern-alien "cfgetispeed"
656 (function speed-t
(* alien-termios
)))
658 (export 'cfgetospeed
:sb-posix
)
659 (declaim (inline cfgetospeed
))
660 (defun cfgetospeed (termios)
661 (declare (type termios termios
))
662 (with-alien-termios a-termios
()
663 (termios-to-alien termios a-termios
)
664 (alien-funcall (extern-alien "cfgetospeed"
665 (function speed-t
(* alien-termios
)))
671 (export 'time
:sb-posix
)
673 (let ((result (alien-funcall (extern-alien "time"
674 (function time-t
(* time-t
)))
679 (export 'utime
:sb-posix
)
680 (defun utime (filename &optional access-time modification-time
)
681 (let ((fun (extern-alien "utime" (function int c-string
683 (name (filename filename
)))
684 (if (not (and access-time modification-time
))
685 (alien-funcall fun name nil
)
686 (with-alien ((utimbuf (struct alien-utimbuf
)))
687 (setf (slot utimbuf
'actime
) (or access-time
0)
688 (slot utimbuf
'modtime
) (or modification-time
0))
689 (let ((result (alien-funcall fun name
(alien-sap utimbuf
))))
693 (export 'utimes
:sb-posix
)
694 (defun utimes (filename &optional access-time modification-time
)
695 (flet ((seconds-and-useconds (time)
696 (multiple-value-bind (integer fractional
)
698 (values integer
(cl:truncate
(* fractional
1000000)))))
699 (maybe-syscall-error (value)
703 (let ((fun (extern-alien "utimes" (function int c-string
704 (* (array alien-timeval
2)))))
705 (name (filename filename
)))
706 (if (not (and access-time modification-time
))
707 (maybe-syscall-error (alien-funcall fun name nil
))
708 (with-alien ((buf (array alien-timeval
2)))
709 (let ((actime (deref buf
0))
710 (modtime (deref buf
1)))
711 (setf (values (slot actime
'sec
)
713 (seconds-and-useconds (or access-time
0))
714 (values (slot modtime
'sec
)
715 (slot modtime
'usec
))
716 (seconds-and-useconds (or modification-time
0)))
717 (maybe-syscall-error (alien-funcall fun name
718 (alien-sap buf
))))))))))
723 (export 'getenv
:sb-posix
)
725 (let ((r (alien-funcall
726 (extern-alien "getenv" (function (* char
) c-string
))
728 (declare (type (alien (* char
)) r
))
729 (unless (null-alien r
)
731 (define-call "putenv" int minusp
(string c-string
))
736 (export 'openlog
:sb-posix
)
737 (export 'syslog
:sb-posix
)
738 (export 'closelog
:sb-posix
)
739 (defun openlog (ident options
&optional
(facility log-user
))
740 (alien-funcall (extern-alien
741 "openlog" (function void c-string int int
))
742 ident options facility
))
743 (defun syslog (priority format
&rest args
)
744 "Send a message to the syslog facility, with severity level
745 PRIORITY. The message will be formatted as by CL:FORMAT (rather
746 than C's printf) with format string FORMAT and arguments ARGS."
747 (flet ((syslog1 (priority message
)
748 (alien-funcall (extern-alien
749 "syslog" (function void int c-string c-string
))
750 priority
"%s" message
)))
751 (syslog1 priority
(apply #'format nil format args
))))
752 (define-call "closelog" void never-fails
))