x86-64: Integrate Paul Khuong's interleaved raw slot feature.
[sbcl.git] / src / runtime / wrap.c
blob61827b1a48836abc30fe40e58d2f8d299fe7aacf
1 /*
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
17 * more information.
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.
26 #include "sbcl.h"
28 #include <sys/types.h>
29 #include <dirent.h>
30 #include <sys/stat.h>
31 #include <stdlib.h>
32 #include <string.h>
33 #include <ctype.h>
34 #include <unistd.h>
35 #include <errno.h>
36 #include <limits.h>
37 #include <fcntl.h>
39 #ifndef LISP_FEATURE_WIN32
40 #include <pwd.h>
41 #include <time.h>
42 #include <sys/wait.h>
43 #include <sys/resource.h>
44 #include <netdb.h>
45 #endif
46 #include <stdio.h>
48 #if defined(LISP_FEATURE_WIN32)
49 #define WIN32_LEAN_AND_MEAN
50 #include <errno.h>
51 #endif
53 #include "runtime.h"
54 #include "util.h"
55 #include "wrap.h"
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
69 * readlink(2) stuff
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. */
77 char *
78 wrapped_readlink(char *path)
80 int bufsiz = strlen(path) + 16;
81 while (1) {
82 char *result = malloc(bufsiz);
83 int n_read = readlink(path, result, bufsiz);
84 if (n_read < 0) {
85 free(result);
86 return 0;
87 } else if (n_read < bufsiz) {
88 result[n_read] = 0;
89 return result;
90 } else {
91 free(result);
92 bufsiz *= 2;
96 #endif
99 * realpath(3), including a wrapper for Windows.
101 char * sb_realpath (char *path)
103 #ifndef LISP_FEATURE_WIN32
104 char *ret;
105 int errnum;
107 if ((ret = calloc(PATH_MAX, sizeof(char))) == NULL)
108 return NULL;
109 if (realpath(path, ret) == NULL) {
110 errnum = errno;
111 free(ret);
112 errno = errnum;
113 return NULL;
115 return(ret);
116 #else
117 char *ret;
118 char *cp;
119 int errnum;
121 if ((ret = calloc(MAX_PATH, sizeof(char))) == NULL)
122 return NULL;
123 if (GetFullPathName(path, MAX_PATH, ret, &cp) == 0) {
124 errnum = errno;
125 free(ret);
126 errno = errnum;
127 return NULL;
129 return(ret);
130 #endif
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.
145 extern DIR *
146 sb_opendir(char * name)
148 return opendir(name);
151 extern struct dirent *
152 sb_readdir(DIR * dirp)
154 return readdir(dirp);
157 extern int
158 sb_closedir(DIR * dirp)
160 return closedir(dirp);
163 extern char *
164 sb_dirent_name(struct dirent * ent)
166 return ent->d_name;
170 * stat(2) stuff
173 static void
174 copy_to_stat_wrapper(struct stat_wrapper *to, struct stat *from)
176 #define FROB(stem) to->wrapped_st_##stem = from->st_##stem
177 #ifndef LISP_FEATURE_WIN32
178 #define FROB2(stem) to->wrapped_st_##stem = from->st_##stem
179 #else
180 #define FROB2(stem) to->wrapped_st_##stem = 0;
181 #endif
182 FROB(dev);
183 FROB2(ino);
184 FROB(mode);
185 FROB(nlink);
186 FROB2(uid);
187 FROB2(gid);
188 FROB(rdev);
189 FROB(size);
190 FROB2(blksize);
191 FROB2(blocks);
192 FROB(atime);
193 FROB(mtime);
194 FROB(ctime);
195 #undef FROB
199 stat_wrapper(const char *file_name, struct stat_wrapper *buf)
201 struct stat real_buf;
202 int ret;
204 #ifdef LISP_FEATURE_WIN32
206 * Windows won't match the last component of a pathname if there
207 * is a trailing #\/ or #\\, except if it's <drive>:\ or <drive>:/
208 * in which case it behaves the other way around. So we remove the
209 * trailing directory separator unless we are being passed just a
210 * drive name (e.g. "c:\\"). Some, but not all, of this
211 * strangeness is documented at Microsoft's support site (as of
212 * 2006-01-08, at
213 * <http://support.microsoft.com/default.aspx?scid=kb;en-us;168439>)
215 char file_buf[MAX_PATH];
216 strcpy(file_buf, file_name);
217 int len = strlen(file_name);
218 if (len != 0 && (file_name[len-1] == '/' || file_name[len-1] == '\\') &&
219 !(len == 3 && file_name[1] == ':' && isalpha(file_name[0])))
220 file_buf[len-1] = '\0';
221 file_name = file_buf;
222 #endif
224 if ((ret = stat(file_name,&real_buf)) >= 0)
225 copy_to_stat_wrapper(buf, &real_buf);
226 return ret;
229 #ifndef LISP_FEATURE_WIN32
231 lstat_wrapper(const char *file_name, struct stat_wrapper *buf)
233 struct stat real_buf;
234 int ret;
235 if ((ret = lstat(file_name,&real_buf)) >= 0)
236 copy_to_stat_wrapper(buf, &real_buf);
237 return ret;
239 #else
240 /* cleaner to do it here than in Lisp */
241 int lstat_wrapper(const char *file_name, struct stat_wrapper *buf)
243 return stat_wrapper(file_name, buf);
245 #endif
248 fstat_wrapper(int filedes, struct stat_wrapper *buf)
250 struct stat real_buf;
251 int ret;
252 if ((ret = fstat(filedes,&real_buf)) >= 0)
253 copy_to_stat_wrapper(buf, &real_buf);
254 return ret;
257 /* A wrapper for mkstemp(3), for two reasons: (1) mkstemp does not
258 exist on Windows; (2) by passing down a mode_t, we don't need a
259 binding to chmod in SB-UNIX, and need not concern ourselves with
260 umask issues if we want to use mkstemp to make new files in
261 OPEN as implied by the cagey remark (in 'unix.lisp') that
262 "There are good reasons to implement some OPEN options with a[n]
263 mkstemp(3)-like routine, but we don't do that yet." */
265 int sb_mkstemp (char *template, mode_t mode) {
266 int fd;
267 #ifdef LISP_FEATURE_WIN32
268 #define PATHNAME_BUFFER_SIZE MAX_PATH
269 char buf[PATHNAME_BUFFER_SIZE];
271 while (1) {
272 /* Fruit fallen from the tree: for people who like
273 microoptimizations, we might not need to copy the whole
274 template on every loop, but only the last several characters.
275 But I didn't feel like testing the boundary cases in Windows's
276 _mktemp. */
277 strncpy(buf, template, PATHNAME_BUFFER_SIZE);
278 buf[PATHNAME_BUFFER_SIZE-1]=0; /* force NULL-termination */
279 if (_mktemp(buf)) {
280 if ((fd=open(buf, O_CREAT|O_EXCL|O_RDWR, mode))!=-1) {
281 strcpy(template, buf);
282 return (fd);
283 } else
284 if (errno != EEXIST)
285 return (-1);
286 } else
287 return (-1);
289 #undef PATHNAME_BUFFER_SIZE
290 #else
291 /* It makes no sense to reimplement mkstemp() with logic susceptible
292 to the exploit that mkstemp() was designed to avoid.
293 Unfortunately, there is a subtle bug in this more nearly correct technique.
294 open() uses the given creation mode ANDed with the process umask,
295 but fchmod() uses exactly the specified mode. Attempting to perform the
296 masking operation manually would result in another race: you can't obtain
297 the current mask except by calling umask(), which both sets and gets it.
298 But since RUN-PROGRAM is the only use of this, and the mode given is #o600
299 which is the default for mkstemp(), RUN-PROGRAM should be indifferent.
300 [The GNU C library documents but doesn't implement getumask() by the way.]
301 So we're patching a security hole with a known innocuous design flaw
302 by necessity to avoid the gcc linker warning that
303 "the use of `mktemp' is dangerous, better use `mkstemp'" */
304 fd = mkstemp(template);
305 if (fd != -1 && fchmod(fd, mode) == -1) {
306 close(fd); // got a file descriptor but couldn't fchmod() it
307 return -1;
309 return fd;
310 #endif
315 * getpwuid() stuff
318 #ifndef LISP_FEATURE_WIN32
319 /* Return a newly-allocated string holding the username for "uid", or
320 * NULL if there's no such user.
322 * KLUDGE: We also return NULL if malloc() runs out of memory
323 * (returning strdup() result) since it's not clear how to handle that
324 * error better. -- WHN 2001-12-28 */
325 char *
326 uid_username(int uid)
328 struct passwd *p = getpwuid(uid);
329 if (p) {
330 /* The object *p is a static struct which'll be overwritten by
331 * the next call to getpwuid(), so it'd be unsafe to return
332 * p->pw_name without copying. */
333 return strdup(p->pw_name);
334 } else {
335 return 0;
339 char *
340 passwd_homedir(struct passwd *p)
342 if (p) {
343 /* Let's be careful about this, shall we? */
344 size_t len = strlen(p->pw_dir);
345 if (p->pw_dir[len-1] == '/') {
346 return strdup(p->pw_dir);
347 } else {
348 char *result = malloc(len + 2);
349 if (result) {
350 unsigned int nchars = sprintf(result,"%s/",p->pw_dir);
351 if (nchars == len + 1) {
352 return result;
353 } else {
354 return 0;
356 } else {
357 return 0;
360 } else {
361 return 0;
365 char *
366 user_homedir(char *name)
368 return passwd_homedir(getpwnam(name));
371 char *
372 uid_homedir(uid_t uid)
374 return passwd_homedir(getpwuid(uid));
376 #endif /* !LISP_FEATURE_WIN32 */
379 * functions to get miscellaneous C-level variables
381 * (Doing this by calling functions lets us borrow the smarts of the C
382 * linker, so that things don't blow up when libc versions and thus
383 * variable locations change between compile time and run time.)
386 char **
387 wrapped_environ()
389 return environ;
392 #ifdef LISP_FEATURE_WIN32
393 #include <windows.h>
394 #include <time.h>
396 * faked-up implementation of select(). Right now just enough to get through
397 * second genesis.
399 int sb_select(int top_fd, DWORD *read_set, DWORD *write_set, DWORD *except_set, time_t *timeout)
402 * FIXME: Going forward, we may want to use MsgWaitForMultipleObjects
403 * in order to support a windows message loop inside serve-event.
405 HANDLE handles[MAXIMUM_WAIT_OBJECTS];
406 int fds[MAXIMUM_WAIT_OBJECTS];
407 int num_handles;
408 int i;
409 DWORD retval;
410 int polling_write;
411 DWORD win_timeout;
413 num_handles = 0;
414 polling_write = 0;
415 for (i = 0; i < top_fd; i++) {
416 if (except_set) except_set[i >> 5] = 0;
417 if (write_set && (write_set[i >> 5] & (1 << (i & 31)))) polling_write = 1;
418 if (read_set[i >> 5] & (1 << (i & 31))) {
419 read_set[i >> 5] &= ~(1 << (i & 31));
420 fds[num_handles] = i;
421 handles[num_handles++] = (HANDLE) _get_osfhandle(i);
425 win_timeout = INFINITE;
426 if (timeout) win_timeout = (timeout[0] * 1000) + timeout[1];
428 /* Last parameter here is timeout in milliseconds. */
429 /* retval = WaitForMultipleObjects(num_handles, handles, 0, INFINITE); */
430 retval = WaitForMultipleObjects(num_handles, handles, 0, win_timeout);
432 if (retval < WAIT_ABANDONED) {
433 /* retval, at this point, is the index of the single live HANDLE/fd. */
434 read_set[fds[retval] >> 5] |= (1 << (fds[retval] & 31));
435 return 1;
437 return polling_write;
441 * Windows doesn't have gettimeofday(), and we need it for the compiler,
442 * for serve-event, and for a couple other things. We don't need a timezone
443 * yet, however, and the closest we can easily get to a timeval is the
444 * seconds part. So that's what we do.
446 #define UNIX_EPOCH_FILETIME 116444736000000000ULL
448 int sb_gettimeofday(long *timeval, long *timezone)
450 FILETIME ft;
451 ULARGE_INTEGER uft;
452 GetSystemTimeAsFileTime(&ft);
453 uft.LowPart = ft.dwLowDateTime;
454 uft.HighPart = ft.dwHighDateTime;
455 uft.QuadPart -= UNIX_EPOCH_FILETIME;
456 timeval[0] = uft.QuadPart / 10000000;
457 timeval[1] = (uft.QuadPart % 10000000)/10;
459 return 0;
461 #endif
464 /* We will need to define these things or their equivalents for Win32
465 eventually, but for now let's get it working for everyone else. */
466 #ifndef LISP_FEATURE_WIN32
467 /* From SB-BSD-SOCKETS, to get h_errno */
468 int get_h_errno()
470 return h_errno;
473 /* From SB-POSIX, wait-macros */
474 int wifexited(int status) {
475 return WIFEXITED(status);
477 int wexitstatus(int status) {
478 return WEXITSTATUS(status);
480 int wifsignaled(int status) {
481 return WIFSIGNALED(status);
483 int wtermsig(int status) {
484 return WTERMSIG(status);
486 int wifstopped(int status) {
487 return WIFSTOPPED(status);
489 int wstopsig(int status) {
490 return WSTOPSIG(status);
492 /* FIXME: POSIX also defines WIFCONTINUED, but that appears not to
493 exist on at least Linux... */
494 #endif /* !LISP_FEATURE_WIN32 */
496 /* From SB-POSIX, stat-macros */
497 int s_isreg(mode_t mode)
499 return S_ISREG(mode);
501 int s_isdir(mode_t mode)
503 return S_ISDIR(mode);
505 int s_ischr(mode_t mode)
507 return S_ISCHR(mode);
509 int s_isblk(mode_t mode)
511 return S_ISBLK(mode);
513 int s_isfifo(mode_t mode)
515 return S_ISFIFO(mode);
517 #ifndef LISP_FEATURE_WIN32
518 int s_islnk(mode_t mode)
520 #ifdef S_ISLNK
521 return S_ISLNK(mode);
522 #else
523 return ((mode & S_IFMT) == S_IFLNK);
524 #endif
526 int s_issock(mode_t mode)
528 #ifdef S_ISSOCK
529 return S_ISSOCK(mode);
530 #else
531 return ((mode & S_IFMT) == S_IFSOCK);
532 #endif
534 #endif /* !LISP_FEATURE_WIN32 */
536 #ifndef LISP_FEATURE_WIN32
537 int sb_getrusage(int who, struct rusage *rusage)
539 return getrusage(who, rusage);
542 int sb_gettimeofday(struct timeval *tp, void *tzp)
544 return gettimeofday(tp, tzp);
547 int sb_nanosleep(struct timespec *rqtp, struct timespec *rmtp)
549 return nanosleep(rqtp, rmtp);
552 int sb_select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds,
553 struct timeval *timeout)
555 return select(nfds, readfds, writefds, exceptfds, timeout);
558 int sb_getitimer(int which, struct itimerval *value)
560 return getitimer(which, value);
563 int sb_setitimer(int which, struct itimerval *value, struct itimerval *ovalue)
565 return setitimer(which, value, ovalue);
568 int sb_utimes(char *path, struct timeval times[2])
570 return utimes(path, times);
572 #endif /* !LISP_FEATURE_WIN32 */