Newer
Older
;;;; -*- Mode: Lisp; indent-tabs-mode: nil -*-
;;;
;;; --- *UNIX foreign function definitions.
;;;
(in-package :iolib.syscalls)
(eval-when (:compile-toplevel)
(declaim (optimize (speed 3) (safety 1) (debug 1))))
Stelian Ionescu
committed
;; FIXME: move this into an ASDF operation
(eval-when (:compile-toplevel :load-toplevel :execute)
Stelian Ionescu
committed
(define-foreign-library libfixposix
(t (:default "libfixposix")))
(use-foreign-library libfixposix))
;;;-------------------------------------------------------------------------
;;;-------------------------------------------------------------------------
Stelian Ionescu
committed
(defcfun (errno "lfp_errno") :int)
(defun (setf errno) (value)
(foreign-funcall "lfp_set_errno" :int value :int))
Stelian Ionescu
committed
:int
(errnum :int)
Stelian Ionescu
committed
(buflen size-t))
(defentrypoint strerror (&optional (err (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)
(defmethod print-object ((e syscall-error) s)
(with-slots (syscall code identifier message handle handle2) e
(print-unreadable-object (e s :type nil :identity nil)
(cond
(message
(format s "~A" message))
(t
(format s "Syscall ~S signalled error ~A(~S) ~S"
syscall identifier (or code "[No code]")
(or (strerror code) "[Can't get error string.]"))
(when handle (format s " FD=~A" handle))
(when handle2 (format s " FD2=~A" handle2)))))))
;;;-------------------------------------------------------------------------
Stelian Ionescu
committed
;;; Memory manipulation
;;;-------------------------------------------------------------------------
Stelian Ionescu
committed
(defcfun (memset "memset") :pointer
"Fill the first COUNT bytes of BUFFER with the constant VALUE."
(buffer :pointer)
(value :int)
(count size-t))
Stelian Ionescu
committed
"Fill the first COUNT bytes of BUFFER with zeros."
(memset buffer 0 count))
(defcfun (memcpy "memcpy") :pointer
"Copy COUNT octets from SRC to DEST.
The two memory areas must not overlap."
(dest :pointer)
(src :pointer)
Stelian Ionescu
committed
(defcfun (memmove "memmove") :pointer
"Copy COUNT octets from SRC to DEST.
The two memory areas may overlap."
(dest :pointer)
(src :pointer)
;;;-------------------------------------------------------------------------
;;;-------------------------------------------------------------------------
Stelian Ionescu
committed
(flags :uint64)
Stelian Ionescu
committed
(defentrypoint open (path flags &optional (mode #o666))
"Open a file descriptor for PATH using FLAGS and permissions MODE(#o666 by default)."
"Create file PATH with permissions MODE and return the new FD."
"Create pipe, returns two values with the new FDs."
(values (mem-aref fds :int 0)
(mem-aref fds :int 1))))
"Create a FIFO (named pipe) with name PATH and permissions MODE."
"Sets the umask to NEW-MODE and returns the old one."
"Reposition the offset of the open file associated with the file descriptor FD
to the argument OFFSET according to the directive WHENCE."
(fd :int)
Stelian Ionescu
committed
(offset off-t)
(whence :int))
"Check whether the file PATH can be accessed using mode MODE."
(defsyscall (truncate "lfp_truncate")
"Truncate the file PATH to a size of precisely LENGTH octets."
Stelian Ionescu
committed
(length off-t))
(defsyscall (ftruncate "lfp_ftruncate")
"Truncate the file referenced by FD to a size of precisely LENGTH octets."
Stelian Ionescu
committed
(fd :int)
(length off-t))
"Rename file named by OLDPATH to NEWPATH."
(oldpath sstring)
(newpath sstring))
"Create a hard link from file OLDPATH to NEWPATH."
(oldpath sstring)
(newpath sstring))
(defsyscall (symlink "symlink") :int
"Create a symbolic link from file OLDPATH to NEWPATH."
(oldpath sstring)
(newpath sstring))
(defsyscall (%readlink "readlink") ssize-t
"Read the file name pointed by the symbolic link PATH."
(with-foreign-pointer (buf +cstring-path-max+ bufsize)
(let ((count (%readlink path buf bufsize)))
(cstring-to-sstring buf count))))
(defsyscall (%realpath "realpath") sstring
"Read the file name pointed by the symbolic link PATH."
(with-foreign-pointer (buf +cstring-path-max+)
"Delete the file PATH from the file system."
"Change ownership of file PATH to uid OWNER and gid GROUP(dereferences symlinks)."
"Change ownership of an open file referenced by FD to uid OWNER and gid GROUP."
(fd :int)
(owner uid-t)
(group uid-t))
"Change ownership of a file PATH to uid OWNER and gid GROUP(does not dereference symlinks)."
"Change permissions of file PATH to mode MODE."
"Change permissions of open file referenced by FD to mode MODE."
Stelian Ionescu
committed
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
;;;-------------------------------------------------------------------------
;;; I/O
;;;-------------------------------------------------------------------------
(defsyscall (read "read")
(ssize-t :restart t :handle fd)
"Read at most COUNT bytes from FD into the foreign area BUF."
(fd :int)
(buf :pointer)
(count size-t))
(defsyscall (write "write")
(ssize-t :restart t :handle fd)
"Write at most COUNT bytes to FD from the foreign area BUF."
(fd :int)
(buf :pointer)
(count size-t))
(defsyscall (readv "readv")
(ssize-t :restart t :handle fd)
"Read from FD into the first IOVCNT buffers of the IOV array."
(fd :int)
(iov :pointer)
(iovcnt :int))
(defsyscall (writev "writev")
(ssize-t :restart t :handle fd)
"Writes to FD the first IOVCNT buffers of the IOV array."
(fd :int)
(iov :pointer)
(iovcnt :int))
(defsyscall (pread "lfp_pread")
(ssize-t :restart t :handle fd)
"Read at most COUNT bytes from FD at offset OFFSET into the foreign area BUF."
(fd :int)
(buf :pointer)
(count size-t)
(offset off-t))
(defsyscall (pwrite "lfp_pwrite")
(ssize-t :restart t :handle fd)
"Write at most COUNT bytes to FD at offset OFFSET from the foreign area BUF."
(fd :int)
(buf :pointer)
(count size-t)
(offset off-t))
(defsyscall (sendfile "lfp_sendfile")
(ssize-t :restart t :handle infd :handle2 outfd)
(infd :int)
(outfd :int)
(offset off-t)
(nbytes size-t))
Stelian Ionescu
committed
;;;-------------------------------------------------------------------------
;;; Stat()
;;;-------------------------------------------------------------------------
Stelian Ionescu
committed
:int
Stelian Ionescu
committed
(buf :pointer))
Stelian Ionescu
committed
(buf :pointer))
Stelian Ionescu
committed
:int
Stelian Ionescu
committed
(buf :pointer))
;;; 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)
"Get information about file PATH(dereferences symlinks)."
"Get information about file descriptor FD."
"Get information about file PATH(does not dereference symlinks)."
"Schedule all file system buffers to be written to disk.")
"Schedule a file's buffers to be written to disk."
(defsyscall (%mkstemp "lfp_mkstemp") :int
(defentrypoint mkstemp (&optional (template ""))
"Generate a unique temporary filename from TEMPLATE.
Return two values: the file descriptor and the path of the temporary file."
(let ((template (concatenate 'string template "XXXXXX")))
(with-sstring-to-cstring (ptr template)
(values (%mkstemp ptr) (cstring-to-sstring ptr)))))
;;;-------------------------------------------------------------------------
;;;-------------------------------------------------------------------------
"Create directory PATH with permissions MODE."
"Change the current working directory to PATH."
"Change the current working directory to the directory referenced by FD."
(defsyscall (%getcwd "getcwd") :pointer
"Return the current working directory as a string."
(with-cstring-to-sstring (buf +cstring-path-max+ bufsize)
(defsyscall (%mkdtemp "mkdtemp") sstring
(defentrypoint mkdtemp (&optional (template ""))
"Generate a unique temporary filename from TEMPLATE."
(let ((template (concatenate 'string template "XXXXXX")))
;;;-------------------------------------------------------------------------
;;;-------------------------------------------------------------------------
"Duplicate file descriptor FD."
(fd :int))
(:int :restart t :handle oldfd :handle2 newfd)
"Make NEWFD be the copy of OLDFD, closing NEWFD first if necessary."
(oldfd :int)
(newfd :int))
(fd :int)
(cmd :int))
;;; FIXME: Linux/glibc says ARG's type is long, POSIX says it's int.
;;; Is this an issue?
(fd :int)
(cmd :int)
(arg :int))
(defsyscall (%fcntl/pointer "fcntl")
(fd :int)
(cmd :int)
(arg :pointer))
(defentrypoint fcntl (fd cmd &optional (arg nil argp))
((not argp) (%fcntl/noarg fd cmd))
((integerp arg) (%fcntl/int fd cmd arg))
((pointerp arg) (%fcntl/pointer fd cmd arg))
:expected-type '(or null integer foreign-pointer)))))
"Send request REQUEST to file referenced by FD."
(request :unsigned-int))
(defsyscall (%ioctl/pointer "ioctl")
"Send request REQUEST to file referenced by FD using argument ARG."
(request :unsigned-int)
(defentrypoint ioctl (fd request &optional (arg nil argp))
((not argp) (%ioctl/noarg fd request))
((pointerp arg) (%ioctl/pointer fd request arg))
(t (error 'type-error :datum arg
:expected-type '(or null foreign-pointer)))))
Stelian Ionescu
committed
(defsyscall (fd-cloexec-p "lfp_is_fd_cloexec") bool-designator
(fd :int))
(defsyscall (%set-fd-cloexec "lfp_set_fd_cloexec") :int
(fd :int)
(enabled bool-designator))
(defentrypoint (setf fd-cloexec-p) (enabled fd)
(%set-fd-cloexec fd enabled))
(defsyscall (fd-nonblock-p "lfp_is_fd_nonblock") bool-designator
(fd :int))
(defsyscall (%set-fd-nonblock "lfp_set_fd_nonblock") :int
(fd :int)
(enabled bool-designator))
(defentrypoint (setf fd-nonblock-p) (enabled fd)
(%set-fd-nonblock fd enabled))
(defsyscall (fd-open-p "lfp_is_fd_open") bool-designator
(fd :int))
;;;-------------------------------------------------------------------------
;;; TTYs
;;;-------------------------------------------------------------------------
Stelian Ionescu
committed
(defsyscall (openpt "lfp_openpt") :int
(flags :uint64))
Stelian Ionescu
committed
(defsyscall (%ptsname "lfp_ptsname")
(:pointer :handle fd)
(fd :int)
(buf :pointer)
(buflen size-t))
Stelian Ionescu
committed
(defentrypoint ptsname (fd)
(with-foreign-pointer (buf +cstring-path-max+ bufsize)
(%ptsname fd buf bufsize)
(nth-value 0 (foreign-string-to-lisp buf))))
;;;-------------------------------------------------------------------------
Stelian Ionescu
committed
;;; I/O polling
;;;-------------------------------------------------------------------------
(defsyscall (select "lfp_select") :int
"Scan for I/O activity on multiple file descriptors."
(nfds :int)
(readfds :pointer)
(writefds :pointer)
(exceptfds :pointer)
(timeout :pointer))
Stelian Ionescu
committed
(defentrypoint copy-fd-set (from to)
Stelian Ionescu
committed
to)
(defcfun (fd-clr "lfp_fd_clr") :void
(fd :int)
(fd-set :pointer))
(defcfun (fd-isset "lfp_fd_isset") bool
(fd :int)
(fd-set :pointer))
(defcfun (fd-set "lfp_fd_set") :void
(fd :int)
(fd-set :pointer))
(defcfun (fd-zero "lfp_fd_zero") :void
(fd-set :pointer))
;;; FIXME: Until a way to autodetect platform features is implemented
(eval-when (:compile-toplevel :load-toplevel :execute)
(unless (boundp 'pollrdhup)
(defconstant pollrdhup 0)))
"Scan for I/O activity on multiple file descriptors."
(fds :pointer)
(nfds nfds-t)
(timeout :int))
#+linux
(progn
(defsyscall (epoll-create "epoll_create") :int
"Open an epoll file descriptor."
(size :int))
(defsyscall (epoll-ctl "epoll_ctl")
"Control interface for an epoll descriptor."
(epfd :int)
(op :int)
(fd :int)
(event :pointer))
(defsyscall (epoll-wait "epoll_wait")
"Wait for an I/O event on an epoll file descriptor."
(epfd :int)
(events :pointer)
(maxevents :int)
(timeout :int)))
#+bsd
(progn
"Open a kernel event queue.")
"Control interface for a kernel event queue."
(changelist :pointer) ; const struct kevent *
(nchanges :int)
(eventlist :pointer) ; struct kevent *
(nevents :int)
(timeout :pointer)) ; const struct timespec *
(defentrypoint ev-set (%kev %ident %filter %flags %fflags %data %udata)
(with-foreign-slots ((ident filter flags fflags data udata) %kev kevent)
(setf ident %ident filter %filter flags %flags
fflags %fflags data %data udata %udata))))
Stelian Ionescu
committed
;;;-------------------------------------------------------------------------
;;; Socket message readers
;;;-------------------------------------------------------------------------
(defcfun (cmsg.firsthdr "lfp_cmsg_firsthdr") :pointer
(msgh :pointer))
(defcfun (cmsg.nxthdr "lfp_cmsg_nxthdr") :pointer
(msgh :pointer)
(cmsg :pointer))
(defcfun (cmsg.space "lfp_cmsg_space") size-t
(length size-t))
(defcfun (cmsg.len "lfp_cmsg_len") size-t
(length size-t))
(defcfun (cmsg.data "lfp_cmsg_data") :pointer
(cmsg :pointer))
Stelian Ionescu
committed
;;;-------------------------------------------------------------------------
;;; Directory walking
;;;-------------------------------------------------------------------------
(defsyscall (opendir "opendir") :pointer
"Open directory PATH for listing of its contents."
Stelian Ionescu
committed
(defsyscall (closedir "closedir") :int
"Close directory DIR when done listing its contents."
Stelian Ionescu
committed
Stelian Ionescu
committed
(defsyscall (%readdir "lfp_readdir") :int
Stelian Ionescu
committed
(dirp :pointer)
(entry :pointer)
(result :pointer))
"Reads an item from the listing of directory DIR (reentrant)."
Stelian Ionescu
committed
(with-foreign-objects ((entry 'dirent) (result :pointer))
Stelian Ionescu
committed
(if (null-pointer-p (mem-ref result :pointer))
nil
(with-foreign-slots ((name type fileno) entry dirent)
(values (cstring-to-sstring name) type fileno)))))
Stelian Ionescu
committed
(defsyscall (rewinddir "rewinddir") :void
Stelian Ionescu
committed
(defsyscall (seekdir "seekdir") :void
"Seek into directory DIR to position POS(as returned by TELLDIR)."
Stelian Ionescu
committed
;;; FIXME: According to POSIX docs "no errors are defined" for
;;; telldir() but Linux manpages specify a possible EBADF.
(defsyscall (telldir "telldir") off-t
"Return the current location in directory DIR."
Stelian Ionescu
committed
;;;-------------------------------------------------------------------------
;;;-------------------------------------------------------------------------
"Map file referenced by FD at offset OFFSET into address space of the
calling process at address ADDR and length LENGTH.
PROT describes the desired memory protection of the mapping.
FLAGS determines whether updates to the mapping are visible to other
processes mapping the same region."
(addr :pointer)
Stelian Ionescu
committed
(length size-t)
(prot :int)
(flags :int)
(fd :int)
(offset off-t))
"Unmap pages of memory starting at address ADDR with length LENGTH."
(addr :pointer)
(length size-t))
;;;-------------------------------------------------------------------------
;;; Process creation and info
;;;-------------------------------------------------------------------------
(defsyscall (fork "fork") pid-t)
(defsyscall (execv "execv") :int
(path sstring)
(argv :pointer))
(pid pid-t)
(status :pointer)
(options :int))
(with-foreign-pointer (status (sizeof :int))
(let ((ret (%waitpid pid status options)))
(values ret (mem-ref status :int)))))
(defsyscall (getpid "getpid") pid-t
"Returns the process id of the current process")
(defsyscall (getppid "getppid") pid-t
"Returns the process id of the current process's parent")
(defsyscall (getuid "getuid") uid-t
"Get real user id of the current process.")
"Set real user id of the current process to UID."
(uid uid-t))
(defsyscall (geteuid "geteuid") uid-t
"Get effective user id of the current process.")
(defsyscall (seteuid "seteuid") :int
"Set effective user id of the current process to UID."
(uid uid-t))
(defsyscall (getgid "getgid") gid-t
"Get real group id of the current process.")
"Set real group id of the current process to GID."
(gid gid-t))
(defsyscall (getegid "getegid") gid-t
"Get effective group id of the current process.")
(defsyscall (setegid "setegid") :int
"Set effective group id of the current process to GID."
(gid gid-t))
(defsyscall (setreuid "setreuid") :int
"Set real and effective user id of the current process to RUID and EUID."
(ruid uid-t)
(euid uid-t))
(defsyscall (setregid "setregid") :int
"Set real and effective group id of the current process to RGID and EGID."
(rgid gid-t)
(egid gid-t))
(defsyscall (getpgid "getpgid") pid-t
"Get process group id of process PID."
(pid pid-t))
(defsyscall (setpgid "setpgid") :int
"Set process group id of process PID to value PGID."
(pid pid-t)
(pgid pid-t))
(defsyscall (getpgrp "getpgrp") pid-t
"Get process group id of the current process.")
(defsyscall (setpgrp "setpgrp") pid-t
"Set process group id of the current process.")
(defsyscall (setsid "setsid") pid-t
"Create session and set process group id of the current process.")
(defsyscall (%getrlimit "lfp_getrlimit")
Stelian Ionescu
committed
:int
(resource :int)
(rlimit :pointer))
(defentrypoint getrlimit (resource)
"Return soft and hard limit of system resource RESOURCE."
(with-foreign-object (rl 'rlimit)
(with-foreign-slots ((cur max) rl rlimit)
(values cur max))))
(defsyscall (%setrlimit "lfp_setrlimit")
Stelian Ionescu
committed
:int
(resource :int)
(rlimit :pointer))
(defentrypoint setrlimit (resource soft-limit hard-limit)
"Set SOFT-LIMIT and HARD-LIMIT of system resource RESOURCE."
(with-foreign-object (rl 'rlimit)
(with-foreign-slots ((cur max) rl rlimit)
(setf cur soft-limit
max hard-limit)
(defsyscall (%getrusage "getrusage") :int
(who :int)
(usage :pointer))
;;; TODO: it might be more convenient to return a wrapper object here
;;; instead like we do in STAT.
"Return resource usage measures of WHO."
(with-foreign-object (ru 'rusage)
(with-foreign-slots ((maxrss ixrss idrss isrss minflt majflt nswap inblock
oublock msgsnd msgrcv nsignals nvcsw nivcsw)
ru rusage)
(values (foreign-slot-value (foreign-slot-pointer ru 'rusage 'utime)
'timeval 'sec)
(foreign-slot-value (foreign-slot-pointer ru 'rusage 'utime)
'timeval 'usec)
(foreign-slot-value (foreign-slot-pointer ru 'rusage 'stime)
'timeval 'sec)
(foreign-slot-value (foreign-slot-pointer ru 'rusage 'stime)
'timeval 'usec)
maxrss ixrss idrss isrss minflt majflt
nswap inblock oublock msgsnd
msgrcv nsignals nvcsw nivcsw))))
(defsyscall (getpriority "getpriority") :int
"Get the scheduling priority of a process, process group, or user,
as indicated by WHICH and WHO."
(which :int)
(who :int))
(defsyscall (setpriority "setpriority") :int
"Set the scheduling priority of a process, process group, or user,
as indicated by WHICH and WHO to VALUE."
(which :int)
(who :int)
(value :int))
(defentrypoint nice (&optional (increment 0))
"Get or set process priority."
;; FIXME: race condition. might need WITHOUT-INTERRUPTS on some impl.s
(let ((retval (foreign-funcall "nice" :int increment :int))
(signal-syscall-error errno "nice")
"terminate the calling process"
(status :int))
;;;-------------------------------------------------------------------------
;;; Signals
;;;-------------------------------------------------------------------------
(defsyscall (sigaction "sigaction") :int
(signum :int)
(act :pointer)
(oldact :pointer))
Stelian Ionescu
committed
(defentrypoint wifexited (status)
(plusp (foreign-funcall "lfp_wifexited" :int status :int)))
(defentrypoint wexitstatus (status)
(foreign-funcall "lfp_wexitstatus" :int status :int))
(defentrypoint wifsignaled (status)
(plusp (foreign-funcall "lfp_wifsignaled" :int status :int)))
(defentrypoint wtermsig (status)
(foreign-funcall "lfp_wtermsig" :int status :int))
(defentrypoint wtermsig* (status)
(foreign-enum-keyword 'signal (wtermsig status)))
Stelian Ionescu
committed
(defentrypoint wcoredump (status)
(plusp (foreign-funcall "lfp_wcoredump" :int status :int)))
(defentrypoint wifstopped (status)
(plusp (foreign-funcall "lfp_wifstopped" :int status :int)))
(defentrypoint wstopsig (status)
(foreign-funcall "lfp_wstopsig" :int status :int))
Stelian Ionescu
committed
(defentrypoint wifcontinued (status)
(plusp (foreign-funcall "lfp_wifcontinued" :int status :int)))
;;;-------------------------------------------------------------------------
;;;-------------------------------------------------------------------------
"Suspend execution for USECONDS microseconds."
Stelian Ionescu
committed
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
(defsyscall (%clock-getres "lfp_clock_getres") :int
"Returns the resolution of the clock CLOCKID."
(clockid clockid-t)
(res :pointer))
(defentrypoint clock-getres (clock-id)
(with-foreign-object (ts 'timespec)
(with-foreign-slots ((sec nsec) ts timespec)
(%clock-getres clock-id ts)
(values sec nsec))))
(defsyscall (%clock-gettime "lfp_clock_gettime") :int
(clockid clockid-t)
(tp :pointer))
(defentrypoint clock-gettime (clock-id)
"Returns the time of the clock CLOCKID."
(with-foreign-object (ts 'timespec)
(with-foreign-slots ((sec nsec) ts timespec)
(%clock-gettime clock-id ts)
(values sec nsec))))
(defsyscall (%clock-settime "lfp_clock_settime") :int
(clockid clockid-t)
(tp :pointer))
(defentrypoint clock-settime (clock-id)
"Sets the time of the clock CLOCKID."
(with-foreign-object (ts 'timespec)
(with-foreign-slots ((sec nsec) ts timespec)
(%clock-settime clock-id ts)
(values sec nsec))))
;; FIXME: replace it with clock_gettime(CLOCK_MONOTONIC, ...)
(defentrypoint get-monotonic-time ()
"Gets current time in seconds from a system's monotonic clock."
(multiple-value-bind (seconds nanoseconds)
Stelian Ionescu
committed
(clock-gettime clock-monotonic)
;;;-------------------------------------------------------------------------
;;;-------------------------------------------------------------------------
(defsyscall (os-environ "lfp_get_environ") :pointer
"Return a pointer to the current process environment.")
(defmacro %obsolete-*environ* ()
(iolib.base::signal-obsolete '*environ* "use function OS-ENVIRON instead"
"symbol macro" :WARN)
`(os-environ))
(define-symbol-macro *environ* (%obsolete-*environ*))
"Returns the value of environment variable NAME."
(signal-syscall-error einval "getenv"))
"Changes the value of environment variable NAME to VALUE.
The environment variable is overwritten only if overwrite is not NIL."
(name :string)
(value :string)
(overwrite bool-designator))
(defsyscall (unsetenv "unsetenv") :int
"Removes the binding of environment variable NAME."
Stelian Ionescu
committed
;; FIXME: move into libfixposix
"Remove all name-value pairs from the environment set the
OS environment to NULL."
(let ((envptr (os-environ)))
(unless (null-pointer-p envptr)
(loop :for i :from 0 :by 1
:for string := (mem-aref envptr :string i)
:for name := (subseq string 0 (position #\= string))
(setf (mem-ref envptr :pointer) (null-pointer)))
(values)))
;;;-------------------------------------------------------------------------
;;;-------------------------------------------------------------------------
(defsyscall (%gethostname "gethostname") :int
"Return the host name of the current machine."
(with-foreign-pointer-as-string ((cstr size) 256)
(defsyscall (%getdomainname "getdomainname") :int
"Return the domain name of the current machine."
(with-foreign-pointer-as-string ((cstr size) 256)
"Get name and information about current kernel."
(with-foreign-object (buf 'utsname)