2008-06-30 21:53:51 -04:00
|
|
|
#include <stdlib.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <time.h>
|
|
|
|
#include <assert.h>
|
|
|
|
#include <errno.h>
|
|
|
|
#include <limits.h>
|
|
|
|
#include <sys/stat.h>
|
|
|
|
#include <sys/types.h>
|
|
|
|
|
2009-08-28 20:54:51 -04:00
|
|
|
#include "dtypes.h"
|
|
|
|
|
2008-06-30 21:53:51 -04:00
|
|
|
#ifdef WIN32
|
|
|
|
#include <malloc.h>
|
|
|
|
#include <sys/timeb.h>
|
|
|
|
#include <windows.h>
|
|
|
|
#undef NO_ERROR
|
|
|
|
#undef MOD_SHIFT
|
|
|
|
#undef TRUE
|
|
|
|
#undef FALSE
|
|
|
|
#undef VOID
|
|
|
|
#else
|
|
|
|
#include <sys/time.h>
|
|
|
|
#include <sys/poll.h>
|
|
|
|
#include <unistd.h>
|
|
|
|
#endif
|
|
|
|
|
2008-09-10 22:37:38 -04:00
|
|
|
#include "dirpath.h"
|
2008-06-30 21:53:51 -04:00
|
|
|
|
|
|
|
void get_cwd(char *buf, size_t size)
|
|
|
|
{
|
|
|
|
#ifndef WIN32
|
|
|
|
getcwd(buf, size);
|
|
|
|
#else
|
|
|
|
GetCurrentDirectory(size, buf);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
int set_cwd(char *buf)
|
|
|
|
{
|
|
|
|
#ifndef WIN32
|
|
|
|
if (chdir(buf) == -1)
|
|
|
|
return 1;
|
|
|
|
#else
|
|
|
|
if (SetCurrentDirectory(buf) == 0)
|
|
|
|
return 1;
|
|
|
|
#endif
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2008-09-10 22:37:38 -04:00
|
|
|
// destructively convert path to directory part
|
|
|
|
void path_to_dirname(char *path)
|
|
|
|
{
|
|
|
|
char *sep = strrchr(path, PATHSEP);
|
|
|
|
if (sep != NULL) {
|
|
|
|
*sep = '\0';
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
path[0] = '\0';
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-06-30 21:53:51 -04:00
|
|
|
#ifdef LINUX
|
|
|
|
char *get_exename(char *buf, size_t size)
|
|
|
|
{
|
|
|
|
char linkname[64]; /* /proc/<pid>/exe */
|
|
|
|
pid_t pid;
|
|
|
|
ssize_t ret;
|
|
|
|
|
|
|
|
/* Get our PID and build the name of the link in /proc */
|
|
|
|
pid = getpid();
|
|
|
|
|
|
|
|
if (snprintf(linkname, sizeof(linkname), "/proc/%i/exe", pid) < 0)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
/* Now read the symbolic link */
|
|
|
|
ret = readlink(linkname, buf, size);
|
|
|
|
|
|
|
|
/* In case of an error, leave the handling up to the caller */
|
|
|
|
if (ret == -1)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
/* Report insufficient buffer size */
|
|
|
|
if ((size_t)ret >= size)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
/* Ensure proper NUL termination */
|
|
|
|
buf[ret] = 0;
|
|
|
|
|
|
|
|
return buf;
|
|
|
|
}
|
2013-06-03 21:40:14 -04:00
|
|
|
#elif defined(OPENBSD)
|
get_exename() for OpenBSD. (#17)
get_exename() for OpenBSD.
Issue
`get_exename()` gets the pathname of the current process. In
femtolisp, this is used to set the top-level `*install-dir*` which in
turn is used as the location of the system image, `flisp.boot`.
There is only a trivial implementation of `get_exename()` for OpenBSD
that simply returns `NULL`. A minor consequence is that the unit test
will fail for the default build (make) because the system image cannot
be found.
Fix
This commit provides an implementation of `get_exename()` for OpenBSD,
so that the system image can be found.
Unlike, say, Linux or FreeBSD, OpenBSD doesn't have a system call to
get the path of the current (or any, for that matter) process. The
present code contains some logic that was put together to emulate the
behavior of the Linux and FreeBSD variants of `get_exename()` as best
as possible. It works as described by the following.
(1) Call `sysctl(3)` (with `CTL_KERN` -> `KERN_PROC_ARGS` ->
`KERN_PROC_ARGV`) to get the "`argv[0]`" of the current process.
If the program (flisp) was called in "`basename` form" (i.e. as
"flisp"), then go to (2). Otherwise, return the value from
`sysctl(3)` which will be an absolute or relative pathname,
e.g. "/usr/local/bin/flisp" or "../flisp".
The code for (1) was adapted from old OpenBSD-specific `tmux` code
that has since been abandoned by the author only because he deemed
it "too expensive". For that code, see
http://sourceforge.net/p/tmux/tmux-code/ci/8c259f562be24570a19fd94b223034ae8c6e4277/tree/osdep-openbsd.c
(2) Since we now only have "flisp", we need to find out where it is
located on the system. We assume that a program like the shell
had to crawl `PATH` to find "flisp"; hence we do the same.
The code for (2) was adapted from the `which` utility in OpenBSD.
See
http://cvsweb.openbsd.org/cgi-bin/cvsweb/~checkout~/src/usr.bin/which/which.c?rev=1.20&content-type=text/plain
Finally, any error condition returns `NULL`, which is the same
behavior of the other `get_exename()` variants.
* Resolve relative pathnames to absolute, for OpenBSD get_exename().
2016-11-15 15:12:14 -05:00
|
|
|
#include <sys/param.h>
|
|
|
|
#include <sys/sysctl.h>
|
|
|
|
|
2013-06-03 21:40:14 -04:00
|
|
|
char *get_exename(char *buf, size_t size)
|
|
|
|
{
|
get_exename() for OpenBSD. (#17)
get_exename() for OpenBSD.
Issue
`get_exename()` gets the pathname of the current process. In
femtolisp, this is used to set the top-level `*install-dir*` which in
turn is used as the location of the system image, `flisp.boot`.
There is only a trivial implementation of `get_exename()` for OpenBSD
that simply returns `NULL`. A minor consequence is that the unit test
will fail for the default build (make) because the system image cannot
be found.
Fix
This commit provides an implementation of `get_exename()` for OpenBSD,
so that the system image can be found.
Unlike, say, Linux or FreeBSD, OpenBSD doesn't have a system call to
get the path of the current (or any, for that matter) process. The
present code contains some logic that was put together to emulate the
behavior of the Linux and FreeBSD variants of `get_exename()` as best
as possible. It works as described by the following.
(1) Call `sysctl(3)` (with `CTL_KERN` -> `KERN_PROC_ARGS` ->
`KERN_PROC_ARGV`) to get the "`argv[0]`" of the current process.
If the program (flisp) was called in "`basename` form" (i.e. as
"flisp"), then go to (2). Otherwise, return the value from
`sysctl(3)` which will be an absolute or relative pathname,
e.g. "/usr/local/bin/flisp" or "../flisp".
The code for (1) was adapted from old OpenBSD-specific `tmux` code
that has since been abandoned by the author only because he deemed
it "too expensive". For that code, see
http://sourceforge.net/p/tmux/tmux-code/ci/8c259f562be24570a19fd94b223034ae8c6e4277/tree/osdep-openbsd.c
(2) Since we now only have "flisp", we need to find out where it is
located on the system. We assume that a program like the shell
had to crawl `PATH` to find "flisp"; hence we do the same.
The code for (2) was adapted from the `which` utility in OpenBSD.
See
http://cvsweb.openbsd.org/cgi-bin/cvsweb/~checkout~/src/usr.bin/which/which.c?rev=1.20&content-type=text/plain
Finally, any error condition returns `NULL`, which is the same
behavior of the other `get_exename()` variants.
* Resolve relative pathnames to absolute, for OpenBSD get_exename().
2016-11-15 15:12:14 -05:00
|
|
|
int mib[4];
|
|
|
|
pid_t pid;
|
|
|
|
size_t len, plen;
|
|
|
|
char **argv, **argv2;
|
|
|
|
char *p, *path, *pathcpy, filename[PATH_MAX];
|
|
|
|
struct stat sbuf;
|
|
|
|
|
|
|
|
pid = getpid();
|
|
|
|
|
|
|
|
mib[0] = CTL_KERN;
|
|
|
|
mib[1] = KERN_PROC_ARGS;
|
|
|
|
mib[2] = pid;
|
|
|
|
mib[3] = KERN_PROC_ARGV;
|
|
|
|
|
|
|
|
buf = NULL;
|
|
|
|
argv = NULL;
|
|
|
|
len = 128;
|
|
|
|
|
|
|
|
// Now, play The Guessing Game with sysctl(3) as to how big argv
|
|
|
|
// is supposed to be. (It's loads of fun for the whole family!)
|
|
|
|
|
|
|
|
while (len < SIZE_MAX / 2) {
|
|
|
|
len *= 2;
|
|
|
|
if ((argv2 = realloc(argv, len)) == NULL)
|
|
|
|
break;
|
|
|
|
argv = argv2;
|
|
|
|
if (sysctl(mib, 4, argv, &len, NULL, 0) == -1) {
|
|
|
|
if (errno == ENOMEM)
|
|
|
|
continue; // Go back and realloc more memory.
|
|
|
|
break; // Bail for some other error in sysctl(3).
|
|
|
|
}
|
|
|
|
// If you made it here, congrats! You guessed right!
|
|
|
|
if (*argv != NULL)
|
|
|
|
buf = strdup(*argv);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
free(argv);
|
|
|
|
|
|
|
|
// If no error occurred in the sysctl(3) KERN_PROC_ARGV call
|
|
|
|
// above, then buf at this point contains some kind of pathname.
|
|
|
|
|
|
|
|
if (buf != NULL) {
|
|
|
|
if (strchr(buf, '/') == NULL) {
|
|
|
|
// buf contains a `basename`-style pathname (i.e. "foo",
|
|
|
|
// as opposed to "../foo" or "/usr/bin/foo"); search the
|
|
|
|
// PATH for its location. (BTW the setgid(2), setuid(2)
|
|
|
|
// calls are a pre-condition for the access(2) call
|
|
|
|
// later.)
|
|
|
|
|
|
|
|
if ( (path = getenv("PATH")) != NULL &&
|
|
|
|
!setgid(getegid()) && !setuid(geteuid()) ) {
|
|
|
|
|
|
|
|
// The strdup(3) call below, if successful, will
|
|
|
|
// allocate memory for the PATH string returned by
|
|
|
|
// getenv(3) above. This is necessary because the man
|
|
|
|
// page of getenv(3) says that its return value
|
|
|
|
// "should be considered read-only"; however, the
|
|
|
|
// strsep(3) call below is going to be destructively
|
|
|
|
// modifying that value. ("Hulk smash!")
|
|
|
|
|
|
|
|
if ((path = strdup(path)) != NULL) {
|
|
|
|
pathcpy = path;
|
|
|
|
len = strlen(buf);
|
|
|
|
while ((p = strsep(&pathcpy, ":")) != NULL) {
|
|
|
|
if (*p == '\0') p = ".";
|
|
|
|
plen = strlen(p);
|
|
|
|
|
|
|
|
// strip trailing '/'
|
|
|
|
while (p[plen-1] == '/') p[--plen] = '\0';
|
|
|
|
|
|
|
|
if (plen + 1 + len < sizeof(filename)) {
|
|
|
|
snprintf(filename, sizeof(filename), "%s/%s", p, buf);
|
|
|
|
if ( (stat(filename, &sbuf) == 0) &&
|
|
|
|
S_ISREG(sbuf.st_mode) &&
|
|
|
|
access(filename, X_OK) == 0 ) {
|
|
|
|
buf = strdup(filename);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
free(path); // free the strdup(3) memory allocation.
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else buf = NULL; // call to getenv(3) or [sg]ete?[ug]id(2) failed.
|
|
|
|
}
|
|
|
|
if ( buf != NULL && *buf != '/' ) {
|
|
|
|
// buf contains a relative pathname (e.g. "../foo");
|
|
|
|
// resolve this to an absolute pathname.
|
|
|
|
if ( strlcpy(filename, buf, sizeof(filename)) >= sizeof(filename) ||
|
|
|
|
realpath(filename, buf) == NULL )
|
|
|
|
buf = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return buf;
|
2013-06-03 21:40:14 -04:00
|
|
|
}
|
2015-04-11 15:21:02 -04:00
|
|
|
#elif defined(FREEBSD)
|
2012-02-26 23:00:47 -05:00
|
|
|
#include <sys/types.h>
|
|
|
|
#include <sys/sysctl.h>
|
|
|
|
|
|
|
|
char *get_exename(char *buf, size_t size)
|
|
|
|
{
|
|
|
|
int mib[4];
|
|
|
|
mib[0] = CTL_KERN;
|
|
|
|
mib[1] = KERN_PROC;
|
|
|
|
mib[2] = KERN_PROC_PATHNAME;
|
|
|
|
mib[3] = -1;
|
|
|
|
sysctl(mib, 4, buf, &size, NULL, 0);
|
|
|
|
|
|
|
|
return buf;
|
|
|
|
}
|
2008-06-30 21:53:51 -04:00
|
|
|
#elif defined(WIN32)
|
|
|
|
char *get_exename(char *buf, size_t size)
|
|
|
|
{
|
|
|
|
if (GetModuleFileName(NULL, buf, size) == 0)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
return buf;
|
|
|
|
}
|
2010-02-24 23:37:33 -05:00
|
|
|
#elif defined(MACOSX)
|
2015-05-06 18:36:41 -04:00
|
|
|
#include <mach-o/dyld.h>
|
2008-06-30 21:53:51 -04:00
|
|
|
char *get_exename(char *buf, size_t size)
|
|
|
|
{
|
2015-05-06 18:36:41 -04:00
|
|
|
uint32_t bufsize = (uint32_t)size;
|
|
|
|
if (_NSGetExecutablePath(buf, &bufsize))
|
|
|
|
return NULL;
|
2008-06-30 21:53:51 -04:00
|
|
|
return buf;
|
|
|
|
}
|
|
|
|
#endif
|