Abstract immediate loading on x86-64.
[sbcl.git] / src / runtime / wrap.c
bloba337e4ea7f6ee614b8ce322387e2bafd87c6a1db
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 <sys/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 #include <math.h>
52 #endif
54 #include "runtime.h"
55 #include "util.h"
56 #include "wrap.h"
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
70 * readlink(2) stuff
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. */
78 char *
79 wrapped_readlink(char *path)
81 int bufsiz = strlen(path) + 16;
82 while (1) {
83 char *result = malloc(bufsiz);
84 int n_read = readlink(path, result, bufsiz);
85 if (n_read < 0) {
86 free(result);
87 return 0;
88 } else if (n_read < bufsiz) {
89 result[n_read] = 0;
90 return result;
91 } else {
92 free(result);
93 bufsiz *= 2;
97 #endif
100 * realpath(3), including a wrapper for Windows.
102 char * sb_realpath (char *path)
104 #ifndef LISP_FEATURE_WIN32
105 char *ret;
106 int errnum;
108 if ((ret = calloc(PATH_MAX, sizeof(char))) == NULL)
109 return NULL;
110 if (realpath(path, ret) == NULL) {
111 errnum = errno;
112 free(ret);
113 errno = errnum;
114 return NULL;
116 return(ret);
117 #else
118 char *ret;
119 char *cp;
120 int errnum;
122 if ((ret = calloc(MAX_PATH, sizeof(char))) == NULL)
123 return NULL;
124 if (GetFullPathName(path, MAX_PATH, ret, &cp) == 0) {
125 errnum = errno;
126 free(ret);
127 errno = errnum;
128 return NULL;
130 return(ret);
131 #endif
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.
146 extern DIR *
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. */
159 errno = 0;
160 return readdir(dirp);
163 extern int
164 sb_closedir(DIR * dirp)
166 return closedir(dirp);
169 extern char *
170 sb_dirent_name(struct dirent * ent)
172 return ent->d_name;
176 * stat(2) stuff
179 static void
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
185 #else
186 #define FROB2(stem) to->wrapped_st_##stem = 0;
187 #endif
188 FROB(dev);
189 FROB2(ino);
190 FROB(mode);
191 FROB(nlink);
192 FROB2(uid);
193 FROB2(gid);
194 FROB(rdev);
195 FROB(size);
196 FROB2(blksize);
197 FROB2(blocks);
198 FROB(atime);
199 FROB(mtime);
200 FROB(ctime);
201 #undef FROB
205 stat_wrapper(const char *file_name, struct stat_wrapper *buf)
207 struct stat real_buf;
208 int ret;
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
218 * 2006-01-08, at
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;
228 #endif
230 if ((ret = stat(file_name,&real_buf)) >= 0)
231 copy_to_stat_wrapper(buf, &real_buf);
232 return ret;
235 #ifndef LISP_FEATURE_WIN32
237 lstat_wrapper(const char *file_name, struct stat_wrapper *buf)
239 struct stat real_buf;
240 int ret;
241 if ((ret = lstat(file_name,&real_buf)) >= 0)
242 copy_to_stat_wrapper(buf, &real_buf);
243 return ret;
245 #else
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);
251 #endif
254 fstat_wrapper(int filedes, struct stat_wrapper *buf)
256 struct stat real_buf;
257 int ret;
258 if ((ret = fstat(filedes,&real_buf)) >= 0)
259 copy_to_stat_wrapper(buf, &real_buf);
260 return ret;
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) {
272 int fd;
273 #ifdef LISP_FEATURE_WIN32
274 #define PATHNAME_BUFFER_SIZE MAX_PATH
275 char buf[PATHNAME_BUFFER_SIZE];
277 while (1) {
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
282 _mktemp. */
283 strncpy(buf, template, PATHNAME_BUFFER_SIZE);
284 buf[PATHNAME_BUFFER_SIZE-1]=0; /* force NULL-termination */
285 if (_mktemp(buf)) {
286 if ((fd=open(buf, O_CREAT|O_EXCL|O_RDWR, mode))!=-1) {
287 strcpy(template, buf);
288 return (fd);
289 } else
290 if (errno != EEXIST)
291 return (-1);
292 } else
293 return (-1);
295 #undef PATHNAME_BUFFER_SIZE
296 #else
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
313 return -1;
315 return fd;
316 #endif
321 * getpwuid() stuff
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 */
331 char *
332 uid_username(int uid)
334 struct passwd *p = getpwuid(uid);
335 if (p) {
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);
340 } else {
341 return 0;
345 char *
346 passwd_homedir(struct passwd *p)
348 if (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);
353 } else {
354 char *result = malloc(len + 2);
355 if (result) {
356 unsigned int nchars = sprintf(result,"%s/",p->pw_dir);
357 if (nchars == len + 1) {
358 return result;
359 } else {
360 return 0;
362 } else {
363 return 0;
366 } else {
367 return 0;
371 char *
372 user_homedir(char *name)
374 return passwd_homedir(getpwnam(name));
377 char *
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.)
392 char **
393 wrapped_environ()
395 return environ;
398 #ifdef LISP_FEATURE_WIN32
399 #include <windows.h>
400 #include <time.h>
402 * faked-up implementation of select(). Right now just enough to get through
403 * second genesis.
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];
413 int num_handles;
414 int i;
415 DWORD retval;
416 int polling_write;
417 DWORD win_timeout;
419 num_handles = 0;
420 polling_write = 0;
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));
441 return 1;
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)
456 FILETIME ft;
457 ULARGE_INTEGER uft;
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;
465 return 0;
467 #endif
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 */
474 int get_h_errno()
476 return 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)
526 #ifdef S_ISLNK
527 return S_ISLNK(mode);
528 #else
529 return ((mode & S_IFMT) == S_IFLNK);
530 #endif
532 int s_issock(mode_t mode)
534 #ifdef S_ISSOCK
535 return S_ISSOCK(mode);
536 #else
537 return ((mode & S_IFMT) == S_IFSOCK);
538 #endif
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) { \
581 return name(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) {
593 return hypot(x, y);
596 #endif