From 3a4d5b974d3af1ae4a8e309468b4e012ad28644e Mon Sep 17 00:00:00 2001 From: Stelian Ionescu Date: Fri, 22 Aug 2008 19:34:09 +0200 Subject: [PATCH] Add IOLIB.SYSCALLS package. Signed-off-by: Stelian Ionescu --- iolib.syscalls.asd | 30 +++ syscalls/conditions.lisp | 85 ++++++++ syscalls/designators.lisp | 47 ++++ syscalls/early.lisp | 119 +++++++++++ syscalls/ffi-functions-unix.lisp | 449 +++++++++++++++++++++++++++++++++++++++ syscalls/ffi-types-unix.lisp | 306 ++++++++++++++++++++++++++ syscalls/ffi-wrappers-unix.lisp | 95 +++++++++ syscalls/os-conditions-unix.lisp | 61 ++++++ syscalls/pkgdcl.lisp | 304 ++++++++++++++++++++++++++ 9 files changed, 1496 insertions(+) create mode 100644 iolib.syscalls.asd create mode 100644 syscalls/conditions.lisp create mode 100644 syscalls/designators.lisp create mode 100644 syscalls/early.lisp create mode 100644 syscalls/ffi-functions-unix.lisp create mode 100644 syscalls/ffi-types-unix.lisp create mode 100644 syscalls/ffi-wrappers-unix.lisp create mode 100644 syscalls/os-conditions-unix.lisp create mode 100644 syscalls/pkgdcl.lisp diff --git a/iolib.syscalls.asd b/iolib.syscalls.asd new file mode 100644 index 0000000..bf58333 --- /dev/null +++ b/iolib.syscalls.asd @@ -0,0 +1,30 @@ +;;;; -*- Mode: Lisp; Syntax: ANSI-Common-Lisp; indent-tabs-mode: nil -*- + +(in-package :common-lisp-user) + +(eval-when (:compile-toplevel :load-toplevel :execute) + (asdf:oos 'asdf:load-op :cffi-grovel)) + +(asdf:defsystem :iolib.syscalls + :description "Syscalls and foreign types." + :maintainer "Stelian Ionescu " + :version "0.5.4" + :licence "MIT" + :depends-on (:iolib.base :cffi :cffi-grovel :trivial-features) + :pathname (merge-pathnames (make-pathname :directory '(:relative "syscalls")) + *load-truename*) + :serial t + :components + ((:file "pkgdcl") + ;; Platform-specific files + (cffi-grovel:grovel-file "ffi-types" + :pathname #+unix "ffi-types-unix") + (:file "conditions") + (:file "os-conditions" + :pathname #+unix "os-conditions-unix") + (:file "designators") + (:file "early") + (cffi-grovel:wrapper-file "ffi-wrappers" + :pathname #+unix "ffi-wrappers-unix") + (:file "ffi-functions" + :pathname #+unix "ffi-functions-unix"))) diff --git a/syscalls/conditions.lisp b/syscalls/conditions.lisp new file mode 100644 index 0000000..8bdfeb1 --- /dev/null +++ b/syscalls/conditions.lisp @@ -0,0 +1,85 @@ +;;;; -*- Mode: Lisp; Syntax: ANSI-Common-Lisp; indent-tabs-mode: nil -*- +;;; +;;; --- Error conditions. +;;; + +(in-package :iolib.syscalls) + +;;;----------------------------------------------------------------------------- +;;; System Errors +;;;----------------------------------------------------------------------------- + +(define-condition system-error (error) + ((code :initarg :code :reader code-of + :documentation "Numeric error code, or NIL.") + (identifier :initarg :identifier :reader identifier-of + :documentation "Keyword identifier, or NIL.") + (message :initarg :message :reader message-of + :documentation "Error description.")) + (:default-initargs :code nil + :identifier :unknown-error) + (:documentation + "Base class for errors signalled by IOlib low-level functions.")) + +(defun system-error (control-string &rest args) + (error 'system-error :message (format nil "~?" control-string args))) + +(define-condition syscall-error (system-error) + () + (:documentation "Base class for syscall errors.")) + +(defun syscall-error (control-string &rest args) + (error 'syscall-error :message (format nil "~?" control-string args))) + + +;;;----------------------------------------------------------------------------- +;;; I/O Poll Errors +;;;----------------------------------------------------------------------------- + +(define-condition poll-error (system-error) + () + (:report (lambda (condition stream) + (format stream "Error caught while polling: ~A" + (message-of condition)))) + (:documentation + "Signaled when an error occurs while polling for I/O readiness +of a file descriptor.")) + +(define-condition poll-timeout (condition) + ((event-type :initarg :event-type :reader event-type-of)) + (:report (lambda (condition stream) + (format stream "Timeout occurred while polling for event ~S" + (event-type-of condition)))) + (:documentation + "Signaled when a timeout occurs while polling for I/O readiness +of a file descriptor.")) + + +;;;----------------------------------------------------------------------------- +;;; Repeat upon conditions +;;;----------------------------------------------------------------------------- + +(defmacro repeat-decreasing-timeout + ((timeout-var timeout &optional (block-name nil blockp)) &body body) + (unless (find timeout-var (flatten body)) + (warn "You probably want to use ~S inside the body ~A" timeout-var body)) + (unless blockp (setf block-name (gensym "BLOCK"))) + (with-unique-names (deadline temp-timeout) + `(let* ((,timeout-var ,timeout) + (,deadline (when ,timeout-var + (+ ,timeout-var (get-monotonic-time))))) + (loop :named ,block-name :do + ,@body + (when ,deadline + (let ((,temp-timeout (- ,deadline (get-monotonic-time)))) + (setf ,timeout-var + (if (plusp ,temp-timeout) + ,temp-timeout + 0)))))))) + +(defmacro repeat-upon-condition-decreasing-timeout + (((&rest conditions) timeout-var timeout &optional (block-name nil blockp)) &body body) + (unless blockp (setf block-name (gensym "BLOCK"))) + `(repeat-decreasing-timeout (,timeout-var ,timeout ,block-name) + (ignore-some-conditions ,conditions + (return-from ,block-name (progn ,@body))))) diff --git a/syscalls/designators.lisp b/syscalls/designators.lisp new file mode 100644 index 0000000..8c91e32 --- /dev/null +++ b/syscalls/designators.lisp @@ -0,0 +1,47 @@ +;;;; -*- Mode: Lisp; Syntax: ANSI-Common-Lisp; indent-tabs-mode: nil -*- +;;; +;;; --- FFI designators. +;;; + +(in-package :iolib.syscalls) + +;;;; Type Designators + +(defmacro define-designator (name cffi-type &body type-clauses) + (let ((type `(quote (or ,@(mapcar #'car type-clauses)))) + (ctype (format-symbol t "~A-DESIGNATOR" name))) + `(progn + (deftype ,name () ,type) + (defun ,name (,name) + (etypecase ,name + ,@type-clauses)) + (define-foreign-type ,ctype () + () + (:simple-parser ,ctype) + (:actual-type ,cffi-type)) + (defmethod expand-to-foreign (value (type ,ctype)) + `(convert-to-foreign + (let ((,',name ,value)) + (etypecase ,',name ,@',type-clauses)) + ,',cffi-type))))) + +(declaim (inline native-namestring)) +(defun native-namestring (pathname) + (cffi-sys:native-namestring pathname)) + +;;; NATIVE-NAMESTRING should take care of complaining when FILENAME +;;; is wild but I don't think it does on all Lisps, so let's check it +;;; explicitly. +(define-designator filename :string + (pathname (when (wild-pathname-p filename) + (system-error "Pathname is wild: ~S." filename)) + (native-namestring (translate-logical-pathname filename))) + (string filename)) + +(define-designator pointer-or-nil :pointer + (null (null-pointer)) + (foreign-pointer pointer-or-nil)) + +(define-designator bool :int + (null 0) + (t 1)) diff --git a/syscalls/early.lisp b/syscalls/early.lisp new file mode 100644 index 0000000..0fab6a8 --- /dev/null +++ b/syscalls/early.lisp @@ -0,0 +1,119 @@ +;;;; -*- Mode: Lisp; Syntax: ANSI-Common-Lisp; indent-tabs-mode: nil -*- +;;; +;;; --- Early definitions. +;;; + +(in-package :iolib.syscalls) + +;;;; Sizes of Standard Types + +(defconstant size-of-char (foreign-type-size :char)) +(defconstant size-of-int (foreign-type-size :int)) +(defconstant size-of-long (foreign-type-size :long)) +(defconstant size-of-long-long (foreign-type-size :long-long)) +(defconstant size-of-pointer (foreign-type-size :pointer)) +(defconstant size-of-short (foreign-type-size :short)) + + +;;; Error predicate that always returns NIL. Not actually used +;;; because the RETURN-WRAPPER optimizes this call away. +(defun never-fails (errcode) + (declare (ignore errcode)) + nil) + +;;; NOTE: This is a pretty neat type that probably deserves to be +;;; included in CFFI. --luis +;;; +;;; This type is used by DEFSYSCALL to automatically check for errors +;;; using the ERROR-PREDICATE function which is passed the foreign +;;; function's return value (after going through RETURN-FILTER). If +;;; ERROR-PREDICATE returns true, ERROR-GENERATOR is invoked. See the +;;; RETURN-WRAPPER parse method and type translation. +(define-foreign-type return-wrapper () + ((error-predicate :initarg :error-predicate :reader error-predicate-of) + (return-filter :initarg :return-filter :reader return-filter-of) + (error-generator :initarg :error-generator :reader error-generator-of) + (base-type :initarg :base-type :reader base-type-of))) + +(define-parse-method return-wrapper + (base-type &key error-predicate (return-filter 'identity) error-generator) + ;; pick a default error-predicate + (unless error-predicate + (case base-type + (:string + (setf error-predicate '(lambda (s) (not (stringp s))))) + (t + (case (cffi::canonicalize-foreign-type base-type) + (:pointer + (setf error-predicate 'null-pointer-p)) + ((:char :short :int :long :long-long) + (setf error-predicate 'minusp)) + ;; FIXME: go here if the canonical type is unsigned. + ((:unsigned-char :unsigned-short :unsigned-int + :unsigned-long :unsigned-long-long :void) + (setf error-predicate 'never-fails)) + (t + (error "Could not choose an error-predicate function.")))))) + (unless (or (eql 'never-fails error-predicate) error-generator) + (error "Function can fail but no error-generator suplied.")) + (make-instance 'return-wrapper + :actual-type base-type + :base-type base-type + :error-predicate error-predicate + :return-filter return-filter + :error-generator error-generator)) + +;;; This type translator sets up the appropriate calls to +;;; RETURN-FILTER, ERROR-PREDICATE and ERROR-GENERATOR around the +;;; foreign function call. +(defmethod expand-from-foreign (value (type return-wrapper)) + (if (and (eql 'identity (return-filter-of type)) + (eql 'never-fails (error-predicate-of type))) + value + `(tagbody :restart + (let ((r (convert-from-foreign ,value ',(base-type-of type)))) + ,(let ((return-exp + (if (eql 'identity (return-filter-of type)) + 'r + `(,(return-filter-of type) r)))) + (if (eql 'never-fails (error-predicate-of type)) + return-exp + `(if (,(error-predicate-of type) r) + (,(error-generator-of type) r) + ,return-exp))))))) + + +(defmacro defentrypoint (name (&rest args) &body body) + `(progn + (declaim (inline ,name)) + (defun ,name ,args ,@body))) + +(defmacro defcfun* (name-and-opts return-type &body args) + (multiple-value-bind (lisp-name c-name options) + (cffi::parse-name-and-options name-and-opts) + `(progn + (declaim (inline ,lisp-name)) + (defcfun (,c-name ,lisp-name ,@options) ,return-type + ,@args)))) + +(defmacro signal-posix-error/restart (ret) + `(if (= eintr (get-errno)) + (go :restart) + (signal-posix-error ,ret))) + +(defmacro return-posix-error/restart (ret) + `(if (= eintr (get-errno)) + (go :restart) + ,ret)) + +(defmacro defsyscall (name-and-opts return-type &body args) + `(defcfun* ,name-and-opts ,return-type ,@args)) + +(defmacro defsyscall* (name-and-opts return-type &body args) + (multiple-value-bind (lisp-name c-name options) + (cffi::parse-name-and-options name-and-opts) + `(progn + (declaim (inline ,lisp-name)) + (defcfun (,c-name ,lisp-name ,@options) + (return-wrapper ,return-type :error-generator return-posix-error/restart) + ,@args)))) diff --git a/syscalls/ffi-functions-unix.lisp b/syscalls/ffi-functions-unix.lisp new file mode 100644 index 0000000..00cde19 --- /dev/null +++ b/syscalls/ffi-functions-unix.lisp @@ -0,0 +1,449 @@ +;;;; -*- Mode: Lisp; Syntax: ANSI-Common-Lisp; indent-tabs-mode: nil -*- +;;; +;;; --- *UNIX foreign function definitions. +;;; + +(in-package :iolib.syscalls) + +;;; Needed for clock_gettime() and friends. +#+linux (load-foreign-library "librt.so") + + +;;;----------------------------------------------------------------------------- +;;; ERRNO-related functions +;;;----------------------------------------------------------------------------- + +(defentrypoint %sys-strerror (&optional (err (get-errno))) + "Look up the error message string for ERRNO. (reentrant)" + (let ((errno + (if (keywordp err) + (foreign-enum-value 'errno-values err) + err))) + (with-foreign-pointer-as-string ((buf bufsiz) 1024) + (%sys-strerror-r errno buf bufsiz)))) + +(defmethod print-object ((posix-error posix-error) stream) + (print-unreadable-object (posix-error stream :type nil :identity nil) + (let ((code (code-of posix-error)) + (identifier (identifier-of posix-error))) + (format stream "POSIX Error ~A code: ~S ~S" + identifier (or code "[No code]") + (or (%sys-strerror code) "[Can't get error string.]"))))) + + +;;;----------------------------------------------------------------------------- +;;; Memory manipulation +;;;----------------------------------------------------------------------------- + +(defcfun* ("memset" %sys-memset) :pointer + (buffer :pointer) + (value :int) + (length size-t)) + +(defentrypoint %sys-bzero (buffer length) + (%sys-memset buffer 0 length)) + +(defcfun* ("memcpy" %sys-memcpy) :pointer + (dest :pointer) + (src :pointer) + (length size-t)) + +(defcfun* ("memmove" %sys-memmove) :pointer + (dest :pointer) + (src :pointer) + (length size-t)) + + +;;;----------------------------------------------------------------------------- +;;; I/O +;;;----------------------------------------------------------------------------- + +(defsyscall* ("read" %sys-read) ssize-t + "Read at most COUNT bytes from FD into the foreign area BUF." + (fd :int) + (buf :pointer) + (count size-t)) + +(defsyscall* ("write" %sys-write) ssize-t + "Write at most COUNT bytes to FD from the foreign area BUF." + (fd :int) + (buf :pointer) + (count size-t)) + + +;;;----------------------------------------------------------------------------- +;;; Files +;;;----------------------------------------------------------------------------- + +(defsyscall* ("open" %%sys-open) :int + (pathname filename-designator) + (flags :int) + (mode mode-t)) + +(defvar *default-open-mode* #o666) + +(defentrypoint %sys-open (pathname flags &optional (mode *default-open-mode*)) + (%%sys-open pathname flags mode)) + +(defsyscall* ("creat" %sys-creat) :int + (pathname filename-designator) + (mode mode-t)) + +(defsyscall ("pipe" %%sys-pipe) :int + (filedes :pointer)) + +(defentrypoint %sys-pipe () + "Create pipe, returns two values with the new FDs." + (with-foreign-object (filedes :int 2) + (%%sys-pipe filedes) + (values (mem-aref filedes :int 0) + (mem-aref filedes :int 1)))) + +(defsyscall ("mkfifo" %sys-mkfifo) :int + "Create a FIFO (named pipe)." + (path filename-designator) + (mode mode-t)) + +(defsyscall "umask" mode-t + "Sets the umask and returns the old one" + (new-mode mode-t)) + +(defsyscall ("access" %sys-access) :int + (path filename-designator) + (amode :int)) + +(defsyscall ("rename" %sys-rename) :int + "Rename a file." + (old filename-designator) + (new filename-designator)) + +(defsyscall ("link" %sys-link) :int + (path1 filename-designator) + (path2 filename-designator)) + +(defsyscall ("symlink" %sys-symlink) :int + "Creates a symbolic link" + (name1 filename-designator) + (name2 filename-designator)) + +(defsyscall ("readlink" %%sys-readlink) ssize-t + (path filename-designator) + (buf :pointer) + (bufsize size-t)) + +(defentrypoint %sys-readlink (path) + "Read value of a symbolic link." + (with-foreign-pointer (buf 4096 bufsize) + (let ((count (%%sys-readlink path buf bufsize))) + (values (foreign-string-to-lisp buf :count count))))) + +(defsyscall ("unlink" %sys-unlink) :int + (path filename-designator)) + +(defsyscall* ("chown" %sys-chown) :int + "Change ownership of a file." + (path filename-designator) + (owner uid-t) + (group uid-t)) + +(defsyscall* ("fchown" %sys-fchown) :int + "Change ownership of an open file." + (fd :int) + (owner uid-t) + (group uid-t)) + +(defsyscall* ("lchown" %sys-lchown) :int + "Change ownership of a file or symlink." + (path filename-designator) + (owner uid-t) + (group uid-t)) + +(defsyscall* ("chmod" %sys-chmod) :int + (path filename-designator) + (mode mode-t)) + +(defsyscall* ("fchmod" %sys-fchmod) :int + (fd :int) + (mode mode-t)) + +;;; STAT() + +(define-c-struct-wrapper stat ()) + +(defconstant +stat-version-linux+ 3) + +;;; If necessary for performance reasons, we can add an optional +;;; argument to this function and use that to reuse a wrapper object. +(defentrypoint funcall-stat (fn arg) + (with-foreign-object (buf 'stat) + (funcall fn arg buf) + (make-instance 'stat :pointer buf))) + +(defentrypoint %sys-stat (path) + "Get information about a file." + (funcall-stat #'%%sys-stat path)) + +(defentrypoint %sys-fstat (fd) + "Get information about a file descriptor" + (funcall-stat #'%%sys-fstat fd)) + +(defentrypoint %sys-lstat (path) + "Get information about a file or symlink." + (funcall-stat #'%%sys-lstat path)) + +(defsyscall ("sync" %sys-sync) :void + "Schedule all file system buffers to be written to disk.") + +(defsyscall* ("fsync" %sys-fsync) :int + (fildes :int)) + +(defsyscall ("mkstemp" %%sys-mkstemp) :int + (template filename-designator)) + +(defentrypoint %sys-mkstemp (&optional (template "")) + (let ((template (concatenate 'string template "XXXXXX"))) + (with-foreign-string (ptr (filename template)) + (values (%%sys-mkstemp ptr) (foreign-string-to-lisp ptr))))) + + +;;;----------------------------------------------------------------------------- +;;; Directories +;;;----------------------------------------------------------------------------- + +(defsyscall "mkdir" :int + "Create a directory." + (path filename-designator) + (mode mode-t)) + +(defsyscall ("rmdir" %sys-rmdir) :int + (path filename-designator)) + +(defsyscall ("chdir" %sys-chdir) :int + "Changes the current working directory" + (path filename-designator)) + +(defsyscall* ("fchdir" %sys-fchdir) :int + (fildes :int)) + +(defsyscall ("getcwd" %%sys-getcwd) :string + (buf :pointer) + (size size-t)) + +(defentrypoint %sys-getcwd () + "Returns the current working directory as a string." + (with-foreign-pointer (buf path-max size) + (%getcwd buf size))) + +(defsyscall ("mkdtemp" %%sys-mkdtemp) :int + (template filename-designator)) + +(defentrypoint %sys-mkdtemp (&optional (template "")) + (let ((template (concatenate 'string template "XXXXXX"))) + (with-foreign-string (ptr (filename template)) + (values (%%sys-mkdtemp ptr) (foreign-string-to-lisp ptr))))) + + +;;;----------------------------------------------------------------------------- +;;; File Descriptors +;;;----------------------------------------------------------------------------- + +(defsyscall ("close" %sys-close) :int + "Close an open file descriptor." + (fd :int)) + +(defsyscall ("dup" %sys-dup) :int + (fildes :int)) + +(defsyscall* ("dup2" %sys-dup2) :int + (fildes1 :int) + (fildes2 :int)) + +(defsyscall* ("ioctl" %%sys-ioctl-without-arg) :int + (fd :int) + (request :int)) + +(defsyscall* ("ioctl" %%sys-ioctl-with-arg) :int + (fd :int) + (request :int) + (arg :pointer)) + +(defentrypoint %sys-ioctl (fd request &optional (arg nil argp)) + "Control device." + (cond + ((not argp) (%%sys-ioctl-without-arg fd request)) + ((pointerp arg) (%%sys-ioctl-with-arg fd request arg)) + (t (error "Wrong argument to ioctl: ~S" arg)))) + +(defentrypoint %sys-fd-open-p (fd) + (not (minusp (%sys-fstat fd)))) + + +;;;----------------------------------------------------------------------------- +;;; File descriptor polling +;;;----------------------------------------------------------------------------- + +;;; FIXME: Until a way to autodetect platform features is implemented +#+(or darwin freebsd) +(define-constant pollrdhup 0) + +(defsyscall ("poll" %sys-poll) :int + "Scan for I/O activity on multiple file descriptors." + (fds :pointer) + (nfds nfds-t) + (timeout :int)) + + +;;;----------------------------------------------------------------------------- +;;; Memory mapping +;;;----------------------------------------------------------------------------- + +(defsyscall ("munmap" %sys-munmap) :int + "Unmap pages of memory." + (addr :pointer) + (len size-t)) + + +;;;----------------------------------------------------------------------------- +;;; Time +;;;----------------------------------------------------------------------------- + +(defsyscall* ("usleep" %sys-usleep) :int + (useconds useconds-t)) + +(defsyscall ("time" %%sys-time) time-t + (tloc :pointer)) + +(defentrypoint %sys-time () + (%%sys-time (null-pointer))) + +(defsyscall ("gettimeofday" %%sys-gettimeofday) :int + (tp :pointer) + (tzp :pointer)) + +(defentrypoint %sys-gettimeofday () + "Return the time in seconds and microseconds." + (with-foreign-object (tv 'timeval) + (with-foreign-slots ((sec usec) tv timeval) + (%%sys-gettimeofday tv (null-pointer)) + (values sec usec)))) + +;;; FIXME: or we can implement this through the MACH functions. +#+darwin +(progn + (defctype kern-return-t :int) + (defctype clock-res-t :int) + (defctype clock-id-t :int) + (defctype port-t :unsigned-int) ; not sure + (defctype clock-serv-t port) + + (defconstant kern-success 0) + + (defconstant system-clock 0) + (defconstant calendar-clock 1) + (defconstant realtime-clock 0) + + (defsyscall ("mach_host_self" %sys-mach-host-self) port-t) + + (defsyscall ("host_get_clock_service" %%sys-host-get-clock-service) kern-return-t + (host port-t) + (id clock-id-t) + (clock-name (:pointer clock-serv-t))) + + (defentrypoint %sys-host-get-clock-service (id &optional (host (%sys-mach-host-self))) + (with-foreign-object (clock 'clock-serv-t) + (%%sys-host-get-clock-service host id clock) + (mem-ref clock :int))) + + (defsyscall ("clock_get_time" %clock-get-time) kern-return-t + (clock-serv clock-serv-t) + (cur-time timespec)) + + (defentrypoint clock-get-time (clock-service) + (with-foreign-object (time 'timespec) + (%clock-get-time clock-service time) + (with-foreign-slots ((tv-sec tv-nsec) time timespec) + (values tv-sec tv-nsec))))) + +#-darwin +(progn + (defsyscall ("clock_getres" %%sys-clock-getres) :int + "Returns the resolution of the clock CLOCKID." + (clockid clockid-t) + (res :pointer)) + + (defentrypoint %sys-clock-getres (clock-id) + (with-foreign-object (ts 'timespec) + (with-foreign-slots ((sec nsec) ts timespec) + (%%sys-clock-getres clock-id ts) + (values sec nsec)))) + + (defsyscall ("clock_gettime" %%sys-clock-gettime) :int + (clockid clockid-t) + (tp :pointer)) + + (defentrypoint %sys-clock-gettime (clock-id) + "Returns the time of the clock CLOCKID." + (with-foreign-object (ts 'timespec) + (with-foreign-slots ((sec nsec) ts timespec) + (%%sys-clock-gettime clock-id ts) + (values sec nsec)))) + + (defsyscall ("clock_settime" %%sys-clock-settime) :int + (clockid clockid-t) + (tp :pointer)) + + (defentrypoint %sys-clock-settime (clock-id) + "Sets the time of the clock CLOCKID." + (with-foreign-object (ts 'timespec) + (with-foreign-slots ((sec nsec) ts timespec) + (%%sys-clock-settime clock-id ts) + (values sec nsec))))) + +(defentrypoint %sys-get-monotonic-time () + "Gets current time in seconds from a system's monotonic clock." + (multiple-value-bind (seconds nanoseconds) + #-darwin (%sys-clock-gettime clock-monotonic) + #+darwin (%sys-clock-get-time (%sys-host-get-clock-service system-clock)) + (+ seconds (/ nanoseconds 1d9)))) + + +;;;----------------------------------------------------------------------------- +;;; Environement +;;;----------------------------------------------------------------------------- + +(defcvar ("environ" :read-only t) (:pointer :string)) + +(defsyscall ("getenv" %sys-getenv) :string + "Returns the value of an environment variable" + (name :string)) + +(defsyscall ("setenv" %sys-setenv) :int + "Changes the value of an environment variable" + (name :string) + (value :string) + (overwrite bool-designator)) + +(defsyscall ("unsetenv" %sys-unsetenv) :int + "Removes the binding of an environment variable" + (name :string)) + + +;;;----------------------------------------------------------------------------- +;;; Local info +;;;----------------------------------------------------------------------------- + +(defsyscall ("gethostname" %%sys-gethostname) :int + (name :pointer) + (namelen size-t)) + +(defentrypoint %sys-gethostname () + (with-foreign-pointer-as-string ((cstr size) 256) + (%%sys-gethostname cstr size))) + +(defsyscall ("getdomainname" %%sys-getdomainname) :int + (name :pointer) + (namelen size-t)) + +(defentrypoint %sys-getdomainname () + (with-foreign-pointer-as-string ((cstr size) 256) + (%%sys-getdomainname cstr size))) diff --git a/syscalls/ffi-types-unix.lisp b/syscalls/ffi-types-unix.lisp new file mode 100644 index 0000000..bb92b6a --- /dev/null +++ b/syscalls/ffi-types-unix.lisp @@ -0,0 +1,306 @@ +;;;; -*- Mode: Lisp; Syntax: ANSI-Common-Lisp; indent-tabs-mode: nil -*- +;;; +;;; --- Grovel definitions for *NIX systems. +;;; + +#+linux +(define "_GNU_SOURCE") + +;;; largefile support on linux +;;; TODO: check if these flags are required on solaris too +#+linux +(progn + (define "_LARGEFILE_SOURCE") + (define "_LARGEFILE64_SOURCE") + (define "_FILE_OFFSET_BITS" 64)) + +(include "stdlib.h" "errno.h" "sys/types.h" "sys/stat.h" "sys/mman.h" + "fcntl.h" "signal.h" "unistd.h" "limits.h" "time.h" "sys/select.h" + "sys/poll.h") + +(in-package :iolib.syscalls) + +(ctype size-t "size_t") +(ctype ssize-t "ssize_t") +(ctype pid-t "pid_t") +(ctype uid-t "uid_t") +(ctype gid-t "gid_t") +(ctype off-t "off_t") +(ctype mode-t "mode_t") + +(constantenum (errno-values :define-constants t) + ((:eperm "EPERM")) + ((:enoent "ENOENT")) + ((:esrch "ESRCH")) + ((:eintr "EINTR")) + ((:eio "EIO")) + ((:enxio "ENXIO")) + ((:e2big "E2BIG")) + ((:enoexec "ENOEXEC")) + ((:ebadf "EBADF")) + ((:echild "ECHILD")) + ((:eagain "EAGAIN")) + ((:enomem "ENOMEM")) + ((:eacces "EACCES")) + ((:efault "EFAULT")) + ((:ebusy "EBUSY")) + ((:eexist "EEXIST")) + ((:exdev "EXDEV")) + ((:enodev "ENODEV")) + ((:enotdir "ENOTDIR")) + ((:eisdir "EISDIR")) + ((:einval "EINVAL")) + ((:enfile "ENFILE")) + ((:emfile "EMFILE")) + ((:enotty "ENOTTY")) + ((:efbig "EFBIG")) + ((:enospc "ENOSPC")) + ((:espipe "ESPIPE")) + ((:erofs "EROFS")) + ((:emlink "EMLINK")) + ((:epipe "EPIPE")) + ((:edom "EDOM")) + ((:erange "ERANGE")) + ((:edeadlk "EDEADLK")) + ((:enametoolong "ENAMETOOLONG")) + ((:enolck "ENOLCK")) + ((:enosys "ENOSYS")) + ((:enotempty "ENOTEMPTY")) + ((:echrng "ECHRNG") :optional t) + ((:el2nsync "EL2NSYNC") :optional t) + ((:el3hlt "EL3HLT") :optional t) + ((:el3rst "EL3RST") :optional t) + ((:elnrng "ELNRNG") :optional t) + ((:eunatch "EUNATCH") :optional t) + ((:enocsi "ENOCSI") :optional t) + ((:el2hlt "EL2HLT") :optional t) + ((:ebade "EBADE") :optional t) + ((:ebadr "EBADR") :optional t) + ((:exfull "EXFULL") :optional t) + ((:enoano "ENOANO") :optional t) + ((:ebadrqc "EBADRQC") :optional t) + ((:ebadslt "EBADSLT") :optional t) + ((:edeadlock "EDEADLOCK") :optional t) + ((:ebfont "EBFONT") :optional t) + ((:enostr "ENOSTR") :optional t) + ((:enodata "ENODATA") :optional t) + ((:etime "ETIME") :optional t) + ((:enosr "ENOSR") :optional t) + ((:enopkg "ENOPKG") :optional t) + ((:eadv "EADV") :optional t) + ((:esrmnt "ESRMNT") :optional t) + ((:ecomm "ECOMM") :optional t) + ((:edotdot "EDOTDOT") :optional t) + ((:enotuniq "ENOTUNIQ") :optional t) + ((:ebadfd "EBADFD") :optional t) + ((:eremchg "EREMCHG") :optional t) + ((:elibacc "ELIBACC") :optional t) + ((:elibbad "ELIBBAD") :optional t) + ((:elibscn "ELIBSCN") :optional t) + ((:elibmax "ELIBMAX") :optional t) + ((:elibexec "ELIBEXEC") :optional t) + ((:eilseq "EILSEQ")) + ((:erestart "ERESTART") :optional t) + ((:estrpipe "ESTRPIPE") :optional t) + ((:euclean "EUCLEAN") :optional t) + ((:enotnam "ENOTNAM") :optional t) + ((:enavail "ENAVAIL") :optional t) + ((:eremoteio "EREMOTEIO") :optional t) + ((:enomedium "ENOMEDIUM") :optional t) + ((:emediumtype "EMEDIUMTYPE") :optional t) + ((:estale "ESTALE")) + ((:enotblk "ENOTBLK")) + ((:etxtbsy "ETXTBSY")) + ((:eusers "EUSERS")) + ((:eloop "ELOOP")) + ((:ewouldblock "EWOULDBLOCK")) + ((:enomsg "ENOMSG")) + ((:eidrm "EIDRM")) + ((:eproto "EPROTO")) + ((:emultihop "EMULTIHOP")) + ((:ebadmsg "EBADMSG")) + ((:eoverflow "EOVERFLOW")) + ((:edquot "EDQUOT")) + ((:einprogress "EINPROGRESS")) + ((:ealready "EALREADY")) + ;; TODO: These errors are related to sockets. However they + ;; might not be unique to them. Remove those that are unique + ;; and keep those that might be set elsewhere. + ((:eprotonosupport "EPROTONOSUPPORT")) + ((:esocktnosupport "ESOCKTNOSUPPORT")) + ((:enotsock "ENOTSOCK")) + ((:edestaddrreq "EDESTADDRREQ")) + ((:emsgsize "EMSGSIZE")) + ((:eprototype "EPROTOTYPE")) + ((:enoprotoopt "ENOPROTOOPT")) + ((:eremote "EREMOTE")) + ((:enolink "ENOLINK")) + ((:epfnosupport "EPFNOSUPPORT")) + ((:eafnosupport "EAFNOSUPPORT")) + ((:eaddrinuse "EADDRINUSE")) + ((:eaddrnotavail "EADDRNOTAVAIL")) + ((:enetdown "ENETDOWN")) + ((:enetunreach "ENETUNREACH")) + ((:enetreset "ENETRESET")) + ((:econnaborted "ECONNABORTED")) + ((:econnreset "ECONNRESET")) + ((:eisconn "EISCONN")) + ((:enotconn "ENOTCONN")) + ((:eshutdown "ESHUTDOWN")) + ((:etoomanyrefs "ETOOMANYREFS")) + ((:etimedout "ETIMEDOUT")) + ((:econnrefused "ECONNREFUSED")) + ((:ehostdown "EHOSTDOWN")) + ((:ehostunreach "EHOSTUNREACH")) + ((:enonet "ENONET") :optional t) + ((:enobufs "ENOBUFS")) + ((:eopnotsupp "EOPNOTSUPP"))) + +;;; open() +(constant (o-rdonly "O_RDONLY")) +(constant (o-wronly "O_WRONLY")) +(constant (o-rdwr "O_RDWR")) +(constant (o-creat "O_CREAT")) +(constant (o-excl "O_EXCL")) +(constant (o-trunc "O_TRUNC")) +(constant (o-append "O_APPEND")) + +(constant (o-noctty "O_NOCTTY")) +(constant (o-nonblock "O_NONBLOCK")) +(constant (o-ndelay "O_NDELAY")) +(constant (o-sync "O_SYNC")) +(constant (o-nofollow "O_NOFOLLOW")) +(constant (o-async "O_ASYNC")) + +;;; lseek() +(constant (seek-set "SEEK_SET")) +(constant (seek-cur "SEEK_CUR")) +(constant (seek-end "SEEK_END")) + +;;; access() +(constant (r-ok "R_OK")) +(constant (w-ok "W_OK")) +(constant (x-ok "X_OK")) +(constant (f-ok "F_OK")) + +;;;; stat() + +(constant (s-irwxu "S_IRWXU") + :documentation "read, write, execute/search by owner") +(constant (s-irusr "S_IRUSR") :documentation "read permission, owner") +(constant (s-iwusr "S_IWUSR") :documentation "write permission, owner") +(constant (s-ixusr "S_IXUSR") :documentation "execute/search permission, owner") +(constant (s-ifmt "S_IFMT") :documentation "bitmask for type of entry") +(constant (s-ififo "S_IFIFO") :documentation "named pipe, aka fifo") +(constant (s-ifchr "S_IFCHR") :documentation "special character-device") +(constant (s-ifdir "S_IFDIR") :documentation "directory") +(constant (s-ifblk "S_IFBLK") :documentation "special block-device") +(constant (s-ifreg "S_IFREG") :documentation "regular file") +(constant (s-ifwht "S_IFWHT") :documentation "whiteout" :optional t) +(constant (s-iread "S_IREAD")) +(constant (s-iwrite "S_IWRITE")) +(constant (s-iexec "S_IEXEC")) + +(constant (s-irwxg "S_IRWXG") + :documentation "read, write, execute/search by group") +(constant (s-irgrp "S_IRGRP") :documentation "read permission, group") +(constant (s-iwgrp "S_IWGRP") :documentation "write permission, group") +(constant (s-ixgrp "S_IXGRP") + :documentation "execute/search permission, group") +(constant (s-irwxo "S_IRWXO") + :documentation "read, write, execute/search by others") +(constant (s-iroth "S_IROTH") :documentation "read permission, others") +(constant (s-iwoth "S_IWOTH") :documentation "write permission, others") +(constant (s-ixoth "S_IXOTH") + :documentation "execute/search permission, others") +(constant (s-isuid "S_ISUID") :documentation "set-user-ID on execution") +(constant (s-isgid "S_ISGID") :documentation "set-group-ID on execution") +(constant (s-isvtx "S_ISVTX") + :documentation "'sticky' bit, many meanings, nonportable") +(constant (s-iflnk "S_IFLNK") :documentation "symbolic link") +(constant (s-ifsock "S_IFSOCK") :documentation "socket") + +(constant (path-max "PATH_MAX" "MAXPATHLEN")) + +;;;; from unistd.h + +(ctype useconds-t "useconds_t") + +;;;; from time.h + +(ctype time-t "time_t") +(ctype suseconds-t "suseconds_t") + +#-darwin +(progn + (ctype clockid-t "clockid_t") + (constant (clock-monotonic "CLOCK_MONOTONIC")) + (constant (clock-realtime "CLOCK_REALTIME"))) + +(cstruct timespec "struct timespec" + "UNIX time specification in seconds and nanoseconds." + (sec "tv_sec" :type time-t) + (nsec "tv_nsec" :type :long)) + +;;;; from sys/select.h + +(cstruct timeval "struct timeval" + "UNIX time specification in seconds and microseconds." + (sec "tv_sec" :type time-t) + (usec "tv_usec" :type suseconds-t)) + +;;;; from sys/stat.h + +(ctype dev-t "dev_t") +(ctype ino-t "ino_t") + +(ctype nlink-t "nlink_t") +(ctype blksize-t "blksize_t") +(ctype blkcnt-t "blkcnt_t") + +(cstruct stat "struct stat" + (dev "st_dev" :type #-mips dev-t #+mips :unsigned-long) + (ino "st_ino" :type ino-t) + (mode "st_mode" :type mode-t) + (nlink "st_nlink" :type nlink-t) + (uid "st_uid" :type uid-t) + (gid "st_gid" :type gid-t) + (rdev "st_rdev" :type #-mips dev-t #+mips :unsigned-long) + (size "st_size" :type off-t) + (blksize "st_blksize" :type blkcnt-t) + (blocks "st_blocks" :type blksize-t) + (atime "st_atime" :type time-t) + (mtime "st_mtime" :type time-t) + (ctime "st_ctime" :type time-t)) + +;;; mmap() +(constant (prot-none "PROT_NONE") :documentation "mmap: no protection") +(constant (prot-read "PROT_READ") :documentation "mmap: read protection") +(constant (prot-write "PROT_WRITE") :documentation "mmap: write protection") +(constant (prot-exec "PROT_EXEC") :documentation "mmap: execute protection") +(constant (map-shared "MAP_SHARED") :documentation "mmap: shared memory") +(constant (map-private "MAP_PRIVATE") :documentation "mmap: private mapping") +(constant (map-fixed "MAP_FIXED") :documentation "mmap: map at location") +(constant (map-failed "MAP_FAILED") :documentation "mmap: failure") + +;;; poll() + +(ctype nfds-t "nfds_t") + +(cstruct pollfd "struct pollfd" + "Poll file descriptor activity specification structure." + (fd "fd" :type :int) + (events "events" :type :short) + (revents "revents" :type :short)) + +(constant (pollin "POLLIN")) +(constant (pollrdnorm "POLLRDNORM")) +(constant (pollrdband "POLLRDBAND")) +(constant (pollpri "POLLPRI")) +(constant (pollout "POLLOUT")) +(constant (pollwrnorm "POLLWRNORM")) +(constant (pollwrband "POLLWRBAND")) +(constant (pollerr "POLLERR")) +#-darwin (constant (pollrdhup "POLLRDHUP")) +(constant (pollhup "POLLHUP")) +(constant (pollnval "POLLNVAL")) diff --git a/syscalls/ffi-wrappers-unix.lisp b/syscalls/ffi-wrappers-unix.lisp new file mode 100644 index 0000000..9abf82e --- /dev/null +++ b/syscalls/ffi-wrappers-unix.lisp @@ -0,0 +1,95 @@ +;;;; -*- Mode: Lisp; Syntax: ANSI-Common-Lisp; indent-tabs-mode: nil -*- +;;; +;;; --- FFI wrappers. +;;; + +(in-package :iolib.syscalls) + +(c "#if defined(__linux__)") +(define "_XOPEN_SOURCE" 600) +(define "_LARGEFILE_SOURCE") +(define "_LARGEFILE64_SOURCE") +(define "_FILE_OFFSET_BITS" 64) +(c "#endif") + +(include "string.h" "errno.h" "sys/types.h" "sys/stat.h" + "unistd.h" "sys/mman.h") + + +;;;----------------------------------------------------------------------------- +;;; Large-file support +;;;----------------------------------------------------------------------------- + +;;; FIXME: this is only necessary on Linux right? + +(defwrapper ("lseek" %sys-lseek) + ("off_t" off-t) + (fildes ("int" :int)) + (offset ("off_t" off-t)) + (whence :int)) + +(defwrapper ("truncate" %sys-truncate) + ("int" (return-wrapper :int :error-generator return-posix-error/restart)) + (path ("const char*" filename-designator)) + (length ("off_t" off-t))) + +(defwrapper ("ftruncate" %sys-ftruncate) + ("int" (return-wrapper :int :error-generator return-posix-error/restart)) + (fd ("int" :int)) + (length ("off_t" off-t))) + +(defwrapper ("mmap" %sys-mmap) + ("void*" :pointer) + (start :pointer) + (length ("size_t" size-t)) + (prot :int) + (flags :int) + (fd ("int" :int)) + (offset ("off_t" off-t))) + +(defwrapper ("stat" %%sys-stat) + ("int" :int) + (file-name ("const char*" filename-designator)) + (buf ("struct stat*" :pointer))) + +(defwrapper ("fstat" %%sys-fstat) + ("int" :int) + (filedes ("int" :int)) + (buf ("struct stat*" :pointer))) + +(defwrapper ("lstat" %%sys-lstat) + ("int" :int) + (file-name ("const char*" filename-designator)) + (buf ("struct stat*" :pointer))) + +(defwrapper ("pread" %sys-pread) + ("ssize_t" (return-wrapper ssize-t :error-generator return-posix-error/restart)) + (fd ("int" :int)) + (buf :pointer) + (count ("size_t" size-t)) + (offset ("off_t" off-t))) + +(defwrapper ("pwrite" %sys-pwrite) + ("ssize_t" (return-wrapper ssize-t :error-generator return-posix-error/restart)) + (fd ("int" :int)) + (buf :pointer) + (count ("size_t" size-t)) + (offset ("off_t" off-t))) + + +;;;----------------------------------------------------------------------------- +;;; ERRNO-related functions +;;;----------------------------------------------------------------------------- + +(defwrapper* "get_errno" :int () + "return errno;") + +(defwrapper* "set_errno" :int ((value :int)) + "errno = value;" + "return errno;") + +(defwrapper ("strerror_r" %sys-strerror-r) + :int + (errnum :int) + (buf :string) + (buflen ("size_t" size-t))) diff --git a/syscalls/os-conditions-unix.lisp b/syscalls/os-conditions-unix.lisp new file mode 100644 index 0000000..5690ed6 --- /dev/null +++ b/syscalls/os-conditions-unix.lisp @@ -0,0 +1,61 @@ +;;;; -*- Mode: Lisp; Syntax: ANSI-Common-Lisp; indent-tabs-mode: nil -*- +;;; +;;; --- *NIX-specific error conditions. +;;; + +(in-package :iolib.syscalls) + +;;;----------------------------------------------------------------------------- +;;; POSIX Syscall Errors +;;;----------------------------------------------------------------------------- + +(define-condition posix-error (syscall-error) + () + (:documentation + "POSIX-ERRORs are signalled whenever ERRNO is set by a POSIX call.")) + +;;; HASH TABLE mapping keywords (such as :EAGAIN) to symbols denoting +;;; subtypes of POSIX-ERROR. +(defparameter *posix-error-map* (make-hash-table :test #'eq)) + +(defun get-posix-error-condition (keyword) + (gethash keyword *posix-error-map*)) + +;;; Define an error condition for each ERRNO value defined in the +;;; ERRNO-VALUES enum type and populate *POSIX-ERROR-MAP*. +(macrolet + ((define-posix-errors (keywords) + `(progn + ,@(loop for kw in keywords collect + (let ((cond-name (intern (symbol-name kw))) + (code (foreign-enum-value 'errno-values kw))) + `(progn + (define-condition ,cond-name (posix-error) () + (:default-initargs :code ,code :identifier ,kw)) + (setf (gethash ,kw *posix-error-map*) ',cond-name))))))) + (define-posix-errors + #.(foreign-enum-keyword-list 'errno-values))) + +;;; Instantiates a subclass of POSIX-ERROR matching ERR or a plain +;;; POSIX-ERROR if no matching subclass is found. ERR can be either a +;;; keyword or an integer both denoting an ERRNO value. +(defun make-posix-error (err) + (multiple-value-bind (error-keyword error-code) + (typecase err + (keyword (values err (foreign-enum-value 'errno-values err :errorp nil))) + (integer (values (foreign-enum-keyword 'errno-values err :errorp nil) err)) + (t (bug "Non-valid error-designator: ~A" err))) + (unless (and error-keyword error-code) + (bug "A non-existent ~A syscall error has been signaled: ~A, ~A" + 'errno-values (or error-keyword :unknown) error-code)) + (make-condition (get-posix-error-condition error-keyword)))) + +(declaim (inline posix-error)) +(defun posix-error (&optional (errno (get-errno))) + (error (make-posix-error errno))) + +;;; Default ERROR-GENERATOR for ERRNO-WRAPPER. +(declaim (inline signal-posix-error)) +(defun signal-posix-error (return-value) + (declare (ignore return-value)) + (posix-error)) diff --git a/syscalls/pkgdcl.lisp b/syscalls/pkgdcl.lisp new file mode 100644 index 0000000..33c412b --- /dev/null +++ b/syscalls/pkgdcl.lisp @@ -0,0 +1,304 @@ +;;;; -*- Mode: Lisp; Syntax: ANSI-Common-Lisp; indent-tabs-mode: nil -*- +;;; +;;; --- Package definition. +;;; + +(in-package :common-lisp-user) + +(defpackage :iolib.syscalls + (:nicknames #:isys) + (:use :iolib.base :cffi) + (:shadow #:time) + (:export + ;; Conditions + #:system-error + #:code-of + #:identifier-of + #:message-of + #:syscall-error + #:posix-error + #:poll-error + #:poll-timeout + + ;; Pathname Functions + #:native-namestring + + ;; Type Designators + #:filename + #:filename-designator + #:pointer-or-nil + #:pointer-or-nil-designator + #:bool + #:bool-designator + + ;; Misc + #:repeat-decreasing-timeout + #:repeat-upon-condition-decreasing-timeout + + ;; Return wrapper + #:return-wrapper + #:error-predicate-of + #:return-filter-of + #:error-generator-of + #:base-type-of + #:never-fails + #:signal-posix-error + #:signal-posix-error/restart + #:return-posix-error/restart + + ;; Syscall definition + #:defentrypoint + #:defcfun* + #:defsyscall + #:defsyscall* + + ;;;-------------------------------------------------------------------------- + ;;; Syscalls + ;;;-------------------------------------------------------------------------- + + ;; Specials + #:*default-open-mode* + #:*environ* + + ;; Errno-related functions + #:%sys-strerror + #:get-errno + #:set-errno + + ;; Memory manipulation functions + #:%sys-memset + #:%sys-bzero + #:%sys-memcpy + #:%sys-memmove + + ;; Files + #:%sys-read + #:%sys-write + #:%sys-pread + #:%sys-pwrite + #:%sys-open + #:%sys-creat + #:%sys-pipe + #:%sys-mkfifo + #:%sys-umask + #:%sys-lseek + #:%sys-access + #:%sys-truncate + #:%sys-ftruncate + #:%sys-rename + #:%sys-link + #:%sys-symlink + #:%sys-readlink + #:%sys-unlink + #:%sys-chown + #:%sys-fchown + #:%sys-lchown + #:%sys-chmod + #:%sys-fchmod + #:%sys-stat + #:%sys-fstat + #:%sys-lstat + #:%sys-sync + #:%sys-fsync + #:%sys-mkstemp + + ;; Directories + #:%sys-mkdir + #:%sys-rmdir + #:%sys-chdir + #:%sys-fchdir + #:%sys-getcwd + #:%sys-mkdtemp + + ;; File descriptors + #:%sys-close + #:%sys-dup + #:%sys-dup2 + #:%sys-ioctl + #:%sys-fd-open-p + + ;; Memory mapping + #:%sys-mmap + #:%sys-munmap + + ;; Time + #:%sys-usleep + #:%sys-time + #:%sys-gettimeofday + #:%sys-get-monotonic-time + + ;; Environment + #:%sys-getenv + #:%sys-setenv + #:%sys-unsetenv + + ;; Local info + #:%sys-gethostname + #:%sys-getdomainname + + ;;;-------------------------------------------------------------------------- + ;;; Foreign types and constants + ;;;-------------------------------------------------------------------------- + + ;; Primitive type sizes + #:size-of-char + #:size-of-int + #:size-of-long + #:size-of-long-long + #:size-of-pointer + #:size-of-short + + ;; Types + #:size-t + #:ssize-t + #:pid-t + #:gid-t + #:uid-t + #:off-t + #:mode-t + #:time-t + #:useconds-t + #:suseconds-t + #:dev-t + #:ino-t + #:nlink-t + #:blksize-t + #:blkcnt-t + #:nfds-t + + ;; OPEN() + #:o-rdonly + #:o-wronly + #:o-rdwr + #:o-creat + #:o-excl + #:o-trunc + #:o-append + #:o-noctty + #:o-nonblock + #:o-ndelay + #:o-sync + #:o-nofollow + #:o-async + + ;; LSEEK() + #:seek-set + #:seek-cur + #:seek-end + + ;; ACCESS() + #:r-ok + #:w-ok + #:x-ok + #:f-ok + + ;; STAT() + #:s-irwxu + #:s-irusr + #:s-iwusr + #:s-ixusr + #:s-ifmt + #:s-ififo + #:s-ifchr + #:s-ifdir + #:s-ifblk + #:s-ifreg + #:s-ifwht + #:s-iread + #:s-iwrite + #:s-iexec + #:s-irwxg + #:s-irgrp + #:s-iwgrp + #:s-ixgrp + #:s-irwxo + #:s-iroth + #:s-iwoth + #:s-ixoth + #:s-isuid + #:s-isgid + #:s-isvtx + #:s-iflnk + #:s-ifsock + #:path-max + + ;; MMAP() + #:prot-none + #:prot-read + #:prot-write + #:prot-exec + #:map-shared + #:map-private + #:map-fixed + #:map-failed + + ;; POLL() + #:pollin + #:pollrdnorm + #:pollrdband + #:pollpri + #:pollout + #:pollwrnorm + #:pollwrband + #:pollerr + #:pollrdhup + #:pollhup + #:pollnval + + ;;; Structs + + ;; timespec + #:timespec + #:sec + #:nsec + + ;; timeval + #:timeval + #:sec + #:usec + + ;; stat + #:stat + #:dev #:stat-dev + #:ino #:stat-ino + #:mode #:stat-mode + #:nlink #:stat-nlink + #:uid #:stat-uid + #:gid #:stat-gid + #:rdev #:stat-rdev + #:size #:stat-size + #:blksize #:stat-blksize + #:blocks #:stat-blocks + #:atime #:stat-atime + #:mtime #:stat-mtime + #:ctime #:stat-ctime + + ;; pollfd + #:pollfd + #:fd + #:events + #:revents + + ;; Syscall error codes + #:errno-values + #:eperm #:enoent #:esrch #:eintr #:eio #:enxio #:e2big #:enoexec + #:ebadf #:echild #:eagain #:enomem #:eacces #:efault #:ebusy #:eexist + #:exdev #:enodev #:enotdir #:eisdir #:einval #:enfile #:emfile + #:enotty #:efbig #:enospc #:espipe #:erofs #:emlink #:epipe #:edom + #:erange #:edeadlk #:enametoolong #:enolck #:enosys #:enotempty + #:echrng #:el2nsync #:el3hlt #:el3rst #:elnrng #:eunatch #:enocsi + #:el2hlt #:ebade #:ebadr #:exfull #:enoano #:ebadrqc #:ebadslt + #:edeadlock #:ebfont #:enostr #:enodata #:etime #:enosr #:enopkg + #:eadv #:esrmnt #:ecomm #:edotdot #:enotuniq #:ebadfd #:elibscn + #:elibmax #:elibexec #:eilseq #:erestart #:estrpipe #:euclean + #:enotnam #:enavail #:eremoteio #:enomedium #:emediumtype #:estale + #:enotblk #:etxtbsy #:eusers #:eloop #:ewouldblock #:enomsg #:eidrm + #:eproto #:emultihop #:ebadmsg #:eoverflow #:edquot #:einprogress + #:ealready #:eprotonosupport #:esocktnosupport #:enotsock + #:edestaddrreq #:emsgsize #:eprototype #:enoprotoopt #:eremote + #:enolink #:epfnosupport #:eafnosupport #:eaddrinuse #:eaddrnotavail + #:enetdown #:enetunreach #:enetreset #:econnaborted #:econnreset + #:eisconn #:enotconn #:eshutdown #:etoomanyrefs #:etimedout + #:econnrefused #:ehostdown #:ehostunreach #:enonet #:enobufs + #:eopnotsupp + )) -- 2.11.4.GIT