2 * wrappers around low-level operations to provide a simpler interface
3 * to the operations that Lisp (and some contributed modules) needs.
5 * The functions in this file are typically called directly from Lisp.
6 * Thus, when their signature changes, they don't need updates in a .h
7 * file somewhere, but they do need updates in the Lisp code. FIXME:
8 * It would be nice to enforce this at compile time. It mighn't even
9 * be all that hard: make the cross-compiler versions of DEFINE-ALIEN-FOO
10 * macros accumulate strings in a list which then gets written out at
11 * the end of sbcl2.h at the end of cross-compilation, then rerun
12 * 'make' in src/runtime/ using the new sbcl2.h as sbcl.h (and make
13 * sure that all the files in src/runtime/ include sbcl.h). */
16 * This software is part of the SBCL system. See the README file for
19 * This software is derived from the CMU CL system, which was
20 * written at Carnegie Mellon University and released into the
21 * public domain. The software is in the public domain and is
22 * provided with absolutely no warranty. See the COPYING and CREDITS
23 * files for more information.
28 #include <sys/types.h>
39 #ifndef LISP_FEATURE_WIN32
43 #include <sys/resource.h>
48 #if defined(LISP_FEATURE_WIN32)
49 #define WIN32_LEAN_AND_MEAN
58 /* Although it might seem as though this should be in some standard
59 Unix header, according to Perry E. Metzger, in a message on
60 sbcl-devel dated 2004-03-29, this is the POSIXly-correct way of
61 using environ: by an explicit declaration. -- CSR, 2004-03-30 */
62 extern char **environ
;
65 * stuff needed by CL:DIRECTORY and other Lisp directory operations
73 #ifndef LISP_FEATURE_WIN32
74 /* a wrapped version of readlink(2):
75 * -- If path isn't a symlink, or is a broken symlink, return 0.
76 * -- If path is a symlink, return a newly allocated string holding
77 * the thing it's linked to. */
79 wrapped_readlink(char *path
)
81 int bufsiz
= strlen(path
) + 16;
83 char *result
= malloc(bufsiz
);
84 int n_read
= readlink(path
, result
, bufsiz
);
88 } else if (n_read
< bufsiz
) {
100 * realpath(3), including a wrapper for Windows.
102 char * sb_realpath (char *path
)
104 #ifndef LISP_FEATURE_WIN32
108 if ((ret
= calloc(PATH_MAX
, sizeof(char))) == NULL
)
110 if (realpath(path
, ret
) == NULL
) {
122 if ((ret
= calloc(MAX_PATH
, sizeof(char))) == NULL
)
124 if (GetFullPathName(path
, MAX_PATH
, ret
, &cp
) == 0) {
134 /* readdir, closedir, and dirent name accessor. The first three are not strictly
135 * necessary, but should save us some #!+netbsd in the build, and this also allows
136 * building Windows versions using the non-ANSI variants of FindFirstFile &co
137 * under the same API. (Use a structure that appends the handle to the WIN32_FIND_DATA
138 * as the return value from sb_opendir, on sb_readdir grab the name from the previous
139 * call and save the new one.) Nikodemus thought he would have to do that to support
140 * DIRECTORY on UNC paths, but turns out opendir &co do TRT on Windows already -- so
141 * leaving that bit of tedium for a later date, once we figure out the whole *A vs. *W
142 * issue out properly. ...FIXME, obviously, as per above.
144 * Once that is done, the lisp side functions are best named OS-OPENDIR, etc.
147 sb_opendir(char * name
)
149 return opendir(name
);
152 extern struct dirent
*
153 sb_readdir(DIR * dirp
)
155 /* NULL returned from readdir() means it reached the end, NULL and
156 non-zero errno means an error occured.
157 When no error has occured, errno is not changed.
158 Set it to 0 beforehand. */
160 return readdir(dirp
);
164 sb_closedir(DIR * dirp
)
166 return closedir(dirp
);
170 sb_dirent_name(struct dirent
* ent
)
180 copy_to_stat_wrapper(struct stat_wrapper
*to
, struct stat
*from
)
182 #define FROB(stem) to->wrapped_st_##stem = from->st_##stem
183 #ifndef LISP_FEATURE_WIN32
184 #define FROB2(stem) to->wrapped_st_##stem = from->st_##stem
186 #define FROB2(stem) to->wrapped_st_##stem = 0;
205 stat_wrapper(const char *file_name
, struct stat_wrapper
*buf
)
207 struct stat real_buf
;
210 #ifdef LISP_FEATURE_WIN32
212 * Windows won't match the last component of a pathname if there
213 * is a trailing #\/ or #\\, except if it's <drive>:\ or <drive>:/
214 * in which case it behaves the other way around. So we remove the
215 * trailing directory separator unless we are being passed just a
216 * drive name (e.g. "c:\\"). Some, but not all, of this
217 * strangeness is documented at Microsoft's support site (as of
219 * <http://support.microsoft.com/default.aspx?scid=kb;en-us;168439>)
221 char file_buf
[MAX_PATH
];
222 strcpy(file_buf
, file_name
);
223 int len
= strlen(file_name
);
224 if (len
!= 0 && (file_name
[len
-1] == '/' || file_name
[len
-1] == '\\') &&
225 !(len
== 3 && file_name
[1] == ':' && isalpha(file_name
[0])))
226 file_buf
[len
-1] = '\0';
227 file_name
= file_buf
;
230 if ((ret
= stat(file_name
,&real_buf
)) >= 0)
231 copy_to_stat_wrapper(buf
, &real_buf
);
235 #ifndef LISP_FEATURE_WIN32
237 lstat_wrapper(const char *file_name
, struct stat_wrapper
*buf
)
239 struct stat real_buf
;
241 if ((ret
= lstat(file_name
,&real_buf
)) >= 0)
242 copy_to_stat_wrapper(buf
, &real_buf
);
246 /* cleaner to do it here than in Lisp */
247 int lstat_wrapper(const char *file_name
, struct stat_wrapper
*buf
)
249 return stat_wrapper(file_name
, buf
);
254 fstat_wrapper(int filedes
, struct stat_wrapper
*buf
)
256 struct stat real_buf
;
258 if ((ret
= fstat(filedes
,&real_buf
)) >= 0)
259 copy_to_stat_wrapper(buf
, &real_buf
);
263 /* A wrapper for mkstemp(3), for two reasons: (1) mkstemp does not
264 exist on Windows; (2) by passing down a mode_t, we don't need a
265 binding to chmod in SB-UNIX, and need not concern ourselves with
266 umask issues if we want to use mkstemp to make new files in
267 OPEN as implied by the cagey remark (in 'unix.lisp') that
268 "There are good reasons to implement some OPEN options with a[n]
269 mkstemp(3)-like routine, but we don't do that yet." */
271 int sb_mkstemp (char *template, mode_t mode
) {
273 #ifdef LISP_FEATURE_WIN32
274 #define PATHNAME_BUFFER_SIZE MAX_PATH
275 char buf
[PATHNAME_BUFFER_SIZE
];
278 /* Fruit fallen from the tree: for people who like
279 microoptimizations, we might not need to copy the whole
280 template on every loop, but only the last several characters.
281 But I didn't feel like testing the boundary cases in Windows's
283 strncpy(buf
, template, PATHNAME_BUFFER_SIZE
);
284 buf
[PATHNAME_BUFFER_SIZE
-1]=0; /* force NULL-termination */
286 if ((fd
=open(buf
, O_CREAT
|O_EXCL
|O_RDWR
, mode
))!=-1) {
287 strcpy(template, buf
);
295 #undef PATHNAME_BUFFER_SIZE
297 /* It makes no sense to reimplement mkstemp() with logic susceptible
298 to the exploit that mkstemp() was designed to avoid.
299 Unfortunately, there is a subtle bug in this more nearly correct technique.
300 open() uses the given creation mode ANDed with the process umask,
301 but fchmod() uses exactly the specified mode. Attempting to perform the
302 masking operation manually would result in another race: you can't obtain
303 the current mask except by calling umask(), which both sets and gets it.
304 But since RUN-PROGRAM is the only use of this, and the mode given is #o600
305 which is the default for mkstemp(), RUN-PROGRAM should be indifferent.
306 [The GNU C library documents but doesn't implement getumask() by the way.]
307 So we're patching a security hole with a known innocuous design flaw
308 by necessity to avoid the gcc linker warning that
309 "the use of `mktemp' is dangerous, better use `mkstemp'" */
310 fd
= mkstemp(template);
311 if (fd
!= -1 && fchmod(fd
, mode
) == -1) {
312 close(fd
); // got a file descriptor but couldn't fchmod() it
324 #ifndef LISP_FEATURE_WIN32
325 /* Return a newly-allocated string holding the username for "uid", or
326 * NULL if there's no such user.
328 * KLUDGE: We also return NULL if malloc() runs out of memory
329 * (returning strdup() result) since it's not clear how to handle that
330 * error better. -- WHN 2001-12-28 */
332 uid_username(int uid
)
334 struct passwd
*p
= getpwuid(uid
);
336 /* The object *p is a static struct which'll be overwritten by
337 * the next call to getpwuid(), so it'd be unsafe to return
338 * p->pw_name without copying. */
339 return strdup(p
->pw_name
);
346 passwd_homedir(struct passwd
*p
)
349 /* Let's be careful about this, shall we? */
350 size_t len
= strlen(p
->pw_dir
);
351 if (p
->pw_dir
[len
-1] == '/') {
352 return strdup(p
->pw_dir
);
354 char *result
= malloc(len
+ 2);
356 unsigned int nchars
= sprintf(result
,"%s/",p
->pw_dir
);
357 if (nchars
== len
+ 1) {
372 user_homedir(char *name
)
374 return passwd_homedir(getpwnam(name
));
378 uid_homedir(uid_t uid
)
380 return passwd_homedir(getpwuid(uid
));
382 #endif /* !LISP_FEATURE_WIN32 */
385 * functions to get miscellaneous C-level variables
387 * (Doing this by calling functions lets us borrow the smarts of the C
388 * linker, so that things don't blow up when libc versions and thus
389 * variable locations change between compile time and run time.)
398 #ifdef LISP_FEATURE_WIN32
402 * faked-up implementation of select(). Right now just enough to get through
405 int sb_select(int top_fd
, DWORD
*read_set
, DWORD
*write_set
, DWORD
*except_set
, time_t *timeout
)
408 * FIXME: Going forward, we may want to use MsgWaitForMultipleObjects
409 * in order to support a windows message loop inside serve-event.
411 HANDLE handles
[MAXIMUM_WAIT_OBJECTS
];
412 int fds
[MAXIMUM_WAIT_OBJECTS
];
421 for (i
= 0; i
< top_fd
; i
++) {
422 if (except_set
) except_set
[i
>> 5] = 0;
423 if (write_set
&& (write_set
[i
>> 5] & (1 << (i
& 31)))) polling_write
= 1;
424 if (read_set
[i
>> 5] & (1 << (i
& 31))) {
425 read_set
[i
>> 5] &= ~(1 << (i
& 31));
426 fds
[num_handles
] = i
;
427 handles
[num_handles
++] = (HANDLE
) _get_osfhandle(i
);
431 win_timeout
= INFINITE
;
432 if (timeout
) win_timeout
= (timeout
[0] * 1000) + timeout
[1];
434 /* Last parameter here is timeout in milliseconds. */
435 /* retval = WaitForMultipleObjects(num_handles, handles, 0, INFINITE); */
436 retval
= WaitForMultipleObjects(num_handles
, handles
, 0, win_timeout
);
438 if (retval
< WAIT_ABANDONED
) {
439 /* retval, at this point, is the index of the single live HANDLE/fd. */
440 read_set
[fds
[retval
] >> 5] |= (1 << (fds
[retval
] & 31));
443 return polling_write
;
447 * Windows doesn't have gettimeofday(), and we need it for the compiler,
448 * for serve-event, and for a couple other things. We don't need a timezone
449 * yet, however, and the closest we can easily get to a timeval is the
450 * seconds part. So that's what we do.
452 #define UNIX_EPOCH_FILETIME 116444736000000000ULL
454 int sb_gettimeofday(long *timeval
, long *timezone
)
458 GetSystemTimeAsFileTime(&ft
);
459 uft
.LowPart
= ft
.dwLowDateTime
;
460 uft
.HighPart
= ft
.dwHighDateTime
;
461 uft
.QuadPart
-= UNIX_EPOCH_FILETIME
;
462 timeval
[0] = uft
.QuadPart
/ 10000000;
463 timeval
[1] = (uft
.QuadPart
% 10000000)/10;
470 /* We will need to define these things or their equivalents for Win32
471 eventually, but for now let's get it working for everyone else. */
472 #ifndef LISP_FEATURE_WIN32
473 /* From SB-BSD-SOCKETS, to get h_errno */
479 /* From SB-POSIX, wait-macros */
480 int wifexited(int status
) {
481 return WIFEXITED(status
);
483 int wexitstatus(int status
) {
484 return WEXITSTATUS(status
);
486 int wifsignaled(int status
) {
487 return WIFSIGNALED(status
);
489 int wtermsig(int status
) {
490 return WTERMSIG(status
);
492 int wifstopped(int status
) {
493 return WIFSTOPPED(status
);
495 int wstopsig(int status
) {
496 return WSTOPSIG(status
);
498 /* FIXME: POSIX also defines WIFCONTINUED, but that appears not to
499 exist on at least Linux... */
500 #endif /* !LISP_FEATURE_WIN32 */
502 /* From SB-POSIX, stat-macros */
503 int s_isreg(mode_t mode
)
505 return S_ISREG(mode
);
507 int s_isdir(mode_t mode
)
509 return S_ISDIR(mode
);
511 int s_ischr(mode_t mode
)
513 return S_ISCHR(mode
);
515 int s_isblk(mode_t mode
)
517 return S_ISBLK(mode
);
519 int s_isfifo(mode_t mode
)
521 return S_ISFIFO(mode
);
523 #ifndef LISP_FEATURE_WIN32
524 int s_islnk(mode_t mode
)
527 return S_ISLNK(mode
);
529 return ((mode
& S_IFMT
) == S_IFLNK
);
532 int s_issock(mode_t mode
)
535 return S_ISSOCK(mode
);
537 return ((mode
& S_IFMT
) == S_IFSOCK
);
540 #endif /* !LISP_FEATURE_WIN32 */
542 #ifndef LISP_FEATURE_WIN32
543 int sb_getrusage(int who
, struct rusage
*rusage
)
545 return getrusage(who
, rusage
);
548 int sb_gettimeofday(struct timeval
*tp
, void *tzp
)
550 return gettimeofday(tp
, tzp
);
553 int sb_nanosleep(struct timespec
*rqtp
, struct timespec
*rmtp
)
555 return nanosleep(rqtp
, rmtp
);
558 int sb_select(int nfds
, fd_set
*readfds
, fd_set
*writefds
, fd_set
*exceptfds
,
559 struct timeval
*timeout
)
561 return select(nfds
, readfds
, writefds
, exceptfds
, timeout
);
564 int sb_getitimer(int which
, struct itimerval
*value
)
566 return getitimer(which
, value
);
569 int sb_setitimer(int which
, struct itimerval
*value
, struct itimerval
*ovalue
)
571 return setitimer(which
, value
, ovalue
);
574 int sb_utimes(char *path
, struct timeval times
[2])
576 return utimes(path
, times
);
578 #else /* !LISP_FEATURE_WIN32 */
579 #define SB_TRIG_WRAPPER(name) \
580 double sb_##name (double x) { \
583 SB_TRIG_WRAPPER(acos
)
584 SB_TRIG_WRAPPER(asin
)
585 SB_TRIG_WRAPPER(cosh
)
586 SB_TRIG_WRAPPER(sinh
)
587 SB_TRIG_WRAPPER(tanh
)
588 SB_TRIG_WRAPPER(asinh
)
589 SB_TRIG_WRAPPER(acosh
)
590 SB_TRIG_WRAPPER(atanh
)
592 double sb_hypot (double x
, double y
) {