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
57 /* Although it might seem as though this should be in some standard
58 Unix header, according to Perry E. Metzger, in a message on
59 sbcl-devel dated 2004-03-29, this is the POSIXly-correct way of
60 using environ: by an explicit declaration. -- CSR, 2004-03-30 */
61 extern char **environ
;
64 * stuff needed by CL:DIRECTORY and other Lisp directory operations
72 #ifndef LISP_FEATURE_WIN32
73 /* a wrapped version of readlink(2):
74 * -- If path isn't a symlink, or is a broken symlink, return 0.
75 * -- If path is a symlink, return a newly allocated string holding
76 * the thing it's linked to. */
78 wrapped_readlink(char *path
)
80 int bufsiz
= strlen(path
) + 16;
82 char *result
= malloc(bufsiz
);
83 int n_read
= readlink(path
, result
, bufsiz
);
87 } else if (n_read
< bufsiz
) {
99 * realpath(3), including a wrapper for Windows.
101 char * sb_realpath (char *path
)
103 #ifndef LISP_FEATURE_WIN32
107 if ((ret
= calloc(PATH_MAX
, sizeof(char))) == NULL
)
109 if (realpath(path
, ret
) == NULL
) {
121 if ((ret
= calloc(MAX_PATH
, sizeof(char))) == NULL
)
123 if (GetFullPathName(path
, MAX_PATH
, ret
, &cp
) == 0) {
133 /* readdir, closedir, and dirent name accessor. The first three are not strictly
134 * necessary, but should save us some #!+netbsd in the build, and this also allows
135 * building Windows versions using the non-ANSI variants of FindFirstFile &co
136 * under the same API. (Use a structure that appends the handle to the WIN32_FIND_DATA
137 * as the return value from sb_opendir, on sb_readdir grab the name from the previous
138 * call and save the new one.) Nikodemus thought he would have to do that to support
139 * DIRECTORY on UNC paths, but turns out opendir &co do TRT on Windows already -- so
140 * leaving that bit of tedium for a later date, once we figure out the whole *A vs. *W
141 * issue out properly. ...FIXME, obviously, as per above.
143 * Once that is done, the lisp side functions are best named OS-OPENDIR, etc.
146 sb_opendir(char * name
)
148 return opendir(name
);
151 extern struct dirent
*
152 sb_readdir(DIR * dirp
)
154 /* NULL returned from readdir() means it reached the end, NULL and
155 non-zero errno means an error occured.
156 When no error has occured, errno is not changed.
157 Set it to 0 beforehand. */
159 return readdir(dirp
);
163 sb_closedir(DIR * dirp
)
165 return closedir(dirp
);
169 sb_dirent_name(struct dirent
* ent
)
179 copy_to_stat_wrapper(struct stat_wrapper
*to
, struct stat
*from
)
181 #define FROB(stem) to->wrapped_st_##stem = from->st_##stem
182 #ifndef LISP_FEATURE_WIN32
183 #define FROB2(stem) to->wrapped_st_##stem = from->st_##stem
185 #define FROB2(stem) to->wrapped_st_##stem = 0;
204 stat_wrapper(const char *file_name
, struct stat_wrapper
*buf
)
206 struct stat real_buf
;
209 #ifdef LISP_FEATURE_WIN32
211 * Windows won't match the last component of a pathname if there
212 * is a trailing #\/ or #\\, except if it's <drive>:\ or <drive>:/
213 * in which case it behaves the other way around. So we remove the
214 * trailing directory separator unless we are being passed just a
215 * drive name (e.g. "c:\\"). Some, but not all, of this
216 * strangeness is documented at Microsoft's support site (as of
218 * <http://support.microsoft.com/default.aspx?scid=kb;en-us;168439>)
220 char file_buf
[MAX_PATH
];
221 strcpy(file_buf
, file_name
);
222 int len
= strlen(file_name
);
223 if (len
!= 0 && (file_name
[len
-1] == '/' || file_name
[len
-1] == '\\') &&
224 !(len
== 3 && file_name
[1] == ':' && isalpha(file_name
[0])))
225 file_buf
[len
-1] = '\0';
226 file_name
= file_buf
;
229 if ((ret
= stat(file_name
,&real_buf
)) >= 0)
230 copy_to_stat_wrapper(buf
, &real_buf
);
234 #ifndef LISP_FEATURE_WIN32
236 lstat_wrapper(const char *file_name
, struct stat_wrapper
*buf
)
238 struct stat real_buf
;
240 if ((ret
= lstat(file_name
,&real_buf
)) >= 0)
241 copy_to_stat_wrapper(buf
, &real_buf
);
245 /* cleaner to do it here than in Lisp */
246 int lstat_wrapper(const char *file_name
, struct stat_wrapper
*buf
)
248 return stat_wrapper(file_name
, buf
);
253 fstat_wrapper(int filedes
, struct stat_wrapper
*buf
)
255 struct stat real_buf
;
257 if ((ret
= fstat(filedes
,&real_buf
)) >= 0)
258 copy_to_stat_wrapper(buf
, &real_buf
);
262 /* A wrapper for mkstemp(3), for two reasons: (1) mkstemp does not
263 exist on Windows; (2) by passing down a mode_t, we don't need a
264 binding to chmod in SB-UNIX, and need not concern ourselves with
265 umask issues if we want to use mkstemp to make new files in
266 OPEN as implied by the cagey remark (in 'unix.lisp') that
267 "There are good reasons to implement some OPEN options with a[n]
268 mkstemp(3)-like routine, but we don't do that yet." */
270 int sb_mkstemp (char *template, mode_t mode
) {
272 #ifdef LISP_FEATURE_WIN32
273 #define PATHNAME_BUFFER_SIZE MAX_PATH
274 char buf
[PATHNAME_BUFFER_SIZE
];
277 /* Fruit fallen from the tree: for people who like
278 microoptimizations, we might not need to copy the whole
279 template on every loop, but only the last several characters.
280 But I didn't feel like testing the boundary cases in Windows's
282 strncpy(buf
, template, PATHNAME_BUFFER_SIZE
);
283 buf
[PATHNAME_BUFFER_SIZE
-1]=0; /* force NULL-termination */
285 if ((fd
=open(buf
, O_CREAT
|O_EXCL
|O_RDWR
, mode
))!=-1) {
286 strcpy(template, buf
);
294 #undef PATHNAME_BUFFER_SIZE
296 /* It makes no sense to reimplement mkstemp() with logic susceptible
297 to the exploit that mkstemp() was designed to avoid.
298 Unfortunately, there is a subtle bug in this more nearly correct technique.
299 open() uses the given creation mode ANDed with the process umask,
300 but fchmod() uses exactly the specified mode. Attempting to perform the
301 masking operation manually would result in another race: you can't obtain
302 the current mask except by calling umask(), which both sets and gets it.
303 But since RUN-PROGRAM is the only use of this, and the mode given is #o600
304 which is the default for mkstemp(), RUN-PROGRAM should be indifferent.
305 [The GNU C library documents but doesn't implement getumask() by the way.]
306 So we're patching a security hole with a known innocuous design flaw
307 by necessity to avoid the gcc linker warning that
308 "the use of `mktemp' is dangerous, better use `mkstemp'" */
309 fd
= mkstemp(template);
310 if (fd
!= -1 && fchmod(fd
, mode
) == -1) {
311 close(fd
); // got a file descriptor but couldn't fchmod() it
323 #ifndef LISP_FEATURE_WIN32
324 /* Return a newly-allocated string holding the username for "uid", or
325 * NULL if there's no such user.
327 * KLUDGE: We also return NULL if malloc() runs out of memory
328 * (returning strdup() result) since it's not clear how to handle that
329 * error better. -- WHN 2001-12-28 */
331 uid_username(int uid
)
333 struct passwd
*p
= getpwuid(uid
);
335 /* The object *p is a static struct which'll be overwritten by
336 * the next call to getpwuid(), so it'd be unsafe to return
337 * p->pw_name without copying. */
338 return strdup(p
->pw_name
);
345 passwd_homedir(struct passwd
*p
)
348 /* Let's be careful about this, shall we? */
349 size_t len
= strlen(p
->pw_dir
);
350 if (p
->pw_dir
[len
-1] == '/') {
351 return strdup(p
->pw_dir
);
353 char *result
= malloc(len
+ 2);
355 unsigned int nchars
= sprintf(result
,"%s/",p
->pw_dir
);
356 if (nchars
== len
+ 1) {
371 user_homedir(char *name
)
373 return passwd_homedir(getpwnam(name
));
377 uid_homedir(uid_t uid
)
379 return passwd_homedir(getpwuid(uid
));
381 #endif /* !LISP_FEATURE_WIN32 */
384 * functions to get miscellaneous C-level variables
386 * (Doing this by calling functions lets us borrow the smarts of the C
387 * linker, so that things don't blow up when libc versions and thus
388 * variable locations change between compile time and run time.)
397 #ifdef LISP_FEATURE_WIN32
401 * faked-up implementation of select(). Right now just enough to get through
404 int sb_select(int top_fd
, DWORD
*read_set
, DWORD
*write_set
, DWORD
*except_set
, time_t *timeout
)
407 * FIXME: Going forward, we may want to use MsgWaitForMultipleObjects
408 * in order to support a windows message loop inside serve-event.
410 HANDLE handles
[MAXIMUM_WAIT_OBJECTS
];
411 int fds
[MAXIMUM_WAIT_OBJECTS
];
420 for (i
= 0; i
< top_fd
; i
++) {
421 if (except_set
) except_set
[i
>> 5] = 0;
422 if (write_set
&& (write_set
[i
>> 5] & (1 << (i
& 31)))) polling_write
= 1;
423 if (read_set
[i
>> 5] & (1 << (i
& 31))) {
424 read_set
[i
>> 5] &= ~(1 << (i
& 31));
425 fds
[num_handles
] = i
;
426 handles
[num_handles
++] = (HANDLE
) _get_osfhandle(i
);
430 win_timeout
= INFINITE
;
431 if (timeout
) win_timeout
= (timeout
[0] * 1000) + timeout
[1];
433 /* Last parameter here is timeout in milliseconds. */
434 /* retval = WaitForMultipleObjects(num_handles, handles, 0, INFINITE); */
435 retval
= WaitForMultipleObjects(num_handles
, handles
, 0, win_timeout
);
437 if (retval
< WAIT_ABANDONED
) {
438 /* retval, at this point, is the index of the single live HANDLE/fd. */
439 read_set
[fds
[retval
] >> 5] |= (1 << (fds
[retval
] & 31));
442 return polling_write
;
446 * Windows doesn't have gettimeofday(), and we need it for the compiler,
447 * for serve-event, and for a couple other things. We don't need a timezone
448 * yet, however, and the closest we can easily get to a timeval is the
449 * seconds part. So that's what we do.
451 #define UNIX_EPOCH_FILETIME 116444736000000000ULL
453 int sb_gettimeofday(long *timeval
, long *timezone
)
457 GetSystemTimeAsFileTime(&ft
);
458 uft
.LowPart
= ft
.dwLowDateTime
;
459 uft
.HighPart
= ft
.dwHighDateTime
;
460 uft
.QuadPart
-= UNIX_EPOCH_FILETIME
;
461 timeval
[0] = uft
.QuadPart
/ 10000000;
462 timeval
[1] = (uft
.QuadPart
% 10000000)/10;
469 /* We will need to define these things or their equivalents for Win32
470 eventually, but for now let's get it working for everyone else. */
471 #ifndef LISP_FEATURE_WIN32
472 /* From SB-BSD-SOCKETS, to get h_errno */
478 /* From SB-POSIX, wait-macros */
479 int wifexited(int status
) {
480 return WIFEXITED(status
);
482 int wexitstatus(int status
) {
483 return WEXITSTATUS(status
);
485 int wifsignaled(int status
) {
486 return WIFSIGNALED(status
);
488 int wtermsig(int status
) {
489 return WTERMSIG(status
);
491 int wifstopped(int status
) {
492 return WIFSTOPPED(status
);
494 int wstopsig(int status
) {
495 return WSTOPSIG(status
);
497 /* FIXME: POSIX also defines WIFCONTINUED, but that appears not to
498 exist on at least Linux... */
499 #endif /* !LISP_FEATURE_WIN32 */
501 /* From SB-POSIX, stat-macros */
502 int s_isreg(mode_t mode
)
504 return S_ISREG(mode
);
506 int s_isdir(mode_t mode
)
508 return S_ISDIR(mode
);
510 int s_ischr(mode_t mode
)
512 return S_ISCHR(mode
);
514 int s_isblk(mode_t mode
)
516 return S_ISBLK(mode
);
518 int s_isfifo(mode_t mode
)
520 return S_ISFIFO(mode
);
522 #ifndef LISP_FEATURE_WIN32
523 int s_islnk(mode_t mode
)
526 return S_ISLNK(mode
);
528 return ((mode
& S_IFMT
) == S_IFLNK
);
531 int s_issock(mode_t mode
)
534 return S_ISSOCK(mode
);
536 return ((mode
& S_IFMT
) == S_IFSOCK
);
539 #endif /* !LISP_FEATURE_WIN32 */
541 #ifndef LISP_FEATURE_WIN32
542 int sb_getrusage(int who
, struct rusage
*rusage
)
544 return getrusage(who
, rusage
);
547 int sb_gettimeofday(struct timeval
*tp
, void *tzp
)
549 return gettimeofday(tp
, tzp
);
552 #ifndef LISP_FEATURE_DARWIN /* reimplements nanosleep in darwin-os.c */
553 int sb_nanosleep(struct timespec
*rqtp
, struct timespec
*rmtp
)
555 return nanosleep(rqtp
, rmtp
);
559 int sb_select(int nfds
, fd_set
*readfds
, fd_set
*writefds
, fd_set
*exceptfds
,
560 struct timeval
*timeout
)
562 return select(nfds
, readfds
, writefds
, exceptfds
, timeout
);
565 int sb_getitimer(int which
, struct itimerval
*value
)
567 return getitimer(which
, value
);
570 int sb_setitimer(int which
, struct itimerval
*value
, struct itimerval
*ovalue
)
572 return setitimer(which
, value
, ovalue
);
575 int sb_utimes(char *path
, struct timeval times
[2])
577 return utimes(path
, times
);
579 #else /* !LISP_FEATURE_WIN32 */
580 #define SB_TRIG_WRAPPER(name) \
581 double sb_##name (double x) { \
584 SB_TRIG_WRAPPER(acos
)
585 SB_TRIG_WRAPPER(asin
)
586 SB_TRIG_WRAPPER(cosh
)
587 SB_TRIG_WRAPPER(sinh
)
588 SB_TRIG_WRAPPER(tanh
)
589 SB_TRIG_WRAPPER(asinh
)
590 SB_TRIG_WRAPPER(acosh
)
591 SB_TRIG_WRAPPER(atanh
)
593 double sb_hypot (double x
, double y
) {