home *** CD-ROM | disk | FTP | other *** search
/ Language/OS - Multiplatform Resource Library / LANGUAGE OS.iso / pcl / src-16f.lha / code / unix.lisp < prev    next >
Encoding:
Text File  |  1992-08-05  |  58.1 KB  |  1,696 lines

  1. ;;; -*- Package: UNIX -*-
  2. ;;;
  3. ;;; **********************************************************************
  4. ;;; This code was written as part of the CMU Common Lisp project at
  5. ;;; Carnegie Mellon University, and has been placed in the public domain.
  6. ;;; If you want to use this code or any part of CMU Common Lisp, please contact
  7. ;;; Scott Fahlman or slisp-group@cs.cmu.edu.
  8. ;;;
  9. (ext:file-comment
  10.   "$Header: unix.lisp,v 1.23 92/08/05 19:59:22 ram Exp $")
  11. ;;;
  12. ;;; **********************************************************************
  13. ;;;
  14. ;;; This file contains the UNIX low-level support.
  15. ;;;
  16. (in-package "UNIX")
  17. (use-package "ALIEN")
  18. (use-package "C-CALL")
  19. (use-package "SYSTEM")
  20. (use-package "EXT")
  21.  
  22. (export '(
  23.       daddr-t caddr-t ino-t swblk-t size-t time-t dev-t off-t uid-t gid-t
  24.       timeval tv-sec tv-usec timezone tz-minuteswest tz-dsttime
  25.       itimerval it-interval it-value tchars t-intrc t-quitc t-startc
  26.       t-stopc t-eofc t-brkc ltchars t-suspc t-dsuspc t-rprntc t-flushc
  27.       t-werasc t-lnextc sgttyb sg-ispeed sg-ospeed sg-erase sg-kill
  28.       sg-flags winsize ws-row ws-col ws-xpixel ws-ypixel
  29.       direct d-off d-ino d-reclen d-namlen d-name
  30.       stat st-dev st-mode st-nlink st-uid st-gid st-rdev st-size
  31.       st-atime st-mtime st-ctime st-blksize st-blocks
  32.       s-ifmt s-ifdir s-ifchr s-ifblk s-ifreg s-iflnk s-ifsock
  33.       s-isuid s-isgid s-isvtx s-iread s-iwrite s-iexec
  34.       ruseage ru-utime ru-stime ru-maxrss ru-ixrss ru-idrss
  35.       ru-isrss ru-minflt ru-majflt ru-nswap ru-inblock ru-oublock
  36.       ru-msgsnd ru-msgrcv ru-nsignals ru-nvcsw ru-nivcsw
  37.       rlimit rlim-cur rlim-max sigcontext sc-onstack sc-mask sc-pc
  38.  
  39.       unix-errno get-unix-error-msg
  40.  
  41.       unix-pathname unix-file-mode unix-fd unix-pid unix-uid unix-gid
  42.  
  43.       unix-access r_ok w_ok x_ok f_ok unix-chdir unix-chmod setuidexec
  44.       setgidexec savetext readown writeown execown readgrp writegrp
  45.       execgrp readoth writeoth execoth unix-fchmod unix-chown unix-fchown
  46.       unix-getdtablesize unix-close unix-creat unix-dup unix-dup2
  47.       unix-fcntl f-dupfd f-getfd f-setfd f-getfl f-setfl f-getown f-setown
  48.       fndelay fappend fasync fcreat ftrunc fexcl unix-link unix-lseek
  49.       l_set l_incr l_xtnd unix-mkdir unix-open o_rdonly o_wronly o_rdwr
  50.       o_append o_creat o_trunc o_excl unix-pipe unix-read unix-readlink
  51.       unix-rename unix-rmdir unix-fast-select fd-setsize fd-set fd-clr
  52.       fd-isset fd-zero unix-select unix-sync unix-fsync unix-truncate
  53.       unix-ftruncate unix-symlink unix-unlink unix-write unix-ioctl
  54.       tcsetpgrp tcgetpgrp tty-process-group
  55.       terminal-speeds tty-raw tty-crmod tty-echo tty-lcase tty-cbreak
  56.       tty-tandem TIOCGETP TIOCSETP TIOCFLUSH TIOCSETC TIOCGETC TIOCSLTC
  57.       TIOCGLTC TIOCNOTTY TIOCSPGRP TIOCGPGRP TIOCGWINSZ TIOCSWINSZ
  58.       KBDCGET KBDCSET KBDCRESET KBDCRST KBDCSSTD KBDSGET KBDGCLICK
  59.       KBDSCLICK FIONREAD unix-exit unix-stat unix-lstat unix-fstat
  60.       unix-getrusage unix-fast-getrusage rusage_self rusage_children
  61.       unix-gettimeofday
  62.       unix-utimes unix-setreuid unix-setregid unix-getpid unix-getppid
  63.       unix-getgid unix-getegid unix-getpgrp unix-setpgrp unix-getuid
  64.       unix-getpagesize unix-gethostname unix-gethostid unix-fork
  65.       unix-current-directory unix-isatty unix-ttyname unix-execve
  66.       unix-socket unix-connect unix-bind unix-listen unix-accept
  67.       unix-recv unix-send))
  68.  
  69. (pushnew :unix *features*)
  70.  
  71.  
  72. ;;;; Common machine independent structures.
  73.  
  74. ;;; From sys/types.h
  75.  
  76. (def-alien-type daddr-t long)
  77. (def-alien-type caddr-t (* char))
  78. (def-alien-type ino-t unsigned-long)
  79. (def-alien-type swblk-t long)
  80. (def-alien-type size-t long)
  81. (def-alien-type time-t long)
  82. (def-alien-type dev-t short)
  83. (def-alien-type off-t long)
  84. (def-alien-type uid-t unsigned-short)
  85. (def-alien-type gid-t unsigned-short)
  86.  
  87. (defconstant FD-SETSIZE 256)
  88.  
  89. (def-alien-type nil
  90.   (struct fd-set
  91.     (fds-bits (array unsigned-long #.(/ fd-setsize 32)))))
  92.  
  93. (defmacro fd-set (offset fd-set)
  94.   (let ((word (gensym))
  95.     (bit (gensym))
  96.     (temp (gensym)))
  97.     `(multiple-value-bind (,word ,bit) (floor ,offset 32)
  98.        (let ((,temp (deref (slot ,fd-set 'fds-bits) ,word)))
  99.      (setf (ldb (byte 1 ,bit) ,temp) 1)
  100.      (setf (deref (slot ,fd-set 'fds-bits) ,word) ,temp)))))
  101.  
  102. (defmacro fd-clr (offset fd-set)
  103.   (let ((word (gensym))
  104.     (bit (gensym))
  105.     (temp (gensym)))
  106.     `(multiple-value-bind (,word ,bit) (floor ,offset 32)
  107.        (let ((,temp (deref (slot ,fd-set 'fds-bits) ,word)))
  108.      (setf (ldb (byte 1 ,bit) ,temp) 0)
  109.      (setf (deref (slot ,fd-set 'fds-bits) ,word) ,temp)))))
  110.  
  111. (defmacro fd-isset (offset fd-set)
  112.   (let ((word (gensym))
  113.     (bit (gensym)))
  114.     `(multiple-value-bind (,word ,bit) (floor ,offset 32)
  115.        (logbitp ,bit (deref (slot ,fd-set 'fds-bits) ,word)))))
  116.  
  117. (defmacro fd-zero (fd-set)
  118.   `(progn
  119.      ,@(loop for index upfrom 0 below (/ fd-setsize 32)
  120.      collect `(setf (deref (slot ,fd-set 'fds-bits) ,index) 0))))
  121.  
  122. ;;; From sys/time.h
  123.  
  124. (def-alien-type nil
  125.   (struct timeval
  126.     (tv-sec long)        ; seconds
  127.     (tv-usec long)))        ; and microseconds
  128.  
  129. (def-alien-type nil
  130.   (struct timezone
  131.     (tz-minuteswest int)        ; minutes west of Greenwich
  132.     (tz-dsttime                ; type of dst correction
  133.      (enum nil :none :usa :aust :wet :met :eet :can))))
  134.  
  135. (def-alien-type nil
  136.   (struct itimerval
  137.     (it-interval (struct timeval))    ; timer interval
  138.     (it-value (struct timeval))))    ; current value
  139.  
  140. ;;; From ioctl.h
  141.  
  142. (def-alien-type nil
  143.   (struct tchars
  144.     (t-intrc char)            ; interrupt
  145.     (t-quitc char)            ; quit
  146.     (t-startc char)            ; start output
  147.     (t-stopc char)            ; stop output
  148.     (t-eofc char)            ; end-of-file
  149.     (t-brkc char)))            ; input delimiter (like nl)
  150.  
  151. (def-alien-type nil
  152.   (struct ltchars
  153.     (t-suspc char)            ; stop process signal
  154.     (t-dsuspc char)            ; delayed stop process signal
  155.     (t-rprntc char)            ; reprint line
  156.     (t-flushc char)            ; flush output (toggles)
  157.     (t-werasc char)            ; word erase
  158.     (t-lnextc char)))            ; literal next character
  159.  
  160. (def-alien-type nil
  161.   (struct sgttyb
  162.     (sg-ispeed char)            ; input speed.
  163.     (sg-ospeed char)            ; output speed
  164.     (sg-erase char)            ; erase character
  165.     (sg-kill char)            ; kill character
  166.     (sg-flags short)))            ; mode flags
  167.  
  168. (def-alien-type nil
  169.   (struct winsize
  170.     (ws-row unsigned-short)        ; rows, in characters
  171.     (ws-col unsigned-short)        ; columns, in characters
  172.     (ws-xpixel unsigned-short)        ; horizontal size, pixels
  173.     (ws-ypixel unsigned-short)))    ; veritical size, pixels
  174.  
  175. ;;; From sys/dir.h
  176.  
  177. (def-alien-type nil
  178.   (struct direct
  179.     #+sunos (d-off long)        ; offset of next disk directory entry
  180.     (d-ino unsigned-long)        ; inode number of entry
  181.     (d-reclen unsigned-short)        ; length of this record
  182.     (d-namlen unsigned-short)        ; length of string in d-name
  183.     (d-name (array char 256))))        ; name must be no longer than this
  184.  
  185. ;;; From sys/stat.h
  186.  
  187. (def-alien-type nil
  188.   (struct stat
  189.     (st-dev dev-t)
  190.     (st-ino ino-t)
  191.     (st-mode unsigned-short)
  192.     (st-nlink short)
  193.     (st-uid uid-t)
  194.     (st-gid gid-t)
  195.     (st-rdev dev-t)
  196.     (st-size off-t)
  197.     (st-atime time-t)
  198.     (st-spare1 int)
  199.     (st-mtime time-t)
  200.     (st-spare2 int)
  201.     (st-ctime time-t)
  202.     (st-spare3 int)
  203.     (st-blksize long)
  204.     (st-blocks long)
  205.     (st-spare4 (array long 2))))
  206.  
  207. (defconstant s-ifmt #o0170000)
  208. (defconstant s-ifdir #o0040000)
  209. (defconstant s-ifchr #o0020000)
  210. (defconstant s-ifblk #o0060000)
  211. (defconstant s-ifreg #o0100000)
  212. (defconstant s-iflnk #o0120000)
  213. (defconstant s-ifsock #o0140000)
  214. (defconstant s-isuid #o0004000)
  215. (defconstant s-isgid #o0002000)
  216. (defconstant s-isvtx #o0001000)
  217. (defconstant s-iread #o0000400)
  218. (defconstant s-iwrite #o0000200)
  219. (defconstant s-iexec #o0000100)
  220.  
  221. ;;; From sys/resource.h
  222.  
  223. (def-alien-type nil
  224.   (struct rusage
  225.     (ru-utime (struct timeval))        ; user time used
  226.     (ru-stime (struct timeval))        ; system time used.
  227.     (ru-maxrss long)
  228.     (ru-ixrss long)            ; integral sharded memory size
  229.     (ru-idrss long)            ; integral unsharded data "
  230.     (ru-isrss long)            ; integral unsharded stack "
  231.     (ru-minflt long)            ; page reclaims
  232.     (ru-majflt long)            ; page faults
  233.     (ru-nswap long)            ; swaps
  234.     (ru-inblock long)            ; block input operations
  235.     (ru-oublock long)            ; block output operations
  236.     (ru-msgsnd long)            ; messages sent
  237.     (ru-msgrcv long)            ; messages received
  238.     (ru-nsignals long)            ; signals received
  239.     (ru-nvcsw long)            ; voluntary context switches
  240.     (ru-nivcsw long)))            ; involuntary "
  241.  
  242. (def-alien-type nil
  243.   (struct rlimit
  244.     (rlim-cur int)            ; current (soft) limit
  245.     (rlim-max int)))            ; maximum value for rlim-cur
  246.  
  247.  
  248.  
  249. ;;;; Errno stuff.
  250.  
  251. (eval-when (compile eval)
  252.  
  253. (defparameter *compiler-unix-errors* nil)
  254.  
  255. (defmacro def-unix-error (name number description)
  256.   `(progn
  257.      (eval-when (compile eval)
  258.        (push (cons ,number ,description) *compiler-unix-errors*))
  259.      (defconstant ,name ,number ,description)
  260.      (export ',name)))
  261.  
  262. (defmacro emit-unix-errors ()
  263.   (let* ((max (apply #'max (mapcar #'car *compiler-unix-errors*)))
  264.      (array (make-array (1+ max) :initial-element nil)))
  265.     (dolist (error *compiler-unix-errors*)
  266.       (setf (svref array (car error)) (cdr error)))
  267.     `(progn
  268.        (defvar *unix-errors* ',array)
  269.        (proclaim '(simple-vector *unix-errors*)))))
  270.  
  271. ) ;eval-when
  272.  
  273. ;;; 
  274. ;;; From <errno.h>
  275. ;;; 
  276. (def-unix-error ESUCCESS 0 "Successful")
  277. (def-unix-error EPERM 1 "Not owner")
  278. (def-unix-error ENOENT 2 "No such file or directory")
  279. (def-unix-error ESRCH 3 "No such process")
  280. (def-unix-error EINTR 4 "Interrupted system call")
  281. (def-unix-error EIO 5 "I/O error")
  282. (def-unix-error ENXIO 6 "No such device or address")
  283. (def-unix-error E2BIG 7 "Arg list too long")
  284. (def-unix-error ENOEXEC 8 "Exec format error")
  285. (def-unix-error EBADF 9 "Bad file number")
  286. (def-unix-error ECHILD 10 "No children")
  287. (def-unix-error EAGAIN 11 "No more processes")
  288. (def-unix-error ENOMEM 12 "Not enough core")
  289. (def-unix-error EACCES 13 "Permission denied")
  290. (def-unix-error EFAULT 14 "Bad address")
  291. (def-unix-error ENOTBLK 15 "Block device required")
  292. (def-unix-error EBUSY 16 "Mount device busy")
  293. (def-unix-error EEXIST 17 "File exists")
  294. (def-unix-error EXDEV 18 "Cross-device link")
  295. (def-unix-error ENODEV 19 "No such device")
  296. (def-unix-error ENOTDIR 20 "Not a director")
  297. (def-unix-error EISDIR 21 "Is a directory")
  298. (def-unix-error EINVAL 22 "Invalid argument")
  299. (def-unix-error ENFILE 23 "File table overflow")
  300. (def-unix-error EMFILE 24 "Too many open files")
  301. (def-unix-error ENOTTY 25 "Not a typewriter")
  302. (def-unix-error ETXTBSY 26 "Text file busy")
  303. (def-unix-error EFBIG 27 "File too large")
  304. (def-unix-error ENOSPC 28 "No space left on device")
  305. (def-unix-error ESPIPE 29 "Illegal seek")
  306. (def-unix-error EROFS 30 "Read-only file system")
  307. (def-unix-error EMLINK 31 "Too many links")
  308. (def-unix-error EPIPE 32 "Broken pipe")
  309. ;;; 
  310. ;;; Math
  311. (def-unix-error EDOM 33 "Argument too large")
  312. (def-unix-error ERANGE 34 "Result too large")
  313. ;;; 
  314. ;;; non-blocking and interrupt i/o
  315. (def-unix-error EWOULDBLOCK 35 "Operation would block")
  316. (def-unix-error EDEADLK 35 "Operation would block") ; Ditto
  317. (def-unix-error EINPROGRESS 36 "Operation now in progress")
  318. (def-unix-error EALREADY 37 "Operation already in progress")
  319. ;;;
  320. ;;; ipc/network software
  321. (def-unix-error ENOTSOCK 38 "Socket operation on non-socket")
  322. (def-unix-error EDESTADDRREQ 39 "Destination address required")
  323. (def-unix-error EMSGSIZE 40 "Message too long")
  324. (def-unix-error EPROTOTYPE 41 "Protocol wrong type for socket")
  325. (def-unix-error ENOPROTOOPT 42 "Protocol not available")
  326. (def-unix-error EPROTONOSUPPORT 43 "Protocol not supported")
  327. (def-unix-error ESOCKTNOSUPPORT 44 "Socket type not supported")
  328. (def-unix-error EOPNOTSUPP 45 "Operation not supported on socket")
  329. (def-unix-error EPFNOSUPPORT 46 "Protocol family not supported")
  330. (def-unix-error EAFNOSUPPORT 47 "Address family not supported by protocol family")
  331. (def-unix-error EADDRINUSE 48 "Address already in use")
  332. (def-unix-error EADDRNOTAVAIL 49 "Can't assign requested address")
  333. ;;;
  334. ;;; operational errors
  335. (def-unix-error ENETDOWN 50 "Network is down")
  336. (def-unix-error ENETUNREACH 51 "Network is unreachable")
  337. (def-unix-error ENETRESET 52 "Network dropped connection on reset")
  338. (def-unix-error ECONNABORTED 53 "Software caused connection abort")
  339. (def-unix-error ECONNRESET 54 "Connection reset by peer")
  340. (def-unix-error ENOBUFS 55 "No buffer space available")
  341. (def-unix-error EISCONN 56 "Socket is already connected")
  342. (def-unix-error ENOTCONN 57 "Socket is not connected")
  343. (def-unix-error ESHUTDOWN 58 "Can't send after socket shutdown")
  344. (def-unix-error ETOOMANYREFS 59 "Too many references: can't splice")
  345. (def-unix-error ETIMEDOUT 60 "Connection timed out")
  346. (def-unix-error ECONNREFUSED 61 "Connection refused")
  347. ;;; 
  348. (def-unix-error ELOOP 62 "Too many levels of symbolic links")
  349. (def-unix-error ENAMETOOLONG 63 "File name too long")
  350. ;;; 
  351. (def-unix-error EHOSTDOWN 64 "Host is down")
  352. (def-unix-error EHOSTUNREACH 65 "No route to host")
  353. (def-unix-error ENOTEMPTY 66 "Directory not empty")
  354. ;;; 
  355. ;;; quotas & resource 
  356. (def-unix-error EPROCLIM 67 "Too many processes")
  357. (def-unix-error EUSERS 68 "Too many users")
  358. (def-unix-error EDQUOT 69 "Disc quota exceeded")
  359. ;;;
  360. ;;; CMU RFS
  361. (def-unix-error ELOCAL 126 "namei should continue locally")
  362. (def-unix-error EREMOTE 127 "namei was handled remotely")
  363. ;;;
  364. ;;; VICE
  365. (def-unix-error EVICEERR 70 "Remote file system error ")
  366. (def-unix-error EVICEOP 71 "syscall was handled by Vice")
  367. ;;;
  368. ;;; Mach Emulation
  369. (def-unix-error ERESTART 72 "Mach Emulation Error (?)")
  370. ;;;
  371. ;;; And now for something completely different ...
  372. (emit-unix-errors)
  373.  
  374. (def-alien-variable ("errno" unix-errno) int)
  375.  
  376. ;;; GET-UNIX-ERROR-MSG -- public.
  377. ;;; 
  378. (defun get-unix-error-msg (&optional (error-number unix-errno))
  379.   "Returns a string describing the error number which was returned by a
  380.   UNIX system call."
  381.   (declare (type integer error-number))
  382.   (if (array-in-bounds-p *unix-errors* error-number)
  383.       (svref *unix-errors* error-number)
  384.       (format nil "Unknown error [~d]" error-number)))
  385.  
  386.  
  387.  
  388. ;;;; Lisp types used by syscalls.
  389.  
  390. (deftype unix-pathname () 'simple-string)
  391. (deftype unix-file-mode () '(unsigned-byte 16))
  392. (deftype unix-fd () `(integer 0 ,most-positive-fixnum))
  393. (deftype unix-pid () '(unsigned-byte 16))
  394. (deftype unix-uid () '(unsigned-byte 16))
  395. (deftype unix-gid () '(unsigned-byte 16))
  396.  
  397.  
  398.  
  399. ;;;; System calls.
  400.  
  401.  
  402. (defmacro syscall ((name &rest arg-types) success-form &rest args)
  403.   `(let ((result (alien-funcall (extern-alien ,name (function int ,@arg-types))
  404.                 ,@args)))
  405.      (if (minusp result)
  406.      (values nil unix-errno)
  407.      ,success-form)))
  408.  
  409. ;;; Like syscall, but if it fails, signal an error instead of returing error
  410. ;;; codes.  Should only be used for syscalls that will never really get an
  411. ;;; error.
  412. ;;;
  413. (defmacro syscall* ((name &rest arg-types) success-form &rest args)
  414.   `(let ((result (alien-funcall (extern-alien ,name (function int ,@arg-types))
  415.                 ,@args)))
  416.      (if (minusp result)
  417.      (error "Syscall ~A failed: ~A" ,name (get-unix-error-msg))
  418.      ,success-form)))
  419.  
  420. (defmacro void-syscall ((name &rest arg-types) &rest args)
  421.   `(syscall (,name ,@arg-types) (values t 0) ,@args))
  422.  
  423. (defmacro int-syscall ((name &rest arg-types) &rest args)
  424.   `(syscall (,name ,@arg-types) (values result 0) ,@args))
  425.  
  426.  
  427. ;;; Unix-access accepts a path and a mode.  It returns two values the
  428. ;;; first is T if the file is accessible and NIL otherwise.  The second
  429. ;;; only has meaning in the second case and is the unix errno value.
  430.  
  431. (defconstant r_ok 4 "Test for read permission")
  432. (defconstant w_ok 2 "Test for write permission")
  433. (defconstant x_ok 1 "Test for execute permission")
  434. (defconstant f_ok 0 "Test for presence of file")
  435.  
  436. (defun unix-access (path mode)
  437.   "Given a file path (a string) and one of four constant modes,
  438.    unix-access returns T if the file is accessible with that
  439.    mode and NIL if not.  It also returns an errno value with
  440.    NIL which determines why the file was not accessible.
  441.  
  442.    The access modes are:
  443.     r_ok     Read permission.
  444.     w_ok     Write permission.
  445.     x_ok     Execute permission.
  446.     f_ok     Presence of file."
  447.   (declare (type unix-pathname path)
  448.        (type (mod 8) mode))
  449.   (void-syscall ("access" c-string int) path mode))
  450.  
  451. ;;; Unix-chdir accepts a directory name and makes that the
  452. ;;; current working directory.
  453.  
  454. (defun unix-chdir (path)
  455.   "Given a file path string, unix-chdir changes the current working 
  456.    directory to the one specified."
  457.   (declare (type unix-pathname path))
  458.   (void-syscall ("chdir" c-string) path))
  459.  
  460. ;;; Unix-chmod accepts a path and a mode and changes the mode to the new mode.
  461.  
  462. (defconstant setuidexec #o4000 "Set user ID on execution")
  463. (defconstant setgidexec #o2000 "Set group ID on execution")
  464. (defconstant savetext #o1000 "Save text image after execution")
  465. (defconstant readown #o400 "Read by owner")
  466. (defconstant writeown #o200 "Write by owner")
  467. (defconstant execown #o100 "Execute (search directory) by owner")
  468. (defconstant readgrp #o40 "Read by group")
  469. (defconstant writegrp #o20 "Write by group")
  470. (defconstant execgrp #o10 "Execute (search directory) by group")
  471. (defconstant readoth #o4 "Read by others")
  472. (defconstant writeoth #o2 "Write by others")
  473. (defconstant execoth #o1 "Execute (search directory) by others")
  474.  
  475. (defun unix-chmod (path mode)
  476.   "Given a file path string and a constant mode, unix-chmod changes the
  477.    permission mode for that file to the one specified. The new mode
  478.    can be created by logically OR'ing the following:
  479.  
  480.       setuidexec        Set user ID on execution.
  481.       setgidexec        Set group ID on execution.
  482.       savetext          Save text image after execution.
  483.       readown           Read by owner.
  484.       writeown          Write by owner.
  485.       execown           Execute (search directory) by owner.
  486.       readgrp           Read by group.
  487.       writegrp          Write by group.
  488.       execgrp           Execute (search directory) by group.
  489.       readoth           Read by others.
  490.       writeoth          Write by others.
  491.       execoth           Execute (search directory) by others.
  492.   
  493.   It returns T on successfully completion; NIL and an error number
  494.   otherwise."
  495.   (declare (type unix-pathname path)
  496.        (type unix-file-mode mode))
  497.   (void-syscall ("chmod" c-string int) path mode))
  498.  
  499. ;;; Unix-fchmod accepts a file descriptor ("fd") and a file protection mode
  500. ;;; ("mode") and changes the protection of the file described by "fd" to 
  501. ;;; "mode".
  502.  
  503. (defun unix-fchmod (fd mode)
  504.   "Given an integer file descriptor and a mode (the same as those
  505.    used for unix-chmod), unix-fchmod changes the permission mode
  506.    for that file to the one specified. T is returned if the call
  507.    was successful."
  508.   (declare (type unix-fd fd)
  509.        (type unix-file-mode mode))
  510.   (void-syscall ("fchmod" int int) fd mode))
  511.  
  512. (defun unix-chown (path uid gid)
  513.   "Given a file path, an integer user-id, and an integer group-id,
  514.    unix-chown changes the owner of the file and the group of the
  515.    file to those specified.  Either the owner or the group may be
  516.    left unchanged by specifying them as -1.  Note: Permission will
  517.    fail if the caller is not the superuser."
  518.   (declare (type unix-pathname path)
  519.        (type (or unix-uid (integer -1 -1)) uid)
  520.        (type (or unix-gid (integer -1 -1)) gid))
  521.   (void-syscall ("chown" c-string int int) path uid gid))
  522.  
  523. ;;; Unix-fchown is exactly the same as unix-chown except that the file
  524. ;;; is specified by a file-descriptor ("fd") instead of a pathname.
  525.  
  526. (defun unix-fchown (fd uid gid)
  527.   "Unix-fchown is like unix-chown, except that it accepts an integer
  528.    file descriptor instead of a file path name."
  529.   (declare (type unix-fd fd)
  530.        (type (or unix-uid (integer -1 -1)) uid)
  531.        (type (or unix-gid (integer -1 -1)) gid))
  532.   (void-syscall ("fchown" int int int) fd uid gid))
  533.  
  534. ;;; Returns the maximum size (i.e. the number of array elements
  535. ;;; of the file descriptor table.
  536.  
  537. (defun unix-getdtablesize ()
  538.   "Unix-getdtablesize returns the maximum size of the file descriptor
  539.    table. (i.e. the maximum number of descriptors that can exist at
  540.    one time.)"
  541.   (int-syscall ("getdtablesize")))
  542.  
  543. ;;; Unix-close accepts a file descriptor and attempts to close the file
  544. ;;; associated with it.
  545.  
  546. (defun unix-close (fd)
  547.   "Unix-close takes an integer file descriptor as an argument and
  548.    closes the file associated with it.  T is returned upon successful
  549.    completion, otherwise NIL and an error number."
  550.   (declare (type unix-fd fd))
  551.   (void-syscall ("close" int) fd))
  552.  
  553. ;;; Unix-creat accepts a file name and a mode.  It creates a new file
  554. ;;; with name and sets it mode to mode (as for chmod).
  555.  
  556. (defun unix-creat (name mode)
  557.   "Unix-creat accepts a file name and a mode (same as those for
  558.    unix-chmod) and creates a file by that name with the specified
  559.    permission mode.  It returns T on success, or NIL and an error
  560.    number otherwise."
  561.   (declare (type unix-pathname name)
  562.        (type unix-file-mode mode))
  563.   (void-syscall ("creat" c-string int) name mode))
  564.  
  565. ;;; Unix-dup returns a duplicate copy of the existing file-descriptor
  566. ;;; passed as an argument.
  567.  
  568. (defun unix-dup (fd)
  569.   "Unix-dup duplicates an existing file descriptor (given as the
  570.    argument) and return it.  If FD is not a valid file descriptor, NIL
  571.    and an error number are returned."
  572.   (declare (type unix-fd fd))
  573.   (int-syscall ("dup" int) fd))
  574.  
  575. ;;; Unix-dup2 makes the second file-descriptor describe the same file
  576. ;;; as the first. If the second file-descriptor points to an open
  577. ;;; file, it is first closed. In any case, the second should have a 
  578. ;;; value which is a valid file-descriptor.
  579.  
  580. (defun unix-dup2 (fd1 fd2)
  581.   "Unix-dup2 duplicates an existing file descriptor just as unix-dup
  582.    does only the new value of the duplicate descriptor may be requested
  583.    through the second argument.  If a file already exists with the
  584.    requested descriptor number, it will be closed and the number
  585.    assigned to the duplicate."
  586.   (declare (type unix-fd fd1 fd2))
  587.   (void-syscall ("dup2" int int) fd1 fd2))
  588.  
  589. ;;; Unix-fcntl takes a file descriptor, an integer command
  590. ;;; number, and optional command arguments.  It performs
  591. ;;; operations on the associated file and/or returns inform-
  592. ;;; ation about the file.
  593.  
  594. ;;; Operations performed on file descriptors:
  595.  
  596. (defconstant F-DUPFD    0  "Duplicate a file descriptor")
  597. (defconstant F-GETFD    1  "Get file desc. flags")
  598. (defconstant F-SETFD    2  "Set file desc. flags")
  599. (defconstant F-GETFL    3  "Get file flags")
  600. (defconstant F-SETFL    4  "Set file flags")
  601. (defconstant F-GETOWN   5  "Get owner")
  602. (defconstant F-SETOWN   6  "Set owner")
  603.  
  604.  
  605. ;;; File flags for F-GETFL and F-SETFL:
  606.  
  607. (defconstant FNDELAY  #o0004   "Non-blocking reads")
  608. (defconstant FAPPEND  #o0010   "Append on each write")
  609. (defconstant FASYNC   #o0100   "Signal pgrp when data ready")
  610. (defconstant FCREAT   #o1000   "Create if nonexistant")
  611. (defconstant FTRUNC   #o2000   "Truncate to zero length")
  612. (defconstant FEXCL    #o4000   "Error if already created")
  613.  
  614. (defun unix-fcntl (fd cmd arg)
  615.   "Unix-fcntl manipulates file descriptors according to the
  616.    argument CMD which can be one of the following:
  617.  
  618.    F-DUPFD         Duplicate a file descriptor.
  619.    F-GETFD         Get file descriptor flags.
  620.    F-SETFD         Set file descriptor flags.
  621.    F-GETFL         Get file flags.
  622.    F-SETFL         Set file flags.
  623.    F-GETOWN        Get owner.
  624.    F-SETOWN        Set owner.
  625.  
  626.    The flags that can be specified for F-SETFL are:
  627.  
  628.    FNDELAY         Non-blocking reads.
  629.    FAPPEND         Append on each write.
  630.    FASYNC          Signal pgrp when data ready.
  631.    FCREAT          Create if nonexistant.
  632.    FTRUNC          Truncate to zero length.
  633.    FEXCL           Error if already created.
  634.    "
  635.   (declare (type unix-fd fd)
  636.        (type (integer 0 6) cmd)
  637.        (type (unsigned-byte 16) arg))
  638.   (int-syscall ("fcntl" int int int) fd cmd arg))
  639.  
  640. ;;; Unix-link creates a hard link from name2 to name1.
  641.  
  642. (defun unix-link (name1 name2)
  643.   "Unix-link creates a hard link from the file with name1 to the
  644.    file with name2."
  645.   (declare (type unix-pathname name1 name2))
  646.   (void-syscall ("link" c-string c-string) name1 name2))
  647.  
  648. ;;; Unix-lseek accepts a file descriptor, an offset, and whence value.
  649.  
  650. (defconstant l_set 0 "set the file pointer")
  651. (defconstant l_incr 1 "increment the file pointer")
  652. (defconstant l_xtnd 2 "extend the file size")
  653.  
  654. (defun unix-lseek (fd offset whence)
  655.   "Unix-lseek accepts a file descriptor and moves the file pointer ahead
  656.    a certain offset for that file.  Whence can be any of the following:
  657.  
  658.    l_set        Set the file pointer.
  659.    l_incr       Increment the file pointer.
  660.    l_xtnd       Extend the file size.
  661.   "
  662.   (declare (type unix-fd fd)
  663.        (type (unsigned-byte 32) offset)
  664.        (type (integer 0 2) whence))
  665.   (int-syscall ("lseek" int off-t int) fd offset whence))
  666.  
  667. ;;; Unix-mkdir accepts a name and a mode and attempts to create the
  668. ;;; corresponding directory with mode mode.
  669.  
  670. (defun unix-mkdir (name mode)
  671.   "Unix-mkdir creates a new directory with the specified name and mode.
  672.    (Same as those for unix-fchmod.)  It returns T upon success, otherwise
  673.    NIL and an error number."
  674.   (declare (type unix-pathname name)
  675.        (type unix-file-mode mode))
  676.   (void-syscall ("mkdir" c-string int) name mode))
  677.  
  678. ;;; Unix-open accepts a pathname (a simple string), flags, and mode and
  679. ;;; attempts to open file with name pathname.
  680.  
  681. (defconstant o_rdonly 0 "Read-only flag.") 
  682. (defconstant o_wronly 1 "Write-only flag.")
  683. (defconstant o_rdwr 2   "Read-write flag.")
  684. (defconstant o_append #o10   "Append flag.")
  685. (defconstant o_creat #o1000  "Create if nonexistant flag.") 
  686. (defconstant o_trunc #o2000  "Truncate flag.")
  687.  
  688. (defconstant o_excl #o4000  "Error if already exists.")
  689.  
  690. (defun unix-open (path flags mode)
  691.   "Unix-open opens the file whose pathname is specified by path
  692.    for reading and/or writing as specified by the flags argument.
  693.    The flags argument can be:
  694.  
  695.      o_rdonly        Read-only flag.
  696.      o_wronly        Write-only flag.
  697.      o_rdwr          Read-and-write flag.
  698.      o_append        Append flag.
  699.      o_creat         Create-if-nonexistant flag.
  700.      o_trunc         Truncate-to-size-0 flag.
  701.  
  702.    If the o_creat flag is specified, then the file is created with
  703.    a permission of argument mode if the file doesn't exist.  An
  704.    integer file descriptor is returned by unix-open."
  705.   (declare (type unix-pathname path)
  706.        (type (unsigned-byte 16) flags)
  707.        (type unix-file-mode mode))
  708.   (int-syscall ("open" c-string int int) path flags mode))
  709.  
  710. (defun unix-pipe ()
  711.   "Unix-pipe sets up a unix-piping mechanism consisting of
  712.   an input pipe and an output pipe.  Unix-Pipe returns two
  713.   values: if no error occurred the first value is the pipe
  714.   to be read from and the second is can be written to.  If
  715.   an error occurred the first value is NIL and the second
  716.   the unix error code."
  717.   (with-alien ((fds (array int 2)))
  718.     (syscall ("pipe" (* int))
  719.          (values (deref fds 0) (deref fds 1))
  720.          (cast fds (* int)))))
  721.  
  722. ;;; Unix-read accepts a file descriptor, a buffer, and the length to read.
  723. ;;; It attempts to read len bytes from the device associated with fd
  724. ;;; and store them into the buffer.  It returns the actual number of
  725. ;;; bytes read.
  726.  
  727. (defun unix-read (fd buf len)
  728.   "Unix-read attempts to read from the file described by fd into
  729.    the buffer buf until it is full.  Len is the length of the buffer.
  730.    The number of bytes actually read is returned or NIL and an error
  731.    number if an error occured."
  732.   (declare (type unix-fd fd)
  733.        (type (unsigned-byte 32) len))
  734.   #+sunos
  735.   ;; Note: Under sunos we touch each page before doing the read to give
  736.   ;; the segv handler a chance to fix the permissions.  Otherwise,
  737.   ;; read will return EFAULT.  This also bypasses a bug in 4.1.1 in which
  738.   ;; read fails with EFAULT if the page has never been touched even if
  739.   ;; the permissions are okay.
  740.   (without-gcing
  741.    (let* ((page-size (get-page-size))
  742.       (1-page-size (1- page-size))
  743.       (sap (etypecase buf
  744.          (system-area-pointer buf)
  745.          (vector (vector-sap buf))))
  746.       (end (sap+ sap len)))
  747.      (declare (type (and fixnum unsigned-byte) page-size 1-page-size)
  748.           (type system-area-pointer sap end)
  749.           (optimize (speed 3) (safety 0)))
  750.      (do ((sap (int-sap (logand (the (unsigned-byte 32)
  751.                      (+ (sap-int sap) 1-page-size))
  752.                 (logxor 1-page-size (ldb (byte 32 0) -1))))
  753.            (sap+ sap page-size)))
  754.      ((sap>= sap end))
  755.        (declare (type system-area-pointer sap))
  756.        (setf (sap-ref-8 sap 0) (sap-ref-8 sap 0)))))
  757.   (int-syscall ("read" int (* char) int) fd buf len))
  758.  
  759. (defun unix-readlink (path)
  760.   "Unix-readlink invokes the readlink system call on the file name
  761.   specified by the simple string path.  It returns up to two values:
  762.   the contents of the symbolic link if the call is successful, or
  763.   NIL and the Unix error number."
  764.   (declare (type unix-pathname path))
  765.   (with-alien ((buf (array char 1024)))
  766.     (syscall ("readlink" c-string (* char) int)
  767.          (let ((string (make-string result)))
  768.            (kernel:copy-from-system-area
  769.         (alien-sap buf) 0
  770.         string (* vm:vector-data-offset vm:word-bits)
  771.         (* result vm:byte-bits))
  772.            string)
  773.          path (cast buf (* char)) 1024)))
  774.  
  775. ;;; Unix-rename accepts two files names and renames the first to the second.
  776.  
  777. (defun unix-rename (name1 name2)
  778.   "Unix-rename renames the file with string name1 to the string
  779.    name2.  NIL and an error code is returned if an error occured."
  780.   (declare (type unix-pathname name1 name2))
  781.   (void-syscall ("rename" c-string c-string) name1 name2))
  782.  
  783. ;;; Unix-rmdir accepts a name and removes the associated directory.
  784.  
  785. (defun unix-rmdir (name)
  786.   "Unix-rmdir attempts to remove the directory name.  NIL and
  787.    an error number is returned if an error occured."
  788.   (declare (type unix-pathname name))
  789.   (void-syscall ("rmdir" c-string) name))
  790.  
  791. ;;; UNIX-FAST-SELECT -- public.
  792. ;;;
  793. (declaim (inline unix-fast-select))
  794. ;;;
  795. (defun unix-fast-select (num-descriptors read-fds write-fds exception-fds
  796.              timeout-secs &optional (timeout-usecs 0))
  797.   "Perform the UNIX select(2) system call."
  798.   (declare (type (integer 0 #.FD-SETSIZE) num-descriptors)
  799.        (type (or (alien (* (struct fd-set))) null)
  800.          read-fds write-fds exception-fds)
  801.        (type (or null (unsigned-byte 31)) timeout-secs)
  802.        (type (unsigned-byte 31) timeout-usecs)
  803.        (optimize (speed 3) (safety 0) (inhibit-warnings 3)))
  804.   (with-alien ((tv (struct timeval)))
  805.     (when timeout-secs
  806.       (setf (slot tv 'tv-sec) timeout-secs)
  807.       (setf (slot tv 'tv-usec) timeout-usecs))
  808.     (int-syscall ("select" int (* (struct fd-set)) (* (struct fd-set))
  809.           (* (struct fd-set)) (* (struct timeval)))
  810.          num-descriptors read-fds write-fds exception-fds
  811.          (if timeout-secs (alien-sap (addr tv)) (int-sap 0)))))
  812.  
  813. ;;; Unix-select accepts sets of file descriptors and waits for an event
  814. ;;; to happen on one of them or to time out.
  815.  
  816. (defmacro num-to-fd-set (fdset num)
  817.   `(if (fixnump ,num)
  818.        (progn
  819.      (setf (deref (slot ,fdset 'fds-bits) 0) ,num)
  820.      ,@(loop for index upfrom 1 below (/ fd-setsize 32)
  821.          collect `(setf (deref (slot ,fdset 'fds-bits) ,index) 0)))
  822.        (progn
  823.      ,@(loop for index upfrom 0 below (/ fd-setsize 32)
  824.          collect `(setf (deref (slot ,fdset 'fds-bits) ,index)
  825.                 (ldb (byte 32 ,(* index 32)) ,num))))))
  826.  
  827. (defmacro fd-set-to-num (nfds fdset)
  828.   `(if (<= ,nfds 32)
  829.        (deref (slot ,fdset 'fds-bits) 0)
  830.        (+ ,@(loop for index upfrom 0 below (/ fd-setsize 32)
  831.           collect `(ash (deref (slot ,fdset 'fds-bits) ,index)
  832.                 ,(* index 32))))))
  833.  
  834. (defun unix-select (nfds rdfds wrfds xpfds to-secs &optional (to-usecs 0))
  835.   "Unix-select examines the sets of descriptors passed as arguments
  836.    to see if they are ready for reading and writing.  See the UNIX
  837.    Programmers Manual for more information."
  838.   (declare (type (integer 0 #.FD-SETSIZE) nfds)
  839.        (type unsigned-byte rdfds wrfds xpfds)
  840.        (type (or (unsigned-byte 31) null) to-secs)
  841.        (type (unsigned-byte 31) to-usecs)
  842.        (optimize (speed 3) (safety 0) (inhibit-warnings 3)))
  843.   (with-alien ((tv (struct timeval))
  844.            (rdf (struct fd-set))
  845.            (wrf (struct fd-set))
  846.            (xpf (struct fd-set)))
  847.     (when to-secs
  848.       (setf (slot tv 'tv-sec) to-secs)
  849.       (setf (slot tv 'tv-usec) to-usecs))
  850.     (num-to-fd-set rdf rdfds)
  851.     (num-to-fd-set wrf wrfds)
  852.     (num-to-fd-set xpf xpfds)
  853.     (macrolet ((frob (lispvar alienvar)
  854.          `(if (zerop ,lispvar)
  855.               (int-sap 0)
  856.               (alien-sap (addr ,alienvar)))))
  857.       (syscall ("select" int (* (struct fd-set)) (* (struct fd-set))
  858.         (* (struct fd-set)) (* (struct timeval)))
  859.            (values result
  860.                (fd-set-to-num nfds rdf)
  861.                (fd-set-to-num nfds wrf)
  862.                (fd-set-to-num nfds xpf))
  863.            nfds (frob rdfds rdf) (frob wrfds wrf) (frob xpfds xpf)
  864.            (if to-secs (alien-sap (addr tv)) (int-sap 0))))))
  865.  
  866.  
  867. ;;; Unix-sync writes all information in core memory which has been modified
  868. ;;; to permanent storage (i.e. disk).
  869.  
  870. (defun unix-sync ()
  871.   "Unix-sync writes all information in core memory which has been
  872.    modified to disk.  It returns NIL and an error code if an error
  873.    occured."
  874.   (void-syscall ("sync")))
  875.  
  876. ;;; Unix-fsync writes the core-image of the file described by "fd" to
  877. ;;; permanent storage (i.e. disk).
  878.  
  879. (defun unix-fsync (fd)
  880.   "Unix-fsync writes the core image of the file described by
  881.    fd to disk."
  882.   (declare (type unix-fd fd))
  883.   (void-syscall ("fsync" int) fd))
  884.  
  885. ;;; Unix-truncate accepts a file name and a new length.  The file is
  886. ;;; truncated to the new length.
  887.  
  888. (defun unix-truncate (name len)
  889.   "Unix-truncate truncates the named file to the length (in
  890.    bytes) specified by len.  NIL and an error number is returned
  891.    if the call is unsuccessful."
  892.   (declare (type unix-pathname name)
  893.        (type (unsigned-byte 32) len))
  894.   (void-syscall ("truncate" c-string int) name len))
  895.  
  896. (defun unix-ftruncate (fd len)
  897.   "Unix-ftruncate is similar to unix-truncate except that the first
  898.    argument is a file descriptor rather than a file name."
  899.   (declare (type unix-fd fd)
  900.        (type (unsigned-byte 32) len))
  901.   (void-syscall ("ftruncate" int int) fd len))
  902.  
  903. (defun unix-symlink (name1 name2)
  904.   "Unix-symlink creates a symbolic link named name2 to the file
  905.    named name1.  NIL and an error number is returned if the call
  906.    is unsuccessful."
  907.   (declare (type unix-pathname name1 name2))
  908.   (void-syscall ("symlink" c-string c-string) name1 name2))
  909.  
  910. ;;; Unix-unlink accepts a name and deletes the directory entry for that
  911. ;;; name and the file if this is the last link.
  912.  
  913. (defun unix-unlink (name)
  914.   "Unix-unlink removes the directory entry for the named file.
  915.    NIL and an error code is returned if the call fails."
  916.   (declare (type unix-pathname name))
  917.   (void-syscall ("unlink" c-string) name))
  918.  
  919. ;;; Unix-write accepts a file descriptor, a buffer, an offset, and the
  920. ;;; length to write.  It attempts to write len bytes to the device
  921. ;;; associated with fd from the the buffer starting at offset.  It returns
  922. ;;; the actual number of bytes written.
  923.  
  924. (defun unix-write (fd buf offset len)
  925.   "Unix-write attempts to write a character buffer (buf) of length
  926.    len to the file described by the file descriptor fd.  NIL and an
  927.    error is returned if the call is unsuccessful."
  928.   (declare (type unix-fd fd)
  929.        (type (unsigned-byte 32) offset len))
  930.   (int-syscall ("write" int (* char) int)
  931.            fd
  932.            (with-alien ((ptr (* char) (etypecase buf
  933.                         ((simple-array * (*))
  934.                          (vector-sap buf))
  935.                         (system-area-pointer
  936.                          buf))))
  937.          (addr (deref ptr offset)))
  938.            len))
  939.  
  940. ;;; Unix-ioctl is used to change parameters of devices in a device
  941. ;;; dependent way.
  942.  
  943.  
  944. (defconstant terminal-speeds
  945.   '#(nil 50 75 110 nil 150 200 300 600 1200 1800 2400 4800 9600 nil nil))
  946.  
  947. (defconstant tty-raw #o40)
  948. (defconstant tty-crmod #o20)
  949. (defconstant tty-echo #o10)
  950. (defconstant tty-lcase #o4)
  951. (defconstant tty-cbreak #o2)
  952. (defconstant tty-tandem #o1)
  953.  
  954. (eval-when (compile load eval)
  955.  
  956. (defconstant iocparm-mask #x7f)
  957. (defconstant ioc_void #x20000000)
  958. (defconstant ioc_out #x40000000)
  959. (defconstant ioc_in #x80000000)
  960. (defconstant ioc_inout (logior ioc_in ioc_out))
  961.  
  962. (defmacro define-ioctl-command (name dev cmd arg &optional (parm-type :void))
  963.   (let* ((ptype (ecase parm-type
  964.           (:void ioc_void)
  965.           (:in ioc_in)
  966.           (:out ioc_out)
  967.           (:inout ioc_inout)))
  968.      (code (logior (ash (char-code dev) 8) cmd ptype)))
  969.     (when arg
  970.       (setf code
  971.         `(logior (ash (logand (alien-size ,arg :bytes)
  972.                   ,iocparm-mask)
  973.               16)
  974.              ,code)))
  975.     `(eval-when (eval load compile)
  976.        (defconstant ,name ,code))))
  977.  
  978. )
  979.  
  980. ;;; TTY ioctl commands.
  981.  
  982. (define-ioctl-command TIOCGETP #\t 8 (struct sgttyb) :out)
  983. (define-ioctl-command TIOCSETP #\t 9 (struct sgttyb) :in)
  984. (define-ioctl-command TIOCFLUSH #\t 16 int :in)
  985. (define-ioctl-command TIOCSETC #\t 17 (struct tchars) :in)
  986. (define-ioctl-command TIOCGETC #\t 18 (struct tchars) :out)
  987. (define-ioctl-command TIOCGWINSZ #\t 104 (struct winsize) :out)
  988. (define-ioctl-command TIOCSWINSZ #\t 103 (struct winsize) :in)
  989.  
  990. (define-ioctl-command TIOCNOTTY #\t 113 nil :void)
  991. (define-ioctl-command TIOCSLTC #\t 117 (struct ltchars) :in)
  992. (define-ioctl-command TIOCGLTC #\t 116 (struct ltchars) :out)
  993. (define-ioctl-command TIOCSPGRP #\t 118 int :in)
  994. (define-ioctl-command TIOCGPGRP #\t 119 int :out)
  995.  
  996. ;;; File ioctl commands.
  997. (define-ioctl-command FIONREAD #\f 127 int :out)
  998.  
  999.  
  1000. (defun unix-ioctl (fd cmd arg)
  1001.   "Unix-ioctl performs a variety of operations on open i/o
  1002.    descriptors.  See the UNIX Programmer's Manual for more
  1003.    information."
  1004.   (declare (type unix-fd fd)
  1005.        (type (unsigned-byte 32) cmd))
  1006.   (void-syscall ("ioctl" int unsigned-int (* char)) fd cmd arg))
  1007.  
  1008. (defun tcsetpgrp (fd pgrp)
  1009.   "Set the tty-process-group for the unix file-descriptor FD to PGRP."
  1010.   (alien:with-alien ((alien-pgrp c-call:int pgrp))
  1011.     (unix-ioctl fd
  1012.         tiocspgrp
  1013.         (alien:alien-sap (alien:addr alien-pgrp)))))
  1014.  
  1015. (defun tcgetpgrp (fd)
  1016.   "Get the tty-process-group for the unix file-descriptor FD."
  1017.   (alien:with-alien ((alien-pgrp c-call:int))
  1018.     (multiple-value-bind (ok err)
  1019.     (unix-ioctl fd
  1020.              tiocgpgrp
  1021.              (alien:alien-sap (alien:addr alien-pgrp)))
  1022.       (if ok
  1023.       (values alien-pgrp nil)
  1024.       (values nil err)))))
  1025.  
  1026. (defun tty-process-group (&optional fd)
  1027.   "Get the tty-process-group for the unix file-descriptor FD.  If not supplied,
  1028.   FD defaults to /dev/tty."
  1029.   (if fd
  1030.       (tcgetpgrp fd)
  1031.       (multiple-value-bind (tty-fd errno)
  1032.       (unix-open "/dev/tty" o_rdwr 0)
  1033.     (cond (tty-fd
  1034.            (multiple-value-prog1
  1035.            (tcgetpgrp tty-fd)
  1036.          (unix-close tty-fd)))
  1037.           (t
  1038.            (values nil errno))))))
  1039.  
  1040. (defun %set-tty-process-group (pgrp &optional fd)
  1041.   "Set the tty-process-group for the unix file-descriptor FD to PGRP.  If not
  1042.   supplied, FD defaults to /dev/tty."
  1043.   (let ((old-sigs
  1044.      (unix-sigblock
  1045.       (sigmask :sigttou :sigttin :sigtstp :sigchld))))
  1046.     (declare (type (unsigned-byte 32) old-sigs))
  1047.     (unwind-protect
  1048.     (if fd
  1049.         (tcsetpgrp fd pgrp)
  1050.         (multiple-value-bind (tty-fd errno)
  1051.         (unix-open "/dev/tty" o_rdwr 0)
  1052.           (cond (tty-fd
  1053.              (multiple-value-prog1
  1054.              (tcsetpgrp tty-fd pgrp)
  1055.                (unix-close tty-fd)))
  1056.             (t
  1057.              (values nil errno)))))
  1058.       (unix-sigsetmask old-sigs))))
  1059.   
  1060. (defsetf tty-process-group (&optional fd) (pgrp)
  1061.   "Set the tty-process-group for the unix file-descriptor FD to PGRP.  If not
  1062.   supplied, FD defaults to /dev/tty."
  1063.   `(%set-tty-process-group ,pgrp ,fd))
  1064.  
  1065.  
  1066. ;;; Unix-exit terminates a program.
  1067.  
  1068. (defun unix-exit (&optional (code 0))
  1069.   "Unix-exit terminates the current process with an optional
  1070.    error code.  If successful, the call doesn't return.  If
  1071.    unsuccessful, the call returns NIL and an error number."
  1072.   (declare (type (signed-byte 32) code))
  1073.   (void-syscall ("exit" int) code))
  1074.  
  1075. ;;; STAT and friends.
  1076.  
  1077. (defmacro extract-stat-results (buf)
  1078.   `(values T
  1079.        (slot ,buf 'st-dev)
  1080.        (slot ,buf 'st-ino)
  1081.        (slot ,buf 'st-mode)
  1082.        (slot ,buf 'st-nlink)
  1083.        (slot ,buf 'st-uid)
  1084.        (slot ,buf 'st-gid)
  1085.        (slot ,buf 'st-rdev)
  1086.        (slot ,buf 'st-size)
  1087.        (slot ,buf 'st-atime)
  1088.        (slot ,buf 'st-mtime)
  1089.        (slot ,buf 'st-ctime)
  1090.        (slot ,buf 'st-blksize)
  1091.        (slot ,buf 'st-blocks)))
  1092.  
  1093. (defun unix-stat (name)
  1094.   "Unix-stat retrieves information about the specified
  1095.    file returning them in the form of multiple values.
  1096.    See the UNIX Programmer's Manual for a description
  1097.    of the values returned.  If the call fails, then NIL
  1098.    and an error number is returned instead."
  1099.   (declare (type unix-pathname name))
  1100.   (with-alien ((buf (struct stat)))
  1101.     (syscall ("stat" c-string (* (struct stat)))
  1102.          (extract-stat-results buf)
  1103.          name (addr buf))))
  1104.  
  1105.  
  1106. (defun unix-lstat (name)
  1107.   "Unix-lstat is similar to unix-stat except the specified
  1108.    file must be a symbolic link."
  1109.   (declare (type unix-pathname name))
  1110.   (with-alien ((buf (struct stat)))
  1111.     (syscall ("lstat" c-string (* (struct stat)))
  1112.          (extract-stat-results buf)
  1113.          name (addr buf))))
  1114.  
  1115. (defun unix-fstat (fd)
  1116.   "Unix-fstat is similar to unix-stat except the file is specified
  1117.    by the file descriptor fd."
  1118.   (declare (type unix-fd fd))
  1119.   (with-alien ((buf (struct stat)))
  1120.     (syscall ("fstat" int (* (struct stat)))
  1121.          (extract-stat-results buf)
  1122.          fd (addr buf))))
  1123.  
  1124.  
  1125. (defconstant rusage_self 0 "The calling process.")
  1126. (defconstant rusage_children -1 "Terminated child processes.")
  1127.  
  1128. (declaim (inline unix-fast-getrusage))
  1129. (defun unix-fast-getrusage (who)
  1130.   "Like call getrusage, but return only the system and user time, and returns
  1131.    the seconds and microseconds as separate values."
  1132.   (declare (values (member t)
  1133.            (unsigned-byte 31) (mod 1000000)
  1134.            (unsigned-byte 31) (mod 1000000)))
  1135.   (with-alien ((usage (struct rusage)))
  1136.     (syscall* ("getrusage" int (* (struct rusage)))
  1137.           (values t
  1138.               (slot (slot usage 'ru-utime) 'tv-sec)
  1139.               (slot (slot usage 'ru-utime) 'tv-usec)
  1140.               (slot (slot usage 'ru-stime) 'tv-sec)
  1141.               (slot (slot usage 'ru-stime) 'tv-usec))
  1142.           who (addr usage))))
  1143.  
  1144. (defun unix-getrusage (who)
  1145.   "Unix-getrusage returns information about the resource usage
  1146.    of the process specified by who.  Who can be either the
  1147.    current process (rusage_self) or all of the terminated
  1148.    child processes (rusage_children).  NIL and an error number
  1149.    is returned if the call fails."
  1150.   (with-alien ((usage (struct rusage)))
  1151.     (syscall* ("getrusage" int (* (struct rusage)))
  1152.           (values t
  1153.               (+ (* (slot (slot usage 'ru-utime) 'tv-sec) 1000000)
  1154.              (slot (slot usage 'ru-utime) 'tv-usec))
  1155.               (+ (* (slot (slot usage 'ru-stime) 'tv-sec) 1000000)
  1156.              (slot (slot usage 'ru-stime) 'tv-usec))
  1157.               (slot usage 'ru-maxrss)
  1158.               (slot usage 'ru-ixrss)
  1159.               (slot usage 'ru-idrss)
  1160.               (slot usage 'ru-isrss)
  1161.               (slot usage 'ru-minflt)
  1162.               (slot usage 'ru-majflt)
  1163.               (slot usage 'ru-nswap)
  1164.               (slot usage 'ru-inblock)
  1165.               (slot usage 'ru-oublock)
  1166.               (slot usage 'ru-msgsnd)
  1167.               (slot usage 'ru-msgrcv)
  1168.               (slot usage 'ru-nsignals)
  1169.               (slot usage 'ru-nvcsw)
  1170.               (slot usage 'ru-nivcsw))
  1171.           who (addr usage))))
  1172.  
  1173. (declaim (inline unix-gettimeofday))
  1174. (defun unix-gettimeofday ()
  1175.   "If it works, unix-gettimeofday returns 5 values: T, the seconds and
  1176.    microseconds of the current time of day, the timezone (in minutes west
  1177.    of Greenwich), and a daylight-savings flag.  If it doesn't work, it
  1178.    returns NIL and the errno."
  1179.   (with-alien ((tv (struct timeval))
  1180.            (tz (struct timezone)))
  1181.     (syscall* ("gettimeofday" (* (struct timeval)) (* (struct timezone)))
  1182.           (values T
  1183.               (slot tv 'tv-sec)
  1184.               (slot tv 'tv-usec)
  1185.               (slot tz 'tz-minuteswest)
  1186.               (slot tz 'tz-dsttime))
  1187.           (addr tv)
  1188.           (addr tz))))
  1189.  
  1190. ;;; Unix-utimes changes the accessed and updated times on UNIX
  1191. ;;; files.  The first argument is the filename (a string) and
  1192. ;;; the second argument is a list of the 4 times- accessed and
  1193. ;;; updated seconds and microseconds.
  1194.  
  1195. (defun unix-utimes (file atime-sec atime-usec mtime-sec mtime-usec)
  1196.   "Unix-utimes sets the 'last-accessed' and 'last-updated'
  1197.    times on a specified file.  NIL and an error number is
  1198.    returned if the call is unsuccessful."
  1199.   (declare (type unix-pathname file)
  1200.        (type (alien unsigned-long)
  1201.          atime-sec atime-usec
  1202.          mtime-sec mtime-usec))
  1203.   (with-alien ((tvp (array (struct timeval) 2)))
  1204.     (setf (slot (deref tvp 0) 'tv-sec) atime-sec)
  1205.     (setf (slot (deref tvp 0) 'tv-usec) atime-usec)
  1206.     (setf (slot (deref tvp 1) 'tv-sec) mtime-sec)
  1207.     (setf (slot (deref tvp 1) 'tv-usec) mtime-usec)
  1208.     (void-syscall ("utimes" c-string (* (struct timeval)))
  1209.           file
  1210.           (cast tvp (* (struct timeval))))))
  1211.  
  1212. ;;; Unix-setreuid sets the real and effective user-id's of the current
  1213. ;;; process to the arguments "ruid" and "euid", respectively.  Usage is
  1214. ;;; restricted for anyone but the super-user.  Setting either "ruid" or
  1215. ;;; "euid" to -1 makes the system use the current id instead.
  1216.  
  1217. (defun unix-setreuid (ruid euid)
  1218.   "Unix-setreuid sets the real and effective user-id's of the current
  1219.    process to the specified ones.  NIL and an error number is returned
  1220.    if the call fails."
  1221.   (void-syscall ("setreuid" int int) ruid euid))
  1222.  
  1223. ;;; Unix-setregid sets the real and effective group-id's of the current
  1224. ;;; process to the arguments "rgid" and "egid", respectively.  Usage is
  1225. ;;; restricted for anyone but the super-user.  Setting either "rgid" or
  1226. ;;; "egid" to -1 makes the system use the current id instead.
  1227.  
  1228. (defun unix-setregid (rgid egid)
  1229.   "Unix-setregid sets the real and effective group-id's of the current
  1230.    process process to the specified ones.  NIL and an error number is
  1231.    returned if the call fails."
  1232.   (void-syscall ("setregid" int int) rgid egid))
  1233.  
  1234. (def-alien-routine ("getpid" unix-getpid) int
  1235.   "Unix-getpid returns the process-id of the current process.")
  1236.  
  1237. (def-alien-routine ("getppid" unix-getppid) int
  1238.   "Unix-getppid returns the process-id of the parent of the current process.")
  1239.  
  1240. (def-alien-routine ("getgid" unix-getgid) int
  1241.   "Unix-getgid returns the real group-id of the current process.")
  1242.  
  1243. (def-alien-routine ("getegid" unix-getegid) int
  1244.   "Unix-getegid returns the effective group-id of the current process.")
  1245.  
  1246. ;;; Unix-getpgrp returns the group-id associated with the
  1247. ;;; process whose process-id is specified as an argument.
  1248. ;;; As usual, if the process-id is 0, it refers to the current
  1249. ;;; process.
  1250.  
  1251. (defun unix-getpgrp (pid)
  1252.   "Unix-getpgrp returns the group-id of the process associated
  1253.    with pid."
  1254.   (int-syscall ("getpgrp" int) pid))
  1255.  
  1256. ;;; Unix-setpgrp sets the group-id of the process specified by 
  1257. ;;; "pid" to the value of "pgrp".  The process must either have
  1258. ;;; the same effective user-id or be a super-user process.
  1259.  
  1260. (defun unix-setpgrp (pid pgrp)
  1261.   "Unix-setpgrp sets the process group on the process pid to
  1262.    pgrp.  NIL and an error number is returned upon failure."
  1263.   (void-syscall ("setpgrp" int int) pid pgrp))
  1264.  
  1265. (def-alien-routine ("getuid" unix-getuid) int
  1266.   "Unix-getuid returns the real user-id associated with the
  1267.    current process.")
  1268.  
  1269. ;;; Unix-getpagesize returns the number of bytes in the system page.
  1270.  
  1271. (defun unix-getpagesize ()
  1272.   "Unix-getpagesize returns the number of bytes in a system page."
  1273.   (int-syscall ("getpagesize")))
  1274.  
  1275. (defun unix-gethostname ()
  1276.   "Unix-gethostname returns the name of the host machine as a string."
  1277.   (with-alien ((buf (array char 256)))
  1278.     (syscall ("gethostname" (* char) int)
  1279.          (cast buf c-string)
  1280.          (cast buf (* char)) 256)))
  1281.  
  1282. (def-alien-routine ("gethostid" unix-gethostid) unsigned-long
  1283.   "Unix-gethostid returns a 32-bit integer which provides unique
  1284.    identification for the host machine.")
  1285.  
  1286. (defun unix-fork ()
  1287.   "Executes the unix fork system call.  Returns 0 in the child and the pid
  1288.    of the child in the parent if it works, or NIL and an error number if it
  1289.    doesn't work."
  1290.   (int-syscall ("fork")))
  1291.  
  1292.  
  1293.  
  1294. ;;; Operations on Unix Directories.
  1295.  
  1296. (export '(open-dir read-dir close-dir))
  1297.  
  1298. (defstruct (directory
  1299.         (:print-function %print-directory))
  1300.   name
  1301.   (dir-struct (required-argument) :type system-area-pointer))
  1302.  
  1303. (defun %print-directory (dir stream depth)
  1304.   (declare (ignore depth))
  1305.   (format stream "#<Directory ~S>" (directory-name dir)))
  1306.  
  1307. (defun open-dir (pathname)
  1308.   (declare (type unix-pathname pathname))
  1309.   (let ((kind (unix-file-kind pathname)))
  1310.     (case kind
  1311.       (:directory
  1312.        (let ((dir-struct
  1313.           (alien-funcall (extern-alien "opendir"
  1314.                        (function system-area-pointer
  1315.                              c-string))
  1316.                  pathname)))
  1317.      (if (zerop (sap-int dir-struct))
  1318.          (values nil unix-errno)
  1319.          (make-directory :name pathname :dir-struct dir-struct))))
  1320.       ((nil)
  1321.        (values nil enoent))
  1322.       (t
  1323.        (values nil enotdir)))))
  1324.  
  1325. (defun read-dir (dir)
  1326.   (declare (type directory dir))
  1327.   (let ((daddr (alien-funcall (extern-alien "readdir"
  1328.                         (function system-area-pointer
  1329.                               system-area-pointer))
  1330.                   (directory-dir-struct dir))))
  1331.     (declare (type system-area-pointer daddr))
  1332.     (if (zerop (sap-int daddr))
  1333.     nil
  1334.     (with-alien ((direct (* (struct direct)) daddr))
  1335.       (let ((nlen (slot direct 'd-namlen))
  1336.         (ino (slot direct 'd-ino)))
  1337.         (declare (type (unsigned-byte 16) nlen))
  1338.         (let ((string (make-string nlen)))
  1339.           (kernel:copy-from-system-area
  1340.            (alien-sap (addr (slot direct 'd-name))) 0
  1341.            string (* vm:vector-data-offset vm:word-bits)
  1342.            (* nlen vm:byte-bits))
  1343.           (values string ino)))))))
  1344.  
  1345. (defun close-dir (dir)
  1346.   (declare (type directory dir))
  1347.   (alien-funcall (extern-alien "closedir"
  1348.                    (function void system-area-pointer))
  1349.          (directory-dir-struct dir))
  1350.   nil)
  1351.  
  1352.  
  1353. (defun unix-current-directory ()
  1354.   (with-alien ((buf (array char 1024)))
  1355.     (values (not (zerop (alien-funcall (extern-alien "getwd"
  1356.                              (function int (* char)))
  1357.                        (cast buf (* char)))))
  1358.         (cast buf c-string))))
  1359.  
  1360.  
  1361.  
  1362. ;;;; Support routines for dealing with unix pathnames.
  1363.  
  1364. (export '(unix-file-kind unix-maybe-prepend-current-directory
  1365.       unix-resolve-links unix-simplify-pathname))
  1366.  
  1367. (defun unix-file-kind (name &optional check-for-links)
  1368.   "Returns either :file, :directory, :link, :special, or NIL."
  1369.   (declare (simple-string name))
  1370.   (multiple-value-bind (res dev ino mode)
  1371.                (if check-for-links
  1372.                (unix-lstat name)
  1373.                (unix-stat name))
  1374.     (declare (type (or fixnum null) mode)
  1375.          (ignore dev ino))
  1376.     (when res
  1377.       (let ((kind (logand mode s-ifmt)))
  1378.     (cond ((eql kind s-ifdir) :directory)
  1379.           ((eql kind s-ifreg) :file)
  1380.           ((eql kind s-iflnk) :link)
  1381.           (t :special))))))
  1382.  
  1383. (defun unix-maybe-prepend-current-directory (name)
  1384.   (declare (simple-string name))
  1385.   (if (and (> (length name) 0) (char= (schar name 0) #\/))
  1386.       name
  1387.       (multiple-value-bind (win dir) (unix-current-directory)
  1388.     (if win
  1389.         (concatenate 'simple-string dir "/" name)
  1390.         name))))
  1391.  
  1392. (defun unix-resolve-links (pathname)
  1393.   "Returns the pathname with all symbolic links resolved."
  1394.   (declare (simple-string pathname))
  1395.   (let ((len (length pathname))
  1396.     (pending pathname))
  1397.     (declare (fixnum len) (simple-string pending))
  1398.     (if (zerop len)
  1399.     pathname
  1400.     (let ((result (make-string 1024 :initial-element (code-char 0)))
  1401.           (fill-ptr 0)
  1402.           (name-start 0))
  1403.       (loop
  1404.         (let* ((name-end (or (position #\/ pending :start name-start) len))
  1405.            (new-fill-ptr (+ fill-ptr (- name-end name-start))))
  1406.           (replace result pending
  1407.                :start1 fill-ptr
  1408.                :end1 new-fill-ptr
  1409.                :start2 name-start
  1410.                :end2 name-end)
  1411.           (let ((kind (unix-file-kind (if (zerop name-end) "/" result) t)))
  1412.         (unless kind (return nil))
  1413.         (cond ((eq kind :link)
  1414.                (multiple-value-bind (link err) (unix-readlink result)
  1415.              (unless link
  1416.                (error "Error reading link ~S: ~S"
  1417.                   (subseq result 0 fill-ptr)
  1418.                   (get-unix-error-msg err)))
  1419.              (cond ((or (zerop (length link))
  1420.                     (char/= (schar link 0) #\/))
  1421.                 ;; It's a relative link
  1422.                 (fill result (code-char 0)
  1423.                       :start fill-ptr
  1424.                       :end new-fill-ptr))
  1425.                    ((string= result "/../" :end1 4)
  1426.                 ;; It's across the super-root.
  1427.                 (let ((slash (or (position #\/ result :start 4)
  1428.                          0)))
  1429.                   (fill result (code-char 0)
  1430.                     :start slash
  1431.                     :end new-fill-ptr)
  1432.                   (setf fill-ptr slash)))
  1433.                    (t
  1434.                 ;; It's absolute.
  1435.                 (and (> (length link) 0)
  1436.                      (char= (schar link 0) #\/))
  1437.                 (fill result (code-char 0) :end new-fill-ptr)
  1438.                 (setf fill-ptr 0)))
  1439.              (setf pending
  1440.                    (if (= name-end len)
  1441.                    link
  1442.                    (concatenate 'simple-string
  1443.                         link
  1444.                         (subseq pending name-end))))
  1445.              (setf len (length pending))
  1446.              (setf name-start 0)))
  1447.               ((= name-end len)
  1448.                (return (subseq result 0 new-fill-ptr)))
  1449.               ((eq kind :directory)
  1450.                (setf (schar result new-fill-ptr) #\/)
  1451.                (setf fill-ptr (1+ new-fill-ptr))
  1452.                (setf name-start (1+ name-end)))
  1453.               (t
  1454.                (return nil))))))))))
  1455.  
  1456. (defun unix-simplify-pathname (src)
  1457.   (declare (simple-string src))
  1458.   (let* ((src-len (length src))
  1459.      (dst (make-string src-len))
  1460.      (dst-len 0)
  1461.      (dots 0)
  1462.      (last-slash nil))
  1463.     (macrolet ((deposit (char)
  1464.             `(progn
  1465.                (setf (schar dst dst-len) ,char)
  1466.                (incf dst-len))))
  1467.       (dotimes (src-index src-len)
  1468.     (let ((char (schar src src-index)))
  1469.       (cond ((char= char #\.)
  1470.          (when dots
  1471.            (incf dots))
  1472.          (deposit char))
  1473.         ((char= char #\/)
  1474.          (case dots
  1475.            (0
  1476.             ;; Either ``/...' or ``...//...'
  1477.             (unless last-slash
  1478.               (setf last-slash dst-len)
  1479.               (deposit char)))
  1480.            (1
  1481.             ;; Either ``./...'' or ``..././...''
  1482.             (decf dst-len))
  1483.            (2
  1484.             ;; We've found ..
  1485.             (cond
  1486.              ((and last-slash (not (zerop last-slash)))
  1487.               ;; There is something before this ..
  1488.               (let ((prev-prev-slash
  1489.                  (position #\/ dst :end last-slash :from-end t)))
  1490.             (cond ((and (= (+ (or prev-prev-slash 0) 2)
  1491.                        last-slash)
  1492.                     (char= (schar dst (- last-slash 2)) #\.)
  1493.                     (char= (schar dst (1- last-slash)) #\.))
  1494.                    ;; The something before this .. is another ..
  1495.                    (deposit char)
  1496.                    (setf last-slash dst-len))
  1497.                   (t
  1498.                    ;; The something is some random dir.
  1499.                    (setf dst-len
  1500.                      (if prev-prev-slash
  1501.                      (1+ prev-prev-slash)
  1502.                      0))
  1503.                    (setf last-slash prev-prev-slash)))))
  1504.              (t
  1505.               ;; There is nothing before this .., so we need to keep it
  1506.               (setf last-slash dst-len)
  1507.               (deposit char))))
  1508.            (t
  1509.             ;; Something other than a dot between slashes.
  1510.             (setf last-slash dst-len)
  1511.             (deposit char)))
  1512.          (setf dots 0))
  1513.         (t
  1514.          (setf dots nil)
  1515.          (setf (schar dst dst-len) char)
  1516.          (incf dst-len))))))
  1517.     (when (and last-slash (not (zerop last-slash)))
  1518.       (case dots
  1519.     (1
  1520.      ;; We've got  ``foobar/.''
  1521.      (decf dst-len))
  1522.     (2
  1523.      ;; We've got ``foobar/..''
  1524.      (unless (and (>= last-slash 2)
  1525.               (char= (schar dst (1- last-slash)) #\.)
  1526.               (char= (schar dst (- last-slash 2)) #\.)
  1527.               (or (= last-slash 2)
  1528.               (char= (schar dst (- last-slash 3)) #\/)))
  1529.        (let ((prev-prev-slash
  1530.           (position #\/ dst :end last-slash :from-end t)))
  1531.          (if prev-prev-slash
  1532.          (setf dst-len (1+ prev-prev-slash))
  1533.          (return-from unix-simplify-pathname "./")))))))
  1534.     (cond ((zerop dst-len)
  1535.        "./")
  1536.       ((= dst-len src-len)
  1537.        dst)
  1538.       (t
  1539.        (subseq dst 0 dst-len)))))
  1540.  
  1541.  
  1542. ;;;; Other random routines.
  1543.  
  1544. (def-alien-routine ("isatty" unix-isatty) boolean
  1545.   "Accepts a Unix file descriptor and returns T if the device
  1546.   associated with it is a terminal."
  1547.   (fd int))
  1548.  
  1549. (def-alien-routine ("ttyname" unix-ttyname) c-string
  1550.   (fd int))
  1551.  
  1552.  
  1553.  
  1554.  
  1555. ;;;; UNIX-EXECVE
  1556.  
  1557. (defun unix-execve (program &optional arg-list
  1558.                 (environment *environment-list*))
  1559.   "Executes the Unix execve system call.  If the system call suceeds, lisp
  1560.    will no longer be running in this process.  If the system call fails this
  1561.    function returns two values: NIL and an error code.  Arg-list should be a
  1562.    list of simple-strings which are passed as arguments to the exec'ed program.
  1563.    Environment should be an a-list mapping symbols to simple-strings which this
  1564.    function bashes together to form the environment for the exec'ed program."
  1565.   (check-type program simple-string)
  1566.   (let ((env-list (let ((envlist nil))
  1567.             (dolist (cons environment)
  1568.               (push (if (cdr cons)
  1569.                 (concatenate 'simple-string
  1570.                          (string (car cons)) "="
  1571.                          (cdr cons))
  1572.                 (car cons))
  1573.                 envlist))
  1574.             envlist)))
  1575.     (sub-unix-execve program arg-list env-list)))
  1576.  
  1577.  
  1578. (defmacro round-bytes-to-words (n)
  1579.   `(logand (the fixnum (+ (the fixnum ,n) 3)) (lognot 3)))
  1580.  
  1581. ;;;
  1582. ;;; STRING-LIST-TO-C-STRVEC    -- Internal
  1583. ;;; 
  1584. ;;; STRING-LIST-TO-C-STRVEC is a function which takes a list of
  1585. ;;; simple-strings and constructs a C-style string vector (strvec) --
  1586. ;;; a null-terminated array of pointers to null-terminated strings.
  1587. ;;; This function returns two values: a sap and a byte count.  When the
  1588. ;;; memory is no longer needed it should be deallocated with
  1589. ;;; vm_deallocate.
  1590. ;;; 
  1591. (defun string-list-to-c-strvec (string-list)
  1592.   ;;
  1593.   ;; Make a pass over string-list to calculate the amount of memory
  1594.   ;; needed to hold the strvec.
  1595.   (let ((string-bytes 0)
  1596.     (vec-bytes (* 4 (1+ (length string-list)))))
  1597.     (declare (fixnum string-bytes vec-bytes))
  1598.     (dolist (s string-list)
  1599.       (check-type s simple-string)
  1600.       (incf string-bytes (round-bytes-to-words (1+ (length s)))))
  1601.     ;;
  1602.     ;; Now allocate the memory and fill it in.
  1603.     (let* ((total-bytes (+ string-bytes vec-bytes))
  1604.        (vec-sap (system:allocate-system-memory total-bytes))
  1605.        (string-sap (sap+ vec-sap vec-bytes))
  1606.        (i 0))
  1607.       (declare (type (and unsigned-byte fixnum) total-bytes i)
  1608.            (type system:system-area-pointer vec-sap string-sap))
  1609.       (dolist (s string-list)
  1610.     (declare (simple-string s))
  1611.     (let ((n (length s)))
  1612.       ;; 
  1613.       ;; Blast the string into place
  1614.       (kernel:copy-to-system-area (the simple-string s)
  1615.                       (* vm:vector-data-offset vm:word-bits)
  1616.                       string-sap 0
  1617.                       (* (1+ n) vm:byte-bits))
  1618.       ;; 
  1619.       ;; Blast the pointer to the string into place
  1620.       (setf (sap-ref-sap vec-sap i) string-sap)
  1621.       (setf string-sap (sap+ string-sap (round-bytes-to-words (1+ n))))
  1622.       (incf i 4)))
  1623.       ;; Blast in last null pointer
  1624.       (setf (sap-ref-sap vec-sap i) (int-sap 0))
  1625.       (values vec-sap total-bytes))))
  1626.  
  1627. (defun sub-unix-execve (program arg-list env-list)
  1628.   (let ((argv nil)
  1629.     (argv-bytes 0)
  1630.     (envp nil)
  1631.     (envp-bytes 0)
  1632.     result error-code)
  1633.     (unwind-protect
  1634.     (progn
  1635.       ;; Blast the stuff into the proper format
  1636.       (multiple-value-setq
  1637.           (argv argv-bytes)
  1638.         (string-list-to-c-strvec arg-list))
  1639.       (multiple-value-setq
  1640.           (envp envp-bytes)
  1641.         (string-list-to-c-strvec env-list))
  1642.       ;;
  1643.       ;; Now do the system call
  1644.       (multiple-value-setq
  1645.           (result error-code)
  1646.         (int-syscall ("execve"
  1647.               (* char) system-area-pointer system-area-pointer)
  1648.              (vector-sap program) argv envp)))
  1649.       ;; 
  1650.       ;; Deallocate memory
  1651.       (when argv
  1652.     (system:deallocate-system-memory argv argv-bytes))
  1653.       (when envp
  1654.     (system:deallocate-system-memory envp envp-bytes)))
  1655.     (values result error-code)))
  1656.  
  1657.  
  1658.  
  1659. ;;;; Socket support.
  1660.  
  1661. (def-alien-routine ("socket" unix-socket) int
  1662.   (domain int)
  1663.   (type int)
  1664.   (protocol int))
  1665.  
  1666. (def-alien-routine ("connect" unix-connect) int
  1667.   (socket int)
  1668.   (sockaddr (* t))
  1669.   (len int))
  1670.  
  1671. (def-alien-routine ("bind" unix-bind) int
  1672.   (socket int)
  1673.   (sockaddr (* t))
  1674.   (len int))
  1675.  
  1676. (def-alien-routine ("listen" unix-listen) int
  1677.   (socket int)
  1678.   (backlog int))
  1679.  
  1680. (def-alien-routine ("accept" unix-accept) int
  1681.   (socket int)
  1682.   (sockaddr (* t))
  1683.   (len int :in-out))
  1684.  
  1685. (def-alien-routine ("recv" unix-recv) int
  1686.   (fd int)
  1687.   (buffer c-string)
  1688.   (length int)
  1689.   (flags int))
  1690.  
  1691. (def-alien-routine ("send" unix-send) int
  1692.   (fd int)
  1693.   (buffer c-string)
  1694.   (length int)
  1695.   (flags int))
  1696.