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
|
|
-;;;
|
7
|
|
-(ext:file-comment
|
8
|
|
- "$Header: src/code/unix-glibc2.lisp $")
|
9
|
|
-;;;
|
10
|
|
-;;; **********************************************************************
|
11
|
|
-;;;
|
12
|
|
-;;; This file contains the UNIX low-level support for glibc2. Based
|
13
|
|
-;;; on unix.lisp 1.56, converted for glibc2 by Peter Van Eynde (1998).
|
14
|
|
-;;; Alpha support by Julian Dolby, 1999.
|
15
|
|
-;;;
|
16
|
|
-;;; All the functions with #+(or) in front are work in progress,
|
17
|
|
-;;; and mostly don't work.
|
18
|
|
-;;;
|
19
|
|
-;; Todo: #+(or)'ed stuff and ioctl's
|
20
|
|
-;;
|
21
|
|
-;;
|
22
|
|
-;; Large File Support (LFS) added by Pierre Mai and Eric Marsden, Feb
|
23
|
|
-;; 2003. This is necessary to be able to read/write/stat files that
|
24
|
|
-;; are larger than 2GB on a 32-bit system. From a C program, defining
|
25
|
|
-;; a preprocessor macro _LARGEFILE64_SOURCE makes the preproccessor
|
26
|
|
-;; replace a call to open() by open64(), and similarly for stat,
|
27
|
|
-;; fstat, lstat, lseek, readdir and friends. Furthermore, certain data
|
28
|
|
-;; types, that are normally 32 bits wide, are replaced by 64-bit wide
|
29
|
|
-;; equivalents: off_t -> off64_t etc. The libc.so fiddles around with
|
30
|
|
-;; weak symbols to support this mess.
|
31
|
|
-;;
|
32
|
|
-;; From CMUCL, we make FFI calls to the xxx64 functions, and use the
|
33
|
|
-;; 64-bit wide versions of the data structures. The most ugly aspect
|
34
|
|
-;; is that some of the stat functions are not available via dlsym, so
|
35
|
|
-;; we reference them explicitly from linux-stubs.S. Another amusing
|
36
|
|
-;; fact is that on glibc 2.2, stat64() returns a struct stat with a
|
37
|
|
-;; 32-bit ino_t, whereas readdir64() returns a struct dirent that
|
38
|
|
-;; contains a 64-bit ino_t. On glibc 2.1, OTOH, both stat64 and
|
39
|
|
-;; readdir64 use structs with 32-bit ino_t.
|
40
|
|
-;;
|
41
|
|
-;; The current version deals with this by going with the glibc 2.2
|
42
|
|
-;; definitions, unless the keyword :glibc2.1 also occurs on *features*,
|
43
|
|
-;; in addition to :glibc2, in which case we go with the glibc 2.1
|
44
|
|
-;; definitions. Note that binaries compiled against glibc 2.1 do in
|
45
|
|
-;; fact work fine on glibc 2.2, because readdir64 is available in both
|
46
|
|
-;; glibc 2.1 and glibc 2.2 versions in glibc 2.2, disambiguated through
|
47
|
|
-;; ELF symbol versioning. We use an entry for readdir64 in linux-stubs.S
|
48
|
|
-;; in order to force usage of the correct version of readdir64 at runtime.
|
49
|
|
-;;
|
50
|
|
-;; So in order to compile for glibc 2.2 and newer, just compile CMUCL
|
51
|
|
-;; on a glibc 2.2 system, and make sure that :glibc2.1 doesn't appear
|
52
|
|
-;; on the *features* list. In order to compile for glibc 2.1 and newer,
|
53
|
|
-;; compile CMUCL on a glibc 2.1 system, and make sure that :glibc2.1 does
|
54
|
|
-;; appear on the *features* list.
|
55
|
|
-
|
56
|
|
-(in-package "UNIX")
|
57
|
|
-(use-package "ALIEN")
|
58
|
|
-(use-package "C-CALL")
|
59
|
|
-(use-package "SYSTEM")
|
60
|
|
-(use-package "EXT")
|
61
|
|
-(intl:textdomain "cmucl-unix-glibc2")
|
62
|
|
-
|
63
|
|
-;; Check the G_BROKEN_FILENAMES environment variable; if set the encoding
|
64
|
|
-;; is locale-dependent...else use :utf-8 on Unicode Lisps. On 8 bit Lisps
|
65
|
|
-;; it must be set to :iso8859-1 (or left as NIL), making files with
|
66
|
|
-;; non-Latin-1 characters "mojibake", but otherwise they'll be inaccessible.
|
67
|
|
-;; Must be set to NIL initially to enable building Lisp!
|
68
|
|
-(defvar *filename-encoding* nil)
|
69
|
|
-
|
70
|
|
-(pushnew :unix *features*)
|
71
|
|
-(pushnew :glibc2 *features*)
|
72
|
|
-
|
73
|
|
-;; needed for bootstrap
|
74
|
|
-(eval-when (:compile-toplevel :load-toplevel :execute)
|
75
|
|
- (defmacro %name->file (string)
|
76
|
|
- `(if *filename-encoding*
|
77
|
|
- (string-encode ,string *filename-encoding*)
|
78
|
|
- ,string))
|
79
|
|
- (defmacro %file->name (string)
|
80
|
|
- `(if *filename-encoding*
|
81
|
|
- (string-decode ,string *filename-encoding*)
|
82
|
|
- ,string)))
|
83
|
|
-
|
84
|
|
-(defconstant +max-u-long+ 4294967295)
|
85
|
|
-
|
86
|
|
-(def-alien-type size-t #-alpha unsigned-int #+alpha long)
|
87
|
|
-(def-alien-type time-t long)
|
88
|
|
-
|
89
|
|
-(def-alien-type uquad-t #+alpha unsigned-long
|
90
|
|
- #-alpha (array unsigned-long 2))
|
91
|
|
-(def-alien-type u-int32-t unsigned-int)
|
92
|
|
-(def-alien-type int64-t (signed 64))
|
93
|
|
-(def-alien-type u-int64-t (unsigned 64))
|
94
|
|
-
|
95
|
|
-(def-alien-type dev-t #-amd64 uquad-t #+amd64 u-int64-t)
|
96
|
|
-(def-alien-type uid-t unsigned-int)
|
97
|
|
-(def-alien-type gid-t unsigned-int)
|
98
|
|
-(def-alien-type ino-t #-amd64 u-int32-t #+amd64 u-int64-t)
|
99
|
|
-(def-alien-type ino64-t u-int64-t)
|
100
|
|
-(def-alien-type mode-t u-int32-t)
|
101
|
|
-(def-alien-type nlink-t #-amd64 unsigned-int #+amd64 u-int64-t)
|
102
|
|
-(def-alien-type off-t int64-t)
|
103
|
|
-(def-alien-type blkcnt-t u-int64-t)
|
104
|
|
-
|
105
|
|
-;;;; Common machine independent structures.
|
106
|
|
-
|
107
|
|
-
|
108
|
|
-;; Needed early in bootstrap.
|
109
|
|
-(defun unix-current-directory ()
|
110
|
|
- _N"Put the absolute pathname of the current working directory in BUF.
|
111
|
|
- If successful, return BUF. If not, put an error message in
|
112
|
|
- BUF and return NULL. BUF should be at least PATH_MAX bytes long."
|
113
|
|
- ;; 5120 is some randomly selected maximum size for the buffer for getcwd.
|
114
|
|
- (with-alien ((buf (array c-call:char 5120)))
|
115
|
|
- (let ((result (alien-funcall
|
116
|
|
- (extern-alien "getcwd"
|
117
|
|
- (function (* c-call:char)
|
118
|
|
- (* c-call:char) c-call:int))
|
119
|
|
- (cast buf (* c-call:char))
|
120
|
|
- 5120)))
|
121
|
|
-
|
122
|
|
- (values (not (zerop (sap-int (alien-sap result))))
|
123
|
|
- (%file->name (cast buf c-call:c-string))))))
|
124
|
|
-
|
125
|
|
-;;; fcntlbits.h
|
126
|
|
-(defconstant o_read o_rdonly _N"Open for reading")
|
127
|
|
-(defconstant o_write o_wronly _N"Open for writing")
|
128
|
|
-
|
129
|
|
-(defconstant o_rdonly 0 _N"Read-only flag.")
|
130
|
|
-(defconstant o_wronly 1 _N"Write-only flag.")
|
131
|
|
-(defconstant o_rdwr 2 _N"Read-write flag.")
|
132
|
|
-(defconstant o_accmode 3 _N"Access mode mask.")
|
133
|
|
-
|
134
|
|
-#-alpha
|
135
|
|
-(progn
|
136
|
|
- (defconstant o_creat #o100 _N"Create if nonexistant flag. (not fcntl)")
|
137
|
|
- (defconstant o_excl #o200 _N"Error if already exists. (not fcntl)")
|
138
|
|
- (defconstant o_noctty #o400 _N"Don't assign controlling tty. (not fcntl)")
|
139
|
|
- (defconstant o_trunc #o1000 _N"Truncate flag. (not fcntl)")
|
140
|
|
- (defconstant o_append #o2000 _N"Append flag.")
|
141
|
|
- (defconstant o_ndelay #o4000 _N"Non-blocking I/O")
|
142
|
|
- (defconstant o_nonblock #o4000 _N"Non-blocking I/O")
|
143
|
|
- (defconstant o_ndelay o_nonblock)
|
144
|
|
- (defconstant o_sync #o10000 _N"Synchronous writes (on ext2)")
|
145
|
|
- (defconstant o_fsync o_sync)
|
146
|
|
- (defconstant o_async #o20000 _N"Asynchronous I/O"))
|
147
|
|
-#+alpha
|
148
|
|
-(progn
|
149
|
|
- (defconstant o_creat #o1000 _N"Create if nonexistant flag. (not fcntl)")
|
150
|
|
- (defconstant o_trunc #o2000 _N"Truncate flag. (not fcntl)")
|
151
|
|
- (defconstant o_excl #o4000 _N"Error if already exists. (not fcntl)")
|
152
|
|
- (defconstant o_noctty #o10000 _N"Don't assign controlling tty. (not fcntl)")
|
153
|
|
- (defconstant o_nonblock #o4 _N"Non-blocking I/O")
|
154
|
|
- (defconstant o_append #o10 _N"Append flag.")
|
155
|
|
- (defconstant o_ndelay o_nonblock)
|
156
|
|
- (defconstant o_sync #o40000 _N"Synchronous writes (on ext2)")
|
157
|
|
- (defconstant o_fsync o_sync)
|
158
|
|
- (defconstant o_async #o20000 _N"Asynchronous I/O"))
|
159
|
|
-
|
160
|
|
-#-alpha
|
161
|
|
-(progn
|
162
|
|
- (defconstant f-getlk 5 _N"Get lock")
|
163
|
|
- (defconstant f-setlk 6 _N"Set lock")
|
164
|
|
- (defconstant f-setlkw 7 _N"Set lock, wait for release")
|
165
|
|
- (defconstant f-setown 8 _N"Set owner (for sockets)")
|
166
|
|
- (defconstant f-getown 9 _N"Get owner (for sockets)"))
|
167
|
|
-#+alpha
|
168
|
|
-(progn
|
169
|
|
- (defconstant f-getlk 7 _N"Get lock")
|
170
|
|
- (defconstant f-setlk 8 _N"Set lock")
|
171
|
|
- (defconstant f-setlkw 9 _N"Set lock, wait for release")
|
172
|
|
- (defconstant f-setown 5 _N"Set owner (for sockets)")
|
173
|
|
- (defconstant f-getown 6 _N"Get owner (for sockets)"))
|
174
|
|
-
|
175
|
|
-(defconstant F-CLOEXEC 1 _N"for f-getfl and f-setfl")
|
176
|
|
-(defun unix-open (path flags mode)
|
177
|
|
- _N"Unix-open opens the file whose pathname is specified by PATH
|
178
|
|
- for reading and/or writing as specified by the FLAGS argument.
|
179
|
|
- Returns an integer file descriptor.
|
180
|
|
- The flags argument can be:
|
181
|
|
-
|
182
|
|
- o_rdonly Read-only flag.
|
183
|
|
- o_wronly Write-only flag.
|
184
|
|
- o_rdwr Read-and-write flag.
|
185
|
|
- o_append Append flag.
|
186
|
|
- o_creat Create-if-nonexistant flag.
|
187
|
|
- o_trunc Truncate-to-size-0 flag.
|
188
|
|
- o_excl Error if the file already exists
|
189
|
|
- o_noctty Don't assign controlling tty
|
190
|
|
- o_ndelay Non-blocking I/O
|
191
|
|
- o_sync Synchronous I/O
|
192
|
|
- o_async Asynchronous I/O
|
193
|
|
-
|
194
|
|
- If the o_creat flag is specified, then the file is created with
|
195
|
|
- a permission of argument MODE if the file doesn't exist."
|
196
|
|
- (declare (type unix-pathname path)
|
197
|
|
- (type fixnum flags)
|
198
|
|
- (type unix-file-mode mode))
|
199
|
|
- (int-syscall ("open64" c-string int int) (%name->file path) flags mode))
|
200
|
|
-
|
201
|
|
-;;; asm/errno.h
|
202
|
|
-(eval-when (compile eval)
|
203
|
|
-
|
204
|
|
-(defparameter *compiler-unix-errors* nil)
|
205
|
|
-
|
206
|
|
-(defmacro def-unix-error (name number description)
|
207
|
|
- `(progn
|
208
|
|
- (eval-when (compile eval)
|
209
|
|
- (push (cons ,number ,description) *compiler-unix-errors*))
|
210
|
|
- (defconstant ,name ,number ,description)
|
211
|
|
- (export ',name)))
|
212
|
|
-
|
213
|
|
-(defmacro emit-unix-errors ()
|
214
|
|
- (let* ((max (apply #'max (mapcar #'car *compiler-unix-errors*)))
|
215
|
|
- (array (make-array (1+ max) :initial-element nil)))
|
216
|
|
- (dolist (error *compiler-unix-errors*)
|
217
|
|
- (setf (svref array (car error)) (cdr error)))
|
218
|
|
- `(progn
|
219
|
|
- (defvar *unix-errors* ',array)
|
220
|
|
- (declaim (simple-vector *unix-errors*)))))
|
221
|
|
-
|
222
|
|
-)
|
223
|
|
-
|
224
|
|
-(def-unix-error ESUCCESS 0 _N"Successful")
|
225
|
|
-(def-unix-error EPERM 1 _N"Operation not permitted")
|
226
|
|
-(def-unix-error ENOENT 2 _N"No such file or directory")
|
227
|
|
-(def-unix-error ESRCH 3 _N"No such process")
|
228
|
|
-(def-unix-error EINTR 4 _N"Interrupted system call")
|
229
|
|
-(def-unix-error EIO 5 _N"I/O error")
|
230
|
|
-(def-unix-error ENXIO 6 _N"No such device or address")
|
231
|
|
-(def-unix-error E2BIG 7 _N"Arg list too long")
|
232
|
|
-(def-unix-error ENOEXEC 8 _N"Exec format error")
|
233
|
|
-(def-unix-error EBADF 9 _N"Bad file number")
|
234
|
|
-(def-unix-error ECHILD 10 _N"No children")
|
235
|
|
-(def-unix-error EAGAIN 11 _N"Try again")
|
236
|
|
-(def-unix-error ENOMEM 12 _N"Out of memory")
|
237
|
|
-(def-unix-error EACCES 13 _N"Permission denied")
|
238
|
|
-(def-unix-error EFAULT 14 _N"Bad address")
|
239
|
|
-(def-unix-error ENOTBLK 15 _N"Block device required")
|
240
|
|
-(def-unix-error EBUSY 16 _N"Device or resource busy")
|
241
|
|
-(def-unix-error EEXIST 17 _N"File exists")
|
242
|
|
-(def-unix-error EXDEV 18 _N"Cross-device link")
|
243
|
|
-(def-unix-error ENODEV 19 _N"No such device")
|
244
|
|
-(def-unix-error ENOTDIR 20 _N"Not a director")
|
245
|
|
-(def-unix-error EISDIR 21 _N"Is a directory")
|
246
|
|
-(def-unix-error EINVAL 22 _N"Invalid argument")
|
247
|
|
-(def-unix-error ENFILE 23 _N"File table overflow")
|
248
|
|
-(def-unix-error EMFILE 24 _N"Too many open files")
|
249
|
|
-(def-unix-error ENOTTY 25 _N"Not a typewriter")
|
250
|
|
-(def-unix-error ETXTBSY 26 _N"Text file busy")
|
251
|
|
-(def-unix-error EFBIG 27 _N"File too large")
|
252
|
|
-(def-unix-error ENOSPC 28 _N"No space left on device")
|
253
|
|
-(def-unix-error ESPIPE 29 _N"Illegal seek")
|
254
|
|
-(def-unix-error EROFS 30 _N"Read-only file system")
|
255
|
|
-(def-unix-error EMLINK 31 _N"Too many links")
|
256
|
|
-(def-unix-error EPIPE 32 _N"Broken pipe")
|
257
|
|
-;;;
|
258
|
|
-;;; Math
|
259
|
|
-(def-unix-error EDOM 33 _N"Math argument out of domain")
|
260
|
|
-(def-unix-error ERANGE 34 _N"Math result not representable")
|
261
|
|
-;;;
|
262
|
|
-(def-unix-error EDEADLK 35 _N"Resource deadlock would occur")
|
263
|
|
-(def-unix-error ENAMETOOLONG 36 _N"File name too long")
|
264
|
|
-(def-unix-error ENOLCK 37 _N"No record locks available")
|
265
|
|
-(def-unix-error ENOSYS 38 _N"Function not implemented")
|
266
|
|
-(def-unix-error ENOTEMPTY 39 _N"Directory not empty")
|
267
|
|
-(def-unix-error ELOOP 40 _N"Too many symbolic links encountered")
|
268
|
|
-(def-unix-error EWOULDBLOCK 11 _N"Operation would block")
|
269
|
|
-(def-unix-error ENOMSG 42 _N"No message of desired type")
|
270
|
|
-(def-unix-error EIDRM 43 _N"Identifier removed")
|
271
|
|
-(def-unix-error ECHRNG 44 _N"Channel number out of range")
|
272
|
|
-(def-unix-error EL2NSYNC 45 _N"Level 2 not synchronized")
|
273
|
|
-(def-unix-error EL3HLT 46 _N"Level 3 halted")
|
274
|
|
-(def-unix-error EL3RST 47 _N"Level 3 reset")
|
275
|
|
-(def-unix-error ELNRNG 48 _N"Link number out of range")
|
276
|
|
-(def-unix-error EUNATCH 49 _N"Protocol driver not attached")
|
277
|
|
-(def-unix-error ENOCSI 50 _N"No CSI structure available")
|
278
|
|
-(def-unix-error EL2HLT 51 _N"Level 2 halted")
|
279
|
|
-(def-unix-error EBADE 52 _N"Invalid exchange")
|
280
|
|
-(def-unix-error EBADR 53 _N"Invalid request descriptor")
|
281
|
|
-(def-unix-error EXFULL 54 _N"Exchange full")
|
282
|
|
-(def-unix-error ENOANO 55 _N"No anode")
|
283
|
|
-(def-unix-error EBADRQC 56 _N"Invalid request code")
|
284
|
|
-(def-unix-error EBADSLT 57 _N"Invalid slot")
|
285
|
|
-(def-unix-error EDEADLOCK EDEADLK _N"File locking deadlock error")
|
286
|
|
-(def-unix-error EBFONT 59 _N"Bad font file format")
|
287
|
|
-(def-unix-error ENOSTR 60 _N"Device not a stream")
|
288
|
|
-(def-unix-error ENODATA 61 _N"No data available")
|
289
|
|
-(def-unix-error ETIME 62 _N"Timer expired")
|
290
|
|
-(def-unix-error ENOSR 63 _N"Out of streams resources")
|
291
|
|
-(def-unix-error ENONET 64 _N"Machine is not on the network")
|
292
|
|
-(def-unix-error ENOPKG 65 _N"Package not installed")
|
293
|
|
-(def-unix-error EREMOTE 66 _N"Object is remote")
|
294
|
|
-(def-unix-error ENOLINK 67 _N"Link has been severed")
|
295
|
|
-(def-unix-error EADV 68 _N"Advertise error")
|
296
|
|
-(def-unix-error ESRMNT 69 _N"Srmount error")
|
297
|
|
-(def-unix-error ECOMM 70 _N"Communication error on send")
|
298
|
|
-(def-unix-error EPROTO 71 _N"Protocol error")
|
299
|
|
-(def-unix-error EMULTIHOP 72 _N"Multihop attempted")
|
300
|
|
-(def-unix-error EDOTDOT 73 _N"RFS specific error")
|
301
|
|
-(def-unix-error EBADMSG 74 _N"Not a data message")
|
302
|
|
-(def-unix-error EOVERFLOW 75 _N"Value too large for defined data type")
|
303
|
|
-(def-unix-error ENOTUNIQ 76 _N"Name not unique on network")
|
304
|
|
-(def-unix-error EBADFD 77 _N"File descriptor in bad state")
|
305
|
|
-(def-unix-error EREMCHG 78 _N"Remote address changed")
|
306
|
|
-(def-unix-error ELIBACC 79 _N"Can not access a needed shared library")
|
307
|
|
-(def-unix-error ELIBBAD 80 _N"Accessing a corrupted shared library")
|
308
|
|
-(def-unix-error ELIBSCN 81 _N".lib section in a.out corrupted")
|
309
|
|
-(def-unix-error ELIBMAX 82 _N"Attempting to link in too many shared libraries")
|
310
|
|
-(def-unix-error ELIBEXEC 83 _N"Cannot exec a shared library directly")
|
311
|
|
-(def-unix-error EILSEQ 84 _N"Illegal byte sequence")
|
312
|
|
-(def-unix-error ERESTART 85 _N"Interrupted system call should be restarted _N")
|
313
|
|
-(def-unix-error ESTRPIPE 86 _N"Streams pipe error")
|
314
|
|
-(def-unix-error EUSERS 87 _N"Too many users")
|
315
|
|
-(def-unix-error ENOTSOCK 88 _N"Socket operation on non-socket")
|
316
|
|
-(def-unix-error EDESTADDRREQ 89 _N"Destination address required")
|
317
|
|
-(def-unix-error EMSGSIZE 90 _N"Message too long")
|
318
|
|
-(def-unix-error EPROTOTYPE 91 _N"Protocol wrong type for socket")
|
319
|
|
-(def-unix-error ENOPROTOOPT 92 _N"Protocol not available")
|
320
|
|
-(def-unix-error EPROTONOSUPPORT 93 _N"Protocol not supported")
|
321
|
|
-(def-unix-error ESOCKTNOSUPPORT 94 _N"Socket type not supported")
|
322
|
|
-(def-unix-error EOPNOTSUPP 95 _N"Operation not supported on transport endpoint")
|
323
|
|
-(def-unix-error EPFNOSUPPORT 96 _N"Protocol family not supported")
|
324
|
|
-(def-unix-error EAFNOSUPPORT 97 _N"Address family not supported by protocol")
|
325
|
|
-(def-unix-error EADDRINUSE 98 _N"Address already in use")
|
326
|
|
-(def-unix-error EADDRNOTAVAIL 99 _N"Cannot assign requested address")
|
327
|
|
-(def-unix-error ENETDOWN 100 _N"Network is down")
|
328
|
|
-(def-unix-error ENETUNREACH 101 _N"Network is unreachable")
|
329
|
|
-(def-unix-error ENETRESET 102 _N"Network dropped connection because of reset")
|
330
|
|
-(def-unix-error ECONNABORTED 103 _N"Software caused connection abort")
|
331
|
|
-(def-unix-error ECONNRESET 104 _N"Connection reset by peer")
|
332
|
|
-(def-unix-error ENOBUFS 105 _N"No buffer space available")
|
333
|
|
-(def-unix-error EISCONN 106 _N"Transport endpoint is already connected")
|
334
|
|
-(def-unix-error ENOTCONN 107 _N"Transport endpoint is not connected")
|
335
|
|
-(def-unix-error ESHUTDOWN 108 _N"Cannot send after transport endpoint shutdown")
|
336
|
|
-(def-unix-error ETOOMANYREFS 109 _N"Too many references: cannot splice")
|
337
|
|
-(def-unix-error ETIMEDOUT 110 _N"Connection timed out")
|
338
|
|
-(def-unix-error ECONNREFUSED 111 _N"Connection refused")
|
339
|
|
-(def-unix-error EHOSTDOWN 112 _N"Host is down")
|
340
|
|
-(def-unix-error EHOSTUNREACH 113 _N"No route to host")
|
341
|
|
-(def-unix-error EALREADY 114 _N"Operation already in progress")
|
342
|
|
-(def-unix-error EINPROGRESS 115 _N"Operation now in progress")
|
343
|
|
-(def-unix-error ESTALE 116 _N"Stale NFS file handle")
|
344
|
|
-(def-unix-error EUCLEAN 117 _N"Structure needs cleaning")
|
345
|
|
-(def-unix-error ENOTNAM 118 _N"Not a XENIX named type file")
|
346
|
|
-(def-unix-error ENAVAIL 119 _N"No XENIX semaphores available")
|
347
|
|
-(def-unix-error EISNAM 120 _N"Is a named type file")
|
348
|
|
-(def-unix-error EREMOTEIO 121 _N"Remote I/O error")
|
349
|
|
-(def-unix-error EDQUOT 122 _N"Quota exceeded")
|
350
|
|
-
|
351
|
|
-;;; And now for something completely different ...
|
352
|
|
-(emit-unix-errors)
|
353
|
|
-
|
354
|
|
-(def-alien-type nil
|
355
|
|
- (struct passwd
|
356
|
|
- (pw-name (* char)) ; user's login name
|
357
|
|
- (pw-passwd (* char)) ; no longer used
|
358
|
|
- (pw-uid uid-t) ; user id
|
359
|
|
- (pw-gid gid-t) ; group id
|
360
|
|
- (pw-gecos (* char)) ; typically user's full name
|
361
|
|
- (pw-dir (* char)) ; user's home directory
|
362
|
|
- (pw-shell (* char)))) ; user's login shell
|
363
|
|
-
|
364
|
|
-;;;; System calls.
|
365
|
|
-
|
366
|
|
-(def-alien-routine ("os_get_errno" unix-get-errno) int)
|
367
|
|
-(def-alien-routine ("os_set_errno" unix-set-errno) int (newvalue int))
|
368
|
|
-(defun unix-errno () (unix-get-errno))
|
369
|
|
-(defun (setf unix-errno) (newvalue) (unix-set-errno newvalue))
|
370
|
|
-
|
371
|
|
-;;; GET-UNIX-ERROR-MSG -- public.
|
372
|
|
-;;;
|
373
|
|
-(defun get-unix-error-msg (&optional (error-number (unix-errno)))
|
374
|
|
- _N"Returns a string describing the error number which was returned by a
|
375
|
|
- UNIX system call."
|
376
|
|
- (declare (type integer error-number))
|
377
|
|
-
|
378
|
|
- (if (array-in-bounds-p *unix-errors* error-number)
|
379
|
|
- (svref *unix-errors* error-number)
|
380
|
|
- (format nil (intl:gettext "Unknown error [~d]") error-number)))
|
381
|
|
-
|
382
|
|
-(defmacro syscall ((name &rest arg-types) success-form &rest args)
|
383
|
|
- `(let ((result (alien-funcall (extern-alien ,name (function int ,@arg-types))
|
384
|
|
- ,@args)))
|
385
|
|
- (if (minusp result)
|
386
|
|
- (values nil (unix-errno))
|
387
|
|
- ,success-form)))
|
388
|
|
-
|
389
|
|
-;;; Like syscall, but if it fails, signal an error instead of returning error
|
390
|
|
-;;; codes. Should only be used for syscalls that will never really get an
|
391
|
|
-;;; error.
|
392
|
|
-;;;
|
393
|
|
-(defmacro syscall* ((name &rest arg-types) success-form &rest args)
|
394
|
|
- `(let ((result (alien-funcall (extern-alien ,name (function int ,@arg-types))
|
395
|
|
- ,@args)))
|
396
|
|
- (if (minusp result)
|
397
|
|
- (error (intl:gettext "Syscall ~A failed: ~A") ,name (get-unix-error-msg))
|
398
|
|
- ,success-form)))
|
399
|
|
-
|
400
|
|
-(defmacro void-syscall ((name &rest arg-types) &rest args)
|
401
|
|
- `(syscall (,name ,@arg-types) (values t 0) ,@args))
|
402
|
|
-
|
403
|
|
-(defmacro int-syscall ((name &rest arg-types) &rest args)
|
404
|
|
- `(syscall (,name ,@arg-types) (values result 0) ,@args))
|
405
|
|
-
|
406
|
|
-;;; Unix-write accepts a file descriptor, a buffer, an offset, and the
|
407
|
|
-;;; length to write. It attempts to write len bytes to the device
|
408
|
|
-;;; associated with fd from the the buffer starting at offset. It returns
|
409
|
|
-;;; the actual number of bytes written.
|
410
|
|
-
|
411
|
|
-(defun unix-write (fd buf offset len)
|
412
|
|
- _N"Unix-write attempts to write a character buffer (buf) of length
|
413
|
|
- len to the file described by the file descriptor fd. NIL and an
|
414
|
|
- error is returned if the call is unsuccessful."
|
415
|
|
- (declare (type unix-fd fd)
|
416
|
|
- (type (unsigned-byte 32) offset len))
|
417
|
|
- (int-syscall ("write" int (* char) int)
|
418
|
|
- fd
|
419
|
|
- (with-alien ((ptr (* char) (etypecase buf
|
420
|
|
- ((simple-array * (*))
|
421
|
|
- (vector-sap buf))
|
422
|
|
- (system-area-pointer
|
423
|
|
- buf))))
|
424
|
|
- (addr (deref ptr offset)))
|
425
|
|
- len))
|
426
|
|
-
|
427
|
|
-(defun unix-pipe ()
|
428
|
|
- _N"Unix-pipe sets up a unix-piping mechanism consisting of
|
429
|
|
- an input pipe and an output pipe. Unix-Pipe returns two
|
430
|
|
- values: if no error occurred the first value is the pipe
|
431
|
|
- to be read from and the second is can be written to. If
|
432
|
|
- an error occurred the first value is NIL and the second
|
433
|
|
- the unix error code."
|
434
|
|
- (with-alien ((fds (array int 2)))
|
435
|
|
- (syscall ("pipe" (* int))
|
436
|
|
- (values (deref fds 0) (deref fds 1))
|
437
|
|
- (cast fds (* int)))))
|
438
|
|
-
|
439
|
|
-;;; UNIX-READ accepts a file descriptor, a buffer, and the length to read.
|
440
|
|
-;;; It attempts to read len bytes from the device associated with fd
|
441
|
|
-;;; and store them into the buffer. It returns the actual number of
|
442
|
|
-;;; bytes read.
|
443
|
|
-
|
444
|
|
-(defun unix-read (fd buf len)
|
445
|
|
- _N"UNIX-READ attempts to read from the file described by fd into
|
446
|
|
- the buffer buf until it is full. Len is the length of the buffer.
|
447
|
|
- The number of bytes actually read is returned or NIL and an error
|
448
|
|
- number if an error occured."
|
449
|
|
- (declare (type unix-fd fd)
|
450
|
|
- (type (unsigned-byte 32) len))
|
451
|
|
- #+gencgc
|
452
|
|
- ;; With gencgc, the collector tries to keep raw objects like strings
|
453
|
|
- ;; in separate pages that are not write-protected. However, this
|
454
|
|
- ;; isn't always true. Thus, BUF will sometimes be write-protected
|
455
|
|
- ;; and the kernel doesn't like writing to write-protected pages. So
|
456
|
|
- ;; go through and touch each page to give the segv handler a chance
|
457
|
|
- ;; to unprotect the pages. (This is taken from unix.lisp.)
|
458
|
|
- (without-gcing
|
459
|
|
- (let* ((page-size (get-page-size))
|
460
|
|
- (1-page-size (1- page-size))
|
461
|
|
- (sap (etypecase buf
|
462
|
|
- (system-area-pointer buf)
|
463
|
|
- (vector (vector-sap buf))))
|
464
|
|
- (end (sap+ sap len)))
|
465
|
|
- (declare (type (and fixnum unsigned-byte) page-size 1-page-size)
|
466
|
|
- (type system-area-pointer sap end)
|
467
|
|
- (optimize (speed 3) (safety 0)))
|
468
|
|
- ;; Touch the beginning of every page
|
469
|
|
- (do ((sap (int-sap (logand (sap-int sap)
|
470
|
|
- (logxor 1-page-size (ldb (byte 32 0) -1))))
|
471
|
|
- (sap+ sap page-size)))
|
472
|
|
- ((sap>= sap end))
|
473
|
|
- (declare (type system-area-pointer sap))
|
474
|
|
- (setf (sap-ref-8 sap 0) (sap-ref-8 sap 0)))))
|
475
|
|
- (int-syscall ("read" int (* char) int) fd buf len))
|
476
|
|
-
|
477
|
|
-;;; Unix-getpagesize returns the number of bytes in the system page.
|
478
|
|
-
|
479
|
|
-(defun unix-getpagesize ()
|
480
|
|
- _N"Unix-getpagesize returns the number of bytes in a system page."
|
481
|
|
- (int-syscall ("getpagesize")))
|
482
|
|
-
|
483
|
|
-;;; sys/stat.h
|
484
|
|
-
|
485
|
|
-(defmacro extract-stat-results (buf)
|
486
|
|
- `(values T
|
487
|
|
- #+(or alpha amd64)
|
488
|
|
- (slot ,buf 'st-dev)
|
489
|
|
- #-(or alpha amd64)
|
490
|
|
- (+ (deref (slot ,buf 'st-dev) 0)
|
491
|
|
- (* (+ +max-u-long+ 1)
|
492
|
|
- (deref (slot ,buf 'st-dev) 1))) ;;; let's hope this works..
|
493
|
|
- (slot ,buf 'st-ino)
|
494
|
|
- (slot ,buf 'st-mode)
|
495
|
|
- (slot ,buf 'st-nlink)
|
496
|
|
- (slot ,buf 'st-uid)
|
497
|
|
- (slot ,buf 'st-gid)
|
498
|
|
- #+(or alpha amd64)
|
499
|
|
- (slot ,buf 'st-rdev)
|
500
|
|
- #-(or alpha amd64)
|
501
|
|
- (+ (deref (slot ,buf 'st-rdev) 0)
|
502
|
|
- (* (+ +max-u-long+ 1)
|
503
|
|
- (deref (slot ,buf 'st-rdev) 1))) ;;; let's hope this works..
|
504
|
|
- (slot ,buf 'st-size)
|
505
|
|
- (slot ,buf 'st-atime)
|
506
|
|
- (slot ,buf 'st-mtime)
|
507
|
|
- (slot ,buf 'st-ctime)
|
508
|
|
- (slot ,buf 'st-blksize)
|
509
|
|
- (slot ,buf 'st-blocks)))
|
510
|
|
-
|
511
|
|
-;;; bits/stat.h
|
512
|
|
-
|
513
|
|
-(def-alien-type nil
|
514
|
|
- (struct stat
|
515
|
|
- (st-dev dev-t)
|
516
|
|
- #-(or alpha amd64) (st-pad1 unsigned-short)
|
517
|
|
- (st-ino ino-t)
|
518
|
|
- #+alpha (st-pad1 unsigned-int)
|
519
|
|
- #-amd64 (st-mode mode-t)
|
520
|
|
- (st-nlink nlink-t)
|
521
|
|
- #+amd64 (st-mode mode-t)
|
522
|
|
- (st-uid uid-t)
|
523
|
|
- (st-gid gid-t)
|
524
|
|
- (st-rdev dev-t)
|
525
|
|
- #-alpha (st-pad2 unsigned-short)
|
526
|
|
- (st-size off-t)
|
527
|
|
- #-alpha (st-blksize unsigned-long)
|
528
|
|
- #-alpha (st-blocks blkcnt-t)
|
529
|
|
- (st-atime time-t)
|
530
|
|
- #-alpha (unused-1 unsigned-long)
|
531
|
|
- (st-mtime time-t)
|
532
|
|
- #-alpha (unused-2 unsigned-long)
|
533
|
|
- (st-ctime time-t)
|
534
|
|
- #+alpha (st-blocks int)
|
535
|
|
- #+alpha (st-pad2 unsigned-int)
|
536
|
|
- #+alpha (st-blksize unsigned-int)
|
537
|
|
- #+alpha (st-flags unsigned-int)
|
538
|
|
- #+alpha (st-gen unsigned-int)
|
539
|
|
- #+alpha (st-pad3 unsigned-int)
|
540
|
|
- #+alpha (unused-1 unsigned-long)
|
541
|
|
- #+alpha (unused-2 unsigned-long)
|
542
|
|
- (unused-3 unsigned-long)
|
543
|
|
- (unused-4 unsigned-long)
|
544
|
|
- #-alpha (unused-5 unsigned-long)))
|
545
|
|
-
|
546
|
|
-(defun unix-stat (name)
|
547
|
|
- _N"UNIX-STAT retrieves information about the specified
|
548
|
|
- file returning them in the form of multiple values.
|
549
|
|
- See the UNIX Programmer's Manual for a description
|
550
|
|
- of the values returned. If the call fails, then NIL
|
551
|
|
- and an error number is returned instead."
|
552
|
|
- (declare (type unix-pathname name))
|
553
|
|
- (when (string= name "")
|
554
|
|
- (setf name "."))
|
555
|
|
- (with-alien ((buf (struct stat)))
|
556
|
|
- (syscall ("stat64" c-string (* (struct stat)))
|
557
|
|
- (extract-stat-results buf)
|
558
|
|
- (%name->file name) (addr buf))))
|
559
|
|
-
|
560
|
|
-(defun unix-fstat (fd)
|
561
|
|
- _N"UNIX-FSTAT is similar to UNIX-STAT except the file is specified
|
562
|
|
- by the file descriptor FD."
|
563
|
|
- (declare (type unix-fd fd))
|
564
|
|
- (with-alien ((buf (struct stat)))
|
565
|
|
- (syscall ("fstat64" int (* (struct stat)))
|
566
|
|
- (extract-stat-results buf)
|
567
|
|
- fd (addr buf))))
|
568
|
|
-
|
569
|
|
-(defun unix-lstat (name)
|
570
|
|
- _N"UNIX-LSTAT is similar to UNIX-STAT except the specified
|
571
|
|
- file must be a symbolic link."
|
572
|
|
- (declare (type unix-pathname name))
|
573
|
|
- (with-alien ((buf (struct stat)))
|
574
|
|
- (syscall ("lstat64" c-string (* (struct stat)))
|
575
|
|
- (extract-stat-results buf)
|
576
|
|
- (%name->file name) (addr buf))))
|
577
|
|
-
|
578
|
|
-;; Encoding of the file mode.
|
579
|
|
-
|
580
|
|
-(defconstant s-ifmt #o0170000 _N"These bits determine file type.")
|
581
|
|
-
|
582
|
|
-;; File types.
|
583
|
|
-
|
584
|
|
-(defconstant s-ififo #o0010000 _N"FIFO")
|
585
|
|
-(defconstant s-ifchr #o0020000 _N"Character device")
|
586
|
|
-(defconstant s-ifdir #o0040000 _N"Directory")
|
587
|
|
-(defconstant s-ifblk #o0060000 _N"Block device")
|
588
|
|
-(defconstant s-ifreg #o0100000 _N"Regular file")
|
589
|
|
-
|
590
|
|
-;; These don't actually exist on System V, but having them doesn't hurt.
|
591
|
|
-
|
592
|
|
-(defconstant s-iflnk #o0120000 _N"Symbolic link.")
|
593
|
|
-(defconstant s-ifsock #o0140000 _N"Socket.")
|
594
|
|
-(defun unix-file-kind (name &optional check-for-links)
|
595
|
|
- _N"Returns either :file, :directory, :link, :special, or NIL."
|
596
|
|
- (declare (simple-string name))
|
597
|
|
- (multiple-value-bind (res dev ino mode)
|
598
|
|
- (if check-for-links
|
599
|
|
- (unix-lstat name)
|
600
|
|
- (unix-stat name))
|
601
|
|
- (declare (type (or fixnum null) mode)
|
602
|
|
- (ignore dev ino))
|
603
|
|
- (when res
|
604
|
|
- (let ((kind (logand mode s-ifmt)))
|
605
|
|
- (cond ((eql kind s-ifdir) :directory)
|
606
|
|
- ((eql kind s-ifreg) :file)
|
607
|
|
- ((eql kind s-iflnk) :link)
|
608
|
|
- (t :special))))))
|
609
|
|
-
|
610
|
|
-(defun unix-maybe-prepend-current-directory (name)
|
611
|
|
- (declare (simple-string name))
|
612
|
|
- (if (and (> (length name) 0) (char= (schar name 0) #\/))
|
613
|
|
- name
|
614
|
|
- (multiple-value-bind (win dir) (unix-current-directory)
|
615
|
|
- (if win
|
616
|
|
- (concatenate 'simple-string dir "/" name)
|
617
|
|
- name))))
|
618
|
|
-
|
619
|
|
-;; Values for the second argument to access.
|
620
|
|
-
|
621
|
|
-;;; Unix-access accepts a path and a mode. It returns two values the
|
622
|
|
-;;; first is T if the file is accessible and NIL otherwise. The second
|
623
|
|
-;;; only has meaning in the second case and is the unix errno value.
|
624
|
|
-
|
625
|
|
-(defun unix-access (path mode)
|
626
|
|
- _N"Given a file path (a string) and one of four constant modes,
|
627
|
|
- unix-access returns T if the file is accessible with that
|
628
|
|
- mode and NIL if not. It also returns an errno value with
|
629
|
|
- NIL which determines why the file was not accessible.
|
630
|
|
-
|
631
|
|
- The access modes are:
|
632
|
|
- r_ok Read permission.
|
633
|
|
- w_ok Write permission.
|
634
|
|
- x_ok Execute permission.
|
635
|
|
- f_ok Presence of file."
|
636
|
|
- (declare (type unix-pathname path)
|
637
|
|
- (type (mod 8) mode))
|
638
|
|
- (void-syscall ("access" c-string int) (%name->file path) mode))
|
639
|
|
-
|
640
|
|
-(defconstant l_set 0 _N"set the file pointer")
|
641
|
|
-(defconstant l_incr 1 _N"increment the file pointer")
|
642
|
|
-(defconstant l_xtnd 2 _N"extend the file size")
|
643
|
|
-
|
644
|
|
-(defun unix-lseek (fd offset whence)
|
645
|
|
- _N"UNIX-LSEEK accepts a file descriptor and moves the file pointer ahead
|
646
|
|
- a certain OFFSET for that file. WHENCE can be any of the following:
|
647
|
|
-
|
648
|
|
- l_set Set the file pointer.
|
649
|
|
- l_incr Increment the file pointer.
|
650
|
|
- l_xtnd Extend the file size.
|
651
|
|
- "
|
652
|
|
- (declare (type unix-fd fd)
|
653
|
|
- (type (signed-byte 64) offset)
|
654
|
|
- (type (integer 0 2) whence))
|
655
|
|
- (let ((result (alien-funcall
|
656
|
|
- (extern-alien "lseek64" (function off-t int off-t int))
|
657
|
|
- fd offset whence)))
|
658
|
|
- (if (minusp result)
|
659
|
|
- (values nil (unix-errno))
|
660
|
|
- (values result 0))))
|
661
|
|
-;;; Unix-close accepts a file descriptor and attempts to close the file
|
662
|
|
-;;; associated with it.
|
663
|
|
-
|
664
|
|
-(defun unix-close (fd)
|
665
|
|
- _N"Unix-close takes an integer file descriptor as an argument and
|
666
|
|
- closes the file associated with it. T is returned upon successful
|
667
|
|
- completion, otherwise NIL and an error number."
|
668
|
|
- (declare (type unix-fd fd))
|
669
|
|
- (void-syscall ("close" int) fd))
|
670
|
|
-
|
671
|
|
-;;; Unix-creat accepts a file name and a mode. It creates a new file
|
672
|
|
-;;; with name and sets it mode to mode (as for chmod).
|
673
|
|
-
|
674
|
|
-(defun unix-creat (name mode)
|
675
|
|
- _N"Unix-creat accepts a file name and a mode (same as those for
|
676
|
|
- unix-chmod) and creates a file by that name with the specified
|
677
|
|
- permission mode. It returns a file descriptor on success,
|
678
|
|
- or NIL and an error number otherwise.
|
679
|
|
-
|
680
|
|
- This interface is made obsolete by UNIX-OPEN."
|
681
|
|
-
|
682
|
|
- (declare (type unix-pathname name)
|
683
|
|
- (type unix-file-mode mode))
|
684
|
|
- (int-syscall ("creat64" c-string int) (%name->file name) mode))
|
685
|
|
-
|
686
|
|
-(defun unix-resolve-links (pathname)
|
687
|
|
- _N"Returns the pathname with all symbolic links resolved."
|
688
|
|
- (declare (simple-string pathname))
|
689
|
|
- (let ((len (length pathname))
|
690
|
|
- (pending pathname))
|
691
|
|
- (declare (fixnum len) (simple-string pending))
|
692
|
|
- (if (zerop len)
|
693
|
|
- pathname
|
694
|
|
- (let ((result (make-string 100 :initial-element (code-char 0)))
|
695
|
|
- (fill-ptr 0)
|
696
|
|
- (name-start 0))
|
697
|
|
- (loop
|
698
|
|
- (let* ((name-end (or (position #\/ pending :start name-start) len))
|
699
|
|
- (new-fill-ptr (+ fill-ptr (- name-end name-start))))
|
700
|
|
- ;; grow the result string, if necessary. the ">=" (instead of
|
701
|
|
- ;; using ">") allows for the trailing "/" if we find this
|
702
|
|
- ;; component is a directory.
|
703
|
|
- (when (>= new-fill-ptr (length result))
|
704
|
|
- (let ((longer (make-string (* 3 (length result))
|
705
|
|
- :initial-element (code-char 0))))
|
706
|
|
- (replace longer result :end1 fill-ptr)
|
707
|
|
- (setq result longer)))
|
708
|
|
- (replace result pending
|
709
|
|
- :start1 fill-ptr
|
710
|
|
- :end1 new-fill-ptr
|
711
|
|
- :start2 name-start
|
712
|
|
- :end2 name-end)
|
713
|
|
- (let ((kind (unix-file-kind (if (zerop name-end) "/" result) t)))
|
714
|
|
- (unless kind (return nil))
|
715
|
|
- (cond ((eq kind :link)
|
716
|
|
- (multiple-value-bind (link err) (unix-readlink result)
|
717
|
|
- (unless link
|
718
|
|
- (error (intl:gettext "Error reading link ~S: ~S")
|
719
|
|
- (subseq result 0 fill-ptr)
|
720
|
|
- (get-unix-error-msg err)))
|
721
|
|
- (cond ((or (zerop (length link))
|
722
|
|
- (char/= (schar link 0) #\/))
|
723
|
|
- ;; It's a relative link
|
724
|
|
- (fill result (code-char 0)
|
725
|
|
- :start fill-ptr
|
726
|
|
- :end new-fill-ptr))
|
727
|
|
- ((string= result "/../" :end1 4)
|
728
|
|
- ;; It's across the super-root.
|
729
|
|
- (let ((slash (or (position #\/ result :start 4)
|
730
|
|
- 0)))
|
731
|
|
- (fill result (code-char 0)
|
732
|
|
- :start slash
|
733
|
|
- :end new-fill-ptr)
|
734
|
|
- (setf fill-ptr slash)))
|
735
|
|
- (t
|
736
|
|
- ;; It's absolute.
|
737
|
|
- (and (> (length link) 0)
|
738
|
|
- (char= (schar link 0) #\/))
|
739
|
|
- (fill result (code-char 0) :end new-fill-ptr)
|
740
|
|
- (setf fill-ptr 0)))
|
741
|
|
- (setf pending
|
742
|
|
- (if (= name-end len)
|
743
|
|
- link
|
744
|
|
- (concatenate 'simple-string
|
745
|
|
- link
|
746
|
|
- (subseq pending name-end))))
|
747
|
|
- (setf len (length pending))
|
748
|
|
- (setf name-start 0)))
|
749
|
|
- ((= name-end len)
|
750
|
|
- (when (eq kind :directory)
|
751
|
|
- (setf (schar result new-fill-ptr) #\/)
|
752
|
|
- (incf new-fill-ptr))
|
753
|
|
- (return (subseq result 0 new-fill-ptr)))
|
754
|
|
- ((eq kind :directory)
|
755
|
|
- (setf (schar result new-fill-ptr) #\/)
|
756
|
|
- (setf fill-ptr (1+ new-fill-ptr))
|
757
|
|
- (setf name-start (1+ name-end)))
|
758
|
|
- (t
|
759
|
|
- (return nil))))))))))
|
760
|
|
-
|
761
|
|
-(defun unix-simplify-pathname (src)
|
762
|
|
- (declare (simple-string src))
|
763
|
|
- (let* ((src-len (length src))
|
764
|
|
- (dst (make-string src-len))
|
765
|
|
- (dst-len 0)
|
766
|
|
- (dots 0)
|
767
|
|
- (last-slash nil))
|
768
|
|
- (macrolet ((deposit (char)
|
769
|
|
- `(progn
|
770
|
|
- (setf (schar dst dst-len) ,char)
|
771
|
|
- (incf dst-len))))
|
772
|
|
- (dotimes (src-index src-len)
|
773
|
|
- (let ((char (schar src src-index)))
|
774
|
|
- (cond ((char= char #\.)
|
775
|
|
- (when dots
|
776
|
|
- (incf dots))
|
777
|
|
- (deposit char))
|
778
|
|
- ((char= char #\/)
|
779
|
|
- (case dots
|
780
|
|
- (0
|
781
|
|
- ;; Either ``/...' or ``...//...'
|
782
|
|
- (unless last-slash
|
783
|
|
- (setf last-slash dst-len)
|
784
|
|
- (deposit char)))
|
785
|
|
- (1
|
786
|
|
- ;; Either ``./...'' or ``..././...''
|
787
|
|
- (decf dst-len))
|
788
|
|
- (2
|
789
|
|
- ;; We've found ..
|
790
|
|
- (cond
|
791
|
|
- ((and last-slash (not (zerop last-slash)))
|
792
|
|
- ;; There is something before this ..
|
793
|
|
- (let ((prev-prev-slash
|
794
|
|
- (position #\/ dst :end last-slash :from-end t)))
|
795
|
|
- (cond ((and (= (+ (or prev-prev-slash 0) 2)
|
796
|
|
- last-slash)
|
797
|
|
- (char= (schar dst (- last-slash 2)) #\.)
|
798
|
|
- (char= (schar dst (1- last-slash)) #\.))
|
799
|
|
- ;; The something before this .. is another ..
|
800
|
|
- (deposit char)
|
801
|
|
- (setf last-slash dst-len))
|
802
|
|
- (t
|
803
|
|
- ;; The something is some random dir.
|
804
|
|
- (setf dst-len
|
805
|
|
- (if prev-prev-slash
|
806
|
|
- (1+ prev-prev-slash)
|
807
|
|
- 0))
|
808
|
|
- (setf last-slash prev-prev-slash)))))
|
809
|
|
- (t
|
810
|
|
- ;; There is nothing before this .., so we need to keep it
|
811
|
|
- (setf last-slash dst-len)
|
812
|
|
- (deposit char))))
|
813
|
|
- (t
|
814
|
|
- ;; Something other than a dot between slashes.
|
815
|
|
- (setf last-slash dst-len)
|
816
|
|
- (deposit char)))
|
817
|
|
- (setf dots 0))
|
818
|
|
- (t
|
819
|
|
- (setf dots nil)
|
820
|
|
- (setf (schar dst dst-len) char)
|
821
|
|
- (incf dst-len))))))
|
822
|
|
- (when (and last-slash (not (zerop last-slash)))
|
823
|
|
- (case dots
|
824
|
|
- (1
|
825
|
|
- ;; We've got ``foobar/.''
|
826
|
|
- (decf dst-len))
|
827
|
|
- (2
|
828
|
|
- ;; We've got ``foobar/..''
|
829
|
|
- (unless (and (>= last-slash 2)
|
830
|
|
- (char= (schar dst (1- last-slash)) #\.)
|
831
|
|
- (char= (schar dst (- last-slash 2)) #\.)
|
832
|
|
- (or (= last-slash 2)
|
833
|
|
- (char= (schar dst (- last-slash 3)) #\/)))
|
834
|
|
- (let ((prev-prev-slash
|
835
|
|
- (position #\/ dst :end last-slash :from-end t)))
|
836
|
|
- (if prev-prev-slash
|
837
|
|
- (setf dst-len (1+ prev-prev-slash))
|
838
|
|
- (return-from unix-simplify-pathname "./")))))))
|
839
|
|
- (cond ((zerop dst-len)
|
840
|
|
- "./")
|
841
|
|
- ((= dst-len src-len)
|
842
|
|
- dst)
|
843
|
|
- (t
|
844
|
|
- (subseq dst 0 dst-len)))))
|
845
|
|
-
|
846
|
|
-(defun unix-gethostname ()
|
847
|
|
- _N"Unix-gethostname returns the name of the host machine as a string."
|
848
|
|
- (with-alien ((buf (array char 256)))
|
849
|
|
- (syscall* ("gethostname" (* char) int)
|
850
|
|
- (cast buf c-string)
|
851
|
|
- (cast buf (* char)) 256)))
|
852
|
|
-
|
853
|
|
-;;; Unix-dup returns a duplicate copy of the existing file-descriptor
|
854
|
|
-;;; passed as an argument.
|
855
|
|
-
|
856
|
|
-(defun unix-dup (fd)
|
857
|
|
- _N"Unix-dup duplicates an existing file descriptor (given as the
|
858
|
|
- argument) and return it. If FD is not a valid file descriptor, NIL
|
859
|
|
- and an error number are returned."
|
860
|
|
- (declare (type unix-fd fd))
|
861
|
|
- (int-syscall ("dup" int) fd))
|
862
|
|
-
|
863
|
|
-;;; Unix-dup2 makes the second file-descriptor describe the same file
|
864
|
|
-;;; as the first. If the second file-descriptor points to an open
|
865
|
|
-;;; file, it is first closed. In any case, the second should have a
|
866
|
|
-;;; value which is a valid file-descriptor.
|
867
|
|
-
|
868
|
|
-(defun unix-dup2 (fd1 fd2)
|
869
|
|
- _N"Unix-dup2 duplicates an existing file descriptor just as unix-dup
|
870
|
|
- does only the new value of the duplicate descriptor may be requested
|
871
|
|
- through the second argument. If a file already exists with the
|
872
|
|
- requested descriptor number, it will be closed and the number
|
873
|
|
- assigned to the duplicate."
|
874
|
|
- (declare (type unix-fd fd1 fd2))
|
875
|
|
- (void-syscall ("dup2" int int) fd1 fd2))
|
876
|
|
-
|
877
|
|
-;;; Unix-exit terminates a program.
|
878
|
|
-
|
879
|
|
-(defun unix-exit (&optional (code 0))
|
880
|
|
- _N"Unix-exit terminates the current process with an optional
|
881
|
|
- error code. If successful, the call doesn't return. If
|
882
|
|
- unsuccessful, the call returns NIL and an error number."
|
883
|
|
- (declare (type (signed-byte 32) code))
|
884
|
|
- (void-syscall ("exit" int) code))
|
885
|
|
-
|
886
|
|
-(def-alien-routine ("getuid" unix-getuid) int
|
887
|
|
- _N"Unix-getuid returns the real user-id associated with the
|
888
|
|
- current process.")
|
889
|
|
-
|
890
|
|
-;;; Unix-chdir accepts a directory name and makes that the
|
891
|
|
-;;; current working directory.
|
892
|
|
-
|
893
|
|
-(defun unix-chdir (path)
|
894
|
|
- _N"Given a file path string, unix-chdir changes the current working
|
895
|
|
- directory to the one specified."
|
896
|
|
- (declare (type unix-pathname path))
|
897
|
|
- (void-syscall ("chdir" c-string) (%name->file path)))
|
898
|
|
-
|
899
|
|
-;;; Unix-chmod accepts a path and a mode and changes the mode to the new mode.
|
900
|
|
-
|
901
|
|
-(defun unix-chmod (path mode)
|
902
|
|
- _N"Given a file path string and a constant mode, unix-chmod changes the
|
903
|
|
- permission mode for that file to the one specified. The new mode
|
904
|
|
- can be created by logically OR'ing the following:
|
905
|
|
-
|
906
|
|
- setuidexec Set user ID on execution.
|
907
|
|
- setgidexec Set group ID on execution.
|
908
|
|
- savetext Save text image after execution.
|
909
|
|
- readown Read by owner.
|
910
|
|
- writeown Write by owner.
|
911
|
|
- execown Execute (search directory) by owner.
|
912
|
|
- readgrp Read by group.
|
913
|
|
- writegrp Write by group.
|
914
|
|
- execgrp Execute (search directory) by group.
|
915
|
|
- readoth Read by others.
|
916
|
|
- writeoth Write by others.
|
917
|
|
- execoth Execute (search directory) by others.
|
918
|
|
-
|
919
|
|
- Thus #o444 and (logior unix:readown unix:readgrp unix:readoth)
|
920
|
|
- are equivalent for 'mode. The octal-base is familar to Unix users.
|
921
|
|
-
|
922
|
|
- It returns T on successfully completion; NIL and an error number
|
923
|
|
- otherwise."
|
924
|
|
- (declare (type unix-pathname path)
|
925
|
|
- (type unix-file-mode mode))
|
926
|
|
- (void-syscall ("chmod" c-string int) (%name->file path) mode))
|
927
|
|
-
|
928
|
|
-;;; Unix-fchmod accepts a file descriptor ("fd") and a file protection mode
|
929
|
|
-;;; ("mode") and changes the protection of the file described by "fd" to
|
930
|
|
-;;; "mode".
|
931
|
|
-
|
932
|
|
-(defun unix-fchmod (fd mode)
|
933
|
|
- _N"Given an integer file descriptor and a mode (the same as those
|
934
|
|
- used for unix-chmod), unix-fchmod changes the permission mode
|
935
|
|
- for that file to the one specified. T is returned if the call
|
936
|
|
- was successful."
|
937
|
|
- (declare (type unix-fd fd)
|
938
|
|
- (type unix-file-mode mode))
|
939
|
|
- (void-syscall ("fchmod" int int) fd mode))
|
940
|
|
-
|
941
|
|
-(defun unix-readlink (path)
|
942
|
|
- _N"Unix-readlink invokes the readlink system call on the file name
|
943
|
|
- specified by the simple string path. It returns up to two values:
|
944
|
|
- the contents of the symbolic link if the call is successful, or
|
945
|
|
- NIL and the Unix error number."
|
946
|
|
- (declare (type unix-pathname path))
|
947
|
|
- (with-alien ((buf (array char 1024)))
|
948
|
|
- (syscall ("readlink" c-string (* char) int)
|
949
|
|
- (let ((string (make-string result)))
|
950
|
|
- #-unicode
|
951
|
|
- (kernel:copy-from-system-area
|
952
|
|
- (alien-sap buf) 0
|
953
|
|
- string (* vm:vector-data-offset vm:word-bits)
|
954
|
|
- (* result vm:byte-bits))
|
955
|
|
- #+unicode
|
956
|
|
- (let ((sap (alien-sap buf)))
|
957
|
|
- (dotimes (k result)
|
958
|
|
- (setf (aref string k) (code-char (sap-ref-8 sap k)))))
|
959
|
|
- (%file->name string))
|
960
|
|
- (%name->file path) (cast buf (* char)) 1024)))
|
961
|
|
-
|
962
|
|
-;;; Unix-unlink accepts a name and deletes the directory entry for that
|
963
|
|
-;;; name and the file if this is the last link.
|
964
|
|
-
|
965
|
|
-(defun unix-unlink (name)
|
966
|
|
- _N"Unix-unlink removes the directory entry for the named file.
|
967
|
|
- NIL and an error code is returned if the call fails."
|
968
|
|
- (declare (type unix-pathname name))
|
969
|
|
- (void-syscall ("unlink" c-string) (%name->file name)))
|
970
|
|
-
|
971
|
|
-;;; fcntl.h
|
972
|
|
-;;;
|
973
|
|
-;;; POSIX Standard: 6.5 File Control Operations <fcntl.h>
|
974
|
|
-
|
975
|
|
-(defconstant r_ok 4 _N"Test for read permission")
|
976
|
|
-(defconstant w_ok 2 _N"Test for write permission")
|
977
|
|
-(defconstant x_ok 1 _N"Test for execute permission")
|
978
|
|
-(defconstant f_ok 0 _N"Test for presence of file")
|
979
|
|
-
|
980
|
|
-(defun unix-fcntl (fd cmd arg)
|
981
|
|
- _N"Unix-fcntl manipulates file descriptors accoridng to the
|
982
|
|
- argument CMD which can be one of the following:
|
983
|
|
-
|
984
|
|
- F-DUPFD Duplicate a file descriptor.
|
985
|
|
- F-GETFD Get file descriptor flags.
|
986
|
|
- F-SETFD Set file descriptor flags.
|
987
|
|
- F-GETFL Get file flags.
|
988
|
|
- F-SETFL Set file flags.
|
989
|
|
- F-GETOWN Get owner.
|
990
|
|
- F-SETOWN Set owner.
|
991
|
|
-
|
992
|
|
- The flags that can be specified for F-SETFL are:
|
993
|
|
-
|
994
|
|
- FNDELAY Non-blocking reads.
|
995
|
|
- FAPPEND Append on each write.
|
996
|
|
- FASYNC Signal pgrp when data ready.
|
997
|
|
- FCREAT Create if nonexistant.
|
998
|
|
- FTRUNC Truncate to zero length.
|
999
|
|
- FEXCL Error if already created.
|
1000
|
|
- "
|
1001
|
|
- (declare (type unix-fd fd)
|
1002
|
|
- (type (unsigned-byte 32) cmd)
|
1003
|
|
- (type (unsigned-byte 32) arg))
|
1004
|
|
- (int-syscall ("fcntl" int unsigned-int unsigned-int) fd cmd arg))
|
1005
|
|
-
|
1006
|
|
-;;;; Memory-mapped files
|
1007
|
|
-
|
1008
|
|
-(defconstant +null+ (sys:int-sap 0))
|
1009
|
|
-
|
1010
|
|
-(defconstant prot_read 1)
|
1011
|
|
-(defconstant prot_write 2)
|
1012
|
|
-(defconstant prot_exec 4)
|
1013
|
|
-(defconstant prot_none 0)
|
1014
|
|
-
|
1015
|
|
-(defconstant map_shared 1)
|
1016
|
|
-(defconstant map_private 2)
|
1017
|
|
-(defconstant map_fixed 16)
|
1018
|
|
-(defconstant map_anonymous 32)
|
1019
|
|
-
|
1020
|
|
-(defconstant ms_async 1)
|
1021
|
|
-(defconstant ms_sync 4)
|
1022
|
|
-(defconstant ms_invalidate 2)
|
1023
|
|
-
|
1024
|
|
-;; The return value from mmap that means mmap failed.
|
1025
|
|
-(defconstant map_failed (int-sap (1- (ash 1 vm:word-bits))))
|
1026
|
|
-
|
1027
|
|
-(defun unix-mmap (addr length prot flags fd offset)
|
1028
|
|
- (declare (type (or null system-area-pointer) addr)
|
1029
|
|
- (type (unsigned-byte 32) length)
|
1030
|
|
- (type (integer 1 7) prot)
|
1031
|
|
- (type (unsigned-byte 32) flags)
|
1032
|
|
- (type (or null unix-fd) fd)
|
1033
|
|
- (type (signed-byte 32) offset))
|
1034
|
|
- ;; Can't use syscall, because the address that is returned could be
|
1035
|
|
- ;; "negative". Hence we explicitly check for mmap returning
|
1036
|
|
- ;; MAP_FAILED.
|
1037
|
|
- (let ((result
|
1038
|
|
- (alien-funcall (extern-alien "mmap" (function system-area-pointer
|
1039
|
|
- system-area-pointer
|
1040
|
|
- size-t int int int off-t))
|
1041
|
|
- (or addr +null+) length prot flags (or fd -1) offset)))
|
1042
|
|
- (if (sap= result map_failed)
|
1043
|
|
- (values nil (unix-errno))
|
1044
|
|
- (values result 0))))
|
1045
|
|
-
|
1046
|
|
-(defun unix-munmap (addr length)
|
1047
|
|
- (declare (type system-area-pointer addr)
|
1048
|
|
- (type (unsigned-byte 32) length))
|
1049
|
|
- (syscall ("munmap" system-area-pointer size-t) t addr length))
|
1050
|
|
-
|
1051
|
|
-(defun unix-msync (addr length flags)
|
1052
|
|
- (declare (type system-area-pointer addr)
|
1053
|
|
- (type (unsigned-byte 32) length)
|
1054
|
|
- (type (signed-byte 32) flags))
|
1055
|
|
- (syscall ("msync" system-area-pointer size-t int) t addr length flags))
|
1056
|
|
-
|
1057
|
|
-;;; Unix-rename accepts two files names and renames the first to the second.
|
1058
|
|
-
|
1059
|
|
-(defun unix-rename (name1 name2)
|
1060
|
|
- _N"Unix-rename renames the file with string name1 to the string
|
1061
|
|
- name2. NIL and an error code is returned if an error occured."
|
1062
|
|
- (declare (type unix-pathname name1 name2))
|
1063
|
|
- (void-syscall ("rename" c-string c-string)
|
1064
|
|
- (%name->file name1) (%name->file name2)))
|
1065
|
|
-
|
1066
|
|
-;;; Unix-rmdir accepts a name and removes the associated directory.
|
1067
|
|
-
|
1068
|
|
-(defun unix-rmdir (name)
|
1069
|
|
- _N"Unix-rmdir attempts to remove the directory name. NIL and
|
1070
|
|
- an error number is returned if an error occured."
|
1071
|
|
- (declare (type unix-pathname name))
|
1072
|
|
- (void-syscall ("rmdir" c-string) (%name->file name)))
|
1073
|
|
-
|
1074
|
|
-(def-alien-type fd-mask #-alpha unsigned-long #+alpha unsigned-int)
|
1075
|
|
-
|
1076
|
|
-(defconstant fd-setsize 1024)
|
1077
|
|
-(defconstant nfdbits 32)
|
1078
|
|
-
|
1079
|
|
-(def-alien-type nil
|
1080
|
|
- (struct fd-set
|
1081
|
|
- (fds-bits (array fd-mask #.(/ fd-setsize nfdbits)))))
|
1082
|
|
-
|
1083
|
|
-;; not checked for linux...
|
1084
|
|
-(defmacro fd-clr (offset fd-set)
|
1085
|
|
- (let ((word (gensym))
|
1086
|
|
- (bit (gensym)))
|
1087
|
|
- `(multiple-value-bind (,word ,bit) (floor ,offset nfdbits)
|
1088
|
|
- (setf (deref (slot ,fd-set 'fds-bits) ,word)
|
1089
|
|
- (logand (deref (slot ,fd-set 'fds-bits) ,word)
|
1090
|
|
- (32bit-logical-not
|
1091
|
|
- (truly-the (unsigned-byte 32) (ash 1 ,bit))))))))
|
1092
|
|
-
|
1093
|
|
-;; not checked for linux...
|
1094
|
|
-(defmacro fd-isset (offset fd-set)
|
1095
|
|
- (let ((word (gensym))
|
1096
|
|
- (bit (gensym)))
|
1097
|
|
- `(multiple-value-bind (,word ,bit) (floor ,offset nfdbits)
|
1098
|
|
- (logbitp ,bit (deref (slot ,fd-set 'fds-bits) ,word)))))
|
1099
|
|
-
|
1100
|
|
-;; not checked for linux...
|
1101
|
|
-(defmacro fd-set (offset fd-set)
|
1102
|
|
- (let ((word (gensym))
|
1103
|
|
- (bit (gensym)))
|
1104
|
|
- `(multiple-value-bind (,word ,bit) (floor ,offset nfdbits)
|
1105
|
|
- (setf (deref (slot ,fd-set 'fds-bits) ,word)
|
1106
|
|
- (logior (truly-the (unsigned-byte 32) (ash 1 ,bit))
|
1107
|
|
- (deref (slot ,fd-set 'fds-bits) ,word))))))
|
1108
|
|
-
|
1109
|
|
-;; not checked for linux...
|
1110
|
|
-(defmacro fd-zero (fd-set)
|
1111
|
|
- `(progn
|
1112
|
|
- ,@(loop for index upfrom 0 below (/ fd-setsize nfdbits)
|
1113
|
|
- collect `(setf (deref (slot ,fd-set 'fds-bits) ,index) 0))))
|
1114
|
|
-
|
1115
|
|
-;;; TTY ioctl commands.
|
1116
|
|
-
|
1117
|
|
-(eval-when (compile load eval)
|
1118
|
|
-
|
1119
|
|
-(defconstant iocparm-mask #x3fff)
|
1120
|
|
-(defconstant ioc_void #x00000000)
|
1121
|
|
-(defconstant ioc_out #x40000000)
|
1122
|
|
-(defconstant ioc_in #x80000000)
|
1123
|
|
-(defconstant ioc_inout (logior ioc_in ioc_out))
|
1124
|
|
-
|
1125
|
|
-(defmacro define-ioctl-command (name dev cmd &optional arg parm-type)
|
1126
|
|
- _N"Define an ioctl command. If the optional ARG and PARM-TYPE are given
|
1127
|
|
- then ioctl argument size and direction are included as for ioctls defined
|
1128
|
|
- by _IO, _IOR, _IOW, or _IOWR. If DEV is a character then the ioctl type
|
1129
|
|
- is the characters code, else DEV may be an integer giving the type."
|
1130
|
|
- (let* ((type (if (characterp dev)
|
1131
|
|
- (char-code dev)
|
1132
|
|
- dev))
|
1133
|
|
- (code (logior (ash type 8) cmd)))
|
1134
|
|
- (when arg
|
1135
|
|
- (setf code `(logior (ash (logand (alien-size ,arg :bytes) ,iocparm-mask)
|
1136
|
|
- 16)
|
1137
|
|
- ,code)))
|
1138
|
|
- (when parm-type
|
1139
|
|
- (let ((dir (ecase parm-type
|
1140
|
|
- (:void ioc_void)
|
1141
|
|
- (:in ioc_in)
|
1142
|
|
- (:out ioc_out)
|
1143
|
|
- (:inout ioc_inout))))
|
1144
|
|
- (setf code `(logior ,dir ,code))))
|
1145
|
|
- `(eval-when (eval load compile)
|
1146
|
|
- (defconstant ,name ,code))))
|
1147
|
|
-)
|
1148
|
|
-
|
1149
|
|
-;;; TTY ioctl commands.
|
1150
|
|
-
|
1151
|
|
-(define-ioctl-command TIOCGWINSZ #\T #x13)
|
1152
|
|
-(define-ioctl-command TIOCSWINSZ #\T #x14)
|
1153
|
|
-(define-ioctl-command TIOCNOTTY #\T #x22)
|
1154
|
|
-(define-ioctl-command TIOCSPGRP #\T #x10)
|
1155
|
|
-(define-ioctl-command TIOCGPGRP #\T #x0F)
|
1156
|
|
-
|
1157
|
|
-;;; File ioctl commands.
|
1158
|
|
-(define-ioctl-command FIONREAD #\T #x1B)
|
1159
|
|
-
|
1160
|
|
-;;; ioctl-types.h
|
1161
|
|
-
|
1162
|
|
-(def-alien-type nil
|
1163
|
|
- (struct winsize
|
1164
|
|
- (ws-row unsigned-short) ; rows, in characters
|
1165
|
|
- (ws-col unsigned-short) ; columns, in characters
|
1166
|
|
- (ws-xpixel unsigned-short) ; horizontal size, pixels
|
1167
|
|
- (ws-ypixel unsigned-short))) ; veritical size, pixels
|
1168
|
|
-
|
1169
|
|
-(defconstant f-getfl 3 _N"Get file flags")
|
1170
|
|
-(defconstant f-setfl 4 _N"Set file flags")
|
1171
|
|
-
|
1172
|
|
-;;; Define some more compatibility macros to be backward compatible with
|
1173
|
|
-;;; BSD systems which did not managed to hide these kernel macros.
|
1174
|
|
-
|
1175
|
|
-(defconstant FAPPEND o_append _N"depricated stuff")
|
1176
|
|
-(defconstant FFSYNC o_fsync _N"depricated stuff")
|
1177
|
|
-(defconstant FASYNC o_async _N"depricated stuff")
|
1178
|
|
-(defconstant FNONBLOCK o_nonblock _N"depricated stuff")
|
1179
|
|
-(defconstant FNDELAY o_ndelay _N"depricated stuff")
|
1180
|
|
-
|
1181
|
|
-(defun unix-mprotect (addr length prot)
|
1182
|
|
- (declare (type system-area-pointer addr)
|
1183
|
|
- (type (unsigned-byte 32) length)
|
1184
|
|
- (type (integer 1 7) prot))
|
1185
|
|
- (syscall ("mprotect" system-area-pointer size-t int)
|
1186
|
|
- t addr length prot))
|
1187
|
|
-
|
1188
|
|
-;;;; Lisp types used by syscalls.
|
1189
|
|
-
|
1190
|
|
-(deftype unix-pathname () 'simple-string)
|
1191
|
|
-(deftype unix-fd () `(integer 0 ,most-positive-fixnum))
|
1192
|
|
-
|
1193
|
|
-(deftype unix-file-mode () '(unsigned-byte 32))
|
1194
|
|
-(deftype unix-pid () '(unsigned-byte 32))
|
1195
|
|
-(deftype unix-uid () '(unsigned-byte 32))
|
1196
|
|
-(deftype unix-gid () '(unsigned-byte 32))
|
1197
|
|
-
|
1198
|
|
-;;; Operations on Unix Directories.
|
1199
|
|
-
|
1200
|
|
-;;; direntry.h
|
1201
|
|
-
|
1202
|
|
-(def-alien-type nil
|
1203
|
|
- (struct dirent
|
1204
|
|
- #+glibc2.1
|
1205
|
|
- (d-ino ino-t) ; inode number of entry
|
1206
|
|
- #-glibc2.1
|
1207
|
|
- (d-ino ino64-t) ; inode number of entry
|
1208
|
|
- (d-off off-t) ; offset of next disk directory entry
|
1209
|
|
- (d-reclen unsigned-short) ; length of this record
|
1210
|
|
- (d_type unsigned-char)
|
1211
|
|
- (d-name (array char 256)))) ; name must be no longer than this
|
1212
|
|
-
|
1213
|
|
-(export '(open-dir read-dir close-dir))
|
1214
|
|
-
|
1215
|
|
-(defstruct (%directory
|
1216
|
|
- (:constructor make-directory)
|
1217
|
|
- (:conc-name directory-)
|
1218
|
|
- (:print-function %print-directory))
|
1219
|
|
- name
|
1220
|
|
- (dir-struct (required-argument) :type system-area-pointer))
|
1221
|
|
-
|
1222
|
|
-(defun %print-directory (dir stream depth)
|
1223
|
|
- (declare (ignore depth))
|
1224
|
|
- (format stream "#<Directory ~S>" (directory-name dir)))
|
1225
|
|
-
|
1226
|
|
-(defun open-dir (pathname)
|
1227
|
|
- (declare (type unix-pathname pathname))
|
1228
|
|
- (when (string= pathname "")
|
1229
|
|
- (setf pathname "."))
|
1230
|
|
- (let ((kind (unix-file-kind pathname)))
|
1231
|
|
- (case kind
|
1232
|
|
- (:directory
|
1233
|
|
- (let ((dir-struct
|
1234
|
|
- (alien-funcall (extern-alien "opendir"
|
1235
|
|
- (function system-area-pointer
|
1236
|
|
- c-string))
|
1237
|
|
- (%name->file pathname))))
|
1238
|
|
- (if (zerop (sap-int dir-struct))
|
1239
|
|
- (values nil (unix-errno))
|
1240
|
|
- (make-directory :name pathname :dir-struct dir-struct))))
|
1241
|
|
- ((nil)
|
1242
|
|
- (values nil enoent))
|
1243
|
|
- (t
|
1244
|
|
- (values nil enotdir)))))
|
1245
|
|
-
|
1246
|
|
-(defun read-dir (dir)
|
1247
|
|
- (declare (type %directory dir))
|
1248
|
|
- (let ((daddr (alien-funcall (extern-alien "readdir64"
|
1249
|
|
- (function system-area-pointer
|
1250
|
|
- system-area-pointer))
|
1251
|
|
- (directory-dir-struct dir))))
|
1252
|
|
- (declare (type system-area-pointer daddr))
|
1253
|
|
- (if (zerop (sap-int daddr))
|
1254
|
|
- nil
|
1255
|
|
- (with-alien ((dirent (* (struct dirent)) daddr))
|
1256
|
|
- (values (%file->name (cast (slot dirent 'd-name) c-string))
|
1257
|
|
- (slot dirent 'd-ino))))))
|
1258
|
|
-
|
1259
|
|
-(defun close-dir (dir)
|
1260
|
|
- (declare (type %directory dir))
|
1261
|
|
- (alien-funcall (extern-alien "closedir"
|
1262
|
|
- (function void system-area-pointer))
|
1263
|
|
- (directory-dir-struct dir))
|
1264
|
|
- nil)
|
1265
|
|
-
|
1266
|
|
-(defconstant rusage_self 0 _N"The calling process.")
|
1267
|
|
-(defconstant rusage_children -1 _N"Terminated child processes.")
|
1268
|
|
-(defconstant rusage_both -2)
|
1269
|
|
-
|
1270
|
|
-(def-alien-type nil
|
1271
|
|
- (struct rusage
|
1272
|
|
- (ru-utime (struct timeval)) ; user time used
|
1273
|
|
- (ru-stime (struct timeval)) ; system time used.
|
1274
|
|
- (ru-maxrss long) ; Maximum resident set size (in kilobytes)
|
1275
|
|
- (ru-ixrss long) ; integral shared memory size
|
1276
|
|
- (ru-idrss long) ; integral unshared data "
|
1277
|
|
- (ru-isrss long) ; integral unshared stack "
|
1278
|
|
- (ru-minflt long) ; page reclaims
|
1279
|
|
- (ru-majflt long) ; page faults
|
1280
|
|
- (ru-nswap long) ; swaps
|
1281
|
|
- (ru-inblock long) ; block input operations
|
1282
|
|
- (ru-oublock long) ; block output operations
|
1283
|
|
- (ru-msgsnd long) ; messages sent
|
1284
|
|
- (ru-msgrcv long) ; messages received
|
1285
|
|
- (ru-nsignals long) ; signals received
|
1286
|
|
- (ru-nvcsw long) ; voluntary context switches
|
1287
|
|
- (ru-nivcsw long)))
|
1288
|
|
-
|
1289
|
|
-(declaim (inline unix-fast-getrusage))
|
1290
|
|
-(defun unix-fast-getrusage (who)
|
1291
|
|
- _N"Like call getrusage, but return only the system and user time, and returns
|
1292
|
|
- the seconds and microseconds as separate values."
|
1293
|
|
- (declare (values (member t)
|
1294
|
|
- (unsigned-byte 31) (mod 1000000)
|
1295
|
|
- (unsigned-byte 31) (mod 1000000)))
|
1296
|
|
- (with-alien ((usage (struct rusage)))
|
1297
|
|
- (syscall* ("getrusage" int (* (struct rusage)))
|
1298
|
|
- (values t
|
1299
|
|
- (slot (slot usage 'ru-utime) 'tv-sec)
|
1300
|
|
- (slot (slot usage 'ru-utime) 'tv-usec)
|
1301
|
|
- (slot (slot usage 'ru-stime) 'tv-sec)
|
1302
|
|
- (slot (slot usage 'ru-stime) 'tv-usec))
|
1303
|
|
- who (addr usage))))
|
1304
|
|
-
|
1305
|
|
-(defun unix-getrusage (who)
|
1306
|
|
- _N"Unix-getrusage returns information about the resource usage
|
1307
|
|
- of the process specified by who. Who can be either the
|
1308
|
|
- current process (rusage_self) or all of the terminated
|
1309
|
|
- child processes (rusage_children). NIL and an error number
|
1310
|
|
- is returned if the call fails."
|
1311
|
|
- (with-alien ((usage (struct rusage)))
|
1312
|
|
- (syscall ("getrusage" int (* (struct rusage)))
|
1313
|
|
- (values t
|
1314
|
|
- (+ (* (slot (slot usage 'ru-utime) 'tv-sec) 1000000)
|
1315
|
|
- (slot (slot usage 'ru-utime) 'tv-usec))
|
1316
|
|
- (+ (* (slot (slot usage 'ru-stime) 'tv-sec) 1000000)
|
1317
|
|
- (slot (slot usage 'ru-stime) 'tv-usec))
|
1318
|
|
- (slot usage 'ru-maxrss)
|
1319
|
|
- (slot usage 'ru-ixrss)
|
1320
|
|
- (slot usage 'ru-idrss)
|
1321
|
|
- (slot usage 'ru-isrss)
|
1322
|
|
- (slot usage 'ru-minflt)
|
1323
|
|
- (slot usage 'ru-majflt)
|
1324
|
|
- (slot usage 'ru-nswap)
|
1325
|
|
- (slot usage 'ru-inblock)
|
1326
|
|
- (slot usage 'ru-oublock)
|
1327
|
|
- (slot usage 'ru-msgsnd)
|
1328
|
|
- (slot usage 'ru-msgrcv)
|
1329
|
|
- (slot usage 'ru-nsignals)
|
1330
|
|
- (slot usage 'ru-nvcsw)
|
1331
|
|
- (slot usage 'ru-nivcsw))
|
1332
|
|
- who (addr usage))))
|
1333
|
|
-
|
1334
|
|
-;;;; Socket support.
|
1335
|
|
-
|
1336
|
|
-;;; Looks a bit naked.
|
1337
|
|
-
|
1338
|
|
-(def-alien-routine ("socket" unix-socket) int
|
1339
|
|
- (domain int)
|
1340
|
|
- (type int)
|
1341
|
|
- (protocol int))
|
1342
|
|
-
|
1343
|
|
-(def-alien-routine ("connect" unix-connect) int
|
1344
|
|
- (socket int)
|
1345
|
|
- (sockaddr (* t))
|
1346
|
|
- (len int))
|
1347
|
|
-
|
1348
|
|
-(def-alien-routine ("bind" unix-bind) int
|
1349
|
|
- (socket int)
|
1350
|
|
- (sockaddr (* t))
|
1351
|
|
- (len int))
|
1352
|
|
-
|
1353
|
|
-(def-alien-routine ("listen" unix-listen) int
|
1354
|
|
- (socket int)
|
1355
|
|
- (backlog int))
|
1356
|
|
-
|
1357
|
|
-(def-alien-routine ("accept" unix-accept) int
|
1358
|
|
- (socket int)
|
1359
|
|
- (sockaddr (* t))
|
1360
|
|
- (len int :in-out))
|
1361
|
|
-
|
1362
|
|
-(def-alien-routine ("recv" unix-recv) int
|
1363
|
|
- (fd int)
|
1364
|
|
- (buffer c-string)
|
1365
|
|
- (length int)
|
1366
|
|
- (flags int))
|
1367
|
|
-
|
1368
|
|
-(def-alien-routine ("send" unix-send) int
|
1369
|
|
- (fd int)
|
1370
|
|
- (buffer c-string)
|
1371
|
|
- (length int)
|
1372
|
|
- (flags int))
|
1373
|
|
-
|
1374
|
|
-(def-alien-routine ("getpeername" unix-getpeername) int
|
1375
|
|
- (socket int)
|
1376
|
|
- (sockaddr (* t))
|
1377
|
|
- (len (* unsigned)))
|
1378
|
|
-
|
1379
|
|
-(def-alien-routine ("getsockname" unix-getsockname) int
|
1380
|
|
- (socket int)
|
1381
|
|
- (sockaddr (* t))
|
1382
|
|
- (len (* unsigned)))
|
1383
|
|
-
|
1384
|
|
-(def-alien-routine ("getsockopt" unix-getsockopt) int
|
1385
|
|
- (socket int)
|
1386
|
|
- (level int)
|
1387
|
|
- (optname int)
|
1388
|
|
- (optval (* t))
|
1389
|
|
- (optlen unsigned :in-out))
|
1390
|
|
-
|
1391
|
|
-(def-alien-routine ("setsockopt" unix-setsockopt) int
|
1392
|
|
- (socket int)
|
1393
|
|
- (level int)
|
1394
|
|
- (optname int)
|
1395
|
|
- (optval (* t))
|
1396
|
|
- (optlen unsigned))
|
1397
|
|
-
|
1398
|
|
-;; Datagram support
|
1399
|
|
-
|
1400
|
|
-(def-alien-routine ("recvfrom" unix-recvfrom) int
|
1401
|
|
- (fd int)
|
1402
|
|
- (buffer c-string)
|
1403
|
|
- (length int)
|
1404
|
|
- (flags int)
|
1405
|
|
- (sockaddr (* t))
|
1406
|
|
- (len int :in-out))
|
1407
|
|
-
|
1408
|
|
-(def-alien-routine ("sendto" unix-sendto) int
|
1409
|
|
- (fd int)
|
1410
|
|
- (buffer c-string)
|
1411
|
|
- (length int)
|
1412
|
|
- (flags int)
|
1413
|
|
- (sockaddr (* t))
|
1414
|
|
- (len int))
|
1415
|
|
-
|
1416
|
|
-(def-alien-routine ("shutdown" unix-shutdown) int
|
1417
|
|
- (socket int)
|
1418
|
|
- (level int))
|
1419
|
|
-
|
1420
|
|
-;;; sys/select.h
|
1421
|
|
-
|
1422
|
|
-;;; UNIX-FAST-SELECT -- public.
|
1423
|
|
-;;;
|
1424
|
|
-(defmacro unix-fast-select (num-descriptors
|
1425
|
|
- read-fds write-fds exception-fds
|
1426
|
|
- timeout-secs &optional (timeout-usecs 0))
|
1427
|
|
- _N"Perform the UNIX select(2) system call."
|
1428
|
|
- (declare (type (integer 0 #.FD-SETSIZE) num-descriptors)
|
1429
|
|
- (type (or (alien (* (struct fd-set))) null)
|
1430
|
|
- read-fds write-fds exception-fds)
|
1431
|
|
- (type (or null (unsigned-byte 31)) timeout-secs)
|
1432
|
|
- (type (unsigned-byte 31) timeout-usecs)
|
1433
|
|
- (optimize (speed 3) (safety 0) (inhibit-warnings 3)))
|
1434
|
|
- `(let ((timeout-secs ,timeout-secs))
|
1435
|
|
- (with-alien ((tv (struct timeval)))
|
1436
|
|
- (when timeout-secs
|
1437
|
|
- (setf (slot tv 'tv-sec) timeout-secs)
|
1438
|
|
- (setf (slot tv 'tv-usec) ,timeout-usecs))
|
1439
|
|
- (int-syscall ("select" int (* (struct fd-set)) (* (struct fd-set))
|
1440
|
|
- (* (struct fd-set)) (* (struct timeval)))
|
1441
|
|
- ,num-descriptors ,read-fds ,write-fds ,exception-fds
|
1442
|
|
- (if timeout-secs (alien-sap (addr tv)) (int-sap 0))))))
|
1443
|
|
-
|
1444
|
|
-
|
1445
|
|
-;;; Unix-select accepts sets of file descriptors and waits for an event
|
1446
|
|
-;;; to happen on one of them or to time out.
|
1447
|
|
-
|
1448
|
|
-(defmacro num-to-fd-set (fdset num)
|
1449
|
|
- `(if (fixnump ,num)
|
1450
|
|
- (progn
|
1451
|
|
- (setf (deref (slot ,fdset 'fds-bits) 0) ,num)
|
1452
|
|
- ,@(loop for index upfrom 1 below (/ fd-setsize nfdbits)
|
1453
|
|
- collect `(setf (deref (slot ,fdset 'fds-bits) ,index) 0)))
|
1454
|
|
- (progn
|
1455
|
|
- ,@(loop for index upfrom 0 below (/ fd-setsize nfdbits)
|
1456
|
|
- collect `(setf (deref (slot ,fdset 'fds-bits) ,index)
|
1457
|
|
- (ldb (byte nfdbits ,(* index nfdbits)) ,num))))))
|
1458
|
|
-
|
1459
|
|
-(defmacro fd-set-to-num (nfds fdset)
|
1460
|
|
- `(if (<= ,nfds nfdbits)
|
1461
|
|
- (deref (slot ,fdset 'fds-bits) 0)
|
1462
|
|
- (+ ,@(loop for index upfrom 0 below (/ fd-setsize nfdbits)
|
1463
|
|
- collect `(ash (deref (slot ,fdset 'fds-bits) ,index)
|
1464
|
|
- ,(* index nfdbits))))))
|
1465
|
|
-
|
1466
|
|
-(defun unix-select (nfds rdfds wrfds xpfds to-secs &optional (to-usecs 0))
|
1467
|
|
- _N"Unix-select examines the sets of descriptors passed as arguments
|
1468
|
|
- to see if they are ready for reading and writing. See the UNIX
|
1469
|
|
- Programmers Manual for more information."
|
1470
|
|
- (declare (type (integer 0 #.FD-SETSIZE) nfds)
|
1471
|
|
- (type unsigned-byte rdfds wrfds xpfds)
|
1472
|
|
- (type (or (unsigned-byte 31) null) to-secs)
|
1473
|
|
- (type (unsigned-byte 31) to-usecs)
|
1474
|
|
- (optimize (speed 3) (safety 0) (inhibit-warnings 3)))
|
1475
|
|
- (with-alien ((tv (struct timeval))
|
1476
|
|
- (rdf (struct fd-set))
|
1477
|
|
- (wrf (struct fd-set))
|
1478
|
|
- (xpf (struct fd-set)))
|
1479
|
|
- (when to-secs
|
1480
|
|
- (setf (slot tv 'tv-sec) to-secs)
|
1481
|
|
- (setf (slot tv 'tv-usec) to-usecs))
|
1482
|
|
- (num-to-fd-set rdf rdfds)
|
1483
|
|
- (num-to-fd-set wrf wrfds)
|
1484
|
|
- (num-to-fd-set xpf xpfds)
|
1485
|
|
- (macrolet ((frob (lispvar alienvar)
|
1486
|
|
- `(if (zerop ,lispvar)
|
1487
|
|
- (int-sap 0)
|
1488
|
|
- (alien-sap (addr ,alienvar)))))
|
1489
|
|
- (syscall ("select" int (* (struct fd-set)) (* (struct fd-set))
|
1490
|
|
- (* (struct fd-set)) (* (struct timeval)))
|
1491
|
|
- (values result
|
1492
|
|
- (fd-set-to-num nfds rdf)
|
1493
|
|
- (fd-set-to-num nfds wrf)
|
1494
|
|
- (fd-set-to-num nfds xpf))
|
1495
|
|
- nfds (frob rdfds rdf) (frob wrfds wrf) (frob xpfds xpf)
|
1496
|
|
- (if to-secs (alien-sap (addr tv)) (int-sap 0))))))
|
1497
|
|
-
|
1498
|
|
-(defun unix-symlink (name1 name2)
|
1499
|
|
- _N"Unix-symlink creates a symbolic link named name2 to the file
|
1500
|
|
- named name1. NIL and an error number is returned if the call
|
1501
|
|
- is unsuccessful."
|
1502
|
|
- (declare (type unix-pathname name1 name2))
|
1503
|
|
- (void-syscall ("symlink" c-string c-string)
|
1504
|
|
- (%name->file name1) (%name->file name2)))
|
1505
|
|
-
|
1506
|
|
-(def-alien-routine ("gethostid" unix-gethostid) unsigned-long
|
1507
|
|
- _N"Unix-gethostid returns a 32-bit integer which provides unique
|
1508
|
|
- identification for the host machine.")
|
1509
|
|
-
|
1510
|
|
-(def-alien-routine ("getpid" unix-getpid) int
|
1511
|
|
- _N"Unix-getpid returns the process-id of the current process.")
|
1512
|
|
-
|
1513
|
|
-;;;; User and group database structures: <pwd.h> and <grp.h>
|
1514
|
|
-(defstruct user-info
|
1515
|
|
- (name "" :type string)
|
1516
|
|
- (password "" :type string)
|
1517
|
|
- (uid 0 :type unix-uid)
|
1518
|
|
- (gid 0 :type unix-gid)
|
1519
|
|
- (gecos "" :type string)
|
1520
|
|
- (dir "" :type string)
|
1521
|
|
- (shell "" :type string))
|
1522
|
|
-
|
1523
|
|
-(defun unix-getpwuid (uid)
|
1524
|
|
- _N"Return a USER-INFO structure for the user identified by UID, or NIL if not found."
|
1525
|
|
- (declare (type unix-uid uid))
|
1526
|
|
- (with-alien ((buf (array c-call:char 1024))
|
1527
|
|
- (user-info (struct passwd))
|
1528
|
|
- (result (* (struct passwd))))
|
1529
|
|
- (let ((returned
|
1530
|
|
- (alien-funcall
|
1531
|
|
- (extern-alien "getpwuid_r"
|
1532
|
|
- (function c-call:int
|
1533
|
|
- c-call:unsigned-int
|
1534
|
|
- (* (struct passwd))
|
1535
|
|
- (* c-call:char)
|
1536
|
|
- c-call:unsigned-int
|
1537
|
|
- (* (* (struct passwd)))))
|
1538
|
|
- uid
|
1539
|
|
- (addr user-info)
|
1540
|
|
- (cast buf (* c-call:char))
|
1541
|
|
- 1024
|
1542
|
|
- (addr result))))
|
1543
|
|
- (when (zerop returned)
|
1544
|
|
- (make-user-info
|
1545
|
|
- :name (string (cast (slot result 'pw-name) c-call:c-string))
|
1546
|
|
- :password (string (cast (slot result 'pw-passwd) c-call:c-string))
|
1547
|
|
- :uid (slot result 'pw-uid)
|
1548
|
|
- :gid (slot result 'pw-gid)
|
1549
|
|
- :gecos (string (cast (slot result 'pw-gecos) c-call:c-string))
|
1550
|
|
- :dir (string (cast (slot result 'pw-dir) c-call:c-string))
|
1551
|
|
- :shell (string (cast (slot result 'pw-shell) c-call:c-string)))))))
|
1552
|
|
-
|
1553
|
|
-(declaim (inline unix-gettimeofday))
|
1554
|
|
-(defun unix-gettimeofday ()
|
1555
|
|
- _N"If it works, unix-gettimeofday returns 5 values: T, the seconds and
|
1556
|
|
- microseconds of the current time of day, the timezone (in minutes west
|
1557
|
|
- of Greenwich), and a daylight-savings flag. If it doesn't work, it
|
1558
|
|
- returns NIL and the errno."
|
1559
|
|
- (with-alien ((tv (struct timeval))
|
1560
|
|
- (tz (struct timezone)))
|
1561
|
|
- (syscall* ("gettimeofday" (* (struct timeval))
|
1562
|
|
- (* (struct timezone)))
|
1563
|
|
- (values T
|
1564
|
|
- (slot tv 'tv-sec)
|
1565
|
|
- (slot tv 'tv-usec)
|
1566
|
|
- (slot tz 'tz-minuteswest)
|
1567
|
|
- (slot tz 'tz-dsttime))
|
1568
|
|
- (addr tv)
|
1569
|
|
- (addr tz))))
|
1570
|
|
-
|
1571
|
|
-;;; Unix-utimes changes the accessed and updated times on UNIX
|
1572
|
|
-;;; files. The first argument is the filename (a string) and
|
1573
|
|
-;;; the second argument is a list of the 4 times- accessed and
|
1574
|
|
-;;; updated seconds and microseconds.
|
1575
|
|
-
|
1576
|
|
-(defun unix-utimes (file atime-sec atime-usec mtime-sec mtime-usec)
|
1577
|
|
- _N"Unix-utimes sets the 'last-accessed' and 'last-updated'
|
1578
|
|
- times on a specified file. NIL and an error number is
|
1579
|
|
- returned if the call is unsuccessful."
|
1580
|
|
- (declare (type unix-pathname file)
|
1581
|
|
- (type (alien unsigned-long)
|
1582
|
|
- atime-sec atime-usec
|
1583
|
|
- mtime-sec mtime-usec))
|
1584
|
|
- (with-alien ((tvp (array (struct timeval) 2)))
|
1585
|
|
- (setf (slot (deref tvp 0) 'tv-sec) atime-sec)
|
1586
|
|
- (setf (slot (deref tvp 0) 'tv-usec) atime-usec)
|
1587
|
|
- (setf (slot (deref tvp 1) 'tv-sec) mtime-sec)
|
1588
|
|
- (setf (slot (deref tvp 1) 'tv-usec) mtime-usec)
|
1589
|
|
- (void-syscall ("utimes" c-string (* (struct timeval)))
|
1590
|
|
- file
|
1591
|
|
- (cast tvp (* (struct timeval))))))
|
1592
|
|
-
|
1593
|
|
-(def-alien-routine ("ttyname" unix-ttyname) c-string
|
1594
|
|
- (fd int))
|
1595
|
|
-
|
1596
|
|
-(def-alien-routine ("isatty" unix-isatty) boolean
|
1597
|
|
- _N"Accepts a Unix file descriptor and returns T if the device
|
1598
|
|
- associated with it is a terminal."
|
1599
|
|
- (fd int))
|
1600
|
|
-
|
1601
|
|
-;;; pty.h
|
1602
|
|
-
|
1603
|
|
-(defun unix-openpty (name termp winp)
|
1604
|
|
- _N"Create pseudo tty master slave pair with NAME and set terminal
|
1605
|
|
- attributes according to TERMP and WINP and return handles for both
|
1606
|
|
- ends in AMASTER and ASLAVE."
|
1607
|
|
- (with-alien ((amaster int)
|
1608
|
|
- (aslave int))
|
1609
|
|
- (values
|
1610
|
|
- (int-syscall ("openpty" (* int) (* int) c-string (* (struct termios))
|
1611
|
|
- (* (struct winsize)))
|
1612
|
|
- (addr amaster) (addr aslave) name termp winp)
|
1613
|
|
- amaster aslave)))
|
1614
|
|
-
|
1615
|
|
-(def-alien-type nil
|
1616
|
|
- (struct utsname
|
1617
|
|
- (sysname (array char 65))
|
1618
|
|
- (nodename (array char 65))
|
1619
|
|
- (release (array char 65))
|
1620
|
|
- (version (array char 65))
|
1621
|
|
- (machine (array char 65))
|
1622
|
|
- (domainname (array char 65))))
|
1623
|
|
-
|
1624
|
|
-(defun unix-uname ()
|
1625
|
|
- _N"Unix-uname returns the name and information about the current kernel. The
|
1626
|
|
- values returned upon success are: sysname, nodename, release, version,
|
1627
|
|
- machine, and domainname. Upon failure, 'nil and the 'errno are returned."
|
1628
|
|
- (with-alien ((utsname (struct utsname)))
|
1629
|
|
- (syscall* ("uname" (* (struct utsname)))
|
1630
|
|
- (values (cast (slot utsname 'sysname) c-string)
|
1631
|
|
- (cast (slot utsname 'nodename) c-string)
|
1632
|
|
- (cast (slot utsname 'release) c-string)
|
1633
|
|
- (cast (slot utsname 'version) c-string)
|
1634
|
|
- (cast (slot utsname 'machine) c-string)
|
1635
|
|
- (cast (slot utsname 'domainname) c-string))
|
1636
|
|
- (addr utsname))))
|
1637
|
|
-
|
1638
|
|
-;;; sys/ioctl.h
|
1639
|
|
-
|
1640
|
|
-(defun unix-ioctl (fd cmd arg)
|
1641
|
|
- _N"Unix-ioctl performs a variety of operations on open i/o
|
1642
|
|
- descriptors. See the UNIX Programmer's Manual for more
|
1643
|
|
- information."
|
1644
|
|
- (declare (type unix-fd fd)
|
1645
|
|
- (type (unsigned-byte 32) cmd))
|
1646
|
|
- (int-syscall ("ioctl" int unsigned-int (* char)) fd cmd arg))
|
1647
|
|
-
|
1648
|
|
-
|
1649
|
|
-;;; Unix-mkdir accepts a name and a mode and attempts to create the
|
1650
|
|
-;;; corresponding directory with mode mode.
|
1651
|
|
-
|
1652
|
|
-(defun unix-mkdir (name mode)
|
1653
|
|
- _N"Unix-mkdir creates a new directory with the specified name and mode.
|
1654
|
|
- (Same as those for unix-chmod.) It returns T upon success, otherwise
|
1655
|
|
- NIL and an error number."
|
1656
|
|
- (declare (type unix-pathname name)
|
1657
|
|
- (type unix-file-mode mode))
|
1658
|
|
- (void-syscall ("mkdir" c-string int) (%name->file name) mode))
|
1659
|
|
-
|
1660
|
|
-;;; timebits.h
|
1661
|
|
-
|
1662
|
|
-;; A time value that is accurate to the nearest
|
1663
|
|
-;; microsecond but also has a range of years.
|
1664
|
|
-(def-alien-type nil
|
1665
|
|
- (struct timeval
|
1666
|
|
- (tv-sec time-t) ; seconds
|
1667
|
|
- (tv-usec time-t))) ; and microseconds
|
1668
|
|
-
|
1669
|
|
-;;; sys/time.h
|
1670
|
|
-
|
1671
|
|
-;; Structure crudely representing a timezone.
|
1672
|
|
-;; This is obsolete and should never be used.
|
1673
|
|
-(def-alien-type nil
|
1674
|
|
- (struct timezone
|
1675
|
|
- (tz-minuteswest int) ; minutes west of Greenwich
|
1676
|
|
- (tz-dsttime int))) ; type of dst correction
|
1677
|
|
-
|
1678
|
|
-;; Type of the second argument to `getitimer' and
|
1679
|
|
-;; the second and third arguments `setitimer'.
|
1680
|
|
-(def-alien-type nil
|
1681
|
|
- (struct itimerval
|
1682
|
|
- (it-interval (struct timeval)) ; timer interval
|
1683
|
|
- (it-value (struct timeval)))) ; current value
|
1684
|
|
-
|
1685
|
|
-(defconstant ITIMER-REAL 0)
|
1686
|
|
-(defconstant ITIMER-VIRTUAL 1)
|
1687
|
|
-(defconstant ITIMER-PROF 2)
|
1688
|
|
-
|
1689
|
|
-(defun unix-getitimer (which)
|
1690
|
|
- _N"Unix-getitimer returns the INTERVAL and VALUE slots of one of
|
1691
|
|
- three system timers (:real :virtual or :profile). On success,
|
1692
|
|
- unix-getitimer returns 5 values,
|
1693
|
|
- T, it-interval-secs, it-interval-usec, it-value-secs, it-value-usec."
|
1694
|
|
- (declare (type (member :real :virtual :profile) which)
|
1695
|
|
- (values t
|
1696
|
|
- (unsigned-byte 29)(mod 1000000)
|
1697
|
|
- (unsigned-byte 29)(mod 1000000)))
|
1698
|
|
- (let ((which (ecase which
|
1699
|
|
- (:real ITIMER-REAL)
|
1700
|
|
- (:virtual ITIMER-VIRTUAL)
|
1701
|
|
- (:profile ITIMER-PROF))))
|
1702
|
|
- (with-alien ((itv (struct itimerval)))
|
1703
|
|
- (syscall* ("getitimer" int (* (struct itimerval)))
|
1704
|
|
- (values T
|
1705
|
|
- (slot (slot itv 'it-interval) 'tv-sec)
|
1706
|
|
- (slot (slot itv 'it-interval) 'tv-usec)
|
1707
|
|
- (slot (slot itv 'it-value) 'tv-sec)
|
1708
|
|
- (slot (slot itv 'it-value) 'tv-usec))
|
1709
|
|
- which (alien-sap (addr itv))))))
|
1710
|
|
-
|
1711
|
|
-(defun unix-setitimer (which int-secs int-usec val-secs val-usec)
|
1712
|
|
- _N" Unix-setitimer sets the INTERVAL and VALUE slots of one of
|
1713
|
|
- three system timers (:real :virtual or :profile). A SIGALRM signal
|
1714
|
|
- will be delivered VALUE <seconds+microseconds> from now. INTERVAL,
|
1715
|
|
- when non-zero, is <seconds+microseconds> to be loaded each time
|
1716
|
|
- the timer expires. Setting INTERVAL and VALUE to zero disables
|
1717
|
|
- the timer. See the Unix man page for more details. On success,
|
1718
|
|
- unix-setitimer returns the old contents of the INTERVAL and VALUE
|
1719
|
|
- slots as in unix-getitimer."
|
1720
|
|
- (declare (type (member :real :virtual :profile) which)
|
1721
|
|
- (type (unsigned-byte 29) int-secs val-secs)
|
1722
|
|
- (type (integer 0 (1000000)) int-usec val-usec)
|
1723
|
|
- (values t
|
1724
|
|
- (unsigned-byte 29)(mod 1000000)
|
1725
|
|
- (unsigned-byte 29)(mod 1000000)))
|
1726
|
|
- (let ((which (ecase which
|
1727
|
|
- (:real ITIMER-REAL)
|
1728
|
|
- (:virtual ITIMER-VIRTUAL)
|
1729
|
|
- (:profile ITIMER-PROF))))
|
1730
|
|
- (with-alien ((itvn (struct itimerval))
|
1731
|
|
- (itvo (struct itimerval)))
|
1732
|
|
- (setf (slot (slot itvn 'it-interval) 'tv-sec ) int-secs
|
1733
|
|
- (slot (slot itvn 'it-interval) 'tv-usec) int-usec
|
1734
|
|
- (slot (slot itvn 'it-value ) 'tv-sec ) val-secs
|
1735
|
|
- (slot (slot itvn 'it-value ) 'tv-usec) val-usec)
|
1736
|
|
- (syscall* ("setitimer" int (* (struct timeval))(* (struct timeval)))
|
1737
|
|
- (values T
|
1738
|
|
- (slot (slot itvo 'it-interval) 'tv-sec)
|
1739
|
|
- (slot (slot itvo 'it-interval) 'tv-usec)
|
1740
|
|
- (slot (slot itvo 'it-value) 'tv-sec)
|
1741
|
|
- (slot (slot itvo 'it-value) 'tv-usec))
|
1742
|
|
- which (alien-sap (addr itvn))(alien-sap (addr itvo))))))
|
1743
|
|
-
|
1744
|
|
-
|
1745
|
|
-;;; termbits.h
|
1746
|
|
-
|
1747
|
|
-(def-alien-type cc-t unsigned-char)
|
1748
|
|
-(def-alien-type speed-t unsigned-int)
|
1749
|
|
-(def-alien-type tcflag-t unsigned-int)
|
1750
|
|
-
|
1751
|
|
-(defconstant +NCCS+ 32
|
1752
|
|
- _N"Size of control character vector.")
|
1753
|
|
-
|
1754
|
|
-(def-alien-type nil
|
1755
|
|
- (struct termios
|
1756
|
|
- (c-iflag tcflag-t)
|
1757
|
|
- (c-oflag tcflag-t)
|
1758
|
|
- (c-cflag tcflag-t)
|
1759
|
|
- (c-lflag tcflag-t)
|
1760
|
|
- (c-line cc-t)
|
1761
|
|
- (c-cc (array cc-t #.+NCCS+))
|
1762
|
|
- (c-ispeed speed-t)
|
1763
|
|
- (c-ospeed speed-t)))
|
1764
|
|
-
|
1765
|
|
-;; c_cc characters
|
1766
|
|
-
|
1767
|
|
-(defmacro def-enum (inc cur &rest names)
|
1768
|
|
- (flet ((defform (name)
|
1769
|
|
- (prog1 (when name `(defconstant ,name ,cur))
|
1770
|
|
- (setf cur (funcall inc cur 1)))))
|
1771
|
|
- `(progn ,@(mapcar #'defform names))))
|
1772
|
|
-
|
1773
|
|
-(def-enum + 0 vintr vquit verase
|
1774
|
|
- vkill veof vtime
|
1775
|
|
- vmin vswtc vstart
|
1776
|
|
- vstop vsusp veol
|
1777
|
|
- vreprint vdiscard vwerase
|
1778
|
|
- vlnext veol2)
|
1779
|
|
-(defvar vdsusp vsusp)
|
1780
|
|
-
|
1781
|
|
-(def-enum + 0 tcsanow tcsadrain tcsaflush)
|
1782
|
|
-
|
1783
|
|
-;; c_iflag bits
|
1784
|
|
-(def-enum ash 1 tty-ignbrk tty-brkint tty-ignpar tty-parmrk tty-inpck
|
1785
|
|
- tty-istrip tty-inlcr tty-igncr tty-icrnl tty-iuclc
|
1786
|
|
- tty-ixon tty-ixany tty-ixoff
|
1787
|
|
- tty-imaxbel)
|
1788
|
|
-
|
1789
|
|
-;; c_oflag bits
|
1790
|
|
-(def-enum ash 1 tty-opost tty-olcuc tty-onlcr tty-ocrnl tty-onocr
|
1791
|
|
- tty-onlret tty-ofill tty-ofdel tty-nldly)
|
1792
|
|
-
|
1793
|
|
-;; c_lflag bits
|
1794
|
|
-(def-enum ash 1 tty-isig tty-icanon tty-xcase tty-echo tty-echoe
|
1795
|
|
- tty-echok tty-echonl tty-noflsh
|
1796
|
|
- tty-tostop tty-echoctl tty-echoprt
|
1797
|
|
- tty-echoke tty-flusho
|
1798
|
|
- tty-pendin tty-iexten)
|
1799
|
|
-
|
1800
|
|
-(defun unix-tcgetattr (fd termios)
|
1801
|
|
- _N"Get terminal attributes."
|
1802
|
|
- (declare (type unix-fd fd))
|
1803
|
|
- (void-syscall ("tcgetattr" int (* (struct termios))) fd termios))
|
1804
|
|
-
|
1805
|
|
-(defun unix-tcsetattr (fd opt termios)
|
1806
|
|
- _N"Set terminal attributes."
|
1807
|
|
- (declare (type unix-fd fd))
|
1808
|
|
- (void-syscall ("tcsetattr" int int (* (struct termios))) fd opt termios))
|
1809
|
|
-
|
1810
|
|
-(defconstant writeown #o200 _N"Write by owner")
|
1811
|
|
-
|
1812
|
|
-;;; termios.h
|
1813
|
|
-
|
1814
|
|
-(defconstant terminal-speeds
|
1815
|
|
- '#(0 50 75 110 134 150 200 300 600 1200 1800 2400
|
1816
|
|
- 4800 9600 19200 38400 57600 115200 230400))
|
1817
|
|
-
|
1818
|
|
-(defun unix-cfgetospeed (termios)
|
1819
|
|
- _N"Get terminal output speed."
|
1820
|
|
- (multiple-value-bind (speed errno)
|
1821
|
|
- (int-syscall ("cfgetospeed" (* (struct termios))) termios)
|
1822
|
|
- (if speed
|
1823
|
|
- (values (svref terminal-speeds speed) 0)
|
1824
|
|
- (values speed errno))))
|
1825
|
|
-
|
1826
|
|
-
|
1827
|
|
-;;; For asdf. Well, only getenv, but might as well make it symmetric.
|
1828
|
|
-
|
1829
|
|
-;; Environment manipulation; man getenv(3)
|
1830
|
|
-(def-alien-routine ("getenv" unix-getenv) c-call:c-string
|
1831
|
|
- (name c-call:c-string)
|
1832
|
|
- _N"Get the value of the environment variable named Name. If no such
|
1833
|
|
- variable exists, Nil is returned.")
|
1834
|
|
-
|
1835
|
|
-;; This doesn't exist in Solaris 8 but does exist in Solaris 10.
|
1836
|
|
-(def-alien-routine ("setenv" unix-setenv) c-call:int
|
1837
|
|
- (name c-call:c-string)
|
1838
|
|
- (value c-call:c-string)
|
1839
|
|
- (overwrite c-call:int)
|
1840
|
|
- _N"Adds the environment variable named Name to the environment with
|
1841
|
|
- the given Value if Name does not already exist. If Name does exist,
|
1842
|
|
- the value is changed to Value if Overwrite is non-zero. Otherwise,
|
1843
|
|
- the value is not changed.")
|
1844
|
|
-
|
1845
|
|
-
|
1846
|
|
-(def-alien-routine ("putenv" unix-putenv) c-call:int
|
1847
|
|
- (name-value c-call:c-string)
|
1848
|
|
- _N"Adds or changes the environment. Name-value must be a string of
|
1849
|
|
- the form \"name=value\". If the name does not exist, it is added.
|
1850
|
|
- If name does exist, the value is updated to the given value.")
|
1851
|
|
-
|
1852
|
|
-(def-alien-routine ("unsetenv" unix-unsetenv) c-call:int
|
1853
|
|
- (name c-call:c-string)
|
1854
|
|
- _N"Removes the variable Name from the environment")
|
1855
|
|
-
|
1856
|
|
-
|
1857
|
|
-;;; For slime, which wants to use unix-execve.
|
1858
|
|
-
|
1859
|
|
-(defmacro round-bytes-to-words (n)
|
1860
|
|
- `(logand (the fixnum (+ (the fixnum ,n) 3)) (lognot 3)))
|
1861
|
|
-
|
1862
|
|
-;;;
|
1863
|
|
-;;; STRING-LIST-TO-C-STRVEC -- Internal
|
1864
|
|
-;;;
|
1865
|
|
-;;; STRING-LIST-TO-C-STRVEC is a function which takes a list of
|
1866
|
|
-;;; simple-strings and constructs a C-style string vector (strvec) --
|
1867
|
|
-;;; a null-terminated array of pointers to null-terminated strings.
|
1868
|
|
-;;; This function returns two values: a sap and a byte count. When the
|
1869
|
|
-;;; memory is no longer needed it should be deallocated with
|
1870
|
|
-;;; vm_deallocate.
|
1871
|
|
-;;;
|
1872
|
|
-(defun string-list-to-c-strvec (string-list)
|
1873
|
|
- ;;
|
1874
|
|
- ;; Make a pass over string-list to calculate the amount of memory
|
1875
|
|
- ;; needed to hold the strvec.
|
1876
|
|
- (let ((string-bytes 0)
|
1877
|
|
- (vec-bytes (* 4 (1+ (length string-list)))))
|
1878
|
|
- (declare (fixnum string-bytes vec-bytes))
|
1879
|
|
- (dolist (s string-list)
|
1880
|
|
- (check-type s simple-string)
|
1881
|
|
- (incf string-bytes (round-bytes-to-words (1+ (length s)))))
|
1882
|
|
- ;;
|
1883
|
|
- ;; Now allocate the memory and fill it in.
|
1884
|
|
- (let* ((total-bytes (+ string-bytes vec-bytes))
|
1885
|
|
- (vec-sap (system:allocate-system-memory total-bytes))
|
1886
|
|
- (string-sap (sap+ vec-sap vec-bytes))
|
1887
|
|
- (i 0))
|
1888
|
|
- (declare (type (and unsigned-byte fixnum) total-bytes i)
|
1889
|
|
- (type system:system-area-pointer vec-sap string-sap))
|
1890
|
|
- (dolist (s string-list)
|
1891
|
|
- (declare (simple-string s))
|
1892
|
|
- (let ((n (length s)))
|
1893
|
|
- ;;
|
1894
|
|
- ;; Blast the string into place
|
1895
|
|
- #-unicode
|
1896
|
|
- (kernel:copy-to-system-area (the simple-string s)
|
1897
|
|
- (* vm:vector-data-offset vm:word-bits)
|
1898
|
|
- string-sap 0
|
1899
|
|
- (* (1+ n) vm:byte-bits))
|
1900
|
|
- #+unicode
|
1901
|
|
- (progn
|
1902
|
|
- ;; FIXME: Do we need to apply some kind of transformation
|
1903
|
|
- ;; to convert Lisp unicode strings to C strings? Utf-8?
|
1904
|
|
- (dotimes (k n)
|
1905
|
|
- (setf (sap-ref-8 string-sap k)
|
1906
|
|
- (logand #xff (char-code (aref s k)))))
|
1907
|
|
- (setf (sap-ref-8 string-sap n) 0))
|
1908
|
|
- ;;
|
1909
|
|
- ;; Blast the pointer to the string into place
|
1910
|
|
- (setf (sap-ref-sap vec-sap i) string-sap)
|
1911
|
|
- (setf string-sap (sap+ string-sap (round-bytes-to-words (1+ n))))
|
1912
|
|
- (incf i 4)))
|
1913
|
|
- ;; Blast in last null pointer
|
1914
|
|
- (setf (sap-ref-sap vec-sap i) (int-sap 0))
|
1915
|
|
- (values vec-sap total-bytes))))
|
1916
|
|
-
|
1917
|
|
-(defun sub-unix-execve (program arg-list env-list)
|
1918
|
|
- (let ((argv nil)
|
1919
|
|
- (argv-bytes 0)
|
1920
|
|
- (envp nil)
|
1921
|
|
- (envp-bytes 0)
|
1922
|
|
- result error-code)
|
1923
|
|
- (unwind-protect
|
1924
|
|
- (progn
|
1925
|
|
- ;; Blast the stuff into the proper format
|
1926
|
|
- (multiple-value-setq
|
1927
|
|
- (argv argv-bytes)
|
1928
|
|
- (string-list-to-c-strvec arg-list))
|
1929
|
|
- (multiple-value-setq
|
1930
|
|
- (envp envp-bytes)
|
1931
|
|
- (string-list-to-c-strvec env-list))
|
1932
|
|
- ;;
|
1933
|
|
- ;; Now do the system call
|
1934
|
|
- (multiple-value-setq
|
1935
|
|
- (result error-code)
|
1936
|
|
- (int-syscall ("execve"
|
1937
|
|
- c-string system-area-pointer system-area-pointer)
|
1938
|
|
- program argv envp)))
|
1939
|
|
- ;;
|
1940
|
|
- ;; Deallocate memory
|
1941
|
|
- (when argv
|
1942
|
|
- (system:deallocate-system-memory argv argv-bytes))
|
1943
|
|
- (when envp
|
1944
|
|
- (system:deallocate-system-memory envp envp-bytes)))
|
1945
|
|
- (values result error-code)))
|
1946
|
|
-
|
1947
|
|
-;;;; UNIX-EXECVE
|
1948
|
|
-(defun unix-execve (program &optional arg-list
|
1949
|
|
- (environment *environment-list*))
|
1950
|
|
- _N"Executes the Unix execve system call. If the system call suceeds, lisp
|
1951
|
|
- will no longer be running in this process. If the system call fails this
|
1952
|
|
- function returns two values: NIL and an error code. Arg-list should be a
|
1953
|
|
- list of simple-strings which are passed as arguments to the exec'ed program.
|
1954
|
|
- Environment should be an a-list mapping symbols to simple-strings which this
|
1955
|
|
- function bashes together to form the environment for the exec'ed program."
|
1956
|
|
- (check-type program simple-string)
|
1957
|
|
- (let ((env-list (let ((envlist nil))
|
1958
|
|
- (dolist (cons environment)
|
1959
|
|
- (push (if (cdr cons)
|
1960
|
|
- (concatenate 'simple-string
|
1961
|
|
- (string (car cons)) "="
|
1962
|
|
- (cdr cons))
|
1963
|
|
- (car cons))
|
1964
|
|
- envlist))
|
1965
|
|
- envlist)))
|
1966
|
|
- (sub-unix-execve (%name->file program) arg-list env-list)))
|
1967
|
|
-
|
1968
|
|
-(defun unix-fork ()
|
1969
|
|
- _N"Executes the unix fork system call. Returns 0 in the child and the pid
|
1970
|
|
- of the child in the parent if it works, or NIL and an error number if it
|
1971
|
|
- doesn't work."
|
1972
|
|
- (int-syscall ("fork")))
|