Add a declaration
[sbcl.git] / src / runtime / wrap.c
blobfaf436a46478809aec0569a41ed966eb0ab5ca50
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 #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 return readdir(dirp);
158 extern int
159 sb_closedir(DIR * dirp)
161 return closedir(dirp);
164 extern char *
165 sb_dirent_name(struct dirent * ent)
167 return ent->d_name;
171 * stat(2) stuff
174 static void
175 copy_to_stat_wrapper(struct stat_wrapper *to, struct stat *from)
177 #define FROB(stem) to->wrapped_st_##stem = from->st_##stem
178 #ifndef LISP_FEATURE_WIN32
179 #define FROB2(stem) to->wrapped_st_##stem = from->st_##stem
180 #else
181 #define FROB2(stem) to->wrapped_st_##stem = 0;
182 #endif
183 FROB(dev);
184 FROB2(ino);
185 FROB(mode);
186 FROB(nlink);
187 FROB2(uid);
188 FROB2(gid);
189 FROB(rdev);
190 FROB(size);
191 FROB2(blksize);
192 FROB2(blocks);
193 FROB(atime);
194 FROB(mtime);
195 FROB(ctime);
196 #undef FROB
200 stat_wrapper(const char *file_name, struct stat_wrapper *buf)
202 struct stat real_buf;
203 int ret;
205 #ifdef LISP_FEATURE_WIN32
207 * Windows won't match the last component of a pathname if there
208 * is a trailing #\/ or #\\, except if it's <drive>:\ or <drive>:/
209 * in which case it behaves the other way around. So we remove the
210 * trailing directory separator unless we are being passed just a
211 * drive name (e.g. "c:\\"). Some, but not all, of this
212 * strangeness is documented at Microsoft's support site (as of
213 * 2006-01-08, at
214 * <http://support.microsoft.com/default.aspx?scid=kb;en-us;168439>)
216 char file_buf[MAX_PATH];
217 strcpy(file_buf, file_name);
218 int len = strlen(file_name);
219 if (len != 0 && (file_name[len-1] == '/' || file_name[len-1] == '\\') &&
220 !(len == 3 && file_name[1] == ':' && isalpha(file_name[0])))
221 file_buf[len-1] = '\0';
222 file_name = file_buf;
223 #endif
225 if ((ret = stat(file_name,&real_buf)) >= 0)
226 copy_to_stat_wrapper(buf, &real_buf);
227 return ret;
230 #ifndef LISP_FEATURE_WIN32
232 lstat_wrapper(const char *file_name, struct stat_wrapper *buf)
234 struct stat real_buf;
235 int ret;
236 if ((ret = lstat(file_name,&real_buf)) >= 0)
237 copy_to_stat_wrapper(buf, &real_buf);
238 return ret;
240 #else
241 /* cleaner to do it here than in Lisp */
242 int lstat_wrapper(const char *file_name, struct stat_wrapper *buf)
244 return stat_wrapper(file_name, buf);
246 #endif
249 fstat_wrapper(int filedes, struct stat_wrapper *buf)
251 struct stat real_buf;
252 int ret;
253 if ((ret = fstat(filedes,&real_buf)) >= 0)
254 copy_to_stat_wrapper(buf, &real_buf);
255 return ret;
258 /* A wrapper for mkstemp(3), for two reasons: (1) mkstemp does not
259 exist on Windows; (2) by passing down a mode_t, we don't need a
260 binding to chmod in SB-UNIX, and need not concern ourselves with
261 umask issues if we want to use mkstemp to make new files in
262 OPEN as implied by the cagey remark (in 'unix.lisp') that
263 "There are good reasons to implement some OPEN options with a[n]
264 mkstemp(3)-like routine, but we don't do that yet." */
266 int sb_mkstemp (char *template, mode_t mode) {
267 int fd;
268 #ifdef LISP_FEATURE_WIN32
269 #define PATHNAME_BUFFER_SIZE MAX_PATH
270 char buf[PATHNAME_BUFFER_SIZE];
272 while (1) {
273 /* Fruit fallen from the tree: for people who like
274 microoptimizations, we might not need to copy the whole
275 template on every loop, but only the last several characters.
276 But I didn't feel like testing the boundary cases in Windows's
277 _mktemp. */
278 strncpy(buf, template, PATHNAME_BUFFER_SIZE);
279 buf[PATHNAME_BUFFER_SIZE-1]=0; /* force NULL-termination */
280 if (_mktemp(buf)) {
281 if ((fd=open(buf, O_CREAT|O_EXCL|O_RDWR, mode))!=-1) {
282 strcpy(template, buf);
283 return (fd);
284 } else
285 if (errno != EEXIST)
286 return (-1);
287 } else
288 return (-1);
290 #undef PATHNAME_BUFFER_SIZE
291 #else
292 /* It makes no sense to reimplement mkstemp() with logic susceptible
293 to the exploit that mkstemp() was designed to avoid.
294 Unfortunately, there is a subtle bug in this more nearly correct technique.
295 open() uses the given creation mode ANDed with the process umask,
296 but fchmod() uses exactly the specified mode. Attempting to perform the
297 masking operation manually would result in another race: you can't obtain
298 the current mask except by calling umask(), which both sets and gets it.
299 But since RUN-PROGRAM is the only use of this, and the mode given is #o600
300 which is the default for mkstemp(), RUN-PROGRAM should be indifferent.
301 [The GNU C library documents but doesn't implement getumask() by the way.]
302 So we're patching a security hole with a known innocuous design flaw
303 by necessity to avoid the gcc linker warning that
304 "the use of `mktemp' is dangerous, better use `mkstemp'" */
305 fd = mkstemp(template);
306 if (fd != -1 && fchmod(fd, mode) == -1) {
307 close(fd); // got a file descriptor but couldn't fchmod() it
308 return -1;
310 return fd;
311 #endif
316 * getpwuid() stuff
319 #ifndef LISP_FEATURE_WIN32
320 /* Return a newly-allocated string holding the username for "uid", or
321 * NULL if there's no such user.
323 * KLUDGE: We also return NULL if malloc() runs out of memory
324 * (returning strdup() result) since it's not clear how to handle that
325 * error better. -- WHN 2001-12-28 */
326 char *
327 uid_username(int uid)
329 struct passwd *p = getpwuid(uid);
330 if (p) {
331 /* The object *p is a static struct which'll be overwritten by
332 * the next call to getpwuid(), so it'd be unsafe to return
333 * p->pw_name without copying. */
334 return strdup(p->pw_name);
335 } else {
336 return 0;
340 char *
341 passwd_homedir(struct passwd *p)
343 if (p) {
344 /* Let's be careful about this, shall we? */
345 size_t len = strlen(p->pw_dir);
346 if (p->pw_dir[len-1] == '/') {
347 return strdup(p->pw_dir);
348 } else {
349 char *result = malloc(len + 2);
350 if (result) {
351 unsigned int nchars = sprintf(result,"%s/",p->pw_dir);
352 if (nchars == len + 1) {
353 return result;
354 } else {
355 return 0;
357 } else {
358 return 0;
361 } else {
362 return 0;
366 char *
367 user_homedir(char *name)
369 return passwd_homedir(getpwnam(name));
372 char *
373 uid_homedir(uid_t uid)
375 return passwd_homedir(getpwuid(uid));
377 #endif /* !LISP_FEATURE_WIN32 */
380 * functions to get miscellaneous C-level variables
382 * (Doing this by calling functions lets us borrow the smarts of the C
383 * linker, so that things don't blow up when libc versions and thus
384 * variable locations change between compile time and run time.)
387 char **
388 wrapped_environ()
390 return environ;
393 #ifdef LISP_FEATURE_WIN32
394 #include <windows.h>
395 #include <time.h>
397 * faked-up implementation of select(). Right now just enough to get through
398 * second genesis.
400 int sb_select(int top_fd, DWORD *read_set, DWORD *write_set, DWORD *except_set, time_t *timeout)
403 * FIXME: Going forward, we may want to use MsgWaitForMultipleObjects
404 * in order to support a windows message loop inside serve-event.
406 HANDLE handles[MAXIMUM_WAIT_OBJECTS];
407 int fds[MAXIMUM_WAIT_OBJECTS];
408 int num_handles;
409 int i;
410 DWORD retval;
411 int polling_write;
412 DWORD win_timeout;
414 num_handles = 0;
415 polling_write = 0;
416 for (i = 0; i < top_fd; i++) {
417 if (except_set) except_set[i >> 5] = 0;
418 if (write_set && (write_set[i >> 5] & (1 << (i & 31)))) polling_write = 1;
419 if (read_set[i >> 5] & (1 << (i & 31))) {
420 read_set[i >> 5] &= ~(1 << (i & 31));
421 fds[num_handles] = i;
422 handles[num_handles++] = (HANDLE) _get_osfhandle(i);
426 win_timeout = INFINITE;
427 if (timeout) win_timeout = (timeout[0] * 1000) + timeout[1];
429 /* Last parameter here is timeout in milliseconds. */
430 /* retval = WaitForMultipleObjects(num_handles, handles, 0, INFINITE); */
431 retval = WaitForMultipleObjects(num_handles, handles, 0, win_timeout);
433 if (retval < WAIT_ABANDONED) {
434 /* retval, at this point, is the index of the single live HANDLE/fd. */
435 read_set[fds[retval] >> 5] |= (1 << (fds[retval] & 31));
436 return 1;
438 return polling_write;
442 * Windows doesn't have gettimeofday(), and we need it for the compiler,
443 * for serve-event, and for a couple other things. We don't need a timezone
444 * yet, however, and the closest we can easily get to a timeval is the
445 * seconds part. So that's what we do.
447 #define UNIX_EPOCH_FILETIME 116444736000000000ULL
449 int sb_gettimeofday(long *timeval, long *timezone)
451 FILETIME ft;
452 ULARGE_INTEGER uft;
453 GetSystemTimeAsFileTime(&ft);
454 uft.LowPart = ft.dwLowDateTime;
455 uft.HighPart = ft.dwHighDateTime;
456 uft.QuadPart -= UNIX_EPOCH_FILETIME;
457 timeval[0] = uft.QuadPart / 10000000;
458 timeval[1] = (uft.QuadPart % 10000000)/10;
460 return 0;
462 #endif
465 /* We will need to define these things or their equivalents for Win32
466 eventually, but for now let's get it working for everyone else. */
467 #ifndef LISP_FEATURE_WIN32
468 /* From SB-BSD-SOCKETS, to get h_errno */
469 int get_h_errno()
471 return h_errno;
474 /* From SB-POSIX, wait-macros */
475 int wifexited(int status) {
476 return WIFEXITED(status);
478 int wexitstatus(int status) {
479 return WEXITSTATUS(status);
481 int wifsignaled(int status) {
482 return WIFSIGNALED(status);
484 int wtermsig(int status) {
485 return WTERMSIG(status);
487 int wifstopped(int status) {
488 return WIFSTOPPED(status);
490 int wstopsig(int status) {
491 return WSTOPSIG(status);
493 /* FIXME: POSIX also defines WIFCONTINUED, but that appears not to
494 exist on at least Linux... */
495 #endif /* !LISP_FEATURE_WIN32 */
497 /* From SB-POSIX, stat-macros */
498 int s_isreg(mode_t mode)
500 return S_ISREG(mode);
502 int s_isdir(mode_t mode)
504 return S_ISDIR(mode);
506 int s_ischr(mode_t mode)
508 return S_ISCHR(mode);
510 int s_isblk(mode_t mode)
512 return S_ISBLK(mode);
514 int s_isfifo(mode_t mode)
516 return S_ISFIFO(mode);
518 #ifndef LISP_FEATURE_WIN32
519 int s_islnk(mode_t mode)
521 #ifdef S_ISLNK
522 return S_ISLNK(mode);
523 #else
524 return ((mode & S_IFMT) == S_IFLNK);
525 #endif
527 int s_issock(mode_t mode)
529 #ifdef S_ISSOCK
530 return S_ISSOCK(mode);
531 #else
532 return ((mode & S_IFMT) == S_IFSOCK);
533 #endif
535 #endif /* !LISP_FEATURE_WIN32 */
537 #ifndef LISP_FEATURE_WIN32
538 int sb_getrusage(int who, struct rusage *rusage)
540 return getrusage(who, rusage);
543 int sb_gettimeofday(struct timeval *tp, void *tzp)
545 return gettimeofday(tp, tzp);
548 int sb_nanosleep(struct timespec *rqtp, struct timespec *rmtp)
550 return nanosleep(rqtp, rmtp);
553 int sb_select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds,
554 struct timeval *timeout)
556 return select(nfds, readfds, writefds, exceptfds, timeout);
559 int sb_getitimer(int which, struct itimerval *value)
561 return getitimer(which, value);
564 int sb_setitimer(int which, struct itimerval *value, struct itimerval *ovalue)
566 return setitimer(which, value, ovalue);
569 int sb_utimes(char *path, struct timeval times[2])
571 return utimes(path, times);
573 #else /* !LISP_FEATURE_WIN32 */
574 #define SB_TRIG_WRAPPER(name) \
575 double sb_##name (double x) { \
576 return name(x); \
578 SB_TRIG_WRAPPER(acos)
579 SB_TRIG_WRAPPER(asin)
580 SB_TRIG_WRAPPER(cosh)
581 SB_TRIG_WRAPPER(sinh)
582 SB_TRIG_WRAPPER(tanh)
583 SB_TRIG_WRAPPER(asinh)
584 SB_TRIG_WRAPPER(acosh)
585 SB_TRIG_WRAPPER(atanh)
587 double sb_hypot (double x, double y) {
588 return hypot(x, y);
591 #endif