1 ;;;; -*- Mode: Lisp; Syntax: ANSI-Common-Lisp; indent-tabs-mode: nil -*-
3 ;;; --- *UNIX foreign function definitions.
6 (in-package :iolib.syscalls
)
8 ;;; Needed for clock_gettime() and friends.
9 (eval-when (:compile-toplevel
:load-toplevel
:execute
)
10 (define-foreign-library librt
12 (use-foreign-library librt
))
15 ;;;-------------------------------------------------------------------------
16 ;;; ERRNO-related functions
17 ;;;-------------------------------------------------------------------------
19 (defentrypoint (setf %sys-errno
) (value)
20 (%%sys-set-errno value
))
22 (defentrypoint %sys-strerror
(&optional
(err (%sys-errno
)))
23 "Look up the error message string for ERRNO. (reentrant)"
26 (foreign-enum-value 'errno-values err
)
28 (with-foreign-pointer-as-string ((buf bufsiz
) 1024)
29 (%sys-strerror-r errno buf bufsiz
))))
31 (defmethod print-object ((posix-error posix-error
) stream
)
32 (print-unreadable-object (posix-error stream
:type nil
:identity nil
)
33 (let ((code (code-of posix-error
))
34 (identifier (identifier-of posix-error
)))
35 (format stream
"POSIX Error ~A code: ~S ~S"
36 identifier
(or code
"[No code]")
37 (or (%sys-strerror code
) "[Can't get error string.]")))))
40 ;;;-------------------------------------------------------------------------
41 ;;; Memory manipulation
42 ;;;-------------------------------------------------------------------------
44 (defcfun* (%sys-memset
"memset") :pointer
49 (defentrypoint %sys-bzero
(buffer length
)
50 (%sys-memset buffer
0 length
))
52 (defcfun* (%sys-memcpy
"memcpy") :pointer
57 (defcfun* (%sys-memmove
"memmove") :pointer
63 ;;;-------------------------------------------------------------------------
65 ;;;-------------------------------------------------------------------------
67 (defsyscall* (%sys-read
"read") ssize-t
68 "Read at most COUNT bytes from FD into the foreign area BUF."
73 (defsyscall* (%sys-write
"write") ssize-t
74 "Write at most COUNT bytes to FD from the foreign area BUF."
80 ;;;-------------------------------------------------------------------------
82 ;;;-------------------------------------------------------------------------
84 (defsyscall* (%%sys-open
"open") :int
85 (pathname filename-designator
)
89 (defvar *default-open-mode
* #o666
)
91 (defentrypoint %sys-open
(pathname flags
&optional
(mode *default-open-mode
*))
92 (%%sys-open pathname flags mode
))
94 (defsyscall* (%sys-creat
"creat") :int
95 (pathname filename-designator
)
98 (defsyscall (%%sys-pipe
"pipe") :int
101 (defentrypoint %sys-pipe
()
102 "Create pipe, returns two values with the new FDs."
103 (with-foreign-object (filedes :int
2)
105 (values (mem-aref filedes
:int
0)
106 (mem-aref filedes
:int
1))))
108 (defsyscall (%sys-mkfifo
"mkfifo") :int
109 "Create a FIFO (named pipe)."
110 (path filename-designator
)
113 (defsyscall (%sys-umask
"umask") mode-t
114 "Sets the umask and returns the old one"
117 (defsyscall (%sys-access
"access") :int
118 (path filename-designator
)
121 (defsyscall (%sys-rename
"rename") :int
123 (old filename-designator
)
124 (new filename-designator
))
126 (defsyscall (%sys-link
"link") :int
127 (path1 filename-designator
)
128 (path2 filename-designator
))
130 (defsyscall (%sys-symlink
"symlink") :int
131 "Creates a symbolic link"
132 (name1 filename-designator
)
133 (name2 filename-designator
))
135 (defsyscall (%%sys-readlink
"readlink") ssize-t
136 (path filename-designator
)
140 (defentrypoint %sys-readlink
(path)
141 "Read value of a symbolic link."
142 (with-foreign-pointer (buf 4096 bufsize
)
143 (let ((count (%%sys-readlink path buf bufsize
)))
144 (values (foreign-string-to-lisp buf
:count count
)))))
146 (defsyscall (%sys-unlink
"unlink") :int
147 (path filename-designator
))
149 (defsyscall* (%sys-chown
"chown") :int
150 "Change ownership of a file."
151 (path filename-designator
)
155 (defsyscall* (%sys-fchown
"fchown") :int
156 "Change ownership of an open file."
161 (defsyscall* (%sys-lchown
"lchown") :int
162 "Change ownership of a file or symlink."
163 (path filename-designator
)
167 (defsyscall* (%sys-chmod
"chmod") :int
168 (path filename-designator
)
171 (defsyscall* (%sys-fchmod
"fchmod") :int
177 (define-c-struct-wrapper stat
())
179 (defconstant +stat-version-linux
+ 3)
181 ;;; If necessary for performance reasons, we can add an optional
182 ;;; argument to this function and use that to reuse a wrapper object.
183 (defentrypoint funcall-stat
(fn arg
)
184 (with-foreign-object (buf 'stat
)
186 (make-instance 'stat
:pointer buf
)))
188 (defentrypoint %sys-stat
(path)
189 "Get information about a file."
190 (funcall-stat #'%%sys-stat path
))
192 (defentrypoint %sys-fstat
(fd)
193 "Get information about a file descriptor"
194 (funcall-stat #'%%sys-fstat fd
))
196 (defentrypoint %sys-lstat
(path)
197 "Get information about a file or symlink."
198 (funcall-stat #'%%sys-lstat path
))
200 (defsyscall (%sys-sync
"sync") :void
201 "Schedule all file system buffers to be written to disk.")
203 (defsyscall* (%sys-fsync
"fsync") :int
206 (defsyscall (%%sys-mkstemp
"mkstemp") :int
207 (template filename-designator
))
209 (defentrypoint %sys-mkstemp
(&optional
(template ""))
210 (let ((template (concatenate 'string template
"XXXXXX")))
211 (with-foreign-string (ptr (filename template
))
212 (values (%%sys-mkstemp ptr
) (foreign-string-to-lisp ptr
)))))
215 ;;;-------------------------------------------------------------------------
217 ;;;-------------------------------------------------------------------------
219 (defsyscall (%sys-mkdir
"mkdir") :int
220 "Create a directory."
221 (path filename-designator
)
224 (defsyscall (%sys-rmdir
"rmdir") :int
225 (path filename-designator
))
227 (defsyscall (%sys-chdir
"chdir") :int
228 "Changes the current working directory"
229 (path filename-designator
))
231 (defsyscall* (%sys-fchdir
"fchdir") :int
234 (defsyscall (%%sys-getcwd
"getcwd") :string
238 (defentrypoint %sys-getcwd
()
239 "Returns the current working directory as a string."
240 (with-foreign-pointer (buf path-max size
)
241 (%%sys-getcwd buf size
)))
243 (defsyscall (%%sys-mkdtemp
"mkdtemp") :int
244 (template filename-designator
))
246 (defentrypoint %sys-mkdtemp
(&optional
(template ""))
247 (let ((template (concatenate 'string template
"XXXXXX")))
248 (with-foreign-string (ptr (filename template
))
249 (values (%%sys-mkdtemp ptr
) (foreign-string-to-lisp ptr
)))))
252 ;;;-------------------------------------------------------------------------
254 ;;;-------------------------------------------------------------------------
256 (defsyscall (%sys-close
"close") :int
257 "Close an open file descriptor."
260 (defsyscall (%sys-dup
"dup") :int
263 (defsyscall* (%sys-dup2
"dup2") :int
267 (defsyscall* (%sys-ioctl
/2 "ioctl") :int
271 (defsyscall* (%sys-ioctl
/3 "ioctl") :int
276 (defentrypoint %sys-fd-open-p
(fd)
277 (not (minusp (%sys-fstat fd
))))
280 ;;;-------------------------------------------------------------------------
281 ;;; File descriptor polling
282 ;;;-------------------------------------------------------------------------
284 ;;; FIXME: Until a way to autodetect platform features is implemented
285 (eval-when (:compile-toplevel
:load-toplevel
:execute
)
286 (unless (boundp 'pollrdhup
)
287 (defconstant pollrdhup
0)))
289 (defsyscall (%sys-poll
"poll") :int
290 "Scan for I/O activity on multiple file descriptors."
296 ;;;-------------------------------------------------------------------------
297 ;;; Directory walking
298 ;;;-------------------------------------------------------------------------
300 (defsyscall (%sys-opendir
"opendir") :pointer
301 "Opens a directory for listing of its contents"
302 (filename filename-designator
))
304 (defsyscall (%sys-closedir
"closedir") :int
305 "Closes a directory when done listing its contents"
308 (defentrypoint %sys-readdir
(dir)
309 "Reads an item from the listing of a directory (reentrant)"
310 (with-foreign-objects ((entry 'dirent
) (result :pointer
))
311 (%%sys-readdir-r dir entry result
)
312 (if (null-pointer-p (mem-ref result
:pointer
))
314 (with-foreign-slots ((name type fileno
) entry dirent
)
315 (values (foreign-string-to-lisp name
) type fileno
)))))
317 (defsyscall (%sys-rewinddir
"rewinddir") :void
318 "Rewinds a directory."
321 (defsyscall (%sys-seekdir
"seekdir") :void
326 ;;; FIXME: According to POSIX docs "no errors are defined" for
327 ;;; telldir() but Linux manpages specify a possible EBADF.
328 (defsyscall (%sys-telldir
"telldir") off-t
329 "Returns the current location in a directory"
333 ;;;-------------------------------------------------------------------------
335 ;;;-------------------------------------------------------------------------
337 (defsyscall (%sys-munmap
"munmap") :int
338 "Unmap pages of memory."
343 ;;;-------------------------------------------------------------------------
344 ;;; Process creation and info
345 ;;;-------------------------------------------------------------------------
347 (defsyscall (%sys-fork
"fork") pid-t
348 "Create a child process.")
350 (defsyscall (%sys-getpid
"getpid") pid-t
351 "Returns the process id of the current process")
353 (defsyscall (%sys-getppid
"getppid") pid-t
354 "Returns the process id of the current process's parent")
356 (defsyscall (%sys-getuid
"getuid") uid-t
357 "Get real user id of the current process.")
359 (defsyscall (%sys-setuid
"setuid") :int
360 "Set real user id of the current process."
363 (defsyscall (%sys-geteuid
"geteuid") uid-t
364 "Get effective user id of the current process.")
366 (defsyscall (%sys-seteuid
"seteuid") :int
367 "Set effective user id of the current process."
370 (defsyscall (%sys-getgid
"getgid") gid-t
371 "Get real group id of the current process.")
373 (defsyscall (%sys-setgid
"setgid") :int
374 "Set real group id of the current process."
377 (defsyscall (%sys-getegid
"getegid") gid-t
378 "Get effective group id of the current process.")
380 (defsyscall (%sys-setegid
"setegid") :int
381 "Set effective group id of the current process."
384 (defsyscall (%sys-setreuid
"setreuid") :int
385 "Set real and effective user id of the current process."
389 (defsyscall (%sys-setregid
"setregid") :int
390 "Set real and effective group id of the current process."
394 (defsyscall (%sys-getpgid
"getpgid") pid-t
395 "Get process group id of a process."
398 (defsyscall (%sys-setpgid
"setpgid") :int
399 "Set process group id of a process."
403 (defsyscall (%sys-getpgrp
"getpgrp") pid-t
404 "Get process group id of the current process.")
406 (defsyscall (%sys-setpgrp
"setpgrp") pid-t
407 "Set process group id of the current process.")
409 (defsyscall (%sys-setsid
"setsid") pid-t
410 "Create session and set process group id of the current process.")
412 (defentrypoint %sys-getrlimit
(resource)
413 (with-foreign-object (rl 'rlimit
)
414 (with-foreign-slots ((cur max
) rl rlimit
)
415 (%%sys-getrlimit resource rl
)
418 (defentrypoint %sys-setrlimit
(resource soft-limit hard-limit
)
419 (with-foreign-object (rl 'rlimit
)
420 (with-foreign-slots ((cur max
) rl rlimit
)
423 (%%sys-setrlimit resource rl
))))
425 (defsyscall (%%sys-getrusage
"getrusage") :int
429 ;;; TODO: it might be more convenient to return a wrapper object here
430 ;;; instead like we do in STAT.
431 (defentrypoint %sys-getrusage
(who)
432 (with-foreign-object (ru 'rusage
)
433 (%%sys-getrusage who ru
)
434 (with-foreign-slots ((maxrss ixrss idrss isrss minflt majflt nswap inblock
435 oublock msgsnd msgrcv nsignals nvcsw nivcsw
)
437 (values (foreign-slot-value (foreign-slot-pointer ru
'rusage
'utime
)
439 (foreign-slot-value (foreign-slot-pointer ru
'rusage
'utime
)
441 (foreign-slot-value (foreign-slot-pointer ru
'rusage
'stime
)
443 (foreign-slot-value (foreign-slot-pointer ru
'rusage
'stime
)
445 maxrss ixrss idrss isrss minflt majflt
446 nswap inblock oublock msgsnd
447 msgrcv nsignals nvcsw nivcsw
))))
449 (defsyscall (%sys-getpriority
"getpriority") :int
453 (defsyscall (%sys-setpriority
"setpriority") :int
458 (defentrypoint %sys-nice
(&optional
(increment 0))
459 "Get or set process priority."
460 ;; FIXME: race condition. might need WITHOUT-INTERRUPTS on some impl.s
461 (setf (%sys-errno
) 0)
462 (let ((r (foreign-funcall "nice" :int increment
:int
)))
463 (if (and (= r -
1) (/= (%sys-errno
) 0))
464 (signal-posix-error r
)
468 ;;;-------------------------------------------------------------------------
470 ;;;-------------------------------------------------------------------------
472 (defsyscall* (%sys-usleep
"usleep") :int
473 (useconds useconds-t
))
475 (defsyscall (%%sys-time
"time") time-t
478 (defentrypoint %sys-time
()
479 (%%sys-time
(null-pointer)))
481 (defsyscall (%%sys-gettimeofday
"gettimeofday") :int
485 (defentrypoint %sys-gettimeofday
()
486 "Return the time in seconds and microseconds."
487 (with-foreign-object (tv 'timeval
)
488 (with-foreign-slots ((sec usec
) tv timeval
)
489 (%%sys-gettimeofday tv
(null-pointer))
492 ;;; FIXME: or we can implement this through the MACH functions.
495 (defctype kern-return-t
:int
)
496 (defctype clock-res-t
:int
)
497 (defctype clock-id-t
:int
)
498 (defctype port-t
:unsigned-int
) ; not sure
499 (defctype clock-serv-t port
)
501 (defconstant kern-success
0)
503 (defconstant system-clock
0)
504 (defconstant calendar-clock
1)
505 (defconstant realtime-clock
0)
507 (defsyscall (%sys-mach-host-self
"mach_host_self") port-t
)
509 (defsyscall (%%sys-host-get-clock-service
"host_get_clock_service") kern-return-t
512 (clock-name (:pointer clock-serv-t
)))
514 (defentrypoint %sys-host-get-clock-service
(id &optional
(host (%sys-mach-host-self
)))
515 (with-foreign-object (clock 'clock-serv-t
)
516 (%%sys-host-get-clock-service host id clock
)
517 (mem-ref clock
:int
)))
519 (defsyscall (%clock-get-time
"clock_get_time") kern-return-t
520 (clock-serv clock-serv-t
)
523 (defentrypoint clock-get-time
(clock-service)
524 (with-foreign-object (time 'timespec
)
525 (%clock-get-time clock-service time
)
526 (with-foreign-slots ((tv-sec tv-nsec
) time timespec
)
527 (values tv-sec tv-nsec
)))))
531 (defsyscall (%%sys-clock-getres
"clock_getres") :int
532 "Returns the resolution of the clock CLOCKID."
536 (defentrypoint %sys-clock-getres
(clock-id)
537 (with-foreign-object (ts 'timespec
)
538 (with-foreign-slots ((sec nsec
) ts timespec
)
539 (%%sys-clock-getres clock-id ts
)
542 (defsyscall (%%sys-clock-gettime
"clock_gettime") :int
546 (defentrypoint %sys-clock-gettime
(clock-id)
547 "Returns the time of the clock CLOCKID."
548 (with-foreign-object (ts 'timespec
)
549 (with-foreign-slots ((sec nsec
) ts timespec
)
550 (%%sys-clock-gettime clock-id ts
)
553 (defsyscall (%%sys-clock-settime
"clock_settime") :int
557 (defentrypoint %sys-clock-settime
(clock-id)
558 "Sets the time of the clock CLOCKID."
559 (with-foreign-object (ts 'timespec
)
560 (with-foreign-slots ((sec nsec
) ts timespec
)
561 (%%sys-clock-settime clock-id ts
)
562 (values sec nsec
)))))
564 (defentrypoint %sys-get-monotonic-time
()
565 "Gets current time in seconds from a system's monotonic clock."
566 (multiple-value-bind (seconds nanoseconds
)
567 #-darwin
(%sys-clock-gettime clock-monotonic
)
568 #+darwin
(%sys-clock-get-time
(%sys-host-get-clock-service system-clock
))
569 (+ seconds
(/ nanoseconds
1d9
))))
572 ;;;-------------------------------------------------------------------------
574 ;;;-------------------------------------------------------------------------
576 (defcvar ("environ" :read-only t
) (:pointer
:string
))
578 (defsyscall (%sys-getenv
"getenv") :string
579 "Returns the value of an environment variable"
582 (defsyscall (%sys-setenv
"setenv") :int
583 "Changes the value of an environment variable"
586 (overwrite bool-designator
))
588 (defsyscall (%sys-unsetenv
"unsetenv") :int
589 "Removes the binding of an environment variable"
593 ;;;-------------------------------------------------------------------------
595 ;;;-------------------------------------------------------------------------
597 (defsyscall (%%sys-gethostname
"gethostname") :int
601 (defentrypoint %sys-gethostname
()
602 (with-foreign-pointer-as-string ((cstr size
) 256)
603 (%%sys-gethostname cstr size
)))
605 (defsyscall (%%sys-getdomainname
"getdomainname") :int
609 (defentrypoint %sys-getdomainname
()
610 (with-foreign-pointer-as-string ((cstr size
) 256)
611 (%%sys-getdomainname cstr size
)))
613 (defsyscall (%%sys-uname
"uname") :int
616 (defentrypoint %sys-uname
()
617 "Get name and information about current kernel."
618 (with-foreign-object (buf 'utsname
)
619 (%sys-bzero buf size-of-utsname
)
621 (macrolet ((utsname-slot (name)
622 `(foreign-string-to-lisp
623 (foreign-slot-pointer buf
'utsname
',name
))))
624 (values (utsname-slot sysname
)
625 (utsname-slot nodename
)
626 (utsname-slot release
)
627 (utsname-slot version
)
628 (utsname-slot machine
)))))
631 ;;;-------------------------------------------------------------------------
633 ;;;-------------------------------------------------------------------------
635 (defcfun (%%sys-getpwuid-r
"getpwuid_r")
636 (return-wrapper :int
:error-predicate
(lambda (x) (not (zerop x
)))
637 :error-generator signal-posix-error-from-return-value
)
644 (defcfun (%%sys-getpwnam-r
"getpwnam_r")
645 (return-wrapper :int
:error-predicate
(lambda (x) (not (zerop x
)))
646 :error-generator signal-posix-error-from-return-value
)
653 (defun funcall-getpw (fn arg
)
654 (with-foreign-objects ((pw 'passwd-entry
) (pwp :pointer
))
655 (with-foreign-pointer (buf 4096 bufsize
)
656 (with-foreign-slots ((name passwd uid gid gecos dir shell
) pw passwd-entry
)
657 (funcall fn arg pw buf bufsize pwp
)
658 (if (null-pointer-p (mem-ref pwp
:pointer
))
660 (values name passwd uid gid gecos dir shell
))))))
662 (defentrypoint %sys-getpwuid
(uid)
663 "Gets the password-entry of a user, by user id."
664 (funcall-getpw #'%%sys-getpwuid-r uid
))
666 (defentrypoint %sys-getpwnam
(name)
667 "Gets the password-entry of a user, by username."
668 (funcall-getpw #'%%sys-getpwnam-r name
))
671 ;;;-------------------------------------------------------------------------
673 ;;;-------------------------------------------------------------------------
675 (defsyscall (%%sys-getgrgid-r
"getgrgid_r")
676 (return-wrapper :int
:error-predicate
(lambda (x) (not (zerop x
)))
677 :error-generator signal-posix-error-from-return-value
)
684 (defsyscall (%%sys-getgrnam-r
"getgrnam_r")
685 (return-wrapper :int
:error-predicate
(lambda (x) (not (zerop x
)))
686 :error-generator signal-posix-error-from-return-value
)
693 (defun funcall-getgr (fn arg
)
694 (with-foreign-objects ((gr 'group-entry
) (grp :pointer
))
695 (with-foreign-pointer (buf 4096 bufsize
)
696 (with-foreign-slots ((name passwd gid
) gr group-entry
)
697 (funcall fn arg gr buf bufsize grp
)
698 (if (null-pointer-p (mem-ref grp
:pointer
))
700 (values name passwd gid
))))))
702 (defentrypoint %sys-getgrgid
(gid)
703 "Gets a group-entry, by group id. (reentrant)"
704 (funcall-getgr #'%%sys-getgrgid-r gid
))
706 (defentrypoint %sys-getgrnam
(name)
707 "Gets a group-entry, by group name. (reentrant)"
708 (funcall-getgr #'%%sys-getgrnam-r name
))